|
|
|
@ -8,6 +8,7 @@ import ( |
|
|
|
|
"log" |
|
|
|
|
"os" |
|
|
|
|
"path" |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
@ -40,6 +41,17 @@ func CreateCluster(c *cli.Context) error { |
|
|
|
|
return errors.New("Cannot use --timeout flag without --wait flag") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// environment variables
|
|
|
|
|
env := []string{"K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml"} |
|
|
|
|
if c.IsSet("env") || c.IsSet("e") { |
|
|
|
|
env = append(env, c.StringSlice("env")...) |
|
|
|
|
} |
|
|
|
|
k3sClusterSecret := "" |
|
|
|
|
if c.Int("workers") > 0 { |
|
|
|
|
k3sClusterSecret = fmt.Sprintf("K3S_CLUSTER_SECRET=%s", GenerateRandomString(20)) |
|
|
|
|
env = append(env, k3sClusterSecret) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// k3s server arguments
|
|
|
|
|
k3sServerArgs := []string{"--https-listen-port", c.String("port")} |
|
|
|
|
if c.IsSet("server-arg") || c.IsSet("x") { |
|
|
|
@ -53,7 +65,7 @@ func CreateCluster(c *cli.Context) error { |
|
|
|
|
fmt.Sprintf("docker.io/rancher/k3s:%s", c.String("version")), |
|
|
|
|
c.String("port"), |
|
|
|
|
k3sServerArgs, |
|
|
|
|
[]string{"K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml"}, |
|
|
|
|
env, |
|
|
|
|
c.String("name"), |
|
|
|
|
strings.Split(c.String("volume"), ","), |
|
|
|
|
) |
|
|
|
@ -101,46 +113,73 @@ func CreateCluster(c *cli.Context) error { |
|
|
|
|
|
|
|
|
|
export KUBECONFIG="$(%s get-kubeconfig --name='%s')" |
|
|
|
|
kubectl cluster-info`, os.Args[0], c.String("name")) |
|
|
|
|
|
|
|
|
|
// worker nodes
|
|
|
|
|
if c.Int("workers") > 0 { |
|
|
|
|
k3sWorkerArgs := []string{} |
|
|
|
|
env := []string{k3sClusterSecret} |
|
|
|
|
log.Printf("Booting %s workers for cluster %s", strconv.Itoa(c.Int("workers")), c.String("name")) |
|
|
|
|
for i := 0; i < c.Int("workers"); i++ { |
|
|
|
|
workerID, err := createWorker( |
|
|
|
|
c.GlobalBool("verbose"), |
|
|
|
|
fmt.Sprintf("docker.io/rancher/k3s:%s", c.String("version")), |
|
|
|
|
k3sWorkerArgs, |
|
|
|
|
env, |
|
|
|
|
c.String("name"), |
|
|
|
|
strings.Split(c.String("volume"), ","), |
|
|
|
|
strconv.Itoa(i), |
|
|
|
|
c.String("port"), |
|
|
|
|
) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("ERROR: failed to create worker node for cluster %s\n%+v", c.String("name"), err) |
|
|
|
|
} |
|
|
|
|
fmt.Printf("Created worker with ID %s\n", workerID) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DeleteCluster removes the cluster container and its cluster directory
|
|
|
|
|
func DeleteCluster(c *cli.Context) error { |
|
|
|
|
ctx := context.Background() |
|
|
|
|
docker, err := client.NewEnvClient() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
clusterNames := []string{} |
|
|
|
|
|
|
|
|
|
// operate on one or all clusters
|
|
|
|
|
clusters := make(map[string]cluster) |
|
|
|
|
if !c.Bool("all") { |
|
|
|
|
clusterNames = append(clusterNames, c.String("name")) |
|
|
|
|
cluster, err := getCluster(c.String("name")) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
clusters[c.String("name")] = cluster |
|
|
|
|
} else { |
|
|
|
|
clusterList, err := getClusterNames() |
|
|
|
|
clusterMap, err := getClusters() |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("ERROR: `--all` specified, but no clusters were found\n%+v", err) |
|
|
|
|
} |
|
|
|
|
clusterNames = append(clusterNames, clusterList...) |
|
|
|
|
// copy clusterMap
|
|
|
|
|
for k, v := range clusterMap { |
|
|
|
|
clusters[k] = v |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// remove clusters one by one instead of appending all names to the docker command
|
|
|
|
|
// this allows for more granular error handling and logging
|
|
|
|
|
for _, name := range clusterNames { |
|
|
|
|
log.Printf("Removing cluster [%s]", name) |
|
|
|
|
cluster, err := getCluster(name) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("WARNING: couldn't get docker info for %s", name) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if err := docker.ContainerRemove(ctx, cluster.id, types.ContainerRemoveOptions{}); err != nil { |
|
|
|
|
log.Printf("WARNING: couldn't delete cluster [%s], trying a force remove now.", cluster.name) |
|
|
|
|
if err := docker.ContainerRemove(ctx, cluster.id, types.ContainerRemoveOptions{Force: true}); err != nil { |
|
|
|
|
log.Printf("FAILURE: couldn't delete cluster container for [%s] -> %+v", cluster.name, err) |
|
|
|
|
for _, cluster := range clusters { |
|
|
|
|
log.Printf("Removing cluster [%s]", cluster.name) |
|
|
|
|
if len(cluster.workers) > 0 { |
|
|
|
|
log.Printf("...Removing %d workers\n", len(cluster.workers)) |
|
|
|
|
for _, worker := range cluster.workers { |
|
|
|
|
if err := removeContainer(worker.ID); err != nil { |
|
|
|
|
log.Println(err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
log.Println("...Removing server") |
|
|
|
|
deleteClusterDir(cluster.name) |
|
|
|
|
if err := removeContainer(cluster.server.ID); err != nil { |
|
|
|
|
return fmt.Errorf("ERROR: Couldn't remove server for cluster %s\n%+v", cluster.name, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log.Printf("SUCCESS: removed cluster [%s]", cluster.name) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -178,7 +217,7 @@ func StopCluster(c *cli.Context) error { |
|
|
|
|
log.Printf("WARNING: couldn't get docker info for %s", name) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if err := docker.ContainerStop(ctx, cluster.id, nil); err != nil { |
|
|
|
|
if err := docker.ContainerStop(ctx, cluster.server.ID, nil); err != nil { |
|
|
|
|
fmt.Printf("WARNING: couldn't stop cluster %s\n%+v", cluster.name, err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
@ -218,7 +257,7 @@ func StartCluster(c *cli.Context) error { |
|
|
|
|
log.Printf("WARNING: couldn't get docker info for %s", name) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if err := docker.ContainerStart(ctx, cluster.id, types.ContainerStartOptions{}); err != nil { |
|
|
|
|
if err := docker.ContainerStart(ctx, cluster.server.ID, types.ContainerStartOptions{}); err != nil { |
|
|
|
|
fmt.Printf("WARNING: couldn't start cluster %s\n%+v", cluster.name, err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
@ -236,12 +275,12 @@ func ListClusters(c *cli.Context) error { |
|
|
|
|
|
|
|
|
|
// GetKubeConfig grabs the kubeconfig from the running cluster and prints the path to stdout
|
|
|
|
|
func GetKubeConfig(c *cli.Context) error { |
|
|
|
|
sourcePath := fmt.Sprintf("%s:/output/kubeconfig.yaml", c.String("name")) |
|
|
|
|
sourcePath := fmt.Sprintf("k3d-%s-server:/output/kubeconfig.yaml", c.String("name")) |
|
|
|
|
destPath, _ := getClusterDir(c.String("name")) |
|
|
|
|
cmd := "docker" |
|
|
|
|
args := []string{"cp", sourcePath, destPath} |
|
|
|
|
if err := runCommand(c.GlobalBool("verbose"), cmd, args...); err != nil { |
|
|
|
|
return fmt.Errorf("ERROR: Couldn't get kubeconfig for cluster [%s]\n%+v", fmt.Sprintf("%s-server", c.String("name")), err) |
|
|
|
|
return fmt.Errorf("ERROR: Couldn't get kubeconfig for cluster [%s]\n%+v", fmt.Sprintf("k3d-%s-server", c.String("name")), err) |
|
|
|
|
} |
|
|
|
|
fmt.Printf("%s\n", path.Join(destPath, "kubeconfig.yaml")) |
|
|
|
|
return nil |
|
|
|
|