diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 874c9bcf75..b326ad0b9b 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -65,7 +65,7 @@ import ( alertingv2alpha1 "kubesphere.io/kubesphere/pkg/kapis/alerting/v2alpha1" clusterkapisv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/cluster/v1alpha1" configv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/config/v1alpha2" - crd "kubesphere.io/kubesphere/pkg/kapis/crd" + "kubesphere.io/kubesphere/pkg/kapis/crd" kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" edgeruntimev1alpha1 "kubesphere.io/kubesphere/pkg/kapis/edgeruntime/v1alpha1" gatewayv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/gateway/v1alpha1" @@ -85,6 +85,7 @@ import ( resourcev1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2" + tenantv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha3" terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2" "kubesphere.io/kubesphere/pkg/kapis/version" "kubesphere.io/kubesphere/pkg/models/auth" @@ -225,6 +226,8 @@ func (s *APIServer) installKubeSphereAPIs(stopCh <-chan struct{}) { s.KubernetesClient.Master())) urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions, stopCh)) + urlruntime.Must(tenantv1alpha3.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), + s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions, stopCh)) urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), rbacAuthorizer, s.KubernetesClient.Config(), s.Config.TerminalOptions)) urlruntime.Must(clusterkapisv1alpha1.AddToContainer(s.container, s.KubernetesClient.KubeSphere(), @@ -263,7 +266,7 @@ func (s *APIServer) installKubeSphereAPIs(stopCh <-chan struct{}) { // installCRDAPIs Install CRDs to the KAPIs with List and Get options func (s *APIServer) installCRDAPIs() { crds := &extv1.CustomResourceDefinitionList{} - //TODO Maybe we need a better label name + // TODO Maybe we need a better label name urlruntime.Must(s.RuntimeClient.List(context.TODO(), crds, runtimeclient.MatchingLabels{"kubesphere.io/resource-served": "true"})) urlruntime.Must(crd.AddToContainer(s.container, s.RuntimeClient, s.RuntimeCache, crds)) } diff --git a/pkg/kapis/tenant/v1alpha2/handler.go b/pkg/kapis/tenant/v1alpha2/handler.go index 06ba372061..5460b78fb6 100644 --- a/pkg/kapis/tenant/v1alpha2/handler.go +++ b/pkg/kapis/tenant/v1alpha2/handler.go @@ -56,7 +56,7 @@ type tenantHandler struct { meteringOptions *meteringclient.Options } -func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, +func NewTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, @@ -72,7 +72,7 @@ func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.In } } -func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Response) { +func (h *tenantHandler) ListWorkspaceTemplates(req *restful.Request, resp *restful.Response) { user, ok := request.UserFrom(req.Request.Context()) queryParam := query.ParseQueryParameter(req) @@ -83,7 +83,7 @@ func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Respo return } - result, err := h.tenant.ListWorkspaces(user, queryParam) + result, err := h.tenant.ListWorkspaceTemplates(user, queryParam) if err != nil { api.HandleInternalError(resp, nil, err) @@ -200,7 +200,7 @@ func (h *tenantHandler) CreateNamespace(request *restful.Request, response *rest response.WriteEntity(created) } -func (h *tenantHandler) CreateWorkspace(request *restful.Request, response *restful.Response) { +func (h *tenantHandler) CreateWorkspaceTemplate(request *restful.Request, response *restful.Response) { var workspace tenantv1alpha2.WorkspaceTemplate err := request.ReadEntity(&workspace) @@ -211,7 +211,7 @@ func (h *tenantHandler) CreateWorkspace(request *restful.Request, response *rest return } - created, err := h.tenant.CreateWorkspace(&workspace) + created, err := h.tenant.CreateWorkspaceTemplate(&workspace) if err != nil { klog.Error(err) @@ -226,7 +226,7 @@ func (h *tenantHandler) CreateWorkspace(request *restful.Request, response *rest response.WriteEntity(created) } -func (h *tenantHandler) DeleteWorkspace(request *restful.Request, response *restful.Response) { +func (h *tenantHandler) DeleteWorkspaceTemplate(request *restful.Request, response *restful.Response) { workspace := request.PathParameter("workspace") opts := metav1.DeleteOptions{} @@ -236,7 +236,7 @@ func (h *tenantHandler) DeleteWorkspace(request *restful.Request, response *rest opts = *metav1.NewDeleteOptions(0) } - err = h.tenant.DeleteWorkspace(workspace, opts) + err = h.tenant.DeleteWorkspaceTemplate(workspace, opts) if err != nil { klog.Error(err) @@ -251,7 +251,7 @@ func (h *tenantHandler) DeleteWorkspace(request *restful.Request, response *rest response.WriteEntity(servererr.None) } -func (h *tenantHandler) UpdateWorkspace(request *restful.Request, response *restful.Response) { +func (h *tenantHandler) UpdateWorkspaceTemplate(request *restful.Request, response *restful.Response) { workspaceName := request.PathParameter("workspace") var workspace tenantv1alpha2.WorkspaceTemplate @@ -270,7 +270,7 @@ func (h *tenantHandler) UpdateWorkspace(request *restful.Request, response *rest return } - updated, err := h.tenant.UpdateWorkspace(&workspace) + updated, err := h.tenant.UpdateWorkspaceTemplate(&workspace) if err != nil { klog.Error(err) @@ -289,10 +289,10 @@ func (h *tenantHandler) UpdateWorkspace(request *restful.Request, response *rest response.WriteEntity(updated) } -func (h *tenantHandler) DescribeWorkspace(request *restful.Request, response *restful.Response) { +func (h *tenantHandler) DescribeWorkspaceTemplate(request *restful.Request, response *restful.Response) { workspaceName := request.PathParameter("workspace") - workspace, err := h.tenant.DescribeWorkspace(workspaceName) + workspace, err := h.tenant.DescribeWorkspaceTemplate(workspaceName) if err != nil { klog.Error(err) @@ -518,7 +518,7 @@ func (h *tenantHandler) PatchNamespace(request *restful.Request, response *restf response.WriteEntity(patched) } -func (h *tenantHandler) PatchWorkspace(request *restful.Request, response *restful.Response) { +func (h *tenantHandler) PatchWorkspaceTemplate(request *restful.Request, response *restful.Response) { workspaceName := request.PathParameter("workspace") var data json.RawMessage err := request.ReadEntity(&data) @@ -528,7 +528,7 @@ func (h *tenantHandler) PatchWorkspace(request *restful.Request, response *restf return } - patched, err := h.tenant.PatchWorkspace(workspaceName, data) + patched, err := h.tenant.PatchWorkspaceTemplate(workspaceName, data) if err != nil { klog.Error(err) diff --git a/pkg/kapis/tenant/v1alpha2/register.go b/pkg/kapis/tenant/v1alpha2/register.go index ae1228cd56..58317cf861 100644 --- a/pkg/kapis/tenant/v1alpha2/register.go +++ b/pkg/kapis/tenant/v1alpha2/register.go @@ -19,15 +19,12 @@ package v1alpha2 import ( "net/http" - "sigs.k8s.io/controller-runtime/pkg/cache" - - "kubesphere.io/kubesphere/pkg/models/metering" - "github.com/emicklei/go-restful" restfulspec "github.com/emicklei/go-restful-openapi" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/cache" quotav1alpha2 "kubesphere.io/api/quota/v1alpha2" tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" @@ -43,6 +40,7 @@ import ( "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models/iam/am" + "kubesphere.io/kubesphere/pkg/models/metering" "kubesphere.io/kubesphere/pkg/models/monitoring" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" "kubesphere.io/kubesphere/pkg/server/errors" @@ -70,7 +68,7 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson} ws := runtime.NewWebService(GroupVersion) - handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, stopCh) + handler := NewTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, stopCh) ws.Route(ws.GET("/clusters"). To(handler.ListClusters). @@ -79,21 +77,21 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s Metadata(restfulspec.KeyOpenAPITags, []string{constants.UserResourceTag})) ws.Route(ws.POST("/workspaces"). - To(handler.CreateWorkspace). + To(handler.CreateWorkspaceTemplate). Reads(tenantv1alpha2.WorkspaceTemplate{}). Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). Doc("Create workspace."). Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) ws.Route(ws.DELETE("/workspaces/{workspace}"). - To(handler.DeleteWorkspace). + To(handler.DeleteWorkspaceTemplate). Param(ws.PathParameter("workspace", "workspace name")). Returns(http.StatusOK, api.StatusOK, errors.None). Doc("Delete workspace."). Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) ws.Route(ws.PUT("/workspaces/{workspace}"). - To(handler.UpdateWorkspace). + To(handler.UpdateWorkspaceTemplate). Param(ws.PathParameter("workspace", "workspace name")). Reads(tenantv1alpha2.WorkspaceTemplate{}). Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). @@ -101,7 +99,7 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) ws.Route(ws.PATCH("/workspaces/{workspace}"). - To(handler.PatchWorkspace). + To(handler.PatchWorkspaceTemplate). Param(ws.PathParameter("workspace", "workspace name")). Consumes(mimePatch...). Reads(tenantv1alpha2.WorkspaceTemplate{}). @@ -110,13 +108,13 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) ws.Route(ws.GET("/workspaces"). - To(handler.ListWorkspaces). + To(handler.ListWorkspaceTemplates). Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). Doc("List all workspaces that belongs to the current user"). Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) ws.Route(ws.GET("/workspaces/{workspace}"). - To(handler.DescribeWorkspace). + To(handler.DescribeWorkspaceTemplate). Param(ws.PathParameter("workspace", "workspace name")). Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). Doc("Describe workspace."). diff --git a/pkg/kapis/tenant/v1alpha3/handler.go b/pkg/kapis/tenant/v1alpha3/handler.go new file mode 100644 index 0000000000..c1ea6d9335 --- /dev/null +++ b/pkg/kapis/tenant/v1alpha3/handler.go @@ -0,0 +1,80 @@ +/* +Copyright 2020 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 ( + "fmt" + + "github.com/emicklei/go-restful" + "k8s.io/client-go/kubernetes" + "k8s.io/klog" + + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/apiserver/request" + kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/models/iam/am" + resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" + "kubesphere.io/kubesphere/pkg/models/tenant" + "kubesphere.io/kubesphere/pkg/simple/client/auditing" + "kubesphere.io/kubesphere/pkg/simple/client/events" + "kubesphere.io/kubesphere/pkg/simple/client/logging" + meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering" + monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring" +) + +type tenantHandler struct { + tenant tenant.Interface + meteringOptions *meteringclient.Options +} + +func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, + evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client, + am am.AccessManagementInterface, authorizer authorizer.Authorizer, + monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, + meteringOptions *meteringclient.Options, stopCh <-chan struct{}) *tenantHandler { + + if meteringOptions == nil || meteringOptions.RetentionDay == "" { + meteringOptions = &meteringclient.DefaultMeteringOption + } + + return &tenantHandler{ + tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourceGetter, stopCh), + meteringOptions: meteringOptions, + } +} + +func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Response) { + queryParam := query.ParseQueryParameter(req) + 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 + } + + result, err := h.tenant.ListWorkspaces(user, queryParam) + if err != nil { + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteEntity(result) +} diff --git a/pkg/kapis/tenant/v1alpha3/register.go b/pkg/kapis/tenant/v1alpha3/register.go new file mode 100644 index 0000000000..4dab916c4b --- /dev/null +++ b/pkg/kapis/tenant/v1alpha3/register.go @@ -0,0 +1,120 @@ +/* +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 ( + "net/http" + + "github.com/emicklei/go-restful" + restfulspec "github.com/emicklei/go-restful-openapi" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/cache" + + tenantv1alpha2 "kubesphere.io/api/tenant/v1alpha2" + + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" + "kubesphere.io/kubesphere/pkg/apiserver/runtime" + kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2" + "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/models/iam/am" + resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" + "kubesphere.io/kubesphere/pkg/server/errors" + "kubesphere.io/kubesphere/pkg/simple/client/auditing" + "kubesphere.io/kubesphere/pkg/simple/client/events" + "kubesphere.io/kubesphere/pkg/simple/client/logging" + meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering" + monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring" +) + +const ( + GroupName = "tenant.kubesphere.io" +) + +var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha3"} + +func Resource(resource string) schema.GroupResource { + return GroupVersion.WithResource(resource).GroupResource() +} + +func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface, + ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client, + auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, + monitoringclient monitoringclient.Interface, cache cache.Cache, meteringOptions *meteringclient.Options, stopCh <-chan struct{}) error { + mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson} + + ws := runtime.NewWebService(GroupVersion) + v1alpha2Handler := v1alpha2.NewTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, stopCh) + handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions, stopCh) + + ws.Route(ws.POST("/workspacetemplates"). + To(v1alpha2Handler.CreateWorkspaceTemplate). + Reads(tenantv1alpha2.WorkspaceTemplate{}). + Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). + Doc("Create workspace."). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) + + ws.Route(ws.DELETE("/workspacetemplates/{workspace}"). + To(v1alpha2Handler.DeleteWorkspaceTemplate). + Param(ws.PathParameter("workspace", "workspace name")). + Returns(http.StatusOK, api.StatusOK, errors.None). + Doc("Delete workspace."). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) + + ws.Route(ws.PUT("/workspacetemplates/{workspace}"). + To(v1alpha2Handler.UpdateWorkspaceTemplate). + Param(ws.PathParameter("workspace", "workspace name")). + Reads(tenantv1alpha2.WorkspaceTemplate{}). + Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). + Doc("Update workspace."). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) + + ws.Route(ws.PATCH("/workspacetemplates/{workspace}"). + To(v1alpha2Handler.PatchWorkspaceTemplate). + Param(ws.PathParameter("workspace", "workspace name")). + Consumes(mimePatch...). + Reads(tenantv1alpha2.WorkspaceTemplate{}). + Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). + Doc("Update workspace."). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) + + ws.Route(ws.GET("/workspacetemplates"). + To(v1alpha2Handler.ListWorkspaceTemplates). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Doc("List all workspaces that belongs to the current user"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) + + ws.Route(ws.GET("/workspacetemplates/{workspace}"). + To(v1alpha2Handler.DescribeWorkspaceTemplate). + Param(ws.PathParameter("workspace", "workspace name")). + Returns(http.StatusOK, api.StatusOK, tenantv1alpha2.WorkspaceTemplate{}). + Doc("Describe workspace."). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceTag})) + + 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.WorkspaceTag})) + + c.Add(ws) + return nil +} diff --git a/pkg/models/tenant/metering.go b/pkg/models/tenant/metering.go index 301fa81438..9f22787b29 100644 --- a/pkg/models/tenant/metering.go +++ b/pkg/models/tenant/metering.go @@ -188,7 +188,7 @@ func (t *tenantOperator) makeQueryOptions(user user.Info, q meteringv1alpha1.Que var wsList *api.ListResult qu := query.New() qu.LabelSelector = q.LabelSelector - wsList, err = t.ListWorkspaces(user, qu) + wsList, err = t.ListWorkspaceTemplates(user, qu) if err != nil { return qo, err } @@ -703,7 +703,7 @@ func (t *tenantOperator) transformMetricData(metrics monitoringmodel.Metrics) me for _, metric := range metrics.Results { metricName := metric.MetricName for _, metricValue := range metric.MetricValues { - //metricValue.SumValue + // metricValue.SumValue podName := metricValue.Metadata["pod"] if s, err := strconv.ParseFloat(metricValue.SumValue, 64); err != nil { klog.Error("failed to parse string to float64") diff --git a/pkg/models/tenant/tenant.go b/pkg/models/tenant/tenant.go index fc4906ea4d..47d5ce7f92 100644 --- a/pkg/models/tenant/tenant.go +++ b/pkg/models/tenant/tenant.go @@ -24,8 +24,6 @@ import ( "strings" "time" - "kubesphere.io/kubesphere/pkg/models/openpitrix" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -58,6 +56,7 @@ import ( "kubesphere.io/kubesphere/pkg/models/logging" "kubesphere.io/kubesphere/pkg/models/metering" "kubesphere.io/kubesphere/pkg/models/monitoring" + "kubesphere.io/kubesphere/pkg/models/openpitrix" resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" resourcesv1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" @@ -72,15 +71,17 @@ import ( const orphanFinalizer = "orphan.finalizers.kubesphere.io" type Interface interface { - ListWorkspaces(user user.Info, query *query.Query) (*api.ListResult, error) + ListWorkspaces(user user.Info, queryParam *query.Query) (*api.ListResult, error) + ListWorkspaceTemplates(user user.Info, query *query.Query) (*api.ListResult, error) + CreateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) + DeleteWorkspaceTemplate(workspace string, opts metav1.DeleteOptions) error + UpdateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) + PatchWorkspaceTemplate(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error) + DescribeWorkspaceTemplate(workspace string) (*tenantv1alpha2.WorkspaceTemplate, error) ListNamespaces(user user.Info, workspace string, query *query.Query) (*api.ListResult, error) ListDevOpsProjects(user user.Info, workspace string, query *query.Query) (*api.ListResult, error) ListFederatedNamespaces(info user.Info, workspace string, param *query.Query) (*api.ListResult, error) CreateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) - CreateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) - DeleteWorkspace(workspace string, opts metav1.DeleteOptions) error - UpdateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) - DescribeWorkspace(workspace string) (*tenantv1alpha2.WorkspaceTemplate, error) ListWorkspaceClusters(workspace string) (*api.ListResult, error) Events(user user.Info, queryParam *eventsv1alpha1.Query) (*eventsv1alpha1.APIResponse, error) QueryLogs(user user.Info, query *loggingv1alpha2.Query) (*loggingv1alpha2.APIResponse, error) @@ -90,7 +91,6 @@ type Interface interface { DeleteNamespace(workspace, namespace string) error UpdateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) PatchNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) - PatchWorkspace(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error) ListClusters(info user.Info) (*api.ListResult, error) Metering(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (monitoring.Metrics, error) MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (metering.ResourceStatistic, error) @@ -134,6 +134,69 @@ func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ks } func (t *tenantOperator) ListWorkspaces(user user.Info, queryParam *query.Query) (*api.ListResult, error) { + listWS := authorizer.AttributesRecord{ + User: user, + Verb: "list", + APIGroup: "*", + Resource: "workspaces", + ResourceRequest: true, + ResourceScope: request.GlobalScope, + } + + decision, _, err := t.authorizer.Authorize(listWS) + if err != nil { + klog.Error(err) + return nil, err + } + + // allowed to list all workspaces + if decision == authorizer.DecisionAllow { + result, err := t.resourceGetter.List(tenantv1alpha1.ResourcePluralWorkspace, "", queryParam) + if err != nil { + klog.Error(err) + return nil, err + } + return result, nil + } + + // retrieving associated resources through role binding + workspaceRoleBindings, err := t.am.ListWorkspaceRoleBindings(user.GetName(), user.GetGroups(), "") + if err != nil { + klog.Error(err) + return nil, err + } + + workspaces := make([]runtime.Object, 0) + for _, roleBinding := range workspaceRoleBindings { + workspaceName := roleBinding.Labels[tenantv1alpha1.WorkspaceLabel] + obj, err := t.resourceGetter.Get(tenantv1alpha1.ResourcePluralWorkspace, "", workspaceName) + if errors.IsNotFound(err) { + klog.Warningf("workspace role binding: %+v found but workspace not exist", roleBinding.Name) + continue + } + if err != nil { + klog.Error(err) + return nil, err + } + workspace := obj.(*tenantv1alpha1.Workspace) + // label matching selector, remove duplicate entity + if queryParam.Selector().Matches(labels.Set(workspace.Labels)) && + !contains(workspaces, workspace) { + workspaces = append(workspaces, workspace) + } + } + + // use default pagination search logic + result := resources.DefaultList(workspaces, queryParam, func(left runtime.Object, right runtime.Object, field query.Field) bool { + return resources.DefaultObjectMetaCompare(left.(*tenantv1alpha1.Workspace).ObjectMeta, right.(*tenantv1alpha1.Workspace).ObjectMeta, field) + }, func(workspace runtime.Object, filter query.Filter) bool { + return resources.DefaultObjectMetaFilter(workspace.(*tenantv1alpha1.Workspace).ObjectMeta, filter) + }) + + return result, nil +} + +func (t *tenantOperator) ListWorkspaceTemplates(user user.Info, queryParam *query.Query) (*api.ListResult, error) { listWS := authorizer.AttributesRecord{ User: user, @@ -396,19 +459,19 @@ func (t *tenantOperator) PatchNamespace(workspace string, namespace *corev1.Name return t.k8sclient.CoreV1().Namespaces().Patch(context.Background(), namespace.Name, types.MergePatchType, data, metav1.PatchOptions{}) } -func (t *tenantOperator) PatchWorkspace(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error) { +func (t *tenantOperator) PatchWorkspaceTemplate(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error) { return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Patch(context.Background(), workspace, types.MergePatchType, data, metav1.PatchOptions{}) } -func (t *tenantOperator) CreateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) { +func (t *tenantOperator) CreateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) { return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Create(context.Background(), workspace, metav1.CreateOptions{}) } -func (t *tenantOperator) UpdateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) { +func (t *tenantOperator) UpdateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) { return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Update(context.Background(), workspace, metav1.UpdateOptions{}) } -func (t *tenantOperator) DescribeWorkspace(workspace string) (*tenantv1alpha2.WorkspaceTemplate, error) { +func (t *tenantOperator) DescribeWorkspaceTemplate(workspace string) (*tenantv1alpha2.WorkspaceTemplate, error) { obj, err := t.resourceGetter.Get(tenantv1alpha2.ResourcePluralWorkspaceTemplate, "", workspace) if err != nil { klog.Error(err) @@ -416,8 +479,9 @@ func (t *tenantOperator) DescribeWorkspace(workspace string) (*tenantv1alpha2.Wo } return obj.(*tenantv1alpha2.WorkspaceTemplate), nil } + func (t *tenantOperator) ListWorkspaceClusters(workspaceName string) (*api.ListResult, error) { - workspace, err := t.DescribeWorkspace(workspaceName) + workspace, err := t.DescribeWorkspaceTemplate(workspaceName) if err != nil { klog.Error(err) return nil, err @@ -457,6 +521,7 @@ func (t *tenantOperator) ListWorkspaceClusters(workspaceName string) (*api.ListR // In this case, you can either set spec: {} as above or remove spec field from your placement policy. The resource will not be propagated to member clusters. return &api.ListResult{Items: []interface{}{}, TotalItems: 0}, nil } + func (t *tenantOperator) ListClusters(user user.Info) (*api.ListResult, error) { listClustersInGlobalScope := authorizer.AttributesRecord{ @@ -510,7 +575,7 @@ func (t *tenantOperator) ListClusters(user user.Info) (*api.ListResult, error) { for _, roleBinding := range workspaceRoleBindings { workspaceName := roleBinding.Labels[tenantv1alpha1.WorkspaceLabel] - workspace, err := t.DescribeWorkspace(workspaceName) + workspace, err := t.DescribeWorkspaceTemplate(workspaceName) if err != nil { klog.Error(err) return nil, err @@ -542,10 +607,10 @@ func (t *tenantOperator) ListClusters(user user.Info) (*api.ListResult, error) { return &api.ListResult{Items: items, TotalItems: len(items)}, nil } -func (t *tenantOperator) DeleteWorkspace(workspace string, opts metav1.DeleteOptions) error { +func (t *tenantOperator) DeleteWorkspaceTemplate(workspace string, opts metav1.DeleteOptions) error { if opts.PropagationPolicy != nil && *opts.PropagationPolicy == metav1.DeletePropagationOrphan { - wsp, err := t.DescribeWorkspace(workspace) + wsp, err := t.DescribeWorkspaceTemplate(workspace) if err != nil { klog.Error(err) return err diff --git a/pkg/models/tenant/tenent_test.go b/pkg/models/tenant/tenent_test.go index 92f26a018a..4fc0164cc9 100644 --- a/pkg/models/tenant/tenent_test.go +++ b/pkg/models/tenant/tenent_test.go @@ -66,7 +66,7 @@ func TestTenantOperator_ListWorkspaces(t *testing.T) { } for i, test := range tests { - result, err := tenantOperator.ListWorkspaces(&user.DefaultInfo{Name: test.username}, query.New()) + result, err := tenantOperator.ListWorkspaceTemplates(&user.DefaultInfo{Name: test.username}, query.New()) if err != nil { if !reflect.DeepEqual(err, test.expectError) { diff --git a/tools/cmd/doc-gen/main.go b/tools/cmd/doc-gen/main.go index dc624562c8..c1d78e1868 100644 --- a/tools/cmd/doc-gen/main.go +++ b/tools/cmd/doc-gen/main.go @@ -24,11 +24,6 @@ import ( "io/ioutil" "log" - kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" - - "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" - "kubesphere.io/kubesphere/pkg/version" - "github.com/emicklei/go-restful" restfulspec "github.com/emicklei/go-restful-openapi" "github.com/go-openapi/loads" @@ -41,10 +36,12 @@ import ( "k8s.io/klog" "kubesphere.io/kubesphere/pkg/apiserver/runtime" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/informers" alertingv2alpha1 "kubesphere.io/kubesphere/pkg/kapis/alerting/v2alpha1" clusterkapisv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/cluster/v1alpha1" + kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2" monitoringv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3" networkv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/network/v1alpha2" @@ -56,10 +53,12 @@ import ( resourcesv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3" metricsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2" + tenantv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha3" terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2" "kubesphere.io/kubesphere/pkg/models/iam/group" "kubesphere.io/kubesphere/pkg/simple/client/alerting" "kubesphere.io/kubesphere/pkg/simple/client/k8s" + "kubesphere.io/kubesphere/pkg/version" ) var output string @@ -129,6 +128,7 @@ func generateSwaggerJson() []byte { urlruntime.Must(resourcesv1alpha2.AddToContainer(container, clientsets.Kubernetes(), informerFactory, "")) urlruntime.Must(resourcesv1alpha3.AddToContainer(container, informerFactory, nil)) urlruntime.Must(tenantv1alpha2.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)) + urlruntime.Must(tenantv1alpha3.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)) urlruntime.Must(terminalv1alpha2.AddToContainer(container, clientsets.Kubernetes(), nil, nil, nil)) urlruntime.Must(metricsv1alpha2.AddToContainer(nil, container, clientsets.Kubernetes(), nil)) urlruntime.Must(networkv1alpha2.AddToContainer(container, ""))