From 7b165e28fe86e5f0057ce35be81c0b71508f0060 Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Mon, 30 Sep 2024 14:10:34 +0400 Subject: [PATCH 01/10] add avalanche --- README.md | 2 + .../roles/avalanche/defaults/main.yml | 7 ++ .../avalanche/tasks/commands/install.yml | 64 +++++++++++++ .../roles/avalanche/tasks/commands/reset.yml | 9 ++ .../avalanche/tasks/commands/restart.yml | 45 +++++++++ .../roles/avalanche/tasks/commands/start.yml | 10 ++ .../roles/avalanche/tasks/commands/stop.yml | 41 +++++++++ .../avalanche/tasks/commands/uninstall.yml | 21 +++++ .../roles/avalanche/tasks/commands/update.yml | 8 ++ depin/services/roles/avalanche/tasks/main.yml | 10 ++ .../roles/avalanche/tasks/metrics.yml | 65 +++++++++++++ .../roles/avalanche/templates/collector.py.j2 | 91 +++++++++++++++++++ .../avalanche/templates/metrics.service.j2 | 15 +++ .../avalanche/templates/systemd.service.j2 | 14 +++ molecule/default/tasks/vars/avalanche.yml | 1 + molecule/libs/tasks/vars/avalanche.yml | 0 16 files changed, 403 insertions(+) create mode 100644 depin/services/roles/avalanche/defaults/main.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/install.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/reset.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/restart.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/start.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/stop.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/uninstall.yml create mode 100644 depin/services/roles/avalanche/tasks/commands/update.yml create mode 100644 depin/services/roles/avalanche/tasks/main.yml create mode 100644 depin/services/roles/avalanche/tasks/metrics.yml create mode 100644 depin/services/roles/avalanche/templates/collector.py.j2 create mode 100644 depin/services/roles/avalanche/templates/metrics.service.j2 create mode 100644 depin/services/roles/avalanche/templates/systemd.service.j2 create mode 100644 molecule/default/tasks/vars/avalanche.yml create mode 100644 molecule/libs/tasks/vars/avalanche.yml diff --git a/README.md b/README.md index 6b668918..96cfb06c 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ apt install pipx pipx install ansible-core pipx inject ansible-core requests pynetbox pyutils pytz netaddr pipx install ansible-lint +sudo pip install pynetbox + ``` ```bash diff --git a/depin/services/roles/avalanche/defaults/main.yml b/depin/services/roles/avalanche/defaults/main.yml new file mode 100644 index 00000000..0ef58ba2 --- /dev/null +++ b/depin/services/roles/avalanche/defaults/main.yml @@ -0,0 +1,7 @@ +# defaults/main.yml + +avalanche_metrics_port: 33006 +avalanche_cmd: "{{ depin_cmd | default('install') }}" + +avalanche_version: "1.10.0" +avalanche_download_url: "https://github.com/ava-labs/avalanchego/releases/download/v{{ avalanche_version }}/avalanchego-linux-amd64-v{{ avalanche_version }}.tar.gz" diff --git a/depin/services/roles/avalanche/tasks/commands/install.yml b/depin/services/roles/avalanche/tasks/commands/install.yml new file mode 100644 index 00000000..eb0fabea --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/install.yml @@ -0,0 +1,64 @@ +# tasks/commands/install.yml + +--- + +- name: Create program folder + become: true + ansible.builtin.file: + state: directory + owner: root + group: root + mode: '0755' + dest: /opt/avalanche/{{ avalanche_version }} + +- name: Download AvalancheGo + become: true + ansible.builtin.get_url: + url: "{{ avalanche_download_url }}" + dest: /tmp/avalanchego.tar.gz + mode: '0644' + +- name: Extract AvalancheGo + become: true + ansible.builtin.unarchive: + src: /tmp/avalanchego.tar.gz + dest: /opt/avalanche/{{ avalanche_version }} + remote_src: yes + extra_opts: + - --strip-components=1 + +- name: Ensure avalanchego binary is executable + become: true + ansible.builtin.file: + path: /opt/avalanche/{{ avalanche_version }}/avalanchego + mode: '0755' + +- name: Symlink avalanchego binary + become: true + ansible.builtin.file: + src: /opt/avalanche/{{ avalanche_version }}/avalanchego + dest: /usr/local/bin/avalanchego + state: link + force: true + +- name: Create systemd service + become: true + ansible.builtin.template: + src: templates/systemd.service.j2 + dest: /etc/systemd/system/avalanchego.service + mode: '0644' + +- name: Reload systemd daemon + become: true + ansible.builtin.systemd: + daemon_reload: yes + +- name: Start Avalanche node + ansible.builtin.include_tasks: + file: commands/start.yml + +- name: Install metrics + vars: + depin_cmd: install + ansible.builtin.include_tasks: + file: tasks/metrics.yml diff --git a/depin/services/roles/avalanche/tasks/commands/reset.yml b/depin/services/roles/avalanche/tasks/commands/reset.yml new file mode 100644 index 00000000..7a48419b --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/reset.yml @@ -0,0 +1,9 @@ +--- +## uninstall and install service +- name: Uninstall node + ansible.builtin.include_tasks: + file: commands/uninstall.yml + +- name: Install node + ansible.builtin.include_tasks: + file: commands/install.yml diff --git a/depin/services/roles/avalanche/tasks/commands/restart.yml b/depin/services/roles/avalanche/tasks/commands/restart.yml new file mode 100644 index 00000000..c3aad00a --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/restart.yml @@ -0,0 +1,45 @@ +--- +## restart service + +- name: Get current service info + become: true + ansible.builtin.systemd: + name: "avalanchego" + register: _avalanchego_before + +- name: Set current PID + ansible.builtin.set_fact: + _avalanche_pid: "{{ _avalanchego_before['status']['ExecMainPID'] }}" + +- name: Restart node + become: true + ansible.builtin.service: + name: avalanchego.service + state: restarted + +- name: Assert + when: "'molecule' in groups" + block: + - name: Get new service info + become: true + ansible.builtin.systemd: + name: "avalanchego" + register: _avalanchego_after + + - name: Debug new service status + debug: + msg: + - "Old PID: {{ _avalanche_pid }}" + - "New PID: {{ _avalanchego_after['status']['ExecMainPID'] }}" + - "Active State: {{ _avalanchego_after['status']['ActiveState'] }}" + + - name: Check service + ansible.builtin.assert: + that: + - _avalanchego_after['status']['ActiveState'] == 'active' + - _avalanche_pid | int != _avalanchego_after['status']['ExecMainPID'] | int + quiet: true + + - name: Update PID + ansible.builtin.set_fact: + _avalanche_pid: "{{ _avalanchego_after['status']['ExecMainPID'] }}" diff --git a/depin/services/roles/avalanche/tasks/commands/start.yml b/depin/services/roles/avalanche/tasks/commands/start.yml new file mode 100644 index 00000000..4a3461ef --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/start.yml @@ -0,0 +1,10 @@ +# tasks/commands/start.yml + +--- +- name: Start Avalanche node + become: true + ansible.builtin.service: + name: avalanchego.service + enabled: true + daemon_reload: true + state: started diff --git a/depin/services/roles/avalanche/tasks/commands/stop.yml b/depin/services/roles/avalanche/tasks/commands/stop.yml new file mode 100644 index 00000000..b5b31d56 --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/stop.yml @@ -0,0 +1,41 @@ +--- +## stop service + +- name: Assert start + when: "'molecule' in groups" + block: + - name: Get service info + become: true + ansible.builtin.systemd: + name: "avalanchego" + register: _avalanchego + + - name: Debug service status before stop + debug: + var: _avalanchego.status + +- name: Stop node + become: true + ansible.builtin.service: + name: avalanchego.service + enabled: false + state: stopped + +- name: Assert + when: "'molecule' in groups" + block: + - name: Get service info + become: true + ansible.builtin.systemd: + name: "avalanchego" + register: _avalanchego + + - name: Debug service status + debug: + var: _avalanchego.status + + - name: Check service + ansible.builtin.assert: + that: + - _avalanchego['status']['ActiveState'] == 'inactive' + quiet: true diff --git a/depin/services/roles/avalanche/tasks/commands/uninstall.yml b/depin/services/roles/avalanche/tasks/commands/uninstall.yml new file mode 100644 index 00000000..05b93ccd --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/uninstall.yml @@ -0,0 +1,21 @@ +--- +- name: Disable systemd service + ansible.builtin.include_tasks: commands/stop.yml + +- name: Uninstall metrics + vars: + depin_cmd: uninstall + ansible.builtin.include_tasks: + file: tasks/metrics.yml + +- name: Delete content & directory + become: true + ansible.builtin.file: + state: absent + path: "{{ uninstall_file }}" + loop: + - /etc/systemd/system/avalanchego.service + - /usr/local/bin/avalanchego + - /opt/avalanche/{{ avalanche_version }} + loop_control: + loop_var: uninstall_file diff --git a/depin/services/roles/avalanche/tasks/commands/update.yml b/depin/services/roles/avalanche/tasks/commands/update.yml new file mode 100644 index 00000000..50d55047 --- /dev/null +++ b/depin/services/roles/avalanche/tasks/commands/update.yml @@ -0,0 +1,8 @@ +--- +- name: Uninstall node + ansible.builtin.include_tasks: + file: commands/uninstall.yml + +- name: Install node + ansible.builtin.include_tasks: + file: commands/install.yml \ No newline at end of file diff --git a/depin/services/roles/avalanche/tasks/main.yml b/depin/services/roles/avalanche/tasks/main.yml new file mode 100644 index 00000000..9699a270 --- /dev/null +++ b/depin/services/roles/avalanche/tasks/main.yml @@ -0,0 +1,10 @@ +# tasks/main.yml + +--- +- name: Avalanche {{ avalanche_cmd }} + ansible.builtin.include_tasks: + file: commands/{{ avalanche_cmd }}.yml + +- name: Configure metrics + ansible.builtin.include_tasks: + file: metrics.yml diff --git a/depin/services/roles/avalanche/tasks/metrics.yml b/depin/services/roles/avalanche/tasks/metrics.yml new file mode 100644 index 00000000..2e3fecae --- /dev/null +++ b/depin/services/roles/avalanche/tasks/metrics.yml @@ -0,0 +1,65 @@ +# tasks/metrics.yml + +--- +- name: Install Avalanche metrics + vars: + _name: "{{ role_name | replace('_', '-') }}" + _metrics_port: avalanche_metrics_port + when: avalanche_cmd != 'uninstall' + become: true + block: + - name: Ensure directory exists + ansible.builtin.file: + path: /etc/deeep-network/collectors + state: directory + mode: '0755' + recurse: true + + - name: Install script + ansible.builtin.template: + src: templates/collector.py.j2 + dest: /etc/deeep-network/collectors/{{ _name }}.py + mode: '0744' + + - name: Install service + ansible.builtin.template: + src: templates/metrics.service.j2 + dest: /etc/systemd/system/collector-{{ _name }}.service + mode: '0644' + + - name: Update prometheus.conf + vars: + _block: | + - name: {{ _name }} + url: 'http://127.0.0.1:{{ vars[_metrics_port] }}/metrics' + ansible.builtin.blockinfile: + path: /etc/netdata/go.d/prometheus.conf + append_newline: true + block: "{{ _block | indent(4, first=true) }}" + + - name: Start service + ansible.builtin.systemd_service: + name: collector-{{ _name }} + enabled: true + daemon_reload: true + state: started + +- name: Uninstall Avalanche metrics + vars: + _name: "{{ role_name | replace('_', '-') }}" + when: avalanche_cmd == 'uninstall' + become: true + block: + - name: Stop service + ansible.builtin.systemd_service: + name: collector-{{ _name }} + enabled: false + state: stopped + + - name: Remove files + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /etc/systemd/system/collector-{{ _name }}.service + - /etc/deeep-network/collectors/{{ _name }}.py diff --git a/depin/services/roles/avalanche/templates/collector.py.j2 b/depin/services/roles/avalanche/templates/collector.py.j2 new file mode 100644 index 00000000..9260daf8 --- /dev/null +++ b/depin/services/roles/avalanche/templates/collector.py.j2 @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +import os +import socket +import time +import os +import time +import subprocess +from subprocess import check_output +import json + + +from prometheus_client import start_http_server, REGISTRY, GC_COLLECTOR, PLATFORM_COLLECTOR, PROCESS_COLLECTOR +from prometheus_client.core import GaugeMetricFamily +from prometheus_client.registry import Collector + +try: + from utils_lxd import lxd_get +except ImportError as imp_exc: + LXD_UTILS_IMPORT_ERROR = imp_exc +else: + LXD_UTILS_IMPORT_ERROR = None + +class MetricsCollector(Collector): + """Collector for Gala Node information""" + def total_uptime_count(sefl, autonomi_service_date): + total_uptime=0 + for x in autonomi_service_date: + state_uptime_list = autonomi_service_date[x].split(":") + hours=0 + if len(state_uptime_list) <= 2: + minutes = int(state_uptime_list[0]) + seconds = int(state_uptime_list[1]) + else: + hours = int(state_uptime_list[0]) + minutes = int(state_uptime_list[1]) + seconds = int(state_uptime_list[2]) + total_uptime=total_uptime+seconds+minutes*60+hours*3600 + return total_uptime + + def collect(self): + result = [] + service_metrics_collected = 1 + + device = 'molecule' + # fetch device hostname + # @note - LXD specific feature + {% if not molecule_inventory is defined -%} + if LXD_UTILS_IMPORT_ERROR is None: + device = lxd_get("1.0/config/user.location")['value'] + device = device['value'] + {% endif %} + + hostname = socket.gethostname() + service = '{{ _name }}' + + _labels = ['device', 'instance', 'service'] + _label_values = [device, hostname, service] + + success = GaugeMetricFamily('service_metrics_collected','service metrics collected successfully', labels=_labels) + success.add_metric(_label_values, value=service_metrics_collected) + + g2 = GaugeMetricFamily('current_state_uptime','seconds in current state', labels=_labels) + g2.add_metric(_label_values, value=state_uptime) + + g3 = GaugeMetricFamily('total_uptime','seconds in last 24 hours', labels=_labels) + g3.add_metric(_label_values, value=total_uptime) + + result.extend([g1, g2, g3]) + service_metrics_collected = 1 + + hostname = socket.gethostname() + service = '{{ _name }}' + + _labels = ['device', 'instance', 'service'] + _label_values = [device, hostname, service] + + success = GaugeMetricFamily('service_metrics_collected','service metrics collected successfully', labels=_labels) + success.add_metric(_label_values, value=service_metrics_collected) + + result.extend([success]) + return result + +if __name__ == "__main__": + REGISTRY.unregister(GC_COLLECTOR) + REGISTRY.unregister(PLATFORM_COLLECTOR) + REGISTRY.unregister(PROCESS_COLLECTOR) + REGISTRY.register(MetricsCollector()) + role_name='role_name' + start_http_server({{ vars[role_name + '_metrics_port'] | int }}) + while True: + time.sleep(30) \ No newline at end of file diff --git a/depin/services/roles/avalanche/templates/metrics.service.j2 b/depin/services/roles/avalanche/templates/metrics.service.j2 new file mode 100644 index 00000000..5bbe69a3 --- /dev/null +++ b/depin/services/roles/avalanche/templates/metrics.service.j2 @@ -0,0 +1,15 @@ +{{ ansible_managed | comment }} + +[Unit] +Description=Prometheus collector - {{ _name }} +After=network-online.target + +[Service] +Type=simple +User=nerdnode +ExecStart=sudo /opt/pipx/venvs/ansible-core/bin/python3 /etc/deeep-network/collectors/{{ _name }}.py +KillSignal=SIGINT +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/depin/services/roles/avalanche/templates/systemd.service.j2 b/depin/services/roles/avalanche/templates/systemd.service.j2 new file mode 100644 index 00000000..985fc640 --- /dev/null +++ b/depin/services/roles/avalanche/templates/systemd.service.j2 @@ -0,0 +1,14 @@ +[Unit] +Description=AvalancheGo node service +After=network.target + +[Service] +User=root +Group=root +Type=simple +ExecStart=/usr/local/bin/avalanchego +Restart=always +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/molecule/default/tasks/vars/avalanche.yml b/molecule/default/tasks/vars/avalanche.yml new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/molecule/default/tasks/vars/avalanche.yml @@ -0,0 +1 @@ + diff --git a/molecule/libs/tasks/vars/avalanche.yml b/molecule/libs/tasks/vars/avalanche.yml new file mode 100644 index 00000000..e69de29b From 77faf1df4ee3d7cce7876c5b2c428112abbd7bca Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Mon, 30 Sep 2024 14:35:05 +0400 Subject: [PATCH 02/10] remove unnecessary logging --- .../roles/avalanche/tasks/commands/stop.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/depin/services/roles/avalanche/tasks/commands/stop.yml b/depin/services/roles/avalanche/tasks/commands/stop.yml index b5b31d56..9908d3d0 100644 --- a/depin/services/roles/avalanche/tasks/commands/stop.yml +++ b/depin/services/roles/avalanche/tasks/commands/stop.yml @@ -1,19 +1,6 @@ --- ## stop service -- name: Assert start - when: "'molecule' in groups" - block: - - name: Get service info - become: true - ansible.builtin.systemd: - name: "avalanchego" - register: _avalanchego - - - name: Debug service status before stop - debug: - var: _avalanchego.status - - name: Stop node become: true ansible.builtin.service: From 4511da9c934003453ee002992f345c9bad6c5aeb Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Mon, 30 Sep 2024 16:33:23 +0400 Subject: [PATCH 03/10] add asserts --- .../avalanche/tasks/commands/install.yml | 32 ++++++++++++++++ .../roles/avalanche/tasks/commands/reset.yml | 2 +- .../avalanche/tasks/commands/restart.yml | 1 - .../avalanche/tasks/commands/uninstall.yml | 38 +++++++++++++++++-- .../roles/avalanche/tasks/commands/update.yml | 13 ++++++- 5 files changed, 80 insertions(+), 6 deletions(-) diff --git a/depin/services/roles/avalanche/tasks/commands/install.yml b/depin/services/roles/avalanche/tasks/commands/install.yml index eb0fabea..b9b825dd 100644 --- a/depin/services/roles/avalanche/tasks/commands/install.yml +++ b/depin/services/roles/avalanche/tasks/commands/install.yml @@ -11,6 +11,17 @@ mode: '0755' dest: /opt/avalanche/{{ avalanche_version }} +- name: Verify that the program folder was created + ansible.builtin.stat: + path: /opt/avalanche/{{ avalanche_version }} + register: avalanche_program_folder + +- name: Assert that the program folder exists + ansible.builtin.assert: + that: + - avalanche_program_folder.stat.exists + - avalanche_program_folder.stat.isdir + - name: Download AvalancheGo become: true ansible.builtin.get_url: @@ -33,6 +44,17 @@ path: /opt/avalanche/{{ avalanche_version }}/avalanchego mode: '0755' +- name: Verify that the AvalancheGo binary exists + ansible.builtin.stat: + path: /opt/avalanche/{{ avalanche_version }}/avalanchego + register: avalanchego_binary + +- name: Assert that the AvalancheGo binary exists + ansible.builtin.assert: + that: + - avalanchego_binary.stat.exists + - avalanchego_binary.stat.mode | int == 755 + - name: Symlink avalanchego binary become: true ansible.builtin.file: @@ -48,6 +70,16 @@ dest: /etc/systemd/system/avalanchego.service mode: '0644' +- name: Verify that the AvalancheGo service file exists + ansible.builtin.stat: + path: /etc/systemd/system/avalanchego.service + register: avalanchego_service_file + +- name: Assert that the AvalancheGo service file exists + ansible.builtin.assert: + that: + - avalanchego_service_file.stat.exists + - name: Reload systemd daemon become: true ansible.builtin.systemd: diff --git a/depin/services/roles/avalanche/tasks/commands/reset.yml b/depin/services/roles/avalanche/tasks/commands/reset.yml index 7a48419b..21de3f84 100644 --- a/depin/services/roles/avalanche/tasks/commands/reset.yml +++ b/depin/services/roles/avalanche/tasks/commands/reset.yml @@ -1,5 +1,5 @@ --- -## uninstall and install service + - name: Uninstall node ansible.builtin.include_tasks: file: commands/uninstall.yml diff --git a/depin/services/roles/avalanche/tasks/commands/restart.yml b/depin/services/roles/avalanche/tasks/commands/restart.yml index c3aad00a..4cafb5bf 100644 --- a/depin/services/roles/avalanche/tasks/commands/restart.yml +++ b/depin/services/roles/avalanche/tasks/commands/restart.yml @@ -1,5 +1,4 @@ --- -## restart service - name: Get current service info become: true diff --git a/depin/services/roles/avalanche/tasks/commands/uninstall.yml b/depin/services/roles/avalanche/tasks/commands/uninstall.yml index 05b93ccd..19079e71 100644 --- a/depin/services/roles/avalanche/tasks/commands/uninstall.yml +++ b/depin/services/roles/avalanche/tasks/commands/uninstall.yml @@ -1,6 +1,8 @@ --- + - name: Disable systemd service - ansible.builtin.include_tasks: commands/stop.yml + ansible.builtin.include_tasks: + file: commands/stop.yml - name: Uninstall metrics vars: @@ -12,10 +14,40 @@ become: true ansible.builtin.file: state: absent - path: "{{ uninstall_file }}" + path: "{{ item }}" loop: - /etc/systemd/system/avalanchego.service - /usr/local/bin/avalanchego - /opt/avalanche/{{ avalanche_version }} loop_control: - loop_var: uninstall_file + loop_var: item + +- name: Verify that the AvalancheGo service file is removed + ansible.builtin.stat: + path: /etc/systemd/system/avalanchego.service + register: avalanchego_service_file + +- name: Assert that the AvalancheGo service file does not exist + ansible.builtin.assert: + that: + - not avalanchego_service_file.stat.exists + +- name: Verify that the AvalancheGo binary is removed + ansible.builtin.stat: + path: /usr/local/bin/avalanchego + register: avalanchego_binary + +- name: Assert that the AvalancheGo binary does not exist + ansible.builtin.assert: + that: + - not avalanchego_binary.stat.exists + +- name: Verify that the AvalancheGo program directory is removed + ansible.builtin.stat: + path: /opt/avalanche/{{ avalanche_version }} + register: avalanchego_directory + +- name: Assert that the AvalancheGo program directory does not exist + ansible.builtin.assert: + that: + - not avalanchego_directory.stat.exists diff --git a/depin/services/roles/avalanche/tasks/commands/update.yml b/depin/services/roles/avalanche/tasks/commands/update.yml index 50d55047..aa108e70 100644 --- a/depin/services/roles/avalanche/tasks/commands/update.yml +++ b/depin/services/roles/avalanche/tasks/commands/update.yml @@ -1,8 +1,19 @@ --- + - name: Uninstall node ansible.builtin.include_tasks: file: commands/uninstall.yml - name: Install node ansible.builtin.include_tasks: - file: commands/install.yml \ No newline at end of file + file: commands/install.yml + +- name: Get AvalancheGo version + ansible.builtin.command: /usr/local/bin/avalanchego --version + register: avalanchego_version_output + changed_when: false + +- name: Assert that AvalancheGo is updated to version {{ avalanche_version }} + ansible.builtin.assert: + that: + - "'avalanchego version {{ avalanche_version }}' in avalanchego_version_output.stdout" From e13e510ac6fe8edd5d9145d4bc3d108b4d69f15b Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Mon, 30 Sep 2024 16:40:38 +0400 Subject: [PATCH 04/10] add asserts --- depin/services/roles/avalanche/templates/collector.py.j2 | 2 +- depin/services/roles/avalanche/templates/systemd.service.j2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/depin/services/roles/avalanche/templates/collector.py.j2 b/depin/services/roles/avalanche/templates/collector.py.j2 index 9260daf8..917edf44 100644 --- a/depin/services/roles/avalanche/templates/collector.py.j2 +++ b/depin/services/roles/avalanche/templates/collector.py.j2 @@ -88,4 +88,4 @@ if __name__ == "__main__": role_name='role_name' start_http_server({{ vars[role_name + '_metrics_port'] | int }}) while True: - time.sleep(30) \ No newline at end of file + time.sleep(30) diff --git a/depin/services/roles/avalanche/templates/systemd.service.j2 b/depin/services/roles/avalanche/templates/systemd.service.j2 index 985fc640..1e73bfcc 100644 --- a/depin/services/roles/avalanche/templates/systemd.service.j2 +++ b/depin/services/roles/avalanche/templates/systemd.service.j2 @@ -11,4 +11,4 @@ Restart=always LimitNOFILE=65536 [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target From fd167725ac33be6fe352b22297714eb3edc6f33e Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Mon, 30 Sep 2024 18:08:50 +0400 Subject: [PATCH 05/10] clean code --- depin/services/roles/avalanche/templates/collector.py.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depin/services/roles/avalanche/templates/collector.py.j2 b/depin/services/roles/avalanche/templates/collector.py.j2 index 917edf44..7b4b7d1b 100644 --- a/depin/services/roles/avalanche/templates/collector.py.j2 +++ b/depin/services/roles/avalanche/templates/collector.py.j2 @@ -21,7 +21,7 @@ else: LXD_UTILS_IMPORT_ERROR = None class MetricsCollector(Collector): - """Collector for Gala Node information""" + """Collector for Avalanche Node information""" def total_uptime_count(sefl, autonomi_service_date): total_uptime=0 for x in autonomi_service_date: From 18a94c818a91cef37256cf381656ec0cdf896ea6 Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Tue, 8 Oct 2024 15:57:20 +0400 Subject: [PATCH 06/10] update install avalanche --- .../roles/avalanche/defaults/main.yml | 36 ++++- .../avalanche/tasks/commands/install.yml | 127 +++++++++++++++++- .../roles/avalanche/templates/config.json.j2 | 6 + .../roles/avalanche/templates/node.json.j2 | 22 +++ .../avalanche/templates/systemd.service.j2 | 9 +- 5 files changed, 187 insertions(+), 13 deletions(-) create mode 100644 depin/services/roles/avalanche/templates/config.json.j2 create mode 100644 depin/services/roles/avalanche/templates/node.json.j2 diff --git a/depin/services/roles/avalanche/defaults/main.yml b/depin/services/roles/avalanche/defaults/main.yml index 0ef58ba2..bf190217 100644 --- a/depin/services/roles/avalanche/defaults/main.yml +++ b/depin/services/roles/avalanche/defaults/main.yml @@ -1,7 +1,39 @@ # defaults/main.yml +# Metrics port for AvalancheGo avalanche_metrics_port: 33006 + +# Command to execute (install, uninstall, etc.) avalanche_cmd: "{{ depin_cmd | default('install') }}" -avalanche_version: "1.10.0" -avalanche_download_url: "https://github.com/ava-labs/avalanchego/releases/download/v{{ avalanche_version }}/avalanchego-linux-amd64-v{{ avalanche_version }}.tar.gz" +# AvalancheGo version to install +avalanche_version: "1.11.11" + +# Determine the architecture (amd64 or arm64) +avalanche_arch: "{{ 'arm64' if ansible_facts['architecture'] == 'aarch64' else 'amd64' }}" + +# Download URL for AvalancheGo binary +avalanche_download_url: "https://github.com/ava-labs/avalanchego/releases/download/v{{ avalanche_version }}/avalanchego-linux-{{ avalanche_arch }}-v{{ avalanche_version }}.tar.gz" + +# Installation directory for AvalancheGo +avalanche_install_dir: '/opt/avalanche/{{ avalanche_version }}' + +# Configuration directory for AvalancheGo +avalanche_config_dir: '/home/{{ ansible_user_id }}/.avalanchego' # Or another appropriate path + +# User and group to run AvalancheGo service +avalanche_user: '{{ ansible_user_id }}' +avalanche_group: '{{ ansible_user_id }}' + +# Network ID ('mainnet' or 'fuji' for testnet) +avalanche_network_id: 'mainnet' + +# Additional necessary variables +avalanche_ip_mode: 'dynamic' # 'dynamic' or 'static' +avalanche_public_ip: '' # Automatically determined if empty and ip_mode == 'static' +avalanche_rpc_public: false # true or false +avalanche_admin_api_enabled: false # true or false +avalanche_index_enabled: false # true or false +avalanche_state_sync_enabled: true # true or false +avalanche_archival_mode: false # true or false +avalanche_db_dir: '' # Path to database directory if needed diff --git a/depin/services/roles/avalanche/tasks/commands/install.yml b/depin/services/roles/avalanche/tasks/commands/install.yml index b9b825dd..236cd30d 100644 --- a/depin/services/roles/avalanche/tasks/commands/install.yml +++ b/depin/services/roles/avalanche/tasks/commands/install.yml @@ -2,6 +2,56 @@ --- +- name: Determine OS family + set_fact: + os_family: "{{ ansible_facts['os_family'] }}" + +- name: Install required packages for AvalancheGo (Debian) + become: true + ansible.builtin.package: + name: + - curl + - wget + - dnsutils + state: present + when: os_family == 'Debian' + +- name: Install required packages for AvalancheGo (RedHat) + become: true + ansible.builtin.package: + name: + - curl + - wget + - bind-utils + - policycoreutils-python-utils + - policycoreutils + state: present + when: os_family == 'RedHat' + +- name: Set avalanche architecture + set_fact: + avalanche_arch: "{{ 'arm64' if ansible_facts['architecture'] == 'aarch64' else 'amd64' }}" + +- name: Set download URL for AvalancheGo + set_fact: + avalanche_download_url: "https://github.com/ava-labs/avalanchego/releases/download/v{{ avalanche_version }}/avalanchego-linux-{{ avalanche_arch }}-v{{ avalanche_version }}.tar.gz" + +- name: Get public IP address + ansible.builtin.uri: + url: https://api.ipify.org + return_content: yes + register: public_ip + when: + - avalanche_public_ip == '' + - avalanche_ip_mode == 'static' + +- name: Set public IP address fact + set_fact: + avalanche_public_ip: "{{ public_ip.content | trim }}" + when: + - avalanche_public_ip == '' + - avalanche_ip_mode == 'static' + - name: Create program folder become: true ansible.builtin.file: @@ -9,11 +59,11 @@ owner: root group: root mode: '0755' - dest: /opt/avalanche/{{ avalanche_version }} + dest: "{{ avalanche_install_dir }}" - name: Verify that the program folder was created ansible.builtin.stat: - path: /opt/avalanche/{{ avalanche_version }} + path: "{{ avalanche_install_dir }}" register: avalanche_program_folder - name: Assert that the program folder exists @@ -28,12 +78,21 @@ url: "{{ avalanche_download_url }}" dest: /tmp/avalanchego.tar.gz mode: '0644' + register: download_result + retries: 3 + delay: 10 + until: download_result is succeeded + +- name: Fail if AvalancheGo download failed + ansible.builtin.fail: + msg: "Failed to download AvalancheGo from {{ avalanche_download_url }}" + when: download_result is failed - name: Extract AvalancheGo become: true ansible.builtin.unarchive: src: /tmp/avalanchego.tar.gz - dest: /opt/avalanche/{{ avalanche_version }} + dest: "{{ avalanche_install_dir }}" remote_src: yes extra_opts: - --strip-components=1 @@ -41,28 +100,82 @@ - name: Ensure avalanchego binary is executable become: true ansible.builtin.file: - path: /opt/avalanche/{{ avalanche_version }}/avalanchego + path: "{{ avalanche_install_dir }}/avalanchego" mode: '0755' - name: Verify that the AvalancheGo binary exists ansible.builtin.stat: - path: /opt/avalanche/{{ avalanche_version }}/avalanchego + path: "{{ avalanche_install_dir }}/avalanchego" register: avalanchego_binary - name: Assert that the AvalancheGo binary exists ansible.builtin.assert: that: - avalanchego_binary.stat.exists - - avalanchego_binary.stat.mode | int == 755 + - (avalanchego_binary.stat.mode | int == 755) or (avalanchego_binary.stat.mode | int == 493) + +- name: Adjust SELinux context for avalanchego binary + become: true + ansible.builtin.command: "semanage fcontext -a -t bin_t '{{ avalanche_install_dir }}/avalanchego' || semanage fcontext -m -t bin_t '{{ avalanche_install_dir }}/avalanchego'" + args: + warn: false + when: ansible_facts['os_family'] == 'RedHat' + +- name: Restore SELinux context + become: true + ansible.builtin.command: "restorecon -Fv '{{ avalanche_install_dir }}/avalanchego'" + when: ansible_facts['os_family'] == 'RedHat' - name: Symlink avalanchego binary become: true ansible.builtin.file: - src: /opt/avalanche/{{ avalanche_version }}/avalanchego + src: "{{ avalanche_install_dir }}/avalanchego" dest: /usr/local/bin/avalanchego state: link force: true +- name: Verify symlink for AvalancheGo binary + ansible.builtin.stat: + path: /usr/local/bin/avalanchego + follow: false + register: avalanchego_symlink + +- name: Assert that the symlink exists and is correct + ansible.builtin.assert: + that: + - avalanchego_symlink.stat.islnk + - avalanchego_symlink.stat.lnk_source == "{{ avalanche_install_dir }}/avalanchego" + +- name: Create configuration directories + become: true + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ avalanche_user }}" + group: "{{ avalanche_group }}" + mode: '0755' + loop: + - "{{ avalanche_config_dir }}/configs" + - "{{ avalanche_config_dir }}/configs/chains/C" + +- name: Deploy node.json configuration + become: true + ansible.builtin.template: + src: node.json.j2 + dest: "{{ avalanche_config_dir }}/configs/node.json" + mode: '0644' + owner: "{{ avalanche_user }}" + group: "{{ avalanche_group }}" + +- name: Deploy config.json configuration + become: true + ansible.builtin.template: + src: config.json.j2 + dest: "{{ avalanche_config_dir }}/configs/chains/C/config.json" + mode: '0644' + owner: "{{ avalanche_user }}" + group: "{{ avalanche_group }}" + - name: Create systemd service become: true ansible.builtin.template: diff --git a/depin/services/roles/avalanche/templates/config.json.j2 b/depin/services/roles/avalanche/templates/config.json.j2 new file mode 100644 index 00000000..d0f243c5 --- /dev/null +++ b/depin/services/roles/avalanche/templates/config.json.j2 @@ -0,0 +1,6 @@ +{ + "state-sync-enabled": {{ avalanche_state_sync_enabled | lower }}{% if avalanche_archival_mode %},{% endif %} + {% if avalanche_archival_mode %} + "pruning-enabled": false + {% endif %} +} diff --git a/depin/services/roles/avalanche/templates/node.json.j2 b/depin/services/roles/avalanche/templates/node.json.j2 new file mode 100644 index 00000000..c345de5f --- /dev/null +++ b/depin/services/roles/avalanche/templates/node.json.j2 @@ -0,0 +1,22 @@ +{ +{% if avalanche_rpc_public %} + "http-host": "", +{% endif %} +{% if avalanche_admin_api_enabled %} + "api-admin-enabled": true, +{% endif %} +{% if avalanche_index_enabled %} + "index-enabled": true, +{% endif %} +{% if avalanche_network_id != 'mainnet' %} + "network-id": "{{ avalanche_network_id }}", +{% endif %} +{% if avalanche_db_dir %} + "db-dir": "{{ avalanche_db_dir }}", +{% endif %} +{% if avalanche_ip_mode == 'dynamic' %} + "public-ip-resolution-service": "opendns" +{% else %} + "public-ip": "{{ avalanche_public_ip }}" +{% endif %} +} diff --git a/depin/services/roles/avalanche/templates/systemd.service.j2 b/depin/services/roles/avalanche/templates/systemd.service.j2 index 1e73bfcc..4540a5e8 100644 --- a/depin/services/roles/avalanche/templates/systemd.service.j2 +++ b/depin/services/roles/avalanche/templates/systemd.service.j2 @@ -3,12 +3,13 @@ Description=AvalancheGo node service After=network.target [Service] -User=root -Group=root +User={{ avalanche_user }} +Group={{ avalanche_group }} Type=simple -ExecStart=/usr/local/bin/avalanchego +ExecStart={{ avalanche_install_dir }}/avalanchego --config-file={{ avalanche_config_dir }}/configs/node.json +LimitNOFILE=32768 Restart=always -LimitNOFILE=65536 +RestartSec=1 [Install] WantedBy=multi-user.target From ab23446e1be9cefae66325229334d583ef44b79c Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Fri, 25 Oct 2024 11:36:13 +0400 Subject: [PATCH 07/10] remove duplicated import --- depin/services/roles/avalanche/templates/collector.py.j2 | 1 - 1 file changed, 1 deletion(-) diff --git a/depin/services/roles/avalanche/templates/collector.py.j2 b/depin/services/roles/avalanche/templates/collector.py.j2 index 7b4b7d1b..ff5c5e1b 100644 --- a/depin/services/roles/avalanche/templates/collector.py.j2 +++ b/depin/services/roles/avalanche/templates/collector.py.j2 @@ -3,7 +3,6 @@ import os import socket import time import os -import time import subprocess from subprocess import check_output import json From 729a6862afe11bed42f6c7fc52ab697b7d6e051c Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Tue, 26 Nov 2024 14:03:46 +0400 Subject: [PATCH 08/10] utilize Path.stem to derive the service name from the file name --- .../roles/avalanche/templates/collector.py.j2 | 74 ++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/depin/services/roles/avalanche/templates/collector.py.j2 b/depin/services/roles/avalanche/templates/collector.py.j2 index ff5c5e1b..46fc9eab 100644 --- a/depin/services/roles/avalanche/templates/collector.py.j2 +++ b/depin/services/roles/avalanche/templates/collector.py.j2 @@ -2,11 +2,10 @@ import os import socket import time -import os import subprocess from subprocess import check_output import json - +from pathlib import Path from prometheus_client import start_http_server, REGISTRY, GC_COLLECTOR, PLATFORM_COLLECTOR, PROCESS_COLLECTOR from prometheus_client.core import GaugeMetricFamily @@ -21,11 +20,11 @@ else: class MetricsCollector(Collector): """Collector for Avalanche Node information""" - def total_uptime_count(sefl, autonomi_service_date): - total_uptime=0 + def total_uptime_count(self, autonomi_service_date): + total_uptime = 0 for x in autonomi_service_date: state_uptime_list = autonomi_service_date[x].split(":") - hours=0 + hours = 0 if len(state_uptime_list) <= 2: minutes = int(state_uptime_list[0]) seconds = int(state_uptime_list[1]) @@ -33,7 +32,7 @@ class MetricsCollector(Collector): hours = int(state_uptime_list[0]) minutes = int(state_uptime_list[1]) seconds = int(state_uptime_list[2]) - total_uptime=total_uptime+seconds+minutes*60+hours*3600 + total_uptime += seconds + minutes * 60 + hours * 3600 return total_uptime def collect(self): @@ -41,42 +40,45 @@ class MetricsCollector(Collector): service_metrics_collected = 1 device = 'molecule' - # fetch device hostname - # @note - LXD specific feature - {% if not molecule_inventory is defined -%} - if LXD_UTILS_IMPORT_ERROR is None: - device = lxd_get("1.0/config/user.location")['value'] - device = device['value'] - {% endif %} + # Fetch device hostname - LXD specific feature + if LXD_UTILS_IMPORT_ERROR is None: + device_info = lxd_get("1.0/config/user.location") + if 'value' in device_info: + device = device_info['value'] hostname = socket.gethostname() - service = '{{ _name }}' + service = Path(__file__).stem _labels = ['device', 'instance', 'service'] _label_values = [device, hostname, service] - success = GaugeMetricFamily('service_metrics_collected','service metrics collected successfully', labels=_labels) + # Placeholder values for state_uptime and total_uptime + state_uptime = 12345 # Replace with actual calculation + total_uptime = 67890 # Replace with actual calculation + + success = GaugeMetricFamily( + 'service_metrics_collected', + 'Service metrics collected successfully', + labels=_labels + ) success.add_metric(_label_values, value=service_metrics_collected) - g2 = GaugeMetricFamily('current_state_uptime','seconds in current state', labels=_labels) - g2.add_metric(_label_values, value=state_uptime) + current_state_uptime = GaugeMetricFamily( + 'current_state_uptime', + 'Seconds in current state', + labels=_labels + ) + current_state_uptime.add_metric(_label_values, value=state_uptime) - g3 = GaugeMetricFamily('total_uptime','seconds in last 24 hours', labels=_labels) - g3.add_metric(_label_values, value=total_uptime) + total_uptime_metric = GaugeMetricFamily( + 'total_uptime', + 'Seconds in last 24 hours', + labels=_labels + ) + total_uptime_metric.add_metric(_label_values, value=total_uptime) - result.extend([g1, g2, g3]) - service_metrics_collected = 1 - - hostname = socket.gethostname() - service = '{{ _name }}' + result.extend([success, current_state_uptime, total_uptime_metric]) - _labels = ['device', 'instance', 'service'] - _label_values = [device, hostname, service] - - success = GaugeMetricFamily('service_metrics_collected','service metrics collected successfully', labels=_labels) - success.add_metric(_label_values, value=service_metrics_collected) - - result.extend([success]) return result if __name__ == "__main__": @@ -84,7 +86,13 @@ if __name__ == "__main__": REGISTRY.unregister(PLATFORM_COLLECTOR) REGISTRY.unregister(PROCESS_COLLECTOR) REGISTRY.register(MetricsCollector()) - role_name='role_name' - start_http_server({{ vars[role_name + '_metrics_port'] | int }}) + + # Use the file name stem as the role name + role_name = Path(__file__).stem + + # Set the metrics port (default to 8000 or fetch from environment variable) + metrics_port = int(os.getenv(f'{role_name.upper()}_METRICS_PORT', 8000)) + start_http_server(metrics_port) + while True: time.sleep(30) From e7ade551aad36a026e78a5723f1d826ece6a3bdf Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Thu, 28 Nov 2024 17:14:49 +0400 Subject: [PATCH 09/10] removed from readme installing pynetbox --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 96cfb06c..b7081a27 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ apt install pipx pipx install ansible-core pipx inject ansible-core requests pynetbox pyutils pytz netaddr pipx install ansible-lint -sudo pip install pynetbox ``` From ac1408f2985d091f900fcab04da2d891e1257fd1 Mon Sep 17 00:00:00 2001 From: Sergei Kuznetsov Date: Thu, 28 Nov 2024 20:03:01 +0400 Subject: [PATCH 10/10] changed place of the port avalanche --- depin/core/roles/metrics/defaults/main.yml | 1 + depin/services/roles/avalanche/defaults/main.yml | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/depin/core/roles/metrics/defaults/main.yml b/depin/core/roles/metrics/defaults/main.yml index 48769996..ec4c5b74 100644 --- a/depin/core/roles/metrics/defaults/main.yml +++ b/depin/core/roles/metrics/defaults/main.yml @@ -8,3 +8,4 @@ metrics_port: autonomi: 33002 hychain: 33003 storagechain: 33004 + avalanche: 33006 diff --git a/depin/services/roles/avalanche/defaults/main.yml b/depin/services/roles/avalanche/defaults/main.yml index bf190217..b3a6159f 100644 --- a/depin/services/roles/avalanche/defaults/main.yml +++ b/depin/services/roles/avalanche/defaults/main.yml @@ -1,8 +1,5 @@ # defaults/main.yml -# Metrics port for AvalancheGo -avalanche_metrics_port: 33006 - # Command to execute (install, uninstall, etc.) avalanche_cmd: "{{ depin_cmd | default('install') }}"