Skip to content

Commit d9a5d32

Browse files
committed
migrate ocp-53906 from otp to cvo repo
1 parent ffe4646 commit d9a5d32

4 files changed

Lines changed: 147 additions & 0 deletions

File tree

.openshift-tests-extension/openshift_payload_cluster-version-operator.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,15 @@
7272
"source": "openshift:payload:cluster-version-operator",
7373
"lifecycle": "blocking",
7474
"environmentSelector": {}
75+
},
76+
{
77+
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator should have correct architecture info in clusterversion status",
78+
"labels": {},
79+
"resources": {
80+
"isolation": {}
81+
},
82+
"source": "openshift:payload:cluster-version-operator",
83+
"lifecycle": "blocking",
84+
"environmentSelector": {}
7585
}
7686
]

test/cvo/cvo.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ package cvo
44

55
import (
66
"context"
7+
"encoding/json"
8+
"time"
79

810
g "github.com/onsi/ginkgo/v2"
911
o "github.com/onsi/gomega"
1012

1113
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/apimachinery/pkg/util/sets"
1215
"k8s.io/client-go/kubernetes"
1316
"k8s.io/client-go/rest"
1417

18+
"github.com/openshift/cluster-version-operator/lib/resourcemerge"
1519
"github.com/openshift/cluster-version-operator/pkg/external"
1620
"github.com/openshift/cluster-version-operator/test/oc"
1721
ocapi "github.com/openshift/cluster-version-operator/test/oc/api"
@@ -99,4 +103,78 @@ var _ = g.Describe(`[Jira:"Cluster Version Operator"] cluster-version-operator`,
99103
sccAnnotation := cvoPod.Annotations["openshift.io/scc"]
100104
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)
101105
})
106+
107+
// Migrated from case Author:jiajliu-Medium-53906-The architecture info in clusterversion's status should be correct
108+
// Refer to https://github.com/jiajliu/openshift-tests-private/blob/1ac5f94ee596419194ff7b0070732cb7930fe39e/test/extended/ota/cvo/cvo.go#L1775
109+
g.It("should have correct architecture info in clusterversion status", func() {
110+
const heterogeneousArchKeyword = "multi"
111+
112+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
113+
defer cancel()
114+
115+
err := util.SkipIfMicroshift(ctx, restCfg)
116+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to determine if cluster is MicroShift")
117+
118+
g.By("Getting release architecture from release info")
119+
ocClient, err := oc.NewOC(ocapi.Options{Logger: logger})
120+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to create oc client")
121+
releaseInfoJSON, err := ocClient.AdmReleaseInfo(ocapi.ReleaseInfoOptions{})
122+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to get release info")
123+
124+
// Extract architecture from release info: metadata.metadata."release.openshift.io/architecture"
125+
// Valid payloads:
126+
// - Stable single-arch: metadata.metadata exists but without "release.openshift.io/architecture"
127+
// - Stable multi-arch: metadata.metadata."release.openshift.io/architecture" = "multi"
128+
// - Nightly single-arch: metadata.metadata not exists
129+
// - Nightly multi-arch: metadata.metadata."release.openshift.io/architecture" = "multi"
130+
var releaseInfo struct {
131+
Metadata *struct {
132+
Metadata map[string]string `json:"metadata"`
133+
} `json:"metadata"`
134+
}
135+
o.Expect(json.Unmarshal([]byte(releaseInfoJSON), &releaseInfo)).To(o.Succeed(), "Failed to unmarshal release info JSON")
136+
if releaseInfo.Metadata == nil {
137+
g.Skip("Release info missing top-level 'metadata' field, cannot determine payload architecture type")
138+
}
139+
140+
releaseArch := releaseInfo.Metadata.Metadata["release.openshift.io/architecture"]
141+
logger.Info("Release architecture from release info", "architecture", releaseArch)
142+
if releaseArch != "" && releaseArch != heterogeneousArchKeyword {
143+
g.Skip("Unknown architecture value in release info: " + releaseArch)
144+
}
145+
146+
g.By("Check the arch info in ClusterVersion status is expected")
147+
configClient, err := util.GetConfigClient(restCfg)
148+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to create config client")
149+
cv, err := configClient.ConfigV1().ClusterVersions().Get(ctx, external.DefaultClusterVersionName, metav1.GetOptions{})
150+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to get ClusterVersion")
151+
releaseAcceptedCond := resourcemerge.FindOperatorStatusCondition(cv.Status.Conditions, "ReleaseAccepted")
152+
o.Expect(releaseAcceptedCond).NotTo(o.BeNil(), "ReleaseAccepted condition not found in ClusterVersion status")
153+
cvArchInfo := releaseAcceptedCond.Message
154+
logger.Info("ClusterVersion ReleaseAccepted message", "message", cvArchInfo)
155+
156+
if releaseArch == "" {
157+
// For non-heterogeneous payload, the architecture info in ClusterVersion status should be consistent with node architectures
158+
g.By("Verifying all nodes have the same architecture")
159+
nodes, err := kubeClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
160+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to list nodes")
161+
o.Expect(nodes.Items).NotTo(o.BeEmpty(), "No nodes found in cluster")
162+
163+
nodeArchs := sets.New[string]()
164+
for _, node := range nodes.Items {
165+
nodeArchs.Insert(node.Status.NodeInfo.Architecture)
166+
}
167+
logger.Info("Node architectures found", "architectures", sets.List(nodeArchs))
168+
o.Expect(nodeArchs).To(o.HaveLen(1), "Expected all nodes to have the same architecture in non-heterogeneous cluster, but found: %v", sets.List(nodeArchs))
169+
170+
expectedArch := sets.List(nodeArchs)[0]
171+
g.By("Verifying ClusterVersion status architecture matches node architecture")
172+
o.Expect(cvArchInfo).To(o.ContainSubstring(expectedArch), "ClusterVersion ReleaseAccepted message should contain node architecture %q, but got: %s", expectedArch, cvArchInfo)
173+
} else {
174+
// For heterogeneous payload, the architecture info in ClusterVersion status should be Multi
175+
g.By("Verifying ClusterVersion status architecture includes architecture=\"Multi\"")
176+
expectedArchMsg := `architecture="Multi"`
177+
o.Expect(cvArchInfo).To(o.ContainSubstring(expectedArchMsg), "ClusterVersion ReleaseAccepted message should contain %q for heterogeneous payload, but got: %s", expectedArchMsg, cvArchInfo)
178+
}
179+
})
102180
})

test/oc/api/api.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,28 @@ type ReleaseExtractOptions struct {
1010
To string
1111
}
1212

13+
type ReleaseInfoOptions struct {
14+
Image string
15+
}
16+
1317
type VersionOptions struct {
1418
Client bool
1519
}
1620

21+
type ExtractOptions struct {
22+
Resource string
23+
Namespace string
24+
To string
25+
}
26+
1727
type Options struct {
1828
Logger logr.Logger
1929
Timeout time.Duration
2030
}
2131

2232
type OC interface {
2333
AdmReleaseExtract(o ReleaseExtractOptions) error
34+
AdmReleaseInfo(o ReleaseInfoOptions) (string, error)
2435
Version(o VersionOptions) (string, error)
36+
Extract(o ExtractOptions) error
2537
}

test/oc/cli/cli.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"os"
78
"os/exec"
9+
"path/filepath"
810
"strings"
911
"time"
1012

@@ -90,6 +92,51 @@ func (c *client) AdmReleaseExtract(o api.ReleaseExtractOptions) error {
9092
return nil
9193
}
9294

95+
func (c *client) AdmReleaseInfo(o api.ReleaseInfoOptions) (string, error) {
96+
// Create temp directory to extract pull-secret
97+
tempDir, err := os.MkdirTemp("", "cvo-test-")
98+
if err != nil {
99+
return "", fmt.Errorf("failed to create temp directory: %w", err)
100+
}
101+
defer func() {
102+
if err := os.RemoveAll(tempDir); err != nil {
103+
c.logger.Error(err, "failed to clean up temp directory", "path", tempDir)
104+
}
105+
}()
106+
107+
// Extract pull-secret from cluster
108+
extractErr := c.Extract(api.ExtractOptions{
109+
Resource: "secret/pull-secret",
110+
Namespace: "openshift-config",
111+
To: tempDir,
112+
})
113+
if extractErr != nil {
114+
return "", fmt.Errorf("failed to extract pull-secret: %w", extractErr)
115+
}
116+
117+
// Use the extracted pull-secret
118+
pullSecret := filepath.Join(tempDir, ".dockerconfigjson")
119+
if _, err := os.Stat(pullSecret); err != nil {
120+
return "", fmt.Errorf("pull-secret file not found at %s: %w", pullSecret, err)
121+
}
122+
123+
args := []string{"adm", "release", "info", "-a", pullSecret, "--insecure", "-o", "json"}
124+
if o.Image != "" {
125+
args = append(args, o.Image)
126+
}
127+
output, err := c.executor.Run(args...)
128+
if err != nil {
129+
return "", err
130+
}
131+
return string(output), nil
132+
}
133+
134+
func (c *client) Extract(o api.ExtractOptions) error {
135+
args := []string{"extract", o.Resource, "-n", o.Namespace, "--confirm", fmt.Sprintf("--to=%s", o.To)}
136+
_, err := c.executor.Run(args...)
137+
return err
138+
}
139+
93140
func (c *client) Version(o api.VersionOptions) (string, error) {
94141
args := []string{"version", fmt.Sprintf("--client=%t", o.Client)}
95142
output, err := c.executor.Run(args...)

0 commit comments

Comments
 (0)