Skip to content

Commit

Permalink
Configure pprof on controller-manager.
Browse files Browse the repository at this point in the history
Generated file.
Adding cluster mode changes.
Updated version for cluster mode.
Skipping version check on dev mode controllers.
Make pprof support case insensitive.
Factored in Justin's feedback.
  • Loading branch information
cheftako committed Nov 6, 2024
1 parent 1e723b5 commit 94f6d3a
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ spec:
spec:
description: ControllerReconcilerSpec is the specification of ControllerReconciler.
properties:
pprof:
description: Configures the debug endpoint on the service.
properties:
pprofPort:
description: The port that the pprof server binds to if enabled
type: integer
pprofSupport:
description: Control if pprof should be turned on and which types
should be enabled.
enum:
- none
- all
type: string
type: object
rateLimit:
description: |-
RateLimit configures the token bucket rate limit to the kubernetes client used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ spec:
spec:
description: NamespacedControllerReconciler is the specification of NamespacedControllerReconciler.
properties:
pprof:
description: Configures the debug endpoint on the service.
properties:
pprofPort:
description: The port that the pprof server binds to if enabled
type: integer
pprofSupport:
description: Control if pprof should be turned on and which types
should be enabled.
enum:
- none
- all
type: string
type: object
rateLimit:
description: |-
RateLimit configures the token bucket rate limit to the kubernetes client used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type NamespacedControllerReconcilerSpec struct {
// If not specified, the default will be Token Bucket with qps 20, burst 30.
// +optional
RateLimit *RateLimit `json:"rateLimit,omitempty"`
// Configures the debug endpoint on the service.
// +optional
Pprof *PprofConfig `json:"pprof,omitempty"`
}

type RateLimit struct {
Expand All @@ -52,6 +55,16 @@ type RateLimit struct {
Burst int `json:"burst,omitempty"`
}

type PprofConfig struct {
// Control if pprof should be turned on and which types should be enabled.
// +kubebuilder:validation:Enum=none;all
// +optional
PprofSupport string `json:"pprofSupport,omitempty"`
// The port that the pprof server binds to if enabled
// +optional
PprofPort int `json:"pprofPort,omitempty"`
}

// NamespacedControllerReconcilerStatus defines the observed state of NamespacedControllerReconciler.
type NamespacedControllerReconcilerStatus struct {
addonv1alpha1.CommonStatus `json:",inline"`
Expand Down Expand Up @@ -92,6 +105,9 @@ type ControllerReconcilerSpec struct {
// If not specified, the default will be Token Bucket with qps 20, burst 30.
// +optional
RateLimit *RateLimit `json:"rateLimit,omitempty"`
// Configures the debug endpoint on the service.
// +optional
Pprof *PprofConfig `json:"pprof,omitempty"`
}

// ControllerReconcilerStatus defines the observed state of ControllerReconciler.
Expand All @@ -116,6 +132,10 @@ var ValidRateLimitControllers = []string{
"cnrm-controller-manager",
}

var SupportedPprofControllers = []string{
"cnrm-controller-manager",
}

func init() {
SchemeBuilder.Register(
&NamespacedControllerReconciler{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,10 @@ func (r *Reconciler) applyControllerReconcilerCR(ctx context.Context, cr *custom
r.log.Error(err, errMsg)
return r.handleApplyControllerReconcilerFailed(ctx, cr, errMsg)
}
if err := controllers.ApplyContainerPprof(m, cr.Name, cr.Spec.Pprof); err != nil {
msg := fmt.Sprintf("failed to apply pprof customization %s: %v", cr.Name, err)
return r.handleApplyControllerReconcilerFailed(ctx, cr, msg)
}
return r.handleApplyControllerReconcilerSucceeded(ctx, cr)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,10 @@ func (r *Reconciler) applyNamespacedControllerReconciler(ctx context.Context, cr
msg := fmt.Sprintf("failed to apply rate limit customization %s: %v", cr.Name, err)
return r.handleApplyNamespacedControllerReconcilerFailed(ctx, cr.Namespace, cr.Name, msg)
}
if err := controllers.ApplyContainerPprof(m, cr.Name, cr.Spec.Pprof); err != nil {
msg := fmt.Sprintf("failed to apply pprof customization %s: %v", cr.Name, err)
return r.handleApplyNamespacedControllerReconcilerFailed(ctx, cr.Namespace, cr.Name, msg)
}
return r.handleApplyNamespacedControllerReconcilerSucceeded(ctx, cr.Namespace, cr.Name)
}

Expand Down
93 changes: 92 additions & 1 deletion operator/pkg/controllers/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ func ApplyContainerRateLimit(m *manifest.Objects, targetControllerName string, r
targetControllerName, strings.Join(customizev1alpha1.ValidRateLimitControllers, ", "))
}

count := 0
for _, item := range m.Items {
if item.GroupVersionKind() != targetControllerGVK {
continue
Expand All @@ -540,7 +541,10 @@ func ApplyContainerRateLimit(m *manifest.Objects, targetControllerName string, r
if err := item.MutateContainers(customizeRateLimitFn(targetContainerName, ratelimit)); err != nil {
return err
}
break // we already found the matching controller, no need to keep looking.
count++
}
if count != 1 {
return fmt.Errorf("rate limit customization for %s modified %d isntances.", targetControllerName, count)

Check failure on line 547 in operator/pkg/controllers/utils.go

View workflow job for this annotation

GitHub Actions / lint

`isntances` is a misspelling of `instances` (misspell)
}
return nil
}
Expand Down Expand Up @@ -586,3 +590,90 @@ func applyRateLimitToContainerArg(container map[string]interface{}, rateLimit *c
}
return nil
}

func ApplyContainerPprof(m *manifest.Objects, targetControllerName string, pprofConfig *customizev1alpha1.PprofConfig) error {
if pprofConfig == nil {
return nil
}

var (
targetContainerName string
targetControllerGVK schema.GroupVersionKind
)
switch targetControllerName {
case "cnrm-controller-manager":
targetContainerName = "manager"
targetControllerGVK = schema.GroupVersionKind{
Group: appsv1.SchemeGroupVersion.Group,
Version: appsv1.SchemeGroupVersion.Version,
Kind: "StatefulSet",
}
default:
return fmt.Errorf("pprof config customization for %s is not supported. "+
"Supported controllers: %s",
targetControllerName, strings.Join(customizev1alpha1.SupportedPprofControllers, ", "))
}

count := 0
for _, item := range m.Items {
if item.GroupVersionKind() != targetControllerGVK {
continue
}
if !strings.HasPrefix(item.GetName(), targetControllerName) {
continue
}
if err := item.MutateContainers(customizePprofConfigFn(targetContainerName, pprofConfig)); err != nil {
return err
}
count++
}
if count != 1 {
return fmt.Errorf("pprof config customization for %s modified %d isntances.", targetControllerName, count)

Check failure on line 631 in operator/pkg/controllers/utils.go

View workflow job for this annotation

GitHub Actions / lint

`isntances` is a misspelling of `instances` (misspell)
}
return nil
}

func customizePprofConfigFn(target string, pprofConfig *customizev1alpha1.PprofConfig) func(container map[string]interface{}) error {
return func(container map[string]interface{}) error {
name, _, err := unstructured.NestedString(container, "name")
if err != nil {
return fmt.Errorf("error reading container name: %w", err)
}
if name != target {
return nil
}
return applyPprofConfigToContainerArg(container, pprofConfig)
}
}

func applyPprofConfigToContainerArg(container map[string]interface{}, pprofConfig *customizev1alpha1.PprofConfig) error {
if pprofConfig == nil {
return nil
}
origArgs, found, err := unstructured.NestedStringSlice(container, "args")
if err != nil {
return fmt.Errorf("error getting args in container: %w", err)
}
wantArgs := []string{}
if strings.ToUpper(pprofConfig.PprofSupport) == "ALL" {
wantArgs = append(wantArgs, "--enable-pprof=true")
} else {
wantArgs = append(wantArgs, "--enable-pprof=false")
}
if pprofConfig.PprofPort > 0 {
wantArgs = append(wantArgs, fmt.Sprintf("--pprof-port=%d", pprofConfig.PprofPort))
}
if found {
for _, arg := range origArgs {
if strings.Contains(arg, "--enable-pprof") || strings.Contains(arg, "--pprof-port") {
// drop the old value on the floor
continue
}
wantArgs = append(wantArgs, arg)
}
}
if err := unstructured.SetNestedStringSlice(container, wantArgs, "args"); err != nil {
return fmt.Errorf("error setting args in container: %w", err)
}
return nil
}
7 changes: 6 additions & 1 deletion operator/pkg/preflight/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import (
)

var (
ulog = ctrl.Log.WithName("UpgradeChecker")
ulog = ctrl.Log.WithName("UpgradeChecker")
devVersion = semver.MustParse("0.0.0-dev")
)

// NewUpgradeChecker provides an implementation of declarative.Preflight that
Expand Down Expand Up @@ -95,6 +96,10 @@ func (u *UpgradeChecker) Preflight(ctx context.Context, o declarative.Declarativ
}

func compareMajorOnly(v, w semver.Version) int {
if v.Equals(devVersion) {
// If we are using a dev controller ignore semver drift.
return 0
}
if v.Major != w.Major {
if v.Major > w.Major {
return 1
Expand Down

0 comments on commit 94f6d3a

Please sign in to comment.