Commit the accumulated infrastructure work that was living only in the working tree: monitoring stack, emergency access/bot, gyro allocator, grimmory, adguard, backup audit and the OpenCode agent definitions. Also ignore Python bytecode, local archives and Nix/direnv artifacts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTocXkGUUazHdKKd3r9k71
306 lines
10 KiB
YAML
306 lines
10 KiB
YAML
---
|
|
- name: Create memoir-bot LXC on mini-pc
|
|
hosts: mini-pc
|
|
gather_facts: false
|
|
vars:
|
|
memoir_bot_vmid: 142
|
|
memoir_bot_hostname: memoir-bot
|
|
memoir_bot_ip: 192.168.1.26/24
|
|
memoir_bot_gateway: 192.168.1.1
|
|
memoir_bot_bridge: vmbr0
|
|
memoir_bot_rootfs: local-lvm:16
|
|
memoir_bot_ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
|
|
memoir_bot_pubkey_file: ~/.ssh/id_ed25519_homelab.pub
|
|
handlers:
|
|
- name: restart memoir-bot lxc
|
|
ansible.builtin.shell: "pct stop {{ memoir_bot_vmid }} || true; pct start {{ memoir_bot_vmid }}"
|
|
changed_when: true
|
|
tasks:
|
|
- name: Check if memoir-bot LXC exists
|
|
ansible.builtin.command: "pct config {{ memoir_bot_vmid }}"
|
|
register: memoir_bot_pct_config
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Install memoir-bot LXC SSH public key on PVE host
|
|
ansible.builtin.copy:
|
|
dest: /tmp/memoir-bot-lxc.pub
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
content: "{{ lookup('file', memoir_bot_pubkey_file) }}\n"
|
|
when: memoir_bot_pct_config.rc != 0
|
|
|
|
- name: Create memoir-bot LXC
|
|
ansible.builtin.command: >-
|
|
pct create {{ memoir_bot_vmid }} {{ memoir_bot_ostemplate }}
|
|
--hostname {{ memoir_bot_hostname }}
|
|
--rootfs {{ memoir_bot_rootfs }}
|
|
--cores 1
|
|
--memory 512
|
|
--swap 512
|
|
--net0 name=eth0,bridge={{ memoir_bot_bridge }},gw={{ memoir_bot_gateway }},ip={{ memoir_bot_ip }},firewall=1
|
|
--nameserver 1.1.1.1
|
|
--unprivileged 1
|
|
--features nesting=1,keyctl=1
|
|
--onboot 1
|
|
--startup order=60
|
|
--cmode shell
|
|
--ssh-public-keys /tmp/memoir-bot-lxc.pub
|
|
when: memoir_bot_pct_config.rc != 0
|
|
|
|
- name: Start memoir-bot LXC
|
|
ansible.builtin.command: "pct start {{ memoir_bot_vmid }}"
|
|
register: memoir_bot_pct_start
|
|
changed_when: memoir_bot_pct_start.rc == 0
|
|
failed_when: memoir_bot_pct_start.rc not in [0, 255]
|
|
|
|
- name: Allow FUSE device in memoir-bot LXC config
|
|
ansible.builtin.lineinfile:
|
|
path: "/etc/pve/lxc/{{ memoir_bot_vmid }}.conf"
|
|
line: "lxc.cgroup2.devices.allow: c 10:229 rwm"
|
|
state: present
|
|
notify: restart memoir-bot lxc
|
|
|
|
- name: Bind mount FUSE device in memoir-bot LXC config
|
|
ansible.builtin.lineinfile:
|
|
path: "/etc/pve/lxc/{{ memoir_bot_vmid }}.conf"
|
|
line: "lxc.mount.entry: /dev/fuse dev/fuse none bind,create=file"
|
|
state: present
|
|
notify: restart memoir-bot lxc
|
|
|
|
- name: Apply pending LXC config changes
|
|
ansible.builtin.meta: flush_handlers
|
|
|
|
- name: Wait for memoir-bot SSH through ru-vps
|
|
ansible.builtin.wait_for_connection:
|
|
timeout: 120
|
|
delegate_to: memoir-bot
|
|
vars:
|
|
ansible_become: false
|
|
|
|
- name: Configure Docker and memoir-bot inside LXC
|
|
hosts: memoir-bot
|
|
gather_facts: true
|
|
vars:
|
|
ansible_become: false
|
|
memoir_bot_source_dir: /home/ada/Documents/Projects/Other/memoir_bot/
|
|
memoir_bot_app_dir: /opt/memoir-bot/app
|
|
memoir_bot_state_dir: /srv/memoir-bot
|
|
memoir_bot_env_file: /srv/memoir-bot/.env
|
|
memoir_bot_env_source: /home/ada/Documents/Projects/Other/memoir_bot/.env
|
|
memoir_bot_ssh_private_key_file: ~/.ssh/id_ed25519
|
|
memoir_bot_ssh_public_key_file: ~/.ssh/id_ed25519.pub
|
|
memoir_bot_vault_repo: git@github.com:ada-dmitry/SecondBrain.git
|
|
memoir_bot_vault_dir: /srv/memoir-bot/vault
|
|
memoir_bot_image: memoir-bot:local
|
|
memoir_bot_container_name: memoir-bot
|
|
tasks:
|
|
- name: Install Docker and deploy dependencies
|
|
ansible.builtin.apt:
|
|
name:
|
|
- docker.io
|
|
- fuse-overlayfs
|
|
- git
|
|
- openssh-client
|
|
- rsync
|
|
- ca-certificates
|
|
- curl
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Ensure Docker config directory exists
|
|
ansible.builtin.file:
|
|
path: /etc/docker
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: Configure Docker storage driver for unprivileged LXC
|
|
ansible.builtin.copy:
|
|
dest: /etc/docker/daemon.json
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
{
|
|
"storage-driver": "fuse-overlayfs"
|
|
}
|
|
register: docker_daemon_config
|
|
|
|
- name: Ensure Docker service is enabled and running
|
|
ansible.builtin.systemd:
|
|
name: docker
|
|
state: "{{ 'restarted' if docker_daemon_config.changed else 'started' }}"
|
|
enabled: true
|
|
|
|
- name: Ensure memoir-bot directories exist
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0750"
|
|
loop:
|
|
- "{{ memoir_bot_app_dir }}"
|
|
- "{{ memoir_bot_state_dir }}"
|
|
- "{{ memoir_bot_state_dir }}/ssh"
|
|
|
|
- name: Copy memoir-bot env example
|
|
ansible.builtin.copy:
|
|
dest: "{{ memoir_bot_state_dir }}/.env.example"
|
|
owner: root
|
|
group: root
|
|
mode: "0640"
|
|
content: |
|
|
BOT_TOKEN=123456:telegram-token
|
|
ALLOWED_USER_IDS=123456789
|
|
OBSIDIAN_VAULT_PATH=/srv/obsidian/vault
|
|
DAILY_NOTES_DIR=03 Journal
|
|
NOTE_PATH_FORMAT=%Y/%m/%d.%m.%y.md
|
|
MESSAGE_TIME_FORMAT=%H:%M
|
|
TELEGRAM_PROXY=
|
|
REMINDER_MIN_HOURS=2
|
|
REMINDER_MAX_HOURS=3
|
|
REMINDER_START_HOUR=7
|
|
REMINDER_END_HOUR=23
|
|
REMINDER_TIMEZONE=Europe/Moscow
|
|
|
|
- name: Copy memoir-bot env file when present locally
|
|
ansible.builtin.copy:
|
|
src: "{{ memoir_bot_env_source }}"
|
|
dest: "{{ memoir_bot_env_file }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
when: lookup('ansible.builtin.fileglob', memoir_bot_env_source) | length > 0
|
|
no_log: true
|
|
|
|
- name: Install GitHub SSH private key for memoir-bot
|
|
ansible.builtin.copy:
|
|
src: "{{ memoir_bot_ssh_private_key_file }}"
|
|
dest: "{{ memoir_bot_state_dir }}/ssh/id_ed25519"
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
no_log: true
|
|
|
|
- name: Install GitHub SSH public key for memoir-bot when present locally
|
|
ansible.builtin.copy:
|
|
src: "{{ memoir_bot_ssh_public_key_file }}"
|
|
dest: "{{ memoir_bot_state_dir }}/ssh/id_ed25519.pub"
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
when: lookup('ansible.builtin.fileglob', memoir_bot_ssh_public_key_file) | length > 0
|
|
|
|
- name: Scan GitHub SSH host key
|
|
ansible.builtin.command: ssh-keyscan github.com
|
|
register: memoir_bot_github_host_key
|
|
changed_when: false
|
|
|
|
- name: Trust GitHub SSH host key for memoir-bot
|
|
ansible.builtin.known_hosts:
|
|
path: "{{ memoir_bot_state_dir }}/ssh/known_hosts"
|
|
name: github.com
|
|
key: "{{ memoir_bot_github_host_key.stdout }}"
|
|
state: present
|
|
|
|
- name: Clone SecondBrain vault
|
|
ansible.builtin.git:
|
|
repo: "{{ memoir_bot_vault_repo }}"
|
|
dest: "{{ memoir_bot_vault_dir }}"
|
|
key_file: "{{ memoir_bot_state_dir }}/ssh/id_ed25519"
|
|
accept_hostkey: true
|
|
update: true
|
|
version: main
|
|
register: memoir_bot_vault_checkout
|
|
|
|
- name: Configure memoir-bot vault Git author name
|
|
ansible.builtin.command: git config user.name memoir-bot
|
|
args:
|
|
chdir: "{{ memoir_bot_vault_dir }}"
|
|
changed_when: false
|
|
|
|
- name: Configure memoir-bot vault Git author email
|
|
ansible.builtin.command: git config user.email memoir-bot@homelab.local
|
|
args:
|
|
chdir: "{{ memoir_bot_vault_dir }}"
|
|
changed_when: false
|
|
|
|
- name: Sync memoir-bot source code
|
|
ansible.posix.synchronize:
|
|
src: "{{ memoir_bot_source_dir }}"
|
|
dest: "{{ memoir_bot_app_dir }}/"
|
|
delete: true
|
|
rsync_opts:
|
|
- "--exclude=.env"
|
|
- "--exclude=.git"
|
|
- "--exclude=.venv"
|
|
- "--exclude=__pycache__"
|
|
- "--exclude=*.pyc"
|
|
register: memoir_bot_source_sync
|
|
|
|
- name: Check if memoir-bot image exists
|
|
ansible.builtin.command: "docker image inspect {{ memoir_bot_image }}"
|
|
register: memoir_bot_image_inspect
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Build memoir-bot image
|
|
ansible.builtin.command: "docker build -t {{ memoir_bot_image }} {{ memoir_bot_app_dir }}"
|
|
when: memoir_bot_source_sync.changed or memoir_bot_image_inspect.rc != 0
|
|
register: memoir_bot_image_build
|
|
changed_when: memoir_bot_image_build.rc == 0
|
|
|
|
- name: Install memoir-bot systemd unit
|
|
ansible.builtin.copy:
|
|
dest: /etc/systemd/system/memoir-bot.service
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
[Unit]
|
|
Description=Memoir Telegram bot container
|
|
After=docker.service
|
|
Requires=docker.service
|
|
ConditionPathExists={{ memoir_bot_env_file }}
|
|
|
|
[Service]
|
|
Restart=always
|
|
RestartSec=10
|
|
ExecStartPre=-/usr/bin/docker rm -f {{ memoir_bot_container_name }}
|
|
ExecStart=/usr/bin/docker run --rm \
|
|
--name {{ memoir_bot_container_name }} \
|
|
--env-file {{ memoir_bot_env_file }} \
|
|
-v {{ memoir_bot_state_dir }}/vault:/srv/obsidian/vault \
|
|
-v {{ memoir_bot_state_dir }}/ssh:/root/.ssh:ro \
|
|
{{ memoir_bot_image }}
|
|
ExecStop=/usr/bin/docker stop {{ memoir_bot_container_name }}
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
register: memoir_bot_unit
|
|
|
|
- name: Reload systemd when memoir-bot unit changes
|
|
ansible.builtin.systemd:
|
|
daemon_reload: true
|
|
when: memoir_bot_unit.changed
|
|
|
|
- name: Check memoir-bot env file
|
|
ansible.builtin.stat:
|
|
path: "{{ memoir_bot_env_file }}"
|
|
register: memoir_bot_env
|
|
|
|
- name: Enable memoir-bot service
|
|
ansible.builtin.systemd:
|
|
name: memoir-bot
|
|
enabled: true
|
|
|
|
- name: Start memoir-bot when env file exists
|
|
ansible.builtin.systemd:
|
|
name: memoir-bot
|
|
state: "{{ 'restarted' if memoir_bot_source_sync.changed or memoir_bot_image_build.changed or memoir_bot_unit.changed or memoir_bot_vault_checkout.changed else 'started' }}"
|
|
when: memoir_bot_env.stat.exists
|