diff --git a/pkg/manifests/manifests.go b/pkg/manifests/manifests.go index c47e2e89ca..5410611aa5 100644 --- a/pkg/manifests/manifests.go +++ b/pkg/manifests/manifests.go @@ -346,6 +346,9 @@ type Factory struct { type InfrastructureReader interface { HighlyAvailableInfrastructure() bool HostedControlPlane() bool + SingleNodeControlPlane() bool + TwoNodeControlPlane() bool + HighlyAvailableControlPlane() bool } // ProxyReader has methods to describe the proxy configuration. @@ -2475,24 +2478,38 @@ func (f *Factory) ControlPlanePrometheusRule() (*monv1.PrometheusRule, error) { r.Namespace = f.namespace - if f.infrastructure.HostedControlPlane() { - groups := []monv1.RuleGroup{} - for _, g := range r.Spec.Groups { - switch g.Name { - case "kubernetes-system-apiserver", - "kubernetes-system-controller-manager", - "kubernetes-system-scheduler": - // skip - default: - groups = append(groups, g) - } - } - r.Spec.Groups = groups + switch { + case f.infrastructure.HostedControlPlane(): + r.Spec.Groups = filterRuleGroups(r, []string{ + "kubernetes-system-apiserver", + "kubernetes-system-controller-manager", + "kubernetes-system-scheduler", + }) + case !f.infrastructure.HighlyAvailableControlPlane(): + r.Spec.Groups = filterRuleGroups(r, []string{ + // This group supports the SNO cluster configuration currently, but not TNO ones (TNA and TNF). This is + // because upstream is only concerned with the broader HA and non-HA scenarios, and not any + // OpenShift-specific cluster configurations. + "kubernetes-resources", + }) } return r, nil } +func filterRuleGroups(rule *monv1.PrometheusRule, ignoreGroups []string) (groups []monv1.RuleGroup) { + for _, g := range rule.Spec.Groups { + if slices.ContainsFunc(ignoreGroups, func(ig string) bool { + return g.Name == ig + }) { + continue + } + groups = append(groups, g) + } + + return +} + func (f *Factory) ControlPlaneKubeletServiceMonitors() ([]*monv1.ServiceMonitor, error) { return serviceMonitors(f.config.CollectionProfilesFeatureGateEnabled, f.ControlPlaneKubeletServiceMonitor, f.ControlPlaneKubeletMinimalServiceMonitor) } diff --git a/pkg/manifests/manifests_test.go b/pkg/manifests/manifests_test.go index 12e35c70a0..c34975a055 100644 --- a/pkg/manifests/manifests_test.go +++ b/pkg/manifests/manifests_test.go @@ -40,6 +40,12 @@ import ( type fakeInfrastructureReader struct { highlyAvailableInfrastructure bool hostedControlPlane bool + singleNodeControlPlane bool + twoNodeControlPlane bool +} + +func (f *fakeInfrastructureReader) HighlyAvailableControlPlane() bool { + return !f.singleNodeControlPlane && !f.twoNodeControlPlane } func (f *fakeInfrastructureReader) HighlyAvailableInfrastructure() bool { @@ -50,8 +56,21 @@ func (f *fakeInfrastructureReader) HostedControlPlane() bool { return f.hostedControlPlane } +func (f *fakeInfrastructureReader) TwoNodeControlPlane() bool { + return f.twoNodeControlPlane +} + +func (f *fakeInfrastructureReader) SingleNodeControlPlane() bool { + return f.singleNodeControlPlane +} + func defaultInfrastructureReader() InfrastructureReader { - return &fakeInfrastructureReader{highlyAvailableInfrastructure: true, hostedControlPlane: false} + return &fakeInfrastructureReader{ + highlyAvailableInfrastructure: true, + hostedControlPlane: false, + singleNodeControlPlane: false, + twoNodeControlPlane: false, + } } type fakeProxyReader struct { diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index 45a8304b08..7bbf9bec17 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -58,6 +58,8 @@ import ( type InfrastructureConfig struct { highlyAvailableInfrastructure bool hostedControlPlane bool + singleNodeControlPlane bool + twoNodeControlPlane bool } var ( @@ -96,6 +98,8 @@ func NewDefaultInfrastructureConfig() *InfrastructureConfig { return &InfrastructureConfig{ highlyAvailableInfrastructure: true, hostedControlPlane: false, + singleNodeControlPlane: false, + twoNodeControlPlane: false, } } @@ -103,13 +107,34 @@ func NewDefaultInfrastructureConfig() *InfrastructureConfig { func NewInfrastructureConfig(i *configv1.Infrastructure) *InfrastructureConfig { ic := NewDefaultInfrastructureConfig() + // Data plane topology modes + // SNO if i.Status.InfrastructureTopology == configv1.SingleReplicaTopologyMode { ic.highlyAvailableInfrastructure = false } + + // TNO includes DualReplica and TNF topology modes. The latter is not exposed in openshift/api/config/v1 yet. + // TNA has a third etcd node, and considered to be highly available. + if i.Status.InfrastructureTopology == configv1.DualReplicaTopologyMode { + ic.highlyAvailableInfrastructure = false + } + + // Control plane topology modes + // SNO + if i.Status.ControlPlaneTopology == configv1.SingleReplicaTopologyMode { + ic.singleNodeControlPlane = true + } + + // TNO includes DualReplica and TNF topology modes. The latter is not exposed in openshift/api/config/v1 yet. + // TNA has a third etcd node, and considered to be highly available. + if i.Status.ControlPlaneTopology == configv1.DualReplicaTopologyMode { + ic.twoNodeControlPlane = true + } + + // External topology mode is used for hosted control planes. if i.Status.ControlPlaneTopology == configv1.ExternalTopologyMode { ic.hostedControlPlane = true } - return ic } @@ -123,6 +148,24 @@ func (ic *InfrastructureConfig) HostedControlPlane() bool { return ic.hostedControlPlane } +// TwoNodeControlPlane implements the InfrastructureReader interface. +func (ic *InfrastructureConfig) TwoNodeControlPlane() bool { + return ic.twoNodeControlPlane +} + +// SingleNodeControlPlane implements the InfrastructureReader interface. +func (ic *InfrastructureConfig) SingleNodeControlPlane() bool { + return ic.singleNodeControlPlane +} + +// HighlyAvailableControlPlane implements the InfrastructureReader interface. +func (ic *InfrastructureConfig) HighlyAvailableControlPlane() bool { + // Following the same pattern as we do for HighlyAvailableInfrastructure, i.e., + // assuming topologies other than the currently known non-HA ones to be HA. + // Additionally, a cluster may have a non-HA control plane and an HA infrastructure, and vice versa. + return !ic.singleNodeControlPlane && !ic.twoNodeControlPlane +} + // ProxyConfig stores information about the proxy configuration. type ProxyConfig struct { httpProxy string