From 1ef22e19eb5a9702239943ca9732c2f8d6c84815 Mon Sep 17 00:00:00 2001 From: qJkee Date: Thu, 5 Sep 2024 14:26:23 +0400 Subject: [PATCH] feat(lvm cluster): make thin pool config editable Make editable overprovisionRatio field in thin pool device class at lvm cluster --- api/v1alpha1/lvmcluster_test.go | 18 -------- api/v1alpha1/lvmcluster_webhook.go | 2 - internal/controllers/vgmanager/controller.go | 17 +++++--- internal/controllers/vgmanager/lvmd/lvmd.go | 45 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/api/v1alpha1/lvmcluster_test.go b/api/v1alpha1/lvmcluster_test.go index d29fd1ea8..cdceac999 100644 --- a/api/v1alpha1/lvmcluster_test.go +++ b/api/v1alpha1/lvmcluster_test.go @@ -418,24 +418,6 @@ var _ = Describe("webhook acceptance tests", func() { Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) }) - It("updating ThinPoolConfig.OverprovisionRatio is not allowed", func(ctx SpecContext) { - resource := defaultLVMClusterInUniqueNamespace(ctx) - Expect(k8sClient.Create(ctx, resource)).To(Succeed()) - - updated := resource.DeepCopy() - - updated.Spec.Storage.DeviceClasses[0].ThinPoolConfig.OverprovisionRatio-- - - err := k8sClient.Update(ctx, updated) - Expect(err).To(HaveOccurred()) - Expect(err).To(Satisfy(k8serrors.IsForbidden)) - statusError := &k8serrors.StatusError{} - Expect(errors.As(err, &statusError)).To(BeTrue()) - Expect(statusError.Status().Message).To(ContainSubstring(ErrThinPoolConfigCannotBeChanged.Error())) - - Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) - }) - It("updating ThinPoolConfig.ChunkSizeCalculationPolicy is not allowed", func(ctx SpecContext) { resource := defaultLVMClusterInUniqueNamespace(ctx) Expect(k8sClient.Create(ctx, resource)).To(Succeed()) diff --git a/api/v1alpha1/lvmcluster_webhook.go b/api/v1alpha1/lvmcluster_webhook.go index 7a509882a..7bde78844 100644 --- a/api/v1alpha1/lvmcluster_webhook.go +++ b/api/v1alpha1/lvmcluster_webhook.go @@ -189,8 +189,6 @@ func (v *lvmClusterValidator) ValidateUpdate(_ context.Context, old, new runtime return warnings, fmt.Errorf("ThinPoolConfig.Name is invalid: %w", ErrThinPoolConfigCannotBeChanged) } else if newThinPoolConfig.SizePercent != oldThinPoolConfig.SizePercent { return warnings, fmt.Errorf("ThinPoolConfig.SizePercent is invalid: %w", ErrThinPoolConfigCannotBeChanged) - } else if newThinPoolConfig.OverprovisionRatio != oldThinPoolConfig.OverprovisionRatio { - return warnings, fmt.Errorf("ThinPoolConfig.OverprovisionRatio is invalid: %w", ErrThinPoolConfigCannotBeChanged) } else if newThinPoolConfig.ChunkSizeCalculationPolicy != oldThinPoolConfig.ChunkSizeCalculationPolicy { return warnings, fmt.Errorf("ThinPoolConfig.ChunkSizeCalculationPolicy is invalid: %w", ErrThinPoolConfigCannotBeChanged) } else if !reflect.DeepEqual(newThinPoolConfig.ChunkSize, oldThinPoolConfig.ChunkSize) { diff --git a/internal/controllers/vgmanager/controller.go b/internal/controllers/vgmanager/controller.go index 4259aa791..56c20c225 100644 --- a/internal/controllers/vgmanager/controller.go +++ b/internal/controllers/vgmanager/controller.go @@ -331,17 +331,20 @@ func (r *Reconciler) applyLVMDConfig(ctx context.Context, volumeGroup *lvmv1alph lvmdConfigWasMissing = true lvmdConfig = &lvmd.Config{} } - existingLvmdConfig := *lvmdConfig + + oldConfig := lvmd.DeepCopyConfig(lvmdConfig) // Add the volume group to device classes inside lvmd config if not exists - found := false + var dc *lvmd.DeviceClass for _, deviceClass := range lvmdConfig.DeviceClasses { if deviceClass.Name == volumeGroup.Name { - found = true + dc = deviceClass + break } } - if !found { - dc := &lvmd.DeviceClass{ + + if dc == nil { + dc = &lvmd.DeviceClass{ Name: volumeGroup.Name, VolumeGroup: volumeGroup.Name, Default: volumeGroup.Spec.Default, @@ -360,9 +363,11 @@ func (r *Reconciler) applyLVMDConfig(ctx context.Context, volumeGroup *lvmv1alph } lvmdConfig.DeviceClasses = append(lvmdConfig.DeviceClasses, dc) + } else if dc.Type == lvmd.TypeThin { + dc.ThinPoolConfig.OverprovisionRatio = float64(volumeGroup.Spec.ThinPoolConfig.OverprovisionRatio) } - if err := r.updateLVMDConfigAfterReconcile(ctx, volumeGroup, &existingLvmdConfig, lvmdConfig, lvmdConfigWasMissing); err != nil { + if err := r.updateLVMDConfigAfterReconcile(ctx, volumeGroup, oldConfig, lvmdConfig, lvmdConfigWasMissing); err != nil { if _, err := r.setVolumeGroupFailedStatus(ctx, volumeGroup, vgs, devices, err); err != nil { logger.Error(err, "failed to set status to failed") } diff --git a/internal/controllers/vgmanager/lvmd/lvmd.go b/internal/controllers/vgmanager/lvmd/lvmd.go index 20f8f9767..857db0e35 100644 --- a/internal/controllers/vgmanager/lvmd/lvmd.go +++ b/internal/controllers/vgmanager/lvmd/lvmd.go @@ -9,6 +9,7 @@ import ( lvmdCMD "github.com/topolvm/topolvm/cmd/lvmd/app" lvmd "github.com/topolvm/topolvm/pkg/lvmd/types" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/yaml" ) @@ -31,6 +32,50 @@ const ( maxReadLength = 2 * 1 << 20 // 2MB ) +func DeepCopyConfig(c *Config) *Config { + if c == nil { + return nil + } + + conf := &Config{ + SocketName: c.SocketName, + } + + for _, dc := range c.DeviceClasses { + newDc := &DeviceClass{ + Name: dc.Name, + VolumeGroup: dc.VolumeGroup, + Default: dc.Default, + StripeSize: dc.StripeSize, + LVCreateOptions: dc.LVCreateOptions, + Type: dc.Type, + } + if dc.SpareGB != nil { + newDc.SpareGB = ptr.To(*dc.SpareGB) + } + if dc.Stripe != nil { + newDc.Stripe = ptr.To(*dc.Stripe) + } + if dc.ThinPoolConfig != nil { + newDc.ThinPoolConfig = &ThinPoolConfig{ + Name: dc.ThinPoolConfig.Name, + OverprovisionRatio: dc.ThinPoolConfig.OverprovisionRatio, + } + } + conf.DeviceClasses = append(conf.DeviceClasses, newDc) + } + + for _, co := range c.LvcreateOptionClasses { + opt := &lvmd.LvcreateOptionClass{ + Name: co.Name, + Options: co.Options, + } + conf.LvcreateOptionClasses = append(conf.LvcreateOptionClasses, opt) + } + + return conf +} + func DefaultConfigurator() *CachedFileConfig { return NewFileConfigurator(DefaultFileConfigPath) }