cloudfall 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. cloudfall/__init__.py +19 -0
  2. cloudfall/__main__.py +5 -0
  3. cloudfall/_bundled/schemas/v1/alert-rule.schema.json +63 -0
  4. cloudfall/_bundled/schemas/v1/application.schema.json +60 -0
  5. cloudfall/_bundled/schemas/v1/artifact.schema.json +71 -0
  6. cloudfall/_bundled/schemas/v1/backup-receipt.schema.json +58 -0
  7. cloudfall/_bundled/schemas/v1/common.schema.json +115 -0
  8. cloudfall/_bundled/schemas/v1/component.schema.json +234 -0
  9. cloudfall/_bundled/schemas/v1/deployment-receipt.schema.json +53 -0
  10. cloudfall/_bundled/schemas/v1/domain.schema.json +208 -0
  11. cloudfall/_bundled/schemas/v1/environment-receipt.schema.json +55 -0
  12. cloudfall/_bundled/schemas/v1/logging-stack.schema.json +473 -0
  13. cloudfall/_bundled/schemas/v1/observed-domain.schema.json +158 -0
  14. cloudfall/_bundled/schemas/v1/observed-server.schema.json +627 -0
  15. cloudfall/_bundled/schemas/v1/operator-policy.schema.json +97 -0
  16. cloudfall/_bundled/schemas/v1/operator-proposal.schema.json +253 -0
  17. cloudfall/_bundled/schemas/v1/release-receipt.schema.json +66 -0
  18. cloudfall/_bundled/schemas/v1/server-type.schema.json +289 -0
  19. cloudfall/_bundled/schemas/v1/server.schema.json +146 -0
  20. cloudfall/_bundled/schemas/v1/service.schema.json +222 -0
  21. cloudfall/_bundled/schemas/v1/ssh-public-key.schema.json +55 -0
  22. cloudfall/agent_tools.py +868 -0
  23. cloudfall/arguments.py +92 -0
  24. cloudfall/audit.py +905 -0
  25. cloudfall/authoring.py +341 -0
  26. cloudfall/cli.py +1748 -0
  27. cloudfall/commands.py +257 -0
  28. cloudfall/cutover.py +370 -0
  29. cloudfall/dashboard.py +407 -0
  30. cloudfall/dashboard_server.py +201 -0
  31. cloudfall/domain.py +1157 -0
  32. cloudfall/importer.py +906 -0
  33. cloudfall/inventory.py +2116 -0
  34. cloudfall/lifecycle.py +874 -0
  35. cloudfall/mcp_server.py +704 -0
  36. cloudfall/migrate.py +730 -0
  37. cloudfall/observation.py +143 -0
  38. cloudfall/operations.py +1228 -0
  39. cloudfall/operator.py +1099 -0
  40. cloudfall/project.py +841 -0
  41. cloudfall/py.typed +0 -0
  42. cloudfall/render_api.py +338 -0
  43. cloudfall/resources.py +67 -0
  44. cloudfall/secrets.py +262 -0
  45. cloudfall/service_evidence.py +659 -0
  46. cloudfall/validation.py +1340 -0
  47. cloudfall-0.2.0.dist-info/METADATA +408 -0
  48. cloudfall-0.2.0.dist-info/RECORD +165 -0
  49. cloudfall-0.2.0.dist-info/WHEEL +4 -0
  50. cloudfall-0.2.0.dist-info/entry_points.txt +4 -0
  51. cloudfall-0.2.0.dist-info/licenses/LICENSE +661 -0
  52. cloudfall_engine/__init__.py +5 -0
  53. cloudfall_engine/__main__.py +5 -0
  54. cloudfall_engine/_bundled/ansible/ansible.cfg +7 -0
  55. cloudfall_engine/_bundled/ansible/playbooks/backup.yml +86 -0
  56. cloudfall_engine/_bundled/ansible/playbooks/baseline.yml +35 -0
  57. cloudfall_engine/_bundled/ansible/playbooks/bootstrap.yml +24 -0
  58. cloudfall_engine/_bundled/ansible/playbooks/data.yml +28 -0
  59. cloudfall_engine/_bundled/ansible/playbooks/deploy.yml +35 -0
  60. cloudfall_engine/_bundled/ansible/playbooks/domains.yml +21 -0
  61. cloudfall_engine/_bundled/ansible/playbooks/health.yml +31 -0
  62. cloudfall_engine/_bundled/ansible/playbooks/inspect.yml +15 -0
  63. cloudfall_engine/_bundled/ansible/playbooks/logging.yml +35 -0
  64. cloudfall_engine/_bundled/ansible/playbooks/restart.yml +31 -0
  65. cloudfall_engine/_bundled/ansible/playbooks/rollback.yml +33 -0
  66. cloudfall_engine/_bundled/ansible/playbooks/services.yml +37 -0
  67. cloudfall_engine/_bundled/ansible/playbooks/time.yml +9 -0
  68. cloudfall_engine/_bundled/ansible/roles/cloudfall_access/defaults/main.yml +2 -0
  69. cloudfall_engine/_bundled/ansible/roles/cloudfall_access/handlers/main.yml +5 -0
  70. cloudfall_engine/_bundled/ansible/roles/cloudfall_access/meta/argument_specs.yml +34 -0
  71. cloudfall_engine/_bundled/ansible/roles/cloudfall_access/meta/main.yml +13 -0
  72. cloudfall_engine/_bundled/ansible/roles/cloudfall_access/tasks/main.yml +59 -0
  73. cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/defaults/main.yml +11 -0
  74. cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/meta/argument_specs.yml +52 -0
  75. cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/meta/main.yml +13 -0
  76. cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/tasks/main.yml +99 -0
  77. cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/defaults/main.yml +15 -0
  78. cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/meta/argument_specs.yml +36 -0
  79. cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/meta/main.yml +13 -0
  80. cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/tasks/main.yml +201 -0
  81. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/defaults/main.yml +10 -0
  82. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/meta/argument_specs.yml +125 -0
  83. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/meta/main.yml +13 -0
  84. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/health.yml +3 -0
  85. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/health_gate.yml +37 -0
  86. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/main.yml +285 -0
  87. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/restart.yml +17 -0
  88. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/rollback.yml +52 -0
  89. cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/templates/component.service.j2 +24 -0
  90. cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/defaults/main.yml +2 -0
  91. cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/handlers/main.yml +5 -0
  92. cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/meta/argument_specs.yml +33 -0
  93. cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/meta/main.yml +13 -0
  94. cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/tasks/main.yml +51 -0
  95. cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/templates/nftables.conf.j2 +31 -0
  96. cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/defaults/main.yml +6 -0
  97. cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/meta/argument_specs.yml +24 -0
  98. cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/meta/main.yml +13 -0
  99. cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/tasks/main.yml +643 -0
  100. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/defaults/main.yml +6 -0
  101. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/handlers/main.yml +29 -0
  102. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/meta/argument_specs.yml +227 -0
  103. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/meta/main.yml +11 -0
  104. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/tasks/main.yml +487 -0
  105. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/alertmanager-defaults.j2 +2 -0
  106. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/alertmanager.yaml.j2 +33 -0
  107. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/grafana.ini.j2 +20 -0
  108. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/loki-datasource.yml.j2 +11 -0
  109. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/loki-systemd-override.conf.j2 +3 -0
  110. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/loki.yaml.j2 +49 -0
  111. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/nginx-loki-gateway.conf.j2 +45 -0
  112. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus-datasource.yml.j2 +11 -0
  113. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus-defaults.j2 +2 -0
  114. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus-rules.yaml.j2 +20 -0
  115. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus.yaml.j2 +24 -0
  116. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/defaults/main.yml +7 -0
  117. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/handlers/main.yml +6 -0
  118. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/meta/argument_specs.yml +122 -0
  119. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/meta/main.yml +11 -0
  120. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/tasks/main.yml +224 -0
  121. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/templates/alloy-systemd-override.conf.j2 +3 -0
  122. cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/templates/config.alloy.j2 +127 -0
  123. cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/defaults/main.yml +4 -0
  124. cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/handlers/main.yml +5 -0
  125. cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/meta/argument_specs.yml +69 -0
  126. cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/meta/main.yml +13 -0
  127. cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/tasks/main.yml +212 -0
  128. cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/templates/domain-site.conf.j2 +54 -0
  129. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/defaults/main.yml +6 -0
  130. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/handlers/main.yml +9 -0
  131. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/meta/argument_specs.yml +91 -0
  132. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/meta/main.yml +13 -0
  133. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/tasks/main.yml +295 -0
  134. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/backup.service.j2 +11 -0
  135. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/backup.sh.j2 +17 -0
  136. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/backup.timer.j2 +10 -0
  137. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/cloudfall.conf.j2 +3 -0
  138. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/restore-check.service.j2 +11 -0
  139. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/restore-check.sh.j2 +27 -0
  140. cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/restore-check.timer.j2 +10 -0
  141. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/defaults/main.yml +2 -0
  142. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/handlers/main.yml +6 -0
  143. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/meta/argument_specs.yml +68 -0
  144. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/meta/main.yml +13 -0
  145. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/tasks/main.yml +148 -0
  146. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/backup.service.j2 +11 -0
  147. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/backup.sh.j2 +14 -0
  148. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/backup.timer.j2 +10 -0
  149. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/cloudfall.conf.j2 +6 -0
  150. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/restore-check.service.j2 +11 -0
  151. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/restore-check.sh.j2 +15 -0
  152. cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/restore-check.timer.j2 +10 -0
  153. cloudfall_engine/_bundled/ansible/roles/cloudfall_time/defaults/main.yml +2 -0
  154. cloudfall_engine/_bundled/ansible/roles/cloudfall_time/meta/argument_specs.yml +10 -0
  155. cloudfall_engine/_bundled/ansible/roles/cloudfall_time/meta/main.yml +13 -0
  156. cloudfall_engine/_bundled/ansible/roles/cloudfall_time/tasks/main.yml +119 -0
  157. cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/defaults/main.yml +3 -0
  158. cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/meta/argument_specs.yml +8 -0
  159. cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/meta/main.yml +13 -0
  160. cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/tasks/main.yml +37 -0
  161. cloudfall_engine/ansible_inventory.py +253 -0
  162. cloudfall_engine/artifact.py +258 -0
  163. cloudfall_engine/cli.py +273 -0
  164. cloudfall_engine/playbook.py +175 -0
  165. cloudfall_engine/py.typed +0 -0
@@ -0,0 +1,487 @@
1
+ ---
2
+ - name: Validate logging backend target and migration guard
3
+ ansible.builtin.assert:
4
+ that:
5
+ - ansible_facts["distribution"] == "Debian"
6
+ - ansible_facts["service_mgr"] == "systemd"
7
+ - cloudfall_logging_backend_stack.backend.server == cloudfall_server_id
8
+ - cloudfall_logging_backend_stack.migration.mode == "parallel"
9
+ - cloudfall_logging_backend_stack.migration.preserveLegacyAgents | bool
10
+ - cloudfall_logging_backend_stack.backend.listenAddress == "127.0.0.1"
11
+ - cloudfall_logging_backend_stack.grafana.listenAddress == "127.0.0.1"
12
+ - >-
13
+ cloudfall_logging_backend_stack.metrics.backend.listenAddress
14
+ == "127.0.0.1"
15
+ fail_msg: >-
16
+ Logging deployment requires its declared Debian backend and the guarded
17
+ parallel migration mode
18
+
19
+ - name: Inspect pre-provisioned backend secret files
20
+ ansible.builtin.stat:
21
+ path: "{{ item }}"
22
+ follow: true
23
+ loop:
24
+ - "{{ cloudfall_logging_backend_stack.gateway.tls.certificatePath }}"
25
+ - "{{ cloudfall_logging_backend_stack.gateway.tls.keyPath }}"
26
+ - "{{ cloudfall_logging_backend_stack.gateway.tls.clientCaPath }}"
27
+ - "{{ cloudfall_logging_backend_stack.grafana.adminPasswordPath }}"
28
+ register: cloudfall_logging_backend_secret_files
29
+
30
+ - name: Require backend secret files before mutation
31
+ ansible.builtin.assert:
32
+ that:
33
+ - item.stat.exists
34
+ - item.stat.isreg
35
+ fail_msg: "Required logging secret file is missing: {{ item.item }}"
36
+ loop: "{{ cloudfall_logging_backend_secret_files.results }}"
37
+ loop_control:
38
+ label: "{{ item.item }}"
39
+
40
+ - name: Inspect backend private files
41
+ ansible.builtin.stat:
42
+ path: "{{ item }}"
43
+ follow: true
44
+ loop:
45
+ - "{{ cloudfall_logging_backend_stack.gateway.tls.keyPath }}"
46
+ - "{{ cloudfall_logging_backend_stack.grafana.adminPasswordPath }}"
47
+ register: cloudfall_logging_backend_private_files
48
+
49
+ - name: Reject world-readable backend private files
50
+ ansible.builtin.assert:
51
+ that:
52
+ - item.stat.mode is match('^0?[46][04]0$')
53
+ fail_msg: "Logging private file permissions are too broad: {{ item.item }}"
54
+ loop: "{{ cloudfall_logging_backend_private_files.results }}"
55
+ loop_control:
56
+ label: "{{ item.item }}"
57
+
58
+ - name: Install Grafana repository prerequisites
59
+ ansible.builtin.apt:
60
+ name:
61
+ - ca-certificates
62
+ - gnupg
63
+ - python3-debian
64
+ state: present
65
+ update_cache: true
66
+ cache_valid_time: 3600
67
+
68
+ - name: Create APT keyring directory
69
+ ansible.builtin.file:
70
+ path: /etc/apt/keyrings
71
+ state: directory
72
+ owner: root
73
+ group: root
74
+ mode: "0755"
75
+
76
+ - name: Install Grafana repository signing key
77
+ ansible.builtin.get_url:
78
+ url: "{{ cloudfall_logging_backend_grafana_repository_key_url }}"
79
+ dest: "{{ cloudfall_logging_backend_grafana_repository_key_path }}"
80
+ owner: root
81
+ group: root
82
+ mode: "0644"
83
+
84
+ - name: Configure stable Grafana package repository
85
+ ansible.builtin.deb822_repository:
86
+ name: grafana
87
+ types:
88
+ - deb
89
+ uris:
90
+ - "{{ cloudfall_logging_backend_grafana_repository_url }}"
91
+ suites:
92
+ - stable
93
+ components:
94
+ - main
95
+ signed_by: "{{ cloudfall_logging_backend_grafana_repository_key_path }}"
96
+ state: present
97
+ register: cloudfall_logging_backend_repository
98
+
99
+ # Not a handler: the refreshed index must exist before the pinned
100
+ # install below runs, and handlers only flush later.
101
+ - name: Refresh APT cache after repository changes # noqa: no-handler
102
+ ansible.builtin.apt:
103
+ update_cache: true
104
+ when: cloudfall_logging_backend_repository is changed
105
+
106
+ - name: Create Loki service group before package configuration
107
+ ansible.builtin.group:
108
+ name: loki
109
+ system: true
110
+ state: present
111
+
112
+ - name: Create Loki service account before package configuration
113
+ ansible.builtin.user:
114
+ name: loki
115
+ group: loki
116
+ shell: /usr/sbin/nologin
117
+ create_home: false
118
+ system: true
119
+ state: present
120
+
121
+ - name: Create Loki configuration directory before package configuration
122
+ ansible.builtin.file:
123
+ path: /etc/loki
124
+ state: directory
125
+ owner: root
126
+ group: loki
127
+ mode: "0750"
128
+
129
+ - name: Create Loki storage directories before package configuration
130
+ ansible.builtin.file:
131
+ path: "{{ item }}"
132
+ state: directory
133
+ owner: loki
134
+ group: loki
135
+ mode: "0750"
136
+ loop:
137
+ - "{{ cloudfall_logging_backend_stack.backend.storage.path }}"
138
+ - "{{ cloudfall_logging_backend_stack.backend.storage.path }}/chunks"
139
+ - "{{ cloudfall_logging_backend_stack.backend.storage.path }}/rules"
140
+ - "{{ cloudfall_logging_backend_stack.backend.storage.path }}/compactor"
141
+
142
+ - name: Create Loki systemd override directory before package configuration
143
+ ansible.builtin.file:
144
+ path: /etc/systemd/system/loki.service.d
145
+ state: directory
146
+ owner: root
147
+ group: root
148
+ mode: "0755"
149
+
150
+ - name: Install safe Loki configuration before package configuration
151
+ ansible.builtin.template:
152
+ src: loki.yaml.j2
153
+ dest: "/etc/loki/cloudfall-{{ cloudfall_logging_backend_stack.id }}.yaml"
154
+ owner: root
155
+ group: loki
156
+ mode: "0640"
157
+ notify: Restart Loki
158
+
159
+ - name: Install Loki systemd guard before package configuration
160
+ ansible.builtin.template:
161
+ src: loki-systemd-override.conf.j2
162
+ dest: /etc/systemd/system/loki.service.d/cloudfall.conf
163
+ owner: root
164
+ group: root
165
+ mode: "0644"
166
+ notify: Restart Loki
167
+
168
+ - name: Create Prometheus service group before package configuration
169
+ ansible.builtin.group:
170
+ name: prometheus
171
+ system: true
172
+ state: present
173
+
174
+ - name: Create Prometheus service account before package configuration
175
+ ansible.builtin.user:
176
+ name: prometheus
177
+ group: prometheus
178
+ shell: /usr/sbin/nologin
179
+ create_home: false
180
+ system: true
181
+ state: present
182
+
183
+ - name: Create Prometheus configuration directory before package configuration
184
+ ansible.builtin.file:
185
+ path: /etc/prometheus
186
+ state: directory
187
+ owner: root
188
+ group: prometheus
189
+ mode: "0750"
190
+
191
+ - name: Create Prometheus storage directory before package configuration
192
+ ansible.builtin.file:
193
+ path: "{{ cloudfall_logging_backend_stack.metrics.backend.storagePath }}"
194
+ state: directory
195
+ owner: prometheus
196
+ group: prometheus
197
+ mode: "0750"
198
+
199
+ - name: Install managed Prometheus configuration before package configuration
200
+ ansible.builtin.template:
201
+ src: prometheus.yaml.j2
202
+ dest: /etc/prometheus/cloudfall.yaml
203
+ owner: root
204
+ group: prometheus
205
+ mode: "0640"
206
+ notify: Restart Prometheus
207
+
208
+ - name: Install declared Prometheus alert rules before package configuration
209
+ ansible.builtin.template:
210
+ src: prometheus-rules.yaml.j2
211
+ dest: /etc/prometheus/cloudfall-rules.yaml
212
+ owner: root
213
+ group: prometheus
214
+ mode: "0640"
215
+ notify: Restart Prometheus
216
+
217
+ - name: Install managed Prometheus arguments before package configuration
218
+ ansible.builtin.template:
219
+ src: prometheus-defaults.j2
220
+ dest: /etc/default/prometheus
221
+ owner: root
222
+ group: root
223
+ mode: "0644"
224
+ notify: Restart Prometheus
225
+
226
+ - name: Inspect pre-provisioned SMTP credential files
227
+ ansible.builtin.stat:
228
+ path: "{{ item.email.authPasswordFile }}"
229
+ follow: true
230
+ loop: >-
231
+ {{
232
+ cloudfall_logging_backend_stack.alerting.receivers
233
+ | selectattr('email', 'defined')
234
+ | selectattr('email.authPasswordFile', 'defined')
235
+ | list
236
+ if 'alerting' in cloudfall_logging_backend_stack
237
+ else []
238
+ }}
239
+ loop_control:
240
+ label: "{{ item.id }}"
241
+ register: cloudfall_logging_backend_smtp_files
242
+
243
+ - name: Require SMTP credential files before mutation
244
+ ansible.builtin.assert:
245
+ that:
246
+ - item.stat.exists
247
+ - item.stat.isreg
248
+ fail_msg: "Required SMTP credential file is missing: {{ item.item.id }}"
249
+ loop: "{{ cloudfall_logging_backend_smtp_files.results | default([]) }}"
250
+ loop_control:
251
+ label: "{{ item.item.id }}"
252
+
253
+ - name: Install declared Alertmanager configuration before package configuration
254
+ ansible.builtin.template:
255
+ src: alertmanager.yaml.j2
256
+ dest: /etc/prometheus/cloudfall-alertmanager.yaml
257
+ owner: root
258
+ group: prometheus
259
+ mode: "0640"
260
+ when: "'alerting' in cloudfall_logging_backend_stack"
261
+ notify: Restart Alertmanager
262
+
263
+ - name: Install declared Alertmanager arguments before package configuration
264
+ ansible.builtin.template:
265
+ src: alertmanager-defaults.j2
266
+ dest: /etc/default/prometheus-alertmanager
267
+ owner: root
268
+ group: root
269
+ mode: "0644"
270
+ when: "'alerting' in cloudfall_logging_backend_stack"
271
+ notify: Restart Alertmanager
272
+
273
+ - name: Install the pinned Alertmanager package
274
+ ansible.builtin.apt:
275
+ name: >-
276
+ {{
277
+ 'prometheus-alertmanager=' ~
278
+ cloudfall_logging_backend_stack.alerting.alertmanager.packageVersion
279
+ if 'packageVersion'
280
+ in cloudfall_logging_backend_stack.alerting.alertmanager
281
+ else 'prometheus-alertmanager'
282
+ }}
283
+ state: present
284
+ update_cache: true
285
+ cache_valid_time: 3600
286
+ policy_rc_d: 101
287
+ when: "'alerting' in cloudfall_logging_backend_stack"
288
+
289
+ - name: Install pinned logging backend packages
290
+ ansible.builtin.apt:
291
+ name:
292
+ - "loki={{ cloudfall_logging_backend_stack.software.lokiPackageVersion }}"
293
+ - "grafana={{ cloudfall_logging_backend_stack.software.grafanaPackageVersion }}"
294
+ - nginx
295
+ state: present
296
+ update_cache: true
297
+ cache_valid_time: 3600
298
+ policy_rc_d: 101
299
+
300
+ - name: Install the Prometheus metrics backend
301
+ ansible.builtin.apt:
302
+ name: >-
303
+ {{
304
+ 'prometheus=' ~
305
+ cloudfall_logging_backend_stack.software.prometheusPackageVersion
306
+ if 'prometheusPackageVersion'
307
+ in cloudfall_logging_backend_stack.software
308
+ else 'prometheus'
309
+ }}
310
+ state: present
311
+ update_cache: true
312
+ cache_valid_time: 3600
313
+ policy_rc_d: 101
314
+
315
+ - name: Create logging secret directory
316
+ ansible.builtin.file:
317
+ path: /etc/cloudfall/logging
318
+ state: directory
319
+ owner: root
320
+ group: root
321
+ mode: "0755"
322
+
323
+ - name: Secure gateway certificate material
324
+ ansible.builtin.file:
325
+ path: "{{ item }}"
326
+ state: file
327
+ owner: root
328
+ group: root
329
+ mode: "0644"
330
+ loop:
331
+ - "{{ cloudfall_logging_backend_stack.gateway.tls.certificatePath }}"
332
+ - "{{ cloudfall_logging_backend_stack.gateway.tls.clientCaPath }}"
333
+
334
+ - name: Secure gateway private key
335
+ ansible.builtin.file:
336
+ path: "{{ cloudfall_logging_backend_stack.gateway.tls.keyPath }}"
337
+ state: file
338
+ owner: root
339
+ group: root
340
+ mode: "0600"
341
+
342
+ - name: Grant Grafana access to its bootstrap password
343
+ ansible.builtin.file:
344
+ path: "{{ cloudfall_logging_backend_stack.grafana.adminPasswordPath }}"
345
+ state: file
346
+ owner: root
347
+ group: grafana
348
+ mode: "0640"
349
+
350
+ - name: Install managed Grafana configuration
351
+ ansible.builtin.template:
352
+ src: grafana.ini.j2
353
+ dest: /etc/grafana/grafana.ini
354
+ owner: root
355
+ group: grafana
356
+ mode: "0640"
357
+ backup: true
358
+ notify: Restart Grafana
359
+
360
+ - name: Provision the local Loki Grafana data source
361
+ ansible.builtin.template:
362
+ src: loki-datasource.yml.j2
363
+ dest: /etc/grafana/provisioning/datasources/cloudfall-loki.yml
364
+ owner: root
365
+ group: grafana
366
+ mode: "0640"
367
+ notify: Restart Grafana
368
+
369
+ - name: Provision the local Prometheus Grafana data source
370
+ ansible.builtin.template:
371
+ src: prometheus-datasource.yml.j2
372
+ dest: /etc/grafana/provisioning/datasources/cloudfall-prometheus.yml
373
+ owner: root
374
+ group: grafana
375
+ mode: "0640"
376
+ notify: Restart Grafana
377
+
378
+ - name: Install mTLS-only Loki ingestion gateway
379
+ ansible.builtin.template:
380
+ src: nginx-loki-gateway.conf.j2
381
+ dest: "/etc/nginx/sites-available/cloudfall-loki-{{ cloudfall_logging_backend_stack.id }}.conf"
382
+ owner: root
383
+ group: root
384
+ mode: "0644"
385
+ notify: Reload Nginx
386
+
387
+ - name: Enable mTLS-only Loki ingestion gateway
388
+ ansible.builtin.file:
389
+ src: "/etc/nginx/sites-available/cloudfall-loki-{{ cloudfall_logging_backend_stack.id }}.conf"
390
+ dest: "/etc/nginx/sites-enabled/cloudfall-loki-{{ cloudfall_logging_backend_stack.id }}.conf"
391
+ state: link
392
+ notify: Reload Nginx
393
+
394
+ - name: Validate Loki configuration
395
+ ansible.builtin.command:
396
+ argv:
397
+ - /usr/bin/loki
398
+ - "-config.file=/etc/loki/cloudfall-{{ cloudfall_logging_backend_stack.id }}.yaml"
399
+ - -verify-config
400
+ changed_when: false
401
+ when: not ansible_check_mode
402
+
403
+ - name: Validate Prometheus configuration
404
+ ansible.builtin.command:
405
+ argv:
406
+ - /usr/bin/promtool
407
+ - check
408
+ - config
409
+ - /etc/prometheus/cloudfall.yaml
410
+ changed_when: false
411
+ when: not ansible_check_mode
412
+
413
+ - name: Validate Nginx configuration
414
+ ansible.builtin.command:
415
+ argv:
416
+ - /usr/sbin/nginx
417
+ - -t
418
+ changed_when: false
419
+ when: not ansible_check_mode
420
+
421
+ - name: Apply validated logging backend configuration
422
+ ansible.builtin.meta: flush_handlers
423
+
424
+ - name: Enable logging backend services
425
+ ansible.builtin.systemd_service:
426
+ name: "{{ item }}"
427
+ enabled: true
428
+ state: started
429
+ daemon_reload: true
430
+ loop: >-
431
+ {{
432
+ ['loki.service', 'prometheus.service', 'nginx.service',
433
+ 'grafana-server.service']
434
+ + (['prometheus-alertmanager.service']
435
+ if 'alerting' in cloudfall_logging_backend_stack else [])
436
+ }}
437
+
438
+ - name: Wait for Loki readiness
439
+ ansible.builtin.uri:
440
+ url: "http://{{ cloudfall_logging_backend_stack.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.backend.port }}/ready"
441
+ status_code: 200
442
+ return_content: false
443
+ register: cloudfall_logging_backend_loki_readiness
444
+ retries: 12
445
+ delay: 5
446
+ until: cloudfall_logging_backend_loki_readiness.status == 200
447
+ when: not ansible_check_mode
448
+
449
+ - name: Wait for Prometheus readiness
450
+ ansible.builtin.uri:
451
+ url: "http://{{ cloudfall_logging_backend_stack.metrics.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.metrics.backend.port }}/-/ready"
452
+ status_code: 200
453
+ return_content: false
454
+ register: cloudfall_logging_backend_prometheus_readiness
455
+ retries: 12
456
+ delay: 5
457
+ until: cloudfall_logging_backend_prometheus_readiness.status == 200
458
+ when: not ansible_check_mode
459
+
460
+ - name: Wait for Alertmanager readiness
461
+ ansible.builtin.uri:
462
+ url: >-
463
+ http://{{
464
+ cloudfall_logging_backend_stack.alerting.alertmanager.listenAddress
465
+ }}:{{
466
+ cloudfall_logging_backend_stack.alerting.alertmanager.port
467
+ }}/-/ready
468
+ status_code: 200
469
+ return_content: false
470
+ register: cloudfall_logging_backend_alertmanager_readiness
471
+ retries: 12
472
+ delay: 5
473
+ until: cloudfall_logging_backend_alertmanager_readiness.status == 200
474
+ when:
475
+ - not ansible_check_mode
476
+ - "'alerting' in cloudfall_logging_backend_stack"
477
+
478
+ - name: Wait for Grafana readiness
479
+ ansible.builtin.uri:
480
+ url: "http://{{ cloudfall_logging_backend_stack.grafana.listenAddress }}:{{ cloudfall_logging_backend_stack.grafana.port }}/api/health"
481
+ status_code: 200
482
+ return_content: false
483
+ register: cloudfall_logging_backend_grafana_readiness
484
+ retries: 12
485
+ delay: 5
486
+ until: cloudfall_logging_backend_grafana_readiness.status == 200
487
+ when: not ansible_check_mode
@@ -0,0 +1,2 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ ARGS="--config.file=/etc/prometheus/cloudfall-alertmanager.yaml --web.listen-address={{ cloudfall_logging_backend_stack.alerting.alertmanager.listenAddress }}:{{ cloudfall_logging_backend_stack.alerting.alertmanager.port }} --cluster.listen-address="
@@ -0,0 +1,33 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ {% set alerting = cloudfall_logging_backend_stack.alerting %}
3
+ route:
4
+ receiver: cloudfall
5
+ group_by:
6
+ - alertname
7
+ - environment
8
+ group_wait: 30s
9
+ group_interval: 5m
10
+ repeat_interval: 4h
11
+
12
+ receivers:
13
+ - name: cloudfall
14
+ {% set webhooks = alerting.receivers | selectattr('webhook', 'defined') | list %}
15
+ {% set emails = alerting.receivers | selectattr('email', 'defined') | list %}
16
+ {% if webhooks %}
17
+ webhook_configs:
18
+ {% for receiver in webhooks %}
19
+ - url: {{ receiver.webhook.url | tojson }}
20
+ {% endfor %}
21
+ {% endif %}
22
+ {% if emails %}
23
+ email_configs:
24
+ {% for receiver in emails %}
25
+ - to: {{ receiver.email.to | tojson }}
26
+ from: {{ receiver.email['from'] | tojson }}
27
+ smarthost: {{ receiver.email.smarthost | tojson }}
28
+ {% if receiver.email.authUsername is defined %}
29
+ auth_username: {{ receiver.email.authUsername | tojson }}
30
+ auth_password_file: {{ receiver.email.authPasswordFile | tojson }}
31
+ {% endif %}
32
+ {% endfor %}
33
+ {% endif %}
@@ -0,0 +1,20 @@
1
+ [server]
2
+ protocol = http
3
+ http_addr = {{ cloudfall_logging_backend_stack.grafana.listenAddress }}
4
+ http_port = {{ cloudfall_logging_backend_stack.grafana.port }}
5
+
6
+ [security]
7
+ admin_user = admin
8
+ admin_password = {{ '$__file{' ~ cloudfall_logging_backend_stack.grafana.adminPasswordPath ~ '}' }}
9
+ disable_gravatar = true
10
+
11
+ [users]
12
+ allow_sign_up = false
13
+
14
+ [analytics]
15
+ reporting_enabled = false
16
+ check_for_updates = false
17
+ check_for_plugin_updates = false
18
+
19
+ [log]
20
+ mode = console
@@ -0,0 +1,11 @@
1
+ ---
2
+ apiVersion: 1
3
+ prune: true
4
+ datasources:
5
+ - name: Cloudfall Loki
6
+ uid: cloudfall-loki
7
+ type: loki
8
+ access: proxy
9
+ url: "http://{{ cloudfall_logging_backend_stack.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.backend.port }}"
10
+ isDefault: true
11
+ editable: false
@@ -0,0 +1,3 @@
1
+ [Service]
2
+ ExecStart=
3
+ ExecStart=/usr/bin/loki -config.file=/etc/loki/cloudfall-{{ cloudfall_logging_backend_stack.id }}.yaml
@@ -0,0 +1,49 @@
1
+ ---
2
+ auth_enabled: false
3
+
4
+ server:
5
+ http_listen_address: {{ cloudfall_logging_backend_stack.backend.listenAddress }}
6
+ http_listen_port: {{ cloudfall_logging_backend_stack.backend.port }}
7
+ grpc_listen_address: 127.0.0.1
8
+ grpc_listen_port: 9096
9
+
10
+ common:
11
+ instance_addr: 127.0.0.1
12
+ path_prefix: {{ cloudfall_logging_backend_stack.backend.storage.path }}
13
+ storage:
14
+ filesystem:
15
+ chunks_directory: {{ cloudfall_logging_backend_stack.backend.storage.path }}/chunks
16
+ rules_directory: {{ cloudfall_logging_backend_stack.backend.storage.path }}/rules
17
+ replication_factor: 1
18
+ ring:
19
+ kvstore:
20
+ store: inmemory
21
+
22
+ query_range:
23
+ results_cache:
24
+ cache:
25
+ embedded_cache:
26
+ enabled: true
27
+ max_size_mb: 100
28
+
29
+ schema_config:
30
+ configs:
31
+ - from: "2024-04-01"
32
+ store: tsdb
33
+ object_store: filesystem
34
+ schema: v13
35
+ index:
36
+ prefix: index_
37
+ period: 24h
38
+
39
+ compactor:
40
+ working_directory: {{ cloudfall_logging_backend_stack.backend.storage.path }}/compactor
41
+ retention_enabled: true
42
+ delete_request_store: filesystem
43
+
44
+ limits_config:
45
+ allow_structured_metadata: true
46
+ retention_period: {{ cloudfall_logging_backend_stack.backend.retentionHours }}h
47
+
48
+ analytics:
49
+ reporting_enabled: false
@@ -0,0 +1,45 @@
1
+ server {
2
+ {% if cloudfall_logging_backend_stack.gateway.listenAddress == '::' %}
3
+ listen [::]:{{ cloudfall_logging_backend_stack.gateway.port }} ssl;
4
+ {% else %}
5
+ listen {{ cloudfall_logging_backend_stack.gateway.listenAddress }}:{{ cloudfall_logging_backend_stack.gateway.port }} ssl;
6
+ {% endif %}
7
+ server_name {{ cloudfall_logging_backend_stack.gateway.serverName }};
8
+
9
+ ssl_certificate {{ cloudfall_logging_backend_stack.gateway.tls.certificatePath }};
10
+ ssl_certificate_key {{ cloudfall_logging_backend_stack.gateway.tls.keyPath }};
11
+ ssl_client_certificate {{ cloudfall_logging_backend_stack.gateway.tls.clientCaPath }};
12
+ ssl_verify_client on;
13
+ ssl_protocols TLSv1.2 TLSv1.3;
14
+ ssl_session_tickets off;
15
+
16
+ client_max_body_size 16m;
17
+
18
+ location = /loki/api/v1/push {
19
+ proxy_http_version 1.1;
20
+ proxy_set_header Host $host;
21
+ proxy_set_header X-Forwarded-Proto https;
22
+ proxy_pass http://{{ cloudfall_logging_backend_stack.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.backend.port }};
23
+ }
24
+
25
+ location = /api/v1/write {
26
+ proxy_http_version 1.1;
27
+ proxy_set_header Host $host;
28
+ proxy_set_header X-Forwarded-Proto https;
29
+ proxy_pass http://{{ cloudfall_logging_backend_stack.metrics.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.metrics.backend.port }};
30
+ }
31
+
32
+ location = /api/v1/alerts {
33
+ limit_except GET {
34
+ deny all;
35
+ }
36
+ proxy_http_version 1.1;
37
+ proxy_set_header Host $host;
38
+ proxy_set_header X-Forwarded-Proto https;
39
+ proxy_pass http://{{ cloudfall_logging_backend_stack.metrics.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.metrics.backend.port }};
40
+ }
41
+
42
+ location / {
43
+ return 404;
44
+ }
45
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ apiVersion: 1
3
+ prune: false
4
+ datasources:
5
+ - name: Cloudfall Prometheus
6
+ uid: cloudfall-prometheus
7
+ type: prometheus
8
+ access: proxy
9
+ url: "http://{{ cloudfall_logging_backend_stack.metrics.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.metrics.backend.port }}"
10
+ isDefault: false
11
+ editable: false
@@ -0,0 +1,2 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ ARGS="--config.file=/etc/prometheus/cloudfall.yaml --web.listen-address={{ cloudfall_logging_backend_stack.metrics.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.metrics.backend.port }} --web.enable-remote-write-receiver --storage.tsdb.path={{ cloudfall_logging_backend_stack.metrics.backend.storagePath }} --storage.tsdb.retention.time={{ cloudfall_logging_backend_stack.metrics.backend.retentionHours }}h"
@@ -0,0 +1,20 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ {% set cloudfall_rules = cloudfall_alert_rules | default([]) %}
3
+ {% if cloudfall_rules %}
4
+ groups:
5
+ - name: cloudfall
6
+ rules:
7
+ {% for rule in cloudfall_rules %}
8
+ - alert: {{ rule.id | replace('-', '_') }}
9
+ expr: {{ rule.expr | tojson }}
10
+ for: {{ rule['for'] }}
11
+ labels:
12
+ severity: {{ rule.severity }}
13
+ environment: {{ rule.environment }}
14
+ cloudfall_rule: {{ rule.id }}
15
+ annotations:
16
+ summary: {{ rule.summary | tojson }}
17
+ {% endfor %}
18
+ {% else %}
19
+ groups: []
20
+ {% endif %}