Merge "image-builder integration for ISO builds"
This commit is contained in:
commit
e075b78d85
@ -7,4 +7,4 @@ Flags:
|
||||
-h, --help help for ejectmedia
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
|
@ -7,4 +7,4 @@ Flags:
|
||||
-h, --help help for poweroff
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
|
@ -7,4 +7,4 @@ Flags:
|
||||
-h, --help help for poweron
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
|
@ -7,4 +7,4 @@ Flags:
|
||||
-h, --help help for powerstatus
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
|
@ -7,4 +7,4 @@ Flags:
|
||||
-h, --help help for reboot
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
|
@ -21,28 +21,19 @@ import (
|
||||
"opendev.org/airship/airshipctl/pkg/phase"
|
||||
)
|
||||
|
||||
// NewImageBuildCommand creates a new command with the capability to build an ISO image.
|
||||
// NewImageBuildCommand creates a new command with the capability to build ISO image.
|
||||
func NewImageBuildCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
var progress bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "build",
|
||||
Short: "Build ISO image",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
p := &phase.RunCommand{
|
||||
Factory: cfgFactory,
|
||||
Options: phase.RunFlags{Progress: progress},
|
||||
}
|
||||
p.Options.PhaseID.Name = config.BootstrapPhase
|
||||
return p.RunE()
|
||||
},
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(
|
||||
&progress,
|
||||
"progress",
|
||||
false,
|
||||
"show progress")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -12,28 +12,28 @@ In a nutshell, users of `airshipctl` should be able to do the following:
|
||||
1. Create an `airshipctl` Airship Configuration for their site - sort of like a
|
||||
kubeconfig file. Airshipctl can create a pre-configured config file by
|
||||
running `airshipctl config init`.
|
||||
2. Create a set of declarative documents representing the infrastructure
|
||||
1. Create a set of declarative documents representing the infrastructure
|
||||
(baremetal, cloud) and software.
|
||||
3. Run `airshipctl document pull` to clone the document repositories in your
|
||||
1. Run `airshipctl document pull` to clone the document repositories in your
|
||||
Airship Configuration.
|
||||
4. When deploying against baremetal infrastructure, run
|
||||
`airshipctl baremetal isogen` to generate a self-contained ISO that can be
|
||||
used to boot the first host in the cluster into an ephemeral Kubernetes node.
|
||||
5. When deploying against baremetal infrastructure, run
|
||||
1. Run `airshipctl image build` to generate a self-contained ISO
|
||||
that can be used to boot the first host in the cluster into an ephemeral
|
||||
Kubernetes node.
|
||||
1. When deploying against baremetal infrastructure, run
|
||||
`airshipctl baremetal remotedirect` to remotely provision the first machine
|
||||
in the cluster using the generated ISO, providing an ephemeral Kubernetes
|
||||
instance that `airshipctl` can communicate with for subsequent steps. This
|
||||
ephemeral host provides a foothold in the target environment so we can follow
|
||||
the standard cluster-api bootstrap flow.
|
||||
6. Run `airshipctl phase run initinfra-ephemeral` to bootstrap the new ephemeral cluster
|
||||
1. Run `airshipctl phase run initinfra-ephemeral` to bootstrap the new ephemeral cluster
|
||||
with enough of the chosen cluster-api provider components to provision the
|
||||
target cluster.
|
||||
7. Run `airshipctl clusterctl` to use the ephemeral Kubernetes host to provision
|
||||
1. Run `airshipctl clusterctl` to use the ephemeral Kubernetes host to provision
|
||||
at least one node of the target cluster using the cluster-api bootstrap flow.
|
||||
8. Run `airshipctl cluster initinfra --clustertype=target` to bootstrap the new
|
||||
1. Run `airshipctl cluster initinfra --clustertype=target` to bootstrap the new
|
||||
target cluster with any remaining infrastructure necessary to begin running
|
||||
more complex workflows such as Argo.
|
||||
9. Run `airshipctl workflow submit sitemanage` to run the out of the box sitemanage
|
||||
1. Run `airshipctl workflow submit sitemanage` to run the out of the box sitemanage
|
||||
workflow, which will leverage Argo to handle bootstrapping the remaining
|
||||
infrastructure as well as deploying and/or updating software.
|
||||
|
||||
|
@ -16,7 +16,7 @@ airshipctl baremetal ejectmedia [flags]
|
||||
-h, --help help for ejectmedia
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -16,7 +16,7 @@ airshipctl baremetal poweroff [flags]
|
||||
-h, --help help for poweroff
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -16,7 +16,7 @@ airshipctl baremetal poweron [flags]
|
||||
-h, --help help for poweron
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -16,7 +16,7 @@ airshipctl baremetal powerstatus [flags]
|
||||
-h, --help help for powerstatus
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -16,7 +16,7 @@ airshipctl baremetal reboot [flags]
|
||||
-h, --help help for reboot
|
||||
-l, --labels string Label(s) to filter desired baremetal host documents
|
||||
-n, --name string Name to filter desired baremetal host document
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap")
|
||||
--phase string airshipctl phase that contains the desired baremetal host document(s) (default "bootstrap-iso")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -14,7 +14,6 @@ airshipctl image build [flags]
|
||||
|
||||
```
|
||||
-h, --help help for build
|
||||
--progress show progress
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
1
go.mod
1
go.mod
@ -9,7 +9,6 @@ require (
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.0.4
|
||||
github.com/containerd/containerd v1.4.1 // indirect
|
||||
github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
|
11
go.sum
11
go.sum
@ -65,8 +65,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
@ -108,8 +106,6 @@ github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1
|
||||
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 h1:HD4PLRzjuCVW79mQ0/pdsalOLHJ+FaEoqJLxfltpb2U=
|
||||
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||
github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/cheggaaa/pb/v3 v3.0.4 h1:QZEPYOj2ix6d5oEg63fbHmpolrnNiwjUsk+h74Yt4bM=
|
||||
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@ -489,18 +485,13 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
|
||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@ -842,9 +833,7 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1,14 +1,20 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: ImageConfiguration
|
||||
kind: IsoConfiguration
|
||||
metadata:
|
||||
name: isogen
|
||||
labels:
|
||||
airshipit.org/deploy-k8s: "false"
|
||||
builder:
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
userDataFileName: user-data
|
||||
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/isogen:latest-ubuntu_focal
|
||||
volume: /srv/iso:/config
|
||||
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
|
||||
volume: /srv/images:/config
|
||||
|
@ -4,4 +4,4 @@ metadata:
|
||||
name: default
|
||||
labels:
|
||||
airshipit.org/deploy-k8s: "false"
|
||||
isoUrl: http://localhost:8099/ubuntu-focal.iso
|
||||
isoUrl: http://localhost:8099/ephemeral.iso
|
||||
|
@ -12,6 +12,8 @@ stringData:
|
||||
# TODO: add download sources to the versions catalogue
|
||||
userData: |
|
||||
#cloud-config
|
||||
# Expect that packages are already installed in base image
|
||||
package_update: false
|
||||
ssh_pwauth: True
|
||||
chpasswd:
|
||||
list: |
|
||||
@ -24,32 +26,7 @@ stringData:
|
||||
gecos: deployer
|
||||
ssh_pwauth: True
|
||||
runcmd:
|
||||
- |
|
||||
cat <<EOF | tee /etc/sysctl.d/k8s.conf
|
||||
net.bridge.bridge-nf-call-ip6tables = 1
|
||||
net.bridge.bridge-nf-call-iptables = 1
|
||||
EOF
|
||||
- sysctl --system
|
||||
- swapoff -a
|
||||
- export HTTP_PROXY=REPLACEMENT_HTTP_PROXY
|
||||
- export HTTPS_PROXY=REPLACEMENT_HTTPS_PROXY
|
||||
- export http_proxy=${HTTP_PROXY}
|
||||
- export https_proxy=${HTTPS_PROXY}
|
||||
- export NO_PROXY=REPLACEMENT_NO_PROXY
|
||||
- export no_proxy=${NO_PROXY}
|
||||
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
|
||||
- curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
|
||||
- echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee -a /etc/apt/sources.list
|
||||
# Replace xenial with focal or $(lsb_release -cs) once available
|
||||
- echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list
|
||||
- apt update
|
||||
- apt install -y
|
||||
docker-ce="$(apt-cache policy docker-ce | grep 19.03.12 | sort | head -n 1 | tr -s " " | cut -d ' ' -f 2)"
|
||||
docker-ce-cli="$(apt-cache policy docker-ce-cli | grep 19.03.12 | sort | head -n 1 | tr -s " " | cut -d ' ' -f 2)"
|
||||
containerd.io
|
||||
- apt install -y kubelet=1.18.6-00 kubeadm=1.18.6-00 kubectl=1.18.6-00
|
||||
- apt-mark hold docker-ce docker-ce-cli containerd.io kubelet kubeadm kubectl
|
||||
- unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY no_proxy NO_PROXY
|
||||
- /bin/bash -c 'kernel_libsubdir="$(ls /lib/modules | head -1)"; config_dir="/lib/modules/${kernel_libsubdir}/build"; mkdir -p "${config_dir}"; if [ -f /run/live/medium/config ] && [ ! -f "${config_dir}/.config" ]; then ln -s /run/live/medium/config "${config_dir}/.config"; fi;'
|
||||
- kubeadm init --config /tmp/kubeadm.yaml
|
||||
- mkdir -p /opt/metal3-dev-env/ironic/html/images
|
||||
write_files:
|
||||
|
@ -19,19 +19,17 @@ move-options: {}
|
||||
action: move
|
||||
---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: ImageConfiguration
|
||||
kind: IsoConfiguration
|
||||
metadata:
|
||||
name: isogen
|
||||
labels:
|
||||
airshipit.org/deploy-k8s: "false"
|
||||
builder:
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
userDataFileName: user-data
|
||||
outputFileName: ephemeral.iso
|
||||
container:
|
||||
containerRuntime: docker
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
volume: /srv/iso:/config
|
||||
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
|
||||
volume: /srv/images:/config
|
||||
---
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: GenericContainer
|
||||
|
@ -1,11 +1,11 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: Phase
|
||||
metadata:
|
||||
name: bootstrap
|
||||
name: bootstrap-iso
|
||||
config:
|
||||
executorRef:
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: ImageConfiguration
|
||||
kind: IsoConfiguration
|
||||
name: isogen
|
||||
documentEntryPoint: ephemeral/bootstrap
|
||||
---
|
||||
|
@ -46,7 +46,7 @@ func init() {
|
||||
&PhasePlan{},
|
||||
&KubeConfig{},
|
||||
&KubernetesApply{},
|
||||
&ImageConfiguration{},
|
||||
&IsoConfiguration{},
|
||||
&RemoteDirectConfiguration{},
|
||||
&ClusterMap{},
|
||||
&ReplacementTransformer{},
|
||||
|
@ -1,59 +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
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Container structure contains parameters related to Docker runtime, used for building image
|
||||
type Container struct {
|
||||
// Container volume directory binding.
|
||||
Volume string `json:"volume,omitempty"`
|
||||
// ISO generator container image URL
|
||||
Image string `json:"image,omitempty"`
|
||||
// Container Runtime Interface driver
|
||||
ContainerRuntime string `json:"containerRuntime,omitempty"`
|
||||
}
|
||||
|
||||
// Builder structure defines metadata files (including Cloud Init metadata) used for image
|
||||
type Builder struct {
|
||||
// Cloud Init user-data file name placed to the container volume root
|
||||
UserDataFileName string `json:"userDataFileName,omitempty"`
|
||||
// Cloud Init network-config file name placed to the container volume root
|
||||
NetworkConfigFileName string `json:"networkConfigFileName,omitempty"`
|
||||
// File name for output metadata
|
||||
OutputMetadataFileName string `json:"outputMetadataFileName,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// ImageConfiguration structure is inherited from apimachinery TypeMeta and ObjectMeta and is a top level
|
||||
// configuration structure for building image
|
||||
type ImageConfiguration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Container *Container `json:"container,omitempty"`
|
||||
Builder *Builder `json:"builder,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultImageConfiguration can be used to safely unmarshal ImageConfiguration object without nil pointers
|
||||
func DefaultImageConfiguration() *ImageConfiguration {
|
||||
return &ImageConfiguration{
|
||||
Container: &Container{},
|
||||
Builder: &Builder{},
|
||||
}
|
||||
}
|
64
pkg/api/v1alpha1/isoconfiguration.go
Normal file
64
pkg/api/v1alpha1/isoconfiguration.go
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// IsoContainer structure contains parameters related to Docker runtime, used for building image
|
||||
type IsoContainer struct {
|
||||
// Container volume directory binding.
|
||||
Volume string `json:"volume,omitempty"`
|
||||
// ISO generator container image URL
|
||||
Image string `json:"image,omitempty"`
|
||||
// Container Runtime Interface driver
|
||||
ContainerRuntime string `json:"containerRuntime,omitempty"`
|
||||
}
|
||||
|
||||
// Isogen structure defines document selection criteria for cloud-init metadata
|
||||
type Isogen struct {
|
||||
// Cloud Init user data will be retrieved from the doc matching this object
|
||||
UserDataSelector types.Selector `json:"userDataSelector,omitempty"`
|
||||
// Cloud init user data will be retrieved from this document key
|
||||
UserDataKey string `jsong:"userDataKey,omitempty"`
|
||||
// Cloud Init network config will be retrieved from the doc matching this object
|
||||
NetworkConfigSelector types.Selector `json:"networkConfigSelector,omitempty"`
|
||||
// Cloud init network config will be retrieved from this document key
|
||||
NetworkConfigKey string `jsong:"networkConfigKey,omitempty"`
|
||||
// File name to use for the output image that will be written to the container volume root
|
||||
OutputFileName string `json:"outputFileName,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// IsoConfiguration structure is inherited from apimachinery TypeMeta and ObjectMeta and is a top level
|
||||
// configuration structure for building image
|
||||
type IsoConfiguration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
IsoContainer *IsoContainer `json:"container,omitempty"`
|
||||
Isogen *Isogen `json:"builder,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultIsoConfiguration can be used to safely unmarshal IsoConfiguration object without nil pointers
|
||||
func DefaultIsoConfiguration() *IsoConfiguration {
|
||||
return &IsoConfiguration{
|
||||
IsoContainer: &IsoContainer{},
|
||||
Isogen: &Isogen{},
|
||||
}
|
||||
}
|
@ -112,21 +112,6 @@ func (in *BootstrapContainer) DeepCopy() *BootstrapContainer {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Builder) DeepCopyInto(out *Builder) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Builder.
|
||||
func (in *Builder) DeepCopy() *Builder {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Builder)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Cluster) DeepCopyInto(out *Cluster) {
|
||||
*out = *in
|
||||
@ -258,21 +243,6 @@ func (in *Clusterctl) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Container) DeepCopyInto(out *Container) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container.
|
||||
func (in *Container) DeepCopy() *Container {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Container)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EphemeralCluster) DeepCopyInto(out *EphemeralCluster) {
|
||||
*out = *in
|
||||
@ -306,41 +276,6 @@ func (in *GenericContainer) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ImageConfiguration) DeepCopyInto(out *ImageConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.Container != nil {
|
||||
in, out := &in.Container, &out.Container
|
||||
*out = new(Container)
|
||||
**out = **in
|
||||
}
|
||||
if in.Builder != nil {
|
||||
in, out := &in.Builder, &out.Builder
|
||||
*out = new(Builder)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageConfiguration.
|
||||
func (in *ImageConfiguration) DeepCopy() *ImageConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ImageConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ImageConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ImageMeta) DeepCopyInto(out *ImageMeta) {
|
||||
*out = *in
|
||||
@ -391,6 +326,73 @@ func (in *InitOptions) DeepCopy() *InitOptions {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IsoConfiguration) DeepCopyInto(out *IsoConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.IsoContainer != nil {
|
||||
in, out := &in.IsoContainer, &out.IsoContainer
|
||||
*out = new(IsoContainer)
|
||||
**out = **in
|
||||
}
|
||||
if in.Isogen != nil {
|
||||
in, out := &in.Isogen, &out.Isogen
|
||||
*out = new(Isogen)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IsoConfiguration.
|
||||
func (in *IsoConfiguration) DeepCopy() *IsoConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IsoConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *IsoConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IsoContainer) DeepCopyInto(out *IsoContainer) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IsoContainer.
|
||||
func (in *IsoContainer) DeepCopy() *IsoContainer {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IsoContainer)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Isogen) DeepCopyInto(out *Isogen) {
|
||||
*out = *in
|
||||
out.UserDataSelector = in.UserDataSelector
|
||||
out.NetworkConfigSelector = in.NetworkConfigSelector
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Isogen.
|
||||
func (in *Isogen) DeepCopy() *Isogen {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Isogen)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeConfig) DeepCopyInto(out *KubeConfig) {
|
||||
*out = *in
|
||||
|
@ -15,27 +15,54 @@
|
||||
package cloudinit
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
const (
|
||||
networkDataKey = "networkData"
|
||||
userDataKey = "userData"
|
||||
var (
|
||||
// Initialize defaults where we expect to find user-data and
|
||||
// network config data in manifests
|
||||
userDataSelectorDefaults = types.Selector{
|
||||
Gvk: resid.Gvk{Kind: document.SecretKind},
|
||||
LabelSelector: document.EphemeralUserDataSelector,
|
||||
}
|
||||
userDataKeyDefault = "userData"
|
||||
networkConfigSelectorDefaults = types.Selector{
|
||||
Gvk: resid.Gvk{Kind: document.BareMetalHostKind},
|
||||
LabelSelector: document.EphemeralHostSelector,
|
||||
}
|
||||
networkConfigKeyDefault = "networkData"
|
||||
)
|
||||
|
||||
// GetCloudData reads YAML document input and generates cloud-init data for
|
||||
// ephemeral node.
|
||||
func GetCloudData(docBundle document.Bundle) (userData []byte, netConf []byte, err error) {
|
||||
userData, err = getUserData(docBundle)
|
||||
|
||||
func GetCloudData(
|
||||
docBundle document.Bundle,
|
||||
userDataSelector types.Selector,
|
||||
userDataKey string,
|
||||
networkConfigSelector types.Selector,
|
||||
networkConfigKey string,
|
||||
) (userData []byte, netConf []byte, err error) {
|
||||
userDataSelectorFinal, userDataKeyFinal := applyDefaultsAndGetData(
|
||||
userDataSelector,
|
||||
userDataSelectorDefaults,
|
||||
userDataKey,
|
||||
userDataKeyDefault,
|
||||
)
|
||||
userData, err = document.GetSecretData(docBundle, userDataSelectorFinal, userDataKeyFinal)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
netConf, err = getNetworkData(docBundle)
|
||||
|
||||
netConfSelectorFinal, netConfKeyFinal := applyDefaultsAndGetData(
|
||||
networkConfigSelector,
|
||||
networkConfigSelectorDefaults,
|
||||
networkConfigKey,
|
||||
networkConfigKeyDefault,
|
||||
)
|
||||
netConf, err = getNetworkData(docBundle, netConfSelectorFinal, netConfKeyFinal)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -43,26 +70,36 @@ func GetCloudData(docBundle document.Bundle) (userData []byte, netConf []byte, e
|
||||
return userData, netConf, err
|
||||
}
|
||||
|
||||
func getUserData(docBundle document.Bundle) ([]byte, error) {
|
||||
// find the user-data document
|
||||
selector := document.NewEphemeralCloudDataSelector()
|
||||
userDataDoc, err := docBundle.SelectOne(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func applyDefaultsAndGetData(
|
||||
docSelector types.Selector,
|
||||
docSelectorDefaults types.Selector,
|
||||
key string,
|
||||
keyDefault string,
|
||||
) (types.Selector, string) {
|
||||
// Assign defaults if there are no user supplied overrides
|
||||
if docSelector.Kind == "" &&
|
||||
docSelector.Name == "" &&
|
||||
docSelector.AnnotationSelector == "" &&
|
||||
docSelector.LabelSelector == "" {
|
||||
docSelector.Kind = docSelectorDefaults.Kind
|
||||
docSelector.LabelSelector = docSelectorDefaults.LabelSelector
|
||||
}
|
||||
|
||||
// finally, try and retrieve the data we want from the document
|
||||
userData, err := decodeData(userDataDoc, userDataKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
keyFinal := key
|
||||
if key == "" {
|
||||
keyFinal = keyDefault
|
||||
}
|
||||
|
||||
return userData, nil
|
||||
return docSelector, keyFinal
|
||||
}
|
||||
|
||||
func getNetworkData(docBundle document.Bundle) ([]byte, error) {
|
||||
func getNetworkData(
|
||||
docBundle document.Bundle,
|
||||
netCfgSelector types.Selector,
|
||||
netCfgKey string,
|
||||
) ([]byte, error) {
|
||||
// find the baremetal host indicated as the ephemeral node
|
||||
selector := document.NewEphemeralBMHSelector()
|
||||
selector := document.NewSelector().ByKind(netCfgSelector.Kind).ByLabel(netCfgSelector.LabelSelector)
|
||||
d, err := docBundle.SelectOne(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -80,37 +117,10 @@ func getNetworkData(docBundle document.Bundle) ([]byte, error) {
|
||||
}
|
||||
|
||||
// finally, try and retrieve the data we want from the document
|
||||
netData, err := decodeData(d, networkDataKey)
|
||||
netData, err := document.DecodeSecretData(d, netCfgKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return netData, nil
|
||||
}
|
||||
|
||||
func decodeData(cfg document.Document, key string) ([]byte, error) {
|
||||
var needsBase64Decode = false
|
||||
|
||||
// TODO(alanmeadows): distinguish between missing net-data key
|
||||
// and missing data/stringData keys in the Secret
|
||||
data, err := cfg.GetStringMap("data")
|
||||
if err == nil {
|
||||
needsBase64Decode = true
|
||||
} else {
|
||||
// we'll catch any error below
|
||||
data, err = cfg.GetStringMap("stringData")
|
||||
if err != nil {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: "data or stringData"}
|
||||
}
|
||||
}
|
||||
|
||||
res, ok := data[key]
|
||||
if !ok {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: key}
|
||||
}
|
||||
|
||||
if needsBase64Decode {
|
||||
return b64.StdEncoding.DecodeString(res)
|
||||
}
|
||||
return []byte(res), nil
|
||||
}
|
||||
|
@ -2,9 +2,7 @@
|
||||
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.
|
||||
@ -21,6 +19,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
func TestGetCloudData(t *testing.T) {
|
||||
@ -28,19 +29,35 @@ func TestGetCloudData(t *testing.T) {
|
||||
require.NoError(t, err, "Building Bundle Failed")
|
||||
|
||||
tests := []struct {
|
||||
labelFilter string
|
||||
expectedUserData []byte
|
||||
expectedNetData []byte
|
||||
expectedErr error
|
||||
labelFilter string
|
||||
userDataSelector types.Selector
|
||||
userDataKey string
|
||||
networkConfigSelector types.Selector
|
||||
networkConfigKey string
|
||||
expectedUserData []byte
|
||||
expectedNetData []byte
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
labelFilter: "test=validdocset",
|
||||
expectedUserData: []byte("cloud-init"),
|
||||
expectedNetData: []byte("net-config"),
|
||||
expectedErr: nil,
|
||||
labelFilter: "test=validdocset",
|
||||
userDataSelector: types.Selector{},
|
||||
networkConfigSelector: types.Selector{},
|
||||
expectedUserData: []byte("cloud-init"),
|
||||
expectedNetData: []byte("net-config"),
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
labelFilter: "test=ephemeralmissing",
|
||||
labelFilter: "test=ephemeralmissing",
|
||||
userDataSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data in (True, true)",
|
||||
},
|
||||
userDataKey: "userData",
|
||||
networkConfigSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "BareMetalHost"},
|
||||
LabelSelector: "airshipit.org/ephemeral-node in (True, true)",
|
||||
},
|
||||
networkConfigKey: "networkData",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: document.ErrDocNotFound{
|
||||
@ -50,7 +67,17 @@ func TestGetCloudData(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=ephemeralduplicate",
|
||||
labelFilter: "test=ephemeralduplicate",
|
||||
userDataSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data in (True, true)",
|
||||
},
|
||||
userDataKey: "userData",
|
||||
networkConfigSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "BareMetalHost"},
|
||||
LabelSelector: "airshipit.org/ephemeral-node in (True, true)",
|
||||
},
|
||||
networkConfigKey: "networkData",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: document.ErrMultiDocsFound{
|
||||
@ -60,7 +87,17 @@ func TestGetCloudData(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=networkdatabadpointer",
|
||||
labelFilter: "test=networkdatabadpointer",
|
||||
userDataSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data in (True, true)",
|
||||
},
|
||||
userDataKey: "userData",
|
||||
networkConfigSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "BareMetalHost"},
|
||||
LabelSelector: "airshipit.org/ephemeral-node in (True, true)",
|
||||
},
|
||||
networkConfigKey: "networkData",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: document.ErrDocNotFound{
|
||||
@ -71,19 +108,55 @@ func TestGetCloudData(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=networkdatamalformed",
|
||||
labelFilter: "test=networkdatamalformed",
|
||||
userDataSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data in (True, true)",
|
||||
},
|
||||
userDataKey: "userData",
|
||||
networkConfigSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "BareMetalHost"},
|
||||
LabelSelector: "airshipit.org/ephemeral-node in (True, true)",
|
||||
},
|
||||
networkConfigKey: "networkData",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: ErrDataNotSupplied{DocName: "networkdatamalformed-malformed", Key: networkDataKey},
|
||||
expectedErr: document.ErrDataNotSupplied{
|
||||
DocName: "networkdatamalformed-malformed",
|
||||
Key: networkConfigKeyDefault,
|
||||
},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=userdatamalformed",
|
||||
labelFilter: "test=userdatamalformed",
|
||||
userDataSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data in (True, true)",
|
||||
},
|
||||
userDataKey: "userData",
|
||||
networkConfigSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "BareMetalHost"},
|
||||
LabelSelector: "airshipit.org/ephemeral-node in (True, true)",
|
||||
},
|
||||
networkConfigKey: "networkData",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: ErrDataNotSupplied{DocName: "userdatamalformed-somesecret", Key: userDataKey},
|
||||
expectedErr: document.ErrDataNotSupplied{
|
||||
DocName: "userdatamalformed-somesecret",
|
||||
Key: userDataKeyDefault,
|
||||
},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=userdatamissing",
|
||||
labelFilter: "test=userdatamissing",
|
||||
userDataSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data in (True, true)",
|
||||
},
|
||||
userDataKey: "userData",
|
||||
networkConfigSelector: types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "BareMetalHost"},
|
||||
LabelSelector: "airshipit.org/ephemeral-node in (True, true)",
|
||||
},
|
||||
networkConfigKey: "networkData",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: document.ErrDocNotFound{
|
||||
@ -105,7 +178,13 @@ func TestGetCloudData(t *testing.T) {
|
||||
require.NoError(t, err, "GetAllDocuments failed")
|
||||
require.NotZero(t, docs)
|
||||
|
||||
actualUserData, actualNetData, actualErr := GetCloudData(filteredBundle)
|
||||
actualUserData, actualNetData, actualErr := GetCloudData(
|
||||
filteredBundle,
|
||||
tt.userDataSelector,
|
||||
tt.userDataKey,
|
||||
tt.networkConfigSelector,
|
||||
tt.networkConfigKey,
|
||||
)
|
||||
|
||||
assert.Equal(t, tt.expectedUserData, actualUserData)
|
||||
assert.Equal(t, tt.expectedNetData, actualNetData)
|
||||
|
@ -1,41 +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 cloudinit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ErrDataNotSupplied error returned of no user-data or network configuration
|
||||
// in the Secret
|
||||
type ErrDataNotSupplied struct {
|
||||
DocName string
|
||||
Key string
|
||||
}
|
||||
|
||||
// ErrDuplicateNetworkDataDocuments error returned if multiple network documents
|
||||
// were found with the same name in the same namespace
|
||||
type ErrDuplicateNetworkDataDocuments struct {
|
||||
DocName string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
func (e ErrDataNotSupplied) Error() string {
|
||||
return fmt.Sprintf("Document %s has no key %s", e.DocName, e.Key)
|
||||
}
|
||||
|
||||
func (e ErrDuplicateNetworkDataDocuments) Error() string {
|
||||
return fmt.Sprintf("Found more than one document with the name %s in namespace %s", e.DocName, e.Namespace)
|
||||
}
|
@ -15,17 +15,12 @@
|
||||
package isogen
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/bootstrap/cloudinit"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
@ -36,19 +31,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
builderConfigFileName = "builder-conf.yaml"
|
||||
|
||||
// progressBarTemplate is a template string for progress bar
|
||||
// looks like 'Prefix [-->______] 20%' where Prefix is trimmed log line from docker container
|
||||
progressBarTemplate = `{{string . "prefix"}} {{bar . }} {{percent . }} `
|
||||
// defaultTerminalWidth is a default width of terminal if it's impossible to determine the actual one
|
||||
defaultTerminalWidth = 80
|
||||
// multiplier is a number of log lines produces while installing 1 package
|
||||
multiplier = 3
|
||||
// reInstallActions is a regular expression to check whether the log line contains of this substrings
|
||||
reInstallActions = `Extracting|Unpacking|Configuring|Preparing|Setting`
|
||||
reInstallBegin = `Retrieving Packages|newly installed`
|
||||
reInstallFinish = `Base system installed successfully|mksquashfs`
|
||||
builderConfigFileName = "builder-conf.yaml"
|
||||
outputFileNameDefault = "ephemerial.iso"
|
||||
userDataFileName = "user-data"
|
||||
networkConfigFileName = "network-data"
|
||||
outputMetadataFileName = "output-metadata.yaml"
|
||||
)
|
||||
|
||||
// BootstrapIsoOptions are used to generate bootstrap ISO
|
||||
@ -56,60 +43,63 @@ type BootstrapIsoOptions struct {
|
||||
DocBundle document.Bundle
|
||||
Builder container.Container
|
||||
Doc document.Document
|
||||
Cfg *v1alpha1.ImageConfiguration
|
||||
Cfg *v1alpha1.IsoConfiguration
|
||||
|
||||
// optional fields for verbose output
|
||||
Debug bool
|
||||
Progress bool
|
||||
Writer io.Writer
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
// VerifyInputs verifies image configuration
|
||||
func VerifyInputs(cfg *v1alpha1.ImageConfiguration) error {
|
||||
if cfg.Container.Volume == "" {
|
||||
func VerifyInputs(cfg *v1alpha1.IsoConfiguration) error {
|
||||
if cfg.IsoContainer.Volume == "" {
|
||||
return config.ErrMissingConfig{
|
||||
What: "Must specify volume bind for ISO builder container",
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.Builder.UserDataFileName == "") || (cfg.Builder.NetworkConfigFileName == "") {
|
||||
return config.ErrMissingConfig{
|
||||
What: "UserDataFileName or NetworkConfigFileName are not specified in ISO builder config",
|
||||
}
|
||||
}
|
||||
|
||||
vols := strings.Split(cfg.Container.Volume, ":")
|
||||
vols := strings.Split(cfg.IsoContainer.Volume, ":")
|
||||
switch {
|
||||
case len(vols) == 1:
|
||||
cfg.Container.Volume = fmt.Sprintf("%s:%s", vols[0], vols[0])
|
||||
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 getContainerCfg(
|
||||
cfg *v1alpha1.ImageConfiguration,
|
||||
func getIsoContainerCfg(
|
||||
cfg *v1alpha1.IsoConfiguration,
|
||||
builderCfgYaml []byte,
|
||||
userData []byte,
|
||||
netConf []byte,
|
||||
) map[string][]byte {
|
||||
hostVol := strings.Split(cfg.Container.Volume, ":")[0]
|
||||
hostVol := strings.Split(cfg.IsoContainer.Volume, ":")[0]
|
||||
|
||||
fls := make(map[string][]byte)
|
||||
fls[filepath.Join(hostVol, cfg.Builder.UserDataFileName)] = userData
|
||||
fls[filepath.Join(hostVol, cfg.Builder.NetworkConfigFileName)] = netConf
|
||||
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.Container.Volume, ":")[1]
|
||||
cntVol := strings.Split(opts.Cfg.IsoContainer.Volume, ":")[1]
|
||||
log.Print("Creating cloud-init for ephemeral K8s")
|
||||
userData, netConf, err := cloudinit.GetCloudData(opts.DocBundle)
|
||||
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
|
||||
}
|
||||
@ -119,21 +109,27 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
||||
return err
|
||||
}
|
||||
|
||||
fls := getContainerCfg(opts.Cfg, builderCfgYaml, userData, netConf)
|
||||
fls := getIsoContainerCfg(opts.Cfg, builderCfgYaml, userData, netConf)
|
||||
if err = util.WriteFiles(fls, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vols := []string{opts.Cfg.Container.Volume}
|
||||
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")),
|
||||
}
|
||||
|
||||
@ -144,25 +140,17 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
||||
|
||||
log.Print("ISO generation is in progress. The whole process could take up to several minutes, please wait...")
|
||||
|
||||
if opts.Debug || opts.Progress {
|
||||
if log.DebugEnabled() {
|
||||
var cLogs io.ReadCloser
|
||||
cLogs, err = opts.Builder.GetContainerLogs()
|
||||
if err != nil {
|
||||
log.Printf("failed to read container logs %s", err)
|
||||
} else {
|
||||
switch {
|
||||
case opts.Progress:
|
||||
if err = ShowProgress(cLogs, opts.Writer); err != nil {
|
||||
log.Debugf("the following error occurred while showing progress bar: %s", err.Error())
|
||||
}
|
||||
case opts.Debug:
|
||||
log.Print("start reading container logs")
|
||||
// either container log output or progress bar will be shown
|
||||
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")
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +159,7 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
||||
}
|
||||
|
||||
log.Print("ISO successfully built.")
|
||||
if !opts.Debug {
|
||||
if !log.DebugEnabled() {
|
||||
log.Print("Removing container.")
|
||||
return opts.Builder.RmContainer()
|
||||
}
|
||||
@ -179,140 +167,3 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
||||
log.Debugf("Debug flag is set. Container %s stopped but not deleted.", opts.Builder.GetID())
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShowProgress prints progress bar during bootstrap ISO preparation
|
||||
func ShowProgress(reader io.ReadCloser, writer io.Writer) error {
|
||||
reFindActions := regexp.MustCompile(reInstallActions)
|
||||
reBeginInstall := regexp.MustCompile(reInstallBegin)
|
||||
reFinishInstall := regexp.MustCompile(reInstallFinish)
|
||||
|
||||
var bar *pb.ProgressBar
|
||||
|
||||
scanner := bufio.NewScanner(reader)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
// Reading container log line by line
|
||||
for scanner.Scan() {
|
||||
curLine := scanner.Text()
|
||||
// Trying to find entry points of package installation
|
||||
switch {
|
||||
case reBeginInstall.MatchString(curLine):
|
||||
if err := finalizePb(bar, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkgCount, err := calculatePkgCount(scanner, writer, curLine)
|
||||
if err != nil {
|
||||
return finalizePb(bar, err)
|
||||
}
|
||||
|
||||
bar, err = initPb(pkgCount, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case reFinishInstall.MatchString(curLine):
|
||||
if err := finalizePb(bar, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
case reFindActions.MatchString(curLine):
|
||||
if err := incrementPb(bar, curLine); err != nil {
|
||||
return finalizePb(bar, err)
|
||||
}
|
||||
case strings.Contains(curLine, "filesystem.squashfs"):
|
||||
fmt.Fprintln(writer, curLine)
|
||||
}
|
||||
}
|
||||
|
||||
if bar != nil && bar.IsStarted() {
|
||||
return finalizePb(bar, ErrUnexpectedPb{})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func finalizePb(bar *pb.ProgressBar, e error) error {
|
||||
if bar != nil && bar.IsStarted() {
|
||||
bar.SetCurrent(bar.Total())
|
||||
if e != nil {
|
||||
setPbPrefix(bar, "An error occurred while log parsing")
|
||||
bar.Finish()
|
||||
return e
|
||||
}
|
||||
|
||||
setPbPrefix(bar, "Completed")
|
||||
bar.Finish()
|
||||
if err := bar.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func initPb(pkgCount int, w io.Writer) (*pb.ProgressBar, error) {
|
||||
bar := pb.ProgressBarTemplate(progressBarTemplate).New(pkgCount * multiplier)
|
||||
bar.SetWriter(w).Start()
|
||||
setPbPrefix(bar, "Installing required packages")
|
||||
if err := bar.Err(); err != nil {
|
||||
return nil, finalizePb(bar, err)
|
||||
}
|
||||
return bar, nil
|
||||
}
|
||||
|
||||
func incrementPb(bar *pb.ProgressBar, curLine string) error {
|
||||
if bar != nil && bar.IsStarted() && bar.Current() < bar.Total() {
|
||||
setPbPrefix(bar, curLine)
|
||||
bar.Increment()
|
||||
if err := bar.Err(); err != nil {
|
||||
return finalizePb(bar, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setPbPrefix(bar *pb.ProgressBar, msg string) {
|
||||
terminalWidth := defaultTerminalWidth
|
||||
halfWidth := terminalWidth / 2
|
||||
bar.SetWidth(terminalWidth)
|
||||
if len(msg) > halfWidth {
|
||||
msg = fmt.Sprintf("%v...", msg[0:halfWidth-3])
|
||||
} else {
|
||||
msg = fmt.Sprintf("%-*v", halfWidth, msg)
|
||||
}
|
||||
bar.Set("prefix", msg)
|
||||
}
|
||||
|
||||
func calculatePkgCount(scanner *bufio.Scanner, writer io.Writer, curLine string) (int, error) {
|
||||
reFindNumbers := regexp.MustCompile("[0-9]+")
|
||||
|
||||
// Trying to count how many packages is going to be installed
|
||||
pkgCount := 0
|
||||
matches := reFindNumbers.FindAllString(curLine, -1)
|
||||
if matches == nil {
|
||||
// There is no numbers in line about base packages, counting them manually to get estimates
|
||||
fmt.Fprint(writer, "Retrieving base packages ")
|
||||
for scanner.Scan() {
|
||||
curLine = scanner.Text()
|
||||
if strings.Contains(curLine, "Retrieving") {
|
||||
pkgCount++
|
||||
fmt.Fprint(writer, ".")
|
||||
}
|
||||
if strings.Contains(curLine, "Chosen extractor") {
|
||||
fmt.Fprintln(writer, " Done")
|
||||
return pkgCount, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(matches) >= 2 {
|
||||
for _, v := range matches[0:2] {
|
||||
j, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
pkgCount += j
|
||||
}
|
||||
if pkgCount > 0 {
|
||||
return pkgCount, nil
|
||||
}
|
||||
}
|
||||
|
||||
return pkgCount, ErrNoParsedNumPkgs{}
|
||||
}
|
||||
|
@ -46,20 +46,19 @@ func TestBootstrapIso(t *testing.T) {
|
||||
|
||||
volBind := tempVol + ":/dst"
|
||||
testErr := fmt.Errorf("TestErr")
|
||||
testCfg := &api.ImageConfiguration{
|
||||
Container: &api.Container{
|
||||
testCfg := &api.IsoConfiguration{
|
||||
IsoContainer: &api.IsoContainer{
|
||||
Volume: volBind,
|
||||
ContainerRuntime: "docker",
|
||||
},
|
||||
Builder: &api.Builder{
|
||||
UserDataFileName: "user-data",
|
||||
NetworkConfigFileName: "net-conf",
|
||||
Isogen: &api.Isogen{
|
||||
OutputFileName: "ephemeral.iso",
|
||||
},
|
||||
}
|
||||
testDoc := &testdoc.MockDocument{
|
||||
MockAsYAML: func() ([]byte, error) { return []byte("TESTDOC"), nil },
|
||||
}
|
||||
testBuilder := &testcontainer.MockContainer{
|
||||
testIsogen := &testcontainer.MockContainer{
|
||||
MockRunCommand: func() error { return nil },
|
||||
MockGetID: func() string { return testID },
|
||||
MockRmContainer: func() error { return nil },
|
||||
@ -75,7 +74,7 @@ func TestBootstrapIso(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
builder *testcontainer.MockContainer
|
||||
cfg *api.ImageConfiguration
|
||||
cfg *api.IsoConfiguration
|
||||
doc *testdoc.MockDocument
|
||||
debug bool
|
||||
expectedOut []string
|
||||
@ -121,7 +120,7 @@ func TestBootstrapIso(t *testing.T) {
|
||||
expectedErr: testErr,
|
||||
},
|
||||
{
|
||||
builder: testBuilder,
|
||||
builder: testIsogen,
|
||||
cfg: testCfg,
|
||||
doc: &testdoc.MockDocument{
|
||||
MockAsYAML: func() ([]byte, error) { return nil, testErr },
|
||||
@ -140,7 +139,6 @@ func TestBootstrapIso(t *testing.T) {
|
||||
Builder: tt.builder,
|
||||
Doc: tt.doc,
|
||||
Cfg: tt.cfg,
|
||||
Debug: tt.debug,
|
||||
}
|
||||
actualErr := bootstrapOpts.CreateBootstrapIso()
|
||||
actualOut := outBuf.String()
|
||||
@ -159,40 +157,27 @@ func TestVerifyInputs(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg *api.ImageConfiguration
|
||||
cfg *api.IsoConfiguration
|
||||
args []string
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "missing-container-field",
|
||||
cfg: &api.ImageConfiguration{
|
||||
Container: &api.Container{},
|
||||
cfg: &api.IsoConfiguration{
|
||||
IsoContainer: &api.IsoContainer{},
|
||||
},
|
||||
expectedErr: config.ErrMissingConfig{
|
||||
What: "Must specify volume bind for ISO builder container",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing-filenames",
|
||||
cfg: &api.ImageConfiguration{
|
||||
Container: &api.Container{
|
||||
Volume: tempVol + ":/dst",
|
||||
},
|
||||
Builder: &api.Builder{},
|
||||
},
|
||||
expectedErr: config.ErrMissingConfig{
|
||||
What: "UserDataFileName or NetworkConfigFileName are not specified in ISO builder config",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid-host-path",
|
||||
cfg: &api.ImageConfiguration{
|
||||
Container: &api.Container{
|
||||
cfg: &api.IsoConfiguration{
|
||||
IsoContainer: &api.IsoContainer{
|
||||
Volume: tempVol + ":/dst:/dst1",
|
||||
},
|
||||
Builder: &api.Builder{
|
||||
UserDataFileName: "user-data",
|
||||
NetworkConfigFileName: "net-conf",
|
||||
Isogen: &api.Isogen{
|
||||
OutputFileName: "ephemeral.iso",
|
||||
},
|
||||
},
|
||||
expectedErr: config.ErrInvalidConfig{
|
||||
@ -201,17 +186,26 @@ func TestVerifyInputs(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
cfg: &api.ImageConfiguration{
|
||||
Container: &api.Container{
|
||||
cfg: &api.IsoConfiguration{
|
||||
IsoContainer: &api.IsoContainer{
|
||||
Volume: tempVol,
|
||||
},
|
||||
Builder: &api.Builder{
|
||||
UserDataFileName: "user-data",
|
||||
NetworkConfigFileName: "net-conf",
|
||||
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 {
|
||||
@ -222,29 +216,3 @@ func TestVerifyInputs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowProgress(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
output string
|
||||
}{
|
||||
{
|
||||
name: "Process-debian-based-logs",
|
||||
input: "testdata/debian-container-logs",
|
||||
output: "testdata/pb-output-debian",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
testInput, err := ioutil.ReadFile(tt.input)
|
||||
require.NoError(t, err)
|
||||
reader := ioutil.NopCloser(bytes.NewReader(testInput))
|
||||
writer := bytes.NewBuffer(nil)
|
||||
err = isogen.ShowProgress(reader, writer)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, writer.String(), "Completed")
|
||||
}
|
||||
}
|
||||
|
@ -21,11 +21,3 @@ type ErrNoParsedNumPkgs struct {
|
||||
func (e ErrNoParsedNumPkgs) Error() string {
|
||||
return "No number of packages to install found in parsed container logs"
|
||||
}
|
||||
|
||||
// ErrUnexpectedPb is returned when progress bar was not finished for some reason
|
||||
type ErrUnexpectedPb struct {
|
||||
}
|
||||
|
||||
func (e ErrUnexpectedPb) Error() string {
|
||||
return "An unexpected error occurred while parsing container logs"
|
||||
}
|
||||
|
358
pkg/bootstrap/isogen/testdata/debian-container-logs
vendored
358
pkg/bootstrap/isogen/testdata/debian-container-logs
vendored
@ -1,358 +0,0 @@
|
||||
+ _debootstrap
|
||||
+ debootstrap --arch=amd64 --variant=minbase --foreign focal /root/LIVE_BOOT/chroot http://archive.ubuntu.com/ubuntu/
|
||||
I: Retrieving InRelease
|
||||
I: Checking Release signature
|
||||
I: Valid Release signature (key id F6ECB3762474EDA9D21B7022871920D1991BC93C)
|
||||
I: Retrieving Packages
|
||||
I: Validating Packages
|
||||
I: Resolving dependencies of required packages...
|
||||
I: Resolving dependencies of base packages...
|
||||
I: Checking component main on http://archive.ubuntu.com/ubuntu...
|
||||
I: Retrieving adduser 3.118ubuntu2
|
||||
I: Validating adduser 3.118ubuntu2
|
||||
I: Retrieving apt 2.0.2
|
||||
I: Validating apt 2.0.2
|
||||
I: Retrieving base-files 11ubuntu5
|
||||
I: Validating base-files 11ubuntu5
|
||||
I: Chosen extractor for .deb packages: dpkg-deb
|
||||
I: Extracting base-files...
|
||||
I: Installing core packages...
|
||||
I: Unpacking required packages...
|
||||
I: Unpacking base-files...
|
||||
I: Configuring required packages...
|
||||
I: Unpacking the base system...
|
||||
I: Unpacking adduser...
|
||||
I: Unpacking apt...
|
||||
I: Configuring the base system...
|
||||
I: Configuring adduser...
|
||||
I: Configuring apt...
|
||||
I: Base system installed successfully.
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
Reading state information... Done
|
||||
The following additional packages will be installed:
|
||||
ca-certificates cloud-guest-utils isc-dhcp-client libdns-export1109
|
||||
libglib2.0-0 libisc-export1105 libnetplan0 libyaml-0-2 netplan.io openssl
|
||||
python3-attr python3-blinker python3-certifi python3-cffi-backend
|
||||
python3-chardet python3-configobj python3-cryptography python3-distutils
|
||||
python3-idna python3-importlib-metadata python3-jinja2 python3-json-pointer
|
||||
python3-jsonpatch python3-jsonschema python3-jwt python3-lib2to3
|
||||
python3-markupsafe python3-more-itertools python3-netifaces python3-oauthlib
|
||||
python3-pkg-resources python3-pyrsistent python3-requests python3-serial
|
||||
python3-setuptools python3-six python3-urllib3 python3-yaml python3-zipp
|
||||
Suggested packages:
|
||||
resolvconf avahi-autoipd isc-dhcp-client-ddns network-manager
|
||||
| wpasupplicant python-attr-doc python-blinker-doc python-configobj-doc
|
||||
python-cryptography-doc python3-cryptography-vectors python-jinja2-doc
|
||||
python-jsonschema-doc python3-crypto python3-openssl python3-socks
|
||||
python3-wxgtk3.0 | python3-wxgtk python-setuptools-doc
|
||||
Recommended packages:
|
||||
eatmydata gdisk software-properties-common isc-dhcp-common libglib2.0-data
|
||||
shared-mime-info xdg-user-dirs
|
||||
The following NEW packages will be installed:
|
||||
ca-certificates cloud-guest-utils cloud-init isc-dhcp-client
|
||||
libdns-export1109 libglib2.0-0 libisc-export1105 libnetplan0 libyaml-0-2
|
||||
netplan.io openssl python3-attr python3-blinker python3-certifi
|
||||
python3-cffi-backend python3-chardet python3-configobj python3-cryptography
|
||||
python3-distutils python3-idna python3-importlib-metadata python3-jinja2
|
||||
python3-json-pointer python3-jsonpatch python3-jsonschema python3-jwt
|
||||
python3-lib2to3 python3-markupsafe python3-more-itertools python3-netifaces
|
||||
python3-oauthlib python3-pkg-resources python3-pyrsistent python3-requests
|
||||
python3-serial python3-setuptools python3-six python3-urllib3 python3-yaml
|
||||
python3-zipp
|
||||
0 upgraded, 40 newly installed, 0 to remove and 0 not upgraded.
|
||||
Need to get 5855 kB of archives.
|
||||
After this operation, 22.3 MB of additional disk space will be used.
|
||||
Get:1 http://archive.ubuntu.com/ubuntu focal/main amd64 openssl amd64 1.1.1f-1ubuntu2 [621 kB]
|
||||
Get:2 http://archive.ubuntu.com/ubuntu focal/main amd64 ca-certificates all 20190110ubuntu1 [146 kB]
|
||||
Get:3 http://archive.ubuntu.com/ubuntu focal/main amd64 libisc-export1105 amd64 1:9.11.16+dfsg-3~build1 [174 kB]
|
||||
Get:4 http://archive.ubuntu.com/ubuntu focal/main amd64 libdns-export1109 amd64 1:9.11.16+dfsg-3~build1 [767 kB]
|
||||
Get:5 http://archive.ubuntu.com/ubuntu focal/main amd64 isc-dhcp-client amd64 4.4.1-2.1ubuntu5 [246 kB]
|
||||
Get:6 http://archive.ubuntu.com/ubuntu focal/main amd64 libglib2.0-0 amd64 2.64.2-1~fakesync1 [1284 kB]
|
||||
Get:7 http://archive.ubuntu.com/ubuntu focal/main amd64 libyaml-0-2 amd64 0.2.2-1 [48.9 kB]
|
||||
Get:8 http://archive.ubuntu.com/ubuntu focal/main amd64 libnetplan0 amd64 0.99-0ubuntu1 [22.9 kB]
|
||||
Get:9 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-yaml amd64 5.3.1-1 [135 kB]
|
||||
Get:10 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-netifaces amd64 0.10.4-1ubuntu4 [16.1 kB]
|
||||
Get:11 http://archive.ubuntu.com/ubuntu focal/main amd64 netplan.io amd64 0.99-0ubuntu1 [70.8 kB]
|
||||
Get:12 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-cffi-backend amd64 1.14.0-1build1 [68.7 kB]
|
||||
Get:13 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-pkg-resources all 45.2.0-1 [130 kB]
|
||||
Get:14 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-six all 1.14.0-2 [12.1 kB]
|
||||
Get:15 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-attr all 19.3.0-2 [33.9 kB]
|
||||
Get:16 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-blinker all 1.4+dfsg1-0.3ubuntu1 [13.2 kB]
|
||||
Get:17 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-certifi all 2019.11.28-1 [149 kB]
|
||||
Get:18 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-chardet all 3.0.4-4build1 [80.4 kB]
|
||||
Get:19 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-configobj all 5.0.6-4 [34.1 kB]
|
||||
Get:20 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-cryptography amd64 2.8-3 [211 kB]
|
||||
Get:21 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-lib2to3 all 3.8.2-1ubuntu1 [74.1 kB]
|
||||
Get:22 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-distutils all 3.8.2-1ubuntu1 [140 kB]
|
||||
Get:23 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-idna all 2.8-1 [34.6 kB]
|
||||
Get:24 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-more-itertools all 4.2.0-1build1 [39.4 kB]
|
||||
Get:25 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-zipp all 1.0.0-1 [5312 B]
|
||||
Get:26 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-importlib-metadata all 1.5.0-1 [9992 B]
|
||||
Get:27 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-markupsafe amd64 1.1.0-1build2 [13.9 kB]
|
||||
Get:28 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-jinja2 all 2.10.1-2 [95.5 kB]
|
||||
Get:29 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-json-pointer all 2.0-0ubuntu1 [8320 B]
|
||||
Get:30 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-jsonpatch all 1.23-3 [12.0 kB]
|
||||
Get:31 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-setuptools all 45.2.0-1 [330 kB]
|
||||
Get:32 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-pyrsistent amd64 0.15.5-1build1 [52.1 kB]
|
||||
Get:33 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-jsonschema all 3.2.0-0ubuntu2 [43.1 kB]
|
||||
Get:34 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-jwt all 1.7.1-2ubuntu2 [17.4 kB]
|
||||
Get:35 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-oauthlib all 3.1.0-1ubuntu2 [84.8 kB]
|
||||
Get:36 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-urllib3 all 1.25.8-2 [88.1 kB]
|
||||
Get:37 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-requests all 2.22.0-2ubuntu1 [47.1 kB]
|
||||
Get:38 http://archive.ubuntu.com/ubuntu focal/main amd64 python3-serial all 3.4-5.1 [72.4 kB]
|
||||
Get:39 http://archive.ubuntu.com/ubuntu focal/main amd64 cloud-guest-utils all 0.31-7-gd99b2d76-0ubuntu1 [16.2 kB]
|
||||
Get:40 http://archive.ubuntu.com/ubuntu focal/main amd64 cloud-init all 20.1-10-g71af48df-0ubuntu5 [406 kB]
|
||||
Fetched 5855 kB in 2s (2541 kB/s)
|
||||
Selecting previously unselected package openssl.
|
||||
(Reading database ... 46818 files and directories currently installed.)
|
||||
Preparing to unpack .../00-openssl_1.1.1f-1ubuntu2_amd64.deb ...
|
||||
Unpacking openssl (1.1.1f-1ubuntu2) ...
|
||||
Selecting previously unselected package ca-certificates.
|
||||
Preparing to unpack .../01-ca-certificates_20190110ubuntu1_all.deb ...
|
||||
Unpacking ca-certificates (20190110ubuntu1) ...
|
||||
Selecting previously unselected package libisc-export1105:amd64.
|
||||
Preparing to unpack .../02-libisc-export1105_1%3a9.11.16+dfsg-3~build1_amd64.deb ...
|
||||
Unpacking libisc-export1105:amd64 (1:9.11.16+dfsg-3~build1) ...
|
||||
Selecting previously unselected package libdns-export1109.
|
||||
Preparing to unpack .../03-libdns-export1109_1%3a9.11.16+dfsg-3~build1_amd64.deb ...
|
||||
Unpacking libdns-export1109 (1:9.11.16+dfsg-3~build1) ...
|
||||
Selecting previously unselected package isc-dhcp-client.
|
||||
Preparing to unpack .../04-isc-dhcp-client_4.4.1-2.1ubuntu5_amd64.deb ...
|
||||
Unpacking isc-dhcp-client (4.4.1-2.1ubuntu5) ...
|
||||
Selecting previously unselected package libglib2.0-0:amd64.
|
||||
Preparing to unpack .../05-libglib2.0-0_2.64.2-1~fakesync1_amd64.deb ...
|
||||
Unpacking libglib2.0-0:amd64 (2.64.2-1~fakesync1) ...
|
||||
Selecting previously unselected package libyaml-0-2:amd64.
|
||||
Preparing to unpack .../06-libyaml-0-2_0.2.2-1_amd64.deb ...
|
||||
Unpacking libyaml-0-2:amd64 (0.2.2-1) ...
|
||||
Selecting previously unselected package libnetplan0:amd64.
|
||||
Preparing to unpack .../07-libnetplan0_0.99-0ubuntu1_amd64.deb ...
|
||||
Unpacking libnetplan0:amd64 (0.99-0ubuntu1) ...
|
||||
Selecting previously unselected package python3-yaml.
|
||||
Preparing to unpack .../08-python3-yaml_5.3.1-1_amd64.deb ...
|
||||
Unpacking python3-yaml (5.3.1-1) ...
|
||||
Selecting previously unselected package python3-netifaces.
|
||||
Preparing to unpack .../09-python3-netifaces_0.10.4-1ubuntu4_amd64.deb ...
|
||||
Unpacking python3-netifaces (0.10.4-1ubuntu4) ...
|
||||
Selecting previously unselected package netplan.io.
|
||||
Preparing to unpack .../10-netplan.io_0.99-0ubuntu1_amd64.deb ...
|
||||
Unpacking netplan.io (0.99-0ubuntu1) ...
|
||||
Selecting previously unselected package python3-cffi-backend.
|
||||
Preparing to unpack .../11-python3-cffi-backend_1.14.0-1build1_amd64.deb ...
|
||||
Unpacking python3-cffi-backend (1.14.0-1build1) ...
|
||||
Selecting previously unselected package python3-pkg-resources.
|
||||
Preparing to unpack .../12-python3-pkg-resources_45.2.0-1_all.deb ...
|
||||
Unpacking python3-pkg-resources (45.2.0-1) ...
|
||||
Selecting previously unselected package python3-six.
|
||||
Preparing to unpack .../13-python3-six_1.14.0-2_all.deb ...
|
||||
Unpacking python3-six (1.14.0-2) ...
|
||||
Selecting previously unselected package python3-attr.
|
||||
Preparing to unpack .../14-python3-attr_19.3.0-2_all.deb ...
|
||||
Unpacking python3-attr (19.3.0-2) ...
|
||||
Selecting previously unselected package python3-blinker.
|
||||
Preparing to unpack .../15-python3-blinker_1.4+dfsg1-0.3ubuntu1_all.deb ...
|
||||
Unpacking python3-blinker (1.4+dfsg1-0.3ubuntu1) ...
|
||||
Selecting previously unselected package python3-certifi.
|
||||
Preparing to unpack .../16-python3-certifi_2019.11.28-1_all.deb ...
|
||||
Unpacking python3-certifi (2019.11.28-1) ...
|
||||
Selecting previously unselected package python3-chardet.
|
||||
Preparing to unpack .../17-python3-chardet_3.0.4-4build1_all.deb ...
|
||||
Unpacking python3-chardet (3.0.4-4build1) ...
|
||||
Selecting previously unselected package python3-configobj.
|
||||
Preparing to unpack .../18-python3-configobj_5.0.6-4_all.deb ...
|
||||
Unpacking python3-configobj (5.0.6-4) ...
|
||||
Selecting previously unselected package python3-cryptography.
|
||||
Preparing to unpack .../19-python3-cryptography_2.8-3_amd64.deb ...
|
||||
Unpacking python3-cryptography (2.8-3) ...
|
||||
Selecting previously unselected package python3-lib2to3.
|
||||
Preparing to unpack .../20-python3-lib2to3_3.8.2-1ubuntu1_all.deb ...
|
||||
Unpacking python3-lib2to3 (3.8.2-1ubuntu1) ...
|
||||
Selecting previously unselected package python3-distutils.
|
||||
Preparing to unpack .../21-python3-distutils_3.8.2-1ubuntu1_all.deb ...
|
||||
Unpacking python3-distutils (3.8.2-1ubuntu1) ...
|
||||
Selecting previously unselected package python3-idna.
|
||||
Preparing to unpack .../22-python3-idna_2.8-1_all.deb ...
|
||||
Unpacking python3-idna (2.8-1) ...
|
||||
Selecting previously unselected package python3-more-itertools.
|
||||
Preparing to unpack .../23-python3-more-itertools_4.2.0-1build1_all.deb ...
|
||||
Unpacking python3-more-itertools (4.2.0-1build1) ...
|
||||
Selecting previously unselected package python3-zipp.
|
||||
Preparing to unpack .../24-python3-zipp_1.0.0-1_all.deb ...
|
||||
Unpacking python3-zipp (1.0.0-1) ...
|
||||
Selecting previously unselected package python3-importlib-metadata.
|
||||
Preparing to unpack .../25-python3-importlib-metadata_1.5.0-1_all.deb ...
|
||||
Unpacking python3-importlib-metadata (1.5.0-1) ...
|
||||
Selecting previously unselected package python3-markupsafe.
|
||||
Preparing to unpack .../26-python3-markupsafe_1.1.0-1build2_amd64.deb ...
|
||||
Unpacking python3-markupsafe (1.1.0-1build2) ...
|
||||
Selecting previously unselected package python3-jinja2.
|
||||
Preparing to unpack .../27-python3-jinja2_2.10.1-2_all.deb ...
|
||||
Unpacking python3-jinja2 (2.10.1-2) ...
|
||||
Selecting previously unselected package python3-json-pointer.
|
||||
Preparing to unpack .../28-python3-json-pointer_2.0-0ubuntu1_all.deb ...
|
||||
Unpacking python3-json-pointer (2.0-0ubuntu1) ...
|
||||
Selecting previously unselected package python3-jsonpatch.
|
||||
Preparing to unpack .../29-python3-jsonpatch_1.23-3_all.deb ...
|
||||
Unpacking python3-jsonpatch (1.23-3) ...
|
||||
Selecting previously unselected package python3-setuptools.
|
||||
Preparing to unpack .../30-python3-setuptools_45.2.0-1_all.deb ...
|
||||
Unpacking python3-setuptools (45.2.0-1) ...
|
||||
Selecting previously unselected package python3-pyrsistent:amd64.
|
||||
Preparing to unpack .../31-python3-pyrsistent_0.15.5-1build1_amd64.deb ...
|
||||
Unpacking python3-pyrsistent:amd64 (0.15.5-1build1) ...
|
||||
Selecting previously unselected package python3-jsonschema.
|
||||
Preparing to unpack .../32-python3-jsonschema_3.2.0-0ubuntu2_all.deb ...
|
||||
Unpacking python3-jsonschema (3.2.0-0ubuntu2) ...
|
||||
Selecting previously unselected package python3-jwt.
|
||||
Preparing to unpack .../33-python3-jwt_1.7.1-2ubuntu2_all.deb ...
|
||||
Unpacking python3-jwt (1.7.1-2ubuntu2) ...
|
||||
Selecting previously unselected package python3-oauthlib.
|
||||
Preparing to unpack .../34-python3-oauthlib_3.1.0-1ubuntu2_all.deb ...
|
||||
Unpacking python3-oauthlib (3.1.0-1ubuntu2) ...
|
||||
Selecting previously unselected package python3-urllib3.
|
||||
Preparing to unpack .../35-python3-urllib3_1.25.8-2_all.deb ...
|
||||
Unpacking python3-urllib3 (1.25.8-2) ...
|
||||
Selecting previously unselected package python3-requests.
|
||||
Preparing to unpack .../36-python3-requests_2.22.0-2ubuntu1_all.deb ...
|
||||
Unpacking python3-requests (2.22.0-2ubuntu1) ...
|
||||
Selecting previously unselected package python3-serial.
|
||||
Preparing to unpack .../37-python3-serial_3.4-5.1_all.deb ...
|
||||
Unpacking python3-serial (3.4-5.1) ...
|
||||
Selecting previously unselected package cloud-guest-utils.
|
||||
Preparing to unpack .../38-cloud-guest-utils_0.31-7-gd99b2d76-0ubuntu1_all.deb ...
|
||||
Unpacking cloud-guest-utils (0.31-7-gd99b2d76-0ubuntu1) ...
|
||||
Selecting previously unselected package cloud-init.
|
||||
Preparing to unpack .../39-cloud-init_20.1-10-g71af48df-0ubuntu5_all.deb ...
|
||||
Unpacking cloud-init (20.1-10-g71af48df-0ubuntu5) ...
|
||||
Setting up python3-pkg-resources (45.2.0-1) ...
|
||||
Setting up python3-attr (19.3.0-2) ...
|
||||
Setting up python3-jwt (1.7.1-2ubuntu2) ...
|
||||
Setting up libyaml-0-2:amd64 (0.2.2-1) ...
|
||||
Setting up libglib2.0-0:amd64 (2.64.2-1~fakesync1) ...
|
||||
No schema files found: doing nothing.
|
||||
Setting up libnetplan0:amd64 (0.99-0ubuntu1) ...
|
||||
Setting up python3-yaml (5.3.1-1) ...
|
||||
Setting up python3-markupsafe (1.1.0-1build2) ...
|
||||
Setting up python3-serial (3.4-5.1) ...
|
||||
Setting up python3-six (1.14.0-2) ...
|
||||
Setting up python3-jinja2 (2.10.1-2) ...
|
||||
Setting up libisc-export1105:amd64 (1:9.11.16+dfsg-3~build1) ...
|
||||
Setting up python3-chardet (3.0.4-4build1) ...
|
||||
Setting up python3-configobj (5.0.6-4) ...
|
||||
Setting up python3-idna (2.8-1) ...
|
||||
Setting up python3-urllib3 (1.25.8-2) ...
|
||||
Setting up python3-netifaces (0.10.4-1ubuntu4) ...
|
||||
Setting up python3-pyrsistent:amd64 (0.15.5-1build1) ...
|
||||
Setting up python3-json-pointer (2.0-0ubuntu1) ...
|
||||
Setting up openssl (1.1.1f-1ubuntu2) ...
|
||||
Setting up python3-lib2to3 (3.8.2-1ubuntu1) ...
|
||||
Setting up cloud-guest-utils (0.31-7-gd99b2d76-0ubuntu1) ...
|
||||
Setting up python3-cffi-backend (1.14.0-1build1) ...
|
||||
Setting up python3-blinker (1.4+dfsg1-0.3ubuntu1) ...
|
||||
Setting up python3-distutils (3.8.2-1ubuntu1) ...
|
||||
Setting up python3-more-itertools (4.2.0-1build1) ...
|
||||
Setting up python3-setuptools (45.2.0-1) ...
|
||||
Setting up libdns-export1109 (1:9.11.16+dfsg-3~build1) ...
|
||||
Setting up python3-jsonpatch (1.23-3) ...
|
||||
update-alternatives: using /usr/bin/jsonpatch-jsondiff to provide /usr/bin/jsondiff (jsondiff) in auto mode
|
||||
Setting up isc-dhcp-client (4.4.1-2.1ubuntu5) ...
|
||||
Setting up python3-zipp (1.0.0-1) ...
|
||||
Setting up netplan.io (0.99-0ubuntu1) ...
|
||||
Setting up ca-certificates (20190110ubuntu1) ...
|
||||
debconf: unable to initialize frontend: Dialog
|
||||
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)
|
||||
debconf: falling back to frontend: Readline
|
||||
debconf: unable to initialize frontend: Readline
|
||||
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)
|
||||
debconf: falling back to frontend: Teletype
|
||||
Updating certificates in /etc/ssl/certs...
|
||||
128 added, 0 removed; done.
|
||||
Setting up python3-certifi (2019.11.28-1) ...
|
||||
Setting up python3-cryptography (2.8-3) ...
|
||||
Setting up python3-requests (2.22.0-2ubuntu1) ...
|
||||
Setting up python3-importlib-metadata (1.5.0-1) ...
|
||||
Setting up python3-oauthlib (3.1.0-1ubuntu2) ...
|
||||
Setting up python3-jsonschema (3.2.0-0ubuntu2) ...
|
||||
Setting up cloud-init (20.1-10-g71af48df-0ubuntu5) ...
|
||||
debconf: unable to initialize frontend: Dialog
|
||||
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)
|
||||
debconf: falling back to frontend: Readline
|
||||
debconf: unable to initialize frontend: Readline
|
||||
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)
|
||||
debconf: falling back to frontend: Teletype
|
||||
No diversion 'diversion of /etc/init/ureadahead.conf to /etc/init/ureadahead.conf.disabled by cloud-init', none removed.
|
||||
Created symlink /etc/systemd/system/cloud-init.target.wants/cloud-config.service → /lib/systemd/system/cloud-config.service.
|
||||
Created symlink /etc/systemd/system/cloud-init.target.wants/cloud-final.service → /lib/systemd/system/cloud-final.service.
|
||||
Created symlink /etc/systemd/system/cloud-init.target.wants/cloud-init-local.service → /lib/systemd/system/cloud-init-local.service.
|
||||
Created symlink /etc/systemd/system/cloud-init.target.wants/cloud-init.service → /lib/systemd/system/cloud-init.service.
|
||||
Processing triggers for libc-bin (2.31-0ubuntu9) ...
|
||||
Processing triggers for ca-certificates (20190110ubuntu1) ...
|
||||
Updating certificates in /etc/ssl/certs...
|
||||
0 added, 0 removed; done.
|
||||
Running hooks in /etc/ca-certificates/update.d...
|
||||
done.
|
||||
# # + rm -rf /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_focal_InRelease /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_focal_main_binary-amd64_Packages /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_focal_main_i18n_Translation-en /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_focal_universe_binary-amd64_Packages /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_focal_universe_i18n_Translation-en /var/lib/apt/lists/auxfiles /var/lib/apt/lists/lock /var/lib/apt/lists/partial
|
||||
#
|
||||
+ mkdir -p /root/LIVE_BOOT/image/openstack/latest
|
||||
+ cp /builder/meta_data.json /root/LIVE_BOOT/image/openstack/latest
|
||||
+ cp /config/user-data /root/LIVE_BOOT/image/openstack/latest/user_data
|
||||
+ yq r -j /config/network-config
|
||||
+ echo 'datasource_list: [ ConfigDrive, None ]'
|
||||
+ _make_kernel
|
||||
+ mkdir -p /root/LIVE_BOOT/scratch /root/LIVE_BOOT/image/live
|
||||
+ mksquashfs /root/LIVE_BOOT/chroot /root/LIVE_BOOT/image/live/filesystem.squashfs -e boot
|
||||
Parallel mksquashfs: Using 24 processors
|
||||
Creating 4.0 filesystem on /root/LIVE_BOOT/image/live/filesystem.squashfs, block size 131072.
|
||||
|
||||
|
||||
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
|
||||
compressed data, compressed metadata, compressed fragments,
|
||||
compressed xattrs, compressed ids
|
||||
duplicates are removed
|
||||
Filesystem size 624492.88 Kbytes (609.86 Mbytes)
|
||||
45.67% of uncompressed filesystem size (1367509.59 Kbytes)
|
||||
Inode table size 459804 bytes (449.03 Kbytes)
|
||||
26.38% of uncompressed inode table size (1743271 bytes)
|
||||
Directory table size 486559 bytes (475.16 Kbytes)
|
||||
44.71% of uncompressed directory table size (1088368 bytes)
|
||||
Xattr table size 36 bytes (0.04 Kbytes)
|
||||
90.00% of uncompressed xattr table size (40 bytes)
|
||||
Number of duplicate files found 8756
|
||||
Number of inodes 52089
|
||||
Number of files 41051
|
||||
Number of fragments 2859
|
||||
Number of symbolic links 1709
|
||||
Number of device nodes 8
|
||||
Number of fifo nodes 0
|
||||
Number of socket nodes 0
|
||||
Number of directories 9321
|
||||
Number of ids (unique uids + gids) 11
|
||||
Number of uids 3
|
||||
root (0)
|
||||
unknown (102)
|
||||
_apt (100)
|
||||
Number of gids 10
|
||||
root (0)
|
||||
shadow (42)
|
||||
unknown (102)
|
||||
unknown (103)
|
||||
utmp (43)
|
||||
unknown (110)
|
||||
tty (5)
|
||||
staff (50)
|
||||
adm (4)
|
||||
mail (8)
|
||||
+ cp /root/LIVE_BOOT/chroot/boot/vmlinuz-5.4.0-26-generic /root/LIVE_BOOT/image/vmlinuz
|
||||
+ cp /root/LIVE_BOOT/chroot/boot/initrd.img-5.4.0-26-generic /root/LIVE_BOOT/image/initrd
|
||||
+ _grub_install
|
||||
+ cp /builder/grub.conf /root/LIVE_BOOT/scratch/grub.cfg
|
||||
+ touch /root/LIVE_BOOT/image/UBUNTU_FOCAL_CUSTOM
|
||||
+ grub-mkstandalone --format=x86_64-efi --output=/root/LIVE_BOOT/scratch/bootx64.efi --locales= --fonts= boot/grub/grub.cfg=/root/LIVE_BOOT/scratch/grub.cfg
|
||||
+ cd /root/LIVE_BOOT/scratch
|
||||
+ dd if=/dev/zero of=efiboot.img bs=1M count=10
|
||||
10+0 records in
|
||||
10+0 records out
|
||||
10485760 bytes (10 MB, 10 MiB) copied, 0.00700445 s, 1.5 GB/s
|
||||
+ mkfs.vfat efiboot.img
|
||||
mkfs.fat 4.1 (2017-01-24)
|
@ -21,7 +21,7 @@ const (
|
||||
Ephemeral = "ephemeral"
|
||||
InitinfraPhase = "initinfra"
|
||||
ClusterctlPhase = InitinfraPhase
|
||||
BootstrapPhase = "bootstrap"
|
||||
BootstrapPhase = "bootstrap-iso"
|
||||
)
|
||||
|
||||
// Constants defining default values
|
||||
|
@ -15,6 +15,7 @@
|
||||
package document
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -290,3 +291,31 @@ func NewDocumentFromBytes(b []byte) (Document, error) {
|
||||
err = doc.SetKustomizeResource(res)
|
||||
return doc, err
|
||||
}
|
||||
|
||||
// DecodeSecretData returns base64-decoded secret data
|
||||
func DecodeSecretData(cfg Document, key string) ([]byte, error) {
|
||||
var needsBase64Decode = false
|
||||
|
||||
// TODO(alanmeadows): distinguish between missing key
|
||||
// and missing data/stringData keys in the Secret
|
||||
data, err := cfg.GetStringMap("data")
|
||||
if err == nil {
|
||||
needsBase64Decode = true
|
||||
} else {
|
||||
// we'll catch any error below
|
||||
data, err = cfg.GetStringMap("stringData")
|
||||
if err != nil {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: "data or stringData"}
|
||||
}
|
||||
}
|
||||
|
||||
res, ok := data[key]
|
||||
if !ok {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: key}
|
||||
}
|
||||
|
||||
if needsBase64Decode {
|
||||
return b64.StdEncoding.DecodeString(res)
|
||||
}
|
||||
return []byte(res), nil
|
||||
}
|
||||
|
@ -49,6 +49,19 @@ type ErrRuntimeObjectKind struct {
|
||||
Obj runtime.Object
|
||||
}
|
||||
|
||||
// ErrDataNotSupplied error returned of no data in the Secret
|
||||
type ErrDataNotSupplied struct {
|
||||
DocName string
|
||||
Key string
|
||||
}
|
||||
|
||||
// ErrDuplicateNetworkDataDocuments error returned if multiple matching documents
|
||||
// were found with the same name in the same namespace
|
||||
type ErrDuplicateNetworkDataDocuments struct {
|
||||
DocName string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// ErrBadValueFormat returned if wrong field type requested
|
||||
type ErrBadValueFormat struct {
|
||||
Value string
|
||||
@ -76,6 +89,14 @@ func (e ErrRuntimeObjectKind) Error() string {
|
||||
return fmt.Sprintf("object %#v has either none or multiple kinds in scheme (expected one)", e.Obj)
|
||||
}
|
||||
|
||||
func (e ErrDataNotSupplied) Error() string {
|
||||
return fmt.Sprintf("Document %s has no key %s", e.DocName, e.Key)
|
||||
}
|
||||
|
||||
func (e ErrDuplicateNetworkDataDocuments) Error() string {
|
||||
return fmt.Sprintf("Found more than one document with the name %s in namespace %s", e.DocName, e.Namespace)
|
||||
}
|
||||
|
||||
func (e ErrBadValueFormat) Error() string {
|
||||
return fmt.Sprintf("value of %s expected to have %s type, got %s", e.Value, e.Expected, e.Actual)
|
||||
}
|
||||
|
@ -189,3 +189,37 @@ func NewClusterctlMetadataSelector() Selector {
|
||||
ClusterctlMetadataVersion,
|
||||
ClusterctlMetadataKind)
|
||||
}
|
||||
|
||||
//GetSecretData returns data located with a given key of a given document
|
||||
func GetSecretData(docBundle Bundle, apiSelector types.Selector, key string) ([]byte, error) {
|
||||
s := NewSelector()
|
||||
if apiSelector.Group != "" && apiSelector.Version != "" && apiSelector.Kind != "" {
|
||||
s = s.ByGvk(apiSelector.Group, apiSelector.Version, apiSelector.Kind)
|
||||
} else if apiSelector.Kind != "" {
|
||||
s = s.ByKind(apiSelector.Kind)
|
||||
}
|
||||
if apiSelector.Namespace != "" {
|
||||
s = s.ByNamespace(apiSelector.Namespace)
|
||||
}
|
||||
if apiSelector.Name != "" {
|
||||
s = s.ByName(apiSelector.Name)
|
||||
}
|
||||
if apiSelector.AnnotationSelector != "" {
|
||||
s = s.ByAnnotation(apiSelector.AnnotationSelector)
|
||||
}
|
||||
if apiSelector.LabelSelector != "" {
|
||||
s = s.ByLabel(apiSelector.LabelSelector)
|
||||
}
|
||||
|
||||
doc, docErr := docBundle.SelectOne(s)
|
||||
if docErr != nil {
|
||||
return nil, docErr
|
||||
}
|
||||
|
||||
// finally, try and retrieve the data we want from the document
|
||||
data, keyErr := DecodeSecretData(doc, key)
|
||||
if keyErr != nil {
|
||||
return nil, keyErr
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
@ -60,6 +60,16 @@ func TestSelectorsPositive(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, doc, 1)
|
||||
})
|
||||
|
||||
t.Run("TestGetSecretData", func(t *testing.T) {
|
||||
data, err := document.GetSecretData(bundle, types.Selector{
|
||||
Gvk: resid.Gvk{Kind: "Secret"},
|
||||
LabelSelector: "airshipit.org/ephemeral-user-data",
|
||||
},
|
||||
"userData")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte("cloud-init"), data)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSelectorsNegative(t *testing.T) {
|
||||
|
@ -28,10 +28,10 @@ func (e ErrUnknownExecutorAction) Error() string {
|
||||
return fmt.Sprintf("unknown action type '%s'", e.Action)
|
||||
}
|
||||
|
||||
// ErrIsoGenNilBundle is returned when isogen executor is not provided with bundle
|
||||
type ErrIsoGenNilBundle struct {
|
||||
// ErrIsogenNilBundle is returned when isogen executor is not provided with bundle
|
||||
type ErrIsogenNilBundle struct {
|
||||
}
|
||||
|
||||
func (e ErrIsoGenNilBundle) Error() string {
|
||||
func (e ErrIsogenNilBundle) Error() string {
|
||||
return "Cannot build iso with empty bundle, no data source is available"
|
||||
}
|
||||
|
@ -40,13 +40,13 @@ type IsogenExecutor struct {
|
||||
ExecutorBundle document.Bundle
|
||||
ExecutorDocument document.Document
|
||||
|
||||
ImgConf *v1alpha1.ImageConfiguration
|
||||
ImgConf *v1alpha1.IsoConfiguration
|
||||
Builder container.Container
|
||||
}
|
||||
|
||||
// RegisterIsogenExecutor adds executor to phase executor registry
|
||||
func RegisterIsogenExecutor(registry map[schema.GroupVersionKind]ifc.ExecutorFactory) error {
|
||||
obj := v1alpha1.DefaultImageConfiguration()
|
||||
obj := v1alpha1.DefaultIsoConfiguration()
|
||||
gvks, _, err := v1alpha1.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -57,9 +57,9 @@ func RegisterIsogenExecutor(registry map[schema.GroupVersionKind]ifc.ExecutorFac
|
||||
|
||||
// NewIsogenExecutor creates instance of phase executor
|
||||
func NewIsogenExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) {
|
||||
apiObj := &v1alpha1.ImageConfiguration{
|
||||
Container: &v1alpha1.Container{},
|
||||
Builder: &v1alpha1.Builder{},
|
||||
apiObj := &v1alpha1.IsoConfiguration{
|
||||
IsoContainer: &v1alpha1.IsoContainer{},
|
||||
Isogen: &v1alpha1.Isogen{},
|
||||
}
|
||||
err := cfg.ExecutorDocument.ToAPIObject(apiObj, v1alpha1.Scheme)
|
||||
if err != nil {
|
||||
@ -83,7 +83,7 @@ func (c *IsogenExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
|
||||
defer close(evtCh)
|
||||
|
||||
if c.ExecutorBundle == nil {
|
||||
handleError(evtCh, ErrIsoGenNilBundle{})
|
||||
handleError(evtCh, ErrIsogenNilBundle{})
|
||||
return
|
||||
}
|
||||
|
||||
@ -104,8 +104,8 @@ func (c *IsogenExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
|
||||
ctx := context.Background()
|
||||
builder, err := container.NewContainer(
|
||||
ctx,
|
||||
c.ImgConf.Container.ContainerRuntime,
|
||||
c.ImgConf.Container.Image)
|
||||
c.ImgConf.IsoContainer.ContainerRuntime,
|
||||
c.ImgConf.IsoContainer.Image)
|
||||
c.Builder = builder
|
||||
if err != nil {
|
||||
handleError(evtCh, err)
|
||||
@ -118,8 +118,6 @@ func (c *IsogenExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
|
||||
Builder: c.Builder,
|
||||
Doc: c.ExecutorDocument,
|
||||
Cfg: c.ImgConf,
|
||||
Debug: log.DebugEnabled(),
|
||||
Progress: opts.Progress,
|
||||
Writer: log.Writer(),
|
||||
}
|
||||
|
||||
@ -145,10 +143,10 @@ func (c *IsogenExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
|
||||
})
|
||||
}
|
||||
|
||||
func verifyArtifacts(cfg *v1alpha1.ImageConfiguration) error {
|
||||
hostVol := strings.Split(cfg.Container.Volume, ":")[0]
|
||||
metadataPath := filepath.Join(hostVol, cfg.Builder.OutputMetadataFileName)
|
||||
_, err := os.Stat(metadataPath)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
package executors_test
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -36,19 +39,17 @@ import (
|
||||
var (
|
||||
isogenExecutorDoc = `
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: ImageConfiguration
|
||||
kind: IsoConfiguration
|
||||
metadata:
|
||||
name: isogen
|
||||
labels:
|
||||
airshipit.org/deploy-k8s: "false"
|
||||
builder:
|
||||
networkConfigFileName: network-config
|
||||
outputMetadataFileName: output-metadata.yaml
|
||||
userDataFileName: user-data
|
||||
outputFileName: ephemeral.iso
|
||||
container:
|
||||
containerRuntime: docker
|
||||
image: quay.io/airshipit/isogen:latest-ubuntu_focal
|
||||
volume: /srv/iso:/config`
|
||||
image: quay.io/airshipit/image-builder:latest-ubuntu_focal
|
||||
volume: /srv/images:/config`
|
||||
executorBundlePath = "../../bootstrap/isogen/testdata/primary/site/test-site/ephemeral/bootstrap"
|
||||
)
|
||||
|
||||
@ -57,7 +58,7 @@ func TestRegisterIsogenExecutor(t *testing.T) {
|
||||
expectedGVK := schema.GroupVersionKind{
|
||||
Group: "airshipit.org",
|
||||
Version: "v1alpha1",
|
||||
Kind: "ImageConfiguration",
|
||||
Kind: "IsoConfiguration",
|
||||
}
|
||||
err := executors.RegisterIsogenExecutor(registry)
|
||||
require.NoError(t, err)
|
||||
@ -83,15 +84,20 @@ func TestIsogenExecutorRun(t *testing.T) {
|
||||
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.ImageConfiguration{
|
||||
Container: &v1alpha1.Container{
|
||||
testCfg := &v1alpha1.IsoConfiguration{
|
||||
IsoContainer: &v1alpha1.IsoContainer{
|
||||
Volume: volBind,
|
||||
ContainerRuntime: "docker",
|
||||
},
|
||||
Builder: &v1alpha1.Builder{
|
||||
UserDataFileName: "user-data",
|
||||
NetworkConfigFileName: "net-conf",
|
||||
Isogen: &v1alpha1.Isogen{
|
||||
OutputFileName: "ephemeral.iso",
|
||||
},
|
||||
}
|
||||
testDoc := &testdoc.MockDocument{
|
||||
|
@ -2,7 +2,7 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: Phase
|
||||
metadata:
|
||||
name: bootstrap
|
||||
name: bootstrap-iso
|
||||
clusterName: ephemeral-cluster
|
||||
config:
|
||||
executorRef:
|
||||
|
@ -2,7 +2,7 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: Phase
|
||||
metadata:
|
||||
name: bootstrap
|
||||
name: bootstrap-iso
|
||||
clusterName: ephemeral-cluster
|
||||
config:
|
||||
executorRef:
|
||||
|
@ -2,7 +2,7 @@
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
kind: Phase
|
||||
metadata:
|
||||
name: bootstrap
|
||||
name: bootstrap-iso
|
||||
clusterName: ephemeral-cluster
|
||||
config:
|
||||
executorRef:
|
||||
|
@ -19,7 +19,7 @@
|
||||
- ./tools/deployment/21_systemwide_executable.sh
|
||||
- ./tools/deployment/22_test_configs.sh
|
||||
- ./tools/deployment/23_pull_documents.sh
|
||||
- ./tools/deployment/24_build_ephemeral_iso.sh
|
||||
- ./tools/deployment/24_build_images.sh
|
||||
- ./tools/deployment/25_deploy_ephemeral_node.sh
|
||||
- ./tools/deployment/26_deploy_metal3_capi_ephemeral_node.sh
|
||||
- ./tools/deployment/30_deploy_controlplane.sh
|
||||
|
@ -15,7 +15,7 @@ airship_config_iso_gen_target_path: "{{ serve_dir }}"
|
||||
airship_config_phase_repo_url: "https://review.opendev.org/airship/airshipctl"
|
||||
airship_config_manifest_directory: "{{ remote_work_dir | default(zuul.project.src_dir) | default(local_src_dir) }}"
|
||||
airship_config_ephemeral_ip: "{{ airship_gate_ipam.nat_network.ephemeral_ip }}"
|
||||
airship_config_iso_builder_docker_image: "quay.io/airshipit/isogen:latest-ubuntu_focal"
|
||||
airship_config_iso_builder_docker_image: "quay.io/airshipit/image-builder:latest-ubuntu_focal"
|
||||
airship_config_site_path: manifests/site/test-site
|
||||
airship_config_ca_data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
airship_config_client_cert_data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
set -xe
|
||||
|
||||
export ISO_DIR=${ISO_DIR:-"/srv/iso"}
|
||||
export IMAGE_DIR=${IMAGE_DIR:-"/srv/images"}
|
||||
export SERVE_PORT=${SERVE_PORT:-"8099"}
|
||||
export AIRSHIPCTL_WS=${AIRSHIPCTL_WS:-$PWD}
|
||||
export USER_NAME=${USER:-"ubuntu"}
|
||||
@ -22,14 +22,14 @@ export USE_PROXY=${USE_PROXY:-"false"}
|
||||
export HTTPS_PROXY=${HTTPS_PROXY:-${https_proxy}}
|
||||
export HTTP_PROXY=${HTTP_PROXY:-${http_proxy}}
|
||||
export NO_PROXY=${NO_PROXY:-${no_proxy}}
|
||||
export AIRSHIP_CONFIG_ISO_GEN_TARGET_PATH=${ISO_DIR}
|
||||
export AIRSHIP_CONFIG_ISO_BUILDER_DOCKER_IMAGE=${BUILDER_IMAGE:-"quay.io/airshipit/isogen:latest-ubuntu_focal"}
|
||||
export AIRSHIP_CONFIG_ISO_GEN_TARGET_PATH=${IMAGE_DIR}
|
||||
export AIRSHIP_CONFIG_ISO_BUILDER_DOCKER_IMAGE=${BUILDER_IMAGE:-"quay.io/airshipit/image-builder:latest-ubuntu_focal"}
|
||||
export REMOTE_TYPE=redfish
|
||||
export REMOTE_INSECURE=true
|
||||
export REMOTE_PROXY=false
|
||||
export AIRSHIP_CONFIG_ISO_SERVE_HOST=${HOST:-"localhost"}
|
||||
export AIRSHIP_CONFIG_ISO_PORT=${SERVE_PORT}
|
||||
export AIRSHIP_CONFIG_ISO_NAME=${ISO_NAME:-"ubuntu-focal.iso"}
|
||||
export AIRSHIP_CONFIG_ISO_NAME=${ISO_NAME:-"ephemeral.iso"}
|
||||
export AIRSHIP_CONFIG_METADATA_PATH=${AIRSHIP_CONFIG_METADATA_PATH:-"manifests/site/test-site/metadata.yaml"}
|
||||
export SYSTEM_ACTION_RETRIES=30
|
||||
export SYSTEM_REBOOT_DELAY=30
|
||||
|
@ -16,27 +16,32 @@ set -xe
|
||||
|
||||
export USER_NAME=${USER:-"ubuntu"}
|
||||
|
||||
ISO_DIR=${ISO_DIR:-"/srv/iso"}
|
||||
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"}
|
||||
|
||||
#Create serving directories and assign permission and ownership
|
||||
sudo rm -rf ${ISO_DIR}
|
||||
sudo mkdir -p ${ISO_DIR}
|
||||
sudo chmod -R 755 ${ISO_DIR}
|
||||
sudo chown -R ${USER_NAME} ${ISO_DIR}
|
||||
sudo rm -rf ${IMAGE_DIR}
|
||||
sudo mkdir -p ${IMAGE_DIR}
|
||||
sudo chmod -R 755 ${IMAGE_DIR}
|
||||
sudo chown -R ${USER_NAME} ${IMAGE_DIR}
|
||||
|
||||
echo "Build ephemeral iso"
|
||||
airshipctl phase run bootstrap --debug
|
||||
unset IFS
|
||||
for phase in $IMAGE_PHASES; do
|
||||
echo "Build phase: $phase"
|
||||
airshipctl phase run $phase --debug
|
||||
done
|
||||
|
||||
echo "List generated iso"
|
||||
ls -lth ${ISO_DIR}
|
||||
echo "List generated images"
|
||||
ls -lth ${IMAGE_DIR}
|
||||
|
||||
echo "Remove the container used for iso generation"
|
||||
echo "Remove the container used for image generation"
|
||||
sudo docker rm $(docker ps -a -f status=exited -q)
|
||||
|
||||
#cleanup the directories
|
||||
if [ "${CLEANUP_SERVE_DIR}" == "true" ] || [ "${CLEANUP_SERVE_DIR}" == "True" ]; then
|
||||
echo "Clean directories used by ephemeral iso build"
|
||||
sudo rm -rf ${ISO_DIR}
|
||||
echo "Clean directories used by image-builder"
|
||||
sudo rm -rf ${IMAGE_DIR}
|
||||
fi
|
@ -14,7 +14,7 @@
|
||||
|
||||
set -ex
|
||||
|
||||
TARGET_IMAGE_DIR="/srv/iso"
|
||||
TARGET_IMAGE_DIR="/srv/images"
|
||||
EPHEMERAL_DOMAIN_NAME="air-ephemeral"
|
||||
TARGET_IMAGE_URL="https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
|
||||
export KUBECONFIG=${KUBECONFIG:-"$HOME/.airship/kubeconfig"}
|
||||
@ -45,7 +45,7 @@ if [ "${DOWNLOAD}" != "304" ]
|
||||
then
|
||||
curl -sSLo ${TARGET_IMAGE_DIR}/target-image.qcow2 ${TARGET_IMAGE_URL}
|
||||
fi
|
||||
md5sum /srv/iso/target-image.qcow2 | cut -d ' ' -f 1 > ${TARGET_IMAGE_DIR}/target-image.qcow2.md5sum
|
||||
md5sum /srv/images/target-image.qcow2 | cut -d ' ' -f 1 > ${TARGET_IMAGE_DIR}/target-image.qcow2.md5sum
|
||||
|
||||
echo "Create target k8s cluster resources"
|
||||
airshipctl phase run controlplane-ephemeral --debug
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
set -xe
|
||||
|
||||
export ISO_DIR=${ISO_DIR:-"/srv/iso"}
|
||||
export IMAGE_DIR=${IMAGE_DIR:-"/srv/images"}
|
||||
export SERVE_PORT=${SERVE_PORT:-"8099"}
|
||||
export AIRSHIPCTL_WS=${AIRSHIPCTL_WS:-$PWD}
|
||||
export USER_NAME=${USER:-"ubuntu"}
|
||||
@ -23,8 +23,8 @@ export HTTPS_PROXY=${HTTPS_PROXY:-${https_proxy}}
|
||||
export HTTPS_PROXY=${HTTP_PROXY:-${http_proxy}}
|
||||
export NO_PROXY=${NO_PROXY:-${no_proxy}}
|
||||
export REMOTE_WORK_DIR=${remote_work_dir:-"/tmp/airship"}
|
||||
export AIRSHIP_CONFIG_ISO_GEN_TARGET_PATH=${ISO_DIR}
|
||||
export AIRSHIP_CONFIG_ISO_BUILDER_DOCKER_IMAGE=${BUILDER_IMAGE:-"quay.io/airshipit/isogen:latest-debian_stable"}
|
||||
export AIRSHIP_CONFIG_ISO_GEN_TARGET_PATH=${IMAGE_DIR}
|
||||
export AIRSHIP_CONFIG_ISO_BUILDER_DOCKER_IMAGE=${BUILDER_IMAGE:-"quay.io/airshipit/image-builder:latest-ubuntu_focal"}
|
||||
export REMOTE_TYPE=redfish
|
||||
export REMOTE_INSECURE=true
|
||||
export REMOTE_PROXY=false
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
set -x
|
||||
|
||||
sudo rm -rf ~/.airship/ ~/.ansible.cfg /srv/iso/* /tmp/airship/
|
||||
sudo rm -rf ~/.airship/ ~/.ansible.cfg /srv/images/* /tmp/airship/
|
||||
sudo service sushy-tools stop
|
||||
sudo service apache2 stop
|
||||
sudo kill -9 $(lsof -t -i:8000 -i:8099)
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
set -xe
|
||||
|
||||
export ISO_DIR=${ISO_DIR:-"/srv/iso"}
|
||||
export IMAGE_DIR=${IMAGE_DIR:-"/srv/images"}
|
||||
export SERVE_PORT=${SERVE_PORT:-"8099"}
|
||||
export AIRSHIPCTL_WS=${AIRSHIPCTL_WS:-$PWD}
|
||||
export TMP_DIR=${TMP_DIR:-"$(dirname $(mktemp -u))"}
|
||||
|
@ -11,7 +11,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
---
|
||||
serve_dir: /srv/iso
|
||||
serve_dir: /srv/images
|
||||
serve_port: 8099
|
||||
local_src_dir: "$AIRSHIPCTL_WS"
|
||||
ansible_user: root
|
||||
|
@ -132,7 +132,7 @@
|
||||
# 21_systemwide_executable.sh is run in the build-gate pre-run above
|
||||
- ./tools/deployment/22_test_configs.sh
|
||||
- ./tools/deployment/23_pull_documents.sh
|
||||
- ./tools/deployment/24_build_ephemeral_iso.sh
|
||||
- ./tools/deployment/24_build_images.sh
|
||||
- ./tools/deployment/25_deploy_ephemeral_node.sh
|
||||
- ./tools/deployment/26_deploy_metal3_capi_ephemeral_node.sh
|
||||
- ./tools/deployment/30_deploy_controlplane.sh
|
||||
@ -142,7 +142,7 @@
|
||||
- ./tools/deployment/34_deploy_worker_node.sh
|
||||
- ./tools/deployment/35_deploy_workload.sh
|
||||
- ./tools/deployment/36_verify_hwcc_profiles.sh
|
||||
serve_dir: /srv/iso
|
||||
serve_dir: /srv/images
|
||||
serve_port: 8099
|
||||
log_roles:
|
||||
- gather-system-logs
|
||||
|
Loading…
Reference in New Issue
Block a user