Skip to content

Feature OCPSTRAT-3156: Configurable log levels for hosted control plane components#2038

Draft
rutvik23 wants to merge 1 commit into
openshift:masterfrom
rutvik23:configurable-log-levels-hcp
Draft

Feature OCPSTRAT-3156: Configurable log levels for hosted control plane components#2038
rutvik23 wants to merge 1 commit into
openshift:masterfrom
rutvik23:configurable-log-levels-hcp

Conversation

@rutvik23

@rutvik23 rutvik23 commented Jun 15, 2026

Copy link
Copy Markdown

Why

HyperShift administrators and support engineers cannot adjust log
verbosity for hosted control plane components during troubleshooting.
Standard OCP has this via operatorv1.LogLevel, but HyperShift has no
equivalent except an ad-hoc, unvalidated annotation for kube-apiserver.
This was reported as RFE-7777 and accepted as crucial for minimal
troubleshooting.

What

Enhancement proposal introducing structured per-component log level
configuration for CPO-managed components via the HostedCluster CR:

  • New ComponentLogLevelSpec type with Normal/Debug/Trace/TraceAll
    enum (matching operatorv1.LogLevel)
  • New optional pointer fields in OperatorConfiguration for 8 core
    control plane components
  • Phased delivery: KAS first (Phase 1), remaining 7 components
    (Phase 2), all remaining CPO-managed components documented
    holistically (Phase 3)
  • Deprecation path for existing kube-apiserver-verbosity-level
    annotation
  • Ships ungated, GA in target release

References

  Introduces an enhancement proposal for structured, per-component
  log level configuration (Normal/Debug/Trace/TraceAll) for hosted
  control plane components managed by CPO via the HostedCluster CR.

  Covers kube-apiserver (Phase 1), 7 remaining core components
  (Phase 2), and documents holistic scope for all CPO-managed
  components (Phase 3). Replaces the existing ad-hoc
  kube-apiserver-verbosity-level annotation with a validated,
  structured API using ComponentLogLevelSpec pointer fields in
  OperatorConfiguration.

  Tracking: https://issues.redhat.com/browse/OCPSTRAT-3156
  RFE: https://issues.redhat.com/browse/RFE-7777
@openshift-ci

openshift-ci Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 15, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 15, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 15, 2026

Copy link
Copy Markdown

@rutvik23: This pull request references OCPSTRAT-3156 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the feature to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Why

HyperShift administrators and support engineers cannot adjust log
verbosity for hosted control plane components during troubleshooting.
Standard OCP has this via operatorv1.LogLevel, but HyperShift has no
equivalent except an ad-hoc, unvalidated annotation for kube-apiserver.
This was reported as RFE-7777 and accepted as crucial for minimal
troubleshooting.

What

Enhancement proposal introducing structured per-component log level
configuration for CPO-managed components via the HostedCluster CR:

  • New ComponentLogLevelSpec type with Normal/Debug/Trace/TraceAll
    enum (matching operatorv1.LogLevel)
  • New optional pointer fields in OperatorConfiguration for 8 core
    control plane components
  • Phased delivery: KAS first (Phase 1), remaining 7 components
    (Phase 2), all remaining CPO-managed components documented
    holistically (Phase 3)
  • Deprecation path for existing kube-apiserver-verbosity-level
    annotation
  • Ships ungated, GA in target release

References

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign csrwng for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

as structured `*ComponentLogLevelSpec` pointers in the existing `OperatorConfiguration`
type. The design is intentionally generic to extend to all remaining CPO-managed components
in future phases. This feature ships ungated (no feature gate) as a low-risk operational
knob that extends an already-GA framework.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing ClusterVersionOperator field in OperatorConfiguration IS gated behind +openshift:enable:FeatureGate=ClusterVersionOperatorConfiguration. The API review guide states: "New fields in existing APIs should always be gated." Skipping the gate here is inconsistent with the precedent set by the only other log-level field in this same struct. What is the justification for treating these 8 new fields differently from the CVO field that lives right next to them?

// +kubebuilder:default=Normal
// +kubebuilder:validation:Enum="";Normal;Debug;Trace;TraceAll
LogLevel LogLevel `json:"logLevel,omitempty"`
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several issues with this type:

  1. Static default on a configuration API. +kubebuilder:default=Normal persists the default at admission time. Per OpenShift API conventions, configuration APIs should default in the controller, not the schema, so the default can evolve over time. If Normal is intended to be permanent, document that explicitly. Otherwise, remove the marker and default in the CPO, with Godoc: "When omitted, this means the user has no opinion and the platform defaults to Normal, which is subject to change over time."

  2. Empty string in enum is ambiguous. The enum includes "" alongside +kubebuilder:default=Normal. If a user submits kubeAPIServer: {}, the field defaults to "Normal". If they explicitly submit logLevel: "", does that differ from omitting it? The OpenShift convention is: "Only allow the zero value when it is semantically important and means something different to being omitted." What is the semantic meaning of "" here?

  3. Single-field wrapper struct. If ComponentLogLevelSpec will only ever contain logLevel, consider using *LogLevel directly on the OperatorConfiguration fields (e.g., KubeAPIServerLogLevel *LogLevel). This is simpler for users (kubeAPIServerLogLevel: Debug vs kubeAPIServer: {logLevel: Debug}) and avoids the extensibility trap described below.

// oAuthServer configures the log verbosity of the oauth-server component.
// +optional
OAuthServer *ComponentLogLevelSpec `json:"oAuthServer,omitempty"`
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These field names (kubeAPIServer, etcd, openShiftAPIServer, etc.) are generic, implying they are the full configuration entry point for that component. But the type is *ComponentLogLevelSpec, which only carries a log level.

If any of these 8 components ever needs additional per-component configuration (resource overrides, feature flags, etc.), you cannot change the type from *ComponentLogLevelSpec to a dedicated struct without breaking structured clients (serialization changes are forbidden post-merge per API review policy).

You already acknowledge this problem for CVO/CNO/Ingress in the Phase 3 note (line 444-454), where those components get LogLevel embedded in their existing dedicated typed structs. That is the correct pattern. Consider one of:

  • Use dedicated per-component types from the start (KubeAPIServerConfig, EtcdConfig, etc.) each with a logLevel field. More boilerplate now, but future-proof.
  • Or rename the fields to be specific: kubeAPIServerLogLevel *LogLevel, etcdLogLevel *LogLevel, etc. Simpler and leaves namespace for future kubeAPIServer *KubeAPIServerConfig fields.

type OperatorConfiguration struct {
// ...existing ClusterVersionOperator, ClusterNetworkOperator, IngressOperator fields...

// kubeAPIServer configures the log verbosity of the kube-apiserver component.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Godoc should describe user-observable behavior per OpenShift API conventions. Currently it says "configures the log verbosity," which is implementation-oriented. Consider adding:

  • What happens when the field is set (rolling restart of the component, increased log volume)
  • What happens when the field is omitted: "When omitted, this means the user has no opinion and the platform defaults to Normal verbosity."

The existing clusterVersionOperator field's Godoc in OperatorConfiguration follows this pattern with behavioral documentation on operatorLogLevel.


For managed services (ROSA HCP, ARO HCP), service-level guardrails may be needed to
restrict `TraceAll` log level, as glog level 8 can dump sensitive data including request
bodies and secrets in component logs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"May be needed" is too weak for a GA feature. TraceAll at glog level 8 dumps request bodies including secrets. On ROSA HCP, those logs flow to CloudWatch, which is customer-visible. This is a concrete data-leak vector, not a hypothetical.

Before GA, the enhancement should commit to one of:

  • Block TraceAll on managed service clusters (admission webhook or CEL)
  • Allow it but ensure logs containing secrets are not forwarded to customer-visible sinks
  • Accept the risk with explicit documented warnings

Deferring the decision to "be decided with PM" (Open Question 1) is not acceptable for a feature shipping GA without a feature gate.

**Risk:** `TraceAll` on managed services (ROSA HCP, ARO HCP) could expose secrets in logs
flowing to CloudWatch or Azure Monitor (customer-visible).
**Mitigation:** Add admission policy or CEL rule blocking `TraceAll` on managed service
clusters. Access model (customer self-service vs SRE/CEE only) to be decided with PM.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mitigation is stated in imperative ("Add admission policy") but is not listed in the GA Criteria (lines 583-598) or the Phase 1/Phase 2 deliverables. Is this a commitment or a suggestion? If it's required for GA, add it to the GA Criteria. If it's deferred, say so explicitly and explain why shipping GA without it is acceptable given the security implications.

**Risk:** Rolling restarts during log level changes could cause brief API unavailability if
multiple components are changed simultaneously.
**Mitigation:** The CPO should apply changes sequentially across components to avoid
simultaneous restarts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Should" is RFC 2119 advisory, not mandatory. If a user patches all 8 components in one oc patch, will the CPO actually serialize the rollouts? Or will it update all deployments in a single reconciliation pass? This matters for the HA guarantee. If sequential application is required for safety, state it as "must" and describe the implementation mechanism (e.g., reconcile one component per pass, proceed only after rollout completes).


The existing `hypershift.openshift.io/kube-apiserver-verbosity-level` annotation is
deprecated on merge of this feature and will be removed in N+2 (two minor releases after
GA).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"N+2" is ambiguous since this EP doesn't specify what "N" is and the Jira target version is not set (the CI bot flagged this). Use concrete OCP versions (e.g., "deprecated in 4.19, removed in 4.21") so readers don't have to cross-reference the target release.

with elevated verbosity. Administrators and SREs can alert on this to track clusters with
non-standard log volume.
- `HostedCluster` condition `NonDefaultLogLevel=False` — all components running at default
verbosity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition is described but missing key details:

  1. What Reason values are expected? Per Kubernetes API conventions, Reason is required and should be a CamelCase programmatic identifier. Define the expected values (e.g., ElevatedVerbosity, AllDefault).

  2. The condition message should enumerate which components have non-default levels. NonDefaultLogLevel=True without component detail forces SREs to inspect the full spec to find which component is elevated. Include something like "kube-apiserver: Debug, etcd: Trace" in the message.

> via a shell one-liner (`/bin/sh -c "... /usr/bin/etcd"`). Injecting a CLI flag means
> string-manipulating the shell command — fragile and breaks if the command format changes.
> `ETCD_LOG_LEVEL` matches all 15 existing etcd config values and uses the existing
> `util.UpsertEnvVar()` utility (from `support/util/containers.go`). etcd internally maps

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the file path is incorrect. UpsertEnvVar lives in support/podspec/containers.go, not support/util/containers.go. There is no containers.go in support/util/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants