@@ -20,6 +20,9 @@ package authenticate
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -46,6 +49,10 @@ type User struct {
|
||||
Extra *map[string]interface{} `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
var requestInfoFactory = request.RequestInfoFactory{
|
||||
APIPrefixes: sets.NewString("api", "apis"),
|
||||
GrouplessAPIPrefixes: sets.NewString("api")}
|
||||
|
||||
func (h Auth) ServeHTTP(resp http.ResponseWriter, req *http.Request) (int, error) {
|
||||
for _, path := range h.Rule.ExceptedPath {
|
||||
if httpserver.Path(req.URL.Path).Matches(path) {
|
||||
@@ -91,10 +98,13 @@ func (h Auth) InjectContext(req *http.Request, token *jwt.Token) (*http.Request,
|
||||
}
|
||||
}
|
||||
|
||||
usr := &user.DefaultInfo{}
|
||||
|
||||
username, ok := payLoad["username"].(string)
|
||||
|
||||
if ok && username != "" {
|
||||
req.Header.Set("X-Token-Username", username)
|
||||
usr.Name = username
|
||||
}
|
||||
|
||||
uid := payLoad["uid"]
|
||||
@@ -103,19 +113,38 @@ func (h Auth) InjectContext(req *http.Request, token *jwt.Token) (*http.Request,
|
||||
switch uid.(type) {
|
||||
case int:
|
||||
req.Header.Set("X-Token-UID", strconv.Itoa(uid.(int)))
|
||||
usr.UID = strconv.Itoa(uid.(int))
|
||||
break
|
||||
case string:
|
||||
req.Header.Set("X-Token-UID", uid.(string))
|
||||
usr.UID = uid.(string)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
groups, ok := payLoad["groups"].([]string)
|
||||
|
||||
if ok && len(groups) > 0 {
|
||||
req.Header.Set("X-Token-Groups", strings.Join(groups, ","))
|
||||
usr.Groups = groups
|
||||
}
|
||||
|
||||
// hard code, support jenkins auth plugin
|
||||
if httpserver.Path(req.URL.Path).Matches("/apis/jenkins.kubesphere.io") || httpserver.Path(req.URL.Path).Matches("job") {
|
||||
req.SetBasicAuth(username, token.Raw)
|
||||
}
|
||||
|
||||
context := request.WithUser(req.Context(), usr)
|
||||
|
||||
requestInfo, err := requestInfoFactory.NewRequestInfo(req)
|
||||
|
||||
if err == nil {
|
||||
context = request.WithRequestInfo(context, requestInfo)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req = req.WithContext(context)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,9 @@ func (c Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request) (int,
|
||||
|
||||
attrs, err := getAuthorizerAttributes(r.Context())
|
||||
|
||||
// without authenticate, no requestInfo found in the context
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
return c.Next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
permitted, err := permissionValidate(attrs)
|
||||
|
||||
35
pkg/apis/addtoscheme_servicemesh_v1alpha2.go
Normal file
35
pkg/apis/addtoscheme_servicemesh_v1alpha2.go
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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 apis
|
||||
|
||||
import (
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
|
||||
"sigs.k8s.io/application/pkg/apis/app/v1beta1"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
|
||||
AddToSchemes = append(AddToSchemes, v1alpha2.SchemeBuilder.AddToScheme)
|
||||
|
||||
// Register networking.istio.io/v1alpha3
|
||||
AddToSchemes = append(AddToSchemes, v1alpha3.SchemeBuilder.AddToScheme)
|
||||
|
||||
// Register application scheme
|
||||
AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme)
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package v1alpha2
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/iam"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
@@ -209,6 +210,37 @@ func addWebService(c *restful.Container) error {
|
||||
Doc("Delete user from workspace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
tags = []string{"unstable"}
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").
|
||||
To(iam.UserNamespaceListHandler).
|
||||
Doc("Get namespace list").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(models.PageableResponse{}))
|
||||
ws.Route(ws.POST("/workspaces/{name}/namespaces").
|
||||
To(iam.NamespaceCreateHandler).
|
||||
Doc("Create namespace").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Writes(v1.Namespace{}))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}/namespaces/{namespace}").To(iam.NamespaceDeleteHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/workspaces/{name}/namespaces/{namespace}").To(iam.NamespaceCheckHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").To(iam.NamespaceCheckHandler))
|
||||
|
||||
// TODO move to /apis/resources.kubesphere.io/workspaces/{workspace}/members/{username}
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}/namespaces").To(iam.NamespacesListHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.GET("/workspaces/{name}/members/{username}/devops").To(iam.DevOpsProjectHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
// TODO /workspaces/{name}/roles/{role}
|
||||
ws.Route(ws.GET("/workspaces/{name}/roles/{role}").To(iam.WorkspaceRoles).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
// TODO move to /apis/resources.kubesphere.io/devops
|
||||
ws.Route(ws.GET("/workspaces/{name}/devops").To(iam.DevOpsProjectHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.POST("/workspaces/{name}/devops").To(iam.DevOpsProjectCreateHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
ws.Route(ws.DELETE("/workspaces/{name}/devops/{id}").To(iam.DevOpsProjectDeleteHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
// TODO merge into /groups
|
||||
ws.Route(ws.GET("/groups/count").To(iam.CountHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
ws.Route(ws.GET("/users/{name}/namespaces").To(iam.NamespacesListHandler).Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
|
||||
c.Add(ws)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -83,13 +83,29 @@ func addWebService(c *restful.Container) error {
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1"))
|
||||
|
||||
tags = []string{"Applications"}
|
||||
|
||||
webservice.Route(webservice.GET("/applications").
|
||||
To(resources.ApplicationHandler).
|
||||
Writes(models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Cluster level resource query").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||
Required(false).
|
||||
DataFormat("key=value,key~value").
|
||||
DefaultValue("")).
|
||||
Param(webservice.QueryParameter("cluster_id", "cluster id")).
|
||||
Param(webservice.QueryParameter("runtime_id", "runtime id")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "page").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
|
||||
To(resources.GetPvcListBySc).
|
||||
Doc("get user's kubectl pod").
|
||||
Param(webservice.PathParameter("username", "username")).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").
|
||||
To(resources.GetPodListByPvc))
|
||||
|
||||
tags = []string{"User resources"}
|
||||
|
||||
|
||||
18
pkg/apis/servicemesh/group.go
Normal file
18
pkg/apis/servicemesh/group.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 servicemesh contains servicemesh API versions
|
||||
package servicemesh
|
||||
16
pkg/apis/servicemesh/metrics/install/install.go
Normal file
16
pkg/apis/servicemesh/metrics/install/install.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apis/servicemesh/metrics/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(c *restful.Container) {
|
||||
urlruntime.Must(v1alpha2.AddToContainer(c))
|
||||
}
|
||||
132
pkg/apis/servicemesh/metrics/v1alpha2/register.go
Normal file
132
pkg/apis/servicemesh/metrics/v1alpha2/register.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/servicemesh/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
const GroupName = "servicemesh.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
|
||||
tags := []string{"ServiceMesh"}
|
||||
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
// Get service metrics
|
||||
// GET /namespaces/{namespace}/services/{service}/metrics
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/metrics").
|
||||
To(metrics.GetServiceMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get app metrics from a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace")).
|
||||
Param(webservice.PathParameter("service", "name of the service")).
|
||||
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
|
||||
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
|
||||
Param(webservice.QueryParameter("step", "metrics step")).
|
||||
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
|
||||
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
|
||||
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
|
||||
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
|
||||
Param(webservice.QueryParameter("reporter", "destination")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get app metrics
|
||||
// Get /namespaces/{namespace}/apps/{app}/metrics
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/apps/{app}/metrics").
|
||||
To(metrics.GetAppMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get app metrics from a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace")).
|
||||
Param(webservice.PathParameter("app", "name of the workload label app value")).
|
||||
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
|
||||
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
|
||||
Param(webservice.QueryParameter("step", "metrics step")).
|
||||
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
|
||||
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
|
||||
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
|
||||
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
|
||||
Param(webservice.QueryParameter("reporter", "destination")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get workload metrics
|
||||
// Get /namespaces/{namespace}/workloads/{workload}/metrics
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/workloads/{workload}/metrics").
|
||||
To(metrics.GetWorkloadMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload metrics from a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace")).
|
||||
Param(webservice.PathParameter("workload", "name of the workload")).
|
||||
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
|
||||
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
|
||||
Param(webservice.QueryParameter("step", "metrics step")).
|
||||
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
|
||||
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
|
||||
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
|
||||
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
|
||||
Param(webservice.QueryParameter("reporter", "destination")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get namespace metrics
|
||||
// Get /namespaces/{namespace}/metrics
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/metrics").
|
||||
To(metrics.GetNamespaceMetrics).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get workload metrics from a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of the namespace")).
|
||||
Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")).
|
||||
Param(webservice.QueryParameter("duration", "metrics duration, in seconds")).
|
||||
Param(webservice.QueryParameter("step", "metrics step")).
|
||||
Param(webservice.QueryParameter("rateInterval", "metrics rate intervals, e.g. 20s")).
|
||||
Param(webservice.QueryParameter("quantiles[]", "metrics quantiles, 0.5, 0.9, 0.99")).
|
||||
Param(webservice.QueryParameter("byLabels[]", "by which labels to group node, e.g. source_workload, destination_service_name")).
|
||||
Param(webservice.QueryParameter("requestProtocol", "request protocol, http/tcp")).
|
||||
Param(webservice.QueryParameter("reporter", "destination")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get namespace graph
|
||||
// Get /namespaces/{namespace}/graph
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/graph").
|
||||
To(metrics.GetNamespaceGraph).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get service graph for a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace")).
|
||||
Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")).
|
||||
Param(webservice.QueryParameter("groupBy", "group nodes by kind")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which time point, default now")).
|
||||
Param(webservice.QueryParameter("injectServiceNodes", "whether to inject service ndoes")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
// Get namespaces graph, for multiple namespaces
|
||||
// Get /namespaces/graph
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/graph").
|
||||
To(metrics.GetNamespacesGraph).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Get service graph for a specific namespace").
|
||||
Param(webservice.PathParameter("namespace", "name of a namespace")).
|
||||
Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")).
|
||||
Param(webservice.QueryParameter("groupBy", "group nodes by kind")).
|
||||
Param(webservice.QueryParameter("queryTime", "from which time point, default now")).
|
||||
Param(webservice.QueryParameter("injectServiceNodes", "whether to inject service ndoes")).
|
||||
Param(webservice.QueryParameter("namespaces", "names of namespaces")).
|
||||
Writes(errors.Error{})).Produces(restful.MIME_JSON)
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
return nil
|
||||
}
|
||||
23
pkg/apis/servicemesh/v1alpha2/doc.go
Normal file
23
pkg/apis/servicemesh/v1alpha2/doc.go
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
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 contains API Schema definitions for the servicemesh v1alpha2 API group
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/servicemesh
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=servicemesh.kubesphere.io
|
||||
package v1alpha2
|
||||
46
pkg/apis/servicemesh/v1alpha2/register.go
Normal file
46
pkg/apis/servicemesh/v1alpha2/register.go
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// NOTE: Boilerplate only. Ignore this file.
|
||||
|
||||
// Package v1alpha2 contains API Schema definitions for the servicemesh v1alpha2 API group
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/servicemesh
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=servicemesh.kubesphere.io
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/runtime/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
SchemeGroupVersion = schema.GroupVersion{Group: "servicemesh.kubesphere.io", Version: "v1alpha2"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
|
||||
|
||||
// AddToScheme is required by pkg/client/...
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Resource is required by pkg/client/listers/...
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
151
pkg/apis/servicemesh/v1alpha2/strategy_types.go
Normal file
151
pkg/apis/servicemesh/v1alpha2/strategy_types.go
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
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/knative/pkg/apis/istio/v1alpha3"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||
|
||||
type StrategyType string
|
||||
|
||||
const (
|
||||
|
||||
// Canary strategy type
|
||||
CanaryType StrategyType = "Canary"
|
||||
|
||||
// BlueGreen strategy type
|
||||
BlueGreenType StrategyType = "BlueGreen"
|
||||
|
||||
// Mirror strategy type
|
||||
Mirror StrategyType = "Mirror"
|
||||
)
|
||||
|
||||
// StrategySpec defines the desired state of Strategy
|
||||
type StrategySpec struct {
|
||||
|
||||
// Strategy type
|
||||
Type StrategyType `json:"type,omitempty"`
|
||||
|
||||
// Label selector for virtual services.
|
||||
// +optional
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty"`
|
||||
|
||||
// Template describes the virtual service that will be created.
|
||||
Template VirtualServiceTemplateSpec `json:"template,omitempty"`
|
||||
|
||||
// Indicates that the strategy is paused and will not be processed
|
||||
// by the strategy controller
|
||||
Paused bool `json:"paused,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualServiceTemplateSpec
|
||||
type VirtualServiceTemplateSpec struct {
|
||||
|
||||
// Metadata of the virtual services created from this template
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec indicates the behavior of a virtual service.
|
||||
// +optional
|
||||
Spec v1alpha3.VirtualServiceSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
// StrategyStatus defines the observed state of Strategy
|
||||
type StrategyStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
|
||||
// The latest available observations of an object's current state.
|
||||
// +optional
|
||||
Conditions []StrategyCondition
|
||||
|
||||
// Represents time when the strategy was acknowledged by the controller.
|
||||
// It is represented in RFC3339 form and is in UTC.
|
||||
// +optional
|
||||
StartTime *metav1.Time
|
||||
|
||||
// Represents time when the strategy was completed.
|
||||
// It is represented in RFC3339 form and is in UTC.
|
||||
// +optional
|
||||
CompletionTime *metav1.Time
|
||||
}
|
||||
|
||||
type StrategyConditionType string
|
||||
|
||||
// These are valid conditions of a strategy.
|
||||
const (
|
||||
// StrategyComplete means the strategy has been delivered to istio.
|
||||
StrategyComplete StrategyConditionType = "Complete"
|
||||
|
||||
// StrategyFailed means the strategy has failed its delivery to istio.
|
||||
StrategyFailed StrategyConditionType = "Failed"
|
||||
)
|
||||
|
||||
// StrategyCondition describes current state of a strategy.
|
||||
type StrategyCondition struct {
|
||||
// Type of strategy condition, Complete or Failed.
|
||||
Type StrategyConditionType
|
||||
|
||||
// Status of the condition, one of True, False, Unknown
|
||||
Status apiextensions.ConditionStatus
|
||||
|
||||
// Last time the condition was checked.
|
||||
// +optional
|
||||
LastProbeTime metav1.Time
|
||||
|
||||
// Last time the condition transit from one status to another
|
||||
// +optional
|
||||
LastTransitionTime metav1.Time
|
||||
|
||||
// reason for the condition's last transition
|
||||
Reason string
|
||||
|
||||
// Human readable message indicating details about last transition.
|
||||
// +optinal
|
||||
Message string
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Strategy is the Schema for the strategies API
|
||||
// +k8s:openapi-gen=true
|
||||
type Strategy struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec StrategySpec `json:"spec,omitempty"`
|
||||
Status StrategyStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// StrategyList contains a list of Strategy
|
||||
type StrategyList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Strategy `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Strategy{}, &StrategyList{})
|
||||
}
|
||||
88
pkg/apis/servicemesh/v1alpha2/strategy_types_test.go
Normal file
88
pkg/apis/servicemesh/v1alpha2/strategy_types_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
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/knative/pkg/apis/istio/v1alpha3"
|
||||
"io/ioutil"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"golang.org/x/net/context"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func TestStorageStrategy(t *testing.T) {
|
||||
key := types.NamespacedName{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
}
|
||||
created := &Strategy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: StrategySpec{
|
||||
Template: VirtualServiceTemplateSpec{
|
||||
Spec: v1alpha3.VirtualServiceSpec{
|
||||
Hosts: []string{
|
||||
"details",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
g := gomega.NewGomegaWithT(t)
|
||||
|
||||
// Test Create
|
||||
fetched := &Strategy{}
|
||||
g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
|
||||
g.Expect(fetched).To(gomega.Equal(created))
|
||||
|
||||
// Test Updating the Labels
|
||||
updated := fetched.DeepCopy()
|
||||
updated.Labels = map[string]string{"hello": "world"}
|
||||
g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
|
||||
g.Expect(fetched).To(gomega.Equal(updated))
|
||||
|
||||
// Test Delete
|
||||
g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred())
|
||||
g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred())
|
||||
}
|
||||
|
||||
func TestStrategyRead(t *testing.T) {
|
||||
|
||||
//g := gomega.NewGomegaWithT(t)
|
||||
|
||||
var str []byte
|
||||
file, err := ioutil.ReadFile("/Users/zry/go/src/kubesphere.io/kubesphere/config/samples/servicemesh_v1alpha2_strategy.yaml")
|
||||
if err == nil {
|
||||
obj, _, _ := scheme.Codecs.UniversalDeserializer().Decode(file, nil, &Strategy{})
|
||||
switch obj.(type) {
|
||||
case *Strategy:
|
||||
str, err = json.Marshal(obj)
|
||||
t.Logf("Read strategy %s", str)
|
||||
}
|
||||
}
|
||||
}
|
||||
55
pkg/apis/servicemesh/v1alpha2/v1alpha2_suite_test.go
Normal file
55
pkg/apis/servicemesh/v1alpha2/v1alpha2_suite_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
var c client.Client
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")},
|
||||
}
|
||||
|
||||
err := SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
176
pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go
Normal file
176
pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go
Normal file
@@ -0,0 +1,176 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes 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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Strategy) DeepCopyInto(out *Strategy) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Strategy.
|
||||
func (in *Strategy) DeepCopy() *Strategy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Strategy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Strategy) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StrategyCondition) DeepCopyInto(out *StrategyCondition) {
|
||||
*out = *in
|
||||
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyCondition.
|
||||
func (in *StrategyCondition) DeepCopy() *StrategyCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StrategyCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StrategyList) DeepCopyInto(out *StrategyList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Strategy, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyList.
|
||||
func (in *StrategyList) DeepCopy() *StrategyList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StrategyList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *StrategyList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StrategySpec) DeepCopyInto(out *StrategySpec) {
|
||||
*out = *in
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = new(v1.LabelSelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Template.DeepCopyInto(&out.Template)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategySpec.
|
||||
func (in *StrategySpec) DeepCopy() *StrategySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StrategySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StrategyStatus) DeepCopyInto(out *StrategyStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]StrategyCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.StartTime != nil {
|
||||
in, out := &in.StartTime, &out.StartTime
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
if in.CompletionTime != nil {
|
||||
in, out := &in.CompletionTime, &out.CompletionTime
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyStatus.
|
||||
func (in *StrategyStatus) DeepCopy() *StrategyStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StrategyStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VirtualServiceTemplateSpec) DeepCopyInto(out *VirtualServiceTemplateSpec) {
|
||||
*out = *in
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualServiceTemplateSpec.
|
||||
func (in *VirtualServiceTemplateSpec) DeepCopy() *VirtualServiceTemplateSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(VirtualServiceTemplateSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
@@ -66,6 +66,10 @@ func CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
err = iam.CreateUser(user)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
@@ -180,7 +184,7 @@ func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
@@ -228,6 +232,12 @@ func NamespacesListHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
func UserDetail(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
usernameFromHeader := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
if username == usernameFromHeader {
|
||||
CurrentUserDetail(req, resp)
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
|
||||
@@ -29,8 +29,6 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
apierror "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
@@ -64,20 +62,6 @@ func WorkspaceRoles(req *restful.Request, resp *restful.Response) {
|
||||
resp.WriteAsJson(roles)
|
||||
}
|
||||
|
||||
func WorkspaceMemberQuery(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func WorkspaceMemberDetail(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("member")
|
||||
@@ -559,26 +543,10 @@ func DevopsRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
func NamespacesRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
//workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
|
||||
namespace, err := iam.GetNamespace(namespaceName)
|
||||
|
||||
if err != nil {
|
||||
if apierror.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("permission undefined")))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if namespace.Labels == nil || namespace.Labels["kubesphere.io/workspace"] != workspaceName {
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(fmt.Errorf("permission undefined")))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
|
||||
58
pkg/apiserver/resources/application.go
Normal file
58
pkg/apiserver/resources/application.go
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
|
||||
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 resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/applications"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ApplicationHandler(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
clusterId := req.QueryParameter("cluster_id")
|
||||
runtimeId := req.QueryParameter("runtime_id")
|
||||
conditions, err := params.ParseConditions(req)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(clusterId) > 0 {
|
||||
app, err := applications.GetApp(clusterId)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := applications.ListApplication(runtimeId, conditions, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
43
pkg/apiserver/servicemesh/metrics/handlers.go
Normal file
43
pkg/apiserver/servicemesh/metrics/handlers.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/kiali/kiali/handlers"
|
||||
)
|
||||
|
||||
// Get app metrics
|
||||
func GetAppMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.AppMetrics(response.ResponseWriter, request.Request)
|
||||
}
|
||||
|
||||
// Get workload metrics
|
||||
func GetWorkloadMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.WorkloadMetrics(response.ResponseWriter, request.Request)
|
||||
}
|
||||
|
||||
// Get service metrics
|
||||
func GetServiceMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.ServiceMetrics(response.ResponseWriter, request.Request)
|
||||
}
|
||||
|
||||
// Get namespace metrics
|
||||
func GetNamespaceMetrics(request *restful.Request, response *restful.Response) {
|
||||
handlers.NamespaceMetrics(response.ResponseWriter, request.Request)
|
||||
}
|
||||
|
||||
// Get service graph for namespace
|
||||
func GetNamespaceGraph(request *restful.Request, response *restful.Response) {
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
if len(namespace) > 0 {
|
||||
request.Request.URL.RawQuery = fmt.Sprintf("%s&namespaces=%s", request.Request.URL.RawQuery, namespace)
|
||||
}
|
||||
|
||||
handlers.GraphNamespaces(response.ResponseWriter, request.Request)
|
||||
}
|
||||
|
||||
// Get service graph for namespaces
|
||||
func GetNamespacesGraph(request *restful.Request, response *restful.Response) {
|
||||
handlers.GraphNamespaces(response.ResponseWriter, request.Request)
|
||||
}
|
||||
@@ -39,18 +39,12 @@ const (
|
||||
DevopsOwner = "owner"
|
||||
DevopsReporter = "reporter"
|
||||
|
||||
envDevopsAPIServer = "DEVOPS_API_SERVER"
|
||||
envAccountAPIServer = "ACCOUNT_API_SERVER"
|
||||
envDevopsProxyToken = "DEVOPS_PROXY_TOKEN"
|
||||
envOpenPitrixProxyToken = "OPENPITRIX_PROXY_TOKEN"
|
||||
|
||||
UserNameHeader = "X-Token-Username"
|
||||
)
|
||||
|
||||
var (
|
||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||
SystemWorkspace = "system-workspace"
|
||||
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
||||
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
||||
DevopsAPIServer = "ks-devops.kubesphere-devops-system.svc"
|
||||
SystemNamespaces = []string{KubeSphereNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
||||
)
|
||||
|
||||
30
pkg/controller/add_strategy.go
Normal file
30
pkg/controller/add_strategy.go
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/controller/strategy"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, strategy.Add)
|
||||
|
||||
// Add application to manager functions
|
||||
//AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 The KubeSphere authors.
|
||||
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.
|
||||
|
||||
148
pkg/controller/strategy/strategy_controller.go
Normal file
148
pkg/controller/strategy/strategy_controller.go
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
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 strategy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
// Add creates a new Strategy Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcileStrategy{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("strategy-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to Strategy
|
||||
err = c.Watch(&source.Kind{Type: &servicemeshv1alpha2.Strategy{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.Watch(&source.Kind{Type: &v1alpha3.VirtualService{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(user): Modify this to be the types you create
|
||||
// Watch a VirtualService created by Strategy
|
||||
err = c.Watch(&source.Kind{Type: &v1alpha3.VirtualService{}}, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &servicemeshv1alpha2.Strategy{},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcileStrategy{}
|
||||
|
||||
// ReconcileStrategy reconciles a Strategy object
|
||||
type ReconcileStrategy struct {
|
||||
client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a Strategy object and makes changes based on the state read
|
||||
// and what is in the Strategy.Spec
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=networking.istio.io,resources=virtualservices,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=networking.istio.io,resources=virtualservices/status,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=servicemesh.kubesphere.io,resources=strategies,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=servicemesh.kubesphere.io,resources=strategies/status,verbs=get;update;patch
|
||||
func (r *ReconcileStrategy) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the Strategy instance
|
||||
strategy := &servicemeshv1alpha2.Strategy{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, strategy)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Define VirtualService to be created
|
||||
vs := &v1alpha3.VirtualService{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: strategy.Name + "-virtualservice",
|
||||
Namespace: strategy.Namespace,
|
||||
Labels: strategy.Spec.Selector.MatchLabels,
|
||||
},
|
||||
Spec: strategy.Spec.Template.Spec,
|
||||
}
|
||||
|
||||
if err := controllerutil.SetControllerReference(strategy, vs, r.scheme); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Check if the VirtualService already exists
|
||||
found := &v1alpha3.VirtualService{}
|
||||
err = r.Get(context.TODO(), types.NamespacedName{Name: vs.Name, Namespace: vs.Namespace}, found)
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
log.Info("Creating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
|
||||
err = r.Create(context.TODO(), vs)
|
||||
return reconcile.Result{}, err
|
||||
} else if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Update the found object and write the result back if there are any changes
|
||||
if !reflect.DeepEqual(vs.Spec, found.Spec) {
|
||||
found.Spec = vs.Spec
|
||||
log.Info("Updating VirtualService", "namespace", vs.Namespace, "name", vs.Name)
|
||||
err = r.Update(context.TODO(), found)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
75
pkg/controller/strategy/strategy_controller_suite_test.go
Normal file
75
pkg/controller/strategy/strategy_controller_suite_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
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 strategy
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/apis"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
143
pkg/controller/strategy/strategy_controller_test.go
Normal file
143
pkg/controller/strategy/strategy_controller_test.go
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
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 strategy
|
||||
|
||||
import (
|
||||
"github.com/knative/pkg/apis/istio/common/v1alpha1"
|
||||
"github.com/knative/pkg/apis/istio/v1alpha3"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"golang.org/x/net/context"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var c client.Client
|
||||
|
||||
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
|
||||
var depKey = types.NamespacedName{Name: "foo-virtualservice", Namespace: "default"}
|
||||
|
||||
const timeout = time.Second * 5
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
g := gomega.NewGomegaWithT(t)
|
||||
instance := &servicemeshv1alpha2.Strategy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: servicemeshv1alpha2.StrategySpec{
|
||||
Type: servicemeshv1alpha2.CanaryType,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"type": "Canary",
|
||||
},
|
||||
},
|
||||
Template: servicemeshv1alpha2.VirtualServiceTemplateSpec{
|
||||
Spec: v1alpha3.VirtualServiceSpec{
|
||||
Hosts: []string{"details"},
|
||||
Gateways: []string{"default"},
|
||||
Http: []v1alpha3.HTTPRoute{
|
||||
{
|
||||
Match: []v1alpha3.HTTPMatchRequest{
|
||||
{
|
||||
Method: &v1alpha1.StringMatch{
|
||||
Exact: "POST",
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: []v1alpha3.DestinationWeight{
|
||||
{
|
||||
Destination: v1alpha3.Destination{
|
||||
Host: "details",
|
||||
Subset: "v1",
|
||||
},
|
||||
Weight: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Route: []v1alpha3.DestinationWeight{
|
||||
{
|
||||
Destination: v1alpha3.Destination{
|
||||
Host: "details",
|
||||
Subset: "v2",
|
||||
},
|
||||
Weight: 40,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
|
||||
// channel when it is finished.
|
||||
mgr, err := manager.New(cfg, manager.Options{})
|
||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
c = mgr.GetClient()
|
||||
|
||||
recFn, requests := SetupTestReconcile(newReconciler(mgr))
|
||||
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
stopMgr, mgrStopped := StartTestManager(mgr, g)
|
||||
|
||||
defer func() {
|
||||
close(stopMgr)
|
||||
mgrStopped.Wait()
|
||||
}()
|
||||
|
||||
// Create the Strategy object and expect the Reconcile and Deployment to be created
|
||||
err = c.Create(context.TODO(), instance)
|
||||
// The instance object may not be a valid object because it might be missing some required fields.
|
||||
// Please modify the instance object by adding required fields and then remove the following if statement.
|
||||
if apierrors.IsInvalid(err) {
|
||||
t.Logf("failed to create object, got an invalid object error: %v", err)
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
defer c.Delete(context.TODO(), instance)
|
||||
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
|
||||
|
||||
vs := &v1alpha3.VirtualService{}
|
||||
g.Eventually(func() error { return c.Get(context.TODO(), depKey, vs) }, timeout).
|
||||
Should(gomega.Succeed())
|
||||
|
||||
if str, err := json.Marshal(vs); err == nil {
|
||||
t.Logf("Created virtual service %s\n", str)
|
||||
}
|
||||
|
||||
// Delete the Deployment and expect Reconcile to be called for Deployment deletion
|
||||
g.Expect(c.Delete(context.TODO(), vs)).NotTo(gomega.HaveOccurred())
|
||||
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
|
||||
//g.Eventually(func() error { return c.Get(context.TODO(), depKey, vs) }, timeout).Should(gomega.Succeed())
|
||||
|
||||
// Manually delete Deployment since GC isn't enabled in the test control plane
|
||||
g.Eventually(func() error { return c.Delete(context.TODO(), vs) }, timeout).
|
||||
Should(gomega.MatchError("virtualservices.networking.istio.io \"foo-virtualservice\" not found"))
|
||||
|
||||
}
|
||||
537
pkg/models/applications/applications.go
Normal file
537
pkg/models/applications/applications.go
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
|
||||
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 applications
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"io/ioutil"
|
||||
v12 "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
OpenPitrixProxyToken string
|
||||
OpenPitrixServer string
|
||||
)
|
||||
|
||||
const (
|
||||
unknown = "-"
|
||||
deploySuffix = "-Deployment"
|
||||
daemonSuffix = "-DaemonSet"
|
||||
stateSuffix = "-StatefulSet"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
Name string `json:"name"`
|
||||
RepoName string `json:"repoName"`
|
||||
Runtime string `json:"namespace"`
|
||||
RuntimeId string `json:"runtime_id"`
|
||||
Version string `json:"version"`
|
||||
VersionId string `json:"version_id"`
|
||||
Status string `json:"status"`
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
App string `json:"app"`
|
||||
AppId string `json:"app_id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
WorkLoads *workLoads `json:"workloads,omitempty"`
|
||||
Services []v1.Service `json:"services,omitempty"`
|
||||
Ingresses []v1beta1.Ingress `json:"ingresses,omitempty"`
|
||||
ClusterID string `json:"cluster_id"`
|
||||
}
|
||||
|
||||
type clusterRole struct {
|
||||
ClusterID string `json:"cluster_id"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type cluster struct {
|
||||
ClusterID string `json:"cluster_id"`
|
||||
Name string `json:"name"`
|
||||
AppID string `json:"app_id"`
|
||||
VersionID string `json:"version_id"`
|
||||
Status string `json:"status"`
|
||||
UpdateTime time.Time `json:"status_time"`
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
RunTimeId string `json:"runtime_id"`
|
||||
Description string `json:"description"`
|
||||
ClusterRoleSets []clusterRole `json:"cluster_role_set"`
|
||||
}
|
||||
|
||||
type clusters struct {
|
||||
Total int `json:"total_count"`
|
||||
Clusters []cluster `json:"cluster_set"`
|
||||
}
|
||||
|
||||
type versionList struct {
|
||||
Total int `json:"total_count"`
|
||||
Versions []version `json:"app_version_set"`
|
||||
}
|
||||
|
||||
type version struct {
|
||||
Name string `json:"name"`
|
||||
VersionID string `json:"version_id"`
|
||||
}
|
||||
|
||||
type runtime struct {
|
||||
RuntimeID string `json:"runtime_id"`
|
||||
Zone string `json:"zone"`
|
||||
}
|
||||
|
||||
type runtimeList struct {
|
||||
Total int `json:"total_count"`
|
||||
Runtimes []runtime `json:"runtime_set"`
|
||||
}
|
||||
|
||||
type app struct {
|
||||
AppId string `json:"app_id"`
|
||||
Name string `json:"name"`
|
||||
ChartName string `json:"chart_name"`
|
||||
RepoId string `json:"repo_id"`
|
||||
}
|
||||
|
||||
type repo struct {
|
||||
RepoId string `json:"repo_id"`
|
||||
Name string `json:"name"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type workLoads struct {
|
||||
Deployments []v12.Deployment `json:"deployments,omitempty"`
|
||||
Statefulsets []v12.StatefulSet `json:"statefulsets,omitempty"`
|
||||
Daemonsets []v12.DaemonSet `json:"daemonsets,omitempty"`
|
||||
}
|
||||
|
||||
type appList struct {
|
||||
Total int `json:"total_count"`
|
||||
Apps []app `json:"app_set"`
|
||||
}
|
||||
|
||||
type repoList struct {
|
||||
Total int `json:"total_count"`
|
||||
Repos []repo `json:"repo_set"`
|
||||
}
|
||||
|
||||
func GetAppInfo(appId string) (string, string, string, error) {
|
||||
url := fmt.Sprintf("%s/v1/apps?app_id=%s", OpenPitrixServer, appId)
|
||||
resp, err := makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, unknown, unknown, err
|
||||
}
|
||||
|
||||
var apps appList
|
||||
err = json.Unmarshal(resp, &apps)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, unknown, unknown, err
|
||||
}
|
||||
|
||||
if len(apps.Apps) == 0 {
|
||||
return unknown, unknown, unknown, err
|
||||
}
|
||||
|
||||
return apps.Apps[0].ChartName, apps.Apps[0].RepoId, apps.Apps[0].AppId, nil
|
||||
}
|
||||
|
||||
func GetRepo(repoId string) (string, error) {
|
||||
url := fmt.Sprintf("%s/v1/repos?repo_id=%s", OpenPitrixServer, repoId)
|
||||
resp, err := makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
var repos repoList
|
||||
err = json.Unmarshal(resp, &repos)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
if len(repos.Repos) == 0 {
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
return repos.Repos[0].Name, nil
|
||||
}
|
||||
|
||||
func GetVersion(versionId string) (string, error) {
|
||||
versionUrl := fmt.Sprintf("%s/v1/app_versions?version_id=%s", OpenPitrixServer, versionId)
|
||||
resp, err := makeHttpRequest("GET", versionUrl, "")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
var versions versionList
|
||||
err = json.Unmarshal(resp, &versions)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
if len(versions.Versions) == 0 {
|
||||
return unknown, nil
|
||||
}
|
||||
return versions.Versions[0].Name, nil
|
||||
}
|
||||
|
||||
func GetRuntime(runtimeId string) (string, error) {
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/v1/runtimes?runtime_id=%s", OpenPitrixServer, runtimeId)
|
||||
resp, err := makeHttpRequest("GET", versionUrl, "")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
var runtimes runtimeList
|
||||
err = json.Unmarshal(resp, &runtimes)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
if len(runtimes.Runtimes) == 0 {
|
||||
return unknown, nil
|
||||
}
|
||||
|
||||
return runtimes.Runtimes[0].Zone, nil
|
||||
}
|
||||
|
||||
func GetWorkLoads(namespace string, clusterRoles []clusterRole) (*workLoads, error) {
|
||||
|
||||
var works workLoads
|
||||
for _, clusterRole := range clusterRoles {
|
||||
workLoadName := clusterRole.Role
|
||||
if len(workLoadName) > 0 {
|
||||
if strings.HasSuffix(workLoadName, deploySuffix) {
|
||||
name := strings.Split(workLoadName, deploySuffix)[0]
|
||||
|
||||
item, err := informers.SharedInformerFactory().Apps().V1().Deployments().Lister().Deployments(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
works.Deployments = append(works.Deployments, *item)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasSuffix(workLoadName, daemonSuffix) {
|
||||
name := strings.Split(workLoadName, daemonSuffix)[0]
|
||||
item, err := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister().DaemonSets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
works.Daemonsets = append(works.Daemonsets, *item)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasSuffix(workLoadName, stateSuffix) {
|
||||
name := strings.Split(workLoadName, stateSuffix)[0]
|
||||
item, err := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister().StatefulSets(namespace).Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
works.Statefulsets = append(works.Statefulsets, *item)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return &works, nil
|
||||
}
|
||||
|
||||
func getLabels(namespace string, workloads *workLoads) *[]map[string]string {
|
||||
k8sClient := k8s.Client()
|
||||
|
||||
var workloadLables []map[string]string
|
||||
if workloads == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, workload := range workloads.Deployments {
|
||||
deploy, err := k8sClient.AppsV1().Deployments(namespace).Get(workload.Name, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
workloadLables = append(workloadLables, deploy.Labels)
|
||||
}
|
||||
|
||||
for _, workload := range workloads.Daemonsets {
|
||||
daemonset, err := k8sClient.AppsV1().DaemonSets(namespace).Get(workload.Name, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
workloadLables = append(workloadLables, daemonset.Labels)
|
||||
}
|
||||
|
||||
for _, workload := range workloads.Statefulsets {
|
||||
statefulset, err := k8sClient.AppsV1().StatefulSets(namespace).Get(workload.Name, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
workloadLables = append(workloadLables, statefulset.Labels)
|
||||
}
|
||||
|
||||
return &workloadLables
|
||||
}
|
||||
|
||||
func isExist(svcs []v1.Service, svc v1.Service) bool {
|
||||
for _, item := range svcs {
|
||||
if item.Name == svc.Name && item.Namespace == svc.Namespace {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getSvcs(namespace string, workLoadLabels *[]map[string]string) []v1.Service {
|
||||
if len(*workLoadLabels) == 0 {
|
||||
return nil
|
||||
}
|
||||
k8sClient := k8s.Client()
|
||||
var services []v1.Service
|
||||
for _, label := range *workLoadLabels {
|
||||
labelSelector := labels.Set(label).AsSelector().String()
|
||||
svcs, err := k8sClient.CoreV1().Services(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
||||
if err != nil {
|
||||
glog.Errorf("get app's svc failed, reason: %v", err)
|
||||
}
|
||||
for _, item := range svcs.Items {
|
||||
if !isExist(services, item) {
|
||||
services = append(services, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return services
|
||||
}
|
||||
|
||||
func getIng(namespace string, services []v1.Service) []v1beta1.Ingress {
|
||||
if services == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ings []v1beta1.Ingress
|
||||
for _, svc := range services {
|
||||
result, err := resources.ListNamespaceResource(namespace, "ingress", ¶ms.Conditions{Fuzzy: map[string]string{"serviceName": svc.Name}}, "", false, -1, 0)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
glog.Error(result)
|
||||
for _, i := range result.Items {
|
||||
ingress := i.(*v1beta1.Ingress)
|
||||
|
||||
exist := false
|
||||
var tmpRules []v1beta1.IngressRule
|
||||
for _, rule := range ingress.Spec.Rules {
|
||||
for _, p := range rule.HTTP.Paths {
|
||||
if p.Backend.ServiceName == svc.Name {
|
||||
exist = true
|
||||
tmpRules = append(tmpRules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if exist {
|
||||
ing := v1beta1.Ingress{}
|
||||
ing.Name = ingress.Name
|
||||
ing.Spec.Rules = tmpRules
|
||||
ings = append(ings, ing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ings
|
||||
}
|
||||
|
||||
func ListApplication(runtimeId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
|
||||
if strings.HasSuffix(OpenPitrixServer, "/") {
|
||||
OpenPitrixServer = strings.TrimSuffix(OpenPitrixServer, "/")
|
||||
}
|
||||
|
||||
defaultStatus := "status=active&status=stopped&status=pending&status=ceased"
|
||||
|
||||
url := fmt.Sprintf("%s/v1/clusters?limit=%s&offset=%s", OpenPitrixServer, strconv.Itoa(limit), strconv.Itoa(offset))
|
||||
|
||||
if len(conditions.Fuzzy["name"]) > 0 {
|
||||
url = fmt.Sprintf("%s&search_word=%s", url, conditions.Fuzzy["name"])
|
||||
}
|
||||
|
||||
if len(conditions.Match["status"]) > 0 {
|
||||
url = fmt.Sprintf("%s&status=%s", url, conditions.Match["status"])
|
||||
} else {
|
||||
url = fmt.Sprintf("%s&%s", url, defaultStatus)
|
||||
}
|
||||
|
||||
if len(runtimeId) > 0 {
|
||||
url = fmt.Sprintf("%s&runtime_id=%s", url, runtimeId)
|
||||
}
|
||||
|
||||
resp, err := makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
glog.Errorf("request %s failed, reason: %s", url, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var clusterList clusters
|
||||
err = json.Unmarshal(resp, &clusterList)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := models.PageableResponse{TotalCount: clusterList.Total}
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, item := range clusterList.Clusters {
|
||||
var app Application
|
||||
|
||||
app.Name = item.Name
|
||||
app.ClusterID = item.ClusterID
|
||||
app.UpdateTime = item.UpdateTime
|
||||
app.Status = item.Status
|
||||
versionInfo, _ := GetVersion(item.VersionID)
|
||||
app.Version = versionInfo
|
||||
app.VersionId = item.VersionID
|
||||
runtimeInfo, _ := GetRuntime(item.RunTimeId)
|
||||
app.Runtime = runtimeInfo
|
||||
app.RuntimeId = item.RunTimeId
|
||||
appInfo, _, appId, _ := GetAppInfo(item.AppID)
|
||||
app.App = appInfo
|
||||
app.AppId = appId
|
||||
app.Description = item.Description
|
||||
|
||||
result.Items = append(result.Items, app)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func GetApp(clusterId string) (*Application, error) {
|
||||
if strings.HasSuffix(OpenPitrixServer, "/") {
|
||||
OpenPitrixServer = strings.TrimSuffix(OpenPitrixServer, "/")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/v1/clusters?cluster_id=%s", OpenPitrixServer, clusterId)
|
||||
|
||||
resp, err := makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var clusterList clusters
|
||||
err = json.Unmarshal(resp, &clusterList)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(clusterList.Clusters) == 0 {
|
||||
return nil, fmt.Errorf("NotFound, clusterId:%s", clusterId)
|
||||
}
|
||||
|
||||
item := clusterList.Clusters[0]
|
||||
var app Application
|
||||
|
||||
app.Name = item.Name
|
||||
app.ClusterID = item.ClusterID
|
||||
app.UpdateTime = item.UpdateTime
|
||||
app.CreateTime = item.CreateTime
|
||||
app.Status = item.Status
|
||||
versionInfo, _ := GetVersion(item.VersionID)
|
||||
app.Version = versionInfo
|
||||
app.VersionId = item.VersionID
|
||||
|
||||
runtimeInfo, _ := GetRuntime(item.RunTimeId)
|
||||
app.Runtime = runtimeInfo
|
||||
app.RuntimeId = item.RunTimeId
|
||||
appInfo, repoId, appId, _ := GetAppInfo(item.AppID)
|
||||
app.App = appInfo
|
||||
app.AppId = appId
|
||||
app.Description = item.Description
|
||||
|
||||
app.RepoName, _ = GetRepo(repoId)
|
||||
|
||||
workloads, err := GetWorkLoads(app.Runtime, item.ClusterRoleSets)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
app.WorkLoads = workloads
|
||||
workloadLabels := getLabels(app.Runtime, app.WorkLoads)
|
||||
app.Services = getSvcs(app.Runtime, workloadLabels)
|
||||
app.Ingresses = getIng(app.Runtime, app.Services)
|
||||
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
func makeHttpRequest(method, url, data string) ([]byte, error) {
|
||||
var req *http.Request
|
||||
|
||||
var err error
|
||||
if method == "GET" {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, strings.NewReader(data))
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", OpenPitrixProxyToken)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpClient := &http.Client{}
|
||||
resp, err := httpClient.Do(req)
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Request to %s failed, method: %s, reason: %s ", url, method, err)
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
err = fmt.Errorf(string(body))
|
||||
}
|
||||
return body, err
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"io/ioutil"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
@@ -174,7 +175,7 @@ func GetRoles(username string, namespace string) ([]*v1.Role, error) {
|
||||
func GetClusterRoles(username string) ([]*v1.ClusterRole, error) {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.SelectorFromSet(labels.Set{"": ""}))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -204,7 +205,7 @@ func GetClusterRoles(username string) ([]*v1.ClusterRole, error) {
|
||||
roles = append(roles, role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
log.Println(err)
|
||||
glog.Warningln(err)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
@@ -572,8 +573,10 @@ func GetRoleSimpleRules(roles []*v1.Role, namespace string) (map[string][]models
|
||||
return rulesMapping, nil
|
||||
}
|
||||
|
||||
//
|
||||
func CreateClusterRoleBinding(username string, clusterRoleName string) error {
|
||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
|
||||
_, err := clusterRoleLister.Get(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -18,19 +18,13 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
kserr "kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
@@ -75,27 +69,18 @@ func GetUsers(names []string) ([]models.User, error) {
|
||||
return make([]models.User, 0), nil
|
||||
}
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
|
||||
conn, err := ldap.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &users)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, name := range names {
|
||||
user, err := UserDetail(name, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, *user)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
@@ -103,32 +88,19 @@ func GetUsers(names []string) ([]models.User, error) {
|
||||
|
||||
func GetUser(name string) (*models.User, error) {
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
|
||||
conn, err := ldap.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
user, err := UserDetail(name, conn)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var user models.User
|
||||
|
||||
err = json.Unmarshal(data, &user)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/redis"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -42,27 +41,18 @@ import (
|
||||
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
|
||||
)
|
||||
|
||||
const (
|
||||
envAdminEmail = "ADMIN_EMAIL"
|
||||
envAdminPWD = "ADMIN_PWD"
|
||||
)
|
||||
|
||||
var (
|
||||
counter Counter
|
||||
AdminEmail = "admin@kubesphere.io"
|
||||
AdminPWD = "passw0rd"
|
||||
counter Counter
|
||||
adminEmail string
|
||||
adminPassword string
|
||||
tokenExpireTime time.Duration
|
||||
)
|
||||
|
||||
func init() {
|
||||
if env := os.Getenv(envAdminEmail); env != "" {
|
||||
AdminEmail = env
|
||||
}
|
||||
if env := os.Getenv(envAdminPWD); env != "" {
|
||||
AdminPWD = env
|
||||
}
|
||||
}
|
||||
func Init(email, password string, t time.Duration) error {
|
||||
adminEmail = email
|
||||
adminPassword = password
|
||||
tokenExpireTime = t
|
||||
|
||||
func DatabaseInit() error {
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
@@ -96,13 +86,16 @@ func checkAndCreateDefaultGroup(conn ldap.Client) error {
|
||||
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
err = createGroupsBaseDN(conn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GroupBaseDN %s create failed: %s\n", ldapclient.GroupSearchBase, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("GroupBaseDN %s not exist: %s\n", ldapclient.GroupSearchBase, err)
|
||||
return fmt.Errorf("iam database init failed: %s\n", err)
|
||||
}
|
||||
|
||||
if len(groups.Entries) == 0 {
|
||||
if groups == nil || len(groups.Entries) == 0 {
|
||||
_, err = CreateGroup(models.Group{Path: constants.SystemWorkspace, Name: constants.SystemWorkspace, Creator: constants.AdminUserName, Description: "system workspace"})
|
||||
|
||||
if err != nil {
|
||||
@@ -127,21 +120,24 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
|
||||
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
err = createUserBaseDN(conn)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("UserBaseDN %s not exist: %s\n", ldapclient.UserSearchBase, err)
|
||||
}
|
||||
|
||||
if len(users.Entries) == 0 {
|
||||
err := CreateUser(models.User{Username: constants.AdminUserName, Email: AdminEmail, Password: AdminPWD, Description: "Administrator account that was always created by default."})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin create failed: %s\n", err)
|
||||
return fmt.Errorf("UserBaseDN %s create failed: %s\n", ldapclient.UserSearchBase, err)
|
||||
}
|
||||
}
|
||||
|
||||
counter = NewCounter(len(users.Entries))
|
||||
if err != nil {
|
||||
return fmt.Errorf("iam database init failed: %s\n", err)
|
||||
}
|
||||
|
||||
if users == nil || len(users.Entries) == 0 {
|
||||
counter = NewCounter(0)
|
||||
err := CreateUser(models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default."})
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin create failed: %s\n", err)
|
||||
}
|
||||
} else {
|
||||
counter = NewCounter(len(users.Entries))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -200,8 +196,6 @@ func Login(username string, password string, ip string) (string, error) {
|
||||
email := result.Entries[0].GetAttributeValue("mail")
|
||||
dn := result.Entries[0].DN
|
||||
|
||||
user := models.User{Username: uid, Email: email}
|
||||
|
||||
// bind as the user to verify their password
|
||||
err = conn.Bind(dn, password)
|
||||
|
||||
@@ -209,25 +203,29 @@ func Login(username string, password string, ip string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if ip != "" {
|
||||
redisClient := redis.Client()
|
||||
redisClient.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", uid), fmt.Sprintf("%s,%s", time.Now().UTC().Format("2006-01-02T15:04:05Z"), ip))
|
||||
redisClient.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -10, -1)
|
||||
}
|
||||
|
||||
claims := jwt.MapClaims{}
|
||||
|
||||
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
|
||||
claims["username"] = user.Username
|
||||
claims["email"] = user.Email
|
||||
claims["exp"] = time.Now().Add(tokenExpireTime).Unix()
|
||||
claims["username"] = uid
|
||||
claims["email"] = email
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
uToken, _ := token.SignedString(jwtutils.Secret)
|
||||
|
||||
loginLog(uid, ip)
|
||||
|
||||
return uToken, nil
|
||||
}
|
||||
|
||||
func loginLog(uid, ip string) {
|
||||
if ip != "" {
|
||||
redisClient := redis.Client()
|
||||
redisClient.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", uid), fmt.Sprintf("%s,%s", time.Now().UTC().Format("2006-01-02T15:04:05Z"), ip))
|
||||
redisClient.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -10, -1)
|
||||
}
|
||||
}
|
||||
|
||||
func UserList(limit int, offset int) (int, []models.User, error) {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
@@ -668,7 +666,7 @@ func CreateUser(user models.User) error {
|
||||
}
|
||||
|
||||
if len(result.Entries) > 0 {
|
||||
return errors.New("username or email already exists")
|
||||
return ldap.NewError(ldap.LDAPResultEntryAlreadyExists, fmt.Errorf("username or email already exists"))
|
||||
}
|
||||
|
||||
maxUid, err := getMaxUid(conn)
|
||||
|
||||
@@ -732,7 +732,7 @@ func MonitorAllWorkspacesStatistics() *FormatedLevelMetric {
|
||||
wg.Add(4)
|
||||
|
||||
go func() {
|
||||
orgNums, errOrg := workspaces.Count()
|
||||
orgNums, errOrg := workspaces.WorkspaceCount()
|
||||
if errOrg != nil {
|
||||
glog.Errorln(errOrg.Error())
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ const (
|
||||
daemonsetsKey = "count/daemonsets.apps"
|
||||
deploymentsKey = "count/deployments.apps"
|
||||
ingressKey = "count/ingresses.extensions"
|
||||
rolesKey = "count/roles.rbac.authorization.k8s.io"
|
||||
clusterRolesKey = "count/cluster-role"
|
||||
servicesKey = "count/services"
|
||||
statefulsetsKey = "count/statefulsets.apps"
|
||||
persistentvolumeclaimsKey = "persistentvolumeclaims"
|
||||
@@ -47,18 +45,26 @@ const (
|
||||
|
||||
var (
|
||||
resourceMap = map[string]string{daemonsetsKey: resources.DaemonSets, deploymentsKey: resources.Deployments,
|
||||
ingressKey: resources.Ingresses, rolesKey: resources.Roles, servicesKey: resources.Services,
|
||||
ingressKey: resources.Ingresses, servicesKey: resources.Services,
|
||||
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
|
||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses,
|
||||
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
|
||||
)
|
||||
|
||||
func getUsage(namespace, resource string) (int, error) {
|
||||
list, err := resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{}, "", false, -1, 0)
|
||||
var result *models.PageableResponse
|
||||
var err error
|
||||
if resource == resources.Namespaces || resource == resources.StorageClasses {
|
||||
result, err = resources.ListClusterResource(resource, ¶ms.Conditions{}, "", false, 1, 0)
|
||||
} else {
|
||||
result, err = resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{}, "", false, 1, 0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return list.TotalCount, nil
|
||||
|
||||
return result.TotalCount, nil
|
||||
}
|
||||
|
||||
func GetClusterQuotas() (*models.ResourceQuota, error) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
v12 "k8s.io/api/apps/v1"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
@@ -30,16 +31,149 @@ import (
|
||||
type podSearcher struct {
|
||||
}
|
||||
|
||||
func podBelongTo(item *v1.Pod, kind string, name string) bool {
|
||||
|
||||
if strings.EqualFold(kind, "Deployment") {
|
||||
if podBelongToDeployment(item, name) {
|
||||
return true
|
||||
}
|
||||
} else if strings.EqualFold(kind, "ReplicaSet") {
|
||||
if podBelongToReplicaSet(item, name) {
|
||||
return true
|
||||
}
|
||||
} else if strings.EqualFold(kind, "DaemonSet") {
|
||||
if podBelongToDaemonSet(item, name) {
|
||||
return true
|
||||
}
|
||||
} else if strings.EqualFold(kind, "StatefulSet") {
|
||||
if podBelongToStatefulSet(item, name) {
|
||||
return true
|
||||
}
|
||||
} else if strings.EqualFold(kind, "Job") {
|
||||
if podBelongToJob(item, name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func replicaSetBelongToDeployment(replicaSet *v12.ReplicaSet, name string) bool {
|
||||
for _, owner := range replicaSet.OwnerReferences {
|
||||
if owner.Kind == "Deployment" && owner.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBelongToDaemonSet(item *v1.Pod, name string) bool {
|
||||
for _, owner := range item.OwnerReferences {
|
||||
if owner.Kind == "DaemonSet" && owner.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBelongToJob(item *v1.Pod, name string) bool {
|
||||
for _, owner := range item.OwnerReferences {
|
||||
if owner.Kind == "Job" && owner.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBelongToReplicaSet(item *v1.Pod, name string) bool {
|
||||
for _, owner := range item.OwnerReferences {
|
||||
if owner.Kind == "ReplicaSet" && owner.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBelongToStatefulSet(item *v1.Pod, name string) bool {
|
||||
replicas, err := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister().ReplicaSets(item.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, r := range replicas {
|
||||
if replicaSetBelongToDeployment(r, name) {
|
||||
return podBelongToReplicaSet(item, r.Name)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBelongToDeployment(item *v1.Pod, name string) bool {
|
||||
replicas, err := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister().ReplicaSets(item.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, r := range replicas {
|
||||
if replicaSetBelongToDeployment(r, name) {
|
||||
return podBelongToReplicaSet(item, r.Name)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBindPVC(item *v1.Pod, pvcName string) bool {
|
||||
for _, v := range item.Spec.Volumes {
|
||||
if v.VolumeSource.PersistentVolumeClaim != nil &&
|
||||
v.VolumeSource.PersistentVolumeClaim.ClaimName == pvcName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func podBelongToService(item *v1.Pod, serviceName string) bool {
|
||||
service, err := informers.SharedInformerFactory().Core().V1().Services().Lister().Services(item.Namespace).Get(serviceName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for k, v := range service.Spec.Selector {
|
||||
if item.Labels[k] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case "ownerKind":
|
||||
fallthrough
|
||||
case "ownerName":
|
||||
kind := match["ownerKind"]
|
||||
name := match["ownerName"]
|
||||
if !podBelongTo(item, kind, name) {
|
||||
return false
|
||||
}
|
||||
case "nodeName":
|
||||
if item.Spec.NodeName != v {
|
||||
return false
|
||||
}
|
||||
case "pvcName":
|
||||
if !podBindPVC(item, v) {
|
||||
return false
|
||||
}
|
||||
case "serviceName":
|
||||
if !podBelongToService(item, v) {
|
||||
return false
|
||||
}
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
if item.Labels[k] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -131,6 +131,8 @@ func ListClusterResource(resource string, conditions *params.Conditions, orderBy
|
||||
|
||||
if searcher, ok := clusterResources[resource]; ok {
|
||||
result, err = searcher.search(conditions, orderBy, reverse)
|
||||
} else if searcher, ok := namespacedResources[resource]; ok {
|
||||
result, err = searcher.search("", conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, fmt.Errorf("not support")
|
||||
}
|
||||
|
||||
7
pkg/models/servicemesh/metrics/handlers.go
Normal file
7
pkg/models/servicemesh/metrics/handlers.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package metrics
|
||||
|
||||
import "github.com/emicklei/go-restful"
|
||||
|
||||
func GetAppMetrics(request *restful.Request, response *restful.Response) {
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"net/http"
|
||||
|
||||
@@ -40,7 +41,6 @@ import (
|
||||
"errors"
|
||||
"regexp"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -56,7 +56,6 @@ import (
|
||||
|
||||
func UnBindDevopsProject(workspace string, devops string) error {
|
||||
db := mysql.Client()
|
||||
defer db.Close()
|
||||
return db.Delete(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||
}
|
||||
|
||||
@@ -306,7 +305,6 @@ func Namespaces(workspaceName string) ([]*core.Namespace, error) {
|
||||
|
||||
func BindingDevopsProject(workspace string, devops string) error {
|
||||
db := mysql.Client()
|
||||
defer db.Close()
|
||||
return db.Create(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||
}
|
||||
|
||||
@@ -332,27 +330,11 @@ func Delete(workspace *models.Workspace) error {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, workspace.Name), nil)
|
||||
err = iam.DeleteGroup(workspace.Name)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := http.DefaultClient.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return kserr.Parse(data)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -401,34 +383,13 @@ func workspaceRoleRelease(workspace string) error {
|
||||
|
||||
func Create(workspace *models.Workspace) (*models.Workspace, error) {
|
||||
|
||||
data, err := json.Marshal(workspace)
|
||||
|
||||
group, err := iam.CreateGroup(workspace.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := http.Post(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer), restful.MIME_JSON, bytes.NewReader(data))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer result.Body.Close()
|
||||
data, err = ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var created models.Workspace
|
||||
|
||||
err = json.Unmarshal(data, &created)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
created := models.Workspace{
|
||||
Group: *group,
|
||||
}
|
||||
|
||||
created.Members = make([]string, 0)
|
||||
@@ -446,78 +407,35 @@ func Create(workspace *models.Workspace) (*models.Workspace, error) {
|
||||
|
||||
func Edit(workspace *models.Workspace) (*models.Workspace, error) {
|
||||
|
||||
data, err := json.Marshal(workspace)
|
||||
group, err := iam.UpdateGroup(&workspace.Group)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, workspace.Name), bytes.NewReader(data))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
workspace.Group = *group
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := http.DefaultClient.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err = ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var edited models.Workspace
|
||||
|
||||
err = json.Unmarshal(data, &edited)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &edited, nil
|
||||
return workspace, nil
|
||||
}
|
||||
|
||||
func Detail(name string) (*models.Workspace, error) {
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, name))
|
||||
|
||||
conn, err := ldap.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
defer conn.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var group models.Group
|
||||
|
||||
err = json.Unmarshal(data, &group)
|
||||
group, err := iam.GroupDetail(name, conn)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := mysql.Client()
|
||||
defer db.Close()
|
||||
|
||||
workspace, err := convertGroupToWorkspace(db, group)
|
||||
workspace, err := convertGroupToWorkspace(db, *group)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -570,45 +488,33 @@ func ListWorkspaceByUser(username string, keyword string) ([]*models.Workspace,
|
||||
|
||||
func fetch(names []string) ([]*models.Workspace, error) {
|
||||
|
||||
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer)
|
||||
|
||||
if names != nil {
|
||||
if len(names) == 0 {
|
||||
return make([]*models.Workspace, 0), nil
|
||||
} else {
|
||||
url = url + "?path=" + strings.Join(names, ",")
|
||||
if names != nil && len(names) == 0 {
|
||||
return make([]*models.Workspace, 0), nil
|
||||
}
|
||||
var groups []models.Group
|
||||
var err error
|
||||
if names == nil {
|
||||
groups, err = iam.ChildList("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
conn, err := ldap.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
for _, name := range names {
|
||||
group, err := iam.GroupDetail(name, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groups = append(groups, *group)
|
||||
}
|
||||
}
|
||||
|
||||
result, err := http.Get(url)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var groups []models.Group
|
||||
|
||||
err = json.Unmarshal(data, &groups)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := mysql.Client()
|
||||
|
||||
defer db.Close()
|
||||
|
||||
workspaces := make([]*models.Workspace, 0)
|
||||
for _, group := range groups {
|
||||
workspace, err := convertGroupToWorkspace(db, group)
|
||||
@@ -624,7 +530,6 @@ func fetch(names []string) ([]*models.Workspace, error) {
|
||||
func ListDevopsProjectsByUser(username string, workspace string, keyword string, orderBy string, reverse bool, limit int, offset int) (int, []models.DevopsProject, error) {
|
||||
|
||||
db := mysql.Client()
|
||||
defer db.Close()
|
||||
|
||||
var workspaceDOPBindings []models.WorkspaceDPBinding
|
||||
|
||||
@@ -850,43 +755,6 @@ func Roles(workspace *models.Workspace) ([]*v1.ClusterRole, error) {
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func GetWorkspaceMembers(workspace string, keyword string) ([]models.User, error) {
|
||||
|
||||
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/workspaces/%s/members", constants.AccountAPIServer, workspace)
|
||||
|
||||
if keyword != "" {
|
||||
url = url + "?keyword=" + keyword
|
||||
}
|
||||
|
||||
result, err := http.Get(url)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
var users []models.User
|
||||
|
||||
err = json.Unmarshal(data, &users)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
|
||||
}
|
||||
|
||||
func WorkspaceRoleInit(workspace *models.Workspace) error {
|
||||
k8sClient := k8s.Client()
|
||||
|
||||
@@ -1222,7 +1090,6 @@ func CreateWorkspaceRoleBinding(workspace *models.Workspace, username string, ro
|
||||
func GetDevOpsProjects(workspaceName string) ([]string, error) {
|
||||
|
||||
db := mysql.Client()
|
||||
defer db.Close()
|
||||
|
||||
var workspaceDOPBindings []models.WorkspaceDPBinding
|
||||
|
||||
@@ -1266,42 +1133,15 @@ func WorkspaceNamespaces(workspaceName string) ([]string, error) {
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func Count() (int, error) {
|
||||
func WorkspaceCount() (int, error) {
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/count", constants.AccountAPIServer))
|
||||
workspaces, err := iam.ChildList("")
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return 0, kserr.Parse(data)
|
||||
}
|
||||
var count map[string]json.Number
|
||||
|
||||
err = json.Unmarshal(data, &count)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
value := count["total_count"]
|
||||
|
||||
v, err := value.Int64()
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(v), nil
|
||||
return len(workspaces), nil
|
||||
}
|
||||
|
||||
func GetAllProjectNums() (int, error) {
|
||||
@@ -1315,7 +1155,6 @@ func GetAllProjectNums() (int, error) {
|
||||
|
||||
func GetAllDevOpsProjectsNums() (int, error) {
|
||||
db := mysql.Client()
|
||||
defer db.Close()
|
||||
|
||||
var count int
|
||||
if err := db.Model(&models.WorkspaceDPBinding{}).Count(&count).Error; err != nil {
|
||||
@@ -1325,35 +1164,11 @@ func GetAllDevOpsProjectsNums() (int, error) {
|
||||
}
|
||||
|
||||
func GetAllAccountNums() (int, error) {
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users", constants.AccountAPIServer))
|
||||
totalCount, _, err := iam.UserList(1, 0)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if result.StatusCode > 200 {
|
||||
return 0, kserr.Parse(data)
|
||||
}
|
||||
var count map[string]json.Number
|
||||
|
||||
err = json.Unmarshal(data, &count)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
value := count["total_count"]
|
||||
|
||||
v, err := value.Int64()
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(v), nil
|
||||
return totalCount, nil
|
||||
}
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
*/
|
||||
package options
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var SharedOptions = NewServerRunOptions()
|
||||
import "github.com/spf13/pflag"
|
||||
|
||||
type ServerRunOptions struct {
|
||||
// server bind address
|
||||
@@ -38,8 +34,6 @@ type ServerRunOptions struct {
|
||||
|
||||
// tls private key file
|
||||
TlsPrivateKey string
|
||||
|
||||
CommandLine *pflag.FlagSet
|
||||
}
|
||||
|
||||
func NewServerRunOptions() *ServerRunOptions {
|
||||
@@ -50,14 +44,16 @@ func NewServerRunOptions() *ServerRunOptions {
|
||||
SecurePort: 0,
|
||||
TlsCertFile: "",
|
||||
TlsPrivateKey: "",
|
||||
CommandLine: &pflag.FlagSet{},
|
||||
}
|
||||
|
||||
s.CommandLine.StringVar(&s.BindAddress, "bind-address", "0.0.0.0", "server bind address")
|
||||
s.CommandLine.IntVar(&s.InsecurePort, "insecure-port", 9090, "insecure port number")
|
||||
s.CommandLine.IntVar(&s.SecurePort, "secure-port", 0, "secure port number")
|
||||
s.CommandLine.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
|
||||
s.CommandLine.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
|
||||
fs.StringVar(&s.BindAddress, "bind-address", "0.0.0.0", "server bind address")
|
||||
fs.IntVar(&s.InsecurePort, "insecure-port", 9090, "insecure port number")
|
||||
fs.IntVar(&s.SecurePort, "secure-port", 0, "secure port number")
|
||||
fs.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
|
||||
fs.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/container/intsets"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -36,7 +34,7 @@ const (
|
||||
|
||||
func ParsePaging(req *restful.Request) (limit, offset int) {
|
||||
paging := req.QueryParameter(PagingParam)
|
||||
limit = intsets.MaxInt
|
||||
limit = 10
|
||||
offset = 0
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(paging); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
|
||||
@@ -38,11 +38,11 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
prometheusAPIEndpoint string
|
||||
PrometheusAPIEndpoint string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&prometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
|
||||
flag.StringVar(&PrometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
|
||||
}
|
||||
|
||||
type MonitoringRequestParams struct {
|
||||
@@ -71,7 +71,7 @@ type MonitoringRequestParams struct {
|
||||
}
|
||||
|
||||
func SendMonitoringRequest(queryType string, params string) string {
|
||||
epurl := prometheusAPIEndpoint + queryType + params
|
||||
epurl := PrometheusAPIEndpoint + queryType + params
|
||||
|
||||
response, err := http.DefaultClient.Get(epurl)
|
||||
if err != nil {
|
||||
|
||||
7
pkg/utils/utils.go
Normal file
7
pkg/utils/utils.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package utils
|
||||
|
||||
func CheckError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user