Support LAN deployment and managed Python runtime
Made-with: Cursor
This commit is contained in:
@@ -2,6 +2,8 @@ courseware_state_dir: "{{ courseware_root }}/state"
|
||||
courseware_markers_dir: "{{ courseware_state_dir }}/markers"
|
||||
courseware_logs_dir: "{{ courseware_state_dir }}/logs"
|
||||
courseware_run_dir: "{{ courseware_state_dir }}/run"
|
||||
courseware_cache_dir: "{{ courseware_state_dir }}/cache"
|
||||
courseware_tmp_dir: "{{ courseware_state_dir }}/tmp"
|
||||
courseware_repos_dir: "{{ courseware_state_dir }}/repos"
|
||||
courseware_venvs_dir: "{{ courseware_state_dir }}/venvs"
|
||||
courseware_models_dir: "{{ courseware_state_dir }}/models"
|
||||
@@ -17,6 +19,10 @@ courseware_lab1_models_dir: "{{ courseware_models_dir }}/lab1"
|
||||
courseware_ollama_models_dir: "{{ courseware_models_dir }}/ollama"
|
||||
courseware_node_runtime_dir: "{{ courseware_tools_dir }}/node-runtime"
|
||||
courseware_node_runtime_bin_dir: "{{ courseware_node_runtime_dir }}/node_modules/node/bin"
|
||||
courseware_uv_dir: "{{ courseware_tools_dir }}/uv"
|
||||
courseware_uv_bin: "{{ courseware_uv_dir }}/bin/uv"
|
||||
courseware_uv_cache_dir: "{{ courseware_cache_dir }}/uv"
|
||||
courseware_python_runtime_dir: "{{ courseware_tools_dir }}/python"
|
||||
courseware_netron_venv_dir: "{{ courseware_venvs_dir }}/netron"
|
||||
courseware_wetty_dir: "{{ courseware_tools_dir }}/wetty"
|
||||
courseware_promptfoo_dir: "{{ courseware_lab6_dir }}"
|
||||
@@ -25,7 +31,15 @@ courseware_wiki_runtime_config_path: "{{ courseware_wiki_repo_dir }}/public/cour
|
||||
courseware_llama_cpp_bin_dir: "{{ courseware_repos_dir }}/llama.cpp/build/bin"
|
||||
|
||||
courseware_bind_host: "0.0.0.0"
|
||||
courseware_url_host: "127.0.0.1"
|
||||
courseware_url_host: >-
|
||||
{{
|
||||
(lookup('env', 'COURSEWARE_URL_HOST') | trim)
|
||||
if (lookup('env', 'COURSEWARE_URL_HOST') | trim | length) > 0
|
||||
else (
|
||||
ansible_default_ipv4.address
|
||||
| default(ansible_all_ipv4_addresses | default(['127.0.0.1']) | first)
|
||||
)
|
||||
}}
|
||||
courseware_ports:
|
||||
ollama: 11434
|
||||
open_webui: 8080
|
||||
@@ -44,6 +58,8 @@ courseware_chunkviz_commit: "a891eacafda1f28a12373ad3b00102e68f07c57f"
|
||||
courseware_promptfoo_version: "0.119.0"
|
||||
courseware_kiln_release_tag: "v0.18.1"
|
||||
courseware_node_runtime_version: "20.20.2"
|
||||
courseware_python_runtime_version: "3.12"
|
||||
courseware_uv_spec: "uv"
|
||||
courseware_wetty_spec: "wetty@2.5.0"
|
||||
courseware_wetty_base_path: "/wetty"
|
||||
courseware_wiki_repo: "https://git.zuccaro.me/bzuccaro/LLM-Labs.git"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- { role: preflight, tags: ["preflight"] }
|
||||
- directories
|
||||
- packages
|
||||
- python_runtime
|
||||
- netron
|
||||
- lab1_assets
|
||||
- lab_assets
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
- "{{ courseware_markers_dir }}"
|
||||
- "{{ courseware_logs_dir }}"
|
||||
- "{{ courseware_run_dir }}"
|
||||
- "{{ courseware_cache_dir }}"
|
||||
- "{{ courseware_tmp_dir }}"
|
||||
- "{{ courseware_uv_cache_dir }}"
|
||||
- "{{ courseware_repos_dir }}"
|
||||
- "{{ courseware_venvs_dir }}"
|
||||
- "{{ courseware_models_dir }}"
|
||||
|
||||
@@ -4,6 +4,24 @@
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Check Open WebUI virtual environment Python version
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_venvs_dir }}/open-webui/bin/python"
|
||||
- -c
|
||||
- "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
|
||||
register: courseware_open_webui_venv_python_version
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Remove Open WebUI virtual environment with incompatible Python
|
||||
file:
|
||||
path: "{{ courseware_venvs_dir }}/open-webui"
|
||||
state: absent
|
||||
when:
|
||||
- courseware_open_webui_venv_python_version.rc == 0
|
||||
- courseware_open_webui_venv_python_version.stdout != courseware_python_runtime_version
|
||||
|
||||
- name: Create Open WebUI virtual environment
|
||||
command:
|
||||
argv:
|
||||
@@ -36,6 +54,24 @@
|
||||
- "{{ courseware_open_webui_spec }}"
|
||||
- "numpy<2"
|
||||
|
||||
- name: Check Embedding Atlas virtual environment Python version
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_venvs_dir }}/embedding-atlas/bin/python"
|
||||
- -c
|
||||
- "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
|
||||
register: courseware_embedding_atlas_venv_python_version
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Remove Embedding Atlas virtual environment with incompatible Python
|
||||
file:
|
||||
path: "{{ courseware_venvs_dir }}/embedding-atlas"
|
||||
state: absent
|
||||
when:
|
||||
- courseware_embedding_atlas_venv_python_version.rc == 0
|
||||
- courseware_embedding_atlas_venv_python_version.stdout != courseware_python_runtime_version
|
||||
|
||||
- name: Create Embedding Atlas virtual environment
|
||||
command:
|
||||
argv:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
- pkg-config
|
||||
- python3
|
||||
- python3-pip
|
||||
- python3-setuptools
|
||||
- python3-venv
|
||||
- unzip
|
||||
- zstd
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
- name: Create contained Python runtime manager virtual environment
|
||||
command:
|
||||
argv:
|
||||
- /usr/bin/python3
|
||||
- -m
|
||||
- venv
|
||||
- "{{ courseware_uv_dir }}"
|
||||
args:
|
||||
creates: "{{ courseware_uv_dir }}/bin/python"
|
||||
|
||||
- name: Upgrade contained Python runtime manager tooling
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_uv_dir }}/bin/python"
|
||||
- -m
|
||||
- pip
|
||||
- install
|
||||
- --upgrade
|
||||
- pip
|
||||
- setuptools
|
||||
- wheel
|
||||
|
||||
- name: Install contained Python runtime manager
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_uv_dir }}/bin/python"
|
||||
- -m
|
||||
- pip
|
||||
- install
|
||||
- "{{ courseware_uv_spec }}"
|
||||
|
||||
- name: Install managed CPython runtime
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_uv_bin }}"
|
||||
- python
|
||||
- install
|
||||
- "{{ courseware_python_runtime_version }}"
|
||||
- --install-dir
|
||||
- "{{ courseware_python_runtime_dir }}"
|
||||
environment:
|
||||
UV_PYTHON_INSTALL_DIR: "{{ courseware_python_runtime_dir }}"
|
||||
UV_CACHE_DIR: "{{ courseware_uv_cache_dir }}"
|
||||
XDG_CACHE_HOME: "{{ courseware_cache_dir }}"
|
||||
TMPDIR: "{{ courseware_tmp_dir }}"
|
||||
register: courseware_python_runtime_install
|
||||
changed_when: "'Installed Python' in courseware_python_runtime_install.stdout"
|
||||
|
||||
- name: Resolve managed CPython runtime
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_uv_bin }}"
|
||||
- python
|
||||
- find
|
||||
- "{{ courseware_python_runtime_version }}"
|
||||
environment:
|
||||
UV_PYTHON_INSTALL_DIR: "{{ courseware_python_runtime_dir }}"
|
||||
UV_CACHE_DIR: "{{ courseware_uv_cache_dir }}"
|
||||
XDG_CACHE_HOME: "{{ courseware_cache_dir }}"
|
||||
TMPDIR: "{{ courseware_tmp_dir }}"
|
||||
register: courseware_python_runtime_find
|
||||
changed_when: false
|
||||
|
||||
- name: Set managed Python runtime for courseware venvs
|
||||
set_fact:
|
||||
courseware_python_bin: "{{ courseware_python_runtime_find.stdout | trim }}"
|
||||
|
||||
- name: Verify managed Python runtime version
|
||||
command:
|
||||
argv:
|
||||
- "{{ courseware_python_bin }}"
|
||||
- -c
|
||||
- "import sys; expected=tuple(map(int, '{{ courseware_python_runtime_version }}'.split('.'))); raise SystemExit(0 if sys.version_info[:len(expected)] == expected else 1)"
|
||||
changed_when: false
|
||||
@@ -46,6 +46,25 @@
|
||||
enabled: true
|
||||
when: ansible_service_mgr == "systemd"
|
||||
|
||||
- name: Check systemd sshd listener policy
|
||||
become: true
|
||||
command: ss -ltn
|
||||
register: courseware_terminal_systemd_ss_listeners
|
||||
changed_when: false
|
||||
when: ansible_service_mgr == "systemd"
|
||||
|
||||
- name: Restart sshd with systemd when listener policy is not active
|
||||
become: true
|
||||
systemd:
|
||||
name: ssh
|
||||
state: restarted
|
||||
enabled: true
|
||||
when:
|
||||
- ansible_service_mgr == "systemd"
|
||||
- >-
|
||||
'0.0.0.0:22' not in courseware_terminal_systemd_ss_listeners.stdout
|
||||
or '[::]:22' in courseware_terminal_systemd_ss_listeners.stdout
|
||||
|
||||
- name: Check for running sshd when systemd is unavailable
|
||||
become: true
|
||||
command: pgrep -x sshd
|
||||
@@ -89,19 +108,18 @@
|
||||
environment:
|
||||
PATH: "{{ courseware_node_runtime_bin_dir }}:{{ ansible_env.PATH }}"
|
||||
|
||||
- name: Check loopback sshd listener
|
||||
- name: Check sshd listener
|
||||
become: true
|
||||
command: ss -ltn
|
||||
register: courseware_terminal_ss_listeners
|
||||
changed_when: false
|
||||
|
||||
- name: Assert sshd is loopback-only
|
||||
- name: Assert sshd accepts LAN and loopback clients
|
||||
assert:
|
||||
that:
|
||||
- "'127.0.0.1:22' in courseware_terminal_ss_listeners.stdout"
|
||||
- "'0.0.0.0:22' not in courseware_terminal_ss_listeners.stdout"
|
||||
- "'0.0.0.0:22' in courseware_terminal_ss_listeners.stdout"
|
||||
- "'[::]:22' not in courseware_terminal_ss_listeners.stdout"
|
||||
fail_msg: "sshd must listen only on 127.0.0.1:22 for the browser terminal deployment."
|
||||
fail_msg: "sshd must listen on 0.0.0.0:22 so VPN/LAN SSH clients and local WeTTY can connect."
|
||||
|
||||
- name: Assert WeTTY binary exists
|
||||
stat:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Managed by Local Courseware Deployment.
|
||||
ListenAddress 127.0.0.1
|
||||
ListenAddress 0.0.0.0
|
||||
AddressFamily inet
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication yes
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
args:
|
||||
executable: /bin/bash
|
||||
creates: "{{ courseware_unsloth_home }}/.install_complete"
|
||||
environment:
|
||||
UV_CACHE_DIR: "{{ courseware_uv_cache_dir }}"
|
||||
XDG_CACHE_HOME: "{{ courseware_cache_dir }}"
|
||||
TMPDIR: "{{ courseware_tmp_dir }}"
|
||||
rescue:
|
||||
- name: Capture Unsloth installer log tail
|
||||
shell: |
|
||||
@@ -41,3 +45,18 @@
|
||||
|
||||
Last log lines:
|
||||
{{ courseware_unsloth_install_log_tail.stdout | default('(no log output captured)') }}
|
||||
|
||||
- name: Install x86_64-compatible NumPy for Unsloth Studio
|
||||
command:
|
||||
argv:
|
||||
- "{{ ansible_env.HOME }}/.unsloth/studio/unsloth_studio/bin/python"
|
||||
- -m
|
||||
- pip
|
||||
- install
|
||||
- "numpy<2"
|
||||
environment:
|
||||
UV_CACHE_DIR: "{{ courseware_uv_cache_dir }}"
|
||||
XDG_CACHE_HOME: "{{ courseware_cache_dir }}"
|
||||
TMPDIR: "{{ courseware_tmp_dir }}"
|
||||
register: courseware_unsloth_numpy_install
|
||||
changed_when: "'Successfully installed' in courseware_unsloth_numpy_install.stdout"
|
||||
|
||||
Reference in New Issue
Block a user