blob: f73de6a60b7fdc4ba8081922a255d4e1406c2bca [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 }}"
228 openstack_helm_endpoints_senlin_api_host: "clustering.{{ domain_name }}"
Mohammed Naser096ade02022-12-15 09:53:33 -0500229 openstack_helm_endpoints_magnum_api_host: "container-infra.{{ domain_name }}"
230 openstack_helm_endpoints_magnum_registry_host: "container-infra-registry.{{ domain_name }}"
Mohammed Naser92614e92023-02-10 05:57:17 +0000231 openstack_helm_endpoints_rgw_host: "object-store.{{ domain_name }}"
okozachenko1203f916c0c2023-03-23 21:13:27 +1100232 openstack_helm_endpoints_manila_api_host: "share.{{ domain_name }}"
Mohammed Naser46e15522022-03-19 16:07:44 -0400233
234 - name: Write new endpoints file to disk
235 ansible.builtin.copy:
236 content: "{{ endpoints | to_nice_yaml(indent=2, width=180) }}"
237 dest: "{{ _endpoints_path }}"
238
239 - name: Ensure the endpoints file exists
240 ansible.builtin.file:
241 path: "{{ _endpoints_path }}"
242 state: touch
243
244- name: Generate Neutron configuration for workspace
245 hosts: localhost
246 gather_facts: false
247 vars:
248 _neutron_path: "{{ workspace_path }}/group_vars/all/neutron.yml"
249 # Input variables
250 tasks:
251 - name: Ensure the Neutron configuration file exists
252 ansible.builtin.file:
253 path: "{{ _neutron_path }}"
254 state: touch
255
256 - name: Load the current Neutron configuration into a variable
257 ansible.builtin.include_vars:
258 file: "{{ _neutron_path }}"
259 name: neutron
260
261 - name: Generate Neutron values for missing variables
262 ansible.builtin.set_fact:
263 neutron: "{{ neutron | default({}) | combine({item.key: item.value}) }}"
264 # NOTE(mnaser): We don't want to override existing Ceph configurations,
265 # so we generate a stub one if and only if it doesn't exist
266 when: item.key not in neutron
Mohammed Naser46e15522022-03-19 16:07:44 -0400267 with_dict:
Mohammed Naser2145fc32023-01-29 23:23:03 +0000268 neutron_networks:
okozachenko45fd72c2022-04-15 14:36:46 +1000269 - name: public
270 external: true
271 shared: true
272 mtu_size: 1500
273 port_security_enabled: true
274 provider_network_type: flat
275 provider_physical_network: external
276 subnets:
277 - name: public-subnet
278 cidr: 10.96.250.0/24
okozachenko87131922022-04-09 01:04:53 +1000279 gateway_ip: 10.96.250.10
okozachenko45fd72c2022-04-15 14:36:46 +1000280 allocation_pool_start: 10.96.250.200
281 allocation_pool_end: 10.96.250.220
okozachenko45fd72c2022-04-15 14:36:46 +1000282 enable_dhcp: true
Mohammed Naser46e15522022-03-19 16:07:44 -0400283
284 - name: Write new Neutron configuration file to disk
285 ansible.builtin.copy:
286 content: "{{ neutron | to_nice_yaml(indent=2, width=180) }}"
287 dest: "{{ _neutron_path }}"
288
okozachenko45fd72c2022-04-15 14:36:46 +1000289- name: Generate Nova configuration for workspace
290 hosts: localhost
291 gather_facts: false
292 vars:
293 _nova_path: "{{ workspace_path }}/group_vars/all/nova.yml"
294 # Input variables
295 tasks:
296 - name: Ensure the Nova configuration file exists
297 ansible.builtin.file:
298 path: "{{ _nova_path }}"
299 state: touch
300
301 - name: Load the current Nova configuration into a variable
302 ansible.builtin.include_vars:
303 file: "{{ _nova_path }}"
304 name: nova
305
306 - name: Generate Nova values for missing variables
307 ansible.builtin.set_fact:
308 nova: "{{ nova | default({}) | combine({item.key: item.value}) }}"
309 # NOTE(mnaser): We don't want to override existing Nova configurations,
310 # so we generate a stub one if and only if it doesn't exist
311 when: item.key not in nova
312 with_dict:
Mohammed Naser2145fc32023-01-29 23:23:03 +0000313 nova_flavors:
okozachenko45fd72c2022-04-15 14:36:46 +1000314 - name: m1.tiny
315 ram: 512
316 disk: 1
317 vcpus: 1
318 - name: m1.small
319 ram: 2048
320 disk: 20
321 vcpus: 1
322 - name: "m1.medium"
323 ram: 4096
324 disk: 40
325 vcpus: 2
326 - name: "m1.large"
327 ram: 8192
328 disk: 80
329 vcpus: 4
330 - name: "m1.xlarge"
331 ram: 16384
332 disk: 160
333 vcpus: 8
334
335 - name: Write new Nova configuration file to disk
336 ansible.builtin.copy:
337 content: "{{ nova | to_nice_yaml(indent=2, width=180) }}"
338 dest: "{{ _nova_path }}"
339
Mohammed Naser46e15522022-03-19 16:07:44 -0400340- name: Generate secrets for workspace
341 hosts: localhost
342 gather_facts: false
343 vars:
344 secrets_path: "{{ workspace_path }}/group_vars/all/secrets.yml"
345 tasks:
346 - name: Ensure the secrets file exists
347 ansible.builtin.file:
348 path: "{{ secrets_path }}"
349 state: touch
350
351 - name: Load the current secrets into a variable
352 ansible.builtin.include_vars:
353 file: "{{ secrets_path }}"
354 name: secrets
355
356 - name: Generate secrets for missing variables
357 ansible.builtin.set_fact:
358 secrets: "{{ secrets | default({}) | combine({item: lookup('password', '/dev/null chars=ascii_lowercase,ascii_uppercase,digits length=32')}) }}"
359 # NOTE(mnaser): We don't want to override existing secrets, so we generate
360 # a new one if and only if it doesn't exist
361 when: item not in secrets
362 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
363 # doing this using `with_fileglob` or `with_filetree`
364 with_lines: >
365 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
Oleksandr Kozachenkob0093492023-09-06 21:43:47 +0200366 xargs egrep '(undef|^# \w+_keycloak_client_secret)' |
okozachenko43771bd2022-04-30 01:22:46 +1000367 egrep -v '(_host|region_name|_ssh_key|_vip|_interface|_kek)' |
Oleksandr Kozachenkob0093492023-09-06 21:43:47 +0200368 cut -d':' -f2 |
369 sed 's/^# //'
okozachenko43771bd2022-04-30 01:22:46 +1000370
371 - name: Generate base64 encoded secrets
372 ansible.builtin.set_fact:
373 secrets: "{{ secrets | default({}) | combine({item: lookup('password', '/dev/null chars=ascii_lowercase,ascii_uppercase,digits length=32') | b64encode}) }}"
374 # NOTE(mnaser): We don't want to override existing secrets, so we generate
375 # a new one if and only if it doesn't exist
376 when: item not in secrets
377 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
378 # doing this using `with_fileglob` or `with_filetree`
379 with_lines: >
380 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
381 xargs grep undef |
382 egrep '(_kek)' |
Mohammed Naser46e15522022-03-19 16:07:44 -0400383 cut -d':' -f2
384
Mohammed Naser01338322022-03-22 14:51:31 -0400385 - name: Generate temporary files for generating keys for missing variables
386 ansible.builtin.tempfile:
387 state: file
388 prefix: "{{ item }}"
389 register: _ssh_key_file
390 # NOTE(mnaser): We don't want to override existing secrets, so we generate
391 # a new one if and only if it doesn't exist
392 when: item not in secrets
393 # NOTE(mnaser): This is absolutely hideous but there's no clean way of
394 # doing this using `with_fileglob` or `with_filetree`
395 with_lines: >
396 ls {{ playbook_dir }}/../roles/*/defaults/main.yml |
397 xargs grep undef |
398 egrep '(_ssh_key)' |
399 cut -d':' -f2
400
401 - name: Generate SSH keys for missing variables
Oleksandr Kdc273472023-12-20 14:09:12 +0100402 when: item.path is defined
Mohammed Naser01338322022-03-22 14:51:31 -0400403 community.crypto.openssh_keypair:
404 path: "{{ item.path }}"
405 regenerate: full_idempotence
406 register: _openssh_keypair
407 loop: "{{ _ssh_key_file.results }}"
408 loop_control:
409 label: "{{ item.item }}"
410
411 - name: Set values for SSH keys
Oleksandr Kdc273472023-12-20 14:09:12 +0100412 when: item.path is defined
Mohammed Naser01338322022-03-22 14:51:31 -0400413 ansible.builtin.set_fact:
414 secrets: "{{ secrets | default({}) | combine({item.item: lookup('file', item.path)}) }}"
415 loop: "{{ _ssh_key_file.results }}"
416 loop_control:
417 label: "{{ item.item }}"
418
419 - name: Delete the temporary files generated for SSH keys
Oleksandr Kdc273472023-12-20 14:09:12 +0100420 when: item.path is defined
Mohammed Naser01338322022-03-22 14:51:31 -0400421 ansible.builtin.file:
422 path: "{{ item.path }}"
423 state: absent
424 loop: "{{ _ssh_key_file.results }}"
425 loop_control:
426 label: "{{ item.item }}"
427
Mohammed Naser46e15522022-03-19 16:07:44 -0400428 - name: Write new secrets file to disk
429 ansible.builtin.copy:
430 content: "{{ secrets | to_nice_yaml }}"
431 dest: "{{ secrets_path }}"
432
433 - name: Encrypt secrets file with Vault password
434 ansible.builtin.shell:
435 ansible-vault encrypt --vault-password-file {{ secrets_vault_password_file }} {{ secrets_path }}
436 when:
okozachenko45fd72c2022-04-15 14:36:46 +1000437 - secrets_vault_password_file is defined