Skip to content

Commit

Permalink
CLI commands for KfCluster (#311)
Browse files Browse the repository at this point in the history
* KfCluster CLI commands

* Update kfcluster_delete.go

* Add aliases

* Add size command

---------

Co-authored-by: Haardik Dharma <haardik@civo.com>
  • Loading branch information
haardikdharma10 and haardikdharma10 authored May 2, 2023
1 parent 992d4ab commit 368f98e
Show file tree
Hide file tree
Showing 10 changed files with 427 additions and 3 deletions.
38 changes: 38 additions & 0 deletions cmd/kfcluster/kfcluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Package kfcluster is the root command for Civo KFCluster
package kfcluster

import (
"errors"

"github.com/spf13/cobra"
)

// KFClusterCmd is the root command for the kfcluster subcommand
var KFClusterCmd = &cobra.Command{
Use: "kfcluster",
Aliases: []string{"kfclusters", "kf", "kfc", "kfcs", "kubeflow", "kfaas"},
Short: "Manage Civo Kubeflow Clusters",
Long: `Create, update, delete, and list Civo Kubeflow Clusters.`,
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Help()
if err != nil {
return err
}
return errors.New("a valid subcommand is required")
},
}

func init() {
KFClusterCmd.AddCommand(kfcListCmd)
KFClusterCmd.AddCommand(kfcCreateCmd)
KFClusterCmd.AddCommand(kfcUpdateCmd)
KFClusterCmd.AddCommand(kfcDeleteCmd)
KFClusterCmd.AddCommand(kfcSizeCmd)

kfcCreateCmd.Flags().StringVarP(&firewallID, "firewall", "", "", "the firewall to use for the kubeflow cluster")
kfcCreateCmd.Flags().StringVarP(&networkID, "network", "n", "", "the network to use for the kubeflow cluster")
kfcCreateCmd.Flags().StringVarP(&size, "size", "s", "g3.kf.small", "the size of the kubeflow cluster.")
kfcCreateCmd.MarkFlagRequired("network")

kfcUpdateCmd.Flags().StringVarP(&updatedName, "name", "n", "", "the new name for the kubeflow cluster")
}
95 changes: 95 additions & 0 deletions cmd/kfcluster/kfcluster_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package kfcluster

import (
"fmt"
"os"

"github.com/civo/civogo"
"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
"github.com/spf13/cobra"
)

var networkID, firewallID, size string

var kfcCreateCmd = &cobra.Command{
Use: "create",
Aliases: []string{"new", "add"},
Example: "civo kfcluster create <KFCLUSTER-NAME> --network <NETWORK_ID> --size <SIZE> --firewall <FIREWALL_ID>",
Short: "Create a new kubeflow cluster",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()
client, err := config.CivoAPIClient()
if err != nil {
utility.Error("Creating the connection to Civo's API failed with %s", err)
os.Exit(1)
}

if common.RegionSet != "" {
client.Region = common.RegionSet
}

var network *civogo.Network
if networkID != "" {
network, err = client.FindNetwork(networkID)
if err != nil {
utility.Error("the network %s doesn't exist", networkID)
os.Exit(1)
}
}

if firewallID != "" {
_, err = client.FindFirewall(firewallID)
if err != nil {
utility.Error("the firewall %s doesn't exist", firewallID)
os.Exit(1)
}
}

sizes, err := client.ListInstanceSizes()
if err != nil {
utility.Error("Unable to list sizes %s", err)
os.Exit(1)
}

sizeIsValid := false
if size != "" {
for _, s := range sizes {
if s.Name == size && utility.SizeType(s.Name) == "KfCluster" {
sizeIsValid = true
break
}
}
if !sizeIsValid {
utility.Error("The provided size is not valid")
os.Exit(1)
}
}

kfCluster := civogo.CreateKfClusterReq{
Name: args[0],
NetworkID: network.ID,
Size: size,
FirewallID: firewallID,
Region: client.Region,
}

kfc, err := client.CreateKfCluster(kfCluster)
if err != nil {
utility.Error("Error creating kfcluster %s", err)
os.Exit(1)
}

ow := utility.NewOutputWriterWithMap(map[string]string{"id": kfc.ID, "name": kfc.Name})
switch common.OutputFormat {
case "json":
ow.WriteSingleObjectJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
fmt.Printf("KfCluster (%s) with ID %s has been created\n", utility.Green(kfc.Name), kfc.ID)
}
},
}
105 changes: 105 additions & 0 deletions cmd/kfcluster/kfcluster_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package kfcluster

import (
"errors"
"fmt"
"strings"

pluralize "github.com/alejandrojnm/go-pluralize"
"github.com/civo/civogo"
"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"

"os"

"github.com/spf13/cobra"
)

var kfClusterList []utility.ObjecteList
var kfcDeleteCmd = &cobra.Command{
Use: "delete",
Aliases: []string{"rm", "remove", "destroy"},
Short: "Delete a kubeflow cluster",
Example: "civo kfc delete <KFCLUSTER-NAME>",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()

client, err := config.CivoAPIClient()
if err != nil {
utility.Error("Creating the connection to Civo's API failed with %s", err)
os.Exit(1)
}

if common.RegionSet != "" {
client.Region = common.RegionSet
}

if len(args) == 1 {
kfc, err := client.FindKfCluster(args[0])
if err != nil {
if errors.Is(err, civogo.ZeroMatchesError) {
utility.Error("sorry there is no %s kfcluster in your account", utility.Red(args[0]))
os.Exit(1)
}
if errors.Is(err, civogo.MultipleMatchesError) {
utility.Error("sorry we found more than one kfcluster with that name in your account")
os.Exit(1)
}
}
kfClusterList = append(kfClusterList, utility.ObjecteList{ID: kfc.ID, Name: kfc.Name})
} else {
for _, v := range args {
kfc, err := client.FindKfCluster(v)
if err == nil {
kfClusterList = append(kfClusterList, utility.ObjecteList{ID: kfc.ID, Name: kfc.Name})
}
}
}

kfcNameList := []string{}
for _, v := range kfClusterList {
kfcNameList = append(kfcNameList, v.Name)
}

if utility.UserConfirmedDeletion(pluralize.Pluralize(len(kfClusterList), "KfCluster"), common.DefaultYes, strings.Join(kfcNameList, ", ")) {

for _, v := range kfClusterList {
kfc, err := client.FindKfCluster(v.ID)
if err != nil {
utility.Error("%s", err)
os.Exit(1)
}
_, err = client.DeleteKfCluster(kfc.ID)
if err != nil {
utility.Error("Error deleting the KfCluster: %s", err)
os.Exit(1)
}
}

ow := utility.NewOutputWriter()

for _, v := range kfClusterList {
ow.StartLine()
ow.AppendDataWithLabel("id", v.ID, "ID")
ow.AppendDataWithLabel("kfcluster", v.Name, "KfCluster")
}

switch common.OutputFormat {
case "json":
if len(kfClusterList) == 1 {
ow.WriteSingleObjectJSON(common.PrettySet)
} else {
ow.WriteMultipleObjectsJSON(common.PrettySet)
}
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
fmt.Printf("The %s (%s) has been deleted\n", pluralize.Pluralize(len(kfClusterList), "kfcluster"), utility.Green(strings.Join(kfcNameList, ", ")))
}
} else {
fmt.Println("Operation aborted")
}
},
}
55 changes: 55 additions & 0 deletions cmd/kfcluster/kfcluster_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package kfcluster

import (
"os"

"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
"github.com/spf13/cobra"
)

var kfcListCmd = &cobra.Command{
Use: "ls",
Aliases: []string{"list", "all"},
Example: `civo kfc ls`,
Short: "List all kubeflow clusters",
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()

client, err := config.CivoAPIClient()
if err != nil {
utility.Error("Creating the connection to Civo's API failed with %s", err)
os.Exit(1)
}

if common.RegionSet != "" {
client.Region = common.RegionSet
}

kfclusters, err := client.ListKfClusters()
if err != nil {
utility.Error("%s", err)
os.Exit(1)
}

ow := utility.NewOutputWriter()
for _, kfc := range kfclusters.Items {
ow.StartLine()
ow.AppendDataWithLabel("id", kfc.ID, "ID")
ow.AppendDataWithLabel("name", kfc.Name, "Name")
ow.AppendDataWithLabel("size", kfc.Size, "Size")
ow.AppendDataWithLabel("kubeflow_ready", kfc.KubeflowReady, "Kubeflow Ready")
ow.AppendDataWithLabel("dashboard_url", kfc.DashboardURL, "Dashboard URL")
}

switch common.OutputFormat {
case "json":
ow.WriteMultipleObjectsJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
ow.WriteTable()
}
},
}
66 changes: 66 additions & 0 deletions cmd/kfcluster/kfcluster_size.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package kfcluster

import (
"os"
"strconv"
"strings"

"github.com/civo/civogo"
"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
"github.com/spf13/cobra"
)

var kfcSizeCmd = &cobra.Command{
Use: "size",
Example: "civo kfc size",
Aliases: []string{"sizes", "all"},
Short: "List all available KFCluster sizes",
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()

client, err := config.CivoAPIClient()
if common.RegionSet != "" {
client.Region = common.RegionSet
}
if err != nil {
utility.Error("Creating the connection to Civo's API failed with %s", err)
os.Exit(1)
}

filter := []civogo.InstanceSize{}
sizes, err := client.ListInstanceSizes()
if err != nil {
utility.Error("%s", err)
return
}

for _, size := range sizes {
if strings.Contains(size.Name, ".kf.") {
filter = append(filter, size)
}
}

ow := utility.NewOutputWriter()
for _, size := range filter {
ow.StartLine()
ow.AppendDataWithLabel("name", size.Name, "Name")
ow.AppendDataWithLabel("description", size.Description, "Description")
ow.AppendDataWithLabel("type", "KfCluster", "Type")
ow.AppendDataWithLabel("cpu_cores", strconv.Itoa(size.CPUCores), "CPU Cores")
ow.AppendDataWithLabel("ram_mb", strconv.Itoa(size.RAMMegabytes), "RAM MB")
ow.AppendDataWithLabel("disk_gb", strconv.Itoa(size.DiskGigabytes), "SSD GB")
ow.AppendDataWithLabel("selectable", utility.BoolToYesNo(size.Selectable), "Selectable")
}

switch common.OutputFormat {
case "json":
ow.WriteMultipleObjectsJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
ow.WriteTable()
}
},
}
Loading

0 comments on commit 368f98e

Please sign in to comment.