code refactor (#1922)

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-02-25 18:16:51 +08:00
committed by GitHub
parent abf9fee845
commit 0664eeb559
9 changed files with 87 additions and 766 deletions

View File

@@ -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{}

View File

@@ -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 Interface interface {
GetKubeConfig(username string) (string, error)
}
type cluster struct {
Cluster clusterInfo `yaml:"cluster"`
Name string `yaml:"name"`
type operator struct {
}
type contextInfo struct {
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
NameSpace string `yaml:"namespace"`
func (o operator) GetKubeConfig(username string) (string, error) {
panic("implement me")
}
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)
}
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
func NewKubeconfigOperator() Interface {
return &operator{}
}

View File

@@ -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) {