Files
atproto-pds-ansible/playbook.yml
T
2026-11-04 16:55:41 -05:00

319 lines
11 KiB
YAML

---
- name: Deploy PDS
hosts: pds
become: yes
vars_files:
- vars/main.yml
vars:
pds_data_dir: /pds
pds_image_tag: "0.4"
pds_blob_upload_limit: 314572800
pds_rate_limits_enabled: true
pds_invite_required: true
pds_crawlers: https://relay.fire.hose.cam
pds_backup_period: 24h
pds_backup_s3_bucket: atprotopds-backup
pds_backup_s3_region: bhs
pds_backup_s3_endpoint: https://s3.bhs.io.cloud.ovh.net
pds_backup_s3_access_key: "{{ pds_blobstore_s3_access_key }}"
pds_backup_s3_secret_key: "{{ pds_blobstore_s3_secret_key }}"
pds_grafana_image_tag: "13.1.1"
tasks:
- name: Run PDS installer (first time only)
shell: >-
echo "n" | bash <(curl -fsSL
https://raw.githubusercontent.com/bluesky-social/pds/main/installer.sh)
{{ pds_data_dir }} {{ pds_hostname }} {{ pds_admin_email }}
args:
creates: "{{ pds_data_dir }}/account.sqlite"
executable: /bin/bash
- name: Read existing secrets from pds.env
shell: grep -E '^(PDS_JWT_SECRET|PDS_ADMIN_PASSWORD|PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX)=' {{ pds_data_dir }}/pds.env
register: existing_secrets
changed_when: false
- name: Set secret facts
set_fact:
pds_jwt_secret: "{{ existing_secrets.stdout_lines | select('match', '^PDS_JWT_SECRET=') | first | regex_replace('^PDS_JWT_SECRET=', '') }}"
pds_admin_password: "{{ existing_secrets.stdout_lines | select('match', '^PDS_ADMIN_PASSWORD=') | first | regex_replace('^PDS_ADMIN_PASSWORD=', '') }}"
pds_plc_rotation_key: "{{ existing_secrets.stdout_lines | select('match', '^PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=') | first | regex_replace('^PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=', '') }}"
- name: Install rclone
apt:
name: rclone
state: present
update_cache: yes
- name: Create rclone config directory
file:
path: /etc/rclone
state: directory
mode: "0755"
- name: Deploy rclone config
template:
src: templates/rclone.conf.j2
dest: /etc/rclone/rclone.conf
mode: "0600"
notify: apply changes
- name: Deploy backup script
template:
src: templates/backup.sh.j2
dest: /usr/local/bin/backup.sh
mode: "0755"
notify: apply changes
- name: Deploy backup service
template:
src: templates/backup.service.j2
dest: /etc/systemd/system/pds-backup.service
mode: "0644"
- name: Deploy backup timer
template:
src: templates/backup.timer.j2
dest: /etc/systemd/system/pds-backup.timer
mode: "0644"
- name: Enable backup timer
systemd:
name: pds-backup.timer
enabled: yes
state: started
daemon_reload: yes
- name: Pre-deploy backup
shell: /usr/local/bin/backup.sh predeploy
when: existing_secrets.stdout_lines | length > 0
- name: Deploy pds.env
template:
src: templates/pds.env.j2
dest: "{{ pds_data_dir }}/pds.env"
mode: "0600"
notify: apply changes
- name: Deploy compose.yaml
template:
src: templates/compose.yaml.j2
dest: "{{ pds_data_dir }}/compose.yaml"
mode: "0644"
notify: apply changes
- name: Deploy Caddyfile
template:
src: templates/Caddyfile.j2
dest: "{{ pds_data_dir }}/caddy/etc/caddy/Caddyfile"
mode: "0644"
notify: apply changes
- name: Download pdsadmin
get_url:
url: https://raw.githubusercontent.com/bluesky-social/pds/main/pdsadmin.sh
dest: /usr/local/bin/pdsadmin
mode: "0755"
- name: Flush handlers
meta: flush_handlers
- name: PDS Health check
uri:
url: "https://{{ pds_hostname }}/xrpc/_health"
method: GET
status_code: 200
retries: 3
delay: 5
- name: Check backup timer is active
command: systemctl is-active pds-backup.timer
changed_when: false
- name: Check last backup run succeeded
shell: systemctl show pds-backup.service -p ExecMainStatus --value
register: pds_backup_exit_code
changed_when: false
failed_when: pds_backup_exit_code.stdout != "0"
- name: Clone pds-operator repo
git:
repo: "{{ pds_operator_repo }}"
dest: "{{ pds_data_dir }}/operator"
version: "{{ pds_operator_version | default('main') }}"
update: yes
force: no
when: pds_operator_enabled is defined and pds_operator_enabled | bool
register: operator_repo
notify: restart operator
- name: Read operator session secret (if exists)
shell: grep -E '^SESSION_SECRET=' {{ pds_data_dir }}/operator/.env 2>/dev/null | cut -d= -f2
register: operator_existing_secret
changed_when: false
failed_when: false
when: pds_operator_enabled is defined and pds_operator_enabled | bool
- name: Generate operator session secret (first run)
shell: openssl rand -hex 32
register: operator_new_secret
when:
- pds_operator_enabled is defined and pds_operator_enabled | bool
- operator_existing_secret.stdout | default('') | length == 0
- name: Set operator session secret fact
set_fact:
pds_operator_session_secret: "{{ operator_existing_secret.stdout if (operator_existing_secret.stdout | default('') | length > 0) else operator_new_secret.stdout }}"
when: pds_operator_enabled is defined and pds_operator_enabled | bool
- name: Create operator data directory
file:
path: "{{ pds_data_dir }}/operator/data"
state: directory
owner: "1000"
group: "1000"
mode: "0755"
when: pds_operator_enabled is defined and pds_operator_enabled | bool
- name: Deploy operator .env
template:
src: templates/pds-operator.env.j2
dest: "{{ pds_data_dir }}/operator/.env"
mode: "0600"
when: pds_operator_enabled is defined and pds_operator_enabled | bool
notify: restart operator
- name: Deploy operator compose
template:
src: templates/pds-operator-compose.yaml.j2
dest: "{{ pds_data_dir }}/operator/compose.yaml"
mode: "0644"
when: pds_operator_enabled is defined and pds_operator_enabled | bool
notify: restart operator
- name: Clone cities labeler repo
git:
repo: "{{ pds_cities_repo }}"
dest: "{{ pds_data_dir }}/cities"
version: "{{ pds_cities_version | default('main') }}"
update: yes
force: no
when: pds_cities_enabled is defined and pds_cities_enabled | bool
notify: restart cities
- name: Create cities labeler data directory
file:
path: "{{ pds_data_dir }}/cities/data"
state: directory
owner: "1000"
group: "1000"
mode: "0755"
when: pds_cities_enabled is defined and pds_cities_enabled | bool
- name: Deploy cities labeler .env
template:
src: templates/cities-labeler.env.j2
dest: "{{ pds_data_dir }}/cities/.env"
mode: "0600"
when: pds_cities_enabled is defined and pds_cities_enabled | bool
notify: restart cities
- name: Deploy cities labeler compose
template:
src: templates/cities-labeler-compose.yaml.j2
dest: "{{ pds_data_dir }}/cities/compose.yaml"
mode: "0644"
when: pds_cities_enabled is defined and pds_cities_enabled | bool
notify: restart cities
- name: Create monitoring directories
file:
path: "{{ item }}"
state: directory
mode: "0755"
loop:
- "{{ pds_data_dir }}/monitoring"
- "{{ pds_data_dir }}/monitoring/grafana/provisioning/datasources"
- "{{ pds_data_dir }}/monitoring/grafana/provisioning/dashboards"
- "{{ pds_data_dir }}/monitoring/dashboards"
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
- name: Deploy monitoring compose
template:
src: templates/monitoring-compose.yaml.j2
dest: "{{ pds_data_dir }}/monitoring/compose.yaml"
mode: "0644"
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
notify: restart monitoring
- name: Deploy Prometheus config
template:
src: templates/prometheus.yml.j2
dest: "{{ pds_data_dir }}/monitoring/prometheus.yml"
mode: "0644"
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
notify: restart monitoring
- name: Deploy Grafana datasource provisioning
template:
src: templates/grafana-datasources.yml.j2
dest: "{{ pds_data_dir }}/monitoring/grafana/provisioning/datasources/prometheus.yml"
mode: "0644"
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
notify: restart monitoring
- name: Deploy Grafana dashboard provisioning
template:
src: templates/grafana-dashboards.yml.j2
dest: "{{ pds_data_dir }}/monitoring/grafana/provisioning/dashboards/pds.yml"
mode: "0644"
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
notify: restart monitoring
- name: Download PDS Overview dashboard
get_url:
url: https://raw.githubusercontent.com/bluesky-social/pds/main/monitoring/dashboards/pds-overview.json
dest: "{{ pds_data_dir }}/monitoring/dashboards/pds-overview.json"
mode: "0644"
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
notify: restart monitoring
- name: Start monitoring stack
shell: cd {{ pds_data_dir }}/monitoring && docker compose up -d
when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool
- name: Flush handlers (operator + cities + monitoring)
meta: flush_handlers
- name: Operator health check
uri:
url: "https://{{ pds_operator_hostname }}/oauth/client-metadata.json"
method: GET
status_code: 200
retries: 5
delay: 10
when: pds_operator_enabled is defined and pds_operator_enabled | bool
- name: Cities labeler health check
uri:
url: "https://{{ pds_cities_hostname }}/xrpc/_health"
method: GET
status_code: 200
retries: 5
delay: 10
when: pds_cities_enabled is defined and pds_cities_enabled | bool
handlers:
- name: apply changes
shell: cd {{ pds_data_dir }} && docker compose up -d && docker restart caddy
- name: restart monitoring
shell: cd {{ pds_data_dir }}/monitoring && docker compose up -d --force-recreate
- name: restart operator
shell: cd {{ pds_data_dir }}/operator && docker compose up -d --build
- name: restart cities
shell: cd {{ pds_data_dir }}/cities && docker compose up -d --build