From 549fdda8e25c724633cba3d7cda3dc7c8cfafd69 Mon Sep 17 00:00:00 2001 From: Benjamin Brahmer Date: Sun, 16 Aug 2026 17:50:13 +0200 Subject: [PATCH 1/2] add meshviewer role for map server --- group_vars/versions.yml | 1 + roles/meshviewer/defaults/main.yml | 155 +++++++++++++++++++++++++ roles/meshviewer/tasks/download.yml | 42 +++++++ roles/meshviewer/tasks/main.yml | 88 ++++++++++++++ roles/meshviewer/templates/config.json | 21 ++++ setup.yml | 1 + 6 files changed, 308 insertions(+) create mode 100644 roles/meshviewer/defaults/main.yml create mode 100644 roles/meshviewer/tasks/download.yml create mode 100644 roles/meshviewer/tasks/main.yml create mode 100644 roles/meshviewer/templates/config.json diff --git a/group_vars/versions.yml b/group_vars/versions.yml index a468a27..ee627c8 100644 --- a/group_vars/versions.yml +++ b/group_vars/versions.yml @@ -1,3 +1,4 @@ batman_version: "2026.2" node_exporter_version: "1.12.1" bootstrap_version: "5.3.8" +meshviewer_version: "13.2.0" diff --git a/roles/meshviewer/defaults/main.yml b/roles/meshviewer/defaults/main.yml new file mode 100644 index 0000000..854b619 --- /dev/null +++ b/roles/meshviewer/defaults/main.yml @@ -0,0 +1,155 @@ +--- +meshviewer_target_host: map-ffsh +meshviewer_owner: www-data +meshviewer_group: www-data + +meshviewer_release_repo: freifunk/meshviewer +meshviewer_install_dir: /var/www/map/meshviewer +meshviewer_version_file: "{{ meshviewer_install_dir }}/.meshviewer_version" + +meshviewer_device_pictures_repo: https://github.com/freifunk/device-pictures.git +meshviewer_device_pictures_dir: /var/www/map/device-pictures + +meshviewer_data_path: + - https://map.freifunk-suedholstein.de/data/ +meshviewer_site_name: Freifunk Südholstein +meshviewer_max_age: 21 +meshviewer_node_zoom: 19 + +meshviewer_grafana: + url: /_grafana + orgId: 1 + +meshviewer_map_layers: + - name: OpenStreetMap + url: "https://tiles.freifunk-suedholstein.de/{z}/{x}/{y}.png" + config: + type: osm + maxZoom: 19 + attribution: >- + Report Bug | Map data © OpenStreetMap contributor + - name: Esri.WorldImagery + url: "//server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}" + config: + maxZoom: 20 + attribution: >- + Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, + GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User + Community + +meshviewer_fixed_center: + - [53.9286, 9.3356] + - [53.3743, 10.7308] + +meshviewer_domain_names: + - domain: ffrz + name: Lauenburg + - domain: ffod + name: Stormarn + - domain: ffsh + name: Südholstein + +meshviewer_node_infos: [] + +meshviewer_node_charts: + - name: Clientstatistik + datasourceUid: "000000001" + datasourceType: influxdb + query: >- + SELECT mean("clients.total") AS "Clients" FROM "node" WHERE ("nodeid" + =~ /^$node$/) AND $timeFilter GROUP BY time($interval) fill(null) + from: now-7d + to: now-1m + maxDataPoints: 300 + series: + - name: Clients + color: "#73BF69" + - name: Trafficstatistik + datasourceUid: "000000001" + datasourceType: influxdb + query: >- + SELECT non_negative_derivative(first("traffic.forward.bytes"), 2m) * 8 + / 120 AS "Traffic IN", non_negative_derivative(first("traffic.tx.bytes"), + 2m) * 8 / 120 AS "Traffic OUT", non_negative_derivative(first("traffic.forward.bytes"), + 2m) * 8 / 120 AS "Traffic FORWARD" FROM "node" WHERE ("nodeid" =~ /^$node$/) + AND $timeFilter GROUP BY time($interval) fill(null) + format: ".2~s" + unitSuffix: bit/s + from: now-7d + to: now-1m + maxDataPoints: 300 + series: + - name: Traffic IN + color: "#73BF69" + - name: Traffic OUT + color: "#F2495C" + - name: Traffic FORWARD + color: "#5794F2" + - name: Airtime 2.4GHz & 5GHz + datasourceUid: "000000001" + datasourceType: influxdb + query: >- + SELECT last("airtime11g.chan_util") AS "2.4GHz", last("airtime11a.chan_util") + AS "5GHz" FROM "node" WHERE ("nodeid" =~ /^$node$/) AND $timeFilter GROUP + BY time(5m) fill(null) + format: .2f + unitSuffix: "%" + from: now-7d + to: now-1m + maxDataPoints: 300 + series: + - name: 2.4GHz + color: "#FF9830" + - name: 5GHz + color: "#56A64B" + +meshviewer_global_infos: [] + +meshviewer_global_charts: + - name: Knoten und Clients + datasourceUid: "000000001" + datasourceType: influxdb + query: >- + SELECT mean("clients.total") AS "Clients", mean("nodes") AS "Knoten", + mean("gateways") AS "Gateways" FROM "global" WHERE $timeFilter GROUP + BY time($interval) fill(previous) + from: now-7d + to: now-1m + maxDataPoints: 300 + series: + - name: Clients + color: "#73BF69" + - name: Knoten + color: "#5794F2" + - name: Gateways + color: "#F2CC0C" + +meshviewer_link_list: + - title: Homepage + href: https://www.freifunk-suedholstein.de + - title: Impressum + href: https://www.freifunk-suedholstein.de/impressum/ + - title: Datenschutz + href: https://www.freifunk-suedholstein.de/datenschutz/ + +meshviewer_device_pictures_url: "https://map.freifunk-suedholstein.de/pictures-svg/{MODEL_NORMALIZED}.svg" +meshviewer_device_pictures_source: >- + https://github.com/freifunk/device-pictures +meshviewer_device_pictures_license: CC-BY-NC-SA 4.0 + +meshviewer_deprecation_text: >- +

Achtung! Dieses Gerät verfügt über wenig Speicher, daher wird es bald keine + Updates mehr erhalten!

Tritt gerne über unsere Webseite mit uns in + Kontakt um dich auszutauschen: https://freifunk-suedholstein.de

+meshviewer_deprecation_enabled: true + +meshviewer_eol_text: >- +

Dieses Gerät ist veraltet und wird keine Updates mehr erhalten!

Tritt + gerne über unsere Webseite mit uns in Kontakt um dich auszutauschen: https://freifunk-suedholstein.de

+ +meshviewer_cron_weekday: "0" +meshviewer_cron_hour: "3" +meshviewer_cron_minute: "0" diff --git a/roles/meshviewer/tasks/download.yml b/roles/meshviewer/tasks/download.yml new file mode 100644 index 0000000..958e572 --- /dev/null +++ b/roles/meshviewer/tasks/download.yml @@ -0,0 +1,42 @@ +--- +- name: Download meshviewer release + ansible.builtin.get_url: + url: "https://github.com/{{ meshviewer_release_repo }}/releases/download/v{{ meshviewer_version }}/meshviewer-build.zip" + dest: "/tmp/meshviewer-{{ meshviewer_version }}.zip" + mode: "0644" + +- name: Clear previous meshviewer installation + ansible.builtin.file: + path: "{{ meshviewer_install_dir }}" + state: absent + +- name: Recreate meshviewer install directory + ansible.builtin.file: + path: "{{ meshviewer_install_dir }}" + state: directory + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + mode: "0755" + +- name: Unpack meshviewer + ansible.builtin.unarchive: + src: "/tmp/meshviewer-{{ meshviewer_version }}.zip" + dest: "{{ meshviewer_install_dir }}" + remote_src: true + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + when: not ansible_check_mode + +- name: Record installed meshviewer version + ansible.builtin.copy: + content: "{{ meshviewer_version }}" + dest: "{{ meshviewer_version_file }}" + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + mode: "0644" + when: not ansible_check_mode + +- name: Delete meshviewer archive + ansible.builtin.file: + path: "/tmp/meshviewer-{{ meshviewer_version }}.zip" + state: absent diff --git a/roles/meshviewer/tasks/main.yml b/roles/meshviewer/tasks/main.yml new file mode 100644 index 0000000..6450ad9 --- /dev/null +++ b/roles/meshviewer/tasks/main.yml @@ -0,0 +1,88 @@ +--- +- name: Skip meshviewer on non-target hosts + ansible.builtin.meta: end_role + when: inventory_hostname != meshviewer_target_host + +- name: Install meshviewer dependencies + ansible.builtin.apt: + name: + - unzip + - git + +- name: Create meshviewer install directory + ansible.builtin.file: + path: "{{ meshviewer_install_dir }}" + state: directory + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + mode: "0755" + +- name: Create device-pictures directory + ansible.builtin.file: + path: "{{ meshviewer_device_pictures_dir }}" + state: directory + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + mode: "0755" + +- name: Check currently installed meshviewer version + ansible.builtin.slurp: + src: "{{ meshviewer_version_file }}" + register: meshviewer_installed_version_raw + failed_when: false + +# slurp fails silently (registered above) when no release has been installed yet +- name: Set meshviewer installed version fact + ansible.builtin.set_fact: + meshviewer_installed_version: "{{ (meshviewer_installed_version_raw.content | b64decode) if meshviewer_installed_version_raw.content + is defined else '' }}" + +- name: Print meshviewer version and target + ansible.builtin.debug: + msg: "Currently installed meshviewer: {{ meshviewer_installed_version }}, target is: {{ meshviewer_version }}" + +- name: Check if meshviewer needs to be installed or upgraded + ansible.builtin.include_tasks: download.yml + when: meshviewer_installed_version != meshviewer_version + +- name: Install meshviewer configuration + ansible.builtin.template: + src: config.json + dest: "{{ meshviewer_install_dir }}/config.json" + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + mode: "0644" + +- name: Configure Git safe directory for device-pictures + ansible.builtin.command: + argv: + - git + - config + - --global + - --add + - safe.directory + - "{{ meshviewer_device_pictures_dir }}" + changed_when: false + +- name: Clone or update device-pictures + ansible.builtin.git: + repo: "{{ meshviewer_device_pictures_repo }}" + dest: "{{ meshviewer_device_pictures_dir }}" + version: main + update: true + +- name: Adjust device-pictures ownership + ansible.builtin.file: + path: "{{ meshviewer_device_pictures_dir }}" + state: directory + owner: "{{ meshviewer_owner }}" + group: "{{ meshviewer_group }}" + recurse: true + +- name: Schedule weekly device-pictures update + ansible.builtin.cron: + name: update device-pictures + weekday: "{{ meshviewer_cron_weekday }}" + hour: "{{ meshviewer_cron_hour }}" + minute: "{{ meshviewer_cron_minute }}" + job: "cd {{ meshviewer_device_pictures_dir }} && git pull -qpf" diff --git a/roles/meshviewer/templates/config.json b/roles/meshviewer/templates/config.json new file mode 100644 index 0000000..d9a6bb9 --- /dev/null +++ b/roles/meshviewer/templates/config.json @@ -0,0 +1,21 @@ +{{ { + "dataPath": meshviewer_data_path, + "siteName": meshviewer_site_name, + "maxAge": meshviewer_max_age, + "nodeZoom": meshviewer_node_zoom, + "grafana": meshviewer_grafana, + "mapLayers": meshviewer_map_layers, + "fixedCenter": meshviewer_fixed_center, + "domainNames": meshviewer_domain_names, + "nodeInfos": meshviewer_node_infos, + "nodeCharts": meshviewer_node_charts, + "globalInfos": meshviewer_global_infos, + "globalCharts": meshviewer_global_charts, + "linkList": meshviewer_link_list, + "devicePictures": meshviewer_device_pictures_url, + "devicePicturesSource": meshviewer_device_pictures_source, + "devicePicturesLicense": meshviewer_device_pictures_license, + "deprecation_text": meshviewer_deprecation_text, + "deprecation_enabled": meshviewer_deprecation_enabled, + "eol_text": meshviewer_eol_text +} | to_nice_json }} diff --git a/setup.yml b/setup.yml index 7bdc602..1ca56f9 100644 --- a/setup.yml +++ b/setup.yml @@ -96,6 +96,7 @@ - {role: batctl, tags: "batctl"} - {role: firmware_release, tags: "firmware-release"} - {role: firmware_selector, tags: "firmware-selector"} + - {role: meshviewer, tags: "meshviewer"} post_tasks: - name: Check if reboot is required From 1ebfa024881688d0405e48a598a394c7f5af7f08 Mon Sep 17 00:00:00 2001 From: Benjamin Brahmer Date: Sun, 16 Aug 2026 17:51:51 +0200 Subject: [PATCH 2/2] change file type to .j2 --- roles/meshviewer/tasks/main.yml | 2 +- roles/meshviewer/templates/{config.json => config.json.j2} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename roles/meshviewer/templates/{config.json => config.json.j2} (100%) diff --git a/roles/meshviewer/tasks/main.yml b/roles/meshviewer/tasks/main.yml index 6450ad9..c7d72a7 100644 --- a/roles/meshviewer/tasks/main.yml +++ b/roles/meshviewer/tasks/main.yml @@ -47,7 +47,7 @@ - name: Install meshviewer configuration ansible.builtin.template: - src: config.json + src: config.json.j2 dest: "{{ meshviewer_install_dir }}/config.json" owner: "{{ meshviewer_owner }}" group: "{{ meshviewer_group }}" diff --git a/roles/meshviewer/templates/config.json b/roles/meshviewer/templates/config.json.j2 similarity index 100% rename from roles/meshviewer/templates/config.json rename to roles/meshviewer/templates/config.json.j2