From 1378757350bd757426bb865c48d4e14aeca13dc8 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Mon, 9 May 2022 11:50:29 -0400 Subject: [PATCH] feat: cleanup shared PVC when no longer in use Fix #826 Signed-off-by: Andrew Obuchowicz --- pkg/provision/storage/commonStorage.go | 34 ++++++++++++++++++++++++-- pkg/provision/storage/shared.go | 19 ++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pkg/provision/storage/commonStorage.go b/pkg/provision/storage/commonStorage.go index 0f5b14cfb..58eb1732c 100644 --- a/pkg/provision/storage/commonStorage.go +++ b/pkg/provision/storage/commonStorage.go @@ -19,9 +19,12 @@ import ( "fmt" dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/devworkspace-operator/pkg/config" "github.com/devfile/devworkspace-operator/pkg/provision/sync" corev1 "k8s.io/api/core/v1" + k8sErrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" "github.com/devfile/devworkspace-operator/pkg/constants" @@ -71,8 +74,35 @@ func (p *CommonStorageProvisioner) ProvisionStorage(podAdditions *v1alpha1.PodAd return nil } -func (*CommonStorageProvisioner) CleanupWorkspaceStorage(workspace *dw.DevWorkspace, clusterAPI sync.ClusterAPI) error { - return runCommonPVCCleanupJob(workspace, clusterAPI) +func (p *CommonStorageProvisioner) CleanupWorkspaceStorage(workspace *dw.DevWorkspace, clusterAPI sync.ClusterAPI) error { + totalWorkspaces, err := getSharedPVCWorkspaceCount(workspace.Namespace, clusterAPI) + if err != nil { + return err + } + + // If the number of common + async workspaces that exist (started or stopped) is zero, + // delete common PVC instead of running cleanup job + if totalWorkspaces > 1 { + return runCommonPVCCleanupJob(workspace, clusterAPI) + } else { + sharedPVC := &corev1.PersistentVolumeClaim{} + namespacedName := types.NamespacedName{Name: config.Workspace.PVCName, Namespace: workspace.Namespace} + err := clusterAPI.Client.Get(clusterAPI.Ctx, namespacedName, sharedPVC) + + if err != nil { + if k8sErrors.IsNotFound(err) { + return nil + } + return err + } + + err = clusterAPI.Client.Delete(clusterAPI.Ctx, sharedPVC) + if err != nil && !k8sErrors.IsNotFound(err) { + return err + } + } + + return nil } // rewriteContainerVolumeMounts rewrites the VolumeMounts in a set of PodAdditions according to the 'common' PVC strategy diff --git a/pkg/provision/storage/shared.go b/pkg/provision/storage/shared.go index fa8e92255..1af370760 100644 --- a/pkg/provision/storage/shared.go +++ b/pkg/provision/storage/shared.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" "github.com/devfile/devworkspace-operator/pkg/config" @@ -235,3 +236,21 @@ func checkForExistingCommonPVC(namespace string, api sync.ClusterAPI) (string, e } return existingPVC.Name, nil } + +// getSharedPVCWorkspaceCount returns the total number of workspaces which are using a shared PVC +// (i.e the workspaces storage-class attribute is set to "common", "async", or unset which defaults to "common") +func getSharedPVCWorkspaceCount(namespace string, api sync.ClusterAPI) (total int, err error) { + workspaces := &dw.DevWorkspaceList{} + err = api.Client.List(api.Ctx, workspaces, &client.ListOptions{Namespace: namespace}) + if err != nil { + return 0, err + } + for _, workspace := range workspaces.Items { + storageClass := workspace.Spec.Template.Attributes.GetString(constants.DevWorkspaceStorageTypeAttribute, nil) + // Note, if the storageClass attribute isin't set (ie. storageClass == ""), then the storage class being used is "common" + if storageClass == constants.AsyncStorageClassType || storageClass == constants.CommonStorageClassType || storageClass == "" { + total++ + } + } + return total, nil +}