Compare commits

..

14 Commits

Author SHA1 Message Date
Wiley Wang
7a479e6493 Merge pull request #174 from wnxn/express
get k8s version through k8sclient at express branch
2018-09-26 13:46:20 +08:00
wileywang
e1aed9f652 get k8s version through k8sclient 2018-09-25 17:52:41 +08:00
Wiley Wang
337d71d677 Merge pull request #169 from wnxn/express
Add controller to create Ceph secret in express branch
2018-09-25 15:32:25 +08:00
wileywang
390491ee31 Add controller to create Ceph secret 2018-09-19 16:25:30 +08:00
zryfish
733bea4e74 Merge pull request #164 from wnxn/express
update dependency at express branch
2018-09-17 13:38:01 +08:00
Wiley Wang
484cc0ecbb update dependency 2018-09-17 03:15:19 +00:00
calvinyv
e4aa866ca5 Merge pull request #155 from calvinyv/refact_docs
refactor docs
2018-08-08 14:31:28 +08:00
Calvin Yu
b3bfb549e0 refactor docs 2018-08-08 14:16:14 +08:00
richardxz
bf6c3245e4 add desciption field in application response 2018-08-06 03:21:54 +00:00
richardxz
e803897d10 add resync function and support to view deployed applications 2018-07-31 14:04:36 +08:00
richardxz
a4a48eb4fc add swagger ui 2018-07-31 14:04:05 +08:00
jeff
5091a87c1e fix router config bug 2018-07-23 11:09:05 +08:00
jeff
2b031861d6 update vendor 2018-07-11 20:01:08 +08:00
yanmingfan
88b5fb3186 alter components function to filter uncomponents svc 2018-07-11 19:42:23 +08:00
64 changed files with 1522 additions and 9472 deletions

5
Gopkg.lock generated
View File

@@ -775,9 +775,6 @@
"gopkg.in/yaml.v2", "gopkg.in/yaml.v2",
"k8s.io/api/apps/v1", "k8s.io/api/apps/v1",
"k8s.io/api/apps/v1beta2", "k8s.io/api/apps/v1beta2",
"k8s.io/api/autoscaling/v1",
"k8s.io/api/batch/v1",
"k8s.io/api/batch/v1beta1",
"k8s.io/api/core/v1", "k8s.io/api/core/v1",
"k8s.io/api/extensions/v1beta1", "k8s.io/api/extensions/v1beta1",
"k8s.io/api/policy/v1beta1", "k8s.io/api/policy/v1beta1",
@@ -794,8 +791,6 @@
"k8s.io/client-go/kubernetes", "k8s.io/client-go/kubernetes",
"k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/kubernetes/scheme",
"k8s.io/client-go/listers/apps/v1", "k8s.io/client-go/listers/apps/v1",
"k8s.io/client-go/listers/batch/v1",
"k8s.io/client-go/listers/batch/v1beta1",
"k8s.io/client-go/listers/core/v1", "k8s.io/client-go/listers/core/v1",
"k8s.io/client-go/listers/extensions/v1beta1", "k8s.io/client-go/listers/extensions/v1beta1",
"k8s.io/client-go/listers/rbac/v1", "k8s.io/client-go/listers/rbac/v1",

View File

@@ -19,8 +19,6 @@ package components
import ( import (
"net/http" "net/http"
"github.com/golang/glog"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
@@ -32,56 +30,22 @@ func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(handleGetComponents).Filter(route.RouteLogging)). ws.Route(ws.GET(subPath).To(handleGetComponents).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML). Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON) Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/{namespace}/{componentName}").To(handleGetComponentStatus).
Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/health").To(handleGetSystemHealthStatus).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
} }
func handleGetSystemHealthStatus(request *restful.Request, response *restful.Response) { //get all components
if status, err := models.GetSystemHealthStatus(); err != nil {
err = response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
if err != nil {
glog.Errorln(err)
}
} else {
err = response.WriteAsJson(status)
if err != nil {
glog.Errorln(err)
}
}
}
// get a specific component status
func handleGetComponentStatus(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
componentName := request.PathParameter("componentName")
if component, err := models.GetComponentStatus(namespace, componentName); err != nil {
err = response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
if err != nil {
glog.Errorln(err)
}
} else {
if err = response.WriteAsJson(component); err != nil {
glog.Errorln(err)
}
}
}
// get all components
func handleGetComponents(request *restful.Request, response *restful.Response) { func handleGetComponents(request *restful.Request, response *restful.Response) {
result, err := models.GetAllComponentsStatus() result, err := models.GetComponents()
if err != nil { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else { } else {
response.WriteAsJson(result) response.WriteAsJson(result)
} }
} }

View File

@@ -1,56 +0,0 @@
/*
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 daemonsets
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"daemonsets"}
ws.Route(ws.GET(subPath).To(getDaemonSetRevision).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle daemonset" +
" operation").Param(ws.PathParameter("daemonset", "daemonset's name").DataType("string")).Param(ws.PathParameter("namespace",
"daemonset's namespace").DataType("string")).Param(ws.PathParameter("revision", "daemonset's revision")).Writes(v1.DaemonSet{}))
}
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
daemonset := req.PathParameter("daemonset")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
res, err := models.GetDaemonSetRevision(namespace, daemonset, revision)
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: err.Error()})
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
}
resp.WriteEntity(res)
}

View File

@@ -1,56 +0,0 @@
/*
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 deployments
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"deployments"}
ws.Route(ws.GET(subPath).To(getDeployRevision).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle deployment" +
" operation").Param(ws.PathParameter("deployment", "deployment's name").DataType("string")).Param(ws.PathParameter("namespace",
"deployment's namespace").DataType("string")).Param(ws.PathParameter("deployment", "deployment's name")).Writes(v1.ReplicaSet{}))
}
func getDeployRevision(req *restful.Request, resp *restful.Response) {
deploy := req.PathParameter("deployment")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
res, err := models.GetDeployRevision(namespace, deploy, revision)
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: err.Error()})
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
}
resp.WriteEntity(res)
}

View File

@@ -1,57 +0,0 @@
/*
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 hpa
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/api/errors"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/client"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"horizontalpodautoscalers"}
ws.Route(ws.GET(subPath).To(getHpa).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc(
"get horizontalpodautoscalers").Param(ws.PathParameter("namespace",
"horizontalpodautoscalers's namespace").DataType("string")).Param(ws.PathParameter(
"horizontalpodautoscaler", "horizontalpodautoscaler's name")).Writes(v1.HorizontalPodAutoscaler{}))
}
func getHpa(req *restful.Request, resp *restful.Response) {
hpa := req.PathParameter("horizontalpodautoscaler")
namespace := req.PathParameter("namespace")
client := client.NewK8sClient()
res, err := client.AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(hpa, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusOK, nil)
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, nil)
}
}
resp.WriteEntity(res)
}

View File

@@ -63,7 +63,7 @@ func userRolesHandler(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("username") username := req.PathParameter("username")
roles, err := iam.GetRoles("", username) roles, err := iam.GetRoles(username)
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
@@ -206,7 +206,7 @@ func clusterRoleRulesHandler(req *restful.Request, resp *restful.Response) {
var rules []iam.Rule var rules []iam.Rule
if name == "" { if name == "" {
rules = iam.ClusterRoleRuleMapping rules = iam.ClusterRoleRuleGroup
} else { } else {
var err error var err error
rules, err = iam.GetClusterRoleRules(name) rules, err = iam.GetClusterRoleRules(name)
@@ -227,7 +227,7 @@ func roleRulesHandler(req *restful.Request, resp *restful.Response) {
var rules []iam.Rule var rules []iam.Rule
if namespace == "" && name == "" { if namespace == "" && name == "" {
rules = iam.RoleRuleMapping rules = iam.RoleRuleGroup
} else { } else {
var err error var err error
rules, err = iam.GetRoleRules(namespace, name) rules, err = iam.GetRoleRules(namespace, name)

View File

@@ -21,25 +21,18 @@ import (
"kubesphere.io/kubesphere/pkg/apis/v1alpha/components" "kubesphere.io/kubesphere/pkg/apis/v1alpha/components"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/containers" "kubesphere.io/kubesphere/pkg/apis/v1alpha/containers"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/daemonsets"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/deployments"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/hpa"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/iam" "kubesphere.io/kubesphere/pkg/apis/v1alpha/iam"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/jobs"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/monitoring"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/nodes" "kubesphere.io/kubesphere/pkg/apis/v1alpha/nodes"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/pods" "kubesphere.io/kubesphere/pkg/apis/v1alpha/pods"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/quota" "kubesphere.io/kubesphere/pkg/apis/v1alpha/quota"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/registries" "kubesphere.io/kubesphere/pkg/apis/v1alpha/registries"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/resources" "kubesphere.io/kubesphere/pkg/apis/v1alpha/resources"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/routes" "kubesphere.io/kubesphere/pkg/apis/v1alpha/routes"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/statefulsets"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/storage" "kubesphere.io/kubesphere/pkg/apis/v1alpha/storage"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/terminal" "kubesphere.io/kubesphere/pkg/apis/v1alpha/terminal"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/users" "kubesphere.io/kubesphere/pkg/apis/v1alpha/users"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/volumes" "kubesphere.io/kubesphere/pkg/apis/v1alpha/volumes"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/workloadstatus" "kubesphere.io/kubesphere/pkg/apis/v1alpha/workloadstatus"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/workspaces"
_ "kubesphere.io/kubesphere/pkg/filter/container" _ "kubesphere.io/kubesphere/pkg/filter/container"
) )
@@ -61,14 +54,8 @@ func init() {
terminal.Register(ws, "/namespaces/{namespace}/pod/{pod}/shell/{container}") terminal.Register(ws, "/namespaces/{namespace}/pod/{pod}/shell/{container}")
workloadstatus.Register(ws, "/status") workloadstatus.Register(ws, "/status")
quota.Register(ws, "/quota") quota.Register(ws, "/quota")
hpa.Register(ws, "/namespaces/{namespace}/horizontalpodautoscalers/{horizontalpodautoscaler}")
jobs.Register(ws, "/namespaces/{namespace}/jobs/{job}")
deployments.Register(ws, "/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}")
daemonsets.Register(ws, "/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}")
statefulsets.Register(ws, "/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}")
resources.Register(ws, "/resources") resources.Register(ws, "/resources")
monitoring.Register(ws, "/monitoring")
workspaces.Register(ws, "/workspaces")
// add webservice to default container // add webservice to default container
restful.Add(ws) restful.Add(ws)

View File

@@ -1,63 +0,0 @@
/*
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 jobs
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"fmt"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/controllers"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"jobs"}
ws.Route(ws.POST(subPath).To(handleJob).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle job" +
" operation").Param(ws.PathParameter("job", "job name").DataType("string")).Param(ws.PathParameter("namespace",
"job's namespace").DataType("string")).Param(ws.QueryParameter("a",
"action").DataType("string")).Writes(""))
}
func handleJob(req *restful.Request, resp *restful.Response) {
var res interface{}
var err error
job := req.PathParameter("job")
namespace := req.PathParameter("namespace")
action := req.QueryParameter("a")
switch action {
case "rerun":
res, err = controllers.JobReRun(namespace, job)
default:
resp.WriteHeaderAndEntity(http.StatusForbidden, constants.MessageResponse{Message: fmt.Sprintf("invalid operation %s", action)})
return
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(res)
}

View File

@@ -1,443 +0,0 @@
/*
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 monitoring
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models/metrics"
)
func (u Monitor) monitorPod(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
podName := requestParams.PodName
metricName := requestParams.MetricsName
if podName != "" {
// single pod single metric
queryType, params, nullRule := metrics.AssemblePodMetricRequestInfo(requestParams, metricName)
var res *metrics.FormatedMetric
if !nullRule {
res = metrics.GetMetric(queryType, params, metricName)
}
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelPod)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
}
func (u Monitor) monitorContainer(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if requestParams.MetricsFilter != "" {
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelContainer)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelContainerName)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else {
res := metrics.MonitorContainer(requestParams, metricName)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorWorkload(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkload)
var sortedMetrics *metrics.FormatedLevelMetric
var maxMetricCount int
wlKind := requestParams.WorkloadKind
// sorting
if wlKind == "" {
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkload)
} else {
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
}
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
func (u Monitor) monitorAllWorkspaces(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
tp := requestParams.Tp
if tp == "_statistics" {
// merge multiple metric: all-devops, all-roles, all-projects...this api is designed for admin
res := metrics.MonitorAllWorkspacesStatistics()
response.WriteAsJson(res)
} else if tp == "rank" {
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkspace)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else {
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorOneWorkspace(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
tp := requestParams.Tp
if tp == "rank" {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else if tp == "_statistics" {
wsName := requestParams.WsName
// merge multiple metric: devops, roles, projects...
res := metrics.MonitorOneWorkspaceStatistics(wsName)
response.WriteAsJson(res)
} else {
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorNamespace(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
nsName := requestParams.NsName
if nsName != "" {
// single
queryType, params := metrics.AssembleNamespaceMetricRequestInfo(requestParams, metricName)
res := metrics.GetMetric(queryType, params, metricName)
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
}
func (u Monitor) monitorCluster(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if metricName != "" {
// single
queryType, params := metrics.AssembleClusterMetricRequestInfo(requestParams, metricName)
res := metrics.GetMetric(queryType, params, metricName)
response.WriteAsJson(res)
} else {
// multiple
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelCluster)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorNode(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if metricName != "" {
// single
queryType, params := metrics.AssembleNodeMetricRequestInfo(requestParams, metricName)
res := metrics.GetMetric(queryType, params, metricName)
nodeAddress := metrics.GetNodeAddressInfo()
metrics.AddNodeAddressMetric(res, nodeAddress)
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNode)
nodeAddress := metrics.GetNodeAddressInfo()
for i := 0; i < len(rawMetrics.Results); i++ {
metrics.AddNodeAddressMetric(&rawMetrics.Results[i], nodeAddress)
}
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNode)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
}
// k8s component(controller, scheduler, etcd) status
func (u Monitor) monitorComponentStatus(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
status := metrics.MonitorComponentStatus(requestParams)
response.WriteAsJson(status)
}
type Monitor struct {
}
func Register(ws *restful.WebService, subPath string) {
tags := []string{"monitoring apis"}
u := Monitor{}
ws.Route(ws.GET(subPath+"/clusters").To(u.monitorCluster).
Filter(route.RouteLogging).
Doc("monitor cluster level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("cluster_cpu_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes").To(u.monitorNode).
Filter(route.RouteLogging).
Doc("monitor nodes level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("node_cpu_utilisation")).
Param(ws.QueryParameter("nodes_filter", "node re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}").To(u.monitorNode).
Filter(route.RouteLogging).
Doc("monitor specific node level metrics").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("node_cpu_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces").To(u.monitorNamespace).
Filter(route.RouteLogging).
Doc("monitor namespaces level metrics").
Param(ws.QueryParameter("namespaces_filter", "namespaces re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}").To(u.monitorNamespace).
Filter(route.RouteLogging).
Doc("monitor specific namespace level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("namespace_memory_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor pods level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods/{pod_name}").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor specific pod level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}/pods").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor pods level metrics by nodeid").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}/pods/{pod_name}").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor specific pod level metrics by nodeid").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}/pods/{pod_name}/containers").To(u.monitorContainer).
Filter(route.RouteLogging).
Doc("monitor specific pod level metrics by nodeid").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true)).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true)).
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods/{pod_name}/containers").To(u.monitorContainer).
Filter(route.RouteLogging).
Doc("monitor containers level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods/{pod_name}/containers/{container_name}").To(u.monitorContainer).
Filter(route.RouteLogging).
Doc("monitor specific container level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.PathParameter("container_name", "specific container").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/workloads/{workload_kind}").To(u.monitorWorkload).
Filter(route.RouteLogging).
Doc("monitor specific workload level metrics").
Param(ws.PathParameter("ns_name", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.PathParameter("workload_kind", "workload kind").DataType("string").Required(false).DefaultValue("daemonset")).
Param(ws.QueryParameter("workload_name", "workload name").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "max metric items in a page").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/workloads").To(u.monitorWorkload).
Filter(route.RouteLogging).
Doc("monitor all workload level metrics").
Param(ws.PathParameter("ns_name", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("workloads_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
// list all namespace in this workspace by selected metrics
ws.Route(ws.GET(subPath+"/workspaces/{workspace_name}").To(u.monitorOneWorkspace).
Filter(route.RouteLogging).
Doc("monitor workspaces level metrics").
Param(ws.PathParameter("workspace_name", "workspace name").DataType("string").Required(true)).
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").DataType("string").Required(false).DefaultValue("k.*")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/workspaces").To(u.monitorAllWorkspaces).
Filter(route.RouteLogging).
Doc("monitor workspaces level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("workspace_memory_utilisation")).
Param(ws.QueryParameter("workspaces_filter", "workspaces re2 expression filter").DataType("string").Required(false).DefaultValue(".*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/components").To(u.monitorComponentStatus).
Filter(route.RouteLogging).
Doc("monitor k8s components status").
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}

View File

@@ -55,23 +55,6 @@ func Register(ws *restful.WebService, subPath string) {
Consumes(restful.MIME_JSON). Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON) Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}/searchwords/{searchWord}").
Param(ws.PathParameter("namespace", "registry secret's namespace")).
Param(ws.PathParameter("name", "registry secret's name")).
Param(ws.PathParameter("searchWord", "keyword use to search image")).
To(handlerImageSearch).
Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}/tags").
Param(ws.QueryParameter("image", "imageName")).
Param(ws.PathParameter("namespace", "registry secret's namespace")).
Param(ws.PathParameter("name", "registry secret's name")).
To(handlerGetImageTags).
Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
} }
func handlerRegistryValidation(request *restful.Request, response *restful.Response) { func handlerRegistryValidation(request *restful.Request, response *restful.Response) {
@@ -94,30 +77,6 @@ func handlerRegistryValidation(request *restful.Request, response *restful.Respo
} }
func handlerImageSearch(request *restful.Request, response *restful.Response) {
registry := request.PathParameter("name")
searchWord := request.PathParameter("searchWord")
namespace := request.PathParameter("namespace")
res := models.ImageSearch(namespace, registry, searchWord)
response.WriteEntity(res)
}
func handlerGetImageTags(request *restful.Request, response *restful.Response) {
registry := request.PathParameter("name")
image := request.QueryParameter("image")
namespace := request.PathParameter("namespace")
res := models.GetImageTags(namespace, registry, image)
response.WriteEntity(res)
}
func handleCreateRegistries(request *restful.Request, response *restful.Response) { func handleCreateRegistries(request *restful.Request, response *restful.Response) {
registries := models.Registries{} registries := models.Registries{}

View File

@@ -23,9 +23,6 @@ import (
"github.com/emicklei/go-restful-openapi" "github.com/emicklei/go-restful-openapi"
"fmt"
"strings"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
) )
@@ -34,37 +31,15 @@ func Register(ws *restful.WebService, subPath string) {
tags := []string{"resources"} tags := []string{"resources"}
ws.Route(ws.GET(subPath+"/{resource}").To(listResource). ws.Route(ws.GET(subPath+"/{resource}").To(handleResource).Produces(restful.MIME_JSON).Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Get resource" +
Produces(restful.MIME_JSON). " list").Param(ws.PathParameter("resource", "resource name").DataType(
Metadata(restfulspec.KeyOpenAPITags, tags). "string")).Param(ws.QueryParameter("conditions", "search "+
Doc("Get resource list"). "conditions").DataType("string")).Param(ws.QueryParameter("paging",
Param(ws.PathParameter("resource", "resource name").DataType("string")). "support paging function").DataType("string")).Writes(models.ResourceList{}))
Param(ws.QueryParameter("conditions", "search conditions").DataType("string")).
Param(ws.QueryParameter("reverse", "support reverse ordering").DataType("bool").DefaultValue("false")).
Param(ws.QueryParameter("order", "the field for sorting").DataType("string")).
Param(ws.QueryParameter("paging", "support paging function").DataType("string")).
Writes(models.ResourceList{}))
} }
func isInvalid(str string) bool { func handleResource(req *restful.Request, resp *restful.Response) {
invalidList := []string{"exec", "insert", "select", "delete", "update", "count", "*", "%", "truncate", "drop"}
str = strings.Replace(str, "=", " ", -1)
str = strings.Replace(str, ",", " ", -1)
str = strings.Replace(str, "~", " ", -1)
items := strings.Split(str, " ")
for _, invalid := range invalidList {
for _, item := range items {
if item == invalid || strings.ToLower(item) == invalid {
return true
}
}
}
return false
}
func listResource(req *restful.Request, resp *restful.Response) {
resource := req.PathParameter("resource") resource := req.PathParameter("resource")
if resource == "applications" { if resource == "applications" {
@@ -73,23 +48,7 @@ func listResource(req *restful.Request, resp *restful.Response) {
} }
conditions := req.QueryParameter("conditions") conditions := req.QueryParameter("conditions")
paging := req.QueryParameter("paging") paging := req.QueryParameter("paging")
orderField := req.QueryParameter("order") res, err := models.ListResource(resource, conditions, paging)
reverse := req.QueryParameter("reverse")
if len(orderField) > 0 {
if reverse == "true" {
orderField = fmt.Sprintf("%s %s", orderField, "desc")
} else {
orderField = fmt.Sprintf("%s %s", orderField, "asc")
}
}
if isInvalid(conditions) || isInvalid(paging) || isInvalid(orderField) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid input"})
return
}
res, err := models.ListResource(resource, conditions, paging, orderField)
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return return
@@ -99,6 +58,7 @@ func listResource(req *restful.Request, resp *restful.Response) {
} }
func handleApplication(req *restful.Request, resp *restful.Response) { func handleApplication(req *restful.Request, resp *restful.Response) {
//searchWord := req.QueryParameter("search-word")
paging := req.QueryParameter("paging") paging := req.QueryParameter("paging")
clusterId := req.QueryParameter("cluster_id") clusterId := req.QueryParameter("cluster_id")
runtimeId := req.QueryParameter("runtime_id") runtimeId := req.QueryParameter("runtime_id")

View File

@@ -1,56 +0,0 @@
/*
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 statefulsets
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"statefulsets"}
ws.Route(ws.GET(subPath).To(getDaemonSetRevision).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle statefulset" +
" operation").Param(ws.PathParameter("statefulset", "statefulset's name").DataType("string")).Param(ws.PathParameter("namespace",
"statefulset's namespace").DataType("string")).Param(ws.PathParameter("revision", "statefulset's revision")).Writes(v1.StatefulSet{}))
}
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
statefulset := req.PathParameter("statefulset")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
res, err := models.GetStatefulSetRevision(namespace, statefulset, revision)
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: err.Error()})
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
}
resp.WriteEntity(res)
}

View File

@@ -26,7 +26,7 @@ import (
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/kubectl" "kubesphere.io/kubesphere/pkg/models/iam"
) )
func Register(ws *restful.WebService, subPath string) { func Register(ws *restful.WebService, subPath string) {
@@ -55,6 +55,13 @@ func createUser(req *restful.Request, resp *restful.Response) {
return return
} }
err = models.CreateKubectlDeploy(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "successfully created"}) resp.WriteEntity(constants.MessageResponse{Message: "successfully created"})
} }
@@ -62,7 +69,7 @@ func delUser(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user") user := req.PathParameter("user")
err := kubectl.DelKubectlDeploy(user) err := models.DelKubectlDeploy(user)
if err != nil && !apierrors.IsNotFound(err) { if err != nil && !apierrors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
@@ -76,6 +83,13 @@ func delUser(req *restful.Request, resp *restful.Response) {
return return
} }
err = iam.DeleteRoleBindings(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "successfully deleted"}) resp.WriteEntity(constants.MessageResponse{Message: "successfully deleted"})
} }
@@ -83,7 +97,7 @@ func getKubectl(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user") user := req.PathParameter("user")
kubectlPod, err := kubectl.GetKubectlPod(user) kubectlPod, err := models.GetKubectlPod(user)
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})

View File

@@ -1,536 +0,0 @@
package workspaces
import (
"net/http"
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
"fmt"
"strings"
"k8s.io/kubernetes/pkg/util/slice"
"strconv"
"regexp"
"sort"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/metrics"
"kubesphere.io/kubesphere/pkg/models/workspaces"
)
const UserNameHeader = "X-Token-Username"
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(UserWorkspaceListHandler))
ws.Route(ws.POST(subPath).To(WorkspaceCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}").To(DeleteWorkspaceHandler))
ws.Route(ws.GET(subPath + "/{name}").To(WorkspaceDetailHandler))
ws.Route(ws.PUT(subPath + "/{name}").To(WorkspaceEditHandler))
ws.Route(ws.GET(subPath + "/{workspace}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.GET(subPath + "/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.POST(subPath + "/{name}/namespaces").To(NamespaceCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET(subPath + "/{name}/devops").To(DevOpsProjectHandler))
ws.Route(ws.GET(subPath + "/{name}/members/{username}/devops").To(DevOpsProjectHandler))
ws.Route(ws.POST(subPath + "/{name}/devops").To(DevOpsProjectCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
ws.Route(ws.GET(subPath + "/{name}/members").To(MembersHandler))
ws.Route(ws.GET(subPath + "/{name}/members/{member}").To(MemberHandler))
ws.Route(ws.GET(subPath + "/{name}/roles").To(RolesHandler))
ws.Route(ws.GET(subPath + "/{name}/roles/{role}").To(RoleHandler))
ws.Route(ws.POST(subPath + "/{name}/members").To(MembersInviteHandler))
ws.Route(ws.DELETE(subPath + "/{name}/members").To(MembersRemoveHandler))
}
func RoleHandler(req *restful.Request, resp *restful.Response) {
workspaceName := req.PathParameter("name")
roleName := req.PathParameter("role")
if !slice.ContainsString(constants.WorkSpaceRoles, roleName, nil) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: fmt.Sprintf("role %s not found", roleName)})
return
}
role, rules, err := iam.WorkspaceRoleRules(workspaceName, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
users, err := iam.WorkspaceRoleUsers(workspaceName, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(map[string]interface{}{"role": role, "rules": rules, "users": users})
}
func RolesHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
roles, err := workspaces.Roles(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(roles)
}
func MembersHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
keyword := req.QueryParameter("keyword")
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(users)
}
func MemberHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("member")
user, err := iam.GetUser(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
namespaces, err := workspaces.Namespaces(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
user.WorkspaceRole = user.WorkspaceRoles[workspace]
roles := make(map[string]string)
for _, namespace := range namespaces {
if role := user.Roles[namespace.Name]; role != "" {
roles[namespace.Name] = role
}
}
user.Roles = roles
user.Rules = nil
user.WorkspaceRules = nil
user.WorkspaceRoles = nil
user.ClusterRules = nil
resp.WriteEntity(user)
}
func MembersInviteHandler(req *restful.Request, resp *restful.Response) {
var users []workspaces.UserInvite
workspace := req.PathParameter("name")
err := req.ReadEntity(&users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.Invite(workspace, users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
}
func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
query := req.QueryParameter("name")
workspace := req.PathParameter("name")
names := strings.Split(query, ",")
err := workspaces.RemoveMembers(workspace, names)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
}
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
exist, err := workspaces.NamespaceExistCheck(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(map[string]bool{"exist": exist})
}
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
workspace := req.PathParameter("name")
err := workspaces.DeleteNamespace(workspace, namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
}
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("id")
workspace := req.PathParameter("name")
force := req.QueryParameter("force")
username := req.HeaderParameter(UserNameHeader)
err := workspaces.UnBindDevopsProject(workspace, devops)
if err != nil && force != "true" {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "success"})
}
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
var devops workspaces.DevopsProject
err := req.ReadEntity(&devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(project)
}
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
namespace := &v1.Namespace{}
err := req.ReadEntity(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
if namespace.Annotations == nil {
namespace.Annotations = make(map[string]string, 0)
}
namespace.Annotations["creator"] = username
namespace.Annotations["workspace"] = workspace
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 0)
}
namespace.Labels["kubesphere.io/workspace"] = workspace
namespace, err = workspaces.CreateNamespace(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(namespace)
}
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
result := constants.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range devOpsProjects {
result.Items = append(result.Items, n)
}
resp.WriteEntity(result)
}
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
username := req.HeaderParameter(UserNameHeader)
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid workspace name"})
return
}
workspace.Path = workspace.Name
workspace.Members = nil
if workspace.Admin != "" {
workspace.Creator = workspace.Admin
} else {
workspace.Creator = username
}
created, err := workspaces.Create(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(created)
}
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
if name == "" || strings.Contains(name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid workspace name"})
return
}
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.Delete(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "success"})
}
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
name := req.PathParameter("name")
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
if name != workspace.Name {
resp.WriteError(http.StatusBadRequest, fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid workspace name"})
return
}
workspace.Path = workspace.Name
workspace.Members = nil
edited, err := workspaces.Edit(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(edited)
}
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(workspace)
}
// List all workspaces for the current user
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
keyword := req.QueryParameter("keyword")
username := req.HeaderParameter(UserNameHeader)
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
sort.Slice(ws, func(i, j int) bool {
t1, err := ws[i].GetCreateTime()
if err != nil {
return false
}
t2, err := ws[j].GetCreateTime()
if err != nil {
return true
}
return t1.After(t2)
})
resp.WriteEntity(ws)
}
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
if err != nil {
withMetrics = false
}
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
if page < 0 {
page = 1
}
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
workspaceName := req.PathParameter("workspace")
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
if withMetrics {
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
result := constants.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range namespaces {
result.Items = append(result.Items, n)
}
resp.WriteEntity(result)
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net" "net"
@@ -32,20 +33,11 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
"os"
"os/signal"
"sync"
"syscall"
"k8s.io/api/core/v1"
_ "kubesphere.io/kubesphere/pkg/apis/v1alpha" _ "kubesphere.io/kubesphere/pkg/apis/v1alpha"
"kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/controllers" "kubesphere.io/kubesphere/pkg/models/controllers"
"kubesphere.io/kubesphere/pkg/models/kubectl"
"kubesphere.io/kubesphere/pkg/models/workspaces"
"kubesphere.io/kubesphere/pkg/options" "kubesphere.io/kubesphere/pkg/options"
) )
@@ -76,42 +68,26 @@ func newKubeSphereServer(options *options.ServerRunOptions) *kubeSphereServer {
func preCheck() error { func preCheck() error {
k8sClient := client.NewK8sClient() k8sClient := client.NewK8sClient()
_, err := k8sClient.CoreV1().Namespaces().Get(constants.KubeSphereControlNamespace, metaV1.GetOptions{}) _, err := k8sClient.CoreV1().Namespaces().Get(constants.KubeSphereControlNamespace, metaV1.GetOptions{})
if err != nil { if err != nil && !errors.IsNotFound(err) {
if errors.IsNotFound(err) { return err
_, err = k8sClient.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metaV1.ObjectMeta{Name: constants.KubeSphereControlNamespace}}) }
if err != nil {
return err if errors.IsNotFound(err) {
} namespace := v1.Namespace{ObjectMeta: metaV1.ObjectMeta{Name: constants.KubeSphereControlNamespace}}
} else { _, err = k8sClient.CoreV1().Namespaces().Create(&namespace)
if err != nil {
return err return err
} }
} }
_, err = k8sClient.AppsV1().Deployments(constants.KubeSphereControlNamespace).Get(constants.AdminUserName, metaV1.GetOptions{}) _, err = k8sClient.AppsV1().Deployments(constants.KubeSphereControlNamespace).Get(constants.AdminUserName, metaV1.GetOptions{})
if err != nil { if errors.IsNotFound(err) {
if errors.IsNotFound(err) { models.CreateKubeConfig(constants.AdminUserName)
if err = models.CreateKubeConfig(constants.AdminUserName); err != nil { models.CreateKubectlDeploy(constants.AdminUserName)
return err return nil
}
if err = kubectl.CreateKubectlDeploy(constants.AdminUserName); err != nil {
return err
}
} else {
return err
}
} }
return err
db := client.NewSharedDBClient()
defer db.Close()
if !db.HasTable(&workspaces.WorkspaceDPBinding{}) {
if err := db.CreateTable(&workspaces.WorkspaceDPBinding{}).Error; err != nil {
return err
}
}
return nil
} }
func registerSwagger() { func registerSwagger() {
@@ -142,10 +118,7 @@ func (server *kubeSphereServer) run() {
return return
} }
var wg sync.WaitGroup go controllers.Run()
stopChan := make(chan struct{})
wg.Add(1)
go controllers.Run(stopChan, &wg)
registerSwagger() registerSwagger()
@@ -174,12 +147,7 @@ func (server *kubeSphereServer) run() {
go func() { glog.Fatal(http.ListenAndServe(insecureAddr, nil)) }() go func() { glog.Fatal(http.ListenAndServe(insecureAddr, nil)) }()
} }
sigs := make(chan os.Signal) select {}
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
close(stopChan)
wg.Wait()
} }
func Run() { func Run() {

View File

@@ -15,12 +15,13 @@ package client
import ( import (
"fmt" "fmt"
"log"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"log"
"kubesphere.io/kubesphere/pkg/logs" "kubesphere.io/kubesphere/pkg/logs"
"kubesphere.io/kubesphere/pkg/options" "kubesphere.io/kubesphere/pkg/options"
) )
@@ -30,24 +31,6 @@ var dbClient *gorm.DB
const database = "kubesphere" const database = "kubesphere"
func NewDBClient() *gorm.DB { func NewDBClient() *gorm.DB {
user := options.ServerOptions.GetMysqlUser()
passwd := options.ServerOptions.GetMysqlPassword()
addr := options.ServerOptions.GetMysqlAddr()
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, passwd, addr, database)
db, err := gorm.Open("mysql", conn)
if err != nil {
glog.Error(err)
panic(err)
}
db.SetLogger(log.New(logs.GlogWriter{}, " ", 0))
return db
}
func NewSharedDBClient() *gorm.DB {
if dbClient != nil { if dbClient != nil {
err := dbClient.DB().Ping() err := dbClient.DB().Ping()
@@ -59,5 +42,23 @@ func NewSharedDBClient() *gorm.DB {
} }
} }
return NewDBClient() user := options.ServerOptions.GetMysqlUser()
passwd := options.ServerOptions.GetMysqlPassword()
addr := options.ServerOptions.GetMysqlAddr()
if dbClient == nil {
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, passwd, addr, database)
glog.Info(conn)
db, err := gorm.Open("mysql", conn)
if err != nil {
glog.Error(err)
panic(err)
}
db.SetLogger(log.New(logs.GlogWriter{}, " ", 0))
dbClient = db
return dbClient
}
return dbClient
} }

View File

@@ -1,198 +0,0 @@
/*
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 client
import (
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"os"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
)
const (
DefaultScheme = "http"
DefaultPrometheusPort = "9090"
PrometheusApiPath = "/api/v1/"
DefaultQueryStep = "10m"
DefaultQueryTimeout = "10s"
RangeQueryType = "query_range?"
DefaultQueryType = "query?"
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
)
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
var PrometheusEndpointUrl string
func init() {
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
PrometheusAPIServer = env
}
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
}
type MonitoringRequestParams struct {
Params url.Values
QueryType string
SortMetricName string
SortType string
PageNum string
LimitNum string
Tp string
MetricsFilter string
NodesFilter string
WsFilter string
NsFilter string
PodsFilter string
ContainersFilter string
MetricsName string
WorkloadName string
WlFilter string
NodeId string
WsName string
NsName string
PodName string
ContainerName string
WorkloadKind string
}
var client = &http.Client{}
func SendMonitoringRequest(queryType string, params string) string {
epurl := PrometheusEndpointUrl + queryType + params
response, err := client.Get(epurl)
if err != nil {
glog.Error(err)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
glog.Error(err)
}
return string(contents)
}
return ""
}
func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestParams {
instantTime := strings.Trim(request.QueryParameter("time"), " ")
start := strings.Trim(request.QueryParameter("start"), " ")
end := strings.Trim(request.QueryParameter("end"), " ")
step := strings.Trim(request.QueryParameter("step"), " ")
timeout := strings.Trim(request.QueryParameter("timeout"), " ")
sortMetricName := strings.Trim(request.QueryParameter("sort_metric"), " ")
sortType := strings.Trim(request.QueryParameter("sort_type"), " ")
pageNum := strings.Trim(request.QueryParameter("page"), " ")
limitNum := strings.Trim(request.QueryParameter("limit"), " ")
tp := strings.Trim(request.QueryParameter("type"), " ")
metricsFilter := strings.Trim(request.QueryParameter("metrics_filter"), " ")
nodesFilter := strings.Trim(request.QueryParameter("nodes_filter"), " ")
wsFilter := strings.Trim(request.QueryParameter("workspaces_filter"), " ")
nsFilter := strings.Trim(request.QueryParameter("namespaces_filter"), " ")
wlFilter := strings.Trim(request.QueryParameter("workloads_filter"), " ")
podsFilter := strings.Trim(request.QueryParameter("pods_filter"), " ")
containersFilter := strings.Trim(request.QueryParameter("containers_filter"), " ")
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
nodeId := strings.Trim(request.PathParameter("node_id"), " ")
wsName := strings.Trim(request.PathParameter("workspace_name"), " ")
nsName := strings.Trim(request.PathParameter("ns_name"), " ")
podName := strings.Trim(request.PathParameter("pod_name"), " ")
containerName := strings.Trim(request.PathParameter("container_name"), " ")
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
var requestParams = MonitoringRequestParams{
SortMetricName: sortMetricName,
SortType: sortType,
PageNum: pageNum,
LimitNum: limitNum,
Tp: tp,
MetricsFilter: metricsFilter,
NodesFilter: nodesFilter,
WsFilter: wsFilter,
NsFilter: nsFilter,
PodsFilter: podsFilter,
ContainersFilter: containersFilter,
MetricsName: metricsName,
WorkloadName: workloadName,
WlFilter: wlFilter,
NodeId: nodeId,
WsName: wsName,
NsName: nsName,
PodName: podName,
ContainerName: containerName,
WorkloadKind: workloadKind,
}
if timeout == "" {
timeout = DefaultQueryTimeout
}
if step == "" {
step = DefaultQueryStep
}
// Whether query or query_range request
u := url.Values{}
if start != "" && end != "" {
u.Set("start", convertTimeGranularity(start))
u.Set("end", convertTimeGranularity(end))
u.Set("step", step)
u.Set("timeout", timeout)
requestParams.QueryType = RangeQueryType
requestParams.Params = u
return &requestParams
}
if instantTime != "" {
u.Set("time", instantTime)
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
} else {
//u.Set("time", strconv.FormatInt(int64(time.Now().Unix()), 10))
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
}
glog.Errorln("Parse request %s failed", u)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
}
func convertTimeGranularity(ts string) string {
timeFloat, err := strconv.ParseFloat(ts, 64)
if err != nil {
glog.Errorf("convert second timestamp %s to minute timestamp failed", ts)
return strconv.FormatInt(int64(time.Now().Unix()), 10)
}
timeInt := int64(timeFloat)
// convert second timestamp to minute timestamp
secondTime := time.Unix(timeInt, 0).Truncate(time.Minute).Unix()
return strconv.FormatInt(secondTime, 10)
}

View File

@@ -16,8 +16,6 @@ limitations under the License.
package constants package constants
import "os"
type MessageResponse struct { type MessageResponse struct {
Message string `json:"message"` Message string `json:"message"`
} }
@@ -40,38 +38,4 @@ const (
DataHome = "/etc/kubesphere" DataHome = "/etc/kubesphere"
IngressControllerFolder = DataHome + "/ingress-controller" IngressControllerFolder = DataHome + "/ingress-controller"
IngressControllerPrefix = "kubesphere-router-" IngressControllerPrefix = "kubesphere-router-"
DevopsAPIServerEnv = "DEVOPS_API_SERVER"
AccountAPIServerEnv = "ACCOUNT_API_SERVER"
DevopsProxyTokenEnv = "DEVOPS_PROXY_TOKEN"
OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN"
WorkspaceLabelKey = "kubesphere.io/workspace"
WorkspaceAdmin = "workspace-admin"
ClusterAdmin = "cluster-admin"
WorkspaceRegular = "workspace-regular"
WorkspaceViewer = "workspace-viewer"
DevopsOwner = "owner"
DevopsReporter = "reporter"
) )
var (
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
AccountAPIServer = "ks-account.kubesphere-system.svc"
DevopsProxyToken = ""
OpenPitrixProxyToken = ""
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
)
func init() {
if env := os.Getenv(DevopsAPIServerEnv); env != "" {
DevopsAPIServer = env
}
if env := os.Getenv(AccountAPIServerEnv); env != "" {
AccountAPIServer = env
}
if env := os.Getenv(DevopsProxyTokenEnv); env != "" {
DevopsProxyToken = env
}
if env := os.Getenv(OpenPitrixProxyTokenEnv); env != "" {
OpenPitrixProxyToken = env
}
}

View File

@@ -18,7 +18,6 @@ package container
import ( import (
"strings" "strings"
"time"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
@@ -26,16 +25,14 @@ import (
func logFilter() restful.FilterFunction { func logFilter() restful.FilterFunction {
return func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { return func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
start := time.Now()
chain.ProcessFilter(req, resp) chain.ProcessFilter(req, resp)
glog.Infof("%s - \"%s %s %s\" %d %d in %dms", glog.Infof("%s - \"%s %s %s\" %d %d",
strings.Split(req.Request.RemoteAddr, ":")[0], strings.Split(req.Request.RemoteAddr, ":")[0],
req.Request.Method, req.Request.Method,
req.Request.URL.RequestURI(), req.Request.URL.RequestURI(),
req.Request.Proto, req.Request.Proto,
resp.StatusCode(), resp.StatusCode(),
resp.ContentLength(), resp.ContentLength(),
time.Since(start)/time.Millisecond,
) )
} }
} }

View File

@@ -19,226 +19,150 @@ package models
import ( import (
"time" "time"
v13 "k8s.io/api/core/v1" "github.com/golang/glog"
"k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/models/controllers"
"k8s.io/apimachinery/pkg/labels"
"github.com/golang/glog"
) )
// Namespaces need to watch type ComponentsCount struct {
var SYSTEM_NAMESPACES = [...]string{"kubesphere-system", "openpitrix-system", "kube-system"} KubernetesCount int `json:"kubernetesCount"`
OpenpitrixCount int `json:"openpitrixCount"`
type Component struct { KubesphereCount int `json:"kubesphereCount"`
Name string `json:"name"`
Namespace string `json:"namespace"`
SelfLink string `json:"selfLink"`
Label interface{} `json:"label"`
StartedAt time.Time `json:"startedAt"`
TotalBackends int `json:"totalBackends"`
HealthyBackends int `json:"healthyBackends"`
} }
func GetComponentStatus(namespace string, componentName string) (interface{}, error) { type Components struct {
lister, err := controllers.GetLister(controllers.Services) Name string `json:"name"`
if err != nil { Namespace string `json:"namespace"`
glog.Errorln(err) SelfLink string `json:"selfLink"`
return nil, err Label interface{} `json:"label"`
} HealthStatus string `json:"healthStatus"`
CreateTime time.Time `json:"createTime"`
serviceLister := lister.(v12.ServiceLister)
service, err := serviceLister.Services(namespace).Get(componentName)
if err != nil {
glog.Error(err)
return nil, err
}
lister, err = controllers.GetLister(controllers.Pods)
if err != nil {
glog.Errorln(err)
return nil, err
}
podLister := lister.(v12.PodLister)
set := labels.Set(service.Spec.Selector)
pods, err := podLister.Pods(namespace).List(set.AsSelector())
if err != nil {
glog.Errorln(err)
return nil, err
} else {
component := Component{
Name: service.Name,
Namespace: service.Namespace,
SelfLink: service.SelfLink,
Label: service.Spec.Selector,
StartedAt: service.CreationTimestamp.Time,
HealthyBackends: 0,
TotalBackends: 0,
}
for _, v := range pods {
component.TotalBackends++
component.HealthyBackends++
for _, c := range v.Status.ContainerStatuses {
if !c.Ready {
component.HealthyBackends--
break
}
}
}
return component, nil
}
} }
func GetSystemHealthStatus() (map[string]interface{}, error) { /***
* get all components from k8s and kubesphere system
status := make(map[string]interface{}) *
*/
func GetComponents() (map[string]interface{}, error) {
result := make(map[string]interface{})
componentsList := make([]Components, 0)
k8sClient := client.NewK8sClient() k8sClient := client.NewK8sClient()
var count ComponentsCount
var components Components
csList, err := k8sClient.Core().ComponentStatuses().List(v1.ListOptions{}) label := ""
if err != nil { namespaces := []string{constants.KubeSystemNamespace, constants.OpenPitrixNamespace, constants.KubeSphereNamespace}
glog.Errorln(err) for _, ns := range namespaces {
return nil, err
}
for _, cs := range csList.Items { if ns == constants.KubeSystemNamespace {
status[cs.Name] = cs.Conditions[0] label = "kubernetes.io/cluster-service=true"
} } else if ns == constants.OpenPitrixNamespace {
label = "app=openpitrix"
// get kubesphere-system components } else {
label = "app=kubesphere"
systemComponentStatus, err := GetAllComponentsStatus()
if err != nil {
glog.Errorln(err)
}
for k, v := range systemComponentStatus {
status[k] = v
}
// get node status
lister, err := controllers.GetLister(controllers.Nodes)
if err != nil {
glog.Errorln(err)
return status, nil
}
nodeLister := lister.(v12.NodeLister)
nodes, err := nodeLister.List(labels.Everything())
if err != nil {
glog.Errorln(err)
return status, nil
}
nodeStatus := make(map[string]int)
totalNodes := 0
healthyNodes := 0
for _, nodes := range nodes {
totalNodes++
for _, condition := range nodes.Status.Conditions {
if condition.Type == v13.NodeReady && condition.Status == v13.ConditionTrue {
healthyNodes++
}
} }
} option := meta_v1.ListOptions{
nodeStatus["totalNodes"] = totalNodes
nodeStatus["healthyNodes"] = healthyNodes
status["nodes"] = nodeStatus LabelSelector: label,
}
servicelists, err := k8sClient.CoreV1().Services(ns).List(option)
return status, nil
}
func GetAllComponentsStatus() (map[string]interface{}, error) {
status := make(map[string]interface{})
var err error
lister, err := controllers.GetLister(controllers.Services)
if err != nil {
glog.Errorln(err)
return nil, err
}
serviceLister := lister.(v12.ServiceLister)
lister, err = controllers.GetLister(controllers.Pods)
if err != nil {
glog.Errorln(err)
return nil, err
}
podLister := lister.(v12.PodLister)
for _, ns := range SYSTEM_NAMESPACES {
nsStatus := make(map[string]interface{})
services, err := serviceLister.Services(ns).List(labels.Everything())
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
continue
return result, err
} }
for _, service := range services { if len(servicelists.Items) > 0 {
set := labels.Set(service.Spec.Selector) for _, service := range servicelists.Items {
if len(set) == 0 { switch ns {
continue
}
component := Component{ case constants.KubeSystemNamespace:
Name: service.Name, count.KubernetesCount++
Namespace: service.Namespace, case constants.OpenPitrixNamespace:
SelfLink: service.SelfLink, count.OpenpitrixCount++
Label: service.Spec.Selector, default:
StartedAt: service.CreationTimestamp.Time, count.KubesphereCount++
HealthyBackends: 0,
TotalBackends: 0,
}
pods, err := podLister.Pods(ns).List(set.AsSelector())
if err != nil {
glog.Errorln(err)
continue
}
for _, pod := range pods {
component.TotalBackends++
component.HealthyBackends++
for _, c := range pod.Status.ContainerStatuses {
if !c.Ready {
component.HealthyBackends--
break
}
} }
components.Name = service.Name
components.Namespace = service.Namespace
components.CreateTime = service.CreationTimestamp.Time
components.Label = service.Spec.Selector
components.SelfLink = service.SelfLink
label := service.Spec.Selector
combination := ""
for key, val := range label {
labelstr := key + "=" + val
if combination == "" {
combination = labelstr
} else {
combination = combination + "," + labelstr
}
}
option := meta_v1.ListOptions{
LabelSelector: combination,
}
podsList, err := k8sClient.CoreV1().Pods(ns).List(option)
if err != nil {
glog.Error(err)
return result, err
}
if len(podsList.Items) > 0 {
var health bool
for _, pod := range podsList.Items {
for _, status := range pod.Status.ContainerStatuses {
if status.Ready == false {
health = status.Ready
break
} else {
health = status.Ready
}
}
if health == false {
components.HealthStatus = "unhealth"
break
}
}
if health == true {
components.HealthStatus = "health"
}
} else {
components.HealthStatus = "unhealth"
}
componentsList = append(componentsList, components)
} }
nsStatus[service.Name] = component
} }
if len(nsStatus) > 0 {
status[ns] = nsStatus
}
} }
result["count"] = count
result["item"] = componentsList
return result, nil
return status, err
} }

View File

@@ -240,7 +240,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, deploySurffix) { if strings.HasSuffix(workLoadName, deploySurffix) {
name := strings.Split(workLoadName, deploySurffix)[0] name := strings.Split(workLoadName, deploySurffix)[0]
ctl := ResourceControllers.Controllers[Deployments] ctl := ResourceControllers.Controllers[Deployments]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "") _, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil)
works.Deployments = append(works.Deployments, items.([]Deployment)...) works.Deployments = append(works.Deployments, items.([]Deployment)...)
continue continue
} }
@@ -248,7 +248,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, daemonSurffix) { if strings.HasSuffix(workLoadName, daemonSurffix) {
name := strings.Split(workLoadName, daemonSurffix)[0] name := strings.Split(workLoadName, daemonSurffix)[0]
ctl := ResourceControllers.Controllers[Daemonsets] ctl := ResourceControllers.Controllers[Daemonsets]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "") _, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil)
works.Daemonsets = append(works.Daemonsets, items.([]Daemonset)...) works.Daemonsets = append(works.Daemonsets, items.([]Daemonset)...)
continue continue
} }
@@ -256,7 +256,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, stateSurffix) { if strings.HasSuffix(workLoadName, stateSurffix) {
name := strings.Split(workLoadName, stateSurffix)[0] name := strings.Split(workLoadName, stateSurffix)[0]
ctl := ResourceControllers.Controllers[Statefulsets] ctl := ResourceControllers.Controllers[Statefulsets]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "") _, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil)
works.Statefulsets = append(works.Statefulsets, items.([]Statefulset)...) works.Statefulsets = append(works.Statefulsets, items.([]Statefulset)...)
continue continue
} }
@@ -265,6 +265,16 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
return &works return &works
} }
//
//func (ctl *ApplicationCtl) getCreator(desc string) string {
// var dc description
// err := json.Unmarshal([]byte(desc), &dc)
// if err != nil {
// return unknown
// }
// return dc.Creator
//}
func (ctl *ApplicationCtl) getLabels(namespace string, workloads *workLoads) *[]map[string]string { func (ctl *ApplicationCtl) getLabels(namespace string, workloads *workLoads) *[]map[string]string {
k8sClient := client.NewK8sClient() k8sClient := client.NewK8sClient()
@@ -339,7 +349,7 @@ func (ctl *ApplicationCtl) getIng(namespace string, services *[]Service) *[]ing
ingCtl := ResourceControllers.Controllers[Ingresses] ingCtl := ResourceControllers.Controllers[Ingresses]
var ings []ing var ings []ing
for _, svc := range *services { for _, svc := range *services {
_, items, err := ingCtl.ListWithConditions(fmt.Sprintf("namespace = '%s' and rules like '%%%s%%' ", namespace, svc.Name), nil, "") _, items, err := ingCtl.ListWithConditions(fmt.Sprintf("namespace = '%s' and rules like '%%%s%%' ", namespace, svc.Name), nil)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return nil return nil
@@ -427,7 +437,6 @@ func (ctl *ApplicationCtl) ListApplication(runtimeId string, match, fuzzy map[st
appInfo, _, appId, _ := ctl.GetAppInfo(item.AppID) appInfo, _, appId, _ := ctl.GetAppInfo(item.AppID)
app.App = appInfo app.App = appInfo
app.AppId = appId app.AppId = appId
app.Description = item.Description
apps = append(apps, app) apps = append(apps, app)
} }

View File

@@ -1,185 +0,0 @@
/*
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 controllers
import (
"time"
"fmt"
"regexp"
"strings"
"github.com/golang/glog"
"github.com/pkg/errors"
rbac "k8s.io/api/rbac/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/kubectl"
)
func (ctl *ClusterRoleBindingCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ClusterRoleBindingCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ClusterRoleBindingCtl) total() int {
return 0
}
func (ctl *ClusterRoleBindingCtl) handleWorkspaceRoleChange(clusterRole *rbac.ClusterRoleBinding) {
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(clusterRole.Name); len(groups) == 3 {
workspace := groups[1]
go ctl.restNamespaceRoleBinding(workspace)
}
}
func (ctl *ClusterRoleBindingCtl) restNamespaceRoleBinding(workspace string) {
selector := labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspace})
namespaces, err := ctl.K8sClient.CoreV1().Namespaces().List(meta_v1.ListOptions{LabelSelector: selector.String()})
if err != nil {
glog.Warning("workspace roles sync failed", workspace, err)
return
}
for _, namespace := range namespaces.Items {
pathJson := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, initTimeAnnotateKey, "")
_, err := ctl.K8sClient.CoreV1().Namespaces().Patch(namespace.Name, "application/strategic-merge-patch+json", []byte(pathJson))
if err != nil {
glog.Warning("workspace roles sync failed", workspace, err)
return
}
}
}
func (ctl *ClusterRoleBindingCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
ctl.informer = informerFactory.Rbac().V1().ClusterRoleBindings().Informer()
ctl.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
ctl.handleTerminalCreate(clusterRoleBinding)
},
UpdateFunc: func(old, new interface{}) {
oldValue := old.(*rbac.ClusterRoleBinding)
newValue := new.(*rbac.ClusterRoleBinding)
if !subjectsCompile(oldValue.Subjects, newValue.Subjects) {
ctl.handleWorkspaceRoleChange(newValue)
ctl.handleTerminalUpdate(oldValue, newValue)
}
},
DeleteFunc: func(obj interface{}) {
clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
ctl.handleTerminalDelete(clusterRoleBinding)
},
})
}
func (ctl *ClusterRoleBindingCtl) handleTerminalCreate(clusterRoleBinding *rbac.ClusterRoleBinding) {
if clusterRoleBinding.RoleRef.Name == constants.ClusterAdmin {
for _, subject := range clusterRoleBinding.Subjects {
if subject.Kind == rbac.UserKind {
err := kubectl.CreateKubectlDeploy(subject.Name)
if err != nil {
glog.Error(fmt.Sprintf("create %s's terminal pod failed:%s", subject.Name, err))
}
}
}
}
}
func (ctl *ClusterRoleBindingCtl) handleTerminalUpdate(old *rbac.ClusterRoleBinding, new *rbac.ClusterRoleBinding) {
if new.RoleRef.Name == constants.ClusterAdmin {
for _, newSubject := range new.Subjects {
isAdded := true
for _, oldSubject := range old.Subjects {
if oldSubject == newSubject {
isAdded = false
break
}
}
if isAdded && newSubject.Kind == rbac.UserKind {
err := kubectl.CreateKubectlDeploy(newSubject.Name)
if err != nil {
glog.Error(fmt.Sprintf("create %s's terminal pod failed:%s", newSubject.Name, err))
}
}
}
for _, oldSubject := range old.Subjects {
isDeleted := true
for _, newSubject := range new.Subjects {
if newSubject == oldSubject {
isDeleted = false
break
}
}
if isDeleted && oldSubject.Kind == rbac.UserKind {
err := kubectl.DelKubectlDeploy(oldSubject.Name)
if err != nil {
glog.Error(fmt.Sprintf("delete %s's terminal pod failed:%s", oldSubject.Name, err))
}
}
}
}
}
func (ctl *ClusterRoleBindingCtl) handleTerminalDelete(clusterRoleBinding *rbac.ClusterRoleBinding) {
if clusterRoleBinding.RoleRef.Name == constants.ClusterAdmin {
for _, subject := range clusterRoleBinding.Subjects {
if subject.Kind == rbac.UserKind {
err := kubectl.DelKubectlDeploy(subject.Name)
if err != nil {
glog.Error(fmt.Sprintf("delete %s's terminal pod failed:%s", subject.Name, err))
}
}
}
}
}
func subjectsCompile(s1 []rbac.Subject, s2 []rbac.Subject) bool {
if len(s1) != len(s2) {
return false
}
for i, v := range s1 {
if v.Name != s2[i].Name || v.Kind != s2[i].Kind {
return false
}
}
return true
}
func (ctl *ClusterRoleBindingCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ClusterRoleBindingCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, errors.New("not implement")
}
func (ctl *ClusterRoleBindingCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,13 +30,8 @@ import (
const systemPrefix = "system:" const systemPrefix = "system:"
func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole { func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
if strings.HasPrefix(name, systemPrefix) || item.Annotations == nil || len(item.Annotations[creator]) == 0 { if strings.HasPrefix(name, systemPrefix) {
return nil return nil
} }
@@ -45,7 +40,7 @@ func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole {
createTime = time.Now() createTime = time.Now()
} }
object := &ClusterRole{Name: name, CreateTime: createTime, Annotation: MapString{item.Annotations}, DisplayName: displayName} object := &ClusterRole{Name: name, CreateTime: createTime, Annotation: Annotation{item.Annotations}}
return object return object
} }
@@ -74,9 +69,7 @@ func (ctl *ClusterRoleCtl) sync(stopChan chan struct{}) {
for _, item := range list { for _, item := range list {
obj := ctl.generateObject(*item) obj := ctl.generateObject(*item)
if obj != nil { if obj != nil {
if err := db.Create(obj).Error; err != nil { db.Create(obj)
glog.Error("cluster roles sync error", err)
}
} }
} }
@@ -86,13 +79,13 @@ func (ctl *ClusterRoleCtl) sync(stopChan chan struct{}) {
func (ctl *ClusterRoleCtl) total() int { func (ctl *ClusterRoleCtl) total() int {
list, err := ctl.lister.List(labels.Everything()) list, err := ctl.lister.List(labels.Everything())
if err != nil { if err != nil {
glog.Errorf("count %s failed, reason:%s", err, ctl.Name()) glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0 return 0
} }
count := 0 count := 0
for _, item := range list { for _, item := range list {
if !strings.HasPrefix(item.Name, systemPrefix) && item.Annotations != nil && len(item.Annotations[creator]) > 0 { if !strings.HasPrefix(item.Name, systemPrefix) {
count++ count++
} }
} }
@@ -113,27 +106,22 @@ func (ctl *ClusterRoleCtl) initListerAndInformer() {
object := obj.(*v1.ClusterRole) object := obj.(*v1.ClusterRole)
mysqlObject := ctl.generateObject(*object) mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil { if mysqlObject != nil {
if err := db.Create(mysqlObject).Error; err != nil { db.Create(mysqlObject)
glog.Error("cluster roles sync error", err)
}
} }
}, },
UpdateFunc: func(old, new interface{}) { UpdateFunc: func(old, new interface{}) {
object := new.(*v1.ClusterRole) object := new.(*v1.ClusterRole)
mysqlObject := ctl.generateObject(*object) mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil { if mysqlObject != nil {
if err := db.Save(mysqlObject).Error; err != nil { db.Save(mysqlObject)
glog.Error("cluster roles update error", err)
}
} }
}, },
DeleteFunc: func(obj interface{}) { DeleteFunc: func(obj interface{}) {
var item ClusterRole
object := obj.(*v1.ClusterRole) object := obj.(*v1.ClusterRole)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
if err := db.Delete(ClusterRole{}, "name=?", object.Name).Error; err != nil {
glog.Error("cluster roles delete error", err)
}
}, },
}) })
ctl.informer = informer ctl.informer = informer
@@ -148,23 +136,15 @@ func (ctl *ClusterRoleCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *ClusterRoleCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *ClusterRoleCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var object ClusterRole var object ClusterRole
var list []ClusterRole var list []ClusterRole
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
db := ctl.DB db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order) listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *ClusterRoleCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -23,18 +23,9 @@ import (
"strings" "strings"
"time" "time"
"sync"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/pkg/errors" "github.com/pkg/errors"
"kubesphere.io/kubesphere/pkg/constants"
)
const (
checkPeriod = 30 * time.Minute
sleepPeriod = 15 * time.Second
) )
func listWithConditions(db *gorm.DB, total *int, object, list interface{}, conditions string, paging *Paging, order string) { func listWithConditions(db *gorm.DB, total *int, object, list interface{}, conditions string, paging *Paging, order string) {
@@ -80,8 +71,6 @@ func makeHttpRequest(method, url, data string) ([]byte, error) {
req, err = http.NewRequest(method, url, strings.NewReader(data)) req, err = http.NewRequest(method, url, strings.NewReader(data))
} }
req.Header.Add("Authorization", constants.OpenPitrixProxyToken)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return nil, err return nil, err
@@ -125,20 +114,13 @@ func hasSynced(ctl Controller) bool {
func checkAndResync(ctl Controller, stopChan chan struct{}) { func checkAndResync(ctl Controller, stopChan chan struct{}) {
defer close(stopChan) defer close(stopChan)
lastTime := time.Now()
for { for {
select { select {
case <-ctl.chanStop(): case <-ctl.chanStop():
return return
default: default:
if time.Now().Sub(lastTime) < checkPeriod { time.Sleep(30 * time.Minute)
time.Sleep(sleepPeriod)
break
}
lastTime = time.Now()
if !hasSynced(ctl) { if !hasSynced(ctl) {
glog.Errorf("the data in db and kubernetes is inconsistent, resync %s controller", ctl.Name()) glog.Errorf("the data in db and kubernetes is inconsistent, resync %s controller", ctl.Name())
close(stopChan) close(stopChan)
@@ -149,10 +131,9 @@ func checkAndResync(ctl Controller, stopChan chan struct{}) {
} }
} }
func listAndWatch(ctl Controller, wg *sync.WaitGroup) { func listAndWatch(ctl Controller) {
defer handleCrash(ctl) defer handleCrash(ctl)
defer ctl.CloseDB()
defer wg.Done()
stopChan := make(chan struct{}) stopChan := make(chan struct{})
go ctl.sync(stopChan) go ctl.sync(stopChan)

View File

@@ -1,162 +0,0 @@
/*
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 controllers
import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *ConfigMapCtl) generateObject(item v1.ConfigMap) *ConfigMap {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
var entries []string
for entry := range item.Data {
entries = append(entries, entry)
}
object := &ConfigMap{
Name: item.Name,
Namespace: item.Namespace,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
DisplayName: displayName,
Entries: strings.Join(entries, ","),
}
return object
}
func (ctl *ConfigMapCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ConfigMapCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&ConfigMap{}) {
db.DropTable(&ConfigMap{})
}
db = db.CreateTable(&ConfigMap{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
db.Create(obj)
}
}
ctl.informer.Run(stopChan)
}
func (ctl *ConfigMapCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *ConfigMapCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().ConfigMaps().Lister()
informer := informerFactory.Core().V1().ConfigMaps().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.ConfigMap)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Create(mysqlObject)
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.ConfigMap)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Save(mysqlObject)
}
},
DeleteFunc: func(obj interface{}) {
var item ConfigMap
object := obj.(*v1.ConfigMap)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *ConfigMapCtl) CountWithConditions(conditions string) int {
var object ConfigMap
if strings.Contains(conditions, "namespace") {
conditions = ""
}
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *ConfigMapCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var object ConfigMap
var list []ConfigMap
var total int
if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *ConfigMapCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,64 +0,0 @@
/*
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 controllers
import (
"time"
"k8s.io/client-go/informers"
)
func (ctl *ControllerRevisionCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ControllerRevisionCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ControllerRevisionCtl) total() int {
return 0
}
func (ctl *ControllerRevisionCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().ControllerRevisions().Lister()
informer := informerFactory.Apps().V1().ControllerRevisions().Informer()
ctl.informer = informer
}
func (ctl *ControllerRevisionCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ControllerRevisionCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, nil
}
func (ctl *ControllerRevisionCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,158 +0,0 @@
/*
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 controllers
import (
"time"
"github.com/golang/glog"
"k8s.io/api/batch/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *CronJobCtl) generateObject(item v1beta1.CronJob) *CronJob {
var status, displayName string
var lastScheduleTime *time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
status = Running
if *item.Spec.Suspend {
status = Pause
}
schedule := item.Spec.Schedule
if item.Status.LastScheduleTime != nil {
lastScheduleTime = &item.Status.LastScheduleTime.Time
}
active := len(item.Status.Active)
object := &CronJob{
Namespace: namespace,
Name: name,
DisplayName: displayName,
LastScheduleTime: lastScheduleTime,
Active: active,
Schedule: schedule,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.ObjectMeta.Labels},
}
return object
}
func (ctl *CronJobCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *CronJobCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&CronJob{}) {
db.DropTable(&CronJob{})
}
db = db.CreateTable(&CronJob{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *CronJobCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *CronJobCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Batch().V1beta1().CronJobs().Lister()
informer := informerFactory.Batch().V1beta1().CronJobs().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1beta1.CronJob)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1beta1.CronJob)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item CronJob
object := obj.(*v1beta1.CronJob)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *CronJobCtl) CountWithConditions(conditions string) int {
var object CronJob
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *CronJobCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []CronJob
var object CronJob
var total int
if len(order) == 0 {
order = "lastScheduleTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *CronJobCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -28,11 +28,8 @@ import (
) )
func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset { func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset {
var app, status, displayName string var app string
var status string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
availablePodNum := item.Status.NumberAvailable availablePodNum := item.Status.NumberAvailable
@@ -58,19 +55,8 @@ func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset {
status = Updating status = Updating
} }
object := &Daemonset{ object := &Daemonset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
Namespace: namespace, App: app, CreateTime: createTime, Status: status, NodeSelector: string(nodeSelectorStr), Annotation: Annotation{item.Annotations}}
Name: name,
DisplayName: displayName,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
CreateTime: createTime,
Status: status,
NodeSelector: string(nodeSelectorStr),
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
}
return object return object
} }
@@ -149,21 +135,25 @@ func (ctl *DaemonsetCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *DaemonsetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *DaemonsetCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Daemonset var list []Daemonset
var object Daemonset var object Daemonset
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *DaemonsetCtl) Lister() interface{} { //func (ctl *DaemonsetCtl) Count(namespace string) int {
// var count int
return ctl.lister // db := ctl.DB
} // if len(namespace) == 0 {
// db.Model(&Daemonset{}).Count(&count)
// } else {
// db.Model(&Daemonset{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -27,13 +27,9 @@ import (
) )
func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment { func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
var app, status, displayName string var app string
var status string
var updateTime time.Time var updateTime time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
availablePodNum := item.Status.AvailableReplicas availablePodNum := item.Status.AvailableReplicas
@@ -45,13 +41,9 @@ func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
app = release + "/" + chart app = release + "/" + chart
} }
for _, condition := range item.Status.Conditions { for _, conditon := range item.Status.Conditions {
if updateTime.IsZero() { if conditon.Type == "Available" {
updateTime = condition.LastUpdateTime.Time updateTime = conditon.LastUpdateTime.Time
} else {
if updateTime.Before(condition.LastUpdateTime.Time) {
updateTime = condition.LastUpdateTime.Time
}
} }
} }
if updateTime.IsZero() { if updateTime.IsZero() {
@@ -68,18 +60,8 @@ func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
} }
} }
return &Deployment{ return &Deployment{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
Namespace: namespace, App: app, UpdateTime: updateTime, Status: status, Annotation: Annotation{item.Annotations}}
Name: name,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
UpdateTime: updateTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
DisplayName: displayName,
}
} }
func (ctl *DeploymentCtl) Name() string { func (ctl *DeploymentCtl) Name() string {
@@ -156,21 +138,14 @@ func (ctl *DeploymentCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *DeploymentCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *DeploymentCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Deployment var list []Deployment
var object Deployment var object Deployment
var total int var total int
if len(order) == 0 { order := "updateTime desc"
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *DeploymentCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,16 +30,9 @@ import (
) )
func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress { func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
var ip, tls, displayName string
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
var ip, tls string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
if createTime.IsZero() { if createTime.IsZero() {
createTime = time.Now() createTime = time.Now()
@@ -70,17 +63,7 @@ func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
ruleStr, _ := json.Marshal(ingRules) ruleStr, _ := json.Marshal(ingRules)
object := &Ingress{ object := &Ingress{Namespace: namespace, Name: name, TlsTermination: tls, Ip: ip, CreateTime: createTime, Annotation: Annotation{item.Annotations}, Rules: string(ruleStr)}
Namespace: namespace,
Name: name,
DisplayName: displayName,
TlsTermination: tls,
Ip: ip,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Rules: string(ruleStr),
Labels: MapString{item.Labels},
}
return object return object
} }
@@ -160,21 +143,25 @@ func (ctl *IngressCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *IngressCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *IngressCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Ingress var list []Ingress
var object Ingress var object Ingress
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *IngressCtl) Lister() interface{} { //func (ctl *IngressCtl) Count(namespace string) int {
// var count int
return ctl.lister // db := ctl.DB
} // if len(namespace) == 0 {
// db.Model(&Ingress{}).Count(&count)
// } else {
// db.Model(&Ingress{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -1,318 +0,0 @@
/*
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 controllers
import (
"encoding/json"
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/api/batch/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"reflect"
"strings"
"kubesphere.io/kubesphere/pkg/client"
)
var k8sClient *kubernetes.Clientset
const retryTimes = 3
func (ctl *JobCtl) generateObject(item v1.Job) *Job {
var status, displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
succeedPodNum := item.Status.Succeeded
desirePodNum := *item.Spec.Completions
createTime := item.CreationTimestamp.Time
updteTime := createTime
for _, condition := range item.Status.Conditions {
if condition.Type == "Failed" && condition.Status == "True" {
status = Failed
}
if condition.Type == "Complete" && condition.Status == "True" {
status = Completed
}
if updteTime.Before(condition.LastProbeTime.Time) {
updteTime = condition.LastProbeTime.Time
}
if updteTime.Before(condition.LastTransitionTime.Time) {
updteTime = condition.LastTransitionTime.Time
}
}
if desirePodNum > succeedPodNum && len(status) == 0 {
status = Running
}
object := &Job{
Namespace: namespace,
Name: name,
DisplayName: displayName,
Desire: desirePodNum,
Completed: succeedPodNum,
UpdateTime: updteTime,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
}
return object
}
func (ctl *JobCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *JobCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Job{}) {
db.DropTable(&Job{})
}
db = db.CreateTable(&Job{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *JobCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *JobCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Batch().V1().Jobs().Lister()
informer := informerFactory.Batch().V1().Jobs().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Job)
mysqlObject := ctl.generateObject(*object)
ctl.makeRevision(object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Job)
mysqlObject := ctl.generateObject(*object)
ctl.makeRevision(object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Job
object := obj.(*v1.Job)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *JobCtl) CountWithConditions(conditions string) int {
var object Job
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *JobCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Job
var object Job
var total int
if len(order) == 0 {
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *JobCtl) Lister() interface{} {
return ctl.lister
}
func getRevisions(job v1.Job) (JobRevisions, error) {
revisions := make(JobRevisions)
if _, exist := job.Annotations["revisions"]; exist {
revisionsStr := job.Annotations["revisions"]
err := json.Unmarshal([]byte(revisionsStr), &revisions)
if err != nil {
return nil, fmt.Errorf("failed to get job %s's revisions, reason: %s", job.Name, err)
}
}
return revisions, nil
}
func getCurrentRevision(item *v1.Job) JobRevision {
var revision JobRevision
for _, condition := range item.Status.Conditions {
if condition.Type == "Failed" && condition.Status == "True" {
revision.Status = Failed
revision.Reasons = append(revision.Reasons, condition.Reason)
revision.Messages = append(revision.Messages, condition.Message)
}
if condition.Type == "Complete" && condition.Status == "True" {
revision.Status = Completed
}
}
if len(revision.Status) == 0 {
revision.Status = Running
}
revision.DesirePodNum = *item.Spec.Completions
revision.Succeed = item.Status.Succeeded
revision.Failed = item.Status.Failed
revision.StartTime = item.CreationTimestamp.Time
revision.Uid = string(item.UID)
if item.Status.CompletionTime != nil {
revision.CompletionTime = item.Status.CompletionTime.Time
}
return revision
}
func deleteJob(namespace, job string) error {
deletePolicy := metav1.DeletePropagationBackground
err := k8sClient.BatchV1().Jobs(namespace).Delete(job, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
return err
}
func (ctl *JobCtl) makeRevision(job *v1.Job) {
revisionIndex := -1
revisions, err := getRevisions(*job)
if err != nil {
glog.Error(err)
return
}
uid := job.UID
for index, revision := range revisions {
if revision.Uid == string(uid) {
currentRevision := getCurrentRevision(job)
if reflect.DeepEqual(currentRevision, revision) {
return
} else {
revisionIndex = index
break
}
}
}
if revisionIndex == -1 {
revisionIndex = len(revisions) + 1
}
revisions[revisionIndex] = getCurrentRevision(job)
revisionsByte, err := json.Marshal(revisions)
if err != nil {
glog.Error(err)
}
if job.Annotations == nil {
job.Annotations = make(map[string]string)
}
job.Annotations["revisions"] = string(revisionsByte)
ctl.K8sClient.BatchV1().Jobs(job.Namespace).Update(job)
}
func JobReRun(namespace, jobName string) (string, error) {
k8sClient = client.NewK8sClient()
job, err := k8sClient.BatchV1().Jobs(namespace).Get(jobName, metav1.GetOptions{})
if err != nil {
return "", err
}
newJob := *job
newJob.ResourceVersion = ""
newJob.Status = v1.JobStatus{}
newJob.ObjectMeta.UID = ""
newJob.Annotations["revisions"] = strings.Replace(job.Annotations["revisions"], Running, Unfinished, -1)
delete(newJob.Spec.Selector.MatchLabels, "controller-uid")
delete(newJob.Spec.Template.ObjectMeta.Labels, "controller-uid")
err = deleteJob(namespace, jobName)
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", jobName, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
for i := 0; i < retryTimes; i++ {
_, err = k8sClient.BatchV1().Jobs(namespace).Create(&newJob)
if err != nil {
time.Sleep(time.Second)
continue
}
break
}
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", jobName, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
return "succeed", nil
}

View File

@@ -46,19 +46,17 @@ import (
const ( const (
provider = "kubernetes" provider = "kubernetes"
admin = "admin" admin = "admin"
operator = "operator" editor = "editor"
viewer = "viewer" viewer = "viewer"
kubectlNamespace = constants.KubeSphereControlNamespace kubectlNamespace = constants.KubeSphereControlNamespace
kubectlConfigKey = "config" kubectlConfigKey = "config"
openPitrixRuntimeAnnotateKey = "openpitrix_runtime" openPitrixRuntimeAnnotateKey = "openpitrix_runtime"
creatorAnnotateKey = "creator" creatorAnnotateKey = "creator"
initTimeAnnotateKey = "kubesphere.io/init-time"
workspaceLabelKey = "kubesphere.io/workspace"
) )
var adminRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}} var adminRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}
var editorRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "kubesphere.io", "account.kubesphere.io"}, Resources: []string{"*"}}} var editorRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch"}, Resources: []string{"*"}}}
var viewerRules = []rbac.PolicyRule{{Verbs: []string{"list", "get", "watch"}, APIGroups: []string{"", "apps", "extensions", "batch", "kubesphere.io", "account.kubesphere.io"}, Resources: []string{"*"}}} var viewerRules = []rbac.PolicyRule{{Verbs: []string{"list", "get", "watch"}, APIGroups: []string{"", "apps", "extensions", "batch"}, Resources: []string{"*"}}}
type runTime struct { type runTime struct {
RuntimeId string `json:"runtime_id"` RuntimeId string `json:"runtime_id"`
@@ -133,182 +131,101 @@ func (ctl *NamespaceCtl) createOpRuntime(namespace string) ([]byte, error) {
return makeHttpRequest("POST", url, string(body)) return makeHttpRequest("POST", url, string(body))
} }
func (ctl *NamespaceCtl) updateSystemRoleBindings(namespace *v1.Namespace) error { func (ctl *NamespaceCtl) createDefaultRoleBinding(ns, user string) error {
workspace := "" roleBinding := &rbac.RoleBinding{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: ns},
Subjects: []rbac.Subject{{Name: user, Kind: rbac.UserKind}}, RoleRef: rbac.RoleRef{Kind: "Role", Name: admin}}
if namespace.Labels != nil { _, err := ctl.K8sClient.RbacV1().RoleBindings(ns).Create(roleBinding)
workspace = namespace.Labels[workspaceLabelKey]
if err != nil && !errors.IsAlreadyExists(err) {
glog.Error(err)
return err
} }
adminBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(admin, metaV1.GetOptions{}) return nil
}
if err != nil { func (ctl *NamespaceCtl) createDefaultRole(ns string) error {
if errors.IsNotFound(err) { adminRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: ns}, Rules: adminRules}
adminBinding = new(rbac.RoleBinding) editorRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: editor, Namespace: ns}, Rules: editorRules}
adminBinding.Name = admin viewerRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: viewer, Namespace: ns}, Rules: viewerRules}
adminBinding.Namespace = namespace.Name
adminBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: admin} _, err := ctl.K8sClient.RbacV1().Roles(ns).Create(adminRole)
} else {
return err if err != nil && !errors.IsAlreadyExists(err) {
} return err
} }
adminBinding.Subjects = make([]rbac.Subject, 0) _, err = ctl.K8sClient.RbacV1().Roles(ns).Create(editorRole)
if workspace != "" { if err != nil && !errors.IsAlreadyExists(err) {
workspaceAdmin, err := ctl.K8sClient.RbacV1().ClusterRoleBindings().Get(fmt.Sprintf("system:%s:%s", workspace, constants.WorkspaceAdmin), metaV1.GetOptions{}) return err
if err != nil {
return err
}
adminBinding.Subjects = append(adminBinding.Subjects, workspaceAdmin.Subjects...)
} }
if adminBinding.ResourceVersion == "" { _, err = ctl.K8sClient.RbacV1().Roles(ns).Create(viewerRole)
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(adminBinding)
if err != nil && !errors.IsAlreadyExists(err) {
return err
}
return nil
}
func (ctl *NamespaceCtl) createRoleAndRuntime(item v1.Namespace) {
var creator string
var runtime string
ns := item.Name
if item.Annotations == nil {
creator = ""
runtime = ""
} else { } else {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(adminBinding) runtime = item.Annotations[openPitrixRuntimeAnnotateKey]
} creator = item.Annotations[creatorAnnotateKey]
if err != nil {
return err
}
viewerBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(viewer, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
viewerBinding = new(rbac.RoleBinding)
viewerBinding.Name = viewer
viewerBinding.Namespace = namespace.Name
viewerBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: viewer}
} else {
return err
}
}
viewerBinding.Subjects = make([]rbac.Subject, 0)
if workspace != "" {
workspaceViewer, err := ctl.K8sClient.RbacV1().ClusterRoleBindings().Get(fmt.Sprintf("system:%s:%s", workspace, constants.WorkspaceViewer), metaV1.GetOptions{})
if err != nil {
return err
}
viewerBinding.Subjects = append(viewerBinding.Subjects, workspaceViewer.Subjects...)
}
if viewerBinding.ResourceVersion == "" {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(viewerBinding)
} else {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(viewerBinding)
}
if err != nil {
return err
}
return nil
}
func (ctl *NamespaceCtl) createDefaultRoleBinding(namespace *v1.Namespace) error {
creator := ""
if namespace.Annotations != nil {
creator = namespace.Annotations[creatorAnnotateKey]
}
// create once
if creator != "" {
creatorBindingName := fmt.Sprintf("%s-admin", creator)
creatorBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(creatorBindingName, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
creatorBinding = new(rbac.RoleBinding)
creatorBinding.Name = creatorBindingName
creatorBinding.Namespace = namespace.Name
creatorBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: admin}
} else {
return err
}
}
creatorBinding.Subjects = []rbac.Subject{{Kind: rbac.UserKind, Name: creator}}
if creatorBinding.ResourceVersion == "" {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(creatorBinding)
} else {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(creatorBinding)
}
if err != nil {
return err
}
}
return nil
}
func (ctl *NamespaceCtl) CreateDefaultRoleAndRoleBinding(namespace *v1.Namespace) error {
adminRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: namespace.Name, Annotations: map[string]string{creatorAnnotateKey: "system"}}, Rules: adminRules}
operatorRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: operator, Namespace: namespace.Name, Annotations: map[string]string{creatorAnnotateKey: "system"}}, Rules: editorRules}
viewerRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: viewer, Namespace: namespace.Name, Annotations: map[string]string{creatorAnnotateKey: "system"}}, Rules: viewerRules}
_, err := ctl.K8sClient.RbacV1().Roles(namespace.Name).Create(adminRole)
if err != nil && !errors.IsAlreadyExists(err) {
return err
} else if err == nil {
if err := ctl.createDefaultRoleBinding(namespace); err != nil {
glog.Warning("default role binding create failed", namespace.Name)
}
}
_, err = ctl.K8sClient.RbacV1().Roles(namespace.Name).Create(operatorRole)
if err != nil && !errors.IsAlreadyExists(err) {
return err
}
_, err = ctl.K8sClient.RbacV1().Roles(namespace.Name).Create(viewerRole)
if err != nil && !errors.IsAlreadyExists(err) {
return err
}
return nil
}
func (ctl *NamespaceCtl) createRoleAndRuntime(namespace *v1.Namespace) {
runtime := ""
initTime := ""
if namespace.Annotations != nil {
runtime = namespace.Annotations[openPitrixRuntimeAnnotateKey]
initTime = namespace.Annotations[initTimeAnnotateKey]
} }
componentsNamespaces := []string{constants.KubeSystemNamespace, constants.OpenPitrixNamespace, constants.IstioNamespace, constants.KubeSphereNamespace} componentsNamespaces := []string{constants.KubeSystemNamespace, constants.OpenPitrixNamespace, constants.IstioNamespace, constants.KubeSphereNamespace}
if runtime == "" && !slice.ContainsString(componentsNamespaces, namespace.Name, nil) { if len(runtime) == 0 && !slice.ContainsString(componentsNamespaces, ns, nil) {
_, runtimeCreateError := ctl.createOpRuntime(namespace.Name) glog.Infoln("create runtime:", ns)
var runtimeCreateError error
resp, runtimeCreateError := ctl.createOpRuntime(ns)
if runtimeCreateError == nil {
var runtime runTime
runtimeCreateError = json.Unmarshal(resp, &runtime)
if runtimeCreateError == nil {
if item.Annotations == nil {
item.Annotations = make(map[string]string, 0)
}
item.Annotations[openPitrixRuntimeAnnotateKey] = runtime.RuntimeId
_, runtimeCreateError = ctl.K8sClient.CoreV1().Namespaces().Update(&item)
}
}
if runtimeCreateError != nil { if runtimeCreateError != nil {
glog.Error("runtime create error:", runtimeCreateError) glog.Error("runtime create error:", runtimeCreateError)
} }
}
if initTime == "" { if len(creator) > 0 {
err := ctl.CreateDefaultRoleAndRoleBinding(namespace) roleCreateError := ctl.createDefaultRole(ns)
if err == nil { glog.Infoln("create default role:", ns)
err = ctl.updateSystemRoleBindings(namespace) if roleCreateError == nil {
if err != nil {
glog.Error("role binding update error:", err) roleBindingError := ctl.createDefaultRoleBinding(ns, creator)
} glog.Infoln("create default role binding:", ns)
} else { if roleBindingError != nil {
glog.Error("default role create error:", err) glog.Error("default role binding create error:", roleBindingError)
} }
if err == nil {
pathJson := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, initTimeAnnotateKey, time.Now().UTC().Format("2006-01-02T15:04:05Z")) } else {
_, err = ctl.K8sClient.CoreV1().Namespaces().Patch(namespace.Name, "application/strategic-merge-patch+json", []byte(pathJson)) glog.Error("default role create error:", roleCreateError)
if err != nil {
glog.Error("annotations patch error init failed:", namespace.Name, err)
} }
} }
} }
} }
@@ -376,12 +293,7 @@ func (ctl *NamespaceCtl) createCephSecretAfterNewNs(item v1.Namespace) {
} }
} }
func (ctl *NamespaceCtl) generateObject(item *v1.Namespace) *Namespace { func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
@@ -391,13 +303,7 @@ func (ctl *NamespaceCtl) generateObject(item *v1.Namespace) *Namespace {
createTime = time.Now() createTime = time.Now()
} }
object := &Namespace{ object := &Namespace{Name: name, CreateTime: createTime, Status: status, Annotation: Annotation{item.Annotations}}
Name: name,
DisplayName: displayName,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
}
return object return object
} }
@@ -416,17 +322,17 @@ func (ctl *NamespaceCtl) sync(stopChan chan struct{}) {
db = db.CreateTable(&Namespace{}) db = db.CreateTable(&Namespace{})
ctl.initListerAndInformer() ctl.initListerAndInformer()
//list, err := ctl.lister.List(labels.Everything()) list, err := ctl.lister.List(labels.Everything())
//if err != nil { if err != nil {
// glog.Error(err) glog.Error(err)
// return return
//} }
//for _, item := range list { for _, item := range list {
// obj := ctl.generateObject(item) obj := ctl.generateObject(*item)
// db.Create(obj) db.Create(obj)
// ctl.createRoleAndRuntime(item) ctl.createRoleAndRuntime(*item)
//} }
ctl.informer.Run(stopChan) ctl.informer.Run(stopChan)
} }
@@ -452,16 +358,16 @@ func (ctl *NamespaceCtl) initListerAndInformer() {
AddFunc: func(obj interface{}) { AddFunc: func(obj interface{}) {
object := obj.(*v1.Namespace) object := obj.(*v1.Namespace)
mysqlObject := ctl.generateObject(object) mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject) db.Create(mysqlObject)
ctl.createRoleAndRuntime(object) ctl.createRoleAndRuntime(*object)
ctl.createCephSecretAfterNewNs(*object) ctl.createCephSecretAfterNewNs(*object)
}, },
UpdateFunc: func(old, new interface{}) { UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Namespace) object := new.(*v1.Namespace)
mysqlObject := ctl.generateObject(object) mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject) db.Save(mysqlObject)
ctl.createRoleAndRuntime(object) ctl.createRoleAndRuntime(*object)
}, },
DeleteFunc: func(obj interface{}) { DeleteFunc: func(obj interface{}) {
var item Namespace var item Namespace
@@ -469,6 +375,7 @@ func (ctl *NamespaceCtl) initListerAndInformer() {
db.Where("name=?", object.Name).Find(&item) db.Where("name=?", object.Name).Find(&item)
db.Delete(item) db.Delete(item)
ctl.deleteOpRuntime(*object) ctl.deleteOpRuntime(*object)
}, },
}) })
@@ -481,14 +388,12 @@ func (ctl *NamespaceCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Namespace var list []Namespace
var object Namespace var object Namespace
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
@@ -496,7 +401,7 @@ func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging, o
for index := range list { for index := range list {
usage, err := ctl.GetNamespaceQuota(list[index].Name) usage, err := ctl.GetNamespaceQuota(list[index].Name)
if err == nil { if err == nil {
list[index].Usage = usage list[index].Usaeg = usage
} }
} }
} }
@@ -513,7 +418,7 @@ func (ctl *NamespaceCtl) GetNamespaceQuota(namespace string) (v1.ResourceList, e
usage := make(v1.ResourceList) usage := make(v1.ResourceList)
resourceList := []string{Daemonsets, Deployments, Ingresses, Roles, Services, Statefulsets, PersistentVolumeClaim, Pods, Jobs, Cronjobs} resourceList := []string{Daemonsets, Deployments, Ingresses, Roles, Services, Statefulsets, PersistentVolumeClaim, Pods}
for _, resourceName := range resourceList { for _, resourceName := range resourceList {
used := getUsage(namespace, resourceName) used := getUsage(namespace, resourceName)
var quantity resource.Quantity var quantity resource.Quantity
@@ -528,8 +433,3 @@ func (ctl *NamespaceCtl) GetNamespaceQuota(namespace string) (v1.ResourceList, e
usage["runningPods"] = quantity usage["runningPods"] = quantity
return usage, nil return usage, nil
} }
func (ctl *NamespaceCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,188 +0,0 @@
/*
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 controllers
import (
"time"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
const NodeRoleLabel = "node-role.kubernetes.io/"
func (ctl *NodeCtl) generateObject(item v1.Node) *Node {
var status, ip, displayName, msgStr string
var msg, role []string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.ObjectMeta.CreationTimestamp.Time
annotation := item.Annotations
// in case of multiple roles
for label, _ := range item.Labels {
if strings.HasPrefix(label, NodeRoleLabel) {
if parts := strings.Split(label, "/"); len(parts) == 2 {
role = append(role, parts[1])
}
}
}
for _, condition := range item.Status.Conditions {
if condition.Type == "Ready" {
if condition.Status == "True" {
status = Running
} else {
status = Error
}
} else {
if condition.Status == "True" {
msg = append(msg, condition.Reason)
}
}
}
if len(msg) > 0 {
msgStr = strings.Join(msg, ",")
if status == Running {
status = Warning
}
}
for _, address := range item.Status.Addresses {
if address.Type == "InternalIP" {
ip = address.Address
}
}
object := &Node{
Name: name,
DisplayName: displayName,
Ip: ip,
Status: status,
CreateTime: createTime,
Annotation: MapString{annotation},
Taints: Taints{item.Spec.Taints},
Msg: msgStr,
Role: strings.Join(role, ","),
Labels: MapString{item.Labels}}
return object
}
func (ctl *NodeCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *NodeCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Node{}) {
db.DropTable(&Node{})
}
db = db.CreateTable(&Node{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *NodeCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s failed, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *NodeCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Nodes().Lister()
informer := informerFactory.Core().V1().Nodes().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Node)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Node)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Node
object := obj.(*v1.Node)
db.Where("name=? ", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *NodeCtl) CountWithConditions(conditions string) int {
var object Node
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *NodeCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Node
var object Node
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *NodeCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -166,29 +166,35 @@ func getStatusAndRestartCount(pod v1.Pod) (string, int) {
} }
func (ctl *PodCtl) generateObject(item v1.Pod) *Pod { func (ctl *PodCtl) generateObject(item v1.Pod) *Pod {
name := item.Name
namespace := item.Namespace
podIp := item.Status.PodIP
nodeName := item.Spec.NodeName
nodeIp := item.Status.HostIP
status, restartCount := getStatusAndRestartCount(item)
createTime := item.CreationTimestamp.Time
containerStatus := item.Status.ContainerStatuses
containerSpecs := item.Spec.Containers
var ownerKind, ownerName string var containers Containers
// For ReplicaSet,ReplicaController,DaemonSet,StatefulSet,Job,CronJob, k8s will automatically for _, containerSpec := range containerSpecs {
// set ownerReference for pods, in case of setting ownerReference manually. var container Container
if item.OwnerReferences != nil && len(item.OwnerReferences) > 0 { container.Name = containerSpec.Name
ownerKind = item.OwnerReferences[0].Kind container.Image = containerSpec.Image
ownerName = item.OwnerReferences[0].Name container.Ports = containerSpec.Ports
container.Resources = containerSpec.Resources
for _, status := range containerStatus {
if container.Name == status.Name {
container.Ready = status.Ready
}
}
containers = append(containers, container)
} }
object := &Pod{ object := &Pod{Namespace: namespace, Name: name, Node: nodeName, PodIp: podIp, Status: status, NodeIp: nodeIp,
Namespace: item.Namespace, CreateTime: createTime, Annotation: Annotation{item.Annotations}, Containers: containers, RestartCount: restartCount}
Name: item.Name,
Node: item.Spec.NodeName,
Status: item.Status,
CreateTime: item.CreationTimestamp.Time,
OwnerKind: ownerKind,
OwnerName: ownerName,
Spec: item.Spec,
Metadata: item.ObjectMeta,
Kind: item.TypeMeta.Kind,
APIVersion: item.TypeMeta.APIVersion,
}
return object return object
} }
@@ -271,21 +277,25 @@ func (ctl *PodCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *PodCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *PodCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Pod var list []Pod
var object Pod var object Pod
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *PodCtl) Lister() interface{} { //func (ctl *PodCtl) Count(namespace string) int {
// var count int
return ctl.lister // db := ctl.DB
} // if len(namespace) == 0 {
// db.Model(&Pod{}).Count(&count)
// } else {
// db.Model(&Pod{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -30,20 +30,10 @@ import (
) )
func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc { func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
createTime := item.CreationTimestamp.Time
status := fmt.Sprintf("%s", item.Status.Phase) status := fmt.Sprintf("%s", item.Status.Phase)
if item.DeletionTimestamp != nil { createTime := item.CreationTimestamp.Time
status = "Terminating"
}
var capacity, storageClass, accessModeStr string var capacity, storageClass, accessModeStr string
if createTime.IsZero() { if createTime.IsZero() {
@@ -68,18 +58,8 @@ func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
accessModeStr = strings.Join(accessModeList, ",") accessModeStr = strings.Join(accessModeList, ",")
object := &Pvc{ object := &Pvc{Namespace: namespace, Name: name, Status: status, Capacity: capacity,
Namespace: namespace, AccessMode: accessModeStr, StorageClassName: storageClass, CreateTime: createTime, Annotation: Annotation{item.Annotations}}
Name: name,
DisplayName: displayName,
Status: status,
Capacity: capacity,
AccessMode: accessModeStr,
StorageClassName: storageClass,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
}
return object return object
} }
@@ -158,14 +138,12 @@ func (ctl *PvcCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Pvc var list []Pvc
var object Pvc var object Pvc
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
@@ -185,7 +163,13 @@ func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging, order s
return total, list, nil return total, list, nil
} }
func (ctl *PvcCtl) Lister() interface{} { //func (ctl *PvcCtl) Count(namespace string) int {
// var count int
return ctl.lister // db := ctl.DB
} // if len(namespace) == 0 {
// db.Model(&Pvc{}).Count(&count)
// } else {
// db.Model(&Pvc{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -1,64 +0,0 @@
/*
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 controllers
import (
"time"
"k8s.io/client-go/informers"
)
func (ctl *ReplicaSetCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ReplicaSetCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ReplicaSetCtl) total() int {
return 0
}
func (ctl *ReplicaSetCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().ReplicaSets().Lister()
informer := informerFactory.Apps().V1().ReplicaSets().Informer()
ctl.informer = informer
}
func (ctl *ReplicaSetCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ReplicaSetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, nil
}
func (ctl *ReplicaSetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,57 +0,0 @@
/*
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 controllers
import (
"time"
"github.com/pkg/errors"
"k8s.io/client-go/informers"
)
func (ctl *RoleBindingCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *RoleBindingCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *RoleBindingCtl) total() int {
return 0
}
func (ctl *RoleBindingCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().RoleBindings().Lister()
ctl.informer = informerFactory.Rbac().V1().RoleBindings().Informer()
}
func (ctl *RoleBindingCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *RoleBindingCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, errors.New("not implement")
}
func (ctl *RoleBindingCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -28,14 +28,8 @@ import (
) )
func (ctl *RoleCtl) generateObject(item v1.Role) *Role { func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) == 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
if strings.HasPrefix(name, systemPrefix) || item.Annotations == nil || len(item.Annotations[creator]) == 0 { if strings.HasPrefix(name, systemPrefix) {
return nil return nil
} }
namespace := item.Namespace namespace := item.Namespace
@@ -44,13 +38,7 @@ func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
createTime = time.Now() createTime = time.Now()
} }
object := &Role{ object := &Role{Namespace: namespace, Name: name, CreateTime: createTime, Annotation: Annotation{item.Annotations}}
Namespace: namespace,
Name: name,
DisplayName: displayName,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
}
return object return object
} }
@@ -88,13 +76,13 @@ func (ctl *RoleCtl) sync(stopChan chan struct{}) {
func (ctl *RoleCtl) total() int { func (ctl *RoleCtl) total() int {
list, err := ctl.lister.List(labels.Everything()) list, err := ctl.lister.List(labels.Everything())
if err != nil { if err != nil {
glog.Errorf("count %s failed, reason:%s", err, ctl.Name()) glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0 return 0
} }
count := 0 count := 0
for _, item := range list { for _, item := range list {
if !strings.HasPrefix(item.Name, systemPrefix) && item.Annotations != nil && len(item.Annotations[creator]) > 0 { if !strings.HasPrefix(item.Name, systemPrefix) {
count++ count++
} }
} }
@@ -144,21 +132,21 @@ func (ctl *RoleCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *RoleCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *RoleCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Role var list []Role
var object Role var object Role
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *RoleCtl) Lister() interface{} { //func (ctl *RoleCtl) Count(namespace string) int {
// var count int
return ctl.lister // db := ctl.DB
} // db.Model(&Role{}).Where("namespace = ?", namespace).Count(&count)
// return count
//}

View File

@@ -17,18 +17,12 @@ limitations under the License.
package controllers package controllers
import ( import (
"errors"
"fmt"
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"os"
"sync"
"syscall"
"kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/client"
) )
@@ -37,9 +31,10 @@ type resourceControllers struct {
k8sClient *kubernetes.Clientset k8sClient *kubernetes.Clientset
} }
var stopChan chan struct{}
var ResourceControllers resourceControllers var ResourceControllers resourceControllers
func (rec *resourceControllers) runController(name string, stopChan chan struct{}, wg *sync.WaitGroup) { func (rec *resourceControllers) runContoller(name string) {
var ctl Controller var ctl Controller
attr := CommonAttribute{DB: client.NewDBClient(), K8sClient: rec.k8sClient, stopChan: stopChan, attr := CommonAttribute{DB: client.NewDBClient(), K8sClient: rec.k8sClient, stopChan: stopChan,
aliveChan: make(chan struct{}), Name: name} aliveChan: make(chan struct{}), Name: name}
@@ -66,37 +61,16 @@ func (rec *resourceControllers) runController(name string, stopChan chan struct{
ctl = &NamespaceCtl{CommonAttribute: attr} ctl = &NamespaceCtl{CommonAttribute: attr}
case StorageClasses: case StorageClasses:
ctl = &StorageClassCtl{CommonAttribute: attr} ctl = &StorageClassCtl{CommonAttribute: attr}
case Jobs:
ctl = &JobCtl{CommonAttribute: attr}
case Cronjobs:
ctl = &CronJobCtl{CommonAttribute: attr}
case Nodes:
ctl = &NodeCtl{CommonAttribute: attr}
case Replicasets:
ctl = &ReplicaSetCtl{CommonAttribute: attr}
case ControllerRevisions:
ctl = &ControllerRevisionCtl{CommonAttribute: attr}
case ConfigMaps:
ctl = &ConfigMapCtl{CommonAttribute: attr}
case Secrets:
ctl = &SecretCtl{CommonAttribute: attr}
case ClusterRoleBindings:
ctl = &ClusterRoleBindingCtl{CommonAttribute: attr}
case RoleBindings:
ctl = &RoleBindingCtl{CommonAttribute: attr}
default: default:
return return
} }
rec.Controllers[name] = ctl rec.Controllers[name] = ctl
wg.Add(1) go listAndWatch(ctl)
go listAndWatch(ctl, wg)
} }
func dbHealthCheck(db *gorm.DB) { func dbHealthCheck(db *gorm.DB) {
defer db.Close()
for { for {
count := 0 count := 0
var err error var err error
@@ -105,26 +79,27 @@ func dbHealthCheck(db *gorm.DB) {
if err != nil { if err != nil {
count++ count++
} }
time.Sleep(5 * time.Second) time.Sleep(1 * time.Second)
} }
if count > 3 { if count > 3 {
syscall.Kill(os.Getpid(), syscall.SIGTERM) panic(err)
} }
} }
} }
func Run(stopChan chan struct{}, wg *sync.WaitGroup) { func Run() {
defer wg.Done()
stopChan := make(chan struct{})
defer close(stopChan)
k8sClient := client.NewK8sClient() k8sClient := client.NewK8sClient()
ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)} ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)}
for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services, for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services,
Ingresses, Roles, RoleBindings, ClusterRoles, ClusterRoleBindings, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets, Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses} {
ControllerRevisions, ConfigMaps, Secrets} { ResourceControllers.runContoller(item)
ResourceControllers.runController(item, stopChan, wg)
} }
go dbHealthCheck(client.NewDBClient()) go dbHealthCheck(client.NewDBClient())
@@ -132,25 +107,14 @@ func Run(stopChan chan struct{}, wg *sync.WaitGroup) {
for { for {
for ctlName, controller := range ResourceControllers.Controllers { for ctlName, controller := range ResourceControllers.Controllers {
select { select {
case <-stopChan:
return
case _, isClose := <-controller.chanAlive(): case _, isClose := <-controller.chanAlive():
if !isClose { if !isClose {
glog.Errorf("controller %s have stopped, restart it", ctlName) glog.Errorf("controller %s have stopped, restart it", ctlName)
ResourceControllers.runController(ctlName, stopChan, wg) ResourceControllers.runContoller(ctlName)
} }
default: default:
time.Sleep(3 * time.Second) time.Sleep(5 * time.Second)
} }
} }
} }
} }
func GetLister(controller string) (interface{}, error) {
if ctl, ok := ResourceControllers.Controllers[controller]; ok {
if ctl.Lister() != nil {
return ctl.Lister(), nil
}
}
return nil, errors.New(fmt.Sprintf("lister of %s not alive", controller))
}

View File

@@ -1,157 +0,0 @@
/*
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 controllers
import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *SecretCtl) generateObject(item v1.Secret) *Secret {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
object := &Secret{
Name: item.Name,
Namespace: item.Namespace,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
DisplayName: displayName,
Entries: len(item.Data),
Type: string(item.Type),
}
return object
}
func (ctl *SecretCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *SecretCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Secret{}) {
db.DropTable(&Secret{})
}
db = db.CreateTable(&Secret{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
db.Create(obj)
}
}
ctl.informer.Run(stopChan)
}
func (ctl *SecretCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *SecretCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Secrets().Lister()
informer := informerFactory.Core().V1().Secrets().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Secret)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Create(mysqlObject)
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Secret)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Save(mysqlObject)
}
},
DeleteFunc: func(obj interface{}) {
var item Secret
object := obj.(*v1.Secret)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *SecretCtl) CountWithConditions(conditions string) int {
var object Secret
if strings.Contains(conditions, "namespace") {
conditions = ""
}
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *SecretCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var object Secret
var list []Secret
var total int
if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *SecretCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -69,25 +69,12 @@ func getExternalIp(item v1.Service) string {
} }
func generateSvcObject(item v1.Service) *Service { func generateSvcObject(item v1.Service) *Service {
var app string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
externalIp := getExternalIp(item) externalIp := getExternalIp(item)
serviceType := item.Spec.Type serviceType := item.Spec.Type
vip := item.Spec.ClusterIP vip := item.Spec.ClusterIP
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
}
ports := "" ports := ""
var nodePorts []string var nodePorts []string
@@ -95,8 +82,8 @@ func generateSvcObject(item v1.Service) *Service {
createTime = time.Now() createTime = time.Now()
} }
if len(item.Spec.ClusterIP) == 0 || item.Spec.ClusterIP == "None" { if len(item.Spec.ClusterIP) == 0 {
if len(item.Spec.Selector) != 0 { if len(item.Spec.Selector) == 0 {
serviceType = "Headless(Selector)" serviceType = "Headless(Selector)"
} }
@@ -131,16 +118,13 @@ func generateSvcObject(item v1.Service) *Service {
object := &Service{ object := &Service{
Namespace: namespace, Namespace: namespace,
Name: name, Name: name,
DisplayName: displayName,
ServiceType: string(serviceType), ServiceType: string(serviceType),
ExternalIp: externalIp, ExternalIp: externalIp,
VirtualIp: vip, VirtualIp: vip,
CreateTime: createTime, CreateTime: createTime,
Ports: ports, Ports: ports,
NodePorts: strings.Join(nodePorts, ","), NodePorts: strings.Join(nodePorts, ","),
Annotation: MapString{item.Annotations}, Annotation: Annotation{item.Annotations},
Labels: MapString{item.Labels},
App: app,
} }
return object return object
@@ -225,21 +209,14 @@ func (ctl *ServiceCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *ServiceCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *ServiceCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Service var list []Service
var object Service var object Service
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *ServiceCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,11 +30,6 @@ import (
func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset { func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset {
var app string var app string
var status string var status string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
availablePodNum := item.Status.ReadyReplicas availablePodNum := item.Status.ReadyReplicas
@@ -61,18 +56,8 @@ func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset {
} }
} }
statefulSetObject := &Statefulset{ statefulSetObject := &Statefulset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
Namespace: namespace, App: app, CreateTime: createTime, Status: status, Annotation: Annotation{item.Annotations}}
Name: name,
DisplayName: displayName,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
}
return statefulSetObject return statefulSetObject
} }
@@ -152,21 +137,14 @@ func (ctl *StatefulsetCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *StatefulsetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *StatefulsetCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Statefulset var list []Statefulset
var object Statefulset var object Statefulset
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *StatefulsetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -40,16 +40,9 @@ const (
func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass { func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
isDefault := false isDefault := false
provisioner := item.Provisioner
if item.Annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true" { if item.Annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true" {
isDefault = true isDefault = true
} }
@@ -58,14 +51,7 @@ func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass {
createTime = time.Now() createTime = time.Now()
} }
object := &StorageClass{ object := &StorageClass{Name: name, CreateTime: createTime, IsDefault: isDefault, Annotation: Annotation{item.Annotations}}
Name: name,
DisplayName: displayName,
CreateTime: createTime,
IsDefault: isDefault,
Annotation: MapString{item.Annotations},
Provisioner: provisioner,
}
return object return object
} }
@@ -234,14 +220,12 @@ func (ctl *StorageClassCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []StorageClass var list []StorageClass
var object StorageClass var object StorageClass
var total int var total int
if len(order) == 0 { order := "createTime desc"
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
@@ -254,8 +238,3 @@ func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging
return total, list, nil return total, list, nil
} }
func (ctl *StorageClassCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -19,9 +19,6 @@ package controllers
import ( import (
"time" "time"
"github.com/golang/glog"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"database/sql/driver" "database/sql/driver"
"encoding/json" "encoding/json"
"errors" "errors"
@@ -30,8 +27,6 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
appV1 "k8s.io/client-go/listers/apps/v1" appV1 "k8s.io/client-go/listers/apps/v1"
batchv1 "k8s.io/client-go/listers/batch/v1"
batchv1beta1 "k8s.io/client-go/listers/batch/v1beta1"
coreV1 "k8s.io/client-go/listers/core/v1" coreV1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/listers/extensions/v1beta1" "k8s.io/client-go/listers/extensions/v1beta1"
rbacV1 "k8s.io/client-go/listers/rbac/v1" rbacV1 "k8s.io/client-go/listers/rbac/v1"
@@ -40,19 +35,22 @@ import (
) )
const ( const (
resyncCircle = 600 resyncCircle = 600
Stopped = "stopped" Stopped = "stopped"
PvcPending = "pending" PvcPending = "Pending"
Running = "running" Running = "running"
Updating = "updating" Updating = "updating"
Failed = "failed" tablePods = "pods"
Unfinished = "unfinished" tableDeployments = "deployments"
Completed = "completed" tableDaemonsets = "daemonsets"
Pause = "pause" tableStatefulsets = "statefulsets"
Warning = "warning" tableNamespaces = "namespaces"
Error = "error" tableIngresses = "ingresses"
DisplayName = "displayName" tablePersistentVolumeClaim = "pvcs"
creator = "creator" tableRoles = "roles"
tableClusterRoles = "cluster_roles"
tableServices = "services"
tableStorageClasses = "storage_classes"
Pods = "pods" Pods = "pods"
Deployments = "deployments" Deployments = "deployments"
@@ -62,26 +60,17 @@ const (
Ingresses = "ingresses" Ingresses = "ingresses"
PersistentVolumeClaim = "persistent-volume-claims" PersistentVolumeClaim = "persistent-volume-claims"
Roles = "roles" Roles = "roles"
RoleBindings = "role-bindings"
ClusterRoles = "cluster-roles" ClusterRoles = "cluster-roles"
ClusterRoleBindings = "cluster-role-bindings"
Services = "services" Services = "services"
StorageClasses = "storage-classes" StorageClasses = "storage-classes"
Applications = "applications" Applications = "applications"
Jobs = "jobs"
Cronjobs = "cronjobs"
Nodes = "nodes"
Replicasets = "replicasets"
ControllerRevisions = "controllerrevisions"
ConfigMaps = "configmaps"
Secrets = "secrets"
) )
type MapString struct { type Annotation struct {
Values map[string]string `json:"values" gorm:"type:TEXT"` Values map[string]string `gorm:"type:TEXT"`
} }
func (annotation *MapString) Scan(val interface{}) error { func (annotation *Annotation) Scan(val interface{}) error {
switch val := val.(type) { switch val := val.(type) {
case string: case string:
return json.Unmarshal([]byte(val), annotation) return json.Unmarshal([]byte(val), annotation)
@@ -93,104 +82,92 @@ func (annotation *MapString) Scan(val interface{}) error {
return nil return nil
} }
func (annotation MapString) Value() (driver.Value, error) { func (annotation Annotation) Value() (driver.Value, error) {
bytes, err := json.Marshal(annotation) bytes, err := json.Marshal(annotation)
return string(bytes), err return string(bytes), err
} }
type Taints struct {
Values []v1.Taint `json:"values" gorm:"type:TEXT"`
}
func (taints *Taints) Scan(val interface{}) error {
switch val := val.(type) {
case string:
return json.Unmarshal([]byte(val), taints)
case []byte:
return json.Unmarshal(val, taints)
default:
return errors.New("not support")
}
return nil
}
func (taints Taints) Value() (driver.Value, error) {
bytes, err := json.Marshal(taints)
return string(bytes), err
}
type Deployment struct { type Deployment struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Namespace string `gorm:"primary_key" json:"namespace"`
Namespace string `gorm:"primary_key" json:"namespace"` App string `json:"app,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"` Available int32 `json:"available"`
Desire int32 `json:"desire"` Desire int32 `json:"desire"`
Status string `json:"status"` Status string `json:"status"`
Labels MapString `json:"labels"` Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"` UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"` }
func (Deployment) TableName() string {
return tableDeployments
} }
type Statefulset struct { type Statefulset struct {
Name string `gorm:"primary_key" json:"name,omitempty"` Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"` App string `json:"app,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"` Available int32 `json:"available"`
Desire int32 `json:"desire"` Desire int32 `json:"desire"`
Status string `json:"status"` Status string `json:"status"`
Annotation MapString `json:"annotations"` Annotation Annotation `json:"annotations"`
Labels MapString `json:"labels"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` }
func (Statefulset) TableName() string {
return tableStatefulsets
} }
type Daemonset struct { type Daemonset struct {
Name string `gorm:"primary_key" json:"name,omitempty"` Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"` App string `json:"app,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"` Available int32 `json:"available"`
Desire int32 `json:"desire"` Desire int32 `json:"desire"`
Status string `json:"status"` Status string `json:"status"`
NodeSelector string `json:"nodeSelector, omitempty"` NodeSelector string `json:"nodeSelector, omitempty"`
Annotation MapString `json:"annotations"` Annotation Annotation `json:"annotations"`
Labels MapString `json:"labels"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` }
func (Daemonset) TableName() string {
return tableDaemonsets
} }
type Service struct { type Service struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"` Namespace string `gorm:"primary_key" json:"namespace"`
ServiceType string `gorm:"column:type" json:"type,omitempty"` ServiceType string `json:"type,omitempty"`
App string `json:"app,omitempty"` VirtualIp string `json:"virtualIp,omitempty"`
VirtualIp string `gorm:"column:virtualIp" json:"virtualIp,omitempty"` ExternalIp string `json:"externalIp,omitempty"`
ExternalIp string `gorm:"column:externalIp" json:"externalIp,omitempty"`
Ports string `json:"ports,omitempty"` Ports string `json:"ports,omitempty"`
NodePorts string `gorm:"column:nodePorts" json:"nodePorts,omitempty"` NodePorts string `json:"nodePorts,omitempty"`
Annotation MapString `json:"annotations"` Annotation Annotation `json:"annotations"`
Labels MapString `json:"labels"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` }
func (Service) TableName() string {
return tableServices
} }
type Pvc struct { type Pvc struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Namespace string `gorm:"primary_key" json:"namespace"`
Namespace string `gorm:"primary_key" json:"namespace"` Status string `json:"status,omitempty"`
Status string `json:"status,omitempty"` Capacity string `json:"capacity,omitempty"`
Capacity string `json:"capacity,omitempty"` AccessMode string `json:"accessMode,omitempty"`
AccessMode string `gorm:"column:accessMode" json:"accessMode,omitempty"` Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Labels MapString `json:"labels"` StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` InUse bool `gorm:"-" json:"inUse"`
StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"` }
InUse bool `gorm:"column:inUse" json:"inUse"`
func (Pvc) TableName() string {
return tablePersistentVolumeClaim
} }
type ingressRule struct { type ingressRule struct {
@@ -201,77 +178,30 @@ type ingressRule struct {
} }
type Ingress struct { type Ingress struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Namespace string `gorm:"primary_key" json:"namespace"`
Namespace string `gorm:"primary_key" json:"namespace"` Ip string `json:"ip,omitempty"`
Ip string `json:"ip,omitempty"` Rules string `gorm:"type:text" json:"rules, omitempty"`
Rules string `gorm:"type:text" json:"rules, omitempty"` TlsTermination string `json:"tlsTermination,omitempty"`
TlsTermination string `gorm:"column:tlsTermination" json:"tlsTermination,omitempty"` Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Labels MapString `json:"labels"` }
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (Ingress) TableName() string {
return tableIngresses
} }
type Pod struct { type Pod struct {
// search and sort field, not seen in response Name string `gorm:"primary_key" json:"name"`
Name string `gorm:"primary_key" json:"-"` Namespace string `gorm:"primary_key" json:"namespace"`
Namespace string `gorm:"primary_key" json:"-"` Status string `json:"status,omitempty"`
Node string `json:"-"` Node string `json:"node,omitempty"`
OwnerKind string `gorm:"column:ownerKind" json:"-"` NodeIp string `json:"nodeIp,omitempty"`
OwnerName string `gorm:"column:ownerName" json:"-"` PodIp string `json:"podIp,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"-"` Containers Containers `gorm:"type:text" json:"containers,omitempty"`
Annotation Annotation `json:"annotations"`
// Kubernetes Standard Pod Specification RestartCount int `json:"restartCount"`
Kind string `json:"kind,omitempty"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
APIVersion string `gorm:"column:apiVersion" json:"apiVersion,omitempty"`
Spec v1.PodSpec `sql:"-" json:"spec,omitempty"`
Metadata v12.ObjectMeta `sql:"-" json:"metadata,omitempty"`
Status v1.PodStatus `sql:"-" json:"status,omitempty"`
// shadow field, used only for database
MetadataString string `gorm:"column:metadata;type:text" json:"-"`
SpecString string `gorm:"column:podSpec;type:text" json:"-"`
StatusString string `gorm:"column:status;type:text" json:"-"`
}
func (pod *Pod) AfterFind(scope *gorm.Scope) (err error) {
if err = json.Unmarshal([]byte(pod.SpecString), &pod.Spec); err != nil {
glog.Errorln(err)
}
if err = json.Unmarshal([]byte(pod.MetadataString), &pod.Metadata); err != nil {
glog.Errorln(err)
}
if err = json.Unmarshal([]byte(pod.StatusString), &pod.Status); err != nil {
glog.Errorln(err)
}
return nil
}
func (pod *Pod) BeforeSave(scope *gorm.Scope) (err error) {
if bytes, err := json.Marshal(pod.Spec); err == nil {
pod.SpecString = string(bytes)
} else {
glog.Errorln(err)
}
if bytes, err := json.Marshal(pod.Metadata); err == nil {
pod.MetadataString = string(bytes)
} else {
glog.Errorln(err)
}
if bytes, err := json.Marshal(pod.Status); err == nil {
pod.StatusString = string(bytes)
} else {
glog.Errorln(err)
}
return nil
} }
type Container struct { type Container struct {
@@ -300,119 +230,61 @@ func (containers Containers) Value() (driver.Value, error) {
return string(bytes), err return string(bytes), err
} }
func (Pod) TableName() string {
return tablePods
}
type Role struct { type Role struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Namespace string `gorm:"primary_key" json:"namespace"`
Namespace string `gorm:"primary_key" json:"namespace"` Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` }
func (Role) TableName() string {
return tableRoles
} }
type ClusterRole struct { type ClusterRole struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` }
func (ClusterRole) TableName() string {
return tableClusterRoles
} }
type Namespace struct { type Namespace struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Creator string `json:"creator,omitempty"`
Creator string `json:"creator,omitempty"` Status string `json:"status"`
Status string `json:"status"`
Descrition string `json:"description,omitempty"` Descrition string `json:"description,omitempty"`
Annotation MapString `json:"annotations"` Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Usage v1.ResourceList `gorm:"-" json:"usage,omitempty"` Usaeg v1.ResourceList `gorm:"-" json:"usage,omitempty"`
}
func (Namespace) TableName() string {
return tableNamespaces
} }
type StorageClass struct { type StorageClass struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` Creator string `json:"creator,omitempty"`
Creator string `json:"creator,omitempty"` Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` IsDefault bool `json:"default"`
IsDefault bool `json:"default"` Count int `json:"count"`
Count int `json:"count"`
Provisioner string `json:"provisioner"`
} }
type JobRevisions map[int]JobRevision func (StorageClass) TableName() string {
return tableStorageClasses
type JobRevision struct {
Status string `json:"status"`
Reasons []string `json:"reasons"`
Messages []string `json:"messages"`
Succeed int32 `json:"succeed"`
DesirePodNum int32 `json:"desire"`
Failed int32 `json:"failed"`
Uid string `json:"uid"`
StartTime time.Time `json:"start-time"`
CompletionTime time.Time `json:"completion-time"`
}
type Job struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Completed int32 `json:"completed"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
}
type CronJob struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Active int `json:"active"`
Schedule string `json:"schedule"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
LastScheduleTime *time.Time `gorm:"column:lastScheduleTime" json:"lastScheduleTime,omitempty"`
}
type Node struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Ip string `json:"ip"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
Taints Taints `json:"taints"`
Msg string `json:"msg"`
Role string `json:"role"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type ConfigMap struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Annotation MapString `json:"annotations"`
Entries string `gorm:"type:text" json:"entries"`
}
type Secret struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Annotation MapString `json:"annotations"`
Entries int `json:"entries"`
Type string `json:"type"`
} }
type Paging struct { type Paging struct {
Limit, Offset, Page int Limit, Offset int
} }
type Controller interface { type Controller interface {
@@ -423,9 +295,7 @@ type Controller interface {
initListerAndInformer() initListerAndInformer()
sync(stopChan chan struct{}) sync(stopChan chan struct{})
Name() string Name() string
CloseDB() ListWithConditions(condition string, paging *Paging) (int, interface{}, error)
Lister() interface{}
ListWithConditions(condition string, paging *Paging, order string) (int, interface{}, error)
} }
type CommonAttribute struct { type CommonAttribute struct {
@@ -446,11 +316,6 @@ func (ca *CommonAttribute) chanAlive() chan struct{} {
return ca.aliveChan return ca.aliveChan
} }
func (ca *CommonAttribute) CloseDB() {
ca.DB.Close()
}
type DeploymentCtl struct { type DeploymentCtl struct {
CommonAttribute CommonAttribute
lister appV1.DeploymentLister lister appV1.DeploymentLister
@@ -516,56 +381,3 @@ type ClusterRoleCtl struct {
informer cache.SharedIndexInformer informer cache.SharedIndexInformer
CommonAttribute CommonAttribute
} }
type ClusterRoleBindingCtl struct {
lister rbacV1.ClusterRoleBindingLister
informer cache.SharedIndexInformer
CommonAttribute
}
type RoleBindingCtl struct {
lister rbacV1.RoleBindingLister
informer cache.SharedIndexInformer
CommonAttribute
}
type JobCtl struct {
lister batchv1.JobLister
informer cache.SharedIndexInformer
CommonAttribute
}
type CronJobCtl struct {
lister batchv1beta1.CronJobLister
informer cache.SharedIndexInformer
CommonAttribute
}
type NodeCtl struct {
lister coreV1.NodeLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ReplicaSetCtl struct {
lister appV1.ReplicaSetLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ControllerRevisionCtl struct {
lister appV1.ControllerRevisionLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ConfigMapCtl struct {
lister coreV1.ConfigMapLister
informer cache.SharedIndexInformer
CommonAttribute
}
type SecretCtl struct {
lister coreV1.SecretLister
informer cache.SharedIndexInformer
CommonAttribute
}

View File

@@ -1,162 +1,18 @@
package iam package iam
import ( import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/rbac/v1" "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v12 "k8s.io/client-go/listers/rbac/v1"
"k8s.io/kubernetes/pkg/util/slice" "k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/models/controllers"
ksErr "kubesphere.io/kubesphere/pkg/util/errors"
) )
const ClusterRoleKind = "ClusterRole" const ClusterRoleKind = "ClusterRole"
// Get user list based on workspace role
func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings)
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
if err != nil {
return nil, err
}
names := make([]string, 0)
for _, subject := range workspaceRoleBinding.Subjects {
if subject.Kind == v1.UserKind {
names = append(names, subject.Name)
}
}
users, err := GetUsers(names)
if err != nil {
return nil, err
}
for i := 0; i < len(users); i++ {
users[i].WorkspaceRole = roleName
}
return users, nil
}
func GetUsers(names []string) ([]User, error) {
var users []User
if names == nil || len(names) == 0 {
return make([]User, 0), nil
}
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
if err != nil {
return nil, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return nil, err
}
if result.StatusCode > 200 {
return nil, ksErr.Wrap(data)
}
err = json.Unmarshal(data, &users)
if err != nil {
return nil, err
}
return users, nil
}
func GetUser(name string) (*User, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
if err != nil {
return nil, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return nil, err
}
if result.StatusCode > 200 {
return nil, ksErr.Wrap(data)
}
var user User
err = json.Unmarshal(data, &user)
if err != nil {
return nil, err
}
return &user, nil
}
// Get rules
func WorkspaceRoleRules(workspace string, roleName string) (*v1.ClusterRole, []Rule, error) {
clusterRoleName := fmt.Sprintf("system:%s:%s", workspace, roleName)
workspaceRole, err := GetClusterRole(clusterRoleName)
if err != nil {
return nil, nil, err
}
for i := 0; i < len(workspaceRole.Rules); i++ {
workspaceRole.Rules[i].ResourceNames = nil
}
rules := make([]Rule, 0)
for i := 0; i < len(WorkspaceRoleRuleMapping); i++ {
rule := Rule{Name: WorkspaceRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(WorkspaceRoleRuleMapping[i].Actions); j++ {
if rulesMatchesAction(workspaceRole.Rules, WorkspaceRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, WorkspaceRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
workspaceRole.Name = roleName
return workspaceRole, rules, nil
}
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) { func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {
clusterRoles, err := GetClusterRoles(username) clusterRoles, err := GetClusterRoles(username)
@@ -171,22 +27,18 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
} }
if requiredRule.Size() == 0 { if requiredRule.Size() == 0 {
if RulesMatchesRequired(clusterRules, v1.PolicyRule{ if ruleValidate(clusterRules, v1.PolicyRule{
Verbs: []string{"get"}, Verbs: []string{"get", "list"},
APIGroups: []string{"kubesphere.io"}, APIGroups: []string{""},
Resources: []string{"workspaces/namespaces"}, Resources: []string{"namespaces"},
}) { }) {
return true, nil, nil return true, nil, nil
} }
} else { } else if ruleValidate(clusterRules, requiredRule) {
return true, nil, nil
if RulesMatchesRequired(clusterRules, requiredRule) {
return true, nil, nil
}
} }
roles, err := GetRoles("", username) roles, err := GetRoles(username)
if err != nil { if err != nil {
return false, nil, err return false, nil, err
@@ -206,7 +58,7 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
namespaces = make([]string, 0) namespaces = make([]string, 0)
for namespace, rules := range rulesMapping { for namespace, rules := range rulesMapping {
if requiredRule.Size() == 0 || RulesMatchesRequired(rules, requiredRule) { if requiredRule.Size() == 0 || ruleValidate(rules, requiredRule) {
namespaces = append(namespaces, namespace) namespaces = append(namespaces, namespace)
} }
} }
@@ -214,55 +66,70 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
return false, namespaces, nil return false, namespaces, nil
} }
func GetRole(namespace string, name string) (*v1.Role, error) { func DeleteRoleBindings(username string) error {
lister, err := controllers.GetLister(controllers.Roles) k8s := client.NewK8sClient()
roleBindings, err := k8s.RbacV1().RoleBindings("").List(meta_v1.ListOptions{})
if err != nil { if err != nil {
return nil, err return err
} }
roleLister := lister.(v12.RoleLister) for _, roleBinding := range roleBindings.Items {
role, err := roleLister.Roles(namespace).Get(name)
if err != nil {
return nil, err
}
return role.DeepCopy(), nil
}
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings) length1 := len(roleBinding.Subjects)
if err != nil { for index, subject := range roleBinding.Subjects {
return nil, err if subject.Kind == v1.UserKind && subject.Name == username {
} roleBinding.Subjects = append(roleBinding.Subjects[:index], roleBinding.Subjects[index+1:]...)
index--
}
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister) length2 := len(roleBinding.Subjects)
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
if err != nil { if length2 == 0 {
return nil, err k8s.RbacV1().RoleBindings(roleBinding.Namespace).Delete(roleBinding.Name, &meta_v1.DeleteOptions{})
} } else if length2 < length1 {
k8s.RbacV1().RoleBindings(roleBinding.Namespace).Update(&roleBinding)
users := make([]string, 0)
for _, s := range clusterRoleBinding.Subjects {
if s.Kind == v1.UserKind && !slice.ContainsString(users, s.Name, nil) {
users = append(users, s.Name)
} }
} }
return users, nil
clusterRoleBindingList, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
for _, roleBinding := range clusterRoleBindingList.Items {
length1 := len(roleBinding.Subjects)
for index, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username {
roleBinding.Subjects = append(roleBinding.Subjects[:index], roleBinding.Subjects[index+1:]...)
index--
}
}
length2 := len(roleBinding.Subjects)
if length2 == 0 {
k8s.RbacV1().ClusterRoleBindings().Delete(roleBinding.Name, &meta_v1.DeleteOptions{})
} else if length2 < length1 {
k8s.RbacV1().ClusterRoleBindings().Update(&roleBinding)
}
}
return nil
}
func GetRole(namespace string, name string) (*v1.Role, error) {
k8s := client.NewK8sClient()
role, err := k8s.RbacV1().Roles(namespace).Get(name, meta_v1.GetOptions{})
if err != nil {
return nil, err
}
return role, nil
} }
func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) { func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings) k8s := client.NewK8sClient()
roleBindingList, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -270,9 +137,9 @@ func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
items := make([]v1.ClusterRoleBinding, 0) items := make([]v1.ClusterRoleBinding, 0)
for _, clusterRoleBinding := range clusterRoleBindings { for _, roleBinding := range roleBindingList.Items {
if clusterRoleBinding.RoleRef.Name == name { if roleBinding.RoleRef.Name == name {
items = append(items, *clusterRoleBinding) items = append(items, roleBinding)
} }
} }
@@ -280,15 +147,9 @@ func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
} }
func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) { func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) {
lister, err := controllers.GetLister(controllers.RoleBindings) k8s := client.NewK8sClient()
if err != nil { roleBindingList, err := k8s.RbacV1().RoleBindings(namespace).List(meta_v1.ListOptions{})
return nil, err
}
roleBindingLister := lister.(v12.RoleBindingLister)
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -296,9 +157,9 @@ func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) {
items := make([]v1.RoleBinding, 0) items := make([]v1.RoleBinding, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindingList.Items {
if roleBinding.RoleRef.Name == name { if roleBinding.RoleRef.Name == name {
items = append(items, *roleBinding) items = append(items, roleBinding)
} }
} }
@@ -306,61 +167,30 @@ func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) {
} }
func GetClusterRole(name string) (*v1.ClusterRole, error) { func GetClusterRole(name string) (*v1.ClusterRole, error) {
lister, err := controllers.GetLister(controllers.ClusterRoles) k8s := client.NewK8sClient()
role, err := k8s.RbacV1().ClusterRoles().Get(name, meta_v1.GetOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return role, nil
clusterRoleLister := lister.(v12.ClusterRoleLister)
role, err := clusterRoleLister.Get(name)
if err != nil {
return nil, err
}
return role.DeepCopy(), nil
} }
func GetRoles(namespace string, username string) ([]v1.Role, error) { func GetRoles(username string) ([]v1.Role, error) {
lister, err := controllers.GetLister(controllers.RoleBindings) k8s := client.NewK8sClient()
roleBindings, err := k8s.RbacV1().RoleBindings("").List(meta_v1.ListOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
roleBindingLister := lister.(v12.RoleBindingLister)
lister, err = controllers.GetLister(controllers.Roles)
if err != nil {
return nil, err
}
roleLister := lister.(v12.RoleLister)
lister, err = controllers.GetLister(controllers.ClusterRoles)
if err != nil {
return nil, err
}
clusterRoleLister := lister.(v12.ClusterRoleLister)
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
roles := make([]v1.Role, 0) roles := make([]v1.Role, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings.Items {
for _, subject := range roleBinding.Subjects { for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username { if subject.Kind == v1.UserKind && subject.Name == username {
if roleBinding.RoleRef.Kind == ClusterRoleKind { if roleBinding.RoleRef.Kind == ClusterRoleKind {
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name) clusterRole, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
if err == nil { if err == nil {
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules} var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
role.Namespace = roleBinding.Namespace role.Namespace = roleBinding.Namespace
@@ -375,9 +205,9 @@ func GetRoles(namespace string, username string) ([]v1.Role, error) {
} else { } else {
if subject.Kind == v1.UserKind && subject.Name == username { if subject.Kind == v1.UserKind && subject.Name == username {
role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name) rule, err := k8s.RbacV1().Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
if err == nil { if err == nil {
roles = append(roles, *role) roles = append(roles, *rule)
break break
} else if apierrors.IsNotFound(err) { } else if apierrors.IsNotFound(err) {
glog.Infoln(err.Error()) glog.Infoln(err.Error())
@@ -397,26 +227,10 @@ func GetRoles(namespace string, username string) ([]v1.Role, error) {
return roles, nil return roles, nil
} }
// Get cluster roles by username
func GetClusterRoles(username string) ([]v1.ClusterRole, error) { func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
k8s := client.NewK8sClient()
lister, err := controllers.GetLister(controllers.ClusterRoleBindings) clusterRoleBindings, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
lister, err = controllers.GetLister(controllers.ClusterRoles)
if err != nil {
return nil, err
}
clusterRoleLister := lister.(v12.ClusterRoleLister)
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -424,25 +238,20 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
roles := make([]v1.ClusterRole, 0) roles := make([]v1.ClusterRole, 0)
for _, roleBinding := range clusterRoleBindings { for _, roleBinding := range clusterRoleBindings.Items {
for _, subject := range roleBinding.Subjects { for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username { if subject.Kind == v1.UserKind && subject.Name == username {
if roleBinding.RoleRef.Kind == ClusterRoleKind { if roleBinding.RoleRef.Kind == ClusterRoleKind {
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name) role, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
if err == nil { if err == nil {
role = role.DeepCopy()
if role.Annotations == nil { if role.Annotations == nil {
role.Annotations = make(map[string]string, 0) role.Annotations = make(map[string]string, 0)
} }
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
if roleBinding.Annotations != nil &&
roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == roleBinding.RoleRef.Name {
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
}
roles = append(roles, *role) roles = append(roles, *role)
break break
} else if apierrors.IsNotFound(err) { } else if apierrors.IsNotFound(err) {
glog.Warning(err) glog.Infoln(err.Error())
break break
} else { } else {
return nil, err return nil, err
@@ -455,189 +264,34 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
return roles, nil return roles, nil
} }
func GetUserRules(username string) (map[string][]Rule, error) { func ruleValidate(rules []v1.PolicyRule, rule v1.PolicyRule) bool {
items := make(map[string][]Rule, 0) for _, apiGroup := range rule.APIGroups {
userRoles, err := GetRoles("", username) if len(rule.NonResourceURLs) == 0 {
for _, resource := range rule.Resources {
if err != nil { //if len(Rule.ResourceNames) == 0 {
return nil, err
}
rulesMapping := make(map[string][]v1.PolicyRule, 0) for _, verb := range rule.Verbs {
if !verbValidate(rules, apiGroup, "", resource, "", verb) {
for _, role := range userRoles { return false
rules := rulesMapping[role.Namespace]
if rules == nil {
rules = make([]v1.PolicyRule, 0)
}
rules = append(rules, role.Rules...)
rulesMapping[role.Namespace] = rules
}
for namespace, policyRules := range rulesMapping {
rules := convertToRules(policyRules)
if len(rules) > 0 {
items[namespace] = rules
}
}
return items, nil
}
func convertToRules(policyRules []v1.PolicyRule) []Rule {
rules := make([]Rule, 0)
for i := 0; i < (len(RoleRuleMapping)); i++ {
rule := Rule{Name: RoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(RoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(policyRules, RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules
}
func GetUserClusterRules(username string) ([]Rule, error) {
rules := make([]Rule, 0)
clusterRoles, err := GetClusterRoles(username)
if err != nil {
return nil, err
}
clusterRules := make([]v1.PolicyRule, 0)
for _, role := range clusterRoles {
clusterRules = append(clusterRules, role.Rules...)
}
for i := 0; i < (len(ClusterRoleRuleMapping)); i++ {
rule := Rule{Name: ClusterRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(clusterRules, ClusterRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func GetClusterRoleRules(name string) ([]Rule, error) {
clusterRole, err := GetClusterRole(name)
if err != nil {
return nil, err
}
rules := make([]Rule, 0)
for i := 0; i < len(ClusterRoleRuleMapping); i++ {
rule := Rule{Name: ClusterRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(clusterRole.Rules, ClusterRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func GetRoleRules(namespace string, name string) ([]Rule, error) {
role, err := GetRole(namespace, name)
if err != nil {
return nil, err
}
rules := make([]Rule, 0)
for i := 0; i < len(RoleRuleMapping); i++ {
rule := Rule{Name: RoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(RoleRuleMapping[i].Actions); j++ {
if rulesMatchesAction(role.Rules, RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func rulesMatchesAction(rules []v1.PolicyRule, action Action) bool {
for _, rule := range action.Rules {
if !RulesMatchesRequired(rules, rule) {
return false
}
}
return true
}
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
for _, rule := range rules {
if ruleMatchesRequired(rule, required) {
return true
}
}
return false
}
func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
if len(required.NonResourceURLs) == 0 {
for _, apiGroup := range required.APIGroups {
for _, resource := range required.Resources {
resources := strings.Split(resource, "/")
resource = resources[0]
var subsource string
if len(resources) > 1 {
subsource = resources[1]
}
if len(required.ResourceNames) == 0 {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
return false
}
}
} else {
for _, resourceName := range required.ResourceNames {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
return false
}
}
} }
} }
//} else {
// for _, resourceName := range Rule.ResourceNames {
// for _, verb := range Rule.Verbs {
// if !verbValidate(rules, apiGroup, "", resource, resourceName, verb) {
// return false
// }
// }
// }
//}
} }
} } else {
} else { for _, nonResourceURL := range rule.NonResourceURLs {
for _, apiGroup := range required.APIGroups { for _, verb := range rule.Verbs {
for _, nonResourceURL := range required.NonResourceURLs { if !verbValidate(rules, apiGroup, nonResourceURL, "", "", verb) {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
return false return false
} }
} }
@@ -647,94 +301,22 @@ func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
return true return true
} }
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool { func verbValidate(rules []v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, resourceName string, verb string) bool {
for _, rule := range rules {
if resource == "" { if slice.ContainsString(rule.APIGroups, apiGroup, nil) || slice.ContainsString(rule.APIGroups, v1.APIGroupAll, nil) {
return false if slice.ContainsString(rule.Verbs, verb, nil) || slice.ContainsString(rule.Verbs, v1.VerbAll, nil) {
} if nonResourceURL == "" {
if slice.ContainsString(rule.Resources, resource, nil) || slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.ResourceAll) { if resourceName == "" {
return false return true
} } else if slice.ContainsString(rule.ResourceNames, resourceName, nil) || slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
return true
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) { }
return false }
} } else if slice.ContainsString(rule.NonResourceURLs, nonResourceURL, nil) || slice.ContainsString(rule.NonResourceURLs, v1.NonResourceAll, nil) {
return true
combinedResource := resource }
}
if subresource != "" {
combinedResource = combinedResource + "/" + subresource
}
for _, res := range rule.Resources {
// match "*"
if res == v1.ResourceAll || res == combinedResource {
return true
}
// match "*/subresource"
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
return true
}
// match "resource/*"
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
return true
}
}
return false
}
func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
return false
}
if nonResourceURL == "" {
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
} else {
return ruleMatchesNonResource(rule, nonResourceURL)
}
}
func ruleMatchesNonResource(rule v1.PolicyRule, nonResourceURL string) bool {
if nonResourceURL == "" {
return false
}
for _, spec := range rule.NonResourceURLs {
if pathMatches(nonResourceURL, spec) {
return true
}
}
return false
}
func pathMatches(path, spec string) bool {
// Allow wildcard match
if spec == "*" {
return true
}
// Allow exact match
if spec == path {
return true
}
// Allow a trailing * subpath match
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
return true
}
return false
}
func hasString(slice []string, value string) bool {
for _, s := range slice {
if s == value {
return true
} }
} }
return false return false

File diff suppressed because it is too large Load Diff

161
pkg/models/iam/tools.go Normal file
View File

@@ -0,0 +1,161 @@
/*
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 iam
import (
"k8s.io/api/rbac/v1"
)
func GetUserRules(username string) (map[string][]Rule, error) {
items := make(map[string][]Rule, 0)
userRoles, err := GetRoles(username)
if err != nil {
return nil, err
}
rulesMapping := make(map[string][]v1.PolicyRule, 0)
for _, role := range userRoles {
rules := rulesMapping[role.Namespace]
if rules == nil {
rules = make([]v1.PolicyRule, 0)
}
rules = append(rules, role.Rules...)
rulesMapping[role.Namespace] = rules
}
for namespace, policyRules := range rulesMapping {
rules := convertToRules(policyRules)
if len(rules) > 0 {
items[namespace] = rules
}
}
return items, nil
}
func convertToRules(policyRules []v1.PolicyRule) []Rule {
rules := make([]Rule, 0)
for i := 0; i < (len(RoleRuleGroup)); i++ {
rule := Rule{Name: RoleRuleGroup[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(RoleRuleGroup[i].Actions)); j++ {
if actionValidate(policyRules, RoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleGroup[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules
}
func GetUserClusterRules(username string) ([]Rule, error) {
rules := make([]Rule, 0)
clusterRoles, err := GetClusterRoles(username)
if err != nil {
return nil, err
}
clusterRules := make([]v1.PolicyRule, 0)
for _, role := range clusterRoles {
clusterRules = append(clusterRules, role.Rules...)
}
for i := 0; i < (len(ClusterRoleRuleGroup)); i++ {
rule := Rule{Name: ClusterRoleRuleGroup[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleGroup[i].Actions)); j++ {
if actionValidate(clusterRules, ClusterRoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleGroup[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func GetClusterRoleRules(name string) ([]Rule, error) {
clusterRole, err := GetClusterRole(name)
if err != nil {
return nil, err
}
rules := make([]Rule, 0)
for i := 0; i < len(ClusterRoleRuleGroup); i++ {
rule := Rule{Name: ClusterRoleRuleGroup[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleGroup[i].Actions)); j++ {
if actionValidate(clusterRole.Rules, ClusterRoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleGroup[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func GetRoleRules(namespace string, name string) ([]Rule, error) {
role, err := GetRole(namespace, name)
if err != nil {
return nil, err
}
rules := make([]Rule, 0)
for i := 0; i < len(RoleRuleGroup); i++ {
rule := Rule{Name: RoleRuleGroup[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(RoleRuleGroup[i].Actions); j++ {
if actionValidate(role.Rules, RoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleGroup[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func actionValidate(rules []v1.PolicyRule, action Action) bool {
for _, rule := range action.Rules {
if !ruleValidate(rules, rule) {
return false
}
}
return true
}

View File

@@ -1,39 +0,0 @@
package iam
import (
"k8s.io/api/rbac/v1"
)
type Action struct {
Name string `json:"name"`
Rules []v1.PolicyRule `json:"rules"`
}
type Rule struct {
Name string `json:"name"`
Actions []Action `json:"actions"`
}
type SimpleRule struct {
Name string `json:"name"`
Actions []string `json:"actions"`
}
type User struct {
Username string `json:"username"`
Groups []string `json:"groups"`
Password string `json:"password,omitempty"`
AvatarUrl string `json:"avatar_url"`
Description string `json:"description"`
Email string `json:"email"`
LastLoginTime string `json:"last_login_time"`
Status int `json:"status"`
ClusterRole string `json:"cluster_role"`
ClusterRules []SimpleRule `json:"cluster_rules,omitempty"`
Roles map[string]string `json:"roles,omitempty"`
Rules map[string][]SimpleRule `json:"rules,omitempty"`
Role string `json:"role,omitempty"`
WorkspaceRoles map[string]string `json:"workspace_roles,omitempty"`
WorkspaceRole string `json:"workspace_role,omitempty"`
WorkspaceRules map[string][]SimpleRule `json:"workspace_rules,omitempty"`
}

View File

@@ -29,23 +29,15 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"crypto/tls"
"io/ioutil"
"net/http"
"time"
kubeclient "kubesphere.io/kubesphere/pkg/client" kubeclient "kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
) )
const ( const TYPE = "kubernetes.io/dockerconfigjson"
TYPE = "kubernetes.io/dockerconfigjson"
SECRET = "Secret" const SECRET = "Secret"
APIVERSION = "v1"
TYPEHARBOR = "harbor" const APIVERSION = "v1"
TYPEDOCKERHUB = "dockerhub"
TYPEDOCKERREGISTRY = "docker-registry"
)
type AuthInfo struct { type AuthInfo struct {
Username string `json:"username"` Username string `json:"username"`
@@ -53,50 +45,6 @@ type AuthInfo struct {
ServerHost string `json:"serverhost"` ServerHost string `json:"serverhost"`
} }
type DockerConfigEntry struct {
Username string `json:"username"`
Password string `json:"password"`
Auth string `json:"auth"`
}
type RegistryInfo struct {
user, password, registryType, url string
}
type dockerConfig map[string]map[string]DockerConfigEntry
type harborRepo struct {
RepoName string `json:"repository_name"`
}
type harborRepos struct {
Repos []harborRepo `json:"repository"`
}
type registryRepos struct {
Repositories []string
}
type registryTags struct {
Name string `json:"name"`
Tags []string `json:"tags"`
}
type dockerhubRepo struct {
RepoName string `json:"repo_name"`
}
type dockerhubRepos struct {
Repositories []dockerhubRepo `json:"results"`
}
type dockerhubTag struct {
TagName string `json:"name"`
}
type dockerhubTags struct {
Tags []dockerhubTag `json:"results"`
}
func NewAuthInfo(para Registries) *AuthInfo { func NewAuthInfo(para Registries) *AuthInfo {
return &AuthInfo{ return &AuthInfo{
@@ -492,237 +440,3 @@ func GetReisgtries(name string) (Registries, error) {
return reg, nil return reg, nil
} }
// by image secret to get registry'info, like username, password, registry url ...
func getRegistryInfo(namespace, registryName string) *RegistryInfo {
var registry RegistryInfo
k8sClient := kubeclient.NewK8sClient()
secret, err := k8sClient.CoreV1().Secrets(namespace).Get(registryName, meta_v1.GetOptions{})
if err != nil {
glog.Error(err)
return nil
}
registry.registryType = secret.Annotations["type"]
data := secret.Data[v1.DockerConfigJsonKey]
authsMap := make(dockerConfig)
err = json.Unmarshal(data, &authsMap)
if err != nil {
glog.Error(err)
return nil
}
for url, config := range authsMap["auths"] {
registry.url = url
registry.user = config.Username
registry.password = config.Password
break
}
return &registry
}
func ImageSearch(namespace, registryName, searchWord string) []string {
registry := getRegistryInfo(namespace, registryName)
if registry == nil {
return nil
}
switch registry.registryType {
case TYPEDOCKERHUB:
return searchDockerHub(registry.url, searchWord)
case TYPEDOCKERREGISTRY:
return searchDockerRegistry(registry.url, searchWord)
case TYPEHARBOR:
return searchHarbor(registry.url, registry.user, registry.password, searchWord)
}
return nil
}
func GetImageTags(namespace, registryName, imageName string) []string {
registry := getRegistryInfo(namespace, registryName)
if registry == nil {
return nil
}
switch registry.registryType {
case TYPEDOCKERHUB:
return getTagInDockerHub(registry.url, imageName)
case TYPEDOCKERREGISTRY:
return getTagInDockerRegistry(registry.url, imageName)
case TYPEHARBOR:
return getTagInHarbor(registry.url, registry.user, registry.password, imageName)
}
return nil
}
func httpGet(url, username, password string, insecure bool) ([]byte, error) {
var httpClient *http.Client
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
if insecure {
httpClient = &http.Client{}
} else {
req.SetBasicAuth(username, password)
tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
httpClient = &http.Client{Timeout: 20 * time.Second, Transport: tr}
}
resp, err := httpClient.Do(req)
if err != nil {
err := fmt.Errorf("Request to %s failed reason: %s ", url, err)
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest || err != nil {
return nil, err
}
return body, nil
}
func searchHarbor(url, username, password, searchWord string) []string {
url = strings.TrimSuffix(url, "/") + fmt.Sprintf("/api/search?q=%s", searchWord)
body, err := httpGet(url, username, password, false)
if err != nil || len(body) == 0 {
glog.Error(err)
return nil
}
var repos harborRepos
repoList := make([]string, 0, 100)
err = json.Unmarshal(body, &repos)
if err != nil {
glog.Error(err)
return nil
}
for _, repo := range repos.Repos {
repoList = append(repoList, repo.RepoName)
}
return repoList
}
func searchDockerRegistry(url, searchword string) []string {
url = strings.TrimSuffix(url, "/") + "/v2/_catalog"
body, err := httpGet(url, "", "", true)
if err != nil || len(body) == 0 {
glog.Error(err)
return nil
}
var repos registryRepos
err = json.Unmarshal(body, &repos)
if err != nil {
glog.Error(err)
return nil
}
repoList := make([]string, 0, 100)
for _, repo := range repos.Repositories {
if strings.HasPrefix(repo, searchword) {
repoList = append(repoList, repo)
}
}
return repoList
}
func searchDockerHub(url, searchWord string) []string {
url = fmt.Sprintf("https://hub.docker.com/v2/search/repositories/?page=1&query=%s&page_size=50", searchWord)
body, err := httpGet(url, "", "", true)
if err != nil || len(body) == 0 {
glog.Error(err)
return nil
}
var repos dockerhubRepos
err = json.Unmarshal(body, &repos)
if err != nil {
glog.Error(err)
return nil
}
repoList := make([]string, 0, 50)
for _, repo := range repos.Repositories {
repoList = append(repoList, repo.RepoName)
}
return repoList
}
func getTagInHarbor(url, username, password, imageName string) []string {
url = strings.TrimSuffix(url, "/") + fmt.Sprintf("/api/repositories/%s/tags", imageName)
body, err := httpGet(url, username, password, false)
if err != nil || len(body) == 0 {
glog.Error(err)
return nil
}
var tagList []string
err = json.Unmarshal(body, &tagList)
if err != nil {
glog.Error(err)
return nil
}
return tagList
}
func getTagInDockerRegistry(url, imageName string) []string {
url = strings.TrimSuffix(url, "/") + fmt.Sprintf("/v2/%s/tags/list", imageName)
body, err := httpGet(url, "", "", true)
if err != nil || len(body) == 0 {
glog.Error(err)
return nil
}
var tags registryTags
err = json.Unmarshal(body, &tags)
if err != nil {
glog.Error(err)
return nil
}
return tags.Tags
}
func getTagInDockerHub(url, imageName string) []string {
if !strings.Contains(imageName, "/") {
imageName = fmt.Sprintf("library/%s", imageName)
}
url = fmt.Sprintf("https://hub.docker.com/v2/repositories/%s/tags/?page=1&page_size=200", imageName)
body, err := httpGet(url, "", "", true)
if err != nil || len(body) == 0 {
glog.Error(err)
return nil
}
var tags dockerhubTags
err = json.Unmarshal(body, &tags)
if err != nil {
glog.Error(err)
return nil
}
tagList := make([]string, 0, 200)
for _, tag := range tags.Tags {
tagList = append(tagList, tag.TagName)
}
return tagList
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubectl package models
import ( import (
"fmt" "fmt"

0
pkg/models/metrics/containers.go Executable file → Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,200 +0,0 @@
/*
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 metrics
import (
"strings"
)
func MakeWorkloadPromQL(metricName, nsName, wlFilter string) string {
if wlFilter == "" {
wlFilter = ".*"
}
var promql = RulePromQLTmplMap[metricName]
promql = strings.Replace(promql, "$2", nsName, -1)
promql = strings.Replace(promql, "$3", wlFilter, -1)
return promql
}
func MakeSpecificWorkloadRule(wkKind, wkName, namespace string) string {
var rule = PodInfoRule
if namespace == "" {
namespace = ".*"
}
// alertnatives values: Deployment StatefulSet ReplicaSet DaemonSet
wkKind = strings.ToLower(wkKind)
switch wkKind {
case "deployment":
wkKind = ReplicaSet
if wkName != "" {
wkName = "~\"^" + wkName + `-(\\w)+$"`
} else {
wkName = "~\".*\""
}
rule = strings.Replace(rule, "$1", wkKind, -1)
rule = strings.Replace(rule, "$2", wkName, -1)
rule = strings.Replace(rule, "$3", namespace, -1)
return rule
case "replicaset":
wkKind = ReplicaSet
case "statefulset":
wkKind = StatefulSet
case "daemonset":
wkKind = DaemonSet
}
if wkName == "" {
wkName = "~\".*\""
} else {
wkName = "\"" + wkName + "\""
}
rule = strings.Replace(rule, "$1", wkKind, -1)
rule = strings.Replace(rule, "$2", wkName, -1)
rule = strings.Replace(rule, "$3", namespace, -1)
return rule
}
func MakeAllWorkspacesPromQL(metricsName, nsFilter string) string {
var promql = RulePromQLTmplMap[metricsName]
nsFilter = "!~\"" + nsFilter + "\""
promql = strings.Replace(promql, "$1", nsFilter, -1)
return promql
}
func MakeSpecificWorkspacePromQL(metricsName, nsFilter string) string {
var promql = RulePromQLTmplMap[metricsName]
nsFilter = "=~\"" + nsFilter + "\""
promql = strings.Replace(promql, "$1", nsFilter, -1)
return promql
}
func MakeContainerPromQL(nsName, nodeId, podName, containerName, metricName, containerFilter string) string {
var promql string
if nsName != "" {
// get container metrics from namespace-pod
promql = RulePromQLTmplMap[metricName]
promql = strings.Replace(promql, "$1", nsName, -1)
} else {
// get container metrics from node-pod
promql = RulePromQLTmplMap[metricName+"_node"]
promql = strings.Replace(promql, "$1", nodeId, -1)
}
promql = strings.Replace(promql, "$2", podName, -1)
if containerName == "" {
if containerFilter == "" {
containerFilter = ".*"
}
promql = strings.Replace(promql, "$3", containerFilter, -1)
} else {
promql = strings.Replace(promql, "$3", containerName, -1)
}
return promql
}
func MakePodPromQL(metricName, nsName, nodeID, podName, podFilter string) string {
if podFilter == "" {
podFilter = ".*"
}
var promql = ""
if nsName != "" {
// get pod metrics by namespace
if podName != "" {
// specific pod
promql = RulePromQLTmplMap[metricName]
promql = strings.Replace(promql, "$1", nsName, -1)
promql = strings.Replace(promql, "$2", podName, -1)
} else {
// all pods
metricName += "_all"
promql = RulePromQLTmplMap[metricName]
promql = strings.Replace(promql, "$1", nsName, -1)
promql = strings.Replace(promql, "$2", podFilter, -1)
}
} else if nodeID != "" {
// get pod metrics by nodeid
metricName += "_node"
promql = RulePromQLTmplMap[metricName]
promql = strings.Replace(promql, "$3", nodeID, -1)
if podName != "" {
// specific pod
promql = strings.Replace(promql, "$2", podName, -1)
} else {
promql = strings.Replace(promql, "$2", podFilter, -1)
}
}
return promql
}
func MakeNamespacePromQL(nsName string, nsFilter string, metricsName string) string {
var recordingRule = RulePromQLTmplMap[metricsName]
if nsName != "" {
nsFilter = nsName
} else {
if nsFilter == "" {
nsFilter = ".*"
}
}
recordingRule = strings.Replace(recordingRule, "$1", nsFilter, -1)
return recordingRule
}
// cluster rule
func MakeClusterRule(metricsName string) string {
var rule = RulePromQLTmplMap[metricsName]
return rule
}
// node rule
func MakeNodeRule(nodeID string, nodesFilter string, metricsName string) string {
var rule = RulePromQLTmplMap[metricsName]
if nodesFilter == "" {
nodesFilter = ".*"
}
if strings.Contains(metricsName, "disk_size") || strings.Contains(metricsName, "pod") || strings.Contains(metricsName, "usage") || strings.Contains(metricsName, "inode") || strings.Contains(metricsName, "load") {
// disk size promql
if nodeID != "" {
nodesFilter = "{" + "node" + "=" + "\"" + nodeID + "\"" + "}"
} else {
nodesFilter = "{" + "node" + "=~" + "\"" + nodesFilter + "\"" + "}"
}
rule = strings.Replace(rule, "$1", nodesFilter, -1)
} else {
// cpu, memory, network, disk_iops rules
if nodeID != "" {
// specific node
rule = rule + "{" + "node" + "=" + "\"" + nodeID + "\"" + "}"
} else {
// all nodes or specific nodes filted with re2 syntax
rule = rule + "{" + "node" + "=~" + "\"" + nodesFilter + "\"" + "}"
}
}
return rule
}

View File

@@ -1,579 +0,0 @@
/*
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 metrics
const (
ResultTypeVector = "vector"
ResultTypeMatrix = "matrix"
MetricStatus = "status"
MetricStatusError = "error"
MetricStatusSuccess = "success"
ResultItemMetric = "metric"
ResultItemMetricResource = "resource"
ResultItemValue = "value"
ResultItemValues = "values"
ResultSortTypeDesc = "desc"
ResultSortTypeAsce = "asce"
)
const (
MetricNameWorkloadCount = "workload_count"
MetricNameNamespacePodCount = "namespace_pod_count"
MetricNameWorkspaceAllOrganizationCount = "workspace_all_organization_count"
MetricNameWorkspaceAllAccountCount = "workspace_all_account_count"
MetricNameWorkspaceAllProjectCount = "workspace_all_project_count"
MetricNameWorkspaceAllDevopsCount = "workspace_all_devops_project_count"
MetricNameClusterAllProjectCount = "cluster_namespace_count"
MetricNameWorkspaceNamespaceCount = "workspace_namespace_count"
MetricNameWorkspaceDevopsCount = "workspace_devops_project_count"
MetricNameWorkspaceMemberCount = "workspace_member_count"
MetricNameWorkspaceRoleCount = "workspace_role_count"
MetricNameComponentOnLine = "component_online_count"
MetricNameComponentLine = "component_count"
)
const (
WorkspaceResourceKindOrganization = "organization"
WorkspaceResourceKindAccount = "account"
WorkspaceResourceKindNamespace = "namespace"
WorkspaceResourceKindDevops = "devops"
WorkspaceResourceKindMember = "member"
WorkspaceResourceKindRole = "role"
)
const (
MetricLevelCluster = "cluster"
MetricLevelClusterWorkspace = "cluster_workspace"
MetricLevelNode = "node"
MetricLevelWorkspace = "workspace"
MetricLevelNamespace = "namespace"
MetricLevelPod = "pod"
MetricLevelPodName = "pod_name"
MetricLevelContainer = "container"
MetricLevelContainerName = "container_name"
MetricLevelWorkload = "workload"
)
const (
ReplicaSet = "ReplicaSet"
StatefulSet = "StatefulSet"
DaemonSet = "DaemonSet"
Deployment = "Deployment"
)
const (
NodeStatusRule = `kube_node_status_condition{condition="Ready"} > 0`
PodInfoRule = `kube_pod_info{created_by_kind="$1",created_by_name=$2,namespace="$3"}`
NamespaceLabelRule = `kube_namespace_labels`
WorkloadReplicaSetOwnerRule = `kube_pod_owner{namespace="$1", owner_name!="<none>", owner_kind="ReplicaSet"}`
WorkspaceNamespaceLabelRule = `sum(kube_namespace_labels{label_kubesphere_io_workspace != ""}) by (label_kubesphere_io_workspace)`
ExcludedVirtualNetworkInterfaces = `interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)"`
)
const (
WorkspaceJoinedKey = "label_kubesphere_io_workspace"
)
type MetricMap map[string]string
var ClusterMetricsNames = []string{
"cluster_cpu_utilisation",
"cluster_cpu_usage",
"cluster_cpu_total",
"cluster_memory_utilisation",
"cluster_memory_available",
"cluster_memory_total",
"cluster_memory_usage_wo_cache",
"cluster_net_utilisation",
"cluster_net_bytes_transmitted",
"cluster_net_bytes_received",
"cluster_disk_read_iops",
"cluster_disk_write_iops",
"cluster_disk_read_throughput",
"cluster_disk_write_throughput",
"cluster_disk_size_usage",
"cluster_disk_size_utilisation",
"cluster_disk_size_capacity",
"cluster_disk_size_available",
"cluster_disk_inode_total",
"cluster_disk_inode_usage",
"cluster_disk_inode_utilisation",
"cluster_node_online",
"cluster_node_offline",
"cluster_node_total",
"cluster_pod_count",
"cluster_pod_quota",
"cluster_pod_utilisation",
"cluster_pod_running_count",
"cluster_pod_succeeded_count",
"cluster_pod_abnormal_count",
"cluster_ingresses_extensions_count",
"cluster_cronjob_count",
"cluster_pvc_count",
"cluster_daemonset_count",
"cluster_deployment_count",
"cluster_endpoint_count",
"cluster_hpa_count",
"cluster_job_count",
"cluster_statefulset_count",
"cluster_replicaset_count",
"cluster_service_count",
"cluster_secret_count",
"cluster_namespace_count",
"cluster_load1",
"cluster_load5",
"cluster_load15",
}
var NodeMetricsNames = []string{
"node_cpu_utilisation",
"node_cpu_total",
"node_cpu_usage",
"node_memory_utilisation",
"node_memory_usage_wo_cache",
"node_memory_available",
"node_memory_total",
"node_net_utilisation",
"node_net_bytes_transmitted",
"node_net_bytes_received",
"node_disk_read_iops",
"node_disk_write_iops",
"node_disk_read_throughput",
"node_disk_write_throughput",
"node_disk_size_capacity",
"node_disk_size_available",
"node_disk_size_usage",
"node_disk_size_utilisation",
"node_disk_inode_total",
"node_disk_inode_usage",
"node_disk_inode_utilisation",
"node_pod_count",
"node_pod_quota",
"node_pod_utilisation",
"node_pod_running_count",
"node_pod_succeeded_count",
"node_pod_abnormal_count",
"node_load1",
"node_load5",
"node_load15",
}
var WorkspaceMetricsNames = []string{
"workspace_cpu_usage",
"workspace_memory_usage",
"workspace_memory_usage_wo_cache",
"workspace_net_bytes_transmitted",
"workspace_net_bytes_received",
"workspace_pod_count",
"workspace_pod_running_count",
"workspace_pod_succeeded_count",
"workspace_pod_abnormal_count",
"workspace_ingresses_extensions_count",
"workspace_cronjob_count",
"workspace_pvc_count",
"workspace_daemonset_count",
"workspace_deployment_count",
"workspace_endpoint_count",
"workspace_hpa_count",
"workspace_job_count",
"workspace_statefulset_count",
"workspace_replicaset_count",
"workspace_service_count",
"workspace_secret_count",
"workspace_all_project_count",
}
var NamespaceMetricsNames = []string{
"namespace_cpu_usage",
"namespace_memory_usage",
"namespace_memory_usage_wo_cache",
"namespace_net_bytes_transmitted",
"namespace_net_bytes_received",
"namespace_pod_count",
"namespace_pod_running_count",
"namespace_pod_succeeded_count",
"namespace_pod_abnormal_count",
"namespace_configmap_count_used",
"namespace_jobs_batch_count_used",
"namespace_roles_count_used",
"namespace_memory_limit_used",
"namespace_pvc_used",
"namespace_memory_request_used",
"namespace_pvc_count_used",
"namespace_cronjobs_batch_count_used",
"namespace_ingresses_extensions_count_used",
"namespace_cpu_limit_used",
"namespace_storage_request_used",
"namespace_deployment_count_used",
"namespace_pod_count_used",
"namespace_statefulset_count_used",
"namespace_daemonset_count_used",
"namespace_secret_count_used",
"namespace_service_count_used",
"namespace_cpu_request_used",
"namespace_service_loadbalancer_used",
"namespace_configmap_count_hard",
"namespace_jobs_batch_count_hard",
"namespace_roles_count_hard",
"namespace_memory_limit_hard",
"namespace_pvc_hard",
"namespace_memory_request_hard",
"namespace_pvc_count_hard",
"namespace_cronjobs_batch_count_hard",
"namespace_ingresses_extensions_count_hard",
"namespace_cpu_limit_hard",
"namespace_storage_request_hard",
"namespace_deployment_count_hard",
"namespace_pod_count_hard",
"namespace_statefulset_count_hard",
"namespace_daemonset_count_hard",
"namespace_secret_count_hard",
"namespace_service_count_hard",
"namespace_cpu_request_hard",
"namespace_service_loadbalancer_hard",
"namespace_cronjob_count",
"namespace_pvc_count",
"namespace_daemonset_count",
"namespace_deployment_count",
"namespace_endpoint_count",
"namespace_hpa_count",
"namespace_job_count",
"namespace_statefulset_count",
"namespace_replicaset_count",
"namespace_service_count",
"namespace_secret_count",
"namespace_ingresses_extensions_count",
}
var PodMetricsNames = []string{
"pod_cpu_usage",
"pod_memory_usage",
"pod_memory_usage_wo_cache",
"pod_net_bytes_transmitted",
"pod_net_bytes_received",
}
var WorkloadMetricsNames = []string{
"workload_pod_cpu_usage",
"workload_pod_memory_usage",
"workload_pod_memory_usage_wo_cache",
"workload_pod_net_bytes_transmitted",
"workload_pod_net_bytes_received",
"workload_deployment_replica",
"workload_deployment_replica_available",
"workload_statefulset_replica",
"workload_statefulset_replica_available",
"workload_daemonset_replica",
"workload_daemonset_replica_available",
}
var ContainerMetricsNames = []string{
"container_cpu_usage",
"container_memory_usage",
"container_memory_usage_wo_cache",
//"container_net_bytes_transmitted",
//"container_net_bytes_received",
}
var RulePromQLTmplMap = MetricMap{
//cluster
"cluster_cpu_utilisation": ":node_cpu_utilisation:avg1m",
"cluster_cpu_usage": `:node_cpu_utilisation:avg1m * sum(node:node_num_cpu:sum)`,
"cluster_cpu_total": "sum(node:node_num_cpu:sum)",
"cluster_memory_utilisation": ":node_memory_utilisation:",
"cluster_memory_available": "sum(node:node_memory_bytes_available:sum)",
"cluster_memory_total": "sum(node:node_memory_bytes_total:sum)",
"cluster_memory_usage_wo_cache": "sum(node:node_memory_bytes_total:sum) - sum(node:node_memory_bytes_available:sum)",
"cluster_net_utilisation": ":node_net_utilisation:sum_irate",
"cluster_net_bytes_transmitted": "sum(node:node_net_bytes_transmitted:sum_irate)",
"cluster_net_bytes_received": "sum(node:node_net_bytes_received:sum_irate)",
"cluster_disk_read_iops": "sum(node:data_volume_iops_reads:sum)",
"cluster_disk_write_iops": "sum(node:data_volume_iops_writes:sum)",
"cluster_disk_read_throughput": "sum(node:data_volume_throughput_bytes_read:sum)",
"cluster_disk_write_throughput": "sum(node:data_volume_throughput_bytes_written:sum)",
"cluster_disk_size_usage": `sum(max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
"cluster_disk_size_utilisation": `1 - sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node)) / sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
"cluster_disk_size_capacity": `sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
"cluster_disk_size_available": `sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
"cluster_disk_inode_total": `sum(node:disk_inodes_total:)`,
"cluster_disk_inode_usage": `sum(node:disk_inodes_total:) - sum(node:disk_inodes_free:)`,
"cluster_disk_inode_utilisation": `1 - sum(node:disk_inodes_free:) / sum(node:disk_inodes_total:)`,
"cluster_namespace_count": `count(kube_namespace_annotations)`,
// cluster_pod_count = cluster_pod_running_count + cluster_pod_succeeded_count + cluster_pod_abnormal_count
"cluster_pod_count": `sum((kube_pod_status_scheduled{condition="true"} > 0) * on (pod) group_left(node) (sum by (node, pod) (kube_pod_info)) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_quota": `sum(kube_node_status_capacity_pods unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_utilisation": `sum(kube_pod_info unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)) / sum(kube_node_status_capacity_pods unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_running_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Succeeded"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_succeeded_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Running"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_abnormal_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Succeeded|Running"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_node_online": `sum(kube_node_status_condition{condition="Ready",status="true"})`,
"cluster_node_offline": `sum(kube_node_status_condition{condition="Ready",status=~"unknown|false"})`,
"cluster_node_total": `sum(kube_node_status_condition{condition="Ready"})`,
"cluster_ingresses_extensions_count": `sum(kube_ingress_labels)`,
"cluster_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/configmaps"}) by (resource, type)`,
"cluster_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/jobs.batch"}) by (resource, type)`,
"cluster_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/roles.rbac.authorization.k8s.io"}) by (resource, type)`,
"cluster_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="limits.memory"}) by (resource, type)`,
"cluster_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="persistentvolumeclaims"}) by (resource, type)`,
"cluster_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.memory"}) by (resource, type)`,
"cluster_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/persistentvolumeclaims"}) by (resource, type)`,
"cluster_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/cronjobs.batch"}) by (resource, type)`,
"cluster_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/ingresses.extensions"}) by (resource, type)`,
"cluster_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="limits.cpu"}) by (resource, type)`,
"cluster_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.storage"}) by (resource, type)`,
"cluster_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/deployments.apps"}) by (resource, type)`,
"cluster_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/pods"}) by (resource, type)`,
"cluster_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/statefulsets.apps"}) by (resource, type)`,
"cluster_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/daemonsets.apps"}) by (resource, type)`,
"cluster_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/secrets"}) by (resource, type)`,
"cluster_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/services"}) by (resource, type)`,
"cluster_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.cpu"}) by (resource, type)`,
"cluster_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="services.loadbalancers"}) by (resource, type)`,
"cluster_cronjob_count": `sum(kube_cronjob_labels)`,
"cluster_pvc_count": `sum(kube_persistentvolumeclaim_info)`,
"cluster_daemonset_count": `sum(kube_daemonset_labels)`,
"cluster_deployment_count": `sum(kube_deployment_labels)`,
"cluster_endpoint_count": `sum(kube_endpoint_labels)`,
"cluster_hpa_count": `sum(kube_hpa_labels)`,
"cluster_job_count": `sum(kube_job_labels)`,
"cluster_statefulset_count": `sum(kube_statefulset_labels)`,
"cluster_replicaset_count": `count(kube_replicaset_created)`,
"cluster_service_count": `sum(kube_service_info)`,
"cluster_secret_count": `sum(kube_secret_info)`,
"cluster_pv_count": `sum(kube_persistentvolume_labels)`,
"cluster_load1": `sum(node_load1{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
"cluster_load5": `sum(node_load5{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
"cluster_load15": `sum(node_load15{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
//node
"node_cpu_utilisation": "node:node_cpu_utilisation:avg1m",
"node_cpu_total": "node:node_num_cpu:sum",
"node_memory_utilisation": "node:node_memory_utilisation:",
"node_memory_available": "node:node_memory_bytes_available:sum",
"node_memory_total": "node:node_memory_bytes_total:sum",
"node_memory_usage_wo_cache": "node:node_memory_bytes_total:sum$1 - node:node_memory_bytes_available:sum$1",
"node_net_utilisation": "node:node_net_utilisation:sum_irate",
"node_net_bytes_transmitted": "node:node_net_bytes_transmitted:sum_irate",
"node_net_bytes_received": "node:node_net_bytes_received:sum_irate",
"node_disk_read_iops": "node:data_volume_iops_reads:sum",
"node_disk_write_iops": "node:data_volume_iops_writes:sum",
"node_disk_read_throughput": "node:data_volume_throughput_bytes_read:sum",
"node_disk_write_throughput": "node:data_volume_throughput_bytes_written:sum",
"node_disk_size_capacity": `max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
"node_disk_size_available": `max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
"node_disk_size_usage": `max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
"node_disk_size_utilisation": `max(((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) / node_filesystem_size{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
"node_disk_inode_total": `node:disk_inodes_total:$1`,
"node_disk_inode_usage": `node:disk_inodes_total:$1 - node:disk_inodes_free:$1`,
"node_disk_inode_utilisation": `(1 - (node:disk_inodes_free:$1 / node:disk_inodes_total:$1))`,
"node_pod_count": `sum by (node) ((kube_pod_status_scheduled{condition="true"} > 0) * on (pod) group_left(node) kube_pod_info$1 unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"node_pod_quota": `sum(kube_node_status_capacity_pods$1) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_utilisation": `(sum(kube_pod_info$1) by (node) / sum(kube_node_status_capacity_pods$1) by (node)) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_running_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Succeeded"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_succeeded_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Running"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_abnormal_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Succeeded|Running"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
// without log node: unless on(node) kube_node_labels{label_role="log"}
"node_cpu_usage": `node:node_cpu_utilisation:avg1m$1 * node:node_num_cpu:sum$1`,
"node_load1": `sum by (node) (node_load1{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
"node_load5": `sum by (node) (node_load5{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
"node_load15": `sum by (node) (node_load15{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
//namespace
"namespace_cpu_usage": `namespace:container_cpu_usage_seconds_total:sum_rate{namespace!="", namespace=~"$1"} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_usage": `namespace:container_memory_usage_bytes:sum{namespace!="", namespace=~"$1"} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_usage_wo_cache": `namespace:container_memory_usage_bytes_wo_cache:sum{namespace!="", namespace=~"$1"}* on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_net_bytes_transmitted": `sum by (namespace) (irate(container_network_transmit_bytes_total{namespace!="", namespace=~"$1", pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))* on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_net_bytes_received": `sum by (namespace) (irate(container_network_receive_bytes_total{namespace!="", namespace=~"$1", pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count": `sum(kube_pod_status_phase{phase!~"Failed|Succeeded", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_running_count": `sum(kube_pod_status_phase{phase="Running", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_succeeded_count": `sum(kube_pod_status_phase{phase="Succeeded", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_abnormal_count": `sum(kube_pod_status_phase{phase=~"Failed|Pending|Unknown", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_configmap_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_jobs_batch_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_roles_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_limit_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjobs_batch_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_limit_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_storage_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_loadbalancer_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjob_count": `sum(kube_cronjob_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count": `sum(kube_persistentvolumeclaim_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count": `sum(kube_daemonset_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count": `sum(kube_deployment_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_endpoint_count": `sum(kube_endpoint_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_hpa_count": `sum(kube_hpa_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_job_count": `sum(kube_job_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count": `sum(kube_statefulset_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_replicaset_count": `count(kube_replicaset_created{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count": `sum(kube_service_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count": `sum(kube_secret_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count": `sum(kube_ingress_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
// pod
"pod_cpu_usage": `sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""}[5m])) by (namespace, pod_name)`,
"pod_memory_usage": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""}) by (namespace, pod_name)`,
"pod_memory_usage_wo_cache": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""} - container_memory_cache{job="kubelet", namespace="$1", pod_name!="", pod_name="$2",image!=""}) by (namespace, pod_name)`,
"pod_net_bytes_transmitted": `sum by (namespace, pod_name) (irate(container_network_transmit_bytes_total{namespace="$1", pod_name!="", pod_name="$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
"pod_net_bytes_received": `sum by (namespace, pod_name) (irate(container_network_receive_bytes_total{namespace="$1", pod_name!="", pod_name="$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
"pod_cpu_usage_all": `sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""}[5m])) by (namespace, pod_name)`,
"pod_memory_usage_all": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""}) by (namespace, pod_name)`,
"pod_memory_usage_wo_cache_all": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""} - container_memory_cache{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""}) by (namespace, pod_name)`,
"pod_net_bytes_transmitted_all": `sum by (namespace, pod_name) (irate(container_network_transmit_bytes_total{namespace="$1", pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
"pod_net_bytes_received_all": `sum by (namespace, pod_name) (irate(container_network_receive_bytes_total{namespace="$1", pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
"pod_cpu_usage_node": `sum by (node, pod_name) (irate(container_cpu_usage_seconds_total{job="kubelet",pod_name!="", pod_name=~"$2", image!=""}[5m]) * on (namespace, pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
"pod_memory_usage_node": `sum by (node, pod_name) (container_memory_usage_bytes{job="kubelet",pod_name!="", pod_name=~"$2", image!=""} * on (namespace, pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
"pod_memory_usage_wo_cache_node": `sum by (node, pod_name) ((container_memory_usage_bytes{job="kubelet",pod_name!="", pod_name=~"$2", image!=""} - container_memory_cache{job="kubelet",pod_name!="", pod_name=~"$2", image!=""}) * on (namespace, pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
"pod_net_bytes_transmitted_node": `sum by (node, pod_name) (irate(container_network_transmit_bytes_total{pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
"pod_net_bytes_received_node": `sum by (node, pod_name) (irate(container_network_receive_bytes_total{pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
// workload
"workload_pod_cpu_usage": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_memory_usage": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(container_memory_usage_bytes{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_memory_usage_wo_cache": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(container_memory_usage_bytes{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""} - container_memory_cache{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_net_bytes_transmitted": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_network_transmit_bytes_total{namespace="$2", pod_name!="", pod_name=~"$3", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_net_bytes_received": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_network_receive_bytes_total{namespace="$2", pod_name!="", pod_name=~"$3", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_deployment_replica": `label_join(sum (label_join(label_replace(kube_deployment_spec_replicas{namespace="$2", deployment=~"$3"}, "owner_kind", "Deployment", "", ""), "workload", "", "deployment")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_deployment_replica_available": `label_join(sum (label_join(label_replace(kube_deployment_status_replicas_available{namespace="$2", deployment=~"$3"}, "owner_kind", "Deployment", "", ""), "workload", "", "deployment")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_statefulset_replica": `label_join(sum (label_join(label_replace(kube_statefulset_replicas{namespace="$2", statefulset=~"$3"}, "owner_kind", "StatefulSet", "", ""), "workload", "", "statefulset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_statefulset_replica_available": `label_join(sum (label_join(label_replace(kube_statefulset_status_replicas_current{namespace="$2", statefulset=~"$3"}, "owner_kind", "StatefulSet", "", ""), "workload", "", "statefulset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_daemonset_replica": `label_join(sum (label_join(label_replace(kube_daemonset_status_desired_number_scheduled{namespace="$2", daemonset=~"$3"}, "owner_kind", "DaemonSet", "", ""), "workload", "", "daemonset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_daemonset_replica_available": `label_join(sum (label_join(label_replace(kube_daemonset_status_number_available{namespace="$2", daemonset=~"$3"}, "owner_kind", "DaemonSet", "", ""), "workload", "", "daemonset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
// container
"container_cpu_usage": `sum(irate(container_cpu_usage_seconds_total{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}[5m])) by (namespace, pod_name, container_name)`,
"container_memory_usage": `sum(container_memory_usage_bytes{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}) by (namespace, pod_name, container_name)`,
"container_memory_usage_wo_cache": `container_memory_usage_bytes{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"} - ignoring(id, image, endpoint, instance, job, name, service) container_memory_cache{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}`,
"container_net_bytes_transmitted": `sum(irate(container_network_transmit_bytes_total{job="kubelet", namespace="$1", pod_name="$2", container_name="POD", ` + ExcludedVirtualNetworkInterfaces + `}[5m])) by (namespace, pod_name, container_name)`,
"container_net_bytes_received": `sum(irate(container_network_receive_bytes_total{job="kubelet", namespace="$1", pod_name="$2", container_name="POD", ` + ExcludedVirtualNetworkInterfaces + `}[5m])) by (namespace, pod_name, container_name)`,
"container_cpu_usage_node": `sum by (node, pod_name, container_name) (irate(container_cpu_usage_seconds_total{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
"container_memory_usage_node": `sum by (node, pod_name, container_name) (container_memory_usage_bytes{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""} * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
"container_memory_usage_wo_cache_node": `sum by (node, pod_name, container_name) ((container_memory_usage_bytes{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""} - container_memory_cache{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""}) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
"container_net_bytes_transmitted_node": `sum by (node, pod_name, container_name) (irate(container_network_transmit_bytes_total{job="kubelet", ` + ExcludedVirtualNetworkInterfaces + `, pod_name="$2", container_name="POD", container_name!="", image!=""}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
"container_net_bytes_received_node": `sum by (node, pod_name, container_name) (irate(container_network_receive_bytes_total{job="kubelet", ` + ExcludedVirtualNetworkInterfaces + `, pod_name="$2", container_name="POD", container_name!="", image!=""}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
// workspace
"workspace_cpu_usage": `sum(namespace:container_cpu_usage_seconds_total:sum_rate{namespace!="", namespace$1})`,
"workspace_memory_usage": `sum(namespace:container_memory_usage_bytes:sum{namespace!="", namespace$1})`,
"workspace_memory_usage_wo_cache": `sum(namespace:container_memory_usage_bytes_wo_cache:sum{namespace!="", namespace$1})`,
"workspace_net_bytes_transmitted": `sum(sum by (namespace) (irate(container_network_transmit_bytes_total{namespace!="", namespace$1, pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])))`,
"workspace_net_bytes_received": `sum(sum by (namespace) (irate(container_network_receive_bytes_total{namespace!="", namespace$1, pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])))`,
"workspace_pod_count": `sum(kube_pod_status_phase{phase!~"Failed|Succeeded", namespace!="", namespace$1})`,
"workspace_pod_running_count": `sum(kube_pod_status_phase{phase="Running", namespace!="", namespace$1})`,
"workspace_pod_succeeded_count": `sum(kube_pod_status_phase{phase="Succeeded", namespace!="", namespace$1})`,
"workspace_pod_abnormal_count": `sum(kube_pod_status_phase{phase=~"Failed|Pending|Unknown", namespace!="", namespace$1})`,
"workspace_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/configmaps"}) by (resource, type)`,
"workspace_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/jobs.batch"}) by (resource, type)`,
"workspace_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/roles.rbac.authorization.k8s.io"}) by (resource, type)`,
"workspace_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="limits.memory"}) by (resource, type)`,
"workspace_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="persistentvolumeclaims"}) by (resource, type)`,
"workspace_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="requests.memory"}) by (resource, type)`,
"workspace_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/persistentvolumeclaims"}) by (resource, type)`,
"workspace_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/cronjobs.batch"}) by (resource, type)`,
"workspace_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/ingresses.extensions"}) by (resource, type)`,
"workspace_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="limits.cpu"}) by (resource, type)`,
"workspace_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="requests.storage"}) by (resource, type)`,
"workspace_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/deployments.apps"}) by (resource, type)`,
"workspace_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/pods"}) by (resource, type)`,
"workspace_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/statefulsets.apps"}) by (resource, type)`,
"workspace_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/daemonsets.apps"}) by (resource, type)`,
"workspace_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/secrets"}) by (resource, type)`,
"workspace_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/services"}) by (resource, type)`,
"workspace_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="requests.cpu"}) by (resource, type)`,
"workspace_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="services.loadbalancers"}) by (resource, type)`,
"workspace_ingresses_extensions_count": `sum(kube_ingress_labels{namespace!="", namespace$1})`,
"workspace_cronjob_count": `sum(kube_cronjob_labels{namespace!="", namespace$1})`,
"workspace_pvc_count": `sum(kube_persistentvolumeclaim_info{namespace!="", namespace$1})`,
"workspace_daemonset_count": `sum(kube_daemonset_labels{namespace!="", namespace$1})`,
"workspace_deployment_count": `sum(kube_deployment_labels{namespace!="", namespace$1})`,
"workspace_endpoint_count": `sum(kube_endpoint_labels{namespace!="", namespace$1})`,
"workspace_hpa_count": `sum(kube_hpa_labels{namespace!="", namespace$1})`,
"workspace_job_count": `sum(kube_job_labels{namespace!="", namespace$1})`,
"workspace_statefulset_count": `sum(kube_statefulset_labels{namespace!="", namespace$1})`,
"workspace_replicaset_count": `count(kube_replicaset_created{namespace!="", namespace$1})`,
"workspace_service_count": `sum(kube_service_info{namespace!="", namespace$1})`,
"workspace_secret_count": `sum(kube_secret_info{namespace!="", namespace$1})`,
"workspace_all_project_count": `count(kube_namespace_annotations)`,
}

View File

@@ -1,51 +0,0 @@
package metrics
import (
"net/url"
"strings"
"k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/client"
)
func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
var nsNameList []string
for i := range namespaces {
nsNameList = append(nsNameList, namespaces[i].Name)
}
nsFilter := "^(" + strings.Join(nsNameList, "|") + ")$"
var timeRelateParams = make(url.Values)
params := client.MonitoringRequestParams{
NsFilter: nsFilter,
Params: timeRelateParams,
QueryType: client.DefaultQueryType,
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
}
rawMetrics := MonitorAllMetrics(&params, MetricLevelNamespace)
for _, result := range rawMetrics.Results {
for _, data := range result.Data.Result {
metricDescMap, ok := data["metric"].(map[string]interface{})
if ok {
if ns, exist := metricDescMap["namespace"]; exist {
timeAndValue, ok := data["value"].([]interface{})
if ok && len(timeAndValue) == 2 {
for i := 0; i < len(namespaces); i++ {
if namespaces[i].Name == ns {
if namespaces[i].Annotations == nil {
namespaces[i].Annotations = make(map[string]string, 0)
}
namespaces[i].Annotations[result.MetricName] = timeAndValue[1].(string)
}
}
}
}
}
}
}
return namespaces
}

0
pkg/models/metrics/nodes.go Executable file → Normal file
View File

0
pkg/models/metrics/pods.go Executable file → Normal file
View File

View File

@@ -1,298 +0,0 @@
/*
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 metrics
import (
"math"
"sort"
"strconv"
"unicode"
"runtime/debug"
"github.com/golang/glog"
)
const (
DefaultPageLimit = 5
DefaultPage = 1
)
type FormatedMetricDataWrapper struct {
fmtMetricData FormatedMetricData
by func(p, q *map[string]interface{}) bool
}
func (wrapper FormatedMetricDataWrapper) Len() int {
return len(wrapper.fmtMetricData.Result)
}
func (wrapper FormatedMetricDataWrapper) Less(i, j int) bool {
return wrapper.by(&wrapper.fmtMetricData.Result[i], &wrapper.fmtMetricData.Result[j])
}
func (wrapper FormatedMetricDataWrapper) Swap(i, j int) {
wrapper.fmtMetricData.Result[i], wrapper.fmtMetricData.Result[j] = wrapper.fmtMetricData.Result[j], wrapper.fmtMetricData.Result[i]
}
// sorted metric by ascending or descending order
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric, resourceType string) (*FormatedLevelMetric, int) {
defer func() {
if err := recover(); err != nil {
glog.Errorln(err)
debug.PrintStack()
}
}()
if sortMetricName == "" {
return fmtLevelMetric, -1
}
// default sort type is descending order
if sortType == "" {
sortType = ResultSortTypeDesc
}
var currentResourceMap = make(map[string]int)
// indexMap store sorted index for each node/namespace/pod
var indexMap = make(map[string]int)
i := 0
for _, metricItem := range fmtLevelMetric.Results {
if metricItem.Data.ResultType == ResultTypeVector && metricItem.Status == MetricStatusSuccess {
if metricItem.MetricName == sortMetricName {
if sortType == ResultSortTypeAsce {
// desc
sort.Sort(FormatedMetricDataWrapper{metricItem.Data, func(p, q *map[string]interface{}) bool {
value1 := (*p)[ResultItemValue].([]interface{})
value2 := (*q)[ResultItemValue].([]interface{})
v1, _ := strconv.ParseFloat(value1[len(value1)-1].(string), 64)
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
if v1 == v2 {
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
return resourceName1.(string) < resourceName2.(string)
}
return v1 < v2
}})
} else {
// desc
sort.Sort(FormatedMetricDataWrapper{metricItem.Data, func(p, q *map[string]interface{}) bool {
value1 := (*p)[ResultItemValue].([]interface{})
value2 := (*q)[ResultItemValue].([]interface{})
v1, _ := strconv.ParseFloat(value1[len(value1)-1].(string), 64)
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
if v1 == v2 {
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
return resourceName1.(string) > resourceName2.(string)
}
return v1 > v2
}})
}
for _, r := range metricItem.Data.Result {
// for some reasons, 'metric' may not contain `resourceType` field
// example: {"metric":{},"value":[1541142931.731,"3"]}
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
key := k.(string)
if exist {
if _, exist := indexMap[key]; !exist {
indexMap[key] = i
i = i + 1
}
}
}
}
// iterator all metric to find max metricItems length
for _, r := range metricItem.Data.Result {
k, ok := r[ResultItemMetric].(map[string]interface{})[resourceType]
if ok {
currentResourceMap[k.(string)] = 1
}
}
}
}
var keys []string
for k := range currentResourceMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, resource := range keys {
if _, exist := indexMap[resource]; !exist {
indexMap[resource] = i
i = i + 1
}
}
// sort other metric
for i := 0; i < len(fmtLevelMetric.Results); i++ {
re := fmtLevelMetric.Results[i]
if re.Data.ResultType == ResultTypeVector && re.Status == MetricStatusSuccess {
sortedMetric := make([]map[string]interface{}, len(indexMap))
for j := 0; j < len(re.Data.Result); j++ {
r := re.Data.Result[j]
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
if exist {
index, exist := indexMap[k.(string)]
if exist {
sortedMetric[index] = r
}
}
}
fmtLevelMetric.Results[i].Data.Result = sortedMetric
}
}
return fmtLevelMetric, len(indexMap)
}
func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric, maxLength int) interface{} {
if maxLength <= 0 {
return fmtLevelMetric
}
// matrix type can not be sorted
for _, metricItem := range fmtLevelMetric.Results {
if metricItem.Data.ResultType != ResultTypeVector {
return fmtLevelMetric
}
}
var page = DefaultPage
if pageNum != "" {
p, err := strconv.Atoi(pageNum)
if err != nil {
glog.Errorln(err)
} else {
if p > 0 {
page = p
}
}
} else {
// the default mode is none paging
return fmtLevelMetric
}
var limit = DefaultPageLimit
if limitNum != "" {
l, err := strconv.Atoi(limitNum)
if err != nil {
glog.Errorln(err)
} else {
if l > 0 {
limit = l
}
}
}
// the i page: [(page-1) * limit, (page) * limit - 1]
start := (page - 1) * limit
end := (page)*limit - 1
for i := 0; i < len(fmtLevelMetric.Results); i++ {
// only pageing when result type is `vector` and result status is `success`
if fmtLevelMetric.Results[i].Data.ResultType != ResultTypeVector || fmtLevelMetric.Results[i].Status != MetricStatusSuccess {
continue
}
resultLen := len(fmtLevelMetric.Results[i].Data.Result)
if start >= resultLen {
fmtLevelMetric.Results[i].Data.Result = nil
continue
}
if end >= resultLen {
end = resultLen - 1
}
slice := fmtLevelMetric.Results[i].Data.Result[start : end+1]
fmtLevelMetric.Results[i].Data.Result = slice
}
allPage := int(math.Ceil(float64(maxLength) / float64(limit)))
return &PagedFormatedLevelMetric{
Message: "paged",
TotalPage: allPage,
TotalItem: maxLength,
CurrentPage: page,
Metric: *fmtLevelMetric,
}
}
// maybe this function is time consuming
func ReformatJson(metric string, metricsName string, needDelParams ...string) *FormatedMetric {
var formatMetric FormatedMetric
err := jsonIter.Unmarshal([]byte(metric), &formatMetric)
if err != nil {
glog.Errorln("Unmarshal metric json failed", err.Error(), metric)
}
if formatMetric.MetricName == "" {
if metricsName != "" {
formatMetric.MetricName = metricsName
}
}
// retrive metrics success
if formatMetric.Status == MetricStatusSuccess {
result := formatMetric.Data.Result
for _, res := range result {
metric, exist := res[ResultItemMetric]
metricMap, sure := metric.(map[string]interface{})
if exist && sure {
delete(metricMap, "__name__")
}
if len(needDelParams) > 0 {
for _, p := range needDelParams {
delete(metricMap, p)
}
}
}
}
return &formatMetric
}
func ReformatNodeStatusField(nodeMetric *FormatedMetric) *FormatedMetric {
metricCount := len(nodeMetric.Data.Result)
for i := 0; i < metricCount; i++ {
metric, exist := nodeMetric.Data.Result[i][ResultItemMetric]
if exist {
status, exist := metric.(map[string]interface{})[MetricStatus]
if exist {
status = UpperFirstLetter(status.(string))
metric.(map[string]interface{})[MetricStatus] = status
}
}
}
return nodeMetric
}
func UpperFirstLetter(str string) string {
for i, ch := range str {
return string(unicode.ToUpper(ch)) + str[i+1:]
}
return ""
}

View File

@@ -40,15 +40,12 @@ const (
persistentvolumeclaimsKey = "persistentvolumeclaims" persistentvolumeclaimsKey = "persistentvolumeclaims"
storageClassesKey = "count/storageClass" storageClassesKey = "count/storageClass"
namespaceKey = "count/namespace" namespaceKey = "count/namespace"
jobsKey = "count/jobs.batch"
cronJobsKey = "count/cronjobs.batch"
) )
var resourceMap = map[string]string{daemonsetsKey: controllers.Daemonsets, deploymentsKey: controllers.Deployments, var resourceMap = map[string]string{daemonsetsKey: controllers.Daemonsets, deploymentsKey: controllers.Deployments,
ingressKey: controllers.Ingresses, rolesKey: controllers.Roles, servicesKey: controllers.Services, ingressKey: controllers.Ingresses, rolesKey: controllers.Roles, servicesKey: controllers.Services,
statefulsetsKey: controllers.Statefulsets, persistentvolumeclaimsKey: controllers.PersistentVolumeClaim, podsKey: controllers.Pods, statefulsetsKey: controllers.Statefulsets, persistentvolumeclaimsKey: controllers.PersistentVolumeClaim, podsKey: controllers.Pods,
namespaceKey: controllers.Namespaces, storageClassesKey: controllers.StorageClasses, clusterRolesKey: controllers.ClusterRoles, namespaceKey: controllers.Namespaces, storageClassesKey: controllers.StorageClasses, clusterRolesKey: controllers.ClusterRoles}
jobsKey: controllers.Jobs, cronJobsKey: controllers.Cronjobs}
type ResourceQuota struct { type ResourceQuota struct {
NameSpace string `json:"namespace"` NameSpace string `json:"namespace"`

View File

@@ -1,19 +1,3 @@
/*
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 package models
import ( import (
@@ -40,19 +24,11 @@ type ResourceList struct {
Items interface{} `json:"items,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) { func getController(resource string) (controllers.Controller, error) {
switch resource { switch resource {
case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses, case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses,
controllers.PersistentVolumeClaim, controllers.Roles, controllers.ClusterRoles, controllers.Services, controllers.PersistentVolumeClaim, controllers.Roles, controllers.ClusterRoles, controllers.Services,
controllers.Pods, controllers.Namespaces, controllers.StorageClasses, controllers.Jobs, controllers.Cronjobs, controllers.Pods, controllers.Namespaces, controllers.StorageClasses:
controllers.Nodes, controllers.Secrets, controllers.ConfigMaps:
return controllers.ResourceControllers.Controllers[resource], nil return controllers.ResourceControllers.Controllers[resource], nil
default: default:
@@ -62,21 +38,20 @@ func getController(resource string) (controllers.Controller, error) {
} }
func getConditions(str string) (*searchConditions, map[string]string, error) { func getConditions(str string) (map[string]string, map[string]string, error) {
match := make(map[string]string) match := make(map[string]string)
fuzzy := 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 { if len(str) == 0 {
return nil, nil, nil return nil, nil, nil
} }
list := strings.Split(str, ",")
for _, item := range list {
if strings.Count(item, "=") >= 2 {
return nil, nil, errors.New("invalid condition input, invalid character \"=\"")
}
conditions := strings.Split(str, ",") if strings.Count(item, "~") >= 2 {
for _, item := range conditions { return nil, nil, errors.New("invalid condition input, invalid character \"~\"")
if strings.Count(item, "=") >= 2 || strings.Count(item, "~") >= 2 {
return nil, nil, errors.New("invalid condition input")
} }
if strings.Count(item, "=") == 1 { if strings.Count(item, "=") == 1 {
@@ -84,17 +59,7 @@ func getConditions(str string) (*searchConditions, map[string]string, error) {
if len(kvs) < 2 || len(kvs[1]) == 0 { if len(kvs) < 2 || len(kvs[1]) == 0 {
return nil, nil, errors.New("invalid condition input") return nil, nil, errors.New("invalid condition input")
} }
match[kvs[0]] = kvs[1]
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 continue
} }
@@ -103,132 +68,86 @@ func getConditions(str string) (*searchConditions, map[string]string, error) {
if len(kvs) < 2 || len(kvs[1]) == 0 { if len(kvs) < 2 || len(kvs[1]) == 0 {
return nil, nil, errors.New("invalid condition input") return nil, nil, errors.New("invalid condition input")
} }
if !strings.Contains(kvs[0], "|") { fuzzy[kvs[0]] = kvs[1]
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 continue
} }
return nil, nil, errors.New("invalid condition input") return nil, nil, errors.New("invalid condition input")
}
return &searchConditions{match: match, fuzzyOr: fuzzyOr, matchOr: matchOr, fuzzy: fuzzy}, orderField, nil }
return match, fuzzy, nil
} }
func getPaging(resourceName, pagingStr string) (*controllers.Paging, error) { func getPaging(resourceName, pagingStr string) (*controllers.Paging, map[string]int, error) {
defaultPaging := &controllers.Paging{Limit: 10, Offset: 0, Page: 1} defaultPaging := &controllers.Paging{Limit: 10, Offset: 0}
paging := controllers.Paging{} defautlPagingMap := map[string]int{"page": 1, "limit": 10}
if resourceName == controllers.Namespaces { if resourceName == controllers.Namespaces {
defaultPaging = nil defaultPaging = nil
defautlPagingMap = map[string]int{"page": 0, "limit": 0}
} }
pagingMap := make(map[string]int)
if len(pagingStr) == 0 { if len(pagingStr) == 0 {
return defaultPaging, nil return defaultPaging, defautlPagingMap, nil
} }
list := strings.Split(pagingStr, ",") list := strings.Split(pagingStr, ",")
for _, item := range list { for _, item := range list {
kvs := strings.Split(item, "=") kvs := strings.Split(item, "=")
if len(kvs) < 2 { if len(kvs) < 2 {
return nil, errors.New("invalid Paging input") return nil, nil, errors.New("invalid Paging input")
} }
value, err := strconv.Atoi(kvs[1]) value, err := strconv.Atoi(kvs[1])
if err != nil || value <= 0 { if err != nil {
return nil, errors.New("invalid Paging input") return nil, nil, errors.New("invalid Paging input")
} }
if kvs[0] == limit { pagingMap[kvs[0]] = value
paging.Limit = value
}
if kvs[0] == page {
paging.Page = value
}
} }
if paging.Limit > 0 && paging.Page > 0 { if pagingMap[limit] <= 0 || pagingMap[page] <= 0 {
paging.Offset = (paging.Page - 1) * paging.Limit return nil, nil, errors.New("invalid Paging input")
return &paging, nil
} }
return defaultPaging, nil if pagingMap[limit] > 0 && pagingMap[page] > 0 {
offset := (pagingMap[page] - 1) * pagingMap[limit]
return &controllers.Paging{Limit: pagingMap[limit], Offset: offset}, pagingMap, nil
}
return defaultPaging, defautlPagingMap, nil
} }
func generateOrder(orderField map[string]string, order string) string { func ListResource(resourceName, conditonSrt, pagingStr string) (*ResourceList, error) {
if len(orderField) == 0 { match, fuzzy, err := getConditions(conditonSrt)
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 { if err != nil {
return nil, err return nil, err
} }
order = generateOrder(OrderFields, order) paging, pagingMap, err := getPaging(resourceName, pagingStr)
conditionStr := generateConditionStr(conditions)
paging, err := getPaging(resourceName, pagingStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
conditionStr := generateConditionStr(match, fuzzy)
ctl, err := getController(resourceName) ctl, err := getController(resourceName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
total, items, err := ctl.ListWithConditions(conditionStr, paging, order) total, items, err := ctl.ListWithConditions(conditionStr, paging)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if paging != nil { return &ResourceList{Total: total, Items: items, Page: pagingMap[page], Limit: pagingMap[limit]}, 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 { func generateConditionStr(match map[string]string, fuzzy map[string]string) string {
shouldUseAnd := false
shouldUseBrackets := false
conditionStr := "" conditionStr := ""
if conditions == nil { for k, v := range match {
return conditionStr
}
for k, v := range conditions.match {
if len(conditionStr) == 0 { if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v) conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else { } else {
@@ -236,7 +155,7 @@ func generateConditionStr(conditions *searchConditions) string {
} }
} }
for k, v := range conditions.fuzzy { for k, v := range fuzzy {
if len(conditionStr) == 0 { if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v) conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v)
} else { } else {
@@ -244,42 +163,6 @@ func generateConditionStr(conditions *searchConditions) string {
} }
} }
if len(conditionStr) > 0 {
shouldUseAnd = true
}
for k, v := range conditions.matchOr {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else {
if shouldUseAnd {
conditionStr = fmt.Sprintf("%s And (%s = \"%s\" ", conditionStr, k, v)
shouldUseBrackets = true
shouldUseAnd = false
} 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 {
if shouldUseAnd {
conditionStr = fmt.Sprintf("%s And (%s like '%%%s%%' ", conditionStr, k, v)
shouldUseAnd = false
shouldUseBrackets = true
} else {
conditionStr = fmt.Sprintf("%s OR %s like '%%%s%%' ", conditionStr, k, v)
}
}
}
if shouldUseBrackets {
conditionStr = fmt.Sprintf("%s )", conditionStr)
}
return conditionStr return conditionStr
} }
@@ -299,9 +182,9 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
notReadyStatus = controllers.PvcPending notReadyStatus = controllers.PvcPending
} }
if len(namespace) > 0 { if len(namespace) > 0 {
status, err = ListResource(resource, fmt.Sprintf("status=%s,namespace=%s", notReadyStatus, namespace), "", "") status, err = ListResource(resource, fmt.Sprintf("status=%s,namespace=%s", notReadyStatus, namespace), "")
} else { } else {
status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "", "") status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "")
} }
if err != nil { if err != nil {
@@ -325,30 +208,25 @@ func GetApplication(clusterId string) (interface{}, error) {
return ctl.GetApp(clusterId) return ctl.GetApp(clusterId)
} }
func ListApplication(runtimeId, conditionStr, pagingStr string) (*ResourceList, error) { func ListApplication(runtimeId, conditions, pagingStr string) (*ResourceList, error) {
paging, err := getPaging(controllers.Applications, pagingStr) paging, pagingMap, err := getPaging(controllers.Applications, pagingStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
conditions, _, err := getConditions(conditionStr) match, fuzzy, err := getConditions(conditions)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return nil, err return nil, err
} }
if conditions == nil {
conditions = &searchConditions{}
}
ctl := &controllers.ApplicationCtl{OpenpitrixAddr: options.ServerOptions.GetOpAddress()} ctl := &controllers.ApplicationCtl{OpenpitrixAddr: options.ServerOptions.GetOpAddress()}
total, items, err := ctl.ListApplication(runtimeId, match, fuzzy, paging)
total, items, err := ctl.ListApplication(runtimeId, conditions.match, conditions.fuzzy, paging)
if err != nil { if err != nil {
glog.Errorf("get application list failed, reason: %s", err) glog.Errorf("get application list failed, reason: %s", err)
return nil, err return nil, err
} }
return &ResourceList{Total: total, Items: items, Page: paging.Page, Limit: paging.Limit}, nil return &ResourceList{Total: total, Items: items, Page: pagingMap[page], Limit: pagingMap[limit]}, nil
} }

View File

@@ -1,112 +0,0 @@
/*
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 (
"fmt"
"strconv"
"github.com/golang/glog"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
appsV1 "k8s.io/client-go/listers/apps/v1"
"kubesphere.io/kubesphere/pkg/models/controllers"
)
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
deployLister := controllers.ResourceControllers.Controllers[controllers.Deployments].Lister().(appsV1.DeploymentLister)
deploy, err := deployLister.Deployments(namespace).Get(name)
if err != nil {
glog.Errorf("get deployment %s failed, reason: %s", name, err)
return nil, err
}
labelMap := deploy.Spec.Template.Labels
labelSelector := labels.Set(labelMap).AsSelector()
rsLister := controllers.ResourceControllers.Controllers[controllers.Replicasets].Lister().(appsV1.ReplicaSetLister)
rsList, err := rsLister.ReplicaSets(namespace).List(labelSelector)
if err != nil {
return nil, err
}
for _, rs := range rsList {
if rs.Annotations["deployment.kubernetes.io/revision"] == revision {
return rs, nil
}
}
return nil, errors.NewNotFound(v1.Resource("deployment revision"), fmt.Sprintf("%s#%s", name, revision))
}
func GetDaemonSetRevision(namespace, name, revision string) (*v1.ControllerRevision, error) {
revisionInt, err := strconv.Atoi(revision)
if err != nil {
return nil, err
}
dsLister := controllers.ResourceControllers.Controllers[controllers.Daemonsets].Lister().(appsV1.DaemonSetLister)
ds, err := dsLister.DaemonSets(namespace).Get(name)
if err != nil {
glog.Errorf("get Daemonset %s failed, reason: %s", name, err)
return nil, err
}
labels := ds.Spec.Template.Labels
return getControllerRevision(namespace, name, labels, revisionInt)
}
func GetStatefulSetRevision(namespace, name, revision string) (*v1.ControllerRevision, error) {
revisionInt, err := strconv.Atoi(revision)
if err != nil {
return nil, err
}
stLister := controllers.ResourceControllers.Controllers[controllers.Statefulsets].Lister().(appsV1.StatefulSetLister)
st, err := stLister.StatefulSets(namespace).Get(name)
if err != nil {
glog.Errorf("get Daemonset %s failed, reason: %s", name, err)
return nil, err
}
labels := st.Spec.Template.Labels
return getControllerRevision(namespace, name, labels, revisionInt)
}
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
labelSelector := labels.Set(labelMap).AsSelector()
revisionLister := controllers.ResourceControllers.Controllers[controllers.ControllerRevisions].Lister().(appsV1.ControllerRevisionLister)
revisions, err := revisionLister.ControllerRevisions(namespace).List(labelSelector)
if err != nil {
return nil, err
}
for _, controllerRevision := range revisions {
if controllerRevision.Revision == int64(revision) {
return controllerRevision, nil
}
}
return nil, errors.NewNotFound(v1.Resource("revision"), fmt.Sprintf("%s#%s", name, revision))
}

View File

@@ -1,46 +0,0 @@
package workspaces
import "time"
type Workspace struct {
Group `json:",inline"`
Admin string `json:"admin,omitempty"`
Namespaces []string `json:"namespaces"`
DevopsProjects []string `json:"devops_projects"`
}
type UserInvite struct {
Username string `json:"username"`
Role string `json:"role"`
}
type Group struct {
Path string `json:"path"`
Name string `json:"name"`
Gid string `json:"gid"`
Members []string `json:"members"`
Logo string `json:"logo"`
Creator string `json:"creator"`
CreateTime string `json:"create_time"`
ChildGroups []string `json:"child_groups,omitempty"`
Description string `json:"description"`
}
func (g Group) GetCreateTime() (time.Time, error) {
return time.Parse("2006-01-02T15:04:05Z", g.CreateTime)
}
type WorkspaceDPBinding struct {
Workspace string `gorm:"primary_key"`
DevOpsProject string `gorm:"primary_key"`
}
type DevopsProject struct {
ProjectId *string `json:"project_id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
Creator string `json:"creator"`
CreateTime *time.Time `json:"create_time,omitempty"`
Status *string `json:"status"`
Visibility *string `json:"visibility,omitempty"`
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +0,0 @@
package errors
import (
"encoding/json"
"errors"
)
func Wrap(data []byte) error {
var j map[string]string
err := json.Unmarshal(data, &j)
if err != nil {
return errors.New(string(data))
} else if message := j["message"]; message != "" {
return errors.New(message)
} else if message := j["Error"]; message != "" {
return errors.New(message)
} else {
return errors.New(string(data))
}
}