clean old devops code
todo impl use informer Signed-off-by: runzexia <runzexia@yunify.com>
This commit is contained in:
@@ -2,24 +2,24 @@ package v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/im"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type iamHandler struct {
|
||||
amOperator am.AccessManagementInterface
|
||||
imOperator im.IdentityManagementInterface
|
||||
am am.AccessManagementInterface
|
||||
im im.IdentityManagementInterface
|
||||
}
|
||||
|
||||
func newIAMHandler(k8sClient k8s.Client, factory informers.InformerFactory, ldapClient ldappool.Interface, cacheClient cache.Interface, options *authoptions.AuthenticationOptions) *iamHandler {
|
||||
func newIAMHandler(im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) *iamHandler {
|
||||
return &iamHandler{
|
||||
amOperator: am.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()),
|
||||
imOperator: im.NewLDAPOperator(ldapClient),
|
||||
am: am,
|
||||
im: im,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,22 @@ func (h *iamHandler) ModifyUser(request *restful.Request, response *restful.Resp
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeUser(req *restful.Request, resp *restful.Response) {
|
||||
panic("implement me")
|
||||
username := req.PathParameter("user")
|
||||
user, err := h.im.DescribeUser(username)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
globalRole, err := h.am.GetRoleOfUserInTargetScope(iamv1alpha2.GlobalScope, "", username)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, req, err)
|
||||
return
|
||||
}
|
||||
result := iamv1alpha2.UserDetail{User: user, GlobalRole: globalRole}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUsers(req *restful.Request, resp *restful.Response) {
|
||||
@@ -48,9 +63,39 @@ func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRolesOfUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
|
||||
var roles []iamv1alpha2.Role
|
||||
var err error
|
||||
|
||||
if strings.HasSuffix(req.Request.URL.Path, "workspaceroles") {
|
||||
roles, err = h.am.ListRolesOfUser(iamv1alpha2.WorkspaceScope, username)
|
||||
} else if strings.HasSuffix(req.Request.URL.Path, "clusterroles") {
|
||||
roles, err = h.am.ListRolesOfUser(iamv1alpha2.ClusterScope, username)
|
||||
} else if strings.HasSuffix(req.Request.URL.Path, "namespaceroles") {
|
||||
roles, err = h.am.ListRolesOfUser(iamv1alpha2.NamespaceScope, username)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
result := iamv1alpha2.RoleList{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
Kind: "List",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ListMeta: v1.ListMeta{},
|
||||
Items: roles,
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -22,15 +22,14 @@ import (
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/im"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -38,19 +37,38 @@ const groupName = "iam.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory, ldapClient ldappool.Interface, cacheClient cache.Interface, options *authoptions.AuthenticationOptions) error {
|
||||
func AddToContainer(container *restful.Container, im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
handler := newIAMHandler(k8sClient, factory, ldapClient, cacheClient, options)
|
||||
handler := newIAMHandler(im, am, options)
|
||||
|
||||
// implemented by create CRD object.
|
||||
//ws.Route(ws.POST("/users"))
|
||||
//ws.Route(ws.DELETE("/users/{user}"))
|
||||
//ws.Route(ws.PUT("/users/{user}"))
|
||||
//ws.Route(ws.GET("/users/{user}"))
|
||||
ws.Route(ws.GET("/users/{user}").
|
||||
To(handler.DescribeUser).
|
||||
Doc("Retrieve user details.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.UserDetail{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
// TODO move to resources api
|
||||
//ws.Route(ws.GET("/users"))
|
||||
ws.Route(ws.GET("/users/{user}/workspaceroles").
|
||||
To(handler.ListRolesOfUser).
|
||||
Doc("Retrieve user roles in workspaces.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.RoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
ws.Route(ws.GET("/users/{user}/clusterroles").
|
||||
To(handler.ListRolesOfUser).
|
||||
Doc("Retrieve user roles in clusters.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.RoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
ws.Route(ws.GET("/users/{user}/namespaceroles").
|
||||
To(handler.ListRolesOfUser).
|
||||
Doc("Retrieve user roles in namespaces.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.RoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles").
|
||||
To(handler.ListRoles).
|
||||
@@ -104,6 +122,6 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informer
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
c.Add(ws)
|
||||
container.Add(ws)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/api/monitoring/v1alpha2"
|
||||
model "kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
k k8s.Client
|
||||
mo model.MonitoringOperator
|
||||
}
|
||||
|
||||
func newHandler(k k8s.Client, m monitoring.Interface) *handler {
|
||||
return &handler{k, model.NewMonitoringOperator(m)}
|
||||
}
|
||||
|
||||
func (h handler) handleClusterMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelCluster)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleNodeMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelNode)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleWorkspaceMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelWorkspace)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleNamespaceMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelNamespace)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleWorkloadMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelWorkload)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handlePodMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelPod)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleContainerMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelContainer)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handlePVCMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelPVC)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleComponentMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
p, err := h.parseRequestParams(req, monitoring.LevelComponent)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, p)
|
||||
}
|
||||
|
||||
func (h handler) handleNamedMetricsQuery(resp *restful.Response, p params) {
|
||||
var res v1alpha2.APIResponse
|
||||
var err error
|
||||
|
||||
if p.isRangeQuery() {
|
||||
res, err = h.mo.GetNamedMetricsOverTime(p.start, p.end, p.step, p.option)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
res, err = h.mo.GetNamedMetrics(p.time, p.option)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
if p.shouldSort() {
|
||||
var rows int
|
||||
res, rows = h.mo.SortMetrics(res, p.target, p.order, p.identifier)
|
||||
res = h.mo.PageMetrics(res, p.page, p.limit, rows)
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteAsJson(res)
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
model "kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultStep = 10 * time.Minute
|
||||
DefaultFilter = ".*"
|
||||
DefaultOrder = model.OrderDescending
|
||||
DefaultPage = 1
|
||||
DefaultLimit = 5
|
||||
)
|
||||
|
||||
type params struct {
|
||||
time time.Time
|
||||
start, end time.Time
|
||||
step time.Duration
|
||||
|
||||
target string
|
||||
identifier string
|
||||
order string
|
||||
page int
|
||||
limit int
|
||||
|
||||
option monitoring.QueryOption
|
||||
}
|
||||
|
||||
func (p params) isRangeQuery() bool {
|
||||
return !p.time.IsZero()
|
||||
}
|
||||
|
||||
func (p params) shouldSort() bool {
|
||||
return p.target != ""
|
||||
}
|
||||
|
||||
func (h handler) parseRequestParams(req *restful.Request, lvl monitoring.MonitoringLevel) (params, error) {
|
||||
timestamp := req.QueryParameter("time")
|
||||
start := req.QueryParameter("start")
|
||||
end := req.QueryParameter("end")
|
||||
step := req.QueryParameter("step")
|
||||
target := req.QueryParameter("sort_metric")
|
||||
order := req.QueryParameter("sort_type")
|
||||
page := req.QueryParameter("page")
|
||||
limit := req.QueryParameter("limit")
|
||||
metricFilter := req.QueryParameter("metrics_filter")
|
||||
resourceFilter := req.QueryParameter("resources_filter")
|
||||
nodeName := req.PathParameter("node")
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
workloadKind := req.PathParameter("kind")
|
||||
workloadName := req.PathParameter("workload")
|
||||
podName := req.PathParameter("pod")
|
||||
containerName := req.PathParameter("container")
|
||||
pvcName := req.PathParameter("pvc")
|
||||
storageClassName := req.PathParameter("storageclass")
|
||||
componentType := req.PathParameter("component")
|
||||
|
||||
var p params
|
||||
var err error
|
||||
if start != "" && end != "" {
|
||||
p.start, err = time.Parse(time.RFC3339, start)
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
p.end, err = time.Parse(time.RFC3339, end)
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
if step == "" {
|
||||
p.step = DefaultStep
|
||||
} else {
|
||||
p.step, err = time.ParseDuration(step)
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
}
|
||||
} else if start == "" && end == "" {
|
||||
if timestamp == "" {
|
||||
p.time = time.Now()
|
||||
} else {
|
||||
p.time, err = time.Parse(time.RFC3339, req.QueryParameter("time"))
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return p, errors.Errorf("'time' and the combination of 'start' and 'end' are mutually exclusive.")
|
||||
}
|
||||
|
||||
// hide metrics from a deleted namespace having the same name
|
||||
namespace := req.QueryParameter("namespace")
|
||||
if req.QueryParameter("namespace") != "" {
|
||||
ns, err := h.k.Kubernetes().CoreV1().Namespaces().Get(namespace, corev1.GetOptions{})
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
|
||||
cts := ns.CreationTimestamp.Time
|
||||
if p.start.Before(cts) {
|
||||
p.start = cts
|
||||
}
|
||||
if p.end.Before(cts) {
|
||||
return p, errors.Errorf("End timestamp must not be before namespace creation time.")
|
||||
}
|
||||
}
|
||||
|
||||
if resourceFilter == "" {
|
||||
resourceFilter = DefaultFilter
|
||||
}
|
||||
|
||||
if metricFilter == "" {
|
||||
metricFilter = DefaultFilter
|
||||
}
|
||||
if componentType != "" {
|
||||
metricFilter = fmt.Sprintf("/^(?=.*%s)(?=.*%s)/s", componentType, metricFilter)
|
||||
}
|
||||
|
||||
// should sort
|
||||
if target != "" {
|
||||
p.page = DefaultPage
|
||||
p.limit = DefaultLimit
|
||||
if order != model.OrderAscending {
|
||||
p.order = DefaultOrder
|
||||
}
|
||||
if page != "" {
|
||||
p.page, err = strconv.Atoi(req.QueryParameter("page"))
|
||||
if err != nil || p.page <= 0 {
|
||||
return p, errors.Errorf("Invalid parameter 'page'.")
|
||||
}
|
||||
}
|
||||
if limit != "" {
|
||||
p.limit, err = strconv.Atoi(req.QueryParameter("limit"))
|
||||
if err != nil || p.limit <= 0 {
|
||||
return p, errors.Errorf("Invalid parameter 'limit'.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch lvl {
|
||||
case monitoring.LevelCluster:
|
||||
p.option = monitoring.ClusterOption{MetricFilter: metricFilter}
|
||||
case monitoring.LevelNode:
|
||||
p.identifier = model.IdentifierNode
|
||||
p.option = monitoring.NodeOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
NodeName: nodeName,
|
||||
}
|
||||
case monitoring.LevelWorkspace:
|
||||
p.identifier = model.IdentifierWorkspace
|
||||
p.option = monitoring.WorkspaceOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
WorkspaceName: workspaceName,
|
||||
}
|
||||
case monitoring.LevelNamespace:
|
||||
p.identifier = model.IdentifierNamespace
|
||||
p.option = monitoring.NamespaceOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
WorkspaceName: workspaceName,
|
||||
NamespaceName: namespaceName,
|
||||
}
|
||||
case monitoring.LevelWorkload:
|
||||
p.identifier = model.IdentifierWorkload
|
||||
p.option = monitoring.WorkloadOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
NamespaceName: namespaceName,
|
||||
WorkloadKind: workloadKind,
|
||||
WorkloadName: workloadName,
|
||||
}
|
||||
case monitoring.LevelPod:
|
||||
p.identifier = model.IdentifierPod
|
||||
p.option = monitoring.PodOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
NodeName: nodeName,
|
||||
NamespaceName: namespaceName,
|
||||
WorkloadKind: workloadKind,
|
||||
WorkloadName: workloadName,
|
||||
PodName: podName,
|
||||
}
|
||||
case monitoring.LevelContainer:
|
||||
p.identifier = model.IdentifierContainer
|
||||
p.option = monitoring.ContainerOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
NamespaceName: namespaceName,
|
||||
PodName: podName,
|
||||
ContainerName: containerName,
|
||||
}
|
||||
case monitoring.LevelPVC:
|
||||
p.identifier = model.IdentifierPVC
|
||||
p.option = monitoring.PVCOption{
|
||||
MetricFilter: metricFilter,
|
||||
ResourceFilter: resourceFilter,
|
||||
NamespaceName: namespaceName,
|
||||
StorageClassName: storageClassName,
|
||||
PersistentVolumeClaimName: pvcName,
|
||||
}
|
||||
case monitoring.LevelComponent:
|
||||
p.option = monitoring.ComponentOption{
|
||||
MetricFilter: metricFilter,
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
194
pkg/kapis/monitoring/v1alpha3/handler.go
Normal file
194
pkg/kapis/monitoring/v1alpha3/handler.go
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 v1alpha3
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
model "kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
k kubernetes.Interface
|
||||
mo model.MonitoringOperator
|
||||
}
|
||||
|
||||
func newHandler(k kubernetes.Interface, m monitoring.Interface) *handler {
|
||||
return &handler{k, model.NewMonitoringOperator(m)}
|
||||
}
|
||||
|
||||
func (h handler) handleClusterMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelCluster)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handleNodeMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelNode)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handleWorkspaceMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelWorkspace)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handleNamespaceMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelNamespace)
|
||||
if err != nil {
|
||||
if err.Error() == ErrNoHit {
|
||||
res := handleNoHit(opt.namedMetrics)
|
||||
resp.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handleWorkloadMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelWorkload)
|
||||
if err != nil {
|
||||
if err.Error() == ErrNoHit {
|
||||
res := handleNoHit(opt.namedMetrics)
|
||||
resp.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handlePodMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelPod)
|
||||
if err != nil {
|
||||
if err.Error() == ErrNoHit {
|
||||
res := handleNoHit(opt.namedMetrics)
|
||||
resp.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handleContainerMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelContainer)
|
||||
if err != nil {
|
||||
if err.Error() == ErrNoHit {
|
||||
res := handleNoHit(opt.namedMetrics)
|
||||
resp.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handlePVCMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelPVC)
|
||||
if err != nil {
|
||||
if err.Error() == ErrNoHit {
|
||||
res := handleNoHit(opt.namedMetrics)
|
||||
resp.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func (h handler) handleComponentMetricsQuery(req *restful.Request, resp *restful.Response) {
|
||||
params := parseRequestParams(req)
|
||||
opt, err := h.makeQueryOptions(params, monitoring.LevelComponent)
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
h.handleNamedMetricsQuery(resp, opt)
|
||||
}
|
||||
|
||||
func handleNoHit(namedMetrics []string) model.Metrics {
|
||||
var res model.Metrics
|
||||
for _, metic := range namedMetrics {
|
||||
res.Results = append(res.Results, monitoring.Metric{
|
||||
MetricName: metic,
|
||||
MetricData: monitoring.MetricData{},
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (h handler) handleNamedMetricsQuery(resp *restful.Response, q queryOptions) {
|
||||
var res model.Metrics
|
||||
|
||||
var metrics []string
|
||||
for _, metric := range q.namedMetrics {
|
||||
ok, _ := regexp.MatchString(q.metricFilter, metric)
|
||||
if ok {
|
||||
metrics = append(metrics, metric)
|
||||
}
|
||||
}
|
||||
if len(metrics) == 0 {
|
||||
resp.WriteAsJson(res)
|
||||
return
|
||||
}
|
||||
|
||||
if q.isRangeQuery() {
|
||||
res = h.mo.GetNamedMetricsOverTime(metrics, q.start, q.end, q.step, q.option)
|
||||
} else {
|
||||
res = h.mo.GetNamedMetrics(metrics, q.time, q.option)
|
||||
if q.shouldSort() {
|
||||
res = *res.Sort(q.target, q.order, q.identifier).Page(q.page, q.limit)
|
||||
}
|
||||
}
|
||||
resp.WriteAsJson(res)
|
||||
}
|
||||
268
pkg/kapis/monitoring/v1alpha3/helper.go
Normal file
268
pkg/kapis/monitoring/v1alpha3/helper.go
Normal file
@@ -0,0 +1,268 @@
|
||||
package v1alpha3
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
model "kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultStep = 10 * time.Minute
|
||||
DefaultFilter = ".*"
|
||||
DefaultOrder = model.OrderDescending
|
||||
DefaultPage = 1
|
||||
DefaultLimit = 5
|
||||
|
||||
ComponentEtcd = "etcd"
|
||||
ComponentAPIServer = "apiserver"
|
||||
ComponentScheduler = "scheduler"
|
||||
|
||||
ErrNoHit = "'end' must be after the namespace creation time."
|
||||
ErrParamConflict = "'time' and the combination of 'start' and 'end' are mutually exclusive."
|
||||
ErrInvalidStartEnd = "'start' must be before 'end'."
|
||||
ErrInvalidPage = "Invalid parameter 'page'."
|
||||
ErrInvalidLimit = "Invalid parameter 'limit'."
|
||||
)
|
||||
|
||||
type reqParams struct {
|
||||
time string
|
||||
start string
|
||||
end string
|
||||
step string
|
||||
target string
|
||||
order string
|
||||
page string
|
||||
limit string
|
||||
metricFilter string
|
||||
resourceFilter string
|
||||
nodeName string
|
||||
workspaceName string
|
||||
namespaceName string
|
||||
workloadKind string
|
||||
workloadName string
|
||||
podName string
|
||||
containerName string
|
||||
pvcName string
|
||||
storageClassName string
|
||||
componentType string
|
||||
}
|
||||
|
||||
type queryOptions struct {
|
||||
metricFilter string
|
||||
namedMetrics []string
|
||||
|
||||
start time.Time
|
||||
end time.Time
|
||||
time time.Time
|
||||
step time.Duration
|
||||
|
||||
target string
|
||||
identifier string
|
||||
order string
|
||||
page int
|
||||
limit int
|
||||
|
||||
option monitoring.QueryOption
|
||||
}
|
||||
|
||||
func (q queryOptions) isRangeQuery() bool {
|
||||
return !q.time.IsZero()
|
||||
}
|
||||
|
||||
func (q queryOptions) shouldSort() bool {
|
||||
return q.target != "" && q.identifier != ""
|
||||
}
|
||||
|
||||
func parseRequestParams(req *restful.Request) reqParams {
|
||||
var r reqParams
|
||||
r.time = req.QueryParameter("time")
|
||||
r.start = req.QueryParameter("start")
|
||||
r.end = req.QueryParameter("end")
|
||||
r.step = req.QueryParameter("step")
|
||||
r.target = req.QueryParameter("sort_metric")
|
||||
r.order = req.QueryParameter("sort_type")
|
||||
r.page = req.QueryParameter("page")
|
||||
r.limit = req.QueryParameter("limit")
|
||||
r.metricFilter = req.QueryParameter("metrics_filter")
|
||||
r.resourceFilter = req.QueryParameter("resources_filter")
|
||||
r.nodeName = req.PathParameter("node")
|
||||
r.workspaceName = req.PathParameter("workspace")
|
||||
r.namespaceName = req.PathParameter("namespace")
|
||||
r.workloadKind = req.PathParameter("kind")
|
||||
r.workloadName = req.PathParameter("workload")
|
||||
r.podName = req.PathParameter("pod")
|
||||
r.containerName = req.PathParameter("container")
|
||||
r.pvcName = req.PathParameter("pvc")
|
||||
r.storageClassName = req.PathParameter("storageclass")
|
||||
r.componentType = req.PathParameter("component")
|
||||
return r
|
||||
}
|
||||
|
||||
func (h handler) makeQueryOptions(r reqParams, lvl monitoring.Level) (q queryOptions, err error) {
|
||||
if r.resourceFilter == "" {
|
||||
r.resourceFilter = DefaultFilter
|
||||
}
|
||||
|
||||
q.metricFilter = r.metricFilter
|
||||
if r.metricFilter == "" {
|
||||
q.metricFilter = DefaultFilter
|
||||
}
|
||||
|
||||
switch lvl {
|
||||
case monitoring.LevelCluster:
|
||||
q.option = monitoring.ClusterOption{}
|
||||
q.namedMetrics = model.ClusterMetrics
|
||||
case monitoring.LevelNode:
|
||||
q.identifier = model.IdentifierNode
|
||||
q.namedMetrics = model.NodeMetrics
|
||||
q.option = monitoring.NodeOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
NodeName: r.nodeName,
|
||||
}
|
||||
case monitoring.LevelWorkspace:
|
||||
q.identifier = model.IdentifierWorkspace
|
||||
q.namedMetrics = model.WorkspaceMetrics
|
||||
q.option = monitoring.WorkspaceOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
WorkspaceName: r.workspaceName,
|
||||
}
|
||||
case monitoring.LevelNamespace:
|
||||
q.identifier = model.IdentifierNamespace
|
||||
q.namedMetrics = model.NamespaceMetrics
|
||||
q.option = monitoring.NamespaceOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
WorkspaceName: r.workspaceName,
|
||||
NamespaceName: r.namespaceName,
|
||||
}
|
||||
case monitoring.LevelWorkload:
|
||||
q.identifier = model.IdentifierWorkload
|
||||
q.namedMetrics = model.WorkloadMetrics
|
||||
q.option = monitoring.WorkloadOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
NamespaceName: r.namespaceName,
|
||||
WorkloadKind: r.workloadKind,
|
||||
}
|
||||
case monitoring.LevelPod:
|
||||
q.identifier = model.IdentifierPod
|
||||
q.namedMetrics = model.PodMetrics
|
||||
q.option = monitoring.PodOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
NodeName: r.nodeName,
|
||||
NamespaceName: r.namespaceName,
|
||||
WorkloadKind: r.workloadKind,
|
||||
WorkloadName: r.workloadName,
|
||||
PodName: r.podName,
|
||||
}
|
||||
case monitoring.LevelContainer:
|
||||
q.identifier = model.IdentifierContainer
|
||||
q.namedMetrics = model.ContainerMetrics
|
||||
q.option = monitoring.ContainerOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
NamespaceName: r.namespaceName,
|
||||
PodName: r.podName,
|
||||
ContainerName: r.containerName,
|
||||
}
|
||||
case monitoring.LevelPVC:
|
||||
q.identifier = model.IdentifierPVC
|
||||
q.namedMetrics = model.PVCMetrics
|
||||
q.option = monitoring.PVCOption{
|
||||
ResourceFilter: r.resourceFilter,
|
||||
NamespaceName: r.namespaceName,
|
||||
StorageClassName: r.storageClassName,
|
||||
PersistentVolumeClaimName: r.pvcName,
|
||||
}
|
||||
case monitoring.LevelComponent:
|
||||
q.option = monitoring.ComponentOption{}
|
||||
switch r.componentType {
|
||||
case ComponentEtcd:
|
||||
q.namedMetrics = model.EtcdMetrics
|
||||
case ComponentAPIServer:
|
||||
q.namedMetrics = model.APIServerMetrics
|
||||
case ComponentScheduler:
|
||||
q.namedMetrics = model.SchedulerMetrics
|
||||
}
|
||||
}
|
||||
|
||||
// Parse time params
|
||||
if r.start != "" && r.end != "" {
|
||||
startInt, err := strconv.ParseInt(r.start, 10, 64)
|
||||
if err != nil {
|
||||
return q, err
|
||||
}
|
||||
q.start = time.Unix(startInt, 0)
|
||||
|
||||
endInt, err := strconv.ParseInt(r.end, 10, 64)
|
||||
if err != nil {
|
||||
return q, err
|
||||
}
|
||||
q.end = time.Unix(endInt, 0)
|
||||
|
||||
if r.step == "" {
|
||||
q.step = DefaultStep
|
||||
} else {
|
||||
q.step, err = time.ParseDuration(r.step)
|
||||
if err != nil {
|
||||
return q, err
|
||||
}
|
||||
}
|
||||
|
||||
if q.start.After(q.end) {
|
||||
return q, errors.New(ErrInvalidStartEnd)
|
||||
}
|
||||
} else if r.start == "" && r.end == "" {
|
||||
if r.time == "" {
|
||||
q.time = time.Now()
|
||||
} else {
|
||||
timeInt, err := strconv.ParseInt(r.time, 10, 64)
|
||||
if err != nil {
|
||||
return q, err
|
||||
}
|
||||
q.time = time.Unix(timeInt, 0)
|
||||
}
|
||||
} else {
|
||||
return q, errors.Errorf(ErrParamConflict)
|
||||
}
|
||||
|
||||
// Ensure query start time to be after the namespace creation time
|
||||
if r.namespaceName != "" {
|
||||
ns, err := h.k.CoreV1().Namespaces().Get(r.namespaceName, corev1.GetOptions{})
|
||||
if err != nil {
|
||||
return q, err
|
||||
}
|
||||
|
||||
cts := ns.CreationTimestamp.Time
|
||||
if q.start.Before(cts) {
|
||||
q.start = cts
|
||||
}
|
||||
if q.end.Before(cts) {
|
||||
return q, errors.New(ErrNoHit)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse sorting and paging params
|
||||
if r.target != "" {
|
||||
q.page = DefaultPage
|
||||
q.limit = DefaultLimit
|
||||
if q.order != model.OrderAscending {
|
||||
r.order = DefaultOrder
|
||||
}
|
||||
if r.page != "" {
|
||||
q.page, err = strconv.Atoi(r.page)
|
||||
if err != nil || q.page <= 0 {
|
||||
return q, errors.New(ErrInvalidPage)
|
||||
}
|
||||
}
|
||||
if r.limit != "" {
|
||||
q.limit, err = strconv.Atoi(r.limit)
|
||||
if err != nil || q.limit <= 0 {
|
||||
return q, errors.New(ErrInvalidLimit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
148
pkg/kapis/monitoring/v1alpha3/helper_test.go
Normal file
148
pkg/kapis/monitoring/v1alpha3/helper_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package v1alpha3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
model "kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParseRequestParams(t *testing.T) {
|
||||
tests := []struct {
|
||||
params reqParams
|
||||
lvl monitoring.Level
|
||||
namespace corev1.Namespace
|
||||
expected queryOptions
|
||||
expectedErr bool
|
||||
}{
|
||||
{
|
||||
params: reqParams{
|
||||
time: "abcdef",
|
||||
},
|
||||
lvl: monitoring.LevelCluster,
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
params: reqParams{
|
||||
time: "1585831995",
|
||||
},
|
||||
lvl: monitoring.LevelCluster,
|
||||
expected: queryOptions{
|
||||
time: time.Unix(1585831995, 0),
|
||||
metricFilter: ".*",
|
||||
namedMetrics: model.ClusterMetrics,
|
||||
option: monitoring.ClusterOption{},
|
||||
},
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
params: reqParams{
|
||||
start: "1585830000",
|
||||
end: "1585839999",
|
||||
step: "1m",
|
||||
namespaceName: "default",
|
||||
},
|
||||
lvl: monitoring.LevelNamespace,
|
||||
namespace: corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
CreationTimestamp: metav1.Time{
|
||||
Time: time.Unix(1585836666, 0),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: queryOptions{
|
||||
start: time.Unix(1585836666, 0),
|
||||
end: time.Unix(1585839999, 0),
|
||||
step: time.Minute,
|
||||
identifier: model.IdentifierNamespace,
|
||||
metricFilter: ".*",
|
||||
namedMetrics: model.NamespaceMetrics,
|
||||
option: monitoring.NamespaceOption{
|
||||
ResourceFilter: ".*",
|
||||
NamespaceName: "default",
|
||||
},
|
||||
},
|
||||
expectedErr: false,
|
||||
},
|
||||
{
|
||||
params: reqParams{
|
||||
start: "1585830000",
|
||||
end: "1585839999",
|
||||
step: "1m",
|
||||
namespaceName: "default",
|
||||
},
|
||||
lvl: monitoring.LevelNamespace,
|
||||
namespace: corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
CreationTimestamp: metav1.Time{
|
||||
Time: time.Unix(1589999999, 0),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
params: reqParams{
|
||||
start: "1585830000",
|
||||
end: "1585839999",
|
||||
step: "1m",
|
||||
namespaceName: "non-exist",
|
||||
},
|
||||
lvl: monitoring.LevelNamespace,
|
||||
namespace: corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
CreationTimestamp: metav1.Time{
|
||||
Time: time.Unix(1589999999, 0),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedErr: true,
|
||||
},
|
||||
{
|
||||
params: reqParams{
|
||||
time: "1585830000",
|
||||
componentType: "etcd",
|
||||
metricFilter: "etcd_server_list",
|
||||
},
|
||||
lvl: monitoring.LevelComponent,
|
||||
expected: queryOptions{
|
||||
time: time.Unix(1585830000, 0),
|
||||
metricFilter: "etcd_server_list",
|
||||
namedMetrics: model.EtcdMetrics,
|
||||
option: monitoring.ComponentOption{},
|
||||
},
|
||||
expectedErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
client := fake.NewSimpleClientset(&tt.namespace)
|
||||
handler := newHandler(client, nil)
|
||||
|
||||
result, err := handler.makeQueryOptions(tt.params, tt.lvl)
|
||||
if err != nil {
|
||||
if !tt.expectedErr {
|
||||
t.Fatalf("unexpected err: %s.", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if tt.expectedErr {
|
||||
t.Fatalf("failed to catch error.")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(result, tt.expected) {
|
||||
t.Fatalf("unexpected return: %v.", result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,16 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package v1alpha2
|
||||
package v1alpha3
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api/monitoring/v1alpha2"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
model "kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"net/http"
|
||||
)
|
||||
@@ -36,7 +36,7 @@ const (
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient monitoring.Interface) error {
|
||||
func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monitoringClient monitoring.Interface) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
h := newHandler(k8sClient, monitoringClient)
|
||||
@@ -50,8 +50,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes").
|
||||
@@ -68,8 +68,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NodeMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}").
|
||||
@@ -82,8 +82,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NodeMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/workspaces").
|
||||
@@ -100,8 +100,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}").
|
||||
@@ -114,8 +114,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").
|
||||
@@ -133,8 +133,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces").
|
||||
@@ -151,8 +151,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").
|
||||
@@ -165,8 +165,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads").
|
||||
@@ -184,8 +184,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkloadMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{kind}").
|
||||
@@ -204,8 +204,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkloadMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods").
|
||||
@@ -223,8 +223,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PodMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").
|
||||
@@ -238,8 +238,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PodMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{kind}/{workload}/pods").
|
||||
@@ -259,8 +259,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PodMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods").
|
||||
@@ -278,8 +278,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PodMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/nodes/{node}/pods/{pod}").
|
||||
@@ -293,8 +293,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PodMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers").
|
||||
@@ -313,8 +313,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ContainerMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers/{container}").
|
||||
@@ -329,8 +329,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ContainerMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
|
||||
@@ -348,8 +348,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PVCMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/persistentvolumeclaims").
|
||||
@@ -367,8 +367,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("page", "The page number. This field paginates result data of each metric, then returns a specific page. For example, setting **page** to 2 returns the second page. It only applies to sorted metric data.").DataType("integer").Required(false)).
|
||||
Param(ws.QueryParameter("limit", "Page size, the maximum number of results in a single page. Defaults to 5.").DataType("integer").Required(false).DefaultValue("5")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PVCMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}").
|
||||
@@ -382,8 +382,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.PVCMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET("/components/{component}").
|
||||
@@ -396,8 +396,8 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, monitoringClient
|
||||
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
|
||||
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ComponentMetricsTag}).
|
||||
Writes(v1alpha2.APIResponse{}).
|
||||
Returns(http.StatusOK, RespOK, v1alpha2.APIResponse{})).
|
||||
Writes(model.Metrics{}).
|
||||
Returns(http.StatusOK, RespOK, model.Metrics{})).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
c.Add(ws)
|
||||
@@ -49,6 +49,7 @@ func AddToContainer(c *restful.Container, client kubernetes.Interface, factory i
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
|
||||
To(handler.handleListNamespaceResources).
|
||||
Deprecate().
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("Namespace level resource query").
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
@@ -66,9 +67,10 @@ func AddToContainer(c *restful.Container, client kubernetes.Interface, factory i
|
||||
|
||||
webservice.Route(webservice.GET("/{resources}").
|
||||
To(handler.handleListNamespaceResources).
|
||||
Deprecate().
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}).
|
||||
Doc("Cluster level resource query").
|
||||
Doc("Cluster level resources").
|
||||
Param(webservice.PathParameter("resources", "cluster level resource type, e.g. nodes,workspaces,storageclasses,clusterroles.")).
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
namespacedResourceGetter *resource.NamespacedResourceGetter
|
||||
namespacedResourceGetter *resource.ResourceGetter
|
||||
componentsGetter components.ComponentsGetter
|
||||
}
|
||||
|
||||
@@ -22,22 +22,8 @@ func New(factory informers.InformerFactory) *Handler {
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) handleGetNamespacedResource(request *restful.Request, response *restful.Response) {
|
||||
resource := request.PathParameter("resources")
|
||||
namespace := request.PathParameter("namespace")
|
||||
name := request.PathParameter("name")
|
||||
|
||||
result, err := h.namespacedResourceGetter.Get(resource, namespace, name)
|
||||
if err != nil {
|
||||
api.HandleInternalError(response, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteHeaderAndEntity(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// handleListNamedResource retrieves namespaced scope resources
|
||||
func (h Handler) handleListNamespacedResource(request *restful.Request, response *restful.Response) {
|
||||
// handleListResources retrieves resources
|
||||
func (h Handler) handleListResources(request *restful.Request, response *restful.Response) {
|
||||
query := query.ParseQueryParameter(request)
|
||||
resource := request.PathParameter("resources")
|
||||
namespace := request.PathParameter("namespace")
|
||||
@@ -48,7 +34,7 @@ func (h Handler) handleListNamespacedResource(request *restful.Request, response
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteHeaderAndEntity(http.StatusOK, result)
|
||||
response.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h Handler) handleGetComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
|
||||
@@ -45,14 +45,26 @@ func AddToContainer(c *restful.Container, informerFactory informers.InformerFact
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
handler := New(informerFactory)
|
||||
|
||||
webservice.Route(webservice.GET("/{resources}").
|
||||
To(handler.handleListResources).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{tagNamespacedResource}).
|
||||
Doc("Cluster level resources").
|
||||
Param(webservice.PathParameter("resources", "cluster level resource type, e.g. pods,jobs,configmaps,services.")).
|
||||
Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)).
|
||||
Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")).
|
||||
Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)).
|
||||
Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")).
|
||||
Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, api.ListResult{}))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
|
||||
To(handler.handleGetNamespacedResource).
|
||||
To(handler.handleListResources).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{tagNamespacedResource}).
|
||||
Doc("Namespace level resource query").
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("resources", "namespace level resource type, e.g. pods,jobs,configmaps,services.")).
|
||||
Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)).
|
||||
Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=0")).
|
||||
Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")).
|
||||
Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)).
|
||||
Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")).
|
||||
Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")).
|
||||
|
||||
@@ -1,196 +1,60 @@
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/emicklei/go-restful"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/request"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||
"kubesphere.io/kubesphere/pkg/models/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/tenant"
|
||||
apierr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type tenantHandler struct {
|
||||
tenant tenant.Interface
|
||||
am am.AccessManagementInterface
|
||||
}
|
||||
|
||||
func newTenantHandler(k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) *tenantHandler {
|
||||
func newTenantHandler(k8sClient k8s.Client, factory informers.InformerFactory) *tenantHandler {
|
||||
|
||||
return &tenantHandler{
|
||||
tenant: tenant.New(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory(), factory.KubeSphereSharedInformerFactory(), db),
|
||||
am: am.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()),
|
||||
tenant: tenant.New(k8sClient, factory),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
user, ok := request.UserFrom(req.Request.Context())
|
||||
|
||||
if err != nil {
|
||||
if !ok {
|
||||
err := errors.New("cannot obtain user info")
|
||||
klog.Errorln(err)
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
api.HandleForbidden(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) DescribeWorkspace(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
result, err := h.tenant.DescribeWorkspace(username, workspaceName)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
api.HandleNotFound(resp, nil, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
// /workspaces/{workspace}/members/{username}/namespaces
|
||||
if username == "" {
|
||||
// /workspaces/{workspace}/namespaces
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
conditions.Match[constants.WorkspaceLabelKey] = workspace
|
||||
|
||||
result, err := h.tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
namespaces := make([]*v1.Namespace, 0)
|
||||
|
||||
for _, item := range result.Items {
|
||||
namespaces = append(namespaces, item.(*v1.Namespace).DeepCopy())
|
||||
}
|
||||
|
||||
namespaces = monitoring.GetNamespacesWithMetrics(namespaces)
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range namespaces {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
result.Items = items
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) CreateNamespace(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
var namespace v1.Namespace
|
||||
err := req.ReadEntity(&namespace)
|
||||
if err != nil {
|
||||
api.HandleNotFound(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = h.tenant.DescribeWorkspace("", workspace)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
api.HandleForbidden(resp, nil, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
created, err := h.tenant.CreateNamespace(workspace, &namespace, username)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsAlreadyExists(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) DeleteNamespace(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
err := h.tenant.DeleteNamespace(workspace, namespace)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
api.HandleNotFound(resp, nil, err)
|
||||
} else {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(apierr.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, nil, err)
|
||||
return
|
||||
}
|
||||
conditions.Match["workspace"] = workspace
|
||||
|
||||
result, err := h.tenant.ListDevopsProjects(conditions, orderBy, reverse, limit, offset)
|
||||
result, err := h.tenant.ListWorkspaces(user.GetName())
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Response) {
|
||||
user, ok := request.UserFrom(req.Request.Context())
|
||||
|
||||
if !ok {
|
||||
err := errors.New("cannot obtain user info")
|
||||
klog.Errorln(err)
|
||||
api.HandleForbidden(resp, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
worksapceName := req.PathParameter("workspace")
|
||||
|
||||
result, err := h.tenant.ListNamespaces(worksapceName, user.GetName())
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, nil, err)
|
||||
|
||||
@@ -23,16 +23,11 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -42,61 +37,21 @@ const (
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) error {
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
handler := newTenantHandler(k8sClient, factory, db)
|
||||
handler := newTenantHandler(k8sClient, factory)
|
||||
|
||||
ws.Route(ws.GET("/workspaces").
|
||||
To(handler.ListWorkspaces).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Doc("List all workspaces that belongs to the current user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}").
|
||||
To(handler.DescribeWorkspace).
|
||||
Doc("Describe the specified workspace").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, api.StatusOK, v1alpha1.Workspace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").
|
||||
To(handler.ListNamespaces).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("List the namespaces of the specified workspace for the current user").
|
||||
Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}/namespaces").
|
||||
To(handler.ListNamespaces).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "workspace member's username")).
|
||||
Doc("List the namespaces for the workspace member").
|
||||
Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/namespaces").
|
||||
To(handler.CreateNamespace).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("Create a namespace in the specified workspace").
|
||||
Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/namespaces/{namespace}").
|
||||
To(handler.DeleteNamespace).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("namespace", "the name of the namespace")).
|
||||
Doc("Delete the specified namespace from the workspace").
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/devops").
|
||||
To(handler.ListDevopsProjects).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.QueryParameter(params.PagingParam, "page").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(ws.QueryParameter(params.ConditionsParam, "query conditions").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Doc("List devops projects for the current user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
|
||||
c.Add(ws)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user