diff --git a/cmd/ucind/cluster/create.go b/cmd/ucind/cluster/create.go new file mode 100644 index 00000000..fe31a931 --- /dev/null +++ b/cmd/ucind/cluster/create.go @@ -0,0 +1,34 @@ +package cluster + +import ( + "fmt" + "github.com/spf13/cobra" + "uncloud/internal/ucind" +) + +type createOptions struct { +} + +func NewCreateCommand() *cobra.Command { + //opts := createOptions{} + cmd := &cobra.Command{ + Use: "create [NAME]", + Short: "Create a new cluster.", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + p := cmd.Context().Value("provisioner").(*ucind.Provisioner) + + name := DefaultClusterName + if len(args) > 0 { + name = args[0] + } + + if err := p.CreateCluster(cmd.Context(), name, ucind.CreateClusterOptions{}); err != nil { + return fmt.Errorf("create cluster '%s': %w", name, err) + } + fmt.Printf("Cluster '%s' created.\n", name) + return nil + }, + } + return cmd +} diff --git a/cmd/ucind/cluster/remove.go b/cmd/ucind/cluster/remove.go new file mode 100644 index 00000000..4a791733 --- /dev/null +++ b/cmd/ucind/cluster/remove.go @@ -0,0 +1,30 @@ +package cluster + +import ( + "fmt" + "github.com/spf13/cobra" + "uncloud/internal/ucind" +) + +func NewRemoveCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "rm [NAME]", + Short: "Remove a cluster.", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + p := cmd.Context().Value("provisioner").(*ucind.Provisioner) + + name := DefaultClusterName + if len(args) > 0 { + name = args[0] + } + + if err := p.RemoveCluster(cmd.Context(), name); err != nil { + return fmt.Errorf("remove cluster '%s': %w", name, err) + } + fmt.Printf("Cluster '%s' removed.\n", name) + return nil + }, + } + return cmd +} diff --git a/cmd/ucind/cluster/root.go b/cmd/ucind/cluster/root.go new file mode 100644 index 00000000..34d99cde --- /dev/null +++ b/cmd/ucind/cluster/root.go @@ -0,0 +1,20 @@ +package cluster + +import ( + "github.com/spf13/cobra" +) + +const DefaultClusterName = "ucind-default" + +func NewRootCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "cluster", + Short: "Manage local Docker-based clusters.", + } + cmd.AddCommand( + NewCreateCommand(), + //NewListCommand(), + NewRemoveCommand(), + ) + return cmd +} diff --git a/cmd/ucind/main.go b/cmd/ucind/main.go new file mode 100644 index 00000000..4f90df76 --- /dev/null +++ b/cmd/ucind/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "context" + "fmt" + "github.com/docker/docker/client" + "github.com/spf13/cobra" + "uncloud/cmd/ucind/cluster" + "uncloud/internal/ucind" +) + +func main() { + cmd := &cobra.Command{ + Use: "ucind", + Short: "A CLI tool for running Uncloud test clusters using Docker.", + Long: "A CLI tool for running Uncloud test clusters using Docker.\n" + + "Machines in a ucind cluster are Docker containers running a ucind image. All machines within a cluster " + + "are connected to the same Docker network.", + SilenceUsage: true, + SilenceErrors: true, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return fmt.Errorf("create Docker client: %w", err) + } + + p := ucind.NewProvisioner(cli) + // Persist the provisioner in the context so it can be used by subcommands. + cmd.SetContext(context.WithValue(cmd.Context(), "provisioner", p)) + return nil + }, + } + + cmd.AddCommand( + cluster.NewRootCommand(), + ) + cobra.CheckErr(cmd.Execute()) +}