From 730aa213a40aae5d612d38d7892556f57b70b8cf Mon Sep 17 00:00:00 2001 From: Chuan-Yen Chiang Date: Sun, 19 Oct 2025 10:16:12 +0200 Subject: [PATCH 1/3] Migrate provider template to namespaced resources with safe-start support This commit migrates the provider template from cluster-scoped to namespaced managed resources, aligning with Crossplane v2.0 best practices for improved multi-tenancy and resource isolation. It also implements safe-start support to prevent controller race conditions during startup. Key changes: API Updates: - Consolidate ProviderConfig and related types into unified types.go - Add namespaced ProviderConfig alongside cluster-scoped ClusterProviderConfig - Add namespaced ProviderConfigUsage and ClusterProviderConfigUsage - Update MyType to use namespaced scope by default - Remove deprecated StoreConfig (external secret stores no longer supported in v2) - Migrate to crossplane-runtime v2.0.0-rc.1 with breaking changes Controller Enhancements: - Implement safe-start pattern with SetupGated functions - Add gate-based controller registration to wait for CRDs - Add customresourcesgate controller to watch for CRD availability - Update credential extraction to support both namespaced and cluster-scoped configs - Support dynamic ProviderConfig reference kind switching - Remove deprecated feature flag system in favor of runtime feature package Dependencies: - Upgrade to crossplane-runtime v2.0.0-rc.1 - Add k8s.io/apiextensions-apiserver for CRD scheme registration - Update controller-runtime to v0.21.0 - Update Go toolchain to 1.24.5 Templates and Examples: - Update code generation templates for namespaced resources - Add namespace field to example manifests - Update ProviderConfig examples to demonstrate new structure - Remove StoreConfig examples This migration provides better resource isolation, simplified authentication patterns, and improved startup reliability through the safe-start mechanism. Signed-off-by: $(git config user.name) <$(git config user.email)> Signed-off-by: Chuan-Yen Chiang --- apis/generate.go | 8 - apis/sample/v1alpha1/mytype_types.go | 9 +- apis/sample/v1alpha1/zz_generated.deepcopy.go | 2 +- apis/sample/v1alpha1/zz_generated.managed.go | 30 +-- .../v1alpha1/zz_generated.managedlist.go | 2 +- apis/v1alpha1/doc.go | 4 + apis/v1alpha1/groupversion_info.go | 40 ---- apis/v1alpha1/providerconfig_types.go | 82 ------- apis/v1alpha1/providerconfigusage_types.go | 67 ------ apis/v1alpha1/register.go | 61 +++++ apis/v1alpha1/storeconfig_types.go | 90 ------- apis/v1alpha1/types.go | 125 ++++++++++ apis/v1alpha1/zz_generated.deepcopy.go | 170 +++++++------ apis/v1alpha1/zz_generated.pc.go | 22 +- apis/v1alpha1/zz_generated.pcu.go | 26 +- apis/v1alpha1/zz_generated.pculist.go | 11 +- cmd/provider/main.go | 64 ++--- examples/provider/config.yaml | 21 +- examples/sample/mytype.yaml | 16 +- examples/storeconfig/vault.yaml | 19 -- go.mod | 98 ++++---- go.sum | 214 +++++++++-------- .../APIVERSION/KIND_LOWER_types.go.tmpl | 10 +- .../controller/KIND_LOWER/KIND_LOWER.go.tmpl | 78 +++--- .../KIND_LOWER/KIND_LOWER_test.go.tmpl | 6 +- internal/controller/config/config.go | 38 ++- internal/controller/mytype/mytype.go | 109 +++++++-- internal/controller/mytype/mytype_test.go | 6 +- internal/controller/template.go | 16 +- internal/features/features.go | 32 --- ...sample.template.crossplane.io_mytypes.yaml | 137 +---------- ....crossplane.io_clusterproviderconfigs.yaml | 172 ++++++++++++++ ...splane.io_clusterproviderconfigusages.yaml | 97 ++++++++ ...emplate.crossplane.io_providerconfigs.yaml | 14 +- ...te.crossplane.io_providerconfigusages.yaml | 33 +-- .../template.crossplane.io_storeconfigs.yaml | 223 ------------------ 36 files changed, 1055 insertions(+), 1097 deletions(-) delete mode 100644 apis/v1alpha1/groupversion_info.go delete mode 100644 apis/v1alpha1/providerconfig_types.go delete mode 100644 apis/v1alpha1/providerconfigusage_types.go create mode 100644 apis/v1alpha1/register.go delete mode 100644 apis/v1alpha1/storeconfig_types.go create mode 100644 apis/v1alpha1/types.go delete mode 100644 examples/storeconfig/vault.yaml delete mode 100644 internal/features/features.go create mode 100644 package/crds/template.crossplane.io_clusterproviderconfigs.yaml create mode 100644 package/crds/template.crossplane.io_clusterproviderconfigusages.yaml delete mode 100644 package/crds/template.crossplane.io_storeconfigs.yaml diff --git a/apis/generate.go b/apis/generate.go index e8253a48..ce4a0f93 100644 --- a/apis/generate.go +++ b/apis/generate.go @@ -1,5 +1,3 @@ -//go:build generate - /* Copyright 2025 The Crossplane Authors. @@ -29,9 +27,3 @@ limitations under the License. //go:generate go run -tags generate github.com/crossplane/crossplane-tools/cmd/angryjet generate-methodsets --header-file=../hack/boilerplate.go.txt ./... package apis - -import ( - _ "sigs.k8s.io/controller-tools/cmd/controller-gen" //nolint:typecheck - - _ "github.com/crossplane/crossplane-tools/cmd/angryjet" //nolint:typecheck -) diff --git a/apis/sample/v1alpha1/mytype_types.go b/apis/sample/v1alpha1/mytype_types.go index 1e2da6fb..ce3ce4f9 100644 --- a/apis/sample/v1alpha1/mytype_types.go +++ b/apis/sample/v1alpha1/mytype_types.go @@ -22,7 +22,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" + xpv2 "github.com/crossplane/crossplane-runtime/v2/apis/common/v2" ) // MyTypeParameters are the configurable fields of a MyType. @@ -38,8 +39,8 @@ type MyTypeObservation struct { // A MyTypeSpec defines the desired state of a MyType. type MyTypeSpec struct { - xpv1.ResourceSpec `json:",inline"` - ForProvider MyTypeParameters `json:"forProvider"` + xpv2.ManagedResourceSpec `json:",inline"` + ForProvider MyTypeParameters `json:"forProvider"` } // A MyTypeStatus represents the observed state of a MyType. @@ -56,7 +57,7 @@ type MyTypeStatus struct { // +kubebuilder:printcolumn:name="EXTERNAL-NAME",type="string",JSONPath=".metadata.annotations.crossplane\\.io/external-name" // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Cluster,categories={crossplane,managed,template} +// +kubebuilder:resource:scope=Namespaced,categories={crossplane,managed,template} type MyType struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/apis/sample/v1alpha1/zz_generated.deepcopy.go b/apis/sample/v1alpha1/zz_generated.deepcopy.go index 0b1e5a90..e0aad00c 100644 --- a/apis/sample/v1alpha1/zz_generated.deepcopy.go +++ b/apis/sample/v1alpha1/zz_generated.deepcopy.go @@ -104,7 +104,7 @@ func (in *MyTypeParameters) DeepCopy() *MyTypeParameters { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MyTypeSpec) DeepCopyInto(out *MyTypeSpec) { *out = *in - in.ResourceSpec.DeepCopyInto(&out.ResourceSpec) + in.ManagedResourceSpec.DeepCopyInto(&out.ManagedResourceSpec) out.ForProvider = in.ForProvider } diff --git a/apis/sample/v1alpha1/zz_generated.managed.go b/apis/sample/v1alpha1/zz_generated.managed.go index 7cdfc478..922c2677 100644 --- a/apis/sample/v1alpha1/zz_generated.managed.go +++ b/apis/sample/v1alpha1/zz_generated.managed.go @@ -6,35 +6,25 @@ package v1alpha1 -import xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" +import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" // GetCondition of this MyType. func (mg *MyType) GetCondition(ct xpv1.ConditionType) xpv1.Condition { return mg.Status.GetCondition(ct) } -// GetDeletionPolicy of this MyType. -func (mg *MyType) GetDeletionPolicy() xpv1.DeletionPolicy { - return mg.Spec.DeletionPolicy -} - // GetManagementPolicies of this MyType. func (mg *MyType) GetManagementPolicies() xpv1.ManagementPolicies { return mg.Spec.ManagementPolicies } // GetProviderConfigReference of this MyType. -func (mg *MyType) GetProviderConfigReference() *xpv1.Reference { +func (mg *MyType) GetProviderConfigReference() *xpv1.ProviderConfigReference { return mg.Spec.ProviderConfigReference } -// GetPublishConnectionDetailsTo of this MyType. -func (mg *MyType) GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo { - return mg.Spec.PublishConnectionDetailsTo -} - // GetWriteConnectionSecretToReference of this MyType. -func (mg *MyType) GetWriteConnectionSecretToReference() *xpv1.SecretReference { +func (mg *MyType) GetWriteConnectionSecretToReference() *xpv1.LocalSecretReference { return mg.Spec.WriteConnectionSecretToReference } @@ -43,27 +33,17 @@ func (mg *MyType) SetConditions(c ...xpv1.Condition) { mg.Status.SetConditions(c...) } -// SetDeletionPolicy of this MyType. -func (mg *MyType) SetDeletionPolicy(r xpv1.DeletionPolicy) { - mg.Spec.DeletionPolicy = r -} - // SetManagementPolicies of this MyType. func (mg *MyType) SetManagementPolicies(r xpv1.ManagementPolicies) { mg.Spec.ManagementPolicies = r } // SetProviderConfigReference of this MyType. -func (mg *MyType) SetProviderConfigReference(r *xpv1.Reference) { +func (mg *MyType) SetProviderConfigReference(r *xpv1.ProviderConfigReference) { mg.Spec.ProviderConfigReference = r } -// SetPublishConnectionDetailsTo of this MyType. -func (mg *MyType) SetPublishConnectionDetailsTo(r *xpv1.PublishConnectionDetailsTo) { - mg.Spec.PublishConnectionDetailsTo = r -} - // SetWriteConnectionSecretToReference of this MyType. -func (mg *MyType) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) { +func (mg *MyType) SetWriteConnectionSecretToReference(r *xpv1.LocalSecretReference) { mg.Spec.WriteConnectionSecretToReference = r } diff --git a/apis/sample/v1alpha1/zz_generated.managedlist.go b/apis/sample/v1alpha1/zz_generated.managedlist.go index 39341c53..7fe7e5d8 100644 --- a/apis/sample/v1alpha1/zz_generated.managedlist.go +++ b/apis/sample/v1alpha1/zz_generated.managedlist.go @@ -6,7 +6,7 @@ package v1alpha1 -import resource "github.com/crossplane/crossplane-runtime/pkg/resource" +import resource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" // GetItems of this MyTypeList. func (l *MyTypeList) GetItems() []resource.Managed { diff --git a/apis/v1alpha1/doc.go b/apis/v1alpha1/doc.go index 39c7eca9..26313fc7 100644 --- a/apis/v1alpha1/doc.go +++ b/apis/v1alpha1/doc.go @@ -14,4 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +// Package v1alpha1 contains the core resources of the Template provider. +// +kubebuilder:object:generate=true +// +groupName=template.crossplane.io +// +versionName=v1alpha1 package v1alpha1 diff --git a/apis/v1alpha1/groupversion_info.go b/apis/v1alpha1/groupversion_info.go deleted file mode 100644 index 7a861dd6..00000000 --- a/apis/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2025 The Crossplane Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package v1alpha1 contains the core resources of the Template provider. -// +kubebuilder:object:generate=true -// +groupName=template.crossplane.io -// +versionName=v1alpha1 -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -// Package type metadata. -const ( - Group = "template.crossplane.io" - Version = "v1alpha1" -) - -var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} -) diff --git a/apis/v1alpha1/providerconfig_types.go b/apis/v1alpha1/providerconfig_types.go deleted file mode 100644 index b94bb557..00000000 --- a/apis/v1alpha1/providerconfig_types.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2025 The Crossplane Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "reflect" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" -) - -// A ProviderConfigSpec defines the desired state of a ProviderConfig. -type ProviderConfigSpec struct { - // Credentials required to authenticate to this provider. - Credentials ProviderCredentials `json:"credentials"` -} - -// ProviderCredentials required to authenticate. -type ProviderCredentials struct { - // Source of the provider credentials. - // +kubebuilder:validation:Enum=None;Secret;InjectedIdentity;Environment;Filesystem - Source xpv1.CredentialsSource `json:"source"` - - xpv1.CommonCredentialSelectors `json:",inline"` -} - -// A ProviderConfigStatus reflects the observed state of a ProviderConfig. -type ProviderConfigStatus struct { - xpv1.ProviderConfigStatus `json:",inline"` -} - -// +kubebuilder:object:root=true - -// A ProviderConfig configures a Template provider. -// +kubebuilder:subresource:status -// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" -// +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 -// +kubebuilder:resource:scope=Cluster -type ProviderConfig struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ProviderConfigSpec `json:"spec"` - Status ProviderConfigStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// ProviderConfigList contains a list of ProviderConfig. -type ProviderConfigList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []ProviderConfig `json:"items"` -} - -// ProviderConfig type metadata. -var ( - ProviderConfigKind = reflect.TypeOf(ProviderConfig{}).Name() - ProviderConfigGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigKind}.String() - ProviderConfigKindAPIVersion = ProviderConfigKind + "." + SchemeGroupVersion.String() - ProviderConfigGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigKind) -) - -func init() { - SchemeBuilder.Register(&ProviderConfig{}, &ProviderConfigList{}) -} diff --git a/apis/v1alpha1/providerconfigusage_types.go b/apis/v1alpha1/providerconfigusage_types.go deleted file mode 100644 index 7ef495c1..00000000 --- a/apis/v1alpha1/providerconfigusage_types.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 2025 The Crossplane Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "reflect" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" -) - -// +kubebuilder:object:root=true - -// A ProviderConfigUsage indicates that a resource is using a ProviderConfig. -// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" -// +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name" -// +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind" -// +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name" -// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,template} -type ProviderConfigUsage struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - xpv1.ProviderConfigUsage `json:",inline"` -} - -// +kubebuilder:object:root=true - -// ProviderConfigUsageList contains a list of ProviderConfigUsage -type ProviderConfigUsageList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []ProviderConfigUsage `json:"items"` -} - -// ProviderConfigUsage type metadata. -var ( - ProviderConfigUsageKind = reflect.TypeOf(ProviderConfigUsage{}).Name() - ProviderConfigUsageGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigUsageKind}.String() - ProviderConfigUsageKindAPIVersion = ProviderConfigUsageKind + "." + SchemeGroupVersion.String() - ProviderConfigUsageGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageKind) - - ProviderConfigUsageListKind = reflect.TypeOf(ProviderConfigUsageList{}).Name() - ProviderConfigUsageListGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigUsageListKind}.String() - ProviderConfigUsageListKindAPIVersion = ProviderConfigUsageListKind + "." + SchemeGroupVersion.String() - ProviderConfigUsageListGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageListKind) -) - -func init() { - SchemeBuilder.Register(&ProviderConfigUsage{}, &ProviderConfigUsageList{}) -} diff --git a/apis/v1alpha1/register.go b/apis/v1alpha1/register.go new file mode 100644 index 00000000..2ddab777 --- /dev/null +++ b/apis/v1alpha1/register.go @@ -0,0 +1,61 @@ +package v1alpha1 + +import ( + "reflect" + + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +// Package type metadata. +const ( + Group = "template.crossplane.io" + Version = "v1alpha1" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) + +// ProviderConfig type metadata. +var ( + ProviderConfigKind = reflect.TypeOf(ProviderConfig{}).Name() + ProviderConfigGroupKind = schema.GroupKind{Group: Group, Kind: ProviderConfigKind}.String() + ProviderConfigGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigKind) +) + +// ProviderConfigUsage type metadata. +var ( + ProviderConfigUsageKind = reflect.TypeOf(ProviderConfigUsage{}).Name() + ProviderConfigUsageGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageKind) + + ProviderConfigUsageListKind = reflect.TypeOf(ProviderConfigUsageList{}).Name() + ProviderConfigUsageListGroupVersionKind = SchemeGroupVersion.WithKind(ProviderConfigUsageListKind) +) + +// ClusterProviderConfig type metadata +var ( + ClusterProviderConfigKind = reflect.TypeOf(ClusterProviderConfig{}).Name() + ClusterProviderConfigGroupKind = schema.GroupKind{Group: Group, Kind: ClusterProviderConfigKind}.String() + ClusterProviderConfigGroupVersionKind = SchemeGroupVersion.WithKind(ClusterProviderConfigKind) +) + +// ClusterProviderConfigUsage type metadata. +var ( + ClusterProviderConfigUsageKind = reflect.TypeOf(ClusterProviderConfigUsage{}).Name() + ClusterProviderConfigUsageGroupVersionKind = SchemeGroupVersion.WithKind(ClusterProviderConfigUsageKind) + + ClusterProviderConfigUsageListKind = reflect.TypeOf(ClusterProviderConfigUsageList{}).Name() + ClusterProviderConfigUsageListGroupVersionKind = SchemeGroupVersion.WithKind(ClusterProviderConfigUsageListKind) +) + +func init() { + SchemeBuilder.Register(&ProviderConfig{}, &ProviderConfigList{}) + SchemeBuilder.Register(&ProviderConfigUsage{}, &ProviderConfigUsageList{}) + SchemeBuilder.Register(&ClusterProviderConfig{}, &ClusterProviderConfigList{}) + SchemeBuilder.Register(&ClusterProviderConfigUsage{}, &ClusterProviderConfigUsageList{}) +} diff --git a/apis/v1alpha1/storeconfig_types.go b/apis/v1alpha1/storeconfig_types.go deleted file mode 100644 index 49171462..00000000 --- a/apis/v1alpha1/storeconfig_types.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2025 The Crossplane Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - "reflect" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" -) - -// A StoreConfigSpec defines the desired state of a ProviderConfig. -type StoreConfigSpec struct { - xpv1.SecretStoreConfig `json:",inline"` -} - -// A StoreConfigStatus represents the status of a StoreConfig. -type StoreConfigStatus struct { - xpv1.ConditionedStatus `json:",inline"` -} - -// +kubebuilder:object:root=true - -// A StoreConfig configures how GCP controller should store connection details. -// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" -// +kubebuilder:printcolumn:name="TYPE",type="string",JSONPath=".spec.type" -// +kubebuilder:printcolumn:name="DEFAULT-SCOPE",type="string",JSONPath=".spec.defaultScope" -// +kubebuilder:resource:scope=Cluster,categories={crossplane,store,gcp} -// +kubebuilder:subresource:status -type StoreConfig struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec StoreConfigSpec `json:"spec"` - Status StoreConfigStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// StoreConfigList contains a list of StoreConfig -type StoreConfigList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []StoreConfig `json:"items"` -} - -// Note(turkenh): To be generated with AngryJet - -// GetStoreConfig returns SecretStoreConfig -func (in *StoreConfig) GetStoreConfig() xpv1.SecretStoreConfig { - return in.Spec.SecretStoreConfig -} - -// GetCondition of this StoreConfig. -func (in *StoreConfig) GetCondition(ct xpv1.ConditionType) xpv1.Condition { - return in.Status.GetCondition(ct) -} - -// SetConditions of this StoreConfig. -func (in *StoreConfig) SetConditions(c ...xpv1.Condition) { - in.Status.SetConditions(c...) -} - -// StoreConfig type metadata. -var ( - StoreConfigKind = reflect.TypeOf(StoreConfig{}).Name() - StoreConfigGroupKind = schema.GroupKind{Group: Group, Kind: StoreConfigKind}.String() - StoreConfigKindAPIVersion = StoreConfigKind + "." + SchemeGroupVersion.String() - StoreConfigGroupVersionKind = SchemeGroupVersion.WithKind(StoreConfigKind) -) - -func init() { - SchemeBuilder.Register(&StoreConfig{}, &StoreConfigList{}) -} diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go new file mode 100644 index 00000000..a7be6541 --- /dev/null +++ b/apis/v1alpha1/types.go @@ -0,0 +1,125 @@ +package v1alpha1 + +import ( + xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" + xpv2 "github.com/crossplane/crossplane-runtime/v2/apis/common/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// A ProviderConfigStatus defines the status of a Provider. +type ProviderConfigStatus struct { + xpv1.ProviderConfigStatus `json:",inline"` +} + +// ProviderCredentials required to authenticate. +type ProviderCredentials struct { + // Source of the provider credentials. + // +kubebuilder:validation:Enum=None;Secret;InjectedIdentity;Environment;Filesystem + Source xpv1.CredentialsSource `json:"source"` + + xpv1.CommonCredentialSelectors `json:",inline"` +} + +type ProviderConfigSpec struct { + // Credentials required to authenticate to this provider. + Credentials ProviderCredentials `json:"credentials"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:storageversion + +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 +// +kubebuilder:resource:scope=Namespaced,categories={crossplane,provider,template} +// A ProviderConfig configures a Helm 'provider', i.e. a connection to a particular +type ProviderConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ProviderConfigSpec `json:"spec"` + Status ProviderConfigStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ProviderConfigList contains a list of Provider +type ProviderConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ProviderConfig `json:"items"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:storageversion + +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name" +// +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind" +// +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name" +// +kubebuilder:resource:scope=Namespaced,categories={crossplane,provider,template} +// A ProviderConfigUsage indicates that a resource is using a ProviderConfig. +type ProviderConfigUsage struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + xpv2.TypedProviderConfigUsage `json:",inline"` +} + +// +kubebuilder:object:root=true + +// ProviderConfigUsageList contains a list of ProviderConfigUsage +type ProviderConfigUsageList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ProviderConfigUsage `json:"items"` +} + +// +kubebuilder:object:root=true + +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:printcolumn:name="SECRET-NAME",type="string",JSONPath=".spec.credentials.secretRef.name",priority=1 +// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,template} +// A ClusterProviderConfig configures a Template provider. +type ClusterProviderConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ProviderConfigSpec `json:"spec"` + Status ProviderConfigStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ClusterProviderConfigList contains a list of ProviderConfig. +type ClusterProviderConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterProviderConfig `json:"items"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:storageversion + +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:printcolumn:name="CONFIG-NAME",type="string",JSONPath=".providerConfigRef.name" +// +kubebuilder:printcolumn:name="RESOURCE-KIND",type="string",JSONPath=".resourceRef.kind" +// +kubebuilder:printcolumn:name="RESOURCE-NAME",type="string",JSONPath=".resourceRef.name" +// +kubebuilder:resource:scope=Cluster,categories={crossplane,provider,template} +// A ClusterProviderConfigUsage indicates that a resource is using a ClusterProviderConfig. +type ClusterProviderConfigUsage struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + xpv2.TypedProviderConfigUsage `json:",inline"` +} + +// +kubebuilder:object:root=true + +// ClusterProviderConfigUsageList contains a list of ClusterProviderConfigUsage +type ClusterProviderConfigUsageList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterProviderConfigUsage `json:"items"` +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 6cd5ab2e..efcc1f3d 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -13,7 +13,7 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderConfig) DeepCopyInto(out *ProviderConfig) { +func (in *ClusterProviderConfig) DeepCopyInto(out *ClusterProviderConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -21,18 +21,18 @@ func (in *ProviderConfig) DeepCopyInto(out *ProviderConfig) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfig. -func (in *ProviderConfig) DeepCopy() *ProviderConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderConfig. +func (in *ClusterProviderConfig) DeepCopy() *ClusterProviderConfig { if in == nil { return nil } - out := new(ProviderConfig) + out := new(ClusterProviderConfig) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProviderConfig) DeepCopyObject() runtime.Object { +func (in *ClusterProviderConfig) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -40,31 +40,31 @@ func (in *ProviderConfig) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderConfigList) DeepCopyInto(out *ProviderConfigList) { +func (in *ClusterProviderConfigList) DeepCopyInto(out *ClusterProviderConfigList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]ProviderConfig, len(*in)) + *out = make([]ClusterProviderConfig, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigList. -func (in *ProviderConfigList) DeepCopy() *ProviderConfigList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderConfigList. +func (in *ClusterProviderConfigList) DeepCopy() *ClusterProviderConfigList { if in == nil { return nil } - out := new(ProviderConfigList) + out := new(ClusterProviderConfigList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProviderConfigList) DeepCopyObject() runtime.Object { +func (in *ClusterProviderConfigList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -72,57 +72,84 @@ func (in *ProviderConfigList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderConfigSpec) DeepCopyInto(out *ProviderConfigSpec) { +func (in *ClusterProviderConfigUsage) DeepCopyInto(out *ClusterProviderConfigUsage) { *out = *in - in.Credentials.DeepCopyInto(&out.Credentials) + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.TypedProviderConfigUsage.DeepCopyInto(&out.TypedProviderConfigUsage) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigSpec. -func (in *ProviderConfigSpec) DeepCopy() *ProviderConfigSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderConfigUsage. +func (in *ClusterProviderConfigUsage) DeepCopy() *ClusterProviderConfigUsage { if in == nil { return nil } - out := new(ProviderConfigSpec) + out := new(ClusterProviderConfigUsage) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterProviderConfigUsage) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) { +func (in *ClusterProviderConfigUsageList) DeepCopyInto(out *ClusterProviderConfigUsageList) { *out = *in - in.ProviderConfigStatus.DeepCopyInto(&out.ProviderConfigStatus) + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterProviderConfigUsage, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus. -func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProviderConfigUsageList. +func (in *ClusterProviderConfigUsageList) DeepCopy() *ClusterProviderConfigUsageList { if in == nil { return nil } - out := new(ProviderConfigStatus) + out := new(ClusterProviderConfigUsageList) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterProviderConfigUsageList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) { +func (in *ProviderConfig) DeepCopyInto(out *ProviderConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.ProviderConfigUsage.DeepCopyInto(&out.ProviderConfigUsage) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage. -func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfig. +func (in *ProviderConfig) DeepCopy() *ProviderConfig { if in == nil { return nil } - out := new(ProviderConfigUsage) + out := new(ProviderConfig) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProviderConfigUsage) DeepCopyObject() runtime.Object { +func (in *ProviderConfig) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -130,31 +157,31 @@ func (in *ProviderConfigUsage) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderConfigUsageList) DeepCopyInto(out *ProviderConfigUsageList) { +func (in *ProviderConfigList) DeepCopyInto(out *ProviderConfigList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]ProviderConfigUsage, len(*in)) + *out = make([]ProviderConfig, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsageList. -func (in *ProviderConfigUsageList) DeepCopy() *ProviderConfigUsageList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigList. +func (in *ProviderConfigList) DeepCopy() *ProviderConfigList { if in == nil { return nil } - out := new(ProviderConfigUsageList) + out := new(ProviderConfigList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProviderConfigUsageList) DeepCopyObject() runtime.Object { +func (in *ProviderConfigList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -162,42 +189,57 @@ func (in *ProviderConfigUsageList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderCredentials) DeepCopyInto(out *ProviderCredentials) { +func (in *ProviderConfigSpec) DeepCopyInto(out *ProviderConfigSpec) { *out = *in - in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors) + in.Credentials.DeepCopyInto(&out.Credentials) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderCredentials. -func (in *ProviderCredentials) DeepCopy() *ProviderCredentials { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigSpec. +func (in *ProviderConfigSpec) DeepCopy() *ProviderConfigSpec { if in == nil { return nil } - out := new(ProviderCredentials) + out := new(ProviderConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) { + *out = *in + in.ProviderConfigStatus.DeepCopyInto(&out.ProviderConfigStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus. +func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus { + if in == nil { + return nil + } + out := new(ProviderConfigStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StoreConfig) DeepCopyInto(out *StoreConfig) { +func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + in.TypedProviderConfigUsage.DeepCopyInto(&out.TypedProviderConfigUsage) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreConfig. -func (in *StoreConfig) DeepCopy() *StoreConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage. +func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage { if in == nil { return nil } - out := new(StoreConfig) + out := new(ProviderConfigUsage) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *StoreConfig) DeepCopyObject() runtime.Object { +func (in *ProviderConfigUsage) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -205,31 +247,31 @@ func (in *StoreConfig) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StoreConfigList) DeepCopyInto(out *StoreConfigList) { +func (in *ProviderConfigUsageList) DeepCopyInto(out *ProviderConfigUsageList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]StoreConfig, len(*in)) + *out = make([]ProviderConfigUsage, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreConfigList. -func (in *StoreConfigList) DeepCopy() *StoreConfigList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsageList. +func (in *ProviderConfigUsageList) DeepCopy() *ProviderConfigUsageList { if in == nil { return nil } - out := new(StoreConfigList) + out := new(ProviderConfigUsageList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *StoreConfigList) DeepCopyObject() runtime.Object { +func (in *ProviderConfigUsageList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -237,33 +279,17 @@ func (in *StoreConfigList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StoreConfigSpec) DeepCopyInto(out *StoreConfigSpec) { - *out = *in - in.SecretStoreConfig.DeepCopyInto(&out.SecretStoreConfig) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreConfigSpec. -func (in *StoreConfigSpec) DeepCopy() *StoreConfigSpec { - if in == nil { - return nil - } - out := new(StoreConfigSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StoreConfigStatus) DeepCopyInto(out *StoreConfigStatus) { +func (in *ProviderCredentials) DeepCopyInto(out *ProviderCredentials) { *out = *in - in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) + in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreConfigStatus. -func (in *StoreConfigStatus) DeepCopy() *StoreConfigStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderCredentials. +func (in *ProviderCredentials) DeepCopy() *ProviderCredentials { if in == nil { return nil } - out := new(StoreConfigStatus) + out := new(ProviderCredentials) in.DeepCopyInto(out) return out } diff --git a/apis/v1alpha1/zz_generated.pc.go b/apis/v1alpha1/zz_generated.pc.go index a961c7b0..046581c7 100644 --- a/apis/v1alpha1/zz_generated.pc.go +++ b/apis/v1alpha1/zz_generated.pc.go @@ -6,7 +6,27 @@ package v1alpha1 -import xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" +import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" + +// GetCondition of this ClusterProviderConfig. +func (p *ClusterProviderConfig) GetCondition(ct xpv1.ConditionType) xpv1.Condition { + return p.Status.GetCondition(ct) +} + +// GetUsers of this ClusterProviderConfig. +func (p *ClusterProviderConfig) GetUsers() int64 { + return p.Status.Users +} + +// SetConditions of this ClusterProviderConfig. +func (p *ClusterProviderConfig) SetConditions(c ...xpv1.Condition) { + p.Status.SetConditions(c...) +} + +// SetUsers of this ClusterProviderConfig. +func (p *ClusterProviderConfig) SetUsers(i int64) { + p.Status.Users = i +} // GetCondition of this ProviderConfig. func (p *ProviderConfig) GetCondition(ct xpv1.ConditionType) xpv1.Condition { diff --git a/apis/v1alpha1/zz_generated.pcu.go b/apis/v1alpha1/zz_generated.pcu.go index c6cda0e3..b34ef745 100644 --- a/apis/v1alpha1/zz_generated.pcu.go +++ b/apis/v1alpha1/zz_generated.pcu.go @@ -6,10 +6,30 @@ package v1alpha1 -import xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" +import xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" + +// GetProviderConfigReference of this ClusterProviderConfigUsage. +func (p *ClusterProviderConfigUsage) GetProviderConfigReference() xpv1.ProviderConfigReference { + return p.ProviderConfigReference +} + +// GetResourceReference of this ClusterProviderConfigUsage. +func (p *ClusterProviderConfigUsage) GetResourceReference() xpv1.TypedReference { + return p.ResourceReference +} + +// SetProviderConfigReference of this ClusterProviderConfigUsage. +func (p *ClusterProviderConfigUsage) SetProviderConfigReference(r xpv1.ProviderConfigReference) { + p.ProviderConfigReference = r +} + +// SetResourceReference of this ClusterProviderConfigUsage. +func (p *ClusterProviderConfigUsage) SetResourceReference(r xpv1.TypedReference) { + p.ResourceReference = r +} // GetProviderConfigReference of this ProviderConfigUsage. -func (p *ProviderConfigUsage) GetProviderConfigReference() xpv1.Reference { +func (p *ProviderConfigUsage) GetProviderConfigReference() xpv1.ProviderConfigReference { return p.ProviderConfigReference } @@ -19,7 +39,7 @@ func (p *ProviderConfigUsage) GetResourceReference() xpv1.TypedReference { } // SetProviderConfigReference of this ProviderConfigUsage. -func (p *ProviderConfigUsage) SetProviderConfigReference(r xpv1.Reference) { +func (p *ProviderConfigUsage) SetProviderConfigReference(r xpv1.ProviderConfigReference) { p.ProviderConfigReference = r } diff --git a/apis/v1alpha1/zz_generated.pculist.go b/apis/v1alpha1/zz_generated.pculist.go index 6c06eef4..d08543e1 100644 --- a/apis/v1alpha1/zz_generated.pculist.go +++ b/apis/v1alpha1/zz_generated.pculist.go @@ -6,7 +6,16 @@ package v1alpha1 -import resource "github.com/crossplane/crossplane-runtime/pkg/resource" +import resource "github.com/crossplane/crossplane-runtime/v2/pkg/resource" + +// GetItems of this ClusterProviderConfigUsageList. +func (p *ClusterProviderConfigUsageList) GetItems() []resource.ProviderConfigUsage { + items := make([]resource.ProviderConfigUsage, len(p.Items)) + for i := range p.Items { + items[i] = &p.Items[i] + } + return items +} // GetItems of this ProviderConfigUsageList. func (p *ProviderConfigUsageList) GetItems() []resource.ProviderConfigUsage { diff --git a/cmd/provider/main.go b/cmd/provider/main.go index bee31c61..58665b1a 100644 --- a/cmd/provider/main.go +++ b/cmd/provider/main.go @@ -17,38 +17,35 @@ limitations under the License. package main import ( - "context" "fmt" "io" "os" "path/filepath" "time" + "github.com/alecthomas/kingpin/v2" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "gopkg.in/alecthomas/kingpin.v2" - kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/leaderelection/resourcelock" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/metrics" - changelogsv1alpha1 "github.com/crossplane/crossplane-runtime/apis/changelogs/proto/v1alpha1" - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" - "github.com/crossplane/crossplane-runtime/pkg/controller" - "github.com/crossplane/crossplane-runtime/pkg/feature" - "github.com/crossplane/crossplane-runtime/pkg/logging" - "github.com/crossplane/crossplane-runtime/pkg/ratelimiter" - "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/statemetrics" + changelogsv1alpha1 "github.com/crossplane/crossplane-runtime/v2/apis/changelogs/proto/v1alpha1" + "github.com/crossplane/crossplane-runtime/v2/pkg/controller" + "github.com/crossplane/crossplane-runtime/v2/pkg/feature" + "github.com/crossplane/crossplane-runtime/v2/pkg/gate" + "github.com/crossplane/crossplane-runtime/v2/pkg/logging" + "github.com/crossplane/crossplane-runtime/v2/pkg/ratelimiter" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/customresourcesgate" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/v2/pkg/statemetrics" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime/schema" "github.com/crossplane/provider-template/apis" - "github.com/crossplane/provider-template/apis/v1alpha1" template "github.com/crossplane/provider-template/internal/controller" - "github.com/crossplane/provider-template/internal/features" "github.com/crossplane/provider-template/internal/version" ) @@ -64,11 +61,9 @@ func main() { maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may checked for drift from the desired state.").Default("10").Int() - namespace = app.Flag("namespace", "Namespace used to set as default scope in default secret store config.").Default("crossplane-system").Envar("POD_NAMESPACE").String() - enableExternalSecretStores = app.Flag("enable-external-secret-stores", "Enable support for ExternalSecretStores.").Default("false").Envar("ENABLE_EXTERNAL_SECRET_STORES").Bool() - enableManagementPolicies = app.Flag("enable-management-policies", "Enable support for Management Policies.").Default("false").Envar("ENABLE_MANAGEMENT_POLICIES").Bool() - enableChangeLogs = app.Flag("enable-changelogs", "Enable support for capturing change logs during reconciliation.").Default("false").Envar("ENABLE_CHANGE_LOGS").Bool() - changelogsSocketPath = app.Flag("changelogs-socket-path", "Path for changelogs socket (if enabled)").Default("/var/run/changelogs/changelogs.sock").Envar("CHANGELOGS_SOCKET_PATH").String() + enableManagementPolicies = app.Flag("enable-management-policies", "Enable support for Management Policies.").Default("true").Envar("ENABLE_MANAGEMENT_POLICIES").Bool() + enableChangeLogs = app.Flag("enable-changelogs", "Enable support for capturing change logs during reconciliation.").Default("false").Envar("ENABLE_CHANGE_LOGS").Bool() + changelogsSocketPath = app.Flag("changelogs-socket-path", "Path for changelogs socket (if enabled)").Default("/var/run/changelogs/changelogs.sock").Envar("CHANGELOGS_SOCKET_PATH").String() ) kingpin.MustParse(app.Parse(os.Args[1:])) @@ -109,7 +104,9 @@ func main() { RenewDeadline: func() *time.Duration { d := 50 * time.Second; return &d }(), }) kingpin.FatalIfError(err, "Cannot create controller manager") + kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add Template APIs to scheme") + kingpin.FatalIfError(apiextensionsv1.AddToScheme(mgr.GetScheme()), "Cannot add CustomResourceDefinition to scheme") metricRecorder := managed.NewMRMetricRecorder() stateMetrics := statemetrics.NewMRStateMetrics() @@ -123,6 +120,7 @@ func main() { PollInterval: *pollInterval, GlobalRateLimiter: ratelimiter.NewGlobal(*maxReconcileRate), Features: &feature.Flags{}, + Gate: new(gate.Gate[schema.GroupVersionKind]), MetricOptions: &controller.MetricOptions{ PollStateMetricInterval: *pollStateMetricInterval, MRMetrics: metricRecorder, @@ -130,28 +128,9 @@ func main() { }, } - if *enableExternalSecretStores { - o.Features.Enable(features.EnableAlphaExternalSecretStores) - log.Info("Alpha feature enabled", "flag", features.EnableAlphaExternalSecretStores) - - // Ensure default store config exists. - kingpin.FatalIfError(resource.Ignore(kerrors.IsAlreadyExists, mgr.GetClient().Create(context.Background(), &v1alpha1.StoreConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - Spec: v1alpha1.StoreConfigSpec{ - // NOTE(turkenh): We only set required spec and expect optional - // ones to properly be initialized with CRD level default values. - SecretStoreConfig: xpv1.SecretStoreConfig{ - DefaultScope: *namespace, - }, - }, - })), "cannot create default store config") - } - if *enableManagementPolicies { - o.Features.Enable(features.EnableAlphaManagementPolicies) - log.Info("Alpha feature enabled", "flag", features.EnableAlphaManagementPolicies) + o.Features.Enable(feature.EnableBetaManagementPolicies) + log.Info("Beta feature enabled", "flag", feature.EnableBetaManagementPolicies) } if *enableChangeLogs { @@ -169,6 +148,7 @@ func main() { o.ChangeLogOptions = &clo } - kingpin.FatalIfError(template.Setup(mgr, o), "Cannot setup Template controllers") + kingpin.FatalIfError(customresourcesgate.Setup(mgr, o), "Cannot setup CRD gate controller") + kingpin.FatalIfError(template.SetupGated(mgr, o), "Cannot setup Template controllers") kingpin.FatalIfError(mgr.Start(ctrl.SetupSignalHandler()), "Cannot start controller manager") } diff --git a/examples/provider/config.yaml b/examples/provider/config.yaml index 6a536457..05b652e8 100644 --- a/examples/provider/config.yaml +++ b/examples/provider/config.yaml @@ -1,25 +1,38 @@ apiVersion: v1 kind: Namespace metadata: - name: crossplane-system + name: default --- apiVersion: v1 kind: Secret metadata: - namespace: crossplane-system + namespace: default name: example-provider-secret type: Opaque data: - # credentials: BASE64ENCODED_PROVIDER_CREDS + credentials: QkFTRTY0RU5DT0RFRF9QUk9WSURFUl9DUkVEUwo= --- apiVersion: template.crossplane.io/v1alpha1 kind: ProviderConfig metadata: name: example + namespace: default spec: credentials: source: Secret secretRef: - namespace: crossplane-system + namespace: default + name: example-provider-secret + key: credentials +--- +apiVersion: template.crossplane.io/v1alpha1 +kind: ClusterProviderConfig +metadata: + name: example +spec: + credentials: + source: Secret + secretRef: + namespace: default name: example-provider-secret key: credentials diff --git a/examples/sample/mytype.yaml b/examples/sample/mytype.yaml index a73ff5c2..8a4e9716 100644 --- a/examples/sample/mytype.yaml +++ b/examples/sample/mytype.yaml @@ -2,8 +2,22 @@ apiVersion: sample.template.crossplane.io/v1alpha1 kind: MyType metadata: name: example + namespace: default spec: forProvider: configurableField: test providerConfigRef: - name: example \ No newline at end of file + name: example + kind: ProviderConfig +--- +apiVersion: sample.template.crossplane.io/v1alpha1 +kind: MyType +metadata: + name: cluster-example + namespace: default +spec: + forProvider: + configurableField: test + providerConfigRef: + name: example + kind: ClusterProviderConfig diff --git a/examples/storeconfig/vault.yaml b/examples/storeconfig/vault.yaml deleted file mode 100644 index 1f2d881a..00000000 --- a/examples/storeconfig/vault.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: template.crossplane.io/v1alpha1 -kind: StoreConfig -metadata: - name: vault -spec: - type: Vault - defaultScope: crossplane-system - vault: - server: http://vault.vault-system:8200 - mountPath: secret/ - version: v2 - auth: - method: Token - token: - source: Secret - secretRef: - namespace: crossplane-system - name: vault-token - key: token diff --git a/go.mod b/go.mod index 554a4c1e..4317120c 100644 --- a/go.mod +++ b/go.mod @@ -1,51 +1,50 @@ module github.com/crossplane/provider-template -go 1.23.0 +go 1.24.0 -toolchain go1.23.8 +toolchain go1.24.5 + +tool sigs.k8s.io/controller-tools/cmd/controller-gen + +tool github.com/crossplane/crossplane-tools/cmd/angryjet require ( - github.com/crossplane/crossplane-runtime v1.20.0 - github.com/crossplane/crossplane-tools v0.0.0-20240522174801-1ad3d4c87f21 - github.com/google/go-cmp v0.6.0 + github.com/alecthomas/kingpin/v2 v2.4.0 + github.com/crossplane/crossplane-runtime/v2 v2.0.0 + github.com/google/go-cmp v0.7.0 github.com/pkg/errors v0.9.1 - google.golang.org/grpc v1.65.0 - gopkg.in/alecthomas/kingpin.v2 v2.2.6 - k8s.io/apimachinery v0.31.2 - k8s.io/client-go v0.31.2 - sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/controller-tools v0.16.5 + google.golang.org/grpc v1.74.2 + k8s.io/apiextensions-apiserver v0.33.0 + k8s.io/apimachinery v0.33.3 + k8s.io/client-go v0.33.3 + sigs.k8s.io/controller-runtime v0.21.0 ) require ( dario.cat/mergo v1.0.1 // indirect - github.com/alecthomas/kingpin/v2 v2.4.0 // indirect - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/dave/jennifer v1.7.0 // indirect + github.com/crossplane/crossplane-tools v0.0.0-20250731192036-00d407d8b7ec // indirect + github.com/dave/jennifer v1.7.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.9.11+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/gofuzz v1.2.0 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -55,40 +54,45 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/cobra v1.9.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect + go.opentelemetry.io/otel v1.36.0 // indirect + go.opentelemetry.io/otel/trace v1.36.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/oauth2 v0.29.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.26.0 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect + golang.org/x/time v0.9.0 // indirect + golang.org/x/tools v0.32.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.31.2 // indirect - k8s.io/apiextensions-apiserver v0.31.2 // indirect - k8s.io/component-base v0.31.2 // indirect + k8s.io/api v0.33.3 // indirect + k8s.io/code-generator v0.33.0 // indirect + k8s.io/component-base v0.33.0 // indirect + k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect + sigs.k8s.io/controller-tools v0.18.0 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 40ad8799..5051a301 100644 --- a/go.sum +++ b/go.sum @@ -2,24 +2,22 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/crossplane/crossplane-runtime v1.20.0 h1:I54uipRIecqZyms+vz1J/l62yjVQ7HV5w+Nh3RMrUtc= -github.com/crossplane/crossplane-runtime v1.20.0/go.mod h1:lfV1VJenDc9PNVLxDC80YjPoTm+JdSZ13xlS2h37Dvg= -github.com/crossplane/crossplane-tools v0.0.0-20240522174801-1ad3d4c87f21 h1:8wb7/zCbVPkeX68WbVESWJmSWQE5SZKzz0g9X4FlXRw= -github.com/crossplane/crossplane-tools v0.0.0-20240522174801-1ad3d4c87f21/go.mod h1:cN0Y7PFGQMM8mcagXVCbeQoKtipmFWQTPZYyziCPBUI= -github.com/dave/jennifer v1.7.0 h1:uRbSBH9UTS64yXbh4FrMHfgfY762RD+C7bUPKODpSJE= -github.com/dave/jennifer v1.7.0/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= +github.com/crossplane/crossplane-runtime/v2 v2.0.0 h1:PK2pTKfshdDZ5IfoiMRiCi0PBnIjqbS0KGXEJgRdrb4= +github.com/crossplane/crossplane-runtime/v2 v2.0.0/go.mod h1:pkd5UzmE8esaZAApevMutR832GjJ1Qgc5Ngr78ByxrI= +github.com/crossplane/crossplane-tools v0.0.0-20250731192036-00d407d8b7ec h1:+51Et4UW8XrvGne8RAqn9qEIfhoqPXYqIp/kQvpMaAo= +github.com/crossplane/crossplane-tools v0.0.0-20250731192036-00d407d8b7ec/go.mod h1:8etxwmP4cZwJDwen4+PQlnc1tggltAhEfyyigmdHulQ= +github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= +github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -28,49 +26,50 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -79,6 +78,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -86,6 +87,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -104,48 +107,62 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -155,60 +172,56 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= -golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -218,36 +231,41 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= -k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= -k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= -k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= -k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= -k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= +k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs= +k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc= +k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= +k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= +k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= +k8s.io/code-generator v0.33.0 h1:B212FVl6EFqNmlgdOZYWNi77yBv+ed3QgQsMR8YQCw4= +k8s.io/code-generator v0.33.0/go.mod h1:KnJRokGxjvbBQkSJkbVuBbu6z4B0rC7ynkpY5Aw6m9o= +k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk= +k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU= +k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog= +k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/controller-tools v0.16.5 h1:5k9FNRqziBPwqr17AMEPPV/En39ZBplLAdOwwQHruP4= -sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= +k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= +sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl b/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl index ed04c5f3..d9a24869 100644 --- a/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl +++ b/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl @@ -22,7 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + xpv2 "github.com/crossplane/crossplane-runtime/v2/apis/common/v2" ) // {{ .Env.KIND }}Parameters are the configurable fields of a {{ .Env.KIND }}. @@ -38,13 +38,13 @@ type {{ .Env.KIND }}Observation struct { // A {{ .Env.KIND }}Spec defines the desired state of a {{ .Env.KIND }}. type {{ .Env.KIND }}Spec struct { - xpv1.ResourceSpec `json:",inline"` - ForProvider {{ .Env.KIND }}Parameters `json:"forProvider"` + xpv2.ManagedResourceSpec `json:",inline"` + ForProvider {{ .Env.KIND }}Parameters `json:"forProvider"` } // A {{ .Env.KIND }}Status represents the observed state of a {{ .Env.KIND }}. type {{ .Env.KIND }}Status struct { - xpv1.ResourceStatus `json:",inline"` + xpv2.ResourceStatus `json:",inline"` AtProvider {{ .Env.KIND }}Observation `json:"atProvider,omitempty"` } @@ -56,7 +56,7 @@ type {{ .Env.KIND }}Status struct { // +kubebuilder:printcolumn:name="EXTERNAL-NAME",type="string",JSONPath=".metadata.annotations.crossplane\\.io/external-name" // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Cluster,categories={crossplane,managed,{{ .Env.PROVIDER | strings.ToLower }}} +// +kubebuilder:resource:scope=Namespaced,categories={crossplane,managed,{{ .Env.PROVIDER | strings.ToLower }}} type {{ .Env.KIND }} struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl b/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl index fd76dc2d..d9bdd928 100644 --- a/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl +++ b/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl @@ -20,30 +20,29 @@ import ( "context" "fmt" - "github.com/crossplane/crossplane-runtime/pkg/feature" + "github.com/crossplane/crossplane-runtime/v2/pkg/feature" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/crossplane/crossplane-runtime/pkg/connection" - "github.com/crossplane/crossplane-runtime/pkg/controller" - "github.com/crossplane/crossplane-runtime/pkg/event" - "github.com/crossplane/crossplane-runtime/pkg/ratelimiter" - "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/statemetrics" + "github.com/crossplane/crossplane-runtime/v2/pkg/controller" + "github.com/crossplane/crossplane-runtime/v2/pkg/event" + "github.com/crossplane/crossplane-runtime/v2/pkg/ratelimiter" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource" + "github.com/crossplane/crossplane-runtime/v2/pkg/statemetrics" - "{{ .Env.PROJECT_REPO | strings.ToLower }}/apis/{{ .Env.GROUP | strings.ToLower }}/{{ .Env.APIVERSION | strings.ToLower }}" + {{ .Env.APIVERSION | strings.ToLower }} "{{ .Env.PROJECT_REPO | strings.ToLower }}/apis/{{ .Env.GROUP | strings.ToLower }}/{{ .Env.APIVERSION | strings.ToLower }}" apisv1alpha1 "{{ .Env.PROJECT_REPO | strings.ToLower }}/apis/v1alpha1" - "{{ .Env.PROJECT_REPO | strings.ToLower }}/internal/features" ) const ( errNot{{ .Env.KIND }} = "managed resource is not a {{ .Env.KIND }} custom resource" errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" + errGetCPC = "cannot get ClusterProviderConfig" errGetCreds = "cannot get credentials" errNewClient = "cannot create new Service" @@ -58,12 +57,9 @@ var ( // Setup adds a controller that reconciles {{ .Env.KIND }} managed resources. func Setup(mgr ctrl.Manager, o controller.Options) error { - name := managed.ControllerName(v1alpha1.{{ .Env.KIND }}GroupKind) + name := managed.ControllerName({{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}GroupKind) cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())} - if o.Features.Enabled(features.EnableAlphaExternalSecretStores) { - cps = append(cps, connection.NewDetailsManager(mgr.GetClient(), apisv1alpha1.StoreConfigGroupVersionKind)) - } opts := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{ @@ -73,8 +69,10 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), - managed.WithConnectionPublishers(cps...), - managed.WithManagementPolicies(), + } + + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + opts = append(opts, managed.WithManagementPolicies()) } if o.Features.Enabled(feature.EnableAlphaChangeLogs) { @@ -87,20 +85,20 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { if o.MetricOptions != nil && o.MetricOptions.MRStateMetrics != nil { stateMetricsRecorder := statemetrics.NewMRStateRecorder( - mgr.GetClient(), o.Logger, o.MetricOptions.MRStateMetrics, &v1alpha1.{{ .Env.KIND }}List{}, o.MetricOptions.PollStateMetricInterval, + mgr.GetClient(), o.Logger, o.MetricOptions.MRStateMetrics, &{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}List{}, o.MetricOptions.PollStateMetricInterval, ) if err := mgr.Add(stateMetricsRecorder); err != nil { - return errors.Wrap(err, "cannot register MR state metrics recorder for kind v1alpha1.{{ .Env.KIND }}List") + return errors.Wrap(err, "cannot register MR state metrics recorder for kind {{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}List") } } - r := managed.NewReconciler(mgr, resource.ManagedKind(v1alpha1.{{ .Env.KIND }}GroupVersionKind), opts...) + r := managed.NewReconciler(mgr, resource.ManagedKind({{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}GroupVersionKind), opts...) return ctrl.NewControllerManagedBy(mgr). Named(name). WithOptions(o.ForControllerRuntime()). WithEventFilter(resource.DesiredStateChanged()). - For(&v1alpha1.{{ .Env.KIND }}{}). + For(&{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}{}). Complete(ratelimiter.NewReconciler(name, r, o.GlobalRateLimiter)) } @@ -108,7 +106,7 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { // is called. type connector struct { kube client.Client - usage resource.Tracker + usage *resource.ProviderConfigUsageTracker newServiceFn func(creds []byte) (interface{}, error) } @@ -118,21 +116,37 @@ type connector struct { // 3. Getting the credentials specified by the ProviderConfig. // 4. Using the credentials to form a client. func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { - cr, ok := mg.(*v1alpha1.{{ .Env.KIND }}) + cr, ok := mg.(*{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}) if !ok { return nil, errors.New(errNot{{ .Env.KIND }}) } - if err := c.usage.Track(ctx, mg); err != nil { + if err := c.usage.Track(ctx, cr); err != nil { return nil, errors.Wrap(err, errTrackPCUsage) } - pc := &apisv1alpha1.ProviderConfig{} - if err := c.kube.Get(ctx, types.NamespacedName{Name: cr.GetProviderConfigReference().Name}, pc); err != nil { - return nil, errors.Wrap(err, errGetPC) - } + var cd apisv1alpha1.ProviderCredentials - cd := pc.Spec.Credentials + // Switch to ModernManaged resource to get ProviderConfigRef + m := mg.(resource.ModernManaged) + ref := m.GetProviderConfigReference() + + switch ref.Kind { + case "ProviderConfig": + pc := &apisv1alpha1.ProviderConfig{} + if err := c.kube.Get(ctx, types.NamespacedName{Name: ref.Name, Namespace: m.GetNamespace()}, pc); err != nil { + return nil, errors.Wrap(err, errGetPC) + } + cd = pc.Spec.Credentials + case "ClusterProviderConfig": + cpc := &apisv1alpha1.ClusterProviderConfig{} + if err := c.kube.Get(ctx, types.NamespacedName{Name: ref.Name}, cpc); err != nil { + return nil, errors.Wrap(err, errGetCPC) + } + cd = cpc.Spec.Credentials + default: + return nil, errors.Errorf("unsupported provider config kind: %s", ref.Kind) + } data, err := resource.CommonCredentialExtractor(ctx, cd.Source, c.kube, cd.CommonCredentialSelectors) if err != nil { return nil, errors.Wrap(err, errGetCreds) @@ -155,7 +169,7 @@ type external struct { } func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.ExternalObservation, error) { - cr, ok := mg.(*v1alpha1.{{ .Env.KIND }}) + cr, ok := mg.(*{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}) if !ok { return managed.ExternalObservation{}, errors.New(errNot{{ .Env.KIND }}) } @@ -181,7 +195,7 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex } func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.ExternalCreation, error) { - cr, ok := mg.(*v1alpha1.{{ .Env.KIND }}) + cr, ok := mg.(*{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}) if !ok { return managed.ExternalCreation{}, errors.New(errNot{{ .Env.KIND }}) } @@ -196,7 +210,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext } func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.ExternalUpdate, error) { - cr, ok := mg.(*v1alpha1.{{ .Env.KIND }}) + cr, ok := mg.(*{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}) if !ok { return managed.ExternalUpdate{}, errors.New(errNot{{ .Env.KIND }}) } @@ -211,7 +225,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext } func (c *external) Delete(ctx context.Context, mg resource.Managed) (managed.ExternalDelete, error) { - cr, ok := mg.(*v1alpha1.{{ .Env.KIND }}) + cr, ok := mg.(*{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}) if !ok { return managed.ExternalDelete{}, errors.New(errNot{{ .Env.KIND }}) } diff --git a/hack/helpers/controller/KIND_LOWER/KIND_LOWER_test.go.tmpl b/hack/helpers/controller/KIND_LOWER/KIND_LOWER_test.go.tmpl index d1372284..283b1ae9 100644 --- a/hack/helpers/controller/KIND_LOWER/KIND_LOWER_test.go.tmpl +++ b/hack/helpers/controller/KIND_LOWER/KIND_LOWER_test.go.tmpl @@ -22,9 +22,9 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/test" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource" + "github.com/crossplane/crossplane-runtime/v2/pkg/test" ) // Unlike many Kubernetes projects Crossplane does not use third party testing diff --git a/internal/controller/config/config.go b/internal/controller/config/config.go index 7ff60e02..e9035573 100644 --- a/internal/controller/config/config.go +++ b/internal/controller/config/config.go @@ -17,11 +17,11 @@ limitations under the License. package config import ( - "github.com/crossplane/crossplane-runtime/pkg/controller" - "github.com/crossplane/crossplane-runtime/pkg/event" - "github.com/crossplane/crossplane-runtime/pkg/ratelimiter" - "github.com/crossplane/crossplane-runtime/pkg/reconciler/providerconfig" - "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/crossplane/crossplane-runtime/v2/pkg/controller" + "github.com/crossplane/crossplane-runtime/v2/pkg/event" + "github.com/crossplane/crossplane-runtime/v2/pkg/ratelimiter" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/providerconfig" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource" ctrl "sigs.k8s.io/controller-runtime" "github.com/crossplane/provider-template/apis/v1alpha1" @@ -30,10 +30,18 @@ import ( // Setup adds a controller that reconciles ProviderConfigs by accounting for // their current usage. func Setup(mgr ctrl.Manager, o controller.Options) error { + if err := setupNamespacedProviderConfig(mgr, o); err != nil { + return err + } + return setupClusterProviderConfig(mgr, o) +} + +func setupNamespacedProviderConfig(mgr ctrl.Manager, o controller.Options) error { name := providerconfig.ControllerName(v1alpha1.ProviderConfigGroupKind) of := resource.ProviderConfigKinds{ Config: v1alpha1.ProviderConfigGroupVersionKind, + Usage: v1alpha1.ProviderConfigUsageGroupVersionKind, UsageList: v1alpha1.ProviderConfigUsageListGroupVersionKind, } @@ -48,3 +56,23 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { Watches(&v1alpha1.ProviderConfigUsage{}, &resource.EnqueueRequestForProviderConfig{}). Complete(ratelimiter.NewReconciler(name, r, o.GlobalRateLimiter)) } + +func setupClusterProviderConfig(mgr ctrl.Manager, o controller.Options) error { + name := providerconfig.ControllerName(v1alpha1.ClusterProviderConfigGroupKind) + of := resource.ProviderConfigKinds{ + Config: v1alpha1.ClusterProviderConfigGroupVersionKind, + Usage: v1alpha1.ClusterProviderConfigUsageGroupVersionKind, + UsageList: v1alpha1.ClusterProviderConfigUsageListGroupVersionKind, + } + + r := providerconfig.NewReconciler(mgr, of, + providerconfig.WithLogger(o.Logger.WithValues("controller", name)), + providerconfig.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) + + return ctrl.NewControllerManagedBy(mgr). + Named(name). + WithOptions(o.ForControllerRuntime()). + For(&v1alpha1.ClusterProviderConfig{}). + Watches(&v1alpha1.ClusterProviderConfigUsage{}, &resource.EnqueueRequestForProviderConfig{}). + Complete(ratelimiter.NewReconciler(name, r, o.GlobalRateLimiter)) +} diff --git a/internal/controller/mytype/mytype.go b/internal/controller/mytype/mytype.go index 917bc652..b730fe10 100644 --- a/internal/controller/mytype/mytype.go +++ b/internal/controller/mytype/mytype.go @@ -20,30 +20,29 @@ import ( "context" "fmt" - "github.com/crossplane/crossplane-runtime/pkg/feature" - + xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" + "github.com/crossplane/crossplane-runtime/v2/pkg/controller" + "github.com/crossplane/crossplane-runtime/v2/pkg/event" + "github.com/crossplane/crossplane-runtime/v2/pkg/feature" + "github.com/crossplane/crossplane-runtime/v2/pkg/meta" + "github.com/crossplane/crossplane-runtime/v2/pkg/ratelimiter" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource" + "github.com/crossplane/crossplane-runtime/v2/pkg/statemetrics" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/crossplane/crossplane-runtime/pkg/connection" - "github.com/crossplane/crossplane-runtime/pkg/controller" - "github.com/crossplane/crossplane-runtime/pkg/event" - "github.com/crossplane/crossplane-runtime/pkg/ratelimiter" - "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/statemetrics" - "github.com/crossplane/provider-template/apis/sample/v1alpha1" apisv1alpha1 "github.com/crossplane/provider-template/apis/v1alpha1" - "github.com/crossplane/provider-template/internal/features" ) const ( errNotMyType = "managed resource is not a MyType custom resource" errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" + errGetCPC = "cannot get ClusterProviderConfig" errGetCreds = "cannot get credentials" errNewClient = "cannot create new Service" @@ -56,25 +55,32 @@ var ( newNoOpService = func(_ []byte) (interface{}, error) { return &NoOpService{}, nil } ) +// SetupGated adds a controller that reconciles MyType managed resources with safe-start support. +func SetupGated(mgr ctrl.Manager, o controller.Options) error { + o.Gate.Register(func() { + if err := Setup(mgr, o); err != nil { + panic(errors.Wrap(err, "cannot setup MyType controller")) + } + }, v1alpha1.MyTypeGroupVersionKind) + return nil +} + // Setup adds a controller that reconciles MyType managed resources. func Setup(mgr ctrl.Manager, o controller.Options) error { name := managed.ControllerName(v1alpha1.MyTypeGroupKind) - cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())} - if o.Features.Enabled(features.EnableAlphaExternalSecretStores) { - cps = append(cps, connection.NewDetailsManager(mgr.GetClient(), apisv1alpha1.StoreConfigGroupVersionKind)) - } - opts := []managed.ReconcilerOption{ - managed.WithExternalConnecter(&connector{ + managed.WithExternalConnector(&connector{ kube: mgr.GetClient(), usage: resource.NewProviderConfigUsageTracker(mgr.GetClient(), &apisv1alpha1.ProviderConfigUsage{}), newServiceFn: newNoOpService}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), - managed.WithConnectionPublishers(cps...), - managed.WithManagementPolicies(), + } + + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + opts = append(opts, managed.WithManagementPolicies()) } if o.Features.Enabled(feature.EnableAlphaChangeLogs) { @@ -108,7 +114,7 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { // is called. type connector struct { kube client.Client - usage resource.Tracker + usage *resource.ProviderConfigUsageTracker newServiceFn func(creds []byte) (interface{}, error) } @@ -123,16 +129,33 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.New(errNotMyType) } - if err := c.usage.Track(ctx, mg); err != nil { + if err := c.usage.Track(ctx, cr); err != nil { return nil, errors.Wrap(err, errTrackPCUsage) } - pc := &apisv1alpha1.ProviderConfig{} - if err := c.kube.Get(ctx, types.NamespacedName{Name: cr.GetProviderConfigReference().Name}, pc); err != nil { - return nil, errors.Wrap(err, errGetPC) + var cd apisv1alpha1.ProviderCredentials + + // Switch to ModernManaged resource to get ProviderConfigRef + m := mg.(resource.ModernManaged) + ref := m.GetProviderConfigReference() + + switch ref.Kind { + case "ProviderConfig": + pc := &apisv1alpha1.ProviderConfig{} + if err := c.kube.Get(ctx, types.NamespacedName{Name: ref.Name, Namespace: m.GetNamespace()}, pc); err != nil { + return nil, errors.Wrap(err, errGetPC) + } + cd = pc.Spec.Credentials + case "ClusterProviderConfig": + cpc := &apisv1alpha1.ClusterProviderConfig{} + if err := c.kube.Get(ctx, types.NamespacedName{Name: ref.Name}, cpc); err != nil { + return nil, errors.Wrap(err, errGetCPC) + } + cd = cpc.Spec.Credentials + default: + return nil, errors.Errorf("unsupported provider config kind: %s", ref.Kind) } - cd := pc.Spec.Credentials data, err := resource.CommonCredentialExtractor(ctx, cd.Source, c.kube, cd.CommonCredentialSelectors) if err != nil { return nil, errors.Wrap(err, errGetCreds) @@ -155,6 +178,15 @@ type external struct { } func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.ExternalObservation, error) { + // If the managed resource is marked for deletion then deleted it. + // Because there is no external resource to observe, we return false for + // ResourceExists. + if meta.WasDeleted(mg) { + return managed.ExternalObservation{ + ResourceExists: false, + }, nil + } + cr, ok := mg.(*v1alpha1.MyType) if !ok { return managed.ExternalObservation{}, errors.New(errNotMyType) @@ -163,6 +195,24 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex // These fmt statements should be removed in the real implementation. fmt.Printf("Observing: %+v", cr) + // Simulate external resource doesn't exist, and enter to create the flow + if meta.GetExternalName(cr) == "" { + return managed.ExternalObservation{ + ResourceExists: false, + }, nil + } + + // Simulate external resource exists and not in sync + if cr.Status.AtProvider.ConfigurableField != cr.Spec.ForProvider.ConfigurableField { + // This case should trigger an update + return managed.ExternalObservation{ + ResourceExists: true, + ResourceUpToDate: false, + }, nil + } + + // Now the resource is in sync and ready to use, so mark it as available. + cr.Status.SetConditions(xpv1.Available()) return managed.ExternalObservation{ // Return false when the external resource does not exist. This lets // the managed resource reconciler know that it needs to call Create to @@ -182,12 +232,17 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.ExternalCreation, error) { cr, ok := mg.(*v1alpha1.MyType) + cr.Status.SetConditions(xpv1.Creating()) if !ok { return managed.ExternalCreation{}, errors.New(errNotMyType) } fmt.Printf("Creating: %+v", cr) + // Copy ConfigurableField to AtProvider and complete the creation. + cr.Status.AtProvider.ConfigurableField = cr.Spec.ForProvider.ConfigurableField + meta.SetExternalName(cr, "my-external-name") + return managed.ExternalCreation{ // Optionally return any details that may be required to connect to the // external resource. These will be stored as the connection secret. @@ -203,6 +258,9 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext fmt.Printf("Updating: %+v", cr) + // Copy ConfigurableField to AtProvider and complete the update. + cr.Status.AtProvider.ConfigurableField = cr.Spec.ForProvider.ConfigurableField + return managed.ExternalUpdate{ // Optionally return any details that may be required to connect to the // external resource. These will be stored as the connection secret. @@ -212,6 +270,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext func (c *external) Delete(ctx context.Context, mg resource.Managed) (managed.ExternalDelete, error) { cr, ok := mg.(*v1alpha1.MyType) + cr.Status.SetConditions(xpv1.Deleting()) if !ok { return managed.ExternalDelete{}, errors.New(errNotMyType) } diff --git a/internal/controller/mytype/mytype_test.go b/internal/controller/mytype/mytype_test.go index c4c28582..0ad0aad0 100644 --- a/internal/controller/mytype/mytype_test.go +++ b/internal/controller/mytype/mytype_test.go @@ -22,9 +22,9 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" - "github.com/crossplane/crossplane-runtime/pkg/resource" - "github.com/crossplane/crossplane-runtime/pkg/test" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource" + "github.com/crossplane/crossplane-runtime/v2/pkg/test" ) // Unlike many Kubernetes projects Crossplane does not use third party testing diff --git a/internal/controller/template.go b/internal/controller/template.go index e4bc5186..7b43a806 100644 --- a/internal/controller/template.go +++ b/internal/controller/template.go @@ -17,13 +17,27 @@ limitations under the License. package controller import ( - "github.com/crossplane/crossplane-runtime/pkg/controller" + "github.com/crossplane/crossplane-runtime/v2/pkg/controller" ctrl "sigs.k8s.io/controller-runtime" "github.com/crossplane/provider-template/internal/controller/config" "github.com/crossplane/provider-template/internal/controller/mytype" ) +// SetupGated creates all Template controllers with safe-start support and adds them to +// the supplied manager. +func SetupGated(mgr ctrl.Manager, o controller.Options) error { + for _, setup := range []func(ctrl.Manager, controller.Options) error{ + config.Setup, + mytype.SetupGated, + } { + if err := setup(mgr, o); err != nil { + return err + } + } + return nil +} + // Setup creates all Template controllers with the supplied logger and adds them to // the supplied manager. func Setup(mgr ctrl.Manager, o controller.Options) error { diff --git a/internal/features/features.go b/internal/features/features.go deleted file mode 100644 index 9e48846e..00000000 --- a/internal/features/features.go +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 2022 The Crossplane Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package features - -import "github.com/crossplane/crossplane-runtime/pkg/feature" - -// Feature flags. -const ( - // EnableAlphaExternalSecretStores enables alpha support for - // External Secret Stores. See the below design for more details. - // https://github.com/crossplane/crossplane/blob/390ddd/design/design-doc-external-secret-stores.md - EnableAlphaExternalSecretStores feature.Flag = "EnableAlphaExternalSecretStores" - - // EnableAlphaManagementPolicies enables alpha support for - // Management Policies. See the below design for more details. - // https://github.com/crossplane/crossplane/blob/master/design/design-doc-observe-only-resources.md - EnableAlphaManagementPolicies feature.Flag = "EnableAlphaManagementPolicies" -) diff --git a/package/crds/sample.template.crossplane.io_mytypes.yaml b/package/crds/sample.template.crossplane.io_mytypes.yaml index 668ca05d..3d87132c 100644 --- a/package/crds/sample.template.crossplane.io_mytypes.yaml +++ b/package/crds/sample.template.crossplane.io_mytypes.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 name: mytypes.sample.template.crossplane.io spec: group: sample.template.crossplane.io @@ -16,7 +16,7 @@ spec: listKind: MyTypeList plural: mytypes singular: mytype - scope: Cluster + scope: Namespaced versions: - additionalPrinterColumns: - jsonPath: .status.conditions[?(@.type=='Ready')].status @@ -56,20 +56,6 @@ spec: spec: description: A MyTypeSpec defines the desired state of a MyType. properties: - deletionPolicy: - default: Delete - description: |- - DeletionPolicy specifies what will happen to the underlying external - when this managed resource is deleted - either "Delete" or "Orphan" the - external resource. - This field is planned to be deprecated in favor of the ManagementPolicies - field in a future release. Currently, both could be set independently and - non-default values would be honored if the feature flag is enabled. - See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223 - enum: - - Orphan - - Delete - type: string forProvider: description: MyTypeParameters are the configurable fields of a MyType. properties: @@ -86,10 +72,6 @@ spec: through a Crossplane feature flag. ManagementPolicies specify the array of actions Crossplane is allowed to take on the managed and external resources. - This field is planned to replace the DeletionPolicy field in a future - release. Currently, both could be set independently and non-default - values would be honored if the feature flag is enabled. If both are - custom, the DeletionPolicy field will be ignored. See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223 and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md items: @@ -107,118 +89,21 @@ spec: type: array providerConfigRef: default: + kind: ClusterProviderConfig name: default description: |- ProviderConfigReference specifies how the provider that will be used to create, observe, update, and delete this managed resource should be configured. properties: - name: - description: Name of the referenced object. + kind: + description: Kind of the referenced object. type: string - policy: - description: Policies for referencing. - properties: - resolution: - default: Required - description: |- - Resolution specifies whether resolution of this reference is required. - The default is 'Required', which means the reconcile will fail if the - reference cannot be resolved. 'Optional' means this reference will be - a no-op if it cannot be resolved. - enum: - - Required - - Optional - type: string - resolve: - description: |- - Resolve specifies when this reference should be resolved. The default - is 'IfNotPresent', which will attempt to resolve the reference only when - the corresponding field is not present. Use 'Always' to resolve the - reference on every reconcile. - enum: - - Always - - IfNotPresent - type: string - type: object - required: - - name - type: object - publishConnectionDetailsTo: - description: |- - PublishConnectionDetailsTo specifies the connection secret config which - contains a name, metadata and a reference to secret store config to - which any connection details for this managed resource should be written. - Connection details frequently include the endpoint, username, - and password required to connect to the managed resource. - properties: - configRef: - default: - name: default - description: |- - SecretStoreConfigRef specifies which secret store config should be used - for this ConnectionSecret. - properties: - name: - description: Name of the referenced object. - type: string - policy: - description: Policies for referencing. - properties: - resolution: - default: Required - description: |- - Resolution specifies whether resolution of this reference is required. - The default is 'Required', which means the reconcile will fail if the - reference cannot be resolved. 'Optional' means this reference will be - a no-op if it cannot be resolved. - enum: - - Required - - Optional - type: string - resolve: - description: |- - Resolve specifies when this reference should be resolved. The default - is 'IfNotPresent', which will attempt to resolve the reference only when - the corresponding field is not present. Use 'Always' to resolve the - reference on every reconcile. - enum: - - Always - - IfNotPresent - type: string - type: object - required: - - name - type: object - metadata: - description: Metadata is the metadata for connection secret. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations are the annotations to be added to connection secret. - - For Kubernetes secrets, this will be used as "metadata.annotations". - - It is up to Secret Store implementation for others store types. - type: object - labels: - additionalProperties: - type: string - description: |- - Labels are the labels/tags to be added to connection secret. - - For Kubernetes secrets, this will be used as "metadata.labels". - - It is up to Secret Store implementation for others store types. - type: object - type: - description: |- - Type is the SecretType for the connection secret. - - Only valid for Kubernetes Secret Stores. - type: string - type: object name: - description: Name is the name of the connection secret. + description: Name of the referenced object. type: string required: + - kind - name type: object writeConnectionSecretToRef: @@ -227,20 +112,12 @@ spec: Secret to which any connection details for this managed resource should be written. Connection details frequently include the endpoint, username, and password required to connect to the managed resource. - This field is planned to be replaced in a future release in favor of - PublishConnectionDetailsTo. Currently, both could be set independently - and connection details would be published to both without affecting - each other. properties: name: description: Name of the secret. type: string - namespace: - description: Namespace of the secret. - type: string required: - name - - namespace type: object required: - forProvider diff --git a/package/crds/template.crossplane.io_clusterproviderconfigs.yaml b/package/crds/template.crossplane.io_clusterproviderconfigs.yaml new file mode 100644 index 00000000..0388ce2a --- /dev/null +++ b/package/crds/template.crossplane.io_clusterproviderconfigs.yaml @@ -0,0 +1,172 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: clusterproviderconfigs.template.crossplane.io +spec: + group: template.crossplane.io + names: + categories: + - crossplane + - provider + - template + kind: ClusterProviderConfig + listKind: ClusterProviderConfigList + plural: clusterproviderconfigs + singular: clusterproviderconfig + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .spec.credentials.secretRef.name + name: SECRET-NAME + priority: 1 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: A ClusterProviderConfig configures a Template provider. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + credentials: + description: Credentials required to authenticate to this provider. + properties: + env: + description: |- + Env is a reference to an environment variable that contains credentials + that must be used to connect to the provider. + properties: + name: + description: Name is the name of an environment variable. + type: string + required: + - name + type: object + fs: + description: |- + Fs is a reference to a filesystem location that contains credentials that + must be used to connect to the provider. + properties: + path: + description: Path is a filesystem path. + type: string + required: + - path + type: object + secretRef: + description: |- + A SecretRef is a reference to a secret key that contains the credentials + that must be used to connect to the provider. + properties: + key: + description: The key to select. + type: string + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - key + - name + - namespace + type: object + source: + description: Source of the provider credentials. + enum: + - None + - Secret + - InjectedIdentity + - Environment + - Filesystem + type: string + required: + - source + type: object + required: + - credentials + type: object + status: + description: A ProviderConfigStatus defines the status of a Provider. + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastTransitionTime: + description: |- + LastTransitionTime is the last time this condition transitioned from one + status to another. + format: date-time + type: string + message: + description: |- + A Message containing details about this condition's last transition from + one status to another, if any. + type: string + observedGeneration: + description: |- + ObservedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + type: integer + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown? + type: string + type: + description: |- + Type of this condition. At most one of each condition type may apply to + a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + users: + description: Users of this provider configuration. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/package/crds/template.crossplane.io_clusterproviderconfigusages.yaml b/package/crds/template.crossplane.io_clusterproviderconfigusages.yaml new file mode 100644 index 00000000..f9785cb4 --- /dev/null +++ b/package/crds/template.crossplane.io_clusterproviderconfigusages.yaml @@ -0,0 +1,97 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: clusterproviderconfigusages.template.crossplane.io +spec: + group: template.crossplane.io + names: + categories: + - crossplane + - provider + - template + kind: ClusterProviderConfigUsage + listKind: ClusterProviderConfigUsageList + plural: clusterproviderconfigusages + singular: clusterproviderconfigusage + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .providerConfigRef.name + name: CONFIG-NAME + type: string + - jsonPath: .resourceRef.kind + name: RESOURCE-KIND + type: string + - jsonPath: .resourceRef.name + name: RESOURCE-NAME + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: A ClusterProviderConfigUsage indicates that a resource is using + a ClusterProviderConfig. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + providerConfigRef: + description: ProviderConfigReference to the provider config being used. + properties: + kind: + description: Kind of the referenced object. + type: string + name: + description: Name of the referenced object. + type: string + required: + - kind + - name + type: object + resourceRef: + description: ResourceReference to the managed resource using the provider + config. + properties: + apiVersion: + description: APIVersion of the referenced object. + type: string + kind: + description: Kind of the referenced object. + type: string + name: + description: Name of the referenced object. + type: string + uid: + description: UID of the referenced object. + type: string + required: + - apiVersion + - kind + - name + type: object + required: + - providerConfigRef + - resourceRef + type: object + served: true + storage: true + subresources: {} diff --git a/package/crds/template.crossplane.io_providerconfigs.yaml b/package/crds/template.crossplane.io_providerconfigs.yaml index 3798b6aa..86fe119c 100644 --- a/package/crds/template.crossplane.io_providerconfigs.yaml +++ b/package/crds/template.crossplane.io_providerconfigs.yaml @@ -3,16 +3,20 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 name: providerconfigs.template.crossplane.io spec: group: template.crossplane.io names: + categories: + - crossplane + - provider + - template kind: ProviderConfig listKind: ProviderConfigList plural: providerconfigs singular: providerconfig - scope: Cluster + scope: Namespaced versions: - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp @@ -25,7 +29,8 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: A ProviderConfig configures a Template provider. + description: A ProviderConfig configures a Helm 'provider', i.e. a connection + to a particular properties: apiVersion: description: |- @@ -45,7 +50,6 @@ spec: metadata: type: object spec: - description: A ProviderConfigSpec defines the desired state of a ProviderConfig. properties: credentials: description: Credentials required to authenticate to this provider. @@ -107,7 +111,7 @@ spec: - credentials type: object status: - description: A ProviderConfigStatus reflects the observed state of a ProviderConfig. + description: A ProviderConfigStatus defines the status of a Provider. properties: conditions: description: Conditions of the resource. diff --git a/package/crds/template.crossplane.io_providerconfigusages.yaml b/package/crds/template.crossplane.io_providerconfigusages.yaml index 41280f94..e91f1418 100644 --- a/package/crds/template.crossplane.io_providerconfigusages.yaml +++ b/package/crds/template.crossplane.io_providerconfigusages.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.18.0 name: providerconfigusages.template.crossplane.io spec: group: template.crossplane.io @@ -16,7 +16,7 @@ spec: listKind: ProviderConfigUsageList plural: providerconfigusages singular: providerconfigusage - scope: Cluster + scope: Namespaced versions: - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp @@ -56,35 +56,14 @@ spec: providerConfigRef: description: ProviderConfigReference to the provider config being used. properties: + kind: + description: Kind of the referenced object. + type: string name: description: Name of the referenced object. type: string - policy: - description: Policies for referencing. - properties: - resolution: - default: Required - description: |- - Resolution specifies whether resolution of this reference is required. - The default is 'Required', which means the reconcile will fail if the - reference cannot be resolved. 'Optional' means this reference will be - a no-op if it cannot be resolved. - enum: - - Required - - Optional - type: string - resolve: - description: |- - Resolve specifies when this reference should be resolved. The default - is 'IfNotPresent', which will attempt to resolve the reference only when - the corresponding field is not present. Use 'Always' to resolve the - reference on every reconcile. - enum: - - Always - - IfNotPresent - type: string - type: object required: + - kind - name type: object resourceRef: diff --git a/package/crds/template.crossplane.io_storeconfigs.yaml b/package/crds/template.crossplane.io_storeconfigs.yaml deleted file mode 100644 index c9c77b65..00000000 --- a/package/crds/template.crossplane.io_storeconfigs.yaml +++ /dev/null @@ -1,223 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.5 - name: storeconfigs.template.crossplane.io -spec: - group: template.crossplane.io - names: - categories: - - crossplane - - store - - gcp - kind: StoreConfig - listKind: StoreConfigList - plural: storeconfigs - singular: storeconfig - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: AGE - type: date - - jsonPath: .spec.type - name: TYPE - type: string - - jsonPath: .spec.defaultScope - name: DEFAULT-SCOPE - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: A StoreConfig configures how GCP controller should store connection - details. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: A StoreConfigSpec defines the desired state of a ProviderConfig. - properties: - defaultScope: - description: |- - DefaultScope used for scoping secrets for "cluster-scoped" resources. - If store type is "Kubernetes", this would mean the default namespace to - store connection secrets for cluster scoped resources. - In case of "Vault", this would be used as the default parent path. - Typically, should be set as Crossplane installation namespace. - type: string - kubernetes: - description: |- - Kubernetes configures a Kubernetes secret store. - If the "type" is "Kubernetes" but no config provided, in cluster config - will be used. - properties: - auth: - description: Credentials used to connect to the Kubernetes API. - properties: - env: - description: |- - Env is a reference to an environment variable that contains credentials - that must be used to connect to the provider. - properties: - name: - description: Name is the name of an environment variable. - type: string - required: - - name - type: object - fs: - description: |- - Fs is a reference to a filesystem location that contains credentials that - must be used to connect to the provider. - properties: - path: - description: Path is a filesystem path. - type: string - required: - - path - type: object - secretRef: - description: |- - A SecretRef is a reference to a secret key that contains the credentials - that must be used to connect to the provider. - properties: - key: - description: The key to select. - type: string - name: - description: Name of the secret. - type: string - namespace: - description: Namespace of the secret. - type: string - required: - - key - - name - - namespace - type: object - source: - description: Source of the credentials. - enum: - - None - - Secret - - Environment - - Filesystem - type: string - required: - - source - type: object - required: - - auth - type: object - plugin: - description: Plugin configures External secret store as a plugin. - properties: - configRef: - description: ConfigRef contains store config reference info. - properties: - apiVersion: - description: APIVersion of the referenced config. - type: string - kind: - description: Kind of the referenced config. - type: string - name: - description: Name of the referenced config. - type: string - required: - - apiVersion - - kind - - name - type: object - endpoint: - description: Endpoint is the endpoint of the gRPC server. - type: string - type: object - type: - default: Kubernetes - description: |- - Type configures which secret store to be used. Only the configuration - block for this store will be used and others will be ignored if provided. - Default is Kubernetes. - enum: - - Kubernetes - - Vault - - Plugin - type: string - required: - - defaultScope - type: object - status: - description: A StoreConfigStatus represents the status of a StoreConfig. - properties: - conditions: - description: Conditions of the resource. - items: - description: A Condition that may apply to a resource. - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the last time this condition transitioned from one - status to another. - format: date-time - type: string - message: - description: |- - A Message containing details about this condition's last transition from - one status to another, if any. - type: string - observedGeneration: - description: |- - ObservedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - type: integer - reason: - description: A Reason for this condition's last transition from - one status to another. - type: string - status: - description: Status of this condition; is it currently True, - False, or Unknown? - type: string - type: - description: |- - Type of this condition. At most one of each condition type may apply to - a resource at any point in time. - type: string - required: - - lastTransitionTime - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} From 5c2d3231c33ff06b016cd44387edf7c28e544826 Mon Sep 17 00:00:00 2001 From: Chuan-Yen Chiang Date: Sun, 19 Oct 2025 19:28:07 +0200 Subject: [PATCH 2/3] Refactor templates and remove deprecated Setup function This commit refactors the provider template code generation templates and removes the non-gated Setup function in favor of the safe-start pattern. Key changes: Template Updates: - Add SetupGated function to controller template for safe-start support - Update controller template to use v1alpha1 instead of dynamic API version - Fix typo: WithExternalConnecter -> WithExternalConnector - Remove unused ConnectionPublisher initialization - Add missing xpv1 import for ResourceStatus in type templates - Change Status to use xpv1.ResourceStatus instead of xpv2.ResourceStatus - Improve error constant alignment and formatting Controller Cleanup: - Remove deprecated Setup function from template.go - Keep only SetupGated function for safe-start pattern - All controllers now exclusively use gated setup Package Metadata: - Add safe-start capability to crossplane.yaml package metadata Documentation: - Fix capitalization: "Template provider" -> "template provider" - Fix capitalization: "group Sample" -> "group sample" These changes ensure all generated controllers follow the safe-start pattern and improve consistency across the template codebase. Signed-off-by: Chuan-Yen Chiang --- apis/sample/sample.go | 2 +- apis/sample/v1alpha1/groupversion_info.go | 2 +- .../APIVERSION/KIND_LOWER_types.go.tmpl | 3 +- .../controller/KIND_LOWER/KIND_LOWER.go.tmpl | 33 +++++++++++-------- internal/controller/template.go | 14 -------- package/crossplane.yaml | 3 ++ 6 files changed, 27 insertions(+), 30 deletions(-) diff --git a/apis/sample/sample.go b/apis/sample/sample.go index d5facdae..19ddc53e 100644 --- a/apis/sample/sample.go +++ b/apis/sample/sample.go @@ -14,5 +14,5 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package sample contains group Sample API versions +// Package sample contains group sample API versions package sample diff --git a/apis/sample/v1alpha1/groupversion_info.go b/apis/sample/v1alpha1/groupversion_info.go index 0a27cdc1..bd0a64bd 100644 --- a/apis/sample/v1alpha1/groupversion_info.go +++ b/apis/sample/v1alpha1/groupversion_info.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package v1alpha1 contains the v1alpha1 group Sample resources of the Template provider. +// Package v1alpha1 contains the v1alpha1 group Sample resources of the template provider. // +kubebuilder:object:generate=true // +groupName=sample.template.crossplane.io // +versionName=v1alpha1 diff --git a/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl b/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl index d9a24869..0205293c 100644 --- a/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl +++ b/hack/helpers/apis/GROUP_LOWER/APIVERSION/KIND_LOWER_types.go.tmpl @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" xpv2 "github.com/crossplane/crossplane-runtime/v2/apis/common/v2" ) @@ -44,7 +45,7 @@ type {{ .Env.KIND }}Spec struct { // A {{ .Env.KIND }}Status represents the observed state of a {{ .Env.KIND }}. type {{ .Env.KIND }}Status struct { - xpv2.ResourceStatus `json:",inline"` + xpv1.ResourceStatus `json:",inline"` AtProvider {{ .Env.KIND }}Observation `json:"atProvider,omitempty"` } diff --git a/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl b/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl index d9bdd928..1b13e38c 100644 --- a/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl +++ b/hack/helpers/controller/KIND_LOWER/KIND_LOWER.go.tmpl @@ -39,11 +39,11 @@ import ( ) const ( - errNot{{ .Env.KIND }} = "managed resource is not a {{ .Env.KIND }} custom resource" + errNot{{ .Env.KIND }} = "managed resource is not a {{ .Env.KIND }} custom resource" errTrackPCUsage = "cannot track ProviderConfig usage" - errGetPC = "cannot get ProviderConfig" - errGetCPC = "cannot get ClusterProviderConfig" - errGetCreds = "cannot get credentials" + errGetPC = "cannot get ProviderConfig" + errGetCPC = "cannot get ClusterProviderConfig" + errGetCreds = "cannot get credentials" errNewClient = "cannot create new Service" ) @@ -55,14 +55,21 @@ var ( newNoOpService = func(_ []byte) (interface{}, error) { return &NoOpService{}, nil } ) -// Setup adds a controller that reconciles {{ .Env.KIND }} managed resources. -func Setup(mgr ctrl.Manager, o controller.Options) error { - name := managed.ControllerName({{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}GroupKind) +// SetupGated adds a controller that reconciles {{ .Env.KIND }} managed resources with safe-start support. +func SetupGated(mgr ctrl.Manager, o controller.Options) error { + o.Gate.Register(func() { + if err := Setup(mgr, o); err != nil { + panic(errors.Wrap(err, "cannot setup {{ .Env.KIND }} controller")) + } + }, v1alpha1.{{ .Env.KIND }}GroupVersionKind) + return nil +} - cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())} +func Setup(mgr ctrl.Manager, o controller.Options) error { + name := managed.ControllerName(v1alpha1.{{ .Env.KIND }}GroupKind) opts := []managed.ReconcilerOption{ - managed.WithExternalConnecter(&connector{ + managed.WithExternalConnector(&connector{ kube: mgr.GetClient(), usage: resource.NewProviderConfigUsageTracker(mgr.GetClient(), &apisv1alpha1.ProviderConfigUsage{}), newServiceFn: newNoOpService}), @@ -85,20 +92,20 @@ func Setup(mgr ctrl.Manager, o controller.Options) error { if o.MetricOptions != nil && o.MetricOptions.MRStateMetrics != nil { stateMetricsRecorder := statemetrics.NewMRStateRecorder( - mgr.GetClient(), o.Logger, o.MetricOptions.MRStateMetrics, &{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}List{}, o.MetricOptions.PollStateMetricInterval, + mgr.GetClient(), o.Logger, o.MetricOptions.MRStateMetrics, &v1alpha1.{{ .Env.KIND }}List{}, o.MetricOptions.PollStateMetricInterval, ) if err := mgr.Add(stateMetricsRecorder); err != nil { - return errors.Wrap(err, "cannot register MR state metrics recorder for kind {{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}List") + return errors.Wrap(err, "cannot register MR state metrics recorder for kind v1alpha1.{{ .Env.KIND }}List") } } - r := managed.NewReconciler(mgr, resource.ManagedKind({{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}GroupVersionKind), opts...) + r := managed.NewReconciler(mgr, resource.ManagedKind(v1alpha1.{{ .Env.KIND }}GroupVersionKind), opts...) return ctrl.NewControllerManagedBy(mgr). Named(name). WithOptions(o.ForControllerRuntime()). WithEventFilter(resource.DesiredStateChanged()). - For(&{{ .Env.APIVERSION | strings.ToLower }}.{{ .Env.KIND }}{}). + For(&v1alpha1.{{ .Env.KIND }}{}). Complete(ratelimiter.NewReconciler(name, r, o.GlobalRateLimiter)) } diff --git a/internal/controller/template.go b/internal/controller/template.go index 7b43a806..fb497f1d 100644 --- a/internal/controller/template.go +++ b/internal/controller/template.go @@ -37,17 +37,3 @@ func SetupGated(mgr ctrl.Manager, o controller.Options) error { } return nil } - -// Setup creates all Template controllers with the supplied logger and adds them to -// the supplied manager. -func Setup(mgr ctrl.Manager, o controller.Options) error { - for _, setup := range []func(ctrl.Manager, controller.Options) error{ - config.Setup, - mytype.Setup, - } { - if err := setup(mgr, o); err != nil { - return err - } - } - return nil -} diff --git a/package/crossplane.yaml b/package/crossplane.yaml index e14f9f78..f6e6887d 100644 --- a/package/crossplane.yaml +++ b/package/crossplane.yaml @@ -8,3 +8,6 @@ metadata: meta.crossplane.io/license: Apache-2.0 meta.crossplane.io/description: | A template that can be used to create Crossplane providers. +spec: + capabilities: + - safe-start From e9688c8167480e1c887f76532b421581c07a0c69 Mon Sep 17 00:00:00 2001 From: Chuan-Yen Chiang Date: Sun, 19 Oct 2025 19:44:22 +0200 Subject: [PATCH 3/3] Rename template.go to register.go and update documentation This commit renames the controller registration file for better clarity and updates the README with instructions for using the safe-start pattern. Changes: - Rename internal/controller/template.go -> internal/controller/register.go to better reflect its purpose as a controller registration file - Update README.md to include step for registering new types in SetupGated function in register.go The rename makes it clearer that this file is responsible for registering controllers with the manager, and the README update ensures developers know to use the SetupGated function when adding new resource types. Signed-off-by: Chuan-Yen Chiang --- README.md | 1 + internal/controller/{template.go => register.go} | 0 2 files changed, 1 insertion(+) rename internal/controller/{template.go => register.go} (100%) diff --git a/README.md b/README.md index f06a7afa..53764b21 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ with the following features that are meant to be refactored: 5. Replace the *sample* group with your new group in apis/{provider}.go 5. Replace the *mytype* type with your new type in internal/controller/{provider}.go 5. Replace the default controller and ProviderConfig implementations with your own +5. Register your new type into `SetupGated` function in `internal/controller/register.go` 5. Run `make reviewable` to run code generation, linters, and tests. 5. Run `make build` to build the provider. diff --git a/internal/controller/template.go b/internal/controller/register.go similarity index 100% rename from internal/controller/template.go rename to internal/controller/register.go