From 24869f47ee612f0057933d5d132e15c7773f4d52 Mon Sep 17 00:00:00 2001 From: Ryan Blundon Date: Tue, 26 May 2026 11:48:23 -0500 Subject: [PATCH] deply hermes VM --- .../host_vars/carousel-of-progress/vars.yml | 16 ++ ansible/inventory.yml | 6 + ansible/playbooks/day1_deploy_hermes.yml | 79 +++++++++ .../playbooks/roles/common/defaults/main.yml | 1 + .../playbooks/roles/hermes/defaults/main.yml | 15 ++ .../playbooks/roles/hermes/handlers/main.yml | 9 + ansible/playbooks/roles/hermes/tasks/main.yml | 156 ++++++++++++++++++ .../roles/hermes/templates/hermes.service.j2 | 23 +++ .../traefik/dynamic => archive}/grafana.yml | 0 boilerplates/traefik/dynamic/jarvis.yml | 4 +- 10 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 ansible/host_vars/carousel-of-progress/vars.yml create mode 100644 ansible/playbooks/day1_deploy_hermes.yml create mode 100644 ansible/playbooks/roles/hermes/defaults/main.yml create mode 100644 ansible/playbooks/roles/hermes/handlers/main.yml create mode 100644 ansible/playbooks/roles/hermes/tasks/main.yml create mode 100644 ansible/playbooks/roles/hermes/templates/hermes.service.j2 rename {boilerplates/traefik/dynamic => archive}/grafana.yml (100%) diff --git a/ansible/host_vars/carousel-of-progress/vars.yml b/ansible/host_vars/carousel-of-progress/vars.yml new file mode 100644 index 0000000..199297a --- /dev/null +++ b/ansible/host_vars/carousel-of-progress/vars.yml @@ -0,0 +1,16 @@ +--- +# ------------------------------------------------------------------------------ +# FILE: ansible/host_vars/astro_orbiter/vars.yml +# HOST: astro-orbiter (10.1.71.130) +# ROLE: Ollama inference host with AMD RX 5700 GPU passthrough +# ------------------------------------------------------------------------------ + +ansible_host: 10.1.71.131 +ansible_user: wed +ansible_become: true + +# LVM root expansion — xlarge template uses sda3 partition, standard VG/LV names +common_expand_root_lvm: true +common_root_pv: /dev/sda3 +common_root_vg: ubuntu-vg +common_root_lv: ubuntu-lv diff --git a/ansible/inventory.yml b/ansible/inventory.yml index efbe11e..210841f 100755 --- a/ansible/inventory.yml +++ b/ansible/inventory.yml @@ -65,6 +65,12 @@ ollama_server: ansible_user: wed ansible_become: true +hermes_server: + hosts: + carousel-of-progress: + ansible_host: 10.1.71.131 + ansible_user: wed + ansible_become: true papermc_server: # ansible-galaxy role install engonzal.papermc hosts: diff --git a/ansible/playbooks/day1_deploy_hermes.yml b/ansible/playbooks/day1_deploy_hermes.yml new file mode 100644 index 0000000..5049dce --- /dev/null +++ b/ansible/playbooks/day1_deploy_hermes.yml @@ -0,0 +1,79 @@ +--- +# ============================================================================= +# day1_deploy_hermes.yml +# Deploy Hermes Agent (Nous Research) on carousel-of-progress (10.1.71.131) +# +# FIRST-RUN WORKFLOW: +# 1. Run this playbook: +# ansible-playbook playbooks/day1_deploy_hermes.yml +# +# 2. SSH to the host and run the setup wizard as the hermes user: +# ssh wed@carousel-of-progress.local.mk-labs.cloud +# sudo -u hermes hermes setup +# +# 3. Once configured, start and verify the service: +# sudo systemctl start hermes +# sudo systemctl status hermes +# sudo journalctl -u hermes -f +# +# VARIABLES: +# hermes_skip_browser: true — set to skip Playwright/Chromium install +# (saves ~300MB if browser automation not needed) +# ============================================================================= + +- name: Deploy Hermes Agent on carousel-of-progress + hosts: carousel-of-progress + gather_facts: true + + pre_tasks: + - name: Verify target is carousel-of-progress + ansible.builtin.assert: + that: + - inventory_hostname == "carousel-of-progress" + fail_msg: > + This playbook is scoped to carousel-of-progress only. + Got: {{ inventory_hostname }} + + - name: Confirm OS is Ubuntu + ansible.builtin.assert: + that: + - ansible_distribution == "Ubuntu" + fail_msg: > + This playbook requires Ubuntu. Found: {{ ansible_distribution }}. + (If running Fedora, swap apt tasks for dnf and adjust Playwright deps.) + + roles: + - role: hermes + vars: + hermes_skip_browser: false # set true to skip Chromium install + + post_tasks: + - name: Verify hermes binary is accessible system-wide + ansible.builtin.command: hermes --version + register: hermes_version_check + changed_when: false + failed_when: hermes_version_check.rc != 0 + + - name: Print hermes version + ansible.builtin.debug: + msg: "{{ hermes_version_check.stdout }}" + + - name: Print post-install instructions + ansible.builtin.debug: + msg: + - "============================================================" + - "Hermes installed on carousel-of-progress (10.1.71.131)" + - "============================================================" + - "Next steps:" + - " 1. SSH to the host:" + - " ssh wed@carousel-of-progress.local.mk-labs.cloud" + - " 2. Run the setup wizard as the hermes user:" + - " sudo -u hermes hermes setup" + - " 3. After config, start the service:" + - " sudo systemctl start hermes" + - " 4. Verify:" + - " sudo systemctl status hermes" + - " sudo journalctl -u hermes -f" + - "============================================================" + - "Service is ENABLED but NOT STARTED — config required first." + - "============================================================" diff --git a/ansible/playbooks/roles/common/defaults/main.yml b/ansible/playbooks/roles/common/defaults/main.yml index 5e0e391..93bab39 100644 --- a/ansible/playbooks/roles/common/defaults/main.yml +++ b/ansible/playbooks/roles/common/defaults/main.yml @@ -8,6 +8,7 @@ common_timezone: America/Chicago common_ntp_server: "sundial.local.mk-labs.cloud" common_packages: + - acl - curl - wget - vim diff --git a/ansible/playbooks/roles/hermes/defaults/main.yml b/ansible/playbooks/roles/hermes/defaults/main.yml new file mode 100644 index 0000000..f1e0b97 --- /dev/null +++ b/ansible/playbooks/roles/hermes/defaults/main.yml @@ -0,0 +1,15 @@ +--- +# Hermes service user +hermes_user: hermes +hermes_group: hermes +hermes_home: /home/hermes + +# Install flags +# Set to true if you don't need browser automation (skips Playwright/Chromium) +hermes_skip_browser: false + +# systemd service name +hermes_service_name: hermes + +# Path where hermes binary will be accessible system-wide +hermes_bin_symlink: /usr/local/bin/hermes diff --git a/ansible/playbooks/roles/hermes/handlers/main.yml b/ansible/playbooks/roles/hermes/handlers/main.yml new file mode 100644 index 0000000..a0104fd --- /dev/null +++ b/ansible/playbooks/roles/hermes/handlers/main.yml @@ -0,0 +1,9 @@ +--- +- name: reload systemd + ansible.builtin.systemd: + daemon_reload: true + +- name: restart hermes + ansible.builtin.systemd: + name: "{{ hermes_service_name }}" + state: restarted diff --git a/ansible/playbooks/roles/hermes/tasks/main.yml b/ansible/playbooks/roles/hermes/tasks/main.yml new file mode 100644 index 0000000..ad4acb8 --- /dev/null +++ b/ansible/playbooks/roles/hermes/tasks/main.yml @@ -0,0 +1,156 @@ +--- +# --------------------------------------------------------------------------- +# 1. System prerequisites (run as root via become) +# --------------------------------------------------------------------------- + +- name: Install system packages required by Hermes installer + ansible.builtin.apt: + name: + - git + - curl + - ffmpeg + - ripgrep + state: present + update_cache: true + become: true + +- name: Install Node.js 22 (required for browser automation and WhatsApp bridge) + block: + - name: Download NodeSource setup script + ansible.builtin.get_url: + url: https://deb.nodesource.com/setup_22.x + dest: /tmp/nodesource_setup.sh + mode: "0755" + + - name: Run NodeSource setup script + ansible.builtin.command: bash /tmp/nodesource_setup.sh + args: + creates: /etc/apt/sources.list.d/nodesource.list + + - name: Install nodejs + ansible.builtin.apt: + name: nodejs + state: present + update_cache: true + become: true + +# --------------------------------------------------------------------------- +# 2. Install Playwright system deps for Chromium (root-only step) +# Per docs: this is the one thing that genuinely needs root. +# Skipped entirely if hermes_skip_browser is true. +# --------------------------------------------------------------------------- + +- name: Install Playwright Chromium system dependencies + ansible.builtin.command: npx --yes playwright install-deps chromium + become: true + when: not hermes_skip_browser + changed_when: true + environment: + DEBIAN_FRONTEND: noninteractive + +# --------------------------------------------------------------------------- +# 3. Create dedicated hermes service user +# --------------------------------------------------------------------------- + +- name: Create hermes group + ansible.builtin.group: + name: "{{ hermes_group }}" + state: present + system: true + become: true + +- name: Create hermes user + ansible.builtin.user: + name: "{{ hermes_user }}" + group: "{{ hermes_group }}" + home: "{{ hermes_home }}" + shell: /bin/bash + system: true + create_home: true + comment: "Hermes Agent service account" + become: true + +- name: Grant hermes user passwordless sudo + ansible.builtin.copy: + content: "hermes ALL=(ALL) NOPASSWD:ALL\n" + dest: /etc/sudoers.d/hermes + owner: root + group: root + mode: "0440" + validate: /usr/sbin/visudo -cf %s + become: true + +- name: Ensure hermes home directory has correct permissions + ansible.builtin.file: + path: "{{ hermes_home }}" + owner: "{{ hermes_user }}" + group: "{{ hermes_group }}" + mode: "0750" + state: directory + become: true + +# --------------------------------------------------------------------------- +# 4. Run the Hermes installer as the hermes user +# --------------------------------------------------------------------------- + +- name: Check if hermes is already installed + ansible.builtin.stat: + path: "{{ hermes_home }}/.hermes/hermes-agent/venv/bin/hermes" + register: hermes_binary + +- name: Run Hermes installer as hermes user + ansible.builtin.shell: | + curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh \ + | bash -s -- --skip-setup{% if hermes_skip_browser %} --skip-browser{% endif %} + args: + executable: /bin/bash + become: true + become_user: "{{ hermes_user }}" + environment: + HOME: "{{ hermes_home }}" + PATH: "{{ hermes_home }}/.local/bin:/usr/local/bin:/usr/bin:/bin" + when: not hermes_binary.stat.exists + changed_when: true + +# --------------------------------------------------------------------------- +# 5. Symlink hermes binary into system PATH +# Per docs: service accounts often lack ~/.local/bin in PATH; symlink +# into /usr/local/bin so hermes is always accessible. +# --------------------------------------------------------------------------- + +- name: Symlink hermes binary to system PATH + ansible.builtin.file: + src: "{{ hermes_home }}/.hermes/hermes-agent/venv/bin/hermes" + dest: "{{ hermes_bin_symlink }}" + state: link + force: true + become: true + +# --------------------------------------------------------------------------- +# 6. Install systemd service unit +# NOTE: The service starts in 'gateway' mode for persistent operation. +# You must run 'sudo -u hermes hermes setup' interactively on first boot +# to configure your LLM provider and any messaging gateways before +# enabling the service. +# --------------------------------------------------------------------------- + +- name: Deploy hermes systemd service unit + ansible.builtin.template: + src: hermes.service.j2 + dest: /etc/systemd/system/{{ hermes_service_name }}.service + owner: root + group: root + mode: "0644" + become: true + notify: + - reload systemd + +- name: Flush handlers to reload systemd now + ansible.builtin.meta: flush_handlers + +- name: Enable hermes service (but do not start — config required first) + ansible.builtin.systemd: + name: "{{ hermes_service_name }}" + enabled: true + state: stopped + become: true diff --git a/ansible/playbooks/roles/hermes/templates/hermes.service.j2 b/ansible/playbooks/roles/hermes/templates/hermes.service.j2 new file mode 100644 index 0000000..0c4f294 --- /dev/null +++ b/ansible/playbooks/roles/hermes/templates/hermes.service.j2 @@ -0,0 +1,23 @@ +[Unit] +Description=Hermes Agent (Nous Research) +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User={{ hermes_user }} +Group={{ hermes_group }} +WorkingDirectory={{ hermes_home }} +Environment="HOME={{ hermes_home }}" +Environment="PATH={{ hermes_home }}/.local/bin:/usr/local/bin:/usr/bin:/bin" +Environment="HERMES_HOME={{ hermes_home }}/.hermes" +ExecStart={{ hermes_home }}/.hermes/hermes-agent/venv/bin/hermes gateway +TimeoutStopSec=200 +Restart=on-failure +RestartSec=10 +StandardOutput=journal +StandardError=journal +SyslogIdentifier=hermes + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/boilerplates/traefik/dynamic/grafana.yml b/archive/grafana.yml similarity index 100% rename from boilerplates/traefik/dynamic/grafana.yml rename to archive/grafana.yml diff --git a/boilerplates/traefik/dynamic/jarvis.yml b/boilerplates/traefik/dynamic/jarvis.yml index a3c32ea..7694072 100644 --- a/boilerplates/traefik/dynamic/jarvis.yml +++ b/boilerplates/traefik/dynamic/jarvis.yml @@ -27,9 +27,9 @@ http: jarvis: loadBalancer: servers: - - url: "http://10.1.71.130:9119" + - url: "http://10.1.71.131:9119" jarvis-api: loadBalancer: servers: - - url: "http://10.1.71.130:8642" + - url: "http://10.1.71.131:8642"