Files
kubesphere/pkg/models/resources.go
2018-09-17 10:24:01 +08:00

333 lines
8.4 KiB
Go

/*
Copyright 2018 The KubeSphere Authors.
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 models
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/models/controllers"
"kubesphere.io/kubesphere/pkg/options"
)
const (
limit = "limit"
page = "page"
)
type ResourceList struct {
Total int `json:"total,omitempty"`
Page int `json:"page,omitempty"`
Limit int `json:"limit,omitempty"`
Items interface{} `json:"items,omitempty"`
}
type searchConditions struct {
match map[string]string
fuzzy map[string]string
matchOr map[string]string
fuzzyOr map[string]string
}
func getController(resource string) (controllers.Controller, error) {
switch resource {
case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses,
controllers.PersistentVolumeClaim, controllers.Roles, controllers.ClusterRoles, controllers.Services,
controllers.Pods, controllers.Namespaces, controllers.StorageClasses, controllers.Jobs, controllers.Cronjobs,
controllers.Nodes:
return controllers.ResourceControllers.Controllers[resource], nil
default:
return nil, fmt.Errorf("invalid resource Name '%s'", resource)
}
return nil, nil
}
func getConditions(str string) (*searchConditions, map[string]string, error) {
match := make(map[string]string)
fuzzy := make(map[string]string)
matchOr := make(map[string]string)
fuzzyOr := make(map[string]string)
orderField := make(map[string]string)
if len(str) == 0 {
return nil, nil, nil
}
conditions := strings.Split(str, ",")
for _, item := range conditions {
if strings.Count(item, "=") >= 2 || strings.Count(item, "~") >= 2 {
return nil, nil, errors.New("invalid condition input")
}
if strings.Count(item, "=") == 1 {
kvs := strings.Split(item, "=")
if len(kvs) < 2 || len(kvs[1]) == 0 {
return nil, nil, errors.New("invalid condition input")
}
if !strings.Contains(kvs[0], "|") {
match[kvs[0]] = kvs[1]
} else {
multiFields := strings.Split(kvs[0], "|")
for _, filed := range multiFields {
if len(filed) > 0 {
matchOr[filed] = kvs[1]
}
}
}
continue
}
if strings.Count(item, "~") == 1 {
kvs := strings.Split(item, "~")
if len(kvs) < 2 || len(kvs[1]) == 0 {
return nil, nil, errors.New("invalid condition input")
}
if !strings.Contains(kvs[0], "|") {
fuzzy[kvs[0]] = kvs[1]
} else {
multiFields := strings.Split(kvs[0], "|")
if len(multiFields) > 1 && len(multiFields[1]) > 0 {
orderField[multiFields[0]] = kvs[1]
}
for _, filed := range multiFields {
if len(filed) > 0 {
fuzzyOr[filed] = kvs[1]
}
}
}
continue
}
return nil, nil, errors.New("invalid condition input")
}
return &searchConditions{match: match, fuzzyOr: fuzzyOr, matchOr: matchOr, fuzzy: fuzzy}, orderField, nil
}
func getPaging(resourceName, pagingStr string) (*controllers.Paging, error) {
defaultPaging := &controllers.Paging{Limit: 10, Offset: 0, Page: 1}
paging := controllers.Paging{}
if resourceName == controllers.Namespaces {
defaultPaging = nil
}
if len(pagingStr) == 0 {
return defaultPaging, nil
}
list := strings.Split(pagingStr, ",")
for _, item := range list {
kvs := strings.Split(item, "=")
if len(kvs) < 2 {
return nil, errors.New("invalid Paging input")
}
value, err := strconv.Atoi(kvs[1])
if err != nil || value <= 0 {
return nil, errors.New("invalid Paging input")
}
if kvs[0] == limit {
paging.Limit = value
}
if kvs[0] == page {
paging.Page = value
}
}
if paging.Limit > 0 && paging.Page > 0 {
paging.Offset = (paging.Page - 1) * paging.Limit
return &paging, nil
}
return defaultPaging, nil
}
func generateOrder(orderField map[string]string, order string) string {
if len(orderField) == 0 {
return order
}
var str string
for k, v := range orderField {
if len(str) > 0 {
str = fmt.Sprintf("%s, (%s like '%%%s%%')", str, k, v)
} else {
str = fmt.Sprintf("(%s like '%%%s%%')", k, v)
}
}
if len(order) == 0 {
return fmt.Sprintf("%s desc", str)
} else {
return fmt.Sprintf("%s, %s", str, order)
}
}
func ListResource(resourceName, conditonSrt, pagingStr, order string) (*ResourceList, error) {
conditions, OrderFields, err := getConditions(conditonSrt)
if err != nil {
return nil, err
}
order = generateOrder(OrderFields, order)
conditionStr := generateConditionStr(conditions)
paging, err := getPaging(resourceName, pagingStr)
if err != nil {
return nil, err
}
ctl, err := getController(resourceName)
if err != nil {
return nil, err
}
total, items, err := ctl.ListWithConditions(conditionStr, paging, order)
if err != nil {
return nil, err
}
if paging != nil {
return &ResourceList{Total: total, Items: items, Page: paging.Page, Limit: paging.Limit}, nil
} else {
return &ResourceList{Total: total, Items: items}, nil
}
}
func generateConditionStr(conditions *searchConditions) string {
conditionStr := ""
if conditions == nil {
return conditionStr
}
for k, v := range conditions.match {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else {
conditionStr = fmt.Sprintf("%s AND %s = \"%s\" ", conditionStr, k, v)
}
}
for k, v := range conditions.fuzzy {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v)
} else {
conditionStr = fmt.Sprintf("%s AND %s like '%%%s%%' ", conditionStr, k, v)
}
}
for k, v := range conditions.matchOr {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else {
conditionStr = fmt.Sprintf("%s OR %s = \"%s\" ", conditionStr, k, v)
}
}
for k, v := range conditions.fuzzyOr {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v)
} else {
conditionStr = fmt.Sprintf("%s OR %s like '%%%s%%' ", conditionStr, k, v)
}
}
return conditionStr
}
type workLoadStatus struct {
NameSpace string `json:"namespace"`
Count map[string]int `json:"data"`
Items map[string]interface{} `json:"items,omitempty"`
}
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
res := workLoadStatus{Count: make(map[string]int), NameSpace: namespace, Items: make(map[string]interface{})}
var status *ResourceList
var err error
for _, resource := range []string{controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.PersistentVolumeClaim} {
notReadyStatus := controllers.Updating
if resource == controllers.PersistentVolumeClaim {
notReadyStatus = controllers.PvcPending
}
if len(namespace) > 0 {
status, err = ListResource(resource, fmt.Sprintf("status=%s,namespace=%s", notReadyStatus, namespace), "", "")
} else {
status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "", "")
}
if err != nil {
return nil, err
}
count := status.Total
res.Count[resource] = count
}
return &res, nil
}
func GetClusterResourceStatus() (*workLoadStatus, error) {
return GetNamespacesResourceStatus("")
}
func GetApplication(clusterId string) (interface{}, error) {
ctl := &controllers.ApplicationCtl{OpenpitrixAddr: options.ServerOptions.GetOpAddress()}
return ctl.GetApp(clusterId)
}
func ListApplication(runtimeId, conditionStr, pagingStr string) (*ResourceList, error) {
paging, err := getPaging(controllers.Applications, pagingStr)
if err != nil {
return nil, err
}
conditions, _, err := getConditions(conditionStr)
if err != nil {
glog.Error(err)
return nil, err
}
if conditions == nil {
conditions = &searchConditions{}
}
ctl := &controllers.ApplicationCtl{OpenpitrixAddr: options.ServerOptions.GetOpAddress()}
total, items, err := ctl.ListApplication(runtimeId, conditions.match, conditions.fuzzy, paging)
if err != nil {
glog.Errorf("get application list failed, reason: %s", err)
return nil, err
}
return &ResourceList{Total: total, Items: items, Page: paging.Page, Limit: paging.Limit}, nil
}