From a48a6c6eef30feb99df67aebed26d5c497b0199f Mon Sep 17 00:00:00 2001 From: Alexandr Marchenko Date: Fri, 10 Dec 2021 12:00:37 +0200 Subject: [PATCH] [local-path-provisioner] add reclaimPolicy field. --- .../crds/doc-ru-local_path_provisioner.yaml | 3 + .../crds/local_path_provisioner.yaml | 6 + .../031-local-path-provisioner/docs/FAQ.md | 1 + .../031-local-path-provisioner/docs/README.md | 3 +- .../docs/README_RU.md | 3 +- .../031-local-path-provisioner/docs/USAGE.md | 14 +++ .../docs/USAGE_RU.md | 15 +++ .../hooks/get_crds_test.go | 16 ++- .../internal/v1alpha1/localpathprovisioner.go | 3 + .../hooks/storage_classes.go | 106 ++++++++++++++++++ .../hooks/storage_classes_test.go | 83 ++++++++++++++ .../images/local-path-provisioner/Dockerfile | 5 +- .../openapi/values.yaml | 7 +- .../templates/storage-classes.yaml | 2 +- 14 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 modules/031-local-path-provisioner/hooks/storage_classes.go create mode 100644 modules/031-local-path-provisioner/hooks/storage_classes_test.go diff --git a/modules/031-local-path-provisioner/crds/doc-ru-local_path_provisioner.yaml b/modules/031-local-path-provisioner/crds/doc-ru-local_path_provisioner.yaml index f637fb644bb..a72f8b5571f 100644 --- a/modules/031-local-path-provisioner/crds/doc-ru-local_path_provisioner.yaml +++ b/modules/031-local-path-provisioner/crds/doc-ru-local_path_provisioner.yaml @@ -16,3 +16,6 @@ spec: path: description: | Корневой путь на ноде к директории для хранения PV. + reclaimPolicy: + description: | + Сохранять ли PV после удаления PVC. diff --git a/modules/031-local-path-provisioner/crds/local_path_provisioner.yaml b/modules/031-local-path-provisioner/crds/local_path_provisioner.yaml index ea3c8b4a99f..d2655fa9dd6 100644 --- a/modules/031-local-path-provisioner/crds/local_path_provisioner.yaml +++ b/modules/031-local-path-provisioner/crds/local_path_provisioner.yaml @@ -42,3 +42,9 @@ spec: description: | Node root path for PV's. example: "/opt/local-path-provisioner" + reclaimPolicy: + type: string + enum: ["Retain", "Delete"] + default: "Retain" + description: | + Retain policy for PV's. diff --git a/modules/031-local-path-provisioner/docs/FAQ.md b/modules/031-local-path-provisioner/docs/FAQ.md index 58b74612ee8..61d0293a2fb 100644 --- a/modules/031-local-path-provisioner/docs/FAQ.md +++ b/modules/031-local-path-provisioner/docs/FAQ.md @@ -27,3 +27,4 @@ prometheus: | ``` Wait for the restart of Prometheus Pods. + diff --git a/modules/031-local-path-provisioner/docs/README.md b/modules/031-local-path-provisioner/docs/README.md index 0e200849430..b57a0e4d19c 100644 --- a/modules/031-local-path-provisioner/docs/README.md +++ b/modules/031-local-path-provisioner/docs/README.md @@ -20,4 +20,5 @@ When a Pod orders a disk: ``` ## Limitations -The disk size limit is not supported for the local path provisioned volumes. + +- The disk size limit is not supported for the local path provisioned volumes. diff --git a/modules/031-local-path-provisioner/docs/README_RU.md b/modules/031-local-path-provisioner/docs/README_RU.md index 3df42a87002..a6217581b3e 100644 --- a/modules/031-local-path-provisioner/docs/README_RU.md +++ b/modules/031-local-path-provisioner/docs/README_RU.md @@ -19,4 +19,5 @@ title: "Модуль local-path-provisioner" ``` ## Ограничения -Ограничение на размер диска не поддерживается для локальных томов. + +- Ограничение на размер диска не поддерживается для локальных томов. diff --git a/modules/031-local-path-provisioner/docs/USAGE.md b/modules/031-local-path-provisioner/docs/USAGE.md index 321abd86954..579dae5ee58 100644 --- a/modules/031-local-path-provisioner/docs/USAGE.md +++ b/modules/031-local-path-provisioner/docs/USAGE.md @@ -3,7 +3,20 @@ title: "The local-path-provisioner module: configuration examples" --- ## Example CR `LocalPathProvisioner` +Reclaim policy set by default to `Retain`. +```yaml +apiVersion: deckhouse.io/v1alpha1 +kind: LocalPathProvisioner +metadata: + name: localpath-system +spec: + nodeGroups: + - system + path: "/opt/local-path-provisioner" +``` +## Example CR `LocalPathProvisioner` with `reclaimPolicy` set +Reclaim policy set to `Delete`. ```yaml apiVersion: deckhouse.io/v1alpha1 kind: LocalPathProvisioner @@ -13,4 +26,5 @@ spec: nodeGroups: - system path: "/opt/local-path-provisioner" + reclaimPolicy: "Delete" ``` diff --git a/modules/031-local-path-provisioner/docs/USAGE_RU.md b/modules/031-local-path-provisioner/docs/USAGE_RU.md index 1ec8b0a9908..8d373ebee03 100644 --- a/modules/031-local-path-provisioner/docs/USAGE_RU.md +++ b/modules/031-local-path-provisioner/docs/USAGE_RU.md @@ -3,7 +3,20 @@ title: "Модуль local-path-provisioner: примеры конфигурац --- ## Пример CR `LocalPathProvisioner` +Reclaim policy устанавливается по умолчанию в `Retain`. +```yaml +apiVersion: deckhouse.io/v1alpha1 +kind: LocalPathProvisioner +metadata: + name: localpath-system +spec: + nodeGroups: + - system + path: "/opt/local-path-provisioner" +``` +## Пример CR `LocalPathProvisioner` с установленным `reclaimPolicy` +Reclaim policy устанавливается в `Delete`. ```yaml apiVersion: deckhouse.io/v1alpha1 kind: LocalPathProvisioner @@ -13,4 +26,6 @@ spec: nodeGroups: - system path: "/opt/local-path-provisioner" + reclaimPolicy: "Delete" ``` + diff --git a/modules/031-local-path-provisioner/hooks/get_crds_test.go b/modules/031-local-path-provisioner/hooks/get_crds_test.go index 169b8d49f12..ac36438d64c 100644 --- a/modules/031-local-path-provisioner/hooks/get_crds_test.go +++ b/modules/031-local-path-provisioner/hooks/get_crds_test.go @@ -49,6 +49,7 @@ spec: nodeGroups: - master path: "/local" + reclaimPolicy: "Retain" `)) f.RunHook() }) @@ -61,7 +62,8 @@ spec: "name": "local1", "spec": { "nodeGroups": ["master"], - "path": "/local" + "path": "/local", + "reclaimPolicy": "Retain" } }]`)) }) @@ -90,6 +92,7 @@ spec: - worker - system path: "/opt/local-path-provisioner" + reclaimPolicy: "Delete" `)) f.RunHook() }) @@ -102,7 +105,8 @@ spec: "name": "local1", "spec": { "nodeGroups": ["worker", "system"], - "path": "/opt/local-path-provisioner" + "path": "/opt/local-path-provisioner", + "reclaimPolicy": "Delete" } }]`)) }) @@ -123,6 +127,7 @@ spec: - master - worker path: "/opt/local-path-provisioner" + reclaimPolicy: "Delete" --- apiVersion: deckhouse.io/v1alpha1 kind: LocalPathProvisioner @@ -130,6 +135,7 @@ metadata: name: local2 spec: path: "/local" + reclaimPolicy: "Retain" `)) f.RunHook() }) @@ -140,13 +146,15 @@ spec: "name": "local1", "spec": { "nodeGroups": ["master", "worker"], - "path": "/opt/local-path-provisioner" + "path": "/opt/local-path-provisioner", + "reclaimPolicy": "Delete" } }, { "name": "local2", "spec": { - "path": "/local" + "path": "/local", + "reclaimPolicy": "Retain" } } ]`)) diff --git a/modules/031-local-path-provisioner/hooks/internal/v1alpha1/localpathprovisioner.go b/modules/031-local-path-provisioner/hooks/internal/v1alpha1/localpathprovisioner.go index 9469168be55..5ba8e3f7968 100644 --- a/modules/031-local-path-provisioner/hooks/internal/v1alpha1/localpathprovisioner.go +++ b/modules/031-local-path-provisioner/hooks/internal/v1alpha1/localpathprovisioner.go @@ -38,4 +38,7 @@ type LocalPathProvisionerSpec struct { // Node root path for local path provisioner pvs. Path string `json:"path"` + + // Reclaim policy + ReclaimPolicy string `json:"reclaimPolicy"` } diff --git a/modules/031-local-path-provisioner/hooks/storage_classes.go b/modules/031-local-path-provisioner/hooks/storage_classes.go new file mode 100644 index 00000000000..5aa1e43a25a --- /dev/null +++ b/modules/031-local-path-provisioner/hooks/storage_classes.go @@ -0,0 +1,106 @@ +/* +Copyright 2021 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 + +import ( + "fmt" + + "github.com/flant/addon-operator/pkg/module_manager/go_hook" + "github.com/flant/addon-operator/sdk" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "github.com/deckhouse/deckhouse/modules/031-local-path-provisioner/hooks/internal/v1alpha1" +) + +type StorageClass struct { + Name string + ReclaimPolicy string +} + +var _ = sdk.RegisterFunc(&go_hook.HookConfig{ + Queue: "/modules/local-path-provisioner", + OnBeforeHelm: &go_hook.OrderedConfig{Order: 20}, + Kubernetes: []go_hook.KubernetesConfig{ + { + Name: "module_storageclasses", + ApiVersion: "storage.k8s.io/v1", + Kind: "StorageClass", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"module": "local-path-provisioner"}, + }, + FilterFunc: applyModuleStorageClassesFilter, + }, + { + Name: "module_crds", + ApiVersion: "deckhouse.io/v1alpha1", + Kind: "LocalPathProvisioner", + FilterFunc: applyModuleCRDFilter, + }, + }, +}, storageClasses) + +func applyModuleStorageClassesFilter(obj *unstructured.Unstructured) (go_hook.FilterResult, error) { + var sc = &storagev1.StorageClass{} + err := sdk.FromUnstructured(obj, sc) + if err != nil { + return nil, fmt.Errorf("cannot convert kubernetes object: %v", err) + } + + return StorageClass{Name: sc.Name, ReclaimPolicy: string(*sc.ReclaimPolicy)}, nil +} + +func applyModuleCRDFilter(obj *unstructured.Unstructured) (go_hook.FilterResult, error) { + lpp := new(v1alpha1.LocalPathProvisioner) + err := sdk.FromUnstructured(obj, lpp) + if err != nil { + return nil, err + } + + return StorageClass{ + Name: lpp.Name, + ReclaimPolicy: lpp.Spec.ReclaimPolicy, + }, nil +} + +func storageClasses(input *go_hook.HookInput) error { + var existedStorageClasses []StorageClass + + if len(input.Snapshots["module_storageclasses"]) == 0 || len(input.Snapshots["module_crds"]) == 0 { + return nil + } + + for _, snapshot := range input.Snapshots["module_storageclasses"] { + sc := snapshot.(StorageClass) + existedStorageClasses = append(existedStorageClasses, sc) + } + + for _, snapshot := range input.Snapshots["module_crds"] { + crd := snapshot.(StorageClass) + for _, storageClass := range existedStorageClasses { + if storageClass.Name == crd.Name { + if storageClass.ReclaimPolicy != crd.ReclaimPolicy { + input.LogEntry.Infof("Deleting storageclass/%s because its parameters has been changed", storageClass.Name) + input.PatchCollector.Delete("storage.k8s.io/v1", "StorageClass", "", storageClass.Name) + } + break + } + } + } + return nil +} diff --git a/modules/031-local-path-provisioner/hooks/storage_classes_test.go b/modules/031-local-path-provisioner/hooks/storage_classes_test.go new file mode 100644 index 00000000000..98a0669d995 --- /dev/null +++ b/modules/031-local-path-provisioner/hooks/storage_classes_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2021 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 + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + . "github.com/deckhouse/deckhouse/testing/hooks" +) + +const clusterStorageClasses = ` +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + labels: + module: local-path-provisioner + name: localpath-worker +reclaimPolicy: Retain +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + labels: + module: local-path-provisioner + name: localpath-worker2 +reclaimPolicy: Delete +` + +var _ = Describe("Local Path Provisioner hooks :: delete SC when reclaimPolicy in CRD is changed ::", func() { + f := HookExecutionConfigInit(`{"localPathProvisioner":{"internal": {}}}`, "") + f.RegisterCRD("deckhouse.io", "v1alpha1", "LocalPathProvisioner", false) + + Context("Fresh cluster", func() { + BeforeEach(func() { + f.BindingContexts.Set(f.KubeStateSet(clusterStorageClasses)) + f.RunHook() + }) + It("Should run", func() { + Expect(f).To(ExecuteSuccessfully()) + Expect(f.BindingContexts.Array()).ShouldNot(BeEmpty()) + }) + }) + + Context("With adding localPathProvisioner crd", func() { + BeforeEach(func() { + f.BindingContexts.Set(f.KubeStateSet(clusterStorageClasses + ` +--- +apiVersion: deckhouse.io/v1alpha1 +kind: LocalPathProvisioner +metadata: + name: localpath-worker +spec: + nodeGroups: + - worker + path: "/local" + reclaimPolicy: "Delete" +`)) + f.RunHook() + }) + It("Should remove localpath-worker storage class", func() { + Expect(f).To(ExecuteSuccessfully()) + Expect(f.BindingContexts.Array()).ShouldNot(BeEmpty()) + Expect(f.KubernetesGlobalResource("StorageClass", "localpath-worker").Exists()).To(BeFalse()) + Expect(f.KubernetesGlobalResource("StorageClass", "localpath-worker2").Exists()).To(BeTrue()) + }) + }) +}) diff --git a/modules/031-local-path-provisioner/images/local-path-provisioner/Dockerfile b/modules/031-local-path-provisioner/images/local-path-provisioner/Dockerfile index fd53866c1e9..1863d06e410 100644 --- a/modules/031-local-path-provisioner/images/local-path-provisioner/Dockerfile +++ b/modules/031-local-path-provisioner/images/local-path-provisioner/Dockerfile @@ -5,8 +5,9 @@ ARG VERSION=0.0.21 ARG COMMIT_REF=755e331a276d4dd26f84377db5504a38109df8fb RUN apk add --no-cache go git -RUN git clone https://github.com/rancher/local-path-provisioner.git -WORKDIR /local-path-provisioner +RUN mkdir /src +RUN git clone https://github.com/rancher/local-path-provisioner.git /src +WORKDIR /src RUN git checkout "${COMMIT_REF}" # Do not create directory if not found (GH: #224) diff --git a/modules/031-local-path-provisioner/openapi/values.yaml b/modules/031-local-path-provisioner/openapi/values.yaml index 9ef31da3b52..9758cbe9853 100644 --- a/modules/031-local-path-provisioner/openapi/values.yaml +++ b/modules/031-local-path-provisioner/openapi/values.yaml @@ -38,6 +38,11 @@ properties: minLength: 1 description: | Node root path for local-path-provisioner PV's. + reclaimPolicy: + type: string + enum: ["Retain", "Delete"] + description: | + Retain policy for PV's. x-examples: - [] - - [{"name":"test1","spec":{"nodeGroups": ["master","worker"],"path": "/tmp/test"}}, {"name":"test2","spec":{"path": "/opt/local-path-provisioner"}}] + - [{"name":"test1", "spec":{"nodeGroups": ["master","worker"], "path": "/tmp/test", reclaimPolicy: "Retain"}}, {"name":"test2", "spec":{"path": "/opt/local-path-provisioner", reclaimPolicy: "Delete"}}] diff --git a/modules/031-local-path-provisioner/templates/storage-classes.yaml b/modules/031-local-path-provisioner/templates/storage-classes.yaml index e6c4505deb9..113551cfc72 100644 --- a/modules/031-local-path-provisioner/templates/storage-classes.yaml +++ b/modules/031-local-path-provisioner/templates/storage-classes.yaml @@ -9,7 +9,7 @@ metadata: provisioner: deckhouse.io/{{ $localPathProvisioner.name }} allowVolumeExpansion: true volumeBindingMode: WaitForFirstConsumer -reclaimPolicy: Delete +reclaimPolicy: {{ $localPathProvisioner.spec.reclaimPolicy }} {{- if $localPathProvisioner.spec.nodeGroups }} allowedTopologies: - matchLabelExpressions: