From 7e16c13a9d2c86e6c3e5708f5ebc6a7c4d7ff057 Mon Sep 17 00:00:00 2001 From: mikejgray Date: Mon, 18 Nov 2024 22:08:21 -0600 Subject: [PATCH] feat: install neon node client --- ansible/hub.yaml | 11 +++- ansible/neon-node.yaml | 63 +++++++++++++++++++ ansible/templates/neon-hub.yml.j2 | 16 +++++ .../neon-node/neon-node-requirements.j2.txt | 1 + .../templates/neon-node/neon-node.service.j2 | 16 +++++ .../neon-node/rust-messagebus.service.j2 | 13 ++++ ansible/templates/neon-node/start-node.py | 4 ++ ansible/templates/neon.yaml.j2 | 39 ++++-------- ansible/templates/nginx.conf.j2 | 14 +++++ installer.sh | 16 ++++- scripts/common.sh | 2 +- 11 files changed, 164 insertions(+), 31 deletions(-) create mode 100644 ansible/neon-node.yaml create mode 100644 ansible/templates/neon-node/neon-node-requirements.j2.txt create mode 100644 ansible/templates/neon-node/neon-node.service.j2 create mode 100644 ansible/templates/neon-node/rust-messagebus.service.j2 create mode 100644 ansible/templates/neon-node/start-node.py diff --git a/ansible/hub.yaml b/ansible/hub.yaml index a0fe9a0..4d2b354 100644 --- a/ansible/hub.yaml +++ b/ansible/hub.yaml @@ -43,6 +43,7 @@ # Hub xdg_dir: /home/neon/xdg common_name: neon-hub.local + install_neon_node: "1" secrets_file: "{{ playbook_dir }}/neon_hub_secrets.yaml" # Docker - this will change rarely docker_user: "{{ ansible_user | default(lookup('env', 'USER')) }}" @@ -67,9 +68,6 @@ - geerlingguy.docker tasks: - # TODO: Loops, move neon.yaml to /opt/neon/config, create user neon.yaml with templating - # TODO: Time zone config, 12/24 hr time config - # TODO: Debug config # Prepare - name: Ensure package prerequisites are installed ansible.builtin.package: @@ -120,6 +118,8 @@ - "{{ xdg_dir }}/config/neon" - "/home/neon/compose" - "/home/neon/.config/pulse" + - "/home/neon/.config/systemd" + - "/home/neon/.config/systemd/user" - name: Create {{ xdg_dir }}/config/rabbitmq folder ansible.builtin.file: path: "{{ xdg_dir }}/config/rabbitmq" @@ -221,6 +221,11 @@ delay: 3 environment: DOCKER_TIMEOUT: "900" + # Neon Node Client + - name: Install Neon Node Client + import_tasks: neon-node.yaml + when: install_neon_node == "1" + # Finish - name: Create file indicating successful deployment ansible.builtin.file: path: "{{ xdg_dir }}/neon-installed" diff --git a/ansible/neon-node.yaml b/ansible/neon-node.yaml new file mode 100644 index 0000000..68077d3 --- /dev/null +++ b/ansible/neon-node.yaml @@ -0,0 +1,63 @@ +--- +- name: Copy Neon Node files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "0644" + owner: neon + group: neon + loop: + - { "src": "templates/neon-node/neon-node-requirements.j2.txt", "dest": "/home/neon/neon-node-requirements.txt"} + - { "src": "templates/neon-node/start-node.py", "dest": "/home/neon/start-node.py"} +- name: Create Neon Node config folder + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: "2775" # Keeps the group sticky + owner: neon + group: neon + loop: + - /root/xdg/config + - /root/xdg/config/neon +- name: Create symlinked neon.yaml + ansible.builtin.file: + src: /home/neon/xdg/config/neon/neon.yaml + dest: /root/xdg/config/neon/neon.yaml + state: link +- name: Install Neon Node voice client + ansible.builtin.pip: + requirements: "/home/neon/neon-node-requirements.txt" + virtualenv: "/home/neon/.venvs/neon-node" + extra_args: "--pre" # TODO: Remove after a stable release +# - name: Download Rust messagebus +# ansible.builtin.get_url: +# url: https://github.com/OscillateLabsLLC/ovos-rust-messagebus/releases/download/v1.0.0/ovos_messagebus-x86_64-unknown-linux-gnu.tar.gz +# dest: /home/neon +# mode: 0755 +# - name: Unarchive Rust messagebus +# ansible.builtin.unarchive: +# remote_src: true +# src: /home/neon/ovos_messagebus-x86_64-unknown-linux-gnu.tar.gz +# dest: /home/neon +- name: Set up Neon Node services + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: neon + group: neon + mode: 0644 + backup: true + loop: + - { "src": "templates/neon-node/neon-node.service.j2", "dest": "/etc/systemd/system/neon-node.service" } + # - { "src": "templates/neon-node/rust-messagebus.service.j2", "dest": "/etc/systemd/system/neon-messagebus.service" } +- name: Enable and start Neon Node services + ansible.builtin.systemd_service: + name: "{{ item }}" + enabled: true + force: true + daemon_reload: true + state: restarted + become: true + loop: + # - neon-messagebus.service + - neon-node.service diff --git a/ansible/templates/neon-hub.yml.j2 b/ansible/templates/neon-hub.yml.j2 index a6b2347..a531a11 100644 --- a/ansible/templates/neon-hub.yml.j2 +++ b/ansible/templates/neon-hub.yml.j2 @@ -341,3 +341,19 @@ services: - /home/neon/compose/nginx.conf:/etc/nginx/nginx.conf:ro - /home/neon/{{ common_name }}.crt:/etc/ssl/certs/{{ common_name }}.crt:ro - /home/neon/{{ common_name }}.key:/etc/ssl/private/{{ common_name }}.key:ro +{% if install_neon_node %} + hub_config: + <<: *podman + logging: *default-logging + restart: unless-stopped + depends_on: + - neon-hana + image: ghcr.io/oscillatelabsllc/neon-hub-config:main # TODO: + container_name: neon-hub-config + networks: + neon-core: + volumes: + - ${NEON_CONFIG_FOLDER}:/xdg/config + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro +{% endif %} diff --git a/ansible/templates/neon-node/neon-node-requirements.j2.txt b/ansible/templates/neon-node/neon-node-requirements.j2.txt new file mode 100644 index 0000000..d095a65 --- /dev/null +++ b/ansible/templates/neon-node/neon-node-requirements.j2.txt @@ -0,0 +1 @@ +neon-nodes[voice-client]~=0.0 \ No newline at end of file diff --git a/ansible/templates/neon-node/neon-node.service.j2 b/ansible/templates/neon-node/neon-node.service.j2 new file mode 100644 index 0000000..b87fdf2 --- /dev/null +++ b/ansible/templates/neon-node/neon-node.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Documentation=https://github.com/NeonGeckoCom/neon-nodes/blob/dev/README.md +Description=Neon Node Voice Client + +[Service] +ExecStart=/home/neon/.venvs/neon-node/bin/python /home/neon/start-node.py +ExecReload=/usr/bin/kill -HUP $MAINPID +ExecStop=/usr/bin/kill -KILL $MAINPID +Restart=on-failure +RestartSec=5s +Environment="OVOS_CONFIG_BASE_FOLDER=neon" +Environment="OVOS_CONFIG_FILENAME=neon.yaml" +Environment="XDG_CONFIG_HOME=/home/neon/xdg/config" + +[Install] +WantedBy=neon-messagebus.service diff --git a/ansible/templates/neon-node/rust-messagebus.service.j2 b/ansible/templates/neon-node/rust-messagebus.service.j2 new file mode 100644 index 0000000..e058710 --- /dev/null +++ b/ansible/templates/neon-node/rust-messagebus.service.j2 @@ -0,0 +1,13 @@ +[Unit] +Documentation=https://github.com/OscillateLabsLLC/ovos-rust-messagebus/blob/dev/README.md +Description=Neon Rust Messagebus + +[Service] +ExecStart=/home/neon/ovos_messagebus-x86_64-unknown-linux-gnu +ExecReload=/usr/bin/kill -HUP $MAINPID +ExecStop=/usr/bin/kill -KILL $MAINPID +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=multi-user.target diff --git a/ansible/templates/neon-node/start-node.py b/ansible/templates/neon-node/start-node.py new file mode 100644 index 0000000..f912665 --- /dev/null +++ b/ansible/templates/neon-node/start-node.py @@ -0,0 +1,4 @@ +from neon_utils.process_utils import start_systemd_service +from neon_nodes.voice_client import NeonVoiceClient + +start_systemd_service(NeonVoiceClient().watchdog()) diff --git a/ansible/templates/neon.yaml.j2 b/ansible/templates/neon.yaml.j2 index 4111be8..9fb5a88 100644 --- a/ansible/templates/neon.yaml.j2 +++ b/ansible/templates/neon.yaml.j2 @@ -1,21 +1,7 @@ -hana: - server_host: "0.0.0.0" - port: 8080 - mq_default_timeout: 10 - access_token_ttl: 86400 # 1 day - refresh_token_ttl: 604800 # 1 week - requests_per_minute: 60 - auth_requests_per_minute: 6 # This counts valid and invalid requests from an IP address - access_token_secret: "{{ hana.access_token_secret }}" - refresh_token_secret: "{{ hana.refresh_token_secret }}" - fastapi_title: "My HANA API Host" - fastapi_summary: "Personal HTTP API to access my DIANA backend." - disable_auth: True - stt_max_length_encoded: 500000 # Arbitrary limit that is larger than any expected voice command - tts_max_words: 128 # Arbitrary limit that is longer than any default LLM token limit - enable_email: False # Disabled by default; anyone with access to the API will be able to send emails from the configured address - node_username: neon_node # Username to authenticate Node API access; leave empty to disable Node API access - node_password: "{{ hana.node_pw }}" # Password associated with node_username +LOG_LEVEL: INFO +system_unit: imperial +time_format: half +lang: en-us MQ: port: 5672 server: neon-rabbitmq @@ -53,18 +39,19 @@ MQ: neon_chat_api: password: "{{ users.neon_core.password }}" user: neon_core -iris: - default_lang: en-us - languages: - - en-us - webui_chatbot_label: "Neon AI" - webui_mic_label: "Speak with Neon" - webui_input_placeholder: "Speak with Neon" - webui_ws_url: wss://iris-websat.{{ common_name }}/ws # Note that this is self-signed websocket: host: neon-messagebus listener: enable_voice_loop: False +{% if install_neon_node %} +neon_node: + description: Neon Hub Node # Friendly description of the node + hana_address: http://{{ common_name }}:8082 # Hana server HTTP address + hana_username: neon_node # Hana node user username + hana_password: {{ hana.node_pw }} +microphone: # Required here for Neon Node + module: ovos-microphone-plugin-alsa +{% endif %} # api_services: # alpha_vantage: # api_key: CUSTOM_KEY_HERE diff --git a/ansible/templates/nginx.conf.j2 b/ansible/templates/nginx.conf.j2 index ebcee71..66ef7ae 100644 --- a/ansible/templates/nginx.conf.j2 +++ b/ansible/templates/nginx.conf.j2 @@ -109,4 +109,18 @@ http { proxy_pass http://yacht:8000; } } +{% if install_neon_node %} + # Neon Hub Config + server { + listen 443 ssl; + server_name config.{{ common_name }} + + ssl_certificate /etc/ssl/certs/{{ common_name }}.crt; + ssl_certificate_key /etc/ssl/private/{{ common_name }}.key; + + location / { + proxy_pass http://hub_config:80; + } + } +{% endif %} } \ No newline at end of file diff --git a/installer.sh b/installer.sh index 8d751ac..f00e430 100755 --- a/installer.sh +++ b/installer.sh @@ -110,12 +110,26 @@ case $HOSTNAME_CHOICE in ;; esac +INSTALL_NODE_VOICE_CLIENT_CHOICE=$(whiptail --title "Neon Hub Installer" --menu "Install the Neon Node Voice Client? This allows you to treat your Hub as a Node." 15 78 3 \ +"1" "Yes (default)" \ +"2" "No" 3>&1 1>&2 2>&3) + +case $INSTALL_NODE_VOICE_CLIENT_CHOICE in + 1) + INSTALL_NODE_VOICE_CLIENT=1 + ;; + 2) + INSTALL_NODE_VOICE_CLIENT=0 + ;; +esac + # Installation echo "Installing Neon Hub. This may take some time, take a break and relax." echo "You can find installation logs at $LOG_FILE." export ANSIBLE_CONFIG=ansible.cfg -ansible-playbook -i 127.0.0.1 -e "xdg_dir=$XDG_DIR common_name=$HOSTNAME" "${ansible_debug[@]}" ansible/hub.yaml | tee $ANSIBLE_LOG_FILE +ansible-playbook -i 127.0.0.1 -e "xdg_dir=$XDG_DIR common_name=$HOSTNAME install_neon_node=$INSTALL_NODE_VOICE_CLIENT" \ +"${ansible_debug[@]}" ansible/hub.yaml | tee $ANSIBLE_LOG_FILE if [ "${PIPESTATUS[0]}" -eq 0 ]; then show_message "Neon Hub has been successfully installed!" diff --git a/scripts/common.sh b/scripts/common.sh index bf896aa..7c123be 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -77,7 +77,7 @@ function required_packages() { case "$DISTRO_NAME" in debian | ubuntu | raspbian | linuxmint | zorin) - UPDATE=1 apt_ensure python3 python3-dev python3-pip python3-venv whiptail jq git &>>"$LOG_FILE" + UPDATE=1 apt_ensure python3 python3-dev python3-pip python3-venv python3-virtualenv whiptail jq git &>>"$LOG_FILE" ;; fedora) echo "Neon Hub only supports Debian-based distributions at the moment." | tee -a "$LOG_FILE"