diff --git a/ansible/deploy.yml b/ansible/deploy.yml index 461ef11..e3242f6 100644 --- a/ansible/deploy.yml +++ b/ansible/deploy.yml @@ -44,20 +44,43 @@ | default([]) | subelements('physical_networks') }} - hosts: libvirt + vars: + # Allocations are stored in the localhost's vars. + nodes: >- + {{ hostvars['localhost'].allocations.result[inventory_hostname] + | default([]) }} tasks: - - include_tasks: libvirt_create_vms.yml + - name: Create Libvirt VMs + include_tasks: libvirt_create_vms.yml vars: - # Allocations are stored in the localhost's vars. - nodes: >- - {{ hostvars['localhost'].allocations.result[inventory_hostname] - | default([]) }} + libvirt_nodes: "{{ nodes }}" - - include_role: - name: virtualbmc + - name: Check that enough ports are available for Virtual BMC + fail: + msg: > + {{ nodes | count }} nodes were specified to be added to Virtual BMC, + but only {{ ipmi_port_range_end - ipmi_port_range_start }} ports are + available for use by Virtual BMC. + when: >- + (nodes | count) > (ipmi_port_range_end - ipmi_port_range_start) + + - name: Set up Virtual BMC daemon + include_role: + name: virtualbmc-daemon vars: - vbmc_libvirt_domains: >- - {{ hostvars['localhost'].allocations.result[inventory_hostname] - | default([]) | map(attribute='name') | list }} - vbmc_log_directory: "{{ log_directory }}" + vbmcd_virtualenv_path: "{{ virtualenv_path }}" + vbmcd_python_upper_contraints_url: "{{ python_upper_constraints_url }}" + when: (nodes | count) > 0 + + - name: Register domains with Virtual BMC + include_role: + name: virtualbmc-domain + vars: + vbmc_domain: "{{ domain }}" + vbmc_ipmi_port: "{{ ipmi_port_range_start + port_offset }}" vbmc_virtualenv_path: "{{ virtualenv_path }}" - vbmc_python_upper_contraints_url: "{{ python_upper_constraints_url }}" + vbmc_log_directory: "{{ log_directory }}" + loop: "{{ nodes | map(attribute='name') | list }}" + loop_control: + loop_var: domain + index_var: port_offset diff --git a/ansible/group_vars/libvirt b/ansible/group_vars/libvirt index 694a712..0e797d2 100644 --- a/ansible/group_vars/libvirt +++ b/ansible/group_vars/libvirt @@ -11,3 +11,7 @@ libvirt_pool_group: "{{ ansible_user_id }}" # By default, allow QEMU without hardware virtualisation since this is a # development tool. libvirt_require_vt: false + +# The range of ports available for use for node IPMI traffic. +ipmi_port_range_start: 6230 +ipmi_port_range_end: 6240 diff --git a/ansible/libvirt_create_vms.yml b/ansible/libvirt_create_vms.yml index 24b5fc3..95cf164 100644 --- a/ansible/libvirt_create_vms.yml +++ b/ansible/libvirt_create_vms.yml @@ -6,6 +6,6 @@ libvirt_vm_default_console_log_dir: "{{ log_directory }}" # Configure VM definitions for the Libvirt provider. libvirt_vms: >- - {{ nodes | map('set_libvirt_interfaces') - | map('set_libvirt_volume_pool') - | list }} + {{ libvirt_nodes | map('set_libvirt_interfaces') + | map('set_libvirt_volume_pool') + | list }} diff --git a/ansible/roles/virtualbmc-daemon/README.md b/ansible/roles/virtualbmc-daemon/README.md new file mode 100644 index 0000000..9c6f976 --- /dev/null +++ b/ansible/roles/virtualbmc-daemon/README.md @@ -0,0 +1,17 @@ +Virtual BMC Daemon +================== + +This role sets up the Virtual BMC daemon in systemd. + +Requirements +------------ + +- systemd + +Role Variables +-------------- + +- `vbmcd_virtualenv_path`: The path to the virtualenv in which to install + Virtual BMC. +- `vbmcd_python_upper_constraints_url`: The URL of the upper constraints file + to pass to pip when installing Python packages. diff --git a/ansible/roles/virtualbmc-daemon/defaults/main.yml b/ansible/roles/virtualbmc-daemon/defaults/main.yml new file mode 100644 index 0000000..1bca599 --- /dev/null +++ b/ansible/roles/virtualbmc-daemon/defaults/main.yml @@ -0,0 +1,6 @@ +--- +# The path to the virtualenv in which to install Virtual BMC. +vbmcd_virtualenv_path: +# The URL of the upper constraints file to pass to pip when installing Python +# packages. +vbmcd_python_upper_constraints_url: diff --git a/ansible/roles/virtualbmc/files/requirements.txt b/ansible/roles/virtualbmc-daemon/files/requirements.txt similarity index 100% rename from ansible/roles/virtualbmc/files/requirements.txt rename to ansible/roles/virtualbmc-daemon/files/requirements.txt diff --git a/ansible/roles/virtualbmc-daemon/tasks/main.yml b/ansible/roles/virtualbmc-daemon/tasks/main.yml new file mode 100644 index 0000000..6f57966 --- /dev/null +++ b/ansible/roles/virtualbmc-daemon/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Set service name + set_fact: + service: vbmcd + +- name: Ensure Python requirements are installed + pip: + requirements: "{{ '/'.join([role_path, 'files', 'requirements.txt']) }}" + extra_args: >- + -c {{ vbmcd_python_upper_contraints_url }} + virtualenv: "{{ vbmcd_virtualenv_path }}" + +- name: Ensure Virtual BMC systemd service is configured + template: + src: templates/{{ item }}.j2 + dest: /etc/systemd/system/{{ item }} + owner: root + group: root + mode: 0644 + become: true + register: service_file + loop: + - "{{ service }}.service" + +- name: Ensure Virtual BMC systemd service is started and enabled + systemd: + name: "{{ service }}" + enabled: yes + state: started + daemon_reload: "{{ service_file.changed }}" + become: true diff --git a/ansible/templates/vbmcd.service.j2 b/ansible/roles/virtualbmc-daemon/templates/vbmcd.service.j2 similarity index 55% rename from ansible/templates/vbmcd.service.j2 rename to ansible/roles/virtualbmc-daemon/templates/vbmcd.service.j2 index cb959e9..00b0133 100644 --- a/ansible/templates/vbmcd.service.j2 +++ b/ansible/roles/virtualbmc-daemon/templates/vbmcd.service.j2 @@ -4,4 +4,4 @@ Description=Virtual BMC daemon [Service] Type=simple Restart=on-failure -ExecStart="{{ virtualenv_path }}/bin/vbmcd" --foreground +ExecStart="{{ vbmcd_virtualenv_path }}/bin/vbmcd" --foreground diff --git a/ansible/roles/virtualbmc-domain/README.md b/ansible/roles/virtualbmc-domain/README.md new file mode 100644 index 0000000..9ce0236 --- /dev/null +++ b/ansible/roles/virtualbmc-domain/README.md @@ -0,0 +1,27 @@ +Virtual BMC Domain +================== + +This role ensures a Libvirt domain is added to and started in Virtual BMC. + +Requirements +------------ + +- Virtual BMC installed in a virtualenv +- Virtual BMC daemon running + +Role Variables +-------------- + +- `vbmc_domain`: The name of the Libvirt domain to be added to Virtual BMC. +- `vbmc_virtualenv_path`: The path to the virtualenv in which Virtual BMC is + installed. +- `vbmc_ipmi_listen_address`: The address on which Virtual BMC will listen for + IPMI traffic. Default is 0.0.0.0. +- `vbmc_ipmi_port`: The port on which Virtual BMC will listen for IPMI traffic. + Default is 6230. +- `vbmc_ipmi_username`: The IPMI username that Virtual BMC will use. Default is + 'username'. +- `vbmc_ipmi_password`: The IPMI password that Virtual BMC will use. Default is + 'password'. +- `vbmc_log_directory`: The directory in which to store Virtual BMC logs. If + `None`, output will not be logged to a file. Default is `None`. diff --git a/ansible/roles/virtualbmc-domain/defaults/main.yml b/ansible/roles/virtualbmc-domain/defaults/main.yml new file mode 100644 index 0000000..25f4416 --- /dev/null +++ b/ansible/roles/virtualbmc-domain/defaults/main.yml @@ -0,0 +1,16 @@ +--- +# The address on which VBMC will listen for IPMI traffic for this domain. +vbmc_ipmi_listen_address: 0.0.0.0 +# The port on which VBMC will listen for IPMI traffic for this domain. +vbmc_ipmi_port: 6230 +# The IPMI username that VBMC will use. +vbmc_ipmi_username: username +# The IPMI password that VBMC will use. +vbmc_ipmi_password: password + +# The name of the Libvirt domain to be added to Virtual BMC. +vbmc_domain: +# The directory in which to store VBMC logs. +vbmc_log_directory: +# The path to the virtualenv in which Virtual BMC is installed. +vbmc_virtualenv_path: diff --git a/ansible/roles/virtualbmc/tasks/domain.yml b/ansible/roles/virtualbmc-domain/tasks/main.yml similarity index 51% rename from ansible/roles/virtualbmc/tasks/domain.yml rename to ansible/roles/virtualbmc-domain/tasks/main.yml index 296a34f..4873ea7 100644 --- a/ansible/roles/virtualbmc/tasks/domain.yml +++ b/ansible/roles/virtualbmc-domain/tasks/main.yml @@ -1,38 +1,54 @@ --- -- name: Set common strings +- name: Set VBMC command string set_fact: # vbmcd should already be running, so --no-daemon stops vbmc from spawning # another instance of the daemon. - cmd: "'{{ vbmc_virtualenv_path }}/bin/vbmc' --no-daemon" - log_arg: "--log-file '{{ vbmc_log_directory }}/vbmc-{{ domain }}.log'" + cmd: >- + '{{ vbmc_virtualenv_path }}/bin/vbmc' + --no-daemon + {% if vbmc_log_directory is not none %} + --log-file '{{ vbmc_log_directory }}/vbmc-{{ domain }}.log' + {% endif %} # Even if the domain is present in VBMC, we can't guarantee that it's # configured correctly. It's easiest to delete and re-add it; this should # involve minimal downtime. - name: Ensure domain is stopped and deleted in VBMC command: >- - {{ cmd }} {{ item }} '{{ domain }}' {{ log_arg }} + {{ cmd }} {{ item }} '{{ domain }}' loop: - stop - delete register: res - changed_when: res.rc != 0 + changed_when: res.rc == 0 failed_when: - res.rc != 0 - "'No domain with matching name' not in res.stderr" become: true +# The commands above tend to return before the daemon has completed the action. +# Check here to be safe. +- name: Wait to ensure socket is closed + wait_for: + host: "{{ vbmc_ipmi_listen_address }}" + port: "{{ vbmc_ipmi_port }}" + state: stopped + timeout: 15 + - name: Ensure domain is added to VBMC command: >- {{ cmd }} add '{{ domain }}' - --port {{ port }} + --port {{ vbmc_ipmi_port }} --username '{{ vbmc_ipmi_username }}' --password '{{ vbmc_ipmi_password }}' --address {{ vbmc_ipmi_listen_address }} - {{ log_arg }} become: true - name: Ensure domain is started in VBMC command: > - {{ cmd }} start '{{ domain }}' {{ log_arg }} + {{ cmd }} start '{{ domain }}' + register: res + # Retry a few times in case the VBMC daemon has been slow to process the last + # few commands. + until: res is succeeded become: true diff --git a/ansible/roles/virtualbmc/README.md b/ansible/roles/virtualbmc/README.md deleted file mode 100644 index 486a83d..0000000 --- a/ansible/roles/virtualbmc/README.md +++ /dev/null @@ -1,25 +0,0 @@ -Virtual BMC -=========== - -This role sets up Virtual BMC. It will configure the Virtual BMC daemon in -systemd, and add the specified domains to the daemon. - -Requirements ------------- - -- systemd - -Role Variables --------------- - -- `vbmc_libvirt_domains`: A list of Libvirt domain names to be added to Virtual - BMC. -- `vbmc_ipmi_listen_address`: The address on which Virtual BMC will listen for - IPMI traffic. -- `vbmc_ipmi_port_range_start`, `vbmc_ipmi_port_range_end`: The range of ports - available for use by Virtual BMC. -- `vbmc_ipmi_username`: The IPMI username that Virtual BMC will use. -- `vbmc_ipmi_password`: The IPMI password that Virtual BMC will use. -- `vbmc_log_directory`: The directory in which to store Virtual BMC logs. -- `vbmc_virtualenv_path`: The path to the virtualenv in which to install - Virtual BMC. diff --git a/ansible/roles/virtualbmc/defaults/main.yml b/ansible/roles/virtualbmc/defaults/main.yml deleted file mode 100644 index 6560a2d..0000000 --- a/ansible/roles/virtualbmc/defaults/main.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# A list of Libvirt domain names to be added to VBMC. -vbmc_libvirt_domains: [] -# The address on which VBMC will listen for IPMI traffic. -vbmc_ipmi_listen_address: 0.0.0.0 -# The range of ports available for use by VBMC. -vbmc_ipmi_port_range_start: 6230 -vbmc_ipmi_port_range_end: 6240 -# The IPMI username that VBMC will use. -vbmc_ipmi_username: username -# The IPMI password that VBMC will use. -vbmc_ipmi_password: password - -# The directory in which to store VBMC logs. -vbmc_log_directory: -# The path to the virtualenv in which to install Virtual BMC. -vbmc_virtualenv_path: diff --git a/ansible/roles/virtualbmc/tasks/main.yml b/ansible/roles/virtualbmc/tasks/main.yml deleted file mode 100644 index 02ee15d..0000000 --- a/ansible/roles/virtualbmc/tasks/main.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -- name: Set service name - set_fact: - service: vbmcd - -- name: Check that enough ports are available for Virtual BMC - fail: - msg: > - {{ vbmc_libvirt_domains | count }} nodes were specified to be added to - Virtual BMC, but only - {{ vbmc_ipmi_port_range_end - vbmc_ipmi_port_range_start }} ports - are available for use by Virtual BMC. - when: >- - (vbmc_libvirt_domains | count) > - (vbmc_ipmi_port_range_end - vbmc_ipmi_port_range_start) - -- name: Ensure Python requirements are installed - pip: - requirements: "{{ '/'.join([role_path, 'files', 'requirements.txt']) }}" - extra_args: >- - -c {{ vbmc_python_upper_contraints_url }} - virtualenv: "{{ vbmc_virtualenv_path }}" - -- name: Ensure Virtual BMC systemd service is configured - template: - src: templates/{{ item }}.j2 - dest: /etc/systemd/system/{{ item }} - owner: root - group: root - mode: 0644 - become: true - register: vbmc_service_file - loop: - - "{{ service }}.service" - -- name: Ensure Virtual BMC systemd service is started and enabled - systemd: - name: "{{ service }}" - enabled: yes - state: started - daemon_reload: "{{ vbmc_service_file.changed }}" - become: true - -- include_tasks: domain.yml - vars: - domain: "{{ domain }}" - port: "{{ vbmc_ipmi_port_range_start + port_offset }}" - loop: "{{ vbmc_libvirt_domains }}" - loop_control: - loop_var: domain - index_var: port_offset