From 66850ee3ee6ca3ae5fcb3db9e2fecffdcbfab657 Mon Sep 17 00:00:00 2001 From: Wiley Wang Date: Tue, 14 Jan 2020 19:57:34 +0800 Subject: [PATCH] Add API for setting default storage class (#1757) Signed-off-by: Xin Wang --- pkg/apiserver/resources/storage.go | 25 ++++++++++++++ pkg/kapis/resources/v1alpha2/register.go | 10 +++++- pkg/models/storage/storage.go | 43 +++++++++++++++++++++--- 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/pkg/apiserver/resources/storage.go b/pkg/apiserver/resources/storage.go index 330aa3668..41ba4cc67 100644 --- a/pkg/apiserver/resources/storage.go +++ b/pkg/apiserver/resources/storage.go @@ -20,8 +20,10 @@ package resources import ( "github.com/emicklei/go-restful" "k8s.io/api/core/v1" + "k8s.io/klog" "net/http" + storagev1 "k8s.io/api/storage/v1" "kubesphere.io/kubesphere/pkg/models/storage" "kubesphere.io/kubesphere/pkg/server/errors" ) @@ -69,3 +71,26 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) { response.WriteAsJson(result) } + +func PatchStorageClass(request *restful.Request, response *restful.Response) { + scObj := &storagev1.StorageClass{} + err := request.ReadEntity(scObj) + if err != nil { + klog.Errorf("read entity error: %s", err.Error()) + response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err)) + return + } + klog.V(5).Infof("succeed to read entity %v", scObj) + scName := request.PathParameter("storageclass") + if scObj.Annotations[storage.IsDefaultStorageClassAnnotation] == "true" { + // Set default storage class + sc, err := storage.SetDefaultStorageClass(scName) + if err != nil { + response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err)) + return + } + response.WriteEntity(sc) + return + } + response.WriteEntity(errors.None) +} diff --git a/pkg/kapis/resources/v1alpha2/register.go b/pkg/kapis/resources/v1alpha2/register.go index 5568aa02a..2e183efed 100644 --- a/pkg/kapis/resources/v1alpha2/register.go +++ b/pkg/kapis/resources/v1alpha2/register.go @@ -22,6 +22,7 @@ import ( "github.com/emicklei/go-restful-openapi" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/runtime/schema" "kubesphere.io/kubesphere/pkg/apiserver/components" "kubesphere.io/kubesphere/pkg/apiserver/git" @@ -257,7 +258,14 @@ func addWebService(c *restful.Container) error { Returns(http.StatusOK, ok, status.WorkLoadStatus{}). To(workloadstatuses.GetNamespacedAbnormalWorkloads)) - c.Add(webservice) + webservice.Route(webservice.PATCH("/storageclasses/{storageclass}"). + To(resources.PatchStorageClass). + Doc("patch storage class"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}). + Returns(http.StatusOK, ok, storagev1.StorageClass{}). + Writes(storagev1.StorageClass{}). + Param(webservice.PathParameter("storageclass", "the name of storage class"))) + c.Add(webservice) return nil } diff --git a/pkg/models/storage/storage.go b/pkg/models/storage/storage.go index 4c784defb..4958d3c4a 100644 --- a/pkg/models/storage/storage.go +++ b/pkg/models/storage/storage.go @@ -18,6 +18,7 @@ package storage import ( + "kubesphere.io/kubesphere/pkg/simple/client" "strconv" "k8s.io/api/core/v1" @@ -27,16 +28,17 @@ import ( "kubesphere.io/kubesphere/pkg/informers" ) +const ( + IsDefaultStorageClassAnnotation = "storageclass.kubernetes.io/is-default-class" + betaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class" +) + type ScMetrics struct { Capacity string `json:"capacity,omitempty"` Usage string `json:"usage,omitempty"` PvcNumber string `json:"pvcNumber"` } -func init() { - -} - func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) { persistentVolumeClaimLister := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister() all, err := persistentVolumeClaimLister.List(labels.Everything()) @@ -102,3 +104,36 @@ func GetScList() ([]*storageV1.StorageClass, error) { return scList, nil } + +func SetDefaultStorageClass(defaultScName string) (*storageV1.StorageClass, error) { + scLister := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister() + // 1. verify storage class name + sc, err := scLister.Get(defaultScName) + if sc == nil || err != nil { + return sc, err + } + // 2. unset all default sc and then set default sc + scList, err := scLister.List(labels.Everything()) + if err != nil { + return nil, err + } + k8sClient := client.ClientSets().K8s().Kubernetes() + var defaultSc *storageV1.StorageClass + for _, sc := range scList { + _, hasDefault := sc.Annotations[IsDefaultStorageClassAnnotation] + _, hasBeta := sc.Annotations[betaIsDefaultStorageClassAnnotation] + if sc.Name == defaultScName || hasDefault || hasBeta { + delete(sc.Annotations, IsDefaultStorageClassAnnotation) + delete(sc.Annotations, betaIsDefaultStorageClassAnnotation) + if sc.Name == defaultScName { + sc.Annotations[IsDefaultStorageClassAnnotation] = "true" + defaultSc = sc + } + _, err := k8sClient.StorageV1().StorageClasses().Update(sc) + if err != nil { + return nil, err + } + } + } + return defaultSc, nil +}