* feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> * feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> --------- Signed-off-by: ci-bot <ci-bot@kubesphere.io> Co-authored-by: ks-ci-bot <ks-ci-bot@example.com> Co-authored-by: joyceliu <joyceliu@yunify.com>
410 lines
11 KiB
Go
410 lines
11 KiB
Go
/*
|
|
* Please refer to the LICENSE file in the root directory of the project.
|
|
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
|
*/
|
|
|
|
package v1beta1
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/emicklei/go-restful/v3"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apiserver/pkg/authentication/user"
|
|
"k8s.io/klog/v2"
|
|
corev1alpha1 "kubesphere.io/api/core/v1alpha1"
|
|
quotav1alpha2 "kubesphere.io/api/quota/v1alpha2"
|
|
|
|
"kubesphere.io/kubesphere/pkg/api"
|
|
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
|
|
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
|
"kubesphere.io/kubesphere/pkg/apiserver/request"
|
|
servererr "kubesphere.io/kubesphere/pkg/server/errors"
|
|
"kubesphere.io/kubesphere/pkg/simple/client/overview"
|
|
)
|
|
|
|
func (h *handler) ListNamespaces(req *restful.Request, resp *restful.Response) {
|
|
workspace := req.PathParameter("workspace")
|
|
queryParam := query.ParseQueryParameter(req)
|
|
|
|
var workspaceMember user.Info
|
|
if username := req.PathParameter("workspacemember"); username != "" {
|
|
workspaceMember = &user.DefaultInfo{
|
|
Name: username,
|
|
}
|
|
} else {
|
|
requestUser, ok := request.UserFrom(req.Request.Context())
|
|
if !ok {
|
|
err := fmt.Errorf("cannot obtain user info")
|
|
klog.Errorln(err)
|
|
api.HandleForbidden(resp, nil, err)
|
|
return
|
|
}
|
|
workspaceMember = requestUser
|
|
}
|
|
|
|
result, err := h.tenant.ListNamespaces(workspaceMember, workspace, queryParam)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, nil, err)
|
|
return
|
|
}
|
|
|
|
resp.WriteEntity(result)
|
|
}
|
|
|
|
func (h *handler) CreateNamespace(request *restful.Request, response *restful.Response) {
|
|
workspace := request.PathParameter("workspace")
|
|
var namespace corev1.Namespace
|
|
|
|
err := request.ReadEntity(&namespace)
|
|
|
|
if err != nil {
|
|
klog.Error(err)
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
|
|
created, err := h.tenant.CreateNamespace(workspace, &namespace)
|
|
|
|
if err != nil {
|
|
klog.Error(err)
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, request, err)
|
|
return
|
|
}
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(created)
|
|
}
|
|
|
|
func (h *handler) ListWorkspaceClusters(request *restful.Request, response *restful.Response) {
|
|
workspaceName := request.PathParameter("workspace")
|
|
|
|
result, err := h.tenant.ListWorkspaceClusters(workspaceName)
|
|
|
|
if err != nil {
|
|
klog.Error(err)
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, request, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(result)
|
|
}
|
|
|
|
func (h *handler) DescribeNamespace(request *restful.Request, response *restful.Response) {
|
|
workspaceName := request.PathParameter("workspace")
|
|
namespaceName := request.PathParameter("namespace")
|
|
ns, err := h.tenant.DescribeNamespace(workspaceName, namespaceName)
|
|
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, request, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(ns)
|
|
}
|
|
|
|
func (h *handler) DeleteNamespace(request *restful.Request, response *restful.Response) {
|
|
workspaceName := request.PathParameter("workspace")
|
|
namespaceName := request.PathParameter("namespace")
|
|
|
|
err := h.tenant.DeleteNamespace(workspaceName, namespaceName)
|
|
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, request, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(servererr.None)
|
|
}
|
|
|
|
func (h *handler) UpdateNamespace(request *restful.Request, response *restful.Response) {
|
|
workspaceName := request.PathParameter("workspace")
|
|
namespaceName := request.PathParameter("namespace")
|
|
|
|
var namespace corev1.Namespace
|
|
err := request.ReadEntity(&namespace)
|
|
if err != nil {
|
|
klog.Error(err)
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
|
|
if namespaceName != namespace.Name {
|
|
err := fmt.Errorf("the name of the object (%s) does not match the name on the URL (%s)", namespace.Name, namespaceName)
|
|
klog.Errorf("%+v", err)
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
|
|
updated, err := h.tenant.UpdateNamespace(workspaceName, &namespace)
|
|
|
|
if err != nil {
|
|
klog.Error(err)
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, request, err)
|
|
return
|
|
}
|
|
if errors.IsBadRequest(err) {
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(updated)
|
|
}
|
|
|
|
func (h *handler) PatchNamespace(request *restful.Request, response *restful.Response) {
|
|
workspaceName := request.PathParameter("workspace")
|
|
namespaceName := request.PathParameter("namespace")
|
|
|
|
var namespace corev1.Namespace
|
|
err := request.ReadEntity(&namespace)
|
|
if err != nil {
|
|
klog.Error(err)
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
|
|
namespace.Name = namespaceName
|
|
|
|
patched, err := h.tenant.PatchNamespace(workspaceName, &namespace)
|
|
|
|
if err != nil {
|
|
klog.Error(err)
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, request, err)
|
|
return
|
|
}
|
|
if errors.IsBadRequest(err) {
|
|
api.HandleBadRequest(response, request, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(patched)
|
|
}
|
|
|
|
func (h *handler) ListClusters(r *restful.Request, response *restful.Response) {
|
|
user, ok := request.UserFrom(r.Request.Context())
|
|
|
|
if !ok {
|
|
response.WriteEntity([]interface{}{})
|
|
return
|
|
}
|
|
|
|
queryParam := query.ParseQueryParameter(r)
|
|
result, err := h.tenant.ListClusters(user, queryParam)
|
|
if err != nil {
|
|
klog.Error(err)
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, r, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, r, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(result)
|
|
}
|
|
|
|
func (h *handler) CreateWorkspaceResourceQuota(r *restful.Request, response *restful.Response) {
|
|
workspaceName := r.PathParameter("workspace")
|
|
resourceQuota := "av1alpha2.ResourceQuota{}
|
|
err := r.ReadEntity(resourceQuota)
|
|
if err != nil {
|
|
api.HandleBadRequest(response, r, err)
|
|
return
|
|
}
|
|
result, err := h.tenant.CreateWorkspaceResourceQuota(workspaceName, resourceQuota)
|
|
if err != nil {
|
|
api.HandleInternalError(response, r, err)
|
|
return
|
|
}
|
|
response.WriteEntity(result)
|
|
}
|
|
|
|
func (h *handler) DeleteWorkspaceResourceQuota(r *restful.Request, response *restful.Response) {
|
|
workspace := r.PathParameter("workspace")
|
|
resourceQuota := r.PathParameter("resourcequota")
|
|
|
|
if err := h.tenant.DeleteWorkspaceResourceQuota(workspace, resourceQuota); err != nil {
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, r, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, r, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(servererr.None)
|
|
}
|
|
|
|
func (h *handler) UpdateWorkspaceResourceQuota(r *restful.Request, response *restful.Response) {
|
|
workspaceName := r.PathParameter("workspace")
|
|
resourceQuotaName := r.PathParameter("resourcequota")
|
|
resourceQuota := "av1alpha2.ResourceQuota{}
|
|
err := r.ReadEntity(resourceQuota)
|
|
if err != nil {
|
|
api.HandleBadRequest(response, r, err)
|
|
return
|
|
}
|
|
|
|
if resourceQuotaName != resourceQuota.Name {
|
|
err := fmt.Errorf("the name of the object (%s) does not match the name on the URL (%s)", resourceQuota.Name, resourceQuotaName)
|
|
klog.Errorf("%+v", err)
|
|
api.HandleBadRequest(response, r, err)
|
|
return
|
|
}
|
|
|
|
result, err := h.tenant.UpdateWorkspaceResourceQuota(workspaceName, resourceQuota)
|
|
if err != nil {
|
|
api.HandleInternalError(response, r, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(result)
|
|
}
|
|
|
|
func (h *handler) DescribeWorkspaceResourceQuota(r *restful.Request, response *restful.Response) {
|
|
workspaceName := r.PathParameter("workspace")
|
|
resourceQuotaName := r.PathParameter("resourcequota")
|
|
|
|
resourceQuota, err := h.tenant.DescribeWorkspaceResourceQuota(workspaceName, resourceQuotaName)
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
api.HandleNotFound(response, r, err)
|
|
return
|
|
}
|
|
api.HandleInternalError(response, r, err)
|
|
return
|
|
}
|
|
|
|
response.WriteEntity(resourceQuota)
|
|
}
|
|
|
|
func (h *handler) GetWorkspaceMetrics(req *restful.Request, resp *restful.Response) {
|
|
workspace := req.PathParameter("workspace")
|
|
|
|
user, ok := request.UserFrom(req.Request.Context())
|
|
if !ok {
|
|
err := fmt.Errorf("cannot obtain user info")
|
|
klog.Errorln(err)
|
|
api.HandleForbidden(resp, nil, err)
|
|
return
|
|
}
|
|
parameter := query.ParseQueryParameter(req)
|
|
prefix := "workspace"
|
|
|
|
namespaces, err := h.tenant.ListNamespaces(user, workspace, parameter)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
|
|
metrics, err := h.counter.GetMetrics([]string{overview.WorkspaceRoleBindingCount, overview.WorkspaceRoleCount},
|
|
"", workspace, prefix)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
|
|
metrics.AddMetric(overview.CustomMetric(overview.NamespaceCount, prefix, namespaces.TotalItems))
|
|
|
|
_ = resp.WriteEntity(metrics)
|
|
|
|
}
|
|
|
|
func (h *handler) GetPlatformMetrics(req *restful.Request, resp *restful.Response) {
|
|
user, ok := request.UserFrom(req.Request.Context())
|
|
if !ok {
|
|
err := fmt.Errorf("cannot obtain user info")
|
|
klog.Errorln(err)
|
|
api.HandleForbidden(resp, nil, err)
|
|
return
|
|
}
|
|
parameter := query.ParseQueryParameter(req)
|
|
prefix := "platform"
|
|
|
|
metricNames := []string{overview.UserCount}
|
|
metrics, err := h.counter.GetMetrics(metricNames, "", "", prefix)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
|
|
// check if the user has permission to visit extensions
|
|
attr := authorizer.AttributesRecord{
|
|
User: user,
|
|
Verb: "list",
|
|
APIGroup: corev1alpha1.GroupName,
|
|
APIVersion: corev1alpha1.SchemeGroupVersion.Version,
|
|
Resource: "installplans",
|
|
ResourceRequest: true,
|
|
ResourceScope: request.GlobalScope,
|
|
}
|
|
|
|
decision, _, err := h.auth.Authorize(attr)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
|
|
if decision == authorizer.DecisionAllow {
|
|
// get installed extension count
|
|
installPlanList := &corev1alpha1.InstallPlanList{}
|
|
err = h.client.List(req.Request.Context(), installPlanList)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
metrics.AddMetric(overview.CustomMetric(overview.InstallPlanCount, prefix, len(installPlanList.Items)))
|
|
}
|
|
|
|
// get count of workspaces a tenant can access
|
|
workspaces, err := h.tenant.ListWorkspaceTemplates(user, parameter)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
if workspaces.TotalItems != 0 {
|
|
metrics.AddMetric(overview.CustomMetric(overview.WorkspaceCount, prefix, workspaces.TotalItems))
|
|
}
|
|
|
|
// get count of clusters a tenant can access
|
|
if parameter.LabelSelector == "" {
|
|
parameter.LabelSelector = "kubesphere.io/managed=true"
|
|
} else {
|
|
parameter.LabelSelector = fmt.Sprintf("%s,%s", parameter.LabelSelector, "kubesphere.io/managed=true")
|
|
}
|
|
clusters, err := h.tenant.ListClusters(user, parameter)
|
|
if err != nil {
|
|
api.HandleInternalError(resp, req, err)
|
|
return
|
|
}
|
|
if clusters.TotalItems != 0 {
|
|
metrics.AddMetric(overview.CustomMetric(overview.ClusterCount, prefix, clusters.TotalItems))
|
|
}
|
|
|
|
_ = resp.WriteEntity(metrics)
|
|
}
|