From d8e8268202a212998dfc9917b793c743543648df Mon Sep 17 00:00:00 2001 From: Britania Rodriguez Reyes Date: Wed, 30 Jul 2025 18:24:04 -0500 Subject: [PATCH 1/5] add status object for managed namespace placement --- .../v1beta1/clusterresourceplacement_types.go | 10 +- ...s-fleet.io_managednamespaceplacements.yaml | 495 ++++++++++++++++++ 2 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml diff --git a/apis/placement/v1beta1/clusterresourceplacement_types.go b/apis/placement/v1beta1/clusterresourceplacement_types.go index e17ff7648..ac40de9b9 100644 --- a/apis/placement/v1beta1/clusterresourceplacement_types.go +++ b/apis/placement/v1beta1/clusterresourceplacement_types.go @@ -1495,6 +1495,14 @@ func (rpl *ResourcePlacementList) GetPlacementObjs() []PlacementObj { return objs } +// ManagedNamespacePlacement is used to represent which clusters the namespace has been placed on to. +type ManagedNamespacePlacement struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Status []ResourcePlacementStatus `json:"status,omitempty"` +} + func init() { - SchemeBuilder.Register(&ClusterResourcePlacement{}, &ClusterResourcePlacementList{}, &ResourcePlacement{}, &ResourcePlacementList{}) + SchemeBuilder.Register(&ClusterResourcePlacement{}, &ClusterResourcePlacementList{}, &ResourcePlacement{}, &ResourcePlacementList{}, &ManagedNamespacePlacement{}) } diff --git a/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml b/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml new file mode 100644 index 000000000..96f91f7dc --- /dev/null +++ b/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml @@ -0,0 +1,495 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: managednamespaceplacements.placement.kubernetes-fleet.io +spec: + group: placement.kubernetes-fleet.io + names: + kind: ManagedNamespacePlacement + listKind: ManagedNamespacePlacementList + plural: managednamespaceplacements + singular: managednamespaceplacement + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: ManagedNamespacePlacement is used to represent which clusters + the namespace has been placed on to. + 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 + status: + items: + description: ResourcePlacementStatus represents the placement status + of selected resources for one target cluster. + properties: + applicableClusterResourceOverrides: + description: |- + ApplicableClusterResourceOverrides contains a list of applicable ClusterResourceOverride snapshots associated with + the selected resources. + + This field is alpha-level and is for the override policy feature. + items: + type: string + type: array + applicableResourceOverrides: + description: |- + ApplicableResourceOverrides contains a list of applicable ResourceOverride snapshots associated with the selected + resources. + + This field is alpha-level and is for the override policy feature. + items: + description: NamespacedName comprises a resource name, with a + mandatory namespace. + properties: + name: + description: Name is the name of the namespaced scope resource. + type: string + namespace: + description: Namespace is namespace of the namespaced scope + resource. + type: string + required: + - name + - namespace + type: object + type: array + clusterName: + description: |- + ClusterName is the name of the cluster this resource is assigned to. + If it is not empty, its value should be unique cross all placement decisions for the Placement. + type: string + conditions: + description: |- + Conditions is an array of current observed conditions on the cluster. + Each condition corresponds to the resource snapshot at the index specified by `ObservedResourceIndex`. + For example, the condition of type `RolloutStarted` is observing the rollout status of the resource snapshot with index `ObservedResourceIndex`. + 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 + diffedPlacements: + description: |- + DiffedPlacements is a list of resources that have configuration differences from their + corresponding hub cluster manifests. Fleet will report such differences when: + + * The CRP uses the ReportDiff apply strategy, which instructs Fleet to compare the hub + cluster manifests against the live resources without actually performing any apply op; or + * Fleet finds a pre-existing resource on the member cluster side that does not match its + hub cluster counterpart, and the CRP has been configured to only take over a resource if + no configuration differences are found. + + To control the object size, only the first 100 diffed resources will be included. + This field is only meaningful if the `ClusterName` is not empty. + items: + description: DiffedResourcePlacement contains the details of a + resource with configuration differences. + properties: + envelope: + description: Envelope identifies the envelope object that + contains this resource. + properties: + name: + description: Name of the envelope object. + type: string + namespace: + description: Namespace is the namespace of the envelope + object. Empty if the envelope object is cluster scoped. + type: string + type: + default: ConfigMap + description: Type of the envelope object. + enum: + - ConfigMap + - ClusterResourceEnvelope + - ResourceEnvelope + type: string + required: + - name + type: object + firstDiffedObservedTime: + description: |- + FirstDiffedObservedTime is the first time the resource on the target cluster is + observed to have configuration differences. + format: date-time + type: string + group: + description: Group is the group name of the selected resource. + type: string + kind: + description: Kind represents the Kind of the selected resources. + type: string + name: + description: Name of the target resource. + type: string + namespace: + description: Namespace is the namespace of the resource. Empty + if the resource is cluster scoped. + type: string + observationTime: + description: ObservationTime is the time when we observe the + configuration differences for the resource. + format: date-time + type: string + observedDiffs: + description: |- + ObservedDiffs are the details about the found configuration differences. Note that + Fleet might truncate the details as appropriate to control the object size. + + Each detail entry specifies how the live state (the state on the member + cluster side) compares against the desired state (the state kept in the hub cluster manifest). + + An event about the details will be emitted as well. + items: + description: |- + PatchDetail describes a patch that explains an observed configuration drift or + difference. + + A patch detail can be transcribed as a JSON patch operation, as specified in RFC 6902. + properties: + path: + description: The JSON path that points to a field that + has drifted or has configuration differences. + type: string + valueInHub: + description: |- + The value at the JSON path from the hub cluster side. + + This field can be empty if the JSON path does not exist on the hub cluster side; i.e., + applying the manifest from the hub cluster side would remove the field. + type: string + valueInMember: + description: |- + The value at the JSON path from the member cluster side. + + This field can be empty if the JSON path does not exist on the member cluster side; i.e., + applying the manifest from the hub cluster side would add a new field. + type: string + required: + - path + type: object + type: array + targetClusterObservedGeneration: + description: |- + TargetClusterObservedGeneration is the generation of the resource on the target cluster + that contains the configuration differences. + + This might be nil if the resource has not been created yet on the target cluster. + format: int64 + type: integer + version: + description: Version is the version of the selected resource. + type: string + required: + - firstDiffedObservedTime + - kind + - name + - observationTime + - version + type: object + maxItems: 100 + type: array + driftedPlacements: + description: |- + DriftedPlacements is a list of resources that have drifted from their desired states + kept in the hub cluster, as found by Fleet using the drift detection mechanism. + + To control the object size, only the first 100 drifted resources will be included. + This field is only meaningful if the `ClusterName` is not empty. + items: + description: DriftedResourcePlacement contains the details of + a resource with configuration drifts. + properties: + envelope: + description: Envelope identifies the envelope object that + contains this resource. + properties: + name: + description: Name of the envelope object. + type: string + namespace: + description: Namespace is the namespace of the envelope + object. Empty if the envelope object is cluster scoped. + type: string + type: + default: ConfigMap + description: Type of the envelope object. + enum: + - ConfigMap + - ClusterResourceEnvelope + - ResourceEnvelope + type: string + required: + - name + type: object + firstDriftedObservedTime: + description: |- + FirstDriftedObservedTime is the first time the resource on the target cluster is + observed to have configuration drifts. + format: date-time + type: string + group: + description: Group is the group name of the selected resource. + type: string + kind: + description: Kind represents the Kind of the selected resources. + type: string + name: + description: Name of the target resource. + type: string + namespace: + description: Namespace is the namespace of the resource. Empty + if the resource is cluster scoped. + type: string + observationTime: + description: ObservationTime is the time when we observe the + configuration drifts for the resource. + format: date-time + type: string + observedDrifts: + description: |- + ObservedDrifts are the details about the found configuration drifts. Note that + Fleet might truncate the details as appropriate to control the object size. + + Each detail entry specifies how the live state (the state on the member + cluster side) compares against the desired state (the state kept in the hub cluster manifest). + + An event about the details will be emitted as well. + items: + description: |- + PatchDetail describes a patch that explains an observed configuration drift or + difference. + + A patch detail can be transcribed as a JSON patch operation, as specified in RFC 6902. + properties: + path: + description: The JSON path that points to a field that + has drifted or has configuration differences. + type: string + valueInHub: + description: |- + The value at the JSON path from the hub cluster side. + + This field can be empty if the JSON path does not exist on the hub cluster side; i.e., + applying the manifest from the hub cluster side would remove the field. + type: string + valueInMember: + description: |- + The value at the JSON path from the member cluster side. + + This field can be empty if the JSON path does not exist on the member cluster side; i.e., + applying the manifest from the hub cluster side would add a new field. + type: string + required: + - path + type: object + type: array + targetClusterObservedGeneration: + description: |- + TargetClusterObservedGeneration is the generation of the resource on the target cluster + that contains the configuration drifts. + format: int64 + type: integer + version: + description: Version is the version of the selected resource. + type: string + required: + - firstDriftedObservedTime + - kind + - name + - observationTime + - targetClusterObservedGeneration + - version + type: object + maxItems: 100 + type: array + failedPlacements: + description: |- + FailedPlacements is a list of all the resources failed to be placed to the given cluster or the resource is unavailable. + Note that we only include 100 failed resource placements even if there are more than 100. + This field is only meaningful if the `ClusterName` is not empty. + items: + description: FailedResourcePlacement contains the failure details + of a failed resource placement. + properties: + condition: + description: The failed condition status. + 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 + envelope: + description: Envelope identifies the envelope object that + contains this resource. + properties: + name: + description: Name of the envelope object. + type: string + namespace: + description: Namespace is the namespace of the envelope + object. Empty if the envelope object is cluster scoped. + type: string + type: + default: ConfigMap + description: Type of the envelope object. + enum: + - ConfigMap + - ClusterResourceEnvelope + - ResourceEnvelope + type: string + required: + - name + type: object + group: + description: Group is the group name of the selected resource. + type: string + kind: + description: Kind represents the Kind of the selected resources. + type: string + name: + description: Name of the target resource. + type: string + namespace: + description: Namespace is the namespace of the resource. Empty + if the resource is cluster scoped. + type: string + version: + description: Version is the version of the selected resource. + type: string + required: + - condition + - kind + - name + - version + type: object + maxItems: 100 + type: array + observedResourceIndex: + description: |- + ObservedResourceIndex is the index of the resource snapshot that is currently being rolled out to the given cluster. + This field is only meaningful if the `ClusterName` is not empty. + type: string + type: object + type: array + type: object + served: true + storage: true From 4df8f2fa8bece7c9695a9006ea268196d3d46ec1 Mon Sep 17 00:00:00 2001 From: Britania Rodriguez Reyes Date: Wed, 30 Jul 2025 18:42:15 -0500 Subject: [PATCH 2/5] add suggestions Signed-off-by: Britania Rodriguez Reyes --- .../v1beta1/clusterresourceplacement_types.go | 20 +- .../v1beta1/zz_generated.deepcopy.go | 50 +- ...s-fleet.io_managednamespaceplacements.yaml | 776 +++++++++--------- 3 files changed, 464 insertions(+), 382 deletions(-) diff --git a/apis/placement/v1beta1/clusterresourceplacement_types.go b/apis/placement/v1beta1/clusterresourceplacement_types.go index ac40de9b9..a798237cf 100644 --- a/apis/placement/v1beta1/clusterresourceplacement_types.go +++ b/apis/placement/v1beta1/clusterresourceplacement_types.go @@ -1495,12 +1495,30 @@ func (rpl *ResourcePlacementList) GetPlacementObjs() []PlacementObj { return objs } +// +genclient +// +genclient:Namespaced +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope="Namespaced" +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + // ManagedNamespacePlacement is used to represent which clusters the namespace has been placed on to. type ManagedNamespacePlacement struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Status []ResourcePlacementStatus `json:"status,omitempty"` + // The observed status of the ManagedNamespacePlacement. + // +kubebuilder:validation:Optional + Status ManagedNamespacePlacementStatus `json:"status,omitempty"` +} + +// ManagedNamespacePlacementStatus represents the status of a ManagedNamespacePlacement. +type ManagedNamespacePlacementStatus struct { + + // ResourcePlacements contains the placement statuses for the namespace. + // +kubebuilder:validation:Optional + ResourcePlacements []ResourcePlacementStatus `json:"resourcePlacements,omitempty"` } func init() { diff --git a/apis/placement/v1beta1/zz_generated.deepcopy.go b/apis/placement/v1beta1/zz_generated.deepcopy.go index 851e87d9b..9fddfa906 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" ) @@ -1356,6 +1356,54 @@ 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 *ManagedNamespacePlacement) DeepCopyInto(out *ManagedNamespacePlacement) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedNamespacePlacement. +func (in *ManagedNamespacePlacement) DeepCopy() *ManagedNamespacePlacement { + if in == nil { + return nil + } + out := new(ManagedNamespacePlacement) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagedNamespacePlacement) 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 *ManagedNamespacePlacementStatus) DeepCopyInto(out *ManagedNamespacePlacementStatus) { + *out = *in + if in.ResourcePlacements != nil { + in, out := &in.ResourcePlacements, &out.ResourcePlacements + *out = make([]ResourcePlacementStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedNamespacePlacementStatus. +func (in *ManagedNamespacePlacementStatus) DeepCopy() *ManagedNamespacePlacementStatus { + if in == nil { + return nil + } + out := new(ManagedNamespacePlacementStatus) + in.DeepCopyInto(out) + 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 diff --git a/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml b/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml index 96f91f7dc..91234a317 100644 --- a/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml +++ b/config/crd/bases/placement.kubernetes-fleet.io_managednamespaceplacements.yaml @@ -38,353 +38,60 @@ spec: metadata: type: object status: - items: - description: ResourcePlacementStatus represents the placement status - of selected resources for one target cluster. - properties: - applicableClusterResourceOverrides: - description: |- - ApplicableClusterResourceOverrides contains a list of applicable ClusterResourceOverride snapshots associated with - the selected resources. + description: The observed status of the ManagedNamespacePlacement. + properties: + resourcePlacements: + description: ResourcePlacements contains the placement statuses for + the namespace. + items: + description: ResourcePlacementStatus represents the placement status + of selected resources for one target cluster. + properties: + applicableClusterResourceOverrides: + description: |- + ApplicableClusterResourceOverrides contains a list of applicable ClusterResourceOverride snapshots associated with + the selected resources. - This field is alpha-level and is for the override policy feature. - items: - type: string - type: array - applicableResourceOverrides: - description: |- - ApplicableResourceOverrides contains a list of applicable ResourceOverride snapshots associated with the selected - resources. - - This field is alpha-level and is for the override policy feature. - items: - description: NamespacedName comprises a resource name, with a - mandatory namespace. - properties: - name: - description: Name is the name of the namespaced scope resource. - type: string - namespace: - description: Namespace is namespace of the namespaced scope - resource. - type: string - required: - - name - - namespace - type: object - type: array - clusterName: - description: |- - ClusterName is the name of the cluster this resource is assigned to. - If it is not empty, its value should be unique cross all placement decisions for the Placement. - type: string - conditions: - description: |- - Conditions is an array of current observed conditions on the cluster. - Each condition corresponds to the resource snapshot at the index specified by `ObservedResourceIndex`. - For example, the condition of type `RolloutStarted` is observing the rollout status of the resource snapshot with index `ObservedResourceIndex`. - 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 + This field is alpha-level and is for the override policy feature. + items: 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 - diffedPlacements: - description: |- - DiffedPlacements is a list of resources that have configuration differences from their - corresponding hub cluster manifests. Fleet will report such differences when: - - * The CRP uses the ReportDiff apply strategy, which instructs Fleet to compare the hub - cluster manifests against the live resources without actually performing any apply op; or - * Fleet finds a pre-existing resource on the member cluster side that does not match its - hub cluster counterpart, and the CRP has been configured to only take over a resource if - no configuration differences are found. + type: array + applicableResourceOverrides: + description: |- + ApplicableResourceOverrides contains a list of applicable ResourceOverride snapshots associated with the selected + resources. - To control the object size, only the first 100 diffed resources will be included. - This field is only meaningful if the `ClusterName` is not empty. - items: - description: DiffedResourcePlacement contains the details of a - resource with configuration differences. - properties: - envelope: - description: Envelope identifies the envelope object that - contains this resource. + This field is alpha-level and is for the override policy feature. + items: + description: NamespacedName comprises a resource name, with + a mandatory namespace. properties: name: - description: Name of the envelope object. + description: Name is the name of the namespaced scope + resource. type: string namespace: - description: Namespace is the namespace of the envelope - object. Empty if the envelope object is cluster scoped. - type: string - type: - default: ConfigMap - description: Type of the envelope object. - enum: - - ConfigMap - - ClusterResourceEnvelope - - ResourceEnvelope + description: Namespace is namespace of the namespaced + scope resource. type: string required: - name + - namespace type: object - firstDiffedObservedTime: - description: |- - FirstDiffedObservedTime is the first time the resource on the target cluster is - observed to have configuration differences. - format: date-time - type: string - group: - description: Group is the group name of the selected resource. - type: string - kind: - description: Kind represents the Kind of the selected resources. - type: string - name: - description: Name of the target resource. - type: string - namespace: - description: Namespace is the namespace of the resource. Empty - if the resource is cluster scoped. - type: string - observationTime: - description: ObservationTime is the time when we observe the - configuration differences for the resource. - format: date-time - type: string - observedDiffs: - description: |- - ObservedDiffs are the details about the found configuration differences. Note that - Fleet might truncate the details as appropriate to control the object size. - - Each detail entry specifies how the live state (the state on the member - cluster side) compares against the desired state (the state kept in the hub cluster manifest). - - An event about the details will be emitted as well. - items: - description: |- - PatchDetail describes a patch that explains an observed configuration drift or - difference. - - A patch detail can be transcribed as a JSON patch operation, as specified in RFC 6902. - properties: - path: - description: The JSON path that points to a field that - has drifted or has configuration differences. - type: string - valueInHub: - description: |- - The value at the JSON path from the hub cluster side. - - This field can be empty if the JSON path does not exist on the hub cluster side; i.e., - applying the manifest from the hub cluster side would remove the field. - type: string - valueInMember: - description: |- - The value at the JSON path from the member cluster side. - - This field can be empty if the JSON path does not exist on the member cluster side; i.e., - applying the manifest from the hub cluster side would add a new field. - type: string - required: - - path - type: object - type: array - targetClusterObservedGeneration: - description: |- - TargetClusterObservedGeneration is the generation of the resource on the target cluster - that contains the configuration differences. - - This might be nil if the resource has not been created yet on the target cluster. - format: int64 - type: integer - version: - description: Version is the version of the selected resource. - type: string - required: - - firstDiffedObservedTime - - kind - - name - - observationTime - - version - type: object - maxItems: 100 - type: array - driftedPlacements: - description: |- - DriftedPlacements is a list of resources that have drifted from their desired states - kept in the hub cluster, as found by Fleet using the drift detection mechanism. - - To control the object size, only the first 100 drifted resources will be included. - This field is only meaningful if the `ClusterName` is not empty. - items: - description: DriftedResourcePlacement contains the details of - a resource with configuration drifts. - properties: - envelope: - description: Envelope identifies the envelope object that - contains this resource. - properties: - name: - description: Name of the envelope object. - type: string - namespace: - description: Namespace is the namespace of the envelope - object. Empty if the envelope object is cluster scoped. - type: string - type: - default: ConfigMap - description: Type of the envelope object. - enum: - - ConfigMap - - ClusterResourceEnvelope - - ResourceEnvelope - type: string - required: - - name - type: object - firstDriftedObservedTime: - description: |- - FirstDriftedObservedTime is the first time the resource on the target cluster is - observed to have configuration drifts. - format: date-time - type: string - group: - description: Group is the group name of the selected resource. - type: string - kind: - description: Kind represents the Kind of the selected resources. - type: string - name: - description: Name of the target resource. - type: string - namespace: - description: Namespace is the namespace of the resource. Empty - if the resource is cluster scoped. - type: string - observationTime: - description: ObservationTime is the time when we observe the - configuration drifts for the resource. - format: date-time - type: string - observedDrifts: - description: |- - ObservedDrifts are the details about the found configuration drifts. Note that - Fleet might truncate the details as appropriate to control the object size. - - Each detail entry specifies how the live state (the state on the member - cluster side) compares against the desired state (the state kept in the hub cluster manifest). - - An event about the details will be emitted as well. - items: - description: |- - PatchDetail describes a patch that explains an observed configuration drift or - difference. - - A patch detail can be transcribed as a JSON patch operation, as specified in RFC 6902. - properties: - path: - description: The JSON path that points to a field that - has drifted or has configuration differences. - type: string - valueInHub: - description: |- - The value at the JSON path from the hub cluster side. - - This field can be empty if the JSON path does not exist on the hub cluster side; i.e., - applying the manifest from the hub cluster side would remove the field. - type: string - valueInMember: - description: |- - The value at the JSON path from the member cluster side. - - This field can be empty if the JSON path does not exist on the member cluster side; i.e., - applying the manifest from the hub cluster side would add a new field. - type: string - required: - - path - type: object - type: array - targetClusterObservedGeneration: - description: |- - TargetClusterObservedGeneration is the generation of the resource on the target cluster - that contains the configuration drifts. - format: int64 - type: integer - version: - description: Version is the version of the selected resource. - type: string - required: - - firstDriftedObservedTime - - kind - - name - - observationTime - - targetClusterObservedGeneration - - version - type: object - maxItems: 100 - type: array - failedPlacements: - description: |- - FailedPlacements is a list of all the resources failed to be placed to the given cluster or the resource is unavailable. - Note that we only include 100 failed resource placements even if there are more than 100. - This field is only meaningful if the `ClusterName` is not empty. - items: - description: FailedResourcePlacement contains the failure details - of a failed resource placement. - properties: - condition: - description: The failed condition status. + type: array + clusterName: + description: |- + ClusterName is the name of the cluster this resource is assigned to. + If it is not empty, its value should be unique cross all placement decisions for the Placement. + type: string + conditions: + description: |- + Conditions is an array of current observed conditions on the cluster. + Each condition corresponds to the resource snapshot at the index specified by `ObservedResourceIndex`. + For example, the condition of type `RolloutStarted` is observing the rollout status of the resource snapshot with index `ObservedResourceIndex`. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. properties: lastTransitionTime: description: |- @@ -437,59 +144,368 @@ spec: - status - type type: object - envelope: - description: Envelope identifies the envelope object that - contains this resource. + type: array + diffedPlacements: + description: |- + DiffedPlacements is a list of resources that have configuration differences from their + corresponding hub cluster manifests. Fleet will report such differences when: + + * The CRP uses the ReportDiff apply strategy, which instructs Fleet to compare the hub + cluster manifests against the live resources without actually performing any apply op; or + * Fleet finds a pre-existing resource on the member cluster side that does not match its + hub cluster counterpart, and the CRP has been configured to only take over a resource if + no configuration differences are found. + + To control the object size, only the first 100 diffed resources will be included. + This field is only meaningful if the `ClusterName` is not empty. + items: + description: DiffedResourcePlacement contains the details + of a resource with configuration differences. + properties: + envelope: + description: Envelope identifies the envelope object that + contains this resource. + properties: + name: + description: Name of the envelope object. + type: string + namespace: + description: Namespace is the namespace of the envelope + object. Empty if the envelope object is cluster + scoped. + type: string + type: + default: ConfigMap + description: Type of the envelope object. + enum: + - ConfigMap + - ClusterResourceEnvelope + - ResourceEnvelope + type: string + required: + - name + type: object + firstDiffedObservedTime: + description: |- + FirstDiffedObservedTime is the first time the resource on the target cluster is + observed to have configuration differences. + format: date-time + type: string + group: + description: Group is the group name of the selected resource. + type: string + kind: + description: Kind represents the Kind of the selected + resources. + type: string + name: + description: Name of the target resource. + type: string + namespace: + description: Namespace is the namespace of the resource. + Empty if the resource is cluster scoped. + type: string + observationTime: + description: ObservationTime is the time when we observe + the configuration differences for the resource. + format: date-time + type: string + observedDiffs: + description: |- + ObservedDiffs are the details about the found configuration differences. Note that + Fleet might truncate the details as appropriate to control the object size. + + Each detail entry specifies how the live state (the state on the member + cluster side) compares against the desired state (the state kept in the hub cluster manifest). + + An event about the details will be emitted as well. + items: + description: |- + PatchDetail describes a patch that explains an observed configuration drift or + difference. + + A patch detail can be transcribed as a JSON patch operation, as specified in RFC 6902. + properties: + path: + description: The JSON path that points to a field + that has drifted or has configuration differences. + type: string + valueInHub: + description: |- + The value at the JSON path from the hub cluster side. + + This field can be empty if the JSON path does not exist on the hub cluster side; i.e., + applying the manifest from the hub cluster side would remove the field. + type: string + valueInMember: + description: |- + The value at the JSON path from the member cluster side. + + This field can be empty if the JSON path does not exist on the member cluster side; i.e., + applying the manifest from the hub cluster side would add a new field. + type: string + required: + - path + type: object + type: array + targetClusterObservedGeneration: + description: |- + TargetClusterObservedGeneration is the generation of the resource on the target cluster + that contains the configuration differences. + + This might be nil if the resource has not been created yet on the target cluster. + format: int64 + type: integer + version: + description: Version is the version of the selected resource. + type: string + required: + - firstDiffedObservedTime + - kind + - name + - observationTime + - version + type: object + maxItems: 100 + type: array + driftedPlacements: + description: |- + DriftedPlacements is a list of resources that have drifted from their desired states + kept in the hub cluster, as found by Fleet using the drift detection mechanism. + + To control the object size, only the first 100 drifted resources will be included. + This field is only meaningful if the `ClusterName` is not empty. + items: + description: DriftedResourcePlacement contains the details + of a resource with configuration drifts. properties: + envelope: + description: Envelope identifies the envelope object that + contains this resource. + properties: + name: + description: Name of the envelope object. + type: string + namespace: + description: Namespace is the namespace of the envelope + object. Empty if the envelope object is cluster + scoped. + type: string + type: + default: ConfigMap + description: Type of the envelope object. + enum: + - ConfigMap + - ClusterResourceEnvelope + - ResourceEnvelope + type: string + required: + - name + type: object + firstDriftedObservedTime: + description: |- + FirstDriftedObservedTime is the first time the resource on the target cluster is + observed to have configuration drifts. + format: date-time + type: string + group: + description: Group is the group name of the selected resource. + type: string + kind: + description: Kind represents the Kind of the selected + resources. + type: string name: - description: Name of the envelope object. + description: Name of the target resource. type: string namespace: - description: Namespace is the namespace of the envelope - object. Empty if the envelope object is cluster scoped. + description: Namespace is the namespace of the resource. + Empty if the resource is cluster scoped. type: string - type: - default: ConfigMap - description: Type of the envelope object. - enum: - - ConfigMap - - ClusterResourceEnvelope - - ResourceEnvelope + observationTime: + description: ObservationTime is the time when we observe + the configuration drifts for the resource. + format: date-time + type: string + observedDrifts: + description: |- + ObservedDrifts are the details about the found configuration drifts. Note that + Fleet might truncate the details as appropriate to control the object size. + + Each detail entry specifies how the live state (the state on the member + cluster side) compares against the desired state (the state kept in the hub cluster manifest). + + An event about the details will be emitted as well. + items: + description: |- + PatchDetail describes a patch that explains an observed configuration drift or + difference. + + A patch detail can be transcribed as a JSON patch operation, as specified in RFC 6902. + properties: + path: + description: The JSON path that points to a field + that has drifted or has configuration differences. + type: string + valueInHub: + description: |- + The value at the JSON path from the hub cluster side. + + This field can be empty if the JSON path does not exist on the hub cluster side; i.e., + applying the manifest from the hub cluster side would remove the field. + type: string + valueInMember: + description: |- + The value at the JSON path from the member cluster side. + + This field can be empty if the JSON path does not exist on the member cluster side; i.e., + applying the manifest from the hub cluster side would add a new field. + type: string + required: + - path + type: object + type: array + targetClusterObservedGeneration: + description: |- + TargetClusterObservedGeneration is the generation of the resource on the target cluster + that contains the configuration drifts. + format: int64 + type: integer + version: + description: Version is the version of the selected resource. type: string required: + - firstDriftedObservedTime + - kind - name + - observationTime + - targetClusterObservedGeneration + - version type: object - group: - description: Group is the group name of the selected resource. - type: string - kind: - description: Kind represents the Kind of the selected resources. - type: string - name: - description: Name of the target resource. - type: string - namespace: - description: Namespace is the namespace of the resource. Empty - if the resource is cluster scoped. - type: string - version: - description: Version is the version of the selected resource. - type: string - required: - - condition - - kind - - name - - version - type: object - maxItems: 100 - type: array - observedResourceIndex: - description: |- - ObservedResourceIndex is the index of the resource snapshot that is currently being rolled out to the given cluster. - This field is only meaningful if the `ClusterName` is not empty. - type: string - type: object - type: array + maxItems: 100 + type: array + failedPlacements: + description: |- + FailedPlacements is a list of all the resources failed to be placed to the given cluster or the resource is unavailable. + Note that we only include 100 failed resource placements even if there are more than 100. + This field is only meaningful if the `ClusterName` is not empty. + items: + description: FailedResourcePlacement contains the failure + details of a failed resource placement. + properties: + condition: + description: The failed condition status. + 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 + envelope: + description: Envelope identifies the envelope object that + contains this resource. + properties: + name: + description: Name of the envelope object. + type: string + namespace: + description: Namespace is the namespace of the envelope + object. Empty if the envelope object is cluster + scoped. + type: string + type: + default: ConfigMap + description: Type of the envelope object. + enum: + - ConfigMap + - ClusterResourceEnvelope + - ResourceEnvelope + type: string + required: + - name + type: object + group: + description: Group is the group name of the selected resource. + type: string + kind: + description: Kind represents the Kind of the selected + resources. + type: string + name: + description: Name of the target resource. + type: string + namespace: + description: Namespace is the namespace of the resource. + Empty if the resource is cluster scoped. + type: string + version: + description: Version is the version of the selected resource. + type: string + required: + - condition + - kind + - name + - version + type: object + maxItems: 100 + type: array + observedResourceIndex: + description: |- + ObservedResourceIndex is the index of the resource snapshot that is currently being rolled out to the given cluster. + This field is only meaningful if the `ClusterName` is not empty. + type: string + type: object + type: array + type: object type: object served: true storage: true + subresources: + status: {} From aa72aa00943a50721ab3d375aef8e4459852ff98 Mon Sep 17 00:00:00 2001 From: Britania Rodriguez Reyes Date: Wed, 30 Jul 2025 18:51:03 -0500 Subject: [PATCH 3/5] add list object --- .../v1beta1/clusterresourceplacement_types.go | 13 ++++++-- .../v1beta1/zz_generated.deepcopy.go | 32 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/apis/placement/v1beta1/clusterresourceplacement_types.go b/apis/placement/v1beta1/clusterresourceplacement_types.go index a798237cf..db315b982 100644 --- a/apis/placement/v1beta1/clusterresourceplacement_types.go +++ b/apis/placement/v1beta1/clusterresourceplacement_types.go @@ -1515,12 +1515,21 @@ type ManagedNamespacePlacement struct { // ManagedNamespacePlacementStatus represents the status of a ManagedNamespacePlacement. type ManagedNamespacePlacementStatus struct { - // ResourcePlacements contains the placement statuses for the namespace. // +kubebuilder:validation:Optional ResourcePlacements []ResourcePlacementStatus `json:"resourcePlacements,omitempty"` } +// ManagedNamespacePlacementList contains a list of ManagedNamespacePlacement. +// +kubebuilder:resource:scope="Namespaced" +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ManagedNamespacePlacementList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ManagedNamespacePlacement `json:"items"` +} + + func init() { - SchemeBuilder.Register(&ClusterResourcePlacement{}, &ClusterResourcePlacementList{}, &ResourcePlacement{}, &ResourcePlacementList{}, &ManagedNamespacePlacement{}) + SchemeBuilder.Register(&ClusterResourcePlacement{}, &ClusterResourcePlacementList{}, &ResourcePlacement{}, &ResourcePlacementList{}, &ManagedNamespacePlacement{}, &ManagedNamespacePlacementList{}) } diff --git a/apis/placement/v1beta1/zz_generated.deepcopy.go b/apis/placement/v1beta1/zz_generated.deepcopy.go index 9fddfa906..074a7a598 100644 --- a/apis/placement/v1beta1/zz_generated.deepcopy.go +++ b/apis/placement/v1beta1/zz_generated.deepcopy.go @@ -1382,6 +1382,38 @@ func (in *ManagedNamespacePlacement) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedNamespacePlacementList) DeepCopyInto(out *ManagedNamespacePlacementList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ManagedNamespacePlacement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedNamespacePlacementList. +func (in *ManagedNamespacePlacementList) DeepCopy() *ManagedNamespacePlacementList { + if in == nil { + return nil + } + out := new(ManagedNamespacePlacementList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagedNamespacePlacementList) 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 *ManagedNamespacePlacementStatus) DeepCopyInto(out *ManagedNamespacePlacementStatus) { *out = *in From 0ad9ff36e4b159034be5dba24dfa7b77e3be21cf Mon Sep 17 00:00:00 2001 From: Britania Rodriguez Reyes Date: Wed, 30 Jul 2025 22:57:17 -0500 Subject: [PATCH 4/5] fix formatting Signed-off-by: Britania Rodriguez Reyes --- apis/placement/v1beta1/clusterresourceplacement_types.go | 1 - apis/placement/v1beta1/zz_generated.deepcopy.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apis/placement/v1beta1/clusterresourceplacement_types.go b/apis/placement/v1beta1/clusterresourceplacement_types.go index db315b982..ad84b8193 100644 --- a/apis/placement/v1beta1/clusterresourceplacement_types.go +++ b/apis/placement/v1beta1/clusterresourceplacement_types.go @@ -1529,7 +1529,6 @@ type ManagedNamespacePlacementList struct { Items []ManagedNamespacePlacement `json:"items"` } - func init() { SchemeBuilder.Register(&ClusterResourcePlacement{}, &ClusterResourcePlacementList{}, &ResourcePlacement{}, &ResourcePlacementList{}, &ManagedNamespacePlacement{}, &ManagedNamespacePlacementList{}) } diff --git a/apis/placement/v1beta1/zz_generated.deepcopy.go b/apis/placement/v1beta1/zz_generated.deepcopy.go index 074a7a598..757e68f6b 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 ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) From 7d750613c45040d328176944a4ef472ea353e5c6 Mon Sep 17 00:00:00 2001 From: Britania Rodriguez Reyes Date: Thu, 31 Jul 2025 13:59:40 -0500 Subject: [PATCH 5/5] fix unit test --- cmd/crdinstaller/utils/util_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/crdinstaller/utils/util_test.go b/cmd/crdinstaller/utils/util_test.go index 30e1e461a..4ba367f30 100644 --- a/cmd/crdinstaller/utils/util_test.go +++ b/cmd/crdinstaller/utils/util_test.go @@ -55,6 +55,7 @@ func runTest(t *testing.T, crdPath string) { name: "hub mode v1beta1 with actual directory", mode: "hub", wantedCRDNames: []string{ + "managednamespaceplacements.placement.kubernetes-fleet.io", "memberclusters.cluster.kubernetes-fleet.io", "internalmemberclusters.cluster.kubernetes-fleet.io", "clusterapprovalrequests.placement.kubernetes-fleet.io",