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.urls import fetch_url, url_argument_spec
SYNCTHING_API_URI = "/rest/system/config"
SYNCTHING_API_URI = "/rest/config/devices"
if platform.system() == 'Windows':
DEFAULT_ST_CONFIG_LOCATION = '%localappdata%/Syncthing/config.xml'
elif platform.system() == 'Darwin':
@ -91,8 +91,11 @@ else:
DEFAULT_ST_CONFIG_LOCATION = '$HOME/.config/syncthing/config.xml'
def make_headers(host, api_key):
url = '{}{}'.format(host, SYNCTHING_API_URI)
def make_headers(host, api_key, device=None):
if device:
url = '{}{}/{}'.format(host, SYNCTHING_API_URI, device)
else:
url = '{}{}'.format(host, SYNCTHING_API_URI)
headers = {'X-Api-Key': api_key }
return url, headers
@ -112,11 +115,19 @@ def get_key_from_filesystem(module):
"the API key manually.")
# Fetch Syncthing configuration
def get_config(module):
url, headers = make_headers(module.params['host'], module.params['api_key'])
def remote_config(module, method='GET', config=None, result=None, device=None):
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(
module, url, data=None, headers=headers,
method='GET', timeout=module.params['timeout'])
module, url, data=data, headers=headers,
method=method, timeout=module.params['timeout'])
if not info or info['status'] != 200:
result['response'] = info
@ -131,19 +142,22 @@ def get_config(module):
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
def post_config(module, config, result):
url, headers = make_headers(module.params['host'], module.params['api_key'])
headers['Content-Type'] = 'application/json'
result['msg'] = config
resp, info = fetch_url(
module, url, data=json.dumps(config), headers=headers,
method='POST', timeout=module.params['timeout'])
if not info or info['status'] != 200:
result['response'] = str(info)
module.fail_json(msg='Error occured while posting new config', **result)
def post_device(module, config, result=None, device=None):
return remote_config(module, method='POST', config=config, result=result,
device=device)
def put_device(module, config, result=None, device=None):
return remote_config(module, method='PUT', config=config, result=result,
device=device)
def patch_device(module, config, result=None, device=None):
return remote_config(module, method='PATCH', config=config, result=result,
device=device)
# Returns an object of a new device
def create_device(params):
@ -204,35 +218,26 @@ def run_module():
if not module.params['api_key']:
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':
# Remove device from list, if found
for idx, device in enumerate(config['devices']):
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)
if device_exists:
delete_device(module, device=device['deviceID'], result=result)
result['changed'] = True
if result['changed']:
post_config(module, config, result)
elif device_exists: # exists but maybe needs changing
if device['paused'] != want_pause:
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)