Compare commits
24 Commits
master
...
a6bc7ffe04
| Author | SHA1 | Date | |
|---|---|---|---|
| a6bc7ffe04 | |||
| c529e71ebc | |||
| cb46de2b6d | |||
| 9169117b25 | |||
| 6c94c519fb | |||
| efd96a42b8 | |||
| 68661c3cca | |||
| 1db20c7ac0 | |||
| 7b155b427b | |||
| ca8721e98f | |||
| cdb2559d8f | |||
| 443f6623df | |||
| 6cf418fe00 | |||
| 47ec5fe621 | |||
| 240f945cce | |||
| 663a04556f | |||
| 6febd1acf1 | |||
| 008187860c | |||
| cd1be6b5e1 | |||
| 15be6149fd | |||
| ca29ad200d | |||
| 8079099cee | |||
| 9e79185b07 | |||
| b88bf2860f |
@@ -1,5 +1,6 @@
|
|||||||
skip_list:
|
skip_list:
|
||||||
- run-once
|
- run-once
|
||||||
- var-naming[no-role-prefix] # user-facing API dicts (cis, system, hypervisor) are intentionally not role-prefixed
|
- var-naming[no-role-prefix] # user-facing API dicts (cis, system, hypervisor) are intentionally not role-prefixed
|
||||||
|
- args[module] # false positives from variable-based module_defaults (_proxmox_auth, _vmware_auth)
|
||||||
exclude_paths:
|
exclude_paths:
|
||||||
- roles/global_defaults/
|
- roles/global_defaults/
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -202,14 +202,29 @@ When `interfaces` is empty, the flat fields (`bridge`, `ip`, `prefix`, `gateway`
|
|||||||
|
|
||||||
#### `system.users`
|
#### `system.users`
|
||||||
|
|
||||||
|
Dict keyed by username. At least one user must have a `password` (used for SSH access during bootstrap). Users without a password get locked accounts (key-only auth).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
system:
|
||||||
|
users:
|
||||||
|
svcansible:
|
||||||
|
password: "vault_lookup"
|
||||||
|
keys:
|
||||||
|
- "ssh-ed25519 AAAA..."
|
||||||
|
appuser:
|
||||||
|
sudo: "ALL=(ALL) NOPASSWD: ALL"
|
||||||
|
keys:
|
||||||
|
- "ssh-ed25519 BBBB..."
|
||||||
|
```
|
||||||
|
|
||||||
| Key | Type | Default | Description |
|
| Key | Type | Default | Description |
|
||||||
| ---------- | ----------- | ------- | -------------------------------------------------- |
|
| ---------- | ----------- | ------- | -------------------------------------------------- |
|
||||||
| `name` | string | -- | Username (required) |
|
| *(dict key)* | string | -- | Username (required) |
|
||||||
| `password` | string | -- | User password (required for first user) |
|
| `password` | string | -- | User password (required for at least one user) |
|
||||||
| `keys` | list | `[]` | SSH public keys |
|
| `keys` | list | `[]` | SSH public keys |
|
||||||
| `sudo` | bool/string | -- | `true` for NOPASSWD ALL, or custom sudoers string |
|
| `sudo` | bool/string | -- | `true` for NOPASSWD ALL, or custom sudoers string |
|
||||||
|
|
||||||
The first user's credentials are prompted interactively via `vars_prompt` unless supplied in inventory or `-e`.
|
Users must be defined in inventory. The dict format enables additive merging across inventory layers with `hash_behaviour=merge`.
|
||||||
|
|
||||||
#### `system.root`
|
#### `system.root`
|
||||||
|
|
||||||
@@ -398,7 +413,7 @@ ansible-playbook -i inventory.yml main.yml
|
|||||||
ansible-playbook -i inventory.yml main.yml -e @vars.yml
|
ansible-playbook -i inventory.yml main.yml -e @vars.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Credentials for the first user and root are prompted interactively via `vars_prompt` unless already set in inventory or passed via `-e`.
|
All credentials (`system.users`, `system.root.password`) must be defined in inventory or passed via `-e`.
|
||||||
|
|
||||||
Example inventory files are included:
|
Example inventory files are included:
|
||||||
|
|
||||||
@@ -408,7 +423,7 @@ Example inventory files are included:
|
|||||||
|
|
||||||
## 7. Security
|
## 7. Security
|
||||||
|
|
||||||
Use **Ansible Vault** for all sensitive values (`hypervisor.password`, `system.luks.passphrase`, `system.users[].password`, `system.root.password`).
|
Use **Ansible Vault** for all sensitive values (`hypervisor.password`, `system.luks.passphrase`, user passwords in `system.users`, `system.root.password`).
|
||||||
|
|
||||||
## 8. Safety
|
## 8. Safety
|
||||||
|
|
||||||
|
|||||||
100
main.yml
100
main.yml
@@ -14,94 +14,7 @@
|
|||||||
strategy: free # noqa: run-once[play]
|
strategy: free # noqa: run-once[play]
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
become: true
|
become: true
|
||||||
vars_prompt:
|
|
||||||
- name: user_name
|
|
||||||
prompt: |
|
|
||||||
What is your username?
|
|
||||||
private: false
|
|
||||||
|
|
||||||
- name: user_public_key
|
|
||||||
prompt: |
|
|
||||||
What is your ssh key?
|
|
||||||
private: false
|
|
||||||
|
|
||||||
- name: user_password
|
|
||||||
prompt: |
|
|
||||||
What is your password?
|
|
||||||
confirm: true
|
|
||||||
|
|
||||||
- name: root_password
|
|
||||||
prompt: |
|
|
||||||
What is your root password?
|
|
||||||
confirm: true
|
|
||||||
pre_tasks:
|
pre_tasks:
|
||||||
- name: Apply prompted authentication values to system input
|
|
||||||
no_log: true
|
|
||||||
vars:
|
|
||||||
system_input: "{{ system | default({}) }}"
|
|
||||||
system_users_input: "{{ system_input.users | default([]) }}"
|
|
||||||
system_first_user: >-
|
|
||||||
{{
|
|
||||||
system_users_input[0]
|
|
||||||
if (system_users_input is iterable and system_users_input is not string
|
|
||||||
and system_users_input is not mapping and system_users_input | length > 0)
|
|
||||||
else {}
|
|
||||||
}}
|
|
||||||
system_root_input: "{{ (system_input.root | default({})) if (system_input.root is mapping) else {} }}"
|
|
||||||
prompt_user_name: "{{ user_name | default(system_user_name | default(''), true) | string }}"
|
|
||||||
prompt_user_key: "{{ user_public_key | default(user_key | default(system_user_key | default(''), true), true) | string | trim }}"
|
|
||||||
prompt_user_password: "{{ user_password | default(system_user_password | default(''), true) | string }}"
|
|
||||||
prompt_root_password: "{{ root_password | default(system_root_password | default(''), true) | string }}"
|
|
||||||
resolved_user:
|
|
||||||
name: >-
|
|
||||||
{{
|
|
||||||
system_first_user.name | string
|
|
||||||
if (system_first_user.name | default('') | string | length) > 0
|
|
||||||
else prompt_user_name
|
|
||||||
}}
|
|
||||||
keys: >-
|
|
||||||
{{
|
|
||||||
system_first_user['keys']
|
|
||||||
if (system_first_user['keys'] is defined
|
|
||||||
and system_first_user['keys'] is iterable
|
|
||||||
and system_first_user['keys'] is not string
|
|
||||||
and system_first_user['keys'] | length > 0)
|
|
||||||
else (
|
|
||||||
[prompt_user_key]
|
|
||||||
if (prompt_user_key | length > 0)
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
password: >-
|
|
||||||
{{
|
|
||||||
system_first_user.password | string
|
|
||||||
if (system_first_user.password | default('') | string | length) > 0
|
|
||||||
else prompt_user_password
|
|
||||||
}}
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
system: >-
|
|
||||||
{{
|
|
||||||
system_input
|
|
||||||
| combine(
|
|
||||||
{
|
|
||||||
'users': (
|
|
||||||
[resolved_user]
|
|
||||||
+ (system_users_input[1:]
|
|
||||||
if (system_users_input is sequence
|
|
||||||
and system_users_input is not string
|
|
||||||
and system_users_input | length > 1)
|
|
||||||
else [])
|
|
||||||
),
|
|
||||||
'root': {
|
|
||||||
'password': (
|
|
||||||
(system_root_input.password | default('') | string | length) > 0
|
|
||||||
) | ternary(system_root_input.password | string, prompt_root_password)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
recursive=True
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
|
|
||||||
- name: Load global defaults
|
- name: Load global defaults
|
||||||
ansible.builtin.import_role:
|
ansible.builtin.import_role:
|
||||||
name: global_defaults
|
name: global_defaults
|
||||||
@@ -160,8 +73,6 @@
|
|||||||
ansible.builtin.include_role:
|
ansible.builtin.include_role:
|
||||||
name: cleanup
|
name: cleanup
|
||||||
public: true
|
public: true
|
||||||
vars:
|
|
||||||
ansible_become: false
|
|
||||||
|
|
||||||
rescue:
|
rescue:
|
||||||
- name: Delete VM on bootstrap failure
|
- name: Delete VM on bootstrap failure
|
||||||
@@ -208,10 +119,15 @@
|
|||||||
when:
|
when:
|
||||||
- post_reboot_can_connect | bool
|
- post_reboot_can_connect | bool
|
||||||
no_log: true
|
no_log: true
|
||||||
|
vars:
|
||||||
|
_primary: "{{ (system_cfg.users | dict2items | selectattr('value.password', 'defined') | first) }}"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_user: "{{ system_cfg.users[0].name }}"
|
ansible_connection: ssh
|
||||||
ansible_password: "{{ system_cfg.users[0].password }}"
|
ansible_host: "{{ system_cfg.network.ip }}"
|
||||||
ansible_become_password: "{{ system_cfg.users[0].password }}"
|
ansible_port: 22
|
||||||
|
ansible_user: "{{ _primary.key }}"
|
||||||
|
ansible_password: "{{ _primary.value.password }}"
|
||||||
|
ansible_become_password: "{{ _primary.value.password }}"
|
||||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,11 @@
|
|||||||
register: bootstrap_debian_update_result
|
register: bootstrap_debian_update_result
|
||||||
changed_when: bootstrap_debian_update_result.rc == 0
|
changed_when: bootstrap_debian_update_result.rc == 0
|
||||||
|
|
||||||
|
- name: Upgrade all packages to latest versions
|
||||||
|
ansible.builtin.command: "{{ chroot_command }} apt full-upgrade -y"
|
||||||
|
register: bootstrap_debian_upgrade_result
|
||||||
|
changed_when: "'0 upgraded' not in bootstrap_debian_upgrade_result.stdout"
|
||||||
|
|
||||||
- name: Install extra packages
|
- name: Install extra packages
|
||||||
when: bootstrap_debian_extra_args | trim | length > 0
|
when: bootstrap_debian_extra_args | trim | length > 0
|
||||||
ansible.builtin.command: "{{ chroot_command }} apt install -y {{ bootstrap_debian_extra_args }}"
|
ansible.builtin.command: "{{ chroot_command }} apt install -y {{ bootstrap_debian_extra_args }}"
|
||||||
|
|||||||
@@ -54,6 +54,11 @@
|
|||||||
register: bootstrap_ubuntu_update_result
|
register: bootstrap_ubuntu_update_result
|
||||||
changed_when: bootstrap_ubuntu_update_result.rc == 0
|
changed_when: bootstrap_ubuntu_update_result.rc == 0
|
||||||
|
|
||||||
|
- name: Upgrade all packages to latest versions
|
||||||
|
ansible.builtin.command: "{{ chroot_command }} apt full-upgrade -y"
|
||||||
|
register: bootstrap_ubuntu_upgrade_result
|
||||||
|
changed_when: "'0 upgraded' not in bootstrap_ubuntu_upgrade_result.stdout"
|
||||||
|
|
||||||
- name: Install extra packages
|
- name: Install extra packages
|
||||||
when: bootstrap_ubuntu_extra_args | trim | length > 0
|
when: bootstrap_ubuntu_extra_args | trim | length > 0
|
||||||
ansible.builtin.command: "{{ chroot_command }} apt install -y {{ bootstrap_ubuntu_extra_args }}"
|
ansible.builtin.command: "{{ chroot_command }} apt install -y {{ bootstrap_ubuntu_extra_args }}"
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ bootstrap_debian:
|
|||||||
- lrzsz
|
- lrzsz
|
||||||
- mtr
|
- mtr
|
||||||
- ncdu
|
- ncdu
|
||||||
|
- needrestart
|
||||||
- net-tools
|
- net-tools
|
||||||
- network-manager
|
- network-manager
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
@@ -262,6 +263,7 @@ bootstrap_ubuntu:
|
|||||||
- mtr
|
- mtr
|
||||||
- ncdu
|
- ncdu
|
||||||
- ncurses-term
|
- ncurses-term
|
||||||
|
- needrestart
|
||||||
- net-tools
|
- net-tools
|
||||||
- network-manager
|
- network-manager
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
- name: Initialize cleaned VM XML
|
- name: Initialize cleaned VM XML
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_get_xml.get_xml }}"
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_get_xml.get_xml }}"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Remove boot ISO device from VM XML (source match)
|
- name: Remove boot ISO device from VM XML (source match)
|
||||||
when: boot_iso is defined and boot_iso | length > 0
|
when: boot_iso is defined and boot_iso | length > 0
|
||||||
@@ -28,7 +27,6 @@
|
|||||||
when: boot_iso is defined and boot_iso | length > 0
|
when: boot_iso is defined and boot_iso | length > 0
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_boot_source.xmlstring }}"
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_boot_source.xmlstring }}"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Remove boot ISO device from VM XML (target fallback)
|
- name: Remove boot ISO device from VM XML (target fallback)
|
||||||
community.general.xml:
|
community.general.xml:
|
||||||
@@ -40,7 +38,6 @@
|
|||||||
- name: Update cleaned VM XML after removing boot ISO
|
- name: Update cleaned VM XML after removing boot ISO
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_boot.xmlstring }}"
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_boot.xmlstring }}"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Remove cloud-init ISO device from VM XML (source match)
|
- name: Remove cloud-init ISO device from VM XML (source match)
|
||||||
community.general.xml:
|
community.general.xml:
|
||||||
@@ -52,7 +49,6 @@
|
|||||||
- name: Update cleaned VM XML after removing cloud-init ISO source match
|
- name: Update cleaned VM XML after removing cloud-init ISO source match
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_cloudinit_source.xmlstring }}"
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_cloudinit_source.xmlstring }}"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Remove cloud-init ISO device from VM XML (target fallback)
|
- name: Remove cloud-init ISO device from VM XML (target fallback)
|
||||||
community.general.xml:
|
community.general.xml:
|
||||||
@@ -64,7 +60,6 @@
|
|||||||
- name: Update cleaned VM XML after removing cloud-init ISO
|
- name: Update cleaned VM XML after removing cloud-init ISO
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_cloudinit.xmlstring }}"
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_cloudinit.xmlstring }}"
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Strip XML declaration for libvirt define
|
- name: Strip XML declaration for libvirt define
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
@@ -76,7 +71,6 @@
|
|||||||
| regex_replace("(?i)encoding=[\"'][^\"']+[\"']", "")
|
| regex_replace("(?i)encoding=[\"'][^\"']+[\"']", "")
|
||||||
| trim
|
| trim
|
||||||
}}
|
}}
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Update VM definition without installer media
|
- name: Update VM definition without installer media
|
||||||
community.libvirt.virt:
|
community.libvirt.virt:
|
||||||
|
|||||||
@@ -25,3 +25,4 @@
|
|||||||
community.proxmox.proxmox_kvm:
|
community.proxmox.proxmox_kvm:
|
||||||
vmid: "{{ system_cfg.id }}"
|
vmid: "{{ system_cfg.id }}"
|
||||||
state: restarted
|
state: restarted
|
||||||
|
no_log: true
|
||||||
|
|||||||
@@ -7,34 +7,11 @@
|
|||||||
xen_installer_media_enabled: "{{ xen_installer_media_enabled | default(false) }}"
|
xen_installer_media_enabled: "{{ xen_installer_media_enabled | default(false) }}"
|
||||||
block:
|
block:
|
||||||
- name: Ensure Xen disk definitions exist
|
- name: Ensure Xen disk definitions exist
|
||||||
when: virtualization_xen_disks is not defined
|
ansible.builtin.include_tasks: ../../virtualization/tasks/_xen_disks.yml
|
||||||
ansible.builtin.set_fact:
|
|
||||||
cleanup_xen_disks: "{{ cleanup_xen_disks | default([]) + [cleanup_xen_disk_cfg] }}"
|
|
||||||
vars:
|
|
||||||
device_letter_map: "{{ disk_letter_map }}"
|
|
||||||
device_letter: "{{ device_letter_map[ansible_loop.index0] }}"
|
|
||||||
cleanup_xen_disk_cfg: >-
|
|
||||||
{{
|
|
||||||
{
|
|
||||||
'path': (
|
|
||||||
virtualization_xen_disk_path ~ '/' ~ hostname ~ '.qcow2'
|
|
||||||
if ansible_loop.index0 == 0
|
|
||||||
else virtualization_xen_disk_path ~ '/' ~ hostname ~ '-disk' ~ ansible_loop.index0 ~ '.qcow2'
|
|
||||||
),
|
|
||||||
'target': 'xvd' ~ device_letter,
|
|
||||||
'size': (item.size | float)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
loop: "{{ system_cfg.disks }}"
|
|
||||||
loop_control:
|
|
||||||
label: "{{ item | to_json }}"
|
|
||||||
extended: true
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Render Xen VM configuration without installer media
|
- name: Render Xen VM configuration without installer media
|
||||||
vars:
|
vars:
|
||||||
xen_installer_media_enabled: false
|
xen_installer_media_enabled: false
|
||||||
virtualization_xen_disks: "{{ virtualization_xen_disks | default(cleanup_xen_disks | default([])) }}"
|
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: xen.cfg.j2
|
src: xen.cfg.j2
|
||||||
dest: /tmp/xen-{{ hostname }}.cfg
|
dest: /tmp/xen-{{ hostname }}.cfg
|
||||||
|
|||||||
@@ -52,9 +52,7 @@
|
|||||||
vars:
|
vars:
|
||||||
configuration_grub_cfg_cmd: >-
|
configuration_grub_cfg_cmd: >-
|
||||||
{{
|
{{
|
||||||
'/usr/sbin/' + _configuration_platform.grub_mkconfig_prefix + ' -o '
|
'/usr/sbin/' + _configuration_platform.grub_mkconfig_prefix + ' -o /boot/grub2/grub.cfg'
|
||||||
+ partitioning_efi_mountpoint
|
|
||||||
+ '/EFI/' + _efi_vendor + '/grub.cfg'
|
|
||||||
if os_family == 'RedHat'
|
if os_family == 'RedHat'
|
||||||
else '/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg'
|
else '/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg'
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -86,7 +86,6 @@
|
|||||||
device: "{{ configuration_luks_device }}"
|
device: "{{ configuration_luks_device }}"
|
||||||
passphrase: "{{ configuration_luks_passphrase }}"
|
passphrase: "{{ configuration_luks_passphrase }}"
|
||||||
new_keyfile: "/mnt{{ configuration_luks_keyfile_path }}"
|
new_keyfile: "/mnt{{ configuration_luks_keyfile_path }}"
|
||||||
register: configuration_luks_addkey_retry
|
|
||||||
failed_when: false
|
failed_when: false
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
|
|||||||
@@ -80,11 +80,10 @@
|
|||||||
host stderr={{ configuration_luks_tpm2_enroll_host.stderr | default('') }}
|
host stderr={{ configuration_luks_tpm2_enroll_host.stderr | default('') }}
|
||||||
rescue:
|
rescue:
|
||||||
- name: Warn about TPM2 enrollment failure
|
- name: Warn about TPM2 enrollment failure
|
||||||
ansible.builtin.fail:
|
ansible.builtin.debug:
|
||||||
msg: >-
|
msg: >-
|
||||||
WARNING: TPM2 enrollment failed — falling back to keyfile auto-decrypt.
|
WARNING: TPM2 enrollment failed — falling back to keyfile auto-decrypt.
|
||||||
The system will use a keyfile instead of TPM2 for automatic LUKS unlock.
|
The system will use a keyfile instead of TPM2 for automatic LUKS unlock.
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Fallback to keyfile auto-decrypt
|
- name: Fallback to keyfile auto-decrypt
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
set smartindent
|
set smartindent
|
||||||
set mouse=a
|
set mouse=a
|
||||||
insertafter: EOF
|
insertafter: EOF
|
||||||
marker: "# {mark} CUSTOM VIM CONFIG"
|
marker: "\" {mark} CUSTOM VIM CONFIG"
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
# Tuned for VM workloads: low swappiness, aggressive writeback, large page-cluster
|
# Tuned for VM workloads: low swappiness, aggressive writeback, large page-cluster
|
||||||
|
|||||||
@@ -15,15 +15,15 @@
|
|||||||
validate: /usr/sbin/visudo --check --file=%s
|
validate: /usr/sbin/visudo --check --file=%s
|
||||||
|
|
||||||
- name: Deploy per-user sudoers rules
|
- name: Deploy per-user sudoers rules
|
||||||
when: item.sudo | default(false)
|
when: item.value.sudo is defined and (item.value.sudo | string | length > 0)
|
||||||
vars:
|
vars:
|
||||||
configuration_sudoers_rule: >-
|
configuration_sudoers_rule: >-
|
||||||
{{ item.sudo if item.sudo is string else 'ALL=(ALL) NOPASSWD: ALL' }}
|
{{ item.value.sudo if item.value.sudo is string else 'ALL=(ALL) NOPASSWD: ALL' }}
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
content: "{{ item.name }} {{ configuration_sudoers_rule }}\n"
|
content: "{{ item.key }} {{ configuration_sudoers_rule }}\n"
|
||||||
dest: "/mnt/etc/sudoers.d/{{ item.name }}"
|
dest: "/mnt/etc/sudoers.d/{{ item.key }}"
|
||||||
mode: "0440"
|
mode: "0440"
|
||||||
validate: /usr/sbin/visudo --check --file=%s
|
validate: /usr/sbin/visudo --check --file=%s
|
||||||
loop: "{{ system_cfg.users }}"
|
loop: "{{ system_cfg.users | dict2items }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.name }}"
|
label: "{{ item.key }}"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Set root password
|
- name: Set root password
|
||||||
|
when: (system_cfg.root.password | default('') | string | length) > 0
|
||||||
ansible.builtin.shell: >-
|
ansible.builtin.shell: >-
|
||||||
set -o pipefail &&
|
set -o pipefail &&
|
||||||
echo 'root:{{ system_cfg.root.password | password_hash("sha512") }}' | {{ chroot_command }} /usr/sbin/chpasswd -e
|
echo 'root:{{ system_cfg.root.password | password_hash("sha512") }}' | {{ chroot_command }} /usr/sbin/chpasswd -e
|
||||||
@@ -9,6 +10,13 @@
|
|||||||
changed_when: configuration_root_result.rc == 0
|
changed_when: configuration_root_result.rc == 0
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
|
- name: Lock root account when no password is set
|
||||||
|
when: (system_cfg.root.password | default('') | string | length) == 0
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
{{ chroot_command }} /usr/bin/passwd -l root
|
||||||
|
register: configuration_root_lock_result
|
||||||
|
changed_when: configuration_root_lock_result.rc == 0
|
||||||
|
|
||||||
- name: Set root shell
|
- name: Set root shell
|
||||||
ansible.builtin.command: >-
|
ansible.builtin.command: >-
|
||||||
{{ chroot_command }} /usr/sbin/usermod --shell {{ system_cfg.root.shell }} root
|
{{ chroot_command }} /usr/sbin/usermod --shell {{ system_cfg.root.shell }} root
|
||||||
@@ -18,44 +26,43 @@
|
|||||||
- name: Create user accounts
|
- name: Create user accounts
|
||||||
vars:
|
vars:
|
||||||
configuration_user_group: "{{ _configuration_platform.user_group }}"
|
configuration_user_group: "{{ _configuration_platform.user_group }}"
|
||||||
# UID starts at 1000; safe for fresh installs only
|
|
||||||
configuration_useradd_cmd: >-
|
configuration_useradd_cmd: >-
|
||||||
{{ chroot_command }} /usr/sbin/useradd --create-home --user-group
|
{{ chroot_command }} /usr/sbin/useradd --create-home --user-group
|
||||||
--uid {{ 1000 + ansible_loop.index0 }}
|
--uid {{ 1000 + _idx }}
|
||||||
--groups {{ configuration_user_group }} {{ item.name }}
|
--groups {{ configuration_user_group }} {{ item.key }}
|
||||||
--password {{ item.password | password_hash('sha512') }} --shell {{ item.shell | default('/bin/bash') }}
|
{{ ('--password ' ~ (item.value.password | password_hash('sha512'))) if (item.value.password | default('') | string | length > 0) else '' }}
|
||||||
|
--shell {{ item.value.shell | default('/bin/bash') }}
|
||||||
ansible.builtin.command: "{{ configuration_useradd_cmd }}"
|
ansible.builtin.command: "{{ configuration_useradd_cmd }}"
|
||||||
loop: "{{ system_cfg.users }}"
|
loop: "{{ system_cfg.users | dict2items }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
extended: true
|
index_var: _idx
|
||||||
label: "{{ item.name }}"
|
label: "{{ item.key }}"
|
||||||
register: configuration_user_result
|
register: configuration_user_result
|
||||||
changed_when: configuration_user_result.rc == 0
|
changed_when: configuration_user_result.rc == 0
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
- name: Ensure .ssh directory exists
|
- name: Ensure .ssh directory exists
|
||||||
when: item['keys'] | default([]) | length > 0
|
when: (item.value['keys'] | default([]) | length) > 0
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "/mnt/home/{{ item.name }}/.ssh"
|
path: "/mnt/home/{{ item.key }}/.ssh"
|
||||||
state: directory
|
state: directory
|
||||||
owner: "{{ 1000 + ansible_loop.index0 }}"
|
owner: "{{ 1000 + _idx }}"
|
||||||
group: "{{ 1000 + ansible_loop.index0 }}"
|
group: "{{ 1000 + _idx }}"
|
||||||
mode: "0700"
|
mode: "0700"
|
||||||
loop: "{{ system_cfg.users }}"
|
loop: "{{ system_cfg.users | dict2items }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
extended: true
|
index_var: _idx
|
||||||
label: "{{ item.name }}"
|
label: "{{ item.key }}"
|
||||||
|
|
||||||
- name: Add SSH public keys to authorized_keys
|
- name: Deploy SSH authorized_keys
|
||||||
vars:
|
when: (item.value['keys'] | default([]) | length) > 0
|
||||||
configuration_uid: "{{ 1000 + (system_cfg.users | map(attribute='name') | list).index(item.0.name) }}"
|
ansible.builtin.copy:
|
||||||
ansible.builtin.lineinfile:
|
content: "{{ item.value['keys'] | join('\n') }}\n"
|
||||||
path: "/mnt/home/{{ item.0.name }}/.ssh/authorized_keys"
|
dest: "/mnt/home/{{ item.key }}/.ssh/authorized_keys"
|
||||||
line: "{{ item.1 }}"
|
owner: "{{ 1000 + _idx }}"
|
||||||
owner: "{{ configuration_uid }}"
|
group: "{{ 1000 + _idx }}"
|
||||||
group: "{{ configuration_uid }}"
|
|
||||||
mode: "0600"
|
mode: "0600"
|
||||||
create: true
|
loop: "{{ system_cfg.users | dict2items }}"
|
||||||
loop: "{{ system_cfg.users | subelements('keys', skip_missing=True) }}"
|
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.0.name }}: {{ item.1[:40] }}..."
|
index_var: _idx
|
||||||
|
label: "{{ item.key }}"
|
||||||
|
|||||||
@@ -87,9 +87,10 @@
|
|||||||
- name: Switch to SSH connection
|
- name: Switch to SSH connection
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_connection: ssh
|
ansible_connection: ssh
|
||||||
|
ansible_host: "{{ system_cfg.network.ip }}"
|
||||||
|
ansible_port: 22
|
||||||
ansible_user: root
|
ansible_user: root
|
||||||
ansible_password: ""
|
ansible_password: ""
|
||||||
ansible_host: "{{ system_cfg.network.ip }}"
|
|
||||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
- name: Reset connection for SSH switchover
|
- name: Reset connection for SSH switchover
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ system_defaults:
|
|||||||
mirror: ""
|
mirror: ""
|
||||||
packages: []
|
packages: []
|
||||||
disks: []
|
disks: []
|
||||||
users: []
|
users: {}
|
||||||
root:
|
root:
|
||||||
password: ""
|
password: ""
|
||||||
shell: "/bin/bash"
|
shell: "/bin/bash"
|
||||||
@@ -129,6 +129,10 @@ system_defaults:
|
|||||||
rhel_repo:
|
rhel_repo:
|
||||||
source: "iso" # iso|satellite|none — how RHEL systems get packages post-install
|
source: "iso" # iso|satellite|none — how RHEL systems get packages post-install
|
||||||
url: "" # Satellite/custom repo URL when source=satellite
|
url: "" # Satellite/custom repo URL when source=satellite
|
||||||
|
aur:
|
||||||
|
enabled: false
|
||||||
|
helper: "yay" # yay|paru
|
||||||
|
user: "_aur_builder"
|
||||||
chroot:
|
chroot:
|
||||||
tool: "arch-chroot" # arch-chroot|chroot|systemd-nspawn
|
tool: "arch-chroot" # arch-chroot|chroot|systemd-nspawn
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
}}
|
}}
|
||||||
# --- Storage & accounts ---
|
# --- Storage & accounts ---
|
||||||
disks: "{{ system_raw.disks | default([]) }}"
|
disks: "{{ system_raw.disks | default([]) }}"
|
||||||
users: "{{ system_raw.users | default([]) }}"
|
users: "{{ system_raw.users | default({}) }}"
|
||||||
root:
|
root:
|
||||||
password: "{{ system_raw.root.password | string }}"
|
password: "{{ system_raw.root.password | string }}"
|
||||||
shell: "{{ system_raw.root.shell | default('/bin/bash') | string }}"
|
shell: "{{ system_raw.root.shell | default('/bin/bash') | string }}"
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
that:
|
that:
|
||||||
- system is mapping
|
- system is mapping
|
||||||
- system.network is not defined or system.network is mapping
|
- system.network is not defined or system.network is mapping
|
||||||
- system.users is not defined or (system.users is iterable and system.users is not string and system.users is not mapping)
|
- system.users is not defined or system.users is mapping
|
||||||
- system.root is not defined or system.root is mapping
|
- system.root is not defined or system.root is mapping
|
||||||
- system.luks is not defined or system.luks is mapping
|
- system.luks is not defined or system.luks is mapping
|
||||||
- system.features is not defined or system.features is mapping
|
- system.features is not defined or system.features is mapping
|
||||||
fail_msg: "system and its nested keys (network, root, luks, features) must be dictionaries; system.users must be a list."
|
fail_msg: "system and its nested keys (network, root, luks, features, users) must be dictionaries."
|
||||||
quiet: true
|
quiet: true
|
||||||
|
|
||||||
- name: Validate DNS lists (not strings)
|
- name: Validate DNS lists (not strings)
|
||||||
@@ -25,17 +25,17 @@
|
|||||||
quiet: true
|
quiet: true
|
||||||
|
|
||||||
- name: Validate system.users entries
|
- name: Validate system.users entries
|
||||||
when: system.users is defined and system.users | length > 0
|
when: system.users is defined and system.users is mapping and system.users | length > 0
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- item is mapping
|
- item.value is mapping
|
||||||
- item.name is defined and (item.name | string | length) > 0
|
- item.key | string | length > 0
|
||||||
- item['keys'] is not defined or (item['keys'] is iterable and item['keys'] is not string)
|
- item.value['keys'] is not defined or (item.value['keys'] is iterable and item.value['keys'] is not string)
|
||||||
fail_msg: "Each system.users[] entry must be a dict with 'name'; 'keys' must be a list."
|
fail_msg: "Each system.users entry must be a dict keyed by username; 'keys' must be a list."
|
||||||
quiet: true
|
quiet: true
|
||||||
loop: "{{ system.users }}"
|
loop: "{{ system.users | dict2items }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.name | default('(unnamed)') }}"
|
label: "{{ item.key }}"
|
||||||
|
|
||||||
- name: Validate system features input types
|
- name: Validate system features input types
|
||||||
when: system.features is defined
|
when: system.features is defined
|
||||||
|
|||||||
@@ -81,10 +81,14 @@
|
|||||||
when:
|
when:
|
||||||
- system_cfg.type == "virtual"
|
- system_cfg.type == "virtual"
|
||||||
- hypervisor_type != "vmware"
|
- hypervisor_type != "vmware"
|
||||||
|
vars:
|
||||||
|
_primary: "{{ (system_cfg.users | dict2items | selectattr('value.password', 'defined') | first) }}"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_user: "{{ system_cfg.users[0].name }}"
|
ansible_host: "{{ system_cfg.network.ip }}"
|
||||||
ansible_password: "{{ system_cfg.users[0].password }}"
|
ansible_port: 22
|
||||||
ansible_become_password: "{{ system_cfg.users[0].password }}"
|
ansible_user: "{{ _primary.key }}"
|
||||||
|
ansible_password: "{{ _primary.value.password }}"
|
||||||
|
ansible_become_password: "{{ _primary.value.password }}"
|
||||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
@@ -92,12 +96,12 @@
|
|||||||
when: hypervisor_type == "vmware"
|
when: hypervisor_type == "vmware"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_connection: vmware_tools
|
ansible_connection: vmware_tools
|
||||||
ansible_vmware_host: "{{ hypervisor_cfg.url }}"
|
ansible_host: "{{ hypervisor_cfg.url }}"
|
||||||
ansible_vmware_port: 443
|
ansible_port: 443
|
||||||
|
ansible_user: root
|
||||||
|
ansible_password: ""
|
||||||
ansible_vmware_user: "{{ hypervisor_cfg.username }}"
|
ansible_vmware_user: "{{ hypervisor_cfg.username }}"
|
||||||
ansible_vmware_password: "{{ hypervisor_cfg.password }}"
|
ansible_vmware_password: "{{ hypervisor_cfg.password }}"
|
||||||
ansible_vmware_guest_path: "/{{ hypervisor_cfg.datacenter }}/vm{{ system_cfg.path }}/{{ hostname }}"
|
ansible_vmware_guest_path: "/{{ hypervisor_cfg.datacenter }}/vm{{ system_cfg.path }}/{{ hostname }}"
|
||||||
ansible_vmware_validate_certs: "{{ hypervisor_cfg.certs | bool }}"
|
ansible_vmware_validate_certs: "{{ hypervisor_cfg.certs | bool }}"
|
||||||
ansible_vmware_tools_user: root
|
|
||||||
ansible_vmware_tools_password: "{{ system_cfg.root.password }}"
|
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|||||||
@@ -261,13 +261,16 @@
|
|||||||
fail_msg: "Invalid system sizing. Check system.cpus, system.memory, and system.disks[0].size."
|
fail_msg: "Invalid system sizing. Check system.cpus, system.memory, and system.disks[0].size."
|
||||||
quiet: true
|
quiet: true
|
||||||
|
|
||||||
- name: Validate at least one user is defined
|
- name: Validate at least one user with a password is defined
|
||||||
|
vars:
|
||||||
|
_pw_users: "{{ system_cfg.users | dict2items | selectattr('value.password', 'defined') | list }}"
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- system_cfg.users | default([]) | length > 0
|
- system_cfg.users | default({}) | length > 0
|
||||||
- system_cfg.users[0].name is defined and (system_cfg.users[0].name | string | length) > 0
|
- _pw_users | length > 0
|
||||||
- system_cfg.users[0].password is defined and (system_cfg.users[0].password | string | length) > 0
|
- _pw_users[0].key | string | length > 0
|
||||||
fail_msg: "At least one user with a name and password must be defined in system.users[]."
|
- _pw_users[0].value.password | string | length > 0
|
||||||
|
fail_msg: "At least one user with a password must be defined in system.users."
|
||||||
quiet: true
|
quiet: true
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
ansible.builtin.command: >-
|
ansible.builtin.command: >-
|
||||||
tune2fs -O "^orphan_file,^metadata_csum_seed"
|
tune2fs -O "^orphan_file,^metadata_csum_seed"
|
||||||
"{{ install_drive }}{{ partitioning_part_sep }}{{ partitioning_boot_fs_partition_suffix }}"
|
"{{ install_drive }}{{ partitioning_part_sep }}{{ partitioning_boot_fs_partition_suffix }}"
|
||||||
register: partitioning_boot_ext4_tune_result
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Create swap filesystem
|
- name: Create swap filesystem
|
||||||
|
|||||||
@@ -65,9 +65,7 @@
|
|||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.command: "{{ item }}"
|
||||||
loop:
|
loop:
|
||||||
- "partprobe {{ install_drive }}"
|
- "partprobe {{ install_drive }}"
|
||||||
- "blockdev --rereadpt {{ install_drive }}"
|
|
||||||
- "udevadm settle"
|
- "udevadm settle"
|
||||||
register: partitioning_partprobe_result
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
@@ -91,9 +89,7 @@
|
|||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.command: "{{ item }}"
|
||||||
loop:
|
loop:
|
||||||
- "partprobe {{ install_drive }}"
|
- "partprobe {{ install_drive }}"
|
||||||
- "blockdev --rereadpt {{ install_drive }}"
|
|
||||||
- "udevadm settle"
|
- "udevadm settle"
|
||||||
register: partitioning_partprobe_retry
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
@@ -116,6 +112,5 @@
|
|||||||
loop:
|
loop:
|
||||||
- "partprobe {{ install_drive }}"
|
- "partprobe {{ install_drive }}"
|
||||||
- "udevadm settle"
|
- "udevadm settle"
|
||||||
register: partitioning_partprobe_settle
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
algorithm: "{{ system_cfg.luks.pbkdf }}"
|
algorithm: "{{ system_cfg.luks.pbkdf }}"
|
||||||
iteration_time: "{{ (system_cfg.luks.iter | float) / 1000 }}"
|
iteration_time: "{{ (system_cfg.luks.iter | float) / 1000 }}"
|
||||||
passphrase: "{{ system_cfg.luks.passphrase | string }}"
|
passphrase: "{{ system_cfg.luks.passphrase | string }}"
|
||||||
register: partitioning_luks_format_result
|
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
- name: Force-close LUKS mapper
|
- name: Force-close LUKS mapper
|
||||||
@@ -51,7 +50,6 @@
|
|||||||
name: "{{ system_cfg.luks.mapper }}"
|
name: "{{ system_cfg.luks.mapper }}"
|
||||||
passphrase: "{{ system_cfg.luks.passphrase | string }}"
|
passphrase: "{{ system_cfg.luks.passphrase | string }}"
|
||||||
allow_discards: "{{ 'discard' in (system_cfg.luks.options | lower) }}"
|
allow_discards: "{{ 'discard' in (system_cfg.luks.options | lower) }}"
|
||||||
register: partitioning_luks_open_result
|
|
||||||
no_log: true
|
no_log: true
|
||||||
rescue:
|
rescue:
|
||||||
- name: Force-close stale LUKS mapper
|
- name: Force-close stale LUKS mapper
|
||||||
@@ -79,7 +77,6 @@
|
|||||||
name: "{{ system_cfg.luks.mapper }}"
|
name: "{{ system_cfg.luks.mapper }}"
|
||||||
passphrase: "{{ system_cfg.luks.passphrase | string }}"
|
passphrase: "{{ system_cfg.luks.passphrase | string }}"
|
||||||
allow_discards: "{{ 'discard' in (system_cfg.luks.options | lower) }}"
|
allow_discards: "{{ 'discard' in (system_cfg.luks.options | lower) }}"
|
||||||
register: partitioning_luks_open_retry
|
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
- name: Get LUKS UUID
|
- name: Get LUKS UUID
|
||||||
|
|||||||
@@ -56,7 +56,6 @@
|
|||||||
- { subvol: var_log_audit }
|
- { subvol: var_log_audit }
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.subvol }}"
|
label: "{{ item.subvol }}"
|
||||||
register: partitioning_btrfs_subvol_result
|
|
||||||
|
|
||||||
- name: Set quotas for subvolumes
|
- name: Set quotas for subvolumes
|
||||||
when: system_cfg.features.cis.enabled | bool
|
when: system_cfg.features.cis.enabled | bool
|
||||||
@@ -74,7 +73,6 @@
|
|||||||
btrfs filesystem mkswapfile --size {{ partitioning_swap_size_gb }}g --uuid clear /mnt/@swap/swapfile
|
btrfs filesystem mkswapfile --size {{ partitioning_swap_size_gb }}g --uuid clear /mnt/@swap/swapfile
|
||||||
args:
|
args:
|
||||||
creates: /mnt/@swap/swapfile
|
creates: /mnt/@swap/swapfile
|
||||||
register: partitioning_btrfs_swap_result
|
|
||||||
|
|
||||||
- name: Unmount Partition
|
- name: Unmount Partition
|
||||||
ansible.posix.mount:
|
ansible.posix.mount:
|
||||||
|
|||||||
26
roles/virtualization/tasks/_xen_disks.yml
Normal file
26
roles/virtualization/tasks/_xen_disks.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- name: Build Xen disk definitions
|
||||||
|
when: virtualization_xen_disks is not defined
|
||||||
|
block:
|
||||||
|
- name: Compute Xen disk configuration
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
virtualization_xen_disks: "{{ virtualization_xen_disks | default([]) + [_xen_disk_cfg] }}"
|
||||||
|
vars:
|
||||||
|
device_letter_map: "{{ disk_letter_map }}"
|
||||||
|
device_letter: "{{ device_letter_map[ansible_loop.index0] }}"
|
||||||
|
_xen_disk_cfg: >-
|
||||||
|
{{
|
||||||
|
{
|
||||||
|
'path': (
|
||||||
|
virtualization_xen_disk_path ~ '/' ~ hostname ~ '.qcow2'
|
||||||
|
if ansible_loop.index0 == 0
|
||||||
|
else virtualization_xen_disk_path ~ '/' ~ hostname ~ '-disk' ~ ansible_loop.index0 ~ '.qcow2'
|
||||||
|
),
|
||||||
|
'target': 'xvd' ~ device_letter,
|
||||||
|
'size': (item.size | float)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
loop: "{{ system_cfg.disks }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item | to_json }}"
|
||||||
|
extended: true
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
- xl
|
- xl
|
||||||
- destroy
|
- destroy
|
||||||
- "{{ hostname }}"
|
- "{{ hostname }}"
|
||||||
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
- name: Remove Xen VM config
|
- name: Remove Xen VM config
|
||||||
|
|||||||
@@ -35,8 +35,8 @@
|
|||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{{ out }}
|
{{ out }}
|
||||||
community.proxmox.proxmox_kvm:
|
community.proxmox.proxmox_kvm:
|
||||||
ciuser: "{{ system_cfg.users[0].name }}"
|
ciuser: "{{ (system_cfg.users | dict2items | selectattr('value.password', 'defined') | first).key }}"
|
||||||
cipassword: "{{ system_cfg.users[0].password }}"
|
cipassword: "{{ (system_cfg.users | dict2items | selectattr('value.password', 'defined') | first).value.password }}"
|
||||||
ciupgrade: false
|
ciupgrade: false
|
||||||
vmid: "{{ system_cfg.id }}"
|
vmid: "{{ system_cfg.id }}"
|
||||||
name: "{{ hostname }}"
|
name: "{{ hostname }}"
|
||||||
|
|||||||
@@ -2,28 +2,7 @@
|
|||||||
- name: Deploy VM on Xen
|
- name: Deploy VM on Xen
|
||||||
block:
|
block:
|
||||||
- name: Build disk definitions
|
- name: Build disk definitions
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.include_tasks: _xen_disks.yml
|
||||||
virtualization_xen_disks: "{{ virtualization_xen_disks | default([]) + [virtualization_xen_disk_cfg] }}"
|
|
||||||
vars:
|
|
||||||
device_letter_map: "{{ disk_letter_map }}"
|
|
||||||
device_letter: "{{ device_letter_map[ansible_loop.index0] }}"
|
|
||||||
virtualization_xen_disk_cfg: >-
|
|
||||||
{{
|
|
||||||
{
|
|
||||||
'path': (
|
|
||||||
virtualization_xen_disk_path ~ '/' ~ hostname ~ '.qcow2'
|
|
||||||
if ansible_loop.index0 == 0
|
|
||||||
else virtualization_xen_disk_path ~ '/' ~ hostname ~ '-disk' ~ ansible_loop.index0 ~ '.qcow2'
|
|
||||||
),
|
|
||||||
'target': 'xvd' ~ device_letter,
|
|
||||||
'size': (item.size | float)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
loop: "{{ system_cfg.disks }}"
|
|
||||||
loop_control:
|
|
||||||
label: "{{ item | to_json }}"
|
|
||||||
extended: true
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Create VM disks for Xen
|
- name: Create VM disks for Xen
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
|||||||
@@ -4,17 +4,22 @@ ssh_pwauth: true
|
|||||||
package_update: false
|
package_update: false
|
||||||
package_upgrade: false
|
package_upgrade: false
|
||||||
users:
|
users:
|
||||||
{% for user in system_cfg.users %}
|
{% for username, attrs in system_cfg.users.items() %}
|
||||||
- name: "{{ user.name }}"
|
- name: "{{ username }}"
|
||||||
primary_group: "{{ user.name }}"
|
primary_group: "{{ username }}"
|
||||||
groups: users
|
groups: users
|
||||||
|
{% if attrs.sudo | default(false) | bool %}
|
||||||
sudo: "ALL=(ALL) NOPASSWD:ALL"
|
sudo: "ALL=(ALL) NOPASSWD:ALL"
|
||||||
passwd: "{{ user.password | password_hash('sha512') }}"
|
{% endif %}
|
||||||
|
{% if attrs.password | default('') | length > 0 %}
|
||||||
|
passwd: "{{ attrs.password | password_hash('sha512') }}"
|
||||||
lock_passwd: false
|
lock_passwd: false
|
||||||
{% set ssh_keys = user['keys'] | default([]) %}
|
{% else %}
|
||||||
{% if ssh_keys | length > 0 %}
|
lock_passwd: true
|
||||||
|
{% endif %}
|
||||||
|
{% if 'keys' in attrs and attrs['keys'] is iterable and attrs['keys'] is not string and attrs['keys'] | length > 0 %}
|
||||||
ssh_authorized_keys:
|
ssh_authorized_keys:
|
||||||
{% for key in ssh_keys %}
|
{% for key in attrs['keys'] %}
|
||||||
- "{{ key }}"
|
- "{{ key }}"
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user