mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-20 03:56:33 +00:00
Compare commits
13 Commits
5cdcc18a99
...
feature/ke
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fcf6a1ab6 | |||
| 4d9890406e | |||
| 59b652958f | |||
| a327adf8db | |||
| 7a38cb90fb | |||
| 9d6cf03f5b | |||
| 9439ac7f76 | |||
| 23353ac878 | |||
| 8beda2d45d | |||
| 5773409bd7 | |||
| b3ea962338 | |||
| b9fbf92461 | |||
| 6824e444b0 |
@@ -7,3 +7,4 @@ MODE_DEBUG: false # This enables debugging in ansible an
|
||||
MODE_RESET: false # Cleans up all Infinito.Nexus files. It's necessary to run to whole playbook and not particial roles when using this function.
|
||||
MODE_CLEANUP: "{{ MODE_DEBUG | bool }}" # Cleanup unused files and configurations
|
||||
MODE_ASSERT: "{{ MODE_DEBUG | bool }}" # Executes validation tasks during the run.
|
||||
MODE_BACKUP: true # Executes the Backup before the deployment
|
||||
|
||||
@@ -6,12 +6,12 @@ SYS_TIMER_ALL_ENABLED: "{{ MODE_DEBUG }}" # Runtime Var
|
||||
|
||||
## Server Tact Variables
|
||||
|
||||
HOURS_SERVER_AWAKE: "0..23" # Ours in which the server is "awake" (100% working). Rest of the time is reserved for maintanance
|
||||
HOURS_SERVER_AWAKE: "6..23" # Ours in which the server is "awake" (100% working). Rest of the time is reserved for maintanance
|
||||
RANDOMIZED_DELAY_SEC: "5min" # Random delay for systemd timers to avoid peak loads.
|
||||
|
||||
## Timeouts for all services
|
||||
SYS_TIMEOUT_DOCKER_RPR_HARD: "10min"
|
||||
SYS_TIMEOUT_DOCKER_RPR_SOFT: "{{ SYS_TIMEOUT_DOCKER_RPR_HARD }}"
|
||||
SYS_TIMEOUT_DOCKER_RPR_SOFT: "{{ SYS_TIMEOUT_DOCKER_RPR_HARD }}"
|
||||
SYS_TIMEOUT_CLEANUP_SERVICES: "15min"
|
||||
SYS_TIMEOUT_DOCKER_UPDATE: "20min"
|
||||
SYS_TIMEOUT_STORAGE_OPTIMIZER: "{{ SYS_TIMEOUT_DOCKER_UPDATE }}"
|
||||
|
||||
@@ -5,7 +5,7 @@ network:
|
||||
docker:
|
||||
services:
|
||||
openldap:
|
||||
image: "bitnami/openldap"
|
||||
image: "bitnamilegacy/openldap"
|
||||
name: "openldap"
|
||||
version: "latest"
|
||||
network: "openldap"
|
||||
|
||||
@@ -6,7 +6,7 @@ docker:
|
||||
name: postgres
|
||||
# Please set an version in your inventory file!
|
||||
# Rolling release isn't recommended
|
||||
version: "latest"
|
||||
version: "17-3.5"
|
||||
backup:
|
||||
database_routine: true
|
||||
cpus: "2.0"
|
||||
@@ -14,5 +14,5 @@ docker:
|
||||
mem_limit: "6g"
|
||||
pids_limit: 1024
|
||||
volumes:
|
||||
data: "postgres_data"
|
||||
network: "postgres"
|
||||
data: "postgres_data"
|
||||
network: "postgres"
|
||||
@@ -5,7 +5,7 @@ RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
git \
|
||||
postgresql-server-dev-all \
|
||||
postgresql-server-dev-{{ POSTGRES_VERSION_MAJOR | default('all', true) }} \
|
||||
&& git clone https://github.com/pgvector/pgvector.git /tmp/pgvector \
|
||||
&& cd /tmp/pgvector \
|
||||
&& make \
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# General
|
||||
application_id: svc-db-postgres
|
||||
entity_name: "{{ application_id | get_entity_name }}"
|
||||
|
||||
# Docker
|
||||
docker_compose_flush_handlers: true
|
||||
@@ -9,11 +10,12 @@ database_type: "{{ application_id | get_entity_name }
|
||||
|
||||
## Postgres
|
||||
POSTGRES_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
|
||||
POSTGRES_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.postgres.name') }}"
|
||||
POSTGRES_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.postgres.image') }}"
|
||||
POSTGRES_SUBNET: "{{ networks.local['svc-db-postgres'].subnet }}"
|
||||
POSTGRES_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.name') }}"
|
||||
POSTGRES_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.image') }}"
|
||||
POSTGRES_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.version') }}"
|
||||
POSTGRES_VERSION_MAJOR: "{{ POSTGRES_VERSION | regex_replace('^([0-9]+).*', '\\1') }}"
|
||||
POSTGRES_NETWORK_NAME: "{{ applications | get_app_conf(application_id, 'docker.network') }}"
|
||||
POSTGRES_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.postgres.version') }}"
|
||||
POSTGRES_SUBNET: "{{ networks.local['svc-db-postgres'].subnet }}"
|
||||
POSTGRES_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.POSTGRES_PASSWORD') }}"
|
||||
POSTGRES_PORT: "{{ database_port | default(ports.localhost.database[ application_id ]) }}"
|
||||
POSTGRES_INIT: "{{ database_username is defined and database_password is defined and database_name is defined }}"
|
||||
|
||||
@@ -5,21 +5,23 @@
|
||||
- sys-ctl-alm-telegram
|
||||
- sys-ctl-alm-email
|
||||
vars:
|
||||
flush_handlers: true
|
||||
system_service_timer_enabled: false
|
||||
system_service_copy_files: true
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} %I"
|
||||
system_service_tpl_on_failure: ""
|
||||
flush_handlers: true
|
||||
system_service_timer_enabled: false
|
||||
system_service_copy_files: true
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} %I"
|
||||
system_service_tpl_on_failure: ""
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
- name: "Include core service for '{{ system_service_id }}'"
|
||||
include_role:
|
||||
name: sys-service
|
||||
vars:
|
||||
flush_handlers: true
|
||||
system_service_timer_enabled: false
|
||||
system_service_copy_files: true
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} %I"
|
||||
system_service_tpl_on_failure: "" # No on failure needed, because it's anyhow the default on failure procedure
|
||||
flush_handlers: true
|
||||
system_service_timer_enabled: false
|
||||
system_service_copy_files: true
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} %I"
|
||||
system_service_tpl_on_failure: "" # No on failure needed, because it's anyhow the default on failure procedure
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
- name: Assert '{{ system_service_id }}'
|
||||
block:
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
vars:
|
||||
system_service_copy_files: false
|
||||
system_service_timer_enabled: true
|
||||
system_service_force_linear_sync: true
|
||||
system_service_force_flush: "{{ MODE_BACKUP | bool }}"
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_BACKUP_DOCKER_TO_LOCAL }}"
|
||||
system_service_tpl_exec_start_pre: '/usr/bin/python {{ PATH_SYSTEM_LOCK_SCRIPT }} {{ SYS_SERVICE_GROUP_MANIPULATION | join(" ") }} --ignore {{ SYS_SERVICE_BACKUP_DOCKER_2_LOC }} --timeout "{{ SYS_TIMEOUT_BACKUP_SERVICES }}"'
|
||||
system_service_tpl_exec_start: "/bin/sh -c '{{ BKP_DOCKER_2_LOC_EXEC }}'"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
system_service_tpl_exec_start: dockreap --no-confirmation
|
||||
system_service_tpl_exec_start_pre: "" # Anonymous volumes can allways be removed. It isn't necessary to wait for any service to stop.
|
||||
system_service_copy_files: false
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
- include_tasks: utils/run_once.yml
|
||||
when:
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} --backups-folder-path {{ BACKUPS_FOLDER_PATH }} --maximum-backup-size-percent {{SIZE_PERCENT_MAXIMUM_BACKUP}}"
|
||||
system_service_tpl_exec_start_pre: '/usr/bin/python {{ PATH_SYSTEM_LOCK_SCRIPT }} {{ SYS_SERVICE_GROUP_MANIPULATION | join(" ") }} --ignore {{ SYS_SERVICE_GROUP_CLEANUP | join(" ") }} --timeout "{{ SYS_TIMEOUT_BACKUP_SERVICES }}"'
|
||||
system_service_copy_files: true
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
- include_tasks: utils/run_once.yml
|
||||
vars:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
- include_role:
|
||||
name: sys-service
|
||||
vars:
|
||||
system_service_timer_enabled: true
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_CLEANUP_CERTS }}"
|
||||
system_service_copy_files: false
|
||||
system_service_timer_enabled: true
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_CLEANUP_CERTS }}"
|
||||
system_service_copy_files: false
|
||||
system_service_force_linear_sync: false
|
||||
@@ -14,3 +14,4 @@
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} {{ SIZE_PERCENT_CLEANUP_DISC_SPACE }}"
|
||||
system_service_tpl_exec_start_pre: '/usr/bin/python {{ PATH_SYSTEM_LOCK_SCRIPT }} {{ SYS_SERVICE_GROUP_MANIPULATION | join(" ") }} --ignore {{ SYS_SERVICE_GROUP_CLEANUP | join(" ") }} --timeout "{{ SYS_TIMEOUT_BACKUP_SERVICES }}"'
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
@@ -21,5 +21,5 @@
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_tpl_exec_start_pre: '/usr/bin/python {{ PATH_SYSTEM_LOCK_SCRIPT }} {{ SYS_SERVICE_GROUP_MANIPULATION | join(" ") }} --ignore {{ SYS_SERVICE_GROUP_CLEANUP| join(" ") }} --timeout "{{ SYS_TIMEOUT_CLEANUP_SERVICES }}"'
|
||||
system_service_tpl_exec_start: '/bin/sh -c "{{ CLEANUP_FAILED_BACKUPS_PKG }} --all --workers {{ CLEANUP_FAILED_BACKUPS_WORKERS }} --yes"'
|
||||
|
||||
system_service_force_linear_sync: false
|
||||
- include_tasks: utils/run_once.yml
|
||||
|
||||
@@ -14,6 +14,32 @@ Designed for Archlinux systems, this role periodically checks whether web resour
|
||||
- **Domain Extraction:** Parses all `.conf` files in the NGINX config folder to determine the list of domains to check.
|
||||
- **Automated Execution:** Registers a systemd service and timer for recurring health checks.
|
||||
- **Error Notification:** Integrates with `sys-ctl-alm-compose` for alerting on failure.
|
||||
- **Ignore List Support:** Optional variable to suppress network block reports from specific external domains.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Variables
|
||||
|
||||
- **`HEALTH_CSP_IGNORE_NETWORK_BLOCKS_FROM`** (list, default: `[]`)
|
||||
Optional list of domains whose network block failures (e.g., ORB) should be ignored during CSP checks.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
HEALTH_CSP_IGNORE_NETWORK_BLOCKS_FROM:
|
||||
- pxscdn.com
|
||||
- cdn.example.org
|
||||
```
|
||||
|
||||
This will run the CSP checker with:
|
||||
|
||||
```bash
|
||||
checkcsp start --short --ignore-network-blocks-from pxscdn.com -- cdn.example.org <domains...>
|
||||
```
|
||||
|
||||
### Systemd Integration
|
||||
|
||||
The role configures a systemd service and timer which executes the CSP crawler periodically against all NGINX domains.
|
||||
|
||||
## License
|
||||
|
||||
@@ -24,4 +50,4 @@ Infinito.Nexus NonCommercial License
|
||||
|
||||
Kevin Veen-Birkenbach
|
||||
Consulting & Coaching Solutions
|
||||
[https://www.veen.world](https://www.veen.world)
|
||||
[https://www.veen.world](https://www.veen.world)
|
||||
|
||||
5
roles/sys-ctl-hlth-csp/defaults/main.yml
Normal file
5
roles/sys-ctl-hlth-csp/defaults/main.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
# List of domains whose network block failures (e.g., ORB) should be ignored
|
||||
# during CSP checks. This is useful for suppressing known external resources
|
||||
# (e.g., third-party CDNs) that cannot be influenced but otherwise cause
|
||||
# unnecessary alerts in the crawler reports.
|
||||
HEALTH_CSP_IGNORE_NETWORK_BLOCKS_FROM: []
|
||||
@@ -21,11 +21,20 @@ def extract_domains(config_path):
|
||||
print(f"Directory {config_path} not found.", file=sys.stderr)
|
||||
return None
|
||||
|
||||
def run_checkcsp(domains):
|
||||
def run_checkcsp(domains, ignore_network_blocks_from):
|
||||
"""
|
||||
Executes the 'checkcsp' command with the given domains.
|
||||
Executes the 'checkcsp' command with the given domains and optional ignores.
|
||||
"""
|
||||
cmd = ["checkcsp", "start", "--short"] + domains
|
||||
cmd = ["checkcsp", "start", "--short"]
|
||||
|
||||
# pass through ignore list only if not empty
|
||||
if ignore_network_blocks_from:
|
||||
cmd.append("--ignore-network-blocks-from")
|
||||
cmd.extend(ignore_network_blocks_from)
|
||||
cmd.append("--")
|
||||
|
||||
cmd += domains
|
||||
|
||||
try:
|
||||
result = subprocess.run(cmd, check=True)
|
||||
return result.returncode
|
||||
@@ -45,6 +54,12 @@ def main():
|
||||
required=True,
|
||||
help="Directory containing NGINX .conf files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ignore-network-blocks-from",
|
||||
nargs="*",
|
||||
default=[],
|
||||
help="Optional: one or more domains whose network block failures should be ignored"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
domains = extract_domains(args.nginx_config_dir)
|
||||
@@ -55,7 +70,7 @@ def main():
|
||||
print("No domains found to check.")
|
||||
sys.exit(0)
|
||||
|
||||
rc = run_checkcsp(domains)
|
||||
rc = run_checkcsp(domains, args.ignore_network_blocks_from)
|
||||
sys.exit(rc)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_tpl_timeout_start_sec: "{{ CURRENT_PLAY_DOMAINS_ALL | timeout_start_sec_for_domains }}"
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} --nginx-config-dir={{ NGINX.DIRECTORIES.HTTP.SERVERS }}"
|
||||
system_service_tpl_exec_start: >-
|
||||
{{ system_service_script_exec }}
|
||||
--nginx-config-dir={{ NGINX.DIRECTORIES.HTTP.SERVERS }}
|
||||
--ignore-network-blocks-from {{ HEALTH_CSP_IGNORE_NETWORK_BLOCKS_FROM | join(' ') }}
|
||||
|
||||
- include_tasks: utils/run_once.yml
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
- include_role:
|
||||
name: sys-service
|
||||
vars:
|
||||
system_service_state: restarted
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_MAINTANANCE_LETSENCRYPT_DEPLOY }}"
|
||||
persistent: "true"
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_state: restarted
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_MAINTANANCE_LETSENCRYPT_DEPLOY }}"
|
||||
persistent: "true"
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_force_linear_sync: false
|
||||
@@ -15,8 +15,9 @@
|
||||
- include_role:
|
||||
name: sys-service
|
||||
vars:
|
||||
system_service_copy_files: false
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_MAINTANANCE_LETSENCRYPT_RENEW }}"
|
||||
persistent: true
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_copy_files: false
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_MAINTANANCE_LETSENCRYPT_RENEW }}"
|
||||
persistent: true
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
- include_role:
|
||||
name: sys-service
|
||||
vars:
|
||||
system_service_suppress_flush: true # It takes a super long time - Better wait for failure of timed service instead of executing it on every play
|
||||
system_service_copy_files: false
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_REPAIR_BTRFS_AUTO_BALANCER }}"
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_tpl_exec_start: "/bin/sh -c 'btrfs-auto-balancer 90 10'"
|
||||
system_service_suppress_flush: true # It takes a super long time - Better wait for failure of timed service instead of executing it on every play
|
||||
system_service_copy_files: false
|
||||
system_service_on_calendar: "{{ SYS_SCHEDULE_REPAIR_BTRFS_AUTO_BALANCER }}"
|
||||
system_service_timer_enabled: true
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_tpl_exec_start: "/bin/sh -c 'btrfs-auto-balancer 90 10'"
|
||||
system_service_force_linear_sync: true
|
||||
@@ -12,5 +12,6 @@
|
||||
system_service_tpl_exec_start: '{{ system_service_script_exec }} {{ PATH_DOCKER_COMPOSE_INSTANCES }}'
|
||||
system_service_tpl_exec_start_post: "/usr/bin/systemctl start {{ SYS_SERVICE_CLEANUP_ANONYMOUS_VOLUMES }}"
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_force_linear_sync: true
|
||||
|
||||
- include_tasks: utils/run_once.yml
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
system_service_tpl_exec_start_pre: "/usr/bin/python {{ PATH_SYSTEM_LOCK_SCRIPT }} {{ SYS_SERVICE_GROUP_MANIPULATION | join(' ') }} --ignore {{ SYS_SERVICE_GROUP_CLEANUP| join(' ') }} {{ SYS_SERVICE_REPAIR_DOCKER_SOFT }} --timeout '{{ SYS_TIMEOUT_DOCKER_RPR_SOFT }}'"
|
||||
system_service_tpl_exec_start: >
|
||||
/bin/sh -c '{{ system_service_script_exec }} --manipulation-string "{{ SYS_SERVICE_GROUP_MANIPULATION | join(" ") }}" {{ PATH_DOCKER_COMPOSE_INSTANCES }}'
|
||||
system_service_force_linear_sync: true
|
||||
|
||||
- include_tasks: utils/run_once.yml
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
- name: "Enable systemctl service"
|
||||
systemd:
|
||||
name: "{{ system_service_id | get_service_name(SOFTWARE_NAME) }}"
|
||||
name: "{{ system_service_name }}"
|
||||
enabled: yes
|
||||
daemon_reload: true
|
||||
become: true
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
async: "{{ system_service_async }}"
|
||||
poll: "{{ system_service_poll }}"
|
||||
listen: refresh systemctl service
|
||||
|
||||
- name: "Set systemctl service state"
|
||||
systemd:
|
||||
name: "{{ system_service_id | get_service_name(SOFTWARE_NAME) }}"
|
||||
name: "{{ system_service_name }}"
|
||||
state: "{{ system_service_state }}"
|
||||
become: true
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
||||
async: "{{ system_service_async }}"
|
||||
poll: "{{ system_service_poll }}"
|
||||
when: not (system_service_suppress_flush | bool)
|
||||
listen: refresh systemctl service
|
||||
@@ -31,7 +31,7 @@
|
||||
- name: "setup systemctl '{{ system_service_id }}'"
|
||||
template:
|
||||
src: "{{ system_service_template_src }}"
|
||||
dest: "{{ [ PATH_SYSTEM_SERVICE_DIR, system_service_id | get_service_name(SOFTWARE_NAME) ] | path_join }}"
|
||||
dest: "{{ [ PATH_SYSTEM_SERVICE_DIR, system_service_name ] | path_join }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
@@ -46,5 +46,5 @@
|
||||
command: /bin/true
|
||||
notify: refresh systemctl service
|
||||
when: not system_service_uses_at
|
||||
when: system_force_flush | bool
|
||||
when: system_service_force_flush | bool
|
||||
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
UNIT_SUFFIX_REMOVER_PACKAGE: "unsure"
|
||||
UNIT_SUFFIX_REMOVER_PACKAGE: "unsure"
|
||||
system_service_name: "{{ system_service_id | get_service_name(SOFTWARE_NAME) }}"
|
||||
|
||||
## Paths
|
||||
system_service_role_name: "{{ system_service_id | regex_replace('@','') }}"
|
||||
system_service_role_dir: "{{ [ playbook_dir, 'roles', system_service_role_name ] | path_join }}"
|
||||
system_service_script_dir: "{{ [ PATH_SYSTEMCTL_SCRIPTS, system_service_id ] | path_join }}"
|
||||
system_service_role_name: "{{ system_service_id | regex_replace('@','') }}"
|
||||
system_service_role_dir: "{{ [ playbook_dir, 'roles', system_service_role_name ] | path_join }}"
|
||||
system_service_script_dir: "{{ [ PATH_SYSTEMCTL_SCRIPTS, system_service_id ] | path_join }}"
|
||||
|
||||
## Settings
|
||||
system_force_flush: "{{ SYS_SERVICE_ALL_ENABLED | bool }}" # When set to true it activates the flushing of services. defaults to SYS_SERVICE_ALL_ENABLED
|
||||
system_service_suppress_flush: "{{ (system_service_id in SYS_SERVICE_SUPPRESS_FLUSH) | bool }}" # When set to true it suppresses the flushing of services
|
||||
system_service_copy_files: true # When set to false file copying will be skipped
|
||||
system_service_timer_enabled: false # When set to true timer will be loaded
|
||||
system_service_state: "{{ SYS_SERVICE_DEFAULT_STATE }}"
|
||||
system_service_force_linear_sync: "{{ system_service_name in SYS_SERVICE_GROUP_MANIPULATION }}" # Disables automatic async
|
||||
system_service_force_flush: "{{ SYS_SERVICE_ALL_ENABLED | bool }}" # When set to true it activates the flushing of services. defaults to SYS_SERVICE_ALL_ENABLED
|
||||
system_service_suppress_flush: "{{ (system_service_id in SYS_SERVICE_SUPPRESS_FLUSH) | bool }}" # When set to true it suppresses the flushing of services
|
||||
system_service_copy_files: true # When set to false file copying will be skipped
|
||||
system_service_timer_enabled: false # When set to true timer will be loaded
|
||||
system_service_state: "{{ SYS_SERVICE_DEFAULT_STATE }}"
|
||||
|
||||
## ASYNC Settings
|
||||
system_service_async: "{{ omit if (system_service_force_linear_sync | bool or not ASYNC_ENABLED | bool) else ASYNC_TIME }}"
|
||||
system_service_poll: "{{ omit if (system_service_force_linear_sync | bool or not ASYNC_ENABLED | bool) else ASYNC_POLL }}"
|
||||
|
||||
# Dynamic Loaded ( Just available when dependencies are loaded )
|
||||
system_service_script_base: "{{ system_service_script_src | basename | regex_replace('\\.j2$', '') }}"
|
||||
system_service_script_type: "{{ system_service_script_base | filetype }}"
|
||||
system_service_script_inter: "/bin/{{ 'bash' if system_service_script_type == 'sh' else 'python3'}}"
|
||||
system_service_script_exec: "{{ system_service_script_inter }} {{ system_service_id | get_service_script_path( system_service_script_type ) }}"
|
||||
system_service_script_base: "{{ system_service_script_src | basename | regex_replace('\\.j2$', '') }}"
|
||||
system_service_script_type: "{{ system_service_script_base | filetype }}"
|
||||
system_service_script_inter: "/bin/{{ 'bash' if system_service_script_type == 'sh' else 'python3'}}"
|
||||
system_service_script_exec: "{{ system_service_script_inter }} {{ system_service_id | get_service_script_path( system_service_script_type ) }}"
|
||||
|
||||
# Service template
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
include_role:
|
||||
name: sys-ctl-cln-anon-volumes
|
||||
vars:
|
||||
system_force_flush: true
|
||||
system_service_force_flush: true
|
||||
- include_tasks: utils/run_once.yml
|
||||
when: run_once_sys_ctl_cln_anon_volumes is not defined
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
# Configure CORS headers dynamically based on role variables.
|
||||
# If no variable is defined, defaults are applied (e.g. same-origin).
|
||||
# Discussion: https://chat.openai.com/share/2671b961-c1b0-472d-bae2-2804d0455e8a
|
||||
{# Configure CORS headers dynamically based on role variables.
|
||||
If no variable is defined, defaults are applied (e.g. same-origin).
|
||||
Discussion: https://chat.openai.com/share/2671b961-c1b0-472d-bae2-2804d0455e8a #}
|
||||
|
||||
{# Access-Control-Allow-Origin #}
|
||||
{% if aca_origin is defined %}
|
||||
add_header 'Access-Control-Allow-Origin' {{ aca_origin }};
|
||||
{% else %}
|
||||
add_header 'Access-Control-Allow-Origin' $scheme://$host always;
|
||||
{% endif %}
|
||||
|
||||
{# Access-Control-Allow-Credentials #}
|
||||
|
||||
@@ -17,6 +17,10 @@ docker:
|
||||
image: "baserow/baserow"
|
||||
version: "latest"
|
||||
name: "baserow"
|
||||
cpus: 1.0
|
||||
mem_reservation: 0.5g
|
||||
mem_limit: 1g
|
||||
pids_limit: 512
|
||||
volumes:
|
||||
data: "baserow_data"
|
||||
server:
|
||||
|
||||
@@ -64,12 +64,6 @@
|
||||
depends_on:
|
||||
{{ ESPOCRM_SERVICE }}:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "exec 3<>/dev/tcp/127.0.0.1/8080 && echo 'OK' && exec 3<&- 3>&-"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 40s
|
||||
|
||||
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
|
||||
data:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
load_dependencies: True # When set to false the dependencies aren't loaded. Helpful for developing
|
||||
load_dependencies: True # When set to false the dependencies aren't loaded. Helpful for developing
|
||||
actions:
|
||||
import_realm: True # Import REALM
|
||||
import_realm: True # Import REALM
|
||||
create_automation_client: True
|
||||
features:
|
||||
matomo: true
|
||||
css: true
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
shell: "{{ KEYCLOAK_EXEC_KCADM }} get client-scopes -r {{ KEYCLOAK_REALM }} --format json"
|
||||
register: all_scopes
|
||||
changed_when: false
|
||||
failed_when: "'HTTP 401' in (all_scopes.stderr | default(''))"
|
||||
|
||||
- name: Extract RBAC scope id
|
||||
set_fact:
|
||||
|
||||
63
roles/web-app-keycloak/tasks/05a_service_account.yml
Normal file
63
roles/web-app-keycloak/tasks/05a_service_account.yml
Normal file
@@ -0,0 +1,63 @@
|
||||
# Creates a confidential client with service account, fetches the secret,
|
||||
# and grants realm-management/realm-admin to its service-account user.
|
||||
|
||||
- name: "Ensure automation client exists (confidential + service accounts)"
|
||||
shell: |
|
||||
{{ KEYCLOAK_EXEC_KCADM }} create clients -r {{ KEYCLOAK_REALM }} \
|
||||
-s clientId={{ KEYCLOAK_AUTOMATION_CLIENT_ID }} \
|
||||
-s protocol=openid-connect \
|
||||
-s publicClient=false \
|
||||
-s serviceAccountsEnabled=true \
|
||||
-s directAccessGrantsEnabled=false
|
||||
register: create_client
|
||||
changed_when: create_client.rc == 0
|
||||
failed_when: create_client.rc != 0 and ('already exists' not in (create_client.stderr | lower))
|
||||
|
||||
- name: "Resolve automation client id"
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get clients -r {{ KEYCLOAK_REALM }}
|
||||
--query 'clientId={{ KEYCLOAK_AUTOMATION_CLIENT_ID }}' --fields id --format json | jq -r '.[0].id'
|
||||
register: auto_client_id_cmd
|
||||
changed_when: false
|
||||
|
||||
- name: "Fail if client id could not be resolved"
|
||||
assert:
|
||||
that:
|
||||
- "(auto_client_id_cmd.stdout | trim) is match('^[0-9a-f-]+$')"
|
||||
fail_msg: "Automation client id could not be resolved."
|
||||
|
||||
- name: "Read client secret"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get clients/{{ auto_client_id_cmd.stdout | trim }}/client-secret
|
||||
-r {{ KEYCLOAK_REALM }} --format json | jq -r .value
|
||||
register: auto_client_secret_cmd
|
||||
changed_when: false
|
||||
|
||||
- name: "Expose client secret as a fact"
|
||||
set_fact:
|
||||
KEYCLOAK_AUTOMATION_CLIENT_SECRET: "{{ auto_client_secret_cmd.stdout | trim }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Grant {{ KEYCLOAK_AUTOMATION_GRANT_ROLE }} to service account"
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} add-roles -r {{ KEYCLOAK_REALM }}
|
||||
--uusername service-account-{{ KEYCLOAK_AUTOMATION_CLIENT_ID }}
|
||||
--cclientid realm-management
|
||||
--rolename {{ KEYCLOAK_AUTOMATION_GRANT_ROLE }}
|
||||
register: grant_role
|
||||
changed_when: grant_role.rc == 0
|
||||
failed_when: grant_role.rc != 0 and ('already exists' not in (grant_role.stderr | lower))
|
||||
|
||||
- name: "Verify client-credentials login works"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} config credentials
|
||||
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }}
|
||||
--realm {{ KEYCLOAK_REALM }}
|
||||
--client {{ KEYCLOAK_AUTOMATION_CLIENT_ID }}
|
||||
--client-secret {{ KEYCLOAK_AUTOMATION_CLIENT_SECRET }} &&
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get realms/{{ KEYCLOAK_REALM }} --format json | jq -r '.realm'
|
||||
register: verify_cc
|
||||
changed_when: false
|
||||
failed_when: (verify_cc.rc != 0) or ((verify_cc.stdout | trim) != (KEYCLOAK_REALM | trim))
|
||||
@@ -36,6 +36,42 @@
|
||||
--password {{ KEYCLOAK_MASTER_API_USER_PASSWORD }}
|
||||
changed_when: false
|
||||
|
||||
- name: Verify kcadm session works (quick read)
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get realms --format json | jq -r '.[0].realm' | head -n1
|
||||
register: kcadm_verify
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
(kcadm_verify.rc != 0)
|
||||
or ('HTTP 401' in (kcadm_verify.stderr | default('')))
|
||||
or ((kcadm_verify.stdout | trim) == '')
|
||||
|
||||
# --- Create & grant automation service account (Option A) ---
|
||||
- name: "Ensure automation service account client (Option A)"
|
||||
include_tasks: 05a_service_account.yml
|
||||
when: applications | get_app_conf(application_id, 'actions.create_automation_client', True)
|
||||
|
||||
# --- Switch session to the service account for all subsequent API work ---
|
||||
- name: kcadm login (realm) using service account
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} config credentials
|
||||
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }}
|
||||
--realm {{ KEYCLOAK_REALM }}
|
||||
--client {{ KEYCLOAK_AUTOMATION_CLIENT_ID }}
|
||||
--client-secret {{ KEYCLOAK_AUTOMATION_CLIENT_SECRET }}
|
||||
changed_when: false
|
||||
|
||||
- name: Verify kcadm session works (exact realm via service account)
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get realms/{{ KEYCLOAK_REALM }} --format json | jq -r '.realm'
|
||||
register: kcadm_verify_sa
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
(kcadm_verify_sa.rc != 0)
|
||||
or ('HTTP 401' in (kcadm_verify_sa.stderr | default('')))
|
||||
or ((kcadm_verify_sa.stdout | trim) != (KEYCLOAK_REALM | trim))
|
||||
|
||||
- name: "Update Client settings"
|
||||
vars:
|
||||
kc_object_kind: "client"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# General
|
||||
application_id: "web-app-keycloak" # Internal Infinito.Nexus application id
|
||||
database_type: "postgres" # Database which will be used
|
||||
application_id: "web-app-keycloak" # Internal Infinito.Nexus application id
|
||||
database_type: "postgres" # Database which will be used
|
||||
|
||||
# Keycloak
|
||||
|
||||
@@ -34,9 +34,16 @@ KEYCLOAK_ADMIN_PASSWORD: "{{ applications | get_app_conf(application_
|
||||
|
||||
## Docker
|
||||
KEYCLOAK_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}" # Name of the keycloak docker container
|
||||
KEYCLOAK_EXEC_KCADM: "docker exec -i {{ KEYCLOAK_CONTAINER }} /opt/keycloak/bin/kcadm.sh" # Init script for keycloak
|
||||
KEYCLOAK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.image') }}" # Keycloak docker image
|
||||
KEYCLOAK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.version') }}" # Keycloak docker version
|
||||
KEYCLOAK_KCADM_CONFIG: "/opt/keycloak/data/kcadm.config"
|
||||
KEYCLOAK_EXEC_KCADM: "docker exec -i {{ KEYCLOAK_CONTAINER }} /opt/keycloak/bin/kcadm.sh --config {{ KEYCLOAK_KCADM_CONFIG }}"
|
||||
|
||||
## Automation Service Account (Option A)
|
||||
KEYCLOAK_AUTOMATION_CLIENT_ID: "infinito-automation"
|
||||
KEYCLOAK_AUTOMATION_GRANT_ROLE: "realm-admin" # or granular roles if you prefer
|
||||
# Will be discovered dynamically and set as a fact during the run:
|
||||
# KEYCLOAK_AUTOMATION_CLIENT_SECRET
|
||||
|
||||
## Server
|
||||
KEYCLOAK_SERVER_HOST: "127.0.0.1:{{ ports.localhost.http[application_id] }}"
|
||||
|
||||
@@ -33,7 +33,7 @@ docker:
|
||||
enabled: true
|
||||
moodle:
|
||||
version: "4.5" # Latest LTS - Necessary for OIDC
|
||||
image: bitnami/moodle
|
||||
image: bitnamilegacy/moodle
|
||||
name: moodle
|
||||
volumes:
|
||||
data: moodle_data
|
||||
|
||||
@@ -23,7 +23,7 @@ server:
|
||||
- "blob:"
|
||||
domains:
|
||||
canonical:
|
||||
- "cloud.{{ PRIMARY_DOMAIN }}"
|
||||
- "next.cloud.{{ PRIMARY_DOMAIN }}"
|
||||
aliases: []
|
||||
docker:
|
||||
volumes:
|
||||
|
||||
@@ -2,16 +2,20 @@ credentials: {}
|
||||
docker:
|
||||
services:
|
||||
redis:
|
||||
enabled: false
|
||||
enabled: false
|
||||
database:
|
||||
enabled: true
|
||||
type: postgres
|
||||
enabled: true
|
||||
type: postgres
|
||||
xwiki:
|
||||
image: xwiki
|
||||
version: lts-<< defaults_applications[web-app-xwiki].docker.services.database.type >>-tomcat
|
||||
name: xwiki
|
||||
image: xwiki
|
||||
version: lts-<< defaults_applications[web-app-xwiki].docker.services.database.type >>-tomcat
|
||||
name: xwiki
|
||||
backup:
|
||||
no_stop_required: true
|
||||
cpus: 1.0
|
||||
mem_reservation: 1g
|
||||
mem_limit: 2g
|
||||
pids_limit: 1024
|
||||
volumes:
|
||||
data: "xwiki_data"
|
||||
features:
|
||||
|
||||
Reference in New Issue
Block a user