diff --git a/README.md b/README.md index ba1f455..3f0538b 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ Default endpoints: The deployment will: -- bind `sshd` to `127.0.0.1:22` only +- leave the host's SSH listen addresses under local control while requiring `127.0.0.1:22` for WeTTY - install WeTTY and expose it at `http://127.0.0.1:7681/wetty` - leave login identity management to the host, so any existing local account with password-based SSH access can sign in through the browser terminal diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index 3d52caf..1a60dbc 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -16,6 +16,9 @@ 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_venv_dir: "{{ courseware_tools_dir }}/uv" +courseware_uv_python_install_dir: "{{ courseware_tools_dir }}/uv-python" +courseware_open_webui_python_version: "3.12" courseware_netron_venv_dir: "{{ courseware_venvs_dir }}/netron" courseware_wetty_dir: "{{ courseware_tools_dir }}/wetty" courseware_promptfoo_dir: "{{ courseware_lab6_dir }}" diff --git a/ansible/roles/open_webui/tasks/main.yml b/ansible/roles/open_webui/tasks/main.yml index 86a9ae6..9eb7ef7 100644 --- a/ansible/roles/open_webui/tasks/main.yml +++ b/ansible/roles/open_webui/tasks/main.yml @@ -4,15 +4,58 @@ state: directory mode: "0755" -- name: Create Open WebUI virtual environment +- name: Create uv helper virtual environment command: argv: - "{{ courseware_python_bin }}" - -m - venv + - "{{ courseware_uv_venv_dir }}" + args: + creates: "{{ courseware_uv_venv_dir }}/bin/python" + +- name: Install uv helper + command: + argv: + - "{{ courseware_uv_venv_dir }}/bin/python" + - -m + - pip + - install + - --upgrade + - pip + - uv + args: + creates: "{{ courseware_uv_venv_dir }}/bin/uv" + +- name: Check Open WebUI virtual environment Python version + command: + argv: + - "{{ courseware_venvs_dir }}/open-webui/bin/python" + - -c + - "import importlib.util, sys; expected = tuple(map(int, '{{ courseware_open_webui_python_version }}'.split('.')[:2])); ok = sys.version_info[:len(expected)] == expected and importlib.util.find_spec('pip') is not None; raise SystemExit(0 if ok else 1)" + register: courseware_open_webui_python_check + changed_when: false + failed_when: false + +- name: Remove incompatible Open WebUI virtual environment + file: + path: "{{ courseware_venvs_dir }}/open-webui" + state: absent + when: courseware_open_webui_python_check.rc != 0 + +- name: Create Open WebUI virtual environment + command: + argv: + - "{{ courseware_uv_venv_dir }}/bin/uv" + - venv + - --seed + - --python + - "{{ courseware_open_webui_python_version }}" - "{{ courseware_venvs_dir }}/open-webui" args: creates: "{{ courseware_venvs_dir }}/open-webui/bin/python" + environment: + UV_PYTHON_INSTALL_DIR: "{{ courseware_uv_python_install_dir }}" - name: Upgrade Open WebUI venv tooling command: diff --git a/ansible/roles/packages/tasks/linux.yml b/ansible/roles/packages/tasks/linux.yml index ce8ccc7..667a64d 100644 --- a/ansible/roles/packages/tasks/linux.yml +++ b/ansible/roles/packages/tasks/linux.yml @@ -14,6 +14,7 @@ - pkg-config - python3 - python3-pip + - python3-setuptools - python3-venv - unzip - zstd diff --git a/ansible/roles/terminal/tasks/main.yml b/ansible/roles/terminal/tasks/main.yml index 6c35a14..dfd8b02 100644 --- a/ansible/roles/terminal/tasks/main.yml +++ b/ansible/roles/terminal/tasks/main.yml @@ -13,7 +13,7 @@ state: directory mode: "0755" -- name: Configure courseware loopback-only sshd policy +- name: Configure courseware sshd policy become: true template: src: sshd-courseware-terminal.conf.j2 @@ -46,6 +46,15 @@ enabled: true when: ansible_service_mgr == "systemd" +- name: Reload sshd when config changed with systemd + become: true + systemd: + name: ssh + state: reloaded + when: + - ansible_service_mgr == "systemd" + - courseware_terminal_sshd_config.changed + - name: Check for running sshd when systemd is unavailable become: true command: pgrep -x sshd @@ -89,19 +98,13 @@ environment: PATH: "{{ courseware_node_runtime_bin_dir }}:{{ ansible_env.PATH }}" -- name: Check loopback sshd listener - become: true - command: ss -ltn - register: courseware_terminal_ss_listeners - changed_when: false - -- name: Assert sshd is loopback-only - 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" - - "'[::]: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." +- name: Wait for sshd to accept local WeTTY connections + wait_for: + host: 127.0.0.1 + port: 22 + state: started + timeout: 10 + msg: "sshd must accept connections on 127.0.0.1:22 for the browser terminal deployment." - name: Assert WeTTY binary exists stat: diff --git a/ansible/roles/terminal/templates/sshd-courseware-terminal.conf.j2 b/ansible/roles/terminal/templates/sshd-courseware-terminal.conf.j2 index 6d98cb4..5230dc9 100644 --- a/ansible/roles/terminal/templates/sshd-courseware-terminal.conf.j2 +++ b/ansible/roles/terminal/templates/sshd-courseware-terminal.conf.j2 @@ -1,6 +1,4 @@ # Managed by Local Courseware Deployment. -ListenAddress 127.0.0.1 -AddressFamily inet PermitRootLogin no PasswordAuthentication yes KbdInteractiveAuthentication no