cheliequan
2023-05-24 49a352c6540ff77a2dd2c704d6a613be60ea52e0
src/cluster/cluster.go
@@ -1,18 +1,16 @@
package main
package cluster
import (
   "_/E_/git/aps_deploy/src/util"
   "bytes"
   "context"
   "crypto/tls"
   "encoding/json"
   "fmt"
   "log"
   "net/http"
   "os"
   "strings"
   "time"
   "golang.org/x/crypto/ssh"
   "../util"
)
type Cluster struct {
@@ -32,7 +30,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 +45,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 +66,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 +86,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,7 +107,7 @@
   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)
@@ -119,7 +117,7 @@
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", bearerToken))
   client := createHTTPClient()
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
@@ -147,133 +145,6 @@
   }
   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},
   }
   return &http.Client{Transport: transport}
}
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(),
   }
   // 连接到远程服务器
   client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", nodeIP, sshPort), config)
   if err != nil {
      return "", fmt.Errorf("failed to connect to node %s: %v", nodeIP, err)
   }
   defer client.Close()
   // 创建会话
   session, err := client.NewSession()
   if err != nil {
      return "", fmt.Errorf("failed to create SSH session: %v", err)
   }
   defer session.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
   }
   // 安装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)
   if err != nil {
      return fmt.Errorf("failed to install Docker on the remote server: %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)
   if err != nil {
      return fmt.Errorf("failed to install kubectl on the remote server: %v", err)
   }
   fmt.Println("kubectl has been installed on the remote server.")
   return nil
}
type Node struct {
@@ -328,35 +199,36 @@
}
// Deploy Kubernetes roles on a node using SSH
func deployk8sRolesOnNode(nodeIP, sshUsername, sshPassword, remoteSSHCommand string, sshPort int, roles []string) error {
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 := 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
   }
   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)
@@ -368,7 +240,7 @@
   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)
@@ -380,43 +252,7 @@
   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(rancherConfig RancherConfig, clusterName string) error {
   requestBody := createClusterData(clusterName)
   url := fmt.Sprintf("%s/v3/clusters", rancherConfig.RancherURL)
@@ -428,7 +264,7 @@
   req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rancherConfig.BearerToken))
   req.Header.Set("Content-Type", "application/json")
   client := createHTTPClient()
   client := util.CreateHTTPClient()
   resp, err := client.Do(req)
   if err != nil {
@@ -481,12 +317,6 @@
      // 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{
@@ -500,15 +330,15 @@
   }
   //   Deploy clusterId
   clusterID, err := getClusterID(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterName)
   clusterID, err := GetClusterID(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterName)
   if err != nil {
      log.Fatal(err)
      err = createCluster(rancherConfig, clusterName)
      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)
      clusterID, err = GetClusterID(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterName)
      if err != nil {
         log.Fatal(err)
      }
@@ -516,7 +346,7 @@
   fmt.Println(clusterID)
   //   Deploy nodeCommand
   nodeCommand, err := getNodeCommand(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterID)
   nodeCommand, err := GetNodeCommand(rancherConfig.RancherURL, rancherConfig.BearerToken, clusterID)
   if err != nil {
      log.Fatal(err)
   }
@@ -524,19 +354,19 @@
   for _, node := range nodes {
      //Deploy Docker on each node
      err = installDocker(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort)
      err = util.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)
      err = util.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)
      err = Deployk8sRolesOnNode(node.IP, node.SSHUsername, node.SSHPassword, nodeCommand, node.SSHPort, node.Roles)
      if err != nil {
         log.Fatal(err)
      }