Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,15 @@
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator should have correct runlevel and scc",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
}
]
56 changes: 56 additions & 0 deletions test/cvo/cvo.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
package cvo

import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"

g "github.com/onsi/ginkgo/v2"
o "github.com/onsi/gomega"

"github.com/openshift/cluster-version-operator/test/oc"
ocapi "github.com/openshift/cluster-version-operator/test/oc/api"
"github.com/openshift/cluster-version-operator/test/util"
)

var logger = g.GinkgoLogr.WithName("cluster-version-operator-tests")

const cvoNamespace = "openshift-cluster-version"

var _ = g.Describe(`[Jira:"Cluster Version Operator"] cluster-version-operator-tests`, func() {
g.It("should support passing tests", func() {
o.Expect(true).To(o.BeTrue())
Expand All @@ -25,3 +34,50 @@ var _ = g.Describe(`[Jira:"Cluster Version Operator"] cluster-version-operator-t
o.Expect(output).To(o.ContainSubstring("Client Version:"))
})
})

// CVO tests which need access the live cluster will be placed here
var _ = g.Describe(`[Jira:"Cluster Version Operator"] cluster-version-operator`, func() {
var (
restCfg *rest.Config
kubeClient kubernetes.Interface
)

g.BeforeEach(func() {
var err error
// Respects KUBECONFIG env var
restCfg, err = util.GetRestConfig()
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to load Kubernetes configuration. Please ensure KUBECONFIG environment variable is set.")

kubeClient, err = util.GetKubeClient(restCfg)
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to create Kubernetes client")
})

// Migrated from case NonHyperShiftHOST-Author:jiajliu-Low-46922-check runlevel and scc in cvo ns
// Refer to https://github.com/openshift/openshift-tests-private/blob/40374cf20946ff03c88712839a5626af2c88ab31/test/extended/ota/cvo/cvo.go#L1081
g.It("should have correct runlevel and scc", func() {
ctx := context.Background()
err := util.SkipIfHypershift(ctx, restCfg)
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to determine if cluster is HyperShift")
err = util.SkipIfMicroshift(ctx, restCfg)
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to determine if cluster is MicroShift")

Comment thread
coderabbitai[bot] marked this conversation as resolved.
g.By("Checking that the 'openshift.io/run-level' label exists on the namespace and has the empty value")
ns, err := kubeClient.CoreV1().Namespaces().Get(ctx, cvoNamespace, metav1.GetOptions{})
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to get namespace %s", cvoNamespace)
runLevel, exists := ns.Labels["openshift.io/run-level"]
o.Expect(exists).To(o.BeTrue(), "The 'openshift.io/run-level' label on namespace %s does not exist", cvoNamespace)
o.Expect(runLevel).To(o.BeEmpty(), "Expected the 'openshift.io/run-level' label value on namespace %s has the empty value, but got %s", cvoNamespace, runLevel)

g.By("Checking that the annotation 'openshift.io/scc annotation' on the CVO pod has the value hostaccess")
podList, err := kubeClient.CoreV1().Pods(cvoNamespace).List(ctx, metav1.ListOptions{
LabelSelector: "k8s-app=cluster-version-operator",
FieldSelector: "status.phase=Running",
})
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to list running CVO pods")
o.Expect(podList.Items).To(o.HaveLen(1), "Expected exactly one running CVO pod, but found: %d", len(podList.Items))

cvoPod := podList.Items[0]
sccAnnotation := cvoPod.Annotations["openshift.io/scc"]
o.Expect(sccAnnotation).To(o.Equal("hostaccess"), "Expected the annotation 'openshift.io/scc annotation' on pod %s to have the value 'hostaccess', but got %s", cvoPod.Name, sccAnnotation)
})
})
108 changes: 108 additions & 0 deletions test/util/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package util

import (
"context"
"time"

g "github.com/onsi/ginkgo/v2"
configv1 "github.com/openshift/api/config/v1"
clientconfigv1 "github.com/openshift/client-go/config/clientset/versioned"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

// IsHypershift checks if running on a HyperShift hosted cluster
// Refer to https://github.com/openshift/origin/blob/31704414237b8bd5c66ad247c105c94abc9470b1/test/extended/util/framework.go#L2301
func IsHypershift(ctx context.Context, restConfig *rest.Config) (bool, error) {
configClient, err := GetConfigClient(restConfig)
if err != nil {
return false, err
}
infrastructure, err := configClient.ConfigV1().Infrastructures().Get(ctx, "cluster", metav1.GetOptions{})
if err != nil {
// If the Infrastructure resource doesn't exist (e.g., in MicroShift),it's not a HyperShift
if apierrors.IsNotFound(err) {
Comment thread
jiajliu marked this conversation as resolved.
return false, nil
}
return false, err
}
return infrastructure.Status.ControlPlaneTopology == configv1.ExternalTopologyMode, nil
}

// SkipIfHypershift skips the test if running on a HyperShift hosted cluster
func SkipIfHypershift(ctx context.Context, restConfig *rest.Config) error {
isHypershift, err := IsHypershift(ctx, restConfig)
if err != nil {
return err
}
if isHypershift {
g.Skip("Skipping test: running on HyperShift hosted cluster!")
}
return nil
}

// IsMicroshift checks if running on a MicroShift cluster
// Refer to https://github.com/openshift/origin/blob/31704414237b8bd5c66ad247c105c94abc9470b1/test/extended/util/framework.go#L2312
func IsMicroshift(ctx context.Context, restConfig *rest.Config) (bool, error) {
kubeClient, err := GetKubeClient(restConfig)
if err != nil {
return false, err
}
var cm *corev1.ConfigMap
duration := 5 * time.Minute
if err := wait.PollUntilContextTimeout(ctx, 10*time.Second, duration, true, func(ctx context.Context) (bool, error) {
// MicroShift cluster contains "microshift-version" configmap in "kube-public" namespace
var err error
cm, err = kubeClient.CoreV1().ConfigMaps("kube-public").Get(ctx, "microshift-version", metav1.GetOptions{})
if err == nil {
return true, nil
}
if apierrors.IsNotFound(err) {
cm = nil
return true, nil
}
g.GinkgoLogr.Info("error accessing microshift-version configmap", "error", err)
return false, nil
}); err != nil {
g.GinkgoLogr.Info("failed to find microshift-version configmap while polling", "duration", duration, "error", err)
return false, err
}
if cm == nil {
g.GinkgoLogr.Info("microshift-version configmap not found")
return false, nil
}
g.GinkgoLogr.Info("MicroShift cluster detected", "version", cm.Data["version"])
return true, nil
}

// SkipIfMicroshift skips the test if running on a MicroShift cluster
func SkipIfMicroshift(ctx context.Context, restConfig *rest.Config) error {
isMicroshift, err := IsMicroshift(ctx, restConfig)
if err != nil {
return err
}
if isMicroshift {
g.Skip("Skipping test: running on MicroShift cluster!")
}
return nil
}

// GetRestConfig loads the Kubernetes REST configuration from KUBECONFIG environment variable.
func GetRestConfig() (*rest.Config, error) {
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}).ClientConfig()
}

// GetKubeClient creates a Kubernetes client from the given REST config.
func GetKubeClient(restConfig *rest.Config) (kubernetes.Interface, error) {
return kubernetes.NewForConfig(restConfig)
}

// GetConfigClient creates an OpenShift config client from the given REST config.
func GetConfigClient(restConfig *rest.Config) (clientconfigv1.Interface, error) {
return clientconfigv1.NewForConfig(restConfig)
}