@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2019 The KubeSphere Authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* /
|
|
||||||
*/
|
|
||||||
|
|
||||||
package openpitrix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/openpitrix/attachment"
|
|
||||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DescribeAttachment(req *restful.Request, resp *restful.Response) {
|
|
||||||
attachmentId := req.PathParameter("attachment")
|
|
||||||
fileName := req.QueryParameter("filename")
|
|
||||||
result, err := attachment.DescribeAttachment(attachmentId)
|
|
||||||
// file raw
|
|
||||||
if fileName != "" {
|
|
||||||
data := result.AttachmentContent[fileName]
|
|
||||||
resp.Write(data)
|
|
||||||
resp.Header().Set("Content-Type", "text/plain")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if status.Code(err) == codes.NotFound {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteEntity(result)
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 The KubeSphere Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
package resources
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/klog"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/kubectl"
|
|
||||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetKubectl(req *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
user := req.PathParameter("user")
|
|
||||||
|
|
||||||
kubectlPod, err := kubectl.GetKubectlPod(user)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(kubectlPod)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetKubeconfig(req *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
user := req.PathParameter("user")
|
|
||||||
|
|
||||||
kubectlConfig, err := kubeconfig.GetKubeConfig(user)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
if k8serr.IsNotFound(err) {
|
|
||||||
// recreate
|
|
||||||
kubeconfig.CreateKubeConfig(user)
|
|
||||||
resp.WriteHeaderAndJson(http.StatusNotFound, errors.Wrap(err), restful.MIME_JSON)
|
|
||||||
} else {
|
|
||||||
resp.WriteHeaderAndJson(http.StatusInternalServerError, errors.Wrap(err), restful.MIME_JSON)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Write([]byte(kubectlConfig))
|
|
||||||
}
|
|
||||||
@@ -1,327 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 The KubeSphere Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
package tenant
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
|
||||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/util/net"
|
|
||||||
"k8s.io/klog"
|
|
||||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
|
||||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/api/logging/v1alpha2"
|
|
||||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/logging"
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/tenant"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
|
||||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
|
||||||
"kubesphere.io/kubesphere/pkg/server/params"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ListWorkspaceRules(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspace := req.PathParameter("workspace")
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
|
|
||||||
rules, err := iam.GetUserWorkspaceSimpleRules(workspace, username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(rules)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
|
||||||
orderBy := req.QueryParameter(params.OrderByParam)
|
|
||||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
|
||||||
reverse := params.ParseReverse(req)
|
|
||||||
|
|
||||||
if orderBy == "" {
|
|
||||||
orderBy = v1alpha2.CreateTime
|
|
||||||
reverse = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DescribeWorkspace(req *restful.Request, resp *restful.Response) {
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
workspaceName := req.PathParameter("workspace")
|
|
||||||
|
|
||||||
result, err := tenant.DescribeWorkspace(username, workspaceName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("describe workspace failed: %+v", err)
|
|
||||||
if k8serr.IsNotFound(err) {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
|
||||||
} else {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(result)
|
|
||||||
}
|
|
||||||
func ListNamespacesByUsername(req *restful.Request, resp *restful.Response) {
|
|
||||||
ListNamespaces(req, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListNamespaces(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspace := req.PathParameter("workspace")
|
|
||||||
username := req.PathParameter("member")
|
|
||||||
// /workspaces/{workspace}/members/{username}/namespaces
|
|
||||||
if username == "" {
|
|
||||||
// /workspaces/{workspace}/namespaces
|
|
||||||
username = req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
|
||||||
orderBy := req.QueryParameter(params.OrderByParam)
|
|
||||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
|
||||||
reverse := params.ParseReverse(req)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
conditions.Match[constants.WorkspaceLabelKey] = workspace
|
|
||||||
|
|
||||||
result, err := tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
namespaces := make([]*v1.Namespace, 0)
|
|
||||||
|
|
||||||
for _, item := range result.Items {
|
|
||||||
namespaces = append(namespaces, item.(*v1.Namespace).DeepCopy())
|
|
||||||
}
|
|
||||||
|
|
||||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
|
||||||
|
|
||||||
items := make([]interface{}, 0)
|
|
||||||
|
|
||||||
for _, item := range namespaces {
|
|
||||||
items = append(items, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Items = items
|
|
||||||
|
|
||||||
resp.WriteAsJson(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateNamespace(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspaceName := req.PathParameter("workspace")
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
var namespace v1.Namespace
|
|
||||||
err := req.ReadEntity(&namespace)
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace, err := tenant.GetWorkspace(workspaceName)
|
|
||||||
|
|
||||||
err = checkResourceQuotas(workspace)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if k8serr.IsNotFound(err) {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
|
||||||
} else {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
created, err := tenant.CreateNamespace(workspaceName, &namespace, username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if k8serr.IsAlreadyExists(err) {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusConflict, err)
|
|
||||||
} else {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.WriteAsJson(created)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteNamespace(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspaceName := req.PathParameter("workspace")
|
|
||||||
namespaceName := req.PathParameter("namespace")
|
|
||||||
|
|
||||||
err := workspaces.DeleteNamespace(workspaceName, namespaceName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(errors.None)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkResourceQuotas(wokrspace *v1alpha1.Workspace) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListNamespaceRules(req *restful.Request, resp *restful.Response) {
|
|
||||||
namespace := req.PathParameter("namespace")
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
|
|
||||||
rules, err := iam.GetUserNamespaceSimpleRules(namespace, username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteError(http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(rules)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LogQuery(req *restful.Request, resp *restful.Response) {
|
|
||||||
operation := req.QueryParameter("operation")
|
|
||||||
req, err := regenerateLoggingRequest(req)
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
|
||||||
case req != nil:
|
|
||||||
logging.LoggingQueryCluster(req, resp)
|
|
||||||
default:
|
|
||||||
if operation == "export" {
|
|
||||||
resp.Header().Set(restful.HEADER_ContentType, "text/plain")
|
|
||||||
resp.Header().Set("Content-Disposition", "attachment")
|
|
||||||
resp.Write(nil)
|
|
||||||
} else {
|
|
||||||
resp.WriteAsJson(loggingv1alpha2.QueryResult{Read: new(loggingv1alpha2.ReadResult)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// override namespace query conditions
|
|
||||||
func regenerateLoggingRequest(req *restful.Request) (*restful.Request, error) {
|
|
||||||
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
|
||||||
|
|
||||||
// regenerate the request for log query
|
|
||||||
newUrl := net.FormatURL("http", "127.0.0.1", 80, "/kapis/logging.kubesphere.io/v1alpha2/cluster")
|
|
||||||
values := req.Request.URL.Query()
|
|
||||||
|
|
||||||
clusterRules, err := iam.GetUserClusterRules(username)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorln(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hasClusterLogAccess := iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}})
|
|
||||||
// if the user is not a cluster admin
|
|
||||||
if !hasClusterLogAccess {
|
|
||||||
queryNamespaces := strings.Split(req.QueryParameter("namespaces"), ",")
|
|
||||||
// then the user can only view logs of namespaces he belongs to
|
|
||||||
namespaces := make([]string, 0)
|
|
||||||
roles, err := iam.GetUserRoles("", username)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorln(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, role := range roles {
|
|
||||||
if !sliceutil.HasString(namespaces, role.Namespace) && iam.RulesMatchesRequired(role.Rules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}}) {
|
|
||||||
namespaces = append(namespaces, role.Namespace)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the user belongs to no namespace
|
|
||||||
// then no log visible
|
|
||||||
if len(namespaces) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
} else if len(queryNamespaces) == 1 && queryNamespaces[0] == "" {
|
|
||||||
values.Set("namespaces", strings.Join(namespaces, ","))
|
|
||||||
} else {
|
|
||||||
inter := intersection(queryNamespaces, namespaces)
|
|
||||||
if len(inter) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
values.Set("namespaces", strings.Join(inter, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newUrl.RawQuery = values.Encode()
|
|
||||||
|
|
||||||
// forward the request to logging model
|
|
||||||
newHttpRequest, _ := http.NewRequest(http.MethodGet, newUrl.String(), nil)
|
|
||||||
return restful.NewRequest(newHttpRequest), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func intersection(s1, s2 []string) (inter []string) {
|
|
||||||
hash := make(map[string]bool)
|
|
||||||
for _, e := range s1 {
|
|
||||||
hash[e] = true
|
|
||||||
}
|
|
||||||
for _, e := range s2 {
|
|
||||||
// If elements present in the hashmap then append intersection list.
|
|
||||||
if hash[e] {
|
|
||||||
inter = append(inter, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Remove dups from slice.
|
|
||||||
inter = removeDups(inter)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//Remove dups from slice.
|
|
||||||
func removeDups(elements []string) (nodups []string) {
|
|
||||||
encountered := make(map[string]bool)
|
|
||||||
for _, element := range elements {
|
|
||||||
if !encountered[element] {
|
|
||||||
nodups = append(nodups, element)
|
|
||||||
encountered[element] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -78,7 +78,7 @@ func addWebService(c *restful.Container, devopsClient devops.Interface,
|
|||||||
Writes([]sonarqube.SonarStatus{}))
|
Writes([]sonarqube.SonarStatus{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
if projectPipleineEnable{
|
if projectPipleineEnable {
|
||||||
projectPipelineHander := NewProjectPipelineHandler(devopsClient, dbClient)
|
projectPipelineHander := NewProjectPipelineHandler(devopsClient, dbClient)
|
||||||
webservice.Route(webservice.GET("/devops/{devops}").
|
webservice.Route(webservice.GET("/devops/{devops}").
|
||||||
To(projectPipelineHander.GetDevOpsProjectHandler).
|
To(projectPipelineHander.GetDevOpsProjectHandler).
|
||||||
@@ -190,8 +190,6 @@ func addWebService(c *restful.Container, devopsClient devops.Interface,
|
|||||||
Returns(http.StatusOK, RespOK, devops.ProjectPipeline{}).
|
Returns(http.StatusOK, RespOK, devops.ProjectPipeline{}).
|
||||||
Writes(devops.ProjectPipeline{}))
|
Writes(devops.ProjectPipeline{}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
webservice.Route(webservice.POST("/devops/{devops}/credentials").
|
webservice.Route(webservice.POST("/devops/{devops}/credentials").
|
||||||
To(projectPipelineHander.CreateDevOpsProjectCredentialHandler).
|
To(projectPipelineHander.CreateDevOpsProjectCredentialHandler).
|
||||||
Doc("Create a credential in the specified DevOps project").
|
Doc("Create a credential in the specified DevOps project").
|
||||||
@@ -785,7 +783,6 @@ The last one is encrypted info, such as the password of the username-password ty
|
|||||||
Writes(devops.ResJson{}))
|
Writes(devops.ResJson{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if s2iEnable {
|
if s2iEnable {
|
||||||
s2iHandler := NewS2iBinaryHandler(ksClient, ksInformer, s3Client)
|
s2iHandler := NewS2iBinaryHandler(ksClient, ksInformer, s3Client)
|
||||||
webservice.Route(webservice.PUT("/namespaces/{namespace}/s2ibinaries/{s2ibinary}/file").
|
webservice.Route(webservice.PUT("/namespaces/{namespace}/s2ibinaries/{s2ibinary}/file").
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ import (
|
|||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/klog"
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
"kubesphere.io/kubesphere/pkg/models/components"
|
"kubesphere.io/kubesphere/pkg/models/components"
|
||||||
"kubesphere.io/kubesphere/pkg/models/git"
|
"kubesphere.io/kubesphere/pkg/models/git"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models/kubectl"
|
||||||
"kubesphere.io/kubesphere/pkg/models/quotas"
|
"kubesphere.io/kubesphere/pkg/models/quotas"
|
||||||
"kubesphere.io/kubesphere/pkg/models/registries"
|
"kubesphere.io/kubesphere/pkg/models/registries"
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||||
@@ -31,6 +34,8 @@ type resourceHandler struct {
|
|||||||
routerOperator routers.RouterOperator
|
routerOperator routers.RouterOperator
|
||||||
gitVerifier git.GitVerifier
|
gitVerifier git.GitVerifier
|
||||||
registryGetter registries.RegistryGetter
|
registryGetter registries.RegistryGetter
|
||||||
|
kubeconfigOperator kubeconfig.Interface
|
||||||
|
kubectlOperator kubectl.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResourceHandler(client k8s.Client) *resourceHandler {
|
func newResourceHandler(client k8s.Client) *resourceHandler {
|
||||||
@@ -45,6 +50,8 @@ func newResourceHandler(client k8s.Client) *resourceHandler {
|
|||||||
routerOperator: routers.NewRouterOperator(client.Kubernetes(), factory.KubernetesSharedInformerFactory()),
|
routerOperator: routers.NewRouterOperator(client.Kubernetes(), factory.KubernetesSharedInformerFactory()),
|
||||||
gitVerifier: git.NewGitVerifier(factory.KubernetesSharedInformerFactory()),
|
gitVerifier: git.NewGitVerifier(factory.KubernetesSharedInformerFactory()),
|
||||||
registryGetter: registries.NewRegistryGetter(factory.KubernetesSharedInformerFactory()),
|
registryGetter: registries.NewRegistryGetter(factory.KubernetesSharedInformerFactory()),
|
||||||
|
kubeconfigOperator: kubeconfig.NewKubeconfigOperator(),
|
||||||
|
kubectlOperator: kubectl.NewKubectlOperator(client.Kubernetes(), factory.KubernetesSharedInformerFactory()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,6 +347,35 @@ func (r *resourceHandler) handleGetNamespacedAbnormalWorkloads(request *restful.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resourceHandler) handleGetAbnormalWorkloads(request *restful.Request, response *restful.Response) {
|
func (r *resourceHandler) GetKubectlPod(request *restful.Request, response *restful.Response) {
|
||||||
r.handleGetNamespacedAbnormalWorkloads(request, response)
|
user := request.PathParameter("user")
|
||||||
|
|
||||||
|
kubectlPod, err := r.kubectlOperator.GetKubectlPod(user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorln(err)
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteEntity(kubectlPod)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *resourceHandler) GetKubeconfig(request *restful.Request, response *restful.Response) {
|
||||||
|
user := request.PathParameter("user")
|
||||||
|
|
||||||
|
kubectlConfig, err := r.kubeconfigOperator.GetKubeConfig(user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
if k8serr.IsNotFound(err) {
|
||||||
|
// recreate
|
||||||
|
response.WriteHeaderAndJson(http.StatusNotFound, errors.Wrap(err), restful.MIME_JSON)
|
||||||
|
} else {
|
||||||
|
response.WriteHeaderAndJson(http.StatusInternalServerError, errors.Wrap(err), restful.MIME_JSON)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Write([]byte(kubectlConfig))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
|
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/resources"
|
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
@@ -82,7 +81,7 @@ func AddToContainer(c *restful.Container, client k8s.Client) error {
|
|||||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")))
|
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")))
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/users/{user}/kubectl").
|
webservice.Route(webservice.GET("/users/{user}/kubectl").
|
||||||
To(resources.GetKubectl).
|
To(handler.GetKubectlPod).
|
||||||
Doc("get user's kubectl pod").
|
Doc("get user's kubectl pod").
|
||||||
Param(webservice.PathParameter("user", "username")).
|
Param(webservice.PathParameter("user", "username")).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.UserResourcesTag}).
|
Metadata(restfulspec.KeyOpenAPITags, []string{constants.UserResourcesTag}).
|
||||||
@@ -90,7 +89,7 @@ func AddToContainer(c *restful.Container, client k8s.Client) error {
|
|||||||
|
|
||||||
webservice.Route(webservice.GET("/users/{user}/kubeconfig").
|
webservice.Route(webservice.GET("/users/{user}/kubeconfig").
|
||||||
Produces("text/plain", restful.MIME_JSON).
|
Produces("text/plain", restful.MIME_JSON).
|
||||||
To(resources.GetKubeconfig).
|
To(handler.GetKubeconfig).
|
||||||
Doc("get users' kubeconfig").
|
Doc("get users' kubeconfig").
|
||||||
Param(webservice.PathParameter("user", "username")).
|
Param(webservice.PathParameter("user", "username")).
|
||||||
Returns(http.StatusOK, api.StatusOK, "").
|
Returns(http.StatusOK, api.StatusOK, "").
|
||||||
@@ -214,7 +213,7 @@ func AddToContainer(c *restful.Container, client k8s.Client) error {
|
|||||||
Doc("get abnormal workloads' count of whole cluster").
|
Doc("get abnormal workloads' count of whole cluster").
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}).
|
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}).
|
||||||
Returns(http.StatusOK, api.StatusOK, api.Workloads{}).
|
Returns(http.StatusOK, api.StatusOK, api.Workloads{}).
|
||||||
To(handler.handleGetAbnormalWorkloads))
|
To(handler.handleGetNamespacedAbnormalWorkloads))
|
||||||
webservice.Route(webservice.GET("/namespaces/{namespace}/abnormalworkloads").
|
webservice.Route(webservice.GET("/namespaces/{namespace}/abnormalworkloads").
|
||||||
Doc("get abnormal workloads' count of specified namespace").
|
Doc("get abnormal workloads' count of specified namespace").
|
||||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import (
|
|||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||||
"kubesphere.io/kubesphere/pkg/models/kubectl"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/clusterrole"
|
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/clusterrole"
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
|
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
|
||||||
@@ -538,17 +537,18 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move to user controller
|
||||||
if clusterRoleName == constants.ClusterAdmin {
|
if clusterRoleName == constants.ClusterAdmin {
|
||||||
// create kubectl pod if cluster role is cluster-admin
|
// create kubectl pod if cluster role is cluster-admin
|
||||||
if err := kubectl.CreateKubectlDeploy(username); err != nil {
|
//if err := kubectl.CreateKubectlDeploy(username); err != nil {
|
||||||
klog.Error("create user terminal pod failed", username, err)
|
// klog.Error("create user terminal pod failed", username, err)
|
||||||
}
|
//}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// delete kubectl pod if cluster role is not cluster-admin, whether it exists or not
|
// delete kubectl pod if cluster role is not cluster-admin, whether it exists or not
|
||||||
if err := kubectl.DelKubectlDeploy(username); err != nil {
|
//if err := kubectl.DelKubectlDeploy(username); err != nil {
|
||||||
klog.Error("delete user terminal pod failed", username, err)
|
// klog.Error("delete user terminal pod failed", username, err)
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterRoleBinding := &rbacv1.ClusterRoleBinding{}
|
clusterRoleBinding := &rbacv1.ClusterRoleBinding{}
|
||||||
|
|||||||
@@ -18,298 +18,17 @@
|
|||||||
|
|
||||||
package kubeconfig
|
package kubeconfig
|
||||||
|
|
||||||
import (
|
type Interface interface {
|
||||||
"bytes"
|
GetKubeConfig(username string) (string, error)
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"io/ioutil"
|
|
||||||
"k8s.io/klog"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
|
||||||
"math/big"
|
|
||||||
rd "math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
caPath = "/etc/kubernetes/pki/ca.crt"
|
|
||||||
keyPath = "/etc/kubernetes/pki/ca.key"
|
|
||||||
clusterName = "kubernetes"
|
|
||||||
kubectlConfigKey = "config"
|
|
||||||
defaultNamespace = "default"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clusterInfo struct {
|
|
||||||
CertificateAuthorityData string `yaml:"certificate-authority-data"`
|
|
||||||
Server string `yaml:"server"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type cluster struct {
|
type operator struct {
|
||||||
Cluster clusterInfo `yaml:"cluster"`
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type contextInfo struct {
|
func (o operator) GetKubeConfig(username string) (string, error) {
|
||||||
Cluster string `yaml:"cluster"`
|
panic("implement me")
|
||||||
User string `yaml:"user"`
|
|
||||||
NameSpace string `yaml:"namespace"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type contextObject struct {
|
func NewKubeconfigOperator() Interface {
|
||||||
Context contextInfo `yaml:"context"`
|
return &operator{}
|
||||||
Name string `yaml:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type userInfo struct {
|
|
||||||
CaData string `yaml:"client-certificate-data"`
|
|
||||||
KeyData string `yaml:"client-key-data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type user struct {
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
User userInfo `yaml:"user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type kubeConfig struct {
|
|
||||||
ApiVersion string `yaml:"apiVersion"`
|
|
||||||
Clusters []cluster `yaml:"clusters"`
|
|
||||||
Contexts []contextObject `yaml:"contexts"`
|
|
||||||
CurrentContext string `yaml:"current-context"`
|
|
||||||
Kind string `yaml:"kind"`
|
|
||||||
Preferences map[string]string `yaml:"preferences"`
|
|
||||||
Users []user `yaml:"users"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CertInformation struct {
|
|
||||||
Country []string
|
|
||||||
Organization []string
|
|
||||||
OrganizationalUnit []string
|
|
||||||
EmailAddress []string
|
|
||||||
Province []string
|
|
||||||
Locality []string
|
|
||||||
CommonName string
|
|
||||||
CrtName, KeyName string
|
|
||||||
IsCA bool
|
|
||||||
Names []pkix.AttributeTypeAndValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func createCRT(RootCa *x509.Certificate, RootKey *rsa.PrivateKey, info CertInformation) ([]byte, []byte, error) {
|
|
||||||
var cert, key bytes.Buffer
|
|
||||||
Crt := newCertificate(info)
|
|
||||||
Key, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf []byte
|
|
||||||
|
|
||||||
buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
pem.Encode(&cert, &pem.Block{Type: "CERTIFICATE", Bytes: buf})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = x509.MarshalPKCS1PrivateKey(Key)
|
|
||||||
pem.Encode(&key, &pem.Block{Type: "PRIVATE KEY", Bytes: buf})
|
|
||||||
|
|
||||||
return cert.Bytes(), key.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Parse(crtPath, keyPath string) (rootcertificate *x509.Certificate, rootPrivateKey *rsa.PrivateKey, err error) {
|
|
||||||
rootcertificate, err = parseCrt(crtPath)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
rootPrivateKey, err = parseKey(keyPath)
|
|
||||||
return rootcertificate, rootPrivateKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCrt(path string) (*x509.Certificate, error) {
|
|
||||||
buf, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
p := &pem.Block{}
|
|
||||||
p, buf = pem.Decode(buf)
|
|
||||||
return x509.ParseCertificate(p.Bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseKey(path string) (*rsa.PrivateKey, error) {
|
|
||||||
buf, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
p, buf := pem.Decode(buf)
|
|
||||||
return x509.ParsePKCS1PrivateKey(p.Bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCertificate(info CertInformation) *x509.Certificate {
|
|
||||||
rd.Seed(time.Now().UnixNano())
|
|
||||||
return &x509.Certificate{
|
|
||||||
SerialNumber: big.NewInt(rd.Int63()),
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Country: info.Country,
|
|
||||||
Organization: info.Organization,
|
|
||||||
OrganizationalUnit: info.OrganizationalUnit,
|
|
||||||
Province: info.Province,
|
|
||||||
CommonName: info.CommonName,
|
|
||||||
Locality: info.Locality,
|
|
||||||
ExtraNames: info.Names,
|
|
||||||
},
|
|
||||||
NotBefore: time.Now(),
|
|
||||||
NotAfter: time.Now().AddDate(20, 0, 0),
|
|
||||||
BasicConstraintsValid: true,
|
|
||||||
IsCA: info.IsCA,
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
|
||||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
|
||||||
EmailAddresses: info.EmailAddress,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateCaAndKey(user, caPath, keyPath string) (string, string, error) {
|
|
||||||
crtInfo := CertInformation{CommonName: user, IsCA: false}
|
|
||||||
|
|
||||||
crt, pri, err := Parse(caPath, keyPath)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
cert, key, err := createCRT(crt, pri, crtInfo)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
base64Cert := base64.StdEncoding.EncodeToString(cert)
|
|
||||||
base64Key := base64.StdEncoding.EncodeToString(key)
|
|
||||||
return base64Cert, base64Key, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createKubeConfig(username string) (string, error) {
|
|
||||||
tmpKubeConfig := kubeConfig{ApiVersion: "v1", Kind: "Config"}
|
|
||||||
serverCa, err := ioutil.ReadFile(caPath)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorln(err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
base64ServerCa := base64.StdEncoding.EncodeToString(serverCa)
|
|
||||||
tmpClusterInfo := clusterInfo{CertificateAuthorityData: base64ServerCa, Server: client.ClientSets().K8s().Master()}
|
|
||||||
tmpCluster := cluster{Cluster: tmpClusterInfo, Name: clusterName}
|
|
||||||
tmpKubeConfig.Clusters = append(tmpKubeConfig.Clusters, tmpCluster)
|
|
||||||
|
|
||||||
contextName := username + "@" + clusterName
|
|
||||||
tmpContext := contextObject{Context: contextInfo{User: username, Cluster: clusterName, NameSpace: defaultNamespace}, Name: contextName}
|
|
||||||
tmpKubeConfig.Contexts = append(tmpKubeConfig.Contexts, tmpContext)
|
|
||||||
|
|
||||||
cert, key, err := generateCaAndKey(username, caPath, keyPath)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpUser := user{User: userInfo{CaData: cert, KeyData: key}, Name: username}
|
|
||||||
tmpKubeConfig.Users = append(tmpKubeConfig.Users, tmpUser)
|
|
||||||
tmpKubeConfig.CurrentContext = contextName
|
|
||||||
|
|
||||||
config, err := yaml.Marshal(tmpKubeConfig)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(config), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateKubeConfig(username string) error {
|
|
||||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
|
||||||
configName := fmt.Sprintf("kubeconfig-%s", username)
|
|
||||||
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
|
|
||||||
|
|
||||||
if errors.IsNotFound(err) {
|
|
||||||
config, err := createKubeConfig(username)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorln(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
data := map[string]string{"config": config}
|
|
||||||
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: configName}, Data: data}
|
|
||||||
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
|
|
||||||
if err != nil && !errors.IsAlreadyExists(err) {
|
|
||||||
klog.Errorf("create username %s's kubeConfig failed, reason: %v", username, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetKubeConfig(username string) (string, error) {
|
|
||||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
|
||||||
configName := fmt.Sprintf("kubeconfig-%s", username)
|
|
||||||
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("cannot get username %s's kubeConfig, reason: %v", username, err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
str := configMap.Data[kubectlConfigKey]
|
|
||||||
var kubeConfig kubeConfig
|
|
||||||
err = yaml.Unmarshal([]byte(str), &kubeConfig)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
masterURL := client.ClientSets().K8s().Master()
|
|
||||||
for i, cluster := range kubeConfig.Clusters {
|
|
||||||
cluster.Cluster.Server = masterURL
|
|
||||||
kubeConfig.Clusters[i] = cluster
|
|
||||||
}
|
|
||||||
data, err := yaml.Marshal(kubeConfig)
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DelKubeConfig(username string) error {
|
|
||||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
|
||||||
configName := fmt.Sprintf("kubeconfig-%s", username)
|
|
||||||
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
|
|
||||||
if errors.IsNotFound(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
deletePolicy := metaV1.DeletePropagationBackground
|
|
||||||
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(configName, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("delete username %s's kubeConfig failed, reason: %v", username, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ package kubectl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -40,6 +41,21 @@ const (
|
|||||||
namespace = constants.KubeSphereControlNamespace
|
namespace = constants.KubeSphereControlNamespace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
GetKubectlPod(username string) (models.PodInfo, error)
|
||||||
|
CreateKubectlDeploy(username string) error
|
||||||
|
DelKubectlDeploy(username string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type operator struct {
|
||||||
|
k8sClient kubernetes.Interface
|
||||||
|
informers informers.SharedInformerFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKubectlOperator(k8sClient kubernetes.Interface, informers informers.SharedInformerFactory) Interface {
|
||||||
|
return &operator{k8sClient: k8sClient, informers: informers}
|
||||||
|
}
|
||||||
|
|
||||||
var DefaultImage = "kubesphere/kubectl:advanced-1.0.0"
|
var DefaultImage = "kubesphere/kubectl:advanced-1.0.0"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -48,24 +64,23 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetKubectlPod(username string) (models.PodInfo, error) {
|
func (o *operator) GetKubectlPod(username string) (models.PodInfo, error) {
|
||||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
|
||||||
deployName := fmt.Sprintf("kubectl-%s", username)
|
deployName := fmt.Sprintf("kubectl-%s", username)
|
||||||
deploy, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
|
deploy, err := o.informers.Apps().V1().Deployments().Lister().Deployments(namespace).Get(deployName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorln(err)
|
klog.Errorln(err)
|
||||||
return models.PodInfo{}, err
|
return models.PodInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
selectors := deploy.Spec.Selector.MatchLabels
|
selectors := deploy.Spec.Selector.MatchLabels
|
||||||
labelSelector := labels.Set(selectors).AsSelector().String()
|
labelSelector := labels.Set(selectors).AsSelector()
|
||||||
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
pods, err := o.informers.Core().V1().Pods().Lister().Pods(namespace).List(labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorln(err)
|
klog.Errorln(err)
|
||||||
return models.PodInfo{}, err
|
return models.PodInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pod, err := selectCorrectPod(namespace, podList.Items)
|
pod, err := selectCorrectPod(namespace, pods)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorln(err)
|
klog.Errorln(err)
|
||||||
return models.PodInfo{}, err
|
return models.PodInfo{}, err
|
||||||
@@ -77,9 +92,9 @@ func GetKubectlPod(username string) (models.PodInfo, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectCorrectPod(namespace string, pods []v1.Pod) (kubectlPod v1.Pod, err error) {
|
func selectCorrectPod(namespace string, pods []*v1.Pod) (kubectlPod *v1.Pod, err error) {
|
||||||
|
|
||||||
var kubectlPodList []v1.Pod
|
var kubectlPodList []*v1.Pod
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
for _, condition := range pod.Status.Conditions {
|
for _, condition := range pod.Status.Conditions {
|
||||||
if condition.Type == "Ready" && condition.Status == "True" {
|
if condition.Type == "Ready" && condition.Status == "True" {
|
||||||
@@ -89,15 +104,16 @@ func selectCorrectPod(namespace string, pods []v1.Pod) (kubectlPod v1.Pod, err e
|
|||||||
}
|
}
|
||||||
if len(kubectlPodList) < 1 {
|
if len(kubectlPodList) < 1 {
|
||||||
err = fmt.Errorf("cannot find valid kubectl pod in namespace:%s", namespace)
|
err = fmt.Errorf("cannot find valid kubectl pod in namespace:%s", namespace)
|
||||||
return v1.Pod{}, err
|
return &v1.Pod{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
random := rand.Intn(len(kubectlPodList))
|
random := rand.Intn(len(kubectlPodList))
|
||||||
|
|
||||||
return kubectlPodList[random], nil
|
return kubectlPodList[random], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateKubectlDeploy(username string) error {
|
func (o *operator) CreateKubectlDeploy(username string) error {
|
||||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
k8sClient := o.k8sClient
|
||||||
deployName := fmt.Sprintf("kubectl-%s", username)
|
deployName := fmt.Sprintf("kubectl-%s", username)
|
||||||
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
|
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -136,8 +152,8 @@ func CreateKubectlDeploy(username string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DelKubectlDeploy(username string) error {
|
func (o *operator) DelKubectlDeploy(username string) error {
|
||||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
k8sClient := o.k8sClient
|
||||||
deployName := fmt.Sprintf("kubectl-%s", username)
|
deployName := fmt.Sprintf("kubectl-%s", username)
|
||||||
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
|
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user