Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,12 @@ make update # Full update (api-deps, workspace-sync, capi-sync
make capi-sync # Sync CAPI provider types (incremental)
make capi-sync-force # Force re-sync all CAPI providers
make verify-capi-sync # Verify CAPI sync is clean (CI target)
make gmp-sync # Regenerate the pinned GMP API snapshot
make verify-gmp-sync # Verify the GMP snapshot reproduces without changing tracked files
```

For GMP API updates, see [the package maintenance guide](support/gmpmonitoring/README.md#maintenance).

## Development Patterns

### Resource Management
Expand Down
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ build: hypershift-operator control-plane-operator control-plane-pki-operator kar
CAPI_PROVIDERS := agent aws azure gcp ibmcloud kubevirt openstack

.PHONY: update
update: api-deps workspace-sync capi-sync deps api api-docs clients docs-aggregate
update: api-deps workspace-sync capi-sync gmp-sync deps api api-docs clients docs-aggregate
$(MAKE) ownership-rules

GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
Expand Down Expand Up @@ -131,7 +131,7 @@ precommit-api-lint-fix: $(GOLANGCI_LINT)
cd api && $(GOLANGCI_LINT) fmt --config ./.golangci.yml --enable gci $(patsubst api/%,%,$(FILES))

.PHONY: lint
lint: generate verify-capi-sync $(HYPERSHIFTLINTER_PLUGIN)
lint: generate verify-capi-sync verify-gmp-sync $(HYPERSHIFTLINTER_PLUGIN)
$(MAKE) api-lint; api_rc=$$?; \
$(GOLANGCI_LINT) run --config ./.golangci.yml --modules-download-mode=readonly -v; main_rc=$$?; \
exit $$(( api_rc > main_rc ? api_rc : main_rc ))
Expand Down Expand Up @@ -249,9 +249,17 @@ $(CRD_SCHEMA_CHECK): $(TOOLS_DIR)/go.mod # Build crd-schema-check tool
cd $(TOOLS_DIR); $(GO) build -o $(BIN_DIR)/crd-schema-check ./crd-schema-check

.PHONY: generate
generate: $(MOCKGEN)
generate: $(MOCKGEN) $(CONTROLLER_GEN)
$(GO) generate ./...

.PHONY: gmp-sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this be invoked by the 'update' target?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in #10041 (comment)

gmp-sync: $(CONTROLLER_GEN)
./hack/update-gmp-api.sh --sync

.PHONY: verify-gmp-sync
verify-gmp-sync: $(CONTROLLER_GEN)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this be invoked by the 'verify' target?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in #10041 (comment)

./hack/update-gmp-api.sh --verify
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Compile all tests
.PHONY: tests
tests: generate
Expand Down Expand Up @@ -811,7 +819,7 @@ test-commit-layout: $(PYTHON_VENV_STAMP) ## Test the restructure-commits layout

.PHONY: verify-codespell
verify-codespell: codespell ## Verify codespell.
@$(CODESPELL) --count --ignore-words=./.codespellignore --skip="./hack/tools/bin/codespell_dist,./docs/site/*,./vendor/*,./api/vendor/*,./hack/tools/vendor/*,./api/hypershift/v1alpha1/*,./support/thirdparty/*,./docs/content/reference/*,./hack/tools/bin/*,./cmd/install/assets/*,./go.sum,./api/go.sum,./hack/workspace/go.work.sum,./api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests,./hack/tools/go.mod,./hack/tools/go.sum,./karpenter-operator/controllers/karpenter/assets/*.yaml,./dev/*,./pkg/capi/*,./hack/capi-vendor/*"
@$(CODESPELL) --count --ignore-words=./.codespellignore --skip="./hack/tools/bin/codespell_dist,./docs/site/*,./support/gmpmonitoring/testdata/*,./vendor/*,./api/vendor/*,./hack/tools/vendor/*,./api/hypershift/v1alpha1/*,./support/thirdparty/*,./docs/content/reference/*,./hack/tools/bin/*,./cmd/install/assets/*,./go.sum,./api/go.sum,./hack/workspace/go.work.sum,./api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests,./hack/tools/go.mod,./hack/tools/go.sum,./karpenter-operator/controllers/karpenter/assets/*.yaml,./dev/*,./pkg/capi/*,./hack/capi-vendor/*"

.PHONY: verify-api-deps
verify-api-deps: $(VERIFY_API_DEPS) ## Verify API dependency allowlist and shared requirements/replacements.
Expand Down
5 changes: 5 additions & 0 deletions OWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ filters:
- gcp-reviewers
labels:
- area/platform/gcp
"^(support/gmpmonitoring/|support/metrics/gmp_monitoring.*\\.go$|hack/gmp-api-gen/|hack/gmp-api-source/|hack/update-gmp-api\\.sh$)":
reviewers:
- gcp-reviewers
labels:
- area/platform/gcp
"^(api|cmd|control-plane-operator|docs|hypershift-operator|product-cli|test)/.*ibmcloud.*":
labels:
- area/platform/ibmcloud
Expand Down
4 changes: 4 additions & 0 deletions cmd/install/assets/hypershift_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ type HyperShiftOperatorDeployment struct {
IncludeVersion bool
UWMTelemetry bool
RHOBSMonitoring bool
EnableGMPMonitoring bool
CVOPrometheusURL string
MonitoringDashboards bool
CertRotationScale time.Duration
Expand Down Expand Up @@ -822,6 +823,9 @@ func (o HyperShiftOperatorDeployment) buildArgs() []string {
if o.RegistryOverrides != "" {
args = append(args, fmt.Sprintf("--registry-overrides=%s", o.RegistryOverrides))
}
if o.EnableGMPMonitoring {
args = append(args, "--enable-gmp-monitoring")
}
return args
}

Expand Down
15 changes: 15 additions & 0 deletions cmd/install/assets/hypershift_operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,21 @@ func TestBuildArgs(t *testing.T) {
},
expectNotContains: []string{"--registry-overrides"},
},
{
name: "When GMP monitoring is enabled, it should include the flag in args",
deployment: HyperShiftOperatorDeployment{
PrivatePlatform: string(hyperv1.NonePlatform),
EnableGMPMonitoring: true,
},
expectContains: []string{"--enable-gmp-monitoring"},
},
{
name: "When GMP monitoring is disabled, it should not include the flag",
deployment: HyperShiftOperatorDeployment{
PrivatePlatform: string(hyperv1.NonePlatform),
},
expectNotContains: []string{"--enable-gmp-monitoring"},
},
{
name: "When all standard options are set, it should include them in args",
deployment: HyperShiftOperatorDeployment{
Expand Down
14 changes: 14 additions & 0 deletions cmd/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ type Options struct {
WaitUntilAvailable bool
WaitUntilEstablished bool
RHOBSMonitoring bool
EnableGMPMonitoring bool
CVOPrometheusURL string
SLOsAlerts bool
MonitoringDashboards bool
Expand Down Expand Up @@ -388,6 +389,17 @@ func (o *Options) validateMonitoringConfig() []error {
if len(o.CVOPrometheusURL) > 0 && !o.RHOBSMonitoring && !o.EnableCVOManagementClusterMetricsAccess {
errs = append(errs, fmt.Errorf("--cvo-prometheus-url requires either --rhobs-monitoring or --enable-cvo-management-cluster-metrics-access to be enabled"))
}
// RHOBS can be enabled through the flag or through additional operator env vars;
// match the operator Deployment builder's normalization when checking the GMP conflict.
rhobsMonitoring := o.RHOBSMonitoring
for key, value := range o.AdditionalOperatorEnvVars {
if strings.TrimSpace(key) == rhobsmonitoring.EnvironmentVariable {
rhobsMonitoring = rhobsMonitoring || strings.TrimSpace(value) == "1"
}
}
if err := metrics.ValidateGMPMonitoring(o.EnableGMPMonitoring, rhobsMonitoring); err != nil {
errs = append(errs, fmt.Errorf("--enable-gmp-monitoring: %w", err))
}
return errs
}

Expand Down Expand Up @@ -496,6 +508,7 @@ func NewCommand(clientProviders ...*util.ClientProvider) *cobra.Command {
cmd.Flags().BoolVar(&opts.WaitUntilAvailable, "wait-until-available", opts.WaitUntilAvailable, "If true, pauses installation until hypershift operator has been rolled out and its webhook service is available (if installing the webhook)")
cmd.Flags().BoolVar(&opts.WaitUntilEstablished, "wait-until-crds-established", opts.WaitUntilEstablished, "If true, pauses installation until all custom resource definitions are established before applying other manifests.")
cmd.PersistentFlags().BoolVar(&opts.RHOBSMonitoring, "rhobs-monitoring", opts.RHOBSMonitoring, "If true, HyperShift will generate and use the RHOBS version of monitoring resources (ServiceMonitors, PodMonitors, etc). For ROSA HCP, this also enables the Cluster Version Operator to query the RHOBS Prometheus for conditional update evaluation. Use --cvo-prometheus-url to override the default Prometheus endpoint.")
cmd.PersistentFlags().BoolVar(&opts.EnableGMPMonitoring, "enable-gmp-monitoring", opts.EnableGMPMonitoring, "If true, HyperShift will use Google Managed Prometheus (monitoring.googleapis.com) monitoring resources instead of the default monitoring.coreos.com resources. Cannot be combined with --rhobs-monitoring.")
cmd.PersistentFlags().StringVar(&opts.CVOPrometheusURL, "cvo-prometheus-url", opts.CVOPrometheusURL, "Prometheus URL for the Cluster Version Operator to query metrics for conditional update risk evaluation. Only effective when --rhobs-monitoring or --enable-cvo-management-cluster-metrics-access is enabled. If not specified, defaults to the RHOBS monitoring stack for ROSA HCP, or the Thanos querier for self-managed HyperShift.")
cmd.PersistentFlags().BoolVar(&opts.SLOsAlerts, "slos-alerts", opts.SLOsAlerts, "If true, HyperShift will generate and use the prometheus alerts for monitoring HostedCluster and NodePools")
cmd.PersistentFlags().BoolVar(&opts.MonitoringDashboards, "monitoring-dashboards", opts.MonitoringDashboards, "If true, HyperShift will generate a monitoring dashboard for every HostedCluster that it creates")
Expand Down Expand Up @@ -1405,6 +1418,7 @@ func setupOperatorResources(opts Options, userCABundleCM *corev1.ConfigMap, trus
IncludeVersion: !opts.Template,
UWMTelemetry: opts.EnableUWMTelemetryRemoteWrite,
RHOBSMonitoring: opts.RHOBSMonitoring,
EnableGMPMonitoring: opts.EnableGMPMonitoring,
CVOPrometheusURL: opts.CVOPrometheusURL,
MonitoringDashboards: opts.MonitoringDashboards,
CertRotationScale: opts.CertRotationScale,
Expand Down
103 changes: 99 additions & 4 deletions cmd/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/openshift/hypershift/hypershift-operator/controllers/sharedingress"
hyperapi "github.com/openshift/hypershift/support/api"
"github.com/openshift/hypershift/support/metrics"
"github.com/openshift/hypershift/support/rhobsmonitoring"

configv1 "github.com/openshift/api/config/v1"
operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1"
Expand Down Expand Up @@ -1922,9 +1923,10 @@ func TestValidateExternalDNSConfig(t *testing.T) {

func TestValidateMonitoringConfig(t *testing.T) {
tests := []struct {
name string
opts Options
expectError bool
name string
opts Options
expectError bool
errorContains string
}{
{
name: "When no monitoring options are set, it should pass",
Expand Down Expand Up @@ -1954,13 +1956,59 @@ func TestValidateMonitoringConfig(t *testing.T) {
},
expectError: false,
},
{
name: "When GMP monitoring is enabled alone, it should pass",
opts: Options{EnableGMPMonitoring: true},
expectError: false,
},
{
name: "When GMP monitoring is enabled with the RHOBS flag, it should fail",
opts: Options{EnableGMPMonitoring: true, RHOBSMonitoring: true},
expectError: true,
errorContains: "--enable-gmp-monitoring",
},
{
name: "When GMP monitoring is enabled with RHOBS via additional operator env vars, it should fail",
opts: Options{EnableGMPMonitoring: true, AdditionalOperatorEnvVars: map[string]string{" " + rhobsmonitoring.EnvironmentVariable + " ": " 1 "}},
expectError: true,
errorContains: "--enable-gmp-monitoring",
},
{
name: "When GMP monitoring is enabled with RHOBS disabled via additional operator env vars, it should pass",
opts: Options{EnableGMPMonitoring: true, AdditionalOperatorEnvVars: map[string]string{rhobsmonitoring.EnvironmentVariable: "0"}},
expectError: false,
},
{
name: "When GMP monitoring is enabled with the RHOBS flag and RHOBS disabled via additional operator env vars, it should fail",
opts: Options{EnableGMPMonitoring: true, RHOBSMonitoring: true, AdditionalOperatorEnvVars: map[string]string{rhobsmonitoring.EnvironmentVariable: "0"}},
expectError: true,
errorContains: "--enable-gmp-monitoring",
},
{
name: "When GMP monitoring is enabled with a blank RHOBS additional operator env var, it should pass",
opts: Options{EnableGMPMonitoring: true, AdditionalOperatorEnvVars: map[string]string{rhobsmonitoring.EnvironmentVariable: " "}},
expectError: false,
},
{
name: "When GMP monitoring is enabled with a non-1 RHOBS additional operator env var, it should pass",
opts: Options{EnableGMPMonitoring: true, AdditionalOperatorEnvVars: map[string]string{rhobsmonitoring.EnvironmentVariable: "true"}},
expectError: false,
},
{
name: "When GMP monitoring is enabled with duplicate RHOBS additional operator env vars after trimming, it should fail",
opts: Options{EnableGMPMonitoring: true, AdditionalOperatorEnvVars: map[string]string{rhobsmonitoring.EnvironmentVariable: "0", " " + rhobsmonitoring.EnvironmentVariable: "1"}},
expectError: true,
errorContains: "--enable-gmp-monitoring",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
g := NewGomegaWithT(t)
errs := tc.opts.validateMonitoringConfig()
if tc.expectError {
if tc.errorContains != "" {
g.Expect(errs).To(ContainElement(MatchError(ContainSubstring(tc.errorContains))))
} else if tc.expectError {
g.Expect(errs).NotTo(BeEmpty())
} else {
g.Expect(errs).To(BeEmpty())
Expand Down Expand Up @@ -2723,6 +2771,53 @@ func TestHyperShiftOperatorManifests_WebhookFlags(t *testing.T) {
}
}

func TestHyperShiftOperatorManifests_GMPMonitoringFlag(t *testing.T) {
tests := []struct {
name string
enableGMPMonitoring bool
}{
{
name: "When GMP monitoring is enabled, it should pass the flag to the operator deployment",
enableGMPMonitoring: true,
},
{
name: "When GMP monitoring is disabled, it should not pass the flag to the operator deployment",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
g := NewGomegaWithT(t)
opts := Options{
PrivatePlatform: string(hyperv1.NonePlatform),
HyperShiftImage: "test-image",
Namespace: "hypershift",
RenderNamespace: true,
EnableGMPMonitoring: tc.enableGMPMonitoring,
}

_, objects, err := hyperShiftOperatorManifests(t.Context(), nil, opts)
g.Expect(err).NotTo(HaveOccurred())

var deployment *appsv1.Deployment
for _, obj := range objects {
if d, ok := obj.(*appsv1.Deployment); ok {
deployment = d
break
}
}
g.Expect(deployment).NotTo(BeNil(), "should find operator deployment")

args := deployment.Spec.Template.Spec.Containers[0].Args
if tc.enableGMPMonitoring {
g.Expect(args).To(ContainElement("--enable-gmp-monitoring"))
} else {
g.Expect(args).NotTo(ContainElement("--enable-gmp-monitoring"))
}
})
}
}

func TestAwsRoleCredentialFileContent(t *testing.T) {
tests := map[string]struct {
roleARN string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ type HostedControlPlaneReconciler struct {
OperateOnReleaseImage string
DefaultIngressDomain string
MetricsSet metrics.MetricsSet
EnableGMPMonitoring bool
KASHealthMetrics *kas.KASHealthMetrics
SREConfigHash string
ec2Client awsapi.EC2API
Expand Down Expand Up @@ -1428,6 +1429,7 @@ func (r *HostedControlPlaneReconciler) reconcileCPOV2(ctx context.Context, hcp *
SetDefaultSecurityContext: r.SetDefaultSecurityContext,
DefaultSecurityContextUID: r.DefaultSecurityContextUID,
MetricsSet: r.MetricsSet,
EnableGMPMonitoring: r.EnableGMPMonitoring,
EnableCIDebugOutput: r.EnableCIDebugOutput,
ImageMetadataProvider: r.ImageMetadataProvider,
NativeSidecarContainersEnabled: r.ManagementClusterCapabilities.Has(capabilities.CapabilityNativeSidecarContainers),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func (cpo *ControlPlaneOperatorOptions) adaptDeployment(cpContext component.Work
)
}

// The HostedCluster controller only enables GMP monitoring for CPO images that declare support,
// since older CPO images reject unknown flags.
if cpContext.EnableGMPMonitoring {
c.Args = append(c.Args, "--enable-gmp-monitoring")
}

c.Env = append(c.Env, []corev1.EnvVar{
{
Name: "CONTROL_PLANE_OPERATOR_IMAGE",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,52 @@ func TestAdaptDeploymentWatchListClientEnv(t *testing.T) {
})
}
}

func TestAdaptDeploymentGMPMonitoringArg(t *testing.T) {
testCases := []struct {
name string
enableGMPMonitoring bool
expectPresent bool
}{
{
name: "When GMP monitoring is enabled, it should pass the flag",
enableGMPMonitoring: true,
expectPresent: true,
},
{
name: "When GMP monitoring is disabled, it should not pass the flag",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
g := NewGomegaWithT(t)

cpo := &ControlPlaneOperatorOptions{
HostedCluster: &hyperv1.HostedCluster{},
Image: "test-image:latest",
UtilitiesImage: "utilities:latest",
HasUtilities: true,
}

cpContext := controlplanecomponent.WorkloadContext{
Context: t.Context(),
HCP: &hyperv1.HostedControlPlane{},
EnableGMPMonitoring: tc.enableGMPMonitoring,
}

deployment, err := assets.LoadDeploymentManifest(ComponentName)
g.Expect(err).ToNot(HaveOccurred())

err = cpo.adaptDeployment(cpContext, deployment)
g.Expect(err).ToNot(HaveOccurred())

args := deployment.Spec.Template.Spec.Containers[0].Args
if tc.expectPresent {
g.Expect(args).To(ContainElement("--enable-gmp-monitoring"))
} else {
g.Expect(args).ToNot(ContainElement("--enable-gmp-monitoring"))
}
})
}
}
Loading