--- - name: Minimal check for doc/rpc Sol host hosts: sol_rpc gather_facts: true become: true vars_files: - ../group_vars/sol_rpc.yml tasks: - name: Install operator packages (Debian/Ubuntu) ansible.builtin.apt: name: - tmux - mc - git - neovim state: present update_cache: true when: ansible_facts.os_family == "Debian" - name: Install Solana host base packages (Debian/Ubuntu) ansible.builtin.apt: name: - chrony - curl - jq - smartmontools - nvme-cli - prometheus-node-exporter state: present update_cache: true when: ansible_facts.os_family == "Debian" - name: Ensure solana group exists ansible.builtin.group: name: "{{ solana_group }}" system: true - name: Ensure solana user exists ansible.builtin.user: name: "{{ solana_user }}" group: "{{ solana_group }}" home: "{{ solana_home }}" system: true create_home: true - name: Ensure root config directories exist ansible.builtin.file: path: "{{ item }}" state: directory owner: root group: root mode: "0755" loop: - /root/.config - /root/.config/mc - /root/.config/nvim - /root/.config/nvim/lua - name: Ensure Solana directories exist ansible.builtin.file: path: "{{ item.path }}" state: directory owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" loop: - { path: "/etc/solana", owner: "root", group: "root", mode: "0755" } - { path: "{{ solana_home }}", owner: "{{ solana_user }}", group: "{{ solana_group }}", mode: "0750" } - { path: "{{ solana_ledger_dir }}", owner: "{{ solana_user }}", group: "{{ solana_group }}", mode: "0750" } - { path: "{{ solana_accounts_dir }}", owner: "{{ solana_user }}", group: "{{ solana_group }}", mode: "0750" } - { path: "{{ solana_log_dir }}", owner: "{{ solana_user }}", group: "{{ solana_group }}", mode: "0750" } - { path: "/opt/solana/bin", owner: "root", group: "root", mode: "0755" } - name: Deploy tmux config (Ctrl+a prefix) ansible.builtin.copy: src: ../files/operator-dotfiles/tmux.conf dest: /root/.tmux.conf owner: root group: root mode: "0644" - name: Deploy Midnight Commander config ansible.builtin.copy: src: "../files/operator-dotfiles/mc/{{ item.src }}" dest: "/root/.config/mc/{{ item.dest }}" owner: root group: root mode: "0644" loop: - { src: "ini", dest: "ini" } - { src: "panels.ini", dest: "panels.ini" } - name: Deploy Neovim config files ansible.builtin.copy: src: "../files/operator-dotfiles/nvim/{{ item.src }}" dest: "/root/.config/nvim/{{ item.dest }}" owner: root group: root mode: "0644" loop: - { src: "init.lua", dest: "init.lua" } - { src: "lazy-lock.json", dest: "lazy-lock.json" } - { src: "lua/options.lua", dest: "lua/options.lua" } - { src: "lua/keymaps.lua", dest: "lua/keymaps.lua" } - { src: "lua/plugins.lua", dest: "lua/plugins.lua" } - { src: "lua/utils.lua", dest: "lua/utils.lua" } - { src: "lua/hazard3_dap.lua", dest: "lua/hazard3_dap.lua" } - name: Deploy solana-rpc systemd unit (runs as solana user) ansible.builtin.template: src: ../templates/solana-rpc.service.j2 dest: /etc/systemd/system/{{ solana_rpc_service_name }}.service owner: root group: root mode: "0644" register: solana_rpc_unit - name: Reload systemd after unit change ansible.builtin.systemd: daemon_reload: true when: solana_rpc_unit.changed - name: Check validator binary exists ansible.builtin.stat: path: "{{ solana_validator_bin }}" register: solana_validator_bin_stat - name: Install Agave toolchain for solana user when validator missing ansible.builtin.shell: | set -euo pipefail sh -c "$(curl -sSfL {{ solana_install_script_url }})" become_user: "{{ solana_user }}" environment: HOME: "{{ solana_home }}" args: executable: /bin/bash when: not solana_validator_bin_stat.stat.exists - name: Link Agave binaries into /opt/solana/bin ansible.builtin.shell: | set -euo pipefail if [ ! -d "{{ solana_active_release_bin_dir }}" ]; then echo "Active release bin dir missing: {{ solana_active_release_bin_dir }}" >&2 exit 1 fi for bin in "{{ solana_active_release_bin_dir }}"/*; do name="$(basename "$bin")" ln -sfn "$bin" "/opt/solana/bin/$name" done args: executable: /bin/bash when: not solana_validator_bin_stat.stat.exists - name: Re-check validator binary after install ansible.builtin.stat: path: "{{ solana_validator_bin }}" register: solana_validator_bin_stat - name: Install Agave build dependencies (Debian/Ubuntu) when validator missing ansible.builtin.apt: name: - build-essential - pkg-config - libssl-dev - clang - cmake - protobuf-compiler - libudev-dev - zlib1g-dev state: present update_cache: true when: - ansible_facts.os_family == "Debian" - not solana_validator_bin_stat.stat.exists - name: Ensure Agave source parent directory exists ansible.builtin.file: path: "{{ agave_src_dir | dirname }}" state: directory owner: "{{ solana_user }}" group: "{{ solana_group }}" mode: "0755" when: not solana_validator_bin_stat.stat.exists - name: Install rustup (Agave build) for solana user when validator missing ansible.builtin.shell: | set -euo pipefail curl -sSfL https://sh.rustup.rs | sh -s -- -y --default-toolchain "{{ agave_rust_toolchain }}" become_user: "{{ solana_user }}" environment: HOME: "{{ solana_home }}" args: executable: /bin/bash creates: "{{ solana_home }}/.cargo/bin/cargo" when: not solana_validator_bin_stat.stat.exists - name: Ensure Rust toolchain is installed for solana user when validator missing ansible.builtin.shell: | set -euo pipefail export PATH="{{ solana_home }}/.cargo/bin:$PATH" rustup toolchain install "{{ agave_rust_toolchain }}" become_user: "{{ solana_user }}" environment: HOME: "{{ solana_home }}" args: executable: /bin/bash when: not solana_validator_bin_stat.stat.exists - name: Clone Agave sources when validator missing ansible.builtin.git: repo: "{{ agave_repo_url }}" dest: "{{ agave_src_dir }}" version: "{{ agave_version_tag }}" depth: 1 update: true become_user: "{{ solana_user }}" environment: HOME: "{{ solana_home }}" when: not solana_validator_bin_stat.stat.exists - name: Build agave-validator from sources when validator missing ansible.builtin.shell: | set -euo pipefail export PATH="{{ solana_home }}/.cargo/bin:$PATH" cd "{{ agave_src_dir }}" cargo +{{ agave_rust_toolchain }} build --release -p agave-validator become_user: "{{ solana_user }}" environment: HOME: "{{ solana_home }}" args: executable: /bin/bash creates: "{{ agave_src_dir }}/target/release/agave-validator" when: not solana_validator_bin_stat.stat.exists - name: Install agave-validator to /opt/solana/bin when built ansible.builtin.copy: remote_src: true src: "{{ agave_src_dir }}/target/release/agave-validator" dest: "{{ solana_validator_bin }}" owner: root group: root mode: "0755" when: not solana_validator_bin_stat.stat.exists - name: Re-check validator binary after source build ansible.builtin.stat: path: "{{ solana_validator_bin }}" register: solana_validator_bin_stat - name: Ensure identity key exists ansible.builtin.shell: | set -euo pipefail "{{ solana_keygen_bin }}" new --no-passphrase -o "{{ solana_identity_path }}" become_user: "{{ solana_user }}" environment: HOME: "{{ solana_home }}" args: executable: /bin/bash creates: "{{ solana_identity_path }}" - name: Check identity key exists ansible.builtin.stat: path: "{{ solana_identity_path }}" register: solana_identity_stat - name: Ensure solana-rpc service state when prerequisites exist ansible.builtin.systemd: name: "{{ solana_rpc_service_name }}" enabled: "{{ solana_rpc_enable_on_boot | bool }}" state: "{{ 'started' if (solana_rpc_start_now | bool) else 'stopped' }}" when: - solana_rpc_manage_service | bool - solana_validator_bin_stat.stat.exists - solana_identity_stat.stat.exists - name: Report skipped solana-rpc start due to missing prerequisites ansible.builtin.debug: msg: - "solana-rpc start skipped: missing prerequisites" - "validator_bin={{ solana_validator_bin }} exists={{ solana_validator_bin_stat.stat.exists }}" - "identity={{ solana_identity_path }} exists={{ solana_identity_stat.stat.exists }}" when: - solana_rpc_manage_service | bool - not (solana_validator_bin_stat.stat.exists and solana_identity_stat.stat.exists) - name: Validate Ansible transport ansible.builtin.ping: - name: Show host basics ansible.builtin.debug: msg: - "inventory_hostname={{ inventory_hostname }}" - "ansible_host={{ ansible_host | default('n/a') }}" - "hostname={{ ansible_facts['hostname'] | default('n/a') }}" - "os_family={{ ansible_facts['os_family'] | default('n/a') }}" - "kernel={{ ansible_facts['kernel'] | default('n/a') }}" - name: Read uptime ansible.builtin.command: uptime register: uptime_cmd changed_when: false - name: Print uptime ansible.builtin.debug: var: uptime_cmd.stdout