wangpengfei
2023-06-02 064c0874e5fd041c4641ef873d1bf72ac98a184d
src/main/main.go
@@ -1,22 +1,22 @@
package main
import (
   "context"
   "flag"
   "fmt"
   "log"
   "math/rand"
   "os"
   "path/filepath"
   "time"
   appsv1 "k8s.io/api/apps/v1"
   apiv1 "k8s.io/api/core/v1"
   "k8s.io/apimachinery/pkg/api/errors"
   metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
   "k8s.io/apimachinery/pkg/util/intstr"
   "basic.com/aps/aps_deploy.git/src/cluster"
   "basic.com/aps/aps_deploy.git/src/rancher"
   "basic.com/aps/aps_deploy.git/src/util"
   "k8s.io/client-go/kubernetes"
   "k8s.io/client-go/tools/clientcmd"
   "basic.com/aps/aps_deploy.git/src/k8s"
   "github.com/spf13/viper"
)
var (
@@ -26,10 +26,104 @@
   namespaces          = []string{"guangsheng", "geruimi", "tongsheng"}
)
func rancher_install_test(node rancher.Node) {
   /*   nodes := []Node{
      {
         Roles:       []string{"etcd", "controlplane", "worker"},
         IP:          "192.168.20.189",
         SSHUsername: "basic",
         SSHPassword: "123",
         SSHPort:     22,
      },
      {
         Roles:       []string{"worker"},
         IP:          "192.168.20.10",
         SSHUsername: "basic",
         SSHPassword: "123",
         SSHPort:     22,
      },
      {
         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 := rancher.InstallDockerAndRancher(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort)
   if err != nil {
      log.Fatalf("Failed to install Rancher: %v", err)
   }
   os.Exit(0)
}
func cluster_test(clusterName string, rancherClusterConfig rancher.RancherClusterConfig) {
   // Create the cluster
   // Rancher configuration
   /*rancherConfig := RancherConfig{
      RancherURL:  "https://192.168.20.119:8443",
      BearerToken: "token-nnrsc:w68zdt8s47fnpjd5xqdl5hhzpz4j2d56kt5nx49nsswcbpdzc28kh5",
   }*/
   fmt.Println(rancherClusterConfig)
   fmt.Println(rancherClusterConfig.RancherURL)
   fmt.Println(rancherClusterConfig.BearerToken)
   //   Deploy clusterId
   clusterID, err := cluster.GetClusterID(rancherClusterConfig.RancherURL, rancherClusterConfig.BearerToken, clusterName)
   if err != nil {
      fmt.Printf("Cluster not found: %s %v\n", clusterName, err)
      err = cluster.CreateCluster(rancherClusterConfig, clusterName)
      if err != nil {
         log.Fatalf("Failed to create cluster: %v", err)
      }
      fmt.Printf("Cluster created: %s\n", clusterName)
      clusterID, err = cluster.GetClusterID(rancherClusterConfig.RancherURL, rancherClusterConfig.BearerToken, clusterName)
      if err != nil {
         log.Fatal(err)
      }
   }
   fmt.Println(clusterID)
   //   Deploy nodeCommand
   nodeCommand, err := cluster.GetNodeCommand(rancherClusterConfig.RancherURL, rancherClusterConfig.BearerToken, clusterID)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println(nodeCommand)
   for _, node := range rancherClusterConfig.Nodes {
      //Deploy Docker on each node
      err = util.InstallDocker(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort)
      if err != nil {
         log.Fatal(err)
      }
      // Deploy Kubectl on each node
      err = util.InstallKubectl(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort)
      if err != nil {
         log.Fatal(err)
      }
      // Deploy Kubernetes roles on each node
      err = cluster.Deployk8sRolesOnNode(node.IP, node.SSHUsername, node.SSHPassword, nodeCommand, node.SSHPort, node.Roles)
      if err != nil {
         log.Fatal(err)
      }
   }
   os.Exit(0)
}
func main() {
   createCmd := flag.NewFlagSet("create", flag.ExitOnError)
   deleteCmd := flag.NewFlagSet("delete", flag.ExitOnError)
   testCmd := flag.NewFlagSet("test", flag.ExitOnError)
   clusterCmd := flag.NewFlagSet("cluster", flag.ExitOnError)
   rancherInstallCmd := flag.NewFlagSet("rancher_install", flag.ExitOnError)
   createNamespace := createCmd.String("ns", "", "Namespace name")
   createDeployment := createCmd.String("deployment", "", "Deployment name")
@@ -40,7 +134,7 @@
   deleteService := deleteCmd.String("service", "", "Service name")
   if len(os.Args) < 2 {
      fmt.Println("create/delete/test command is required")
      fmt.Println("create/delete/test/cluster/rancher_install command is required")
      os.Exit(1)
   }
@@ -51,40 +145,81 @@
      deleteCmd.Parse(os.Args[2:])
   case "test":
      testCmd.Parse(os.Args[2:])
   case "cluster":
      clusterCmd.Parse(os.Args[2:])
   case "rancher_install":
      rancherInstallCmd.Parse(os.Args[2:])
   default:
      flag.PrintDefaults()
      os.Exit(1)
   }
   // 配置 Kubernetes 集群的 kubeconfig 路径
   kubeconfig := flag.String("kubeconfig", filepath.Join(homeDir(), ".kube", "config"), "kubeconfig file")
   flag.Parse()
   if rancherInstallCmd.Parsed() {
      //// 初始化配置解析库
      //viper.SetConfigName("config")
      //viper.SetConfigType("yaml")
      //viper.AddConfigPath("./config")
      //
      //// 读取配置文件
      //err := viper.ReadInConfig()
      //if err != nil {
      //   log.Fatalf("Failed to read config file: %v", err)
      //}
   // 创建 Kubernetes 客户端
   config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
   if err != nil {
      panic(err.Error())
   }
      // 解析配置文件中的字段
      var rancherClusterConfig rancher.RancherClusterConfig
      //err = viper.Unmarshal(&rancherClusterConfig)
      //if err != nil {
      //   log.Fatalf("Failed to unmarshal config: %v", err)
      //}
   clientset, err := kubernetes.NewForConfig(config)
   if err != nil {
      panic(err.Error())
      rancherClusterConfig.Nodes = make([]rancher.Node, 3)
      rancherClusterConfig.Nodes[0] = rancher.Node{
         Roles:       []string{"worker"},
         IP:          "192.168.20.189",
         SSHUsername: "basic",
         SSHPassword: "123",
         SSHPort:     22,
      }
      rancher_install_test(rancherClusterConfig.Nodes[0])
      os.Exit(1)
   }
   // 执行 create 命令
   if createCmd.Parsed() {
      // 配置 Kubernetes 集群的 kubeconfig 路径
      kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file")
      flag.Parse()
      fmt.Println(&kubeconfig)
      // 创建 Kubernetes 客户端
      config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
      if err != nil {
         panic(err.Error())
      }
      fmt.Println(&config)
      clientset, err := kubernetes.NewForConfig(config)
      if err != nil {
         panic(err.Error())
      }
      if *createNamespace == "" || *createDeployment == "" || *createService == "" {
         fmt.Println("Namespace, Deployment, and Service names are required")
         createCmd.PrintDefaults()
         os.Exit(1)
      }
      err := CreateDeploymentAndService(clientset, *createNamespace, *createDeployment, *createService)
      err = k8s.CreateDeploymentAndService(clientset, *createNamespace, *createDeployment, *createService)
      if err != nil {
         panic(err)
      }
      nodeport, err := GetServiceNodePort(clientset, *createNamespace, *createService)
      nodeport, err := k8s.GetServiceNodePort(clientset, *createNamespace, *createService)
      if err != nil {
         panic(err)
      }
@@ -94,13 +229,28 @@
   // 执行 delete 命令
   if deleteCmd.Parsed() {
      // 配置 Kubernetes 集群的 kubeconfig 路径
      kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file")
      flag.Parse()
      // 创建 Kubernetes 客户端
      config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
      if err != nil {
         panic(err.Error())
      }
      clientset, err := kubernetes.NewForConfig(config)
      if err != nil {
         panic(err.Error())
      }
      if *deleteNamespace == "" || *deleteDeployment == "" || *deleteService == "" {
         fmt.Println("Namespace, Deployment, and Service names are required")
         deleteCmd.PrintDefaults()
         os.Exit(1)
      }
      err := DeleteResources(clientset, *deleteNamespace, *deleteDeployment, *deleteService)
      err = k8s.DeleteResources(clientset, *deleteNamespace, *deleteDeployment, *deleteService)
      if err != nil {
         panic(err)
      }
@@ -110,6 +260,21 @@
   // 执行创建和删除测试
   if testCmd.Parsed() {
      // 配置 Kubernetes 集群的 kubeconfig 路径
      kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file")
      flag.Parse()
      // 创建 Kubernetes 客户端
      config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
      if err != nil {
         panic(err.Error())
      }
      clientset, err := kubernetes.NewForConfig(config)
      if err != nil {
         panic(err.Error())
      }
      fmt.Println("\033[97;40mRunning create and delete tests...\033[0m")
      // 创建测试
@@ -117,11 +282,11 @@
      for _, ns := range namespaces {
         deploymentName := ns
         serviceName := ns
         err := 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 {
            nodeport, err := GetServiceNodePort(clientset, ns, ns)
            nodeport, err := k8s.GetServiceNodePort(clientset, ns, ns)
            if err != nil {
               panic(err)
            }
@@ -139,7 +304,7 @@
      // 删除多个 Namespace 下的相同名称的 Deployment 和 Service
      for _, ns := range namespaces {
         err = DeleteResources(clientset, ns, ns, ns)
         err = k8s.DeleteResources(clientset, ns, ns, ns)
         if err != nil {
            panic(err)
         }
@@ -148,376 +313,27 @@
      fmt.Println("Resources deleted.")
   }
}
   if clusterCmd.Parsed() {
      // 初始化配置解析库
      viper.SetConfigName("config")
      viper.SetConfigType("yaml")
      viper.AddConfigPath("./config")
// CheckAndDeleteResources 检测并删除指定的 Namespace、Deployment 和 Service
func CheckAndDeleteResources(clientset *kubernetes.Clientset, namespace, deploymentName, serviceName string) error {
   fmt.Println("\033[1;37;40mChecking and deleting resources in Namespace:", namespace, "\033[0m")
   // 检查并删除 Deployment
   err := deleteDeploymentIfExists(clientset, namespace, deploymentName)
   if err != nil {
      return err
   }
   // 检查并删除 Service
   err = deleteServiceIfExists(clientset, namespace, serviceName)
   if err != nil {
      return err
   }
   return nil
}
// deleteDeploymentIfExists 检查并删除指定的 Deployment(如果存在)
func deleteDeploymentIfExists(clientset *kubernetes.Clientset, namespace, deploymentName string) error {
   fmt.Println("\033[1;37;40mChecking and deleting Deployment:", deploymentName, "\033[0m")
   err := clientset.AppsV1().Deployments(namespace).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{})
   if err != nil {
      if errors.IsNotFound(err) {
         fmt.Printf("Deployment %s not found in Namespace %s\n", deploymentName, namespace)
      } else {
         return fmt.Errorf("failed to delete Deployment: %v", err)
      }
   } else {
      fmt.Printf("Deployment %s deleted from Namespace %s\n", deploymentName, namespace)
   }
   return nil
}
// deleteServiceIfExists 检查并删除指定的 Service(如果存在)
func deleteServiceIfExists(clientset *kubernetes.Clientset, namespace, serviceName string) error {
   fmt.Println("\033[1;37;40mChecking and deleting Service:", serviceName, "\033[0m")
   err := clientset.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{})
   if err != nil {
      if errors.IsNotFound(err) {
         fmt.Printf("Service %s not found in Namespace %s\n", serviceName, namespace)
      } else {
         return fmt.Errorf("failed to delete Service: %v", err)
      }
   } else {
      fmt.Printf("Service %s deleted from Namespace %s\n", serviceName, namespace)
   }
   return nil
}
func CreateDeploymentAndService(clientset *kubernetes.Clientset, namespace, deploymentName, serviceName string) error {
   fmt.Println("\033[1;37;40mCreating resources in Namespace:", namespace, "\033[0m")
   // 检测并删除已存在的 Deployment 和 Service
   err := CheckAndDeleteResources(clientset, namespace, deploymentName, serviceName)
   if err != nil {
      return err
   }
   // 创建 Namespace
   err = createNamespace(clientset, namespace)
   if err != nil {
      return err
   }
   // 创建 Deployment
   err = createDeployment(clientset, namespace, deploymentName)
   if err != nil {
      return err
   }
   // 创建 Service
   err = createService(clientset, namespace, serviceName)
   if err != nil {
      return err
   }
   return nil
}
// createNamespace 创建指定的 Namespace
func createNamespace(clientset *kubernetes.Clientset, namespace string) error {
   log.Printf("Creating Namespace: %s\n", namespace)
   ns := &apiv1.Namespace{
      ObjectMeta: metav1.ObjectMeta{
         Name: namespace,
      },
   }
   _, err := clientset.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
   if err != nil {
      if !errors.IsAlreadyExists(err) {
         return fmt.Errorf("failed to create Namespace: %w", err)
      }
      log.Printf("Namespace %s already exists\n", namespace)
   } else {
      log.Printf("Namespace %s created\n", namespace)
   }
   return nil
}
func createDeployment(clientset *kubernetes.Clientset, namespace, deploymentName string) error {
   fmt.Println("\033[1;37;40mCreating Deployment:", deploymentName, "\033[0m")
   deployment := &appsv1.Deployment{
      ObjectMeta: metav1.ObjectMeta{
         Name: deploymentName,
      },
      Spec: appsv1.DeploymentSpec{
         Replicas: &replicas,
         Selector: &metav1.LabelSelector{
            MatchLabels: map[string]string{
               "cid": namespace,
            },
         },
         Template: apiv1.PodTemplateSpec{
            ObjectMeta: metav1.ObjectMeta{
               Labels: map[string]string{
                  "cid": namespace,
               },
            },
            Spec: apiv1.PodSpec{
               TopologySpreadConstraints: []apiv1.TopologySpreadConstraint{
                  {
                     MaxSkew:           1,
                     TopologyKey:       "kubernetes.io/hostname",
                     WhenUnsatisfiable: apiv1.DoNotSchedule,
                     LabelSelector: &metav1.LabelSelector{
                        MatchLabels: map[string]string{
                           "cid": namespace,
                        },
                     },
                  },
               },
               Containers: []apiv1.Container{
                  {
                     Name:  namespace,
                     Image: "192.168.20.119/apsserver/apsserver:v0.2",
                     Env: []apiv1.EnvVar{
                        {
                           Name:  "NODE_ID",
                           Value: namespace,
                        },
                     },
                  },
               },
            },
         },
      },
   }
   _, err := clientset.AppsV1().Deployments(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
   if err != nil {
      if !errors.IsAlreadyExists(err) {
         return fmt.Errorf("failed to create Deployment: %v", err)
      }
      fmt.Printf("Deployment %s already exists in Namespace %s\n", deploymentName, namespace)
   } else {
      fmt.Printf("Deployment %s created in Namespace %s\n", deploymentName, namespace)
   }
   return nil
}
// createService 创建指定的 Service
func createService(clientset *kubernetes.Clientset, namespace, serviceName string) error {
   fmt.Println("\033[1;37;40mCreating Service:", serviceName, "\033[0m")
   nodePort, err := getRandomNodePort(clientset)
   if err != nil {
      return err
   }
   service := &apiv1.Service{
      ObjectMeta: metav1.ObjectMeta{
         Name: serviceName,
      },
      Spec: apiv1.ServiceSpec{
         Selector: map[string]string{
            "cid": namespace,
         },
         Type: apiv1.ServiceTypeNodePort,
         Ports: []apiv1.ServicePort{
            {
               Name:       "http",
               Protocol:   apiv1.ProtocolTCP,
               Port:       port,
               TargetPort: intstr.FromInt(int(port)),
               NodePort:   nodePort,
            },
         },
      },
   }
   _, err = clientset.CoreV1().Services(namespace).Create(context.TODO(), service, metav1.CreateOptions{})
   if err != nil {
      if !errors.IsAlreadyExists(err) {
         return fmt.Errorf("failed to create Service: %v", err)
      }
      fmt.Printf("Service %s already exists in Namespace %s\n", serviceName, namespace)
   } else {
      fmt.Printf("Service %s created in Namespace %s\n", serviceName, namespace)
   }
   return nil
}
// getRandomNodePort 获取一个未使用的随机 NodePort
func getRandomNodePort(clientset *kubernetes.Clientset) (int32, error) {
   // 获取一个随机的 NodePort
   nodePort := int32(0)
   for {
      // 生成一个随机的 NodePort
      nodePort = generateRandomNodePort()
      // 检查该 NodePort 是否已被使用
      used, err := isNodePortUsed(clientset, nodePort)
      // 读取配置文件
      err := viper.ReadInConfig()
      if err != nil {
         return 0, err
         log.Fatalf("Failed to read config file: %v", err)
      }
      // 如果未被使用,则标记为已使用,并退出循环
      if !used {
         usedNodePorts[nodePort] = true
         break
      // 解析配置文件中的字段
      var rancherClusterConfig rancher.RancherClusterConfig
      err = viper.Unmarshal(&rancherClusterConfig)
      if err != nil {
         log.Fatalf("Failed to unmarshal config: %v", err)
      }
      clusterName := "kubernetus"
      fmt.Println(rancherClusterConfig)
      cluster_test(clusterName, rancherClusterConfig)
   }
   return nodePort, nil
}
// generateRandomNodePort 生成一个随机的 NodePort
func generateRandomNodePort() int32 {
   // 在范围 30000-32767 中生成随机数作为 NodePort
   return int32(rand.Intn(32767-30000+1) + 30000)
}
// isNodePortUsed 检查指定的 NodePort 是否已被使用
func isNodePortUsed(clientset *kubernetes.Clientset, nodePort int32) (bool, error) {
   // 获取所有 Service
   services, err := clientset.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{})
   if err != nil {
      return false, err
   }
   // 检查每个 Service 的 NodePort 是否与指定的 NodePort 相同
   for _, svc := range services.Items {
      for _, port := range svc.Spec.Ports {
         if port.NodePort == nodePort {
            return true, nil
         }
      }
   }
   return false, nil
}
// DeleteResources 删除指定的 Namespace、Deployment 和 Service
func DeleteResources(clientset *kubernetes.Clientset, namespace, deploymentName, serviceName string) error {
   fmt.Println("\033[1;37;40mDeleting resources in Namespace:", namespace, "\033[0m")
   // 删除 Deployment
   err := deleteDeployment(clientset, namespace, deploymentName)
   if err != nil {
      return err
   }
   // 删除 Service
   err = deleteService(clientset, namespace, serviceName)
   if err != nil {
      return err
   }
   // 删除 Namespace
   err = deleteNamespace(clientset, namespace)
   if err != nil {
      return err
   }
   return nil
}
// deleteDeployment 删除指定的 Deployment
func deleteDeployment(clientset *kubernetes.Clientset, namespace, deploymentName string) error {
   fmt.Println("\033[1;37;40mDeleting Deployment:", deploymentName, "\033[0m")
   err := clientset.AppsV1().Deployments(namespace).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{})
   if err != nil {
      if errors.IsNotFound(err) {
         fmt.Printf("Deployment %s not found in Namespace %s\n", deploymentName, namespace)
      } else {
         return fmt.Errorf("failed to delete Deployment: %v", err)
      }
   } else {
      fmt.Printf("Deployment %s deleted from Namespace %s\n", deploymentName, namespace)
   }
   return nil
}
// deleteService 删除指定的 Service
func deleteService(clientset *kubernetes.Clientset, namespace, serviceName string) error {
   fmt.Println("\033[1;37;40mDeleting Service:", serviceName, "\033[0m")
   err := clientset.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{})
   if err != nil {
      if errors.IsNotFound(err) {
         fmt.Printf("Service %s not found in Namespace %s\n", serviceName, namespace)
      } else {
         return fmt.Errorf("failed to delete Service: %v", err)
      }
   } else {
      fmt.Printf("Service %s deleted from Namespace %s\n", serviceName, namespace)
   }
   return nil
}
// deleteNamespace 删除指定的 Namespace
func deleteNamespace(clientset *kubernetes.Clientset, namespace string) error {
   fmt.Println("\033[1;37;40mDeleting Namespace:", namespace, "\033[0m")
   err := clientset.CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{})
   if err != nil {
      if errors.IsNotFound(err) {
         fmt.Printf("Namespace %s not found\n", namespace)
      } else {
         return fmt.Errorf("failed to delete Namespace: %v", err)
      }
   } else {
      fmt.Printf("Namespace %s deleted\n", namespace)
   }
   return nil
}
// homeDir 获取当前用户的家目录路径
func homeDir() string {
   if h := os.Getenv("HOME"); h != "" {
      return h
   }
   return os.Getenv("USERPROFILE") // Windows 环境下获取用户目录
}
// GetServiceNodePort 获取指定 Service 的 NodePort
func GetServiceNodePort(clientset *kubernetes.Clientset, namespace, serviceName string) (int32, error) {
   svc, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{})
   if err != nil {
      return 0, fmt.Errorf("failed to get Service: %v", err)
   }
   // 检查 Service 类型是否为 NodePort
   if svc.Spec.Type != apiv1.ServiceTypeNodePort {
      return 0, fmt.Errorf("Service %s is not of type NodePort", serviceName)
   }
   // 获取第一个端口的 NodePort
   if len(svc.Spec.Ports) > 0 {
      return svc.Spec.Ports[0].NodePort, nil
   }
   return 0, fmt.Errorf("no ports defined for Service %s", serviceName)
}