diff --git a/.golangci.yml b/.golangci.yml index dee81ff..6a543e4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -219,6 +219,13 @@ linters: - staticcheck text: 'SA1019: .+ is deprecated: Use Composition Functions instead.' + # Some shared structs in apis/common/v1 are moved to + # apis/common. To preserve a backward-compatible directory structure + # package had to be named common, which we suppress. + - linters: + - revive + text: "var-naming: avoid meaningless package names" + path: apis/common paths: - zz_generated\..+\.go$ - .+\.pb.go$ diff --git a/apis/common/condition.go b/apis/common/condition.go new file mode 100644 index 0000000..f1c91b8 --- /dev/null +++ b/apis/common/condition.go @@ -0,0 +1,307 @@ +/* +Copyright 2019 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 common + +import ( + "sort" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// A ConditionType represents a condition a resource could be in. +type ConditionType string + +// Condition types. +const ( + // TypeReady resources are believed to be ready to handle work. + TypeReady ConditionType = "Ready" + + // TypeSynced resources are believed to be in sync with the + // Kubernetes resources that manage their lifecycle. + TypeSynced ConditionType = "Synced" + + // TypeHealthy resources are believed to be in a healthy state and to have all + // of their child resources in a healthy state. For example, a claim is + // healthy when the claim is synced and the underlying composite resource is + // both synced and healthy. A composite resource is healthy when the composite + // resource is synced and all composed resources are synced and, if + // applicable, healthy (e.g., the composed resource is a composite resource). + // TODO: This condition is not yet implemented. It is currently just reserved + // as a system condition. See the tracking issue for more details + // https://github.com/crossplane/crossplane/issues/5643. + TypeHealthy ConditionType = "Healthy" +) + +// A ConditionReason represents the reason a resource is in a condition. +type ConditionReason string + +// Reasons a resource is or is not ready. +const ( + ReasonAvailable ConditionReason = "Available" + ReasonUnavailable ConditionReason = "Unavailable" + ReasonCreating ConditionReason = "Creating" + ReasonDeleting ConditionReason = "Deleting" +) + +// Reasons a resource is or is not synced. +const ( + ReasonReconcileSuccess ConditionReason = "ReconcileSuccess" + ReasonReconcileError ConditionReason = "ReconcileError" + ReasonReconcilePaused ConditionReason = "ReconcilePaused" +) + +// See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties + +// A Condition that may apply to a resource. +type Condition struct { //nolint:recvcheck // False positive - only has non-pointer methods AFAICT. + // Type of this condition. At most one of each condition type may apply to + // a resource at any point in time. + Type ConditionType `json:"type"` + + // Status of this condition; is it currently True, False, or Unknown? + Status corev1.ConditionStatus `json:"status"` + + // LastTransitionTime is the last time this condition transitioned from one + // status to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime"` + + // A Reason for this condition's last transition from one status to another. + Reason ConditionReason `json:"reason"` + + // A Message containing details about this condition's last transition from + // one status to another, if any. + // +optional + Message string `json:"message,omitempty"` + + // 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. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// Equal returns true if the condition is identical to the supplied condition, +// ignoring the LastTransitionTime. +func (c Condition) Equal(other Condition) bool { + return c.Type == other.Type && + c.Status == other.Status && + c.Reason == other.Reason && + c.Message == other.Message && + c.ObservedGeneration == other.ObservedGeneration +} + +// WithMessage returns a condition by adding the provided message to existing +// condition. +func (c Condition) WithMessage(msg string) Condition { + c.Message = msg + return c +} + +// WithObservedGeneration returns a condition by adding the provided observed generation +// to existing condition. +func (c Condition) WithObservedGeneration(gen int64) Condition { + c.ObservedGeneration = gen + return c +} + +// IsSystemConditionType returns true if the condition is owned by the +// Crossplane system (e.g, Ready, Synced, Healthy). +func IsSystemConditionType(t ConditionType) bool { + switch t { + case TypeReady, TypeSynced, TypeHealthy: + return true + } + + return false +} + +// NOTE(negz): Conditions are implemented as a slice rather than a map to comply +// with Kubernetes API conventions. Ideally we'd comply by using a map that +// marshalled to a JSON array, but doing so confuses the CRD schema generator. +// https://github.com/kubernetes/community/blob/9bf8cd/contributors/devel/sig-architecture/api-conventions.md#lists-of-named-subobjects-preferred-over-maps + +// NOTE(negz): Do not manipulate Conditions directly. Use the Set method. + +// A ConditionedStatus reflects the observed status of a resource. Only +// one condition of each type may exist. +type ConditionedStatus struct { + // Conditions of the resource. + // +listType=map + // +listMapKey=type + // +optional + Conditions []Condition `json:"conditions,omitempty"` +} + +// NewConditionedStatus returns a stat with the supplied conditions set. +func NewConditionedStatus(c ...Condition) *ConditionedStatus { + s := &ConditionedStatus{} + s.SetConditions(c...) + + return s +} + +// GetCondition returns the condition for the given ConditionType if exists, +// otherwise returns nil. +func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition { + for _, c := range s.Conditions { + if c.Type == ct { + return c + } + } + + return Condition{Type: ct, Status: corev1.ConditionUnknown} +} + +// SetConditions sets the supplied conditions, replacing any existing conditions +// of the same type. This is a no-op if all supplied conditions are identical, +// ignoring the last transition time, to those already set. +func (s *ConditionedStatus) SetConditions(c ...Condition) { + for _, cond := range c { + exists := false + + for i, existing := range s.Conditions { + if existing.Type != cond.Type { + continue + } + + if existing.Equal(cond) { + exists = true + continue + } + + s.Conditions[i] = cond + exists = true + } + + if !exists { + s.Conditions = append(s.Conditions, cond) + } + } +} + +// Equal returns true if the status is identical to the supplied status, +// ignoring the LastTransitionTimes and order of statuses. +func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool { + if s == nil || other == nil { + return s == nil && other == nil + } + + if len(other.Conditions) != len(s.Conditions) { + return false + } + + sc := make([]Condition, len(s.Conditions)) + copy(sc, s.Conditions) + + oc := make([]Condition, len(other.Conditions)) + copy(oc, other.Conditions) + + // We should not have more than one condition of each type. + sort.Slice(sc, func(i, j int) bool { return sc[i].Type < sc[j].Type }) + sort.Slice(oc, func(i, j int) bool { return oc[i].Type < oc[j].Type }) + + for i := range sc { + if !sc[i].Equal(oc[i]) { + return false + } + } + + return true +} + +// Creating returns a condition that indicates the resource is currently +// being created. +func Creating() Condition { + return Condition{ + Type: TypeReady, + Status: corev1.ConditionFalse, + LastTransitionTime: metav1.Now(), + Reason: ReasonCreating, + } +} + +// Deleting returns a condition that indicates the resource is currently +// being deleted. +func Deleting() Condition { + return Condition{ + Type: TypeReady, + Status: corev1.ConditionFalse, + LastTransitionTime: metav1.Now(), + Reason: ReasonDeleting, + } +} + +// Available returns a condition that indicates the resource is +// currently observed to be available for use. +func Available() Condition { + return Condition{ + Type: TypeReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + Reason: ReasonAvailable, + } +} + +// Unavailable returns a condition that indicates the resource is not +// currently available for use. Unavailable should be set only when Crossplane +// expects the resource to be available but knows it is not, for example +// because its API reports it is unhealthy. +func Unavailable() Condition { + return Condition{ + Type: TypeReady, + Status: corev1.ConditionFalse, + LastTransitionTime: metav1.Now(), + Reason: ReasonUnavailable, + } +} + +// ReconcileSuccess returns a condition indicating that Crossplane successfully +// completed the most recent reconciliation of the resource. +func ReconcileSuccess() Condition { + return Condition{ + Type: TypeSynced, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + Reason: ReasonReconcileSuccess, + } +} + +// ReconcileError returns a condition indicating that Crossplane encountered an +// error while reconciling the resource. This could mean Crossplane was +// unable to update the resource to reflect its desired state, or that +// Crossplane was unable to determine the current actual state of the resource. +func ReconcileError(err error) Condition { + return Condition{ + Type: TypeSynced, + Status: corev1.ConditionFalse, + LastTransitionTime: metav1.Now(), + Reason: ReasonReconcileError, + Message: err.Error(), + } +} + +// ReconcilePaused returns a condition that indicates reconciliation on +// the managed resource is paused via the pause annotation. +func ReconcilePaused() Condition { + return Condition{ + Type: TypeSynced, + Status: corev1.ConditionFalse, + LastTransitionTime: metav1.Now(), + Reason: ReasonReconcilePaused, + } +} diff --git a/apis/common/v1/condition_test.go b/apis/common/condition_test.go similarity index 99% rename from apis/common/v1/condition_test.go rename to apis/common/condition_test.go index 5e8c52e..03c52d0 100644 --- a/apis/common/v1/condition_test.go +++ b/apis/common/condition_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1 +package common import ( "testing" diff --git a/apis/common/doc.go b/apis/common/doc.go new file mode 100644 index 0000000..515e9a1 --- /dev/null +++ b/apis/common/doc.go @@ -0,0 +1,3 @@ +// Package common contains core API types used by most Crossplane resources. +// +kubebuilder:object:generate=true +package common diff --git a/apis/common/merge.go b/apis/common/merge.go new file mode 100644 index 0000000..c471ebf --- /dev/null +++ b/apis/common/merge.go @@ -0,0 +1,54 @@ +/* +Copyright 2021 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 common + +import ( + "dario.cat/mergo" +) + +// MergeOptions Specifies merge options on a field path. +type MergeOptions struct { // TODO(aru): add more options that control merging behavior + // Specifies that already existing values in a merged map should be preserved + // +optional + KeepMapValues *bool `json:"keepMapValues,omitempty"` + // Specifies that already existing elements in a merged slice should be preserved + // +optional + AppendSlice *bool `json:"appendSlice,omitempty"` +} + +// MergoConfiguration the default behavior is to replace maps and slices. +func (mo *MergeOptions) MergoConfiguration() []func(*mergo.Config) { + config := []func(*mergo.Config){mergo.WithOverride} + if mo == nil { + return config + } + + if mo.KeepMapValues != nil && *mo.KeepMapValues { + config = config[:0] + } + + if mo.AppendSlice != nil && *mo.AppendSlice { + config = append(config, mergo.WithAppendSlice) + } + + return config +} + +// IsAppendSlice returns true if mo.AppendSlice is set to true. +func (mo *MergeOptions) IsAppendSlice() bool { + return mo != nil && mo.AppendSlice != nil && *mo.AppendSlice +} diff --git a/apis/common/v1/merge_test.go b/apis/common/merge_test.go similarity index 99% rename from apis/common/v1/merge_test.go rename to apis/common/merge_test.go index 8f4caa3..80e1450 100644 --- a/apis/common/v1/merge_test.go +++ b/apis/common/merge_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1 +package common import ( "reflect" diff --git a/apis/common/observation.go b/apis/common/observation.go new file mode 100644 index 0000000..8260be8 --- /dev/null +++ b/apis/common/observation.go @@ -0,0 +1,37 @@ +/* +Copyright 2024 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 common + +// ObservedStatus contains the recent reconciliation stats. +type ObservedStatus struct { + // ObservedGeneration is the latest metadata.generation + // which resulted in either a ready state, or stalled due to error + // it can not recover from without human intervention. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// SetObservedGeneration sets the generation of the main resource +// during the last reconciliation. +func (s *ObservedStatus) SetObservedGeneration(generation int64) { + s.ObservedGeneration = generation +} + +// GetObservedGeneration returns the last observed generation of the main resource. +func (s *ObservedStatus) GetObservedGeneration() int64 { + return s.ObservedGeneration +} diff --git a/apis/common/policies.go b/apis/common/policies.go new file mode 100644 index 0000000..c2e2cfe --- /dev/null +++ b/apis/common/policies.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 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 common + +// ManagementPolicies determine how should Crossplane controllers manage an +// external resource through an array of ManagementActions. +type ManagementPolicies []ManagementAction + +// A ManagementAction represents an action that the Crossplane controllers +// can take on an external resource. +// +kubebuilder:validation:Enum=Observe;Create;Update;Delete;LateInitialize;* +type ManagementAction string + +const ( + // ManagementActionObserve means that the managed resource status.atProvider + // will be updated with the external resource state. + ManagementActionObserve ManagementAction = "Observe" + + // ManagementActionCreate means that the external resource will be created + // using the managed resource spec.initProvider and spec.forProvider. + ManagementActionCreate ManagementAction = "Create" + + // ManagementActionUpdate means that the external resource will be updated + // using the managed resource spec.forProvider. + ManagementActionUpdate ManagementAction = "Update" + + // ManagementActionDelete means that the external resource will be deleted + // when the managed resource is deleted. + ManagementActionDelete ManagementAction = "Delete" + + // ManagementActionLateInitialize means that unspecified fields of the managed + // resource spec.forProvider will be updated with the external resource state. + ManagementActionLateInitialize ManagementAction = "LateInitialize" + + // ManagementActionAll means that all of the above actions will be taken + // by the Crossplane controllers. + ManagementActionAll ManagementAction = "*" +) + +// A DeletionPolicy determines what should happen to the underlying external +// resource when a managed resource is deleted. +// +kubebuilder:validation:Enum=Orphan;Delete +type DeletionPolicy string + +const ( + // DeletionOrphan means the external resource will be orphaned when its + // managed resource is deleted. + DeletionOrphan DeletionPolicy = "Orphan" + + // DeletionDelete means both the external resource will be deleted when its + // managed resource is deleted. + DeletionDelete DeletionPolicy = "Delete" +) + +// A CompositeDeletePolicy determines how the composite resource should be deleted +// when the corresponding claim is deleted. +// +kubebuilder:validation:Enum=Background;Foreground +type CompositeDeletePolicy string + +const ( + // CompositeDeleteBackground means the composite resource will be deleted using + // the Background Propagation Policy when the claim is deleted. + CompositeDeleteBackground CompositeDeletePolicy = "Background" + + // CompositeDeleteForeground means the composite resource will be deleted using + // the Foreground Propagation Policy when the claim is deleted. + CompositeDeleteForeground CompositeDeletePolicy = "Foreground" +) + +// An UpdatePolicy determines how something should be updated - either +// automatically (without human intervention) or manually. +// +kubebuilder:validation:Enum=Automatic;Manual +type UpdatePolicy string + +const ( + // UpdateAutomatic means the resource should be updated automatically, + // without any human intervention. + UpdateAutomatic UpdatePolicy = "Automatic" + + // UpdateManual means the resource requires human intervention to + // update. + UpdateManual UpdatePolicy = "Manual" +) + +// ResolvePolicy is a type for resolve policy. +type ResolvePolicy string + +// ResolutionPolicy is a type for resolution policy. +type ResolutionPolicy string + +const ( + // ResolvePolicyAlways is a resolve option. + // When the ResolvePolicy is set to ResolvePolicyAlways the reference will + // be tried to resolve for every reconcile loop. + ResolvePolicyAlways ResolvePolicy = "Always" + + // ResolutionPolicyRequired is a resolution option. + // When the ResolutionPolicy is set to ResolutionPolicyRequired the execution + // could not continue even if the reference cannot be resolved. + ResolutionPolicyRequired ResolutionPolicy = "Required" + + // ResolutionPolicyOptional is a resolution option. + // When the ReferenceResolutionPolicy is set to ReferencePolicyOptional the + // execution could continue even if the reference cannot be resolved. + ResolutionPolicyOptional ResolutionPolicy = "Optional" +) diff --git a/apis/common/resource.go b/apis/common/resource.go new file mode 100644 index 0000000..c80207d --- /dev/null +++ b/apis/common/resource.go @@ -0,0 +1,328 @@ +/* +Copyright 2019 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 common + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" +) + +const ( + // ResourceCredentialsSecretEndpointKey is the key inside a connection secret for the connection endpoint. + ResourceCredentialsSecretEndpointKey = "endpoint" + // ResourceCredentialsSecretPortKey is the key inside a connection secret for the connection port. + ResourceCredentialsSecretPortKey = "port" + // ResourceCredentialsSecretUserKey is the key inside a connection secret for the connection user. + ResourceCredentialsSecretUserKey = "username" + // ResourceCredentialsSecretPasswordKey is the key inside a connection secret for the connection password. + ResourceCredentialsSecretPasswordKey = "password" + // ResourceCredentialsSecretCAKey is the key inside a connection secret for the server CA certificate. + ResourceCredentialsSecretCAKey = "clusterCA" + // ResourceCredentialsSecretClientCertKey is the key inside a connection secret for the client certificate. + ResourceCredentialsSecretClientCertKey = "clientCert" + // ResourceCredentialsSecretClientKeyKey is the key inside a connection secret for the client key. + ResourceCredentialsSecretClientKeyKey = "clientKey" + // ResourceCredentialsSecretTokenKey is the key inside a connection secret for the bearer token value. + ResourceCredentialsSecretTokenKey = "token" + // ResourceCredentialsSecretKubeconfigKey is the key inside a connection secret for the raw kubeconfig yaml. + ResourceCredentialsSecretKubeconfigKey = "kubeconfig" +) + +// LabelKeyProviderKind is added to ProviderConfigUsages to relate them to their +// ProviderConfig. +const LabelKeyProviderKind = "crossplane.io/provider-config-kind" + +// LabelKeyProviderName is added to ProviderConfigUsages to relate them to their +// ProviderConfig. +const LabelKeyProviderName = "crossplane.io/provider-config" + +// NOTE(negz): The below secret references differ from ObjectReference and +// LocalObjectReference in that they include only the fields Crossplane needs to +// reference a secret, and make those fields required. This reduces ambiguity in +// the API for resource authors. + +// A LocalSecretReference is a reference to a secret in the same namespace as +// the referencer. +type LocalSecretReference struct { + // Name of the secret. + Name string `json:"name"` +} + +// A SecretReference is a reference to a secret in an arbitrary namespace. +type SecretReference struct { + // Name of the secret. + Name string `json:"name"` + + // Namespace of the secret. + Namespace string `json:"namespace"` +} + +// A SecretKeySelector is a reference to a secret key in an arbitrary namespace. +type SecretKeySelector struct { + SecretReference `json:",inline"` + + // The key to select. + Key string `json:"key"` +} + +// A LocalSecretKeySelector is a reference to a secret key +// in the same namespace with the referencing object. +type LocalSecretKeySelector struct { + LocalSecretReference `json:",inline"` + + Key string `json:"key"` +} + +// ToSecretKeySelector is a convenience method for converting the +// LocalSecretKeySelector to a SecretKeySelector with the given namespace. +func (ls *LocalSecretKeySelector) ToSecretKeySelector(namespace string) *SecretKeySelector { + return &SecretKeySelector{ + SecretReference: SecretReference{ + Name: ls.Name, + Namespace: namespace, + }, + Key: ls.Key, + } +} + +// Policy represents the Resolve and Resolution policies of Reference instance. +type Policy struct { + // 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. + // +optional + // +kubebuilder:validation:Enum=Always;IfNotPresent + Resolve *ResolvePolicy `json:"resolve,omitempty"` + + // 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. + // +optional + // +kubebuilder:default=Required + // +kubebuilder:validation:Enum=Required;Optional + Resolution *ResolutionPolicy `json:"resolution,omitempty"` +} + +// IsResolutionPolicyOptional checks whether the resolution policy of relevant reference is Optional. +func (p *Policy) IsResolutionPolicyOptional() bool { + if p == nil || p.Resolution == nil { + return false + } + + return *p.Resolution == ResolutionPolicyOptional +} + +// IsResolvePolicyAlways checks whether the resolution policy of relevant reference is Always. +func (p *Policy) IsResolvePolicyAlways() bool { + if p == nil || p.Resolve == nil { + return false + } + + return *p.Resolve == ResolvePolicyAlways +} + +// A Reference to a named object. +type Reference struct { + // Name of the referenced object. + Name string `json:"name"` + + // Policies for referencing. + // +optional + Policy *Policy `json:"policy,omitempty"` +} + +// A NamespacedReference to a named object. +type NamespacedReference struct { + // Name of the referenced object. + Name string `json:"name"` + // Namespace of the referenced object + // +optional + Namespace string `json:"namespace,omitempty"` + // Policies for referencing. + // +optional + Policy *Policy `json:"policy,omitempty"` +} + +// A TypedReference refers to an object by Name, Kind, and APIVersion. It is +// commonly used to reference cluster-scoped objects or objects where the +// namespace is already known. +type TypedReference struct { + // APIVersion of the referenced object. + APIVersion string `json:"apiVersion"` + + // Kind of the referenced object. + Kind string `json:"kind"` + + // Name of the referenced object. + Name string `json:"name"` + + // UID of the referenced object. + // +optional + UID types.UID `json:"uid,omitempty"` +} + +// A Selector selects an object. +type Selector struct { + // MatchLabels ensures an object with matching labels is selected. + MatchLabels map[string]string `json:"matchLabels,omitempty"` + + // MatchControllerRef ensures an object with the same controller reference + // as the selecting object is selected. + MatchControllerRef *bool `json:"matchControllerRef,omitempty"` + + // Policies for selection. + // +optional + Policy *Policy `json:"policy,omitempty"` +} + +// NamespacedSelector selects a namespaced object. +type NamespacedSelector struct { + // MatchLabels ensures an object with matching labels is selected. + MatchLabels map[string]string `json:"matchLabels,omitempty"` + + // MatchControllerRef ensures an object with the same controller reference + // as the selecting object is selected. + MatchControllerRef *bool `json:"matchControllerRef,omitempty"` + + // Policies for selection. + // +optional + Policy *Policy `json:"policy,omitempty"` + + // Namespace for the selector + // +optional + Namespace string `json:"namespace,omitempty"` +} + +// ProviderConfigReference is a typed reference to a ProviderConfig +// object, with a known api group. +type ProviderConfigReference struct { + // Kind of the referenced object. + Kind string `json:"kind"` + + // Name of the referenced object. + Name string `json:"name"` +} + +// SetGroupVersionKind sets the Kind and APIVersion of a TypedReference. +func (obj *TypedReference) SetGroupVersionKind(gvk schema.GroupVersionKind) { + obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() +} + +// GroupVersionKind gets the GroupVersionKind of a TypedReference. +func (obj *TypedReference) GroupVersionKind() schema.GroupVersionKind { + return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) +} + +// GetObjectKind get the ObjectKind of a TypedReference. +func (obj *TypedReference) GetObjectKind() schema.ObjectKind { return obj } + +// ResourceStatus represents the observed state of a managed resource. +type ResourceStatus struct { + ConditionedStatus `json:",inline"` + ObservedStatus `json:",inline"` +} + +// A CredentialsSource is a source from which provider credentials may be +// acquired. +type CredentialsSource string + +const ( + // CredentialsSourceNone indicates that a provider does not require + // credentials. + CredentialsSourceNone CredentialsSource = "None" + + // CredentialsSourceSecret indicates that a provider should acquire + // credentials from a secret. + CredentialsSourceSecret CredentialsSource = "Secret" + + // CredentialsSourceInjectedIdentity indicates that a provider should use + // credentials via its (pod's) identity; i.e. via IRSA for AWS, + // Workload Identity for GCP, Pod Identity for Azure, or in-cluster + // authentication for the Kubernetes API. + CredentialsSourceInjectedIdentity CredentialsSource = "InjectedIdentity" + + // CredentialsSourceEnvironment indicates that a provider should acquire + // credentials from an environment variable. + CredentialsSourceEnvironment CredentialsSource = "Environment" + + // CredentialsSourceFilesystem indicates that a provider should acquire + // credentials from the filesystem. + CredentialsSourceFilesystem CredentialsSource = "Filesystem" +) + +// CommonCredentialSelectors provides common selectors for extracting +// credentials. +// +//nolint:revive // preserve backward-compatibility +type CommonCredentialSelectors struct { + // Fs is a reference to a filesystem location that contains credentials that + // must be used to connect to the provider. + // +optional + Fs *FsSelector `json:"fs,omitempty"` + + // Env is a reference to an environment variable that contains credentials + // that must be used to connect to the provider. + // +optional + Env *EnvSelector `json:"env,omitempty"` + + // A SecretRef is a reference to a secret key that contains the credentials + // that must be used to connect to the provider. + // +optional + SecretRef *SecretKeySelector `json:"secretRef,omitempty"` +} + +// EnvSelector selects an environment variable. +type EnvSelector struct { + // Name is the name of an environment variable. + Name string `json:"name"` +} + +// FsSelector selects a filesystem location. +type FsSelector struct { + // Path is a filesystem path. + Path string `json:"path"` +} + +// A ProviderConfigStatus defines the observed status of a ProviderConfig. +type ProviderConfigStatus struct { + ConditionedStatus `json:",inline"` + + // Users of this provider configuration. + Users int64 `json:"users,omitempty"` +} + +// A ProviderConfigUsage is a record that a particular managed resource is using +// a particular provider configuration. +type ProviderConfigUsage struct { + // ProviderConfigReference to the provider config being used. + ProviderConfigReference Reference `json:"providerConfigRef"` + + // ResourceReference to the managed resource using the provider config. + ResourceReference TypedReference `json:"resourceRef"` +} + +// A TypedProviderConfigUsage is a record that a particular managed resource is using +// a particular provider configuration. +type TypedProviderConfigUsage struct { + // ProviderConfigReference to the provider config being used. + ProviderConfigReference ProviderConfigReference `json:"providerConfigRef"` + + // ResourceReference to the managed resource using the provider config. + ResourceReference TypedReference `json:"resourceRef"` +} diff --git a/apis/common/v1/condition.go b/apis/common/v1/condition.go index 5a2cc4e..16d2197 100644 --- a/apis/common/v1/condition.go +++ b/apis/common/v1/condition.go @@ -17,23 +17,20 @@ limitations under the License. package v1 import ( - "sort" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/crossplane/crossplane-runtime/apis/common" ) // A ConditionType represents a condition a resource could be in. -type ConditionType string +type ConditionType = common.ConditionType // Condition types. const ( // TypeReady resources are believed to be ready to handle work. - TypeReady ConditionType = "Ready" + TypeReady ConditionType = common.TypeReady // TypeSynced resources are believed to be in sync with the // Kubernetes resources that manage their lifecycle. - TypeSynced ConditionType = "Synced" + TypeSynced ConditionType = common.TypeSynced // TypeHealthy resources are believed to be in a healthy state and to have all // of their child resources in a healthy state. For example, a claim is @@ -44,90 +41,36 @@ const ( // TODO: This condition is not yet implemented. It is currently just reserved // as a system condition. See the tracking issue for more details // https://github.com/crossplane/crossplane/issues/5643. - TypeHealthy ConditionType = "Healthy" + TypeHealthy ConditionType = common.TypeHealthy ) // A ConditionReason represents the reason a resource is in a condition. -type ConditionReason string +type ConditionReason = common.ConditionReason // Reasons a resource is or is not ready. const ( - ReasonAvailable ConditionReason = "Available" - ReasonUnavailable ConditionReason = "Unavailable" - ReasonCreating ConditionReason = "Creating" - ReasonDeleting ConditionReason = "Deleting" + ReasonAvailable = common.ReasonAvailable + ReasonUnavailable = common.ReasonUnavailable + ReasonCreating = common.ReasonCreating + ReasonDeleting = common.ReasonDeleting ) // Reasons a resource is or is not synced. const ( - ReasonReconcileSuccess ConditionReason = "ReconcileSuccess" - ReasonReconcileError ConditionReason = "ReconcileError" - ReasonReconcilePaused ConditionReason = "ReconcilePaused" + ReasonReconcileSuccess = common.ReasonReconcileSuccess + ReasonReconcileError = common.ReasonReconcileError + ReasonReconcilePaused = common.ReasonReconcilePaused ) // See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties // A Condition that may apply to a resource. -type Condition struct { //nolint:recvcheck // False positive - only has non-pointer methods AFAICT. - // Type of this condition. At most one of each condition type may apply to - // a resource at any point in time. - Type ConditionType `json:"type"` - - // Status of this condition; is it currently True, False, or Unknown? - Status corev1.ConditionStatus `json:"status"` - - // LastTransitionTime is the last time this condition transitioned from one - // status to another. - LastTransitionTime metav1.Time `json:"lastTransitionTime"` - - // A Reason for this condition's last transition from one status to another. - Reason ConditionReason `json:"reason"` - - // A Message containing details about this condition's last transition from - // one status to another, if any. - // +optional - Message string `json:"message,omitempty"` - - // 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. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` -} - -// Equal returns true if the condition is identical to the supplied condition, -// ignoring the LastTransitionTime. -func (c Condition) Equal(other Condition) bool { - return c.Type == other.Type && - c.Status == other.Status && - c.Reason == other.Reason && - c.Message == other.Message && - c.ObservedGeneration == other.ObservedGeneration -} - -// WithMessage returns a condition by adding the provided message to existing -// condition. -func (c Condition) WithMessage(msg string) Condition { - c.Message = msg - return c -} - -// WithObservedGeneration returns a condition by adding the provided observed generation -// to existing condition. -func (c Condition) WithObservedGeneration(gen int64) Condition { - c.ObservedGeneration = gen - return c -} +type Condition = common.Condition // IsSystemConditionType returns true if the condition is owned by the // Crossplane system (e.g, Ready, Synced, Healthy). func IsSystemConditionType(t ConditionType) bool { - switch t { - case TypeReady, TypeSynced, TypeHealthy: - return true - } - - return false + return common.IsSystemConditionType(t) } // NOTE(negz): Conditions are implemented as a slice rather than a map to comply @@ -139,122 +82,29 @@ func IsSystemConditionType(t ConditionType) bool { // A ConditionedStatus reflects the observed status of a resource. Only // one condition of each type may exist. -type ConditionedStatus struct { - // Conditions of the resource. - // +listType=map - // +listMapKey=type - // +optional - Conditions []Condition `json:"conditions,omitempty"` -} +type ConditionedStatus = common.ConditionedStatus // NewConditionedStatus returns a stat with the supplied conditions set. func NewConditionedStatus(c ...Condition) *ConditionedStatus { - s := &ConditionedStatus{} - s.SetConditions(c...) - - return s -} - -// GetCondition returns the condition for the given ConditionType if exists, -// otherwise returns nil. -func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition { - for _, c := range s.Conditions { - if c.Type == ct { - return c - } - } - - return Condition{Type: ct, Status: corev1.ConditionUnknown} -} - -// SetConditions sets the supplied conditions, replacing any existing conditions -// of the same type. This is a no-op if all supplied conditions are identical, -// ignoring the last transition time, to those already set. -func (s *ConditionedStatus) SetConditions(c ...Condition) { - for _, cond := range c { - exists := false - - for i, existing := range s.Conditions { - if existing.Type != cond.Type { - continue - } - - if existing.Equal(cond) { - exists = true - continue - } - - s.Conditions[i] = cond - exists = true - } - - if !exists { - s.Conditions = append(s.Conditions, cond) - } - } -} - -// Equal returns true if the status is identical to the supplied status, -// ignoring the LastTransitionTimes and order of statuses. -func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool { - if s == nil || other == nil { - return s == nil && other == nil - } - - if len(other.Conditions) != len(s.Conditions) { - return false - } - - sc := make([]Condition, len(s.Conditions)) - copy(sc, s.Conditions) - - oc := make([]Condition, len(other.Conditions)) - copy(oc, other.Conditions) - - // We should not have more than one condition of each type. - sort.Slice(sc, func(i, j int) bool { return sc[i].Type < sc[j].Type }) - sort.Slice(oc, func(i, j int) bool { return oc[i].Type < oc[j].Type }) - - for i := range sc { - if !sc[i].Equal(oc[i]) { - return false - } - } - - return true + return common.NewConditionedStatus(c...) } // Creating returns a condition that indicates the resource is currently // being created. func Creating() Condition { - return Condition{ - Type: TypeReady, - Status: corev1.ConditionFalse, - LastTransitionTime: metav1.Now(), - Reason: ReasonCreating, - } + return common.Creating() } // Deleting returns a condition that indicates the resource is currently // being deleted. func Deleting() Condition { - return Condition{ - Type: TypeReady, - Status: corev1.ConditionFalse, - LastTransitionTime: metav1.Now(), - Reason: ReasonDeleting, - } + return common.Deleting() } // Available returns a condition that indicates the resource is // currently observed to be available for use. func Available() Condition { - return Condition{ - Type: TypeReady, - Status: corev1.ConditionTrue, - LastTransitionTime: metav1.Now(), - Reason: ReasonAvailable, - } + return common.Available() } // Unavailable returns a condition that indicates the resource is not @@ -262,23 +112,13 @@ func Available() Condition { // expects the resource to be available but knows it is not, for example // because its API reports it is unhealthy. func Unavailable() Condition { - return Condition{ - Type: TypeReady, - Status: corev1.ConditionFalse, - LastTransitionTime: metav1.Now(), - Reason: ReasonUnavailable, - } + return common.Unavailable() } // ReconcileSuccess returns a condition indicating that Crossplane successfully // completed the most recent reconciliation of the resource. func ReconcileSuccess() Condition { - return Condition{ - Type: TypeSynced, - Status: corev1.ConditionTrue, - LastTransitionTime: metav1.Now(), - Reason: ReasonReconcileSuccess, - } + return common.ReconcileSuccess() } // ReconcileError returns a condition indicating that Crossplane encountered an @@ -286,22 +126,11 @@ func ReconcileSuccess() Condition { // unable to update the resource to reflect its desired state, or that // Crossplane was unable to determine the current actual state of the resource. func ReconcileError(err error) Condition { - return Condition{ - Type: TypeSynced, - Status: corev1.ConditionFalse, - LastTransitionTime: metav1.Now(), - Reason: ReasonReconcileError, - Message: err.Error(), - } + return common.ReconcileError(err) } // ReconcilePaused returns a condition that indicates reconciliation on // the managed resource is paused via the pause annotation. func ReconcilePaused() Condition { - return Condition{ - Type: TypeSynced, - Status: corev1.ConditionFalse, - LastTransitionTime: metav1.Now(), - Reason: ReasonReconcilePaused, - } + return common.ReconcilePaused() } diff --git a/apis/common/v1/merge.go b/apis/common/v1/merge.go index 929d8f3..3b16e18 100644 --- a/apis/common/v1/merge.go +++ b/apis/common/v1/merge.go @@ -17,38 +17,8 @@ limitations under the License. package v1 import ( - "dario.cat/mergo" + "github.com/crossplane/crossplane-runtime/apis/common" ) // MergeOptions Specifies merge options on a field path. -type MergeOptions struct { // TODO(aru): add more options that control merging behavior - // Specifies that already existing values in a merged map should be preserved - // +optional - KeepMapValues *bool `json:"keepMapValues,omitempty"` - // Specifies that already existing elements in a merged slice should be preserved - // +optional - AppendSlice *bool `json:"appendSlice,omitempty"` -} - -// MergoConfiguration the default behavior is to replace maps and slices. -func (mo *MergeOptions) MergoConfiguration() []func(*mergo.Config) { - config := []func(*mergo.Config){mergo.WithOverride} - if mo == nil { - return config - } - - if mo.KeepMapValues != nil && *mo.KeepMapValues { - config = config[:0] - } - - if mo.AppendSlice != nil && *mo.AppendSlice { - config = append(config, mergo.WithAppendSlice) - } - - return config -} - -// IsAppendSlice returns true if mo.AppendSlice is set to true. -func (mo *MergeOptions) IsAppendSlice() bool { - return mo != nil && mo.AppendSlice != nil && *mo.AppendSlice -} +type MergeOptions = common.MergeOptions diff --git a/apis/common/v1/observation.go b/apis/common/v1/observation.go index 65ff575..82930b0 100644 --- a/apis/common/v1/observation.go +++ b/apis/common/v1/observation.go @@ -16,22 +16,9 @@ limitations under the License. package v1 +import ( + "github.com/crossplane/crossplane-runtime/apis/common" +) + // ObservedStatus contains the recent reconciliation stats. -type ObservedStatus struct { - // ObservedGeneration is the latest metadata.generation - // which resulted in either a ready state, or stalled due to error - // it can not recover from without human intervention. - // +optional - ObservedGeneration int64 `json:"observedGeneration,omitempty"` -} - -// SetObservedGeneration sets the generation of the main resource -// during the last reconciliation. -func (s *ObservedStatus) SetObservedGeneration(generation int64) { - s.ObservedGeneration = generation -} - -// GetObservedGeneration returns the last observed generation of the main resource. -func (s *ObservedStatus) GetObservedGeneration() int64 { - return s.ObservedGeneration -} +type ObservedStatus = common.ObservedStatus diff --git a/apis/common/v1/policies.go b/apis/common/v1/policies.go index 6145aee..4ffbb46 100644 --- a/apis/common/v1/policies.go +++ b/apis/common/v1/policies.go @@ -16,39 +16,42 @@ limitations under the License. package v1 +import ( + "github.com/crossplane/crossplane-runtime/apis/common" +) + // ManagementPolicies determine how should Crossplane controllers manage an // external resource through an array of ManagementActions. -type ManagementPolicies []ManagementAction +type ManagementPolicies = common.ManagementPolicies // A ManagementAction represents an action that the Crossplane controllers // can take on an external resource. -// +kubebuilder:validation:Enum=Observe;Create;Update;Delete;LateInitialize;* -type ManagementAction string +type ManagementAction = common.ManagementAction const ( // ManagementActionObserve means that the managed resource status.atProvider // will be updated with the external resource state. - ManagementActionObserve ManagementAction = "Observe" + ManagementActionObserve = common.ManagementActionObserve // ManagementActionCreate means that the external resource will be created // using the managed resource spec.initProvider and spec.forProvider. - ManagementActionCreate ManagementAction = "Create" + ManagementActionCreate = common.ManagementActionCreate // ManagementActionUpdate means that the external resource will be updated // using the managed resource spec.forProvider. - ManagementActionUpdate ManagementAction = "Update" + ManagementActionUpdate = common.ManagementActionUpdate // ManagementActionDelete means that the external resource will be deleted // when the managed resource is deleted. - ManagementActionDelete ManagementAction = "Delete" + ManagementActionDelete = common.ManagementActionDelete // ManagementActionLateInitialize means that unspecified fields of the managed // resource spec.forProvider will be updated with the external resource state. - ManagementActionLateInitialize ManagementAction = "LateInitialize" + ManagementActionLateInitialize = common.ManagementActionLateInitialize // ManagementActionAll means that all of the above actions will be taken // by the Crossplane controllers. - ManagementActionAll ManagementAction = "*" + ManagementActionAll = common.ManagementActionAll ) // A DeletionPolicy determines what should happen to the underlying external @@ -68,53 +71,51 @@ const ( // A CompositeDeletePolicy determines how the composite resource should be deleted // when the corresponding claim is deleted. -// +kubebuilder:validation:Enum=Background;Foreground -type CompositeDeletePolicy string +type CompositeDeletePolicy = common.CompositeDeletePolicy const ( // CompositeDeleteBackground means the composite resource will be deleted using // the Background Propagation Policy when the claim is deleted. - CompositeDeleteBackground CompositeDeletePolicy = "Background" + CompositeDeleteBackground = common.CompositeDeleteBackground // CompositeDeleteForeground means the composite resource will be deleted using // the Foreground Propagation Policy when the claim is deleted. - CompositeDeleteForeground CompositeDeletePolicy = "Foreground" + CompositeDeleteForeground = common.CompositeDeleteForeground ) // An UpdatePolicy determines how something should be updated - either // automatically (without human intervention) or manually. -// +kubebuilder:validation:Enum=Automatic;Manual -type UpdatePolicy string +type UpdatePolicy = common.UpdatePolicy const ( // UpdateAutomatic means the resource should be updated automatically, // without any human intervention. - UpdateAutomatic UpdatePolicy = "Automatic" + UpdateAutomatic = common.UpdateAutomatic // UpdateManual means the resource requires human intervention to // update. - UpdateManual UpdatePolicy = "Manual" + UpdateManual = common.UpdateManual ) // ResolvePolicy is a type for resolve policy. -type ResolvePolicy string +type ResolvePolicy = common.ResolvePolicy // ResolutionPolicy is a type for resolution policy. -type ResolutionPolicy string +type ResolutionPolicy = common.ResolutionPolicy const ( // ResolvePolicyAlways is a resolve option. // When the ResolvePolicy is set to ResolvePolicyAlways the reference will // be tried to resolve for every reconcile loop. - ResolvePolicyAlways ResolvePolicy = "Always" + ResolvePolicyAlways = common.ResolvePolicyAlways // ResolutionPolicyRequired is a resolution option. // When the ResolutionPolicy is set to ResolutionPolicyRequired the execution // could not continue even if the reference cannot be resolved. - ResolutionPolicyRequired ResolutionPolicy = "Required" + ResolutionPolicyRequired = common.ResolutionPolicyRequired // ResolutionPolicyOptional is a resolution option. // When the ReferenceResolutionPolicy is set to ReferencePolicyOptional the // execution could continue even if the reference cannot be resolved. - ResolutionPolicyOptional ResolutionPolicy = "Optional" + ResolutionPolicyOptional = common.ResolutionPolicyOptional ) diff --git a/apis/common/v1/resource.go b/apis/common/v1/resource.go index 16e3ede..ded52e1 100644 --- a/apis/common/v1/resource.go +++ b/apis/common/v1/resource.go @@ -18,8 +18,8 @@ package v1 import ( corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" + + "github.com/crossplane/crossplane-runtime/apis/common" ) const ( @@ -45,11 +45,11 @@ const ( // LabelKeyProviderKind is added to ProviderConfigUsages to relate them to their // ProviderConfig. -const LabelKeyProviderKind = "crossplane.io/provider-config-kind" +const LabelKeyProviderKind = common.LabelKeyProviderKind // LabelKeyProviderName is added to ProviderConfigUsages to relate them to their // ProviderConfig. -const LabelKeyProviderName = "crossplane.io/provider-config" +const LabelKeyProviderName = common.LabelKeyProviderName // NOTE(negz): The below secret references differ from ObjectReference and // LocalObjectReference in that they include only the fields Crossplane needs to @@ -58,180 +58,41 @@ const LabelKeyProviderName = "crossplane.io/provider-config" // A LocalSecretReference is a reference to a secret in the same namespace as // the referencer. -type LocalSecretReference struct { - // Name of the secret. - Name string `json:"name"` -} +type LocalSecretReference = common.LocalSecretReference // A SecretReference is a reference to a secret in an arbitrary namespace. -type SecretReference struct { - // Name of the secret. - Name string `json:"name"` - // Namespace of the secret. - Namespace string `json:"namespace"` -} +type SecretReference = common.SecretReference // A SecretKeySelector is a reference to a secret key in an arbitrary namespace. -type SecretKeySelector struct { - SecretReference `json:",inline"` - - // The key to select. - Key string `json:"key"` -} +type SecretKeySelector = common.SecretKeySelector // A LocalSecretKeySelector is a reference to a secret key // in the same namespace with the referencing object. -type LocalSecretKeySelector struct { - LocalSecretReference `json:",inline"` - - Key string `json:"key"` -} - -// ToSecretKeySelector is a convenience method for converting the -// LocalSecretKeySelector to a SecretKeySelector with the given namespace. -func (ls *LocalSecretKeySelector) ToSecretKeySelector(namespace string) *SecretKeySelector { - return &SecretKeySelector{ - SecretReference: SecretReference{ - Name: ls.Name, - Namespace: namespace, - }, - Key: ls.Key, - } -} +type LocalSecretKeySelector = common.LocalSecretKeySelector // Policy represents the Resolve and Resolution policies of Reference instance. -type Policy struct { - // 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. - // +optional - // +kubebuilder:validation:Enum=Always;IfNotPresent - Resolve *ResolvePolicy `json:"resolve,omitempty"` - - // 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. - // +optional - // +kubebuilder:default=Required - // +kubebuilder:validation:Enum=Required;Optional - Resolution *ResolutionPolicy `json:"resolution,omitempty"` -} - -// IsResolutionPolicyOptional checks whether the resolution policy of relevant reference is Optional. -func (p *Policy) IsResolutionPolicyOptional() bool { - if p == nil || p.Resolution == nil { - return false - } - - return *p.Resolution == ResolutionPolicyOptional -} - -// IsResolvePolicyAlways checks whether the resolution policy of relevant reference is Always. -func (p *Policy) IsResolvePolicyAlways() bool { - if p == nil || p.Resolve == nil { - return false - } - - return *p.Resolve == ResolvePolicyAlways -} +type Policy = common.Policy // A Reference to a named object. -type Reference struct { - // Name of the referenced object. - Name string `json:"name"` - - // Policies for referencing. - // +optional - Policy *Policy `json:"policy,omitempty"` -} +type Reference = common.Reference // A NamespacedReference to a named object. -type NamespacedReference struct { - // Name of the referenced object. - Name string `json:"name"` - - // Namespace of the referenced object - // +optional - Namespace string `json:"namespace,omitempty"` - // Policies for referencing. - // +optional - Policy *Policy `json:"policy,omitempty"` -} +type NamespacedReference = common.NamespacedReference // A TypedReference refers to an object by Name, Kind, and APIVersion. It is // commonly used to reference cluster-scoped objects or objects where the // namespace is already known. -type TypedReference struct { - // APIVersion of the referenced object. - APIVersion string `json:"apiVersion"` - - // Kind of the referenced object. - Kind string `json:"kind"` - - // Name of the referenced object. - Name string `json:"name"` - - // UID of the referenced object. - // +optional - UID types.UID `json:"uid,omitempty"` -} +type TypedReference = common.TypedReference // A Selector selects an object. -type Selector struct { - // MatchLabels ensures an object with matching labels is selected. - MatchLabels map[string]string `json:"matchLabels,omitempty"` - - // MatchControllerRef ensures an object with the same controller reference - // as the selecting object is selected. - MatchControllerRef *bool `json:"matchControllerRef,omitempty"` - - // Policies for selection. - // +optional - Policy *Policy `json:"policy,omitempty"` -} +type Selector = common.Selector // NamespacedSelector selects a namespaced object. -type NamespacedSelector struct { - // MatchLabels ensures an object with matching labels is selected. - MatchLabels map[string]string `json:"matchLabels,omitempty"` - - // MatchControllerRef ensures an object with the same controller reference - // as the selecting object is selected. - MatchControllerRef *bool `json:"matchControllerRef,omitempty"` - - // Policies for selection. - // +optional - Policy *Policy `json:"policy,omitempty"` - - // Namespace for the selector - // +optional - Namespace string `json:"namespace,omitempty"` -} +type NamespacedSelector = common.NamespacedSelector // ProviderConfigReference is a typed reference to a ProviderConfig // object, with a known api group. -type ProviderConfigReference struct { - // Kind of the referenced object. - Kind string `json:"kind"` - - // Name of the referenced object. - Name string `json:"name"` -} - -// SetGroupVersionKind sets the Kind and APIVersion of a TypedReference. -func (obj *TypedReference) SetGroupVersionKind(gvk schema.GroupVersionKind) { - obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() -} - -// GroupVersionKind gets the GroupVersionKind of a TypedReference. -func (obj *TypedReference) GroupVersionKind() schema.GroupVersionKind { - return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) -} - -// GetObjectKind get the ObjectKind of a TypedReference. -func (obj *TypedReference) GetObjectKind() schema.ObjectKind { return obj } +type ProviderConfigReference = common.ProviderConfigReference // TODO(negz): Rename Resource* to Managed* to clarify that they enable the // resource.Managed interface. @@ -285,80 +146,48 @@ type ResourceStatus struct { // A CredentialsSource is a source from which provider credentials may be // acquired. -type CredentialsSource string +type CredentialsSource = common.CredentialsSource const ( // CredentialsSourceNone indicates that a provider does not require // credentials. - CredentialsSourceNone CredentialsSource = "None" + CredentialsSourceNone = common.CredentialsSourceNone // CredentialsSourceSecret indicates that a provider should acquire // credentials from a secret. - CredentialsSourceSecret CredentialsSource = "Secret" + CredentialsSourceSecret = common.CredentialsSourceSecret // CredentialsSourceInjectedIdentity indicates that a provider should use // credentials via its (pod's) identity; i.e. via IRSA for AWS, // Workload Identity for GCP, Pod Identity for Azure, or in-cluster // authentication for the Kubernetes API. - CredentialsSourceInjectedIdentity CredentialsSource = "InjectedIdentity" + CredentialsSourceInjectedIdentity = common.CredentialsSourceInjectedIdentity // CredentialsSourceEnvironment indicates that a provider should acquire // credentials from an environment variable. - CredentialsSourceEnvironment CredentialsSource = "Environment" + CredentialsSourceEnvironment = common.CredentialsSourceEnvironment // CredentialsSourceFilesystem indicates that a provider should acquire // credentials from the filesystem. - CredentialsSourceFilesystem CredentialsSource = "Filesystem" + CredentialsSourceFilesystem = common.CredentialsSourceFilesystem ) // CommonCredentialSelectors provides common selectors for extracting // credentials. -type CommonCredentialSelectors struct { - // Fs is a reference to a filesystem location that contains credentials that - // must be used to connect to the provider. - // +optional - Fs *FsSelector `json:"fs,omitempty"` - - // Env is a reference to an environment variable that contains credentials - // that must be used to connect to the provider. - // +optional - Env *EnvSelector `json:"env,omitempty"` - - // A SecretRef is a reference to a secret key that contains the credentials - // that must be used to connect to the provider. - // +optional - SecretRef *SecretKeySelector `json:"secretRef,omitempty"` -} +type CommonCredentialSelectors = common.CommonCredentialSelectors // EnvSelector selects an environment variable. -type EnvSelector struct { - // Name is the name of an environment variable. - Name string `json:"name"` -} +type EnvSelector = common.EnvSelector // FsSelector selects a filesystem location. -type FsSelector struct { - // Path is a filesystem path. - Path string `json:"path"` -} +type FsSelector = common.FsSelector // A ProviderConfigStatus defines the observed status of a ProviderConfig. -type ProviderConfigStatus struct { - ConditionedStatus `json:",inline"` - - // Users of this provider configuration. - Users int64 `json:"users,omitempty"` -} +type ProviderConfigStatus = common.ProviderConfigStatus // A ProviderConfigUsage is a record that a particular managed resource is using // a particular provider configuration. -type ProviderConfigUsage struct { - // ProviderConfigReference to the provider config being used. - ProviderConfigReference Reference `json:"providerConfigRef"` - - // ResourceReference to the managed resource using the provider config. - ResourceReference TypedReference `json:"resourceRef"` -} +type ProviderConfigUsage = common.ProviderConfigUsage // A TargetSpec defines the common fields of objects used for exposing // infrastructure to workloads that can be scheduled to. diff --git a/apis/common/v2/resource.go b/apis/common/v2/resource.go index fe0eec6..ac11702 100644 --- a/apis/common/v2/resource.go +++ b/apis/common/v2/resource.go @@ -16,7 +16,9 @@ limitations under the License. package v2 -import v1 "github.com/crossplane/crossplane-runtime/apis/common/v1" +import ( + "github.com/crossplane/crossplane-runtime/apis/common" +) // A ManagedResourceSpec defines the desired state of a managed resource. type ManagedResourceSpec struct { @@ -25,13 +27,13 @@ type ManagedResourceSpec struct { // be written. Connection details frequently include the endpoint, username, // and password required to connect to the managed resource. // +optional - WriteConnectionSecretToReference *v1.LocalSecretReference `json:"writeConnectionSecretToRef,omitempty"` + WriteConnectionSecretToReference *common.LocalSecretReference `json:"writeConnectionSecretToRef,omitempty"` // ProviderConfigReference specifies how the provider that will be used to // create, observe, update, and delete this managed resource should be // configured. // +kubebuilder:default={"kind": "ClusterProviderConfig", "name": "default"} - ProviderConfigReference *v1.ProviderConfigReference `json:"providerConfigRef,omitempty"` + ProviderConfigReference *common.ProviderConfigReference `json:"providerConfigRef,omitempty"` // THIS IS A BETA FIELD. It is on by default but can be opted out // through a Crossplane feature flag. @@ -41,15 +43,9 @@ type ManagedResourceSpec struct { // and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md // +optional // +kubebuilder:default={"*"} - ManagementPolicies v1.ManagementPolicies `json:"managementPolicies,omitempty"` + ManagementPolicies common.ManagementPolicies `json:"managementPolicies,omitempty"` } // A TypedProviderConfigUsage is a record that a particular managed resource is using // a particular provider configuration. -type TypedProviderConfigUsage struct { - // ProviderConfigReference to the provider config being used. - ProviderConfigReference v1.ProviderConfigReference `json:"providerConfigRef"` - - // ResourceReference to the managed resource using the provider config. - ResourceReference v1.TypedReference `json:"resourceRef"` -} +type TypedProviderConfigUsage = common.TypedProviderConfigUsage