--- - name: "🔍 Resolve the container before preloading on '{{ lmstudio_node }}'" ansible.builtin.include_tasks: utils/cid.yml - name: "⏳ Wait until the LM Studio daemon has finished starting on '{{ lmstudio_node }}'" ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node container exec {{ LMSTUDIO_LOCAL_CID | quote }} {{ 10 | curl(retries=0) }} -fS -o /dev/null http://127.0.0.1:{{ LMSTUDIO_PORT }}/lmstudio-greeting register: lmstudio_daemon_ready changed_when: false retries: 60 delay: 5 until: lmstudio_daemon_ready.rc == 0 delegate_to: "{{ lmstudio_node }}" - name: "🗄️ Measure the space the model store offers on '{{ lmstudio_node }}'" ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node container exec {{ LMSTUDIO_LOCAL_CID | quote }} df -P -B1 {{ LMSTUDIO_MODELS_TARGET | quote }} register: lmstudio_store_space changed_when: false retries: 30 delay: 2 until: lmstudio_store_space.rc == 0 delegate_to: "{{ lmstudio_node }}" when: not (LMSTUDIO_PRESEED_ENABLED | bool) - name: "🛑 Refuse to preload models the store on '{{ lmstudio_node }}' cannot hold" vars: _free: "{{ lmstudio_store_space.stdout_lines[1].split()[3] | int }}" _required: "{{ LMSTUDIO_PRELOAD_LARGEST_BYTES | int }}" ansible.builtin.fail: msg: >- The model store on {{ lmstudio_node }} has {{ (_free | int / 1024 / 1024 / 1024) | round(1) }} GiB free, less than the {{ (_required | int / 1024 / 1024 / 1024) | round(1) }} GiB the largest declared model needs. Shrink AI_LOCAL_MODELS in group_vars/all/16_ai.yml or give the node more disk. when: - not (LMSTUDIO_PRESEED_ENABLED | bool) - _free | int < _required | int - name: "⬇️ Preload the LM Studio models on '{{ lmstudio_node }}'" block: - name: "⬇️ Preload the LM Studio models (first pass)" ansible.builtin.include_tasks: utils/preload/pull.yml rescue: - name: "🐝 Re-raise the preload failure unchanged in swarm" # nocheck: rescue-recovery a timed-out transfer leaves the daemon reporting 0.00% for every further pull, and restarting the container it owns is the only lever the role has, though CI job 105558224377 shows a restart returning rc 0 without clearing it; the generic capture cannot even try, so swarm re-raises here instead, because under any_errors_fatal a rescued host keeps running while every other host is already marked failed, and compose ends the block by preloading again so an unrecovered failure still re-raises ansible.builtin.fail: msg: "{{ ansible_failed_result.msg | default('LM Studio preload failed') }}" when: DEPLOYMENT_MODE == 'swarm' - name: "♻️ Recover the wedged transfer and preload again" ansible.builtin.include_tasks: utils/preload/recover.yml