blob: faeeeff49eb32736cc5c1f17f1eebf34130a7ba0 [file] [log] [blame]
Mohammed Naser46e15522022-03-19 16:07:44 -04001# Copyright (c) 2022 VEXXHOST, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15- name: Generate workspace for Atmosphere
16 hosts: localhost
17 gather_facts: false
18 tasks:
19 - name: Create folders for workspace
20 ansible.builtin.file:
21 path: "{{ workspace_path }}/{{ item }}"
22 state: directory
23 loop:
24 - group_vars
25 - group_vars/all
26 - group_vars/controllers
27 - group_vars/cephs
28 - group_vars/computes
29 - host_vars
30
31- name: Generate Ceph control plane configuration for workspace
32 hosts: localhost
33 gather_facts: false
34 vars:
35 _ceph_path: "{{ workspace_path }}/group_vars/all/ceph.yml"
36 # Input variables
37 ceph_fsid: "{{ lookup('password', '/dev/null chars=ascii_letters,digits') | to_uuid }}"
38 ceph_public_network: 10.96.240.0/24
39 tasks:
40 - name: Ensure the Ceph control plane configuration file exists
41 ansible.builtin.file:
42 path: "{{ _ceph_path }}"
43 state: touch
44
45 - name: Load the current Ceph control plane configuration into a variable
46 ansible.builtin.include_vars:
47 file: "{{ _ceph_path }}"
48 name: ceph
49
50 - name: Generate Ceph control plane values for missing variables
51 ansible.builtin.set_fact:
52 ceph: "{{ ceph | default({}) | combine({item.key: item.value}) }}"
53 # NOTE(mnaser): We don't want to override existing Ceph configurations,
54 # so we generate a stub one if and only if it doesn't exist
55 when: item.key not in ceph
56 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
57 # doing this using `with_fileglob` or `with_filetree`
58 with_dict:
59 ceph_mon_fsid: "{{ ceph_fsid }}"
60 ceph_mon_public_network: "{{ ceph_public_network }}"
61
62 - name: Write new Ceph control plane configuration file to disk
63 ansible.builtin.copy:
64 content: "{{ ceph | to_nice_yaml(indent=2, width=180) }}"
65 dest: "{{ _ceph_path }}"
66
67- name: Generate Ceph OSD configuration for workspace
68 hosts: localhost
69 gather_facts: false
70 vars:
71 _ceph_osd_path: "{{ workspace_path }}/group_vars/cephs/osds.yml"
72 tasks:
73 - name: Ensure the Ceph OSDs configuration file exists
74 ansible.builtin.file:
75 path: "{{ _ceph_osd_path }}"
76 state: touch
77
78 - name: Load the current Ceph OSDs configuration into a variable
79 ansible.builtin.include_vars:
80 file: "{{ _ceph_osd_path }}"
81 name: ceph_osd
82
83 - name: Generate Ceph OSDs values for missing variables
84 ansible.builtin.set_fact:
85 ceph_osd: "{{ ceph_osd | default({}) | combine({item.key: item.value}) }}"
86 # NOTE(mnaser): We don't want to override existing Ceph configurations,
87 # so we generate a stub one if and only if it doesn't exist
88 when: item.key not in ceph_osd
89 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
90 # doing this using `with_fileglob` or `with_filetree`
91 with_dict:
92 ceph_osd_devices:
93 - /dev/vdb
94 - /dev/vdc
95 - /dev/vdd
96
97 - name: Write new Ceph OSDs configuration file to disk
98 ansible.builtin.copy:
99 content: "{{ ceph_osd | to_nice_yaml(indent=2, width=180) }}"
100 dest: "{{ _ceph_osd_path }}"
101
102- name: Generate Kubernetes configuration for workspace
103 hosts: localhost
104 gather_facts: false
105 vars:
106 _kubernetes_path: "{{ workspace_path }}/group_vars/all/kubernetes.yml"
107 tasks:
108 - name: Ensure the Kubernetes configuration file exists
109 ansible.builtin.file:
110 path: "{{ _kubernetes_path }}"
111 state: touch
112
113 - name: Load the current Kubernetes configuration into a variable
114 ansible.builtin.include_vars:
115 file: "{{ _kubernetes_path }}"
116 name: kubernetes
117
118 - name: Generate Kubernetes values for missing variables
119 ansible.builtin.set_fact:
120 kubernetes: "{{ kubernetes | default({}) | combine({item.key: item.value}) }}"
121 # NOTE(mnaser): We don't want to override existing Ceph configurations,
122 # so we generate a stub one if and only if it doesn't exist
123 when: item.key not in kubernetes
124 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
125 # doing this using `with_fileglob` or `with_filetree`
126 with_dict:
127 kubernetes_hostname: 10.96.240.10
128 kubernetes_keepalived_vrid: 42
Mohammed Naser46e15522022-03-19 16:07:44 -0400129 kubernetes_keepalived_vip: 10.96.240.10
130
131 - name: Write new Kubernetes configuration file to disk
132 ansible.builtin.copy:
133 content: "{{ kubernetes | to_nice_yaml(indent=2, width=180) }}"
134 dest: "{{ _kubernetes_path }}"
135
okozachenko85a31332022-04-11 23:34:30 +1000136- name: Generate Keepalived configuration for workspace
137 hosts: localhost
138 gather_facts: false
139 vars:
140 _keepalived_path: "{{ workspace_path }}/group_vars/all/keepalived.yml"
141 tasks:
142 - name: Ensure the Keeaplived configuration file exists
143 ansible.builtin.file:
144 path: "{{ _keepalived_path }}"
145 state: touch
146
147 - name: Load the current Keepalived configuration into a variable
148 ansible.builtin.include_vars:
149 file: "{{ _keepalived_path }}"
150 name: keepalived
151
152 - name: Generate Keepalived values for missing variables
153 ansible.builtin.set_fact:
154 keepalived: "{{ keepalived | default({}) | combine({item.key: item.value}) }}"
155 # NOTE(mnaser): We don't want to override existing Keepalived configurations,
156 # so we generate a stub one if and only if it doesn't exist
157 when: item.key not in keepalived
158 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
159 # doing this using `with_fileglob` or `with_filetree`
160 with_dict:
okozachenko8a516962022-04-22 23:31:20 +1000161 keepalived_interface: br-ex
okozachenko85a31332022-04-11 23:34:30 +1000162 keepalived_vip: 10.96.250.10
163
164 - name: Write new Keepalived configuration file to disk
165 ansible.builtin.copy:
166 content: "{{ keepalived | to_nice_yaml(indent=2, width=180) }}"
167 dest: "{{ _keepalived_path }}"
168
Mohammed Naser46e15522022-03-19 16:07:44 -0400169- name: Generate endpoints for workspace
170 hosts: localhost
Mohammed Naser46e15522022-03-19 16:07:44 -0400171 vars:
172 _endpoints_path: "{{ workspace_path }}/group_vars/all/endpoints.yml"
173 # Input variables
174 region_name: RegionOne
175 domain_name: vexxhost.cloud
176 tasks:
177 - name: Ensure the endpoints file exists
178 ansible.builtin.file:
179 path: "{{ _endpoints_path }}"
180 state: touch
Mohammed Naserf3a14a32022-09-19 15:15:39 -0400181
Mohammed Naser46e15522022-03-19 16:07:44 -0400182 - name: Load the current endpoints into a variable
183 ansible.builtin.include_vars:
184 file: "{{ _endpoints_path }}"
185 name: endpoints
186
187 - name: Generate endpoint skeleton for missing variables
188 ansible.builtin.set_fact:
189 endpoints: |
190 {{
191 endpoints |
192 default({}) |
193 combine({item: default_map[item]})
194 }}
195 # NOTE(mnaser): We don't want to override existing endpoints, so we generate
196 # a stub one if and only if it doesn't exist
197 when: item not in endpoints
198 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
199 # doing this using `with_fileglob` or `with_filetree`
200 with_lines: >
201 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
202 xargs grep undef |
203 egrep '(_host|region_name)' |
204 cut -d':' -f2
205 # NOTE(mnaser): We use these variables to generate map of service name to
206 # service type in order to generate the URLs
207 vars:
208 default_map:
Oleksandr Kozachenkob0093492023-09-06 21:43:47 +0200209 keycloak_host: "keycloak.{{ domain_name }}"
Mohammed Naser91e2fa02024-02-23 01:46:39 -0500210 kube_prometheus_stack_prometheus_host: "prometheus.{{ domain_name }}"
211 kube_prometheus_stack_alertmanager_host: "alertmanager.{{ domain_name }}"
Mohammed Nasercc149682023-04-13 21:26:30 +0000212 kube_prometheus_stack_grafana_host: "grafana.{{ domain_name }}"
Mohammed Naser46e15522022-03-19 16:07:44 -0400213 openstack_helm_endpoints_region_name: "{{ region_name }}"
okozachenko43771bd2022-04-30 01:22:46 +1000214 openstack_helm_endpoints_barbican_api_host: "key-manager.{{ domain_name }}"
Mohammed Naser46e15522022-03-19 16:07:44 -0400215 openstack_helm_endpoints_cinder_api_host: "volume.{{ domain_name }}"
216 openstack_helm_endpoints_designate_api_host: "dns.{{ domain_name }}"
217 openstack_helm_endpoints_glance_api_host: "image.{{ domain_name }}"
218 openstack_helm_endpoints_heat_api_host: "orchestration.{{ domain_name }}"
219 openstack_helm_endpoints_heat_cfn_api_host: "cloudformation.{{ domain_name }}"
220 openstack_helm_endpoints_horizon_api_host: "dashboard.{{ domain_name }}"
221 openstack_helm_endpoints_ironic_api_host: "baremetal.{{ domain_name }}"
222 openstack_helm_endpoints_keystone_api_host: "identity.{{ domain_name }}"
223 openstack_helm_endpoints_neutron_api_host: "network.{{ domain_name }}"
224 openstack_helm_endpoints_nova_api_host: "compute.{{ domain_name }}"
225 openstack_helm_endpoints_nova_novnc_host: "vnc.{{ domain_name }}"
226 openstack_helm_endpoints_octavia_api_host: "load-balancer.{{ domain_name }}"
227 openstack_helm_endpoints_placement_api_host: "placement.{{ domain_name }}"
Mohammed Naser096ade02022-12-15 09:53:33 -0500228 openstack_helm_endpoints_magnum_api_host: "container-infra.{{ domain_name }}"
229 openstack_helm_endpoints_magnum_registry_host: "container-infra-registry.{{ domain_name }}"
Mohammed Naser92614e92023-02-10 05:57:17 +0000230 openstack_helm_endpoints_rgw_host: "object-store.{{ domain_name }}"
okozachenko1203f916c0c2023-03-23 21:13:27 +1100231 openstack_helm_endpoints_manila_api_host: "share.{{ domain_name }}"
Mohammed Naser46e15522022-03-19 16:07:44 -0400232
233 - name: Write new endpoints file to disk
234 ansible.builtin.copy:
235 content: "{{ endpoints | to_nice_yaml(indent=2, width=180) }}"
236 dest: "{{ _endpoints_path }}"
237
238 - name: Ensure the endpoints file exists
239 ansible.builtin.file:
240 path: "{{ _endpoints_path }}"
241 state: touch
242
243- name: Generate Neutron configuration for workspace
244 hosts: localhost
245 gather_facts: false
246 vars:
247 _neutron_path: "{{ workspace_path }}/group_vars/all/neutron.yml"
248 # Input variables
249 tasks:
250 - name: Ensure the Neutron configuration file exists
251 ansible.builtin.file:
252 path: "{{ _neutron_path }}"
253 state: touch
254
255 - name: Load the current Neutron configuration into a variable
256 ansible.builtin.include_vars:
257 file: "{{ _neutron_path }}"
258 name: neutron
259
260 - name: Generate Neutron values for missing variables
261 ansible.builtin.set_fact:
262 neutron: "{{ neutron | default({}) | combine({item.key: item.value}) }}"
263 # NOTE(mnaser): We don't want to override existing Ceph configurations,
264 # so we generate a stub one if and only if it doesn't exist
265 when: item.key not in neutron
Mohammed Naser46e15522022-03-19 16:07:44 -0400266 with_dict:
Mohammed Naser2145fc32023-01-29 23:23:03 +0000267 neutron_networks:
okozachenko45fd72c2022-04-15 14:36:46 +1000268 - name: public
269 external: true
270 shared: true
271 mtu_size: 1500
272 port_security_enabled: true
273 provider_network_type: flat
274 provider_physical_network: external
275 subnets:
276 - name: public-subnet
277 cidr: 10.96.250.0/24
okozachenko87131922022-04-09 01:04:53 +1000278 gateway_ip: 10.96.250.10
okozachenko45fd72c2022-04-15 14:36:46 +1000279 allocation_pool_start: 10.96.250.200
280 allocation_pool_end: 10.96.250.220
okozachenko45fd72c2022-04-15 14:36:46 +1000281 enable_dhcp: true
Mohammed Naser46e15522022-03-19 16:07:44 -0400282
283 - name: Write new Neutron configuration file to disk
284 ansible.builtin.copy:
285 content: "{{ neutron | to_nice_yaml(indent=2, width=180) }}"
286 dest: "{{ _neutron_path }}"
287
okozachenko45fd72c2022-04-15 14:36:46 +1000288- name: Generate Nova configuration for workspace
289 hosts: localhost
290 gather_facts: false
291 vars:
292 _nova_path: "{{ workspace_path }}/group_vars/all/nova.yml"
293 # Input variables
294 tasks:
295 - name: Ensure the Nova configuration file exists
296 ansible.builtin.file:
297 path: "{{ _nova_path }}"
298 state: touch
299
300 - name: Load the current Nova configuration into a variable
301 ansible.builtin.include_vars:
302 file: "{{ _nova_path }}"
303 name: nova
304
305 - name: Generate Nova values for missing variables
306 ansible.builtin.set_fact:
307 nova: "{{ nova | default({}) | combine({item.key: item.value}) }}"
308 # NOTE(mnaser): We don't want to override existing Nova configurations,
309 # so we generate a stub one if and only if it doesn't exist
310 when: item.key not in nova
311 with_dict:
Mohammed Naser2145fc32023-01-29 23:23:03 +0000312 nova_flavors:
okozachenko45fd72c2022-04-15 14:36:46 +1000313 - name: m1.tiny
314 ram: 512
315 disk: 1
316 vcpus: 1
317 - name: m1.small
318 ram: 2048
319 disk: 20
320 vcpus: 1
321 - name: "m1.medium"
322 ram: 4096
323 disk: 40
324 vcpus: 2
325 - name: "m1.large"
326 ram: 8192
327 disk: 80
328 vcpus: 4
329 - name: "m1.xlarge"
330 ram: 16384
331 disk: 160
332 vcpus: 8
333
334 - name: Write new Nova configuration file to disk
335 ansible.builtin.copy:
336 content: "{{ nova | to_nice_yaml(indent=2, width=180) }}"
337 dest: "{{ _nova_path }}"
338
Mohammed Naser46e15522022-03-19 16:07:44 -0400339- name: Generate secrets for workspace
340 hosts: localhost
341 gather_facts: false
342 vars:
343 secrets_path: "{{ workspace_path }}/group_vars/all/secrets.yml"
344 tasks:
345 - name: Ensure the secrets file exists
346 ansible.builtin.file:
347 path: "{{ secrets_path }}"
348 state: touch
349
350 - name: Load the current secrets into a variable
351 ansible.builtin.include_vars:
352 file: "{{ secrets_path }}"
353 name: secrets
354
355 - name: Generate secrets for missing variables
356 ansible.builtin.set_fact:
357 secrets: "{{ secrets | default({}) | combine({item: lookup('password', '/dev/null chars=ascii_lowercase,ascii_uppercase,digits length=32')}) }}"
358 # NOTE(mnaser): We don't want to override existing secrets, so we generate
359 # a new one if and only if it doesn't exist
360 when: item not in secrets
361 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
362 # doing this using `with_fileglob` or `with_filetree`
363 with_lines: >
364 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
Oleksandr Kozachenkob0093492023-09-06 21:43:47 +0200365 xargs egrep '(undef|^# \w+_keycloak_client_secret)' |
okozachenko43771bd2022-04-30 01:22:46 +1000366 egrep -v '(_host|region_name|_ssh_key|_vip|_interface|_kek)' |
Oleksandr Kozachenkob0093492023-09-06 21:43:47 +0200367 cut -d':' -f2 |
368 sed 's/^# //'
okozachenko43771bd2022-04-30 01:22:46 +1000369
370 - name: Generate base64 encoded secrets
371 ansible.builtin.set_fact:
372 secrets: "{{ secrets | default({}) | combine({item: lookup('password', '/dev/null chars=ascii_lowercase,ascii_uppercase,digits length=32') | b64encode}) }}"
373 # NOTE(mnaser): We don't want to override existing secrets, so we generate
374 # a new one if and only if it doesn't exist
375 when: item not in secrets
376 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
377 # doing this using `with_fileglob` or `with_filetree`
378 with_lines: >
379 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
380 xargs grep undef |
381 egrep '(_kek)' |
Mohammed Naser46e15522022-03-19 16:07:44 -0400382 cut -d':' -f2
383
Mohammed Naser01338322022-03-22 14:51:31 -0400384 - name: Generate temporary files for generating keys for missing variables
385 ansible.builtin.tempfile:
386 state: file
387 prefix: "{{ item }}"
388 register: _ssh_key_file
389 # NOTE(mnaser): We don't want to override existing secrets, so we generate
390 # a new one if and only if it doesn't exist
391 when: item not in secrets
392 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
393 # doing this using `with_fileglob` or `with_filetree`
394 with_lines: >
395 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
396 xargs grep undef |
397 egrep '(_ssh_key)' |
398 cut -d':' -f2
399
400 - name: Generate SSH keys for missing variables
Oleksandr Kdc273472023-12-20 14:09:12 +0100401 when: item.path is defined
Mohammed Naser01338322022-03-22 14:51:31 -0400402 community.crypto.openssh_keypair:
403 path: "{{ item.path }}"
404 regenerate: full_idempotence
405 register: _openssh_keypair
406 loop: "{{ _ssh_key_file.results }}"
407 loop_control:
408 label: "{{ item.item }}"
409
410 - name: Set values for SSH keys
Oleksandr Kdc273472023-12-20 14:09:12 +0100411 when: item.path is defined
Mohammed Naser01338322022-03-22 14:51:31 -0400412 ansible.builtin.set_fact:
413 secrets: "{{ secrets | default({}) | combine({item.item: lookup('file', item.path)}) }}"
414 loop: "{{ _ssh_key_file.results }}"
415 loop_control:
416 label: "{{ item.item }}"
417
418 - name: Delete the temporary files generated for SSH keys
Oleksandr Kdc273472023-12-20 14:09:12 +0100419 when: item.path is defined
Mohammed Naser01338322022-03-22 14:51:31 -0400420 ansible.builtin.file:
421 path: "{{ item.path }}"
422 state: absent
423 loop: "{{ _ssh_key_file.results }}"
424 loop_control:
425 label: "{{ item.item }}"
426
Mohammed Naser46e15522022-03-19 16:07:44 -0400427 - name: Write new secrets file to disk
428 ansible.builtin.copy:
429 content: "{{ secrets | to_nice_yaml }}"
430 dest: "{{ secrets_path }}"
431
432 - name: Encrypt secrets file with Vault password
433 ansible.builtin.shell:
434 ansible-vault encrypt --vault-password-file {{ secrets_vault_password_file }} {{ secrets_path }}
435 when:
okozachenko45fd72c2022-04-15 14:36:46 +1000436 - secrets_vault_password_file is defined