Skip to content

Commit

Permalink
Merge pull request #3093 from cheftako/pprof
Browse files Browse the repository at this point in the history
Configure pprof on controller-manager.
  • Loading branch information
google-oss-prow[bot] authored Nov 11, 2024
2 parents 22ac833 + 4232c34 commit dc17f83
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:
port:
description: The port that the pprof server binds to if enabled
type: integer
support:
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:
port:
description: The port that the pprof server binds to if enabled
type: integer
support:
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
Support string `json:"support,omitempty"`
// The port that the pprof server binds to if enabled
// +optional
Port int `json:"port,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 instances.", targetControllerName, count)
}
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 instances.", targetControllerName, count)
}
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.Support) == "ALL" {
wantArgs = append(wantArgs, "--enable-pprof=true")
} else {
wantArgs = append(wantArgs, "--enable-pprof=false")
}
if pprofConfig.Port > 0 {
wantArgs = append(wantArgs, fmt.Sprintf("--pprof-port=%d", pprofConfig.Port))
}
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 dc17f83

Please sign in to comment.