From 84edf42fd61042de1527205423c6fb8b13f5dd3a Mon Sep 17 00:00:00 2001 From: splatypus-bot <282974456+splatypus-bot@users.noreply.github.com> Date: Fri, 8 May 2026 22:31:08 -0400 Subject: [PATCH] feat: add vsphere-component annotation to CredentialsRequest CR Add cloudcredential.openshift.io/vsphere-component: cloudController to openshift-vsphere-cloud-controller-manager CredentialsRequest so CCO can route per-component credentials in PerComponent mode (story #39). Add manifest annotation unit tests (test/manifest/). Co-Authored-By: Claude Sonnet 4.6 (1M context) --- ...perator_17_credentialsrequest-vsphere.yaml | 1 + .../credentials_request_annotation_test.go | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 test/manifest/credentials_request_annotation_test.go diff --git a/manifests/0000_26_cloud-controller-manager-operator_17_credentialsrequest-vsphere.yaml b/manifests/0000_26_cloud-controller-manager-operator_17_credentialsrequest-vsphere.yaml index 2a9aaab7a..6a23ab647 100644 --- a/manifests/0000_26_cloud-controller-manager-operator_17_credentialsrequest-vsphere.yaml +++ b/manifests/0000_26_cloud-controller-manager-operator_17_credentialsrequest-vsphere.yaml @@ -5,6 +5,7 @@ metadata: namespace: openshift-cloud-credential-operator annotations: capability.openshift.io/name: CloudCredential+CloudControllerManager + cloudcredential.openshift.io/vsphere-component: cloudController include.release.openshift.io/self-managed-high-availability: "true" include.release.openshift.io/single-node-developer: "true" spec: diff --git a/test/manifest/credentials_request_annotation_test.go b/test/manifest/credentials_request_annotation_test.go new file mode 100644 index 000000000..2a8eed56e --- /dev/null +++ b/test/manifest/credentials_request_annotation_test.go @@ -0,0 +1,83 @@ +package manifest_test + +import ( + "os" + "strings" + "testing" + + "gopkg.in/yaml.v3" +) + +const vsphereComponentAnnotation = "cloudcredential.openshift.io/vsphere-component" + +type credentialsRequest struct { + Kind string `yaml:"kind"` + Metadata struct { + Name string `yaml:"name"` + Annotations map[string]string `yaml:"annotations"` + } `yaml:"metadata"` +} + +func parseCredentialsRequests(t *testing.T, path string) []credentialsRequest { + t.Helper() + data, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + var out []credentialsRequest + for _, doc := range strings.Split(string(data), "\n---") { + doc = strings.TrimSpace(doc) + if doc == "" { + continue + } + var cr credentialsRequest + if err := yaml.Unmarshal([]byte(doc), &cr); err != nil { + t.Fatalf("unmarshal %s: %v", path, err) + } + if cr.Kind == "CredentialsRequest" { + out = append(out, cr) + } + } + return out +} + +func findCR(crs []credentialsRequest, name string) (credentialsRequest, bool) { + for _, cr := range crs { + if cr.Metadata.Name == name { + return cr, true + } + } + return credentialsRequest{}, false +} + +func TestCCMVSphereCredentialsRequestAnnotation(t *testing.T) { + path := "../../manifests/0000_26_cloud-controller-manager-operator_17_credentialsrequest-vsphere.yaml" + crs := parseCredentialsRequests(t, path) + + cr, ok := findCR(crs, "openshift-vsphere-cloud-controller-manager") + if !ok { + t.Fatal("CredentialsRequest 'openshift-vsphere-cloud-controller-manager' not found in manifest") + } + + got, present := cr.Metadata.Annotations[vsphereComponentAnnotation] + if !present { + t.Fatalf("annotation %q missing from openshift-vsphere-cloud-controller-manager", vsphereComponentAnnotation) + } + if got != "cloudController" { + t.Errorf("annotation value: got %q, want %q", got, "cloudController") + } +} + +func TestAnnotationValueIsNotEmpty(t *testing.T) { + path := "../../manifests/0000_26_cloud-controller-manager-operator_17_credentialsrequest-vsphere.yaml" + crs := parseCredentialsRequests(t, path) + + cr, ok := findCR(crs, "openshift-vsphere-cloud-controller-manager") + if !ok { + t.Fatal("CredentialsRequest 'openshift-vsphere-cloud-controller-manager' not found in manifest") + } + val := cr.Metadata.Annotations[vsphereComponentAnnotation] + if strings.TrimSpace(val) == "" { + t.Errorf("annotation %q must not be empty", vsphereComponentAnnotation) + } +}