From 60488d4d7a3e95ec812819df0f3ad3c7181bf4ee Mon Sep 17 00:00:00 2001 From: bijayasharma Date: Mon, 8 Mar 2021 14:03:13 -0500 Subject: [PATCH] Add phase status command Signed-off-by: bijayasharma Change-Id: I09fc1e84f195982a43c97f80feb82fb2e489771d Relates-To: #411 --- cmd/phase/phase.go | 1 + cmd/phase/status.go | 51 ++++++++++++++ cmd/phase/status_test.go | 35 ++++++++++ .../phase-cmd-with-help.golden | 1 + .../run-with-help.golden | 13 ++++ docs/source/cli/airshipctl_phase.md | 1 + docs/source/cli/airshipctl_phase_status.md | 38 ++++++++++ pkg/phase/command.go | 34 +++++++++ pkg/phase/command_test.go | 70 +++++++++++++++++++ 9 files changed, 244 insertions(+) create mode 100644 cmd/phase/status.go create mode 100644 cmd/phase/status_test.go create mode 100644 cmd/phase/testdata/TestStatusGoldenOutput/run-with-help.golden create mode 100644 docs/source/cli/airshipctl_phase_status.md diff --git a/cmd/phase/phase.go b/cmd/phase/phase.go index ce7f3918d..db570bc5a 100644 --- a/cmd/phase/phase.go +++ b/cmd/phase/phase.go @@ -40,6 +40,7 @@ func NewPhaseCommand(cfgFactory config.Factory) *cobra.Command { phaseRootCmd.AddCommand(NewRunCommand(cfgFactory)) phaseRootCmd.AddCommand(NewTreeCommand(cfgFactory)) phaseRootCmd.AddCommand(NewValidateCommand(cfgFactory)) + phaseRootCmd.AddCommand(NewStatusCommand(cfgFactory)) return phaseRootCmd } diff --git a/cmd/phase/status.go b/cmd/phase/status.go new file mode 100644 index 000000000..22323911c --- /dev/null +++ b/cmd/phase/status.go @@ -0,0 +1,51 @@ +/* + 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 + + https://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 phase + +import ( + "github.com/spf13/cobra" + + "opendev.org/airship/airshipctl/pkg/config" + "opendev.org/airship/airshipctl/pkg/phase" +) + +const ( + statusLong = `Status of the specific life-cycle phase such as ephemeral-control-plane, target-initinfra etc...` + statusExample = ` +#Status of initinfra phase +airshipctl phase status ephemeral-control-plane +` +) + +// NewStatusCommand creates a command to find status of specific phase +func NewStatusCommand(cfgFactory config.Factory) *cobra.Command { + ph := &phase.StatusCommand{ + Factory: cfgFactory, + Options: phase.StatusFlags{}, + } + + statusCmd := &cobra.Command{ + Use: "status", + Short: "Status of the phase", + Long: statusLong, + Args: cobra.ExactArgs(1), + Example: statusExample, + RunE: func(cmd *cobra.Command, args []string) error { + ph.Options.PhaseID.Name = args[0] + return ph.RunE() + }, + } + return statusCmd +} diff --git a/cmd/phase/status_test.go b/cmd/phase/status_test.go new file mode 100644 index 000000000..43b9184bc --- /dev/null +++ b/cmd/phase/status_test.go @@ -0,0 +1,35 @@ +/* + 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 + + https://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 phase_test + +import ( + "testing" + + "opendev.org/airship/airshipctl/cmd/phase" + "opendev.org/airship/airshipctl/testutil" +) + +func TestStatus(t *testing.T) { + tests := []*testutil.CmdTest{ + { + Name: "run-with-help", + CmdLine: "-h", + Cmd: phase.NewStatusCommand(nil), + }, + } + for _, tt := range tests { + testutil.RunTest(t, tt) + } +} diff --git a/cmd/phase/testdata/TestNewPhaseCommandGoldenOutput/phase-cmd-with-help.golden b/cmd/phase/testdata/TestNewPhaseCommandGoldenOutput/phase-cmd-with-help.golden index c2bc2804f..77c0ce9a2 100644 --- a/cmd/phase/testdata/TestNewPhaseCommandGoldenOutput/phase-cmd-with-help.golden +++ b/cmd/phase/testdata/TestNewPhaseCommandGoldenOutput/phase-cmd-with-help.golden @@ -9,6 +9,7 @@ Available Commands: list List phases render Render phase documents from model run Run phase + status Status of the phase tree Tree view of kustomize entrypoints of phase validate Assert that a phase is valid diff --git a/cmd/phase/testdata/TestStatusGoldenOutput/run-with-help.golden b/cmd/phase/testdata/TestStatusGoldenOutput/run-with-help.golden new file mode 100644 index 000000000..cfe02bb43 --- /dev/null +++ b/cmd/phase/testdata/TestStatusGoldenOutput/run-with-help.golden @@ -0,0 +1,13 @@ +Status of the specific life-cycle phase such as ephemeral-control-plane, target-initinfra etc... + +Usage: + status [flags] + +Examples: + +#Status of initinfra phase +airshipctl phase status ephemeral-control-plane + + +Flags: + -h, --help help for status diff --git a/docs/source/cli/airshipctl_phase.md b/docs/source/cli/airshipctl_phase.md index 71342604e..4b4e49972 100644 --- a/docs/source/cli/airshipctl_phase.md +++ b/docs/source/cli/airshipctl_phase.md @@ -27,6 +27,7 @@ such as getting list and applying specific one. * [airshipctl phase list](airshipctl_phase_list.md) - List phases * [airshipctl phase render](airshipctl_phase_render.md) - Render phase documents from model * [airshipctl phase run](airshipctl_phase_run.md) - Run phase +* [airshipctl phase status](airshipctl_phase_status.md) - Status of the phase * [airshipctl phase tree](airshipctl_phase_tree.md) - Tree view of kustomize entrypoints of phase * [airshipctl phase validate](airshipctl_phase_validate.md) - Assert that a phase is valid diff --git a/docs/source/cli/airshipctl_phase_status.md b/docs/source/cli/airshipctl_phase_status.md new file mode 100644 index 000000000..c272a593e --- /dev/null +++ b/docs/source/cli/airshipctl_phase_status.md @@ -0,0 +1,38 @@ +## airshipctl phase status + +Status of the phase + +### Synopsis + +Status of the specific life-cycle phase such as ephemeral-control-plane, target-initinfra etc... + +``` +airshipctl phase status [flags] +``` + +### Examples + +``` + +#Status of initinfra phase +airshipctl phase status ephemeral-control-plane + +``` + +### Options + +``` + -h, --help help for status +``` + +### Options inherited from parent commands + +``` + --airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config") + --debug enable verbose output +``` + +### SEE ALSO + +* [airshipctl phase](airshipctl_phase.md) - Manage phases + diff --git a/pkg/phase/command.go b/pkg/phase/command.go index 5f814fccd..fc0d5345a 100644 --- a/pkg/phase/command.go +++ b/pkg/phase/command.go @@ -302,3 +302,37 @@ func (c *ValidateCommand) RunE() error { } return phase.Validate() } + +// StatusFlags is a struct to define status type +type StatusFlags struct { + Timeout time.Duration + PhaseID ifc.ID + Progress bool +} + +// StatusCommand is a struct which defines status +type StatusCommand struct { + Options StatusFlags + Factory config.Factory +} + +// RunE returns the status of the given phase +func (s *StatusCommand) RunE() error { + cfg, err := s.Factory() + if err != nil { + return err + } + + helper, err := NewHelper(cfg) + if err != nil { + return err + } + + ph, err := NewClient(helper).PhaseByID(s.Options.PhaseID) + if err != nil { + return err + } + + _, err = ph.Status() + return err +} diff --git a/pkg/phase/command_test.go b/pkg/phase/command_test.go index 04302ca76..6e80c4f6e 100644 --- a/pkg/phase/command_test.go +++ b/pkg/phase/command_test.go @@ -535,3 +535,73 @@ func TestValidateCommand(t *testing.T) { }) } } + +func TestStatusCommand(t *testing.T) { + tests := []struct { + name string + errContains string + statusFlags phase.StatusFlags + factory config.Factory + }{ + { + name: "Error config factory", + factory: func() (*config.Config, error) { + return nil, fmt.Errorf(testFactoryErr) + }, + errContains: testFactoryErr, + }, + { + name: "Error new helper", + factory: func() (*config.Config, error) { + return &config.Config{ + CurrentContext: "does not exist", + Contexts: make(map[string]*config.Context), + }, nil + }, + errContains: testNewHelperErr, + }, + { + name: "Error phase by id", + factory: func() (*config.Config, error) { + conf := config.NewConfig() + conf.Manifests = map[string]*config.Manifest{ + "manifest": { + MetadataPath: "broken_metadata.yaml", + TargetPath: "testdata", + PhaseRepositoryName: config.DefaultTestPhaseRepo, + Repositories: map[string]*config.Repository{ + config.DefaultTestPhaseRepo: { + URLString: "", + }, + }, + }, + } + conf.CurrentContext = "context" + conf.Contexts = map[string]*config.Context{ + "context": { + Manifest: "manifest", + }, + } + return conf, nil + }, + errContains: testNoBundlePath, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + command := phase.StatusCommand{ + Options: tt.statusFlags, + Factory: tt.factory, + } + err := command.RunE() + if tt.errContains != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.errContains) + } else { + assert.NoError(t, err) + } + }) + } +}