Skip to content

Commit a5c894b

Browse files
committed
✨ Plumb the Extension API
Copies ClustersExtension functionality `ServiceAccountName` doesn't do anything yet. Signed-off-by: Todd Short <[email protected]>
1 parent 5b8f9d2 commit a5c894b

15 files changed

+668
-153
lines changed

api/v1alpha1/clusterextension_types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha1
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/types"
2122

2223
"github.com/operator-framework/operator-controller/internal/conditionsets"
2324
)
@@ -158,3 +159,21 @@ type ClusterExtensionList struct {
158159
func init() {
159160
SchemeBuilder.Register(&ClusterExtension{}, &ClusterExtensionList{})
160161
}
162+
163+
func (r *ClusterExtension) GetPackageSpec() *ExtensionSourcePackage {
164+
p := &ExtensionSourcePackage{}
165+
166+
p.Channel = r.Spec.Channel
167+
p.Name = r.Spec.PackageName
168+
p.Version = r.Spec.Version
169+
170+
return p
171+
}
172+
173+
func (r *ClusterExtension) GetUID() types.UID {
174+
return r.ObjectMeta.GetUID()
175+
}
176+
177+
func (r *ClusterExtension) GetUpgradeConstraintPolicy() UpgradeConstraintPolicy {
178+
return r.Spec.UpgradeConstraintPolicy
179+
}

api/v1alpha1/extension_types.go

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,22 @@ package v1alpha1
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/types"
2122
)
2223

2324
type ExtensionManagedState string
2425

2526
const (
26-
// Pause resolution of this Extension
27+
// Peform reconcilliation of this Extension
2728
ManagedStateActive ExtensionManagedState = "Active"
28-
// Peform resolution of this Extension
29+
// Pause reconcilliation of this Extension
2930
ManagedStatePaused ExtensionManagedState = "Paused"
3031
)
3132

3233
type ExtensionSourcePackage struct {
3334
//+kubebuilder:validation:MaxLength:=48
3435
//+kubebuilder:validation:Pattern:=^[a-z0-9]+(-[a-z0-9]+)*$
36+
// name specifies the name of the name of the package
3537
Name string `json:"name"`
3638

3739
//+kubebuilder:validation:MaxLength:=64
@@ -42,22 +44,26 @@ type ExtensionSourcePackage struct {
4244
// Examples: 1.2.3, 1.0.0-alpha, 1.0.0-rc.1
4345
//
4446
// For more information on semver, please see https://semver.org/
47+
// version constraint definition
4548
Version string `json:"version,omitempty"`
4649

4750
//+kubebuilder:validation:MaxLength:=48
4851
//+kubebuilder:validation:Pattern:=^[a-z0-9]+([\.-][a-z0-9]+)*$
49-
// Channel constraint definition
52+
// channel constraint definition
5053
Channel string `json:"channel,omitempty"`
51-
}
5254

53-
// TODO: Implement ExtensionSourceDirect containing a URL or other reference mechanism
55+
//+kubebuilder:validation:Enum:=Enforce;Ignore
56+
//+kubebuilder:default:=Enforce
57+
//+kubebuilder:Optional
58+
//
59+
// upgradeConstraintPolicy Defines the policy for how to handle upgrade constraints
60+
UpgradeConstraintPolicy UpgradeConstraintPolicy `json:"upgradeConstraintPolicy,omitempty"`
61+
}
5462

63+
// ExtensionSource defines the source for this Extension, right now, only a package is supported.
5564
type ExtensionSource struct {
5665
// A source package defined by a name, version and/or channel
5766
Package *ExtensionSourcePackage `json:"package,omitempty"`
58-
59-
// A direct package defined by a URL
60-
// TODO: Direct *ExtensionSourceDirect `json:"direct,omitempty"`
6167
}
6268

6369
// ExtensionSpec defines the desired state of Extension
@@ -66,31 +72,17 @@ type ExtensionSpec struct {
6672
//+kubebuilder:default:=Active
6773
//+kubebuilder:Optional
6874
//
69-
// Pause reconciliation on this Extension
75+
// managed controls the management state of the extension. "Active" means this extension will be reconciled and "Paused" means this extension will be ignored.
7076
Managed ExtensionManagedState `json:"managed,omitempty"`
7177

72-
//+kubebuilder:validation:MaxLength:=64
78+
//+kubebuilder:validation:MaxLength:=253
7379
//+kubebuilder:validation:Pattern:=^[a-z0-9]+([\.-][a-z0-9]+)*$
7480
//
75-
// ServiceAccount name used to install this extension
81+
// serviceAccountName is the name of a service account in the Extension's namespace that will be used to manage the installation and lifecycle of the extension.
7682
ServiceAccountName string `json:"serviceAccountName"`
7783

78-
//+kubebuilder:validation:MaxLength:=64
79-
//+kubebuilder:validation:Pattern:=^[a-z0-9]+([\.-][a-z0-9]+)*$
80-
//+kubebuilder:Optional
81-
//
82-
// Location of installation TBD??
83-
DefaultNamespace string `json:"defaultNamespace,omitempty"`
84-
85-
// Source of Extension to be installed
84+
// source of Extension to be installed
8685
Source ExtensionSource `json:"source"`
87-
88-
//+kubebuilder:validation:Enum:=Enforce;Ignore
89-
//+kubebuilder:default:=Enforce
90-
//+kubebuilder:Optional
91-
//
92-
// Defines the policy for how to handle upgrade constraints
93-
UpgradeConstraintPolicy UpgradeConstraintPolicy `json:"upgradeConstraintPolicy,omitempty"`
9486
}
9587

9688
// ExtensionStatus defines the observed state of Extension
@@ -109,6 +101,7 @@ type ExtensionStatus struct {
109101

110102
//+kubebuilder:object:root=true
111103
//+kubebuilder:subresource:status
104+
//+kubebuilder:printcolumn:name="Managed",type=string,JSONPath=`.spec.managed`,description="The current reconciliation state of this extension"
112105

113106
// Extension is the Schema for the extensions API
114107
type Extension struct {
@@ -131,3 +124,18 @@ type ExtensionList struct {
131124
func init() {
132125
SchemeBuilder.Register(&Extension{}, &ExtensionList{})
133126
}
127+
128+
func (r *Extension) GetPackageSpec() *ExtensionSourcePackage {
129+
return r.Spec.Source.Package.DeepCopy()
130+
}
131+
132+
func (r *Extension) GetUID() types.UID {
133+
return r.ObjectMeta.GetUID()
134+
}
135+
136+
func (r *Extension) GetUpgradeConstraintPolicy() UpgradeConstraintPolicy {
137+
if r.Spec.Source.Package != nil {
138+
return r.Spec.Source.Package.UpgradeConstraintPolicy
139+
}
140+
return ""
141+
}

cmd/manager/main.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,16 @@ func main() {
123123
setupLog.Error(err, "unable to create controller", "controller", "ClusterExtension")
124124
os.Exit(1)
125125
}
126-
if err = (&controllers.ExtensionReconciler{
127-
Client: cl,
128-
Scheme: mgr.GetScheme(),
129-
}).SetupWithManager(mgr); err != nil {
130-
setupLog.Error(err, "unable to create controller", "controller", "Extension")
131-
os.Exit(1)
126+
if features.OperatorControllerFeatureGate.Enabled(features.EnableExtensionApi) {
127+
if err = (&controllers.ExtensionReconciler{
128+
Client: cl,
129+
BundleProvider: catalogClient,
130+
Scheme: mgr.GetScheme(),
131+
Resolver: resolver,
132+
}).SetupWithManager(mgr); err != nil {
133+
setupLog.Error(err, "unable to create controller", "controller", "Extension")
134+
os.Exit(1)
135+
}
132136
}
133137
//+kubebuilder:scaffold:builder
134138

config/crd/bases/olm.operatorframework.io_extensions.yaml

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ spec:
1414
singular: extension
1515
scope: Namespaced
1616
versions:
17-
- name: v1alpha1
17+
- additionalPrinterColumns:
18+
- description: The current reconciliation state of this extension
19+
jsonPath: .spec.managed
20+
name: Managed
21+
type: string
22+
name: v1alpha1
1823
schema:
1924
openAPIV3Schema:
2025
description: Extension is the Schema for the extensions API
@@ -34,61 +39,63 @@ spec:
3439
spec:
3540
description: ExtensionSpec defines the desired state of Extension
3641
properties:
37-
defaultNamespace:
38-
description: Location of installation TBD??
39-
maxLength: 64
40-
pattern: ^[a-z0-9]+([\.-][a-z0-9]+)*$
41-
type: string
4242
managed:
4343
default: Active
44-
description: Pause reconciliation on this Extension
44+
description: managed controls the management state of the extension.
45+
"Active" means this extension will be reconciled and "Paused" means
46+
this extension will be ignored.
4547
enum:
4648
- Active
4749
- Paused
4850
type: string
4951
serviceAccountName:
50-
description: ServiceAccount name used to install this extension
51-
maxLength: 64
52+
description: serviceAccountName is the name of a service account in
53+
the Extension's namespace that will be used to manage the installation
54+
and lifecycle of the extension.
55+
maxLength: 253
5256
pattern: ^[a-z0-9]+([\.-][a-z0-9]+)*$
5357
type: string
5458
source:
55-
description: Source of Extension to be installed
59+
description: source of Extension to be installed
5660
properties:
5761
package:
5862
description: A source package defined by a name, version and/or
5963
channel
6064
properties:
6165
channel:
62-
description: Channel constraint definition
66+
description: channel constraint definition
6367
maxLength: 48
6468
pattern: ^[a-z0-9]+([\.-][a-z0-9]+)*$
6569
type: string
6670
name:
71+
description: name specifies the name of the name of the package
6772
maxLength: 48
6873
pattern: ^[a-z0-9]+(-[a-z0-9]+)*$
6974
type: string
75+
upgradeConstraintPolicy:
76+
default: Enforce
77+
description: upgradeConstraintPolicy Defines the policy for
78+
how to handle upgrade constraints
79+
enum:
80+
- Enforce
81+
- Ignore
82+
type: string
7083
version:
7184
description: "Version is an optional semver constraint on
7285
the package version. If not specified, the latest version
7386
available of the package will be installed. If specified,
7487
the specific version of the package will be installed so
7588
long as it is available in any of the content sources available.
7689
Examples: 1.2.3, 1.0.0-alpha, 1.0.0-rc.1 \n For more information
77-
on semver, please see https://semver.org/"
90+
on semver, please see https://semver.org/ version constraint
91+
definition"
7892
maxLength: 64
7993
pattern: ^(\s*(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|[x|X|\*])(\.(0|[1-9]\d*|x|X|\*]))?(\.(0|[1-9]\d*|x|X|\*))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)((?:\s+|,\s*|\s*\|\|\s*)(=||!=|>|<|>=|=>|<=|=<|~|~>|\^)\s*(v?(0|[1-9]\d*|x|X|\*])(\.(0|[1-9]\d*|x|X|\*))?(\.(0|[1-9]\d*|x|X|\*]))?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)\s*)*$
8094
type: string
8195
required:
8296
- name
8397
type: object
8498
type: object
85-
upgradeConstraintPolicy:
86-
default: Enforce
87-
description: Defines the policy for how to handle upgrade constraints
88-
enum:
89-
- Enforce
90-
- Ignore
91-
type: string
9299
required:
93100
- serviceAccountName
94101
- source

config/crd/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# It should be run by config/default
44
resources:
55
- bases/olm.operatorframework.io_clusterextensions.yaml
6+
- bases/olm.operatorframework.io_extensions.yaml
67

78
# the following config is for teaching kustomize how to do kustomization for CRDs.
89
configurations:

internal/controllers/clusterextension_controller.go

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@ import (
4747
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
4848
)
4949

50-
// BundleProvider provides the way to retrieve a list of Bundles from a source,
51-
// generally from a catalog client of some kind.
52-
type BundleProvider interface {
53-
Bundles(ctx context.Context) ([]*catalogmetadata.Bundle, error)
54-
}
55-
5650
// ClusterExtensionReconciler reconciles a ClusterExtension object
5751
type ClusterExtensionReconciler struct {
5852
client.Client
@@ -492,91 +486,6 @@ func mapBundleMediaTypeToBundleProvisioner(mediaType string) (string, error) {
492486
}
493487
}
494488

495-
// setResolvedStatusConditionSuccess sets the resolved status condition to success.
496-
func setResolvedStatusConditionSuccess(conditions *[]metav1.Condition, message string, generation int64) {
497-
apimeta.SetStatusCondition(conditions, metav1.Condition{
498-
Type: ocv1alpha1.TypeResolved,
499-
Status: metav1.ConditionTrue,
500-
Reason: ocv1alpha1.ReasonSuccess,
501-
Message: message,
502-
ObservedGeneration: generation,
503-
})
504-
}
505-
506-
// setResolvedStatusConditionFailed sets the resolved status condition to failed.
507-
func setResolvedStatusConditionFailed(conditions *[]metav1.Condition, message string, generation int64) {
508-
apimeta.SetStatusCondition(conditions, metav1.Condition{
509-
Type: ocv1alpha1.TypeResolved,
510-
Status: metav1.ConditionFalse,
511-
Reason: ocv1alpha1.ReasonResolutionFailed,
512-
Message: message,
513-
ObservedGeneration: generation,
514-
})
515-
}
516-
517-
// setResolvedStatusConditionUnknown sets the resolved status condition to unknown.
518-
func setResolvedStatusConditionUnknown(conditions *[]metav1.Condition, message string, generation int64) {
519-
apimeta.SetStatusCondition(conditions, metav1.Condition{
520-
Type: ocv1alpha1.TypeResolved,
521-
Status: metav1.ConditionUnknown,
522-
Reason: ocv1alpha1.ReasonResolutionUnknown,
523-
Message: message,
524-
ObservedGeneration: generation,
525-
})
526-
}
527-
528-
// setInstalledStatusConditionSuccess sets the installed status condition to success.
529-
func setInstalledStatusConditionSuccess(conditions *[]metav1.Condition, message string, generation int64) {
530-
apimeta.SetStatusCondition(conditions, metav1.Condition{
531-
Type: ocv1alpha1.TypeInstalled,
532-
Status: metav1.ConditionTrue,
533-
Reason: ocv1alpha1.ReasonSuccess,
534-
Message: message,
535-
ObservedGeneration: generation,
536-
})
537-
}
538-
539-
// setInstalledStatusConditionFailed sets the installed status condition to failed.
540-
func setInstalledStatusConditionFailed(conditions *[]metav1.Condition, message string, generation int64) {
541-
apimeta.SetStatusCondition(conditions, metav1.Condition{
542-
Type: ocv1alpha1.TypeInstalled,
543-
Status: metav1.ConditionFalse,
544-
Reason: ocv1alpha1.ReasonInstallationFailed,
545-
Message: message,
546-
ObservedGeneration: generation,
547-
})
548-
}
549-
550-
// setInstalledStatusConditionUnknown sets the installed status condition to unknown.
551-
func setInstalledStatusConditionUnknown(conditions *[]metav1.Condition, message string, generation int64) {
552-
apimeta.SetStatusCondition(conditions, metav1.Condition{
553-
Type: ocv1alpha1.TypeInstalled,
554-
Status: metav1.ConditionUnknown,
555-
Reason: ocv1alpha1.ReasonInstallationStatusUnknown,
556-
Message: message,
557-
ObservedGeneration: generation,
558-
})
559-
}
560-
561-
func setDeprecationStatusesUnknown(conditions *[]metav1.Condition, message string, generation int64) {
562-
conditionTypes := []string{
563-
ocv1alpha1.TypeDeprecated,
564-
ocv1alpha1.TypePackageDeprecated,
565-
ocv1alpha1.TypeChannelDeprecated,
566-
ocv1alpha1.TypeBundleDeprecated,
567-
}
568-
569-
for _, conditionType := range conditionTypes {
570-
apimeta.SetStatusCondition(conditions, metav1.Condition{
571-
Type: conditionType,
572-
Reason: ocv1alpha1.ReasonDeprecated,
573-
Status: metav1.ConditionUnknown,
574-
Message: message,
575-
ObservedGeneration: generation,
576-
})
577-
}
578-
}
579-
580489
// Generate reconcile requests for all cluster extensions affected by a catalog change
581490
func clusterExtensionRequestsForCatalog(c client.Reader, logger logr.Logger) handler.MapFunc {
582491
return func(ctx context.Context, _ client.Object) []reconcile.Request {

0 commit comments

Comments
 (0)