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 --server --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 --token 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 --embed-certs=true --client-key= --client-certificate= 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 --cluster --user= if err := k.Command("kubectl", "config", "set-context", contextName, "--cluster="+contextName, "--user="+contextName).Run(); err != nil { return err } // 3. 切换到新创建的 context // 命令为:kubectl config use-context 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 if err := k.Command( "kubectl", "config", "delete-cluster", contextName).Run(); err != nil { return err } // 2. 删除 user // 命令为:kubectl config delete-user if err := k.Command( "kubectl", "config", "delete-user", contextName).Run(); err != nil { return err } // 3. 删除 context // 命令为:kubectl config delete-context 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.Command( "kubectl", "config", "use-context", k.previousContext).Run() } return nil }