From 3cc7bb4b415e758786ed04d3b506031cd9f1971b Mon Sep 17 00:00:00 2001 From: Ahmed Abdelhalim Date: Mon, 11 Aug 2025 00:33:29 +0200 Subject: Add the bootstrap role to install archlinux w/testing --- molecule/default/converge.yml | 3 ++ molecule/default/prepare.yml | 8 +++ roles/bootstrap/README.md | 84 +++++++++++++++++++++++++++++ roles/bootstrap/meta/argument_specs.yml | 16 ++++++ roles/bootstrap/meta/main.yml | 14 +++++ roles/bootstrap/tasks/install-archlinux.yml | 57 ++++++++++++++++++++ roles/bootstrap/tasks/main.yml | 9 ++++ roles/bootstrap/templates/archlinux.conf.j2 | 4 ++ roles/bootstrap/templates/loader.conf.j2 | 3 ++ 9 files changed, 198 insertions(+) create mode 100644 roles/bootstrap/README.md create mode 100644 roles/bootstrap/meta/argument_specs.yml create mode 100644 roles/bootstrap/meta/main.yml create mode 100644 roles/bootstrap/tasks/install-archlinux.yml create mode 100644 roles/bootstrap/tasks/main.yml create mode 100644 roles/bootstrap/templates/archlinux.conf.j2 create mode 100644 roles/bootstrap/templates/loader.conf.j2 diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 0a26ebd..b4ea57f 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -3,6 +3,7 @@ hosts: instance gather_facts: true vars: + hostname: "{{ test_hostname }}" partition_wipe: false partition_disk: "{{ test_device }}" partition_boot: @@ -39,6 +40,8 @@ - name: "Get test facts" ansible.builtin.set_fact: test_device: "{{ hostvars['localhost']['test_device'] }}" + test_hostname: "{{ hostvars['localhost']['test_hostname'] }}" roles: - role: partition + - role: bootstrap diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index b9f84a7..371f7c3 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -3,6 +3,11 @@ hosts: localhost gather_facts: true tasks: + - name: "Set distro test host name mapping" + ansible.builtin.set_fact: + distro_hostname_mapping: + archlinux: "archlinux.local" + - name: "Create virtual disk image" become: true community.general.filesize: @@ -21,6 +26,7 @@ - name: "Set test facts" ansible.builtin.set_fact: test_device: "{{ loop_device.stdout }}" + test_hostname: "{{ distro_hostname_mapping[lookup('ansible.builtin.env', 'MOLECULE_DISTRO')] }}" cacheable: true - name: "Show test info" @@ -29,3 +35,5 @@ with_items: - name: "Test Device" value: "{{ test_device }}" + - name: "Test Hostname;" + value: "{{ test_hostname }}" diff --git a/roles/bootstrap/README.md b/roles/bootstrap/README.md new file mode 100644 index 0000000..c206179 --- /dev/null +++ b/roles/bootstrap/README.md @@ -0,0 +1,84 @@ +# Ansible Role: bootstrap + +This role bootstraps the installation of a linux distro + +## Role Variables + +- `hostname` the distro linux network hostname to be used. +- `partition_boot` the boot partition definition for role `partition`, to install bootloader +- `partition_root` the root partition definition for role `partition`, to install distro root + +## Dual Booting + +The role is configure for allowing dual boot multiple distros. +For example, the following `archiso.local` and `ubuntuiso.local` diff shows how to do that + +```diff ++ hostname: "archlinux.local" ++ partition_wipe: true +- hostname: "ubuntuiso.local" +- partition_wipe: false + partition_disk: "/dev/sda" + partition_boot: + num: 1 + name: "boot" + flags: [boot, esp] + part_start: "0%" + part_end: "1.0GiB" + fstype: "vfat" + fstype_opts: "-F 32" + dev: "{{ partition_disk }}1" + mount_path: "/mnt/boot" + fstab_opts: "defaults,nodev,nosuid,noexec,umask=0077" + partition_swap: + num: 2 + name: "swap" + flags: [swap] + part_start: "1.0GiB" + part_end: "9.0GiB" + fstype: "ext4" + dev: "{{ partition_disk }}2" + mount_path: "none" + partition_root: ++ num: 3 ++ name: "archlinux" ++ part_start: "9.0GiB" ++ part_end: "59.0GiB" ++ fstype: "ext4" ++ dev: "{{ partition_disk }}3" +- num: 4 +- name: "ubuntu" +- part_start: "59.0GiB" +- part_end: "119.0GiB" +- fstype: "ext4" +- dev: "{{ partition_disk }}4" + mount_path: "/mnt" + partition_extras: ++ - num: 4 ++ name: "ubuntu" ++ part_start: "59.0GiB" ++ part_end: "119.0GiB" ++ fstype: "ext4" ++ dev: "{{ partition_disk }}4" +- - num: 3 +- name: "archlinux" +- part_start: "9.0GiB" +- part_end: "59.0GiB" +- fstype: "ext4" +- dev: "{{ partition_disk }}3" + - num: 5 + name: "other_partiton" + part_start: "119.0GiB" + part_end: "100%" + fstype: "ext4" + dev: "{{ partition_disk }}5" +``` + +In other words, swap the `partition_root` configuration with the partition that is used for the installation, +and keep the rest of the mapping exactly the same. + +It's required that the first system to be installed for dual booting (`archlinux` in the previous example), +sets the `partition_wipe` parameter to `true` in order to wipe the hard drive and partition it correctly, +while the other systems (`ubuntu` in the previous example) sets the `partition_wipe` to `false`. + +Otherwise, the hard drive will be wiped and repartitioned again. diff --git a/roles/bootstrap/meta/argument_specs.yml b/roles/bootstrap/meta/argument_specs.yml new file mode 100644 index 0000000..e391e65 --- /dev/null +++ b/roles/bootstrap/meta/argument_specs.yml @@ -0,0 +1,16 @@ +--- +argument_specs: + main: + options: + hostname: + type: "str" + required: true + description: "The distro linux hostname to be configured (will configure if availabe in inventory)" + partition_boot: + type: "dict" + required: true + description: "Check partition_boot argument in role: partition" + partition_root: + type: "dict" + required: true + description: "Check partition_root argument in role: partition" diff --git a/roles/bootstrap/meta/main.yml b/roles/bootstrap/meta/main.yml new file mode 100644 index 0000000..0e12b9a --- /dev/null +++ b/roles/bootstrap/meta/main.yml @@ -0,0 +1,14 @@ +--- +dependencies: + - partition +galaxy_info: + role_name: bootstarp + author: a14m + description: "Install the linux distro on partitioned drive using pacstrap or debootstrap" + company: "kartoffeln.work GmbH." + license: "license MIT" + min_ansible_version: "2.18" + platforms: + - name: ArchLinux + versions: + - all diff --git a/roles/bootstrap/tasks/install-archlinux.yml b/roles/bootstrap/tasks/install-archlinux.yml new file mode 100644 index 0000000..057a639 --- /dev/null +++ b/roles/bootstrap/tasks/install-archlinux.yml @@ -0,0 +1,57 @@ +--- +- name: "Run pacstrap" + ansible.builtin.command: + cmd: "pacstrap -K {{ mnt_root_path }} base linux linux-firmware" + changed_when: true + +- name: "Generate fstab" + ansible.builtin.shell: + cmd: "genfstab -t PARTLABEL {{ mnt_root_path }} > {{ mnt_root_path }}/etc/fstab" + changed_when: true + +- name: "Run bootclt" + ansible.builtin.command: + cmd: "arch-chroot {{ mnt_root_path }} bootctl install" + changed_when: true + +- name: "Enable systemd-boot-update" + ansible.builtin.command: + cmd: "arch-chroot {{ mnt_root_path }} systemctl enable systemd-boot-update" + changed_when: false + +- name: "Template systemd-boot files" + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "0644" + with_items: + - src: "loader.conf.j2" + dest: "{{ mnt_boot_path }}/loader/loader.conf" + - src: "archlinux.conf.j2" + dest: "{{ mnt_boot_path }}/loader/entries/archlinux.conf" + +- name: "Configure hostname in chroot" + ansible.builtin.copy: + dest: "{{ mnt_root_path }}/etc/hostname" + mode: "0644" + content: "{{ hostname }}" + +- name: "Configure pacman in chroot" + ansible.builtin.copy: + src: "/etc/pacman.conf" + dest: "{{ mnt_root_path }}/etc/pacman.conf" + remote_src: true + force: false + mode: "0644" + +- name: "Ensure pacman is updated in chroot" + ansible.builtin.shell: | + arch-chroot {{ mnt_root_path }} pacman-key --init + arch-chroot {{ mnt_root_path }} pacman-key --populate + arch-chroot {{ mnt_root_path }} pacman -Syyu --noconfirm + changed_when: true + +- name: "Ensure ansible dependencies are installed in chroot" + ansible.builtin.command: + cmd: "arch-chroot {{ mnt_root_path }} pacman -S --noconfirm python3" + changed_when: true diff --git a/roles/bootstrap/tasks/main.yml b/roles/bootstrap/tasks/main.yml new file mode 100644 index 0000000..fbc3de5 --- /dev/null +++ b/roles/bootstrap/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: "Set root,boot partition paths" + ansible.builtin.set_fact: + mnt_boot_path: "{{ partition_boot.mount_path }}" + mnt_root_path: "{{ partition_root.mount_path }}" + +- name: "Install archlinux" + ansible.builtin.include_tasks: "install-archlinux.yml" + when: ansible_os_family == "Archlinux" diff --git a/roles/bootstrap/templates/archlinux.conf.j2 b/roles/bootstrap/templates/archlinux.conf.j2 new file mode 100644 index 0000000..5b35407 --- /dev/null +++ b/roles/bootstrap/templates/archlinux.conf.j2 @@ -0,0 +1,4 @@ +title Arch Linux +linux /vmlinuz-linux +initrd /initramfs-linux.img +options root=PARTLABEL={{ partition_root.name }} ro diff --git a/roles/bootstrap/templates/loader.conf.j2 b/roles/bootstrap/templates/loader.conf.j2 new file mode 100644 index 0000000..dc9bb34 --- /dev/null +++ b/roles/bootstrap/templates/loader.conf.j2 @@ -0,0 +1,3 @@ +default @saved +timeout 5 +editor yes -- cgit v1.2.3