wangpengfei
2023-06-02 064c0874e5fd041c4641ef873d1bf72ac98a184d
src/cluster/cluster.go
@@ -1,18 +1,18 @@
package main
package cluster
import (
   "bytes"
   "context"
   "crypto/tls"
   "encoding/json"
   "fmt"
   "io/ioutil"
   "log"
   "net/http"
   "os"
   "path/filepath"
   "strings"
   "time"
   "golang.org/x/crypto/ssh"
   "basic.com/aps/aps_deploy.git/src/rancher"
   "basic.com/aps/aps_deploy.git/src/util"
)
type Cluster struct {
@@ -24,6 +24,12 @@
   Data []Cluster `json:"data"`
}
type KubectlConfigResponse struct {
   BaseType string `json:"baseType"`
   Config   string `json:"config"`
   Type     string `json:"type"`
}
type RegistrationTokenResponse struct {
   Command string `json:"command"`
}
@@ -32,7 +38,7 @@
   NodeCommand string `json:"nodeCommand"`
}
func createRegistrationToken(serverURL, bearerToken, clusterID string) (string, error) {
func CreateRegistrationToken(serverURL, bearerToken, clusterID string) (string, error) {
   url := fmt.Sprintf("%s/v3/clusterregistrationtokens", serverURL)
   payload := strings.NewReader(fmt.Sprintf(`{
@@ -47,7 +53,7 @@
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
   req.Header.Set("Content-Type", "application/json")
   client := createHTTPClient()
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
@@ -68,7 +74,7 @@
   return tokenResp.Command, nil
}
func getNodeCommand(serverURL, bearerToken, clusterID string) (string, error) {
func GetNodeCommand(serverURL, bearerToken, clusterID string) (string, error) {
   url := fmt.Sprintf("%s/v3/clusterregistrationtokens", serverURL)
   payload := map[string]interface{}{
@@ -88,7 +94,7 @@
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
   req.Header.Set("Content-Type", "application/json")
   client := createHTTPClient()
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
@@ -109,17 +115,17 @@
   return nodeCommandResponse.NodeCommand, nil
}
func getClusterID(serverURL, bearerToken, clusterName string) (string, error) {
func GetClusterID(serverURL, bearerToken, clusterName string) (string, error) {
   url := fmt.Sprintf("%s/v3/clusters", serverURL)
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      return "", fmt.Errorf("failed to create cluster list request: %v", err)
      return "", fmt.Errorf("failed to get cluster list request: %v", err)
   }
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
   client := createHTTPClient()
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
@@ -149,131 +155,99 @@
   return "", fmt.Errorf("cluster '%s' not found", clusterName)
}
// Create an HTTP client with insecure TLS configuration
func createHTTPClient() *http.Client {
   transport := &http.Transport{
      TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
func GetClusters(serverURL, bearerToken string) ([]string, error) {
   url := fmt.Sprintf("%s/v3/clusters", serverURL)
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      return nil, fmt.Errorf("failed to get cluster list request: %v", err)
   }
   return &http.Client{Transport: transport}
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
      return nil, fmt.Errorf("failed to get cluster list: %v", err)
   }
   defer resp.Body.Close()
   if resp.StatusCode != http.StatusOK {
      return nil, fmt.Errorf("failed to get cluster list: unexpected status code %d", resp.StatusCode)
   }
   // Parse the API response
   var clustersResponse ClustersResponse
   err = json.NewDecoder(resp.Body).Decode(&clustersResponse)
   log.Println("3333333333333333333333333")
   log.Printf("%v", resp.Body)
   if err != nil {
      return nil, fmt.Errorf("failed to decode cluster list response: %v", err)
   }
   var clusters = make([]string, 0)
   // Print cluster names
   for _, cluster := range clustersResponse.Data {
      clusters = append(clusters, cluster.ID)
      fmt.Printf("Cluster ID: %s, Name: %s\n", cluster.ID, cluster.Name)
   }
   return clusters, nil
}
func sshExec(nodeIP, sshUsername, sshPassword, remoteSSHCommand string, sshPort int) (string, error) {
   // SSH 连接配置
   config := &ssh.ClientConfig{
      User: sshUsername,
      Auth: []ssh.AuthMethod{
         ssh.Password(sshPassword),
      },
      HostKeyCallback: ssh.InsecureIgnoreHostKey(),
   }
func GetKubectlConfig(serverURL, bearerToken, clusterName string) (string, error) {
   // 连接到远程服务器
   client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", nodeIP, sshPort), config)
   url := fmt.Sprintf("%s/v3/clusters/%s?action=generateKubeconfig", serverURL, clusterName)
   req, err := http.NewRequest("POST", url, nil)
   if err != nil {
      return "", fmt.Errorf("failed to connect to node %s: %v", nodeIP, err)
      return "", fmt.Errorf("failed to get cluster list request: %v", err)
   }
   defer client.Close()
   // 创建会话
   session, err := client.NewSession()
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
   req.Header.Set("Content-Type", "application/json")
   req.Header.Set("Accept", "application/json")
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
      return "", fmt.Errorf("failed to create SSH session: %v", err)
      return "", fmt.Errorf("failed to get cluster list: %v", err)
   }
   defer session.Close()
   defer resp.Body.Close()
   // 创建一个具有超时的上下文
   ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second)
   defer cancel()
   // 通过会话执行远程命令
   outputChan := make(chan string)
   errorChan := make(chan error)
   go func() {
      // 创建一个连接标准输入的管道
      stdinPipe, err := session.StdinPipe()
      if err != nil {
         errorChan <- fmt.Errorf("failed to create stdin pipe: %v", err)
         return
      }
      // 启动会话
      if err := session.Start(fmt.Sprintf("sudo -SE %s", remoteSSHCommand)); err != nil {
         errorChan <- fmt.Errorf("failed to start command: %v err:%v", remoteSSHCommand, err)
         return
      }
      // 将密码写入标准输入管道
      _, err = fmt.Fprintf(stdinPipe, "%s\n", sshPassword)
      if err != nil {
         errorChan <- fmt.Errorf("failed to write password to stdin: %v", err)
         return
      }
      // 等待会话结束
      if err := session.Wait(); err != nil {
         errorChan <- fmt.Errorf("command execution failed: %v err:%v", remoteSSHCommand, err)
         return
      }
      outputChan <- ""
   }()
   // 等待结果或超时
   select {
   case <-ctx.Done():
      // 关闭会话以终止远程命令
      session.Close()
      // 等待会话关闭的 goroutine 结束
      <-outputChan
      return "", fmt.Errorf("SSH command execution timed out")
   case err := <-errorChan:
      return "", err
   case <-outputChan:
      fmt.Printf("Command: %v executed on the remote server: %s\n", remoteSSHCommand, nodeIP)
      return "", nil
   }
}
// 安装Docker
func installDocker(nodeIP, sshUsername, sshPassword string, sshPort int) error {
   // 检查Docker是否已安装
   checkCommand := "which docker"
   _, err := sshExec(nodeIP, sshUsername, sshPassword, checkCommand, sshPort)
   if err == nil {
      fmt.Println("Docker is already installed on the remote server.")
      return nil
   if resp.StatusCode != http.StatusOK {
      return "", fmt.Errorf("failed to get cluster list: unexpected status code %d", resp.StatusCode)
   }
   // 安装Docker
   installCommand := "sudo curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh"
   _, err = sshExec(nodeIP, sshUsername, sshPassword, installCommand, sshPort)
   // Parse the API response
   var kubectlConfig KubectlConfigResponse
   err = json.NewDecoder(resp.Body).Decode(&kubectlConfig)
   if err != nil {
      return fmt.Errorf("failed to install Docker on the remote server: %v", err)
      return "", fmt.Errorf("failed to decode cluster list response: %v", err)
   }
   fmt.Println("Docker has been installed on the remote server.")
   return nil
}
// 安装kubectl
func installKubectl(nodeIP, sshUsername, sshPassword string, sshPort int) error {
   // 检查kubectl是否已安装
   checkCommand := "which kubectl"
   _, err := sshExec(nodeIP, sshUsername, sshPassword, checkCommand, sshPort)
   if err == nil {
      fmt.Println("kubectl is already installed on the remote server.")
      return nil
   }
   // 安装kubectl
   installCommand := "sudo curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && sudo chmod +x kubectl && sudo mv kubectl /usr/local/bin/"
   _, err = sshExec(nodeIP, sshUsername, sshPassword, installCommand, sshPort)
   // 保存 kubeconfig 到文件
   homeDir, err := os.UserHomeDir()
   if err != nil {
      return fmt.Errorf("failed to install kubectl on the remote server: %v", err)
      log.Fatalf("Failed to get home directory: %v", err)
   }
   kubeconfigDir := filepath.Join(homeDir, ".kube")
   err = os.MkdirAll(kubeconfigDir, 0700)
   if err != nil {
      log.Fatalf("Failed to create .kube directory: %v", err)
   }
   kubeconfigPath := filepath.Join(kubeconfigDir, "config")
   err = ioutil.WriteFile(kubeconfigPath, []byte(kubectlConfig.Config), 0600)
   if err != nil {
      log.Fatalf("Failed to save kubeconfig: %v", err)
   }
   fmt.Println("kubectl has been installed on the remote server.")
   return nil
   return kubectlConfig.Config, nil
}
type Node struct {
@@ -283,11 +257,6 @@
   SSHUsername string   `json:"sshUsername"`
   SSHPassword string   `json:"sshPassword"`
   SSHPort     int      `json:"sshPort"`
}
type RancherConfig struct {
   RancherURL  string `json:"rancherURL"`
   BearerToken string `json:"bearerToken"`
}
type ClusterCreateRequest struct {
@@ -328,38 +297,39 @@
}
// Deploy Kubernetes roles on a node using SSH
func deployk8sRolesOnNode(nodeIP, sshUsername, sshPassword, remoteSSHCommand string, sshPort int, roles []string) error {
   rancherAgentInstalled, err := isRancherAgentInstalled(nodeIP, sshUsername, sshPassword, sshPort)
func Deployk8sRolesOnNode(nodeIP, sshUsername, sshPassword, remoteSSHCommand string, sshPort int, roles []string) error {
   rancherAgentInstalled, err := IsRancherAgentInstalled(nodeIP, sshUsername, sshPassword, sshPort)
   if err == nil {
      return nil
   }
   if !rancherAgentInstalled {
   // Add role parameters to nodeCommand
   for _, role := range roles {
      switch role {
      case "etcd":
         remoteSSHCommand += " --etcd"
      case "controlplane":
         remoteSSHCommand += " --controlplane"
      case "worker":
         remoteSSHCommand += " --worker"
      default:
         log.Fatalf("invalid role specified : %s", role)
      // Add role parameters to nodeCommand
      for _, role := range roles {
         switch role {
         case "etcd":
            remoteSSHCommand += " --etcd"
         case "controlplane":
            remoteSSHCommand += " --controlplane"
         case "worker":
            remoteSSHCommand += " --worker"
         default:
            log.Fatalf("invalid role specified : %s", role)
         }
      }
   }
   _, err := sshExec(nodeIP, sshUsername, sshPassword, remoteSSHCommand, sshPort)
   if err != nil {
      return fmt.Errorf("failed to deploy Kubernetes roles on the remote server: %v", err)
      _, err := util.SSHExec(nodeIP, sshUsername, sshPassword, remoteSSHCommand, sshPort)
      if err != nil {
         return fmt.Errorf("failed to deploy Kubernetes roles on the remote server: %v", err)
      }
   }
   return nil
}
func isRancherInstalled(ip, username, password string, sshPort int) (bool, error) {
func IsRancherInstalled(ip, username, password string, sshPort int) (bool, error) {
   // 检查Rancher容器是否已运行
   checkRancherCommand := "sudo docker ps --format '{{.Image}}' | grep -q rancher/rancher:v2.5.17"
   _, err := sshExec(ip, username, password, checkRancherCommand, sshPort)
   _, err := util.SSHExec(ip, username, password, checkRancherCommand, sshPort)
   if err != nil {
      // 如果执行命令出错,则说明Rancher未安装或发生其他错误
      return false, fmt.Errorf("failed to check Rancher installation: %v", err)
@@ -368,10 +338,10 @@
   return true, nil
}
func isRancherAgentInstalled(ip, username, password string, sshPort int) (bool, error) {
func IsRancherAgentInstalled(ip, username, password string, sshPort int) (bool, error) {
   // 检查Rancher容器是否已运行
   checkRancherCommand := "sudo docker ps --format '{{.Image}}' | grep -q rancher/rancher-agent:v2.5."
   _, err := sshExec(ip, username, password, checkRancherCommand, sshPort)
   _, err := util.SSHExec(ip, username, password, checkRancherCommand, sshPort)
   if err != nil {
      // 如果执行命令出错,则说明Rancher未安装或发生其他错误
      return false, fmt.Errorf("failed to check Rancher installation: %v", err)
@@ -380,55 +350,20 @@
   return true, nil
}
func installRancher(ip, username, password string, sshPort int) error {
   rancherInstalled, err := isRancherInstalled(ip, username, password, sshPort)
   if err == nil {
      return nil
   }
   if !rancherInstalled {
      // 安装Rancher命令
      rancherCommand := "sudo docker run --privileged  -d --restart=unless-stopped -p 8081:80 -p 8443:443  -v /opt/rancher:/var/lib/rancher registry.cn-hangzhou.aliyuncs.com/rancher/rancher:v2.5.17"
      _, err = sshExec(ip, username, password, rancherCommand, sshPort)
      if err != nil {
         return fmt.Errorf("failed to install Rancher: %v", err)
      }
   } else {
      fmt.Println("Rancher is already installed on the remote server.")
   }
   return nil
}
func installDockerAndRancher(ip, username, password string, sshPort int) error {
   // 安装Docker命令
   err := installDocker(ip, username, password, sshPort)
   if err != nil {
      return err
   }
   // 安装Rancher命令
   err = installRancher(ip, username, password, sshPort)
   if err != nil {
      return err
   }
   return nil
}
func createCluster(rancherConfig RancherConfig, clusterName string) error {
func CreateCluster(rancherClusterConfig rancher.RancherClusterConfig, clusterName string) error {
   requestBody := createClusterData(clusterName)
   fmt.Println(rancherClusterConfig.RancherURL)
   url := fmt.Sprintf("%s/v3/clusters", rancherConfig.RancherURL)
   url := fmt.Sprintf("%s/v3/clusters", rancherClusterConfig.RancherURL)
   req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
   if err != nil {
      return fmt.Errorf("Failed to create HTTP request: %v", err)
   }
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rancherConfig.BearerToken))
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rancherClusterConfig.BearerToken))
   req.Header.Set("Content-Type", "application/json")
   client := createHTTPClient()
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
@@ -449,97 +384,4 @@
   fmt.Printf("Cluster created: ID=%s, Name=%s\n", responseBody.ID, responseBody.Name)
   return nil
}
func main() {
   clusterName := "kubernetus"
   nodes := []Node{
      {
         ClusterName: clusterName,
         Roles:       []string{"etcd", "controlplane", "worker"},
         IP:          "192.168.20.189",
         SSHUsername: "basic",
         SSHPassword: "123",
         SSHPort:     22,
      },
      {
         ClusterName: clusterName,
         Roles:       []string{"worker"},
         IP:          "192.168.20.10",
         SSHUsername: "basic",
         SSHPassword: "123",
         SSHPort:     22,
      },
      {
         ClusterName: clusterName,
         Roles:       []string{"worker"},
         IP:          "192.168.20.115",
         SSHUsername: "basic",
         SSHPassword: "alien123",
         SSHPort:     22,
      },
      // Add more nodes here if needed
   }
   //install rancher on master node
   err := installDockerAndRancher(nodes[0].IP, nodes[0].SSHUsername, nodes[0].SSHPassword, nodes[0].SSHPort)
   if err != nil {
      log.Fatalf("Failed to install Rancher: %v", err)
   }
   // Create the cluster
   // Rancher configuration
   /*rancherConfig := RancherConfig{
      RancherURL:  "https://192.168.20.119:8443",
      BearerToken: "token-nnrsc:w68zdt8s47fnpjd5xqdl5hhzpz4j2d56kt5nx49nsswcbpdzc28kh5",
   }*/
   rancherConfig := RancherConfig{
      RancherURL:  "https://192.168.20.189:8443",
      BearerToken: "token-t4cdf:h7zhmbvbzdvd9mmjw8zmt8rh4m7rl5gtqpqljlhl9tlr2z26j9lf4l",
   }
   //   Deploy clusterId
   clusterID, err := getClusterID(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterName)
   if err != nil {
      log.Fatal(err)
      err = createCluster(rancherConfig, clusterName)
      if err != nil {
         log.Fatalf("Failed to create cluster: %v", err)
      }
      fmt.Printf("Cluster created: %s\n", clusterName)
      clusterID, err = getClusterID(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterName)
      if err != nil {
         log.Fatal(err)
      }
   }
   fmt.Println(clusterID)
   //   Deploy nodeCommand
   nodeCommand, err := getNodeCommand(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterID)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println(nodeCommand)
   for _, node := range nodes {
      //Deploy Docker on each node
      err = installDocker(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort)
      if err != nil {
         log.Fatal(err)
      }
      // Deploy Kubectl on each node
      err = installKubectl(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort)
      if err != nil {
         log.Fatal(err)
      }
      // Deploy Kubernetes roles on each node
      err = deployk8sRolesOnNode(node.IP, node.SSHUsername, node.SSHPassword, nodeCommand, node.SSHPort, node.Roles)
      if err != nil {
         log.Fatal(err)
      }
   }
   os.Exit(0)
}