From b6ee8f76c2883a934bcf412722e0cf83830173c9 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Mon, 23 Jan 2023 17:33:53 +0100 Subject: Simplify fact gathering by using the cli instead of a webapi request --- README.md | 13 ++++++++-- action_plugins/syncthing_init.py | 19 ++------------ action_plugins/syncthing_pre.py | 46 +++++++++++++++++++++++++++++++++ files/syncthing.fact | 23 ----------------- handlers/main.yaml | 2 +- tasks/main.yaml | 55 +++++++++++++++------------------------- templates/syncthing.fact | 20 +++++++++++++++ 7 files changed, 101 insertions(+), 77 deletions(-) create mode 100644 action_plugins/syncthing_pre.py delete mode 100644 files/syncthing.fact create mode 100644 templates/syncthing.fact diff --git a/README.md b/README.md index 40166b2..004f678 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,23 @@ I wanted a role to install and configure syncthing for me and did not find an ex - the validation of host_vars which virtually no role in the wild ever does - the ability to manage an additional inventory file for devices which ansible cannot manage (like my phone) +## Dependencies + +This role relies on `doas` being installed and configured so that your ansible user can run the syncthing cli as the syncthing user. + +Here is an example of a `doas.conf` that works for the ansible user: +```yaml +permit nopass ansible as syncthing +``` + ## Role variables There is a single variable to specify in the `host_vars` of your hosts: `syncthing`. This is a dict that can contain the following keys: - address: optional string to specify how to connect to the server, must match the format `tcp://` or `tcp://`. Default value is *dynamic* which means a passive host. - shared: a mandatory dict describing the directories this host shares, which can contain the following keys: - name: a mandatory string to name the share in the configuration. It must match on all devices that share this folder. - - path: the path of the folder on the device. This can difer on each device sharing this data. - - peers: a list a strings. Each item should be either the ansible_hostname of another device, or a hostname from the `syncthing_data.yaml` file + - path: the path of the folder on the device. This can differ on each device sharing this data. + - peers: a list a strings. Each item should be either the `ansible_hostname` of another device, or a hostname from the `syncthing_data.yaml` file Configuring a host through its `host_vars` looks like this: ```yaml diff --git a/action_plugins/syncthing_init.py b/action_plugins/syncthing_init.py index eb6cf9f..58dc472 100644 --- a/action_plugins/syncthing_init.py +++ b/action_plugins/syncthing_init.py @@ -28,14 +28,14 @@ class ActionModule(ActionBase): syncthing = hostvars['syncthing'] peer = { 'address': 'dynamic', - 'id': '0000000-0000000-0000000-0000000-0000000-0000000-0000000-0000000', + 'id': '', 'shared': [], } if 'address' in syncthing.keys(): peer['address'] = syncthing['address'] for shared in syncthing['shared']: peer['shared'].append({ 'name': shared['name'], 'path': shared['path'], 'peers': shared['peers']}) - if 'syncthing' in hostvars['ansible_local']: + if 'ansible_local' in hostvars and 'syncthing' in hostvars['ansible_local']: peer['id'] = hostvars['ansible_local']['syncthing']['id'] peers[hostname] = peer @@ -44,24 +44,9 @@ class ActionModule(ActionBase): if task_vars['ansible_host'] in peers.keys(): myself = peers[task_vars['ansible_host']] config = { - 'config_path': "", - 'folders_to_create': [], - 'packages': [], 'peers': {}, - 'service': "syncthing", 'shared': myself['shared'], - 'user_group': "syncthing", } - if task_vars['ansible_distribution'] == 'FreeBSD': - config['config_path'] = "/usr/local/etc/syncthing/config.xml" - config['folders_to_create'] = ["/usr/local/etc/syncthing/", "/var/syncthing"] - config['packages'] = ["p5-libwww", "syncthing"] - elif task_vars['ansible_distribution'] == 'Gentoo': - config['config_path'] = "/var/lib/syncthing/.config/syncthing/config.xml" - config['folders_to_create'] = ["/var/lib/syncthing/.config/syncthing"] - config['packages'] = ["net-p2p/syncthing"] - else: - error_msgs.append(f"syncthing role does not support {task_vars['ansible_distribution']} hosts yet") for shared in myself['shared']: for peer in shared['peers']: if not peer in config['peers'].keys(): diff --git a/action_plugins/syncthing_pre.py b/action_plugins/syncthing_pre.py new file mode 100644 index 0000000..4b7b0b3 --- /dev/null +++ b/action_plugins/syncthing_pre.py @@ -0,0 +1,46 @@ +from ansible.plugins.action import ActionBase +import re +import yaml +from yaml.loader import SafeLoader + +class ActionModule(ActionBase): + def run(self, tmp=None, task_vars=None): + if task_vars is None: + task_vars = dict() + result = super(ActionModule, self).run(tmp, task_vars) + result['changed'] = False + result['failed'] = False + + error_msgs = [] + + ### Compiling host configuration ###################################### + config = {} + if 'syncthing' in task_vars: + config = { + 'config_path': "", + 'folders_to_create': [], + 'packages': [], + 'service': "syncthing", + 'user_group': "syncthing", + } + if task_vars['ansible_distribution'] == 'FreeBSD': + config['config_dir'] = "/usr/local/etc/syncthing/" + config['data_dir'] = "/var/syncthing" + config['packages'] = ["syncthing"] + elif task_vars['ansible_distribution'] == 'Gentoo': + config['config_dir'] = "/var/lib/syncthing/.config/syncthing/" + config['data_dir'] = "/var/lib/syncthing" + config['packages'] = ["net-p2p/syncthing"] + else: + error_msgs.append(f"syncthing role does not support {task_vars['ansible_distribution']} hosts yet") + + ### Results compilation ############################################## + if error_msgs != []: + result['msg'] = ' ; '.join(error_msgs) + result['failed'] = True + + result['ansible_facts'] = { + 'syncthing_pre': config, + } + + return result diff --git a/files/syncthing.fact b/files/syncthing.fact deleted file mode 100644 index 79ea632..0000000 --- a/files/syncthing.fact +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env perl -############################################################################### -# \_o< WARNING : This file is being managed by ansible! >o_/ # -# ~~~~ ~~~~ # -############################################################################### - -use strict; -use warnings; - -use JSON::PP; -use LWP::UserAgent; - -my $id = '0000000-0000000-0000000-0000000-0000000-0000000-0000000-0000000'; - -my $resp = LWP::UserAgent->new()->head('http://localhost:8384/'); -if ($resp->code == 200) { - $id = $resp->header('X-Syncthing-Id'); -} - -my %output = ( - 'id' => $id, -); -print encode_json \%output; diff --git a/handlers/main.yaml b/handlers/main.yaml index 521381f..e9f6369 100644 --- a/handlers/main.yaml +++ b/handlers/main.yaml @@ -1,4 +1,4 @@ - name: restart syncthing service: - name: syncthing + name: "{{ syncthing_pre.service }}" state: restarted diff --git a/tasks/main.yaml b/tasks/main.yaml index 984a0cd..218feb3 100644 --- a/tasks/main.yaml +++ b/tasks/main.yaml @@ -1,5 +1,21 @@ +- action: syncthing_pre + +- name: enforces service directories + file: + state: directory + path: "{{ item }}" + owner: "{{ syncthing_pre.user_group }}" + mode: 0700 + loop: + - "{{ syncthing_pre.config_dir }}" + - "{{ syncthing_pre.data_dir }}" + +- name: Install syncthing dependencies + package: + name: "{{ syncthing_pre.packages }}" + - name: Push syncthing gathering fact on clients - copy: + template: src: syncthing.fact dest: /etc/ansible/facts.d/ mode: 0500 @@ -10,49 +26,20 @@ setup: filter=ansible_local when: syncthing_gathering_fact.changed -#- debug: -# msg: "{{ syncthing_config }}" -# changed_when: true - - action: syncthing_validate - action: syncthing_init -- name: Install syncthing dependencies - package: - name: "{{ syncthing_config.packages }}" - -- name: enforces service directories - file: - state: directory - path: "{{ item }}" - owner: syncthing - mode: 0700 - loop: "{{ syncthing_config.folders_to_create }}" - - name: enforces config file template: src: config.xml - dest: "{{ syncthing_config.config_path }}" - owner: "{{ syncthing_config.user_group }}" - mode: 0640 + dest: "{{ syncthing_pre.config_dir }}" + owner: "{{ syncthing_pre.user_group }}" + mode: 0400 notify: restart syncthing - name: start and enables service service: - name: syncthing + name: "{{ syncthing_pre.service }}" enabled: yes state: started - -- name: reload ansible_local - setup: filter=ansible_local - when: syncthing_gathering_fact.changed - -- name: enforces config file - template: - src: config.xml - dest: "{{ syncthing_config.config_path }}" - owner: "{{ syncthing_config.user_group }}" - mode: 0640 - when: syncthing_gathering_fact.changed - notify: restart syncthing diff --git a/templates/syncthing.fact b/templates/syncthing.fact new file mode 100644 index 0000000..406366b --- /dev/null +++ b/templates/syncthing.fact @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +############################################################################### +# \_o< WARNING : This file is being managed by ansible! >o_/ # +# ~~~~ ~~~~ # +############################################################################### + +use strict; +use warnings; + +use JSON::PP; + +`doas -u {{ syncthing_pre.user_group }} syncthing generate --config {{ syncthing_pre.config_dir }} 2>&1` unless -e "{{ syncthing_pre.config_dir }}/config.xml"; + +my $id = `doas -u {{ syncthing_pre.user_group }} syncthing -device-id --config {{ syncthing_pre.config_dir }} --data {{ syncthing_pre.data_dir }} 2>&1`; +chomp $id; + +my %output = ( + 'id' => $id, +); +print encode_json \%output; -- cgit v1.2.3