diff options
Diffstat (limited to 'roles/install_gentoo')
-rw-r--r-- | roles/install_gentoo/tasks/disks.yml | 141 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/download.yml | 0 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/install.yml | 138 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/main.yml | 25 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/misc.yml | 23 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/mount.yml | 44 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/puppet.yml | 202 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/reboot.yml | 18 | ||||
-rw-r--r-- | roles/install_gentoo/tasks/rootfs.yml | 59 |
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 |