Skip to content

Commit

Permalink
wire ignition
Browse files Browse the repository at this point in the history
Signed-off-by: Antonio Murdaca <antoniomurdaca@gmail.com>
  • Loading branch information
runcom committed Jan 11, 2023
1 parent 35c93de commit 57c09b2
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 46 deletions.
4 changes: 2 additions & 2 deletions internal/blueprint/customizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type IgnitionCustomization struct {

type EmbeddedIgnitionCustomization struct {
ProvisioningURL string `json:"url,omitempty" toml:"url,omitempty"`
Data64 string `json:"data,omitempty" toml:"data,omitempty"`
Config string `json:"config,omitempty" toml:"config,omitempty"`
}

type FirstBootIgnitionCustomization struct {
Expand Down Expand Up @@ -421,7 +421,7 @@ func (c *EmbeddedIgnitionCustomization) CheckEmbeddedIgnition() error {
if c == nil {
return nil
}
if c.Data64 != "" && c.ProvisioningURL != "" {
if c.Config != "" && c.ProvisioningURL != "" {
t := reflect.TypeOf(*c)
return &CustomizationError{fmt.Sprintf("'%s' and '%s' are not allowed at the same time", t.Field(0).Name, t.Field(1).Name)}
}
Expand Down
13 changes: 9 additions & 4 deletions internal/distro/rhel9/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,10 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,

rawImg.Filename = t.Filename()

if bpIgnition := customizations.GetIgnition(); bpIgnition != nil && bpIgnition.FirstBoot != nil && bpIgnition.FirstBoot.ProvisioningURL != "" {
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "ignition.config.url="+bpIgnition.FirstBoot.ProvisioningURL)
}

// 92+ only
if kopts := customizations.GetKernel(); kopts != nil {
rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, kopts.Append)
Expand All @@ -427,11 +431,12 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
}
// ignition configs from blueprint
if bpIgnition := customizations.GetIgnition(); bpIgnition != nil {
if bpIgnition.FirstBoot != nil {
img.IgnitionFirstBoot = ignition.FirstbootOptionsFromBP(*bpIgnition.FirstBoot)
}
if bpIgnition.Embedded != nil {
img.IgnitionEmbedded = ignition.EmbeddedOptionsFromBP(*bpIgnition.Embedded)
var err error
img.IgnitionEmbedded, err = ignition.EmbeddedOptionsFromBP(*bpIgnition.Embedded)
if err != nil {
return nil, err
}
}
}

Expand Down
21 changes: 16 additions & 5 deletions internal/ignition/ignition.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package ignition

import "github.com/osbuild/osbuild-composer/internal/blueprint"
import (
"encoding/base64"
"errors"

"github.com/osbuild/osbuild-composer/internal/blueprint"
)

type FirstBootOptions struct {
ProvisioningURL string
Expand All @@ -13,10 +18,16 @@ func FirstbootOptionsFromBP(bpIgnitionFirstboot blueprint.FirstBootIgnitionCusto

type EmbeddedOptions struct {
ProvisioningURL string
Data64 string
Config string
}

func EmbeddedOptionsFromBP(bpIgnitionEmbedded blueprint.EmbeddedIgnitionCustomization) *EmbeddedOptions {
ignition := EmbeddedOptions(bpIgnitionEmbedded)
return &ignition
func EmbeddedOptionsFromBP(bpIgnitionEmbedded blueprint.EmbeddedIgnitionCustomization) (*EmbeddedOptions, error) {
decodedConfig, err := base64.StdEncoding.DecodeString(bpIgnitionEmbedded.Config)
if err != nil {
return nil, errors.New("can't decode Ignition config")
}
return &EmbeddedOptions{
ProvisioningURL: bpIgnitionEmbedded.ProvisioningURL,
Config: string(decodedConfig),
}, nil
}
5 changes: 0 additions & 5 deletions internal/image/ostree_simplified_installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,6 @@ func (img *OSTreeSimplifiedInstaller) InstantiateManifest(m *manifest.Manifest,
}
}

// ignition firstboot options
if img.IgnitionFirstBoot != nil {
kernelOpts = append(kernelOpts, "coreos.inst.append ignition.config.url="+img.IgnitionFirstBoot.ProvisioningURL)
}

bootTreePipeline.KernelOpts = kernelOpts

rootfsPartitionTable := &disk.PartitionTable{
Expand Down
4 changes: 2 additions & 2 deletions internal/manifest/coi_iso_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ func (p *CoreOSISOTree) serialize() osbuild.Pipeline {
copyInput := ""
// These specific filenames in the root of the ISO are expected by
// coreos-installer-dracut during installation
if p.coiPipeline.Ignition.Data64 != "" {
if p.coiPipeline.Ignition.Config != "" {
filename = "ignition_config"
copyInput = p.coiPipeline.Ignition.Data64
copyInput = p.coiPipeline.Ignition.Config
} else {
filename = "ignition_url"
copyInput = p.coiPipeline.Ignition.ProvisioningURL
Expand Down
4 changes: 2 additions & 2 deletions internal/manifest/coreos_installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ func (p *CoreOSInstaller) getInline() []string {
}
// inline data for ignition embedded (url or data)
if p.Ignition != nil {
if p.Ignition.Data64 != "" {
inlineData = append(inlineData, p.Ignition.Data64)
if p.Ignition.Config != "" {
inlineData = append(inlineData, p.Ignition.Config)
} else {
inlineData = append(inlineData, p.Ignition.ProvisioningURL)
}
Expand Down
142 changes: 116 additions & 26 deletions test/cases/ostree-simplified-installer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -878,8 +878,8 @@ if [[ ${IGNITION} -eq 0 ]]; then
[customizations]
installation_device = "/dev/vda"
[customizations.kernel]
append = "ignition.config.url=http://192.168.100.1/ignition/config.ign"
[customizations.ignition.firstboot]
url = "http://192.168.100.1/ignition/config.ign"
EOF
else
tee "$BLUEPRINT_FILE" > /dev/null << EOF
Expand Down Expand Up @@ -1017,7 +1017,7 @@ check_result
########################################################################

if [[ "${ID}-${VERSION_ID}" = "rhel-9.2" || "${ID}-${VERSION_ID}" = "centos-9" ]]; then
tee "$BLUEPRINT_FILE" > /dev/null <<EOF
tee "$BLUEPRINT_FILE" > /dev/null <<EOF
name = "simplified_iso_with_ignition_embedded_url"
description = "A rhel-edge simplified-installer image with an embedded ignition config URL"
version = "0.0.1"
Expand All @@ -1029,37 +1029,127 @@ installation_device = "/dev/vda"
url = "http://192.168.100.1/ignition/config.ign"
EOF

greenprint "📄 simplified_iso_with_ignition_embedded_url blueprint "
cat "$BLUEPRINT_FILE"
greenprint "📄 simplified_iso_with_ignition_embedded_url blueprint "
cat "$BLUEPRINT_FILE"

# Prepare the blueprint for the compose.
greenprint "📋 Preparing installer blueprint"
sudo composer-cli blueprints push "$BLUEPRINT_FILE"
sudo composer-cli blueprints depsolve simplified_iso_with_ignition_embedded_url

# Build simplified installer iso image.
build_image simplified_iso_with_ignition_embedded_url "${INSTALLER_TYPE}" "${PROD_REPO_URL}/"

# Download the image
greenprint "📥 Downloading the simplified_iso_with_ignition_embedded_url image"
sudo composer-cli compose image "${COMPOSE_ID}" > /dev/null
ISO_FILENAME="${COMPOSE_ID}-${INSTALLER_FILENAME}"
sudo cp "${ISO_FILENAME}" /var/lib/libvirt/images

# Clean compose and blueprints.
greenprint "🧹 Clean up simplified_iso_with_ignition_embedded_url blueprint and compose"
sudo composer-cli compose delete "${COMPOSE_ID}" > /dev/null
sudo composer-cli blueprints delete simplified_iso_with_ignition_embedded_url > /dev/null

# Ensure SELinux is happy with our new images.
greenprint "👿 Running restorecon on image directory"
sudo restorecon -Rv /var/lib/libvirt/images/

# Create qcow2 file for virt install.
greenprint "🖥 Create qcow2 file for virt install"
sudo qemu-img create -f qcow2 "${LIBVIRT_IMAGE_PATH}" 20G

greenprint "💿 Install ostree image via installer(ISO) on UEFI VM"
sudo virt-install --name="${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url"\
--disk path="${LIBVIRT_IMAGE_PATH}",format=qcow2 \
--ram "${MEMORY}" \
--vcpus 2 \
--network network=integration,mac=34:49:22:B0:83:33 \
--os-type linux \
--os-variant ${OS_VARIANT} \
--cdrom "/var/lib/libvirt/images/${ISO_FILENAME}" \
--boot "$BOOT_ARGS" \
--tpm backend.type=emulator,backend.version=2.0,model=tpm-crb \
--nographics \
--noautoconsole \
--wait=15 \
--noreboot

# Installation can get stuck, destroying VM helps
# See https://github.com/osbuild/osbuild-composer/issues/2413
if [[ $(sudo virsh domstate "${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url") == "running" ]]; then
sudo virsh destroy "${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url"
fi

# Start VM.
greenprint "💻 Start UEFI VM"
sudo virsh start "${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url"

# Check for ssh ready to go.
greenprint "🛃 Checking for SSH is ready to go"
for LOOP_COUNTER in $(seq 0 30); do
RESULTS="$(wait_for_ssh_up $IGNITION_GUEST_ADDRESS)"
if [[ $RESULTS == 1 ]]; then
echo "SSH is ready now! 🥳"
break
fi
sleep 10
done

# Check image installation result
check_result

greenprint "🕹 Get ostree install commit value"
INSTALL_HASH=$(curl "${PROD_REPO_URL}/refs/heads/${OSTREE_REF}")

# Prepare the blueprint for the compose.
greenprint "📋 Preparing installer blueprint"
sudo composer-cli blueprints push "$BLUEPRINT_FILE"
sudo composer-cli blueprints depsolve simplified_iso_with_ignition_embedded_url
if [[ ${IGNITION} -eq 0 ]]; then
# Add instance IP address into /etc/ansible/hosts
sudo tee "${TEMPDIR}"/inventory > /dev/null << EOF
[ostree_guest]
${IGNITION_GUEST_ADDRESS}
# Build simplified installer iso image.
build_image simplified_iso_with_ignition_embedded_url "${INSTALLER_TYPE}" "${PROD_REPO_URL}/"
[ostree_guest:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=core
ansible_private_key_file=${SSH_KEY}
ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
ansible_become=yes
ansible_become_method=sudo
ansible_become_pass=${EDGE_USER_PASSWORD}
EOF

# Download the image
greenprint "📥 Downloading the simplified_iso_with_ignition_embedded_url image"
sudo composer-cli compose image "${COMPOSE_ID}" > /dev/null
ISO_FILENAME="${COMPOSE_ID}-${INSTALLER_FILENAME}"
# Test IoT/Edge OS
sudo ansible-playbook -v -i "${TEMPDIR}"/inventory -e image_type=redhat -e ostree_commit="${INSTALL_HASH}" -e skip_rollback_test="true" -e ignition="${HAS_IGNITION}" -e edge_type=edge-simplified-installer -e fdo_credential="false" /usr/share/tests/osbuild-composer/ansible/check_ostree.yaml || RESULTS=0
check_result
fi

# Mount the image
sudo mkdir /mnt/installer
sudo mount -o loop "${ISO_FILENAME}" /mnt/installer
# now try with blueprint user

# Check that the image contains the ignition_url file
if [[ -f "/mnt/installer/ignition_url" ]]; then
RESULTS=1
fi
# Add instance IP address into /etc/ansible/hosts
sudo tee "${TEMPDIR}"/inventory > /dev/null << EOF
[ostree_guest]
${IGNITION_GUEST_ADDRESS}
# Check the resulting image
check_result
[ostree_guest:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=admin
ansible_private_key_file=${SSH_KEY}
ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
ansible_become=yes
ansible_become_method=sudo
ansible_become_pass=${EDGE_USER_PASSWORD}
EOF

sudo umount /mnt/installer
# Test IoT/Edge OS
sudo ansible-playbook -v -i "${TEMPDIR}"/inventory -e image_type=redhat -e ostree_commit="${INSTALL_HASH}" -e skip_rollback_test="true" -e ignition="${HAS_IGNITION}" -e edge_type=edge-simplified-installer -e fdo_credential="false" /usr/share/tests/osbuild-composer/ansible/check_ostree.yaml || RESULTS=0
check_result

# TODO(runcom): run with this image and basically check the same as the previous test with core user
greenprint "🧹 Clean up VM"
if [[ $(sudo virsh domstate "${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url") == "running" ]]; then
sudo virsh destroy "${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url"
fi
sudo virsh undefine "${IMAGE_KEY}-simplified_iso_with_ignition_embedded_url" --nvram
sudo virsh vol-delete --pool images "$LIBVIRT_IMAGE_PATH"
else
greenprint "Skipping ignition embedded url test, it's only for RHEL9"
fi
Expand Down

0 comments on commit 57c09b2

Please sign in to comment.