can add syncthing public address; refactorings

This commit is contained in:
B.J. Dweck 2021-01-31 11:45:07 +02:00
parent afb1a2f7bd
commit 9f4084fb53
4 changed files with 71 additions and 42 deletions

View File

@ -21,7 +21,9 @@ services:
volumes: volumes:
- sync1config:/config - sync1config:/config
environment: environment:
- SYNCTHING_PUBLIC_HOST=sync1 - SYNCTHING_HOSTNAME=sync1
- SYNCTHING_ADDRESS=tcp4://sync1
- SYNCTHING_DATA_PATH=/data
networks: networks:
- syncnet - syncnet
@ -45,7 +47,9 @@ services:
volumes: volumes:
- sync2config:/config - sync2config:/config
environment: environment:
- SYNCTHING_PUBLIC_HOST=sync2 - SYNCTHING_HOSTNAME=sync2
- SYNCTHING_ADDRESS=tcp4://sync2
- SYNCTHING_DATA_PATH=/data
networks: networks:
- syncnet - syncnet

View File

@ -2,27 +2,35 @@ import os
import sys import sys
import time import time
from retrying import retry
import syncthing_monitor.config_xml as xml import syncthing_monitor.config_xml as xml
from .etcd_client import EtcdClient from .etcd_client import EtcdClient
from .syncthing_client import SyncthingClient from .syncthing_client import SyncthingClient
SHARED_FOLDER_ID = "data"
SHARED_FOLDER_LABEL = "syncthing_monitor_data"
SYNCTHING_CONFIG_XML_PATH = '/config/config.xml' SYNCTHING_CONFIG_XML_PATH = '/config/config.xml'
SYNCTHING_GUI_PORT = 8384 SYNCTHING_GUI_PORT = 8384
ETCD_PORT = 2379 ETCD_PORT = 2379
def main(): def main():
program = Program(os.getenv('SYNCTHING_PUBLIC_HOST'), syncthing_mon = SyncthingMonitor(os.getenv('SYNCTHING_HOSTNAME'),
os.getenv('SYNCTHING_ADDRESS'),
os.getenv('SYNCTHING_DATA_PATH'),
SYNCTHING_CONFIG_XML_PATH, "sync", SYNCTHING_GUI_PORT, SYNCTHING_CONFIG_XML_PATH, "sync", SYNCTHING_GUI_PORT,
"etcd", ETCD_PORT) "etcd", ETCD_PORT)
program.start() syncthing_mon.start()
class Program: class SyncthingMonitor:
def __init__(self, syncthing_public_host, def __init__(self, syncthing_public_host, syncthing_address, syncthing_data_path,
syncthing_config_xml_path, syncthing_hostname, syncthing_gui_port, syncthing_config_xml_path, syncthing_hostname, syncthing_gui_port,
etcd_hostname, etcd_port): etcd_hostname, etcd_port):
self.syncthing_public_host = syncthing_public_host self.syncthing_hostname = syncthing_public_host
self.syncthing_address = syncthing_address
self.syncthing_data_path = syncthing_data_path
self.my_device_id = None self.my_device_id = None
self.syncthing = None self.syncthing = None
self.etcd = EtcdClient(etcd_hostname, etcd_port) self.etcd = EtcdClient(etcd_hostname, etcd_port)
@ -30,6 +38,7 @@ class Program:
self.syncthing_hostname = syncthing_hostname self.syncthing_hostname = syncthing_hostname
self.syncthing_config_xml_path = syncthing_config_xml_path self.syncthing_config_xml_path = syncthing_config_xml_path
@retry
def initialize_syncthing(self): def initialize_syncthing(self):
api_key = xml.parse_api_key(self.syncthing_config_xml_path) api_key = xml.parse_api_key(self.syncthing_config_xml_path)
print("Found API Key: {0}".format(api_key)) print("Found API Key: {0}".format(api_key))
@ -41,20 +50,20 @@ class Program:
self.syncthing = SyncthingClient(api_key, self.syncthing_hostname, self.syncthing_gui_port) self.syncthing = SyncthingClient(api_key, self.syncthing_hostname, self.syncthing_gui_port)
@retry
def start(self): def start(self):
self.initialize_syncthing() self.initialize_syncthing()
self.my_device_id = self.syncthing.get_my_device_id() self.my_device_id = self.syncthing.get_my_device_id()
print("Found My Device ID: {0}".format(self.my_device_id)) print("Found My Device ID: {0}".format(self.my_device_id))
self.syncthing.patch_config() self.syncthing.disable_announce_discovery_and_relay()
self.syncthing.create_shared_folder("GXWxf-3zgnU", "SharedFolder", "/data", [{'id': self.my_device_id}]) self.syncthing.create_shared_folder(SHARED_FOLDER_ID, SHARED_FOLDER_LABEL, self.syncthing_data_path,
[{'id': self.my_device_id}])
if not self.syncthing.config_is_in_sync(): self.syncthing.sync_config()
self.syncthing.restart()
self.etcd.register_device_update_handler(self.update_devices) self.etcd.register_device_update_handler(self.update_devices)
self.etcd.add_device_to_cluster(self.my_device_id, self.syncthing_public_host) self.etcd.add_device_to_cluster(self.my_device_id, self.syncthing_hostname, self.syncthing_address)
self.loop() self.loop()
@ -68,12 +77,11 @@ class Program:
def update_devices(self, event): def update_devices(self, event):
device_list = self.etcd.get_device_list() device_list = self.etcd.get_device_list()
self.syncthing.add_devices(device_list) self.syncthing.add_devices(device_list)
self.syncthing.create_shared_folder("GXWxf-3zgnU", "SharedFolder", "/data", device_list) self.syncthing.create_shared_folder(SHARED_FOLDER_ID, SHARED_FOLDER_LABEL, self.syncthing_data_path,
device_list)
self.syncthing.sync_config()
self.syncthing.print_config() self.syncthing.print_config()
if not self.syncthing.config_is_in_sync():
self.syncthing.restart()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -17,7 +17,7 @@ class EtcdClient:
return json.loads(raw_value) return json.loads(raw_value)
@retry @retry
def add_device_to_cluster(self, device_id, public_host): def add_device_to_cluster(self, device_id, hostname, address):
with self.etcd.lock('syncthing_monitor'): with self.etcd.lock('syncthing_monitor'):
cluster_info = self.load_cluster_info() cluster_info = self.load_cluster_info()
@ -26,7 +26,8 @@ class EtcdClient:
new_device = { new_device = {
'id': device_id, 'id': device_id,
'hostname': public_host 'hostname': hostname,
'address': address
} }
cluster_info['devices'].append(new_device) cluster_info['devices'].append(new_device)

View File

@ -11,24 +11,30 @@ class SyncthingClient:
self.host = host self.host = host
self.port = port self.port = port
self.headers = {'X-API-Key': self.api_key} self.headers = {'X-API-Key': self.api_key}
self.myID = None
@retry @retry
def get_my_device_id(self): def get_my_device_id(self):
response = requests.get(self.make_url("/rest/system/status"), headers=self.headers) if self.myID is None:
return json.loads(response.content)["myID"] response = self.get("/rest/system/status")
status = json.loads(response.content)
self.myID = status["myID"]
return self.myID
def add_devices(self, device_list): def add_devices(self, device_list):
for device in device_list: for device in device_list:
self.add_device(device) self.add_device(device)
def add_device(self, device): def add_device(self, device):
device_address = device['address']
if device['id'] == self.myID:
device_address = 'dynamic'
post_data = { post_data = {
"deviceID": device['id'], "deviceID": device['id'],
"name": device['hostname'], "name": device['hostname'],
"addresses": [ "addresses": [device_address],
"dynamic",
"tcp://{0}:22000".format(device['hostname'])
],
"compression": "metadata", "compression": "metadata",
"certName": "", "certName": "",
"introducer": False, "introducer": False,
@ -43,9 +49,7 @@ class SyncthingClient:
"pendingFolders": [], "pendingFolders": [],
"maxRequestKiB": 0 "maxRequestKiB": 0
} }
response = requests.post(self.make_url("/rest/config/devices"), response = self.post("/rest/config/devices", json.dumps(post_data))
headers=self.headers, data=json.dumps(post_data))
print("Attempt to add device {0} to syncthing: {1}".format(device, response.content)) print("Attempt to add device {0} to syncthing: {1}".format(device, response.content))
def create_shared_folder(self, folder_id, label, path, devices): def create_shared_folder(self, folder_id, label, path, devices):
@ -95,40 +99,52 @@ class SyncthingClient:
} }
post_data['devices'].append(folder_device) post_data['devices'].append(folder_device)
response = requests.post(self.make_url("/rest/config/folders"), response = self.post("/rest/config/folders", json.dumps(post_data))
headers=self.headers, data=json.dumps(post_data))
print("Attempt to add shared folder to syncthing: {0}".format(response.content)) print("Attempt to add shared folder to syncthing: {0}".format(response.content))
@retry @retry
def print_config(self): def print_config(self):
response = requests.get(self.make_url("/rest/config/devices"), headers=self.headers) response = self.get("/rest/config/devices")
print("/rest/config/devices: {0}".format(response.content)) print("/rest/config/devices: {0}".format(response.content))
response = requests.get(self.make_url("/rest/config/folders"), headers=self.headers)
response = self.get("/rest/config/folders")
print("/rest/config/folders: {0}".format(response.content)) print("/rest/config/folders: {0}".format(response.content))
response = requests.get(self.make_url("/rest/config/options"), headers=self.headers)
response = self.get("/rest/config/options")
print("/rest/config/options: {0}".format(response.content)) print("/rest/config/options: {0}".format(response.content))
@retry
def config_is_in_sync(self): def config_is_in_sync(self):
response = requests.get(self.make_url("/rest/config/insync"), headers=self.headers) response = self.get("/rest/config/insync")
return bool(json.loads(response.content)['configInSync']) return bool(json.loads(response.content)['configInSync'])
@retry
def restart(self): def restart(self):
response = requests.post(self.make_url("/rest/system/restart"), headers=self.headers, data='') response = self.post("/rest/system/restart", '')
print("System reset: {0}".format(response.content)) print("System reset: {0}".format(response.content))
def sync_config(self):
if not self.config_is_in_sync():
self.restart()
@retry def disable_announce_discovery_and_relay(self):
def patch_config(self):
config_patch = { config_patch = {
"globalAnnounceEnabled": False, "globalAnnounceEnabled": False,
"localAnnounceEnabled": False, "localAnnounceEnabled": False,
"relaysEnabled": False, "relaysEnabled": False,
"announceLANAddresses": False, "announceLANAddresses": False,
} }
response = requests.patch(self.make_url("/rest/config/options"), response = self.patch("/rest/config/options", json.dumps(config_patch))
headers=self.headers, data=json.dumps(config_patch))
print("Patched syncthing configuration: {0}".format(response.content)) print("Patched syncthing configuration: {0}".format(response.content))
def make_url(self, endpoint): def make_url(self, endpoint):
return "http://{0}:{1}{2}".format(self.host, self.port, endpoint) return "http://{0}:{1}{2}".format(self.host, self.port, endpoint)
def get(self, endpoint):
return requests.get(self.make_url(endpoint), headers=self.headers)
def post(self, endpoint, data):
return requests.post(self.make_url(endpoint), headers=self.headers, data=data)
def patch(self, endpoint, data):
return requests.patch(self.make_url(endpoint), headers=self.headers, data=data)