diff --git a/go.mod b/go.mod index bbc0d796..6825d719 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 kusionstack.io/kube-api v0.7.5-0.20260127130112-9424ce325e09 kusionstack.io/kube-utils v0.2.1-0.20251120063041-6043805ee00d - kusionstack.io/kube-xset v0.0.2-0.20260127130229-a7a010eba7e0 + kusionstack.io/kube-xset v0.0.2-0.20260423065316-b75e174759ae kusionstack.io/resourceconsist v0.0.1 sigs.k8s.io/controller-runtime v0.17.3 ) diff --git a/go.sum b/go.sum index fcfdc7c4..fc024300 100644 --- a/go.sum +++ b/go.sum @@ -1081,8 +1081,8 @@ kusionstack.io/kube-api v0.7.5-0.20260127130112-9424ce325e09 h1:Kgc1N61F9KoBi1sH kusionstack.io/kube-api v0.7.5-0.20260127130112-9424ce325e09/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk= kusionstack.io/kube-utils v0.2.1-0.20251120063041-6043805ee00d h1:iQtnK03ia/MN4K/6O75EMI91ep7jpcIG0pWyeREBqtg= kusionstack.io/kube-utils v0.2.1-0.20251120063041-6043805ee00d/go.mod h1:KEHTfo1Y8SWMODnckF6daO2cSIW0FJ8fkk8PBA5O2GU= -kusionstack.io/kube-xset v0.0.2-0.20260127130229-a7a010eba7e0 h1:mU1Jjdfgihju0xiYMmW/jSTGhovca/WEID7QzJrwkmw= -kusionstack.io/kube-xset v0.0.2-0.20260127130229-a7a010eba7e0/go.mod h1:FceKgqapMHhwiyIqCziTQRW27fsSXpPS611AApnyiYI= +kusionstack.io/kube-xset v0.0.2-0.20260423065316-b75e174759ae h1:0uXKJF0G1SJ+p0TKpsXmA+3lHhp5uwyrysMD57rqFpk= +kusionstack.io/kube-xset v0.0.2-0.20260423065316-b75e174759ae/go.mod h1:FceKgqapMHhwiyIqCziTQRW27fsSXpPS611AApnyiYI= kusionstack.io/resourceconsist v0.0.1 h1:+k/jriq5Ld7fQUYfWSMGynz/FesHtl3Rk2fmQPjBe0g= kusionstack.io/resourceconsist v0.0.1/go.mod h1:816xS/fY6EOUbPFjXIWW/TGs8/YE46qP4ElKeIiwFdU= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= diff --git a/pkg/controllers/collaset/collaset_controller.go b/pkg/controllers/collaset/collaset_controller.go index c466b5c8..2b6e3c90 100644 --- a/pkg/controllers/collaset/collaset_controller.go +++ b/pkg/controllers/collaset/collaset_controller.go @@ -56,6 +56,7 @@ type CollaSetController struct { SubResourcePvcAdapter DecorationAdapter ResourceContextAdapterGetter + SubResourceAdapterGetter } func (m *CollaSetController) ControllerName() string { @@ -310,3 +311,11 @@ type ResourceContextAdapterGetter struct{} func (r *ResourceContextAdapterGetter) GetResourceContextAdapter() xsetapi.ResourceContextAdapter { return &ResourceContextAdapter{} } + +type SubResourceAdapterGetter struct{} + +func (s *SubResourceAdapterGetter) GetSubResourceAdapters() []xsetapi.SubResourceAdapter { + return []xsetapi.SubResourceAdapter{ + NewPvcAdapter(), + } +} diff --git a/pkg/controllers/collaset/pod_updater.go b/pkg/controllers/collaset/pod_updater.go index c4ed272d..28e1ec77 100644 --- a/pkg/controllers/collaset/pod_updater.go +++ b/pkg/controllers/collaset/pod_updater.go @@ -81,7 +81,7 @@ func (u *inPlaceIfPossibleUpdater) FulfillTargetUpdatedInfo(ctx context.Context, return fmt.Errorf("fail to build Target from updated revision %s: %v", targetUpdateInfo.UpdateRevision.GetName(), err.Error()) } - if targetUpdateInfo.PvcTmpHashChanged { + if targetUpdateInfo.SubResourceTemplateChanged { targetUpdateInfo.InPlaceUpdateSupport, targetUpdateInfo.OnlyMetadataChanged = false, false return nil } diff --git a/pkg/controllers/collaset/subresource_adapter.go b/pkg/controllers/collaset/subresource_adapter.go new file mode 100644 index 00000000..f71e06dc --- /dev/null +++ b/pkg/controllers/collaset/subresource_adapter.go @@ -0,0 +1,123 @@ +/* +Copyright 2025 The KusionStack 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 collaset + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1" + xsetapi "kusionstack.io/kube-xset/api" + "sigs.k8s.io/controller-runtime/pkg/client" + + "kusionstack.io/kuperator/pkg/controllers/collaset/utils" +) + +// PvcAdapter implements SubResourceAdapter for PersistentVolumeClaim management. +var _ xsetapi.SubResourceAdapter = &PvcAdapter{} + +// PvcAdapter manages PVC subresources for CollaSet. +type PvcAdapter struct { + templateLabelKey string +} + +// NewPvcAdapter creates a new PVC subresource adapter. +func NewPvcAdapter() *PvcAdapter { + return &PvcAdapter{ + templateLabelKey: defaultXSetControllerLabelManager[xsetapi.SubResourceTemplateLabelKey], + } +} + +// Meta returns the GroupVersionKind for PersistentVolumeClaim. +func (p *PvcAdapter) Meta() schema.GroupVersionKind { + return corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim") +} + +// GetTemplates returns PVC templates from the CollaSet spec. +func (p *PvcAdapter) GetTemplates(xset xsetapi.XSetObject) ([]xsetapi.SubResourceTemplate, error) { + cls := xset.(*appsv1alpha1.CollaSet) + templates := cls.Spec.VolumeClaimTemplates + var result []xsetapi.SubResourceTemplate + for i := range templates { + result = append(result, xsetapi.SubResourceTemplate{ + Name: templates[i].Name, + Template: &templates[i], + }) + } + return result, nil +} + +// RetainWhenXSetDeleted returns true if PVCs should be retained when CollaSet is deleted. +func (p *PvcAdapter) RetainWhenXSetDeleted(xset xsetapi.XSetObject) bool { + cls := xset.(*appsv1alpha1.CollaSet) + return utils.PvcPolicyWhenDelete(cls) == appsv1alpha1.RetainPersistentVolumeClaimRetentionPolicyType +} + +// RetainWhenXSetScaled returns true if PVCs should be retained when CollaSet is scaled in. +func (p *PvcAdapter) RetainWhenXSetScaled(xset xsetapi.XSetObject) bool { + cls := xset.(*appsv1alpha1.CollaSet) + return utils.PvcPolicyWhenScaled(cls) == appsv1alpha1.RetainPersistentVolumeClaimRetentionPolicyType +} + +// RecreateWhenXSetUpdated returns false - PVCs are only recreated when template spec changes (hash mismatch), +// not on every update operation. +func (p *PvcAdapter) RecreateWhenXSetUpdated(_ xsetapi.XSetObject) bool { + return false +} + +// AttachToTarget attaches PVCs to the Pod by merging PVC volumes into the Pod's spec.volumes. +func (p *PvcAdapter) AttachToTarget(_ context.Context, target client.Object, resources []client.Object) error { + if len(resources) == 0 { + return nil + } + + pod := target.(*corev1.Pod) + var volumes []corev1.Volume + for _, res := range resources { + pvc, ok := res.(*corev1.PersistentVolumeClaim) + if !ok { + continue + } + templateName := pvc.Labels[p.templateLabelKey] + volumes = append(volumes, corev1.Volume{ + Name: templateName, + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvc.Name, + }, + }, + }) + } + + existingVolumes := pod.Spec.Volumes + volumeMap := make(map[string]corev1.Volume, len(existingVolumes)+len(volumes)) + for i := range existingVolumes { + volumeMap[existingVolumes[i].Name] = existingVolumes[i] + } + for i := range volumes { + volumeMap[volumes[i].Name] = volumes[i] + } + + mergedVolumes := make([]corev1.Volume, 0, len(volumeMap)) + for _, v := range volumeMap { //nolint:gocritic // unavoidable when building slice from map values + mergedVolumes = append(mergedVolumes, v) + } + + pod.Spec.Volumes = mergedVolumes + return nil +} \ No newline at end of file diff --git a/pkg/controllers/collaset/well_known_manager.go b/pkg/controllers/collaset/well_known_manager.go index 54e9d3bc..c340cd41 100644 --- a/pkg/controllers/collaset/well_known_manager.go +++ b/pkg/controllers/collaset/well_known_manager.go @@ -42,6 +42,8 @@ var defaultXSetControllerLabelManager = map[api.XSetLabelAnnotationEnum]string{ api.XCompletingLabel: appsv1alpha1.PodCompletingLabel, api.XExcludeIndicationLabelKey: appsv1alpha1.PodExcludeIndicationLabelKey, + api.SubResourceTemplateLabelKey: appsv1alpha1.PvcTemplateLabelKey, + api.SubResourceTemplateHashLabelKey: appsv1alpha1.PvcTemplateHashLabelKey, api.SubResourcePvcTemplateLabelKey: appsv1alpha1.PvcTemplateLabelKey, api.SubResourcePvcTemplateHashLabelKey: appsv1alpha1.PvcTemplateHashLabelKey, }