|
1 | 1 | --- |
2 | | -- name: Compute facts (OVS) |
3 | | - ansible.builtin.set_fact: |
4 | | - ovs: "{{ ovs_defaults | combine(ovs | d({}), recursive=true) }}" |
| 2 | +- ansible.builtin.import_tasks: |
| 3 | + file: "{{ role_path }}/tasks/openvswitch.yml" |
5 | 4 |
|
6 | | -- when: ((ovs.iface | count) + (ovs.bond | count) + (ovs.br | count)) > 0 |
7 | | - vars: |
8 | | - # helpers |
9 | | - _pci_addr_regex: >- |
10 | | - ^[0-9a-fA-F]{4}[:][0-9a-fA-F]{2}[:][0-9a-fA-F]{2}[.][0-9a-fA-F]{1,2}$ |
11 | | - # general |
12 | | - _dpdk_enabled: >- |
13 | | - {{ ovs.set | d([]) |
14 | | - | selectattr('other_config:dpdk-init', 'defined') |
15 | | - | selectattr('other_config:dpdk-init', 'in', ['true']) |
16 | | - | count > 0 }} |
17 | | - # iface |
18 | | - _dpdk_iface: >- |
19 | | - {%- set output = [] -%} |
20 | | - {%- for k, v in ovs.iface.items() -%} |
21 | | - {%- for u in v.set | d([]) | selectattr('type', 'defined') -%} |
22 | | - {%- if u.type.startswith('dpdk') -%} |
23 | | - {{- output.append([k, v]) -}} |
24 | | - {%- endif -%} |
25 | | - {%- endfor -%} |
26 | | - {%- endfor -%} |
27 | | - {{- dict(output) -}} |
28 | | - _dpdk_pci_addrs_raw: >- |
29 | | - {%- set output = [] -%} |
30 | | - {%- for k, v in _dpdk_iface.items() -%} |
31 | | - {%- for u in v.set | selectattr('options:dpdk-devargs', 'defined') -%} |
32 | | - {%- set _devargs = u['options:dpdk-devargs'] | string -%} |
33 | | - {%- if _devargs | regex_search(_pci_addr_regex) -%} |
34 | | - {{- output.append([_devargs, v.driver | d('vfio-pci')]) -}} |
35 | | - {%- else -%} |
36 | | - {{- output.append([]) -}} |
37 | | - {%- endif -%} |
38 | | - {%- endfor -%} |
39 | | - {%- endfor -%} |
40 | | - {{- output -}} |
41 | | - _dpdk_pci_addrs_items: >- |
42 | | - {{ _dpdk_pci_addrs_raw | select | unique }} |
43 | | - _dpdk_pci_addrs: >- |
44 | | - {{ dict(_dpdk_pci_addrs_items) }} |
45 | | - _internal_iface: >- |
46 | | - {{ ovs.iface | dict2items |
47 | | - | selectattr('key', 'in', ovs.br.keys()) |
48 | | - | items2dict }} |
49 | | - _system_iface: >- |
50 | | - {%- set output = [] -%} |
51 | | - {%- for k, v in ovs.iface.items() | rejectattr(0, 'in', _internal_iface.keys()) -%} |
52 | | - {%- if v.set is undefined or v.set | selectattr('type', 'defined') |
53 | | - | count == 0 |
54 | | - or v.set | selectattr('type', 'defined') |
55 | | - | selectattr('type', 'in', [none, '', 'system']) |
56 | | - | count > 0 -%} |
57 | | - {{- output.append([k, v]) -}} |
58 | | - {%- endif -%} |
59 | | - {%- endfor -%} |
60 | | - {{- dict(output) -}} |
61 | | - _iface: >- |
62 | | - {{ ovs.iface | dict2items |
63 | | - | rejectattr('key', 'in', _dpdk_iface.keys()) |
64 | | - | rejectattr('key', 'in', _internal_iface.keys()) |
65 | | - | items2dict }} |
66 | | - _pci_addrs: >- |
67 | | - {{ command_udevadm_pci_addresses.stdout_lines | d([]) |
68 | | - | select |
69 | | - | map('regex_replace', '^pci-', '') }} |
70 | | - # bond |
71 | | - _dpdk_bond: >- |
72 | | - {{ ovs.bond | dict2items |
73 | | - | selectattr('value.ifaces', 'defined') |
74 | | - | selectattr('value.ifaces', 'subset', _dpdk_iface.keys()) |
75 | | - | items2dict }} |
76 | | - _bond: >- |
77 | | - {{ ovs.bond | dict2items |
78 | | - | selectattr('value.ifaces', 'defined') |
79 | | - | selectattr('value.ifaces', 'subset', _iface.keys()) |
80 | | - | items2dict }} |
81 | | - _bond_ifaces: >- |
82 | | - {{ ovs.bond | dict2items |
83 | | - | selectattr('value.ifaces', 'defined') |
84 | | - | map(attribute='value.ifaces') |
85 | | - | flatten }} |
86 | | - # br |
87 | | - _dpdk_br: >- |
88 | | - {%- set output = [] -%} |
89 | | - {%- for k, v in ovs.br.items() -%} |
90 | | - {%- for u in v.set | d([]) | selectattr('datapath_type', 'defined') -%} |
91 | | - {%- if u.datapath_type in ['netdev'] -%} |
92 | | - {{- output.append([k, v]) -}} |
93 | | - {%- endif -%} |
94 | | - {%- endfor -%} |
95 | | - {%- endfor -%} |
96 | | - {{- dict(output) -}} |
97 | | - _br: >- |
98 | | - {{ ovs.br | dict2items |
99 | | - | rejectattr('key', 'in', _dpdk_br.keys()) |
100 | | - | items2dict }} |
101 | | - _br_ports: >- |
102 | | - {{ ovs.br | dict2items |
103 | | - | selectattr('value.ports', 'defined') |
104 | | - | map(attribute='value.ports') |
105 | | - | flatten }} |
106 | | - block: |
107 | | - - name: Assert DPDK is enabled when DPDK resources are defined |
108 | | - ansible.builtin.assert: |
109 | | - that: (_dpdk_iface | count == 0) |
110 | | - or |
111 | | - (_dpdk_enabled is true) |
112 | | - fail_msg: Please enable DPDK (define other_config:dpdk-init) or remove DPDK resources from OVS config. |
113 | | - |
114 | | - - name: Assert all provided DPDK PCI addresses are valid and unique |
115 | | - ansible.builtin.assert: |
116 | | - that: _dpdk_pci_addrs_raw == _dpdk_pci_addrs_items # no invalid, no duplicated |
117 | | - fail_msg: Please remove invalid / duplicated DPDK PCI addresses from OVS config. |
118 | | - |
119 | | - - name: Assert DPDK PCI devices are not already claimed by PCI/SR-IOV management |
120 | | - ansible.builtin.assert: |
121 | | - that: _intersection | count == 0 |
122 | | - fail_msg: DPDK vs PCI/SR-IOV conflict detected. Please ensure {{ _intersection }} are not being claimed by both implementations. |
123 | | - vars: |
124 | | - _intersection: >- |
125 | | - {{ _dpdk_pci_addrs.keys() | intersect(_slots) }} |
126 | | - _slots: >- |
127 | | - {{ lspci_devices | selectattr('Slot', 'defined') |
128 | | - | map(attribute='Slot') }} |
129 | | - when: |
130 | | - # NOTE: The 'lspci_devices' fact is produced by the helper/pci role. |
131 | | - - lspci_devices is defined |
132 | | - - lspci_devices is sequence |
133 | | - - lspci_devices | count > 0 |
134 | | - |
135 | | - - name: Query lspci if DPDK PCI addresses do exist |
136 | | - ansible.builtin.shell: |
137 | | - cmd: | |
138 | | - set -o errexit |
139 | | - {% for v in _dpdk_pci_addrs.keys() %} |
140 | | - STDOUT="$(lspci -vmm -nkD -s '{{ v }}')" |
141 | | - if [[ -n "$STDOUT" ]]; then |
142 | | - echo "$STDOUT" |
143 | | - echo |
144 | | - else |
145 | | - echo "Could not find '{{ v }}'" >&2 |
146 | | - exit 1 |
147 | | - fi |
148 | | - {% endfor %} |
149 | | - executable: /bin/bash |
150 | | - changed_when: false |
151 | | - |
152 | | - - name: Query udev for PCI addresses |
153 | | - ansible.builtin.command: |
154 | | - cmd: "udevadm info --query=property --property=ID_PATH --value {{ _paths | join(' ') }}" |
155 | | - when: _paths | count > 0 |
156 | | - vars: |
157 | | - _paths: >- |
158 | | - {{ _system_iface.keys() | map('regex_replace', '^(.*)$', "-p '/sys/class/net/\g<1>'") }} |
159 | | - register: command_udevadm_pci_addresses |
160 | | - changed_when: false |
161 | | - |
162 | | - - name: Assert DPDK and non-DPDK devices do not share PCI addresses |
163 | | - ansible.builtin.assert: |
164 | | - that: _dpdk_pci_addrs.keys() | intersect(_pci_addrs) | count == 0 |
165 | | - fail_msg: Please remove conflicting (PCI address) DPDK vs non-DPDK device definitions from OVS config. |
166 | | - |
167 | | - - name: Assert all bond 'ifaces' are unique subset of ovs.iface devices |
168 | | - ansible.builtin.assert: |
169 | | - that: |
170 | | - - _bond_ifaces == _bond_ifaces | unique # no duplicated |
171 | | - - _bond_ifaces is subset(ovs.iface.keys()) |
172 | | - fail_msg: Please ensure bond 'ifaces' are declared in ovs.iface and uniquely distributed among bond resources. |
173 | | - |
174 | | - - name: Assert each bond resource contains at least 2 'ifaces' |
175 | | - ansible.builtin.assert: |
176 | | - that: |
177 | | - - 0 not in _ifaces_counts |
178 | | - - 1 not in _ifaces_counts |
179 | | - fail_msg: Please ensure each bond resource contains at least 2 'ifaces'. |
180 | | - vars: |
181 | | - _ifaces_counts: >- |
182 | | - {{ ovs.bond | dict2items |
183 | | - | selectattr('value.ifaces', 'defined') |
184 | | - | map(attribute='value.ifaces') |
185 | | - | map('count') |
186 | | - | unique }} |
187 | | -
|
188 | | - - name: Assert each bond 'ifaces' are not of mixed DPDK / non-DPDK types |
189 | | - ansible.builtin.assert: |
190 | | - that: |
191 | | - - _bond_keys == _bond_keys | unique # there are no mixed 'ifaces' |
192 | | - - _bond_keys == _all_bond_keys # every bond resource has some valid-ish 'ifaces' |
193 | | - fail_msg: Please ensure each declared bond resource has 'ifaces' of either DPDK or non-DPDK types (never both). |
194 | | - vars: |
195 | | - _bond_keys: >- |
196 | | - {{ _dpdk_bond.keys() | list + _bond.keys() | list }} |
197 | | - _all_bond_keys: >- |
198 | | - {{ ovs.bond.keys() }} |
199 | | -
|
200 | | - - name: Assert ovs.port is a subset of available ports (including internal) |
201 | | - ansible.builtin.assert: |
202 | | - that: |
203 | | - - ovs.port.keys() is subset(ovs.br.keys() | list + _br_ports) |
204 | | - fail_msg: Please ensure ovs.port is a subset of available ports. |
205 | | - |
206 | | - - name: Assert br 'ports' are unique subset of ovs.bond + ovs.iface resources |
207 | | - ansible.builtin.assert: |
208 | | - that: |
209 | | - - _br_ports == _br_ports | unique # no duplicated |
210 | | - - _br_ports is subset(ovs.bond.keys() | list + ovs.iface.keys() | list) |
211 | | - fail_msg: Please ensure br 'ports' are declared in ovs.bond and ovs.iface and uniquely distributed among br resources. |
212 | | - |
213 | | - - name: Assert each non-DPDK br 'ports' do not contain DPDK resources |
214 | | - ansible.builtin.assert: |
215 | | - that: _keys | intersect(_dpdk_keys) | count == 0 |
216 | | - fail_msg: Please ensure no DPDK resource is inserted into non-DPDK br resources. |
217 | | - vars: |
218 | | - _keys: >- |
219 | | - {{ _br | dict2items |
220 | | - | map(attribute='value.ports') |
221 | | - | flatten }} |
222 | | - _dpdk_keys: >- |
223 | | - {{ _dpdk_bond.keys() | list + _dpdk_iface.keys() | list }} |
224 | | -
|
225 | | - - name: Assert that at least one IP address has been provided by the user |
226 | | - ansible.builtin.assert: |
227 | | - that: _ip_addrs | count > 0 |
228 | | - fail_msg: Please define at least one IP address (otherwise all connectivity would be lost). |
229 | | - vars: |
230 | | - _ip_addrs: >- |
231 | | - {{ (ovs.iface.values() | list + ovs.br.values() | list) | selectattr('addrs', 'defined') |
232 | | - | map(attribute='addrs') |
233 | | - | flatten |
234 | | - | selectattr('cidr', 'defined') |
235 | | - | map(attribute='cidr') |
236 | | - | select }} |
237 | | -
|
238 | | - - name: Assert addrs/gw/dns are not declared for br 'ports' and bond 'ifaces' |
239 | | - ansible.builtin.assert: |
240 | | - that: _matched | count == 0 |
241 | | - fail_msg: Please remove addrs/gw/dns attributes from br 'ports' and bond 'ifaces'. |
242 | | - vars: |
243 | | - _keys: >- |
244 | | - {{ (_bond_ifaces + _br_ports) | difference(ovs.bond) }} |
245 | | - _matched: >- |
246 | | - {{ _keys | map('extract', ovs.iface) |
247 | | - | map('dict2items') |
248 | | - | flatten |
249 | | - | selectattr('key', 'in', ['addrs', 'gw', 'dns']) }} |
250 | | -
|
251 | | - - name: Ensure udev rules for vfio |
252 | | - ansible.builtin.copy: |
253 | | - dest: /etc/udev/rules.d/99-vfio.rules |
254 | | - owner: 0 |
255 | | - group: 0 |
256 | | - mode: u=rw,go=r |
257 | | - content: | |
258 | | - SUBSYSTEM=="vfio", GROUP="kvm", MODE="0666" |
259 | | - register: copy_udev_vfio |
260 | | - |
261 | | - - name: Refresh udev rules |
262 | | - ansible.builtin.shell: |
263 | | - cmd: | |
264 | | - set -o errexit |
265 | | - udevadm control --reload-rules && udevadm trigger |
266 | | - executable: /bin/bash |
267 | | - changed_when: true |
268 | | - when: copy_udev_vfio is changed |
269 | | - |
270 | | - - name: Install OVS packages |
271 | | - ansible.builtin.package: |
272 | | - name: "{{ _specific[ansible_distribution] | d(_specific[ansible_os_family]) }}" |
273 | | - vars: |
274 | | - _specific: "{{ _dpdk_enabled | ternary(ovs_packages_dpdk, ovs_packages) }}" |
275 | | - register: package |
276 | | - until: package is success |
277 | | - retries: 12 |
278 | | - delay: 5 |
279 | | - |
280 | | - - when: |
281 | | - - ansible_os_family in ['Debian'] |
282 | | - - _dpdk_enabled is true |
283 | | - block: |
284 | | - - name: Use DPDK version of ovs-vswitchd |
285 | | - community.general.alternatives: |
286 | | - name: ovs-vswitchd |
287 | | - path: /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk |
288 | | - register: alternatives_ovs_vswitchd |
289 | | - |
290 | | - - name: Enable / (Re)Start OVS (NOW) |
291 | | - ansible.builtin.systemd_service: |
292 | | - name: "{{ _specific[ansible_os_family] }}" |
293 | | - state: >- |
294 | | - {{ 'restarted' if _changed else 'started' }} |
295 | | - enabled: true |
296 | | - vars: |
297 | | - _specific: |
298 | | - Debian: openvswitch-switch.service |
299 | | - RedHat: openvswitch.service |
300 | | - Suse: openvswitch.service |
301 | | - _changed: >- |
302 | | - {{ (alternatives_ovs_vswitchd is defined) |
303 | | - and |
304 | | - (alternatives_ovs_vswitchd is changed) }} |
305 | | -
|
306 | | - - name: Install OVS-related scripts |
307 | | - ansible.builtin.template: |
308 | | - src: "{{ item.src }}" |
309 | | - dest: "{{ item.dest }}" |
310 | | - mode: "{{ item.mode }}" |
311 | | - owner: 0 |
312 | | - group: 0 |
313 | | - loop: |
314 | | - - src: opennebula-ovs.sh.jinja |
315 | | - dest: /usr/local/sbin/opennebula-ovs.sh |
316 | | - mode: u=rwx,go=rx |
317 | | - - src: opennebula-ovs.service.jinja |
318 | | - dest: /etc/systemd/system/opennebula-ovs.service |
319 | | - mode: u=rw,go=r |
320 | | - register: template |
321 | | - |
322 | | - - name: Switch to OVS networking |
323 | | - ansible.builtin.systemd_service: |
324 | | - daemon_reload: "{{ item.daemon_reload | d(omit) }}" |
325 | | - name: "{{ item.name | d(omit) }}" |
326 | | - state: "{{ item.state | d(omit) }}" |
327 | | - enabled: "{{ item.enabled | d(omit) }}" |
328 | | - loop: |
329 | | - - daemon_reload: "{{ _changed }}" |
330 | | - - name: opennebula-ovs.service |
331 | | - state: "{{ 'restarted' if _changed else 'started' }}" |
332 | | - enabled: true |
333 | | - vars: |
334 | | - _changed: "{{ template is changed }}" |
| 5 | +- ansible.builtin.import_tasks: |
| 6 | + file: "{{ role_path }}/tasks/vhost.yml" |
0 commit comments