Skip to content

Commit 42d22e5

Browse files
authored
Merge pull request #11 from 33Fraise33/opencode/issue10-20260723203408
Photon deploy, firewall & tests
2 parents a64a3be + 915e4a4 commit 42d22e5

19 files changed

Lines changed: 349 additions & 6 deletions

File tree

AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@
2424

2525
## Roles And Containers
2626

27-
- New roles use the Galaxy layout: `defaults/main.yml`, `tasks/main.yml`, `handlers/main.yml`, `templates/`, `meta/main.yml`, and `README.md`. Put configurable image tags and ports in `defaults`; use `tasks/main.yml` to compose task files.
27+
- New roles use the Galaxy layout: `defaults/main.yml`, `tasks/main.yml`, `handlers/main.yml`, `templates/`, `meta/main.yml`, and `README.md`; use `tasks/main.yml` to compose task files.
2828
- Use `community.docker` modules for Docker containers, networks, and volumes instead of raw Docker shell commands. Make tasks idempotent and declare container state, restart policy, and other intended configuration explicitly.
2929
- Keep secrets, passwords, and API keys in variables for Vault or CI injection, never literals. Generate container config with `.j2` templates and bind-mount it into the container.
30-
- Prefer sane non-critical defaults with Jinja's `default` modifier instead of populating `defaults/main.yml` broadly. Only define critical variables in `defaults/main.yml`; values such as a database name or role-specific username may safely default to the role name, but passwords and other secrets must always be provided explicitly.
30+
- This is personal infrastructure, not a public role collection. Hardcode stable, role-specific settings in tasks. Add a variable only for a secret, an inventory-specific setting, a deliberate override, or a value likely to change frequently. Keep defaults limited to required host-specific values and test overrides.
31+
- For a role with writable persisted data, create a dedicated system user and own its persisted host directories and files with that user. Run the container as that numeric UID:GID when the image supports it. If an image requires a root entrypoint, use its supported UID/GID mechanism and verify that its long-running application process drops privileges; document the exception.
3132
- Prefer application image versions in this order: first, use a major version tag such as `v3` where possible and configure WUD to update within that major version, preventing beta or other incompatible releases; second, use the `latest` tag without setting WUD configuration on the container; third, use a fixed image version tag only when explicitly requested by the owner.
3233

3334
## Testing And CI

molecule/dawarich/converge.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,8 @@
1313
dawarich_postgres_image: imresamu/postgis
1414
dawarich_services_network: molecule-services
1515
dawarich_dns_servers: []
16+
dawarich_photon_api_host: photon.frai.se
17+
dawarich_photon_api_port: "443"
18+
dawarich_photon_api_use_https: "true"
1619
roles:
1720
- role: dawarich

molecule/dawarich/verify.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,25 @@
3131
- name: Assert shared Valkey is running
3232
ansible.builtin.assert:
3333
that: valkey_container.container.State.Status == 'running'
34+
35+
- name: Inspect Dawarich Sidekiq worker
36+
community.docker.docker_container_info:
37+
name: dawarich_sidekiq
38+
register: dawarich_sidekiq
39+
40+
- name: Assert Sidekiq Photon configuration
41+
ansible.builtin.assert:
42+
that:
43+
- dawarich_sidekiq.container.Config.Env is contains('PHOTON_API_HOST=photon.frai.se')
44+
- dawarich_sidekiq.container.Config.Env is contains('PHOTON_API_PORT=443')
45+
- dawarich_sidekiq.container.Config.Env is contains('PHOTON_API_USE_HTTPS=true')
46+
47+
- name: Inspect Dawarich web application
48+
community.docker.docker_container_info:
49+
name: dawarich_app
50+
register: dawarich_app
51+
52+
- name: Assert web application has no Photon configuration
53+
ansible.builtin.assert:
54+
that:
55+
- dawarich_app.container.Config.Env | select('match', '^PHOTON_API_') | list | length == 0

molecule/photon/cleanup.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
- name: Cleanup Photon test dependencies
3+
hosts: all
4+
gather_facts: false
5+
tasks:
6+
- name: Remove Photon test container
7+
community.docker.docker_container:
8+
name: photon
9+
state: absent
10+
11+
- name: Remove Photon test database directory
12+
ansible.builtin.file:
13+
path: /tmp/molecule-photon-data
14+
state: absent
15+
16+
- name: Remove shared Traefik test network
17+
community.docker.docker_network:
18+
name: molecule-traefik
19+
state: absent

molecule/photon/converge.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
- name: Converge Photon role
3+
hosts: all
4+
gather_facts: false
5+
vars:
6+
photon_image: rtuszik/photon-docker:latest
7+
photon_command:
8+
- python3
9+
- -m
10+
- http.server
11+
- "2322"
12+
photon_database_path: /tmp/molecule-photon-data
13+
photon_hostname: photon.test
14+
photon_network: molecule-traefik
15+
photon_healthcheck:
16+
test:
17+
- CMD-SHELL
18+
- >-
19+
curl -fsS http://127.0.0.1:2322/ > /dev/null
20+
interval: 5s
21+
timeout: 5s
22+
retries: 3
23+
start_period: 1s
24+
pre_tasks:
25+
- name: Create shared Traefik test network
26+
community.docker.docker_network:
27+
name: molecule-traefik
28+
driver: bridge
29+
roles:
30+
- role: photon
31+
tasks:
32+
- name: Wait for Photon test container health check
33+
community.docker.docker_container:
34+
name: photon
35+
state: healthy
36+
healthy_wait_timeout: 30
37+
38+
- name: Pause for Photon runtime inspection
39+
ansible.builtin.pause:
40+
seconds: 5

molecule/photon/molecule.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
driver:
3+
name: docker
4+
5+
ansible:
6+
cfg:
7+
defaults:
8+
roles_path: ${MOLECULE_PROJECT_DIRECTORY}/roles
9+
10+
scenario:
11+
test_sequence:
12+
- destroy
13+
- syntax
14+
- create
15+
- prepare
16+
- converge
17+
- idempotence
18+
- verify
19+
- cleanup
20+
- destroy
21+
22+
platforms:
23+
- name: photon-instance
24+
image: geerlingguy/docker-debian12-ansible:latest
25+
pre_build_image: true
26+
privileged: true
27+
volumes:
28+
- /var/run/docker.sock:/var/run/docker.sock
29+
30+
provisioner:
31+
name: ansible
32+
playbooks:
33+
prepare: prepare.yml
34+
inventory:
35+
host_vars:
36+
photon-instance:
37+
ansible_python_interpreter: /usr/bin/python3
38+
39+
verifier:
40+
name: ansible

molecule/photon/prepare.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
- name: Prepare Photon dependencies
3+
hosts: all
4+
gather_facts: false
5+
become: true
6+
tasks:
7+
- name: Install Docker SDK dependencies
8+
ansible.builtin.apt:
9+
name:
10+
- python3-docker
11+
- python3-requests
12+
state: present
13+
update_cache: true

molecule/photon/verify.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
- name: Verify Photon deployment
3+
hosts: all
4+
gather_facts: false
5+
vars:
6+
photon_database_path: /tmp/molecule-photon-data
7+
photon_network: molecule-traefik
8+
tasks:
9+
- name: Gather numeric UID and GID of the host photon user
10+
ansible.builtin.getent:
11+
database: passwd
12+
key: photon
13+
14+
- name: Inspect Photon data directory
15+
ansible.builtin.stat:
16+
path: "{{ photon_database_path }}"
17+
register: photon_data_directory
18+
19+
- name: Assert Photon data directory belongs to the Photon user
20+
ansible.builtin.assert:
21+
that:
22+
- photon_data_directory.stat.pw_name == 'photon'
23+
- photon_data_directory.stat.gr_name == 'photon'
24+
25+
- name: Inspect Photon container
26+
community.docker.docker_container_info:
27+
name: photon
28+
register: photon_container
29+
30+
- name: Assert Photon container configuration
31+
ansible.builtin.assert:
32+
that:
33+
- photon_container.container.State.Status == 'running'
34+
- photon_container.container.State.Health.Status == 'healthy'
35+
- photon_container.container.Config.Image == 'rtuszik/photon-docker:latest'
36+
- photon_container.container.HostConfig.RestartPolicy.Name == 'always'
37+
- >-
38+
photon_container.container.HostConfig.PortBindings is none or
39+
photon_container.container.HostConfig.PortBindings | length == 0
40+
- photon_network in photon_container.container.NetworkSettings.Networks
41+
- >-
42+
photon_container.container.Mounts | selectattr('Destination', 'equalto',
43+
'/photon/data') | list | length == 1
44+
- >-
45+
(photon_container.container.Mounts |
46+
selectattr('Destination', 'equalto', '/photon/data') |
47+
map(attribute='Source') | first) == photon_database_path
48+
- photon_container.container.Config.Env is contains('PUID=' ~ ansible_facts.getent_passwd['photon'][1])
49+
- photon_container.container.Config.Env is contains('PGID=' ~ ansible_facts.getent_passwd['photon'][2])
50+
- photon_container.container.Config.Env is contains('UPDATE_STRATEGY=SEQUENTIAL')
51+
- photon_container.container.Config.Env is contains('UPDATE_INTERVAL=30d')
52+
- photon_container.container.Config.Labels['traefik.enable'] == 'true'
53+
- photon_container.container.Config.Labels['traefik.http.routers.photon.rule'] == 'Host(`photon.test`)'
54+
- photon_container.container.Config.Labels['traefik.http.routers.photon.tls'] == 'true'
55+
- photon_container.container.Config.Labels['traefik.http.routers.photon.tls.certresolver'] == 'le'
56+
- photon_container.container.Config.Labels['traefik.http.services.photon.loadbalancer.server.port'] == '2322'
57+
58+
- name: Check Photon API endpoint from the container
59+
community.docker.docker_container_exec:
60+
container: photon
61+
command: curl -fsS http://127.0.0.1:2322/
62+
register: photon_api_check
63+
changed_when: false
64+
65+
- name: Assert Photon API endpoint succeeded
66+
ansible.builtin.assert:
67+
that: photon_api_check.rc == 0
68+
69+
- name: Inspect Photon service process user
70+
community.docker.docker_container_exec:
71+
container: photon
72+
command: >-
73+
sh -c "awk '/^Uid:/ { print $2 }' /proc/1/status"
74+
register: photon_process_uid
75+
changed_when: false
76+
77+
- name: Assert Photon service process uses the host photon user
78+
ansible.builtin.assert:
79+
that:
80+
- photon_process_uid.stdout == ansible_facts.getent_passwd['photon'][1]

playbooks/dawarich.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
---
2+
- name: Setup Photon reverse geocoding service
3+
hosts: BEOKPDCOVM02
4+
connection: ssh
5+
become: true
6+
roles:
7+
- role: photon
8+
tags: photon
9+
210
- name: Setup shared Valkey and Dawarich
311
hosts: BEOKPDCOVM01
412
connection: ssh

playbooks/group_vars/all.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,12 @@ domain:
186186
answer: "{{ traefik.dco.ipv6 }}"
187187
- domain: time.unitix.be
188188
answer: "{{ traefik.dco.ip }}"
189-
# MEDIA
190-
- domain: "autobrr.frai.se"
189+
# MEDIA
190+
- domain: photon.frai.se
191+
answer: "{{ traefik.media.ipv6 }}"
192+
- domain: photon.frai.se
193+
answer: "{{ traefik.media.ip }}"
194+
- domain: "autobrr.frai.se"
191195
answer: "{{ traefik.media.ip }}"
192196
- domain: "autobrr.frai.se"
193197
answer: "{{ traefik.media.ipv6 }}"
@@ -565,4 +569,4 @@ authelia_oidc_clients:
565569
39306330636537383462656131366662643835663530316537626235636639373636316638303539
566570
33656462653730306433623231646663353136363534313365353236623636643335323761666632
567571
61663765396237356639333531353239316538383531356562643733346134316638366164326132
568-
61393833386366363732
572+
61393833386366363732

0 commit comments

Comments
 (0)