diff --git a/.gitignore b/.gitignore index d544e20..5ba511b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ hosts keys/ +.vscode/ +group_vars/infra.yml \ No newline at end of file diff --git a/all.yml b/all.yml index d899437..340f23c 100644 --- a/all.yml +++ b/all.yml @@ -3,6 +3,8 @@ serial: "{{ hosts_per_batch | d(1) | int }}" strategy: "{{ hosts_strategy | d('linear') }}" tasks: + + # TODO: multiple roles - name: get primary role set_fact: host_primary_role: "{%- if primary_role is defined -%}{{ primary_role }}\ @@ -11,33 +13,30 @@ {%- endif -%}" - - name: import role mappings - import_tasks: mappings.yml - + - name: check if role info file exists + stat: + path: "{{ (playbook_dir, 'roles', host_primary_role, 'tasks', 'info.yml') | path_join }}" + delegate_to: localhost + register: result + no_log: yes - - name: fail if mappings are missing - fail: - msg: role mappings are missing or invalid - when: (common_roles is not defined) or (common_roles | type_debug != 'list') - - - name: warn if current role mapping is missing - debug: - msg: "mapping for role \"{{ host_primary_role }}\" is missing - using default role mapping at stage 6" - when: (extra_roles | d({}))[host_primary_role] is not defined - - - - name: build role mapping - set_fact: - role_mapping: "{{ (((extra_roles | d({}))[host_primary_role] | d([{ 'stage': 6, 'role': host_primary_role }])) + - ([] if host_primary_role in (no_common_roles | d([])) else common_roles) + - ([{ 'stage': 1, 'role': 'container' }] if 'containers' in group_names else []) + - ([{ 'stage': 3, 'role': 'postgres', 'function': 'integrate' }] if host_primary_role in (database_roles | d([])) else []) - ) | sort(attribute='stage') }}" + - name: get role info + include_role: + name: "{{ host_primary_role }}" + tasks_from: info.yml + apply: + no_log: yes + when: result.stat.exists - - name: remember selected stages + - name: build role dependency list and stage info set_fact: + role_deps: "{{ (([{ 'stage': 6, 'role': host_primary_role }] if role_dependency is not defined else [role_dependency]) + + ([role_dependency_common] if (role_dependency_no_common | d(false) == false) else []) + + ([{ 'stage': 1, 'role': 'container' }] if 'containers' in group_names else []) + + ([{ 'stage': 3, 'role': 'postgres', 'function': 'integrate' }] if role_dependency_use_db | d(false) == true else []) + ) | flatten(levels=1) | sort(attribute='stage') }}" selected_stages: "{%- if stage is defined and ((stage | string) is search(',')) -%}{{ stage | string | split(',') | list | map('int') | list }}\ {%- elif (stage is not defined) or ((stage | int) == 0) -%}{{ [1,2,3,4,5,6,7,8,9] }}\ {%- else -%}{{ [stage | int] }}\ @@ -47,9 +46,13 @@ - name: show deployment info debug: - msg: "deploying primary role \"{{ host_primary_role }}\" on host \"{{ inventory_hostname }}\", {{ + msg: "deploying role \"{{ host_primary_role }}\" on host \"{{ inventory_hostname }}\", {{ (('stages ' if (selected_stages | length > 1) else 'stage ') ~ (selected_stages | join(', '))) - if ([1,2,3,4,5,6,7,8,9] | symmetric_difference(selected_stages) | list | length > 0) else 'all stages' }}" + if ([1,2,3,4,5,6,7,8,9] | symmetric_difference(selected_stages) | list | length > 0) else 'all stages' }}\n\n{{ + 'dependencies:\n' ~ (role_deps | map(attribute='stage') | list | zip( + role_deps | map(attribute='role') | list + ) | map('join', ': ') | list | join('\n')) + }}" - name: run pre_tasks diff --git a/group_vars/all.yml b/group_vars/all.yml index a1d2c2c..1f4d11b 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -34,3 +34,10 @@ bogons: services: {} mail_server: {} + +role_dependency_common: + - {stage: 2, role: 'common'} + - {stage: 4, role: 'ns'} + - {stage: 5, role: 'mail-user'} + - {stage: 8, role: 'iptables'} + - {stage: 9, role: 'backup', function: 'setup'} diff --git a/group_vars/infra.yml.template b/group_vars/infra.yml.template index 4c81a67..1cd4246 100644 --- a/group_vars/infra.yml.template +++ b/group_vars/infra.yml.template @@ -7,7 +7,7 @@ int_net: 10.0.0.0/8 int_tld: "corp.{{ tld }}" maintainer_email: "admin@{{ tld }}" -container_default_nameserver: 10.0.0.1 +default_nameserver: 10.0.0.1 networks: srv: diff --git a/mappings.yml b/mappings.yml index fa52d6f..e33e743 100644 --- a/mappings.yml +++ b/mappings.yml @@ -1,12 +1,7 @@ - name: define role list set_fact: # common roles for all primary roles - common_roles: - - {stage: 2, role: 'common'} - - {stage: 3, role: 'ns', function: 'add_records'} - - {stage: 5, role: 'mail-user'} - - {stage: 8, role: 'iptables'} - - {stage: 9, role: 'backup', function: 'setup'} + # these primary roles do not inherit common roles no_common_roles: diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index 5cc2a2c..080045c 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -15,7 +15,7 @@ set_fact: ssh_ok: no host_key_checking: no - ansible_password: "{{ container_password | d(host_password) }}" + ansible_password: "{{ host_password }}" ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | d('') }} -o StrictHostKeyChecking=no" - name: try to connect without key checking @@ -87,21 +87,22 @@ notify: restart dropbear - - name: copy dropbear init file - copy: - src: dropbear_init + - name: template dropbear init file + template: + src: dropbear_init.j2 dest: /etc/init.d/dropbear force: yes + lstrip_blocks: no notify: restart dropbear - name: ensure remote host has ansible key in authorized_keys file lineinfile: path: /root/.ssh/authorized_keys - line: "{{ container_key.public_key }}" + line: "{{ host_ssh_key.public_key }}" create: yes mode: 0400 - when: container_key is defined and container_key.public_key is defined + when: host_ssh_key is defined and host_ssh_key.public_key is defined when: ansible_distribution == 'Alpine' @@ -131,8 +132,8 @@ - name: add etc directory to backup plan include_role: name: backup + tasks_from: add.yml vars: - function: add backup_items: - /etc diff --git a/roles/common/templates/dropbear_init.j2 b/roles/common/templates/dropbear_init.j2 new file mode 100644 index 0000000..724b0e6 --- /dev/null +++ b/roles/common/templates/dropbear_init.j2 @@ -0,0 +1,19 @@ +#!/sbin/openrc-run + +depend() { + use logger dns + need net + after firewall +} + +start() { + ebegin "Starting dropbear" + /usr/sbin/dropbear ${DROPBEAR_OPTS} + eend $? +} + +stop() { + ebegin "Stopping dropbear" + start-stop-daemon --stop --pidfile /var/run/dropbear.pid + eend $? +} diff --git a/roles/container/defaults/main.yml b/roles/container/defaults/main.yml index 16eb2f0..702c3e2 100644 --- a/roles/container/defaults/main.yml +++ b/roles/container/defaults/main.yml @@ -3,5 +3,5 @@ container_pool: production container_distro: alpine container_template: - alpine: alpine-3.15-default_20211202_amd64.tar.xz + alpine: alpine-3.17-default_20221129_amd64.tar.xz debian: debian-11-standard_11.3-1_amd64.tar.zst diff --git a/roles/container/tasks/main.yml b/roles/container/tasks/main.yml index 51cec6c..c1f027b 100644 --- a/roles/container/tasks/main.yml +++ b/roles/container/tasks/main.yml @@ -1,8 +1,9 @@ - name: specify connection parameters set_fact: - pm_api_host: "{{ hostvars[selected_node]['ansible_host'] | mandatory }}" + pm_api_host: "{{ hostvars[selected_node]['ansible_host'] }}" pm_api_user: "{{ hostvars[selected_node]['api_user'] | d('root@pam') }}" - pm_api_password: "{{ hostvars[selected_node]['api_password'] | d(hostvars[selected_node]['ansible_password']) }}" + pm_api_password: "{{ hostvars[selected_node]['api_password'] | + d(hostvars[selected_node]['host_password'] | d(hostvars[selected_node]['ansible_password'])) }}" pm_lxc_storage: "{{ hostvars[selected_node]['lxc_storage'] | d('local-zfs') }}" no_log: yes @@ -12,7 +13,7 @@ msg: some container parameters are missing or invalid when: (container_distro is not defined) or (container_template is not mapping) or (container_template[container_distro] is not defined) or - (container_id is not defined) or (container_password is not defined) + (container_id is not defined) - name: ensure pool exists on cluster node @@ -26,9 +27,12 @@ - block: - - name: ensure pip3 is installed on local node + - name: ensure python dependencies are installed on local node package: - name: py3-pip + name: + - py3-pip + - py3-requests + - py3-netaddr run_once: yes @@ -55,6 +59,21 @@ timeout: 20 + - name: build container network section + set_fact: + container_network_cfg: "{{ { + 'name': 'eth0', + 'hwaddr': container_mac | d(mac_prefix | community.general.random_mac(seed=inventory_hostname)), + 'ip': ansible_host ~ '/' ~ networks[container_network].gw | ansible.utils.ipaddr('prefix'), + 'gw': networks[container_network].gw | ansible.utils.ipaddr('address'), + 'bridge': container_bridge | d('vmbr0'), + 'firewall': 0, + 'tag': networks[container_network].tag | d(None), + 'type': 'veth', + 'mtu': container_mtu | d(hostvars[selected_node]['container_mtu'] | d(1500)) + } | dict2items | rejectattr('value', 'equalto', None) | list | items2dict }}" + + - name: create container if not exists community.general.proxmox: node: "{{ selected_node }}" @@ -62,31 +81,31 @@ api_user: "{{ pm_api_user }}" api_password: "{{ pm_api_password }}" - cores: "{{ hardware.cores }}" - cpus: "{{ hardware.cpus }}" - cpuunits: "{{ hardware.cpuunits }}" - disk: "{{ hardware.disk | string }}" - memory: "{{ hardware.memory }}" - swap: "{{ hardware.swap }}" + cores: "{{ host_hardware.cores }}" + cpus: "{{ host_hardware.cpus }}" + cpuunits: "{{ host_hardware.cpuunits }}" + disk: "{{ host_hardware.disk | string }}" + memory: "{{ host_hardware.memory }}" + swap: "{{ host_hardware.swap }}" description: "{{ container_description | d(omit) }}" - hostname: "{{ inventory_hostname }}" + hostname: "{{ host_name }}" pool: "{{ container_pool | d(omit) }}" vmid: "{{ container_id }}" - password: "{{ container_password }}" - pubkey: "{{ (container_key | d({})).public_key | d(omit) }}" + password: "{{ host_password }}" + pubkey: "{{ (host_ssh_key | d({})).public_key | d(omit) }}" ostemplate: "local:vztmpl/{{ container_template[container_distro] }}" - netif: "{\"net0\":\ - \"name=eth0,hwaddr={{ container_mac | d(mac_prefix | community.general.random_mac(seed=inventory_hostname)) }},\ - ip={{ ansible_host }}/{{ networks[container_network].gw | ansible.utils.ipaddr('prefix') }},\ - gw={{ networks[container_network].gw | ansible.utils.ipaddr('address') }},\ - bridge=vmbr0,\ - firewall=0,\ - tag={{ networks[container_network].tag }},\ - type=veth,\ - mtu={{ container_mtu | d(hostvars[selected_node]['container_mtu'] | d(1500)) }}\"}" + onboot: yes + proxmox_default_behavior: no_defaults + storage: "{{ pm_lxc_storage }}" + unprivileged: yes + timeout: 240 + + netif: "{{ { 'net0': container_network_cfg.keys() | zip(container_network_cfg.values()) | + map('join', '=') | join(',') } | to_json(sort_keys=true) }}" + nameserver: "{%- if container_nameserver is defined -%}\ {{ hostvars[container_nameserver]['ansible_host'] }}\ {%- elif services.filtering_ns is defined -%}\ @@ -95,16 +114,11 @@ {%- else -%} {{ hostvars[services.filtering_ns.hostname]['ansible_host'] }}\ {%- endif -%} - {%- elif container_default_nameserver is defined -%}\ - {{ container_default_nameserver }}\ + {%- elif nameserver is defined -%}\ + {{ nameserver }}\ {%- else -%}\ {{ omit }}\ {%- endif -%}" - onboot: yes - proxmox_default_behavior: no_defaults - storage: "{{ pm_lxc_storage }}" - unprivileged: yes - timeout: 240 mounts: >- { {%- for item in (container_mounts | d([])) -%} @@ -115,39 +129,39 @@ - block: - name: add features to lxc config lineinfile: - path: "/etc/pve/lxc/{{ container_id }}.conf" + path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}" line: "features: {{ container_features | join(',') }}" when: container_features | d([]) | length > 0 - name: check that lxc config is correct lineinfile: - path: "/etc/pve/lxc/{{ container_id }}.conf" + path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}" regexp: "^{{ item.name }}:(\\s*).*$" line: "{{ item.name | mandatory }}:\\g<1>{{ item.value | mandatory }}" backrefs: yes loop: - - { name: cpus, value: "{{ hardware.cpus }}" } - - { name: cores, value: "{{ [hardware.cores, hostvars[selected_node]['max_cores'] | d(hardware.cores)] | min }}" } - - { name: cpuunits, value: "{{ hardware.cpuunits }}" } - - { name: memory, value: "{{ hardware.memory }}" } - - { name: swap, value: "{{ hardware.swap }}" } + - { name: cpus, value: "{{ host_hardware.cpus }}" } + - { name: cores, value: "{{ [host_hardware.cores, hostvars[selected_node]['max_cores'] | d(host_hardware.cores)] | min }}" } + - { name: cpuunits, value: "{{ host_hardware.cpuunits }}" } + - { name: memory, value: "{{ host_hardware.memory }}" } + - { name: swap, value: "{{ host_hardware.swap }}" } - { name: onboot, value: "{{ '1' if (container_active | d(true) == true) else '0' }}" } - name: set startup order and delay lineinfile: - path: "/etc/pve/lxc/{{ container_id }}.conf" + path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}" regexp: '^startup:.*$' - line: "startup: {{ 'order=' ~ (container_order | d(role_dependency[host_primary_role] | d('0'))) ~ ((',up=' ~ container_startup_delay) if container_startup_delay is defined else '') }}" + line: "startup: {{ 'order=' ~ (container_order | d(role_dependency_index | d('0'))) ~ ((',up=' ~ container_startup_delay) if container_startup_delay is defined else '') }}" insertbefore: '^[^\#]' firstmatch: yes - when: (container_order is defined) or (role_dependency[host_primary_role] is defined) or (container_startup_delay is defined) + when: (container_order is defined) or (role_dependency_index is defined) or (container_startup_delay is defined) - name: ensure that cpulimit is not set lineinfile: - path: "/etc/pve/lxc/{{ container_id }}.conf" + path: "{{ ('/etc/pve/lxc', container_id ~ '.conf') | path_join }}" regexp: '^cpulimit:.*$' state: absent @@ -163,6 +177,7 @@ vmid: "{{ container_id }}" proxmox_default_behavior: no_defaults state: "{{ 'started' if (container_active | d(true) == true) else 'stopped' }}" + unprivileged: yes - name: end playbook for current host if container is set to inactive @@ -179,7 +194,7 @@ delay: 2 changed_when: no - delegate_to: 127.0.0.1 + delegate_to: localhost - name: preconfigure container diff --git a/roles/coredns/defaults/main.yml b/roles/coredns/defaults/main.yml index 8abb56c..d55656a 100644 --- a/roles/coredns/defaults/main.yml +++ b/roles/coredns/defaults/main.yml @@ -2,8 +2,8 @@ coredns_user: coredns coredns_group: coredns coredns_conf_dir: /etc/coredns -coredns_conf_file: "{{ coredns_conf_dir }}/coredns.conf" -coredns_tls_file: "{{ coredns_conf_dir }}/tls.conf" +coredns_conf_file: "{{ (coredns_conf_dir, 'coredns.conf') | path_join }}" +coredns_tls_file: "{{ (coredns_conf_dir, 'tls.conf') | path_join }}" -coredns_cert_file: "{{ coredns_conf_dir }}/ecc384.crt" -coredns_key_file: "{{ coredns_conf_dir }}/ecc384.key" +coredns_cert_file: "{{ (coredns_conf_dir, 'ecc384.crt') | path_join }}" +coredns_key_file: "{{ (coredns_conf_dir, 'ecc384.key') | path_join }}" diff --git a/roles/coredns/tasks/add.yml b/roles/coredns/tasks/add.yml new file mode 100644 index 0000000..331a4a5 --- /dev/null +++ b/roles/coredns/tasks/add.yml @@ -0,0 +1,27 @@ +- name: add default record + include_tasks: + file: add_record.yml + apply: + delegate_to: "{{ services.internal_ns }}" + vars: + record: {} + when: (records | d([]) | length) == 0 + + +- name: process other items + include_tasks: + file: add_record.yml + apply: + delegate_to: "{{ services.internal_ns }}" + loop: "{{ records | d([]) }}" + loop_control: + loop_var: record + + +- name: restart coredns + service: + name: coredns + state: restarted + delegate_to: "{{ services.internal_ns }}" + when: (ns_instant | d(false) == false) and + ((ns_records_changed | d(false) == true) or (ns_serial_changed | d(false) == true)) diff --git a/roles/coredns/tasks/add_record.yml b/roles/coredns/tasks/add_record.yml index ac97008..95f72af 100644 --- a/roles/coredns/tasks/add_record.yml +++ b/roles/coredns/tasks/add_record.yml @@ -10,21 +10,13 @@ when: record.zone is defined and record.zone is not string -- name: check if record zone exists - fail: - msg: '"{{ record.zone }}" does not seem to be a valid zone' - when: (record.zone is defined) and - (record.zone != 'root') and - ((int_zones is not defined) or (record.zone not in int_zones)) - - - name: construct record parameters set_fact: ns_zone: "{%- if (record.zone is defined) and (record.zone != 'root') -%}{{ record.zone }}\ {%- else -%}{{ ns_tld | d(int_tld) }}\ {%- endif -%}" ns_name: "{%- if record.name is defined -%}{{ record.name }}\ - {%- else -%}{{ inventory_hostname }}\ + {%- else -%}{{ host_name }}\ {%- endif -%}" ns_type: "{%- if record.type is defined -%}{{ record.type | upper }}\ {%- else -%}A\ @@ -33,6 +25,7 @@ {%- else -%}{{ ansible_host }}\ {%- endif -%}" + - name: set ns_quote set_fact: ns_quote: "{{ '\"' if ns_type == 'TXT' else '' }}" @@ -60,9 +53,9 @@ - name: slurp zone file slurp: - src: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" + src: "{{ (coredns_conf_dir, ns_zone ~ '.zone') | path_join }}" register: zf - changed_when: false + changed_when: no - name: enumerate stdout lines to check if an entry already exists @@ -84,7 +77,7 @@ - name: replace the record lineinfile: - path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" + path: "{{ (coredns_conf_dir, ns_zone ~ '.zone') | path_join }}" regexp: '^\s*{{ ns_name | regex_escape() }}\s+IN\s+{{ ns_type | regex_escape() }}\s+' line: "{{ ns_name }}\tIN\t{{ ns_type }}\t{{ ns_quote ~ ns_value ~ ns_quote }}" backrefs: yes @@ -96,7 +89,7 @@ - name: add the record if it is missing lineinfile: - path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" + path: "{{ (coredns_conf_dir, ns_zone ~ '.zone') | path_join }}" line: "{{ ns_name }}\tIN\t{{ ns_type }}\t{{ ns_quote ~ ns_value ~ ns_quote }}" when: not ns_exists register: rr2 @@ -109,6 +102,8 @@ - name: change serial include_tasks: increase_serial.yml + vars: + zone: "{{ ns_zone }}" when: ns_records_changed | d(false) == true diff --git a/roles/coredns/tasks/add_records.yml b/roles/coredns/tasks/add_records.yml deleted file mode 100644 index 8ce5647..0000000 --- a/roles/coredns/tasks/add_records.yml +++ /dev/null @@ -1,21 +0,0 @@ -- name: add default record - include_tasks: add_record.yml - vars: - record: {} - when: (ns_records | d([]) | length) == 0 - - -- name: process other items - include_tasks: add_record.yml - loop: "{{ ns_records | d([]) }}" - loop_control: - loop_var: record - - -- name: restart coredns - service: - name: coredns - state: restarted - when: (ns_instant | d(false) == false) and - ((ns_records_changed | d(false) == true) or - (ns_serial_changed | d(false) == true)) diff --git a/roles/coredns/tasks/increase_serial.yml b/roles/coredns/tasks/increase_serial.yml index eed3714..b42b3b2 100644 --- a/roles/coredns/tasks/increase_serial.yml +++ b/roles/coredns/tasks/increase_serial.yml @@ -1,13 +1,19 @@ +- name: fail if zone is not defined + fail: + msg: zone is not defined + when: zone is not defined + + - name: slurp zone file slurp: - src: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" + src: "{{ (coredns_conf_dir, zone ~ '.zone') | path_join }}" register: zf - changed_when: false + changed_when: no - name: get SOA serial value set_fact: - ns_old_serial: '{{ zf.content | b64decode | regex_search(''@\s+IN\s+SOA\s+\S+\s+\S+\s*\(\s*(\d+)'', ''\1'') | first }}' + ns_old_serial: '{{ zf.content | b64decode | regex_search(''@\s+IN\s+SOA\s+\S+\s+\S+\s*\(\s*(\d+)'', ''\1'') | first | string }}' - name: get current date @@ -36,7 +42,7 @@ - name: insert new serial replace: - path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" + path: "{{ (coredns_conf_dir, zone ~ '.zone') | path_join }}" regexp: '(@\s+IN\s+SOA\s+\S+\s+\S+\s*\(\s*){{ ns_old_serial }}' replace: '\g<1>{{ ns_new_serial }}' register: result diff --git a/roles/coredns/tasks/info.yml b/roles/coredns/tasks/info.yml new file mode 100644 index 0000000..6633b95 --- /dev/null +++ b/roles/coredns/tasks/info.yml @@ -0,0 +1,13 @@ +- name: set role information + set_fact: + role_dependency: + - {stage: 3, role: 'coredns'} + - {stage: 5, role: 'coredns', tasks_from: 'tls.yml'} + + role_dependency_index: 0 + + role_hardware: + cores: 4 + memory: 128 + swap: 64 + disk: 0.3 diff --git a/roles/coredns/tasks/install.yml b/roles/coredns/tasks/install.yml deleted file mode 100644 index 95049ef..0000000 --- a/roles/coredns/tasks/install.yml +++ /dev/null @@ -1,93 +0,0 @@ -- name: install coredns and dependencies - include_tasks: tasks/install_packages.yml - vars: - package: - - coredns - - alpine: coredns-openrc - - -- name: create user and group - include_tasks: tasks/create_user.yml - vars: - user: - name: "{{ coredns_user }}" - group: "{{ coredns_group }}" - - -- name: create config directory - file: - path: "{{ coredns_conf_dir }}" - state: directory - owner: "{{ coredns_user }}" - group: "{{ coredns_group }}" - notify: restart coredns - - -- name: template corefile - template: - src: corefile.j2 - dest: "{{ coredns_conf_file }}" - force: yes - owner: "{{ coredns_user }}" - group: "{{ coredns_group }}" - mode: 0400 - notify: restart coredns - - -- name: template empty tls file if missing - copy: - content: '' - dest: "{{ coredns_tls_file }}" - force: no - owner: "{{ coredns_user }}" - group: "{{ coredns_group }}" - mode: 0400 - notify: restart coredns - - -- name: template root zone if missing - template: - src: zone.j2 - dest: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" - force: no - mode: 0400 - owner: "{{ coredns_user }}" - group: "{{ coredns_group }}" - notify: restart coredns - - -- name: edit service config - lineinfile: - path: /etc/conf.d/coredns - regexp: "^COREDNS_CONFIG=" - line: "COREDNS_CONFIG={{ coredns_conf_file | quote }}" - notify: restart coredns - - -- name: template init script - template: - src: init.j2 - dest: /etc/init.d/coredns - force: yes - mode: 0755 - notify: restart coredns - - -- name: flush handlers - meta: flush_handlers - - -- name: add directories to backup plan - include_role: - name: backup - vars: - function: add - backup_items: - - "{{ coredns_conf_dir }}" - - -- name: enable and start coredns - service: - name: coredns - enabled: yes - state: started diff --git a/roles/coredns/tasks/install_tls.yml b/roles/coredns/tasks/install_tls.yml deleted file mode 100644 index d58b1bc..0000000 --- a/roles/coredns/tasks/install_tls.yml +++ /dev/null @@ -1,28 +0,0 @@ -- name: deploy ecc384 cert - include_role: - name: ca - vars: - function: certs - ca_options: - mode: '0400' - owner: "{{ coredns_user }}" - group: "{{ coredns_group }}" - concat_inter: true - preset: web - ocsp_must_staple: false - notify: restart coredns - ca_certs: - - type: ecc384 - key: "{{ coredns_key_file }}" - cert: "{{ coredns_cert_file }}" - - -- name: template tls snippet file - template: - src: tls.j2 - dest: "{{ coredns_tls_file }}" - force: yes - owner: "{{ coredns_user }}" - group: "{{ coredns_group }}" - mode: 0400 - notify: restart coredns diff --git a/roles/coredns/tasks/main.yml b/roles/coredns/tasks/main.yml index 78a7e89..068460d 100644 --- a/roles/coredns/tasks/main.yml +++ b/roles/coredns/tasks/main.yml @@ -1,13 +1,102 @@ -- name: install coredns - include_tasks: install.yml - when: function == 'install' +- name: build default tld list + set_fact: + coredns_tld_list: "{{ [ ns_tld | d(int_tld) ] }}" + when: coredns_tld_list is not defined -- name: install coredns tls enhancements - include_tasks: install_tls.yml - when: function == 'install_tls' +- name: install coredns and dependencies + include_tasks: tasks/install_packages.yml + vars: + package: + - coredns + - alpine: coredns-openrc -- name: add records - include_tasks: add_records.yml - when: function == 'add_records' +- name: create user and group + include_tasks: tasks/create_user.yml + vars: + user: + name: "{{ coredns_user }}" + group: "{{ coredns_group }}" + + +- name: create config directory + file: + path: "{{ coredns_conf_dir }}" + state: directory + owner: "{{ coredns_user }}" + group: "{{ coredns_group }}" + notify: restart coredns + + +- name: template corefile + template: + src: corefile.j2 + dest: "{{ coredns_conf_file }}" + force: yes + owner: "{{ coredns_user }}" + group: "{{ coredns_group }}" + mode: 0400 + notify: restart coredns + + +- name: template empty tls file if missing + copy: + content: '' + dest: "{{ coredns_tls_file }}" + force: no + owner: "{{ coredns_user }}" + group: "{{ coredns_group }}" + mode: 0400 + notify: restart coredns + + +- name: template all zones if missing + template: + src: zone.j2 + dest: "{{ (coredns_conf_dir, zone ~ '.zone') | path_join }}" + force: no + mode: 0400 + owner: "{{ coredns_user }}" + group: "{{ coredns_group }}" + notify: restart coredns + loop: "{{ coredns_tld_list }}" + loop_control: + loop_var: zone + + +- name: edit service config + lineinfile: + path: /etc/conf.d/coredns + regexp: "^COREDNS_CONFIG=" + line: "COREDNS_CONFIG={{ coredns_conf_file | quote }}" + notify: restart coredns + + +- name: template init script + template: + src: init.j2 + dest: /etc/init.d/coredns + force: yes + mode: 0755 + notify: restart coredns + + +- name: flush handlers + meta: flush_handlers + + +- name: add directories to backup plan + include_role: + name: backup + tasks_from: add.yml + vars: + backup_items: + - "{{ coredns_conf_dir }}" + + +- name: enable and start coredns + service: + name: coredns + enabled: yes + state: started diff --git a/roles/coredns/tasks/tls.yml b/roles/coredns/tasks/tls.yml new file mode 100644 index 0000000..14e717c --- /dev/null +++ b/roles/coredns/tasks/tls.yml @@ -0,0 +1,25 @@ +- block: + - name: deploy ecc384 cert + include_role: + name: certs + vars: + certs: + cert: "{{ coredns_cert_file }}" + key: "{{ coredns_key_file }}" + ecc: yes + post_hook: service coredns restart + owner: "{{ coredns_user }}" + group: "{{ coredns_group }}" + + + - name: template tls snippet file + template: + src: tls.j2 + dest: "{{ coredns_tls_file }}" + force: yes + owner: "{{ coredns_user }}" + group: "{{ coredns_group }}" + mode: 0400 + notify: restart coredns + + when: host_tls \ No newline at end of file diff --git a/roles/coredns/templates/corefile.j2 b/roles/coredns/templates/corefile.j2 index 0289681..e34d95f 100644 --- a/roles/coredns/templates/corefile.j2 +++ b/roles/coredns/templates/corefile.j2 @@ -1,6 +1,5 @@ (common) { root {{ (coredns_conf_dir ~ '/') | quote }} - file {{ ((ns_tld | d(int_tld)) ~ '.zone') | quote }} any bufsize {{ ns_edns0_bufsize | d(1232) }} @@ -8,8 +7,11 @@ loadbalance } -{{ ns_tld | d(int_tld) }} { - import common -} +{% for zone in coredns_tld_list %} + {{ zone }} { + import common + file {{ (zone ~ '.zone') | quote }} + } +{% endfor %} import {{ coredns_tls_file | quote }} diff --git a/roles/coredns/templates/init.j2 b/roles/coredns/templates/init.j2 index 8e792a1..c1a2591 100644 --- a/roles/coredns/templates/init.j2 +++ b/roles/coredns/templates/init.j2 @@ -4,7 +4,7 @@ name="$SVCNAME" directory="{{ coredns_conf_dir }}" command="/usr/bin/coredns" command_args="-conf ${COREDNS_CONFIG} ${COREDNS_EXTRA_ARGS}" -command_user="{{ coredns_user }}:{{ coredns_group }}" +command_user="{{ coredns_user ~ ':' ~ coredns_group }}" pidfile="/var/run/$SVCNAME.pid" command_background=true start_stop_daemon_args="--stdout-logger logger --stderr-logger logger" diff --git a/roles/coredns/templates/tls.j2 b/roles/coredns/templates/tls.j2 index 5639d8a..44080d9 100644 --- a/roles/coredns/templates/tls.j2 +++ b/roles/coredns/templates/tls.j2 @@ -1,9 +1,13 @@ -tls://{{ ns_tld | d(int_tld) }}:853 { - import common - tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }} -} +{% for zone in coredns_tld_list %} + tls://{{ zone }}:853 { + import common + file {{ (zone ~ '.zone') | quote }} + tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }} + } -https://{{ ns_tld | d(int_tld) }} { - import common - tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }} -} + https://{{ zone }} { + import common + file {{ (zone ~ '.zone') | quote }} + tls {{ coredns_cert_file | quote }} {{ coredns_key_file | quote }} + } +{% endfor %} \ No newline at end of file diff --git a/roles/coredns/templates/zone.j2 b/roles/coredns/templates/zone.j2 index 827785c..10d8cb5 100644 --- a/roles/coredns/templates/zone.j2 +++ b/roles/coredns/templates/zone.j2 @@ -1,32 +1,13 @@ -{%- set primary_ns = inventory_hostname -%} - -{%- if ns_server_group is defined -%} - {%- set primary_ns = hostvars[groups[ns_server_group][0]]['inventory_hostname'] -%} -{%- endif -%} - -{%- set this_name = (ns_name | d(inventory_hostname)) -%} -{%- set this_primary_name = (hostvars[primary_ns]['ns_name'] | d(hostvars[primary_ns]['inventory_hostname'])) -%} -{%- set this_tld = (hostvars[primary_ns]['ns_tld'] | d(ns_tld) | d(int_tld)) -%} - - - -$ORIGIN {{ this_tld }}. +$ORIGIN {{ zone }}. $TTL {{ ns_ttl | d(300) }} -@ IN SOA {{ this_name ~ '.' ~ this_tld }}. {{ (ns_admin | replace('@', '.')) if ns_admin is defined else ('admin' ~ '.' ~ this_tld) }}. ( - 2021010101 +@ IN SOA {{ host_name ~ '.' ~ zone }}. {{ (ns_admin | replace('@', '.')) if ns_admin is defined else ('admin' ~ '.' ~ zone) }}. ( + 2023010101 {{ ns_refresh | d(1200) }} {{ ns_retry | d(300) }} {{ ns_expire | d(1209600) }} {{ ns_neg_ttl | d(300) }} ) -{% if ns_server_group is defined -%} - {% for host in groups[ns_server_group] -%} -@ IN NS {{ (hostvars[host]['ns_name'] | d(hostvars[host]['inventory_hostname'])) ~ '.' ~ this_tld }}. -{{ hostvars[host]['ns_name'] | d(hostvars[host]['inventory_hostname']) }} IN A {{ hostvars[host]['ansible_host'] }} - {% endfor -%} -{% else -%} -@ IN NS {{ this_primary_name ~ '.' ~ this_tld }}. -{{ this_primary_name }} IN A {{ ansible_host }} -{% endif -%} +@ IN NS {{ host_name ~ '.' ~ zone }}. +{{ host_name }} IN A {{ ansible_host }} diff --git a/roles/ns-only/tasks/info.yml b/roles/ns-only/tasks/info.yml new file mode 100644 index 0000000..aa07ad4 --- /dev/null +++ b/roles/ns-only/tasks/info.yml @@ -0,0 +1,7 @@ +- name: set role information + set_fact: + role_dependency: + - { stage: 3, role: 'ns' } + + role_dependency_index: 1 + role_dependency_no_common: yes diff --git a/roles/ns-only/tasks/main.yml b/roles/ns-only/tasks/main.yml new file mode 100644 index 0000000..8c63709 --- /dev/null +++ b/roles/ns-only/tasks/main.yml @@ -0,0 +1,3 @@ +- name: add internal ns records + include_role: + name: ns diff --git a/roles/ns/tasks/main.yml b/roles/ns/tasks/main.yml index 2652ab3..b84cd4d 100644 --- a/roles/ns/tasks/main.yml +++ b/roles/ns/tasks/main.yml @@ -1,16 +1,12 @@ -- name: ns installation - include_tasks: install.yml - when: function == 'install' - - -- block: - - name: add records - include_tasks: add_records.yml - when: services.internal_ns is defined - - - - debug: - msg: internal nameserver is not defined - when: services.internal_ns is not defined - - when: function == 'add_records' \ No newline at end of file +- name: add internal ns records with coredns + block: + - set_fact: + records_tmp: "{{ records | d([]) }}" + + - include_role: + name: coredns + tasks_from: add.yml + vars: + records: "{{ records_tmp }}" + + when: services.internal_ns is defined diff --git a/roles/proxmox/tasks/info.yml b/roles/proxmox/tasks/info.yml new file mode 100644 index 0000000..169c8bf --- /dev/null +++ b/roles/proxmox/tasks/info.yml @@ -0,0 +1,9 @@ +- name: set role information + set_fact: + role_dependency: + - {stage: 1, role: 'common'} + - {stage: 1, role: 'proxmox'} + - {stage: 5, role: 'proxmox', tasks_from: 'rproxy'} + - {stage: 6, role: 'proxmox', tasks_from: 'mail'} + + role_dependency_index: 0 diff --git a/roles/proxmox/tasks/mail.yml b/roles/proxmox/tasks/mail.yml index f14a200..db8e6f8 100644 --- a/roles/proxmox/tasks/mail.yml +++ b/roles/proxmox/tasks/mail.yml @@ -1,72 +1,75 @@ -- name: install libsasl2-modules - package: - name: libsasl2-modules +- block: + - name: install libsasl2-modules + package: + name: libsasl2-modules -- name: edit postfix config - lineinfile: - path: /etc/postfix/main.cf - regexp: '^{{ item.name | regex_escape() }}([^\S\r\n]*)=([^\S\r\n]*)' - line: '{{ item.name }} = {{ item.value }}' - notify: restart postfix - loop: - - { name: myhostname, value: "{{ host_fqdn }}" } - - { name: relayhost, value: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld }}:465" } - - { name: sender_canonical_classes, value: "envelope_sender, header_sender" } - - { name: sender_canonical_maps, value: "regexp:/etc/postfix/sender_canonical_maps" } - - { name: smtp_header_checks, value: "regexp:/etc/postfix/header_check" } - - { name: smtp_use_tls, value: "yes" } - - { name: smtp_sasl_auth_enable, value: "yes" } - - { name: smtp_sasl_security_options, value: "noanonymous" } - - { name: smtp_tls_wrappermode, value: "yes" } - - { name: smtp_tls_security_level, value: "encrypt" } - - { name: smtp_sasl_password_maps, value: "texthash:/etc/postfix/sasl_passwd" } - - { name: smtp_tls_CAfile, value: "/etc/ssl/certs/ca-certificates.crt" } - - { name: notify_classes, value: "" } - - { name: mydestination, value: "" } + - name: edit postfix config + lineinfile: + path: /etc/postfix/main.cf + regexp: '^{{ item.name | regex_escape() }}([^\S\r\n]*)=([^\S\r\n]*)' + line: '{{ item.name }} = {{ item.value }}' + notify: restart postfix + loop: + - { name: myhostname, value: "{{ host_fqdn }}" } + - { name: relayhost, value: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld }}:465" } + - { name: sender_canonical_classes, value: "envelope_sender, header_sender" } + - { name: sender_canonical_maps, value: "regexp:/etc/postfix/sender_canonical_maps" } + - { name: smtp_header_checks, value: "regexp:/etc/postfix/header_check" } + - { name: smtp_use_tls, value: "yes" } + - { name: smtp_sasl_auth_enable, value: "yes" } + - { name: smtp_sasl_security_options, value: "noanonymous" } + - { name: smtp_tls_wrappermode, value: "yes" } + - { name: smtp_tls_security_level, value: "encrypt" } + - { name: smtp_sasl_password_maps, value: "texthash:/etc/postfix/sasl_passwd" } + - { name: smtp_tls_CAfile, value: "/etc/ssl/certs/ca-certificates.crt" } + - { name: notify_classes, value: "" } + - { name: mydestination, value: "" } -- name: edit master.cf - lineinfile: - path: /etc/postfix/master.cf - regexp: '^bounce([^\S\r\n]+)unix' - line: 'bounce unix - - n - 0 discard' - notify: restart postfix + - name: edit master.cf + lineinfile: + path: /etc/postfix/master.cf + regexp: '^bounce([^\S\r\n]+)unix' + line: 'bounce unix - - n - 0 discard' + notify: restart postfix -- name: create postfix files - copy: - dest: "/etc/postfix/{{ item.name }}" - content: "{{ item.content }}" - mode: "{{ item.mode | d(omit) }}" - notify: restart postfix - loop: - - name: sasl_passwd - content: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld ~ ':465 ' ~ - mail_account.username ~ '@' ~ mail_server.tld ~ ':' ~ mail_account.password }}" - mode: '0600' - - name: sender_canonical_maps - content: '/.+/ {{ host_name }}@{{ mail_server.tld }}' - - name: header_check - content: '/From:.*/ REPLACE From: {{ host_name }} <{{ host_name }}@{{ mail_server.tld }}>' + - name: create postfix files + copy: + dest: "/etc/postfix/{{ item.name }}" + content: "{{ item.content }}" + mode: "{{ item.mode | d(omit) }}" + notify: restart postfix + loop: + - name: sasl_passwd + content: "{{ mail_server.mta_actual_hostname ~ '.' ~ int_tld ~ ':465 ' ~ + mail_account.username ~ '@' ~ mail_server.tld ~ ':' ~ mail_account.password }}" + mode: '0600' + - name: sender_canonical_maps + content: '/.+/ {{ host_name }}@{{ mail_server.tld }}' + - name: header_check + content: '/From:.*/ REPLACE From: {{ host_name }} <{{ host_name }}@{{ mail_server.tld }}>' -- name: edit crontab mail config - lineinfile: - path: /etc/crontab - regexp: '^MAILTO=' - line: 'MAILTO=""' - insertafter: '^PATH=' + - name: edit crontab mail config + lineinfile: + path: /etc/crontab + regexp: '^MAILTO=' + line: 'MAILTO=""' + insertafter: '^PATH=' -- name: edit zed config file - lineinfile: - path: /etc/zfs/zed.d/zed.rc - regexp: '^{{ item.name | upper | regex_escape() }}=' - line: '{{ item.name | upper }}="{{ item.value }}"' - notify: restart zed - loop: - - { name: zed_email_addr, value: "{{ maintainer_email }}" } - - { name: zed_email_prog, value: mail } - - { name: zed_email_opts, value: "-s '@SUBJECT@' @ADDRESS@ -r {{ mail_account.username ~ '@' ~ mail_server.tld }}" } - - { name: zed_notify_verbose, value: 1 } + - name: edit zed config file + lineinfile: + path: /etc/zfs/zed.d/zed.rc + regexp: '^{{ item.name | upper | regex_escape() }}=' + line: '{{ item.name | upper }}="{{ item.value }}"' + notify: restart zed + loop: + - { name: zed_email_addr, value: "{{ maintainer_email }}" } + - { name: zed_email_prog, value: mail } + - { name: zed_email_opts, value: "-s '@SUBJECT@' @ADDRESS@ -r {{ mail_account.username ~ '@' ~ mail_server.tld }}" } + - { name: zed_notify_verbose, value: 1 } + + when: (mail_account is mapping) and (mail_server is mapping) diff --git a/roles/proxmox/tasks/main.yml b/roles/proxmox/tasks/main.yml index 86c4d91..7eee284 100644 --- a/roles/proxmox/tasks/main.yml +++ b/roles/proxmox/tasks/main.yml @@ -3,16 +3,83 @@ proxmox_cfg: "{{ proxmox_default_config | d({}) | combine(proxmox_config | d({}), recursive=true) }}" -- name: proxmox installation - include_tasks: install.yml - when: function == 'install' +- name: install extra proxmox packages + package: + name: "{{ item }}" + loop: "{{ proxmox_default_packages + (proxmox_packages | d([])) }}" -- name: proxmox reverse proxy configuration - include_tasks: rproxy.yml - when: function == 'rproxy' +- block: + - name: set cpu scheduler in cron + cron: + name: set cpu scheduler + special_time: reboot + job: 'echo {{ proxmox_cfg.cpu_governor | quote }} | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null' + user: root -- name: proxmox mail configuration - include_tasks: mail.yml - when: (function == 'mail') and (mail_account is mapping) and (mail_server is mapping) + - block: + - name: get current cpu scheduler types + shell: + cmd: cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor + register: result + changed_when: no + + + - name: change cpu scheduler + shell: + cmd: 'echo {{ proxmox_cfg.cpu_governor | quote }} | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor' + when: (result.stdout_lines | unique | length > 1) or ((result.stdout_lines | unique)[0] != proxmox_cfg.cpu_governor) + + rescue: + - name: report that cpu scheduler cannot be changed + debug: + msg: failed to change cpu scheduler + + when: proxmox_cfg.cpu_governor is string + + +- name: disable enterprise repo + apt_repository: + repo: deb https://enterprise.proxmox.com/debian/pve bullseye pve-enterprise + filename: pve-enterprise.list + state: absent + update_cache: no + + +- name: enable community repo + apt_repository: + repo: deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription + filename: pve-community.list + state: present + update_cache: no + + +- name: set datacenter configuration + lineinfile: + path: /etc/pve/datacenter.cfg + regexp: "^{{ item.key }}: " + line: "{{ item.key }}: {{ item.value }}" + mode: 0640 + owner: root + group: www-data + create: yes + loop: "{{ proxmox_cfg.datacenter | dict2items }}" + + +- name: enable auto-reboot on kernel panic + copy: + dest: /etc/sysctl.d/90-auto-reboot.conf + content: "kernel.panic = 5\n" + mode: 0644 + when: proxmox_cfg.auto_reboot | d(true) == true + + +- name: set max arc cache size for zfs + lineinfile: + path: /etc/modprobe.d/zfs.conf + regexp: "^options zfs zfs_arc_max=" + line: "options zfs zfs_arc_max={{ proxmox_cfg.zfs_arc_max }}" + create: yes + mode: 0644 + when: proxmox_cfg.zfs_arc_max is defined diff --git a/roles/proxmox/tasks/rproxy.yml b/roles/proxmox/tasks/rproxy.yml index 9f33840..e962f0b 100644 --- a/roles/proxmox/tasks/rproxy.yml +++ b/roles/proxmox/tasks/rproxy.yml @@ -9,4 +9,3 @@ conf: http: ssl_conf_command: [] - diff --git a/tasks/gen_ssh_key.yml b/tasks/gen_ssh_key.yml index fbb26fc..9cd5861 100644 --- a/tasks/gen_ssh_key.yml +++ b/tasks/gen_ssh_key.yml @@ -13,12 +13,12 @@ mode: 0400 regenerate: full_idempotence type: ed25519 - register: container_key + register: host_ssh_key - name: fail if public key is missing fail: msg: public key is missing - when: container_key.public_key is not defined + when: host_ssh_key.public_key is not defined delegate_to: localhost \ No newline at end of file diff --git a/tasks/includes/stage.yml b/tasks/includes/stage.yml index a16f359..ee6ab65 100644 --- a/tasks/includes/stage.yml +++ b/tasks/includes/stage.yml @@ -11,6 +11,6 @@ - name: include roles for selected stage include_tasks: tasks/includes/role.yml - loop: "{{ role_mapping | selectattr('stage', 'equalto', (this_stage | int)) | list }}" + loop: "{{ role_deps | selectattr('stage', 'equalto', (this_stage | int)) | list }}" loop_control: loop_var: this_role diff --git a/tasks/pre_tasks.yml b/tasks/pre_tasks.yml index e60c7b7..2eab15e 100644 --- a/tasks/pre_tasks.yml +++ b/tasks/pre_tasks.yml @@ -1,15 +1,31 @@ -- name: determine host info +- name: set host name set_fact: - host_name: "{{ actual_hostname | d(inventory_hostname) }}" - host_tld: "{%- if branch is defined -%}{{ branch }}.{%- endif -%}{{ tld if (use_external_tld | d(false) == true) else int_tld }}" - host_tls: "{{ use_tls | d(true) }}" - host_protocol: "{{ 'https' if (use_tls | d(true)) else 'http' }}" - host_metrics: "{{ services.prometheus is defined and (use_metrics | d(true) == true) }}" - host_mail: "{{ mail_server.mta_hostname is defined and (use_mail | d(true) == true) }}" - host_backups: "{{ services.backup is defined and (use_backups | d(true) == true) }}" + host_name: "{{ inventory_hostname }}" + when: host_name is not defined -- name: determine host fqdn and uri +- name: set host tld + set_fact: + host_tld: "{{ ((host_branch ~ '.') if host_branch is defined else '') ~ (tld if (host_external_tld | d(false) == true) else int_tld) }}" + when: host_tld is not defined + + +- name: set host tls + set_fact: + host_tls: yes + when: host_tls is not defined + + +- name: set other host variables + set_fact: + host_protocol: "{{ 'https' if host_tls else 'http' }}" + host_metrics: "{{ services.prometheus is defined and (host_metrics | d(true) == true) }}" + host_mail: "{{ mail_server.mta_hostname is defined and (host_mail | d(true) == true) }}" + host_backups: "{{ services.backup is defined and (host_backups | d(true) == true) }}" + host_is_container: "{{ ('containers' in group_names) or (host_is_container | d(false) == true) }}" + + +- name: set host fqdn and uri set_fact: host_fqdn: "{{ host_name ~ '.' ~ host_tld }}" host_url: "{{ host_protocol }}://{{ host_name ~ '.' ~ host_tld }}" @@ -23,19 +39,20 @@ - name: select a cluster node include_tasks: tasks/select_node.yml - when: "'containers' in group_names" + when: host_is_container - name: set hardware information set_fact: - hardware: "{{ default_container_hardware | combine(role_hardware[host_primary_role] | d({})) | - combine((container_hardware if 'containers' in group_names else host_hardware) | d({})) }}" + host_hardware: "{{ (default_container_hardware | combine(role_hardware | d({})) | + combine(host_hardware | d({}))) if host_is_container + else (host_hardware | d({})) }}" - name: clamp hardware cores to max node number set_fact: - hardware: "{{ hardware | combine({'cores': ([hardware.cores, hostvars[selected_node]['max_cores'] | d(hardware.cores)] | min)}) }}" - when: "not ('containers' in group_names) and (selected_node is defined) and (hostvars[selected_node]['max_cores'] is defined)" + host_hardware: "{{ host_hardware | combine({'cores': ([host_hardware.cores, hostvars[selected_node]['max_cores'] | d(host_hardware.cores)] | min)}) }}" + when: "host_is_container and (selected_node is defined) and (hostvars[selected_node]['max_cores'] is defined)" - block: