Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect if OpenShift cluster is single stack ipv6 #2386

Merged
merged 10 commits into from
Aug 9, 2023
17 changes: 17 additions & 0 deletions controllers/alerts/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
outOfBandUpdateAlert = "KubeVirtCRModified"
unsafeModificationAlert = "UnsupportedHCOModification"
installationNotCompletedAlert = "HCOInstallationIncomplete"
singleStackIPv6Alert = "SingleStackIPv6Unsupported"
severityAlertLabelKey = "severity"
healthImpactAlertLabelKey = "operator_health_impact"
partOfAlertLabelKey = "kubernetes_operator_part_of"
Expand Down Expand Up @@ -140,6 +141,7 @@ func NewPrometheusRuleSpec() *monitoringv1.PrometheusRuleSpec {
createInstallationNotCompletedAlertRule(),
createRequestCPUCoresRule(),
createOperatorHealthStatusRule(),
createSingleStackIPv6AlertRule(),
},
}},
}
Expand Down Expand Up @@ -215,3 +217,18 @@ func createOperatorHealthStatusRule() monitoringv1.Rule {
Expr: intstr.FromString(`label_replace(vector(2) and on() ((kubevirt_hco_system_health_status>1) or (count(ALERTS{kubernetes_operator_part_of="kubevirt", alertstate="firing", operator_health_impact="critical"})>0)) or (vector(1) and on() ((kubevirt_hco_system_health_status==1) or (count(ALERTS{kubernetes_operator_part_of="kubevirt", alertstate="firing", operator_health_impact="warning"})>0))) or vector(0),"name","kubevirt-hyperconverged","","")`),
}
}

func createSingleStackIPv6AlertRule() monitoringv1.Rule {
return monitoringv1.Rule{
Alert: singleStackIPv6Alert,
Expr: intstr.FromString("kubevirt_hco_single_stack_ipv6 == 1"),
Annotations: map[string]string{
"description": "KubeVirt Hyperconverged is not supported on a single stack IPv6 cluster",
"summary": "KubeVirt Hyperconverged is not supported on a single stack IPv6 cluster",
},
Labels: map[string]string{
severityAlertLabelKey: "critical",
healthImpactAlertLabelKey: "critical",
},
}
}
9 changes: 9 additions & 0 deletions controllers/commontestutils/testUtils.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ func (c ClusterInfoMock) IsConsolePluginImageProvided() bool {
func (c ClusterInfoMock) IsMonitoringAvailable() bool {
return true
}
func (c ClusterInfoMock) IsSingleStackIPv6() bool {
return true
}
func (c ClusterInfoMock) GetPod() *corev1.Pod {
return pod
}
Expand Down Expand Up @@ -373,6 +376,9 @@ func (ClusterInfoSNOMock) IsConsolePluginImageProvided() bool {
func (c ClusterInfoSNOMock) IsMonitoringAvailable() bool {
return true
}
func (c ClusterInfoSNOMock) IsSingleStackIPv6() bool {
return true
}

// ClusterInfoSRCPHAIMock mocks Openshift with SingleReplica ControlPlane and HighAvailable Infrastructure
type ClusterInfoSRCPHAIMock struct{}
Expand Down Expand Up @@ -418,6 +424,9 @@ func (ClusterInfoSRCPHAIMock) IsConsolePluginImageProvided() bool {
func (ClusterInfoSRCPHAIMock) IsMonitoringAvailable() bool {
return true
}
func (m ClusterInfoSRCPHAIMock) IsSingleStackIPv6() bool {
return true
}
func (ClusterInfoSRCPHAIMock) GetTLSSecurityProfile(_ *openshiftconfigv1.TLSSecurityProfile) *openshiftconfigv1.TLSSecurityProfile {
return &openshiftconfigv1.TLSSecurityProfile{
Type: openshiftconfigv1.TLSProfileIntermediateType,
Expand Down
15 changes: 14 additions & 1 deletion controllers/hyperconverged/hyperconverged_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1056,11 +1056,24 @@ var _ = Describe("HyperconvergedController", func() {
},
}

ipv4network := &openshiftconfigv1.Network{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
Status: openshiftconfigv1.NetworkStatus{
ClusterNetwork: []openshiftconfigv1.ClusterNetworkEntry{
{
CIDR: "10.128.0.0/14",
},
},
},
}

expected := getBasicDeployment()
Expect(expected.hco.Spec.TLSSecurityProfile).To(BeNil())

resources := expected.toArray()
resources = append(resources, clusterVersion, infrastructure, ingress, apiServer, dns)
resources = append(resources, clusterVersion, infrastructure, ingress, apiServer, dns, ipv4network)
cl := commontestutils.InitClient(resources)

logger := zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)).WithName("hyperconverged_controller_test")
Expand Down
15 changes: 14 additions & 1 deletion controllers/webhooks/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,20 @@ var _ = Describe("HyperconvergedController", func() {
},
}

resources := []client.Object{clusterVersion, infrastructure, ingress, apiServer, dns}
ipv4network := &openshiftconfigv1.Network{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
Status: openshiftconfigv1.NetworkStatus{
ClusterNetwork: []openshiftconfigv1.ClusterNetworkEntry{
{
CIDR: "10.128.0.0/14",
},
},
},
}

resources := []client.Object{clusterVersion, infrastructure, ingress, apiServer, dns, ipv4network}
cl := commontestutils.InitClient(resources)

Expect(hcoutil.GetClusterInfo().Init(context.TODO(), cl, logger)).To(Succeed())
Expand Down
1 change: 1 addition & 0 deletions deploy/cluster_role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ rules:
- clusterversions
- infrastructures
- ingresses
- networks
verbs:
- get
- list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ spec:
- clusterversions
- infrastructures
- ingresses
- networks
verbs:
- get
- list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ spec:
- clusterversions
- infrastructures
- ingresses
- networks
verbs:
- get
- list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ metadata:
certified: "false"
console.openshift.io/disable-operand-delete: "true"
containerImage: quay.io/kubevirt/hyperconverged-cluster-operator:1.11.0-unstable
createdAt: "2023-08-07 12:46:46"
createdAt: "2023-08-08 18:48:31"
description: A unified operator deploying and controlling KubeVirt and its supporting
operators with opinionated defaults
operatorframework.io/initialization-resource: '{"apiVersion":"hco.kubevirt.io/v1beta1","kind":"HyperConverged","metadata":{"annotations":{"deployOVS":"false"},"name":"kubevirt-hyperconverged","namespace":"kubevirt-hyperconverged"},"spec":{}}'
Expand Down Expand Up @@ -416,6 +416,7 @@ spec:
- clusterversions
- infrastructures
- ingresses
- networks
verbs:
- get
- list
Expand Down
2 changes: 2 additions & 0 deletions docs/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All metrics documented here are auto-generated by the utility tool `tools/metric
Indicates whether the HyperConverged custom resource exists (1) or not (0). Type: Gauge.
### kubevirt_hco_out_of_band_modifications_total
Count of out-of-band modifications overwritten by HCO. Type: Counter.
### kubevirt_hco_single_stack_ipv6
Indicates whether the underlying cluster is single stack IPv6 (1) or not (0). Type: Gauge.
### kubevirt_hco_system_health_status
Indicates whether the system health status is healthy (0), warning (1), or error (2), by aggregating the conditions of HCO and its secondary resources. Type: Gauge.
### kubevirt_hco_unsafe_modifications
Expand Down
2 changes: 1 addition & 1 deletion pkg/components/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ func GetClusterPermissions() []rbacv1.PolicyRule {
roleWithAllPermissions("console.openshift.io", stringListToSlice("consoleclidownloads", "consolequickstarts")),
{
APIGroups: stringListToSlice(configOpenshiftIO),
Resources: stringListToSlice("clusterversions", "infrastructures", "ingresses"),
Resources: stringListToSlice("clusterversions", "infrastructures", "ingresses", "networks"),
Verbs: stringListToSlice("get", "list"),
},
{
Expand Down
32 changes: 32 additions & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ const (
HCOMetricUnsafeModifications = "unsafeModifications"
HCOMetricHyperConvergedExists = "HyperConvergedCRExists"
HCOMetricSystemHealthStatus = "systemHealthStatus"
HCOMetricSingleStackIPv6 = "singleStackIpv6"

HyperConvergedExists = float64(1)
HyperConvergedNotExists = float64(0)

SingleStackIPv6True = float64(1)
SingleStackIPv6False = float64(0)
)

const (
Expand Down Expand Up @@ -101,6 +105,19 @@ var HcoMetrics = func() hcoMetrics {
)
},
},
HCOMetricSingleStackIPv6: {
fqName: "kubevirt_hco_single_stack_ipv6",
help: "Indicates whether the underlying cluster is single stack IPv6 (1) or not (0)",
mType: "Gauge",
constLabelPairs: []string{counterLabelAnnName},
initFunc: func(md metricDesc) prometheus.Collector {
return prometheus.NewGauge(
prometheus.GaugeOpts{
Name: md.fqName,
Help: md.help,
})
},
},
}

metricList := make(map[string]prometheus.Collector)
Expand Down Expand Up @@ -267,6 +284,21 @@ func (hm *hcoMetrics) GetHCOMetricSystemHealthStatus() (float64, error) {
return hm.GetMetricValue(HCOMetricSystemHealthStatus, nil)
}

func (hm *hcoMetrics) SetHCOMetricSingleStackIPv6True() error {
return hm.SetMetric(HCOMetricSingleStackIPv6, nil, SingleStackIPv6True)
}

// IsHCOMetricSingleStackIPv6 returns true if underlying OCP cluster is single stack IPv6
func (hm *hcoMetrics) IsHCOMetricSingleStackIPv6() (bool, error) {

val, err := hm.GetMetricValue(HCOMetricSingleStackIPv6, nil)
if err != nil {
return false, err
}

return val == SingleStackIPv6True, nil
}

func getLabelsForObj(kind string, name string) prometheus.Labels {
return prometheus.Labels{counterLabelCompName: strings.ToLower(kind + "/" + name)}
}
Expand Down
32 changes: 32 additions & 0 deletions pkg/util/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
csvv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/client-go/discovery"
"k8s.io/utils/net"

"github.com/kubevirt/hyperconverged-cluster-operator/pkg/metrics"

corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
Expand All @@ -33,6 +36,7 @@ type ClusterInfo interface {
IsInfrastructureHighlyAvailable() bool
IsConsolePluginImageProvided() bool
IsMonitoringAvailable() bool
IsSingleStackIPv6() bool
GetTLSSecurityProfile(hcoTLSSecurityProfile *openshiftconfigv1.TLSSecurityProfile) *openshiftconfigv1.TLSSecurityProfile
RefreshAPIServerCR(ctx context.Context, c client.Client) error
GetPod() *corev1.Pod
Expand All @@ -48,6 +52,7 @@ type ClusterInfoImp struct {
infrastructureHighlyAvailable bool
consolePluginImageProvided bool
monitoringAvailable bool
singlestackipv6 bool
domain string
baseDomain string
ownResources *OwnResources
Expand Down Expand Up @@ -83,6 +88,11 @@ func (c *ClusterInfoImp) Init(ctx context.Context, cl client.Client, logger logr
if err != nil {
return err
}
if c.runningInOpenshift && c.singlestackipv6 {
if err := metrics.HcoMetrics.SetHCOMetricSingleStackIPv6True(); err != nil {
return err
}
}

uiPluginVarValue, uiPluginVarExists := os.LookupEnv(KVUIPluginImageEnvV)
uiProxyVarValue, uiProxyVarExists := os.LookupEnv(KVUIProxyImageEnvV)
Expand Down Expand Up @@ -148,6 +158,24 @@ func (c *ClusterInfoImp) initOpenshift(ctx context.Context, cl client.Client) er

c.controlPlaneHighlyAvailable = clusterInfrastructure.Status.ControlPlaneTopology == openshiftconfigv1.HighlyAvailableTopologyMode
c.infrastructureHighlyAvailable = clusterInfrastructure.Status.InfrastructureTopology == openshiftconfigv1.HighlyAvailableTopologyMode

clusterNetwork := &openshiftconfigv1.Network{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
}
err = cl.Get(ctx, client.ObjectKeyFromObject(clusterNetwork), clusterNetwork)
if err != nil {
return err
}
cn := clusterNetwork.Status.ClusterNetwork
for _, i := range cn {
c.logger.Info("Cluster Network",
"CIDR", i.CIDR,
"Host Prefix", i.HostPrefix,
)
}
c.singlestackipv6 = len(cn) == 1 && net.IsIPv6CIDRString(cn[0].CIDR)
return nil
}

Expand All @@ -171,6 +199,10 @@ func (c *ClusterInfoImp) IsRunningLocally() bool {
return c.runningLocally
}

func (c *ClusterInfoImp) IsSingleStackIPv6() bool {
return c.singlestackipv6
}

func (c *ClusterInfoImp) IsControlPlaneHighlyAvailable() bool {
return c.controlPlaneHighlyAvailable
}
Expand Down
Loading