diff --git a/pkg/testsuites/standard_suites.go b/pkg/testsuites/standard_suites.go index 570fbc230dcb..71d7cc9dd150 100644 --- a/pkg/testsuites/standard_suites.go +++ b/pkg/testsuites/standard_suites.go @@ -426,7 +426,7 @@ var staticSuites = []ginkgo.TestSuite{ This test suite runs tests to validate two-node. `), Qualifiers: []string{ - `name.contains("[Suite:openshift/two-node") || name.contains("[FeatureGate:DualReplica]") || name.contains("[FeatureGate:HighlyAvailableArbiter]")`, + `name.contains("[Suite:openshift/two-node") || name.contains("[OCPFeatureGate:DualReplica]") || name.contains("[OCPFeatureGate:HighlyAvailableArbiter]")`, }, TestTimeout: 60 * time.Minute, }, diff --git a/test/extended/two_node/tnf_topology.go b/test/extended/two_node/tnf_topology.go index 60c90198c6d6..b333dd5ae8ac 100644 --- a/test/extended/two_node/tnf_topology.go +++ b/test/extended/two_node/tnf_topology.go @@ -3,18 +3,20 @@ package two_node import ( "context" "fmt" + "strings" g "github.com/onsi/ginkgo/v2" o "github.com/onsi/gomega" v1 "github.com/openshift/api/config/v1" exutil "github.com/openshift/origin/test/extended/util" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" ) const ensurePodmanEtcdContainerIsRunning = "podman inspect --format '{{.State.Running}}' etcd" -var _ = g.Describe("[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] Two Node with Fencing topology", func() { +var _ = g.Describe("[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing topology", func() { defer g.GinkgoRecover() var ( oc = exutil.NewCLIWithoutNamespace("") @@ -24,13 +26,13 @@ var _ = g.Describe("[sig-node][apigroup:config.openshift.io][OCPFeatureGate:Dual skipIfNotTopology(oc, v1.DualReplicaTopologyMode) }) - g.It("Should validate the number of control-planes, arbiters as configured", func() { + g.It("should only have two control plane nodes and no arbiter nodes", func() { const ( expectedControlPlanes = 2 expectedArbiters = 0 ) - g.By(fmt.Sprintf("Ensuring only %d Control-plane nodes in the cluster, and %d Arbiter nodes", expectedControlPlanes, expectedArbiters)) + g.By(fmt.Sprintf("Ensuring only %d control-plane nodes in the cluster and no arbiter nodes", expectedControlPlanes)) controlPlaneNodes, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ LabelSelector: labelNodeRoleControlPlane, }) @@ -43,61 +45,96 @@ var _ = g.Describe("[sig-node][apigroup:config.openshift.io][OCPFeatureGate:Dual o.Expect(err).ShouldNot(o.HaveOccurred(), "Expected to retrieve arbiter nodes without error") o.Expect(len(arbiterNodes.Items)).To(o.Equal(expectedArbiters), fmt.Sprintf("Expected %d Arbiter Nodes, found %d", expectedArbiters, len(arbiterNodes.Items))) }) + + g.It("should have infrastructure platform type set correctly", func() { + g.By("Checking that the infrastructure platform is set to baremetal or none or external") + infrastructure, err := oc.AdminConfigClient().ConfigV1().Infrastructures().Get(context.Background(), "cluster", metav1.GetOptions{}) + o.Expect(err).ShouldNot(o.HaveOccurred(), "Expected to retrieve infrastructure configuration without error") + + platformType := infrastructure.Status.PlatformStatus.Type + o.Expect(platformType).To(o.Or(o.Equal(v1.BareMetalPlatformType), o.Equal(v1.NonePlatformType), o.Equal(v1.ExternalPlatformType)), + fmt.Sprintf("Expected infrastructure platform to be baremetal or none or external, but found %s", platformType)) + }) + + g.It("should have BareMetalHost operational status set to detached if they exist", func() { + g.By("Checking that BareMetalHost objects have operational status set to detached") + dc := oc.AdminDynamicClient() + + // Use Dynamic Client to get BareMetalHost objects + // Note: move this to common.go if this is used in other tests + baremetalGVR := schema.GroupVersionResource{Group: "metal3.io", Resource: "baremetalhosts", Version: "v1alpha1"} + baremetalClient := dc.Resource(baremetalGVR).Namespace("openshift-machine-api") + + hosts, err := baremetalClient.List(context.Background(), metav1.ListOptions{}) + o.Expect(err).ShouldNot(o.HaveOccurred(), "Expected to retrieve BareMetalHost objects without error") + + // If no BareMetalHost objects exist, skip the test, this is valid for TNF deployments + if len(hosts.Items) == 0 { + g.Skip("No BareMetalHost objects found in openshift-machine-api namespace") + } + + // Check each BareMetalHost has operational status set to detached + for _, host := range hosts.Items { + operationalStatus, found, err := unstructured.NestedString(host.Object, "status", "operationalStatus") + o.Expect(err).ShouldNot(o.HaveOccurred(), fmt.Sprintf("Expected to parse operational status for BareMetalHost %s without error", host.GetName())) + o.Expect(found).To(o.BeTrue(), fmt.Sprintf("Expected operational status field to exist for BareMetalHost %s", host.GetName())) + o.Expect(operationalStatus).To(o.Equal("detached"), + fmt.Sprintf("Expected BareMetalHost %s operational status to be 'detached', but found '%s'", host.GetName(), operationalStatus)) + } + }) + }) -var _ = g.Describe("[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] Two Node with Fencing pods and podman containers", func() { +var _ = g.Describe("[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing", func() { defer g.GinkgoRecover() var ( - oc = exutil.NewCLIWithoutNamespace("") - nodes *corev1.NodeList + oc = exutil.NewCLIWithoutNamespace("") ) g.BeforeEach(func() { skipIfNotTopology(oc, v1.DualReplicaTopologyMode) - - var err error - nodes, err = oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) - o.Expect(err).To(o.BeNil(), "Expected to retrieve all nodes without error") }) - g.It("Should validate the number of etcd pods and containers as configured", func() { + g.It("should have etcd pods and containers configured correctly", func() { const ( expectedEtcdPod = 2 expectedEtcdCtlContainers = 2 expectedEtcdContainers = 0 ) - nodeNameA := nodes.Items[0].Name - nodeNameB := nodes.Items[1].Name - g.By("Ensuring 0 etcd pod containers and 2 etcdctl pod containers are running in the cluster ") - pods, err := oc.AdminKubeClient().CoreV1().Pods("openshift-etcd").List(context.Background(), metav1.ListOptions{}) + pods, err := oc.AdminKubeClient().CoreV1().Pods("openshift-etcd").List(context.Background(), metav1.ListOptions{ + LabelSelector: "app=etcd", + }) o.Expect(err).To(o.BeNil(), "Expected to retrieve etcd pods in openshift-etcd namespace without error") + o.Expect(pods.Items).To(o.HaveLen(expectedEtcdPod), "Expected to retrieve %d etcd pods in openshift-etcd namespace", expectedEtcdPod) - etcdPodCount := 0 etcdContainerCount := 0 etcdctlContainerCount := 0 + for _, pod := range pods.Items { - if pod.Name == "etcd-"+nodeNameA || pod.Name == "etcd-"+nodeNameB { - etcdPodCount += 1 - for _, container := range pod.Spec.Containers { - if container.Name == "etcd" { - etcdContainerCount += 1 - } - if container.Name == "etcdctl" { - etcdctlContainerCount += 1 - } + for _, container := range pod.Spec.Containers { + if container.Name == "etcd" { + etcdContainerCount += 1 + } + if container.Name == "etcdctl" { + etcdctlContainerCount += 1 } } } - o.Expect(etcdPodCount).To(o.Equal(expectedEtcdPod)) o.Expect(etcdctlContainerCount).To(o.Equal(expectedEtcdCtlContainers)) o.Expect(etcdContainerCount).To(o.Equal(expectedEtcdContainers)) }) - g.It("Should verify the number of podman-etcd containers as configured", func() { + g.It("should have podman etcd containers running on each node", func() { + nodes, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ + LabelSelector: labelNodeRoleControlPlane, + }) + o.Expect(err).To(o.BeNil(), "Expected to retrieve control plane nodes without error") + o.Expect(nodes.Items).To(o.HaveLen(2), "Expected to retrieve two control plane nodes for DualReplica topology") + g.By("Ensuring one podman etcd container is running on each node") for _, node := range nodes.Items { - got, err := exutil.DebugNodeRetryWithOptionsAndChroot(oc, node.Name, "openshift-etcd", "podman", "inspect", "--format", "'{{.State.Running}}'", "etcd") + got, err := exutil.DebugNodeRetryWithOptionsAndChroot(oc, node.Name, "openshift-etcd", strings.Split(ensurePodmanEtcdContainerIsRunning, " ")...) o.Expect(err).To(o.BeNil(), fmt.Sprintf("expected to call podman without errors on Node %s: error %v", node.Name, err)) o.Expect(got).To(o.Equal("'true'"), fmt.Sprintf("expected a podman etcd container running on Node %s: got running %s", node.Name, got)) } diff --git a/test/extended/util/annotate/generated/zz_generated.annotations.go b/test/extended/util/annotate/generated/zz_generated.annotations.go index 83b7663a24a5..afb6ead40abb 100644 --- a/test/extended/util/annotate/generated/zz_generated.annotations.go +++ b/test/extended/util/annotate/generated/zz_generated.annotations.go @@ -1281,9 +1281,9 @@ var Annotations = map[string]string{ "[sig-etcd][OCPFeatureGate:HardwareSpeed][Serial] etcd is able to set the hardware speed to \"\" [Timeout:30m][apigroup:machine.openshift.io]": " [Suite:openshift/conformance/serial]", - "[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] Two Node with Fencing pods and podman containers Should validate the number of etcd pods and containers as configured": "", + "[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing should have etcd pods and containers configured correctly": " [Suite:openshift/conformance/parallel]", - "[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] Two Node with Fencing pods and podman containers Should verify the number of podman-etcd containers as configured": "", + "[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing should have podman etcd containers running on each node": " [Suite:openshift/conformance/parallel]", "[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node][Disruptive] Two Node with Fencing etcd recovery Should recover from graceful node shutdown with etcd member re-addition": " [Serial]", @@ -1993,7 +1993,11 @@ var Annotations = map[string]string{ "[sig-node][apigroup:config.openshift.io] CPU Partitioning node validation should have correct cpuset and cpushare set in crio containers": " [Suite:openshift/conformance/parallel]", - "[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] Two Node with Fencing topology Should validate the number of control-planes, arbiters as configured": "", + "[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing topology should have BareMetalHost operational status set to detached if they exist": " [Suite:openshift/conformance/parallel]", + + "[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing topology should have infrastructure platform type set correctly": " [Suite:openshift/conformance/parallel]", + + "[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] Two Node with Fencing topology should only have two control plane nodes and no arbiter nodes": " [Suite:openshift/conformance/parallel]", "[sig-node][apigroup:config.openshift.io][OCPFeatureGate:HighlyAvailableArbiter] expected Master and Arbiter node counts Should validate that there are Master and Arbiter nodes as specified in the cluster": " [Suite:openshift/conformance/parallel]", diff --git a/zz_generated.manifests/test-reporting.yaml b/zz_generated.manifests/test-reporting.yaml index 2d9a2051dcd0..68b76e3cc6d8 100644 --- a/zz_generated.manifests/test-reporting.yaml +++ b/zz_generated.manifests/test-reporting.yaml @@ -184,21 +184,25 @@ spec: [Beta] [Feature:OffByDefault]' - featureGate: DualReplica tests: - - testName: '[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] - Two Node with Fencing pods and podman containers Should validate the number - of etcd pods and containers as configured' - - testName: '[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] - Two Node with Fencing pods and podman containers Should verify the number - of podman-etcd containers as configured' + - testName: '[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] + Two Node with Fencing should have etcd pods and containers configured correctly' + - testName: '[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] + Two Node with Fencing should have podman etcd containers running on each node' - testName: '[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node][Disruptive] Two Node with Fencing etcd recovery Should recover from graceful node shutdown with etcd member re-addition' - testName: '[sig-etcd][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node][Disruptive] Two Node with Fencing etcd recovery Should recover from ungraceful node shutdown with etcd member re-addition' - - testName: '[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica][Suite:openshift/two-node] - Two Node with Fencing topology Should validate the number of control-planes, - arbiters as configured' + - testName: '[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] + Two Node with Fencing topology should have BareMetalHost operational status + set to detached if they exist' + - testName: '[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] + Two Node with Fencing topology should have infrastructure platform type set + correctly' + - testName: '[sig-node][apigroup:config.openshift.io][OCPFeatureGate:DualReplica] + Two Node with Fencing topology should only have two control plane nodes and + no arbiter nodes' - featureGate: DynamicResourceAllocation tests: - testName: '[sig-node] DRA [Feature:DynamicResourceAllocation] [FeatureGate:DynamicResourceAllocation]