diff --git a/README.md b/README.md index 5c257f1a2d..46edc8d0f5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The table below shows the currently provided operating systems for each provider | Amazon Linux 2023 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Azure Linux 3 | ❌ | 💙 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | CentOS 9 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | -| Flatcar | ✅ | 💙 | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | 💙 | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | +| Flatcar | ✅ | 💙 | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | 💙 | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | | Oracle Linux 9 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Photon 4 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Photon 5 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | 💙 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | diff --git a/docs/book/src/capi/providers/3dsoutscale.md b/docs/book/src/capi/providers/3dsoutscale.md index 668e58a4d4..b1be6f2c87 100644 --- a/docs/book/src/capi/providers/3dsoutscale.md +++ b/docs/book/src/capi/providers/3dsoutscale.md @@ -28,6 +28,7 @@ the different operating systems. |------|-------------| | `ubuntu-2204.json` | The settings for the Ubuntu 22.04 image | | `ubuntu-2404.json` | The settings for the Ubuntu 24.04 image | +| `flatcar.json` | The settings for the Flatcar image | You must have your [Access Keys](https://docs.outscale.com/en/userguide/About-Access-Keys.html). You must have your [Account Id](https://docs.outscale.com/en/userguide/Getting-Information-About-Your-Account-and-Quotas.html). @@ -38,3 +39,20 @@ OSC_REGION: Outscale Region OSC_ACCESS_KEY: Outscale Access Key Id OSC_ACCOUNT_ID: Outscale Account Id ``` + +### Flatcar + +Since Outscale does not provide a Flatcar OMI, the Flatcar build uses an Ubuntu OMI as a +bootstrap environment. The build process installs Flatcar to disk using `flatcar-install`, +reboots into Flatcar, and then provisions it with Ansible. + +The following additional environment variables are required for Flatcar builds: +``` +FLATCAR_CHANNEL: Flatcar release channel (stable, beta, alpha). Defaults to stable. +FLATCAR_VERSION: Flatcar version. Defaults to current (latest). +``` + +Example: +```bash +FLATCAR_CHANNEL=stable FLATCAR_VERSION=current make build-osc-flatcar +``` diff --git a/images/capi/Makefile b/images/capi/Makefile index 47d56c5965..69ba4b1480 100644 --- a/images/capi/Makefile +++ b/images/capi/Makefile @@ -389,7 +389,7 @@ DO_BUILD_NAMES ?= do-ubuntu-2204 do-ubuntu-2404 OPENSTACK_BUILD_NAMES ?= openstack-ubuntu-2204 openstack-ubuntu-2404 openstack-flatcar openstack-rockylinux-9 -OSC_BUILD_NAMES ?= osc-ubuntu-2204 osc-ubuntu-2404 +OSC_BUILD_NAMES ?= osc-ubuntu-2204 osc-ubuntu-2404 osc-flatcar QEMU_BUILD_NAMES ?= qemu-ubuntu-2204 qemu-ubuntu-2204-cloudimg qemu-ubuntu-2404 qemu-ubuntu-2404-efi qemu-ubuntu-2204-efi qemu-centos-9 qemu-rhel-9 qemu-rockylinux-9 qemu-rockylinux-9-cloudimg qemu-flatcar @@ -606,11 +606,11 @@ $(OCI_VALIDATE_TARGETS): deps-oci .PHONY: $(OSC_BUILD_TARGETS) $(OSC_BUILD_TARGETS): deps-osc - $(PACKER) build $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/outscale/$(subst build-osc-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/outscale/packer.json + $(PACKER) build $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/outscale/$(subst build-osc-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/outscale/packer$(if $(findstring flatcar,$@),-flatcar,).json .PHONY: $(OSC_VALIDATE_TARGETS) $(OSC_VALIDATE_TARGETS): deps-osc - $(PACKER) validate $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/outscale/$(subst validate-osc-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/outscale/packer.json + $(PACKER) validate $(PACKER_NODE_FLAGS) -var-file="$(abspath packer/outscale/$(subst validate-osc-,,$@).json)" $(ABSOLUTE_PACKER_VAR_FILES) packer/outscale/packer$(if $(findstring flatcar,$@),-flatcar,).json .PHONY: $(POWERVS_BUILD_TARGETS) $(POWERVS_BUILD_TARGETS): deps-powervs @@ -837,6 +837,7 @@ build-oci-all: $(OCI_BUILD_TARGETS) ## Builds all OCI image build-osc-ubuntu-2204: ## Builds Ubuntu 22.04 Outscale Snapshot build-osc-ubuntu-2404: ## Builds Ubuntu 24.04 Outscale Snapshot +build-osc-flatcar: ## Builds Flatcar Outscale Snapshot build-osc-all: $(OSC_BUILD_TARGETS) ## Builds all Outscale Snapshot build-nutanix-ubuntu-2204: ## Builds Ubuntu 22.04 Nutanix image @@ -974,6 +975,7 @@ validate-oci-all: $(OCI_VALIDATE_TARGETS) ## Validates all OCI image packer conf validate-osc-ubuntu-2204: ## Validates Ubuntu 22.04 Outscale Snapshot Packer config validate-osc-ubuntu-2404: ## Validates Ubuntu 24.04 Outscale Snapshot Packer config +validate-osc-flatcar: ## Validates Flatcar Outscale Snapshot Packer config validate-osc-all: $(OSC_VALIDATE_TARGETS) ## Validates all Outscale Snapshot Packer config validate-powervs-centos-9: ## Validates the PowerVS CentOS 9 image packer config diff --git a/images/capi/ansible/roles/gpu/README.md b/images/capi/ansible/roles/gpu/README.md index c77ff460f5..ec34369ada 100644 --- a/images/capi/ansible/roles/gpu/README.md +++ b/images/capi/ansible/roles/gpu/README.md @@ -57,3 +57,26 @@ first to ensure you supply the correct one.**_ _**For example, using the `rocm` use case will install +24GB of libraries as well as the driver so your disk size will need to compensate for this.**_ + +# Flatcar NVIDIA (sysext) + +On Flatcar, NVIDIA drivers are installed via the [systemd-sysext](https://www.flatcar.org/docs/latest/setup/customization/using-nvidia/#prebuilt-sysext-method) mechanism instead of DKMS. +Pre-built driver sysext images are built with every Flatcar release and contain signed kernel modules. +The nvidia-runtime sysext provides container runtime integration. + +The following variables are available: + +| Variable | Default | Description | +|----------|---------|-------------| +| `gpu_flatcar_nvidia_sysext_name` | `nvidia-drivers-570` | Driver sysext identifier written to `/etc/flatcar/enabled-sysext.conf` | +| `gpu_flatcar_nvidia_runtime_url` | _(empty)_ | URL to download the nvidia-runtime `.raw` sysext image | +| `gpu_flatcar_nvidia_runtime_filename` | _(empty)_ | Filename of the nvidia-runtime `.raw` image | + +Example packer configuration: + +```json +{ + "ansible_user_vars": "gpu_vendor=nvidia gpu_flatcar_nvidia_sysext_name=nvidia-drivers-570 gpu_flatcar_nvidia_runtime_url=https://extensions.flatcar.org/extensions/nvidia-runtime-v1.17.9-x86-64.raw gpu_flatcar_nvidia_runtime_filename=nvidia-runtime-v1.17.9-x86-64.raw", + "node_custom_roles_pre": "gpu" +} +``` diff --git a/images/capi/ansible/roles/gpu/defaults/main.yml b/images/capi/ansible/roles/gpu/defaults/main.yml index ad75c953e9..fdcc7272d4 100644 --- a/images/capi/ansible/roles/gpu/defaults/main.yml +++ b/images/capi/ansible/roles/gpu/defaults/main.yml @@ -18,3 +18,6 @@ gpu_block_nouveau_loading: false gpu_systemd_networkd_update_initramfs: >- {%- if ansible_os_family == 'VMware Photon OS' -%} dracut -f{%- elif ansible_os_family == 'Debian' -%} update-initramfs -u{%- endif -%} gpu_nvidia_ceph: false +gpu_flatcar_nvidia_sysext_name: "nvidia-drivers-570" +gpu_flatcar_nvidia_runtime_url: "" +gpu_flatcar_nvidia_runtime_filename: "" diff --git a/images/capi/ansible/roles/gpu/tasks/flatcar-nvidia.yml b/images/capi/ansible/roles/gpu/tasks/flatcar-nvidia.yml new file mode 100644 index 0000000000..e64dfe59bb --- /dev/null +++ b/images/capi/ansible/roles/gpu/tasks/flatcar-nvidia.yml @@ -0,0 +1,46 @@ +# Copyright 2024 The Kubernetes Authors. + +# 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. + +--- +- name: Configure NVIDIA driver sysext + ansible.builtin.copy: + content: "{{ gpu_flatcar_nvidia_sysext_name }}\n" + dest: /etc/flatcar/enabled-sysext.conf + owner: root + group: root + mode: "0644" + +- name: Create nvidia-runtime extension directory + ansible.builtin.file: + path: /opt/extensions/nvidia-runtime + state: directory + owner: root + group: root + mode: "0755" + +- name: Download nvidia-runtime sysext image + ansible.builtin.get_url: + url: "{{ gpu_flatcar_nvidia_runtime_url }}" + dest: "/opt/extensions/nvidia-runtime/{{ gpu_flatcar_nvidia_runtime_filename }}" + owner: root + group: root + mode: "0644" + retries: 5 + delay: 3 + +- name: Create nvidia-runtime sysext symlink + ansible.builtin.file: + src: "/opt/extensions/nvidia-runtime/{{ gpu_flatcar_nvidia_runtime_filename }}" + dest: /etc/extensions/nvidia-runtime.raw + state: link diff --git a/images/capi/ansible/roles/gpu/tasks/main.yml b/images/capi/ansible/roles/gpu/tasks/main.yml index f1ed5f7e35..e745eb79d0 100644 --- a/images/capi/ansible/roles/gpu/tasks/main.yml +++ b/images/capi/ansible/roles/gpu/tasks/main.yml @@ -18,17 +18,22 @@ src: "etc/modprobe.d/blocklist-nouveau.conf" dest: "/etc/modprobe.d/blocklist-nouveau.conf" mode: "0644" + when: ansible_os_family != "Flatcar" - name: Update initramfs ansible.builtin.command: "{{ gpu_systemd_networkd_update_initramfs }}" register: update_initramfs_output - when: (gpu_systemd_networkd_update_initramfs is defined) and (gpu_systemd_networkd_update_initramfs | length > 0) + when: (ansible_os_family != "Flatcar") and (gpu_systemd_networkd_update_initramfs is defined) and (gpu_systemd_networkd_update_initramfs | length > 0) changed_when: update_initramfs_output.rc == 0 - name: Include AMD ansible.builtin.include_tasks: amd.yml when: gpu_vendor == "amd" +- name: Include NVIDIA for Flatcar (sysext) + ansible.builtin.include_tasks: flatcar-nvidia.yml + when: gpu_vendor == "nvidia" and ansible_os_family == "Flatcar" + - name: Include NVIDIA ansible.builtin.include_tasks: nvidia.yml - when: gpu_vendor == "nvidia" + when: gpu_vendor == "nvidia" and ansible_os_family != "Flatcar" diff --git a/images/capi/ansible/roles/providers/tasks/outscale.yml b/images/capi/ansible/roles/providers/tasks/outscale.yml index d30be5612a..0b2768b5d3 100644 --- a/images/capi/ansible/roles/providers/tasks/outscale.yml +++ b/images/capi/ansible/roles/providers/tasks/outscale.yml @@ -9,6 +9,7 @@ - cloud-init - cloud-guest-utils - cloud-initramfs-dyn-netconf + when: ansible_os_family == "Debian" - name: Install Debian specific packages ansible.builtin.apt: diff --git a/images/capi/ansible/roles/sysprep/tasks/flatcar.yml b/images/capi/ansible/roles/sysprep/tasks/flatcar.yml index 70b0c71701..27530bcda1 100644 --- a/images/capi/ansible/roles/sysprep/tasks/flatcar.yml +++ b/images/capi/ansible/roles/sysprep/tasks/flatcar.yml @@ -61,3 +61,8 @@ ansible.builtin.shell: | echo 'set oem_id="{{ oem_id }}"' >> /usr/share/oem/grub.cfg when: (oem_id is defined) and (oem_id != "") + +- name: Set ignition config URL in grub for metal platform + ansible.builtin.shell: | + echo 'set linux_append="$linux_append ignition.config.url={{ ignition_config_url }}"' >> /usr/share/oem/grub.cfg + when: (ignition_config_url is defined) and (ignition_config_url != "") diff --git a/images/capi/packer/goss/goss-vars.yaml b/images/capi/packer/goss/goss-vars.yaml index 85c406031a..872a2fe1a2 100644 --- a/images/capi/packer/goss/goss-vars.yaml +++ b/images/capi/packer/goss/goss-vars.yaml @@ -204,6 +204,8 @@ flatcar: command: openstack: command: + outscale: + command: photon: common-service: apparmor: diff --git a/images/capi/packer/outscale/flatcar.json b/images/capi/packer/outscale/flatcar.json new file mode 100644 index 0000000000..4fc06ce896 --- /dev/null +++ b/images/capi/packer/outscale/flatcar.json @@ -0,0 +1,16 @@ +{ + "ansible_extra_vars": "ansible_python_interpreter=/opt/bin/python oem_id=metal ignition_config_url=http://169.254.169.254/latest/user-data", + "build_name": "flatcar", + "distribution": "flatcar", + "distribution_release": "{{env `FLATCAR_CHANNEL`}}", + "distribution_version": "{{env `FLATCAR_CHANNEL`}}-{{env `FLATCAR_VERSION`}}", + "image_name": "Ubuntu-24.04-2026-01-12", + "kubernetes_cni_source_type": "http", + "kubernetes_source_type": "http", + "python_path": "/opt/pypy/site-packages", + "root_device_name": "/dev/vda", + "ssh_username": "outscale", + "systemd_prefix": "/etc/systemd", + "sysusr_prefix": "/opt", + "sysusrlocal_prefix": "/opt" +} diff --git a/images/capi/packer/outscale/packer-flatcar.json b/images/capi/packer/outscale/packer-flatcar.json new file mode 100644 index 0000000000..f23f37dd66 --- /dev/null +++ b/images/capi/packer/outscale/packer-flatcar.json @@ -0,0 +1,183 @@ +{ + "builders": [ + { + "access_key": "{{ user `access_key` }}", + "force_delete_snapshot": "{{user `overwrite_existing`}}", + "force_deregister": "{{user `overwrite_existing`}}", + "global_permission": "{{ user `global_permission` }}", + "launch_block_device_mappings": [ + { + "delete_on_vm_deletion": true, + "device_name": "/dev/xvdb", + "volume_size": 15, + "volume_type": "standard" + } + ], + "omi_account_ids": [ + "{{ user `account_id` }}" + ], + "omi_boot_modes": [ + "legacy", + "uefi" + ], + "omi_name": "{{user `omi_name`}}", + "region": "{{ user `region` }}", + "secret_key": "{{ user `secret_key` }}", + "source_omi": "{{ user `source_image` }}", + "source_omi_filter": { + "filters": { + "image-name": "{{ user `image_name` }}" + }, + "owners": [ + "{{ user `owner` }}" + ] + }, + "ssh_interface": "public_ip", + "ssh_username": "outscale", + "tags": { + "Base_OMI_Name": "{{ .SourceOMIName }}", + "Extra": "{{ .SourceOMITags.TagName }}", + "OS_Version": "{{user `distribution_release`}}", + "Release": "{{user `distribution_version`}}", + "distribution_release": "{{user `distribution_release`}}", + "distribution_version": "{{user `distribution_version`}}", + "kubernetes_version": "{{user `kubernetes_semver`}}" + }, + "temporary_security_group_source_cidr": "{{user `ssh_source_cidr` }}", + "type": "outscale-bsu", + "vm_type": "{{user `vm_type`}}" + } + ], + "provisioners": [ + { + "environment_vars": [ + "FLATCAR_CHANNEL={{user `flatcar_channel`}}", + "FLATCAR_VERSION={{user `flatcar_version`}}", + "DEBUG_SSH_PUBLIC_KEY={{user `debug_ssh_public_key`}}" + ], + "expect_disconnect": true, + "pause_after": "15s", + "script": "./packer/outscale/scripts/install-flatcar.sh", + "type": "shell" + }, + { + "execute_command": "BUILD_NAME={{user `build_name`}}; if [[ \"${BUILD_NAME}\" == *\"flatcar\"* ]]; then sudo {{.Vars}} -S -E bash '{{.Path}}'; fi", + "script": "./packer/files/flatcar/scripts/bootstrap-flatcar.sh", + "type": "shell" + }, + { + "ansible_env_vars": [ + "ANSIBLE_SSH_ARGS='{{user `existing_ansible_ssh_args`}} -o IdentitiesOnly=yes'" + ], + "extra_arguments": [ + "--extra-vars", + "{{user `ansible_common_vars`}}", + "--extra-vars", + "{{user `ansible_extra_vars`}}", + "--extra-vars", + "{{user `ansible_user_vars`}}" + ], + "playbook_file": "./ansible/python.yml", + "type": "ansible" + }, + { + "ansible_env_vars": [ + "ANSIBLE_SSH_ARGS='{{user `existing_ansible_ssh_args`}} -o IdentitiesOnly=yes'" + ], + "extra_arguments": [ + "--extra-vars", + "{{user `ansible_common_vars`}}", + "--extra-vars", + "{{user `ansible_extra_vars`}}", + "--extra-vars", + "{{user `ansible_user_vars`}}" + ], + "playbook_file": "./ansible/node.yml", + "type": "ansible" + }, + { + "arch": "{{user `goss_arch`}}", + "download_path": "{{user `goss_download_path`}}", + "format": "{{user `goss_format`}}", + "format_options": "{{user `goss_format_options`}}", + "goss_file": "{{user `goss_entry_file`}}", + "inspect": "{{user `goss_inspect_mode`}}", + "remote_folder": "{{user `goss_remote_folder`}}", + "remote_path": "{{user `goss_remote_path`}}", + "skip_install": "{{user `goss_skip_install`}}", + "tests": [ + "{{user `goss_tests_dir`}}" + ], + "type": "goss", + "url": "{{user `goss_url`}}", + "use_sudo": true, + "vars_file": "{{user `goss_vars_file`}}", + "vars_inline": { + "ARCH": "amd64", + "OS": "{{user `distribution` | lower}}", + "OS_VERSION": "{{user `distribution_version` | lower}}", + "PROVIDER": "outscale", + "containerd_gvisor_runtime": "{{user `containerd_gvisor_runtime`}}", + "containerd_gvisor_version": "{{user `containerd_gvisor_version`}}", + "containerd_version": "{{user `containerd_version`}}", + "kubernetes_cni_deb_version": "{{ user `kubernetes_cni_deb_version` }}", + "kubernetes_cni_rpm_version": "{{ split (user `kubernetes_cni_rpm_version`) \"-\" 0 }}", + "kubernetes_cni_source_type": "{{user `kubernetes_cni_source_type`}}", + "kubernetes_cni_version": "{{user `kubernetes_cni_semver` | replace \"v\" \"\" 1}}", + "kubernetes_deb_version": "{{ user `kubernetes_deb_version` }}", + "kubernetes_rpm_version": "{{ split (user `kubernetes_rpm_version`) \"-\" 0 }}", + "kubernetes_source_type": "{{user `kubernetes_source_type`}}", + "kubernetes_version": "{{user `kubernetes_semver` | replace \"v\" \"\" 1}}" + }, + "version": "{{user `goss_version`}}" + } + ], + "variables": { + "access_key": "{{env `OSC_ACCESS_KEY`}}", + "account_id": "{{env `OSC_ACCOUNT_ID`}}", + "ansible_common_vars": "", + "ansible_extra_vars": "", + "ansible_user_vars": "", + "build_name": null, + "build_timestamp": "{{timestamp}}", + "containerd_gvisor_runtime": "false", + "containerd_gvisor_version": "latest", + "containerd_service_url": "https://raw.githubusercontent.com/containerd/containerd/refs/tags/v{{user `containerd_version`}}/containerd.service", + "containerd_version": null, + "crictl_version": null, + "debug_ssh_public_key": "", + "distribution": null, + "distribution_release": null, + "distribution_version": null, + "existing_ansible_ssh_args": "{{env `ANSIBLE_SSH_ARGS`}}", + "flatcar_channel": "{{env `FLATCAR_CHANNEL`}}", + "flatcar_version": "{{env `FLATCAR_VERSION`}}", + "global_permission": "true", + "kubernetes_cni_deb_version": null, + "kubernetes_cni_http_source": null, + "kubernetes_cni_rpm_version": null, + "kubernetes_cni_semver": null, + "kubernetes_cni_source_type": null, + "kubernetes_container_registry": null, + "kubernetes_deb_gpg_key": null, + "kubernetes_deb_repo": null, + "kubernetes_deb_version": null, + "kubernetes_http_source": null, + "kubernetes_load_additional_imgs": null, + "kubernetes_rpm_gpg_check": null, + "kubernetes_rpm_gpg_key": null, + "kubernetes_rpm_repo": null, + "kubernetes_rpm_version": null, + "kubernetes_semver": null, + "kubernetes_series": null, + "kubernetes_source_type": null, + "omi_name": "{{user `build_name`}}-kubernetes-{{user `kubernetes_semver`}}-{{isotime `2006-01-02`}}", + "overwrite_existing": "false", + "owner": "Outscale", + "region": "{{env `OSC_REGION`}}", + "runc_version": null, + "secret_key": "{{env `OSC_SECRET_KEY`}}", + "ssh_source_cidr": "0.0.0.0/0", + "vm_type": "tinav6.c2r4p2" + } +} diff --git a/images/capi/packer/outscale/scripts/install-flatcar.sh b/images/capi/packer/outscale/scripts/install-flatcar.sh new file mode 100755 index 0000000000..400c2b3845 --- /dev/null +++ b/images/capi/packer/outscale/scripts/install-flatcar.sh @@ -0,0 +1,109 @@ +#!/bin/bash +set -euo pipefail + +# Re-execute from tmpfs so bash can keep reading after /dev/vda is overwritten +if [[ "${BASH_SOURCE[0]}" != /dev/shm/* ]]; then + cp "${BASH_SOURCE[0]}" /dev/shm/install-flatcar.sh + exec bash /dev/shm/install-flatcar.sh +fi + +# Wait for cloud-init to finish so boot-time apt operations complete first +sudo cloud-init status --wait + +# Install prerequisites +sudo apt-get update +sudo apt-get install -y bzip2 + +# Format and mount the scratch volume (attached via Packer launch_block_device_mappings). +# All image work happens here — not in RAM and not on /dev/vda which gets overwritten. +SCRATCH_DEV=$(lsblk -dpno NAME,TYPE | awk '$2=="disk" && $1!="/dev/vda" {print $1; exit}') +if [ -z "$SCRATCH_DEV" ]; then + echo "ERROR: No scratch volume found" + exit 1 +fi +sudo mkfs.ext4 -q "$SCRATCH_DEV" +sudo mount "$SCRATCH_DEV" /mnt + +# Capture the SSH public key injected by Packer +SSH_KEY=$(cat ~/.ssh/authorized_keys | head -1) + +# Build the SSH keys JSON array +SSH_KEYS_JSON="\"${SSH_KEY}\"" +if [ -n "${DEBUG_SSH_PUBLIC_KEY:-}" ]; then + SSH_KEYS_JSON="\"${SSH_KEY}\", \"${DEBUG_SSH_PUBLIC_KEY}\"" +fi + +# Create Ignition config +cat < /dev/null +{ + "ignition": { "version": "3.0.0" }, + "passwd": { + "users": [ + { + "name": "outscale", + "groups": ["wheel", "sudo", "docker"], + "sshAuthorizedKeys": [ + ${SSH_KEYS_JSON} + ] + } + ] + }, + "systemd": { + "units": [ + { + "enabled": true, + "name": "docker.service" + }, + { + "mask": true, + "name": "update-engine.service" + }, + { + "mask": true, + "name": "locksmithd.service" + } + ] + } +} +EOF + +# Download and decompress the Flatcar image to the scratch volume +BASE_URL="https://${FLATCAR_CHANNEL}.release.flatcar-linux.net/amd64-usr/${FLATCAR_VERSION}" +sudo wget --tries 10 --timeout=20 --retry-connrefused \ + -O /mnt/flatcar_image.bin.bz2 "${BASE_URL}/flatcar_production_image.bin.bz2" +sudo bunzip2 /mnt/flatcar_image.bin.bz2 + +# Embed the Ignition config into the image's OEM partition via loopback. +# All tools (losetup, blkid, mount, cp) work because Ubuntu is still intact. +LOOP=$(sudo losetup --find --show --partscan /mnt/flatcar_image.bin) +sleep 1 + +OEM_PART="" +for part in ${LOOP}p*; do + LABEL=$(sudo blkid -s LABEL -o value "$part" 2>/dev/null || true) + if [ "$LABEL" = "OEM" ]; then + OEM_PART="$part" + break + fi +done + +if [ -z "$OEM_PART" ]; then + echo "ERROR: Could not find OEM partition in Flatcar image" + sudo losetup --detach "$LOOP" + exit 1 +fi + +sudo mkdir -p /mnt/oem +sudo mount "$OEM_PART" /mnt/oem +sudo cp /mnt/ignition.json /mnt/oem/config.ign +sudo umount /mnt/oem +sudo losetup --detach "$LOOP" + +# Write the Flatcar image (with embedded Ignition config) to the root disk +# and immediately reboot via sysrq (bash builtin echo + kernel VFS, no +# userspace binaries needed from the now-destroyed root filesystem). +sudo bash -c ' + dd bs=1M if=/mnt/flatcar_image.bin of=/dev/vda conv=fdatasync status=none + echo 1 > /proc/sys/kernel/sysrq + echo b > /proc/sysrq-trigger +'