Introduce phases and phase plan
Airship API is extended with Phase and PhasePlan objects which implemet k8s runtime.Object interface. Phase plan command is added to airshipctl. Closes: #262 Closes: #261 Closes: #260 Change-Id: I4c299ec9078af4ace29ab46bd6440f47ae18a094
This commit is contained in:
parent
c05286d3f6
commit
325d824503
@ -45,6 +45,7 @@ func NewPhaseCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Comman
|
|||||||
|
|
||||||
phaseRootCmd.AddCommand(NewApplyCommand(rootSettings, client.DefaultClient))
|
phaseRootCmd.AddCommand(NewApplyCommand(rootSettings, client.DefaultClient))
|
||||||
phaseRootCmd.AddCommand(NewRenderCommand(rootSettings))
|
phaseRootCmd.AddCommand(NewRenderCommand(rootSettings))
|
||||||
|
phaseRootCmd.AddCommand(NewPlanCommand(rootSettings))
|
||||||
|
|
||||||
return phaseRootCmd
|
return phaseRootCmd
|
||||||
}
|
}
|
||||||
|
61
cmd/phase/plan.go
Normal file
61
cmd/phase/plan.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/phase"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cmdLong = `
|
||||||
|
List life-cycle phases which were defined in document model by group.
|
||||||
|
Phases within a group are executed sequentially. Multiple phase groups
|
||||||
|
are executed in parallel.
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPlanCommand creates a command which prints available phases
|
||||||
|
func NewPlanCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command {
|
||||||
|
p := &phase.Cmd{AirshipCTLSettings: rootSettings}
|
||||||
|
|
||||||
|
planCmd := &cobra.Command{
|
||||||
|
Use: "plan",
|
||||||
|
Short: "List phases",
|
||||||
|
Long: cmdLong[1:],
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
phases, err := p.Plan()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tw := util.NewTabWriter(cmd.OutOrStdout())
|
||||||
|
defer tw.Flush()
|
||||||
|
fmt.Fprintf(tw, "GROUP\tPHASE\n")
|
||||||
|
for group, phaseList := range phases {
|
||||||
|
fmt.Fprintf(tw, "%s\t\n", group)
|
||||||
|
for _, phase := range phaseList {
|
||||||
|
fmt.Fprintf(tw, "\t%s\n", phase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return planCmd
|
||||||
|
}
|
35
cmd/phase/plan_test.go
Normal file
35
cmd/phase/plan_test.go
Normal file
@ -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 TestNewPlanCommand(t *testing.T) {
|
||||||
|
tests := []*testutil.CmdTest{
|
||||||
|
{
|
||||||
|
Name: "phase-plan-cmd-with-help",
|
||||||
|
CmdLine: "--help",
|
||||||
|
Cmd: phase.NewPlanCommand(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testcase := range tests {
|
||||||
|
testutil.RunTest(t, testcase)
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ Usage:
|
|||||||
Available Commands:
|
Available Commands:
|
||||||
apply Apply phase to a cluster
|
apply Apply phase to a cluster
|
||||||
help Help about any command
|
help Help about any command
|
||||||
|
plan List phases
|
||||||
render Render phase documents from model
|
render Render phase documents from model
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
9
cmd/phase/testdata/TestNewPlanCommandGoldenOutput/phase-plan-cmd-with-help.golden
vendored
Normal file
9
cmd/phase/testdata/TestNewPlanCommandGoldenOutput/phase-plan-cmd-with-help.golden
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
List life-cycle phases which were defined in document model by group.
|
||||||
|
Phases within a group are executed sequentially. Multiple phase groups
|
||||||
|
are executed in parallel.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
plan [flags]
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-h, --help help for plan
|
@ -31,5 +31,6 @@ Manage the airshipctl config file
|
|||||||
* [airshipctl config set-cluster](airshipctl_config_set-cluster.md) - Manage clusters
|
* [airshipctl config set-cluster](airshipctl_config_set-cluster.md) - Manage clusters
|
||||||
* [airshipctl config set-context](airshipctl_config_set-context.md) - Manage contexts
|
* [airshipctl config set-context](airshipctl_config_set-context.md) - Manage contexts
|
||||||
* [airshipctl config set-credentials](airshipctl_config_set-credentials.md) - Manage user credentials
|
* [airshipctl config set-credentials](airshipctl_config_set-credentials.md) - Manage user credentials
|
||||||
|
* [airshipctl config set-management-config](airshipctl_config_set-management-config.md) - Modify an out-of-band management configuration
|
||||||
* [airshipctl config use-context](airshipctl_config_use-context.md) - Switch to a different context
|
* [airshipctl config use-context](airshipctl_config_use-context.md) - Switch to a different context
|
||||||
|
|
||||||
|
33
docs/source/cli/airshipctl_config_set-management-config.md
Normal file
33
docs/source/cli/airshipctl_config_set-management-config.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
## airshipctl config set-management-config
|
||||||
|
|
||||||
|
Modify an out-of-band management configuration
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
Modify an out-of-band management configuration
|
||||||
|
|
||||||
|
```
|
||||||
|
airshipctl config set-management-config NAME [flags]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
-h, --help help for set-management-config
|
||||||
|
--insecure Ignore SSL certificate verification on out-of-band management requests
|
||||||
|
--management-type string Set the out-of-band management type (default "redfish")
|
||||||
|
--use-proxy Use the proxy configuration specified in the local environment (default true)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
--airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config")
|
||||||
|
--debug enable verbose output
|
||||||
|
--kubeconfig string Path to kubeconfig associated with airshipctl configuration. (default "$HOME/.airship/kubeconfig")
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEE ALSO
|
||||||
|
|
||||||
|
* [airshipctl config](airshipctl_config.md) - Manage the airshipctl config file
|
||||||
|
|
@ -26,5 +26,6 @@ such as getting list and applying specific one.
|
|||||||
|
|
||||||
* [airshipctl](airshipctl.md) - A unified entrypoint to various airship components
|
* [airshipctl](airshipctl.md) - A unified entrypoint to various airship components
|
||||||
* [airshipctl phase apply](airshipctl_phase_apply.md) - Apply phase to a cluster
|
* [airshipctl phase apply](airshipctl_phase_apply.md) - Apply phase to a cluster
|
||||||
|
* [airshipctl phase plan](airshipctl_phase_plan.md) - List phases
|
||||||
* [airshipctl phase render](airshipctl_phase_render.md) - Render phase documents from model
|
* [airshipctl phase render](airshipctl_phase_render.md) - Render phase documents from model
|
||||||
|
|
||||||
|
33
docs/source/cli/airshipctl_phase_plan.md
Normal file
33
docs/source/cli/airshipctl_phase_plan.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
## airshipctl phase plan
|
||||||
|
|
||||||
|
List phases
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
List life-cycle phases which were defined in document model by group.
|
||||||
|
Phases within a group are executed sequentially. Multiple phase groups
|
||||||
|
are executed in parallel.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
airshipctl phase plan [flags]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
-h, --help help for plan
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
--airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config")
|
||||||
|
--debug enable verbose output
|
||||||
|
--kubeconfig string Path to kubeconfig associated with airshipctl configuration. (default "$HOME/.airship/kubeconfig")
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEE ALSO
|
||||||
|
|
||||||
|
* [airshipctl phase](airshipctl_phase.md) - Manage phases
|
||||||
|
|
@ -40,6 +40,10 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
Scheme = runtime.NewScheme()
|
Scheme = runtime.NewScheme()
|
||||||
// NOTE add all api objects to scheme here
|
// NOTE add all api objects to scheme here
|
||||||
SchemeBuilder.Register(&Clusterctl{})
|
SchemeBuilder.Register(
|
||||||
|
&Clusterctl{},
|
||||||
|
&Phase{},
|
||||||
|
&PhasePlan{},
|
||||||
|
)
|
||||||
_ = AddToScheme(Scheme) //nolint:errcheck
|
_ = AddToScheme(Scheme) //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
36
pkg/api/v1alpha1/phase_types.go
Normal file
36
pkg/api/v1alpha1/phase_types.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// Phase object to control deployment steps
|
||||||
|
type Phase struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
Config PhaseConfig `json:"config,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PhaseConfig represents configuration for a particular phase. It contins a reference to
|
||||||
|
// phase runner object which should contain runner configuration
|
||||||
|
type PhaseConfig struct {
|
||||||
|
ExecutorRef *corev1.ObjectReference `json:"executorRef"`
|
||||||
|
DocumentEntryPoint string `json:"documentEntryPoint"`
|
||||||
|
}
|
40
pkg/api/v1alpha1/phaseplan_types.go
Normal file
40
pkg/api/v1alpha1/phaseplan_types.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// PhasePlan object represents phase execution sequence
|
||||||
|
type PhasePlan struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
PhaseGroups []PhaseGroup `json:"phaseGroups,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PhaseGroup represents set of phases (i.e. steps) executed sequentially.
|
||||||
|
// Phase groups are executed simultaneously
|
||||||
|
type PhaseGroup struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Phases []PhaseGroupStep `json:"phases,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PhaseGroupStep represents phase (or step) within phase group
|
||||||
|
type PhaseGroupStep struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
@ -5,7 +5,8 @@
|
|||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
@ -99,6 +100,119 @@ func (in *MoveOptions) DeepCopy() *MoveOptions {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Phase) DeepCopyInto(out *Phase) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Config.DeepCopyInto(&out.Config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Phase.
|
||||||
|
func (in *Phase) DeepCopy() *Phase {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Phase)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Phase) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *PhaseConfig) DeepCopyInto(out *PhaseConfig) {
|
||||||
|
*out = *in
|
||||||
|
if in.ExecutorRef != nil {
|
||||||
|
in, out := &in.ExecutorRef, &out.ExecutorRef
|
||||||
|
*out = new(v1.ObjectReference)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhaseConfig.
|
||||||
|
func (in *PhaseConfig) DeepCopy() *PhaseConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PhaseConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *PhaseGroup) DeepCopyInto(out *PhaseGroup) {
|
||||||
|
*out = *in
|
||||||
|
if in.Phases != nil {
|
||||||
|
in, out := &in.Phases, &out.Phases
|
||||||
|
*out = make([]PhaseGroupStep, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhaseGroup.
|
||||||
|
func (in *PhaseGroup) DeepCopy() *PhaseGroup {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PhaseGroup)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *PhaseGroupStep) DeepCopyInto(out *PhaseGroupStep) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhaseGroupStep.
|
||||||
|
func (in *PhaseGroupStep) DeepCopy() *PhaseGroupStep {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PhaseGroupStep)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *PhasePlan) DeepCopyInto(out *PhasePlan) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.PhaseGroups != nil {
|
||||||
|
in, out := &in.PhaseGroups, &out.PhaseGroups
|
||||||
|
*out = make([]PhaseGroup, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhasePlan.
|
||||||
|
func (in *PhasePlan) DeepCopy() *PhasePlan {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PhasePlan)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *PhasePlan) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Provider) DeepCopyInto(out *Provider) {
|
func (in *Provider) DeepCopyInto(out *Provider) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
74
pkg/phase/phase.go
Normal file
74
pkg/phase/phase.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PhaseDirName directory for bundle with phases
|
||||||
|
// TODO (dukov) Remove this once repository metadata is ready
|
||||||
|
PhaseDirName = "phases"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cmd object to work with phase api
|
||||||
|
type Cmd struct {
|
||||||
|
*environment.AirshipCTLSettings
|
||||||
|
DryRun bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Cmd) getBundle() (document.Bundle, error) {
|
||||||
|
ccm, err := p.Config.CurrentContextManifest()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return document.NewBundleByPath(filepath.Join(ccm.TargetPath, ccm.SubPath, PhaseDirName))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plan shows available phase names
|
||||||
|
func (p *Cmd) Plan() (map[string][]string, error) {
|
||||||
|
bundle, err := p.getBundle()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
plan := &airshipv1.PhasePlan{}
|
||||||
|
selector, err := document.NewSelector().ByObject(plan, airshipv1.Scheme)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
doc, err := bundle.SelectOne(selector)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := doc.ToAPIObject(plan, airshipv1.Scheme); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string][]string)
|
||||||
|
for _, phaseGroup := range plan.PhaseGroups {
|
||||||
|
phases := make([]string, len(phaseGroup.Phases))
|
||||||
|
for i, phase := range phaseGroup.Phases {
|
||||||
|
phases[i] = phase.Name
|
||||||
|
}
|
||||||
|
result[phaseGroup.Name] = phases
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
99
pkg/phase/phase_test.go
Normal file
99
pkg/phase/phase_test.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
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"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"sigs.k8s.io/kustomize/api/resid"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/environment"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/phase"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPhasePlan(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
settings func() *environment.AirshipCTLSettings
|
||||||
|
expectedPlan map[string][]string
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "No context",
|
||||||
|
settings: func() *environment.AirshipCTLSettings {
|
||||||
|
s := makeDefaultSettings()
|
||||||
|
s.Config.CurrentContext = "badCtx"
|
||||||
|
return s
|
||||||
|
},
|
||||||
|
expectedErr: config.ErrMissingConfig{What: "Context with name 'badCtx'"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Valid Phase Plan",
|
||||||
|
settings: makeDefaultSettings,
|
||||||
|
expectedPlan: map[string][]string{
|
||||||
|
"group1": {
|
||||||
|
"isogen",
|
||||||
|
"remotedirect",
|
||||||
|
"initinfra",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "No Phase Plan",
|
||||||
|
settings: func() *environment.AirshipCTLSettings {
|
||||||
|
s := makeDefaultSettings()
|
||||||
|
m, err := s.Config.CurrentContextManifest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
m.SubPath = "no_plan_site"
|
||||||
|
return s
|
||||||
|
},
|
||||||
|
expectedErr: document.ErrDocNotFound{
|
||||||
|
Selector: document.Selector{
|
||||||
|
Selector: types.Selector{
|
||||||
|
Gvk: resid.Gvk{
|
||||||
|
Group: "airshipit.org",
|
||||||
|
Version: "v1alpha1",
|
||||||
|
Kind: "PhasePlan",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
tt := test
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
cmd := phase.Cmd{AirshipCTLSettings: tt.settings()}
|
||||||
|
actualPlan, actualErr := cmd.Plan()
|
||||||
|
assert.Equal(t, tt.expectedErr, actualErr)
|
||||||
|
assert.Equal(t, tt.expectedPlan, actualPlan)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeDefaultSettings() *environment.AirshipCTLSettings {
|
||||||
|
testSettings := &environment.AirshipCTLSettings{
|
||||||
|
AirshipConfigPath: "testdata/airshipconfig.yaml",
|
||||||
|
KubeConfigPath: "testdata/kubeconfig.yaml",
|
||||||
|
}
|
||||||
|
testSettings.InitConfig()
|
||||||
|
return testSettings
|
||||||
|
}
|
44
pkg/phase/testdata/airshipconfig.yaml
vendored
Normal file
44
pkg/phase/testdata/airshipconfig.yaml
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
bootstrapInfo:
|
||||||
|
dummy_bootstrap_config:
|
||||||
|
container:
|
||||||
|
volume: /tmp/airship:/config
|
||||||
|
image: quay.io/airshipit/isogen:latest-debian_stable
|
||||||
|
containerRuntime: docker
|
||||||
|
builder:
|
||||||
|
userDataFileName: user-data
|
||||||
|
networkConfigFileName: network-config
|
||||||
|
outputMetadataFileName: output-metadata.yaml
|
||||||
|
remoteDirect:
|
||||||
|
isoUrl: http://localhost:8099/debian-custom.iso
|
||||||
|
remoteType: redfish
|
||||||
|
clusters:
|
||||||
|
dummycluster:
|
||||||
|
clusterType:
|
||||||
|
ephemeral:
|
||||||
|
bootstrapInfo: dummy_bootstrap_config
|
||||||
|
clusterKubeconf: dummycluster_ephemeral
|
||||||
|
contexts:
|
||||||
|
dummy_cluster:
|
||||||
|
contextKubeconf: dummy_cluster
|
||||||
|
manifest: dummy_manifest
|
||||||
|
currentContext: dummy_cluster
|
||||||
|
kind: Config
|
||||||
|
manifests:
|
||||||
|
dummy_manifest:
|
||||||
|
primaryRepositoryName: primary
|
||||||
|
repositories:
|
||||||
|
primary:
|
||||||
|
auth:
|
||||||
|
sshKey: testdata/test-key.pem
|
||||||
|
type: ssh-key
|
||||||
|
checkout:
|
||||||
|
branch: ""
|
||||||
|
force: false
|
||||||
|
remoteRef: ""
|
||||||
|
tag: v1.0.1
|
||||||
|
url: http://dummy.url.com/primary.git
|
||||||
|
subPath: valid_site
|
||||||
|
targetPath: testdata
|
||||||
|
users:
|
||||||
|
dummy_user: {}
|
19
pkg/phase/testdata/kubeconfig.yaml
vendored
Normal file
19
pkg/phase/testdata/kubeconfig.yaml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
clusters:
|
||||||
|
- cluster:
|
||||||
|
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1Ea3lPVEUzTURNd09Wb1hEVEk1TURreU5qRTNNRE13T1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUZyCkdxM0kyb2dZci81Y01Udy9Na1pORTNWQURzdEdyU240WjU2TDhPUGhMcUhDN2t1dno2dVpES3dCSGtGeTBNK2MKRXIzd2piUGE1aTV5NmkyMGtxSHBVMjdPZTA0dzBXV2s4N0RSZVlWaGNoZVJHRXoraWt3SndIcGRmMjJVemZNKwpkSDBzaUhuMVd6UnovYk4za3hMUzJlMnZ2U1Y3bmNubk1YRUd4OXV0MUY0NThHeWxxdmxXTUlWMzg5Q2didXFDCkcwcFdiMTBLM0RVZWdiT25Xa1FmSm5sTWRRVVZDUVdZZEZaaklrcWtkWi9hVTRobkNEV01oZXNWRnFNaDN3VVAKczhQay9BNWh1ZFFPbnFRNDVIWXZLdjZ5RjJWcDUyWExBRUx3NDJ4aVRKZlh0V1h4eHR6cU4wY1lyL2VxeS9XMQp1YVVGSW5xQjFVM0JFL1oxbmFrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKUUVKQVBLSkFjVDVuK3dsWGJsdU9mS0J3c2gKZTI4R1c5R2QwM0N0NGF3RzhzMXE1ZHNua2tpZmVTUENHVFZ1SXF6UTZDNmJaSk9SMDMvVEl5ejh6NDJnaitDVApjWUZXZkltM2RKTnpRL08xWkdySXZZNWdtcWJtWDlpV0JaU24rRytEOGxubzd2aGMvY0tBRFR5OTMvVU92MThuCkdhMnIrRGJJcHcyTWVBVEl2elpxRS9RWlVSQ25DMmdjUFhTVzFqN2h4R3o1a3ZNcGVDZTdQYVUvdVFvblVHSWsKZ2t6ZzI4NHQvREhUUzc4N1V1SUg5cXBaV09yTFNMOGFBeUxQUHhWSXBteGZmbWRETE9TS2VUemRlTmxoSitUMwowQlBVaHBQTlJBNTNJN0hRQjhVUDR2elNONTkzZ1VFbVlFQ2Jic2RYSzB6ZVR6SDdWWHR2Zmd5WTVWWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||||
|
server: https://127.0.0.1:6443
|
||||||
|
name: dummycluster_ephemeral
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: dummycluster_ephemeral
|
||||||
|
user: kubernetes-admin
|
||||||
|
name: dummy_cluster
|
||||||
|
current-context: dummy_cluster
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users:
|
||||||
|
- name: kubernetes-admin
|
||||||
|
user:
|
||||||
|
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||||
|
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
0
pkg/phase/testdata/no_plan_site/phases/kustomization.yaml
vendored
Normal file
0
pkg/phase/testdata/no_plan_site/phases/kustomization.yaml
vendored
Normal file
2
pkg/phase/testdata/valid_site/phases/kustomization.yaml
vendored
Normal file
2
pkg/phase/testdata/valid_site/phases/kustomization.yaml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
resources:
|
||||||
|
- phaseplan.yaml
|
10
pkg/phase/testdata/valid_site/phases/phaseplan.yaml
vendored
Normal file
10
pkg/phase/testdata/valid_site/phases/phaseplan.yaml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: PhasePlan
|
||||||
|
metadata:
|
||||||
|
name: phasePlan
|
||||||
|
phaseGroups:
|
||||||
|
- name: group1
|
||||||
|
phases:
|
||||||
|
- name: isogen
|
||||||
|
- name: remotedirect
|
||||||
|
- name: initinfra
|
Loading…
Reference in New Issue
Block a user