Update to new API and refactor

- the previous API calls (/rest/sysutem/config) are deprecated, so it's
  been adjusted to use the new ones (/rest/config/devices and
  /rest/config/devices/*id*)
- the code is simplified to operate just on one devices rather than
  the list of devices, the new API has sufficient functionality to do
  this
This commit is contained in:
Peter Šurda 2024-04-21 21:55:15 +08:00
parent 3a49d17dfd
commit ea36487819
Signed by untrusted user: PeterSurda
GPG Key ID: 3E47497CF67ABB95

View File

@ -82,7 +82,7 @@ from xml.etree.ElementTree import parse
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url, url_argument_spec from ansible.module_utils.urls import fetch_url, url_argument_spec
SYNCTHING_API_URI = "/rest/system/config" SYNCTHING_API_URI = "/rest/config/devices"
if platform.system() == 'Windows': if platform.system() == 'Windows':
DEFAULT_ST_CONFIG_LOCATION = '%localappdata%/Syncthing/config.xml' DEFAULT_ST_CONFIG_LOCATION = '%localappdata%/Syncthing/config.xml'
elif platform.system() == 'Darwin': elif platform.system() == 'Darwin':
@ -91,8 +91,11 @@ else:
DEFAULT_ST_CONFIG_LOCATION = '$HOME/.config/syncthing/config.xml' DEFAULT_ST_CONFIG_LOCATION = '$HOME/.config/syncthing/config.xml'
def make_headers(host, api_key): def make_headers(host, api_key, device=None):
url = '{}{}'.format(host, SYNCTHING_API_URI) if device:
url = '{}{}/{}'.format(host, SYNCTHING_API_URI, device)
else:
url = '{}{}'.format(host, SYNCTHING_API_URI)
headers = {'X-Api-Key': api_key } headers = {'X-Api-Key': api_key }
return url, headers return url, headers
@ -112,11 +115,19 @@ def get_key_from_filesystem(module):
"the API key manually.") "the API key manually.")
# Fetch Syncthing configuration # Fetch Syncthing configuration
def get_config(module): def remote_config(module, method='GET', config=None, result=None, device=None):
url, headers = make_headers(module.params['host'], module.params['api_key']) url, headers = make_headers(module.params['host'], module.params['api_key'],
device)
data = config
if config:
headers['Content-Type'] = 'application/json'
data = json.dumps(config)
if not result:
result = {}
resp, info = fetch_url( resp, info = fetch_url(
module, url, data=None, headers=headers, module, url, data=data, headers=headers,
method='GET', timeout=module.params['timeout']) method=method, timeout=module.params['timeout'])
if not info or info['status'] != 200: if not info or info['status'] != 200:
result['response'] = info result['response'] = info
@ -131,19 +142,22 @@ def get_config(module):
return json.loads(content) return json.loads(content)
def get_device(module, device=None):
return remote_config(module, device=device)
def delete_device(module, device, result=None):
return remote_config(module, method='DELETE', device=device, result=result)
# Post the new configuration to Syncthing API # Post the new configuration to Syncthing API
def post_config(module, config, result): def post_device(module, config, result=None, device=None):
url, headers = make_headers(module.params['host'], module.params['api_key']) return remote_config(module, method='POST', config=config, result=result,
headers['Content-Type'] = 'application/json' device=device)
def put_device(module, config, result=None, device=None):
result['msg'] = config return remote_config(module, method='PUT', config=config, result=result,
resp, info = fetch_url( device=device)
module, url, data=json.dumps(config), headers=headers, def patch_device(module, config, result=None, device=None):
method='POST', timeout=module.params['timeout']) return remote_config(module, method='PATCH', config=config, result=result,
device=device)
if not info or info['status'] != 200:
result['response'] = str(info)
module.fail_json(msg='Error occured while posting new config', **result)
# Returns an object of a new device # Returns an object of a new device
def create_device(params): def create_device(params):
@ -204,35 +218,26 @@ def run_module():
if not module.params['api_key']: if not module.params['api_key']:
module.params['api_key'] = get_key_from_filesystem(module) module.params['api_key'] = get_key_from_filesystem(module)
config = get_config(module) device = get_device(module, module.params['id'])
device_exists = False
if 'deviceID' in device and device['deviceID'] == module.params['id']:
device_exists = True
want_pause = module.params['state'] == 'pause'
if module.params['state'] == 'absent': if module.params['state'] == 'absent':
# Remove device from list, if found if device_exists:
for idx, device in enumerate(config['devices']): delete_device(module, device=device['deviceID'], result=result)
if device['deviceID'] == module.params['id']:
config['devices'].pop(idx)
result['changed'] = True
break
else:
# Bail-out if device is already added
for device in config['devices']:
if device['deviceID'] == module.params['id']:
want_pause = module.params['state'] == 'pause'
if (want_pause and device['paused']) or \
(not want_pause and not device['paused']):
module.exit_json(**result)
else:
device['paused'] = want_pause
result['changed'] = True
break
# Append the new device into configuration
if not result['changed']:
device = create_device(module.params)
config['devices'].append(device)
result['changed'] = True result['changed'] = True
elif device_exists: # exists but maybe needs changing
if result['changed']: if device['paused'] != want_pause:
post_config(module, config, result) device['paused'] = want_pause
patch_device(module, config=device, result=result,
device=device['deviceID'])
result['changed'] = True
else: # Doesn't exist but needs to be added
device = create_device(module.params)
post_device(module, config=device, result=result)
result['changed'] = True
module.exit_json(**result) module.exit_json(**result)