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,24 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ global:
3
+ scrape_interval: {{ cloudfall_logging_backend_stack.metrics.collection.intervalSeconds }}s
4
+ evaluation_interval: {{ cloudfall_logging_backend_stack.metrics.collection.intervalSeconds }}s
5
+
6
+ rule_files:
7
+ - /etc/prometheus/cloudfall-rules.yaml
8
+ {% if cloudfall_logging_backend_stack.alerting is defined %}
9
+
10
+ alerting:
11
+ alertmanagers:
12
+ - static_configs:
13
+ - targets:
14
+ - "{{ cloudfall_logging_backend_stack.alerting.alertmanager.listenAddress }}:{{ cloudfall_logging_backend_stack.alerting.alertmanager.port }}"
15
+ {% endif %}
16
+
17
+ scrape_configs:
18
+ - job_name: prometheus
19
+ static_configs:
20
+ - targets:
21
+ - "{{ cloudfall_logging_backend_stack.metrics.backend.listenAddress }}:{{ cloudfall_logging_backend_stack.metrics.backend.port }}"
22
+ labels:
23
+ environment: "{{ cloudfall_logging_backend_stack.environment }}"
24
+ server: "{{ cloudfall_logging_backend_stack.backend.server }}"
@@ -0,0 +1,7 @@
1
+ ---
2
+ cloudfall_logging_collector_stack: {}
3
+ cloudfall_logging_collector_metrics_role: alloy
4
+ cloudfall_logging_collector_grafana_repository_key_url: >-
5
+ https://apt.grafana.com/gpg-full.key
6
+ cloudfall_logging_collector_grafana_repository_key_path: /etc/apt/keyrings/grafana.asc
7
+ cloudfall_logging_collector_grafana_repository_url: https://apt.grafana.com
@@ -0,0 +1,6 @@
1
+ ---
2
+ - name: Restart Alloy
3
+ ansible.builtin.systemd_service:
4
+ name: alloy.service
5
+ state: restarted
6
+ daemon_reload: true
@@ -0,0 +1,122 @@
1
+ ---
2
+ argument_specs:
3
+ main:
4
+ short_description: Install Alloy without removing legacy log agents
5
+ options:
6
+ cloudfall_logging_collector_stack:
7
+ type: dict
8
+ required: true
9
+ options:
10
+ id:
11
+ type: str
12
+ required: true
13
+ environment:
14
+ type: str
15
+ required: true
16
+ migration:
17
+ type: dict
18
+ required: true
19
+ options:
20
+ mode:
21
+ type: str
22
+ choices:
23
+ - parallel
24
+ required: true
25
+ preserveLegacyAgents:
26
+ type: bool
27
+ required: true
28
+ software:
29
+ type: dict
30
+ required: true
31
+ options:
32
+ lokiPackageVersion:
33
+ type: str
34
+ required: true
35
+ grafanaPackageVersion:
36
+ type: str
37
+ required: true
38
+ alloyPackageVersion:
39
+ type: str
40
+ required: true
41
+ prometheusPackageVersion:
42
+ type: str
43
+ metrics:
44
+ type: dict
45
+ required: true
46
+ options:
47
+ backend:
48
+ type: dict
49
+ required: true
50
+ collection:
51
+ type: dict
52
+ required: true
53
+ options:
54
+ intervalSeconds:
55
+ type: int
56
+ required: true
57
+ backend:
58
+ type: dict
59
+ required: true
60
+ gateway:
61
+ type: dict
62
+ required: true
63
+ options:
64
+ serverName:
65
+ type: str
66
+ required: true
67
+ listenAddress:
68
+ type: str
69
+ required: true
70
+ port:
71
+ type: int
72
+ required: true
73
+ tls:
74
+ type: dict
75
+ required: true
76
+ grafana:
77
+ type: dict
78
+ required: true
79
+ alerting:
80
+ type: dict
81
+ collectors:
82
+ type: dict
83
+ required: true
84
+ options:
85
+ servers:
86
+ type: list
87
+ elements: str
88
+ required: true
89
+ clientTls:
90
+ type: dict
91
+ required: true
92
+ options:
93
+ caPath:
94
+ type: path
95
+ required: true
96
+ certificatePath:
97
+ type: path
98
+ required: true
99
+ keyPath:
100
+ type: path
101
+ required: true
102
+ journal:
103
+ type: dict
104
+ required: true
105
+ options:
106
+ enabled:
107
+ type: bool
108
+ required: true
109
+ maxAgeHours:
110
+ type: int
111
+ required: true
112
+ files:
113
+ type: list
114
+ elements: dict
115
+ required: true
116
+ cloudfall_services:
117
+ type: list
118
+ elements: dict
119
+ default: []
120
+ cloudfall_logging_collector_metrics_role:
121
+ type: str
122
+ default: alloy
@@ -0,0 +1,11 @@
1
+ ---
2
+ galaxy_info:
3
+ author: Cloudfall
4
+ description: Install the Cloudfall Grafana Alloy log collector
5
+ license: AGPL-3.0-or-later
6
+ min_ansible_version: "2.21"
7
+ platforms:
8
+ - name: Debian
9
+ versions:
10
+ - bookworm
11
+ dependencies: []
@@ -0,0 +1,224 @@
1
+ ---
2
+ - name: Validate logging collector target and migration guard
3
+ ansible.builtin.assert:
4
+ that:
5
+ - ansible_facts["distribution"] == "Debian"
6
+ - ansible_facts["service_mgr"] == "systemd"
7
+ - cloudfall_server_id in cloudfall_logging_collector_stack.collectors.servers
8
+ - cloudfall_logging_collector_stack.migration.mode == "parallel"
9
+ - cloudfall_logging_collector_stack.migration.preserveLegacyAgents | bool
10
+ - cloudfall_logging_collector_stack.collectors.journal.enabled | bool
11
+ fail_msg: >-
12
+ Logging collection requires a declared Debian collector and the guarded
13
+ parallel migration mode
14
+
15
+ - name: Inspect pre-provisioned collector TLS files
16
+ ansible.builtin.stat:
17
+ path: "{{ item }}"
18
+ follow: true
19
+ loop:
20
+ - "{{ cloudfall_logging_collector_stack.collectors.clientTls.caPath }}"
21
+ - "{{ cloudfall_logging_collector_stack.collectors.clientTls.certificatePath }}"
22
+ - "{{ cloudfall_logging_collector_stack.collectors.clientTls.keyPath }}"
23
+ register: cloudfall_logging_collector_tls_files
24
+
25
+ - name: Require collector TLS files before mutation
26
+ ansible.builtin.assert:
27
+ that:
28
+ - item.stat.exists
29
+ - item.stat.isreg
30
+ fail_msg: "Required collector TLS file is missing: {{ item.item }}"
31
+ loop: "{{ cloudfall_logging_collector_tls_files.results }}"
32
+ loop_control:
33
+ label: "{{ item.item }}"
34
+
35
+ - name: Reject world-readable collector private key
36
+ ansible.builtin.assert:
37
+ that:
38
+ - item.stat.mode is match('^0?[46][04]0$')
39
+ fail_msg: >-
40
+ Collector private key permissions are too broad:
41
+ {{ cloudfall_logging_collector_stack.collectors.clientTls.keyPath }}
42
+ loop: "{{ cloudfall_logging_collector_tls_files.results }}"
43
+ when: item.item == cloudfall_logging_collector_stack.collectors.clientTls.keyPath
44
+
45
+ - name: Install Grafana repository prerequisites
46
+ ansible.builtin.apt:
47
+ name:
48
+ - ca-certificates
49
+ - gnupg
50
+ - python3-debian
51
+ state: present
52
+ update_cache: true
53
+ cache_valid_time: 3600
54
+
55
+ - name: Create APT keyring directory
56
+ ansible.builtin.file:
57
+ path: /etc/apt/keyrings
58
+ state: directory
59
+ owner: root
60
+ group: root
61
+ mode: "0755"
62
+
63
+ - name: Install Grafana repository signing key
64
+ ansible.builtin.get_url:
65
+ url: "{{ cloudfall_logging_collector_grafana_repository_key_url }}"
66
+ dest: "{{ cloudfall_logging_collector_grafana_repository_key_path }}"
67
+ owner: root
68
+ group: root
69
+ mode: "0644"
70
+
71
+ - name: Configure stable Grafana package repository
72
+ ansible.builtin.deb822_repository:
73
+ name: grafana
74
+ types:
75
+ - deb
76
+ uris:
77
+ - "{{ cloudfall_logging_collector_grafana_repository_url }}"
78
+ suites:
79
+ - stable
80
+ components:
81
+ - main
82
+ signed_by: "{{ cloudfall_logging_collector_grafana_repository_key_path }}"
83
+ state: present
84
+ register: cloudfall_logging_collector_repository
85
+
86
+ # Not a handler: the refreshed index must exist before the pinned
87
+ # install below runs, and handlers only flush later.
88
+ - name: Refresh APT cache after repository changes # noqa: no-handler
89
+ ansible.builtin.apt:
90
+ update_cache: true
91
+ when: cloudfall_logging_collector_repository is changed
92
+
93
+ - name: Create Alloy service group before package configuration
94
+ ansible.builtin.group:
95
+ name: alloy
96
+ system: true
97
+ state: present
98
+
99
+ - name: Create Alloy service account before package configuration
100
+ ansible.builtin.user:
101
+ name: alloy
102
+ group: alloy
103
+ groups:
104
+ - adm
105
+ - systemd-journal
106
+ append: true
107
+ shell: /usr/sbin/nologin
108
+ create_home: false
109
+ system: true
110
+ state: present
111
+
112
+ - name: Create Alloy configuration directory before package configuration
113
+ ansible.builtin.file:
114
+ path: /etc/alloy
115
+ state: directory
116
+ owner: root
117
+ group: alloy
118
+ mode: "0750"
119
+
120
+ - name: Create Alloy state directory before package configuration
121
+ ansible.builtin.file:
122
+ path: /var/lib/alloy
123
+ state: directory
124
+ owner: alloy
125
+ group: alloy
126
+ mode: "0750"
127
+
128
+ - name: Create Alloy systemd override directory before package configuration
129
+ ansible.builtin.file:
130
+ path: /etc/systemd/system/alloy.service.d
131
+ state: directory
132
+ owner: root
133
+ group: root
134
+ mode: "0755"
135
+
136
+ - name: Install safe Alloy configuration before package configuration
137
+ ansible.builtin.template:
138
+ src: config.alloy.j2
139
+ dest: /etc/alloy/cloudfall.alloy
140
+ owner: root
141
+ group: alloy
142
+ mode: "0640"
143
+ notify: Restart Alloy
144
+
145
+ - name: Install Alloy systemd guard before package configuration
146
+ ansible.builtin.template:
147
+ src: alloy-systemd-override.conf.j2
148
+ dest: /etc/systemd/system/alloy.service.d/cloudfall.conf
149
+ owner: root
150
+ group: root
151
+ mode: "0644"
152
+ notify: Restart Alloy
153
+
154
+ - name: Install pinned Alloy package
155
+ ansible.builtin.apt:
156
+ name: "alloy={{ cloudfall_logging_collector_stack.software.alloyPackageVersion }}"
157
+ state: present
158
+ update_cache: true
159
+ cache_valid_time: 3600
160
+ policy_rc_d: 101
161
+
162
+ - name: Create logging secret directory
163
+ ansible.builtin.file:
164
+ path: /etc/cloudfall/logging
165
+ state: directory
166
+ owner: root
167
+ group: root
168
+ mode: "0755"
169
+
170
+ - name: Grant Alloy access to collector TLS material
171
+ ansible.builtin.file:
172
+ path: "{{ item }}"
173
+ state: file
174
+ owner: root
175
+ group: alloy
176
+ mode: "0640"
177
+ loop:
178
+ - "{{ cloudfall_logging_collector_stack.collectors.clientTls.caPath }}"
179
+ - "{{ cloudfall_logging_collector_stack.collectors.clientTls.certificatePath }}"
180
+ - "{{ cloudfall_logging_collector_stack.collectors.clientTls.keyPath }}"
181
+
182
+ - name: Grant Alloy journal access
183
+ ansible.builtin.user:
184
+ name: alloy
185
+ groups:
186
+ - adm
187
+ - systemd-journal
188
+ append: true
189
+
190
+ - name: Validate Alloy configuration
191
+ ansible.builtin.command:
192
+ argv:
193
+ - /usr/bin/alloy
194
+ - validate
195
+ - /etc/alloy/cloudfall.alloy
196
+ changed_when: false
197
+ when: not ansible_check_mode
198
+
199
+ - name: Apply validated Alloy configuration
200
+ ansible.builtin.meta: flush_handlers
201
+
202
+ - name: Enable Alloy without changing legacy agents
203
+ ansible.builtin.systemd_service:
204
+ name: alloy.service
205
+ enabled: true
206
+ state: started
207
+
208
+ - name: Wait for Alloy readiness
209
+ ansible.builtin.uri:
210
+ url: http://127.0.0.1:12345/-/ready
211
+ status_code: 200
212
+ return_content: false
213
+ register: cloudfall_logging_collector_alloy_readiness
214
+ retries: 12
215
+ delay: 5
216
+ until: cloudfall_logging_collector_alloy_readiness.status == 200
217
+ when: not ansible_check_mode
218
+
219
+ - name: Verify Alloy component health
220
+ ansible.builtin.uri:
221
+ url: http://127.0.0.1:12345/-/healthy
222
+ status_code: 200
223
+ return_content: false
224
+ when: not ansible_check_mode
@@ -0,0 +1,3 @@
1
+ [Service]
2
+ ExecStart=
3
+ ExecStart=/usr/bin/alloy run --storage.path=/var/lib/alloy/data /etc/alloy/cloudfall.alloy
@@ -0,0 +1,127 @@
1
+ logging {
2
+ level = "info"
3
+ format = "logfmt"
4
+ }
5
+
6
+ loki.relabel "journal" {
7
+ forward_to = []
8
+
9
+ rule {
10
+ source_labels = ["__journal__systemd_unit"]
11
+ target_label = "unit"
12
+ }
13
+ }
14
+
15
+ loki.write "cloudfall" {
16
+ external_labels = {
17
+ environment = "{{ cloudfall_logging_collector_stack.environment }}",
18
+ server = "{{ cloudfall_server_id }}",
19
+ }
20
+
21
+ endpoint {
22
+ url = "https://{{ cloudfall_logging_collector_stack.gateway.serverName }}:{{ cloudfall_logging_collector_stack.gateway.port }}/loki/api/v1/push"
23
+
24
+ tls_config {
25
+ ca_file = "{{ cloudfall_logging_collector_stack.collectors.clientTls.caPath }}"
26
+ cert_file = "{{ cloudfall_logging_collector_stack.collectors.clientTls.certificatePath }}"
27
+ key_file = "{{ cloudfall_logging_collector_stack.collectors.clientTls.keyPath }}"
28
+ server_name = "{{ cloudfall_logging_collector_stack.gateway.serverName }}"
29
+ min_version = "TLS12"
30
+ }
31
+ }
32
+ }
33
+
34
+ loki.source.journal "systemd" {
35
+ forward_to = [loki.write.cloudfall.receiver]
36
+ relabel_rules = loki.relabel.journal.rules
37
+ max_age = "{{ cloudfall_logging_collector_stack.collectors.journal.maxAgeHours }}h"
38
+ labels = {
39
+ source = "journal",
40
+ }
41
+ }
42
+
43
+ prometheus.exporter.unix "host" {
44
+ }
45
+
46
+ prometheus.scrape "host" {
47
+ targets = prometheus.exporter.unix.host.targets
48
+ forward_to = [prometheus.remote_write.cloudfall.receiver]
49
+ scrape_interval = "{{ cloudfall_logging_collector_stack.metrics.collection.intervalSeconds }}s"
50
+ }
51
+
52
+ prometheus.remote_write "cloudfall" {
53
+ external_labels = {
54
+ environment = "{{ cloudfall_logging_collector_stack.environment }}",
55
+ server = "{{ cloudfall_server_id }}",
56
+ }
57
+
58
+ endpoint {
59
+ url = "https://{{ cloudfall_logging_collector_stack.gateway.serverName }}:{{ cloudfall_logging_collector_stack.gateway.port }}/api/v1/write"
60
+
61
+ tls_config {
62
+ ca_file = "{{ cloudfall_logging_collector_stack.collectors.clientTls.caPath }}"
63
+ cert_file = "{{ cloudfall_logging_collector_stack.collectors.clientTls.certificatePath }}"
64
+ key_file = "{{ cloudfall_logging_collector_stack.collectors.clientTls.keyPath }}"
65
+ server_name = "{{ cloudfall_logging_collector_stack.gateway.serverName }}"
66
+ min_version = "TLS12"
67
+ }
68
+ }
69
+ }
70
+ {% for service in cloudfall_services | default([]) %}
71
+ {% if service.metrics is defined and service.serviceKind in ('postgresql', 'redis') %}
72
+ {% set component = service.id | replace('-', '_') %}
73
+
74
+ {% if service.serviceKind == 'postgresql' %}
75
+ prometheus.exporter.postgres "{{ component }}" {
76
+ data_source_names = [
77
+ "postgresql://{{ cloudfall_logging_collector_metrics_role }}@:{{ service.bind.port }}/postgres?host=/var/run/postgresql&sslmode=disable",
78
+ ]
79
+ }
80
+ {% else %}
81
+ prometheus.exporter.redis "{{ component }}" {
82
+ redis_addr = "{{ service.bind.address }}:{{ service.bind.port }}"
83
+ }
84
+ {% endif %}
85
+
86
+ prometheus.relabel "{{ component }}" {
87
+ forward_to = [prometheus.remote_write.cloudfall.receiver]
88
+
89
+ rule {
90
+ target_label = "service"
91
+ replacement = "{{ service.id }}"
92
+ }
93
+ }
94
+
95
+ prometheus.scrape "{{ component }}" {
96
+ targets = prometheus.exporter.{{ 'postgres' if service.serviceKind == 'postgresql' else 'redis' }}.{{ component }}.targets
97
+ forward_to = [prometheus.relabel.{{ component }}.receiver]
98
+ scrape_interval = "{{ cloudfall_logging_collector_stack.metrics.collection.intervalSeconds }}s"
99
+ }
100
+ {% endif %}
101
+ {% endfor %}
102
+ {% for item in cloudfall_logging_collector_stack.collectors.files %}
103
+ {% if cloudfall_server_id in item.servers %}
104
+
105
+ local.file_match "{{ item.id | replace('-', '_') }}" {
106
+ path_targets = [
107
+ {
108
+ "__path__" = "{{ item.path }}",
109
+ "source" = "file",
110
+ "job" = "{{ item.id }}",
111
+ {% if item.application is defined %}
112
+ "application" = "{{ item.application }}",
113
+ {% endif %}
114
+ {% if item.component is defined %}
115
+ "component" = "{{ item.component }}",
116
+ {% endif %}
117
+ },
118
+ ]
119
+ }
120
+
121
+ loki.source.file "{{ item.id | replace('-', '_') }}" {
122
+ targets = local.file_match.{{ item.id | replace('-', '_') }}.targets
123
+ forward_to = [loki.write.cloudfall.receiver]
124
+ tail_from_end = true
125
+ }
126
+ {% endif %}
127
+ {% endfor %}
@@ -0,0 +1,4 @@
1
+ ---
2
+ cloudfall_nginx_site_issue_certificate: false
3
+ cloudfall_nginx_site_acme_webroot: /var/lib/letsencrypt
4
+ cloudfall_nginx_site_receipt_directory: ""
@@ -0,0 +1,5 @@
1
+ ---
2
+ - name: Reload Nginx
3
+ ansible.builtin.systemd_service:
4
+ name: nginx.service
5
+ state: reloaded
@@ -0,0 +1,69 @@
1
+ ---
2
+ argument_specs:
3
+ main:
4
+ short_description: Converge one declared public domain route
5
+ options:
6
+ cloudfall_nginx_site_domain:
7
+ type: dict
8
+ required: true
9
+ options:
10
+ id:
11
+ type: str
12
+ required: true
13
+ primaryName:
14
+ type: str
15
+ required: true
16
+ aliases:
17
+ type: list
18
+ elements: str
19
+ required: true
20
+ proxy:
21
+ type: dict
22
+ required: true
23
+ options:
24
+ server:
25
+ type: str
26
+ required: true
27
+ configurationPath:
28
+ type: path
29
+ required: true
30
+ service:
31
+ type: str
32
+ required: true
33
+ upstream:
34
+ type: dict
35
+ options:
36
+ address:
37
+ type: str
38
+ required: true
39
+ port:
40
+ type: int
41
+ required: true
42
+ origin:
43
+ type: dict
44
+ required: true
45
+ edge:
46
+ type: dict
47
+ required: true
48
+ tls:
49
+ type: dict
50
+ required: true
51
+ options:
52
+ mode:
53
+ type: str
54
+ choices:
55
+ - disabled
56
+ - required
57
+ required: true
58
+ healthCheck:
59
+ type: dict
60
+ required: true
61
+ cloudfall_nginx_site_issue_certificate:
62
+ type: bool
63
+ default: false
64
+ cloudfall_nginx_site_acme_webroot:
65
+ type: path
66
+ default: /var/lib/letsencrypt
67
+ cloudfall_nginx_site_receipt_directory:
68
+ type: str
69
+ default: ""
@@ -0,0 +1,13 @@
1
+ ---
2
+ galaxy_info:
3
+ role_name: cloudfall_nginx_site
4
+ author: Cloudfall
5
+ description: Render one declared Domain as a managed Nginx virtual host
6
+ license: AGPL-3.0-or-later
7
+ min_ansible_version: "2.21"
8
+ platforms:
9
+ - name: Debian
10
+ versions:
11
+ - bookworm
12
+ - trixie
13
+ dependencies: []