cheliequan
2023-05-24 49a352c6540ff77a2dd2c704d6a613be60ea52e0
重构项目,导出函数手写字母大写
1个文件已添加
2 文件已重命名
5个文件已修改
425 ■■■■■ 已修改文件
go.mod 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/cluster/cluster.go 246 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/k8s/create.go 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/k8s/delete.go 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/main.go 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/rancher/ranche.go 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/util/util.go 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod
@@ -3,6 +3,7 @@
go 1.14
require (
    golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0
    k8s.io/api v0.20.2
    k8s.io/apimachinery v0.20.2
    k8s.io/client-go v0.20.0
go.sum
@@ -160,6 +160,12 @@
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rancher/client-go v1.5.1 h1:RqwrSLR+sgaXTC/0nraGDDB58fFySWuMyANCpxdXN2I=
github.com/rancher/client-go v1.25.4-rancher1 h1:9MlBC8QbgngUkhNzMR8rZmmCIj6WNRHFOnYiwC2Kty4=
github.com/rancher/go-rancher v0.1.0 h1:YIKWwe5giu2WICfyCcGqX+m4XTRbMpA8vzLxl1Kwb7w=
github.com/rancher/go-rancher v0.1.0/go.mod h1:7oQvGNiJsGvrUgB+7AH8bmdzuR0uhULfwKb43Ht0hUk=
github.com/rancherio/go-rancher v0.1.0 h1:rwAwhMXyNdA82hglnWxKwkoAvQ8UKo0i0SudM1mTYfY=
github.com/rancherio/go-rancher v0.1.0/go.mod h1:VXd0Uc4WrlOE85WC4Syk7rY+VNPxBhHXoTgcB1Gquo0=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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)
        }
src/k8s/create.go
File was renamed from src/create/main.go
@@ -1,4 +1,4 @@
package create
package k8s
import (
    "context"
@@ -6,9 +6,9 @@
    "fmt"
    "log"
    "math/rand"
    "os"
    "path/filepath"
    "../util"
    appsv1 "k8s.io/api/apps/v1"
    apiv1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/errors"
@@ -27,7 +27,7 @@
func main() {
    // 配置 Kubernetes 集群的 kubeconfig 路径
    kubeconfig := flag.String("kubeconfig", filepath.Join(homeDir(), ".kube", "config"), "kubeconfig file")
    kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file")
    flag.Parse()
    // 创建 Kubernetes 客户端
@@ -320,14 +320,6 @@
    }
    return false, nil
}
// homeDir 获取当前用户的家目录路径
func homeDir() string {
    if h := os.Getenv("HOME"); h != "" {
        return h
    }
    return os.Getenv("USERPROFILE") // Windows 环境下获取用户目录
}
// GetServiceNodePort 获取指定 Service 的 NodePort
src/k8s/delete.go
File was renamed from src/delete/main.go
@@ -1,12 +1,12 @@
package delete
package k8s
import (
    "context"
    "flag"
    "fmt"
    "os"
    "path/filepath"
    "../util"
    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
@@ -22,7 +22,7 @@
func main() {
    // 配置 Kubernetes 集群的 kubeconfig 路径
    kubeconfig := flag.String("kubeconfig", filepath.Join(homeDir(), ".kube", "config"), "kubeconfig file")
    kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file")
    flag.Parse()
    // 创建 Kubernetes 客户端
@@ -124,12 +124,4 @@
    }
    return nil
}
// homeDir 获取当前用户的家目录路径
func homeDir() string {
    if h := os.Getenv("HOME"); h != "" {
        return h
    }
    return os.Getenv("USERPROFILE") // Windows 环境下获取用户目录
}
src/main/main.go
@@ -8,11 +8,11 @@
    "path/filepath"
    "time"
    "../util"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "basic.com/aps/aps_deploy.git/src/create"
    "basic.com/aps/aps_deploy.git/src/delete"
    "../k8s"
)
var (
@@ -53,7 +53,7 @@
    }
    // 配置 Kubernetes 集群的 kubeconfig 路径
    kubeconfig := flag.String("kubeconfig", filepath.Join(homeDir(), ".kube", "config"), "kubeconfig file")
    kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file")
    flag.Parse()
    // 创建 Kubernetes 客户端
@@ -75,12 +75,12 @@
            os.Exit(1)
        }
        err := create.CreateDeploymentAndService(clientset, *createNamespace, *createDeployment, *createService)
        err := k8s.CreateDeploymentAndService(clientset, *createNamespace, *createDeployment, *createService)
        if err != nil {
            panic(err)
        }
        nodeport, err := create.GetServiceNodePort(clientset, *createNamespace, *createService)
        nodeport, err := k8s.GetServiceNodePort(clientset, *createNamespace, *createService)
        if err != nil {
            panic(err)
        }
@@ -96,7 +96,7 @@
            os.Exit(1)
        }
        err := delete.DeleteResources(clientset, *deleteNamespace, *deleteDeployment, *deleteService)
        err := k8s.DeleteResources(clientset, *deleteNamespace, *deleteDeployment, *deleteService)
        if err != nil {
            panic(err)
        }
@@ -113,7 +113,7 @@
        for _, ns := range namespaces {
            deploymentName := ns
            serviceName := ns
            err := create.CreateDeploymentAndService(clientset, ns, deploymentName, serviceName)
            err := k8s.CreateDeploymentAndService(clientset, ns, deploymentName, serviceName)
            if err != nil {
                log.Printf("\033[97;41mFailed to create resources in namespace %s: %v\033[0m\n", ns, err)
            } else {
@@ -135,7 +135,7 @@
        // 删除多个 Namespace 下的相同名称的 Deployment 和 Service
        for _, ns := range namespaces {
            err = delete.DeleteResources(clientset, ns, ns, ns)
            err = k8s.DeleteResources(clientset, ns, ns, ns)
            if err != nil {
                panic(err)
            }
@@ -145,11 +145,3 @@
    }
}
// homeDir 获取当前用户的家目录路径
func homeDir() string {
        if h := os.Getenv("HOME"); h != "" {
                return h
        }
        return os.Getenv("USERPROFILE") // Windows 环境下获取用户目录
}
src/rancher/ranche.go
New file
@@ -0,0 +1,110 @@
package rancher
import (
    "fmt"
    "log"
    "os"
    "../util"
)
type Node struct {
    ClusterName string   `json:"clusterName"`
    Roles       []string `json:"roles"`
    IP          string   `json:"ip"`
    SSHUsername string   `json:"sshUsername"`
    SSHPassword string   `json:"sshPassword"`
    SSHPort     int      `json:"sshPort"`
}
type RancherConfig struct {
    RancherURL  string `json:"rancherURL"`
    BearerToken string `json:"bearerToken"`
}
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 := util.SSHExec(ip, username, password, checkRancherCommand, sshPort)
    if err != nil {
        // 如果执行命令出错,则说明Rancher未安装或发生其他错误
        return false, fmt.Errorf("failed to check Rancher installation: %v", err)
    }
    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 = util.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 := util.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 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)
    }
    os.Exit(0)
}
src/util/util.go
@@ -12,14 +12,14 @@
)
// homeDir 获取当前用户的家目录路径
func homeDir() string {
func HomeDir() string {
    if h := os.Getenv("HOME"); h != "" {
        return h
    }
    return os.Getenv("USERPROFILE") // Windows 环境下获取用户目录
}
func sshExec(nodeIP, sshUsername, sshPassword, remoteSSHCommand string, sshPort int) (string, error) {
func SSHExec(nodeIP, sshUsername, sshPassword, remoteSSHCommand string, sshPort int) (string, error) {
    // SSH 连接配置
    config := &ssh.ClientConfig{
        User: sshUsername,
@@ -97,7 +97,7 @@
}
// 安装Docker
func installDocker(nodeIP, sshUsername, sshPassword string, sshPort int) error {
func InstallDocker(nodeIP, sshUsername, sshPassword string, sshPort int) error {
    // 检查Docker是否已安装
    checkCommand := "which docker"
    _, err := sshExec(nodeIP, sshUsername, sshPassword, checkCommand, sshPort)
@@ -118,7 +118,7 @@
}
// Create an HTTP client with insecure TLS configuration
func createHTTPClient() *http.Client {
func CreateHTTPClient() *http.Client {
    transport := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
@@ -126,7 +126,7 @@
}
// 安装kubectl
func installKubectl(nodeIP, sshUsername, sshPassword string, sshPort int) error {
func InstallKubectl(nodeIP, sshUsername, sshPassword string, sshPort int) error {
    // 检查kubectl是否已安装
    checkCommand := "which kubectl"
    _, err := sshExec(nodeIP, sshUsername, sshPassword, checkCommand, sshPort)