aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'roles/install_gentoo')
-rw-r--r--roles/install_gentoo/tasks/disks.yml141
-rw-r--r--roles/install_gentoo/tasks/download.yml0
-rw-r--r--roles/install_gentoo/tasks/install.yml138
-rw-r--r--roles/install_gentoo/tasks/main.yml25
-rw-r--r--roles/install_gentoo/tasks/misc.yml23
-rw-r--r--roles/install_gentoo/tasks/mount.yml44
-rw-r--r--roles/install_gentoo/tasks/puppet.yml202
-rw-r--r--roles/install_gentoo/tasks/reboot.yml18
-rw-r--r--roles/install_gentoo/tasks/rootfs.yml59
9 files changed, 650 insertions, 0 deletions
diff --git a/roles/install_gentoo/tasks/disks.yml b/roles/install_gentoo/tasks/disks.yml
new file mode 100644
index 0000000..a39aa45
--- /dev/null
+++ b/roles/install_gentoo/tasks/disks.yml
@@ -0,0 +1,141 @@
+---
+- name: disks
+ tags:
+ - disks
+ block:
+ - name: check for mounted disk
+ # Not perfect.
+ ansible.builtin.command: "grep '{{ item }}' /proc/mounts"
+ failed_when: false
+ changed_when: false
+ register: check_mounted_disk
+ check_mode: no
+ loop:
+ - /dev/nvme0n1
+ - /dev/nvme1n1
+
+ - name: debug
+ ansible.builtin.debug:
+ msg: "{{ check_mounted_disk }}"
+
+ - name: abort if disk mounted
+ ansible.builtin.fail:
+ msg: "Aborting install due to {{ item }} being mounted"
+ when: item.rc == 0
+ loop: "{{ check_mounted_disk.results }}"
+
+ - name: write partition layout file
+ ansible.builtin.copy:
+ dest: /tmp/partition.sfdisk
+ # RootFS on LVM
+ content: |
+ label: gpt
+ p1 : start=1MiB, size=63MiB, type=uefi, name=EFI
+ p2 : start=64MiB, size=448MiB, type=raid, name=BOOT
+ p3 : start=512MiB, size=+, type=lvm, name=LVM
+ tags:
+ - partition
+
+ - name: partition disks
+ ansible.builtin.shell: "/usr/sbin/sfdisk {{ item }} </tmp/partition.sfdisk"
+ loop:
+ - /dev/nvme0n1
+ - /dev/nvme1n1
+ tags:
+ - partition
+
+ - name: fact md1 devices
+ ansible.builtin.set_fact:
+ md1_dev: "{{ ansible_loop.allitems|join(' ') }}"
+ loop:
+ - /dev/nvme0n1p1
+ - /dev/nvme1n1p1
+ loop_control:
+ extended: true
+ tags:
+ - mdadm
+
+ - name: fact md2 devices
+ ansible.builtin.set_fact:
+ md2_dev: "{{ ansible_loop.allitems|join(' ') }}"
+ loop:
+ - /dev/nvme0n1p2
+ - /dev/nvme1n1p2
+ loop_control:
+ extended: true
+ tags:
+ - mdadm
+
+ - name: mdadm p1
+ ansible.builtin.command: "mdadm --create -e 1.0 /dev/md1 --level=raid1 -n 2 {{ md1_dev }}"
+ tags:
+ - mdadm
+
+ - name: mdadm p2
+ ansible.builtin.command: "mdadm --create -e 1.0 /dev/md2 --level=raid1 -n 2 {{ md2_dev }}"
+ tags:
+ - mdadm
+
+ - name: format p1/mkfs
+ ansible.builtin.command: "mkfs.fat -F 16 -n EFI {{ item }}"
+ tags:
+ - mkfs
+ loop:
+ - /dev/md1
+
+ - name: format p2/mkfs
+ ansible.builtin.command: "mkfs.ext4 -T floppy,news -L BOOT {{ item }}"
+ loop:
+ - /dev/md2
+ tags:
+ - mkfs
+
+ - name: format p3/pvcreate
+ ansible.builtin.command: "pvcreate {{ ansible_loop.allitems|join(' ') }}"
+ loop_control:
+ extended: true
+ loop:
+ - /dev/nvme0n1p3
+ - /dev/nvme1n1p3
+ tags:
+ - lvm
+ - pvcreate
+
+ - name: fact vgcreate PVs
+ ansible.builtin.set_fact:
+ pvs: "{{ ansible_loop.allitems|join(' ') }}"
+ loop:
+ - /dev/nvme0n1p3
+ - /dev/nvme1n1p3
+ loop_control:
+ extended: true
+ tags:
+ - lvm
+ - vgcreate
+
+ - name: fact vgs
+ ansible.builtin.set_fact:
+ vgs: "{{ hostname }}"
+ tags:
+ - disk
+ - mount
+ - lvm
+
+ - name: vgcreate
+ ansible.builtin.command: "vgcreate {{ hostname }} {{ pvs }}"
+ tags:
+ - lvm
+ - vgcreate
+
+ - name: lvcreate root
+ ansible.builtin.command: "lvcreate --type raid1 -L 30g --name rootfs {{ vgs }}"
+ tags:
+ - lvm
+ - lvcreate
+
+ - name: mkfs root
+ ansible.builtin.command: "mkfs.ext4 -T floppy,news -L ROOTFS /dev/{{ vgs }}/rootfs"
+ tags:
+ - rootfs
+ - mkfs
+
diff --git a/roles/install_gentoo/tasks/download.yml b/roles/install_gentoo/tasks/download.yml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/roles/install_gentoo/tasks/download.yml
diff --git a/roles/install_gentoo/tasks/install.yml b/roles/install_gentoo/tasks/install.yml
new file mode 100644
index 0000000..c083e0f
--- /dev/null
+++ b/roles/install_gentoo/tasks/install.yml
@@ -0,0 +1,138 @@
+---
+- name: install
+ tags:
+ - install
+ block:
+ - name: create directories
+ ansible.builtin.file:
+ path: "{{ chroot }}/{{ item.path }}"
+ owner: "{{ item.owner | default('root') }}"
+ group: "{{ item.group | default('root') }}"
+ mode: "{{ item.mode | default('u=rwx,g=rx,o=rx') }}"
+ state: directory
+ recurse: true
+ loop:
+ - path: /etc/portage/package.keywords
+ - path: /etc/portage/package.mask
+ - path: /etc/portage/repos.conf
+ - path: /var/cache/portage/distfiles
+ mode: 'u=rwx,g=rwx,o=rx'
+ owner: 0
+ group: 250 # portage
+
+ - name: /etc/hostname
+ ansible.builtin.copy:
+ dest: "{{ chroot }}/etc/hostname"
+ content: "{{ hostname }}\n" # TODO: fqdn in the systemd world?
+
+ - name: resolv.conf
+ ansible.builtin.copy:
+ dest: "{{ chroot }}/etc/resolv.conf"
+ content: |
+ domain gentoo.org
+ nameserver 8.8.8.8
+ nameserver 8.8.4.4
+ nameserver 2001:4860:4860::8888
+ nameserver 2001:4860:4860::8844
+
+ - name: stat /dev/shm
+ ansible.builtin.stat:
+ path: /dev/shm
+ follow: false # explicitly; we need this to NOT be a link
+ register: stat_dev_shm
+
+ - name: fix /dev/shm
+ ansible.builtin.shell: >
+ rm -f /dev/shm && mkdir /dev/shm && mount --types tmpfs --options nosuid,nodev,noexec shm /dev/shm && chmod 1777 /dev/shm /run/shm
+ when: not stat_dev_shm.stat.exists or stat_dev_shm.stat.islnk
+
+ - name: virtual.fstab
+ ansible.builtin.copy:
+ dest: /tmp/virtual.fstab
+ content: |
+ /proc {{ chroot }}/proc proc rw,relatime 0 0
+ /sys {{ chroot }}/sys bind rbind,rslave 0 0
+ /dev {{ chroot }}/dev bind rbind,rslave 0 0
+ /run {{ chroot }}/run bind bind,slave 0 0
+
+ - name: mount virtual
+ # TODO: how to safely check if this is needed at all?
+ ansible.builtin.command: mount -T /tmp/virtual.fstab -a
+
+ - name: /etc/portage/repos.conf/gentoo.conf
+ ansible.builtin.copy:
+ dest: "{{ chroot }}/etc/portage/repos.conf/gentoo.conf"
+ src: "{{ chroot }}/usr/share/portage/config/repos.conf"
+ remote_src: true
+
+ # TODO: change profile (stick to matching tarball for MVP)
+
+ # binhost: handled by catalyst
+ #- name: "{{ chroot }}"/etc/portage/binrepos.conf/gentoobinhost.conf
+ # ansible.builtin.copy:
+ # path: "{{ chroot }}"/etc/portage/binrepos.conf/gentoobinhost.conf
+ # content: |
+ # ...
+
+ - name: cmd nproc
+ ansible.builtin.command: nproc
+ register: cmd_nproc
+
+ - name: fact nproc
+ ansible.builtin.set_fact:
+ nproc: "{{ cmd_nproc.stdout }}"
+
+ # TODO: infra-overlay
+ - name: make-ansible.conf
+ ansible.builtin.copy:
+ dest: "{{ chroot }}/etc/portage/make-ansible.conf"
+ content: |
+ FEATURES="${FEATURES} getbinpkg binpkg-request-signature binpkg-multi-instance compress-index compressdebug -news split-elog split-log splitdebug unmerge-logs"
+ RUBY_TARGETS="ruby31"
+ DISTDIR=/var/cache/portage/distfiles
+ #PORTDIR_OVERLAY="\${PORTDIR_OVERLAY} /usr/local/infra-overlay"
+ MAKEOPTS="-j {{ nproc|int }}"
+ # complete math hack; there are no logarithms here
+ EMERGE_DEFAULT_OPTS="--jobs {{ (((nproc|int)/4 + 1)|int) }}"
+ # infra runs hardened everywhere
+ # shadow & augeas needed for puppet
+ # dracut for kernel
+ USE="${USE} hardened shadow augeas dracut modules-compress -fonts -themes -qt -qt4 -qt5 -X gtk -gtk2 -gtk3 -qt6 -kde -gnome"
+
+ - name: make.conf include ansible file for bootstrap
+ ansible.builtin.lineinfile:
+ path: "{{ chroot }}/etc/portage/make.conf"
+ state: present
+ line: 'source /etc/portage/make-ansible.conf'
+
+ - name: locale
+ ansible.builtin.lineinfile:
+ path: "{{ chroot }}/etc/locale.gen"
+ state: present
+ line: "{{ item }}"
+ loop:
+ - en_US ISO-8859-1
+ - en_US.UTF-8 UTF-8
+ register: locale
+
+ - name: locale-gen
+ when: locale.changed
+ ansible.builtin.command: "chroot {{ chroot }} locale-gen"
+
+ - name: env-update
+ ansible.builtin.command: >
+ chroot {{ chroot }} /usr/sbin/env-update
+
+ - name: check /var/db/repos/gentoo/metadata/timestamp.commit
+ ansible.builtin.stat:
+ path: "{{ chroot }}/var/db/repos/gentoo/metadata/timestamp.commit"
+ register: stat_timestamp_commit
+
+ - name: emerge-webrsync
+ ansible.builtin.command: >
+ chroot {{ chroot }} /usr/sbin/emerge-webrsync --verbose --keep
+ when: not stat_timestamp_commit.stat.exists
+
+ - name: emerge some base infra packages before puppet
+ ansible.builtin.command: >
+ chroot {{ chroot }} emerge -uq {{ base_packages|join(' ') }}
diff --git a/roles/install_gentoo/tasks/main.yml b/roles/install_gentoo/tasks/main.yml
new file mode 100644
index 0000000..b528285
--- /dev/null
+++ b/roles/install_gentoo/tasks/main.yml
@@ -0,0 +1,25 @@
+---
+- include_tasks: misc.yml
+ tags:
+ - misc
+
+- include_tasks: disks.yml
+ tags:
+ - disks
+ - mount
+
+- include_tasks: mount.yml
+ tags:
+ - mount
+
+- include_tasks: rootfs.yml
+ tags:
+ - rootfs
+
+- include_tasks: install.yml
+ tags:
+ - install
+
+- include_tasks: puppet.yml
+ tags:
+ - puppet
diff --git a/roles/install_gentoo/tasks/misc.yml b/roles/install_gentoo/tasks/misc.yml
new file mode 100644
index 0000000..cf51f78
--- /dev/null
+++ b/roles/install_gentoo/tasks/misc.yml
@@ -0,0 +1,23 @@
+---
+# Set this extremely early, because it gets included into LVM & MD data.
+# TODO: should it be the FQDN or not
+- name: hostname
+ ansible.builtin.command: hostname {{ hostname }}
+
+- name: sysctl for install
+ ansible.posix.sysctl:
+ name: "{{ item.name }}"
+ value: "{{ item.value }}"
+ sysctl_set: "{{ item.sysctl_set | default (true) }}"
+ state: "{{ item.state | default('present') }}"
+ ignoreerrors: "{{ item.ignoreerrors | default (false) }}"
+ loop:
+ - { name: dev.raid.speed_limit_max, value: 2000000 }
+ tags:
+ - misc
+
+- name: import keys
+ ansible.builtin.command:
+ cmd: " gpg --auto-key-locate=clear,nodefault,wkd --locate-key releng@gentoo.org"
+ tags:
+ - misc
diff --git a/roles/install_gentoo/tasks/mount.yml b/roles/install_gentoo/tasks/mount.yml
new file mode 100644
index 0000000..74672cb
--- /dev/null
+++ b/roles/install_gentoo/tasks/mount.yml
@@ -0,0 +1,44 @@
+---
+- name: mkdir /mnt/gentoo
+ ansible.builtin.file:
+ path: /mnt/gentoo
+ state: directory
+ tags:
+ - mount
+
+- name: mount /
+ ansible.builtin.command: "mount /dev/{{ vgs }}/rootfs /mnt/gentoo"
+ tags:
+ - mount
+
+- name: mkdir /mnt/gentoo/boot
+ ansible.builtin.file:
+ path: /mnt/gentoo/boot
+ state: directory
+ tags:
+ - mount
+
+- name: mount /boot
+ ansible.builtin.command: "mount LABEL=BOOT /mnt/gentoo/boot"
+ tags:
+ - mount
+
+- name: mkdir /mnt/gentoo/boot/efi
+ ansible.builtin.file:
+ path: /mnt/gentoo/boot/efi
+ state: directory
+ tags:
+ - mount
+
+- name: mount /boot/efi
+ ansible.builtin.command: "mount LABEL=EFI /mnt/gentoo/boot/efi"
+ tags:
+ - mount
+
+- name: mkdir /mnt/gentoo/tmp
+ ansible.builtin.file:
+ path: /mnt/gentoo/tmp
+ state: directory
+ mode: '01777'
+ tags:
+ - mount
diff --git a/roles/install_gentoo/tasks/puppet.yml b/roles/install_gentoo/tasks/puppet.yml
new file mode 100644
index 0000000..e413297
--- /dev/null
+++ b/roles/install_gentoo/tasks/puppet.yml
@@ -0,0 +1,202 @@
+---
+- name: puppet
+ tags:
+ - puppet
+ block:
+ - name: stat /usr/lib/sysusers.d/acct-group-puppet.conf
+ ansible.builtin.stat:
+ path: "{{ chroot }}/usr/lib/sysusers.d/acct-group-puppet.conf"
+ register: stat_puppet_group
+
+ - name: stat /usr/lib/sysusers.d/acct-user-puppet.conf
+ ansible.builtin.stat:
+ path: "{{ chroot }}/usr/lib/sysusers.d/acct-user-puppet.conf"
+ register: stat_puppet_user
+
+ - name: ensure puppet user & group exist
+ ansible.builtin.command: >
+ chroot {{ chroot }} emerge -1 acct-group/puppet acct-user/puppet
+ when: (not stat_puppet_user.stat.exists) or (not stat_puppet_group.stat.exists)
+
+ - name: getent puppet
+ ansible.builtin.command: >
+ chroot {{ chroot }} getent passwd puppet
+ register: getent_puppet
+
+ - name: set puppet uid/gid
+ ansible.builtin.set_fact:
+ puppet_uid: "{{ (getent_puppet.stdout | split(':'))[2] }}"
+ puppet_gid: "{{ (getent_puppet.stdout | split(':'))[3] }}"
+
+ - name: create directories
+ ansible.builtin.file:
+ path: "{{ chroot }}/{{ item.path }}"
+ owner: "{{ item.owner | default('root') }}"
+ group: "{{ item.group | default('root') }}"
+ mode: "{{ item.mode | default('0755') }}"
+ state: directory
+ recurse: true
+ loop:
+ - path: /etc/puppetlabs
+ mode: '0750'
+ group: "{{ puppet_gid }}"
+ #- path: /etc/puppetlabs/puppet # this should be a symlink to /etc/puppet/
+ - path: /etc/puppet
+ mode: '0750'
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/devices
+ mode: '0750'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/facter
+ mode: '0750'
+ owner: root
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/ssl
+ mode: '0751'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/ssl/certs/
+ mode: '0755'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/ssl/certificate_requests
+ mode: '0755'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/ssl/public_keys/
+ mode: '0755'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/ssl/private_keys/
+ mode: '0750'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+ - path: /etc/puppet/ssl/private/
+ mode: '0750'
+ owner: "{{ puppet_uid }}"
+ group: "{{ puppet_gid }}"
+
+ # If the paths exist and they are only empty, we can safely convert it.
+ - name: cleanup non-symlink /etc/puppetlabs/puppet
+ ansible.builtin.shell: >
+ chroot {{ chroot }} bash -c 'if test ! -L /etc/puppetlabs/puppet && test -d /etc/puppetlabs/puppet ; then rm /etc/puppetlabs/puppet/ssl/.keep_app-admin_puppet-0 ; rmdir -v /etc/puppetlabs/puppet/ssl/* /etc/puppetlabs/puppet/ssl /etc/puppetlabs/puppet/devices /etc/puppetlabs/puppet/ ; ln -vsf /etc/puppet /etc/puppetlabs/puppet; fi'
+
+ # TODO: add check for non-empty /etc/puppetlabs/puppet/
+
+ - name: /etc/puppetlabs/puppet
+ ansible.builtin.file:
+ state: link
+ src: "/etc/puppet"
+ dest: "{{ chroot }}/etc/puppetlabs/puppet"
+ follow: false
+ force: true
+
+ - name: check for /etc/puppet/puppet.conf
+ ansible.builtin.stat:
+ path: "{{ chroot }}/etc/puppet/puppet.conf"
+ register: stat_etc_puppet_puppet_conf
+
+ - name: bootstrap /etc/puppet/puppet.conf
+ when: not stat_etc_puppet_puppet_conf.stat.exists
+ ansible.builtin.copy:
+ dest: "{{ chroot }}/etc/puppet/puppet.conf"
+ content: |
+ [main]
+ environment = puppet7
+ use_srv_records = true
+ srv_domain = puppet.infra.gentoo.org
+ #server = puppetmaster.gentoo.org
+ #ca_server = puppetca.gentoo.org
+ #pluginsync = true
+ report = true
+ splaylimit = 900
+ certificate_expire_warning = 7d
+ parser = future
+ trusted_node_data = true
+ stringify_facts = false
+ number_of_facts_soft_limit = 16384
+ include_legacy_facts = true
+
+ - name: check for /etc/puppet/csr_attributes.yaml
+ ansible.builtin.stat:
+ path: "{{ chroot }}/etc/puppet/csr_attributes.yaml"
+ register: stat_etc_puppet_csr_attributes_yaml
+
+ - name: /etc/puppet/csr_attributes.yaml
+ when: not stat_etc_puppet_csr_attributes_yaml.stat.exists
+ ansible.builtin.copy:
+ dest: "{{ chroot }}/etc/puppet/csr_attributes.yaml"
+ mode: '0640'
+ owner: root
+ group: "{{ puppet_gid }}"
+ # TODO: nicer way to generate YAML here
+ content: |
+ custom_attributes:
+ 1.2.840.113549.1.9.7: '{{ puppet_autosign_token }}'
+
+ - name: check for /usr/bin/puppet
+ ansible.builtin.stat:
+ path: "{{ chroot }}/usr/bin/puppet"
+ register: stat_usr_bin_puppet
+
+ - name: install puppet
+ ansible.builtin.command: >
+ chroot {{ chroot }} emerge -qu app-admin/puppet
+ when: not stat_usr_bin_puppet.stat.exists
+
+ # Do this AFTER puppet
+ - name: install ~arch msgpack
+ ansible.builtin.shell: >
+ ACCEPT_KEYWORDS=~amd64 chroot {{ chroot }} emerge -qu dev-ruby/msgpack
+ when: not stat_usr_bin_puppet.stat.exists
+
+ - name: puppet cert check, pass1
+ ansible.builtin.stat:
+ path: "{{ chroot }}/etc/puppet/ssl/certs/{{ hostname }}.gentoo.org.pem"
+ register: stat_puppet_cert_pass1
+
+ - name: puppet enrollment
+ #chroot {{ chroot }} puppet agent --onetime --test --verbose
+ # TODO: it needs to use wait at least once
+ ansible.builtin.command: >
+ timeout 30 chroot {{ chroot }} /usr/sbin/puppet ssl bootstrap --onetime --verbose --waitforcert=10
+ when: not stat_puppet_cert_pass1.stat.exists
+
+ - name: puppet cert check, pass2
+ ansible.builtin.stat:
+ path: "{{ chroot }}/etc/puppet/ssl/certs/{{ hostname }}.gentoo.org.pem"
+ register: stat_puppet_cert_pass2
+
+ - name: puppet enrollment failed
+ ansible.builtin.fail:
+ msg: >
+ You should run this on the master (if the fingerprints match):
+ puppet cert list
+ puppet cert sign {{ hostname }}.gentoo.org
+ when: not stat_puppet_cert_pass2.stat.exists
+
+ - name: initial puppet run
+ ansible.builtin.command: >
+ chroot {{ chroot }} /usr/bin/puppet agent --onetime --no-daemonize --test
+
+ # TODO: verify if obsolete
+ - name: make.conf final pass
+ ansible.builtin.command: >
+ chroot {{ chroot }} /usr/local/sbin/update-config /etc/portage/make.conf /etc/portage/make.conf.d .conf
+
+ # TODO: verify if obsolete
+ - name: etc-update
+ ansible.builtin.command: >
+ chroot {{ chroot }} etc-update --automode -5
+
+ # TODO: verify if obsolete
+ - name: check if root password is set
+ ansible.builtin.command: >
+ awk -F: '/^root:/{if($2 == "*"){ exit 1; }}' {{chroot}}/etc/shadow
+ register: root_password_set
+
+ - name: abort if no root password
+ ansible.builtin.fail:
+ msg: "No root password set on {{ hostname }}"
+ when: root_password_set.rc == 1
diff --git a/roles/install_gentoo/tasks/reboot.yml b/roles/install_gentoo/tasks/reboot.yml
new file mode 100644
index 0000000..439900b
--- /dev/null
+++ b/roles/install_gentoo/tasks/reboot.yml
@@ -0,0 +1,18 @@
+---
+- name: umount virtual
+ #grep -e /mnt/gentoo/sys -e /mnt/gentoo/dev -e /mnt/gentoo/run -e /mnt/gentoo/proc /proc/mounts |awk '{print $2}' |sort -r |xargs umount
+ ansible.builtin.shell: >
+ grep {{ [' -e ' | product(ansible_loop.allitems) | map ('join') | list | join(' ') }} /proc/mounts |awk '{print $2}' |sort -r |xargs umount
+ loop:
+ - /sys
+ - /dev
+ - /run
+ - /proc
+ loop_control:
+ extended: true
+
+- name: umount physical
+ ansible.builtin.shell: >
+ grep /mnt/gentoo /proc/mounts |awk '{print $2}' |sort -r |xargs --verbose umount
+ loop_control:
+ extended: true
diff --git a/roles/install_gentoo/tasks/rootfs.yml b/roles/install_gentoo/tasks/rootfs.yml
new file mode 100644
index 0000000..1933ea0
--- /dev/null
+++ b/roles/install_gentoo/tasks/rootfs.yml
@@ -0,0 +1,59 @@
+---
+- name: download latest
+ ansible.builtin.get_url:
+ url: "{{ base_url }}/latest-{{ tarball_variant }}.txt"
+ dest: "/mnt/gentoo/tmp/latest-{{ tarball_variant }}.txt" # required for if-modified
+ register: res_latest
+ tags:
+ - rootfs
+
+- name: verify latest
+ ansible.builtin.command:
+ cmd: "gpg --verify /mnt/gentoo/tmp/latest-{{ tarball_variant }}.txt"
+ tags:
+ - rootfs
+ - download
+
+- name: set tarball fact
+ ansible.builtin.shell: |
+ sed '/^---.*BEGIN.*SIGNATURE/,/^---.END.*SIGNATURE/d; /^#\|^$/d; s, .*,,g; 3,$p' -n /mnt/gentoo/tmp/latest-{{ tarball_variant }}.txt
+ register: tarball_rel_url
+ tags:
+ - rootfs
+
+- name: download sha256
+ ansible.builtin.get_url:
+ url: "{{ base_url }}/{{ item.rel_url }}"
+ dest: "/mnt/gentoo/tmp/{{ item.rel_url | basename }}" # required for if-modified
+ when: res_latest.changed
+ tags:
+ - rootfs
+ - download
+ loop:
+ - rel_url: "{{ tarball_rel_url.stdout }}.sha256"
+
+- name: verify sha256
+ ansible.builtin.command:
+ cmd: "gpg --verify /mnt/gentoo/tmp/{{ tarball_rel_url.stdout | basename }}.sha256"
+ tags:
+ - rootfs
+ - download
+
+- name: download tarball
+ ansible.builtin.get_url:
+ url: "{{ base_url }}/{{ item.rel_url }}"
+ dest: "/mnt/gentoo/tmp/{{ item.rel_url | basename }}" # required for if-modified
+ when: res_latest.changed
+ tags:
+ - rootfs
+ - download
+ loop:
+ - rel_url: "{{ tarball_rel_url.stdout }}"
+ checksum: "sha256:/mnt/gentoo/tmp/{{ tarball_rel_url.stdout }}.sha256"
+
+- name: unpack
+ ansible.builtin.command: "tar xpf /mnt/gentoo/tmp/{{ tarball_rel_url.stdout | basename }} --xattrs-include='*.*' --numeric-owner -C /mnt/gentoo"
+ when: res_latest.changed
+ tags:
+ - rootfs
+ - unpack