未验证 提交 0664eeb5 编写于 作者: H hongming 提交者: GitHub

code refactor (#1922)

Signed-off-by: Nhongming <talonwan@yunify.com>
上级 abf9fee8
/*
*
* 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)
}
/*
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))
}
/*
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{}))
}
if projectPipleineEnable{
if projectPipleineEnable {
projectPipelineHander := NewProjectPipelineHandler(devopsClient, dbClient)
webservice.Route(webservice.GET("/devops/{devops}").
To(projectPipelineHander.GetDevOpsProjectHandler).
......@@ -190,8 +190,6 @@ func addWebService(c *restful.Container, devopsClient devops.Interface,
Returns(http.StatusOK, RespOK, devops.ProjectPipeline{}).
Writes(devops.ProjectPipeline{}))
webservice.Route(webservice.POST("/devops/{devops}/credentials").
To(projectPipelineHander.CreateDevOpsProjectCredentialHandler).
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{}))
}
if s2iEnable {
s2iHandler := NewS2iBinaryHandler(ksClient, ksInformer, s3Client)
webservice.Route(webservice.PUT("/namespaces/{namespace}/s2ibinaries/{s2ibinary}/file").
......@@ -808,7 +805,7 @@ The last one is encrypted info, such as the password of the username-password ty
Param(webservice.PathParameter("file", "the name of binary file")).
Returns(http.StatusOK, RespOK, nil))
}
c.Add(webservice)
return nil
......
......@@ -5,10 +5,13 @@ import (
"github.com/emicklei/go-restful"
v1 "k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/components"
"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/registries"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
......@@ -31,6 +34,8 @@ type resourceHandler struct {
routerOperator routers.RouterOperator
gitVerifier git.GitVerifier
registryGetter registries.RegistryGetter
kubeconfigOperator kubeconfig.Interface
kubectlOperator kubectl.Interface
}
func newResourceHandler(client k8s.Client) *resourceHandler {
......@@ -45,6 +50,8 @@ func newResourceHandler(client k8s.Client) *resourceHandler {
routerOperator: routers.NewRouterOperator(client.Kubernetes(), factory.KubernetesSharedInformerFactory()),
gitVerifier: git.NewGitVerifier(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) {
r.handleGetNamespacedAbnormalWorkloads(request, response)
func (r *resourceHandler) GetKubectlPod(request *restful.Request, response *restful.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"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/resources"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants"
"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")))
webservice.Route(webservice.GET("/users/{user}/kubectl").
To(resources.GetKubectl).
To(handler.GetKubectlPod).
Doc("get user's kubectl pod").
Param(webservice.PathParameter("user", "username")).
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").
Produces("text/plain", restful.MIME_JSON).
To(resources.GetKubeconfig).
To(handler.GetKubeconfig).
Doc("get users' kubeconfig").
Param(webservice.PathParameter("user", "username")).
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").
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}).
Returns(http.StatusOK, api.StatusOK, api.Workloads{}).
To(handler.handleGetAbnormalWorkloads))
To(handler.handleGetNamespacedAbnormalWorkloads))
webservice.Route(webservice.GET("/namespaces/{namespace}/abnormalworkloads").
Doc("get abnormal workloads' count of specified namespace").
Param(webservice.PathParameter("namespace", "the name of the project")).
......
......@@ -28,7 +28,6 @@ import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"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/clusterrole"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
......@@ -538,17 +537,18 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
return err
}
// TODO move to user controller
if clusterRoleName == constants.ClusterAdmin {
// create kubectl pod if cluster role is cluster-admin
if err := kubectl.CreateKubectlDeploy(username); err != nil {
klog.Error("create user terminal pod failed", username, err)
}
//if err := kubectl.CreateKubectlDeploy(username); err != nil {
// klog.Error("create user terminal pod failed", username, err)
//}
} else {
// delete kubectl pod if cluster role is not cluster-admin, whether it exists or not
if err := kubectl.DelKubectlDeploy(username); err != nil {
klog.Error("delete user terminal pod failed", username, err)
}
//if err := kubectl.DelKubectlDeploy(username); err != nil {
// klog.Error("delete user terminal pod failed", username, err)
//}
}
clusterRoleBinding := &rbacv1.ClusterRoleBinding{}
......
......@@ -18,298 +18,17 @@
package kubeconfig
import (
"bytes"
"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 {
Cluster clusterInfo `yaml:"cluster"`
Name string `yaml:"name"`
}
type contextInfo struct {
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
NameSpace string `yaml:"namespace"`
}
type contextObject struct {
Context contextInfo `yaml:"context"`
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)
type Interface interface {
GetKubeConfig(username string) (string, error)
}
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,
}
type operator struct {
}
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 (o operator) GetKubeConfig(username string) (string, error) {
panic("implement me")
}
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
func NewKubeconfigOperator() Interface {
return &operator{}
}
......@@ -20,9 +20,10 @@ package kubectl
import (
"fmt"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/simple/client"
"math/rand"
"os"
......@@ -40,6 +41,21 @@ const (
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"
func init() {
......@@ -48,24 +64,23 @@ func init() {
}
}
func GetKubectlPod(username string) (models.PodInfo, error) {
k8sClient := client.ClientSets().K8s().Kubernetes()
func (o *operator) GetKubectlPod(username string) (models.PodInfo, error) {
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 {
klog.Errorln(err)
return models.PodInfo{}, err
}
selectors := deploy.Spec.Selector.MatchLabels
labelSelector := labels.Set(selectors).AsSelector().String()
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
labelSelector := labels.Set(selectors).AsSelector()
pods, err := o.informers.Core().V1().Pods().Lister().Pods(namespace).List(labelSelector)
if err != nil {
klog.Errorln(err)
return models.PodInfo{}, err
}
pod, err := selectCorrectPod(namespace, podList.Items)
pod, err := selectCorrectPod(namespace, pods)
if err != nil {
klog.Errorln(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 _, condition := range pod.Status.Conditions {
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 {
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))
return kubectlPodList[random], nil
}
func CreateKubectlDeploy(username string) error {
k8sClient := client.ClientSets().K8s().Kubernetes()
func (o *operator) CreateKubectlDeploy(username string) error {
k8sClient := o.k8sClient
deployName := fmt.Sprintf("kubectl-%s", username)
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
if err == nil {
......@@ -136,8 +152,8 @@ func CreateKubectlDeploy(username string) error {
return err
}
func DelKubectlDeploy(username string) error {
k8sClient := client.ClientSets().K8s().Kubernetes()
func (o *operator) DelKubectlDeploy(username string) error {
k8sClient := o.k8sClient
deployName := fmt.Sprintf("kubectl-%s", username)
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
if errors.IsNotFound(err) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册