Skip to content

Commit

Permalink
Implement API changes according to RFC spec
Browse files Browse the repository at this point in the history
resolves #1088

Summary:
* v1 API now uses a `SourceConfig` discriminated union which will allow
  modularity for future install sources (bundles, charts, etc).
* `SourceConfig` uses CEL validation to ensure only valid field names &
  values are utilized (`sourceType: Catalog` ensures that the `catalog`
field is also set in `SourceConfig`).
* Added new `clusterextension_admission` unit test for `SourceConfig`
  objects. The test covers both valid and invalid cases.
* Fixed `clusterextension_controller` test where an unset
  `ClusterExtension` spec caused a null pointer deref.
* Moved `ClusterSelector` from `ClusterExtension.Spec` to `ClusterExtension.Source.Catalog`
  and renamed to `Selector`.
* Updated GoDocs to reflect the new API spec and included post-review changes
* Fixed all definitions of `kind: ClusterExtension` in docs and scripts
  to reflect the API changes.

Signed-off-by: Josh Manning <[email protected]>
  • Loading branch information
jsm84 committed Aug 29, 2024
1 parent bf7f766 commit 8e55961
Show file tree
Hide file tree
Showing 16 changed files with 796 additions and 403 deletions.
143 changes: 93 additions & 50 deletions api/v1alpha1/clusterextension_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,97 @@ const (

// ClusterExtensionSpec defines the desired state of ClusterExtension
type ClusterExtensionSpec struct {
// source is a required field which selects the installation source of content
// for this ClusterExtension. Selection is performed by setting the sourceType.
//
// Catalog is currently the only implemented sourceType, and setting the
// sourcetype to "Catalog" requires the catalog field to also be defined.
//
// Below is a minimal example of a source definition (in yaml):
//
// source:
// sourceType: Catalog
// catalog:
// packageName: example-package
//
Source SourceConfig `json:"source"`

// installNamespace is a reference to the Namespace in which the bundle of
// content for the package referenced in the packageName field will be applied.
// The bundle may contain cluster-scoped resources or resources that are
// applied to other Namespaces. This Namespace is expected to exist.
//
// installNamespace is required, immutable, and follows the DNS label standard
// as defined in RFC 1123. This means that valid values:
// - Contain no more than 63 characters
// - Contain only lowercase alphanumeric characters or '-'
// - Start with an alphanumeric character
// - End with an alphanumeric character
//
// Some examples of valid values are:
// - some-namespace
// - 123-namespace
// - 1-namespace-2
// - somenamespace
//
// Some examples of invalid values are:
// - -some-namespace
// - some-namespace-
// - thisisareallylongnamespacenamethatisgreaterthanthemaximumlength
// - some.namespace
//
//+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
//+kubebuilder:validation:MaxLength:=63
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="installNamespace is immutable"
InstallNamespace string `json:"installNamespace"`

// preflight is an optional field that can be used to configure the preflight checks run before installation or upgrade of the content for the package specified in the packageName field.
//
// When specified, it overrides the default configuration of the preflight checks that are required to execute successfully during an install/upgrade operation.
//
// When not specified, the default configuration for each preflight check will be used.
//
//+optional
Preflight *PreflightConfig `json:"preflight,omitempty"`

// serviceAccount is a required reference to a ServiceAccount that exists
// in the installNamespace. The provided ServiceAccount is used to install and
// manage the content for the package specified in the packageName field.
//
// In order to successfully install and manage the content for the package,
// the ServiceAccount provided via this field should be configured with the
// appropriate permissions to perform the necessary operations on all the
// resources that are included in the bundle of content being applied.
ServiceAccount ServiceAccountReference `json:"serviceAccount"`
}

const SourceTypeCatalog = "Catalog"

// SourceConfig is a discriminated union which selects the installation source.
// +union
// +kubebuilder:validation:XValidation:rule="self.sourceType == 'Catalog' && has(self.catalog)",message="sourceType Catalog requires catalog field"
type SourceConfig struct {
// sourceType is a required reference to the type of install source.
//
// Allowed values are ["Catalog"]
//
// When this field is set to "Catalog", information for determining the appropriate
// bundle of content to install will be fetched from ClusterCatalog resources existing
// on the cluster. When using the Catalog sourceType, the catalog field must also be set.
//
// +unionDiscriminator
// +kubebuilder:validation:Enum:="Catalog"
SourceType string `json:"sourceType"`

// catalog is used to configure how information is sourced from a catalog. This field must be defined when sourceType is set to "Catalog",
// and must be the only field defined for this sourceType.
//
// +optional.
Catalog *CatalogSource `json:"catalog,omitempty"`
}

// CatalogSource defines the required fields for catalog source.
type CatalogSource struct {
// packageName is a reference to the name of the package to be installed
// and is used to filter the content from catalogs.
//
Expand Down Expand Up @@ -196,15 +287,15 @@ type ClusterExtensionSpec struct {
//+optional
Channel string `json:"channel,omitempty"`

// catalogSelector is an optional field that can be used
// selector is an optional field that can be used
// to filter the set of ClusterCatalogs used in the bundle
// selection process.
//
// When unspecified, all ClusterCatalogs will be used in
// the bundle selection process.
//
//+optional
CatalogSelector metav1.LabelSelector `json:"catalogSelector,omitempty"`
Selector metav1.LabelSelector `json:"selector,omitempty"`

// upgradeConstraintPolicy is an optional field that controls whether
// the upgrade path(s) defined in the catalog are enforced for the package
Expand All @@ -228,54 +319,6 @@ type ClusterExtensionSpec struct {
//+kubebuilder:default:=Enforce
//+optional
UpgradeConstraintPolicy UpgradeConstraintPolicy `json:"upgradeConstraintPolicy,omitempty"`

// installNamespace is a reference to the Namespace in which the bundle of
// content for the package referenced in the packageName field will be applied.
// The bundle may contain cluster-scoped resources or resources that are
// applied to other Namespaces. This Namespace is expected to exist.
//
// installNamespace is required, immutable, and follows the DNS label standard
// as defined in RFC 1123. This means that valid values:
// - Contain no more than 63 characters
// - Contain only lowercase alphanumeric characters or '-'
// - Start with an alphanumeric character
// - End with an alphanumeric character
//
// Some examples of valid values are:
// - some-namespace
// - 123-namespace
// - 1-namespace-2
// - somenamespace
//
// Some examples of invalid values are:
// - -some-namespace
// - some-namespace-
// - thisisareallylongnamespacenamethatisgreaterthanthemaximumlength
// - some.namespace
//
//+kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
//+kubebuilder:validation:MaxLength:=63
//+kubebuilder:validation:XValidation:rule="self == oldSelf",message="installNamespace is immutable"
InstallNamespace string `json:"installNamespace"`

// preflight is an optional field that can be used to configure the preflight checks run before installation or upgrade of the content for the package specified in the packageName field.
//
// When specified, it overrides the default configuration of the preflight checks that are required to execute successfully during an install/upgrade operation.
//
// When not specified, the default configuration for each preflight check will be used.
//
//+optional
Preflight *PreflightConfig `json:"preflight,omitempty"`

// serviceAccount is a required reference to a ServiceAccount that exists
// in the installNamespace. The provided ServiceAccount is used to install and
// manage the content for the package specified in the packageName field.
//
// In order to successfully install and manage the content for the package,
// the ServiceAccount provided via this field should be configured with the
// appropriate permissions to perform the necessary operations on all the
// resources that are included in the bundle of content being applied.
ServiceAccount ServiceAccountReference `json:"serviceAccount"`
}

// ServiceAccountReference references a serviceAccount.
Expand Down
38 changes: 37 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8e55961

Please sign in to comment.