diff --git a/README.md b/README.md index 494e6bed..62d43386 100644 --- a/README.md +++ b/README.md @@ -418,18 +418,18 @@ pve_cluster_enabled: no # Set this to yes to configure hosts to be clustered tog pve_cluster_clustername: "{{ pve_group }}" # Should be set to the name of the PVE cluster ``` -Information about the following can be found in the PVE Documentation in the -[Cluster Manager][pvecm-network] chapter. +The following variables are used to provide networking information to corosync. +These are known as ring0_addr/ring1_addr or link0_addr/link1_addr, depending on +PVE version. They should be IPv4 or IPv6 addresses. For more information, refer +to the [Cluster Manager][pvecm-network] chapter in the PVE Documentation. ``` -pve_cluster_ring0_addr: "{{ ansible_default_ipv4.address }}" -pve_cluster_bindnet0_addr: "{{ pve_cluster_ring0_addr }}" -# pve_cluster_ring1_addr: "another interface's IP address or hostname" -# pve_cluster_bindnet1_addr: "{{ pve_cluster_ring1_addr }}" - +# pve_cluster_addr0: "{{ ansible_default_ipv4.address }}" +# pve_cluster_addr1: "another interface's IP address or hostname" ``` You can set options in the datacenter.cfg configuration file: + ``` pve_datacenter_cfg: keyboard: en-us diff --git a/defaults/main.yml b/defaults/main.yml index 3e4339b0..71f45723 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -29,14 +29,8 @@ pve_ceph_crush_rules: [] # pve_ssl_certificate: "contents of certificate" pve_cluster_enabled: no pve_cluster_clustername: "{{ pve_group }}" -# PVE 5.x (Debian Stretch) clustering options -pve_cluster_ring0_addr: "{{ ansible_default_ipv4.address }}" -pve_cluster_bindnet0_addr: "{{ pve_cluster_ring0_addr }}" -# pve_cluster_ring1_addr: "another interface's IP address or hostname" -# pve_cluster_bindnet1_addr: "{{ pve_cluster_ring1_addr }}" -# PVE 6.x (Debian Buster) clustering options -pve_cluster_link0_addr: "{{ ansible_default_ipv4.address }}" -# pve_cluster_link1_addr: "another interface's IP address or hostname" +# pve_cluster_addr0: "{{ ansible_default_ipv4.address }}" +# pve_cluster_addr1: "{{ ansible_eth1.ipv4.address }} pve_datacenter_cfg: {} pve_ssl_letsencrypt: false pve_groups: [] diff --git a/tasks/load_variables.yml b/tasks/load_variables.yml new file mode 100644 index 00000000..3a5c2ed7 --- /dev/null +++ b/tasks/load_variables.yml @@ -0,0 +1,43 @@ +--- +- name: Gather distribution specific variables + include_vars: "debian-{{ ansible_distribution_release }}.yml" + +- block: + # Per Proxmox documentation, bindnet_addr is expected to be an IP address and + # ring_addr can be either hostname or IP, but this role has always used an IP + # address. Thus, we're deprecating them. See below references. + # https://pve.proxmox.com/wiki/Separate_Cluster_Network#Setup_at_Cluster_Creation + # https://git.proxmox.com/?p=pve-cluster.git;a=blob;f=data/PVE/Corosync.pm;h=8b5c91e0da084da4e9ba7423176872a0c16ef5af;hb=refs/heads/stable-5#l209 + - name: LEGACY - Define pve_cluster_addr0 from bindnet0_addr/ring0_addr + set_fact: + pve_cluster_addr0: "{{ pve_cluster_bindnet0_addr | default(pve_cluster_ring0_addr) }}" + when: pve_cluster_ring0_addr is defined and ansible_distribution_release == 'stretch' + + - name: LEGACY - Define pve_cluster_addr0 from link0_addr + set_fact: + pve_cluster_addr0: "{{ pve_cluster_link0_addr }}" + when: pve_cluster_link0_addr is defined and ansible_distribution_release == 'buster' + when: pve_cluster_addr0 is not defined + +- block: + - name: LEGACY - Define pve_cluster_addr1 from bindnet1_addr/ring1_addr + set_fact: + pve_cluster_addr1: "{{ pve_cluster_bindnet1_addr | default(pve_cluster_ring1_addr) }}" + when: pve_cluster_ring1_addr is defined and ansible_distribution_release == 'stretch' + + - name: LEGACY - Define pve_cluster_addr1 from link1_addr + set_fact: + pve_cluster_addr1: "{{ pve_cluster_link1_addr }}" + when: pve_cluster_link1_addr is defined and ansible_distribution_release == 'buster' + when: pve_cluster_addr1 is not defined + +- name: Define pve_cluster_addr0 if not provided + set_fact: + pve_cluster_addr0: "{{ pve_cluster_addr0 | default(_pve_cluster_addr0) }}" + +- name: Calculate list of SSH addresses + set_fact: + pve_cluster_ssh_addrs: >- + ["{{ ansible_fqdn }}", "{{ ansible_hostname }}", + "{{ pve_cluster_addr0 }}", + {% if pve_cluster_addr1 is defined %}"{{ pve_cluster_addr1 }}"{% endif %}] diff --git a/tasks/main.yml b/tasks/main.yml index 05c19588..a418dc5f 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,13 +1,12 @@ --- # tasks file for ansible-role-proxmox -- name: Gather distribution specific variables - include_vars: "debian-{{ ansible_distribution_release }}.yml" +- import_tasks: load_variables.yml -- name: Ensure that we have an IP address for all cluster hosts +- name: Ensure that facts are present for all cluster hosts assert: that: - - "hostvars[item].ansible_default_ipv4.address is defined" - msg: "Missing IP address and other information for {{ item }}. Have you gathered its facts?" + - "hostvars[item].ansible_facts" + msg: "Could not load facts for {{ item }}. Please run your playbook against all hosts in {{ pve_group }}." with_items: "{{ groups[pve_group] }}" - name: Ensure this host is in the group specified @@ -27,25 +26,57 @@ blockinfile: dest: /etc/hosts marker: "# {mark} ANSIBLE MANAGED: Proxmox Cluster Hosts" - content: | - {% for host in groups[pve_group] %} - {{ hostvars[host].ansible_default_ipv4.address }} {{ hostvars[host].ansible_fqdn }} {{ hostvars[host].ansible_hostname }}{% if ansible_fqdn == hostvars[host].ansible_fqdn %} pvelocalhost{% endif %} + content: "\ + {% for host in groups[pve_group] %}\ + {{ hostvars[host].pve_cluster_addr0 }} + {{ hostvars[host].ansible_fqdn }} + {{ hostvars[host].ansible_hostname }}\ + {% if ansible_fqdn == hostvars[host].ansible_fqdn %} pvelocalhost{% endif %} - {% endfor %} + + {% endfor %}" - name: Remove conflicting lines in hosts files lineinfile: dest: /etc/hosts # expanded, this turns out to be, for example: - # regexp: '^(?!10\.0\.3\.17 test01\.lxc test01( pvelocalhost)?)(?!10\.0\.3\.17)[\w:.]+(\s+.*)?\s(test01\.lxc|test01|pvelocalhost)(\s+.*|\s*)$' + # regexp: "^(?!10\.0\.3\.17\\ test01\.lxc\\ test01\\ pvelocalhost)(?!10\.0\.3\.17)[0-9a-f:.]+(\s+.*)?\s(test01\.lxc|test01|pvelocalhost)(\s+.*|\s*)$' # basically first we ignore lines that match from the host enumeration task # above, then we match against different IPs (e.g. NOT 10.0.3.17) that have # the hostname/fqdn we inserted a record for previously, taking care also to # detect word boundaries (\b wasn't working for some reason) - regexp: '^(?!{{ hostvars[item].ansible_default_ipv4.address | regex_escape() }} {{ hostvars[item].ansible_fqdn | regex_escape() }} {{ hostvars[item].ansible_hostname | regex_escape() }}( pvelocalhost)?)(?!{{ hostvars[item].ansible_default_ipv4.address | regex_escape() }})[\w:.]+(\s+.*)?\s({{ hostvars[item].ansible_fqdn | regex_escape() }}|{{ hostvars[item].ansible_hostname | regex_escape() }}{% if ansible_fqdn == hostvars[item].ansible_fqdn %}|pvelocalhost{% endif %})(\s+.*|\s*)$' + regexp: "\ + ^(?!\ + {{ _correct_line | regex_escape() }}\ + )\ + {# Ignore lines starting with the current cluster host #}\ + (?!{{ _correct_ip | regex_escape() }})\ + {# Match an IPv4/v6 address at the start #}\ + [0-9a-f:.]\ + {# Match any hostnames, surrounded by whitespace #}\ + +(\\s+.*)?\\s\ + (\ + {{ _match_hosts | map('regex_escape') | join('|') }}\ + )\ + (\\s+.*|\\s*)$" state: absent backup: yes - with_items: "{{ groups[pve_group] }}" + loop: "{{ groups[pve_group] }}" + vars: + _correct_line: "\ + {{ hostvars[item].pve_cluster_addr0 }} + {{ hostvars[item].ansible_fqdn }} + {{ hostvars[item].ansible_hostname }}\ + {% if ansible_fqdn == hostvars[item].ansible_fqdn %} pvelocalhost{% endif %}" + _correct_ip: "{{ hostvars[item].pve_cluster_addr0 }}" + _match_hosts: >- + [ + "{{ hostvars[item].ansible_fqdn }}", + "{{ hostvars[item].ansible_hostname }}", + {% if ansible_fqdn == hostvars[item].ansible_fqdn %} + "pvelocalhost" + {% endif %} + ] - name: Trust Proxmox' packaging key apt_key: diff --git a/tasks/pve_add_node.yml b/tasks/pve_add_node.yml index 3b3d248a..af6656a7 100644 --- a/tasks/pve_add_node.yml +++ b/tasks/pve_add_node.yml @@ -4,26 +4,19 @@ _pve_current_node: "{{ item }}" - name: Add node to Proxmox cluster - command: "pvecm add {{ hostvars[groups[pve_group][0]]['ansible_default_ipv4']['address'] }} \ - -use_ssh \ - -ring0_addr {{ pve_cluster_ring0_addr }}{% if pve_cluster_ring1_addr is defined %} \ - -ring1_addr {{ pve_cluster_ring1_addr }}{% endif %}" + command: >- + pvecm add {{ hostvars[groups[pve_group][0]].pve_cluster_addr0 }} -use_ssh + {{ addr0_flag }} {{ pve_cluster_addr0 }} + {% if pve_cluster_addr1 is defined %} + {{ addr1_flag }} {{ pve_cluster_addr1 }} + {% endif %} args: creates: "{{ pve_cluster_conf }}" + vars: + addr0_flag: "{{ (ansible_distribution_release == 'buster') | ternary('-link0', '-ring0_addr') }}" + addr1_flag: "{{ (ansible_distribution_release == 'buster') | ternary('-link1', '-ring1_addr') }}" when: - "inventory_hostname == _pve_current_node" - - "ansible_distribution_release == 'stretch'" - -- name: Add node to Proxmox cluster - command: "pvecm add {{ hostvars[groups[pve_group][0]]['ansible_default_ipv4']['address'] }} \ - -use_ssh \ - -link0 {{ pve_cluster_link0_addr }}{% if pve_cluster_link1_addr is defined %} \ - -link1 {{ pve_cluster_link1_addr }}{% endif %}" - args: - creates: "{{ pve_cluster_conf }}" - when: - - "inventory_hostname == _pve_current_node" - - "ansible_distribution_release == 'buster'" - name: Remove stale corosync lock file due to lack of quorum during initialization file: diff --git a/tasks/pve_cluster_config.yml b/tasks/pve_cluster_config.yml index b2ae7b3d..fb85a15e 100644 --- a/tasks/pve_cluster_config.yml +++ b/tasks/pve_cluster_config.yml @@ -35,28 +35,20 @@ when: "(_pve_found_clusters | default([]) | length) == 1" - name: Initialize a Proxmox cluster - command: "pvecm create {{ pve_cluster_clustername }} -bindnet0_addr {{ pve_cluster_bindnet0_addr }} \ - -ring0_addr {{ pve_cluster_ring0_addr }}\ - {% if pve_cluster_bindnet1_addr is defined and pve_cluster_ring1_addr is defined %} \ - -bindnet1_addr {{ pve_cluster_bindnet1_addr }} -ring1_addr {{ pve_cluster_ring1_addr }}{% endif %}" - args: - creates: "{{ pve_cluster_conf }}" - when: - - "_pve_found_clusters is not defined" - - "inventory_hostname == groups[pve_group][0]" - - "ansible_distribution_release == 'stretch'" - -- name: Initialize a Proxmox cluster - command: "pvecm create {{ pve_cluster_clustername }} \ - -link0 {{ pve_cluster_link0_addr }}\ - {% if pve_cluster_link1_addr is defined %} \ - -link1 {{ pve_cluster_link1_addr }}{% endif %}" + command: >- + pvecm create {{ pve_cluster_clustername }} + {{ addr0_flag }} {{ pve_cluster_addr0 }} + {% if pve_cluster_addr1 is defined %} + {{ addr1_flag }} {{ pve_cluster_addr1 }} + {% endif %} args: creates: "{{ pve_cluster_conf }}" + vars: + addr0_flag: "{{ (ansible_distribution_release == 'buster') | ternary('-link0', '-ring0_addr') }}" + addr1_flag: "{{ (ansible_distribution_release == 'buster') | ternary('-link1', '-ring1_addr') }}" when: - "_pve_found_clusters is not defined" - "inventory_hostname == groups[pve_group][0]" - - "ansible_distribution_release == 'buster'" - name: Wait for quorum on initialization node proxmox_query: diff --git a/tasks/ssh_cluster_config.yml b/tasks/ssh_cluster_config.yml index 9632ad9a..43aaef0d 100644 --- a/tasks/ssh_cluster_config.yml +++ b/tasks/ssh_cluster_config.yml @@ -33,7 +33,7 @@ marker: "# {mark}: PVE host configuration options (managed by ansible)." content: | {% for host in groups[pve_group] %} - Host {{ hostvars[host].ansible_fqdn }} {{ hostvars[host].ansible_hostname }} {{ hostvars[host].ansible_default_ipv4.address }} + Host {{ hostvars[host].pve_cluster_ssh_addrs | join(" ") }} IdentityFile /root/.ssh/id_rsa Port {{ pve_ssh_port }} {% endfor %} @@ -44,7 +44,7 @@ marker: "# {mark}: Allow root logins from PVE hosts (managed by ansible)." content: | {% for host in groups[pve_group] %} - Match Address {{ hostvars[host].ansible_default_ipv4.address }} + Match Address {{ hostvars[host].pve_cluster_ssh_addrs | join(",") }} PermitRootLogin prohibit-password {% endfor %} validate: "/usr/sbin/sshd -t -f %s" @@ -74,7 +74,7 @@ content: | {% for host in groups[pve_group] %} {% for keytype in ['rsa', 'ed25519', 'ecdsa'] %} - {{ hostvars[host].ansible_fqdn }},{{ hostvars[host].ansible_hostname }},{{ hostvars[host].ansible_default_ipv4.address }} {{ ' '.join(lookup('file', pve_fetch_directory + '/' + host + '/ssh_host_' + keytype + '_key.pub').split()[:-1]) }} + {{ hostvars[host].pve_cluster_ssh_addrs | join(",") }} {{ ' '.join(lookup('file', pve_fetch_directory + '/' + host + '/ssh_host_' + keytype + '_key.pub').split()[:-1]) }} {% endfor %} {% endfor %} when: diff --git a/vars/main.yml b/vars/main.yml index 871123b5..b49eb989 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -2,3 +2,6 @@ # vars file for ansible-role-proxmox pve_base_dir: "/etc/pve" pve_cluster_conf: "{{ pve_base_dir }}/corosync.conf" + +# defaults that need to be host facts +_pve_cluster_addr0: "{{ ansible_default_ipv4.address }}"