Merge "Remove isogen executor and related code"

This commit is contained in:
Zuul 2021-03-09 19:21:45 +00:00 committed by Gerrit Code Review
commit ecb2a042dd
20 changed files with 11 additions and 912 deletions

View File

@ -1,20 +0,0 @@
apiVersion: airshipit.org/v1alpha1
kind: IsoConfiguration
metadata:
name: isogen
labels:
airshipit.org/deploy-k8s: "false"
builder:
userDataSelector:
kind: Secret
labelSelector: airshipit.org/ephemeral-user-data
userDataKey: userData
networkConfigSelector:
kind: BareMetalHost
labelSelector: airshipit.org/ephemeral-node
networkConfigKey: networkData
outputFileName: ephemeral.iso
container:
containerRuntime: docker
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
volume: /srv/images:/config

View File

@ -1,4 +1,3 @@
resources: resources:
- secret.yaml - secret.yaml
- image_configuration.yaml
- remote_direct_configuration.yaml - remote_direct_configuration.yaml

View File

@ -36,19 +36,6 @@ move-options: {}
action: move action: move
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: IsoConfiguration
metadata:
name: isogen
labels:
airshipit.org/deploy-k8s: "false"
builder:
outputFileName: ephemeral.iso
container:
containerRuntime: docker
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
volume: /srv/images:/config
---
apiVersion: airshipit.org/v1alpha1
kind: GenericContainer kind: GenericContainer
metadata: metadata:
name: encrypter name: encrypter
@ -195,7 +182,7 @@ spec:
image: quay.io/airshipit/cloud-init:latest image: quay.io/airshipit/cloud-init:latest
mounts: mounts:
- type: bind - type: bind
src: /srv/iso src: /srv/images
dst: /config dst: /config
rw: true rw: true
config: | config: |
@ -214,7 +201,7 @@ config: |
networkConfigKey: networkData networkConfigKey: networkData
outputFileName: ephemeral.iso outputFileName: ephemeral.iso
container: container:
volume: /fake/path/iso:/config # for compatibility with image-builder volume: /srv/images:/config # for compatibility with image-builder
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
@ -235,7 +222,7 @@ spec:
image: quay.io/airshipit/image-builder:latest-ubuntu_focal image: quay.io/airshipit/image-builder:latest-ubuntu_focal
mounts: mounts:
- type: bind - type: bind
src: /srv/iso src: /srv/images
dst: /config dst: /config
rw: true rw: true
envVars: envVars:

View File

@ -1,16 +1,5 @@
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: Phase kind: Phase
metadata:
name: bootstrap-iso
config:
executorRef:
apiVersion: airshipit.org/v1alpha1
kind: IsoConfiguration
name: isogen
documentEntryPoint: ephemeral/bootstrap
---
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata: metadata:
name: initinfra-ephemeral name: initinfra-ephemeral
clusterName: ephemeral-cluster clusterName: ephemeral-cluster

View File

@ -1,170 +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 isogen
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/bootstrap/cloudinit"
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/container"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/log"
"opendev.org/airship/airshipctl/pkg/util"
)
const (
builderConfigFileName = "builder-conf.yaml"
outputFileNameDefault = "ephemerial.iso"
userDataFileName = "user-data"
networkConfigFileName = "network-data"
outputMetadataFileName = "output-metadata.yaml"
)
// BootstrapIsoOptions are used to generate bootstrap ISO
type BootstrapIsoOptions struct {
DocBundle document.Bundle
Builder container.Container
Doc document.Document
Cfg *v1alpha1.IsoConfiguration
// optional fields for verbose output
Writer io.Writer
}
// VerifyInputs verifies image configuration
func VerifyInputs(cfg *v1alpha1.IsoConfiguration) error {
if cfg.IsoContainer.Volume == "" {
return config.ErrMissingConfig{
What: "Must specify volume bind for ISO builder container",
}
}
vols := strings.Split(cfg.IsoContainer.Volume, ":")
switch {
case len(vols) == 1:
cfg.IsoContainer.Volume = fmt.Sprintf("%s:%s", vols[0], vols[0])
case len(vols) > 2:
return config.ErrInvalidConfig{
What: "Bad container volume format. Use hostPath:contPath",
}
}
if cfg.Isogen.OutputFileName == "" {
log.Debugf("No outputFileName provided to Isogen. Using default: %s", outputFileNameDefault)
cfg.Isogen.OutputFileName = outputFileNameDefault
}
return nil
}
func getIsoContainerCfg(
cfg *v1alpha1.IsoConfiguration,
builderCfgYaml []byte,
userData []byte,
netConf []byte,
) map[string][]byte {
hostVol := strings.Split(cfg.IsoContainer.Volume, ":")[0]
fls := make(map[string][]byte)
fls[filepath.Join(hostVol, userDataFileName)] = userData
fls[filepath.Join(hostVol, networkConfigFileName)] = netConf
fls[filepath.Join(hostVol, builderConfigFileName)] = builderCfgYaml
return fls
}
// CreateBootstrapIso prepares and runs appropriate container to create a bootstrap ISO
func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
cntVol := strings.Split(opts.Cfg.IsoContainer.Volume, ":")[1]
log.Print("Creating cloud-init for ephemeral K8s")
userData, netConf, err := cloudinit.GetCloudData(
opts.DocBundle,
opts.Cfg.Isogen.UserDataSelector,
opts.Cfg.Isogen.UserDataKey,
opts.Cfg.Isogen.NetworkConfigSelector,
opts.Cfg.Isogen.NetworkConfigKey,
)
if err != nil {
return err
}
builderCfgYaml, err := opts.Doc.AsYAML()
if err != nil {
return err
}
fls := getIsoContainerCfg(opts.Cfg, builderCfgYaml, userData, netConf)
if err = util.WriteFiles(fls, 0600); err != nil {
return err
}
vols := []string{opts.Cfg.IsoContainer.Volume}
builderCfgLocation := filepath.Join(cntVol, builderConfigFileName)
log.Printf("Running default container command. Mounted dir: %s", vols)
envVars := []string{
fmt.Sprintf("IMAGE_TYPE=iso"),
fmt.Sprintf("BUILDER_CONFIG=%s", builderCfgLocation),
fmt.Sprintf("USER_DATA_FILE=%s", userDataFileName),
fmt.Sprintf("NET_CONFIG_FILE=%s", networkConfigFileName),
fmt.Sprintf("OUTPUT_FILE_NAME=%s", opts.Cfg.Isogen.OutputFileName),
fmt.Sprintf("OUTPUT_METADATA_FILE_NAME=%s", outputMetadataFileName),
fmt.Sprintf("http_proxy=%s", os.Getenv("http_proxy")),
fmt.Sprintf("https_proxy=%s", os.Getenv("https_proxy")),
fmt.Sprintf("HTTP_PROXY=%s", os.Getenv("HTTP_PROXY")),
fmt.Sprintf("HTTPS_PROXY=%s", os.Getenv("HTTPS_PROXY")),
fmt.Sprintf("no_proxy=%s", os.Getenv("no_proxy")),
fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY")),
}
err = opts.Builder.RunCommand(container.RunCommandOptions{EnvVars: envVars, Binds: vols})
if err != nil {
return err
}
log.Print("ISO generation is in progress. The whole process could take up to several minutes, please wait...")
if log.DebugEnabled() {
var cLogs io.ReadCloser
cLogs, err = opts.Builder.GetContainerLogs(container.GetLogOptions{Stderr: true, Follow: true})
if err != nil {
log.Printf("failed to read container logs %s", err)
} else {
log.Print("start reading container logs")
if _, err = io.Copy(opts.Writer, cLogs); err != nil {
log.Debugf("failed to write container logs to log output %s", err)
}
log.Print("got EOF from container logs")
}
}
if err = opts.Builder.WaitUntilFinished(); err != nil {
return err
}
log.Print("ISO successfully built.")
if !log.DebugEnabled() {
log.Print("Removing container.")
return opts.Builder.RmContainer()
}
log.Debugf("Debug flag is set. Container %s stopped but not deleted.", opts.Builder.GetID())
return nil
}

View File

@ -1,218 +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 isogen_test
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
api "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/bootstrap/isogen"
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/log"
"opendev.org/airship/airshipctl/testutil"
testcontainer "opendev.org/airship/airshipctl/testutil/container"
testdoc "opendev.org/airship/airshipctl/testutil/document"
)
const testID = "TESTID"
func TestBootstrapIso(t *testing.T) {
bundle, err := document.NewBundleByPath("testdata/primary/site/test-site/ephemeral/bootstrap")
require.NoError(t, err, "Building Bundle Failed")
tempVol, cleanup := testutil.TempDir(t, "bootstrap-test")
defer cleanup(t)
volBind := tempVol + ":/dst"
testErr := fmt.Errorf("TestErr")
testCfg := &api.IsoConfiguration{
IsoContainer: &api.IsoContainer{
Volume: volBind,
ContainerRuntime: "docker",
},
Isogen: &api.Isogen{
OutputFileName: "ephemeral.iso",
},
}
testDoc := &testdoc.MockDocument{
MockAsYAML: func() ([]byte, error) { return []byte("TESTDOC"), nil },
}
testIsogen := &testcontainer.MockContainer{
MockRunCommand: func() error { return nil },
MockGetID: func() string { return testID },
MockRmContainer: func() error { return nil },
}
expOut := []string{
"Creating cloud-init for ephemeral K8s",
fmt.Sprintf("Running default container command. Mounted dir: [%s]", volBind),
"ISO successfully built.",
"Debug flag is set. Container TESTID stopped but not deleted.",
"Removing container.",
}
tests := []struct {
builder *testcontainer.MockContainer
cfg *api.IsoConfiguration
doc *testdoc.MockDocument
debug bool
expectedOut []string
expectedErr error
}{
{
builder: &testcontainer.MockContainer{
MockRunCommand: func() error { return testErr },
MockWaitUntilFinished: func() error { return nil },
MockRmContainer: func() error { return nil },
},
cfg: testCfg,
doc: testDoc,
debug: false,
expectedOut: []string{expOut[0], expOut[1]},
expectedErr: testErr,
},
{
builder: &testcontainer.MockContainer{
MockRunCommand: func() error { return nil },
MockGetID: func() string { return "TESTID" },
MockWaitUntilFinished: func() error { return nil },
MockRmContainer: func() error { return nil },
MockGetContainerLogs: func() (io.ReadCloser, error) { return ioutil.NopCloser(strings.NewReader("")), nil },
},
cfg: testCfg,
doc: testDoc,
debug: true,
expectedOut: []string{expOut[0], expOut[1], expOut[2], expOut[3]},
expectedErr: nil,
},
{
builder: &testcontainer.MockContainer{
MockRunCommand: func() error { return nil },
MockGetID: func() string { return "TESTID" },
MockRmContainer: func() error { return testErr },
MockWaitUntilFinished: func() error { return nil },
},
cfg: testCfg,
doc: testDoc,
debug: false,
expectedOut: []string{expOut[0], expOut[1], expOut[2], expOut[4]},
expectedErr: testErr,
},
{
builder: testIsogen,
cfg: testCfg,
doc: &testdoc.MockDocument{
MockAsYAML: func() ([]byte, error) { return nil, testErr },
},
debug: false,
expectedOut: []string{expOut[0]},
expectedErr: testErr,
},
}
for _, tt := range tests {
outBuf := &bytes.Buffer{}
log.Init(tt.debug, outBuf)
bootstrapOpts := isogen.BootstrapIsoOptions{
DocBundle: bundle,
Builder: tt.builder,
Doc: tt.doc,
Cfg: tt.cfg,
}
actualErr := bootstrapOpts.CreateBootstrapIso()
actualOut := outBuf.String()
for _, line := range tt.expectedOut {
assert.True(t, strings.Contains(actualOut, line))
}
assert.Equal(t, tt.expectedErr, actualErr)
}
}
func TestVerifyInputs(t *testing.T) {
tempVol, cleanup := testutil.TempDir(t, "bootstrap-test")
defer cleanup(t)
tests := []struct {
name string
cfg *api.IsoConfiguration
args []string
expectedErr error
}{
{
name: "missing-container-field",
cfg: &api.IsoConfiguration{
IsoContainer: &api.IsoContainer{},
},
expectedErr: config.ErrMissingConfig{
What: "Must specify volume bind for ISO builder container",
},
},
{
name: "invalid-host-path",
cfg: &api.IsoConfiguration{
IsoContainer: &api.IsoContainer{
Volume: tempVol + ":/dst:/dst1",
},
Isogen: &api.Isogen{
OutputFileName: "ephemeral.iso",
},
},
expectedErr: config.ErrInvalidConfig{
What: "Bad container volume format. Use hostPath:contPath",
},
},
{
name: "success",
cfg: &api.IsoConfiguration{
IsoContainer: &api.IsoContainer{
Volume: tempVol,
},
Isogen: &api.Isogen{
OutputFileName: "ephemeral.iso",
},
},
expectedErr: nil,
},
{
name: "success-using-output-file-default-",
cfg: &api.IsoConfiguration{
IsoContainer: &api.IsoContainer{
Volume: tempVol,
},
Isogen: &api.Isogen{},
},
expectedErr: nil,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(subTest *testing.T) {
actualErr := isogen.VerifyInputs(tt.cfg)
assert.Equal(subTest, tt.expectedErr, actualErr)
})
}
}

View File

@ -1,23 +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 isogen
// ErrNoParsedNumPkgs is returned when it's unable to find number of packages to install
type ErrNoParsedNumPkgs struct {
}
func (e ErrNoParsedNumPkgs) Error() string {
return "No number of packages to install found in parsed container logs"
}

View File

@ -1,2 +0,0 @@
resources:
- secret.yaml

View File

@ -1,66 +0,0 @@
# in this document set, we have an ephemeral node with
# the right label, resolvable/valid network data and
# a user-data secret with the right label
#
# we also introduce a second baremetal host that is not
# labeled as the ephemeral node to facilitate testing
apiVersion: v1
kind: Secret
metadata:
labels:
test: validdocset
name: master-1-bmc
type: Opaque
stringData:
username: foobar
password: goober
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/ephemeral-user-data: 'true'
test: validdocset
name: airship-isogen-userdata
type: Opaque
stringData:
userData: cloud-init
---
apiVersion: v1
kind: Secret
metadata:
labels:
test: validdocset
name: master-1-networkdata
namespace: metal3
type: Opaque
stringData:
networkData: net-config
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
test: validdocset
name: master-2
bmc:
address: ipmi://127.0.0.1
credentialsName: master-2-bmc
networkData:
name: master-2-networkdata
namespace: metal3
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/ephemeral-node: 'true'
test: validdocset
name: master-1
spec:
bmc:
address: ipmi://127.0.0.1
credentialsName: master-1-bmc
networkData:
name: master-1-networkdata
namespace: metal3

View File

@ -36,8 +36,6 @@ const (
WaitType WaitType
// ClusterctlType event emitted by Clusterctl executor // ClusterctlType event emitted by Clusterctl executor
ClusterctlType ClusterctlType
// IsogenType event emitted by Isogen executor
IsogenType
// BootstrapType event emitted by Bootstrap executor // BootstrapType event emitted by Bootstrap executor
BootstrapType BootstrapType
// GenericContainerType event emitted by GenericContainer // GenericContainerType event emitted by GenericContainer
@ -54,7 +52,6 @@ type Event struct {
ErrorEvent ErrorEvent ErrorEvent ErrorEvent
StatusPollerEvent statuspollerevent.Event StatusPollerEvent statuspollerevent.Event
ClusterctlEvent ClusterctlEvent ClusterctlEvent ClusterctlEvent
IsogenEvent IsogenEvent
BootstrapEvent BootstrapEvent BootstrapEvent BootstrapEvent
GenericContainerEvent GenericContainerEvent GenericContainerEvent GenericContainerEvent
BaremetalManagerEvent BaremetalManagerEvent BaremetalManagerEvent BaremetalManagerEvent
@ -70,7 +67,6 @@ type GenericEvent struct {
var mapTypeToEvent = map[Type]string{ var mapTypeToEvent = map[Type]string{
ClusterctlType: "ClusterctlEvent", ClusterctlType: "ClusterctlEvent",
IsogenType: "IsogenEvent",
BootstrapType: "BootstrapEvent", BootstrapType: "BootstrapEvent",
GenericContainerType: "GenericContainerEvent", GenericContainerType: "GenericContainerEvent",
} }
@ -82,12 +78,6 @@ var unknownEventType = map[Type]string{
WaitType: "WaitType", WaitType: "WaitType",
} }
var isogenOperationToString = map[IsogenOperation]string{
IsogenStart: "IsogenStart",
IsogenValidation: "IsogenValidation",
IsogenEnd: "IsogenEnd",
}
var clusterctlOperationToString = map[ClusterctlOperation]string{ var clusterctlOperationToString = map[ClusterctlOperation]string{
ClusterctlInitStart: "ClusterctlInitStart", ClusterctlInitStart: "ClusterctlInitStart",
ClusterctlInitEnd: "ClusterctlInitEnd", ClusterctlInitEnd: "ClusterctlInitEnd",
@ -127,9 +117,6 @@ func Normalize(e Event) GenericEvent {
case ClusterctlType: case ClusterctlType:
operation = clusterctlOperationToString[e.ClusterctlEvent.Operation] operation = clusterctlOperationToString[e.ClusterctlEvent.Operation]
message = e.ClusterctlEvent.Message message = e.ClusterctlEvent.Message
case IsogenType:
operation = isogenOperationToString[e.IsogenEvent.Operation]
message = e.IsogenEvent.Message
case BootstrapType: case BootstrapType:
operation = bootstrapOperationToString[e.BootstrapEvent.Operation] operation = bootstrapOperationToString[e.BootstrapEvent.Operation]
message = e.BootstrapEvent.Message message = e.BootstrapEvent.Message
@ -195,31 +182,6 @@ func (e Event) WithClusterctlEvent(concreteEvent ClusterctlEvent) Event {
return e return e
} }
// IsogenOperation type
type IsogenOperation int
const (
// IsogenStart operation
IsogenStart IsogenOperation = iota
// IsogenValidation operation
IsogenValidation
// IsogenEnd operation
IsogenEnd
)
// IsogenEvent needs to to track events in isogen executor
type IsogenEvent struct {
Operation IsogenOperation
Message string
}
// WithIsogenEvent sets type and actual isogen event
func (e Event) WithIsogenEvent(concreteEvent IsogenEvent) Event {
e.Type = IsogenType
e.IsogenEvent = concreteEvent
return e
}
// BootstrapOperation type // BootstrapOperation type
type BootstrapOperation int type BootstrapOperation int

View File

@ -54,9 +54,9 @@ func TestPrintEvent(t *testing.T) {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
p := events.NewGenericPrinter(tt.writer, tt.formatterType) p := events.NewGenericPrinter(tt.writer, tt.formatterType)
e := events.NewEvent().WithIsogenEvent(events.IsogenEvent{ e := events.NewEvent().WithGenericContainerEvent(events.GenericContainerEvent{
Operation: events.IsogenStart, Operation: events.GenericContainerStart,
Message: "starting ISO generation", Message: "starting generic container generation",
}) })
ge := events.Normalize(e) ge := events.Normalize(e)
err := p.PrintEvent(ge) err := p.PrintEvent(ge)

View File

@ -40,7 +40,7 @@ func DefaultExecutorRegistry() map[schema.GroupVersionKind]ifc.ExecutorFactory {
execMap := make(map[schema.GroupVersionKind]ifc.ExecutorFactory) execMap := make(map[schema.GroupVersionKind]ifc.ExecutorFactory)
for _, execName := range []string{executors.Clusterctl, executors.KubernetesApply, for _, execName := range []string{executors.Clusterctl, executors.KubernetesApply,
executors.Isogen, executors.GenericContainer, executors.Ephemeral, executors.BMHManager} { executors.GenericContainer, executors.Ephemeral, executors.BMHManager} {
if err := executors.RegisterExecutor(execName, execMap); err != nil { if err := executors.RegisterExecutor(execName, execMap); err != nil {
log.Fatal(ErrExecutorRegistration{ExecutorName: execName, Err: err}) log.Fatal(ErrExecutorRegistration{ExecutorName: execName, Err: err})
} }

View File

@ -26,7 +26,6 @@ import (
const ( const (
Clusterctl = "clusterctl" Clusterctl = "clusterctl"
KubernetesApply = "kubernetes-apply" KubernetesApply = "kubernetes-apply"
Isogen = "isogen"
GenericContainer = "generic-container" GenericContainer = "generic-container"
Ephemeral = "ephemeral" Ephemeral = "ephemeral"
BMHManager = "BaremetalManager" BMHManager = "BaremetalManager"
@ -45,9 +44,6 @@ func RegisterExecutor(executorName string, registry map[schema.GroupVersionKind]
case KubernetesApply: case KubernetesApply:
gvks, _, err = airshipv1.Scheme.ObjectKinds(&airshipv1.KubernetesApply{}) gvks, _, err = airshipv1.Scheme.ObjectKinds(&airshipv1.KubernetesApply{})
execObj = NewKubeApplierExecutor execObj = NewKubeApplierExecutor
case Isogen:
gvks, _, err = airshipv1.Scheme.ObjectKinds(airshipv1.DefaultIsoConfiguration())
execObj = NewIsogenExecutor
case GenericContainer: case GenericContainer:
gvks, _, err = airshipv1.Scheme.ObjectKinds(airshipv1.DefaultGenericContainer()) gvks, _, err = airshipv1.Scheme.ObjectKinds(airshipv1.DefaultGenericContainer())
execObj = NewContainerExecutor execObj = NewContainerExecutor

View File

@ -61,16 +61,6 @@ func TestRegisterExecutor(t *testing.T) {
Kind: "GenericContainer", Kind: "GenericContainer",
}, },
}, },
{
name: "register isogen executor",
executorName: executors.Isogen,
registry: make(map[schema.GroupVersionKind]ifc.ExecutorFactory),
expectedGVK: schema.GroupVersionKind{
Group: "airshipit.org",
Version: "v1alpha1",
Kind: "IsoConfiguration",
},
},
{ {
name: "register k8s applier executor", name: "register k8s applier executor",
executorName: executors.KubernetesApply, executorName: executors.KubernetesApply,

View File

@ -30,14 +30,6 @@ func (e ErrUnknownExecutorAction) Error() string {
e.Action, e.ExecutorName) e.Action, e.ExecutorName)
} }
// ErrIsogenNilBundle is returned when isogen executor is not provided with bundle
type ErrIsogenNilBundle struct {
}
func (e ErrIsogenNilBundle) Error() string {
return "Cannot build iso with empty bundle, no data source is available"
}
// ErrUnknownExecutorName is returned for unknown executor name parameter // ErrUnknownExecutorName is returned for unknown executor name parameter
// received by RegisterExecutor function // received by RegisterExecutor function
type ErrUnknownExecutorName struct { type ErrUnknownExecutorName struct {

View File

@ -1,150 +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 executors
import (
"context"
"io"
"os"
"path/filepath"
"strings"
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/bootstrap/isogen"
"opendev.org/airship/airshipctl/pkg/container"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/errors"
"opendev.org/airship/airshipctl/pkg/events"
"opendev.org/airship/airshipctl/pkg/log"
"opendev.org/airship/airshipctl/pkg/phase/ifc"
)
var _ ifc.Executor = &IsogenExecutor{}
// IsogenExecutor contains resources for isogen executor
type IsogenExecutor struct {
ExecutorBundle document.Bundle
ExecutorDocument document.Document
ImgConf *v1alpha1.IsoConfiguration
Builder container.Container
}
// NewIsogenExecutor creates instance of phase executor
func NewIsogenExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) {
apiObj := &v1alpha1.IsoConfiguration{
IsoContainer: &v1alpha1.IsoContainer{},
Isogen: &v1alpha1.Isogen{},
}
err := cfg.ExecutorDocument.ToAPIObject(apiObj, v1alpha1.Scheme)
if err != nil {
return nil, err
}
bundle, err := cfg.BundleFactory()
if err != nil {
return nil, err
}
return &IsogenExecutor{
ExecutorBundle: bundle,
ExecutorDocument: cfg.ExecutorDocument,
ImgConf: apiObj,
}, nil
}
// Run isogen as a phase runner
func (c *IsogenExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
defer close(evtCh)
if c.ExecutorBundle == nil {
handleError(evtCh, ErrIsogenNilBundle{})
return
}
evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenStart,
Message: "starting ISO generation",
})
if opts.DryRun {
log.Print("command isogen will be executed")
evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenEnd,
})
return
}
if c.Builder == nil {
ctx := context.Background()
builder, err := container.NewContainer(
ctx,
c.ImgConf.IsoContainer.ContainerRuntime,
c.ImgConf.IsoContainer.Image)
c.Builder = builder
if err != nil {
handleError(evtCh, err)
return
}
}
bootstrapOpts := isogen.BootstrapIsoOptions{
DocBundle: c.ExecutorBundle,
Builder: c.Builder,
Doc: c.ExecutorDocument,
Cfg: c.ImgConf,
Writer: log.Writer(),
}
err := bootstrapOpts.CreateBootstrapIso()
if err != nil {
handleError(evtCh, err)
return
}
evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenValidation,
Message: "image is generated successfully, verifying artifacts",
})
err = verifyArtifacts(c.ImgConf)
if err != nil {
handleError(evtCh, err)
return
}
evtCh <- events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenEnd,
Message: "iso generation is complete and artifacts verified",
})
}
func verifyArtifacts(cfg *v1alpha1.IsoConfiguration) error {
hostVol := strings.Split(cfg.IsoContainer.Volume, ":")[0]
outputFilePath := filepath.Join(hostVol, cfg.Isogen.OutputFileName)
_, err := os.Stat(outputFilePath)
return err
}
// Validate executor configuration and documents
func (c *IsogenExecutor) Validate() error {
return errors.ErrNotImplemented{}
}
// Render executor documents
func (c *IsogenExecutor) Render(w io.Writer, _ ifc.RenderOptions) error {
// will be implemented later
_, err := w.Write([]byte{})
return err
}

View File

@ -1,163 +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 executors_test
import (
"log"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/container"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/events"
"opendev.org/airship/airshipctl/pkg/phase/executors"
"opendev.org/airship/airshipctl/pkg/phase/ifc"
"opendev.org/airship/airshipctl/testutil"
testcontainer "opendev.org/airship/airshipctl/testutil/container"
testdoc "opendev.org/airship/airshipctl/testutil/document"
)
var (
isogenExecutorDoc = `
apiVersion: airshipit.org/v1alpha1
kind: IsoConfiguration
metadata:
name: isogen
labels:
airshipit.org/deploy-k8s: "false"
builder:
outputFileName: ephemeral.iso
container:
containerRuntime: docker
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
volume: /srv/images:/config`
executorBundlePath = "../../bootstrap/isogen/testdata/primary/site/test-site/ephemeral/bootstrap"
)
func TestNewIsogenExecutor(t *testing.T) {
execDoc, err := document.NewDocumentFromBytes([]byte(isogenExecutorDoc))
require.NoError(t, err)
_, err = executors.NewIsogenExecutor(ifc.ExecutorConfig{
ExecutorDocument: execDoc,
BundleFactory: testBundleFactory(executorBundlePath)})
require.NoError(t, err)
}
func TestIsogenExecutorRun(t *testing.T) {
bundle, err := document.NewBundleByPath(executorBundlePath)
require.NoError(t, err)
require.NotNil(t, bundle)
tempVol, cleanup := testutil.TempDir(t, "bootstrap-test")
defer cleanup(t)
emptyFileName := filepath.Join(tempVol, "ephemeral.iso")
emptyFile, createErr := os.Create(emptyFileName)
require.NoError(t, createErr)
log.Println(emptyFile)
emptyFile.Close()
volBind := tempVol + ":/dst"
testCfg := &v1alpha1.IsoConfiguration{
IsoContainer: &v1alpha1.IsoContainer{
Volume: volBind,
ContainerRuntime: "docker",
},
Isogen: &v1alpha1.Isogen{
OutputFileName: "ephemeral.iso",
},
}
testDoc := &testdoc.MockDocument{
MockAsYAML: func() ([]byte, error) { return []byte("TESTDOC"), nil },
}
testCases := []struct {
name string
builder *testcontainer.MockContainer
expectedEvt []events.Event
}{
{
name: "Run isogen successfully",
builder: &testcontainer.MockContainer{
MockRunCommand: func() error { return nil },
MockGetID: func() string { return "TESTID" },
MockRmContainer: func() error { return nil },
MockWaitUntilFinished: func() error { return nil },
},
expectedEvt: []events.Event{
events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenStart,
}),
events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenValidation,
}),
events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenEnd,
}),
},
},
{
name: "Fail on container command",
builder: &testcontainer.MockContainer{
MockRunCommand: func() error {
return container.ErrRunContainerCommand{Cmd: "super fail"}
},
MockGetID: func() string { return "TESTID" },
MockRmContainer: func() error { return nil },
},
expectedEvt: []events.Event{
events.NewEvent().WithIsogenEvent(events.IsogenEvent{
Operation: events.IsogenStart,
}),
wrapError(container.ErrRunContainerCommand{Cmd: "super fail"}),
},
},
}
for _, test := range testCases {
tt := test
t.Run(tt.name, func(t *testing.T) {
executor := &executors.IsogenExecutor{
ExecutorDocument: testDoc,
ExecutorBundle: bundle,
ImgConf: testCfg,
Builder: tt.builder,
}
ch := make(chan events.Event)
go executor.Run(ch, ifc.RunOptions{})
var actualEvt []events.Event
for evt := range ch {
// Skip timestamp for comparison
evt.Timestamp = time.Time{}
if evt.Type == events.IsogenType {
// Set message to empty string, so it's not compared
evt.IsogenEvent.Message = ""
}
actualEvt = append(actualEvt, evt)
}
for i := range tt.expectedEvt {
// Skip timestamp for comparison
tt.expectedEvt[i].Timestamp = time.Time{}
}
assert.Equal(t, tt.expectedEvt, actualEvt)
})
}
}

View File

@ -123,9 +123,6 @@ func TestHelperPlan(t *testing.T) {
Name: testPlanName, Name: testPlanName,
}, },
Phases: []airshipv1.PhaseStep{ Phases: []airshipv1.PhaseStep{
{
Name: "isogen",
},
{ {
Name: "remotedirect", Name: "remotedirect",
}, },

View File

@ -3,7 +3,6 @@ kind: PhasePlan
metadata: metadata:
name: phasePlan name: phasePlan
phases: phases:
- name: isogen
- name: remotedirect - name: remotedirect
- name: initinfra - name: initinfra
- name: some_phase - name: some_phase

View File

@ -20,7 +20,7 @@ IMAGE_DIR=${IMAGE_DIR:-"/srv/images"}
CLEANUP_SERVE_DIR=${CLEANUP_SERVE_DIR:-"false"} CLEANUP_SERVE_DIR=${CLEANUP_SERVE_DIR:-"false"}
SITE_NAME=${SITE_NAME:-test-site} SITE_NAME=${SITE_NAME:-test-site}
# List of phases to run to build images. # List of phases to run to build images.
IMAGE_PHASES=${IMAGE_PHASES:-"bootstrap-iso"} IMAGE_PHASE_PLANS=${IMAGE_PHASE_PLANS:-"iso"}
#Create serving directories and assign permission and ownership #Create serving directories and assign permission and ownership
sudo rm -rf ${IMAGE_DIR} sudo rm -rf ${IMAGE_DIR}
@ -29,9 +29,9 @@ sudo chmod -R 755 ${IMAGE_DIR}
sudo chown -R ${USER_NAME} ${IMAGE_DIR} sudo chown -R ${USER_NAME} ${IMAGE_DIR}
unset IFS unset IFS
for phase in $IMAGE_PHASES; do for plan in $IMAGE_PHASE_PLANS; do
echo "Build phase: $phase" echo "Build phase plan: $plan"
airshipctl phase run $phase --debug airshipctl plan run $plan --debug
done done
echo "List generated images" echo "List generated images"