You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.5 KiB

package framework
import (
"bytes"
"fmt"
"os"
"os/exec"
"regexp"
"strings"
)
type KubectlConfig struct {
previousContext string
config *Config // 主要是使用里面的stdout/stderr
}
func NewKubectlConfig(config *Config) *KubectlConfig {
return &KubectlConfig{
config: config,
}
}
var contextNameRegex = regexp.MustCompile("[^a-zA-Z0-9_]")
func (k *KubectlConfig) getContextName(config *ClusterConfig) string {
return fmt.Sprintf("%s-context",
contextNameRegex.ReplaceAllString(
strings.ToLower(config.Name),
""))
}
func (k *KubectlConfig) Command(cmd string, args ...string) *exec.Cmd {
command := exec.Command(cmd, args...)
command.Stdout = k.config.Stdout
command.Stderr = k.config.Stderr
return command
}
func (k *KubectlConfig) SetContext(config *ClusterConfig) error {
contextName := k.getContextName(config)
// 1. 获取当前context保存起来如果有
// 获取命令为kubectl config current-context
cmd := k.Command("kubectl",
"config",
"current-context")
currentContext := &bytes.Buffer{}
cmd.Stdout = currentContext
err := cmd.Run()
// 如果执行成功,说明存在 currentcontext就把它保存起来在DeleteContext的时候来回复
defer func() {
if err == nil {
k.previousContext = strings.TrimSpace(currentContext.String())
}
}()
// 2. 从 clusterconfig 创建 context
// context 组成:
// - cluster
// - credentials
// - user
// 三个元素组成context
// 2.1 设置 cluster
// 命令为kubectl config set-cluster <contextName> --server <MasterIP> --insecure-skip-tls-verify=true
if err := k.Command(
"kubectl",
"config",
"set-cluster",
contextName,
"--server", config.MasterIP,
"--insecure-skip-tls-verify=true").Run(); err != nil {
return err
}
// 2.2 设置授权
if config.Rest.BearerToken != "" {
// 命令为kubectl config set-credentials <contextName> --token <config.Rest.BearerToken>
if err := k.Command(
"kubectl",
"config",
"set-credentials",
contextName,
"--token", config.Rest.BearerToken).Run(); err != nil {
return err
}
} else if config.Rest.CertData != nil && config.Rest.KeyData != nil {
keyFile := fmt.Sprintf(KeyTempFileFmt, contextName)
certFile := fmt.Sprintf(CertTempFileFmt, contextName)
if err := os.WriteFile(keyFile, config.Rest.KeyData, os.ModePerm); err != nil {
return err
}
defer func() {
_ = os.Remove(keyFile)
}()
if err := os.WriteFile(certFile, config.Rest.CertData, os.ModePerm); err != nil {
return err
}
defer func() {
_ = os.Remove(certFile)
}()
// 命令为kubectl config set-credentials <contextName> --embed-certs=true --client-key=<keyFile> --client-certificate=<certFile>
if err := k.Command(
"kubectl",
"config",
"set-credentials",
contextName,
"--embed-certs=true",
"--client-key="+keyFile,
"--client-certificate="+certFile).Run(); err != nil {
return err
}
} else {
return fmt.Errorf("Counld not find credentials in config or credential method is not supported")
}
// 2.3 组合 context
// 命令为kubectl config set-context <contextName> --cluster <contextName> --user=<contextName>
if err := k.Command("kubectl",
"config",
"set-context",
contextName,
"--cluster="+contextName,
"--user="+contextName).Run(); err != nil {
return err
}
// 3. 切换到新创建的 context
// 命令为kubectl config use-context <contextName>
if err := k.Command(
"kubectl",
"config",
"use-context", contextName).Run(); err != nil {
return err
}
return nil
}
func (k *KubectlConfig) DeleteContext(config *ClusterConfig) error {
contextName := k.getContextName(config)
// 1. 删除 cluster
// 命令为kubectl config delete-cluster <contextName>
if err := k.Command(
"kubectl",
"config",
"delete-cluster", contextName).Run(); err != nil {
return err
}
// 2. 删除 user
// 命令为kubectl config delete-user <contextName>
if err := k.Command(
"kubectl",
"config",
"delete-user", contextName).Run(); err != nil {
return err
}
// 3. 删除 context
// 命令为kubectl config delete-context <contextName>
if err := k.Command(
"kubectl",
"config",
"delete-context", contextName).Run(); err != nil {
return err
}
// 4. 如果 previousContext 不为空,恢复到之前的 context
if k.previousContext != "" {
// 命令为kubectl config use-context <k.previousContext>
// 不处理执行错误,因为这里出错不影响测试任务
_ = k.Command(
"kubectl",
"config",
"use-context", k.previousContext).Run()
}
return nil
}