Skip to content

Commit

Permalink
CLID-10: Generate CatalogSource files (openshift#784)
Browse files Browse the repository at this point in the history
CLID-10: targetCatalog replaces deprecated field targetName(removed) for GetUniqueName.

CLID-10,CFE-824: Add updateStrategy to generated catalog source

Failover to regular catalogSource generation if template generation fails

V2 - Modify naming convention for catalogSource
  • Loading branch information
sherine-k authored and aguidirh committed Jan 31, 2024
1 parent d276e39 commit c59c984
Show file tree
Hide file tree
Showing 46 changed files with 5,519 additions and 1,805 deletions.
3 changes: 1 addition & 2 deletions v2/go.mod
Expand Up @@ -15,7 +15,6 @@ require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0-rc3
github.com/openshift/api v0.0.0-20230223193310-d964c7a58d75
github.com/openshift/library-go v0.0.0-20230308200407-f3277c772011
github.com/operator-framework/operator-registry v1.26.4
github.com/otiai10/copy v1.2.0
github.com/sirupsen/logrus v1.9.3
Expand All @@ -24,6 +23,7 @@ require (
github.com/stretchr/testify v1.8.4
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
golang.org/x/crypto v0.10.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 @@ -158,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
2 changes: 0 additions & 2 deletions v2/go.sum
Expand Up @@ -731,8 +731,6 @@ github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaL
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/openshift/api v0.0.0-20230223193310-d964c7a58d75 h1:OQJsfiach1cKBI1xUSNXKzuqi8nTpDRccR8gMGFkTIU=
github.com/openshift/api v0.0.0-20230223193310-d964c7a58d75/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4=
github.com/openshift/library-go v0.0.0-20230308200407-f3277c772011 h1:RL6hf0cNc9uVZXQkU74a/J91XEo5iip2mWvJTwKgMg4=
github.com/openshift/library-go v0.0.0-20230308200407-f3277c772011/go.mod h1:OspkL5FZZapzNcka6UkNMFD7ifLT/dWUNvtwErpRK9k=
github.com/operator-framework/operator-registry v1.26.4 h1:5jKY/V5zVuPsjV6ct2T97px4+iI/eZoTDfymmKudiSU=
github.com/operator-framework/operator-registry v1.26.4/go.mod h1:DZcTzhAyZf/NLi2UwBQA1F/qh4FwgYBcgBx2yBz8I+Q=
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M=
Expand Down
4 changes: 2 additions & 2 deletions v2/pkg/additional/local_stored_collector.go
Expand Up @@ -48,7 +48,7 @@ func (o LocalStorageCollector) AdditionalImagesCollector(ctx context.Context) ([

o.Log.Debug("source %s", src)
o.Log.Debug("destination %s", dest)
allImages = append(allImages, v1alpha3.CopyImageSchema{Source: src, Destination: dest})
allImages = append(allImages, v1alpha3.CopyImageSchema{Source: src, Destination: dest, Origin: src, Type: v1alpha2.TypeGeneric})

}
}
Expand Down Expand Up @@ -85,7 +85,7 @@ func (o LocalStorageCollector) AdditionalImagesCollector(ctx context.Context) ([

o.Log.Debug("source %s", src)
o.Log.Debug("destination %s", dest)
allImages = append(allImages, v1alpha3.CopyImageSchema{Origin: img.Name, Source: src, Destination: dest})
allImages = append(allImages, v1alpha3.CopyImageSchema{Origin: img.Name, Source: src, Destination: dest, Type: v1alpha2.TypeGeneric})
}
}
return allImages, nil
Expand Down
4 changes: 2 additions & 2 deletions v2/pkg/additional/local_stored_collector_test.go
Expand Up @@ -124,7 +124,7 @@ func (o MockManifest) GetOperatorConfig(file string) (*v1alpha3.OperatorConfigSc
return ocs, nil
}

func (o MockManifest) GetRelatedImagesFromCatalogByFilter(filePath, label string, op v1alpha2.Operator, mp map[string]v1alpha3.ISCPackage) (map[string][]v1alpha3.RelatedImage, error) {
func (o MockManifest) GetRelatedImagesFromCatalogByFilter(filePath, label string, op v1alpha2.Operator) (map[string][]v1alpha3.RelatedImage, error) {
return nil, nil
}

Expand Down Expand Up @@ -169,7 +169,7 @@ func (o MockManifest) GetImageManifest(name string) (*v1alpha3.OCISchema, error)
}, nil
}

func (o MockManifest) GetRelatedImagesFromCatalog(filePath, label string) (map[string][]v1alpha3.RelatedImage, error) {
func (o MockManifest) GetRelatedImagesFromCatalog(filePath, label string, op v1alpha2.Operator) (map[string][]v1alpha3.RelatedImage, error) {
relatedImages := make(map[string][]v1alpha3.RelatedImage)
relatedImages["abc"] = []v1alpha3.RelatedImage{
{Name: "testA", Image: "quay.io/name/sometestimage-a@sha256:f30638f60452062aba36a26ee6c036feead2f03b28f2c47f2b0a991e41baebea"},
Expand Down
265 changes: 265 additions & 0 deletions v2/pkg/api/operator-framework/v1alpha1/catalogsource_types.go
@@ -0,0 +1,265 @@
package v1alpha1

import (
"encoding/json"
"fmt"
"time"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

const (
// GroupName is the group name used in this package.
GroupName = "operators.coreos.com"
// GroupVersion is the group version used in this package.
GroupVersion = "v1alpha1"
CatalogSourceCRDAPIVersion = GroupName + "/" + GroupVersion
CatalogSourceKind = "CatalogSource"
DefaultRegistryPollDuration = 15 * time.Minute
)

// SourceType indicates the type of backing store for a CatalogSource
type SourceType string

const (
// SourceTypeInternal (deprecated) specifies a CatalogSource of type SourceTypeConfigmap
SourceTypeInternal SourceType = "internal"

// SourceTypeConfigmap specifies a CatalogSource that generates a configmap-server registry
SourceTypeConfigmap SourceType = "configmap"

// SourceTypeGrpc specifies a CatalogSource that can use an operator registry image to generate a
// registry-server or connect to a pre-existing registry at an address.
SourceTypeGrpc SourceType = "grpc"
)

type CatalogSourceSpec struct {
// SourceType is the type of source
SourceType SourceType `json:"sourceType"`

// Priority field assigns a weight to the catalog source to prioritize them so that it can be consumed by the dependency resolver.
// Usage:
// Higher weight indicates that this catalog source is preferred over lower weighted catalog sources during dependency resolution.
// The range of the priority value can go from positive to negative in the range of int32.
// The default value to a catalog source with unassigned priority would be 0.
// The catalog source with the same priority values will be ranked lexicographically based on its name.
// +optional
Priority int `json:"priority,omitempty"`

// ConfigMap is the name of the ConfigMap to be used to back a configmap-server registry.
// Only used when SourceType = SourceTypeConfigmap or SourceTypeInternal.
// +optional
ConfigMap string `json:"configMap,omitempty"`

// Address is a host that OLM can use to connect to a pre-existing registry.
// Format: <registry-host or ip>:<port>
// Only used when SourceType = SourceTypeGrpc.
// Ignored when the Image field is set.
// +optional
Address string `json:"address,omitempty"`

// Image is an operator-registry container image to instantiate a registry-server with.
// Only used when SourceType = SourceTypeGrpc.
// If present, the address field is ignored.
// +optional
Image string `json:"image,omitempty"`

// GrpcPodConfig exposes different overrides for the pod spec of the CatalogSource Pod.
// Only used when SourceType = SourceTypeGrpc and Image is set.
// +optional
GrpcPodConfig *GrpcPodConfig `json:"grpcPodConfig,omitempty"`

// UpdateStrategy defines how updated catalog source images can be discovered
// Consists of an interval that defines polling duration and an embedded strategy type
// +optional
UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`

// Secrets represent set of secrets that can be used to access the contents of the catalog.
// It is best to keep this list small, since each will need to be tried for every catalog entry.
// +optional
Secrets []string `json:"secrets,omitempty"`

// Metadata
DisplayName string `json:"displayName,omitempty"`
Description string `json:"description,omitempty"`
Publisher string `json:"publisher,omitempty"`
Icon Icon `json:"icon,omitempty"`
}

type Icon struct{}
type SecurityConfig string

const (
Legacy SecurityConfig = "legacy"
Restricted SecurityConfig = "restricted"
)

// GrpcPodConfig contains configuration specified for a catalog source
type GrpcPodConfig struct {
// NodeSelector is a selector which must be true for the pod to fit on a node.
// Selector which must match a node's labels for the pod to be scheduled on that node.
// +optional
NodeSelector map[string]string `json:"nodeSelector,omitempty"`

// Tolerations are the catalog source's pod's tolerations.
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`

// Affinity is the catalog source's pod's affinity.
// +optional
Affinity *corev1.Affinity `json:"affinity,omitempty"`

// If specified, indicates the pod's priority.
// If not specified, the pod priority will be default or zero if there is no
// default.
// +optional
PriorityClassName *string `json:"priorityClassName,omitempty"`

// SecurityContextConfig can be one of `legacy` or `restricted`. The CatalogSource's pod is either injected with the
// right pod.spec.securityContext and pod.spec.container[*].securityContext values to allow the pod to run in Pod
// Security Admission (PSA) `restricted` mode, or doesn't set these values at all, in which case the pod can only be
// run in PSA `baseline` or `privileged` namespaces. Currently if the SecurityContextConfig is unspecified, the default
// value of `legacy` is used. Specifying a value other than `legacy` or `restricted` result in a validation error.
// When using older catalog images, which could not be run in `restricted` mode, the SecurityContextConfig should be
// set to `legacy`.
//
// In a future version will the default will be set to `restricted`, catalog maintainers should rebuild their catalogs
// with a version of opm that supports running catalogSource pods in `restricted` mode to prepare for these changes.
//
// More information about PSA can be found here: https://kubernetes.io/docs/concepts/security/pod-security-admission/'
// +optional
// +kubebuilder:validation:Enum=legacy;restricted
// +kubebuilder:default:=legacy
SecurityContextConfig SecurityConfig `json:"securityContextConfig,omitempty"`

// MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server,
// which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod
// will have the following modifications made to the container running the server:
// - the $GOMEMLIMIT environment variable will be set to this value in bytes
// - the memory request will be set to this value
//
// This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if
// a catalog being served is very large and needs more than the default allocation. If your index image has a file-
// system cache, determine a good approximation for this value by doubling the size of the package cache at
// /tmp/cache/cache/packages.json in the index image.
//
// This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set.
// +optional
MemoryTarget *resource.Quantity `json:"memoryTarget,omitempty"`

// ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and
// use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is
// configured to use *must* be using the file-based catalogs in order to utilize this feature.
// +optional
ExtractContent *ExtractContentConfig `json:"extractContent,omitempty"`
}

// ExtractContentConfig configures context extraction from a file-based catalog index image.
type ExtractContentConfig struct {
// CacheDir is the directory storing the pre-calculated API cache.
CacheDir string `json:"cacheDir"`
// CatalogDir is the directory storing the file-based catalog contents.
CatalogDir string `json:"catalogDir"`
}

// UpdateStrategy holds all the different types of catalog source update strategies
// Currently only registry polling strategy is implemented
type UpdateStrategy struct {
*RegistryPoll `json:"registryPoll,omitempty"`
}

type RegistryPoll struct {
// Interval is used to determine the time interval between checks of the latest catalog source version.
// The catalog operator polls to see if a new version of the catalog source is available.
// If available, the latest image is pulled and gRPC traffic is directed to the latest catalog source.
RawInterval string `json:"interval,omitempty"`
Interval *metav1.Duration `json:"-"`
ParsingError string `json:"-"`
}

// UnmarshalJSON implements the encoding/json.Unmarshaler interface.
func (u *UpdateStrategy) UnmarshalJSON(data []byte) (err error) {
type alias struct {
*RegistryPoll `json:"registryPoll,omitempty"`
}
us := alias{}
if err = json.Unmarshal(data, &us); err != nil {
return err
}
registryPoll := &RegistryPoll{
RawInterval: us.RegistryPoll.RawInterval,
}
duration, err := time.ParseDuration(registryPoll.RawInterval)
if err != nil {
registryPoll.ParsingError = fmt.Sprintf("error parsing spec.updateStrategy.registryPoll.interval. Using the default value of %s instead. Error: %s", DefaultRegistryPollDuration, err)
registryPoll.Interval = &metav1.Duration{Duration: DefaultRegistryPollDuration}
} else {
registryPoll.Interval = &metav1.Duration{Duration: duration}
}
u.RegistryPoll = registryPoll
return nil
}

type RegistryServiceStatus struct {
Protocol string `json:"protocol,omitempty"`
ServiceName string `json:"serviceName,omitempty"`
ServiceNamespace string `json:"serviceNamespace,omitempty"`
Port string `json:"port,omitempty"`
CreatedAt metav1.Time `json:"createdAt,omitempty"`
}

func (s *RegistryServiceStatus) Address() string {
return fmt.Sprintf("%s.%s.svc:%s", s.ServiceName, s.ServiceNamespace, s.Port)
}

type GRPCConnectionState struct {
Address string `json:"address,omitempty"`
LastObservedState string `json:"lastObservedState"`
LastConnectTime metav1.Time `json:"lastConnect,omitempty"`
}

type CatalogSourceStatus struct{}

type ConfigMapResourceReference struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
UID types.UID `json:"uid,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
}

func (r *ConfigMapResourceReference) IsAMatch(object *metav1.ObjectMeta) bool {
return r.UID == object.GetUID() && r.ResourceVersion == object.GetResourceVersion()
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +genclient
// +kubebuilder:resource:shortName=catsrc,categories=olm
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Display",type=string,JSONPath=`.spec.displayName`,description="The pretty name of the catalog"
// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.sourceType`,description="The type of the catalog"
// +kubebuilder:printcolumn:name="Publisher",type=string,JSONPath=`.spec.publisher`,description="The publisher of the catalog"
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`

// CatalogSource is a repository of CSVs, CRDs, and operator packages.
type CatalogSource struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`

Spec CatalogSourceSpec `json:"spec"`
// +optional
Status CatalogSourceStatus `json:"status"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// CatalogSourceList is a repository of CSVs, CRDs, and operator packages.
type CatalogSourceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`

Items []CatalogSource `json:"items"`
}

0 comments on commit c59c984

Please sign in to comment.