Initial commit: arr-stack homelab + local AI
Docker Compose media stack (gluetun, *arr, Jellyfin), Ternary-Bonsai AI (Open WebUI, Forgejo, optional OpenHands), and Ansible bootstrap for the SER5 Ubuntu host.
This commit is contained in:
commit
3645d1314c
33 changed files with 2673 additions and 0 deletions
6
ansible/roles/users/handlers/main.yml
Normal file
6
ansible/roles/users/handlers/main.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
- name: Reload udev
|
||||
ansible.builtin.shell: |
|
||||
udevadm control --reload-rules
|
||||
udevadm trigger
|
||||
changed_when: true
|
||||
171
ansible/roles/users/tasks/main.yml
Normal file
171
ansible/roles/users/tasks/main.yml
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
# Local homelab operator account — broad permissions (LAN-trusted host)
|
||||
|
||||
- name: Ensure stack user exists with bash shell
|
||||
ansible.builtin.user:
|
||||
name: "{{ stack_owner }}"
|
||||
state: present
|
||||
shell: /bin/bash
|
||||
create_home: true
|
||||
groups: "{{ extra_user_groups }}"
|
||||
append: true
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Ensure useful system groups exist (create if missing)
|
||||
ansible.builtin.group:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop: "{{ extra_user_groups }}"
|
||||
failed_when: false
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Add stack user to all useful groups
|
||||
ansible.builtin.user:
|
||||
name: "{{ stack_owner }}"
|
||||
groups: "{{ extra_user_groups }}"
|
||||
append: true
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Passwordless sudo for stack user (full admin)
|
||||
ansible.builtin.copy:
|
||||
dest: "/etc/sudoers.d/{{ stack_owner }}"
|
||||
mode: "0440"
|
||||
owner: root
|
||||
group: root
|
||||
validate: "visudo -cf %s"
|
||||
content: |
|
||||
# Homelab operator — passwordless sudo (local trusted host)
|
||||
{{ stack_owner }} ALL=(ALL) NOPASSWD:ALL
|
||||
Defaults:{{ stack_owner }} !env_reset
|
||||
Defaults:{{ stack_owner }} secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
|
||||
tags: [users, permissions, sudo]
|
||||
|
||||
- name: Allow stack user to manage Docker and arr-stack via systemctl without password
|
||||
ansible.builtin.copy:
|
||||
dest: "/etc/sudoers.d/{{ stack_owner }}-services"
|
||||
mode: "0440"
|
||||
owner: root
|
||||
group: root
|
||||
validate: "visudo -cf %s"
|
||||
content: |
|
||||
# Redundant with NOPASSWD:ALL; kept explicit for clarity if sudo is tightened later
|
||||
{{ stack_owner }} ALL=(root) NOPASSWD: /bin/systemctl * docker*, /bin/systemctl * containerd*, /bin/systemctl * arr-stack*, /usr/bin/systemctl * docker*, /usr/bin/systemctl * containerd*, /usr/bin/systemctl * arr-stack*
|
||||
tags: [users, permissions, sudo]
|
||||
|
||||
- name: Install ACL tools
|
||||
ansible.builtin.apt:
|
||||
name: acl
|
||||
state: present
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Own stack and storage roots
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ stack_owner }}"
|
||||
group: "{{ stack_group }}"
|
||||
mode: "0775"
|
||||
loop:
|
||||
- "{{ stack_root }}"
|
||||
- "{{ storage_root }}"
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Recursive ownership of stack tree
|
||||
ansible.builtin.file:
|
||||
path: "{{ stack_root }}"
|
||||
state: directory
|
||||
owner: "{{ stack_owner }}"
|
||||
group: "{{ stack_group }}"
|
||||
recurse: true
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Recursive ownership of storage tree
|
||||
ansible.builtin.file:
|
||||
path: "{{ storage_root }}"
|
||||
state: directory
|
||||
owner: "{{ stack_owner }}"
|
||||
group: "{{ stack_group }}"
|
||||
recurse: true
|
||||
# Large trees: may take a moment; safe to re-run
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Default ACLs so new files under stack stay group-writable
|
||||
ansible.builtin.command: >
|
||||
setfacl -R -d -m u:{{ stack_owner }}:rwx,g:{{ stack_group }}:rwx,o::r-x {{ item }}
|
||||
loop:
|
||||
- "{{ stack_root }}"
|
||||
- "{{ storage_root }}"
|
||||
changed_when: true
|
||||
failed_when: false
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Current ACLs for stack owner full access
|
||||
ansible.builtin.command: >
|
||||
setfacl -R -m u:{{ stack_owner }}:rwx,g:{{ stack_group }}:rwx {{ item }}
|
||||
loop:
|
||||
- "{{ stack_root }}"
|
||||
- "{{ storage_root }}"
|
||||
changed_when: true
|
||||
failed_when: false
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Discover DRM nodes for permission tweak
|
||||
ansible.builtin.find:
|
||||
paths: /dev/dri
|
||||
patterns: "*"
|
||||
file_type: any
|
||||
register: dri_nodes
|
||||
failed_when: false
|
||||
tags: [users, permissions, gpu]
|
||||
|
||||
- name: Make /dev/dri nodes world-accessible (trusted local host)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
if [ -d /dev/dri ]; then
|
||||
chmod a+rw /dev/dri/* 2>/dev/null || true
|
||||
ls -la /dev/dri
|
||||
fi
|
||||
register: dri_chmod
|
||||
changed_when: "'rw' in dri_chmod.stdout"
|
||||
failed_when: false
|
||||
tags: [users, permissions, gpu]
|
||||
|
||||
- name: Persist permissive DRM udev rule for trusted host
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/udev/rules.d/99-homelab-dri-permissive.rules
|
||||
mode: "0644"
|
||||
content: |
|
||||
# Trusted LAN homelab — allow any user/container access to GPU nodes
|
||||
KERNEL=="renderD*", MODE="0666"
|
||||
KERNEL=="card*", MODE="0666"
|
||||
KERNEL=="controlD*", MODE="0666"
|
||||
notify: Reload udev
|
||||
tags: [users, permissions, gpu]
|
||||
|
||||
- name: Ensure docker socket is group-writable for docker group
|
||||
ansible.builtin.file:
|
||||
path: /var/run/docker.sock
|
||||
group: docker
|
||||
mode: "0660"
|
||||
failed_when: false
|
||||
tags: [users, permissions, docker]
|
||||
|
||||
- name: Verify stack user can sudo without password
|
||||
become: true
|
||||
become_user: "{{ stack_owner }}"
|
||||
ansible.builtin.command: sudo -n true
|
||||
changed_when: false
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Show stack user identity and groups
|
||||
become: true
|
||||
become_user: "{{ stack_owner }}"
|
||||
ansible.builtin.command: id
|
||||
register: stack_user_id
|
||||
changed_when: false
|
||||
tags: [users, permissions]
|
||||
|
||||
- name: Report stack user permissions
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ stack_user_id.stdout }}"
|
||||
tags: [users, permissions]
|
||||
Loading…
Add table
Add a link
Reference in a new issue