Merge "Add generic container executor"
This commit is contained in:
commit
92ceea5581
@ -32,3 +32,16 @@ container:
|
||||
containerRuntime: docker
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
volume: /srv/iso:/config
|
||||
---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: GenericContainer
|
||||
metadata:
|
||||
name: generic-container
|
||||
labels:
|
||||
airshipit.org/deploy-k8s: "false"
|
||||
outputToStdout: true
|
||||
spec:
|
||||
container:
|
||||
image: quay.io/sample/image:v0.0.1
|
||||
config: |
|
||||
foo: bar
|
||||
|
64
pkg/api/v1alpha1/genericcontainer_types.go
Normal file
64
pkg/api/v1alpha1/genericcontainer_types.go
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
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"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
)
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// GenericContainer provides info about generic container
|
||||
type GenericContainer struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
// If set to will print output of RunFns to Stdout
|
||||
PrintOutput bool `json:"printOutput,omitempty"`
|
||||
// Settings for for a container
|
||||
Spec runtimeutil.FunctionSpec `json:"spec,omitempty"`
|
||||
// Config for the RunFns function in a custom format
|
||||
Config string `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultGenericContainer can be used to safely unmarshal GenericContainer object without nil pointers
|
||||
func DefaultGenericContainer() *GenericContainer {
|
||||
return &GenericContainer{
|
||||
Spec: runtimeutil.FunctionSpec{},
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *GenericContainer) DeepCopyInto(out *GenericContainer) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
|
||||
out.Spec = in.Spec
|
||||
out.Spec.Container = in.Spec.Container
|
||||
out.Spec.Container.Network = in.Spec.Container.Network
|
||||
if in.Spec.Container.StorageMounts != nil {
|
||||
in, out := &in.Spec.Container.StorageMounts, &out.Spec.Container.StorageMounts
|
||||
*out = make([]runtimeutil.StorageMount, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.Spec.Starlark = in.Spec.Starlark
|
||||
out.Spec.Exec = in.Spec.Exec
|
||||
if in.Spec.StorageMounts != nil {
|
||||
in, out := &in.Spec.StorageMounts, &out.Spec.StorageMounts
|
||||
*out = make([]runtimeutil.StorageMount, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ func init() {
|
||||
&ReplacementTransformer{},
|
||||
&Templater{},
|
||||
&BootConfiguration{},
|
||||
&GenericContainer{},
|
||||
)
|
||||
_ = AddToScheme(Scheme) //nolint:errcheck
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
@ -288,6 +288,24 @@ func (in *EphemeralCluster) DeepCopy() *EphemeralCluster {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericContainer.
|
||||
func (in *GenericContainer) DeepCopy() *GenericContainer {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(GenericContainer)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *GenericContainer) 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 *ImageConfiguration) DeepCopyInto(out *ImageConfiguration) {
|
||||
*out = *in
|
||||
|
202
pkg/container/executor.go
Normal file
202
pkg/container/executor.go
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
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 container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/runfn"
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/pkg/errors"
|
||||
"opendev.org/airship/airshipctl/pkg/events"
|
||||
"opendev.org/airship/airshipctl/pkg/phase/ifc"
|
||||
)
|
||||
|
||||
const (
|
||||
// yamlSeparator uses to separate yaml files
|
||||
yamlSeparator = "---\n"
|
||||
)
|
||||
|
||||
var _ ifc.Executor = &Executor{}
|
||||
|
||||
// Executor contains resources for generic container executor
|
||||
type Executor struct {
|
||||
ExecutorBundle document.Bundle
|
||||
ExecutorDocument document.Document
|
||||
|
||||
ContConf *v1alpha1.GenericContainer
|
||||
RunFns runfn.RunFns
|
||||
targetPath string
|
||||
}
|
||||
|
||||
// RegisterExecutor adds executor to phase executor registry
|
||||
func RegisterExecutor(registry map[schema.GroupVersionKind]ifc.ExecutorFactory) error {
|
||||
obj := v1alpha1.DefaultGenericContainer()
|
||||
gvks, _, err := v1alpha1.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
registry[gvks[0]] = NewExecutor
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewExecutor creates instance of phase executor
|
||||
func NewExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) {
|
||||
bundle, err := cfg.BundleFactory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiObj := &v1alpha1.GenericContainer{
|
||||
Spec: runtimeutil.FunctionSpec{},
|
||||
}
|
||||
err = cfg.ExecutorDocument.ToAPIObject(apiObj, v1alpha1.Scheme)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Executor{
|
||||
ExecutorBundle: bundle,
|
||||
ExecutorDocument: cfg.ExecutorDocument,
|
||||
|
||||
ContConf: apiObj,
|
||||
RunFns: runfn.RunFns{
|
||||
Functions: []*kyaml.RNode{},
|
||||
},
|
||||
targetPath: cfg.Helper.TargetPath(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Run generic container as a phase runner
|
||||
func (c *Executor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
|
||||
defer close(evtCh)
|
||||
|
||||
evtCh <- events.NewEvent().WithGenericContainerEvent(events.GenericContainerEvent{
|
||||
Operation: events.GenericContainerStart,
|
||||
Message: "starting generic container",
|
||||
})
|
||||
|
||||
if opts.DryRun {
|
||||
log.Print("generic container will be executed")
|
||||
evtCh <- events.NewEvent().WithGenericContainerEvent(events.GenericContainerEvent{
|
||||
Operation: events.GenericContainerStop,
|
||||
Message: "DryRun execution finished",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.SetInput(evtCh)
|
||||
c.PrepareFunctions(evtCh)
|
||||
c.SetMounts()
|
||||
|
||||
if c.ContConf.PrintOutput {
|
||||
c.RunFns.Output = os.Stdout
|
||||
}
|
||||
|
||||
err := c.RunFns.Execute()
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
return
|
||||
}
|
||||
|
||||
evtCh <- events.NewEvent().WithGenericContainerEvent(events.GenericContainerEvent{
|
||||
Operation: events.GenericContainerStop,
|
||||
Message: "execution of the generic container finished",
|
||||
})
|
||||
}
|
||||
|
||||
// SetInput sets input for function
|
||||
func (c *Executor) SetInput(evtCh chan events.Event) {
|
||||
docs, err := c.ExecutorBundle.GetAllDocuments()
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
return
|
||||
}
|
||||
|
||||
docsBytes := make([]byte, 0)
|
||||
for _, doc := range docs {
|
||||
data, err := doc.AsYAML()
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
return
|
||||
}
|
||||
docsBytes = append(docsBytes, []byte(yamlSeparator)...)
|
||||
docsBytes = append(docsBytes, data...)
|
||||
}
|
||||
c.RunFns.Input = bytes.NewReader(docsBytes)
|
||||
}
|
||||
|
||||
// PrepareFunctions prepares data for function
|
||||
func (c *Executor) PrepareFunctions(evtCh chan events.Event) {
|
||||
rnode, err := kyaml.Parse(c.ContConf.Config)
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
return
|
||||
}
|
||||
// Transform GenericContainer.Spec to annotation,
|
||||
// because we need to specify runFns config in annotation
|
||||
spec, err := yaml.Marshal(c.ContConf.Spec)
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
return
|
||||
}
|
||||
annotation := kyaml.SetAnnotation(runtimeutil.FunctionAnnotationKey, string(spec))
|
||||
_, err = annotation.Filter(rnode)
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.RunFns.Functions = append(c.RunFns.Functions, rnode)
|
||||
}
|
||||
|
||||
// SetMounts allows to set relative path for storage mounts to prevent security issues
|
||||
func (c *Executor) SetMounts() {
|
||||
if len(c.ContConf.Spec.Container.StorageMounts) == 0 {
|
||||
return
|
||||
}
|
||||
storageMounts := c.ContConf.Spec.Container.StorageMounts
|
||||
for i, mount := range storageMounts {
|
||||
storageMounts[i].Src = filepath.Join(c.targetPath, mount.Src)
|
||||
}
|
||||
c.RunFns.StorageMounts = storageMounts
|
||||
}
|
||||
|
||||
// Validate executor configuration and documents
|
||||
func (c *Executor) Validate() error {
|
||||
return errors.ErrNotImplemented{}
|
||||
}
|
||||
|
||||
// Render executor documents
|
||||
func (c *Executor) Render(_ io.Writer, _ ifc.RenderOptions) error {
|
||||
return errors.ErrNotImplemented{}
|
||||
}
|
||||
|
||||
func handleError(ch chan<- events.Event, err error) {
|
||||
ch <- events.NewEvent().WithErrorEvent(events.ErrorEvent{
|
||||
Error: err,
|
||||
})
|
||||
}
|
253
pkg/container/executor_test.go
Normal file
253
pkg/container/executor_test.go
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
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 container_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/runfn"
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/container"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/pkg/events"
|
||||
"opendev.org/airship/airshipctl/pkg/phase"
|
||||
"opendev.org/airship/airshipctl/pkg/phase/ifc"
|
||||
)
|
||||
|
||||
const (
|
||||
executorDoc = `
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: GenericContainer
|
||||
metadata:
|
||||
name: generic-container
|
||||
labels:
|
||||
airshipit.org/deploy-k8s: "false"
|
||||
spec:
|
||||
container:
|
||||
image: quay.io/test/image:v0.0.1
|
||||
config: |
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: GenericContainerValues
|
||||
object:
|
||||
executables:
|
||||
- name: test
|
||||
cmdline: /tmp/x/script.sh
|
||||
env:
|
||||
- name: var
|
||||
value: testval
|
||||
volumeMounts:
|
||||
- name: default
|
||||
mountPath: /tmp/x
|
||||
volumes:
|
||||
- name: default
|
||||
secret:
|
||||
name: test-script
|
||||
defaultMode: 0777`
|
||||
//nolint: lll
|
||||
transformedFunction = `apiVersion: airshipit.org/v1alpha1
|
||||
kind: GenericContainerValues
|
||||
object:
|
||||
executables:
|
||||
- name: test
|
||||
cmdline: /tmp/x/script.sh
|
||||
env:
|
||||
- name: var
|
||||
value: testval
|
||||
volumeMounts:
|
||||
- name: default
|
||||
mountPath: /tmp/x
|
||||
volumes:
|
||||
- name: default
|
||||
secret:
|
||||
name: test-script
|
||||
defaultMode: 0777
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: "container:\n image: quay.io/test/image:v0.0.1\n
|
||||
\ network: {}\nexec: {}\nstarlark: {}\n"
|
||||
`
|
||||
singleExecutorBundlePath = "testdata/single"
|
||||
firstDocInput = `---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: test-script
|
||||
stringData:
|
||||
script.sh: |
|
||||
#!/bin/sh
|
||||
echo WORKS! $var >&2
|
||||
type: Opaque`
|
||||
manyExecutorBundlePath = "testdata/many"
|
||||
secondDocInput = `---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
airshipit.org/ephemeral-node: "true"
|
||||
name: master-0-bmc-secret
|
||||
type: Opaque
|
||||
`
|
||||
yamlSeparator = "---\n"
|
||||
)
|
||||
|
||||
func TestRegisterExecutor(t *testing.T) {
|
||||
registry := make(map[schema.GroupVersionKind]ifc.ExecutorFactory)
|
||||
expectedGVK := schema.GroupVersionKind{
|
||||
Group: "airshipit.org",
|
||||
Version: "v1alpha1",
|
||||
Kind: "GenericContainer",
|
||||
}
|
||||
err := container.RegisterExecutor(registry)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, found := registry[expectedGVK]
|
||||
assert.True(t, found)
|
||||
}
|
||||
|
||||
func TestNewExecutor(t *testing.T) {
|
||||
execDoc, err := document.NewDocumentFromBytes([]byte(executorDoc))
|
||||
require.NoError(t, err)
|
||||
_, err = container.NewExecutor(ifc.ExecutorConfig{
|
||||
ExecutorDocument: execDoc,
|
||||
BundleFactory: testBundleFactory(singleExecutorBundlePath),
|
||||
Helper: makeDefaultHelper(t),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSetInputSingleDocument(t *testing.T) {
|
||||
bundle, err := document.NewBundleByPath(singleExecutorBundlePath)
|
||||
require.NoError(t, err)
|
||||
execDoc, err := document.NewDocumentFromBytes([]byte(executorDoc))
|
||||
require.NoError(t, err)
|
||||
e := &container.Executor{
|
||||
ExecutorBundle: bundle,
|
||||
ExecutorDocument: execDoc,
|
||||
|
||||
ContConf: &v1alpha1.GenericContainer{
|
||||
Spec: runtimeutil.FunctionSpec{},
|
||||
},
|
||||
RunFns: runfn.RunFns{
|
||||
Functions: []*kyaml.RNode{},
|
||||
},
|
||||
}
|
||||
ch := make(chan events.Event)
|
||||
e.SetInput(ch)
|
||||
assert.Empty(t, ch)
|
||||
|
||||
// need to use kustomize here, because
|
||||
// it changes order of lines in document
|
||||
doc, err := document.NewDocumentFromBytes([]byte(firstDocInput))
|
||||
require.NoError(t, err)
|
||||
docBytes, err := doc.AsYAML()
|
||||
require.NoError(t, err)
|
||||
docBytes = append([]byte(yamlSeparator), docBytes...)
|
||||
|
||||
assert.Equal(t, bytes.NewReader(docBytes), e.RunFns.Input)
|
||||
}
|
||||
|
||||
func TestSetInputManyDocuments(t *testing.T) {
|
||||
bundle, err := document.NewBundleByPath(manyExecutorBundlePath)
|
||||
require.NoError(t, err)
|
||||
execDoc, err := document.NewDocumentFromBytes([]byte(executorDoc))
|
||||
require.NoError(t, err)
|
||||
e := &container.Executor{
|
||||
ExecutorBundle: bundle,
|
||||
ExecutorDocument: execDoc,
|
||||
|
||||
ContConf: &v1alpha1.GenericContainer{
|
||||
Spec: runtimeutil.FunctionSpec{},
|
||||
},
|
||||
RunFns: runfn.RunFns{
|
||||
Functions: []*kyaml.RNode{},
|
||||
},
|
||||
}
|
||||
ch := make(chan events.Event)
|
||||
e.SetInput(ch)
|
||||
assert.Empty(t, ch)
|
||||
|
||||
// need to use kustomize here, because
|
||||
// it changes order of lines in document
|
||||
docSecond, err := document.NewDocumentFromBytes([]byte(secondDocInput))
|
||||
require.NoError(t, err)
|
||||
docSecondBytes, err := docSecond.AsYAML()
|
||||
require.NoError(t, err)
|
||||
docBytes := append([]byte(yamlSeparator), docSecondBytes...)
|
||||
|
||||
docFirst, err := document.NewDocumentFromBytes([]byte(firstDocInput))
|
||||
require.NoError(t, err)
|
||||
docFirstBytes, err := docFirst.AsYAML()
|
||||
require.NoError(t, err)
|
||||
docBytes = append(docBytes, []byte(yamlSeparator)...)
|
||||
docBytes = append(docBytes, docFirstBytes...)
|
||||
|
||||
assert.Equal(t, bytes.NewReader(docBytes), e.RunFns.Input)
|
||||
}
|
||||
|
||||
func TestPrepareFunctions(t *testing.T) {
|
||||
bundle, err := document.NewBundleByPath(singleExecutorBundlePath)
|
||||
require.NoError(t, err)
|
||||
execDoc, err := document.NewDocumentFromBytes([]byte(executorDoc))
|
||||
require.NoError(t, err)
|
||||
contConf := &v1alpha1.GenericContainer{
|
||||
Spec: runtimeutil.FunctionSpec{},
|
||||
}
|
||||
err = execDoc.ToAPIObject(contConf, v1alpha1.Scheme)
|
||||
require.NoError(t, err)
|
||||
e := &container.Executor{
|
||||
ExecutorBundle: bundle,
|
||||
ExecutorDocument: execDoc,
|
||||
|
||||
ContConf: contConf,
|
||||
RunFns: runfn.RunFns{
|
||||
Functions: []*kyaml.RNode{},
|
||||
},
|
||||
}
|
||||
|
||||
ch := make(chan events.Event)
|
||||
e.PrepareFunctions(ch)
|
||||
assert.Empty(t, ch)
|
||||
strFuncs, err := e.RunFns.Functions[0].String()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, transformedFunction, strFuncs)
|
||||
}
|
||||
|
||||
func testBundleFactory(path string) document.BundleFactoryFunc {
|
||||
return func() (document.Bundle, error) {
|
||||
return document.NewBundleByPath(path)
|
||||
}
|
||||
}
|
||||
|
||||
func makeDefaultHelper(t *testing.T) ifc.Helper {
|
||||
t.Helper()
|
||||
cfg := config.NewConfig()
|
||||
cfg.Manifests[config.AirshipDefaultManifest].TargetPath = "./testdata"
|
||||
cfg.Manifests[config.AirshipDefaultManifest].MetadataPath = "metadata.yaml"
|
||||
cfg.Manifests[config.AirshipDefaultManifest].Repositories[config.DefaultTestPhaseRepo].URLString = ""
|
||||
cfg.SetLoadedConfigPath(".")
|
||||
helper, err := phase.NewHelper(cfg)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, helper)
|
||||
return helper
|
||||
}
|
2
pkg/container/testdata/many/kustomization.yaml
vendored
Normal file
2
pkg/container/testdata/many/kustomization.yaml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
resources:
|
||||
- secret.yaml
|
18
pkg/container/testdata/many/secret.yaml
vendored
Normal file
18
pkg/container/testdata/many/secret.yaml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: test-script
|
||||
stringData:
|
||||
script.sh: |
|
||||
#!/bin/sh
|
||||
echo WORKS! $var >&2
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
airshipit.org/ephemeral-node: "true"
|
||||
name: master-0-bmc-secret
|
||||
type: Opaque
|
0
pkg/container/testdata/metadata.yaml
vendored
Normal file
0
pkg/container/testdata/metadata.yaml
vendored
Normal file
2
pkg/container/testdata/single/kustomization.yaml
vendored
Normal file
2
pkg/container/testdata/single/kustomization.yaml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
resources:
|
||||
- secret.yaml
|
9
pkg/container/testdata/single/secret.yaml
vendored
Normal file
9
pkg/container/testdata/single/secret.yaml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: test-script
|
||||
type: Opaque
|
||||
stringData:
|
||||
script.sh: |
|
||||
#!/bin/sh
|
||||
echo WORKS! $var >&2
|
@ -39,18 +39,21 @@ const (
|
||||
IsogenType
|
||||
// BootstrapType event emitted by Bootstrap executor
|
||||
BootstrapType
|
||||
//GenericContainerType event emitted by GenericContainer
|
||||
GenericContainerType
|
||||
)
|
||||
|
||||
// Event holds all possible events that can be produced by airship
|
||||
type Event struct {
|
||||
Type Type
|
||||
Timestamp time.Time
|
||||
ApplierEvent applyevent.Event
|
||||
ErrorEvent ErrorEvent
|
||||
StatusPollerEvent statuspollerevent.Event
|
||||
ClusterctlEvent ClusterctlEvent
|
||||
IsogenEvent IsogenEvent
|
||||
BootstrapEvent BootstrapEvent
|
||||
Type Type
|
||||
Timestamp time.Time
|
||||
ApplierEvent applyevent.Event
|
||||
ErrorEvent ErrorEvent
|
||||
StatusPollerEvent statuspollerevent.Event
|
||||
ClusterctlEvent ClusterctlEvent
|
||||
IsogenEvent IsogenEvent
|
||||
BootstrapEvent BootstrapEvent
|
||||
GenericContainerEvent GenericContainerEvent
|
||||
}
|
||||
|
||||
// NewEvent create new event with timestamp
|
||||
@ -152,3 +155,26 @@ func (e Event) WithBootstrapEvent(concreteEvent BootstrapEvent) Event {
|
||||
e.BootstrapEvent = concreteEvent
|
||||
return e
|
||||
}
|
||||
|
||||
// GenericContainerOperation type
|
||||
type GenericContainerOperation int
|
||||
|
||||
const (
|
||||
// GenericContainerStart operation
|
||||
GenericContainerStart GenericContainerOperation = iota
|
||||
// GenericContainerStop operation
|
||||
GenericContainerStop
|
||||
)
|
||||
|
||||
// GenericContainerEvent needs to to track events in GenericContainer executor
|
||||
type GenericContainerEvent struct {
|
||||
Operation GenericContainerOperation
|
||||
Message string
|
||||
}
|
||||
|
||||
// WithGenericContainerEvent sets type and actual GenericContainer event
|
||||
func (e Event) WithGenericContainerEvent(concreteEvent GenericContainerEvent) Event {
|
||||
e.Type = GenericContainerType
|
||||
e.GenericContainerEvent = concreteEvent
|
||||
return e
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func (p *DefaultProcessor) Process(ch <-chan Event) error {
|
||||
case ErrorType:
|
||||
log.Printf("Received error on event channel %v", e.ErrorEvent)
|
||||
p.errors = append(p.errors, e.ErrorEvent.Error)
|
||||
case ClusterctlType, IsogenType:
|
||||
case ClusterctlType, IsogenType, GenericContainerType:
|
||||
// TODO each event needs to be interface that allows us to print it for example
|
||||
// Stringer interface or AsYAML for further processing.
|
||||
// For now we print the event object as is
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/bootstrap/isogen"
|
||||
clusterctl "opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||
"opendev.org/airship/airshipctl/pkg/container"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/pkg/events"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/applier"
|
||||
@ -48,6 +49,9 @@ func DefaultExecutorRegistry() map[schema.GroupVersionKind]ifc.ExecutorFactory {
|
||||
if err := isogen.RegisterExecutor(execMap); err != nil {
|
||||
log.Fatal(ErrExecutorRegistration{ExecutorName: "isogen", Err: err})
|
||||
}
|
||||
if err := container.RegisterExecutor(execMap); err != nil {
|
||||
log.Fatal(ErrExecutorRegistration{ExecutorName: "generic-container", Err: err})
|
||||
}
|
||||
return execMap
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user