diff --git a/config.go b/config.go index f6384610..4ea3ca73 100644 --- a/config.go +++ b/config.go @@ -12,6 +12,12 @@ import ( "github.com/olekukonko/tablewriter" ) +type cluster struct { + name string + image string + status string +} + // createDirIfNotExists checks for the existence of a directory and creates it along with all required parents if not. // It returns an error if the directory (or parents) couldn't be created and nil if it worked fine or if the path already exists. func createDirIfNotExists(path string) error { @@ -50,30 +56,30 @@ func getClusterDir(name string) (string, error) { // printClusters prints the names of existing clusters func printClusters(all bool) { - clusters, err := getClusters() + clusterNames, err := getClusterNames() if err != nil { log.Fatalf("ERROR: Couldn't list clusters -> %+v", err) } - docker, err := dockerClient.NewEnvClient() - if err != nil { - log.Printf("WARNING: couldn't get docker info -> %+v", err) + if len(clusterNames) == 0 { + log.Printf("No clusters found!") + return } table := tablewriter.NewWriter(os.Stdout) table.SetHeader([]string{"NAME", "IMAGE", "STATUS"}) - for _, cluster := range clusters { - containerInfo, _ := docker.ContainerInspect(context.Background(), cluster) - clusterData := []string{cluster, containerInfo.Config.Image, containerInfo.ContainerJSONBase.State.Status} - if containerInfo.ContainerJSONBase.State.Status == "running" || all { + for _, clusterName := range clusterNames { + cluster, _ := getCluster(clusterName) + clusterData := []string{cluster.name, cluster.image, cluster.status} + if cluster.status == "running" || all { table.Append(clusterData) } } table.Render() } -// getClusters returns a list of cluster names which are folder names in the config directory -func getClusters() ([]string, error) { +// getClusterNames returns a list of cluster names which are folder names in the config directory +func getClusterNames() ([]string, error) { homeDir, err := homedir.Dir() if err != nil { log.Printf("ERROR: Couldn't get user's home directory") @@ -93,3 +99,26 @@ func getClusters() ([]string, error) { } return clusters, nil } + +// getCluster creates a cluster struct with populated information fields +func getCluster(name string) (cluster, error) { + cluster := cluster{ + name: name, + image: "UNKNOWN", + status: "UNKNOWN", + } + + docker, err := dockerClient.NewEnvClient() + if err != nil { + log.Printf("ERROR: couldn't create docker client -> %+v", err) + return cluster, err + } + containerInfo, err := docker.ContainerInspect(context.Background(), cluster.name) + if err != nil { + log.Printf("WARNING: couldn't get docker info for [%s] -> %+v", cluster.name, err) + } else { + cluster.image = containerInfo.Config.Image + cluster.status = containerInfo.ContainerJSONBase.State.Status + } + return cluster, nil +} diff --git a/main.go b/main.go index ce91b814..a1f5a55b 100644 --- a/main.go +++ b/main.go @@ -52,44 +52,104 @@ kubectl cluster-info`, os.Args[0], c.String("name")) // deleteCluster removes the cluster container and its cluster directory func deleteCluster(c *cli.Context) error { cmd := "docker" - args := []string{"rm", c.String("name")} - log.Printf("Deleting cluster [%s]", c.String("name")) - if err := run(true, cmd, args...); err != nil { - log.Printf("WARNING: couldn't delete cluster [%s], trying a force remove now.", c.String("name")) - args = append(args, "-f") - if err := run(true, cmd, args...); err != nil { - log.Fatalf("FAILURE: couldn't delete cluster [%s] -> %+v", c.String("name"), err) - return err + args := []string{"rm"} + clusters := []string{} + + // operate on one or all clusters + if !c.Bool("all") { + clusters = append(clusters, c.String("name")) + } else { + clusterList, err := getClusterNames() + if err != nil { + log.Fatalf("ERROR: `--all` specified, but no clusters were found.") } + clusters = append(clusters, clusterList...) } - deleteClusterDir(c.String("name")) - log.Printf("SUCCESS: deleted cluster [%s]", c.String("name")) + + // remove clusters one by one instead of appending all names to the docker command + // this allows for more granular error handling and logging + for _, cluster := range clusters { + log.Printf("Removing cluster [%s]", cluster) + args = append(args, cluster) + if err := run(true, cmd, args...); err != nil { + log.Printf("WARNING: couldn't delete cluster [%s], trying a force remove now.", cluster) + args = args[:len(args)-1] // pop last element from list (name of cluster) + args = append(args, "-f", cluster) + if err := run(true, cmd, args...); err != nil { + log.Printf("FAILURE: couldn't delete cluster [%s] -> %+v", cluster, err) + } + args = args[:len(args)-1] // pop last element from list (-f flag) + } + deleteClusterDir(cluster) + log.Printf("SUCCESS: removed cluster [%s]", cluster) + args = args[:len(args)-1] // pop last element from list (name of last cluster) + } + return nil + } // stopCluster stops a running cluster container (restartable) func stopCluster(c *cli.Context) error { cmd := "docker" - args := []string{"stop", c.String("name")} - log.Printf("Stopping cluster [%s]", c.String("name")) - if err := run(true, cmd, args...); err != nil { - log.Fatalf("FAILURE: couldn't stop cluster [%s] -> %+v", c.String("name"), err) - return err + args := []string{"stop"} + clusters := []string{} + + // operate on one or all clusters + if !c.Bool("all") { + clusters = append(clusters, c.String("name")) + } else { + clusterList, err := getClusterNames() + if err != nil { + log.Fatalf("ERROR: `--all` specified, but no clusters were found.") + } + clusters = append(clusters, clusterList...) } - log.Printf("SUCCESS: stopped cluster [%s]", c.String("name")) + + // stop clusters one by one instead of appending all names to the docker command + // this allows for more granular error handling and logging + for _, cluster := range clusters { + log.Printf("Starting cluster [%s]", cluster) + args = append(args, cluster) + if err := run(true, cmd, args...); err != nil { + log.Printf("FAILURE: couldn't stop cluster [%s] -> %+v", cluster, err) + } + log.Printf("SUCCESS: stopped cluster [%s]", cluster) + args = args[:len(args)-1] // pop last element from list (name of last cluster) + } + return nil } // startCluster starts a stopped cluster container func startCluster(c *cli.Context) error { cmd := "docker" - args := []string{"start", c.String("name")} - log.Printf("Starting cluster [%s]", c.String("name")) - if err := run(true, cmd, args...); err != nil { - log.Fatalf("FAILURE: couldn't start cluster [%s] -> %+v", c.String("name"), err) - return err + args := []string{"start"} + clusters := []string{} + + // operate on one or all clusters + if !c.Bool("all") { + clusters = append(clusters, c.String("name")) + } else { + clusterList, err := getClusterNames() + if err != nil { + log.Fatalf("ERROR: `--all` specified, but no clusters were found.") + } + clusters = append(clusters, clusterList...) } - log.Printf("SUCCESS: started cluster [%s]", c.String("name")) + + // start clusters one by one instead of appending all names to the docker command + // this allows for more granular error handling and logging + for _, cluster := range clusters { + log.Printf("Starting cluster [%s]", cluster) + args = append(args, cluster) + if err := run(true, cmd, args...); err != nil { + log.Printf("FAILURE: couldn't start cluster [%s] -> %+v", cluster, err) + } + log.Printf("SUCCESS: started cluster [%s]", cluster) + args = args[:len(args)-1] // pop last element from list (name of last cluster) + } + return nil }