Files
homelab/ansible/roles/llm-inference-multimodel/tasks/systemd.yml
Hermes Agent service account d10255297c llm-inference-multimodel: add Qwen2.5-14B shadow instance (port 8002, gated off — VRAM co-residency not yet confirmed)
- New llama-server-qwen systemd unit template, gated by llm_qwen_service_enabled (default false)
- Idempotent GGUF download task (bartowski Qwen2.5-14B-Instruct-Q5_K_M, stat-guarded)
- Launch flags per local-llm-64k-context-recommendation.md: ctx-size 65536, flash-attn, q8_0 KV cache, batch 2048/ubatch 512, jinja, parallel 1
- verify.yml only starts/verifies the qwen unit when llm_qwen_service_enabled=true
- README: documents live VRAM gate finding (nvidia-smi 2026-08-06: Phi-4+Mistral already ~16.6/24GB, ~7.5GB free -- insufficient for Qwen weights concurrently) and options
- Does NOT touch llama-server-aux (8000) or llama-server-toolcall (8001) service state
2026-08-06 09:08:33 -05:00

83 lines
3.6 KiB
YAML

---
# ------------------------------------------------------------------------------
# FILE: roles/llm-inference-multimodel/tasks/systemd.yml
# DESCRIPTION: Phase 2 — template + deploy both unit files.
# DELIBERATELY DOES NOT START OR ENABLE either service — that is
# Phase 4 (verify.yml)'s job, after Phase 3 firewall scoping is
# in place. This keeps "units land on disk" and "processes
# actually bind ports and load 20+GB into VRAM" as separately
# reviewable checkpoints per Ryan's iterative-build preference.
#
# Two independent units (llama-server-aux.service,
# llama-server-toolcall.service) — NOT one unit with two
# ExecStarts — so either can be stopped/restarted without
# affecting the other (plan §2, §6 rollback requirement).
#
# The pre-existing Gemma unit (whatever discover.yml found it to
# be) is never templated, restarted, or disabled by this file.
# ------------------------------------------------------------------------------
- name: Deploy llama-server-aux systemd unit
ansible.builtin.template:
src: llama-server-aux.service.j2
dest: "/etc/systemd/system/{{ llm_aux_service_name }}.service"
owner: root
group: root
mode: "0644"
become: true
register: llm_aux_unit_deployed
notify:
- reload systemd
- name: Deploy llama-server-toolcall systemd unit
ansible.builtin.template:
src: llama-server-toolcall.service.j2
dest: "/etc/systemd/system/{{ llm_toolcall_service_name }}.service"
owner: root
group: root
mode: "0644"
become: true
register: llm_toolcall_unit_deployed
notify:
- reload systemd
- name: Deploy llama-server-qwen systemd unit (shadow, port 8002)
ansible.builtin.template:
src: llama-server-qwen.service.j2
dest: "/etc/systemd/system/{{ llm_qwen_service_name }}.service"
owner: root
group: root
mode: "0644"
become: true
register: llm_qwen_unit_deployed
notify:
- reload systemd
- name: Flush handlers so daemon-reload lands before any later phase acts on unit state
ansible.builtin.meta: flush_handlers
# NOTE: no `ansible.builtin.systemd: state: started / enabled: true / restarted`
# task here on purpose. Units exist on disk after this phase; nothing is
# running or restarted.
#
# BUGFIX (found in production): this file used to `notify: restart
# llama-server-*` on the template tasks above, followed by the
# flush_handlers meta task. That combination meant Phase 2 (the `systemd`
# tag) fired the restart handlers itself — on any run where either unit's
# rendered content changed (including the very first apply), BOTH services
# got restarted immediately, right here in Phase 2, before Phase 3's
# firewall scoping or Phase 4's smoke tests ever ran. That directly
# contradicted this file's own stated purpose (units land on disk, nothing
# starts/restarts until Phase 4) and caused live services to bounce
# unexpectedly on a routine re-run of just `--tags systemd`.
#
# Fix: Phase 2 only reloads the systemd daemon (harmless, no process
# impact) and records whether each unit's content actually changed via
# `llm_aux_unit_deployed` / `llm_toolcall_unit_deployed` (both `.changed`
# booleans, persisted as play vars for later phases in this same run).
# Phase 4 (verify.yml) is the only phase that starts OR restarts either
# service, and it does so per-instance using those recorded `changed`
# flags — so a content change to one unit's template still never causes
# the other to restart, and no restart happens at all until Phase 4 has
# been reached.