feat: backup appwritefix: CORS error by adding platforms
This commit is contained in:
98
playbooks/backup_appwrite.yml
Normal file
98
playbooks/backup_appwrite.yml
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
# Backs up a running Appwrite instance per the official backup guide:
|
||||
# https://appwrite.io/docs/advanced/self-hosting/production/backups
|
||||
#
|
||||
# What is backed up:
|
||||
# - MariaDB: mysqldump (--single-transaction, consistent without downtime)
|
||||
# - Docker volumes: all data volumes (tar.gz, requires service stop)
|
||||
# - .env file
|
||||
#
|
||||
# Backup is written to: {{ appwrite_backup_root }}/YYYYMMDDTHHMMSS/
|
||||
#
|
||||
# Required vars (from inventory):
|
||||
# appwrite_dir - e.g. /home/ptoal/appwrite
|
||||
#
|
||||
# Optional vars:
|
||||
# appwrite_backup_root - destination parent dir (default: /var/backups/appwrite)
|
||||
# appwrite_compose_project - compose project name (default: basename of appwrite_dir)
|
||||
|
||||
- name: Backup Appwrite
|
||||
hosts: appwrite
|
||||
gather_facts: true
|
||||
become: true
|
||||
|
||||
vars:
|
||||
_compose_project: "{{ appwrite_compose_project | default(appwrite_dir | basename) }}"
|
||||
backup_root: "{{ appwrite_backup_root | default('/var/backups/appwrite') }}"
|
||||
backup_dir: "{{ backup_root }}/{{ ansible_date_time.iso8601_basic_short }}"
|
||||
# appwrite-mariadb volume excluded — covered by the mysqldump below.
|
||||
# appwrite-cache and appwrite-redis are transient but included for
|
||||
# completeness; they are safe to omit if backup size is a concern.
|
||||
appwrite_volumes:
|
||||
- appwrite-uploads
|
||||
- appwrite-functions
|
||||
- appwrite-builds
|
||||
- appwrite-sites
|
||||
- appwrite-certificates
|
||||
- appwrite-config
|
||||
- appwrite-cache
|
||||
- appwrite-redis
|
||||
|
||||
tasks:
|
||||
- name: Create backup directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ backup_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
|
||||
- name: Dump MariaDB
|
||||
# --single-transaction gives a consistent InnoDB snapshot without locking.
|
||||
# Runs while the service is still up so docker compose exec is available.
|
||||
ansible.builtin.shell:
|
||||
cmd: >
|
||||
docker compose exec -T mariadb
|
||||
sh -c 'exec mysqldump --all-databases --add-drop-database
|
||||
--single-transaction --routines --triggers
|
||||
-uroot -p"$MYSQL_ROOT_PASSWORD"'
|
||||
> {{ backup_dir }}/mariadb-dump.sql
|
||||
chdir: "{{ appwrite_dir }}"
|
||||
changed_when: true
|
||||
|
||||
- name: Stop, back up volumes, and restart
|
||||
block:
|
||||
- name: Stop Appwrite service
|
||||
ansible.builtin.systemd:
|
||||
name: appwrite
|
||||
state: stopped
|
||||
|
||||
- name: Back up Docker volumes
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
docker run --rm
|
||||
-v {{ _compose_project }}_{{ item }}:/data
|
||||
-v {{ backup_dir }}:/backup
|
||||
ubuntu tar czf /backup/{{ item }}.tar.gz -C /data .
|
||||
loop: "{{ appwrite_volumes }}"
|
||||
changed_when: true
|
||||
|
||||
- name: Back up .env
|
||||
ansible.builtin.copy:
|
||||
src: "{{ appwrite_dir }}/.env"
|
||||
dest: "{{ backup_dir }}/.env"
|
||||
remote_src: true
|
||||
mode: '0600'
|
||||
|
||||
rescue:
|
||||
- name: Notify that backup failed
|
||||
ansible.builtin.debug:
|
||||
msg: "Backup failed — Appwrite will be restarted. Check {{ backup_dir }} for partial output."
|
||||
|
||||
always:
|
||||
- name: Ensure Appwrite service is started
|
||||
ansible.builtin.systemd:
|
||||
name: appwrite
|
||||
state: started
|
||||
|
||||
- name: Report backup location
|
||||
ansible.builtin.debug:
|
||||
msg: "Backup written to {{ backup_dir }}"
|
||||
176
playbooks/bootstrap_appwrite.yml
Normal file
176
playbooks/bootstrap_appwrite.yml
Normal file
@@ -0,0 +1,176 @@
|
||||
---
|
||||
# Bootstraps a fresh Appwrite instance:
|
||||
# 1. Creates the console admin user
|
||||
# 2. Creates the BAB project
|
||||
# 3. Registers web platforms (CORS allowed origins)
|
||||
# 4. Generates an Ansible automation API key
|
||||
# 5. Stores the API key secret in Vault at kv/oys/bab-appwrite-api-key
|
||||
#
|
||||
# Run once per environment after install_appwrite.yml.
|
||||
# Safe to re-run: account and project creation tolerate 409.
|
||||
# Platform and API key creation are NOT idempotent — re-running creates
|
||||
# duplicates. Delete stale entries from the console.
|
||||
#
|
||||
# Required vars (from inventory):
|
||||
# appwrite_domain - e.g. appwrite.toal.ca (used to build admin URL)
|
||||
# appwrite_project - project ID to create
|
||||
# appwrite_project_name - human-readable project name (default: BAB)
|
||||
# appwrite_web_platforms - list of {name, hostname} dicts for CORS origins
|
||||
#
|
||||
# Note: uses appwrite_domain directly, not appwrite_admin_uri, because
|
||||
# appwrite_admin_uri may point to an app-layer proxy (e.g. nginx) that
|
||||
# does not expose the Appwrite admin/console endpoints.
|
||||
|
||||
- name: Bootstrap Appwrite — Admin, Project, and API Key
|
||||
hosts: appwrite
|
||||
gather_facts: false
|
||||
|
||||
vars:
|
||||
appwrite_admin_uri: "https://{{ appwrite_domain }}/v1"
|
||||
|
||||
tasks:
|
||||
- name: Read admin credentials from Vault
|
||||
community.hashi_vault.vault_kv2_get:
|
||||
path: oys/bab_admin
|
||||
engine_mount_point: kv
|
||||
register: vault_admin
|
||||
no_log: true
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create Appwrite console admin account
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/account"
|
||||
method: POST
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
body:
|
||||
userId: "{{ appwrite_admin_user_id | default('bab-admin') }}"
|
||||
email: "{{ vault_admin.secret.bab_admin_user }}"
|
||||
password: "{{ vault_admin.secret.bab_admin_password }}"
|
||||
status_code: [201, 409, 501]
|
||||
return_content: true
|
||||
delegate_to: localhost
|
||||
no_log: true
|
||||
|
||||
- name: Create admin session
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/account/sessions/email"
|
||||
method: POST
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
body:
|
||||
email: "{{ vault_admin.secret.bab_admin_user }}"
|
||||
password: "{{ vault_admin.secret.bab_admin_password }}"
|
||||
status_code: [201]
|
||||
return_content: true
|
||||
register: admin_session
|
||||
delegate_to: localhost
|
||||
no_log: false
|
||||
|
||||
- name: Create JWT from admin session
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/account/jwt"
|
||||
method: POST
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
Cookie: "{{ admin_session.cookies_string }}"
|
||||
status_code: [201]
|
||||
return_content: true
|
||||
register: admin_jwt
|
||||
delegate_to: localhost
|
||||
no_log: true
|
||||
|
||||
- name: Get admin user teams
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/teams"
|
||||
method: GET
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
X-Appwrite-JWT: "{{ admin_jwt.json.jwt }}"
|
||||
status_code: [200]
|
||||
return_content: true
|
||||
register: admin_teams
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create BAB project
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/projects"
|
||||
method: POST
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
X-Appwrite-JWT: "{{ admin_jwt.json.jwt }}"
|
||||
body:
|
||||
projectId: "{{ appwrite_project }}"
|
||||
name: "{{ appwrite_project_name | default('BAB') }}"
|
||||
teamId: "{{ admin_teams.json.teams[0]['$id'] }}"
|
||||
region: default
|
||||
status_code: [201, 409]
|
||||
return_content: true
|
||||
delegate_to: localhost
|
||||
no_log: false
|
||||
|
||||
- name: Register web platforms (CORS allowed origins)
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/projects/{{ appwrite_project }}/platforms"
|
||||
method: POST
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
X-Appwrite-JWT: "{{ admin_jwt.json.jwt }}"
|
||||
body:
|
||||
type: web
|
||||
name: "{{ item.name }}"
|
||||
hostname: "{{ item.hostname }}"
|
||||
status_code: [201]
|
||||
return_content: true
|
||||
loop: "{{ appwrite_web_platforms | default([]) }}"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create Ansible automation API key
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_admin_uri }}/projects/{{ appwrite_project }}/keys"
|
||||
method: POST
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Project: console
|
||||
X-Appwrite-Response-Format: "1.6"
|
||||
X-Appwrite-JWT: "{{ admin_jwt.json.jwt }}"
|
||||
body:
|
||||
name: ansible-automation
|
||||
scopes:
|
||||
- databases.read
|
||||
- databases.write
|
||||
- collections.read
|
||||
- collections.write
|
||||
- attributes.read
|
||||
- attributes.write
|
||||
- indexes.read
|
||||
- indexes.write
|
||||
- documents.read
|
||||
- documents.write
|
||||
- users.read
|
||||
- users.write
|
||||
status_code: [201]
|
||||
return_content: true
|
||||
register: api_key
|
||||
delegate_to: localhost
|
||||
no_log: true
|
||||
|
||||
- name: Store API key secret in Vault
|
||||
community.hashi_vault.vault_kv2_write:
|
||||
path: oys/bab-appwrite-api-key
|
||||
engine_mount_point: kv
|
||||
data:
|
||||
appwrite_api_key: "{{ api_key.json.secret }}"
|
||||
delegate_to: localhost
|
||||
no_log: true
|
||||
@@ -7,7 +7,7 @@
|
||||
ansible.builtin.uri:
|
||||
body_format: json
|
||||
headers:
|
||||
X-Appwrite-Response-Format: '{{ appwrite_response_format }}'
|
||||
X-Appwrite-Response-Format: '{{ appwrite_response_format | default("1.6") }}'
|
||||
X-Appwrite-Project: '{{ appwrite_project }}'
|
||||
X-Appwrite-Key: '{{ appwrite_api_key }}'
|
||||
return_content: true
|
||||
@@ -46,7 +46,9 @@
|
||||
|
||||
- name: Create Attributes
|
||||
ansible.builtin.uri:
|
||||
url: "{{ appwrite_api_uri }}/databases/{{ bab_database.id }}/collections/{{ item[0].id }}/attributes/{{ ( item[1].format is defined and item[1].format != '' ) |ternary(item[1].format, item[1].type) }}"
|
||||
url: >-
|
||||
{{ appwrite_api_uri }}/databases/{{ bab_database.id }}/collections/{{ item[0].id }}/attributes/{{
|
||||
(item[1].format is defined and item[1].format != '') | ternary(item[1].format, item[1].type) }}
|
||||
method: POST
|
||||
body: "{{ lookup('ansible.builtin.template', 'appwrite_attribute_template.json.j2') }}"
|
||||
status_code: [202, 409]
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
body_format: json
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
X-Appwrite-Response-Format: '{{ appwrite_response_format }}'
|
||||
X-Appwrite-Response-Format: '{{ appwrite_response_format | default("1.6") }}'
|
||||
X-Appwrite-Project: '{{ appwrite_project }}'
|
||||
X-Appwrite-Key: '{{ appwrite_api_key }}'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user