Skip to content

Commit 551cb4a

Browse files
jadhajclaude
andcommitted
Add OpenShift Tests Extension (OTE) for baremetal E2E tests
Implements OTE framework to migrate baremetal E2E tests from openshift-tests-private to cluster-baremetal-operator repository. Changes: - Add cmd/cluster-baremetal-tests-ext/main.go: OTE binary entry point that registers as openshift:payload:cluster-baremetal extension - Add test/e2e/baremetal/deployment_sanity.go: 6 migrated baremetal tests * Cluster operators running check (OCP-29146) * Nodes running check (OCP-29147) * Deployment availability check (OCP-29148) * Worker node validation (OCP-29149) * CPU usage check (OCP-29150) * Memory check (OCP-29151) - Add test/e2e/baremetal/utils.go: Helper functions using compat_otp - Update go.mod: Add OTE dependencies and OpenShift kubernetes replaces - Update Makefile: Add build-tests target with -mod=mod approach - Remove vendor/: Use Go module cache instead of vendoring (10k+ files) Tests use platform=="baremetal" selector and run under origin CI. Binary: cluster-baremetal-tests-ext (payload test extension) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 6a7e66f commit 551cb4a

10,089 files changed

Lines changed: 1816 additions & 2506126 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ bin
1515

1616
# Kubernetes Generated files - skip generated files, except for vendored files
1717

18-
!vendor/**/zz_generated.*
18+
# Use -mod=mod instead of vendoring for OTE dependencies
19+
vendor/
1920

2021
# editor and IDE paraphernalia
2122
.idea

Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ CONTAINER_TOOL ?= docker
1010
# Image URL to use all building/pushing image targets
1111
IMG ?= controller:latest
1212

13-
CONTROLLER_GEN ?= go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go
13+
CONTROLLER_GEN ?= go run sigs.k8s.io/controller-tools/cmd/controller-gen
1414
CRD_OPTIONS="crd:crdVersions=v1"
15-
GOLANGCI_LINT ?= GOLANGCI_LINT_CACHE=$(GOLANGCI_LINT_CACHE) go run vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint/main.go
15+
GOLANGCI_LINT ?= GOLANGCI_LINT_CACHE=$(GOLANGCI_LINT_CACHE) go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint
1616
KUSTOMIZE ?= go run sigs.k8s.io/kustomize/kustomize/v4
1717
MANIFEST_PROFILE ?= default
1818
TMP_DIR := $(shell mktemp -d -t manifests-$(date +%Y-%m-%d-%H-%M-%S)-XXXXXXXXXX)
@@ -35,6 +35,12 @@ test: generate lint manifests unit
3535
build:
3636
go build -o bin/cluster-baremetal-operator main.go
3737

38+
# Build OTE test extension binary
39+
build-tests:
40+
GONOSUMDB="github.com/openshift/origin" CGO_ENABLED=0 GO_COMPLIANCE_POLICY="exempt_all" \
41+
go build -mod=mod -o bin/cluster-baremetal-tests-ext ./cmd/cluster-baremetal-tests-ext
42+
gzip -f bin/cluster-baremetal-tests-ext
43+
3844
# Run against the configured Kubernetes cluster in ~/.kube/config
3945
run: generate manifests
4046
go run ./main.go -images-json $(IMAGES_JSON)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/spf13/cobra"
8+
extcmd "github.com/openshift-eng/openshift-tests-extension/pkg/cmd"
9+
e "github.com/openshift-eng/openshift-tests-extension/pkg/extension"
10+
et "github.com/openshift-eng/openshift-tests-extension/pkg/extension/extensiontests"
11+
g "github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo"
12+
13+
// Import test packages to register Ginkgo specs
14+
_ "github.com/openshift/cluster-baremetal-operator/test/e2e/baremetal"
15+
)
16+
17+
func main() {
18+
// Extension registry
19+
registry := e.NewRegistry()
20+
21+
// Create extension
22+
ext := e.NewExtension(
23+
"openshift", // product
24+
"payload", // type
25+
"cluster-baremetal", // component name
26+
)
27+
28+
// Add suites to the extension
29+
ext.AddSuite(e.Suite{
30+
Name: "cluster-baremetal/all",
31+
Parents: []string{"openshift/conformance/parallel"},
32+
})
33+
34+
// Build test specs from Ginkgo tests automatically
35+
specs, err := g.BuildExtensionTestSpecsFromOpenShiftGinkgoSuite()
36+
if err != nil {
37+
panic(fmt.Sprintf("couldn't build extension test specs from ginkgo: %+v", err.Error()))
38+
}
39+
40+
// Apply environment selectors - baremetal platform only
41+
// All tests should only run on baremetal platform
42+
specs.Select(et.NameContains("")).
43+
Include(et.PlatformEquals("baremetal"))
44+
45+
// Add specs to extension
46+
ext.AddSpecs(specs)
47+
registry.Register(ext)
48+
49+
// Create root command
50+
rootCmd := &cobra.Command{
51+
Use: "cluster-baremetal-tests-ext",
52+
Short: "Cluster BareMetal Operator Test Extension",
53+
Long: "OpenShift Tests Extension for Cluster BareMetal Operator E2E Tests",
54+
}
55+
56+
// Register OTE subcommands (info, list, run-test, run-suite, etc.)
57+
rootCmd.AddCommand(extcmd.DefaultExtensionCommands(registry)...)
58+
59+
if err := rootCmd.Execute(); err != nil {
60+
os.Exit(1)
61+
}
62+
}

go.mod

Lines changed: 272 additions & 27 deletions
Large diffs are not rendered by default.

go.sum

Lines changed: 562 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package baremetal
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
g "github.com/onsi/ginkgo/v2"
8+
o "github.com/onsi/gomega"
9+
compat_otp "github.com/openshift/origin/test/extended/util/compat_otp"
10+
e2e "k8s.io/kubernetes/test/e2e/framework"
11+
)
12+
13+
// var _ = g.Describe("[sig-baremetal] INSTALLER UPI for INSTALLER_GENERAL job on BareMetal", func() {
14+
// defer g.GinkgoRecover()
15+
// var (
16+
// oc = compat_otp.NewCLI("baremetal-deployment-sanity")
17+
18+
// )
19+
// g.BeforeEach(func() {
20+
21+
// })
22+
23+
// g.AfterEach(func() {
24+
25+
// })
26+
27+
// // author: sgoveas@redhat.com
28+
// g.It("Author:sgoveas--Medium-12345-example case", func() {
29+
30+
// })
31+
32+
// })
33+
34+
// var _ = g.Describe("[sig-baremetal] INSTALLER UPI for INSTALLER_DEDICATED job on BareMetal", func() {
35+
// defer g.GinkgoRecover()
36+
// var (
37+
// oc = compat_otp.NewCLI("baremetal-deployment-sanity")
38+
39+
// )
40+
// g.BeforeEach(func() {
41+
42+
// })
43+
44+
// g.AfterEach(func() {
45+
46+
// })
47+
48+
// // author: sgoveas@redhat.com
49+
// g.It("Author:sgoveas--Medium-12345-example case", func() {
50+
51+
// })
52+
53+
// })
54+
55+
var _ = g.Describe("[sig-baremetal] INSTALLER IPI for INSTALLER_GENERAL job on BareMetal", func() {
56+
defer g.GinkgoRecover()
57+
var (
58+
oc = compat_otp.NewCLI("baremetal-deployment-sanity", compat_otp.KubeConfigPath())
59+
iaasPlatform string
60+
)
61+
g.BeforeEach(func() {
62+
compat_otp.SkipForSNOCluster(oc)
63+
iaasPlatform = compat_otp.CheckPlatform(oc)
64+
if !(iaasPlatform == "baremetal") {
65+
e2e.Logf("Cluster is: %s", iaasPlatform)
66+
g.Skip("For Non-baremetal cluster , this is not supported!")
67+
}
68+
})
69+
// author: jhajyahy@redhat.com
70+
// port=yes - 99.7% pass rate (724 runs last 60 days)
71+
g.It("Author:jhajyahy-Medium-29146-Verify that all clusteroperators are Available", func() {
72+
g.By("Running oc get clusteroperators")
73+
res, _ := checkOperatorsRunning(oc)
74+
o.Expect(res).To(o.BeTrue())
75+
})
76+
77+
// author: jhajyahy@redhat.com
78+
// port=yes - 100.0% pass rate (724 runs last 60 days)
79+
g.It("Author:jhajyahy-Medium-29719-Verify that all nodes are up and running", func() {
80+
g.By("Running oc get nodes")
81+
res, _ := checkNodesRunning(oc)
82+
o.Expect(res).To(o.BeTrue())
83+
84+
})
85+
86+
// author: jhajyahy@redhat.com
87+
// port=yes - 99.7% pass rate (724 runs last 60 days)
88+
g.It("Author:jhajyahy-Medium-32361-Verify that deployment exists and is not empty", func() {
89+
g.By("Create new namespace")
90+
oc.SetupProject()
91+
ns32361 := oc.Namespace()
92+
93+
g.By("Create deployment")
94+
deployCreationErr := oc.Run("create").Args("deployment", "deploy32361", "-n", ns32361, "--image", "quay.io/openshifttest/hello-openshift@sha256:4200f438cf2e9446f6bcff9d67ceea1f69ed07a2f83363b7fb52529f7ddd8a83").Execute()
95+
o.Expect(deployCreationErr).NotTo(o.HaveOccurred())
96+
97+
g.By("Check deployment status is available")
98+
waitForDeployStatus(oc, "deploy32361", ns32361, "True")
99+
status, err := oc.AsAdmin().Run("get").Args("deployment", "-n", ns32361, "deploy32361", "-o=jsonpath={.status.conditions[?(@.type=='Available')].status}").Output()
100+
o.Expect(err).NotTo(o.HaveOccurred())
101+
e2e.Logf("\nDeployment %s Status is %s\n", "deploy32361", status)
102+
o.Expect(status).To(o.Equal("True"))
103+
104+
g.By("Check pod is in Running state")
105+
podName := getPodName(oc, ns32361)
106+
podStatus := getPodStatus(oc, ns32361, podName)
107+
o.Expect(podStatus).To(o.Equal("Running"))
108+
})
109+
110+
// author: jhajyahy@redhat.com
111+
// port=yes - 99.9% pass rate (724 runs last 60 days)
112+
g.It("Author:jhajyahy-Medium-34195-Verify all pods replicas are running on workers only", func() {
113+
g.By("Create new namespace")
114+
oc.SetupProject()
115+
ns34195 := oc.Namespace()
116+
117+
g.By("Create deployment with num of workers + 1 replicas")
118+
workerNodes, err := compat_otp.GetClusterNodesBy(oc, "worker")
119+
o.Expect(err).NotTo(o.HaveOccurred())
120+
replicasNum := len(workerNodes) + 1
121+
deployCreationErr := oc.Run("create").Args("deployment", "deploy34195", "-n", ns34195, fmt.Sprintf("--replicas=%d", replicasNum), "--image", "quay.io/openshifttest/hello-openshift@sha256:4200f438cf2e9446f6bcff9d67ceea1f69ed07a2f83363b7fb52529f7ddd8a83").Execute()
122+
o.Expect(deployCreationErr).NotTo(o.HaveOccurred())
123+
waitForDeployStatus(oc, "deploy34195", ns34195, "True")
124+
125+
g.By("Check deployed pods number is as expected")
126+
pods, err := oc.AsAdmin().Run("get").Args("pods", "-n", ns34195, "--field-selector=status.phase=Running", "-o=jsonpath={.items[*].metadata.name}").Output()
127+
o.Expect(err).NotTo(o.HaveOccurred())
128+
podList := strings.Fields(pods)
129+
o.Expect(len(podList)).To(o.Equal(replicasNum))
130+
131+
g.By("Check pods are deployed on worker nodes only")
132+
for _, pod := range podList {
133+
podNodeName, err := compat_otp.GetPodNodeName(oc, ns34195, pod)
134+
o.Expect(err).NotTo(o.HaveOccurred())
135+
res := compat_otp.IsWorkerNode(oc, podNodeName)
136+
if !res {
137+
e2e.Logf("\nPod %s was deployed on non worker node %s\n", pod, podNodeName)
138+
}
139+
o.Expect(res).To(o.BeTrue())
140+
}
141+
})
142+
143+
// author: jhajyahy@redhat.com
144+
// port=yes - 99.7% pass rate (724 runs last 60 days)
145+
g.It("Author:jhajyahy-Medium-39126-Verify maximum CPU usage limit hasn't reached on each of the nodes", func() {
146+
g.By("Running oc get nodes")
147+
cpuExceededNodes := []string{}
148+
sampling_time, err := getClusterUptime(oc)
149+
o.Expect(err).NotTo(o.HaveOccurred())
150+
nodeNames, nodeErr := oc.AsAdmin().WithoutNamespace().Run("get").Args("nodes", "-o=jsonpath={.items[*].metadata.name}").Output()
151+
o.Expect(nodeErr).NotTo(o.HaveOccurred(), "Failed to execute oc get nodes")
152+
nodes := strings.Fields(nodeNames)
153+
for _, node := range nodes {
154+
cpuUsage := getNodeCpuUsage(oc, node, sampling_time)
155+
if cpuUsage > maxCpuUsageAllowed {
156+
cpuExceededNodes = append(cpuExceededNodes, node)
157+
e2e.Logf("\ncpu usage of exceeded node: %s is %.2f%%", node, cpuUsage)
158+
}
159+
}
160+
o.Expect(cpuExceededNodes).Should(o.BeEmpty(), "These nodes exceed max CPU usage allowed: %s", cpuExceededNodes)
161+
})
162+
163+
// author: jhajyahy@redhat.com
164+
// port=yes - 99.6% pass rate (724 runs last 60 days)
165+
g.It("Author:jhajyahy-Medium-39125-Verify that every node memory is sufficient", func() {
166+
g.By("Running oc get nodes")
167+
outOfMemoryNodes := []string{}
168+
nodeNames, nodeErr := oc.AsAdmin().WithoutNamespace().Run("get").Args("nodes", "-o=jsonpath={.items[*].metadata.name}").Output()
169+
o.Expect(nodeErr).NotTo(o.HaveOccurred(), "Failed to execute oc get nodes")
170+
nodes := strings.Fields(nodeNames)
171+
for _, node := range nodes {
172+
availMem := getNodeavailMem(oc, node)
173+
e2e.Logf("\nAvailable mem of Node %s is %d", node, availMem)
174+
if availMem < minRequiredMemoryInBytes {
175+
outOfMemoryNodes = append(outOfMemoryNodes, node)
176+
e2e.Logf("\nNode %s does not meet minimum required memory %s Bytes ", node, minRequiredMemoryInBytes)
177+
}
178+
}
179+
o.Expect(outOfMemoryNodes).Should(o.BeEmpty(), "These nodes does not meet minimum required memory: %s", outOfMemoryNodes)
180+
})
181+
})
182+
183+
// var _ = g.Describe("[sig-baremetal] INSTALLER IPI for INSTALLER_DEDICATED job on BareMetal", func() {
184+
// defer g.GinkgoRecover()
185+
// var (
186+
// oc = compat_otp.NewCLI("baremetal-deployment-sanity")
187+
188+
// )
189+
// g.BeforeEach(func() {
190+
191+
// })
192+
193+
// g.AfterEach(func() {
194+
195+
// })
196+
197+
// // author: sgoveas@redhat.com
198+
// g.It("Author:sgoveas--Medium-12345-example case", func() {
199+
200+
// })
201+
202+
// })

0 commit comments

Comments
 (0)