diff --git a/internal/rukpak/convert/registryv1.go b/internal/rukpak/convert/registryv1.go index e2eff3bc3..c26d16161 100644 --- a/internal/rukpak/convert/registryv1.go +++ b/internal/rukpak/convert/registryv1.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "encoding/json" + "errors" "fmt" "io/fs" "path/filepath" @@ -23,6 +24,7 @@ import ( "sigs.k8s.io/yaml" "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-registry/alpha/property" registrybundle "github.com/operator-framework/operator-registry/pkg/lib/bundle" registry "github.com/operator-framework/operator-controller/internal/rukpak/operator-registry" @@ -43,12 +45,12 @@ func RegistryV1ToHelmChart(ctx context.Context, rv1 fs.FS, installNamespace stri l := log.FromContext(ctx) reg := RegistryV1{} - fileData, err := fs.ReadFile(rv1, filepath.Join("metadata", "annotations.yaml")) + annotationsFileData, err := fs.ReadFile(rv1, filepath.Join("metadata", "annotations.yaml")) if err != nil { return nil, err } annotationsFile := registry.AnnotationsFile{} - if err := yaml.Unmarshal(fileData, &annotationsFile); err != nil { + if err := yaml.Unmarshal(annotationsFileData, &annotationsFile); err != nil { return nil, err } reg.PackageName = annotationsFile.Annotations.PackageName @@ -101,9 +103,61 @@ func RegistryV1ToHelmChart(ctx context.Context, rv1 fs.FS, installNamespace stri return nil, err } + if err := copyMetadataPropertiesToCSV(®.CSV, rv1); err != nil { + return nil, err + } + return toChart(reg, installNamespace, watchNamespaces) } +// copyMetadataPropertiesToCSV copies properties from `metadata/propeties.yaml` (in the filesystem fsys) into +// the CSV's `.metadata.annotations['olm.properties']` value, preserving any properties that are already +// present in the annotations. +func copyMetadataPropertiesToCSV(csv *v1alpha1.ClusterServiceVersion, fsys fs.FS) error { + var allProperties []property.Property + + // First load existing properties from the CSV. We want to preserve these. + if csvPropertiesJSON, ok := csv.Annotations["olm.properties"]; ok { + var csvProperties []property.Property + if err := json.Unmarshal([]byte(csvPropertiesJSON), &csvProperties); err != nil { + return fmt.Errorf("failed to unmarshal csv.metadata.annotations['olm.properties']: %w", err) + } + allProperties = append(allProperties, csvProperties...) + } + + // Next, load properties from the metadata/properties.yaml file, if it exists. + metadataPropertiesJSON, err := fs.ReadFile(fsys, filepath.Join("metadata", "properties.yaml")) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to read properties.yaml file: %w", err) + } + + // If there are no properties, we can stick with whatever + // was already present in the CSV annotations. + if len(metadataPropertiesJSON) == 0 { + return nil + } + + // Otherwise, we need to parse the properties.yaml file and + // append its properties into the CSV annotation. + type registryV1Properties struct { + Properties []property.Property `json:"properties"` + } + + var metadataProperties registryV1Properties + if err := yaml.Unmarshal(metadataPropertiesJSON, &metadataProperties); err != nil { + return fmt.Errorf("failed to unmarshal metadata/properties.yaml: %w", err) + } + allProperties = append(allProperties, metadataProperties.Properties...) + + // Lastly re-marshal all the properties back into a JSON array and update the CSV annotation + allPropertiesJSON, err := json.Marshal(allProperties) + if err != nil { + return fmt.Errorf("failed to marshal registry+v1 properties to json: %w", err) + } + csv.Annotations["olm.properties"] = string(allPropertiesJSON) + return nil +} + func toChart(in RegistryV1, installNamespace string, watchNamespaces []string) (*chart.Chart, error) { plain, err := Convert(in, installNamespace, watchNamespaces) if err != nil { diff --git a/internal/rukpak/convert/registryv1_test.go b/internal/rukpak/convert/registryv1_test.go index 8e9171dec..0be7e9e84 100644 --- a/internal/rukpak/convert/registryv1_test.go +++ b/internal/rukpak/convert/registryv1_test.go @@ -1,7 +1,9 @@ package convert import ( + "context" "fmt" + "os" "strings" "testing" @@ -24,7 +26,7 @@ import ( func TestRegistryV1Converter(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "RegstryV1 suite") + RunSpecs(t, "RegistryV1 suite") } var _ = Describe("RegistryV1 Suite", func() { @@ -418,6 +420,17 @@ var _ = Describe("RegistryV1 Suite", func() { }) }) + Context("Should read the registry+v1 bundle filesystem correctly", func() { + It("should include metadata/properties.yaml and csv.metadata.annotations['olm.properties'] in chart metadata", func() { + fsys := os.DirFS("testdata/combine-properties-bundle") + chrt, err := RegistryV1ToHelmChart(context.Background(), fsys, "", nil) + Expect(err).NotTo(HaveOccurred()) + Expect(chrt).NotTo(BeNil()) + Expect(chrt.Metadata).NotTo(BeNil()) + Expect(chrt.Metadata.Annotations).To(HaveKeyWithValue("olm.properties", `[{"type":"from-csv-annotations-key","value":"from-csv-annotations-value"},{"type":"from-file-key","value":"from-file-value"}]`)) + }) + }) + Context("Should enforce limitations", func() { It("should not allow bundles with webhooks", func() { By("creating a registry v1 bundle") diff --git a/internal/rukpak/convert/testdata/combine-properties-bundle/manifests/csv.yaml b/internal/rukpak/convert/testdata/combine-properties-bundle/manifests/csv.yaml new file mode 100644 index 000000000..a2a620439 --- /dev/null +++ b/internal/rukpak/convert/testdata/combine-properties-bundle/manifests/csv.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.operatorframework.io/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: test.v1.0.0 + annotations: + olm.properties: '[{"type":"from-csv-annotations-key", "value":"from-csv-annotations-value"}]' +spec: + installModes: + - type: AllNamespaces + supported: true diff --git a/internal/rukpak/convert/testdata/combine-properties-bundle/metadata/annotations.yaml b/internal/rukpak/convert/testdata/combine-properties-bundle/metadata/annotations.yaml new file mode 100644 index 000000000..e75867f85 --- /dev/null +++ b/internal/rukpak/convert/testdata/combine-properties-bundle/metadata/annotations.yaml @@ -0,0 +1,3 @@ +annotations: + operators.operatorframework.io.bundle.mediatype.v1: registry+v1 + operators.operatorframework.io.bundle.package.v1: test diff --git a/internal/rukpak/convert/testdata/combine-properties-bundle/metadata/properties.yaml b/internal/rukpak/convert/testdata/combine-properties-bundle/metadata/properties.yaml new file mode 100644 index 000000000..1a6e7abfb --- /dev/null +++ b/internal/rukpak/convert/testdata/combine-properties-bundle/metadata/properties.yaml @@ -0,0 +1,3 @@ +properties: + - type: "from-file-key" + value: "from-file-value"