Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Use default gitleaks rules + module allowlist
[extend]
useDefault = true

[allowlist]
paths = [
'''(?:^|/)images/.*\.patch$''',
]
2 changes: 1 addition & 1 deletion docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Spec:
Persistent Volume Claim Name: my-first-snapshot
Volume Snapshot Class Name: sds-replicated-volume
Status:
Bound Volume Snapshot Content Name: snapcontent-b6072ab7-6ddf-482b-a4e3-693088136d2c
Bound Volume Snapshot Content Name: snapcontent-014df517-39d1-4453-b7b3-9930c563627c
Creation Time: 2020-06-04T13:02:28Z
Ready To Use: true
Restore Size: 500Mi
Expand Down
2 changes: 1 addition & 1 deletion docs/USAGE.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Spec:
Persistent Volume Claim Name: my-first-snapshot
Volume Snapshot Class Name: sds-replicated-volume
Status:
Bound Volume Snapshot Content Name: snapcontent-b6072ab7-6ddf-482b-a4e3-693088136d2c
Bound Volume Snapshot Content Name: snapcontent-014df517-39d1-4453-b7b3-9930c563627c
Creation Time: 2020-06-04T13:02:28Z
Ready To Use: true
Restore Size: 500Mi
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
Copyright 2025 Flant JSC

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 hooks_common

import (
"context"
"errors"
"fmt"

snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
sv1 "k8s.io/api/storage/v1"
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/deckhouse/snapshot-controller/hooks/go/consts"
"github.com/deckhouse/module-sdk/pkg"
"github.com/deckhouse/module-sdk/pkg/registry"
"github.com/deckhouse/sds-common-lib/kubeclient"
)

const hookName = "remove-finalizers-on-module-delete"

func removeFinalizersFromObject(ctx context.Context, cl client.Client, obj client.Object, logger pkg.Logger) error {
logger.Info(fmt.Sprintf("[%s]: Removing finalizers from %s %s", hookName, obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName()))

patch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
obj.SetFinalizers(nil)

if err := cl.Patch(ctx, obj, patch); err != nil {
return fmt.Errorf("failed to patch %s %s: %w", obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName(), err)
}
return nil
}

var _ = registry.RegisterFunc(configRemoveFinalizersOnModuleDelete, handlerRemoveFinalizersOnModuleDelete)

var configRemoveFinalizersOnModuleDelete = &pkg.HookConfig{
OnAfterDeleteHelm: &pkg.OrderedConfig{Order: 10},
}

func handlerRemoveFinalizersOnModuleDelete(ctx context.Context, input *pkg.HookInput) error {
input.Logger.Info(fmt.Sprintf("[%s]: Started removing finalizers on module delete", hookName))
var resultErr error

cl, err := kubeclient.New(
admissionregistrationv1.AddToScheme,
clientgoscheme.AddToScheme,
extv1.AddToScheme,
v1.AddToScheme,
sv1.AddToScheme,
snapv1.AddToScheme)
if err != nil {
return fmt.Errorf("failed to initialize kube client: %w", err)
}

// Remove finalizers from Secrets in module namespace
secretList := &corev1.SecretList{}
if err := cl.List(ctx, secretList, client.InNamespace(consts.ModuleNamespace)); err != nil {
resultErr = errors.Join(resultErr, fmt.Errorf("[%s]: failed to list secrets: %w", hookName, err))
} else {
for i := range secretList.Items {
if err := removeFinalizersFromObject(ctx, cl, &secretList.Items[i], input.Logger); err != nil {
resultErr = errors.Join(resultErr, err)
}
}
}

// Remove finalizers from ConfigMaps in module namespace
configMapList := &corev1.ConfigMapList{}
if err := cl.List(ctx, configMapList, client.InNamespace(consts.ModuleNamespace)); err != nil {
resultErr = errors.Join(resultErr, fmt.Errorf("[%s]: failed to list configmaps: %w", hookName, err))
} else {
for i := range configMapList.Items {
if err := removeFinalizersFromObject(ctx, cl, &configMapList.Items[i], input.Logger); err != nil {
resultErr = errors.Join(resultErr, err)
}
}
}

// Delete ValidatingWebhookConfigurations if configured
for _, name := range consts.WebhookConfigurationsToDelete {
vwc := &admissionregistrationv1.ValidatingWebhookConfiguration{}
if err := cl.Get(ctx, client.ObjectKey{Name: name}, vwc); err == nil {
input.Logger.Info(fmt.Sprintf("[%s]: Deleting ValidatingWebhookConfiguration %s", hookName, name))
if err := cl.Delete(ctx, vwc); err != nil {
resultErr = errors.Join(resultErr, fmt.Errorf("[%s]: failed to delete ValidatingWebhookConfiguration %s: %w", hookName, name, err))
}
}
}

// Remove finalizers from StorageClass if controller creates them
for _, provisioner := range consts.AllowedProvisioners {
scList := &storagev1.StorageClassList{}
if err := cl.List(ctx, scList); err != nil {
resultErr = errors.Join(resultErr, fmt.Errorf("[%s]: failed to list storage classes: %w", hookName, err))
break
}
for i := range scList.Items {
if scList.Items[i].Provisioner != provisioner {
continue
}
if err := removeFinalizersFromObject(ctx, cl, &scList.Items[i], input.Logger); err != nil {
resultErr = errors.Join(resultErr, err)
}
}
}

// Remove finalizers from CRs from module's crd folder
for _, crgvk := range consts.CRGVKsForFinalizerRemoval {
ns := ""
if crgvk.Namespaced {
ns = consts.ModuleNamespace
}
crList := &unstructured.UnstructuredList{}
crList.SetGroupVersionKind(schema.GroupVersionKind{
Group: crgvk.Group,
Version: crgvk.Version,
Kind: crgvk.Kind + "List",
})
if err := cl.List(ctx, crList, client.InNamespace(ns)); err != nil {
input.Logger.Info(fmt.Sprintf("[%s]: skipping CR %s (may not exist): %v", hookName, crgvk.Kind, err))
continue
}
for i := range crList.Items {
cr := &crList.Items[i]
if len(cr.GetFinalizers()) == 0 {
continue
}
if err := removeFinalizersFromObject(ctx, cl, cr, input.Logger); err != nil {
resultErr = errors.Join(resultErr, err)
}
}
}

input.Logger.Info(fmt.Sprintf("[%s]: Finished removing finalizers on module delete", hookName))
return resultErr
}
17 changes: 17 additions & 0 deletions hooks/go/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,20 @@ const (
ValidatingWebhookCertCn string = "snapshot-validation-webhook"
WebhookCertCn string = "webhooks"
)

var AllowedProvisioners = []string{}

var WebhookConfigurationsToDelete = []string{}

var CRGVKsForFinalizerRemoval = []CRGVK{
{Group: "snapshot.storage.k8s.io", Version: "v1", Kind: "VolumeSnapshot", Namespaced: true},
{Group: "snapshot.storage.k8s.io", Version: "v1", Kind: "VolumeSnapshotContent", Namespaced: false},
{Group: "snapshot.storage.k8s.io", Version: "v1", Kind: "VolumeSnapshotClass", Namespaced: false},
}

type CRGVK struct {
Group string
Version string
Kind string
Namespaced bool
}
16 changes: 10 additions & 6 deletions hooks/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ module github.com/deckhouse/snapshot-controller/hooks/go

go 1.25.7

require github.com/deckhouse/module-sdk v0.7.0
require (
github.com/deckhouse/module-sdk v0.7.0
github.com/deckhouse/sds-common-lib v0.0.0-20250428090414-0c2938b30fa7
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0
k8s.io/api v0.32.10
k8s.io/apiextensions-apiserver v0.32.10
k8s.io/apimachinery v0.32.10
k8s.io/client-go v0.32.10
sigs.k8s.io/controller-runtime v0.20.4
)

require (
github.com/DataDog/gostackparse v0.7.0 // indirect
Expand Down Expand Up @@ -80,14 +89,9 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.32.10 // indirect
k8s.io/apiextensions-apiserver v0.32.10 // indirect
k8s.io/apimachinery v0.32.10 // indirect
k8s.io/client-go v0.32.10 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
sigs.k8s.io/controller-runtime v0.20.4 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions hooks/go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ github.com/deckhouse/deckhouse/pkg/log v0.0.0-20250814094423-e9f108b41a1a h1:An8
github.com/deckhouse/deckhouse/pkg/log v0.0.0-20250814094423-e9f108b41a1a/go.mod h1:pbAxTSDcPmwyl3wwKDcEB3qdxHnRxqTV+J0K+sha8bw=
github.com/deckhouse/module-sdk v0.7.0 h1:zS7QjgLqaSqjDTeH6B4k7Fl0z8biuKACL9A6GtpIGeo=
github.com/deckhouse/module-sdk v0.7.0/go.mod h1:+EbBnP8z+poIihgL4l1oxHng5ePqDUK44c39u7sEBss=
github.com/deckhouse/sds-common-lib v0.0.0-20250428090414-0c2938b30fa7 h1:rudy3ychoDH7j8ft9feuF+2lt4PFjkBZOzvzgsT+mQU=
github.com/deckhouse/sds-common-lib v0.0.0-20250428090414-0c2938b30fa7/go.mod h1:tAZI7ZaVeJi5/Fe5Mebw3d6NC4nTHUOOTwZFnHHzxFU=
github.com/docker/cli v28.2.2+incompatible h1:qzx5BNUDFqlvyq4AHzdNB7gSyVTmU4cgsyN9SdInc1A=
github.com/docker/cli v28.2.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
Expand Down Expand Up @@ -103,6 +105,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 h1:Q3jQ1NkFqv5o+F8dMmHd8SfEmlcwNeo1immFApntEwE=
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
Expand Down
1 change: 1 addition & 0 deletions hooks/go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package main
import (
"github.com/deckhouse/module-sdk/pkg/app"
_ "github.com/deckhouse/snapshot-controller/hooks/go/020-webhook-certs"
_ "github.com/deckhouse/snapshot-controller/hooks/go/030-remove-finalizers-on-module-delete"
_ "github.com/deckhouse/snapshot-controller/hooks/go/030-snapshot-validation-webhook-certs"
)

Expand Down
Loading