summaryrefslogtreecommitdiff
path: root/roles/installer
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2021-07-01 20:32:35 +0200
committerChristian Pointner <equinox@spreadspace.org>2021-07-01 20:32:35 +0200
commitc2d011a50b37ad3e02e965dbb8c8960835165764 (patch)
treeb27d2691903db5b52ba31adbdcc4f30975c4cb38 /roles/installer
parentch-equinox-* install ddrecsue (diff)
parentcosmetic changes (diff)
Merge branch 'topic/new-ubuntu-installer'
Diffstat (limited to 'roles/installer')
-rw-r--r--roles/installer/debian/base/tasks/main.yml2
-rw-r--r--roles/installer/debian/iso/tasks/main.yml2
-rw-r--r--roles/installer/debian/preseed/defaults/main.yml2
-rw-r--r--roles/installer/debian/preseed/templates/partman_config.j24
-rw-r--r--roles/installer/debian/usb/tasks/main.yml12
-rw-r--r--roles/installer/ubuntu/autoinstall/defaults/main.yml38
-rw-r--r--roles/installer/ubuntu/autoinstall/files/early-command.py25
-rw-r--r--roles/installer/ubuntu/autoinstall/tasks/main.yml21
-rw-r--r--roles/installer/ubuntu/autoinstall/templates/autoinstall.yml.j2261
-rw-r--r--roles/installer/ubuntu/base/tasks/main.yml15
-rw-r--r--roles/installer/ubuntu/fetch/defaults/main.yml7
-rw-r--r--roles/installer/ubuntu/fetch/tasks/fetch-latest.yml13
-rw-r--r--roles/installer/ubuntu/fetch/tasks/fetch-version.yml41
-rw-r--r--roles/installer/ubuntu/fetch/tasks/main.yml43
-rw-r--r--roles/installer/ubuntu/fetch/vars/main.yml2
-rw-r--r--roles/installer/ubuntu/iso/defaults/main.yml5
-rw-r--r--roles/installer/ubuntu/iso/tasks/main.yml55
-rw-r--r--roles/installer/ubuntu/iso/templates/grub.cfg.j218
-rw-r--r--roles/installer/ubuntu/iso/templates/isolinux.cfg.j215
-rw-r--r--roles/installer/ubuntu/usb/defaults/main.yml6
-rw-r--r--roles/installer/ubuntu/usb/tasks/main.yml71
-rw-r--r--roles/installer/ubuntu/usb/templates/grub.cfg.j222
-rw-r--r--roles/installer/ubuntu/usb/templates/isolinux.cfg.j225
23 files changed, 694 insertions, 11 deletions
diff --git a/roles/installer/debian/base/tasks/main.yml b/roles/installer/debian/base/tasks/main.yml
index 662b8acb..56ca7dc0 100644
--- a/roles/installer/debian/base/tasks/main.yml
+++ b/roles/installer/debian/base/tasks/main.yml
@@ -17,7 +17,7 @@
src: "{{ item }}"
dest: "{{ installer_base_path }}/keyrings/{{ item | basename }}"
-- name: copy ubuntu keyring file
+- name: copy ubuntu archive keyring file
copy:
src: "{{ global_files_dir }}/common/keyrings/ubuntu-archive.gpg"
dest: "{{ installer_base_path }}/keyrings/ubuntu-archive.gpg"
diff --git a/roles/installer/debian/iso/tasks/main.yml b/roles/installer/debian/iso/tasks/main.yml
index 3170c7b5..04d913c3 100644
--- a/roles/installer/debian/iso/tasks/main.yml
+++ b/roles/installer/debian/iso/tasks/main.yml
@@ -4,7 +4,7 @@
vars:
debian_installer_distro: "{{ install_distro }}"
debian_installer_codename: "{{ install_codename }}"
- debian_installer_arch: "{{ install.arch | default('amd64') }}"
+ debian_installer_arch: "{{ install_cooked.arch | default('amd64') }}"
debian_installer_variant: mini-iso
import_role:
role: installer/debian/fetch
diff --git a/roles/installer/debian/preseed/defaults/main.yml b/roles/installer/debian/preseed/defaults/main.yml
index b8d22ea6..a0646b3b 100644
--- a/roles/installer/debian/preseed/defaults/main.yml
+++ b/roles/installer/debian/preseed/defaults/main.yml
@@ -1,5 +1,5 @@
---
-# preseed_initrd
+# preseed_initrd:
# preseed_tmpdir:
preseed_language: en
diff --git a/roles/installer/debian/preseed/templates/partman_config.j2 b/roles/installer/debian/preseed/templates/partman_config.j2
index 9f8c7dcd..39003864 100644
--- a/roles/installer/debian/preseed/templates/partman_config.j2
+++ b/roles/installer/debian/preseed/templates/partman_config.j2
@@ -48,14 +48,14 @@ d-i partman-auto/method string lvm
d-i partman-auto/expert_recipe string \
ansible :: \
{% if (install_cooked.efi | default(false)) %}
-{% set efi_esp_size_mb = (((preseed_efi_esp_size | default(preseed_efi_esp_size)) | human_to_bytes) / (1024*1024)) | int %}
+{% set efi_esp_size_mb = ((preseed_efi_esp_size | human_to_bytes) / (1024*1024)) | int %}
{{ efi_esp_size_mb }} {{ efi_esp_size_mb }} {{ efi_esp_size_mb }} fat16 \
$primary{ } $bootable{ } \
method{ efi } format{ } \
. \
{% endif %}
{% if install_cooked.disks.primary == "software-raid" %}
-{% set swraid_boot_size_mb = (((preseed_swraid_boot_size | default(preseed_swraid_boot_size)) | human_to_bytes) / (1024*1024)) | int %}
+{% set swraid_boot_size_mb = ((preseed_swraid_boot_size | human_to_bytes) / (1024*1024)) | int %}
{{ swraid_boot_size_mb }} {{ swraid_boot_size_mb }} {{ swraid_boot_size_mb }} raid \
$lvmignore{ } $primary{ } $bootable{ } \
method{ raid } \
diff --git a/roles/installer/debian/usb/tasks/main.yml b/roles/installer/debian/usb/tasks/main.yml
index e02f38e6..62bfced7 100644
--- a/roles/installer/debian/usb/tasks/main.yml
+++ b/roles/installer/debian/usb/tasks/main.yml
@@ -8,15 +8,15 @@
- name: fail if usb drive mountpoint does not exist
run_once: true
assert:
- that: usb_install_mountpoint.stat.exists
- msg: the path to the usb drive does not exist
+ that: usb_install_mountpoint.stat.exists and usb_install_mountpoint.stat.isdir
+ msg: the path to the usb drive does not exist or is not a directory
- name: download installer
run_once: true
vars:
debian_installer_distro: "{{ install_distro }}"
debian_installer_codename: "{{ install_codename }}"
- debian_installer_arch: "{{ install.arch | default('amd64') }}"
+ debian_installer_arch: "{{ install_cooked.arch | default('amd64') }}"
debian_installer_variant: netboot
import_role:
role: installer/debian/fetch
@@ -109,12 +109,12 @@
$ sudo syslinux -i /dev/CHANGEME1 -d bios
$ sudo fdisk /dev/CHANGEME
[Here, make sure partition 1 is marked bootable.]
- $ cp /usr/lib/syslinux/modules/bios/* {{ usb_install_path }}/bios/
+ $ cp /usr/lib/syslinux/modules/bios/* {{ (usb_install_path, 'bios/') | path_join }}
for UEFI these steps need to be done
$ sudo apt install syslinux-efi
- $ cp /usr/lib/syslinux/modules/efi64/* {{ usb_install_path }}/EFI/boot/
- $ cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi {{ usb_install_path }}/EFI/boot/bootx64.efi
+ $ cp /usr/lib/syslinux/modules/efi64/* {{ (usb_install_path, 'EFI/boot/') | path_join }}
+ $ cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi {{ (usb_install_path, 'EFI/boot/bootx64.efi') | path_join }}
This will NOT be done automatically.
diff --git a/roles/installer/ubuntu/autoinstall/defaults/main.yml b/roles/installer/ubuntu/autoinstall/defaults/main.yml
new file mode 100644
index 00000000..4af5a42d
--- /dev/null
+++ b/roles/installer/ubuntu/autoinstall/defaults/main.yml
@@ -0,0 +1,38 @@
+---
+# ubuntu_autoinstall_tmpdir:
+
+ubuntu_autoinstall_locale: en_US
+
+ubuntu_autoinstall_keyboard_layout: de
+ubuntu_autoinstall_keyboard_variant: nodeadkeys
+
+ubuntu_autoinstall_timezone: Europe/Vienna
+
+# ubuntu_autoinstall_kernel_image:
+ubuntu_autoinstall_virtual_machine: no
+
+
+ubuntu_autoinstall_efi_esp_size: 128M
+ubuntu_autoinstall_swraid_boot_size: 256M
+
+ubuntu_autoinstall_system_lvm_size_default: all
+ubuntu_autoinstall_system_lvm_volumes_default:
+ - name: root
+ size: 2.5G
+ filesystem: ext4
+ mountpoint: /
+ - name: var
+ size: 1280M
+ filesystem: ext4
+ mountpoint: /var
+ - name: var+log
+ size: 768M
+ filesystem: ext4
+ mountpoint: /var/log
+ mount_options:
+ - nodev
+ - noatime
+ - noexec
+
+
+ubuntu_autoinstall_install_tasks: []
diff --git a/roles/installer/ubuntu/autoinstall/files/early-command.py b/roles/installer/ubuntu/autoinstall/files/early-command.py
new file mode 100644
index 00000000..93d72b2d
--- /dev/null
+++ b/roles/installer/ubuntu/autoinstall/files/early-command.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+
+import os
+from shutil import copyfile
+import yaml
+
+os.umask(0o077)
+copyfile('/autoinstall.yaml', '/autoinstall.yaml_before-early-command')
+
+config = {}
+with open('/autoinstall.yaml', 'r') as file:
+ config = yaml.safe_load(file)
+
+try:
+ for c in config['storage']['config']:
+ if 'type' not in c or c['type'] != 'disk' or 'path' not in c:
+ continue
+
+ c['path'] = os.path.realpath(c['path'])
+
+ with open('/autoinstall.yaml', 'w') as file:
+ yaml.dump(config, file, default_flow_style=False)
+
+except KeyError:
+ pass
diff --git a/roles/installer/ubuntu/autoinstall/tasks/main.yml b/roles/installer/ubuntu/autoinstall/tasks/main.yml
new file mode 100644
index 00000000..a7ea67ba
--- /dev/null
+++ b/roles/installer/ubuntu/autoinstall/tasks/main.yml
@@ -0,0 +1,21 @@
+---
+- name: create autoinstall sub-directory
+ file:
+ path: "{{ ubuntu_autoinstall_tmpdir }}/autoinstall/{{ inventory_hostname }}"
+ state: directory
+
+- name: create empty meta-data file
+ copy:
+ content: ""
+ dest: "{{ ubuntu_autoinstall_tmpdir }}/autoinstall/{{ inventory_hostname }}/meta-data"
+
+- name: copy early-command script
+ run_once: yes
+ copy:
+ src: early-command.py
+ dest: "{{ ubuntu_autoinstall_tmpdir }}/autoinstall/early-command.py"
+
+- name: generate autoinstall.yml as user-data
+ template:
+ src: autoinstall.yml.j2
+ dest: "{{ ubuntu_autoinstall_tmpdir }}/autoinstall/{{ inventory_hostname }}/user-data"
diff --git a/roles/installer/ubuntu/autoinstall/templates/autoinstall.yml.j2 b/roles/installer/ubuntu/autoinstall/templates/autoinstall.yml.j2
new file mode 100644
index 00000000..e166a78f
--- /dev/null
+++ b/roles/installer/ubuntu/autoinstall/templates/autoinstall.yml.j2
@@ -0,0 +1,261 @@
+#cloud-config
+autoinstall:
+ version: 1
+ early-commands:
+ - python3 /cdrom/autoinstall/early-command.py
+
+ locale: "{{ ubuntu_autoinstall_locale }}"
+ keyboard:
+ layout: "{{ ubuntu_autoinstall_keyboard_layout }}"
+ variant: "{{ ubuntu_autoinstall_keyboard_variant }}"
+ toggle: null
+
+ network:
+ version: 2
+ ethernets:
+ {{ install_interface | default(network_cooked.primary.name) }}:
+{% if install_dhcp | default(false) %}
+ dhcp4: yes
+{% else %}
+ addresses:
+ - {{ network_cooked.primary.address }}
+ gateway4: {{ network_cooked.primary.gateway }}
+{% if (network_cooked.nameservers | default([]) | length) > 0 %}
+ nameservers:
+ search: [ {{ host_domain }} ]
+ addresses: [ {{ network_cooked.nameservers | join(', ') }} ]
+{% endif %}
+{% endif %}
+
+ storage:
+ config:
+{% if install_cooked.disks.primary != "software-raid" %}
+ - id: disk-primary
+ type: disk
+ path: {{ install_cooked.disks.primary }}
+{% if install_cooked.efi | default(false) %}
+ ptable: gpt
+{% else %}
+ ptable: msdos
+ grub_device: true
+{% endif %}
+ wipe: superblock-recursive
+{% else %}
+{% for raid_member in install_cooked.disks.raid.members %}
+ - id: raid-disk{{ loop.index }}
+ type: disk
+ path: {{ raid_member }}
+{% if install_cooked.efi | default(false) %}
+ ptable: gpt
+{% else %}
+ ptable: msdos
+ grub_device: true
+{% endif %}
+ wipe: superblock-recursive
+{% endfor %}
+{% endif %}
+
+{% if install_cooked.efi | default(false) %}
+{% set part_offset = 1 %}
+{% if install_cooked.disks.primary != "software-raid" %}
+ - id: partition-esp
+ type: partition
+ device: disk-primary
+ flag: boot
+ number: 1
+ size: {{ ubuntu_autoinstall_efi_esp_size | human_to_bytes }}
+ grub_device: true
+ - id: format-esp
+ type: format
+ volume: partition-esp
+ label: efi
+ fstype: fat32
+ - id: mount-esp
+ type: mount
+ device: format-esp
+ path: /boot/efi
+{% else %}
+{% for raid_member in install_cooked.disks.raid.members %}
+ - id: partition-esp{{ loop.index }}
+ type: partition
+ device: raid-disk{{ loop.index }}
+ flag: boot
+ number: 1
+ size: {{ ubuntu_autoinstall_efi_esp_size | human_to_bytes }}
+ grub_device: true
+ - id: format-esp{{ loop.index }}
+ type: format
+ volume: partition-esp{{ loop.index }}
+ label: efi
+ fstype: fat32
+ - id: mount-esp{{ loop.index }}
+ type: mount
+ device: format-esp{{ loop.index }}
+ path: /boot/efi
+{% endfor %}
+{% endif %}
+
+{% else %}
+{% set part_offset = 0 %}
+{% endif %}
+{% if install_cooked.disks.primary == "software-raid" %}
+{% for raid_member in install_cooked.disks.raid.members %}
+ - id: raid-partition-boot{{ loop.index }}
+ type: partition
+ device: raid-disk{{ loop.index }}
+ number: {{ part_offset + 1 }}
+ size: {{ ubuntu_autoinstall_swraid_boot_size | human_to_bytes }}
+{% endfor %}
+ - id: partition-boot
+ type: raid
+ name: md-boot
+ raidlevel: {{ install_cooked.disks.raid.level }}
+ devices:
+{% for raid_member in install_cooked.disks.raid.members %}
+ - raid-partition-boot{{ loop.index }}
+{% endfor %}
+ - id: format-boot
+ type: format
+ volume: partition-boot
+ fstype: ext4
+ - id: mount-boot
+ type: mount
+ device: format-boot
+ path: /boot
+{% set part_offset = part_offset + 1 %}
+
+{% endif %}
+{% set system_lvm_size = install_cooked.system_lvm.size | default(ubuntu_autoinstall_system_lvm_size_default) %}
+{% set system_lvm_volumes = install_cooked.system_lvm.volumes | default(ubuntu_autoinstall_system_lvm_volumes_default) %}
+{% if install_cooked.disks.primary != "software-raid" %}
+ - id: partition-lvm
+ type: partition
+ device: disk-primary
+ flag: linux
+ number: {{ part_offset + 1 }}
+{% if system_lvm_size != 'all' %}
+ size: {{ system_lvm_size | human_to_bytes }}
+ - id: partition-unused
+ type: partition
+ device: disk-primary
+ flag: linux
+ number: {{ part_offset + 2 }}
+{% endif %}
+ size: -1
+
+{% else %}
+{% for raid_member in install_cooked.disks.raid.members %}
+ - id: raid-partition-lvm{{ loop.index }}
+ type: partition
+ device: raid-disk{{ loop.index }}
+ number: {{ part_offset + 1 }}
+{% if system_lvm_size != 'all' %}
+ size: {{ system_lvm_size | human_to_bytes }}
+ - id: raid-partition-unused{{ loop.index }}
+ type: partition
+ device: raid-disk{{ loop.index }}
+ flag: linux
+ number: {{ part_offset + 2 }}
+{% endif %}
+ size: -1
+{% endfor %}
+ - id: partition-lvm
+ type: raid
+ name: md-lvm
+ raidlevel: {{ install_cooked.disks.raid.level }}
+ devices:
+{% for raid_member in install_cooked.disks.raid.members %}
+ - raid-partition-lvm{{ loop.index }}
+{% endfor %}
+
+{% endif %}
+ - id: lvm-vg-system
+ type: lvm_volgroup
+ devices:
+ - partition-lvm
+ name: {{ host_name }}
+
+{% for volume in system_lvm_volumes %}
+ - id: lvm-lv-{{ volume.name }}
+ type: lvm_partition
+ volgroup: lvm-vg-system
+ name: {{ volume.name }}
+ size: {{ volume.size | human_to_bytes }}
+ - id: format-{{ volume.name }}
+ type: format
+ fstype: {{ volume.filesystem }}
+ volume: lvm-lv-{{ volume.name }}
+ - id: mount-{{ volume.name }}
+ type: mount
+ device: format-{{ volume.name }}
+ path: {{ volume.mountpoint }}
+{% if 'mount_options' in volume and (volume.mount_options | length) > 0 %}
+ options: '{{ volume.mount_options | join(",") }}'
+{% endif %}
+
+{% endfor %}
+ apt:
+ primary:
+ - uri: http://{{ apt_repo_providers[apt_repo_provider].ubuntu.host }}{{ apt_repo_providers[apt_repo_provider].ubuntu.path }}
+ arches:
+ - amd64
+
+ user-data:
+ hostname: "{{ host_name }}"
+ timezone: "{{ ubuntu_autoinstall_timezone }}"
+ disable_root: false
+ users:
+ - name: root
+ ssh_authorized_keys:
+{% for key in ssh_keys_root %}
+ - {{ key }}
+{% endfor %}
+ runcmd:
+ - [ apt-get, -y, -q, purge, snapd, cloud-init, cloud-guest-utils, cloud-initramfs-copymods, cloud-initramfs-dyn-netconf, python3-cryptography, gpg, sosreport, update-notifier-common, ssh-import-id ]
+ - [ rm, -rf, /etc/cloud, /var/lib/cloud ]
+ - [ apt-get, -y, -q, auto-remove ]
+ - [ bash, -c, 'dpkg -l | grep "^rc" | awk "{ print(\$2) }" | xargs dpkg -P' ]
+{% if ubuntu_autoinstall_virtual_machine %}
+ - [ poweroff ]
+{% endif %}
+
+ ssh:
+ install-server: true
+
+ packages:
+ - python3
+ - python3-apt
+{% for task in ubuntu_autoinstall_install_tasks %}
+ - {{ task }}^
+{% endfor %}
+
+ late-commands:
+ - curtin in-target --target=/target -- swapoff -a; sed -e '/^\/swapfile/d' -i /etc/fstab; rm -f /swapfile
+{% if ansible_port is defined %}
+ - curtin in-target --target=/target -- sed -e 's/^\(\s*#*\s*Port.*\)/Port {{ ansible_port }}/' -i /etc/ssh/sshd_config
+{% endif %}
+ - curtin in-target --target=/target -- apt-mark manual iputils-ping isc-dhcp-client netcat-openbsd netplan.io sudo
+ - curtin in-target --target=/target -- apt-get -y -q purge policykit-1 multipath-tools ubuntu-minimal unattended-upgrades sound-theme-freedesktop thin-provisioning-tools cryptsetup byobu open-iscsi btrfs-progs pollinate lxd-agent-loader open-vm-tools
+{% if install_cooked.disks.primary != "software-raid" %}
+ - curtin in-target --target=/target -- apt-get -y -q purge mdadm
+{% endif %}
+ - curtin in-target --target=/target -- env SUDO_FORCE_REMOVE=yes apt-get -y -q purge sudo
+ - curtin in-target --target=/target -- apt-get -y -q autoremove
+ - curtin in-target --target=/target -- bash -c 'dpkg -l | grep "^rc" | awk "{ print(\$2) }" | xargs dpkg -P'
+{# purging the snapd package here would trigger a bug in den postrm script because some filesystems in /run/ can not be unmounted... #}
+{# to workadound this issue we only remove the package here and rely on cloud-init to fully purge it on first boot (see user-data: above) #}
+ - curtin in-target --target=/target -- apt-get -y -q remove snapd
+ - curtin in-target --target=/target -- bash -c 'apt-get update -q && apt-get full-upgrade -y -q'
+{% if ubuntu_autoinstall_kernel_image is defined or ubuntu_autoinstall_virtual_machine %}
+
+write_files:
+ - path: /run/kernel-meta-package
+ content: |
+{% if ubuntu_autoinstall_kernel_image is defined %}
+ {{ ubuntu_autoinstall_kernel_image }}
+{% else %}
+ linux-virtual
+{% endif %}
+ owner: root:root
+ permissions: "0644"
+{% endif %}
diff --git a/roles/installer/ubuntu/base/tasks/main.yml b/roles/installer/ubuntu/base/tasks/main.yml
new file mode 100644
index 00000000..c48ed4b5
--- /dev/null
+++ b/roles/installer/ubuntu/base/tasks/main.yml
@@ -0,0 +1,15 @@
+---
+- name: install gpgv
+ apt:
+ name: gpgv
+ state: present
+
+- name: prepare directory keyrings
+ file:
+ name: "{{ installer_base_path }}/keyrings"
+ state: directory
+
+- name: copy ubuntu cdimage keyring file
+ copy:
+ src: "{{ global_files_dir }}/common/keyrings/ubuntu-cdimage.gpg"
+ dest: "{{ installer_base_path }}/keyrings/ubuntu-cdimage.gpg"
diff --git a/roles/installer/ubuntu/fetch/defaults/main.yml b/roles/installer/ubuntu/fetch/defaults/main.yml
new file mode 100644
index 00000000..f6ac2bc0
--- /dev/null
+++ b/roles/installer/ubuntu/fetch/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+# ubuntu_installer_codename: bionic | focal
+ubuntu_installer_arch: amd64
+# ubuntu_installer_variant: live-server | desktop
+# ubuntu_installer_version: 20.04.1
+
+ubuntu_installer_force_download: no
diff --git a/roles/installer/ubuntu/fetch/tasks/fetch-latest.yml b/roles/installer/ubuntu/fetch/tasks/fetch-latest.yml
new file mode 100644
index 00000000..9baa6d97
--- /dev/null
+++ b/roles/installer/ubuntu/fetch/tasks/fetch-latest.yml
@@ -0,0 +1,13 @@
+---
+- name: downloading SHA256SUMS and signature file for latest release
+ loop:
+ - SHA256SUMS
+ - SHA256SUMS.gpg
+ get_url:
+ url: "https://releases.ubuntu.com/{{ ubuntu_installer_codename }}/{{ item }}"
+ dest: "{{ ubuntu_installer_target_dir }}/{{ item }}"
+ force: "{{ ubuntu_installer_force_download }}"
+
+- name: set download url to releases.ubuntu.com
+ set_fact:
+ ubuntu_installer_base_url: "https://releases.ubuntu.com/{{ ubuntu_installer_codename }}"
diff --git a/roles/installer/ubuntu/fetch/tasks/fetch-version.yml b/roles/installer/ubuntu/fetch/tasks/fetch-version.yml
new file mode 100644
index 00000000..868adc95
--- /dev/null
+++ b/roles/installer/ubuntu/fetch/tasks/fetch-version.yml
@@ -0,0 +1,41 @@
+---
+## we need to try old-releases.ubuntu.com first because otherwise it would be impossible to download the initial release
+## of any codename release. (i.e. 20.04)
+- name: try downloading SHA256SUMS and signature file from old-releases.ubuntu.com
+ loop:
+ - SHA256SUMS
+ - SHA256SUMS.gpg
+ get_url:
+ url: "https://old-releases.ubuntu.com/releases/{{ ubuntu_installer_version }}/{{ item }}"
+ dest: "{{ ubuntu_installer_target_dir }}/{{ item }}"
+ force: yes
+ register: ubuntu_installer_old
+ failed_when: "'status_code' in ubuntu_installer_old and ubuntu_installer_old.status_code not in [200, 404]"
+
+- when: 404 not in (ubuntu_installer_old.results | selectattr('status_code', 'defined') | map(attribute='status_code') | list)
+ block:
+ - name: check if SHA256SUM actually contains the correct iso
+ command: grep -E '^[0-9a-z]{64}\s+\*ubuntu-{{ ubuntu_installer_version }}-{{ ubuntu_installer_variant }}-{{ ubuntu_installer_arch }}.iso$' "{{ ubuntu_installer_target_dir }}/SHA256SUMS"
+ changed_when: false
+ failed_when: false
+ register: ubuntu_installer_old_sha256sum
+
+ - name: set download url to old-releases.ubuntu.com
+ when: (ubuntu_installer_old_sha256sum.stdout_lines | length) > 0
+ set_fact:
+ ubuntu_installer_base_url: "https://old-releases.ubuntu.com/releases/{{ ubuntu_installer_version }}"
+
+- when: ubuntu_installer_base_url is not defined
+ block:
+ - name: try downloading SHA256SUMS and signature file from releases.ubuntu.com
+ loop:
+ - SHA256SUMS
+ - SHA256SUMS.gpg
+ get_url:
+ url: "https://releases.ubuntu.com/{{ ubuntu_installer_version }}/{{ item }}"
+ dest: "{{ ubuntu_installer_target_dir }}/{{ item }}"
+ force: yes
+
+ - name: set download url to releases.ubuntu.com
+ set_fact:
+ ubuntu_installer_base_url: "https://releases.ubuntu.com/{{ ubuntu_installer_version }}"
diff --git a/roles/installer/ubuntu/fetch/tasks/main.yml b/roles/installer/ubuntu/fetch/tasks/main.yml
new file mode 100644
index 00000000..618cfd22
--- /dev/null
+++ b/roles/installer/ubuntu/fetch/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+- name: prepare directories for installer files
+ file:
+ name: "{{ ubuntu_installer_target_dir }}"
+ state: directory
+
+- include_tasks: "fetch-{{ (ubuntu_installer_version is defined) | ternary('version', 'latest') }}.yml"
+
+- name: verfiy signature of SHA256SUMS file
+ command: >-
+ gpgv --keyring "{{ installer_keyrings_path | default(installer_base_path+'/keyrings') }}/ubuntu-cdimage.gpg"
+ "{{ ubuntu_installer_target_dir }}/SHA256SUMS.gpg" "{{ ubuntu_installer_target_dir }}/SHA256SUMS"
+ changed_when: False
+ register: ubuntu_installer_gpg_result
+
+- debug:
+ var: ubuntu_installer_gpg_result.stderr_lines
+
+
+- name: download and verify installer files
+ block:
+ - name: extract file hash from SHA256SUMS
+ command: grep -E '^[0-9a-z]{64}\s+\*ubuntu-{{ ubuntu_installer_version | default("[0-9.]+") }}-{{ ubuntu_installer_variant }}-{{ ubuntu_installer_arch }}.iso$' "{{ ubuntu_installer_target_dir }}/SHA256SUMS"
+ changed_when: false
+ register: ubuntu_installer_sha256sum
+
+ - name: extract filename from SHA256SUM
+ set_fact:
+ ubuntu_installer_filename: "{{ (ubuntu_installer_sha256sum.stdout.split(' ') | last)[1:] }}"
+
+ - debug:
+ msg: "will be downloading: {{ ubuntu_installer_base_url }}/{{ ubuntu_installer_filename }} (this will probably take a while...)"
+
+ - name: download/verify installer file
+ get_url:
+ url: "{{ ubuntu_installer_base_url }}/{{ ubuntu_installer_filename }}"
+ dest: "{{ ubuntu_installer_target_dir }}/{{ ubuntu_installer_filename }}"
+ checksum: "sha256:{{ ubuntu_installer_sha256sum.stdout.split(' ') | first }}"
+ force: "{{ ubuntu_installer_force_download }}"
+
+ rescue:
+ - fail:
+ msg: "download/verification of installer files failed. Is the cd-image variant '{{ ubuntu_installer_variant }}' available for {{ ubuntu_installer_codename }}?"
diff --git a/roles/installer/ubuntu/fetch/vars/main.yml b/roles/installer/ubuntu/fetch/vars/main.yml
new file mode 100644
index 00000000..caf1fa67
--- /dev/null
+++ b/roles/installer/ubuntu/fetch/vars/main.yml
@@ -0,0 +1,2 @@
+---
+ubuntu_installer_target_dir: "{{ installer_base_path }}/{{ ubuntu_installer_codename }}/{{ ubuntu_installer_version | default('latest') }}-{{ ubuntu_installer_variant }}"
diff --git a/roles/installer/ubuntu/iso/defaults/main.yml b/roles/installer/ubuntu/iso/defaults/main.yml
new file mode 100644
index 00000000..cf498757
--- /dev/null
+++ b/roles/installer/ubuntu/iso/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+ubuntu_installer_iso_variant: live-server
+# ubuntu_installer_iso_variant: desktop
+
+iso_install_target_dir: "{{ global_artifacts_dir }}/{{ inventory_hostname }}/ubuntu-installer"
diff --git a/roles/installer/ubuntu/iso/tasks/main.yml b/roles/installer/ubuntu/iso/tasks/main.yml
new file mode 100644
index 00000000..ecfc2265
--- /dev/null
+++ b/roles/installer/ubuntu/iso/tasks/main.yml
@@ -0,0 +1,55 @@
+---
+- name: download installer
+ run_once: true
+ vars:
+ ubuntu_installer_codename: "{{ install_codename }}"
+ ubuntu_installer_arch: "{{ install_cooked.arch | default('amd64') }}"
+ ubuntu_installer_variant: "{{ ubuntu_installer_iso_variant }}"
+ import_role:
+ role: installer/ubuntu/fetch
+
+- block:
+ - name: create temporary workdir
+ tempfile:
+ prefix: "iso-install.{{ inventory_hostname }}."
+ state: directory
+ register: tmpdir
+
+ - name: generate autoinstall files
+ vars:
+ ubuntu_autoinstall_tmpdir: "{{ tmpdir.path }}"
+ import_role:
+ name: installer/ubuntu/autoinstall
+
+ - name: generate isolinux configuration for BIOS boot
+ template:
+ src: isolinux.cfg.j2
+ dest: "{{ tmpdir.path }}/isolinux.cfg"
+
+ - name: generate grub configuration for UEFI boot
+ template:
+ src: grub.cfg.j2
+ dest: "{{ tmpdir.path }}/grub.cfg"
+
+
+ - name: create destination directory
+ file:
+ path: "{{ iso_install_target_dir }}"
+ state: directory
+
+ - name: make sure target image does not exist
+ file:
+ path: "{{ iso_install_target_dir }}/{{ inventory_hostname }}.iso"
+ state: absent
+
+ - name: generate target iso image
+ command: xorriso -indev "{{ ubuntu_installer_target_dir }}/{{ ubuntu_installer_filename }}" -outdev "{{ iso_install_target_dir }}/{{ inventory_hostname }}.iso" -pathspecs on -boot_image any replay -update isolinux.cfg /isolinux/isolinux.cfg -update grub.cfg /boot/grub/grub.cfg -add /autoinstall=autoinstall
+ args:
+ chdir: "{{ tmpdir.path }}"
+
+ always:
+ - name: cleanup temporary workdir
+ when: tmpdir.path is defined
+ file:
+ path: "{{ tmpdir.path }}"
+ state: absent
diff --git a/roles/installer/ubuntu/iso/templates/grub.cfg.j2 b/roles/installer/ubuntu/iso/templates/grub.cfg.j2
new file mode 100644
index 00000000..f49d7f40
--- /dev/null
+++ b/roles/installer/ubuntu/iso/templates/grub.cfg.j2
@@ -0,0 +1,18 @@
+if loadfont $prefix/font.pf2 ; then
+ set gfxmode=auto
+ insmod efi_gop
+ insmod efi_uga
+ insmod gfxterm
+ terminal_output gfxterm
+fi
+
+set menu_color_normal=white/black
+set menu_color_highlight=black/light-gray
+set timeout=10
+set default=0
+
+menuentry "automated installer for {{ inventory_hostname }}" {
+ set gfxpayload=keep
+ linux /casper/vmlinuz quiet nopersistent autoinstall "ds=nocloud;s=/cdrom/autoinstall/{{ inventory_hostname }}/" {{ (install_cooked.kernel_cmdline | default([])) | join(' ') }}
+ initrd /casper/initrd
+}
diff --git a/roles/installer/ubuntu/iso/templates/isolinux.cfg.j2 b/roles/installer/ubuntu/iso/templates/isolinux.cfg.j2
new file mode 100644
index 00000000..99401b8b
--- /dev/null
+++ b/roles/installer/ubuntu/iso/templates/isolinux.cfg.j2
@@ -0,0 +1,15 @@
+DEFAULT {{ inventory_hostname }}
+TIMEOUT 100
+PROMPT 1
+SAY *****************************************
+SAY **
+SAY ** Distro: {{ install_distro }}
+SAY ** Codename: {{ install_codename }}
+SAY **
+SAY ** will be booting automated installer for {{ inventory_hostname }} in 10s ...
+SAY **
+
+LABEL {{ inventory_hostname }}
+ KERNEL /casper/vmlinuz
+ INITRD /casper/initrd
+ APPEND quiet nopersistent autoinstall ds=nocloud;s=/cdrom/autoinstall/{{ inventory_hostname }}/ {{ (install_cooked.kernel_cmdline | default([])) | join(' ') }}
diff --git a/roles/installer/ubuntu/usb/defaults/main.yml b/roles/installer/ubuntu/usb/defaults/main.yml
new file mode 100644
index 00000000..5467946d
--- /dev/null
+++ b/roles/installer/ubuntu/usb/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+ubuntu_installer_usb_variant: live-server
+# ubuntu_installer_usb_variant: desktop
+
+### path to the unmounted usb drive (/dev/...)
+# installer_ubuntu_usb_devicepath
diff --git a/roles/installer/ubuntu/usb/tasks/main.yml b/roles/installer/ubuntu/usb/tasks/main.yml
new file mode 100644
index 00000000..c7eb9e41
--- /dev/null
+++ b/roles/installer/ubuntu/usb/tasks/main.yml
@@ -0,0 +1,71 @@
+---
+- name: check if usb drive device exists
+ run_once: true
+ stat:
+ path: "{{ usb_install_path }}"
+ register: usb_install_device
+
+- name: fail if usb drive path is not a device
+ run_once: true
+ assert:
+ that: usb_install_device.stat.exists and usb_install_device.stat.isblk
+ msg: the path to the usb drive does not exist or is not a block device
+
+- name: download installer
+ run_once: true
+ vars:
+ ubuntu_installer_codename: "{{ install_codename }}"
+ ubuntu_installer_arch: "{{ install_cooked.arch | default('amd64') }}"
+ ubuntu_installer_variant: "{{ ubuntu_installer_usb_variant }}"
+ import_role:
+ role: installer/ubuntu/fetch
+
+- name: write ISO image to usb stick
+ pause:
+ prompt: |
+ Please write the image to the USB drive using something like this:
+
+ $ sudo ddrescue {{ (ubuntu_installer_target_dir, ubuntu_installer_filename) | path_join | realpath }} {{ usb_install_path }} -D --force
+
+ This will NOT be done automatically.
+
+- block:
+ - name: create temporary workdir
+ run_once: true
+ tempfile:
+ prefix: "usb-install.{{ inventory_hostname }}."
+ state: directory
+ register: tmpdir
+
+ - name: generate autoinstall files
+ vars:
+ ubuntu_autoinstall_tmpdir: "{{ tmpdir.path }}"
+ import_role:
+ name: installer/ubuntu/autoinstall
+
+ - name: generate isolinux configuration for BIOS boot
+ run_once: true
+ template:
+ src: isolinux.cfg.j2
+ dest: "{{ tmpdir.path }}/isolinux.cfg"
+
+ - name: generate grub configuration for UEFI boot
+ run_once: true
+ template:
+ src: grub.cfg.j2
+ dest: "{{ tmpdir.path }}/grub.cfg"
+
+ - name: update iso9660 filesystem on installer usb drive
+ run_once: true
+ become: yes
+ command: xorriso -dev "stdio:{{ usb_install_path }}" -pathspecs on -boot_image any replay -update isolinux.cfg /isolinux/isolinux.cfg -update grub.cfg /boot/grub/grub.cfg -find / -disk_name autoinstall -type d -exec rm_r -- -add /autoinstall=autoinstall
+ args:
+ chdir: "{{ tmpdir.path }}"
+
+ always:
+ - name: cleanup temporary workdir
+ run_once: true
+ when: tmpdir.path is defined
+ file:
+ path: "{{ tmpdir.path }}"
+ state: absent
diff --git a/roles/installer/ubuntu/usb/templates/grub.cfg.j2 b/roles/installer/ubuntu/usb/templates/grub.cfg.j2
new file mode 100644
index 00000000..1f97113a
--- /dev/null
+++ b/roles/installer/ubuntu/usb/templates/grub.cfg.j2
@@ -0,0 +1,22 @@
+if loadfont $prefix/font.pf2 ; then
+ set gfxmode=auto
+ insmod efi_gop
+ insmod efi_uga
+ insmod gfxterm
+ terminal_output gfxterm
+fi
+
+set menu_color_normal=white/black
+set menu_color_highlight=black/light-gray
+{% if (ansible_play_hosts_all | length) == 1 %}
+set timeout=10
+set default=0
+{% endif %}
+{% for host in ansible_play_hosts_all %}
+
+menuentry "automated installer for {{ host }}" {
+ set gfxpayload=keep
+ linux /casper/vmlinuz quiet nopersistent autoinstall "ds=nocloud;s=/cdrom/autoinstall/{{ host }}/" {{ (hostvars[host].install_cooked.kernel_cmdline | default([])) | join(' ') }}
+ initrd /casper/initrd
+}
+{% endfor %}
diff --git a/roles/installer/ubuntu/usb/templates/isolinux.cfg.j2 b/roles/installer/ubuntu/usb/templates/isolinux.cfg.j2
new file mode 100644
index 00000000..8360c057
--- /dev/null
+++ b/roles/installer/ubuntu/usb/templates/isolinux.cfg.j2
@@ -0,0 +1,25 @@
+{% if (ansible_play_hosts_all | length) == 1 %}
+DEFAULT {{ inventory_hostname }}
+TIMEOUT 100
+PROMPT 1
+SAY *****************************************
+SAY **
+SAY ** Distro: {{ install_distro }}
+SAY ** Codename: {{ install_codename }}
+SAY **
+SAY ** will be booting automated installer for {{ inventory_hostname }} in 10s ...
+SAY **
+{% else %}
+DEFAULT menu.c32
+TIMEOUT 0
+PROMPT 0
+MENU TITLE {{ install_distro }} / {{ install_codename }}
+{% endif %}
+{% for host in ansible_play_hosts_all %}
+
+LABEL {{ host }}
+ MENU LABEL automatic installer for {{ host }}
+ KERNEL /casper/vmlinuz
+ INITRD /casper/initrd
+ APPEND quiet nopersistent autoinstall ds=nocloud;s=/cdrom/autoinstall/{{ host }}/ {{ (hostvars[host].install_cooked.kernel_cmdline | default([])) | join(' ') }}
+{% endfor %}