Skip to content

Commit

Permalink
CLID-10,CFE-824: Add updateStrategy to generated catalog source
Browse files Browse the repository at this point in the history
  • Loading branch information
sherine-k committed Jan 22, 2024
1 parent ec65a8f commit dd13288
Show file tree
Hide file tree
Showing 11 changed files with 504 additions and 52 deletions.
2 changes: 1 addition & 1 deletion v2/go.mod
Expand Up @@ -24,6 +24,7 @@ require (
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
golang.org/x/crypto v0.10.0
golang.org/x/term v0.9.0
k8s.io/api v0.26.3
k8s.io/apimachinery v0.26.3
k8s.io/klog/v2 v2.100.1
k8s.io/kubectl v0.26.3
Expand Down Expand Up @@ -157,7 +158,6 @@ require (
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.26.3 // indirect
k8s.io/client-go v0.26.3 // indirect
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
Expand Down
7 changes: 3 additions & 4 deletions v2/pkg/api/v1alpha2/types_config.go
Expand Up @@ -141,10 +141,9 @@ type Operator struct {
// SkipDependencies will not include dependencies
// of bundles included in the diff if true.
SkipDependencies bool `json:"skipDependencies,omitempty"`
// OriginalRef is used when the Catalog is an OCI FBC (File Based Catalog) location.
// It contains the reference to the original repo on a remote registry
// Deprecated in oc-mirror 4.13, and will no longer be used.
OriginalRef string `json:"originalRef,omitempty"`
// path on disk for a template to use to complete catalogSource custom resource
// generated by oc-mirror
TargetCatalogSourceTemplate string `json:"targetCatalogSourceTemplate,omitempty"`
}

// GetUniqueName determines the catalog name that will
Expand Down
2 changes: 1 addition & 1 deletion v2/pkg/cli/executor.go
Expand Up @@ -363,7 +363,7 @@ func (o *ExecutorSchema) Complete(args []string) error {
o.Release = release.New(o.Log, o.LogsDir, o.Config, o.Opts, o.Mirror, o.Manifest, cn, o.LocalStorageFQDN, o.ImageBuilder)
o.Operator = operator.New(o.Log, o.LogsDir, o.Config, o.Opts, o.Mirror, o.Manifest, o.LocalStorageFQDN)
o.AdditionalImages = additional.New(o.Log, o.Config, o.Opts, o.Mirror, o.Manifest, o.LocalStorageFQDN)
o.ClusterResources = clusterresources.New(o.Log, o.Opts.Global.WorkingDir)
o.ClusterResources = clusterresources.New(o.Log, o.Opts.Global.WorkingDir, o.Config)
o.Batch = batch.New(o.Log, o.LogsDir, o.Mirror, o.Manifest)

if o.Opts.IsMirrorToDisk() {
Expand Down
72 changes: 57 additions & 15 deletions v2/pkg/clusterresources/clusterresources.go
Expand Up @@ -11,6 +11,7 @@ import (
"time"

confv1 "github.com/openshift/api/config/v1"
ofv1alpha1 "github.com/openshift/oc-mirror/v2/pkg/api/operator-framework/v1alpha1"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha2"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha3"
updateservicev1 "github.com/openshift/oc-mirror/v2/pkg/clusterresources/updateservice/v1"
Expand All @@ -23,13 +24,15 @@ import (

func New(log clog.PluggableLoggerInterface,
workingDir string,
conf v1alpha2.ImageSetConfiguration,
) GeneratorInterface {
return &ClusterResourcesGenerator{Log: log, WorkingDir: workingDir}
return &ClusterResourcesGenerator{Log: log, WorkingDir: workingDir, Config: conf}
}

type ClusterResourcesGenerator struct {
Log clog.PluggableLoggerInterface
WorkingDir string
Config v1alpha2.ImageSetConfiguration
}

func (o *ClusterResourcesGenerator) IDMSGenerator(allRelatedImages []v1alpha3.CopyImageSchema) error {
Expand Down Expand Up @@ -101,9 +104,10 @@ func (o *ClusterResourcesGenerator) IDMSGenerator(allRelatedImages []v1alpha3.Co

func (o *ClusterResourcesGenerator) CatalogSourceGenerator(allRelatedImages []v1alpha3.CopyImageSchema) error {
for _, copyImage := range allRelatedImages {

if copyImage.Type == v1alpha2.TypeOperatorCatalog {
err := o.generateCatalogSource(copyImage.Destination)
// check if ImageSetConfig contains a CatalogSourceTemplate for this catalog, and use it
template := o.getCSTemplate(copyImage.Origin)
err := o.generateCatalogSource(copyImage.Destination, template)
if err != nil {
return err
}
Expand All @@ -112,7 +116,16 @@ func (o *ClusterResourcesGenerator) CatalogSourceGenerator(allRelatedImages []v1
return nil
}

func (o *ClusterResourcesGenerator) generateCatalogSource(catalogRef string) error {
func (o *ClusterResourcesGenerator) getCSTemplate(catalogRef string) string {
for _, op := range o.Config.ImageSetConfigurationSpec.Mirror.Operators {
if strings.Contains(catalogRef, op.Catalog) {
return op.TargetCatalogSourceTemplate
}
}
return ""
}

func (o *ClusterResourcesGenerator) generateCatalogSource(catalogRef string, catalogSourceTemplateFile string) error {

dateTime := time.Now().UTC().Format(time.RFC3339)
// replace all : by -
Expand All @@ -130,17 +143,46 @@ func (o *ClusterResourcesGenerator) generateCatalogSource(catalogRef string) err
if len(errs) != 0 && isValidRFC1123(catalogSourceName) {
return fmt.Errorf("error creating catalog source name: %s", strings.Join(errs, ", "))
}
obj := map[string]interface{}{
"apiVersion": "operators.coreos.com/v1alpha1",
"kind": "CatalogSource",
"metadata": map[string]interface{}{
"name": catalogSourceName,
"namespace": "openshift-marketplace",
},
"spec": map[string]interface{}{
"sourceType": "grpc",
"image": catalogSpec.Reference, // this way the transport prefix (if any) is removed
},

var obj ofv1alpha1.CatalogSource
if catalogSourceTemplateFile != "" {
// Initializing catalogSource `obj` from template
_, err := os.Stat(catalogSourceTemplateFile)
if os.IsNotExist(err) {
return fmt.Errorf("targetCatalogSourceTemplate does not exist: %s", catalogSourceTemplateFile)
}
if err != nil {
return fmt.Errorf("error reading targetCatalogSourceTemplate file %s", catalogSourceTemplateFile)
}
bytesRead, err := os.ReadFile(catalogSourceTemplateFile)
if err != nil {
return fmt.Errorf("error reading targetCatalogSourceTemplate file %s", catalogSourceTemplateFile)
}
err = yaml.Unmarshal(bytesRead, &obj)
if err != nil {
return fmt.Errorf("%s is not a valid catalog source template", catalogSourceTemplateFile)
}
// fill obj with the values for this catalog
obj.Name = catalogSourceName
obj.Namespace = "openshift-marketplace"
obj.Spec.SourceType = "grpc"
obj.Spec.ConfigMap = "" //Force ConfigMap to empty as SourceType is grpc
obj.Spec.Image = catalogSpec.Reference
} else {
obj = ofv1alpha1.CatalogSource{
TypeMeta: metav1.TypeMeta{
APIVersion: ofv1alpha1.GroupName + "/" + ofv1alpha1.GroupVersion,
Kind: "CatalogSource",
},
ObjectMeta: metav1.ObjectMeta{
Name: catalogSourceName,
Namespace: "openshift-marketplace",
},
Spec: ofv1alpha1.CatalogSourceSpec{
SourceType: "grpc",
Image: catalogSpec.Reference,
},
}
}
bytes, err := yaml.Marshal(obj)
if err != nil {
Expand Down
115 changes: 104 additions & 11 deletions v2/pkg/clusterresources/clusterresources_test.go
Expand Up @@ -5,12 +5,15 @@ import (
"path/filepath"
"strings"
"testing"
"time"

ofv1alpha1 "github.com/openshift/oc-mirror/v2/pkg/api/operator-framework/v1alpha1"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha2"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha3"
updateservicev1 "github.com/openshift/oc-mirror/v2/pkg/clusterresources/updateservice/v1"
clog "github.com/openshift/oc-mirror/v2/pkg/log"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -158,18 +161,108 @@ func TestCatalogSourceGenerator(t *testing.T) {
if err != nil {
t.Fatalf("failed to read file: %v", err)
}
var actualCS ofv1alpha1.CatalogSource
err = yaml.Unmarshal(bytes, &actualCS)
if err != nil {
t.Fatalf("failed to unmarshal catalogsource: %v", err)
}
expectedCS := ofv1alpha1.CatalogSource{
TypeMeta: metav1.TypeMeta{
APIVersion: ofv1alpha1.GroupName + "/" + ofv1alpha1.GroupVersion,
Kind: "CatalogSource",
},
ObjectMeta: metav1.ObjectMeta{
Name: strings.TrimSuffix(csFiles[0].Name(), ".yaml"),
Namespace: "openshift-marketplace",
},
Spec: ofv1alpha1.CatalogSourceSpec{
SourceType: "grpc",
Image: "myregistry/mynamespace/redhat/redhat-operator-index:v4.15",
},
}

assert.Equal(t, expectedCS, actualCS, "contents of catalogSource file incorrect")

})

t.Run("Testing GenerateCatalogSource with template: should pass", func(t *testing.T) {

cr := &ClusterResourcesGenerator{
Log: log,
WorkingDir: workingDir,
Config: v1alpha2.ImageSetConfiguration{
ImageSetConfigurationSpec: v1alpha2.ImageSetConfigurationSpec{
Mirror: v1alpha2.Mirror{
Operators: []v1alpha2.Operator{
{
Catalog: "registry.redhat.io/redhat/redhat-operator-index:v4.15",
TargetCatalogSourceTemplate: "../../tests/catalog-source_template.yaml",
},
},
},
},
},
}
err := cr.CatalogSourceGenerator(imageList)
if err != nil {
t.Fatalf("should not fail")
}
_, err = os.Stat(filepath.Join(workingDir, clusterResourcesDir))
if err != nil {
t.Fatalf("output folder should exist")
}

csFiles, err := os.ReadDir(filepath.Join(workingDir, clusterResourcesDir))
if err != nil {
t.Fatalf("ls output folder should not fail")
}

if len(csFiles) != 1 {
t.Fatalf("output folder should contain 1 idms yaml file")
}
// check idmsFile has a name that is
//compliant with Kubernetes requested
// RFC-1035 + RFC1123
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names
customResourceName := strings.TrimSuffix(csFiles[0].Name(), ".yaml")
if !isValidRFC1123(customResourceName) {
t.Fatalf("CatalogSource custom resource name %s doesn't respect RFC1123", csFiles[0].Name())
}
bytes, err := os.ReadFile(filepath.Join(workingDir, clusterResourcesDir, csFiles[0].Name()))
if err != nil {
t.Fatalf("failed to read file: %v", err)
}
var actualCS ofv1alpha1.CatalogSource
err = yaml.Unmarshal(bytes, &actualCS)
if err != nil {
t.Fatalf("failed to unmarshal catalogsource: %v", err)
}
expectedCS := ofv1alpha1.CatalogSource{
TypeMeta: metav1.TypeMeta{
APIVersion: ofv1alpha1.GroupName + "/" + ofv1alpha1.GroupVersion,
Kind: "CatalogSource",
},
ObjectMeta: metav1.ObjectMeta{
Name: strings.TrimSuffix(csFiles[0].Name(), ".yaml"),
Namespace: "openshift-marketplace",
},
Spec: ofv1alpha1.CatalogSourceSpec{
SourceType: "grpc",
Image: "myregistry/mynamespace/redhat/redhat-operator-index:v4.15",
UpdateStrategy: &ofv1alpha1.UpdateStrategy{
RegistryPoll: &ofv1alpha1.RegistryPoll{
RawInterval: "30m0s",
Interval: &metav1.Duration{
Duration: time.Minute * 30,
},

ParsingError: "",
},
},
},
}

contents := string(bytes)
expectedRx := `apiVersion: operators\.coreos\.com\/v1alpha1
kind: CatalogSource
metadata:
name: cs-redhat-operator-index-[tz\-0-9]*
namespace: openshift-marketplace
spec:
image: myregistry\/mynamespace\/redhat\/redhat-operator-index:v4\.15
sourceType: grpc
`
assert.Regexp(t, expectedRx, contents, "contents of catalogSource file incorrect")
assert.Equal(t, expectedCS, actualCS, "contents of catalogSource file incorrect")

})
}
Expand Down
11 changes: 11 additions & 0 deletions v2/tests/catalog-source_template.yaml
@@ -0,0 +1,11 @@
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
name: totalRubbish
namespace: openshift-marketplace
spec:
image: totalRubbish
sourceType: grpc
updateStrategy:
registryPoll:
interval: 30m0s

0 comments on commit dd13288

Please sign in to comment.