From a09cb6b440ee6809e8d704f1833ef94abf88eadb Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Mon, 28 Apr 2025 22:01:18 +1000 Subject: [PATCH 1/2] Added experimental CR-based envelope API Signed-off-by: michaelawyu --- apis/placement/v1alpha1/envelope_types.go | 129 +++++++++++ .../v1alpha1/zz_generated.deepcopy.go | 174 +++++++++++++- ...tes-fleet.io_clusterresourceenvelopes.yaml | 213 ++++++++++++++++++ ...kubernetes-fleet.io_resourceenvelopes.yaml | 212 +++++++++++++++++ examples/envelopes/clusterscoped.yaml | 36 +++ examples/envelopes/namespacescoped.yaml | 33 +++ 6 files changed, 796 insertions(+), 1 deletion(-) create mode 100644 apis/placement/v1alpha1/envelope_types.go create mode 100644 config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml create mode 100644 config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml create mode 100644 examples/envelopes/clusterscoped.yaml create mode 100644 examples/envelopes/namespacescoped.yaml diff --git a/apis/placement/v1alpha1/envelope_types.go b/apis/placement/v1alpha1/envelope_types.go new file mode 100644 index 000000000..db3440e99 --- /dev/null +++ b/apis/placement/v1alpha1/envelope_types.go @@ -0,0 +1,129 @@ +/* +Copyright 2025 The KubeFleet 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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +genclient +// +genclient:nonNamespaced +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope="Cluster",categories={fleet,fleet-placement} +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ClusterResourceEnvelope wraps cluster-scoped resources for placement. +type ClusterResourceEnvelope struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // The desired state of ClusterResourceEnvelope. + // +kubebuilder:validation:Required + Spec EnvelopeSpec `json:"spec"` + + // The observed status of ClusterResourceEnvelope. + // +kubebuilder:validation:Optional + Status ClusterResourceEnvelopeStatus `json:"status,omitempty"` +} + +// EnvelopeSpec helps wrap resources for placement. +type EnvelopeSpec struct { + // A map of wrapped manifests. + // + // Each manifest is uniquely identified by a string key, typically a filename that represents + // the manifest. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinProperties=1 + // +kubebuilder:validation:MaxProperties=50 + Manifests map[string]Manifest `json:"manifests"` +} + +// Manifest is a wrapped resource. +type Manifest struct { + // The resource data. + // +kubebuilder:validation:Required + // +kubebuilder:validation:EmbeddedResource + // +kubebuilder:pruning:PreserveUnknownFields + Data runtime.RawExtension `json:"data"` +} + +// ClusterResourceEnvelopeStatus is the observed status of a ClusterResourceEnvelope. +type ClusterResourceEnvelopeStatus struct { + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // + // Conditions is an array of current observed conditions for ClusterResourceEnvelope. + // +kubebuilder:validation:Optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // ManifestConditions is an array of current observed conditions for each manifest in the envelope. + // +kubebuilder:validation:Optional + ManifestConditions []ManifestCondition `json:"manifestConditions,omitempty"` +} + +// ManifestCondition is the observed conditions of a wrapped manifest. +type ManifestCondition struct { + // The name of the manifest. + // +kubebuilder:validation:Required + Name string `json:"name"` + + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // + // Conditions is an array of current observed conditions for a wrapped manifest. + // +kubebuilder:validation:Optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +genclient +// +genclient:Namespaced +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope="Namespaced",categories={fleet,fleet-placement} +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ResourceEnvelope struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // The desired state of ResourceEnvelope. + // +kubebuilder:validation:Required + Spec EnvelopeSpec `json:"spec"` + + // The observed status of ResourceEnvelope. + // +kubebuilder:validation:Optional + Status ResourceEnvelopeStatus `json:"status,omitempty"` +} + +// ResourceEnvelopeStatus is the observed status of a ResourceEnvelope. +type ResourceEnvelopeStatus struct { + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // + // Conditions is an array of current observed conditions for ResourceEnvelope. + // +kubebuilder:validation:Optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // ManifestConditions is an array of current observed conditions for each manifest in the envelope. + // +kubebuilder:validation:Optional + ManifestConditions []ManifestCondition `json:"manifestConditions,omitempty"` +} diff --git a/apis/placement/v1alpha1/zz_generated.deepcopy.go b/apis/placement/v1alpha1/zz_generated.deepcopy.go index ccbe37c26..2790af308 100644 --- a/apis/placement/v1alpha1/zz_generated.deepcopy.go +++ b/apis/placement/v1alpha1/zz_generated.deepcopy.go @@ -23,7 +23,7 @@ package v1alpha1 import ( "github.com/kubefleet-dev/kubefleet/apis/placement/v1beta1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -161,6 +161,62 @@ func (in *ClusterApprovalRequestList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterResourceEnvelope) DeepCopyInto(out *ClusterResourceEnvelope) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResourceEnvelope. +func (in *ClusterResourceEnvelope) DeepCopy() *ClusterResourceEnvelope { + if in == nil { + return nil + } + out := new(ClusterResourceEnvelope) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterResourceEnvelope) 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 *ClusterResourceEnvelopeStatus) DeepCopyInto(out *ClusterResourceEnvelopeStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ManifestConditions != nil { + in, out := &in.ManifestConditions, &out.ManifestConditions + *out = make([]ManifestCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResourceEnvelopeStatus. +func (in *ClusterResourceEnvelopeStatus) DeepCopy() *ClusterResourceEnvelopeStatus { + if in == nil { + return nil + } + out := new(ClusterResourceEnvelopeStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterResourceOverride) DeepCopyInto(out *ClusterResourceOverride) { *out = *in @@ -596,6 +652,28 @@ func (in *ClusterUpdatingStatus) DeepCopy() *ClusterUpdatingStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvelopeSpec) DeepCopyInto(out *EnvelopeSpec) { + *out = *in + if in.Manifests != nil { + in, out := &in.Manifests, &out.Manifests + *out = make(map[string]Manifest, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvelopeSpec. +func (in *EnvelopeSpec) DeepCopy() *EnvelopeSpec { + if in == nil { + return nil + } + out := new(EnvelopeSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *JSONPatchOverride) DeepCopyInto(out *JSONPatchOverride) { *out = *in @@ -612,6 +690,44 @@ func (in *JSONPatchOverride) DeepCopy() *JSONPatchOverride { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Manifest) DeepCopyInto(out *Manifest) { + *out = *in + in.Data.DeepCopyInto(&out.Data) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Manifest. +func (in *Manifest) DeepCopy() *Manifest { + if in == nil { + return nil + } + out := new(Manifest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManifestCondition) DeepCopyInto(out *ManifestCondition) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManifestCondition. +func (in *ManifestCondition) DeepCopy() *ManifestCondition { + if in == nil { + return nil + } + out := new(ManifestCondition) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OverridePolicy) DeepCopyInto(out *OverridePolicy) { *out = *in @@ -738,6 +854,62 @@ func (in *PlacementRef) DeepCopy() *PlacementRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceEnvelope) DeepCopyInto(out *ResourceEnvelope) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceEnvelope. +func (in *ResourceEnvelope) DeepCopy() *ResourceEnvelope { + if in == nil { + return nil + } + out := new(ResourceEnvelope) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ResourceEnvelope) 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 *ResourceEnvelopeStatus) DeepCopyInto(out *ResourceEnvelopeStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ManifestConditions != nil { + in, out := &in.ManifestConditions, &out.ManifestConditions + *out = make([]ManifestCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceEnvelopeStatus. +func (in *ResourceEnvelopeStatus) DeepCopy() *ResourceEnvelopeStatus { + if in == nil { + return nil + } + out := new(ResourceEnvelopeStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceOverride) DeepCopyInto(out *ResourceOverride) { *out = *in diff --git a/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml b/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml new file mode 100644 index 000000000..112074b90 --- /dev/null +++ b/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml @@ -0,0 +1,213 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: clusterresourceenvelopes.placement.kubernetes-fleet.io +spec: + group: placement.kubernetes-fleet.io + names: + categories: + - fleet + - fleet-placement + kind: ClusterResourceEnvelope + listKind: ClusterResourceEnvelopeList + plural: clusterresourceenvelopes + singular: clusterresourceenvelope + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterResourceEnvelope wraps cluster-scoped resources for placement. + 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: The desired state of ClusterResourceEnvelope. + properties: + manifests: + additionalProperties: + description: Manifest is a wrapped resource. + properties: + data: + description: The resource data. + type: object + x-kubernetes-embedded-resource: true + x-kubernetes-preserve-unknown-fields: true + required: + - data + type: object + description: |- + A map of wrapped manifests. + + Each manifest is uniquely identified by a string key, typically a filename that represents + the manifest. + maxProperties: 50 + minProperties: 1 + type: object + required: + - manifests + type: object + status: + description: The observed status of ClusterResourceEnvelope. + properties: + conditions: + description: Conditions is an array of current observed conditions + for ClusterResourceEnvelope. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + 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 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + manifestConditions: + description: ManifestConditions is an array of current observed conditions + for each manifest in the envelope. + items: + description: ManifestCondition is the observed conditions of a wrapped + manifest. + properties: + conditions: + description: Conditions is an array of current observed conditions + for a wrapped manifest. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + 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 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: The name of the manifest. + type: string + required: + - name + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml b/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml new file mode 100644 index 000000000..37137faa8 --- /dev/null +++ b/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml @@ -0,0 +1,212 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: resourceenvelopes.placement.kubernetes-fleet.io +spec: + group: placement.kubernetes-fleet.io + names: + categories: + - fleet + - fleet-placement + kind: ResourceEnvelope + listKind: ResourceEnvelopeList + plural: resourceenvelopes + singular: resourceenvelope + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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: The desired state of ResourceEnvelope. + properties: + manifests: + additionalProperties: + description: Manifest is a wrapped resource. + properties: + data: + description: The resource data. + type: object + x-kubernetes-embedded-resource: true + x-kubernetes-preserve-unknown-fields: true + required: + - data + type: object + description: |- + A map of wrapped manifests. + + Each manifest is uniquely identified by a string key, typically a filename that represents + the manifest. + maxProperties: 50 + minProperties: 1 + type: object + required: + - manifests + type: object + status: + description: The observed status of ResourceEnvelope. + properties: + conditions: + description: Conditions is an array of current observed conditions + for ResourceEnvelope. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + 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 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + manifestConditions: + description: ManifestConditions is an array of current observed conditions + for each manifest in the envelope. + items: + description: ManifestCondition is the observed conditions of a wrapped + manifest. + properties: + conditions: + description: Conditions is an array of current observed conditions + for a wrapped manifest. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + 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 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: The name of the manifest. + type: string + required: + - name + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/examples/envelopes/clusterscoped.yaml b/examples/envelopes/clusterscoped.yaml new file mode 100644 index 000000000..558b86fc5 --- /dev/null +++ b/examples/envelopes/clusterscoped.yaml @@ -0,0 +1,36 @@ +apiVersion: placement.kubernetes-fleet.io/v1alpha1 +kind: ClusterResourceEnvelope +metadata: + name: example +spec: + manifests: + "webhook.yaml": + data: + apiVersion: admissionregistration.k8s.io/v1 + kind: ValidatingWebhookConfiguration + metadata: + name: guard + webhooks: + - name: guard.example.com + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + clientConfig: + service: + name: guard + namespace: ops + admissionReviewVersions: ["v1"] + sideEffects: None + timeoutSeconds: 10 + "clusterrole.yaml": + data: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: pod-reader + rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] diff --git a/examples/envelopes/namespacescoped.yaml b/examples/envelopes/namespacescoped.yaml new file mode 100644 index 000000000..4642b8139 --- /dev/null +++ b/examples/envelopes/namespacescoped.yaml @@ -0,0 +1,33 @@ +apiVersion: placement.kubernetes-fleet.io/v1alpha1 +kind: ResourceEnvelope +metadata: + name: example +spec: + manifests: + "cm.yaml": + data: + apiVersion: v1 + kind: ConfigMap + metadata: + name: app + data: + foo: bar + "deploy.yaml": + data: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: app + spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: web + image: nginx From 628b58bd36077e9f8d3e11175f1729b2c4a70de3 Mon Sep 17 00:00:00 2001 From: michaelawyu Date: Tue, 29 Apr 2025 10:14:42 +1000 Subject: [PATCH 2/2] Dropped the status field Signed-off-by: michaelawyu --- apis/cluster/v1beta1/zz_generated.deepcopy.go | 2 +- apis/placement/v1alpha1/envelope_types.go | 56 ------- .../v1alpha1/zz_generated.deepcopy.go | 84 +---------- .../v1beta1/zz_generated.deepcopy.go | 2 +- apis/v1alpha1/zz_generated.deepcopy.go | 2 +- ...tes-fleet.io_clusterresourceenvelopes.yaml | 141 ------------------ ...kubernetes-fleet.io_resourceenvelopes.yaml | 141 ------------------ test/apis/v1alpha1/zz_generated.deepcopy.go | 2 +- 8 files changed, 5 insertions(+), 425 deletions(-) diff --git a/apis/cluster/v1beta1/zz_generated.deepcopy.go b/apis/cluster/v1beta1/zz_generated.deepcopy.go index 17e71a1a2..7bb7f501c 100644 --- a/apis/cluster/v1beta1/zz_generated.deepcopy.go +++ b/apis/cluster/v1beta1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/apis/placement/v1alpha1/envelope_types.go b/apis/placement/v1alpha1/envelope_types.go index db3440e99..a8a29fc40 100644 --- a/apis/placement/v1alpha1/envelope_types.go +++ b/apis/placement/v1alpha1/envelope_types.go @@ -35,10 +35,6 @@ type ClusterResourceEnvelope struct { // The desired state of ClusterResourceEnvelope. // +kubebuilder:validation:Required Spec EnvelopeSpec `json:"spec"` - - // The observed status of ClusterResourceEnvelope. - // +kubebuilder:validation:Optional - Status ClusterResourceEnvelopeStatus `json:"status,omitempty"` } // EnvelopeSpec helps wrap resources for placement. @@ -62,38 +58,6 @@ type Manifest struct { Data runtime.RawExtension `json:"data"` } -// ClusterResourceEnvelopeStatus is the observed status of a ClusterResourceEnvelope. -type ClusterResourceEnvelopeStatus struct { - // +patchMergeKey=type - // +patchStrategy=merge - // +listType=map - // +listMapKey=type - // - // Conditions is an array of current observed conditions for ClusterResourceEnvelope. - // +kubebuilder:validation:Optional - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // ManifestConditions is an array of current observed conditions for each manifest in the envelope. - // +kubebuilder:validation:Optional - ManifestConditions []ManifestCondition `json:"manifestConditions,omitempty"` -} - -// ManifestCondition is the observed conditions of a wrapped manifest. -type ManifestCondition struct { - // The name of the manifest. - // +kubebuilder:validation:Required - Name string `json:"name"` - - // +patchMergeKey=type - // +patchStrategy=merge - // +listType=map - // +listMapKey=type - // - // Conditions is an array of current observed conditions for a wrapped manifest. - // +kubebuilder:validation:Optional - Conditions []metav1.Condition `json:"conditions,omitempty"` -} - // +genclient // +genclient:Namespaced // +kubebuilder:object:root=true @@ -106,24 +70,4 @@ type ResourceEnvelope struct { // The desired state of ResourceEnvelope. // +kubebuilder:validation:Required Spec EnvelopeSpec `json:"spec"` - - // The observed status of ResourceEnvelope. - // +kubebuilder:validation:Optional - Status ResourceEnvelopeStatus `json:"status,omitempty"` -} - -// ResourceEnvelopeStatus is the observed status of a ResourceEnvelope. -type ResourceEnvelopeStatus struct { - // +patchMergeKey=type - // +patchStrategy=merge - // +listType=map - // +listMapKey=type - // - // Conditions is an array of current observed conditions for ResourceEnvelope. - // +kubebuilder:validation:Optional - Conditions []metav1.Condition `json:"conditions,omitempty"` - - // ManifestConditions is an array of current observed conditions for each manifest in the envelope. - // +kubebuilder:validation:Optional - ManifestConditions []ManifestCondition `json:"manifestConditions,omitempty"` } diff --git a/apis/placement/v1alpha1/zz_generated.deepcopy.go b/apis/placement/v1alpha1/zz_generated.deepcopy.go index 2790af308..bdc1ec2a8 100644 --- a/apis/placement/v1alpha1/zz_generated.deepcopy.go +++ b/apis/placement/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ package v1alpha1 import ( "github.com/kubefleet-dev/kubefleet/apis/placement/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -167,7 +167,6 @@ func (in *ClusterResourceEnvelope) DeepCopyInto(out *ClusterResourceEnvelope) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResourceEnvelope. @@ -188,35 +187,6 @@ func (in *ClusterResourceEnvelope) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterResourceEnvelopeStatus) DeepCopyInto(out *ClusterResourceEnvelopeStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ManifestConditions != nil { - in, out := &in.ManifestConditions, &out.ManifestConditions - *out = make([]ManifestCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResourceEnvelopeStatus. -func (in *ClusterResourceEnvelopeStatus) DeepCopy() *ClusterResourceEnvelopeStatus { - if in == nil { - return nil - } - out := new(ClusterResourceEnvelopeStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterResourceOverride) DeepCopyInto(out *ClusterResourceOverride) { *out = *in @@ -706,28 +676,6 @@ func (in *Manifest) DeepCopy() *Manifest { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ManifestCondition) DeepCopyInto(out *ManifestCondition) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManifestCondition. -func (in *ManifestCondition) DeepCopy() *ManifestCondition { - if in == nil { - return nil - } - out := new(ManifestCondition) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OverridePolicy) DeepCopyInto(out *OverridePolicy) { *out = *in @@ -860,7 +808,6 @@ func (in *ResourceEnvelope) DeepCopyInto(out *ResourceEnvelope) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceEnvelope. @@ -881,35 +828,6 @@ func (in *ResourceEnvelope) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResourceEnvelopeStatus) DeepCopyInto(out *ResourceEnvelopeStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ManifestConditions != nil { - in, out := &in.ManifestConditions, &out.ManifestConditions - *out = make([]ManifestCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceEnvelopeStatus. -func (in *ResourceEnvelopeStatus) DeepCopy() *ResourceEnvelopeStatus { - if in == nil { - return nil - } - out := new(ResourceEnvelopeStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceOverride) DeepCopyInto(out *ResourceOverride) { *out = *in diff --git a/apis/placement/v1beta1/zz_generated.deepcopy.go b/apis/placement/v1beta1/zz_generated.deepcopy.go index 69f7db476..dec32e99d 100644 --- a/apis/placement/v1beta1/zz_generated.deepcopy.go +++ b/apis/placement/v1beta1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 85550ca19..27a862c43 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml b/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml index 112074b90..0c53b05a3 100644 --- a/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml +++ b/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceenvelopes.yaml @@ -65,147 +65,6 @@ spec: required: - manifests type: object - status: - description: The observed status of ClusterResourceEnvelope. - properties: - conditions: - description: Conditions is an array of current observed conditions - for ClusterResourceEnvelope. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - 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 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - manifestConditions: - description: ManifestConditions is an array of current observed conditions - for each manifest in the envelope. - items: - description: ManifestCondition is the observed conditions of a wrapped - manifest. - properties: - conditions: - description: Conditions is an array of current observed conditions - for a wrapped manifest. - items: - description: Condition contains details for one aspect of - the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - 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 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: The name of the manifest. - type: string - required: - - name - type: object - type: array - type: object required: - spec type: object diff --git a/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml b/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml index 37137faa8..b15627041 100644 --- a/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml +++ b/config/crd/bases/placement.kubernetes-fleet.io_resourceenvelopes.yaml @@ -64,147 +64,6 @@ spec: required: - manifests type: object - status: - description: The observed status of ResourceEnvelope. - properties: - conditions: - description: Conditions is an array of current observed conditions - for ResourceEnvelope. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - 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 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - manifestConditions: - description: ManifestConditions is an array of current observed conditions - for each manifest in the envelope. - items: - description: ManifestCondition is the observed conditions of a wrapped - manifest. - properties: - conditions: - description: Conditions is an array of current observed conditions - for a wrapped manifest. - items: - description: Condition contains details for one aspect of - the current state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - 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 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: The name of the manifest. - type: string - required: - - name - type: object - type: array - type: object required: - spec type: object diff --git a/test/apis/v1alpha1/zz_generated.deepcopy.go b/test/apis/v1alpha1/zz_generated.deepcopy.go index 143bdee7b..081bec913 100644 --- a/test/apis/v1alpha1/zz_generated.deepcopy.go +++ b/test/apis/v1alpha1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1alpha1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" )