LLM-Server: llm/ansible für Check-Modus und ansible-core 2.21 fit gemacht
Nach Live-Check-Modus gegen ghostnet-ki (ok=23, changed=4, failed=0): - Freiraumprüfung auf existierendes Elternelement (df schlägt im Check-Modus auf dem noch nicht angelegten Store fehl) - Rechte-Durchsetzung nur über vorhandene Artefakte (file-Modul im Check-Modus) - assert ohne loop (2.21 lehnt loop auf assert ab); statische Meldungen, Modell-Anwesenheit im Check-Modus nur informell - find file_type=any für Character-Devices (renderD*) - README: Aufruf mit --private-key nach Workstation-Konvention Preview prognostiziert korrekt: 2 Modellverzeichnisse, 2 SOURCE.yml, Netz-Quadlet, 2 Container-Quadlets; gepinntes ROCm-Image bereits im Store. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -32,15 +32,22 @@ cd llm-server/llm/ansible
|
||||
|
||||
## Usage (Testing)
|
||||
|
||||
All commands use the operator deploy key
|
||||
`~/.ssh/id_ed25519_ghostnet_ai_ansible_deploy` (see AGENTS.md; no ssh-agent
|
||||
required):
|
||||
|
||||
```bash
|
||||
# Preview only – no changes, no downloads, no service start:
|
||||
../../../.venv/bin/ansible-playbook -i inventories/testing playbooks/ai.yml --check --diff
|
||||
../../../.venv/bin/ansible-playbook -i inventories/testing playbooks/ai.yml \
|
||||
--check --diff --private-key ~/.ssh/id_ed25519_ghostnet_ai_ansible_deploy
|
||||
|
||||
# Provision model weights only (tag models):
|
||||
../../../.venv/bin/ansible-playbook -i inventories/testing playbooks/ai.yml --tags models
|
||||
../../../.venv/bin/ansible-playbook -i inventories/testing playbooks/ai.yml \
|
||||
--tags models --private-key ~/.ssh/id_ed25519_ghostnet_ai_ansible_deploy
|
||||
|
||||
# Render quadlets and start/verify the selected profile (tag service):
|
||||
../../../.venv/bin/ansible-playbook -i inventories/testing playbooks/ai.yml --tags service
|
||||
../../../.venv/bin/ansible-playbook -i inventories/testing playbooks/ai.yml \
|
||||
--tags service --private-key ~/.ssh/id_ed25519_ghostnet_ai_ansible_deploy
|
||||
```
|
||||
|
||||
`inference_engine_active_profile` selects which rendered quadlet is started;
|
||||
|
||||
@@ -48,12 +48,14 @@
|
||||
- name: Verify the rootless runtime utilities are executable
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- item.stat.exists
|
||||
- item.stat.executable
|
||||
loop: "{{ inference_engine_tools.results }}"
|
||||
- inference_engine_tools.results | selectattr('stat.exists') | list | length
|
||||
== inference_engine_tools.results | length
|
||||
- inference_engine_tools.results | selectattr('stat.executable', 'equalto', true) | list | length
|
||||
== inference_engine_tools.results | length
|
||||
fail_msg: >-
|
||||
{{ item.item }} is missing or not executable; run the host baseline
|
||||
roles first (llm-server/host/ansible).
|
||||
A required rootless runtime utility is missing or not executable
|
||||
(runuser, podman, systemctl or the Podman system generator); run the
|
||||
host baseline roles first (llm-server/host/ansible).
|
||||
tags:
|
||||
- service
|
||||
|
||||
@@ -68,6 +70,9 @@
|
||||
ansible.builtin.find:
|
||||
paths: /dev/dri
|
||||
patterns: renderD*
|
||||
# Render nodes are character devices; the default file_type (file) would
|
||||
# skip them.
|
||||
file_type: any
|
||||
register: inference_engine_render_node_find
|
||||
tags:
|
||||
- service
|
||||
@@ -105,11 +110,17 @@
|
||||
- name: Verify every profile model artifact is present
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- item.stat.exists
|
||||
loop: "{{ inference_engine_models.results }}"
|
||||
- inference_engine_models.results | selectattr('stat.exists', 'equalto', true) | list | length
|
||||
== inference_engine_models.results | length
|
||||
fail_msg: >-
|
||||
Model artifact for {{ item.item.key }} is missing under
|
||||
{{ model_store_root }}; run the model_store role (--tags models) first.
|
||||
Missing model artifacts under {{ model_store_root }}:
|
||||
{{ inference_engine_models.results
|
||||
| selectattr('stat.exists', 'equalto', false)
|
||||
| map(attribute='item.key') | list | join(', ') }};
|
||||
run the model_store role (--tags models) first.
|
||||
# Check mode deliberately downloads nothing, so the preview continues and
|
||||
# only shows the pending quadlet changes; a real run enforces presence.
|
||||
when: not ansible_check_mode
|
||||
tags:
|
||||
- service
|
||||
|
||||
|
||||
@@ -80,7 +80,9 @@
|
||||
- /bin/df
|
||||
- -m
|
||||
- --output=avail
|
||||
- "{{ model_store_root }}"
|
||||
# dirname is used because the store root itself may not exist yet in
|
||||
# check mode; it lives on the same filesystem as the store.
|
||||
- "{{ model_store_root | dirname }}"
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
register: model_store_free_space
|
||||
@@ -151,14 +153,14 @@
|
||||
|
||||
- name: Enforce model artifact ownership and permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ model_store_root }}/{{ item.directory }}/{{ item.file }}"
|
||||
path: "{{ model_store_root }}/{{ item.item.directory }}/{{ item.item.file }}"
|
||||
state: file
|
||||
owner: root
|
||||
group: root
|
||||
mode: "{{ model_store_file_mode }}"
|
||||
loop: "{{ model_store_all_artifacts }}"
|
||||
loop: "{{ model_store_present.results | selectattr('stat.exists', 'equalto', true) | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.profile }}"
|
||||
label: "{{ item.item.profile }}"
|
||||
tags:
|
||||
- models
|
||||
- service
|
||||
|
||||
Reference in New Issue
Block a user