Implement render methods
Change-Id: I03b7aad33576eaa9ef7dfaabfb579ac90cc26a12 Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
This commit is contained in:
parent
0bdbd690db
commit
0c736af2e8
cmd/phase
go.sumpkg
bootstrap/isogen
clusterctl/client
k8s/applier
phase
tools/document
@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/phase/render"
|
"opendev.org/airship/airshipctl/pkg/phase"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -35,48 +35,48 @@ airshipctl phase render initinfra -l app=helm,service=tiller -k Deployment
|
|||||||
|
|
||||||
// NewRenderCommand create a new command for document rendering
|
// NewRenderCommand create a new command for document rendering
|
||||||
func NewRenderCommand(cfgFactory config.Factory) *cobra.Command {
|
func NewRenderCommand(cfgFactory config.Factory) *cobra.Command {
|
||||||
renderSettings := &render.Settings{}
|
filterOptions := &phase.FilterOptions{}
|
||||||
renderCmd := &cobra.Command{
|
renderCmd := &cobra.Command{
|
||||||
Use: "render PHASE_NAME",
|
Use: "render PHASE_NAME",
|
||||||
Short: "Render phase documents from model",
|
Short: "Render phase documents from model",
|
||||||
Example: renderExample,
|
Example: renderExample,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return renderSettings.Render(cfgFactory, args[0], cmd.OutOrStdout())
|
return filterOptions.Render(cfgFactory, args[0], cmd.OutOrStdout())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
addRenderFlags(renderSettings, renderCmd)
|
addRenderFlags(filterOptions, renderCmd)
|
||||||
return renderCmd
|
return renderCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// addRenderFlags adds flags for document render sub-command
|
// addRenderFlags adds flags for document render sub-command
|
||||||
func addRenderFlags(settings *render.Settings, cmd *cobra.Command) {
|
func addRenderFlags(filterOptions *phase.FilterOptions, cmd *cobra.Command) {
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
|
|
||||||
flags.StringVarP(
|
flags.StringVarP(
|
||||||
&settings.Label,
|
&filterOptions.Label,
|
||||||
"label",
|
"label",
|
||||||
"l",
|
"l",
|
||||||
"",
|
"",
|
||||||
"filter documents by Labels")
|
"filter documents by Labels")
|
||||||
|
|
||||||
flags.StringVarP(
|
flags.StringVarP(
|
||||||
&settings.Annotation,
|
&filterOptions.Annotation,
|
||||||
"annotation",
|
"annotation",
|
||||||
"a",
|
"a",
|
||||||
"",
|
"",
|
||||||
"filter documents by Annotations")
|
"filter documents by Annotations")
|
||||||
|
|
||||||
flags.StringVarP(
|
flags.StringVarP(
|
||||||
&settings.APIVersion,
|
&filterOptions.APIVersion,
|
||||||
"apiversion",
|
"apiversion",
|
||||||
"g",
|
"g",
|
||||||
"",
|
"",
|
||||||
"filter documents by API version")
|
"filter documents by API version")
|
||||||
|
|
||||||
flags.StringVarP(
|
flags.StringVarP(
|
||||||
&settings.Kind,
|
&filterOptions.Kind,
|
||||||
"kind",
|
"kind",
|
||||||
"k",
|
"k",
|
||||||
"",
|
"",
|
||||||
|
@ -17,44 +17,17 @@ package phase_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/cmd/phase"
|
"opendev.org/airship/airshipctl/cmd/phase"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
|
||||||
"opendev.org/airship/airshipctl/testutil"
|
"opendev.org/airship/airshipctl/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRender(t *testing.T) {
|
func TestRender(t *testing.T) {
|
||||||
cfg, cleanupCfg := testutil.InitConfig(t)
|
|
||||||
defer cleanupCfg(t)
|
|
||||||
cfg.CurrentContext = "def_ephemeral"
|
|
||||||
cfg.Manifests["test"] = &config.Manifest{
|
|
||||||
TargetPath: "testdata",
|
|
||||||
PrimaryRepositoryName: "testRepo",
|
|
||||||
Repositories: map[string]*config.Repository{
|
|
||||||
"testRepo": {
|
|
||||||
URLString: "http://localhost",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctx, err := cfg.GetContext("def_ephemeral")
|
|
||||||
require.NoError(t, err)
|
|
||||||
ctx.Manifest = "test"
|
|
||||||
settings := func() (*config.Config, error) {
|
|
||||||
return cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []*testutil.CmdTest{
|
tests := []*testutil.CmdTest{
|
||||||
{
|
{
|
||||||
Name: "render-with-help",
|
Name: "render-with-help",
|
||||||
CmdLine: "-h",
|
CmdLine: "-h",
|
||||||
Cmd: phase.NewRenderCommand(nil),
|
Cmd: phase.NewRenderCommand(nil),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "render-with-multiple-labels",
|
|
||||||
CmdLine: "initinfra -l app=helm,name=tiller",
|
|
||||||
Cmd: phase.NewRenderCommand(settings),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
testutil.RunTest(t, tt)
|
testutil.RunTest(t, tt)
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
airshipit.org/clustertype: ephemeral
|
|
||||||
creationTimestamp: null
|
|
||||||
labels:
|
|
||||||
app: helm
|
|
||||||
name: tiller
|
|
||||||
name: tiller-deploy
|
|
||||||
namespace: kube-system
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
strategy: {}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
creationTimestamp: null
|
|
||||||
labels:
|
|
||||||
app: helm
|
|
||||||
name: tiller
|
|
||||||
spec:
|
|
||||||
automountServiceAccountToken: true
|
|
||||||
containers:
|
|
||||||
- env:
|
|
||||||
- name: TILLER_NAMESPACE
|
|
||||||
value: kube-system
|
|
||||||
- name: TILLER_HISTORY_MAX
|
|
||||||
value: "0"
|
|
||||||
image: gcr.io/kubernetes-helm/tiller:v2.12.3
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /liveness
|
|
||||||
port: 44135
|
|
||||||
initialDelaySeconds: 1
|
|
||||||
timeoutSeconds: 1
|
|
||||||
name: tiller
|
|
||||||
ports:
|
|
||||||
- containerPort: 44134
|
|
||||||
name: tiller
|
|
||||||
- containerPort: 44135
|
|
||||||
name: http
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /readiness
|
|
||||||
port: 44135
|
|
||||||
initialDelaySeconds: 1
|
|
||||||
timeoutSeconds: 1
|
|
||||||
resources: {}
|
|
||||||
status: {}
|
|
||||||
...
|
|
@ -1,2 +0,0 @@
|
|||||||
resources:
|
|
||||||
- tiller.yaml
|
|
@ -1,74 +0,0 @@
|
|||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
airshipit.org/clustertype: ephemeral
|
|
||||||
creationTimestamp: null
|
|
||||||
labels:
|
|
||||||
app: helm
|
|
||||||
name: tiller
|
|
||||||
name: tiller-deploy
|
|
||||||
namespace: kube-system
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
strategy: {}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
creationTimestamp: null
|
|
||||||
labels:
|
|
||||||
app: helm
|
|
||||||
name: tiller
|
|
||||||
spec:
|
|
||||||
automountServiceAccountToken: true
|
|
||||||
containers:
|
|
||||||
- env:
|
|
||||||
- name: TILLER_NAMESPACE
|
|
||||||
value: kube-system
|
|
||||||
- name: TILLER_HISTORY_MAX
|
|
||||||
value: "0"
|
|
||||||
image: gcr.io/kubernetes-helm/tiller:v2.12.3
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /liveness
|
|
||||||
port: 44135
|
|
||||||
initialDelaySeconds: 1
|
|
||||||
timeoutSeconds: 1
|
|
||||||
name: tiller
|
|
||||||
ports:
|
|
||||||
- containerPort: 44134
|
|
||||||
name: tiller
|
|
||||||
- containerPort: 44135
|
|
||||||
name: http
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /readiness
|
|
||||||
port: 44135
|
|
||||||
initialDelaySeconds: 1
|
|
||||||
timeoutSeconds: 1
|
|
||||||
resources: {}
|
|
||||||
status: {}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
airshipit.org/clustertype: ephemeral
|
|
||||||
creationTimestamp: null
|
|
||||||
labels:
|
|
||||||
app: helm
|
|
||||||
name: tiller-deploy
|
|
||||||
namespace: kube-system
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- name: tiller
|
|
||||||
port: 44134
|
|
||||||
targetPort: tiller
|
|
||||||
selector:
|
|
||||||
app: helm
|
|
||||||
name: tiller
|
|
||||||
type: ClusterIP
|
|
||||||
status:
|
|
||||||
loadBalancer: {}
|
|
||||||
...
|
|
1
go.sum
1
go.sum
@ -1507,6 +1507,7 @@ k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C
|
|||||||
k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E=
|
k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E=
|
||||||
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd h1:nZX5+wEqTu/EBIYjrZlFOA63z4+Zcy96lDkCZPU9a9c=
|
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd h1:nZX5+wEqTu/EBIYjrZlFOA63z4+Zcy96lDkCZPU9a9c=
|
||||||
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
|
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
|
||||||
|
k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8=
|
||||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||||
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
|
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
|
||||||
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
||||||
|
@ -144,8 +144,10 @@ func (c *Executor) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render executor documents
|
// Render executor documents
|
||||||
func (c *Executor) Render(_ io.Writer, _ ifc.RenderOptions) error {
|
func (c *Executor) Render(w io.Writer, _ ifc.RenderOptions) error {
|
||||||
return errors.ErrNotImplemented{}
|
// will be implemented later
|
||||||
|
_, err := w.Write([]byte{})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleError(ch chan<- events.Event, err error) {
|
func handleError(ch chan<- events.Event, err error) {
|
||||||
|
@ -182,6 +182,8 @@ func (c *ClusterctlExecutor) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render executor documents
|
// Render executor documents
|
||||||
func (c *ClusterctlExecutor) Render(_ io.Writer, _ ifc.RenderOptions) error {
|
func (c *ClusterctlExecutor) Render(w io.Writer, _ ifc.RenderOptions) error {
|
||||||
return errors.ErrNotImplemented{}
|
// will be implemented later
|
||||||
|
_, err := w.Write([]byte{})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,6 @@ func TestExecutorRender(t *testing.T) {
|
|||||||
sampleCfgDoc := executorDoc(t, "init")
|
sampleCfgDoc := executorDoc(t, "init")
|
||||||
bundle, err := document.NewBundleByPath("testdata/executor_init")
|
bundle, err := document.NewBundleByPath("testdata/executor_init")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
expectedErr := airerrors.ErrNotImplemented{}
|
|
||||||
|
|
||||||
executor, err := cctlclient.NewExecutor(
|
executor, err := cctlclient.NewExecutor(
|
||||||
ifc.ExecutorConfig{
|
ifc.ExecutorConfig{
|
||||||
@ -229,7 +228,7 @@ func TestExecutorRender(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
actualOut := &bytes.Buffer{}
|
actualOut := &bytes.Buffer{}
|
||||||
actualErr := executor.Render(actualOut, ifc.RenderOptions{})
|
actualErr := executor.Render(actualOut, ifc.RenderOptions{})
|
||||||
assert.Equal(t, expectedErr, actualErr)
|
assert.Equal(t, nil, actualErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDefaultHelper(t *testing.T) ifc.Helper {
|
func makeDefaultHelper(t *testing.T) ifc.Helper {
|
||||||
|
@ -93,7 +93,7 @@ func (a *Applier) ApplyBundle(bundle document.Bundle, ao ApplyOptions) {
|
|||||||
|
|
||||||
func (a *Applier) getInfos(bundleName string, bundle document.Bundle) ([]*resource.Info, error) {
|
func (a *Applier) getInfos(bundleName string, bundle document.Bundle) ([]*resource.Info, error) {
|
||||||
if bundle == nil {
|
if bundle == nil {
|
||||||
return nil, ErrApplyNilBundle{}
|
return nil, ErrNilBundle{}
|
||||||
}
|
}
|
||||||
selector := document.
|
selector := document.
|
||||||
NewSelector().
|
NewSelector().
|
||||||
|
@ -94,7 +94,7 @@ func TestApplierRun(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bundle failure",
|
name: "bundle failure",
|
||||||
expectedString: "Cannot apply nil bundle",
|
expectedString: "nil bundle provided",
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -28,10 +28,10 @@ func (e ErrApply) Error() string {
|
|||||||
return fmt.Sprintf("Applying of resources to kubernetes cluster has failed, errors are:\n%v", e.errors)
|
return fmt.Sprintf("Applying of resources to kubernetes cluster has failed, errors are:\n%v", e.errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrApplyNilBundle returned when nil bundle is passed to ApplyBundle function
|
// ErrNilBundle returned when bundle is nil
|
||||||
type ErrApplyNilBundle struct {
|
type ErrNilBundle struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ErrApplyNilBundle) Error() string {
|
func (e ErrNilBundle) Error() string {
|
||||||
return "Cannot apply nil bundle"
|
return "nil bundle provided"
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,9 @@ func NewExecutor(opts ExecutorOptions) (*Executor, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if opts.ExecutorBundle == nil {
|
||||||
|
return nil, ErrNilBundle{}
|
||||||
|
}
|
||||||
return &Executor{
|
return &Executor{
|
||||||
Options: opts,
|
Options: opts,
|
||||||
apiObject: apiObj,
|
apiObject: apiObj,
|
||||||
@ -116,9 +119,6 @@ func (e *Executor) prepareApplier(ch chan events.Event) (*Applier, document.Bund
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if e.Options.ExecutorBundle == nil {
|
|
||||||
return nil, nil, ErrApplyNilBundle{}
|
|
||||||
}
|
|
||||||
log.Debug("Filtering out documents that shouldn't be applied to kubernetes from document bundle")
|
log.Debug("Filtering out documents that shouldn't be applied to kubernetes from document bundle")
|
||||||
bundle, err := e.Options.ExecutorBundle.SelectBundle(document.NewDeployToK8sSelector())
|
bundle, err := e.Options.ExecutorBundle.SelectBundle(document.NewDeployToK8sSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -139,6 +139,10 @@ func (e *Executor) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render document set
|
// Render document set
|
||||||
func (e *Executor) Render(w io.Writer, _ ifc.RenderOptions) error {
|
func (e *Executor) Render(w io.Writer, o ifc.RenderOptions) error {
|
||||||
return e.Options.ExecutorBundle.Write(w)
|
bundle, err := e.Options.ExecutorBundle.SelectBundle(o.FilterSelector)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return bundle.Write(w)
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ func TestExecutorRun(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Nil bundle provided",
|
name: "Nil bundle provided",
|
||||||
execDoc: toKubernetesApply(t, ValidExecutorDoc),
|
execDoc: toKubernetesApply(t, ValidExecutorDoc),
|
||||||
containsErr: "Cannot apply nil bundle",
|
containsErr: "nil bundle provided",
|
||||||
kubeconf: testKubeconfig(testValidKubeconfig),
|
kubeconf: testKubeconfig(testValidKubeconfig),
|
||||||
helper: makeDefaultHelper(t),
|
helper: makeDefaultHelper(t),
|
||||||
bundleFunc: func(t *testing.T) document.Bundle {
|
bundleFunc: func(t *testing.T) document.Bundle {
|
||||||
@ -185,17 +185,22 @@ func TestExecutorRun(t *testing.T) {
|
|||||||
ExecutorBundle: tt.bundleFunc(t),
|
ExecutorBundle: tt.bundleFunc(t),
|
||||||
Kubeconfig: tt.kubeconf,
|
Kubeconfig: tt.kubeconf,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
if tt.name == "Nil bundle provided" {
|
||||||
require.NotNil(t, exec)
|
|
||||||
ch := make(chan events.Event)
|
|
||||||
go exec.Run(ch, ifc.RunOptions{})
|
|
||||||
processor := events.NewDefaultProcessor(utils.Streams())
|
|
||||||
err = processor.Process(ch)
|
|
||||||
if tt.containsErr != "" {
|
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Contains(t, err.Error(), tt.containsErr)
|
assert.Contains(t, err.Error(), tt.containsErr)
|
||||||
} else {
|
} else {
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, exec)
|
||||||
|
ch := make(chan events.Event)
|
||||||
|
go exec.Run(ch, ifc.RunOptions{})
|
||||||
|
processor := events.NewDefaultProcessor(utils.Streams())
|
||||||
|
err = processor.Process(ch)
|
||||||
|
if tt.containsErr != "" {
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), tt.containsErr)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package phase
|
package phase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -131,6 +132,16 @@ func (p *phase) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render executor documents
|
||||||
|
func (p *phase) Render(w io.Writer, options ifc.RenderOptions) error {
|
||||||
|
executor, err := p.Executor()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return executor.Render(w, options)
|
||||||
|
}
|
||||||
|
|
||||||
// DocumentRoot root that holds all the documents associated with the phase
|
// DocumentRoot root that holds all the documents associated with the phase
|
||||||
func (p *phase) DocumentRoot() string {
|
func (p *phase) DocumentRoot() string {
|
||||||
if p.apiObj.Config.DocumentEntryPoint == "" {
|
if p.apiObj.Config.DocumentEntryPoint == "" {
|
||||||
|
@ -177,11 +177,11 @@ var _ ifc.Executor = fakeExecutor{}
|
|||||||
type fakeExecutor struct {
|
type fakeExecutor struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e fakeExecutor) Render(w io.Writer, ro ifc.RenderOptions) error {
|
func (e fakeExecutor) Render(_ io.Writer, _ ifc.RenderOptions) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e fakeExecutor) Run(ch chan events.Event, ro ifc.RunOptions) {
|
func (e fakeExecutor) Run(ch chan events.Event, _ ifc.RunOptions) {
|
||||||
defer close(ch)
|
defer close(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,8 +40,10 @@ type RunOptions struct {
|
|||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderOptions is empty for now, but may hold things like format in future
|
// RenderOptions holds options for render method
|
||||||
type RenderOptions struct{}
|
type RenderOptions struct {
|
||||||
|
FilterSelector document.Selector
|
||||||
|
}
|
||||||
|
|
||||||
// WaitOptions holds only timeout now, but may be extended in the future
|
// WaitOptions holds only timeout now, but may be extended in the future
|
||||||
type WaitOptions struct {
|
type WaitOptions struct {
|
||||||
|
@ -15,18 +15,20 @@
|
|||||||
package ifc
|
package ifc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Phase provides a way to interact with a phase
|
// Phase provides a way to interact with a phase
|
||||||
// TODO add render method
|
|
||||||
type Phase interface {
|
type Phase interface {
|
||||||
Validate() error
|
Validate() error
|
||||||
Run(RunOptions) error
|
Run(RunOptions) error
|
||||||
DocumentRoot() string
|
DocumentRoot() string
|
||||||
Details() (string, error)
|
Details() (string, error)
|
||||||
Executor() (Executor, error)
|
Executor() (Executor, error)
|
||||||
|
Render(io.Writer, RenderOptions) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID uniquely identifies the phase
|
// ID uniquely identifies the phase
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package render
|
package phase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@ -20,26 +20,40 @@ import (
|
|||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/document"
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/phase/ifc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FilterOptions holds filters for selector
|
||||||
|
type FilterOptions struct {
|
||||||
|
// Label filters documents by label string
|
||||||
|
Label string
|
||||||
|
// Annotation filters documents by annotation string
|
||||||
|
Annotation string
|
||||||
|
// APIVersion filters documents by API group and version
|
||||||
|
APIVersion string
|
||||||
|
// Kind filters documents by document kind
|
||||||
|
Kind string
|
||||||
|
}
|
||||||
|
|
||||||
// Render prints out filtered documents
|
// Render prints out filtered documents
|
||||||
func (s *Settings) Render(cfgFactory config.Factory, phaseName string, out io.Writer) error {
|
func (fo *FilterOptions) Render(cfgFactory config.Factory, phaseName string, out io.Writer) error {
|
||||||
cfg, err := cfgFactory()
|
cfg, err := cfgFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := cfg.CurrentContextEntryPoint(phaseName)
|
helper, err := NewHelper(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
docBundle, err := document.NewBundleByPath(path)
|
client := NewClient(helper)
|
||||||
|
phase, err := client.PhaseByID(ifc.ID{Name: phaseName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
groupVersion := strings.Split(s.APIVersion, "/")
|
groupVersion := strings.Split(fo.APIVersion, "/")
|
||||||
group := ""
|
group := ""
|
||||||
version := groupVersion[0]
|
version := groupVersion[0]
|
||||||
if len(groupVersion) > 1 {
|
if len(groupVersion) > 1 {
|
||||||
@ -47,11 +61,7 @@ func (s *Settings) Render(cfgFactory config.Factory, phaseName string, out io.Wr
|
|||||||
version = strings.Join(groupVersion[1:], "/")
|
version = strings.Join(groupVersion[1:], "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
sel := document.NewSelector().ByLabel(s.Label).ByAnnotation(s.Annotation).ByGvk(group, version, s.Kind)
|
sel := document.NewSelector().ByLabel(fo.Label).ByAnnotation(fo.Annotation).ByGvk(group, version, fo.Kind)
|
||||||
filteredBundle, err := docBundle.SelectBundle(sel)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredBundle.Write(out)
|
return phase.Render(out, ifc.RenderOptions{FilterSelector: sel})
|
||||||
}
|
}
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
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 render
|
|
||||||
|
|
||||||
// Settings for document rendering
|
|
||||||
type Settings struct {
|
|
||||||
// Label filters documents by label string
|
|
||||||
Label string
|
|
||||||
// Annotation filters documents by annotation string
|
|
||||||
Annotation string
|
|
||||||
// APIVersion filters documents by API group and version
|
|
||||||
APIVersion string
|
|
||||||
// Kind filters documents by document kind
|
|
||||||
Kind string
|
|
||||||
}
|
|
@ -12,7 +12,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package render_test
|
package phase_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/phase/render"
|
"opendev.org/airship/airshipctl/pkg/phase"
|
||||||
"opendev.org/airship/airshipctl/testutil"
|
"opendev.org/airship/airshipctl/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,22 +34,23 @@ func TestRender(t *testing.T) {
|
|||||||
dummyManifest := rs.Manifests["dummy_manifest"]
|
dummyManifest := rs.Manifests["dummy_manifest"]
|
||||||
dummyManifest.TargetPath = "testdata"
|
dummyManifest.TargetPath = "testdata"
|
||||||
dummyManifest.SubPath = ""
|
dummyManifest.SubPath = ""
|
||||||
|
dummyManifest.MetadataPath = "metadata.yaml"
|
||||||
fixturePath := "phase"
|
fixturePath := "phase"
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
settings *render.Settings
|
settings *phase.FilterOptions
|
||||||
expResFile string
|
expResFile string
|
||||||
expErr error
|
expErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "No Filters",
|
name: "No Filters",
|
||||||
settings: &render.Settings{},
|
settings: &phase.FilterOptions{},
|
||||||
expResFile: "noFilter.yaml",
|
expResFile: "noFilter.yaml",
|
||||||
expErr: nil,
|
expErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "All Filters",
|
name: "All Filters",
|
||||||
settings: &render.Settings{
|
settings: &phase.FilterOptions{
|
||||||
Label: "airshipit.org/deploy-k8s=false",
|
Label: "airshipit.org/deploy-k8s=false",
|
||||||
Annotation: "airshipit.org/clustertype=ephemeral",
|
Annotation: "airshipit.org/clustertype=ephemeral",
|
||||||
APIVersion: "metal3.io/v1alpha1",
|
APIVersion: "metal3.io/v1alpha1",
|
||||||
@ -60,7 +61,7 @@ func TestRender(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Multiple Labels",
|
name: "Multiple Labels",
|
||||||
settings: &render.Settings{
|
settings: &phase.FilterOptions{
|
||||||
Label: "airshipit.org/deploy-k8s=false, airshipit.org/ephemeral-node=true",
|
Label: "airshipit.org/deploy-k8s=false, airshipit.org/ephemeral-node=true",
|
||||||
},
|
},
|
||||||
expResFile: "multiLabels.yaml",
|
expResFile: "multiLabels.yaml",
|
||||||
@ -68,7 +69,7 @@ func TestRender(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Malformed Label",
|
name: "Malformed Label",
|
||||||
settings: &render.Settings{
|
settings: &phase.FilterOptions{
|
||||||
Label: "app=(",
|
Label: "app=(",
|
||||||
},
|
},
|
||||||
expResFile: "",
|
expResFile: "",
|
0
pkg/phase/render/testdata/expected/allFilters.yaml → pkg/phase/testdata/expected/allFilters.yaml
vendored
0
pkg/phase/render/testdata/expected/allFilters.yaml → pkg/phase/testdata/expected/allFilters.yaml
vendored
0
pkg/phase/render/testdata/expected/multiLabels.yaml → pkg/phase/testdata/expected/multiLabels.yaml
vendored
0
pkg/phase/render/testdata/expected/multiLabels.yaml → pkg/phase/testdata/expected/multiLabels.yaml
vendored
0
pkg/phase/render/testdata/expected/noFilter.yaml → pkg/phase/testdata/expected/noFilter.yaml
vendored
0
pkg/phase/render/testdata/expected/noFilter.yaml → pkg/phase/testdata/expected/noFilter.yaml
vendored
0
pkg/phase/render/testdata/expected/rawFilter.yaml → pkg/phase/testdata/expected/rawFilter.yaml
vendored
0
pkg/phase/render/testdata/expected/rawFilter.yaml → pkg/phase/testdata/expected/rawFilter.yaml
vendored
2
pkg/phase/testdata/metadata.yaml
vendored
Executable file
2
pkg/phase/testdata/metadata.yaml
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
phase:
|
||||||
|
path: phases
|
11
pkg/phase/testdata/phases/cluster-map.yaml
vendored
Executable file
11
pkg/phase/testdata/phases/cluster-map.yaml
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: ClusterMap
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
airshipit.org/deploy-k8s: "false"
|
||||||
|
name: main-map
|
||||||
|
map:
|
||||||
|
target-cluster:
|
||||||
|
parent: ephemeral-cluster
|
||||||
|
ephemeral-cluster: {}
|
12
pkg/phase/testdata/phases/executors.yaml
vendored
Executable file
12
pkg/phase/testdata/phases/executors.yaml
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: KubernetesApply
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
airshipit.org/deploy-k8s: "false"
|
||||||
|
name: kubernetes-apply
|
||||||
|
config:
|
||||||
|
waitOptions:
|
||||||
|
timeout: 2000
|
||||||
|
pruneOptions:
|
||||||
|
prune: false
|
4
pkg/phase/testdata/phases/kustomization.yaml
vendored
Executable file
4
pkg/phase/testdata/phases/kustomization.yaml
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
resources:
|
||||||
|
- phases.yaml
|
||||||
|
- executors.yaml
|
||||||
|
- cluster-map.yaml
|
12
pkg/phase/testdata/phases/phases.yaml
vendored
Executable file
12
pkg/phase/testdata/phases/phases.yaml
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: Phase
|
||||||
|
metadata:
|
||||||
|
name: phase
|
||||||
|
clusterName: ephemeral-cluster
|
||||||
|
config:
|
||||||
|
executorRef:
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: KubernetesApply
|
||||||
|
name: kubernetes-apply
|
||||||
|
documentEntryPoint: ephemeral/phase
|
@ -12,7 +12,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
set -e
|
set -xe
|
||||||
|
|
||||||
# The root of the manifest structure to be validated.
|
# The root of the manifest structure to be validated.
|
||||||
# This corresponds to the targetPath in an airshipctl config
|
# This corresponds to the targetPath in an airshipctl config
|
||||||
@ -109,7 +109,7 @@ for cluster in ephemeral target; do
|
|||||||
# removed since it was choking in certain cases and got to be more trouble than was worth.
|
# removed since it was choking in certain cases and got to be more trouble than was worth.
|
||||||
# This should be removed once we have a phase map that is smarter.
|
# This should be removed once we have a phase map that is smarter.
|
||||||
# In the meantime, as new phases are added, please add them here as well.
|
# In the meantime, as new phases are added, please add them here as well.
|
||||||
phases="bootstrap initinfra controlplane baremetalhost workers workload tenant"
|
phases="initinfra-ephemeral controlplane-ephemeral initinfra-target workers-target"
|
||||||
|
|
||||||
for phase in $phases; do
|
for phase in $phases; do
|
||||||
# Guard against bootstrap or initinfra being missing, which could be the case for some configs
|
# Guard against bootstrap or initinfra being missing, which could be the case for some configs
|
||||||
|
Loading…
x
Reference in New Issue
Block a user