From b7307da6201be3cc34827f61ee84ac2562b9e05e Mon Sep 17 00:00:00 2001 From: wnxn Date: Thu, 24 May 2018 17:21:41 +0800 Subject: [PATCH 1/2] Add the API of listing all PVC of the specific storageclass --- pkg/apis/v1alpha/install.go | 29 +++++------ pkg/apis/v1alpha/storage/storage_handler.go | 14 ++++++ pkg/models/storage.go | 54 +++++++++++++++++++++ 3 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 pkg/apis/v1alpha/storage/storage_handler.go create mode 100644 pkg/models/storage.go diff --git a/pkg/apis/v1alpha/install.go b/pkg/apis/v1alpha/install.go index f120040a2..772dc7e9f 100644 --- a/pkg/apis/v1alpha/install.go +++ b/pkg/apis/v1alpha/install.go @@ -17,25 +17,26 @@ limitations under the License. package v1alpha import ( - "github.com/emicklei/go-restful" - "kubesphere.io/kubesphere/pkg/apis/v1alpha/nodes" - "kubesphere.io/kubesphere/pkg/apis/v1alpha/kubeconfig" - "kubesphere.io/kubesphere/pkg/apis/v1alpha/kubectl" - "kubesphere.io/kubesphere/pkg/apis/v1alpha/registries" + "github.com/emicklei/go-restful" + "kubesphere.io/kubesphere/pkg/apis/v1alpha/kubeconfig" + "kubesphere.io/kubesphere/pkg/apis/v1alpha/kubectl" + "kubesphere.io/kubesphere/pkg/apis/v1alpha/nodes" + "kubesphere.io/kubesphere/pkg/apis/v1alpha/registries" + "kubesphere.io/kubesphere/pkg/apis/v1alpha/storage" ) func init() { - ws := new(restful.WebService) - ws.Path("/api/v1alpha") + ws := new(restful.WebService) + ws.Path("/api/v1alpha") - nodes.Register(ws,"/nodes") - kubeconfig.Register(ws, "/namespaces/{namespace}/kubeconfig") - kubectl.Register(ws, "/namespaces/{namespace}/kubectl") - registries.Register(ws,"/registries") + nodes.Register(ws, "/nodes") + kubeconfig.Register(ws, "/namespaces/{namespace}/kubeconfig") + kubectl.Register(ws, "/namespaces/{namespace}/kubectl") + registries.Register(ws, "/registries") + storage.Register(ws, "/storage") - // add webservice to default container - restful.Add(ws) + // add webservice to default container + restful.Add(ws) } - diff --git a/pkg/apis/v1alpha/storage/storage_handler.go b/pkg/apis/v1alpha/storage/storage_handler.go new file mode 100644 index 000000000..245c30322 --- /dev/null +++ b/pkg/apis/v1alpha/storage/storage_handler.go @@ -0,0 +1,14 @@ +package storage + +import ( + "github.com/emicklei/go-restful" + "kubesphere.io/kubesphere/pkg/filter/route" + "kubesphere.io/kubesphere/pkg/models" +) + +func Register(ws *restful.WebService, subPath string) { + ws.Route(ws.GET(subPath+"/storageclasses/{storageclass}/persistentvolumeclaims"). + To(models.GetPvcListBySc).Filter(route.RouteLogging)). + Consumes(restful.MIME_JSON, restful.MIME_XML). + Produces(restful.MIME_JSON) +} diff --git a/pkg/models/storage.go b/pkg/models/storage.go new file mode 100644 index 000000000..05f236ba7 --- /dev/null +++ b/pkg/models/storage.go @@ -0,0 +1,54 @@ +package models + +import ( + "github.com/emicklei/go-restful" + "github.com/golang/glog" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/client" + "kubesphere.io/kubesphere/pkg/constants" + "net/http" +) + +type pvcListBySc struct { + Claims []simplePvcList `json:"persistentvolumeclaims"` + Name string `json:"name"` +} + +type simplePvcList struct { + Claim string `json:"name"` + Namespace string `json:"namespace"` +} + +func GetPvcListBySc(request *restful.Request, response *restful.Response) { + + scName := request.PathParameter("storageclass") + glog.Infof("Run GetPvcListBySc: SC = %s", scName) + claims, err := getPvcListBySc(scName) + if err != nil { + response.WriteError(http.StatusInternalServerError, err) + } + result := constants.ResultMessage{ + Kind: constants.KIND, + ApiVersion: constants.APIVERSION, + Data: pvcListBySc{Claims: claims, Name: scName}} + + response.WriteAsJson(result) +} + +func getPvcListBySc(storageclass string) (res []simplePvcList, err error) { + + cli := client.NewK8sClient() + claimList, err := cli.CoreV1().PersistentVolumeClaims("").List(v1.ListOptions{}) + if err != nil { + glog.Error("Read all PVC err: ", err) + return nil, err + } + + for _, claim := range claimList.Items { + if *claim.Spec.StorageClassName != storageclass { + continue + } + res = append(res, simplePvcList{Claim: claim.Name, Namespace: claim.Namespace}) + } + return res, nil +} From 09d7ccaaba2851b837c9761bf729821039115455 Mon Sep 17 00:00:00 2001 From: wnxn Date: Fri, 25 May 2018 14:02:42 +0800 Subject: [PATCH 2/2] 1. Add API of getting SC metrics. 2. Modify response body of the API of listing all PVCs of a SC --- pkg/apis/v1alpha/storage/storage_handler.go | 5 ++ pkg/models/storage.go | 61 ++++++++++++++++++--- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/pkg/apis/v1alpha/storage/storage_handler.go b/pkg/apis/v1alpha/storage/storage_handler.go index 245c30322..0c935e881 100644 --- a/pkg/apis/v1alpha/storage/storage_handler.go +++ b/pkg/apis/v1alpha/storage/storage_handler.go @@ -11,4 +11,9 @@ func Register(ws *restful.WebService, subPath string) { To(models.GetPvcListBySc).Filter(route.RouteLogging)). Consumes(restful.MIME_JSON, restful.MIME_XML). Produces(restful.MIME_JSON) + + ws.Route(ws.GET(subPath+"/storageclasses/{storageclass}/metrics"). + To(models.GetScMetrics).Filter(route.RouteLogging)). + Consumes(restful.MIME_JSON, restful.MIME_XML). + Produces(restful.MIME_JSON) } diff --git a/pkg/models/storage.go b/pkg/models/storage.go index 05f236ba7..2e58dce98 100644 --- a/pkg/models/storage.go +++ b/pkg/models/storage.go @@ -3,6 +3,8 @@ package models import ( "github.com/emicklei/go-restful" "github.com/golang/glog" + v12 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/apis/meta/v1" "kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/constants" @@ -10,15 +12,22 @@ import ( ) type pvcListBySc struct { - Claims []simplePvcList `json:"persistentvolumeclaims"` - Name string `json:"name"` + Name string `json:"name"` + Claims []v12.PersistentVolumeClaim `json:"persistentvolumeclaims"` } -type simplePvcList struct { - Claim string `json:"name"` - Namespace string `json:"namespace"` +type scMetrics struct { + Name string `json:"name"` + Metrics storageMetrics `json:"metrics"` } +type storageMetrics struct { + Capacity string `json:"capacity,omitempty"` + Usage string `json:"usage,omitempty"` +} + +// List all PersistentVolumeClaims of a specific StorageClass +// Extended API URL: "GET /api/v1alpha/storage/storageclasses/{name}/persistentvolumeclaims" func GetPvcListBySc(request *restful.Request, response *restful.Response) { scName := request.PathParameter("storageclass") @@ -30,17 +39,34 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) { result := constants.ResultMessage{ Kind: constants.KIND, ApiVersion: constants.APIVERSION, - Data: pvcListBySc{Claims: claims, Name: scName}} + Data: pvcListBySc{scName, claims}} response.WriteAsJson(result) } -func getPvcListBySc(storageclass string) (res []simplePvcList, err error) { +// Get metrics of a specific StorageClass +// Extended API URL: "GET /api/v1alpha/storage/storageclasses/{name}/metrics" +func GetScMetrics(request *restful.Request, response *restful.Response) { + scName := request.PathParameter("storageclass") + glog.Infof("Run GetPvcListBySc: SC = %s", scName) + + metrics, err := getScMetrics(scName) + if err != nil { + response.WriteError(http.StatusInternalServerError, err) + } + result := constants.ResultMessage{ + Kind: constants.KIND, + ApiVersion: constants.APIVERSION, + Data: scMetrics{Name: scName, Metrics: metrics}, + } + response.WriteAsJson(result) +} + +func getPvcListBySc(storageclass string) (res []v12.PersistentVolumeClaim, err error) { cli := client.NewK8sClient() claimList, err := cli.CoreV1().PersistentVolumeClaims("").List(v1.ListOptions{}) if err != nil { - glog.Error("Read all PVC err: ", err) return nil, err } @@ -48,7 +74,24 @@ func getPvcListBySc(storageclass string) (res []simplePvcList, err error) { if *claim.Spec.StorageClassName != storageclass { continue } - res = append(res, simplePvcList{Claim: claim.Name, Namespace: claim.Namespace}) + res = append(res, claim) } return res, nil } + +func getScMetrics(storageclass string) (res storageMetrics, err error) { + cli := client.NewK8sClient() + pvList, err := cli.CoreV1().PersistentVolumes().List(v1.ListOptions{}) + if err != nil { + return storageMetrics{}, err + } + + var total resource.Quantity + for _, volume := range pvList.Items { + if volume.Spec.StorageClassName != storageclass { + continue + } + total.Add(volume.Spec.Capacity[v12.ResourceStorage]) + } + return storageMetrics{Usage: total.String()}, nil +}