Merge "Remove isogen executor and related code"
This commit is contained in:
commit
ecb2a042dd
@ -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
|
@ -1,4 +1,3 @@
|
||||
resources:
|
||||
- secret.yaml
|
||||
- image_configuration.yaml
|
||||
- remote_direct_configuration.yaml
|
||||
|
@ -36,19 +36,6 @@ move-options: {}
|
||||
action: move
|
||||
---
|
||||
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
|
||||
metadata:
|
||||
name: encrypter
|
||||
@ -195,7 +182,7 @@ spec:
|
||||
image: quay.io/airshipit/cloud-init:latest
|
||||
mounts:
|
||||
- type: bind
|
||||
src: /srv/iso
|
||||
src: /srv/images
|
||||
dst: /config
|
||||
rw: true
|
||||
config: |
|
||||
@ -214,7 +201,7 @@ config: |
|
||||
networkConfigKey: networkData
|
||||
outputFileName: ephemeral.iso
|
||||
container:
|
||||
volume: /fake/path/iso:/config # for compatibility with image-builder
|
||||
volume: /srv/images:/config # for compatibility with image-builder
|
||||
|
||||
---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
@ -235,7 +222,7 @@ spec:
|
||||
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
|
||||
mounts:
|
||||
- type: bind
|
||||
src: /srv/iso
|
||||
src: /srv/images
|
||||
dst: /config
|
||||
rw: true
|
||||
envVars:
|
||||
|
@ -1,16 +1,5 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
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:
|
||||
name: initinfra-ephemeral
|
||||
clusterName: ephemeral-cluster
|
||||
|
@ -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
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
resources:
|
||||
- secret.yaml
|
@ -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
|
@ -36,8 +36,6 @@ const (
|
||||
WaitType
|
||||
// ClusterctlType event emitted by Clusterctl executor
|
||||
ClusterctlType
|
||||
// IsogenType event emitted by Isogen executor
|
||||
IsogenType
|
||||
// BootstrapType event emitted by Bootstrap executor
|
||||
BootstrapType
|
||||
// GenericContainerType event emitted by GenericContainer
|
||||
@ -54,7 +52,6 @@ type Event struct {
|
||||
ErrorEvent ErrorEvent
|
||||
StatusPollerEvent statuspollerevent.Event
|
||||
ClusterctlEvent ClusterctlEvent
|
||||
IsogenEvent IsogenEvent
|
||||
BootstrapEvent BootstrapEvent
|
||||
GenericContainerEvent GenericContainerEvent
|
||||
BaremetalManagerEvent BaremetalManagerEvent
|
||||
@ -70,7 +67,6 @@ type GenericEvent struct {
|
||||
|
||||
var mapTypeToEvent = map[Type]string{
|
||||
ClusterctlType: "ClusterctlEvent",
|
||||
IsogenType: "IsogenEvent",
|
||||
BootstrapType: "BootstrapEvent",
|
||||
GenericContainerType: "GenericContainerEvent",
|
||||
}
|
||||
@ -82,12 +78,6 @@ var unknownEventType = map[Type]string{
|
||||
WaitType: "WaitType",
|
||||
}
|
||||
|
||||
var isogenOperationToString = map[IsogenOperation]string{
|
||||
IsogenStart: "IsogenStart",
|
||||
IsogenValidation: "IsogenValidation",
|
||||
IsogenEnd: "IsogenEnd",
|
||||
}
|
||||
|
||||
var clusterctlOperationToString = map[ClusterctlOperation]string{
|
||||
ClusterctlInitStart: "ClusterctlInitStart",
|
||||
ClusterctlInitEnd: "ClusterctlInitEnd",
|
||||
@ -127,9 +117,6 @@ func Normalize(e Event) GenericEvent {
|
||||
case ClusterctlType:
|
||||
operation = clusterctlOperationToString[e.ClusterctlEvent.Operation]
|
||||
message = e.ClusterctlEvent.Message
|
||||
case IsogenType:
|
||||
operation = isogenOperationToString[e.IsogenEvent.Operation]
|
||||
message = e.IsogenEvent.Message
|
||||
case BootstrapType:
|
||||
operation = bootstrapOperationToString[e.BootstrapEvent.Operation]
|
||||
message = e.BootstrapEvent.Message
|
||||
@ -195,31 +182,6 @@ func (e Event) WithClusterctlEvent(concreteEvent ClusterctlEvent) Event {
|
||||
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
|
||||
type BootstrapOperation int
|
||||
|
||||
|
@ -54,9 +54,9 @@ func TestPrintEvent(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
p := events.NewGenericPrinter(tt.writer, tt.formatterType)
|
||||
e := events.NewEvent().WithIsogenEvent(events.IsogenEvent{
|
||||
Operation: events.IsogenStart,
|
||||
Message: "starting ISO generation",
|
||||
e := events.NewEvent().WithGenericContainerEvent(events.GenericContainerEvent{
|
||||
Operation: events.GenericContainerStart,
|
||||
Message: "starting generic container generation",
|
||||
})
|
||||
ge := events.Normalize(e)
|
||||
err := p.PrintEvent(ge)
|
||||
|
@ -40,7 +40,7 @@ func DefaultExecutorRegistry() map[schema.GroupVersionKind]ifc.ExecutorFactory {
|
||||
execMap := make(map[schema.GroupVersionKind]ifc.ExecutorFactory)
|
||||
|
||||
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 {
|
||||
log.Fatal(ErrExecutorRegistration{ExecutorName: execName, Err: err})
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import (
|
||||
const (
|
||||
Clusterctl = "clusterctl"
|
||||
KubernetesApply = "kubernetes-apply"
|
||||
Isogen = "isogen"
|
||||
GenericContainer = "generic-container"
|
||||
Ephemeral = "ephemeral"
|
||||
BMHManager = "BaremetalManager"
|
||||
@ -45,9 +44,6 @@ func RegisterExecutor(executorName string, registry map[schema.GroupVersionKind]
|
||||
case KubernetesApply:
|
||||
gvks, _, err = airshipv1.Scheme.ObjectKinds(&airshipv1.KubernetesApply{})
|
||||
execObj = NewKubeApplierExecutor
|
||||
case Isogen:
|
||||
gvks, _, err = airshipv1.Scheme.ObjectKinds(airshipv1.DefaultIsoConfiguration())
|
||||
execObj = NewIsogenExecutor
|
||||
case GenericContainer:
|
||||
gvks, _, err = airshipv1.Scheme.ObjectKinds(airshipv1.DefaultGenericContainer())
|
||||
execObj = NewContainerExecutor
|
||||
|
@ -61,16 +61,6 @@ func TestRegisterExecutor(t *testing.T) {
|
||||
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",
|
||||
executorName: executors.KubernetesApply,
|
||||
|
@ -30,14 +30,6 @@ func (e ErrUnknownExecutorAction) Error() string {
|
||||
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
|
||||
// received by RegisterExecutor function
|
||||
type ErrUnknownExecutorName struct {
|
||||
|
@ -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
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
@ -123,9 +123,6 @@ func TestHelperPlan(t *testing.T) {
|
||||
Name: testPlanName,
|
||||
},
|
||||
Phases: []airshipv1.PhaseStep{
|
||||
{
|
||||
Name: "isogen",
|
||||
},
|
||||
{
|
||||
Name: "remotedirect",
|
||||
},
|
||||
|
@ -3,7 +3,6 @@ kind: PhasePlan
|
||||
metadata:
|
||||
name: phasePlan
|
||||
phases:
|
||||
- name: isogen
|
||||
- name: remotedirect
|
||||
- name: initinfra
|
||||
- name: some_phase
|
||||
|
@ -20,7 +20,7 @@ IMAGE_DIR=${IMAGE_DIR:-"/srv/images"}
|
||||
CLEANUP_SERVE_DIR=${CLEANUP_SERVE_DIR:-"false"}
|
||||
SITE_NAME=${SITE_NAME:-test-site}
|
||||
# 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
|
||||
sudo rm -rf ${IMAGE_DIR}
|
||||
@ -29,9 +29,9 @@ sudo chmod -R 755 ${IMAGE_DIR}
|
||||
sudo chown -R ${USER_NAME} ${IMAGE_DIR}
|
||||
|
||||
unset IFS
|
||||
for phase in $IMAGE_PHASES; do
|
||||
echo "Build phase: $phase"
|
||||
airshipctl phase run $phase --debug
|
||||
for plan in $IMAGE_PHASE_PLANS; do
|
||||
echo "Build phase plan: $plan"
|
||||
airshipctl plan run $plan --debug
|
||||
done
|
||||
|
||||
echo "List generated images"
|
||||
|
Loading…
Reference in New Issue
Block a user