diff --git a/main.yml b/main.yml index eee75c7..d876277 100644 --- a/main.yml +++ b/main.yml @@ -1,7 +1,7 @@ --- - name: Create and configure VMs hosts: all - strategy: free + strategy: free # noqa: run-once[play] gather_facts: false become: true vars_prompt: @@ -26,36 +26,65 @@ confirm: true vars_files: vars.yml pre_tasks: - - name: Set ansible_python_interpreter - when: os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] + - name: Validate variables + ansible.builtin.assert: + that: + - install_type in ["virtual", "physical"] + - hypervisor in ["libvirt", "proxmox", "vmware", "none"] + - filesystem in ["btrfs", "ext4", "xfs"] + - install_drive is defined + - install_type == "physical" or vm_size is defined + - install_type == "physical" or vm_memory is defined + - os in ["archlinux", "almalinux", "debian11", "debian12", "debian13", "fedora", "rhel8", "rhel9", "rhel10", "rocky", "ubuntu", "ubuntu-lts"] + - os not in ["rhel8", "rhel9", "rhel10"] or rhel_iso is defined + - >- + install_type == "physical" + or ( + (filesystem == "btrfs" and (vm_size | default(0) | int) >= 10) + or (filesystem != "btrfs" and (vm_size | default(0) | int) >= 20) + ) + - >- + install_type == "physical" + or ( + (vm_size | default(0) | float) + >= ( + (vm_memory | default(0) | float / 1024 >= 16.0) + | ternary( + (vm_memory | default(0) | float / 2048), + [vm_memory | default(0) | float / 1024, 4.0] | max + ) + + 16 + ) + ) + fail_msg: Invalid input specified, please try again. + + - name: Normalize optional flags + ansible.builtin.set_fact: + cis: "{{ cis | default(false) | bool }}" + custom_iso: "{{ custom_iso | default(false) | bool }}" + is_rhel: "{{ os | default('') | lower in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] }}" + is_debian: "{{ os | default('') | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'] }}" + changed_when: false + + - name: Set Python interpreter for RHEL-based installers + when: + - ansible_python_interpreter is not defined + - os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] ansible.builtin.set_fact: ansible_python_interpreter: /usr/bin/python3 + changed_when: false - - name: Set default variables - ansible.builtin.set_fact: - cis: false - - - name: Set SSH Access - when: hypervisor != "vmware" + - name: Set SSH access + when: + - install_type == "virtual" + - hypervisor != "vmware" ansible.builtin.set_fact: ansible_user: "{{ user_name }}" ansible_password: "{{ user_password }}" ansible_become_password: "{{ user_password }}" ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" - - name: Validate variables - ansible.builtin.assert: - that: - - hypervisor in ["libvirt", "proxmox", "vmware", "none"] - - filesystem in ["btrfs", "ext4", "xfs"] - - install_drive is defined - - os in ["archlinux", "almalinux", "debian11", "debian12", "debian13", "fedora", "rhel8", "rhel9", "rhel10", "rocky", "ubuntu", "ubuntu-lts"] - - os not in ["rhel8", "rhel9", "rhel10"] or rhel_iso is defined - - (filesystem == "btrfs" and (vm_size | int) >= 10) or (filesystem != "btrfs" and (vm_size | int) >= 20) - - (vm_size | float) >= ((vm_memory | float / 1024 >= 16.0) | ternary((vm_memory | float / 2048), [vm_memory | float / 1024, 4.0] | max) + 16) - fail_msg: Invalid input specified, please try again. - - - name: Set connection + - name: Set connection for VMware when: hypervisor == "vmware" ansible.builtin.set_fact: ansible_connection: vmware_tools @@ -73,31 +102,65 @@ - role: partitioning vars: - boot_partition_suffix: 1 - main_partition_suffix: 2 + partitioning_boot_partition_suffix: 1 + partitioning_main_partition_suffix: 2 - role: bootstrap - role: configuration - role: cis - when: cis | bool + when: cis | default(false) | bool - role: cleanup - when: install_type == "virtual" - vars: - ansible_connection: local + when: install_type in ["virtual", "physical"] + become: false - tasks: - - name: Set final SSH Credentials - when: hypervisor != 'vmware' or (hypervisor == 'vmware' and vmware_ssh | bool) + post_tasks: + - name: Set post-reboot connection flags + ansible.builtin.set_fact: + post_reboot_can_connect: >- + {{ + (ansible_connection | default('ssh')) != 'ssh' + or ((vm_ip | default('') | string | length) > 0) + or ( + install_type == 'physical' + and (ansible_host | default('') | string | length) > 0 + ) + }} + changed_when: false + + - name: Set final SSH credentials for post-reboot tasks + when: + - post_reboot_can_connect | default(false) | bool ansible.builtin.set_fact: ansible_user: "{{ user_name }}" ansible_password: "{{ user_password }}" ansible_become_password: "{{ user_password }}" ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" - - name: Check if VM is back and running - when: not (hypervisor == 'vmware' and cis | bool) - ansible.builtin.wait_for_connection: - timeout: 300 + - name: Install post-reboot extra packages + when: + - extra_packages is defined + - post_reboot_can_connect | default(false) | bool + block: + - name: Normalize extra package list + ansible.builtin.set_fact: + post_install_extra_packages: >- + {{ + ( + extra_packages + if (extra_packages is iterable and extra_packages is not string) + else (extra_packages | default('') | string).split(',') + ) + | map('trim') + | reject('equalto', '') + | list + }} + changed_when: false + + - name: Install extra packages + when: post_install_extra_packages | length > 0 + ansible.builtin.package: + name: "{{ post_install_extra_packages }}" + state: present diff --git a/roles/environment/tasks/main.yml b/roles/environment/tasks/main.yml index 11c82e4..de6238d 100644 --- a/roles/environment/tasks/main.yml +++ b/roles/environment/tasks/main.yml @@ -1,10 +1,10 @@ --- -- name: Configre work environment - become: true +- name: Configure work environment + become: "{{ hypervisor != 'vmware' }}" block: - name: Wait for connection ansible.builtin.wait_for_connection: - timeout: 60 + timeout: 180 delay: 5 - name: Gather facts @@ -13,118 +13,144 @@ - name: Check if host is booted from the Arch install media ansible.builtin.stat: path: /run/archiso - register: archiso_stat + register: environment_archiso_stat - name: Abort if the host is not booted from the Arch install media + when: + - not (custom_iso | default(false) | bool) + - not environment_archiso_stat.stat.exists ansible.builtin.fail: msg: This host is not booted from the Arch install media! - when: not archiso_stat.stat.exists - - name: Register Network Interface + - name: Select primary Network Interface when: hypervisor == "vmware" - ansible.builtin.shell: "set -o pipefail && ip l | awk -F': ' '!/lo/{print $2; exit}'" - changed_when: interface_name.rc == 0 - register: interface_name + ansible.builtin.set_fact: + environment_interface_name: >- + {{ + ( + (ansible_facts.interfaces | default(ansible_facts['ansible_interfaces'] | default([]))) + | reject('equalto', 'lo') + | list + | first + ) + | default('') + }} + changed_when: false - name: Set IP-Address - when: hypervisor == "vmware" - ansible.builtin.command: "ip addr replace {{ ansible_host }}/{{ vm_nms | default(24) }} dev {{ interface_name.stdout }}" - changed_when: result.rc == 0 - register: result + when: + - hypervisor == "vmware" + - vm_ip is defined + - vm_ip | length + ansible.builtin.command: >- + ip addr replace {{ vm_ip }}/{{ vm_nms | default(24) }} + dev {{ environment_interface_name }} + register: environment_ip_result + changed_when: environment_ip_result.rc == 0 - name: Set Default Gateway - when: hypervisor == "vmware" + when: + - hypervisor == "vmware" + - vm_gw is defined + - vm_gw | length + - vm_ip is defined + - vm_ip | length ansible.builtin.command: "ip route replace default via {{ vm_gw }}" - changed_when: result.rc == 0 - register: result + register: environment_gateway_result + changed_when: environment_gateway_result.rc == 0 - name: Synchronize clock via NTP ansible.builtin.command: timedatectl set-ntp true - changed_when: result.rc == 0 - register: result + register: environment_ntp_result + changed_when: false - name: Configure SSH for root login when: hypervisor == "vmware" and (vmware_ssh is defined and vmware_ssh | bool) block: - - name: Allow empty passwords temporarily + - name: Allow login ansible.builtin.replace: path: /etc/ssh/sshd_config - regexp: "^#?PermitEmptyPasswords.*" - replace: "PermitEmptyPasswords yes" - - - name: Allow root login - ansible.builtin.replace: - path: /etc/ssh/sshd_config - regexp: "^#?PermitRootLogin.*" - replace: "PermitRootLogin yes" + regexp: "{{ item.regexp }}" + replace: "{{ item.replace }}" + loop: + - regexp: "^#?PermitEmptyPasswords.*" + replace: "PermitEmptyPasswords yes" + - regexp: "^#?PermitRootLogin.*" + replace: "PermitRootLogin yes" - name: Reload SSH service to apply changes ansible.builtin.service: name: sshd state: reloaded - - name: Set connection back to SSH + - name: Set SSH connection for VMware ansible.builtin.set_fact: ansible_connection: ssh - ansible_user: "root" - ansible_password: "" - ansible_become_password: "" - ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" + ansible_user: root - - name: Speed-up Bootstrap process - ansible.builtin.lineinfile: - path: /etc/pacman.conf - regexp: ^#ParallelDownloads = - line: ParallelDownloads = 20 - - - name: Wait for Pacman - ansible.builtin.wait_for: - timeout: 15 - - - name: Setup Pacman - community.general.pacman: - update_cache: true - force: true - name: "{{ item.name }}" - state: latest - loop: - - { name: glibc } - - { name: dnf, os: [almalinux, fedora, rhel8, rhel9, rhel10, rocky] } - - { name: debootstrap, os: [debian11, debian12, debian13, ubuntu, ubuntu-lts] } - - { name: debian-archive-keyring, os: [debian11, debian12, debian13] } - - { name: ubuntu-keyring, os: [ubuntu, ubuntu-lts] } - when: "'os' not in item or os in item.os" - retries: 4 - delay: 15 - - - name: Prepare /iso mount and repository for RHEL-based systems - when: os | lower in ["rhel8", "rhel9", "rhel10"] + - name: Prepare installer environment block: - - name: Create /iso directory - ansible.builtin.file: - path: /usr/local/install/redhat/dvd - state: directory - mode: "0755" + - name: Speed-up Bootstrap process + when: not (custom_iso | default(false) | bool) + ansible.builtin.lineinfile: + path: /etc/pacman.conf + regexp: ^#ParallelDownloads = + line: ParallelDownloads = 20 - - name: Mount RHEL ISO - ansible.posix.mount: - src: "{{ '/dev/sr1' if hypervisor == 'vmware' else '/dev/sr2' }}" - path: /usr/local/install/redhat/dvd - fstype: iso9660 - opts: "ro,loop" - state: mounted + - name: Wait for pacman lock to be released + when: not (custom_iso | default(false) | bool) + ansible.builtin.wait_for: + path: /var/lib/pacman/db.lck + state: absent + timeout: 120 + changed_when: false - - name: Configure RHEL Repos for installation - when: os | lower in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"] - block: - - name: Create directories for repository files and RPM GPG keys - ansible.builtin.file: - path: /etc/yum.repos.d - state: directory - mode: "0755" + - name: Setup Pacman + when: + - not (custom_iso | default(false) | bool) + - "'os' not in item or os in item.os" + community.general.pacman: + update_cache: true + force: true + name: "{{ item.name }}" + state: latest + loop: + - {name: glibc} + - {name: dnf, os: [almalinux, fedora, rhel8, rhel9, rhel10, rocky]} + - {name: debootstrap, os: [debian11, debian12, debian13, ubuntu, ubuntu-lts]} + - {name: debian-archive-keyring, os: [debian11, debian12, debian13]} + - {name: ubuntu-keyring, os: [ubuntu, ubuntu-lts]} + retries: 4 + delay: 15 - - name: Create RHEL repository file - ansible.builtin.template: - src: "{{ os | lower }}.repo.j2" - dest: /etc/yum.repos.d/{{ os | lower }}.repo - mode: "0644" + - name: Prepare /iso mount and repository for RHEL-based systems + when: os | lower in ["rhel8", "rhel9", "rhel10"] + block: + - name: Create /iso directory + ansible.builtin.file: + path: /usr/local/install/redhat/dvd + state: directory + mode: "0755" + + - name: Mount RHEL ISO + ansible.posix.mount: + src: "{{ '/dev/sr1' if hypervisor == 'vmware' else '/dev/sr2' }}" + path: /usr/local/install/redhat/dvd + fstype: iso9660 + opts: "ro,loop" + state: mounted + + - name: Configure RHEL Repos for installation + when: is_rhel | default(false) + block: + - name: Create directories for repository files and RPM GPG keys + ansible.builtin.file: + path: /etc/yum.repos.d + state: directory + mode: "0755" + + - name: Create RHEL repository file + ansible.builtin.template: + src: "{{ os | lower }}.repo.j2" + dest: /etc/yum.repos.d/{{ os | lower }}.repo + mode: "0644"