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:
|
resources:
|
||||||
- secret.yaml
|
- secret.yaml
|
||||||
- image_configuration.yaml
|
|
||||||
- remote_direct_configuration.yaml
|
- remote_direct_configuration.yaml
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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})
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
Name: testPlanName,
|
||||||
},
|
},
|
||||||
Phases: []airshipv1.PhaseStep{
|
Phases: []airshipv1.PhaseStep{
|
||||||
{
|
|
||||||
Name: "isogen",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "remotedirect",
|
Name: "remotedirect",
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user