diff --git a/flytectl/cmd/completion.go b/flytectl/cmd/completion.go new file mode 100644 index 0000000000..7c705c2e00 --- /dev/null +++ b/flytectl/cmd/completion.go @@ -0,0 +1,83 @@ +/* +Copyright © 2021 NAME HERE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +// completionCmd represents the completion command +var completionCmd = &cobra.Command{ + Use: "completion [bash|zsh|fish|powershell]", + Short: "Generate completion script", + Long: `To load completions: + +Bash: + + $ source <(flytectl completion bash) + + # To load completions for each session, execute once: + # Linux: + $ flytectl completion bash > /etc/bash_completion.d/flytectl + # macOS: + $ flytectl completion bash > /usr/local/etc/bash_completion.d/flytectl + +Zsh: + + # If shell completion is not already enabled in your environment, + # you will need to enable it. You can execute the following once: + + $ echo "autoload -U compinit; compinit" >> ~/.zshrc + + # To load completions for each session, execute once: + $ flytectl completion zsh > "${fpath[1]}/_flytectl" + + # You will need to start a new shell for this setup to take effect. + +fish: + + $ flytectl completion fish | source + + # To load completions for each session, execute once: + $ flytectl completion fish > ~/.config/fish/completions/flytectl.fish + +PowerShell: + + PS> flytectl completion powershell | Out-String | Invoke-Expression + + # To load completions for every new session, run: + PS> flytectl completion powershell > flytectl.ps1 + # and source this file from your PowerShell profile. +`, + DisableFlagsInUseLine: true, + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.ExactValidArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + switch args[0] { + case "bash": + return cmd.Root().GenBashCompletion(os.Stdout) + case "zsh": + return cmd.Root().GenZshCompletion(os.Stdout) + case "fish": + return cmd.Root().GenFishCompletion(os.Stdout, true) + case "powershell": + return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) + } + return nil + }, +} diff --git a/flytectl/cmd/root.go b/flytectl/cmd/root.go index 52bc75722c..70691d1751 100644 --- a/flytectl/cmd/root.go +++ b/flytectl/cmd/root.go @@ -59,6 +59,7 @@ func newRootCmd() *cobra.Command { rootCmd.AddCommand(register.RemoteRegisterCommand()) rootCmd.AddCommand(delete.RemoteDeleteCommand()) rootCmd.AddCommand(sandbox.CreateSandboxCommand()) + rootCmd.AddCommand(completionCmd) // Added version command versioncmd := version.GetVersionCommand(rootCmd) cmdCore.AddCommands(rootCmd, versioncmd) diff --git a/flytectl/cmd/sandbox/sandbox.go b/flytectl/cmd/sandbox/sandbox.go index cf666b9a48..7ee1f37cb6 100644 --- a/flytectl/cmd/sandbox/sandbox.go +++ b/flytectl/cmd/sandbox/sandbox.go @@ -38,6 +38,9 @@ func CreateSandboxCommand() *cobra.Command { "teardown": {CmdFunc: teardownSandboxCluster, Aliases: []string{}, ProjectDomainNotRequired: true, Short: teardownShort, Long: teardownLong}, + "status": {CmdFunc: sandboxClusterStatus, Aliases: []string{}, ProjectDomainNotRequired: true, + Short: statusShort, + Long: statusLong}, } cmdcore.AddCommands(sandbox, sandboxResourcesFuncs) diff --git a/flytectl/cmd/sandbox/sandbox_test.go b/flytectl/cmd/sandbox/sandbox_test.go index fe3f964572..8537f434e9 100644 --- a/flytectl/cmd/sandbox/sandbox_test.go +++ b/flytectl/cmd/sandbox/sandbox_test.go @@ -13,7 +13,7 @@ func TestCreateSandboxCommand(t *testing.T) { assert.Equal(t, sandboxCommand.Use, "sandbox") assert.Equal(t, sandboxCommand.Short, "Used for testing flyte sandbox.") fmt.Println(sandboxCommand.Commands()) - assert.Equal(t, len(sandboxCommand.Commands()), 2) + assert.Equal(t, len(sandboxCommand.Commands()), 3) cmdNouns := sandboxCommand.Commands() // Sort by Use value. sort.Slice(cmdNouns, func(i, j int) bool { @@ -24,8 +24,12 @@ func TestCreateSandboxCommand(t *testing.T) { assert.Equal(t, cmdNouns[0].Short, startShort) assert.Equal(t, cmdNouns[0].Long, startLong) - assert.Equal(t, cmdNouns[1].Use, "teardown") - assert.Equal(t, cmdNouns[1].Short, teardownShort) - assert.Equal(t, cmdNouns[1].Long, teardownLong) + assert.Equal(t, cmdNouns[1].Use, "status") + assert.Equal(t, cmdNouns[1].Short, statusShort) + assert.Equal(t, cmdNouns[1].Long, statusLong) + + assert.Equal(t, cmdNouns[2].Use, "teardown") + assert.Equal(t, cmdNouns[2].Short, teardownShort) + assert.Equal(t, cmdNouns[2].Long, teardownLong) } diff --git a/flytectl/cmd/sandbox/start_test.go b/flytectl/cmd/sandbox/start_test.go index 7bb7ce0a0d..36e0399b51 100644 --- a/flytectl/cmd/sandbox/start_test.go +++ b/flytectl/cmd/sandbox/start_test.go @@ -154,7 +154,7 @@ func TestStartSandboxFunc(t *testing.T) { mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{ { - ID: "FlyteSandboxClusterName", + ID: docker.FlyteSandboxClusterName, Names: []string{ docker.FlyteSandboxClusterName, }, diff --git a/flytectl/cmd/sandbox/status.go b/flytectl/cmd/sandbox/status.go new file mode 100644 index 0000000000..c9493b4509 --- /dev/null +++ b/flytectl/cmd/sandbox/status.go @@ -0,0 +1,43 @@ +package sandbox + +import ( + "context" + "fmt" + + "github.com/enescakir/emoji" + cmdCore "github.com/flyteorg/flytectl/cmd/core" + "github.com/flyteorg/flytectl/pkg/docker" +) + +const ( + statusShort = "Get the status of the sandbox environment." + statusLong = ` +Status will retrieve the status of the Sandbox environment. Currently FlyteSandbox runs as a local docker container. +This will return the docker status for this container + +Usage +:: + + bin/flytectl sandbox status + +` +) + +func sandboxClusterStatus(ctx context.Context, args []string, cmdCtx cmdCore.CommandContext) error { + cli, err := docker.GetDockerClient() + if err != nil { + return err + } + + return printStatus(ctx, cli) +} + +func printStatus(ctx context.Context, cli docker.Docker) error { + c := docker.GetSandbox(ctx, cli) + if c == nil { + fmt.Printf("%v no Sandbox found \n", emoji.StopSign) + return nil + } + fmt.Printf("Flyte local sandbox cluster container image [%s] with status [%s] is in state [%s]", c.Image, c.Status, c.State) + return nil +} diff --git a/flytectl/cmd/sandbox/status_test.go b/flytectl/cmd/sandbox/status_test.go new file mode 100644 index 0000000000..fa5fbf424a --- /dev/null +++ b/flytectl/cmd/sandbox/status_test.go @@ -0,0 +1,43 @@ +package sandbox + +import ( + "context" + "io" + "testing" + + "github.com/docker/docker/api/types" + cmdCore "github.com/flyteorg/flytectl/cmd/core" + "github.com/flyteorg/flytectl/pkg/docker" + "github.com/flyteorg/flytectl/pkg/docker/mocks" + "github.com/stretchr/testify/assert" +) + +func TestSandboxStatus(t *testing.T) { + t.Run("Sandbox status with zero result", func(t *testing.T) { + ctx := context.Background() + mockOutStream := new(io.Writer) + cmdCtx := cmdCore.NewCommandContext(nil, *mockOutStream) + mockDocker := &mocks.Docker{} + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + docker.Client = mockDocker + err := sandboxClusterStatus(ctx, []string{}, cmdCtx) + assert.Nil(t, err) + }) + t.Run("Sandbox status with running sandbox", func(t *testing.T) { + ctx := context.Background() + mockOutStream := new(io.Writer) + cmdCtx := cmdCore.NewCommandContext(nil, *mockOutStream) + mockDocker := &mocks.Docker{} + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{ + { + ID: docker.FlyteSandboxClusterName, + Names: []string{ + docker.FlyteSandboxClusterName, + }, + }, + }, nil) + docker.Client = mockDocker + err := sandboxClusterStatus(ctx, []string{}, cmdCtx) + assert.Nil(t, err) + }) +} diff --git a/flytectl/go.mod b/flytectl/go.mod index ad4c8f90cc..93af1fc05b 100644 --- a/flytectl/go.mod +++ b/flytectl/go.mod @@ -16,7 +16,7 @@ require ( github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.2.0 - github.com/hashicorp/go-version v1.3.0 // indirect + github.com/hashicorp/go-version v1.3.0 github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23 github.com/kr/text v0.2.0 // indirect github.com/landoop/tableprinter v0.0.0-20180806200924-8bd8c2576d27 @@ -25,7 +25,7 @@ require ( github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/image-spec v1.0.1 github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 github.com/sirupsen/logrus v1.8.0 github.com/spf13/cobra v1.1.3