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,17 @@
1
+ #!/usr/bin/env bash
2
+ # Managed by Cloudfall. Local changes will be overwritten.
3
+ set -euo pipefail
4
+
5
+ backup_directory="{{ cloudfall_postgresql_service.backup.directory }}"
6
+ port="{{ cloudfall_postgresql_service.bind.port }}"
7
+ retention_days="{{ cloudfall_postgresql_service.backup.retentionDays }}"
8
+ timestamp="$(date --utc +%Y%m%dT%H%M%SZ)"
9
+
10
+ {% for database in cloudfall_postgresql_service.postgresql.databases %}
11
+ pg_dump --port "${port}" --format=custom \
12
+ --file "${backup_directory}/{{ database.name }}-${timestamp}.dump" \
13
+ "{{ database.name }}"
14
+ {% endfor %}
15
+
16
+ find "${backup_directory}" -name '*.dump' -type f \
17
+ -mtime "+${retention_days}" -delete
@@ -0,0 +1,10 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall PostgreSQL backup schedule for {{ cloudfall_postgresql_service.id }}
4
+
5
+ [Timer]
6
+ OnCalendar={{ cloudfall_postgresql_service.backup.onCalendar }}
7
+ Persistent=true
8
+
9
+ [Install]
10
+ WantedBy=timers.target
@@ -0,0 +1,3 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ listen_addresses = '{{ cloudfall_postgresql_service.bind.address }}'
3
+ port = {{ cloudfall_postgresql_service.bind.port }}
@@ -0,0 +1,11 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall PostgreSQL restore drill for {{ cloudfall_postgresql_service.id }}
4
+ After=postgresql@{{ cloudfall_postgresql_service.postgresql.majorVersion }}-main.service
5
+ Requires=postgresql@{{ cloudfall_postgresql_service.postgresql.majorVersion }}-main.service
6
+
7
+ [Service]
8
+ Type=oneshot
9
+ User=postgres
10
+ Group=postgres
11
+ ExecStart=/usr/local/sbin/cloudfall-postgresql-restore-check
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # Managed by Cloudfall. Local changes will be overwritten.
3
+ # Restores the newest dump of every declared database into a scratch
4
+ # database, counts catalog rows, and drops the scratch database again.
5
+ set -euo pipefail
6
+
7
+ backup_directory="{{ cloudfall_postgresql_service.backup.directory }}"
8
+ port="{{ cloudfall_postgresql_service.bind.port }}"
9
+
10
+ {% for database in cloudfall_postgresql_service.postgresql.databases %}
11
+ latest="$(find "${backup_directory}" -name '{{ database.name }}-*.dump' \
12
+ -type f | sort | tail -n 1)"
13
+ if [ -z "${latest}" ]; then
14
+ echo "no backup found for {{ database.name }}" >&2
15
+ exit 1
16
+ fi
17
+ scratch="{{ database.name }}_restore_check"
18
+ dropdb --port "${port}" --if-exists "${scratch}"
19
+ createdb --port "${port}" "${scratch}"
20
+ pg_restore --port "${port}" --dbname "${scratch}" --no-owner \
21
+ --exit-on-error "${latest}"
22
+ relations="$(psql --port "${port}" --tuples-only --no-align \
23
+ --command 'SELECT count(*) FROM pg_class' "${scratch}")"
24
+ dropdb --port "${port}" "${scratch}"
25
+ echo "restore check passed for {{ database.name }}:" \
26
+ "${latest} (${relations} catalog relations)"
27
+ {% endfor %}
@@ -0,0 +1,10 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall PostgreSQL restore-drill schedule for {{ cloudfall_postgresql_service.id }}
4
+
5
+ [Timer]
6
+ OnCalendar={{ cloudfall_postgresql_service.backup.restoreCheckOnCalendar }}
7
+ Persistent=true
8
+
9
+ [Install]
10
+ WantedBy=timers.target
@@ -0,0 +1,2 @@
1
+ ---
2
+ cloudfall_redis_service: {}
@@ -0,0 +1,6 @@
1
+ ---
2
+ - name: Restart Redis
3
+ ansible.builtin.systemd_service:
4
+ name: redis-server.service
5
+ state: restarted
6
+ daemon_reload: true
@@ -0,0 +1,68 @@
1
+ ---
2
+ argument_specs:
3
+ main:
4
+ short_description: Converge one declared Redis service
5
+ options:
6
+ cloudfall_redis_service:
7
+ type: dict
8
+ required: true
9
+ options:
10
+ id:
11
+ type: str
12
+ required: true
13
+ serviceKind:
14
+ type: str
15
+ choices:
16
+ - redis
17
+ required: true
18
+ environment:
19
+ type: str
20
+ required: true
21
+ server:
22
+ type: str
23
+ required: true
24
+ bind:
25
+ type: dict
26
+ required: true
27
+ options:
28
+ address:
29
+ type: str
30
+ choices:
31
+ - 127.0.0.1
32
+ required: true
33
+ port:
34
+ type: int
35
+ required: true
36
+ redis:
37
+ type: dict
38
+ required: true
39
+ options:
40
+ packageVersion:
41
+ type: str
42
+ maxmemoryMb:
43
+ type: int
44
+ required: true
45
+ appendOnly:
46
+ type: bool
47
+ required: true
48
+ backup:
49
+ type: dict
50
+ required: true
51
+ options:
52
+ directory:
53
+ type: path
54
+ required: true
55
+ onCalendar:
56
+ type: str
57
+ required: true
58
+ restoreCheckOnCalendar:
59
+ type: str
60
+ retentionDays:
61
+ type: int
62
+ required: true
63
+ metrics:
64
+ type: dict
65
+ options:
66
+ enabled:
67
+ type: bool
68
+ required: true
@@ -0,0 +1,13 @@
1
+ ---
2
+ galaxy_info:
3
+ role_name: cloudfall_redis
4
+ author: cloudfall
5
+ description: Converge one declared loopback Redis service
6
+ license: AGPL-3.0-or-later
7
+ min_ansible_version: "2.16"
8
+ platforms:
9
+ - name: Debian
10
+ versions:
11
+ - bookworm
12
+ - trixie
13
+ dependencies: []
@@ -0,0 +1,148 @@
1
+ ---
2
+ - name: Validate Redis service target and declaration
3
+ ansible.builtin.assert:
4
+ that:
5
+ - ansible_facts["distribution"] == "Debian"
6
+ - ansible_facts["service_mgr"] == "systemd"
7
+ - cloudfall_redis_service.serviceKind == "redis"
8
+ - cloudfall_redis_service.server == cloudfall_server_id
9
+ - cloudfall_redis_service.bind.address == "127.0.0.1"
10
+ fail_msg: >-
11
+ Redis deployment requires its declared Debian server and a
12
+ loopback-only bind address
13
+
14
+ - name: Validate the declared backup calendar expression
15
+ ansible.builtin.command:
16
+ argv:
17
+ - /usr/bin/systemd-analyze
18
+ - calendar
19
+ - "{{ cloudfall_redis_service.backup.onCalendar }}"
20
+ changed_when: false
21
+
22
+ - name: Install the pinned Redis server
23
+ ansible.builtin.apt:
24
+ name: >-
25
+ {{
26
+ 'redis-server=' ~ cloudfall_redis_service.redis.packageVersion
27
+ if 'packageVersion' in cloudfall_redis_service.redis
28
+ else 'redis-server'
29
+ }}
30
+ state: present
31
+ update_cache: true
32
+ cache_valid_time: 3600
33
+ policy_rc_d: 101
34
+
35
+ - name: Install the managed Redis configuration
36
+ ansible.builtin.template:
37
+ src: cloudfall.conf.j2
38
+ dest: /etc/redis/cloudfall.conf
39
+ owner: redis
40
+ group: redis
41
+ mode: "0640"
42
+ notify: Restart Redis
43
+
44
+ - name: Include the managed configuration from the distribution config
45
+ ansible.builtin.blockinfile:
46
+ path: /etc/redis/redis.conf
47
+ marker: "# {mark} CLOUDFALL MANAGED"
48
+ append_newline: true
49
+ prepend_newline: true
50
+ block: include /etc/redis/cloudfall.conf
51
+ notify: Restart Redis
52
+
53
+ - name: Enable and start the Redis server
54
+ ansible.builtin.systemd_service:
55
+ name: redis-server.service
56
+ enabled: true
57
+ state: started
58
+ daemon_reload: true
59
+
60
+ - name: Apply the validated Redis configuration
61
+ ansible.builtin.meta: flush_handlers
62
+
63
+ - name: Wait for Redis readiness
64
+ ansible.builtin.command:
65
+ argv:
66
+ - /usr/bin/redis-cli
67
+ - -p
68
+ - "{{ cloudfall_redis_service.bind.port }}"
69
+ - ping
70
+ register: cloudfall_redis_readiness
71
+ changed_when: false
72
+ retries: 12
73
+ delay: 5
74
+ until: cloudfall_redis_readiness.stdout == "PONG"
75
+ when: not ansible_check_mode
76
+
77
+ - name: Create the backup directory
78
+ ansible.builtin.file:
79
+ path: "{{ cloudfall_redis_service.backup.directory }}"
80
+ state: directory
81
+ owner: redis
82
+ group: redis
83
+ mode: "0700"
84
+
85
+ - name: Install the backup script
86
+ ansible.builtin.template:
87
+ src: backup.sh.j2
88
+ dest: /usr/local/sbin/cloudfall-redis-backup
89
+ owner: root
90
+ group: root
91
+ mode: "0755"
92
+
93
+ - name: Install the restore-check script
94
+ ansible.builtin.template:
95
+ src: restore-check.sh.j2
96
+ dest: /usr/local/sbin/cloudfall-redis-restore-check
97
+ owner: root
98
+ group: root
99
+ mode: "0755"
100
+
101
+ - name: Install the backup service unit
102
+ ansible.builtin.template:
103
+ src: backup.service.j2
104
+ dest: /etc/systemd/system/cloudfall-redis-backup.service
105
+ owner: root
106
+ group: root
107
+ mode: "0644"
108
+
109
+ - name: Install the backup timer unit
110
+ ansible.builtin.template:
111
+ src: backup.timer.j2
112
+ dest: /etc/systemd/system/cloudfall-redis-backup.timer
113
+ owner: root
114
+ group: root
115
+ mode: "0644"
116
+
117
+ - name: Enable the backup timer
118
+ ansible.builtin.systemd_service:
119
+ name: cloudfall-redis-backup.timer
120
+ enabled: true
121
+ state: started
122
+ daemon_reload: true
123
+
124
+ - name: Install the restore-drill service unit
125
+ ansible.builtin.template:
126
+ src: restore-check.service.j2
127
+ dest: /etc/systemd/system/cloudfall-redis-restore-check.service
128
+ owner: root
129
+ group: root
130
+ mode: "0644"
131
+ when: cloudfall_redis_service.backup.restoreCheckOnCalendar is defined
132
+
133
+ - name: Install the restore-drill timer unit
134
+ ansible.builtin.template:
135
+ src: restore-check.timer.j2
136
+ dest: /etc/systemd/system/cloudfall-redis-restore-check.timer
137
+ owner: root
138
+ group: root
139
+ mode: "0644"
140
+ when: cloudfall_redis_service.backup.restoreCheckOnCalendar is defined
141
+
142
+ - name: Enable the restore-drill timer
143
+ ansible.builtin.systemd_service:
144
+ name: cloudfall-redis-restore-check.timer
145
+ enabled: true
146
+ state: started
147
+ daemon_reload: true
148
+ when: cloudfall_redis_service.backup.restoreCheckOnCalendar is defined
@@ -0,0 +1,11 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall Redis backup for {{ cloudfall_redis_service.id }}
4
+ After=redis-server.service
5
+ Requires=redis-server.service
6
+
7
+ [Service]
8
+ Type=oneshot
9
+ User=redis
10
+ Group=redis
11
+ ExecStart=/usr/local/sbin/cloudfall-redis-backup
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # Managed by Cloudfall. Local changes will be overwritten.
3
+ set -euo pipefail
4
+
5
+ backup_directory="{{ cloudfall_redis_service.backup.directory }}"
6
+ port="{{ cloudfall_redis_service.bind.port }}"
7
+ retention_days="{{ cloudfall_redis_service.backup.retentionDays }}"
8
+ timestamp="$(date --utc +%Y%m%dT%H%M%SZ)"
9
+
10
+ redis-cli -p "${port}" --rdb "${backup_directory}/redis-${timestamp}.rdb" \
11
+ > /dev/null
12
+
13
+ find "${backup_directory}" -name 'redis-*.rdb' -type f \
14
+ -mtime "+${retention_days}" -delete
@@ -0,0 +1,10 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall Redis backup schedule for {{ cloudfall_redis_service.id }}
4
+
5
+ [Timer]
6
+ OnCalendar={{ cloudfall_redis_service.backup.onCalendar }}
7
+ Persistent=true
8
+
9
+ [Install]
10
+ WantedBy=timers.target
@@ -0,0 +1,6 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ bind {{ cloudfall_redis_service.bind.address }}
3
+ port {{ cloudfall_redis_service.bind.port }}
4
+ protected-mode yes
5
+ maxmemory {{ cloudfall_redis_service.redis.maxmemoryMb }}mb
6
+ appendonly {{ 'yes' if cloudfall_redis_service.redis.appendOnly else 'no' }}
@@ -0,0 +1,11 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall Redis restore drill for {{ cloudfall_redis_service.id }}
4
+ After=redis-server.service
5
+ Requires=redis-server.service
6
+
7
+ [Service]
8
+ Type=oneshot
9
+ User=redis
10
+ Group=redis
11
+ ExecStart=/usr/local/sbin/cloudfall-redis-restore-check
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ # Managed by Cloudfall. Local changes will be overwritten.
3
+ # Verifies the newest RDB snapshot is structurally restorable.
4
+ set -euo pipefail
5
+
6
+ backup_directory="{{ cloudfall_redis_service.backup.directory }}"
7
+
8
+ latest="$(find "${backup_directory}" -name 'redis-*.rdb' -type f \
9
+ | sort | tail -n 1)"
10
+ if [ -z "${latest}" ]; then
11
+ echo "no backup found for {{ cloudfall_redis_service.id }}" >&2
12
+ exit 1
13
+ fi
14
+ redis-check-rdb "${latest}"
15
+ echo "restore check passed for {{ cloudfall_redis_service.id }}: ${latest}"
@@ -0,0 +1,10 @@
1
+ # Managed by Cloudfall. Local changes will be overwritten.
2
+ [Unit]
3
+ Description=Cloudfall Redis restore-drill schedule for {{ cloudfall_redis_service.id }}
4
+
5
+ [Timer]
6
+ OnCalendar={{ cloudfall_redis_service.backup.restoreCheckOnCalendar }}
7
+ Persistent=true
8
+
9
+ [Install]
10
+ WantedBy=timers.target
@@ -0,0 +1,2 @@
1
+ ---
2
+ cloudfall_time_timezone: Etc/UTC
@@ -0,0 +1,10 @@
1
+ ---
2
+ argument_specs:
3
+ main:
4
+ short_description: Enforce the Cloudfall UTC time baseline
5
+ options:
6
+ cloudfall_time_timezone:
7
+ type: str
8
+ choices:
9
+ - Etc/UTC
10
+ default: Etc/UTC
@@ -0,0 +1,13 @@
1
+ ---
2
+ galaxy_info:
3
+ role_name: cloudfall_time
4
+ author: Cloudfall
5
+ description: Enforce UTC and synchronized system time on Debian hosts
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: []
@@ -0,0 +1,119 @@
1
+ ---
2
+ - name: Validate UTC time target
3
+ ansible.builtin.assert:
4
+ that:
5
+ - ansible_facts["distribution"] == "Debian"
6
+ - ansible_facts["service_mgr"] == "systemd"
7
+ - cloudfall_time_timezone == "Etc/UTC"
8
+ fail_msg: Cloudfall time management requires Debian, systemd, and Etc/UTC
9
+
10
+ - name: Read current time configuration
11
+ ansible.builtin.command:
12
+ argv:
13
+ - /usr/bin/timedatectl
14
+ - show
15
+ - --property=Timezone
16
+ - --property=LocalRTC
17
+ - --property=NTP
18
+ - --property=NTPSynchronized
19
+ changed_when: false
20
+ check_mode: false
21
+ register: cloudfall_time_before
22
+
23
+ - name: Report timezone drift in check mode
24
+ ansible.builtin.debug:
25
+ msg: >-
26
+ Would change timezone from
27
+ {{ cloudfall_time_before.stdout_lines
28
+ | select('match', '^Timezone=')
29
+ | first
30
+ | default('Timezone=unknown') }}
31
+ to Timezone={{ cloudfall_time_timezone }}
32
+ changed_when: true
33
+ when:
34
+ - ansible_check_mode
35
+ - "'Timezone=' ~ cloudfall_time_timezone not in cloudfall_time_before.stdout_lines"
36
+
37
+ - name: Set UTC timezone
38
+ ansible.builtin.command:
39
+ argv:
40
+ - /usr/bin/timedatectl
41
+ - set-timezone
42
+ - "{{ cloudfall_time_timezone }}"
43
+ changed_when: true
44
+ when:
45
+ - not ansible_check_mode
46
+ - "'Timezone=' ~ cloudfall_time_timezone not in cloudfall_time_before.stdout_lines"
47
+
48
+ - name: Report local hardware clock drift in check mode
49
+ ansible.builtin.debug:
50
+ msg: Would configure the hardware clock to use UTC
51
+ changed_when: true
52
+ when:
53
+ - ansible_check_mode
54
+ - "'LocalRTC=no' not in cloudfall_time_before.stdout_lines"
55
+
56
+ - name: Configure hardware clock for UTC
57
+ ansible.builtin.command:
58
+ argv:
59
+ - /usr/bin/timedatectl
60
+ - set-local-rtc
61
+ - "0"
62
+ changed_when: true
63
+ when:
64
+ - not ansible_check_mode
65
+ - "'LocalRTC=no' not in cloudfall_time_before.stdout_lines"
66
+
67
+ - name: Report NTP drift in check mode
68
+ ansible.builtin.debug:
69
+ msg: Would enable network time synchronization
70
+ changed_when: true
71
+ when:
72
+ - ansible_check_mode
73
+ - "'NTP=yes' not in cloudfall_time_before.stdout_lines"
74
+
75
+ - name: Enable network time synchronization
76
+ ansible.builtin.command:
77
+ argv:
78
+ - /usr/bin/timedatectl
79
+ - set-ntp
80
+ - "true"
81
+ changed_when: true
82
+ when:
83
+ - not ansible_check_mode
84
+ - "'NTP=yes' not in cloudfall_time_before.stdout_lines"
85
+
86
+ - name: Read applied time configuration
87
+ ansible.builtin.command:
88
+ argv:
89
+ - /usr/bin/timedatectl
90
+ - show
91
+ - --property=Timezone
92
+ - --property=LocalRTC
93
+ - --property=NTP
94
+ changed_when: false
95
+ check_mode: false
96
+ register: cloudfall_time_after
97
+
98
+ - name: Require applied UTC time configuration
99
+ ansible.builtin.assert:
100
+ that:
101
+ - ansible_check_mode or 'Timezone=' ~ cloudfall_time_timezone in cloudfall_time_after.stdout_lines
102
+ - ansible_check_mode or 'LocalRTC=no' in cloudfall_time_after.stdout_lines
103
+ - ansible_check_mode or 'NTP=yes' in cloudfall_time_after.stdout_lines
104
+ fail_msg: The host did not converge to the Cloudfall UTC time baseline
105
+
106
+ - name: Wait for synchronized network time
107
+ ansible.builtin.command:
108
+ argv:
109
+ - /usr/bin/timedatectl
110
+ - show
111
+ - --property=NTPSynchronized
112
+ - --value
113
+ changed_when: false
114
+ check_mode: false
115
+ register: cloudfall_time_synchronized
116
+ until: cloudfall_time_synchronized.stdout == "yes"
117
+ retries: 12
118
+ delay: 5
119
+ when: not ansible_check_mode
@@ -0,0 +1,3 @@
1
+ ---
2
+ cloudfall_unattended_upgrades_configuration_path: >-
3
+ /etc/apt/apt.conf.d/20auto-upgrades
@@ -0,0 +1,8 @@
1
+ ---
2
+ argument_specs:
3
+ main:
4
+ short_description: Enable automatic Debian security upgrades
5
+ options:
6
+ cloudfall_unattended_upgrades_configuration_path:
7
+ type: path
8
+ default: /etc/apt/apt.conf.d/20auto-upgrades
@@ -0,0 +1,13 @@
1
+ ---
2
+ galaxy_info:
3
+ role_name: cloudfall_unattended_upgrades
4
+ author: Cloudfall
5
+ description: Enable automatic Debian security upgrades
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: []
@@ -0,0 +1,37 @@
1
+ ---
2
+ - name: Validate unattended-upgrades target
3
+ ansible.builtin.assert:
4
+ that:
5
+ - ansible_facts["distribution"] == "Debian"
6
+ - ansible_facts["service_mgr"] == "systemd"
7
+ fail_msg: Cloudfall unattended upgrades require a Debian systemd host
8
+
9
+ - name: Install unattended-upgrades
10
+ ansible.builtin.apt:
11
+ name: unattended-upgrades
12
+ state: present
13
+ update_cache: true
14
+ cache_valid_time: 3600
15
+
16
+ - name: Enable periodic unattended security upgrades
17
+ ansible.builtin.copy:
18
+ dest: "{{ cloudfall_unattended_upgrades_configuration_path }}"
19
+ content: |
20
+ // Managed by Cloudfall. Local changes will be overwritten.
21
+ APT::Periodic::Update-Package-Lists "1";
22
+ APT::Periodic::Unattended-Upgrade "1";
23
+ owner: root
24
+ group: root
25
+ mode: "0644"
26
+
27
+ - name: Enable the apt update timer
28
+ ansible.builtin.systemd_service:
29
+ name: apt-daily.timer
30
+ enabled: true
31
+ state: started
32
+
33
+ - name: Enable the apt upgrade timer
34
+ ansible.builtin.systemd_service:
35
+ name: apt-daily-upgrade.timer
36
+ enabled: true
37
+ state: started