├── .github ├── CODEOWNERS └── workflows │ └── publish-role.yml ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── tasks ├── client-config.yml ├── config.yml ├── install-client.yml ├── install-daemon.yml ├── main.yml ├── networks.yml ├── pools.yml ├── post-install-Debian.yml ├── prelude.yml ├── rbd.yml └── validate.yml ├── templates ├── auth.conf.j2 ├── ceph_secret.xml.j2 ├── libvirtd.conf.j2 ├── network.xml.j2 ├── pool.xml.j2 ├── qemu.conf.j2 ├── sasl.conf.j2 └── socket.j2 ├── tests ├── inventory └── test.yml └── vars ├── Archlinux.yml ├── Debian.yml ├── RedHat.yml └── main.yml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @stackhpc/ansible 2 | -------------------------------------------------------------------------------- /.github/workflows/publish-role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish Ansible Role 3 | 'on': 4 | push: 5 | tags: 6 | - "v?[0-9]+.[0-9]+.[0-9]+" 7 | workflow_dispatch: 8 | jobs: 9 | publish_role: 10 | uses: stackhpc/.github/.github/workflows/publish-role.yml@main 11 | secrets: 12 | GALAXY_API_KEY: ${{ secrets.GALAXY_API_KEY }} 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Libvirt Host 2 | ============ 3 | 4 | This role configures a host as a Libvirt/KVM hypervisor. It can also configure 5 | storage pools and networks on the host. 6 | 7 | Requirements 8 | ------------ 9 | 10 | The host should have Virtualization Technology (VT) enabled. 11 | 12 | Role Variables 13 | -------------- 14 | 15 | `libvirt_host_pools` is a list of pools to define and start. Each item 16 | should be a dict containing the following items: 17 | - `name` The name of the pool. 18 | - `type` The type of the pool, currently only `dir`, `logical` and `rbd` are 19 | supported. `lvm2` is supported as an alias for `logical`, but this alias is 20 | deprecated and will be removed in a future release. 21 | - `capacity` The capacity, in bytes, of the pool. (optional) 22 | - `path` The absolute path to the pool's backing directory. 23 | - `mode` The access mode of the pool. N.B.: This should be specified as an 24 | integer **without** a leading zero; for example: `mode: 755`. (only `dir`) 25 | - `owner` The owner of the pool. (only `dir`) 26 | - `group` The group of the pool. (only `dir`) 27 | - `source` The name of the volume group (when type is `logical`) or RBD pool 28 | (when type is `rbd`). 29 | - `pvs` A list of physical volumes the volume group consists of. (only when 30 | type is `logical`) 31 | - `hosts` The list of the Ceph monitors IPs or hostnames. (only `rbd`) 32 | - `username` The username used for RADOS authentification. (only `rbd`) 33 | - `passphrase` The passphrase used for RADOS authentification. (only `rbd`) 34 | 35 | `libvirt_host_networks` is a list of networks to define and start. Each item 36 | should be a dict containing the following items: 37 | - `name` The name of the network. 38 | - `mode` The forwarding mode of the network, `bridge`, `route`, `open` and `nat` are 39 | supported. Leave empty for a isolated network mode. 40 | - `bridge` The name of the bridge interface for this network. 41 | - `ip` IP address of the virtual bridge, mandatory for `route`, `open` and `nat` mode. 42 | - `netmask` Netmask of the virtual bridge, mandatory for `route`, `open` and `nat` mode. 43 | - `domain` DNS domain name for `route`, `open` and `nat` mode, default to the network 44 | name (optional). 45 | - `dhcp_start` First IP of the DHCP range in `route` , `open` or `nat` mode (optional). 46 | - `dhcp_end` Last IP of the DHCP range in `route`, `open` or `nat` mode (optional). 47 | - `routes` Optional list of additionals routes defined as following: 48 | - `address` Address of the route, required. 49 | - `prefix` Prefix of the route, required. 50 | - `gateway` Gateway of the route, required. 51 | - `metric` Metric of the route (optional). 52 | - `ipv6` IPv6 address of the virtual bridge (optional). 53 | - `ipv6_prefix` IPv6 prefix of the virtual bridge (optional). 54 | - `routesv6` Optional list of additionals IPv6 routes defined as following: 55 | - `address` IPv6 address of the route, required. 56 | - `prefix` IPv6 previx of the route, required. 57 | - `gateway` gateway of the route, required. 58 | - `metric` metric of the route (optional). 59 | 60 | `libvirt_host_require_vt` is whether to require that Intel Virtualisation 61 | Technology (VT) is enabled in order to run this role. While this provides 62 | better VM performance, it may not be available in certain environments. The 63 | default value is `true`. 64 | 65 | `libvirt_host_qemu_emulators`: List of architectures for which to install QEMU 66 | system emulators, e.g. `x86`. The default value is `['x86']` if 67 | 68 | `libvirt_host_require_vt` is `false`, otherwise the default value is an empty 69 | list. 70 | 71 | `libvirt_host_enable_efi_support`: Whether to enable EFI support. This defaults 72 | to false as extra packages need to be installed. 73 | 74 | `libvirt_host_var_prefix`: This determines The directory under /var/run that libvirt 75 | uses to store state, e.g unix domain sockets, as well as the default name of the 76 | PID file. Override this if you have a conflict with the default socket e.g it 77 | could be in use by the nova_libvirt container. Defaults to `""`. 78 | 79 | `libvirt_host_socket_dir`: Where the libvirtd socket is created. Defaults to 80 | `/var/run/{{ libvirt_host_var_prefix }}` if `libvirt_host_var_prefix` is set, 81 | otherwise `""`. 82 | 83 | `libvirt_host_pid_path`: Path to PID file which prevents multiple instances of 84 | the daemon from spawning. Defaults to `/var/run/{{ libvirt_host_var_prefix }}.pid` 85 | if `libvirt_host_var_prefix` is set, otherwise `""`. 86 | 87 | `libvirt_host_libvirtd_args`: Command line arguments passed to libvirtd by the 88 | init system when libvirtd is started - quotes will be added 89 | 90 | `libvirt_host_uri`: The libvirt connnection URI. Defaults to 91 | `qemu+unix:///system?socket={{ libvirt_host_socket_dir }}/libvirt-sock` if 92 | `libvirt_host_var_prefix` is set, otherwise `""`. If set to a falsey value, 93 | an explicit connection URI will not be set when calling virsh or any of 94 | the virt_ ansible modules. 95 | 96 | `libvirt_host_python3`: Whether the python3 version of the libvirt python 97 | bindings should be installed. If `false`, the python 2 bindings will be 98 | installed. 99 | 100 | `libvirt_host_install_daemon`: Whether to install and enable the libvirt 101 | daemon. Default is `true`. 102 | 103 | `libvirt_host_install_client`: Whether to install and enable the libvirt 104 | client. Default is `true`. 105 | 106 | `libvirt_host_extra_daemon_packages`: List of additional packages to install on 107 | libvirt daemon hosts. 108 | 109 | `libvirt_host_extra_client_packages`: List of additional packages to install on 110 | libvirt client hosts. 111 | 112 | `libvirt_host_libvirtd_conf_enabled`: Whether to configure `libvirtd.conf`. 113 | Default is `true`. 114 | 115 | `libvirt_host_libvirtd_conf`: Configuration for `libvirtd.conf`. Dict mapping 116 | option names to values. Default is an empty dict. 117 | 118 | `libvirt_host_qemu_conf_enabled`: Whether to configure `qemu.conf`. Default is 119 | `true`. 120 | 121 | `libvirt_host_qemu_conf`: Configuration for `qemu.conf`. Dict mapping option 122 | names to values. Default is an empty dict. 123 | 124 | `libvirt_host_enable_sasl_support`: Whether to enable SASL authentication 125 | support. Default is `false`. 126 | 127 | `libvirt_host_sasl_conf_enabled`: Whether to configure SASL authentication 128 | (`/etc/sasl2/libvirt.conf`). Default is the same as 129 | `libvirt_host_enable_sasl_support`. 130 | 131 | `libvirt_host_sasl_conf`: Configuration for SASL authentication 132 | (`/etc/sasl2/libvirt.conf`). String. 133 | 134 | `libvirt_host_sasl_mech_list`: List of enabled libvirt SASL authentication 135 | mechanisms. Default is `["SCRAM-SHA-256"]` when `libvirt_host_tls_listen` is 136 | `true`, otherwise `["DIGEST-MD5"]`. 137 | 138 | `libvirt_host_sasl_credentials`: List of SASL authentication credentials to 139 | create. Each item is a dict containing `username` and `password` items. 140 | Default is a single item list containing `libvirt_host_sasl_authname` and 141 | `libvirt_host_sasl_password`. 142 | 143 | `libvirt_host_sasl_authname`: Username for SASL authentication. Default is 144 | `libvirt`. 145 | 146 | `libvirt_host_sasl_password`: Password for SASL authentication. Default is 147 | unset. 148 | 149 | `libvirt_host_sasl_auth_conf_enabled`: Whether to configure SASL authentication 150 | credentials (`/etc/libvirt/auth.conf`). Default is the same as 151 | `libvirt_host_enable_sasl_support`. 152 | 153 | `libvirt_host_sasl_auth_conf`: Configuration for SASL authentication 154 | credentials (`/etc/libvirt/auth.conf`). String. 155 | 156 | `libvirt_host_sasl_auth_conf_filename`: Name of file to write SASL 157 | authentication credentials to. Default is `"/etc/libvirt/auth.conf"`. 158 | 159 | `libvirt_host_sasl_auth_conf_owner`: Owner of file to write SASL 160 | authentication credentials to. Default is `"root"`. 161 | 162 | `libvirt_host_sasl_auth_conf_group`: Group of file to write SASL 163 | authentication credentials to. Default is `"root"`. 164 | 165 | `libvirt_host_sasl_auth_conf_mode`: Mode of file to write SASL 166 | authentication credentials to. Default is `"0600"`. 167 | 168 | `libvirt_host_tcp_listen`: Whether to enable the systemd TCP socket unit. 169 | Default is `false`. 170 | 171 | `libvirt_host_tcp_listen_address`: Systemd TCP socket ListenStream. See man 172 | systemd.socket for format. Default is unset. 173 | 174 | `libvirt_host_tls_listen`: Whether to enable the systemd TLS socket unit. 175 | Default is `false`. 176 | 177 | `libvirt_host_tls_listen_address`: Systemd TLS socket ListenStream. See man 178 | systemd.socket for format. Default is unset. 179 | 180 | `libvirt_host_tls_server_cert`: TLS server certificate. Default is unset. 181 | 182 | `libvirt_host_tls_server_key`: TLS server key. Default is unset. 183 | 184 | `libvirt_host_tls_client_cert`: TLS client certificate. Default is unset. 185 | 186 | `libvirt_host_tls_client_key`: TLS client key. Default is unset. 187 | 188 | `libvirt_host_tls_cacert`: TLS CA certificate. Default is unset. 189 | 190 | `libvirt_host_qemu_tls_enabled`: Encrypt communication between QEMU instances using TLS. 191 | Default is `false`. 192 | 193 | `libvirt_host_qemu_tls_server_cert`: TLS server certificate. Default is `libvirt_host_tls_server_cert`. 194 | 195 | `libvirt_host_qemu_tls_server_key`: TLS server key. Default is `libvirt_host_tls_server_key`. 196 | 197 | `libvirt_host_qemu_tls_client_cert`: TLS client certificate. Default is `libvirt_host_tls_client_cert`. 198 | 199 | `libvirt_host_qemu_tls_client_key`: TLS client key. Default is `libvirt_host_tls_client_key`. 200 | 201 | `libvirt_host_qemu_tls_cacert`: TLS CA certificate. Default is `libvirt_host_tls_cacert`. 202 | 203 | `libvirt_host_qemu_user`: The user that QEMU runs as. This will be used for TLS file ownership 204 | Default is `libvirt-qemu`. 205 | 206 | `libvirt_host_qemu_group`: The group that the QEMU user belongs to. This will be used for TLS file ownership. 207 | Default is `libvirt-qemu`. 208 | 209 | `libvirt_host_vnc_tls_enabled`: Encrypt VNC traffic using TLS. Default is `false`. 210 | 211 | `libvirt_host_vnc_tls_server_cert`: TLS server certificate. Default is `libvirt_host_tls_server_cert`. 212 | 213 | `libvirt_host_vnc_tls_server_key`: TLS server key. Default is `libvirt_host_tls_server_key`. 214 | 215 | `libvirt_host_vnc_tls_cacert`: TLS CA certificate. Default is `libvirt_host_tls_cacert`. 216 | 217 | `libvirt_host_configure_apparmor`: Whether to configure AppArmor for directory 218 | storage pools. 219 | 220 | Dependencies 221 | ------------ 222 | 223 | None 224 | 225 | Example Playbook 226 | ---------------- 227 | 228 | --- 229 | - name: Ensure that Libvirt is configured 230 | hosts: all 231 | roles: 232 | - role: stackhpc.libvirt-host 233 | libvirt_host_pools: 234 | - name: my-pool 235 | type: dir 236 | capacity: 1024 237 | path: /path/to/pool 238 | mode: 755 239 | owner: my-user 240 | group: my-group 241 | - name: lvm_pool 242 | type: logical 243 | source: vg1 244 | target: /dev/vg1 245 | pvs: 246 | - /dev/sda3 247 | - name: rbd-pool 248 | type: rbd 249 | source: rbd 250 | hosts: 251 | - 192.168.42.200 252 | - 192.168.42.204 253 | - 192.168.42.208 254 | username: admin 255 | passphrase: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx 256 | 257 | libvirt_host_networks: 258 | - name: br-example 259 | mode: bridge 260 | bridge: br-example 261 | - name: brnat-example 262 | mode: nat 263 | bridge: brnat-example 264 | domain: example.local 265 | ip: 192.168.133.254 266 | netmask: 255.255.255.0 267 | dhcp_start: 192.168.133.100 268 | dhcp_end: 192.168.133.200 269 | 270 | Author Information 271 | ------------------ 272 | 273 | - Mark Goddard () 274 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # List of pools to define and start. 3 | # Each item should be a dict containing the following items: 4 | # name: The name of the pool. 5 | # type: The type of the pool, currently only 'dir', 'logical' or 'zfs' are 6 | # supported. 'lvm2' is supported as an alias for 'logical', but this 7 | # alias is deprecated and will be removed in a future release. 8 | # capacity: The capacity, in bytes, of the pool. 9 | # path: The absolute path to the pool's backing directory. 10 | # mode: The access mode of the pool. 11 | # owner: The owner of the pool. 12 | # group: The group of the pool. 13 | libvirt_host_pools: [] 14 | 15 | # List of networks to define and start. 16 | # Each item should be a dict containing the following items: 17 | # name: The name of the network. 18 | # mode: The forwarding mode of the network, currently only 'bridge' is 19 | # supported. 20 | # bridge: The name of the bridge interface for this network. 21 | libvirt_host_networks: [] 22 | 23 | # Whether to require that Intel Virtualisation Technology (VT) is enabled in 24 | # order to run this role. While this provides better VM performance, it may not 25 | # be available in certain environments. 26 | libvirt_host_require_vt: true 27 | 28 | # List of architectures for which to install QEMU system emulators, e.g. x86. 29 | libvirt_host_qemu_emulators: "{{ [] if libvirt_host_require_vt | bool else ['x86'] }}" 30 | 31 | # Whether or not to enable UEFI support. In some cases this requires installing 32 | # extra packages. 33 | libvirt_host_enable_efi_support: false 34 | 35 | # This determines The directory under /var/run that libvirt uses to store state, 36 | # e.g unix domain sockets, as well as the default name of the PID file. Override 37 | # this if you have a conflict with the default socket e.g it could be in use by the 38 | # nova_libvirt container 39 | libvirt_host_var_prefix: "" 40 | 41 | # Where the Unix Domain sockets are stored 42 | libvirt_host_socket_dir: >- 43 | {%- if libvirt_host_var_prefix -%} 44 | /var/run/{{ libvirt_host_var_prefix }} 45 | {%- endif -%} 46 | 47 | # Path to PID file which prevents mulitple instances of the daemon from 48 | # spawning 49 | libvirt_host_pid_path: >- 50 | {%- if libvirt_host_var_prefix -%} 51 | /var/run/{{ libvirt_host_var_prefix }}.pid 52 | {%- endif -%} 53 | 54 | # Command line arguments passed to libvirtd by the init system when 55 | # libvirtd is started - quotes will be added 56 | libvirt_host_libvirtd_args: >- 57 | {%- if libvirt_host_pid_path -%} 58 | -p {{ libvirt_host_pid_path }} 59 | {%- endif %} 60 | 61 | # The libvirt connnection URI 62 | libvirt_host_uri: >- 63 | {%- if libvirt_host_socket_dir -%} 64 | qemu+unix:///system?socket={{ libvirt_host_socket_dir }}/libvirt-sock 65 | {%- endif %} 66 | 67 | # Whether the python3 version of the libvirt python bindings should be 68 | # installed. If false, the python 2 bindings will be installed. 69 | libvirt_host_python3: "{{ ansible_facts.python.version.major == 3 }}" 70 | 71 | # Whether to install and enable the libvirt daemon. 72 | libvirt_host_install_daemon: true 73 | 74 | # Whether to install and enable the libvirt client. 75 | libvirt_host_install_client: true 76 | 77 | # List of additional packages to install on libvirt daemon hosts. 78 | libvirt_host_extra_daemon_packages: [] 79 | 80 | # List of additional packages to install on libvirt client hosts. 81 | libvirt_host_extra_client_packages: [] 82 | 83 | # Whether to configure libvirtd.conf. 84 | libvirt_host_libvirtd_conf_enabled: true 85 | # Configuration for libvirtd.conf. Dict mapping option names to values. 86 | libvirt_host_libvirtd_conf: {} 87 | 88 | # Whether to configure qemu.conf. 89 | libvirt_host_qemu_conf_enabled: true 90 | # Configuration for qemu.conf. Dict mapping option names to values. 91 | libvirt_host_qemu_conf: {} 92 | 93 | # Whether to enable SASL authentication support. 94 | libvirt_host_enable_sasl_support: false 95 | 96 | # Whether to configure SASL authentication (/etc/sasl2/libvirt.conf). 97 | libvirt_host_sasl_conf_enabled: "{{ libvirt_host_enable_sasl_support | bool }}" 98 | # Configuration for SASL authentication (/etc/sasl2/libvirt.conf). String. 99 | libvirt_host_sasl_conf: | 100 | mech_list: {{ libvirt_host_sasl_mech_list | join(' ') }} 101 | sasldb_path: /etc/libvirt/passwd.db 102 | # List of enabled libvirt SASL authentication mechanisms. 103 | libvirt_host_sasl_mech_list: 104 | - "{{ 'SCRAM-SHA-256' if libvirt_host_tls_listen | bool else 'DIGEST-MD5' }}" 105 | 106 | # List of SASL authentication credentials to create. Each item is a dict 107 | # containing "username" and "password" items. 108 | libvirt_host_sasl_credentials: 109 | - username: "{{ libvirt_host_sasl_authname }}" 110 | password: "{{ libvirt_host_sasl_password }}" 111 | # Username for SASL authentication. 112 | libvirt_host_sasl_authname: libvirt 113 | # Password for SASL authentication. 114 | libvirt_host_sasl_password: 115 | 116 | # Whether to configure SASL authentication credentials (/etc/libvirt/auth.conf). 117 | libvirt_host_sasl_auth_conf_enabled: "{{ libvirt_host_enable_sasl_support | bool }}" 118 | # Configuration for SASL authentication credentials (/etc/libvirt/auth.conf). String. 119 | libvirt_host_sasl_auth_conf: | 120 | [credentials-default] 121 | authname={{ libvirt_host_sasl_authname }} 122 | password={{ libvirt_host_sasl_password }} 123 | 124 | [auth-libvirt-default] 125 | credentials=default 126 | # Name of file to write SASL authentication credentials to. 127 | libvirt_host_sasl_auth_conf_filename: "/etc/libvirt/auth.conf" 128 | # Owner of file to write SASL authentication credentials to. 129 | libvirt_host_sasl_auth_conf_owner: "root" 130 | # Group of file to write SASL authentication credentials to. 131 | libvirt_host_sasl_auth_conf_group: "root" 132 | # Mode of file to write SASL authentication credentials to. 133 | libvirt_host_sasl_auth_conf_mode: "0600" 134 | 135 | # Whether to enable the systemd TCP socket unit. 136 | libvirt_host_tcp_listen: false 137 | # Systemd TCP socket ListenStream. See man systemd.socket for format. 138 | libvirt_host_tcp_listen_address: 139 | 140 | # Whether to enable the systemd TLS socket unit. 141 | libvirt_host_tls_listen: false 142 | # Systemd TLS socket ListenStream. See man systemd.socket for format. 143 | libvirt_host_tls_listen_address: 144 | # TLS server and client certificates. 145 | libvirt_host_tls_server_cert: 146 | libvirt_host_tls_server_key: 147 | libvirt_host_tls_client_cert: 148 | libvirt_host_tls_client_key: 149 | libvirt_host_tls_cacert: 150 | 151 | # Configure QEMU to use TLS for data transfer between hypervisors 152 | # This is more secure than SASL authentication. 153 | libvirt_host_qemu_tls_enabled: false 154 | 155 | # The user/group used to run the QEMU process. For security reasons, 156 | # Libvirt normally sets this to something other than root. 157 | libvirt_host_qemu_user: "qemu" 158 | libvirt_host_qemu_group: "qemu" 159 | 160 | # Encrypt VNC traffic 161 | libvirt_host_vnc_tls_enabled: false 162 | 163 | # Whether to configure AppArmor for directory storage pools. 164 | libvirt_host_configure_apparmor: "{{ libvirt_host_install_daemon | bool }}" 165 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: reload systemd 4 | systemd: 5 | daemon_reload: true 6 | become: true 7 | 8 | # The socket units cannot be stopped or started if libvirt is running. 9 | - name: stop libvirt 10 | service: 11 | name: libvirtd 12 | state: stopped 13 | become: true 14 | listen: 15 | - restart libvirt 16 | 17 | - name: start libvirtd sockets 18 | service: 19 | name: "{{ item.service }}" 20 | state: "{{ item.enabled | bool | ternary('started', 'stopped') }}" 21 | become: true 22 | loop: "{{ _libvirt_socket_services }}" 23 | loop_control: 24 | label: "{{ item.service }}" 25 | listen: 26 | - restart libvirt 27 | 28 | - name: start libvirt 29 | service: 30 | name: libvirtd 31 | state: started 32 | become: true 33 | 34 | - name: reload libvirt qemu apparmor profile template 35 | command: apparmor_parser -r /etc/apparmor.d/libvirt/TEMPLATE.qemu 36 | become: true 37 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | #role_name: libvirt_host 4 | author: Mark Goddard 5 | description: > 6 | Role to install and configure a host as a Libvirt/KVM hypervisor 7 | company: StackHPC Ltd 8 | license: Apache2 9 | min_ansible_version: 2.0 10 | platforms: 11 | - name: EL 12 | versions: 13 | - 7 14 | - name: Ubuntu 15 | versions: 16 | - all 17 | - name: Debian 18 | versions: 19 | - all 20 | - name: ArchLinux 21 | versions: 22 | - all 23 | galaxy_tags: 24 | - cloud 25 | - kvm 26 | - libvirt 27 | - vm 28 | 29 | dependencies: [] 30 | -------------------------------------------------------------------------------- /tasks/client-config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure client configuration files exist 3 | template: 4 | src: "{{ item.src }}" 5 | dest: "{{ item.dest }}" 6 | owner: "{{ item.owner }}" 7 | group: "{{ item.group }}" 8 | mode: "{{ item.mode }}" 9 | become: true 10 | loop: "{{ _libvirt_client_config_files | selectattr('enabled') }}" 11 | loop_control: 12 | label: "{{ item.dest | basename }}" 13 | vars: 14 | _libvirt_client_config_files: 15 | - src: auth.conf.j2 16 | dest: "{{ libvirt_host_sasl_auth_conf_filename }}" 17 | enabled: "{{ libvirt_host_sasl_auth_conf_enabled | bool }}" 18 | owner: "{{ libvirt_host_sasl_auth_conf_owner }}" 19 | group: "{{ libvirt_host_sasl_auth_conf_group }}" 20 | mode: "{{ libvirt_host_sasl_auth_conf_mode }}" 21 | -------------------------------------------------------------------------------- /tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure services - runs after the install stage 3 | 4 | - name: Create directory for libvirt socket 5 | file: 6 | state: directory 7 | path: "{{ libvirt_host_socket_dir }}" 8 | owner: root 9 | group: root 10 | mode: 0755 11 | become: true 12 | when: libvirt_host_socket_dir | length > 0 13 | 14 | - name: Process lineinfile rules 15 | lineinfile: "{{ rule.args }}" 16 | become: true 17 | loop: "{{ libvirt_host_lineinfile_extra_rules | default([]) }}" 18 | loop_control: 19 | loop_var: rule 20 | when: rule.condition 21 | notify: 22 | - restart libvirt 23 | 24 | - name: Ensure configuration files exist 25 | template: 26 | src: "{{ item.src }}" 27 | dest: "{{ item.dest }}" 28 | owner: root 29 | group: root 30 | mode: 0644 31 | become: true 32 | loop: "{{ _libvirt_config_files | selectattr('enabled') }}" 33 | loop_control: 34 | label: "{{ item.dest | basename }}" 35 | vars: 36 | _libvirt_config_files: 37 | - src: libvirtd.conf.j2 38 | dest: /etc/libvirt/libvirtd.conf 39 | enabled: "{{ libvirt_host_libvirtd_conf_enabled | bool }}" 40 | - src: qemu.conf.j2 41 | dest: /etc/libvirt/qemu.conf 42 | enabled: "{{ libvirt_host_qemu_conf_enabled | bool }}" 43 | - src: sasl.conf.j2 44 | dest: /etc/sasl2/libvirt.conf 45 | enabled: "{{ libvirt_host_sasl_conf_enabled | bool }}" 46 | notify: 47 | - restart libvirt 48 | 49 | - name: Create systemd drop-in directory for socket listen address 50 | file: 51 | path: "/etc/systemd/system/{{ item.service }}.d" 52 | state: directory 53 | owner: root 54 | group: root 55 | mode: 0755 56 | become: true 57 | loop: "{{ _libvirt_socket_services | selectattr('enabled') }}" 58 | when: 59 | - item.listen_address is not none 60 | - item.listen_address | length > 0 61 | loop_control: 62 | label: "{{ item.service }}" 63 | vars: 64 | _libvirt_listen_stream: "{{ item.listen_address }}" 65 | 66 | - name: Configure socket listen address 67 | template: 68 | src: socket.j2 69 | dest: "/etc/systemd/system/{{ item.service }}.d/listen-address.conf" 70 | owner: root 71 | group: root 72 | mode: 0644 73 | become: true 74 | loop: "{{ _libvirt_socket_services | selectattr('enabled') }}" 75 | when: 76 | - item.listen_address is not none 77 | - item.listen_address | length > 0 78 | loop_control: 79 | label: "{{ item.service }}" 80 | vars: 81 | _libvirt_listen_stream: "{{ item.listen_address }}" 82 | notify: 83 | - reload systemd 84 | - restart libvirt 85 | 86 | - name: Create directory for Libvirt TLS certificates and keys 87 | file: 88 | path: "{{ item }}" 89 | state: directory 90 | owner: root 91 | group: root 92 | mode: 0700 93 | become: true 94 | loop: >- 95 | {{ _libvirt_tls_certs.values() | 96 | selectattr('content') | 97 | map(attribute='dest') | 98 | map('dirname') | 99 | unique }} 100 | when: 101 | - libvirt_host_tls_listen | bool 102 | 103 | - name: Copy Libvirt TLS certificates and keys 104 | copy: 105 | content: "{{ _libvirt_loop_item.content }}" 106 | dest: "{{ _libvirt_loop_item.dest }}" 107 | owner: root 108 | group: root 109 | mode: "{{ _libvirt_loop_item.mode }}" 110 | become: true 111 | # NOTE: Loop over keys of _libvirt_tls_certs to avoid leaking the key 112 | # contents. 113 | loop: "{{ _libvirt_tls_certs.keys() }}" 114 | when: 115 | - libvirt_host_tls_listen | bool 116 | - _libvirt_loop_item.content 117 | vars: 118 | _libvirt_loop_item: "{{ _libvirt_tls_certs[item] }}" 119 | notify: restart libvirt 120 | 121 | - name: Ensure libvirt SASL user exists 122 | shell: 123 | cmd: > 124 | set -o pipefail && 125 | echo {{ item.password }} | 126 | saslpasswd2 -c -p -a libvirt {{ item.username }} 127 | executable: /bin/bash 128 | become: true 129 | no_log: true 130 | changed_when: true 131 | loop: "{{ libvirt_host_sasl_credentials }}" 132 | when: libvirt_host_enable_sasl_support | bool 133 | 134 | - name: Create directory for QEMU TLS certificates and keys 135 | file: 136 | path: "{{ item }}" 137 | state: directory 138 | owner: "{{ libvirt_host_qemu_user }}" 139 | group: "{{ libvirt_host_qemu_group }}" 140 | mode: 0700 141 | become: true 142 | loop: >- 143 | {{ _libvirt_host_qemu_tls_certs.values() | 144 | selectattr('content') | 145 | map(attribute='dest') | 146 | map('dirname') | 147 | unique }} 148 | when: 149 | - libvirt_host_qemu_tls_enabled | bool 150 | 151 | - name: Copy QEMU TLS certificates and keys 152 | copy: 153 | content: "{{ _libvirt_host_qemu_loop_item.content }}" 154 | dest: "{{ _libvirt_host_qemu_loop_item.dest }}" 155 | owner: "{{ libvirt_host_qemu_user }}" 156 | group: "{{ libvirt_host_qemu_group }}" 157 | mode: "{{ _libvirt_host_qemu_loop_item.mode }}" 158 | become: true 159 | # NOTE: Loop over keys of _libvirt_host_qemu_tls_certs to avoid leaking the key 160 | # contents. 161 | loop: "{{ _libvirt_host_qemu_tls_certs.keys() }}" 162 | when: 163 | - libvirt_host_qemu_tls_enabled | bool 164 | - _libvirt_host_qemu_loop_item.content 165 | vars: 166 | _libvirt_host_qemu_loop_item: "{{ _libvirt_host_qemu_tls_certs[item] }}" 167 | notify: restart libvirt 168 | 169 | - name: Create directory for Libvirt VNC TLS certificates and keys 170 | file: 171 | path: "{{ item }}" 172 | state: directory 173 | owner: "{{ libvirt_host_qemu_user }}" 174 | group: "{{ libvirt_host_qemu_group }}" 175 | mode: 0700 176 | become: true 177 | loop: >- 178 | {{ _libvirt_host_vnc_tls_certs.values() | 179 | selectattr('content') | 180 | map(attribute='dest') | 181 | map('dirname') | 182 | unique }} 183 | when: 184 | - libvirt_host_vnc_tls_enabled | bool 185 | 186 | - name: Copy Libvirt VNC TLS certificates and keys 187 | copy: 188 | content: "{{ _libvirt_host_vnc_loop_item.content }}" 189 | dest: "{{ _libvirt_host_vnc_loop_item.dest }}" 190 | owner: "{{ libvirt_host_qemu_user }}" 191 | group: "{{ libvirt_host_qemu_group }}" 192 | mode: "{{ _libvirt_host_vnc_loop_item.mode }}" 193 | become: true 194 | # NOTE: Loop over keys of _libvirt_host_vnc_tls_certs to avoid leaking the key 195 | # contents. 196 | loop: "{{ _libvirt_host_vnc_tls_certs.keys() }}" 197 | when: 198 | - libvirt_host_vnc_tls_enabled | bool 199 | - _libvirt_host_vnc_loop_item.content 200 | vars: 201 | _libvirt_host_vnc_loop_item: "{{ _libvirt_host_vnc_tls_certs[item] }}" 202 | notify: restart libvirt 203 | 204 | - name: Flush handlers 205 | meta: flush_handlers 206 | 207 | - name: Ensure the libvirt daemon is started and enabled 208 | service: 209 | name: "{{ item.service }}" 210 | state: "{{ item.enabled | bool | ternary('started', 'stopped') }}" 211 | enabled: "{{ item.enabled | bool }}" 212 | become: True 213 | loop: "{{ _libvirt_services }}" 214 | loop_control: 215 | label: "{{ item.service }}" 216 | vars: 217 | _libvirt_services: 218 | - service: libvirtd-tcp.socket 219 | enabled: "{{ libvirt_host_tcp_listen | bool }}" 220 | - service: libvirtd-tls.socket 221 | enabled: "{{ libvirt_host_tls_listen | bool }}" 222 | - service: libvirtd 223 | enabled: true 224 | -------------------------------------------------------------------------------- /tasks/install-client.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure libvirt client packages are installed 3 | package: 4 | name: "{{ libvirt_host_libvirt_packages_client | select | list }}" 5 | state: present 6 | register: result 7 | until: result is success 8 | retries: 3 9 | become: True 10 | -------------------------------------------------------------------------------- /tasks/install-daemon.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install custom yum repositories 3 | # Although argument splatting is marked as deprecated: 4 | # 5 | # [DEPRECATION WARNING]: Using variables for task params is unsafe, 6 | # especially if the variables come from an external source like facts. This 7 | # feature will be removed in a future release. 8 | # 9 | # The core team had a a change of heart and it is actually being preserved: 10 | # https://github.com/ansible/ansible/pull/43798 11 | yum_repository: "{{ item }}" 12 | loop: "{{ libvirt_host_custom_yum_repos | default([]) }}" 13 | become: true 14 | 15 | - name: Ensure libvirt packages are installed 16 | package: 17 | name: "{{ libvirt_host_libvirt_packages | select | list }}" 18 | state: present 19 | register: result 20 | until: result is success 21 | retries: 3 22 | become: True 23 | 24 | # NOTE: QEMU emulators are available in EPEL on CentOS 7. 25 | - name: Ensure the EPEL repository is enabled 26 | yum: 27 | name: epel-release 28 | state: present 29 | register: result 30 | until: result is success 31 | retries: 3 32 | become: True 33 | when: 34 | - ansible_facts.os_family == "RedHat" 35 | - ansible_facts.distribution_major_version | int == 7 36 | - libvirt_host_qemu_emulators | length > 0 37 | 38 | - name: Ensure QEMU emulator packages are installed 39 | package: 40 | name: "{{ package }}" 41 | state: present 42 | loop: "{{ libvirt_host_qemu_emulators | flatten(levels=1) }}" 43 | # NOTE(mgoddard): CentOS 8 does not provide separate packages per-emulator. 44 | when: ansible_facts.os_family != "RedHat" or ansible_facts.distribution_major_version | int == 7 45 | register: result 46 | until: result is success 47 | retries: 3 48 | become: True 49 | vars: 50 | package: "qemu-system-{{ item }}" 51 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_tasks: prelude.yml 3 | - import_tasks: validate.yml 4 | - name: Include install-daemon.yml 5 | include_tasks: install-daemon.yml 6 | when: libvirt_host_install_daemon | bool 7 | - name: Include install-client.yml 8 | include_tasks: install-client.yml 9 | when: 10 | - not libvirt_host_install_daemon | bool 11 | - libvirt_host_install_client | bool 12 | - name: Run post-install stage 13 | include_tasks: "{{ post_install_path }}" 14 | with_first_found: 15 | - files: 16 | - post-install-{{ ansible_facts.distribution }}.yml 17 | - post-install-{{ ansible_facts.os_family }}.yml 18 | skip: true 19 | loop_control: 20 | loop_var: post_install_path 21 | - name: Include config.yml 22 | include_tasks: config.yml 23 | when: libvirt_host_install_daemon | bool 24 | - name: Include client-config.yml 25 | include_tasks: client-config.yml 26 | when: libvirt_host_install_client | bool 27 | - name: Include pools.yml 28 | include_tasks: pools.yml 29 | when: libvirt_host_pools | length > 0 30 | - name: Include networks.yml 31 | include_tasks: networks.yml 32 | when: libvirt_host_networks | length > 0 33 | -------------------------------------------------------------------------------- /tasks/networks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure libvirt networks are defined 3 | virt_net: 4 | name: "{{ item.name }}" 5 | command: define 6 | xml: "{{ item.xml | default(lookup('template', 'network.xml.j2')) }}" 7 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 8 | with_items: "{{ libvirt_host_networks }}" 9 | become: True 10 | 11 | - name: Ensure libvirt networks are started on boot 12 | virt_net: 13 | name: "{{ item.name }}" 14 | autostart: yes 15 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 16 | with_items: "{{ libvirt_host_networks }}" 17 | become: True 18 | 19 | - name: Ensure libvirt networks are active 20 | virt_net: 21 | name: "{{ item.name }}" 22 | state: active 23 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 24 | with_items: "{{ libvirt_host_networks }}" 25 | become: True 26 | -------------------------------------------------------------------------------- /tasks/pools.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure libvirt LVM storage pool directories exist 3 | lvg: 4 | vg: "{{ item.source }}" 5 | pvs: "{{ item.pvs }}" 6 | when: item.type in ["lvm2", "logical"] 7 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 8 | become: True 9 | 10 | - name: include rbd.yml 11 | include_tasks: 12 | file: rbd.yml 13 | apply: 14 | become: True 15 | when: item.type == "rbd" 16 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 17 | 18 | - name: Ensure libvirt storage pools are defined 19 | virt_pool: 20 | name: "{{ item.name }}" 21 | command: define 22 | xml: "{{ item.xml | default(lookup('template', 'pool.xml.j2')) }}" 23 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 24 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 25 | become: True 26 | 27 | - name: Check libvirt directory storage pool status 28 | virt_pool: 29 | name: "{{ item.name }}" 30 | command: status 31 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 32 | when: item.type == "dir" 33 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 34 | become: True 35 | register: pool_status 36 | 37 | - name: Ensure libvirt directory storage pools are built 38 | virt_pool: 39 | name: "{{ item.item.name }}" 40 | command: build 41 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 42 | when: 43 | - item is not skipped 44 | - item.status != "active" 45 | loop: "{{ pool_status.results }}" 46 | become: True 47 | 48 | - name: Ensure libvirt storage pools are active 49 | virt_pool: 50 | name: "{{ item.name }}" 51 | state: active 52 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 53 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 54 | become: True 55 | 56 | - name: Ensure libvirt storage pools are started on boot 57 | virt_pool: 58 | name: "{{ item.name }}" 59 | autostart: yes 60 | uri: "{{ libvirt_host_uri | default(omit, true) }}" 61 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 62 | become: True 63 | -------------------------------------------------------------------------------- /tasks/post-install-Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # On Debian >= 8 and Ubuntu >= 16.04 the libvirt-bin package has been 3 | # split into libvirt-daemon-system and libvirt-clients. They also seem 4 | # to have changed to location to enviroment file. To prevent the need 5 | # to hard code paths for every major version we determine these 6 | # dynamically. This must be done after installing the package. 7 | # You cannot guard the with_first_found with a condition without 8 | # skip being set to true. This is undeseriable so we have to 9 | # put it behind an include (a block doesn't work). 10 | - name: Check if /etc/default/libvirt-bin exists 11 | stat: 12 | path: /etc/default/libvirt-bin 13 | register: libvirt_bin_stat 14 | tags: vars 15 | 16 | - name: Determine path to libvirt environment file 17 | set_fact: 18 | libvirt_host_lineinfile_extra_rules: 19 | - args: 20 | path: "{{ libvirt_env_path }}" 21 | insertafter: '^#libvirtd_opts=' 22 | regexp: '^libvirtd_opts=' 23 | line: "libvirtd_opts={{ libvirt_host_libvirtd_args }}" 24 | condition: "{{ libvirt_host_libvirtd_args | length > 0 }}" 25 | vars: 26 | libvirt_env_path: "{{ '/etc/default/libvirt-bin' if libvirt_bin_stat.stat.exists else '/etc/default/libvirtd' }}" 27 | tags: vars 28 | 29 | - name: Configure libvirt QEMU apparmor profile template 30 | lineinfile: 31 | path: "/etc/apparmor.d/libvirt/TEMPLATE.qemu" 32 | insertbefore: "^}" 33 | line: " {{ item.path }}/** rwk," 34 | become: true 35 | when: 36 | - libvirt_host_configure_apparmor | bool 37 | - ansible_facts.apparmor.status | default == 'enabled' 38 | - item.type == "dir" 39 | loop: "{{ libvirt_host_pools | flatten(levels=1) }}" 40 | notify: 41 | - reload libvirt qemu apparmor profile template 42 | -------------------------------------------------------------------------------- /tasks/prelude.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This file is intended to be included at the beginning of a playbook. 3 | 4 | - name: gather os specific variables 5 | include_vars: "{{ item }}" 6 | with_first_found: 7 | - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml" 8 | - "{{ ansible_facts.distribution }}.yml" 9 | - "{{ ansible_facts.os_family }}.yml" 10 | tags: vars 11 | -------------------------------------------------------------------------------- /tasks/rbd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install additional packages for rbd support 4 | package: 5 | name: "{{ libvirt_host_packages_rbd_volume_pool | flatten(levels=1) }}" 6 | state: present 7 | notify: restart libvirt 8 | 9 | - name: Create temporary file for Ceph secret 10 | tempfile: 11 | state: file 12 | suffix: .xml 13 | register: secret_tempfile 14 | 15 | - name: Send Ceph secret 16 | template: 17 | src: ceph_secret.xml.j2 18 | dest: "{{ secret_tempfile.path }}" 19 | 20 | - name: Define Ceph secret 21 | command: "virsh secret-define {{ secret_tempfile.path }}" 22 | 23 | - name: Set Ceph secret value 24 | command: "virsh secret-set-value {{ item.name | to_uuid }} {{ item.passphrase }}" 25 | 26 | - name: Delete temporary file 27 | file: 28 | path: "{{ secret_tempfile.path }}" 29 | state: absent 30 | 31 | - name: Flush handlers 32 | meta: flush_handlers 33 | 34 | 35 | -------------------------------------------------------------------------------- /tasks/validate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify that Virtualization Technology (VT) is enabled 3 | command: grep -c -E 'svm|vmx' /proc/cpuinfo 4 | check_mode: False 5 | changed_when: False 6 | failed_when: False 7 | register: result 8 | 9 | - name: Set a fact about whether Virtualization Technology (VT) is enabled 10 | set_fact: 11 | libvirt_host_vt_enabled: "{{ result.rc == 0 }}" 12 | 13 | - name: Notify if Virtualization Technology (VT) is disabled 14 | debug: 15 | msg: > 16 | Virtualization Technology (VT) is currently disabled. Please enable VT 17 | before running this role again. 18 | when: 19 | - not libvirt_host_require_vt | bool 20 | - not libvirt_host_vt_enabled 21 | 22 | - name: Fail if Virtualization Technology (VT) is disabled 23 | fail: 24 | msg: > 25 | Virtualization Technology (VT) is currently disabled. Please enable VT 26 | before running this role again. 27 | when: 28 | - libvirt_host_require_vt | bool 29 | - not libvirt_host_vt_enabled 30 | 31 | - name: Fail if SASL password is not defined 32 | fail: 33 | msg: > 34 | One or more SASL passwords in 'libvirt_host_sasl_credentials' are not 35 | defined 36 | when: 37 | - libvirt_host_enable_sasl_support | bool 38 | - libvirt_host_sasl_credentials | rejectattr('password') | length > 0 39 | -------------------------------------------------------------------------------- /templates/auth.conf.j2: -------------------------------------------------------------------------------- 1 | {{ libvirt_host_sasl_auth_conf }} 2 | -------------------------------------------------------------------------------- /templates/ceph_secret.xml.j2: -------------------------------------------------------------------------------- 1 | 2 | {{ item.name | to_uuid }} 3 | {{ item.name }} pool secret 4 | 5 | {{ item.name }} 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates/libvirtd.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | {% if libvirt_host_socket_dir | length > 0 %} 3 | unix_sock_dir = "{{ libvirt_host_socket_dir }}" 4 | {% endif %} 5 | {% for key, value in libvirt_host_libvirtd_conf.items() %} 6 | {# While the value is not JSON formatted, it is close enough - strings need to be double quoted. #} 7 | {{ key }} = {{ value | to_json }} 8 | {% endfor %} 9 | -------------------------------------------------------------------------------- /templates/network.xml.j2: -------------------------------------------------------------------------------- 1 | 2 | {{ item.name }} 3 | {% if item.mode is defined %}{% endif %} 4 | 5 | {% if item.mode is not defined or item.mode in ['route', 'nat', 'open'] %} 6 | 7 | 8 | {% if item.dhcp_start is defined and item.dhcp_end is defined %} 9 | 10 | 11 | 12 | {% endif %} 13 | 14 | {% if item.routes is defined %} 15 | {% for route in item.routes %} 16 | 17 | {% endfor %} 18 | {% endif %} 19 | {% if item.ipv6 is defined and item.ipv6_prefix is defined %} 20 | 21 | 22 | {% endif %} 23 | {% if item.routesv6 is defined %} 24 | {% for route in item.routesv6 %} 25 | 26 | {% endfor %} 27 | {% endif %} 28 | {% endif %} 29 | 30 | -------------------------------------------------------------------------------- /templates/pool.xml.j2: -------------------------------------------------------------------------------- 1 | {% if item.type == 'lvm2' %} 2 | 3 | {% else %} 4 | 5 | {% endif %} 6 | {{ item.name }} 7 | {% if 'capacity' in item %} 8 | {{ item.capacity }} 9 | {% endif %} 10 | {% if item.type in ['logical', 'lvm2', 'zfs', 'rbd'] %} 11 | 12 | {{ item.source }} 13 | {% if item.type in ['logical', 'lvm2'] %} 14 | 15 | {% endif %} 16 | {% if item.type == 'rbd' %} 17 | {% for host in item.hosts %} 18 | 19 | {% endfor %} 20 | 21 | 22 | 23 | {% endif %} 24 | 25 | {% endif %} 26 | {% if item.type != 'zfs' %} 27 | 28 | {{ item.path | default('placeholder_value') }} 29 | 30 | {% endif %} 31 | 32 | -------------------------------------------------------------------------------- /templates/qemu.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | {% if libvirt_host_vnc_tls_enabled | bool %} 3 | vnc_tls=1 4 | vnc_tls_x509_verify=1 5 | {% endif -%} 6 | {% for key, value in libvirt_host_qemu_conf.items() %} 7 | {# While the value is not JSON formatted, it is close enough - strings need to be double quoted. #} 8 | {{ key }} = {{ value | to_json }} 9 | {% endfor %} 10 | -------------------------------------------------------------------------------- /templates/sasl.conf.j2: -------------------------------------------------------------------------------- 1 | {{ libvirt_host_sasl_conf }} 2 | -------------------------------------------------------------------------------- /templates/socket.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | [Socket] 3 | ListenStream= 4 | ListenStream={{ _libvirt_listen_stream }} 5 | # FreeBind is recommended when listening on a specific address: 6 | # https://www.freedesktop.org/software/systemd/man/systemd.socket.html#FreeBind= 7 | FreeBind=true 8 | -------------------------------------------------------------------------------- /tests/inventory: -------------------------------------------------------------------------------- 1 | localhost ansible_connection='local' ansible_python_interpreter='/usr/bin/env python' 2 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | connection: local 4 | roles: 5 | - stackhpc.libvirt-host 6 | -------------------------------------------------------------------------------- /vars/Archlinux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # List of default daemon packages to install. 3 | libvirt_host_libvirt_packages_default: 4 | - libvirt 5 | - qemu-headless 6 | - ebtables 7 | - dnsmasq 8 | 9 | # List of default client packages to install. 10 | libvirt_host_libvirt_packages_client_default: 11 | - libvirt 12 | - libvirt-python 13 | - python-lxml 14 | 15 | # Packages that are only necessary if you require EFI support 16 | libvirt_host_packages_efi: 17 | - ovmf 18 | 19 | # Packages for RBD volume pool support 20 | libvirt_host_packages_rbd_volume_pool: 21 | - libvirt-storage-rbd 22 | - qemu-block-rbd 23 | 24 | # Packages for SASL authentication support. 25 | libvirt_host_packages_sasl: 26 | - cyrus-sasl 27 | 28 | # These are passed to the lineinfile module to customize configuration files 29 | libvirt_host_lineinfile_extra_rules: [] 30 | -------------------------------------------------------------------------------- /vars/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # List of package dependencies common to all Debian distributions 3 | libvirt_host_libvirt_packages_common: 4 | - qemu-kvm 5 | 6 | # List of all daemon packages to install. 7 | libvirt_host_libvirt_packages_libvirt_daemon: 8 | # The apparmor package contains the apparmor_parser tool. 9 | - "{% if ansible_facts.apparmor.status| default == 'enabled' %}apparmor{% endif %}" 10 | - >- 11 | {%- if (ansible_facts.distribution == "Ubuntu" and 12 | ansible_facts.distribution_major_version is version_compare('16.04', '<')) or 13 | (ansible_facts.distribution == "Debian" and 14 | ansible_facts.distribution_major_version is version_compare('8', '<')) -%} 15 | libvirt-bin 16 | {%- else -%} 17 | libvirt-daemon-system 18 | {%- endif -%} 19 | 20 | # List of default daemon packages to install. 21 | libvirt_host_libvirt_packages_default: "{{ libvirt_host_libvirt_packages_common + libvirt_host_libvirt_packages_libvirt_daemon }}" 22 | 23 | # List of default client packages to install. 24 | libvirt_host_libvirt_packages_client_default: 25 | - libvirt-clients 26 | - "{{ 'python3-libvirt' if libvirt_host_python3 | bool else 'python-libvirt' }}" 27 | - "{{ 'python3-lxml' if libvirt_host_python3 | bool else 'python-lxml' }}" 28 | 29 | # Packages that are only necessary if you require EFI support 30 | libvirt_host_packages_efi: 31 | - ovmf 32 | 33 | # Packages for RBD volume pool support 34 | libvirt_host_packages_rbd_volume_pool: 35 | - libvirt-daemon-driver-storage-rbd 36 | - qemu-block-extra 37 | 38 | # Packages for SASL authentication support. 39 | libvirt_host_packages_sasl: 40 | - libsasl2-modules-gssapi-mit 41 | - sasl2-bin 42 | 43 | # The user/group used to run the QEMU process. For security reasons, 44 | # Libvirt normally sets this to something other than root. 45 | libvirt_host_qemu_user: "libvirt-qemu" 46 | libvirt_host_qemu_group: "libvirt-qemu" 47 | 48 | # These are passed to the lineinfile module to customize configuration files 49 | libvirt_host_lineinfile_extra_rules: [] 50 | -------------------------------------------------------------------------------- /vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # List of default daemon packages to install. 3 | libvirt_host_libvirt_packages_default: 4 | # NOTE(mgoddard): CentOS 8.3 has a bug in which updating qemu-kvm does not 5 | # update libgcrypt. This leads to failues when using libvirt/qemu. See 6 | # https://bugzilla.redhat.com/show_bug.cgi?id=1840485. 7 | - libgcrypt 8 | - libgcrypt-devel 9 | - libvirt 10 | - libvirt-daemon-kvm 11 | - qemu-kvm 12 | 13 | # List of default client packages to install. 14 | libvirt_host_libvirt_packages_client_default: 15 | - libvirt-client 16 | - "{{ 'python3-libvirt' if libvirt_host_python3 | bool else 'libvirt-python' }}" 17 | - "{{ 'python3-lxml' if libvirt_host_python3 | bool else 'python-lxml' }}" 18 | 19 | # Packages that are only necessary if you require EFI support 20 | libvirt_host_packages_efi_by_version: 21 | 7: 22 | - edk2.git-ovmf-x64 # Official OVMF package doesn't boot (CentOS 7.5) 23 | - qemu-kvm-ev # Need smm support for secure boot 24 | 8: 25 | - edk2-ovmf 26 | 9: 27 | - edk2-ovmf 28 | 29 | libvirt_host_packages_efi: >- 30 | {{ libvirt_host_packages_efi_by_version[ansible_facts.distribution_major_version | int] }} 31 | 32 | # Packages for RBD volume pool support 33 | libvirt_host_packages_rbd_volume_pool: 34 | - libvirt-daemon-driver-storage-rbd 35 | - qemu-kvm-block-rbd 36 | 37 | # Packages for SASL authentication support. 38 | libvirt_host_packages_sasl: 39 | - cyrus-sasl 40 | - "{{ 'cyrus-sasl-gssapi' if 'gssapi' in libvirt_host_sasl_mech_list | map('lower') | list else '' }}" 41 | - "{{ 'cyrus-sasl-md5' if 'digest-md5' in libvirt_host_sasl_mech_list | map('lower') | list else '' }}" 42 | - "{{ 'cyrus-sasl-plain' if 'plain' in libvirt_host_sasl_mech_list | map('lower') | list else '' }}" 43 | - "{{ 'cyrus-sasl-scram' if 'scram' in libvirt_host_sasl_mech_list | map('lower') | join(' ') else '' }}" 44 | 45 | libvirt_host_custom_yum_repos_efi_by_version: 46 | 7: 47 | # Add custom repository as OVMF package seems to be broken 48 | - name: qemu-firmware-jenkins 49 | description: upstream OVMF firmware images 50 | baseurl: https://www.kraxel.org/repos/jenkins/ 51 | gpgcheck: no 52 | # Need an updated version of qemu with smm support 53 | - name: centos-qemu-ev 54 | description: CentOS-$releasever - QEMU EV 55 | baseurl: http://mirror.centos.org/$contentdir/$releasever/virt/$basearch/kvm-common/ 56 | gpgcheck: yes 57 | 8: [] 58 | 9: [] 59 | 60 | libvirt_host_custom_yum_repos: >- 61 | {{ libvirt_host_custom_yum_repos_efi_by_version[ansible_facts.distribution_major_version | int] }} 62 | 63 | # These are passed to the lineinfile module to customize configuration files 64 | libvirt_host_lineinfile_extra_rules: 65 | - args: 66 | path: /etc/sysconfig/libvirtd 67 | insertafter: '^#LIBVIRTD_ARGS=' 68 | regexp: '^LIBVIRTD_ARGS=' 69 | line: LIBVIRTD_ARGS="{{ libvirt_host_libvirtd_args }}" 70 | condition: "{{ libvirt_host_libvirtd_args != '' }}" 71 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # List of all packages to install for daemon hosts. 3 | libvirt_host_libvirt_packages: > 4 | {{ libvirt_host_libvirt_packages_default + 5 | libvirt_host_extra_daemon_packages + 6 | libvirt_host_libvirt_packages_client + 7 | (libvirt_host_packages_efi if libvirt_host_enable_efi_support | bool else []) + 8 | (libvirt_host_packages_sasl if libvirt_host_enable_sasl_support | bool else []) 9 | }} 10 | 11 | # List of all packages to install for client hosts. 12 | libvirt_host_libvirt_packages_client: >- 13 | {{ libvirt_host_libvirt_packages_client_default + 14 | libvirt_host_extra_client_packages + 15 | (libvirt_host_packages_sasl if libvirt_host_enable_sasl_support | bool else []) 16 | }} 17 | 18 | # List of socket services. 19 | _libvirt_socket_services: 20 | - service: libvirtd-tcp.socket 21 | enabled: "{{ libvirt_host_tcp_listen | bool }}" 22 | listen_address: "{{ libvirt_host_tcp_listen_address }}" 23 | - service: libvirtd-tls.socket 24 | enabled: "{{ libvirt_host_tls_listen | bool }}" 25 | listen_address: "{{ libvirt_host_tls_listen_address }}" 26 | 27 | # List of TLS certificates. 28 | _libvirt_tls_certs: 29 | servercert: 30 | content: "{{ libvirt_host_tls_server_cert }}" 31 | dest: /etc/pki/libvirt/servercert.pem 32 | mode: "0600" 33 | serverkey: 34 | content: "{{ libvirt_host_tls_server_key }}" 35 | dest: /etc/pki/libvirt/private/serverkey.pem 36 | mode: "0600" 37 | clientcert: 38 | content: "{{ libvirt_host_tls_client_cert }}" 39 | dest: /etc/pki/libvirt/clientcert.pem 40 | mode: "0600" 41 | clientkey: 42 | content: "{{ libvirt_host_tls_client_key }}" 43 | dest: /etc/pki/libvirt/private/clientkey.pem 44 | mode: "0600" 45 | cacert: 46 | content: "{{ libvirt_host_tls_cacert }}" 47 | dest: /etc/pki/CA/cacert.pem 48 | mode: "0644" 49 | 50 | _libvirt_host_qemu_tls_certs: 51 | servercert: 52 | content: "{{ libvirt_host_qemu_tls_server_cert | default(libvirt_host_tls_server_cert) }}" 53 | dest: /etc/pki/qemu/server-cert.pem 54 | mode: "0600" 55 | serverkey: 56 | content: "{{ libvirt_host_qemu_tls_server_key | default(libvirt_host_tls_server_key) }}" 57 | dest: /etc/pki/qemu/server-key.pem 58 | mode: "0600" 59 | clientcert: 60 | content: "{{ libvirt_host_qemu_tls_client_cert | default(libvirt_host_tls_client_cert) }}" 61 | dest: /etc/pki/qemu/client-cert.pem 62 | mode: "0600" 63 | clientkey: 64 | content: "{{ libvirt_host_qemu_tls_client_key | default(libvirt_host_tls_client_key) }}" 65 | dest: /etc/pki/qemu/client-key.pem 66 | mode: "0600" 67 | cacert: 68 | content: "{{ libvirt_host_qemu_tls_cacert | default(libvirt_host_tls_cacert) }}" 69 | dest: /etc/pki/qemu/ca-cert.pem 70 | mode: "0644" 71 | 72 | _libvirt_host_vnc_tls_certs: 73 | servercert: 74 | content: "{{ libvirt_host_vnc_tls_server_cert | default(libvirt_host_tls_server_cert) }}" 75 | dest: /etc/pki/libvirt-vnc/server-cert.pem 76 | mode: "0600" 77 | serverkey: 78 | content: "{{ libvirt_host_vnc_tls_server_key | default(libvirt_host_tls_server_key) }}" 79 | dest: /etc/pki/libvirt-vnc/server-key.pem 80 | mode: "0600" 81 | cacert: 82 | content: "{{ libvirt_host_vnc_tls_cacert | default(libvirt_host_tls_cacert) }}" 83 | dest: /etc/pki/libvirt-vnc/ca-cert.pem 84 | mode: "0644" 85 | --------------------------------------------------------------------------------