diff --git a/collection/plugins/modules/folder_defaults.py b/collection/plugins/modules/folder_defaults.py new file mode 100644 index 0000000..3070b44 --- /dev/null +++ b/collection/plugins/modules/folder_defaults.py @@ -0,0 +1,381 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2018, Rafael Bodill +# Copyright: (c) 2020, Borjan Tchakaloff +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +DOCUMENTATION = ''' +--- +module: folder_defaults + +short_description: Manage Syncthing folder default configurations + +version_added: "2.7" + +description: + - "This module allows you to manage Syncthing folder default configurations. + You can update the default configurations using this module. + It uses the Syncthing REST API to perform these operations." + +options: + id: + description: + - The ID of the module. + type: str + required: false + label: + description: + - The label for the module. + type: str + required: false + filesystemType: + description: + - The filesystem type for the module. + type: str + required: false + default: basic + path: + description: + - The path for the module. + type: str + required: false + default: ~ + type: + description: + - The type of the module. + type: str + required: false + default: sendreceive + choices: [sendreceive, sendonly, receiveonly] + devices: + description: + - List of devices for the module. + type: list + required: false + default: [] + rescanIntervalS: + description: + - The rescan interval for the module in seconds. + type: int + required: false + default: 3600 + fsWatcherEnabled: + description: + - Whether the filesystem watcher is enabled for the module. + type: bool + required: false + default: true + fsWatcherDelayS: + description: + - The filesystem watcher delay for the module in seconds. + type: int + required: false + default: 10 + ignorePerms: + description: + - Whether to ignore permissions for the module. + type: bool + required: false + default: false + autoNormalize: + description: + - Whether to automatically normalize for the module. + type: bool + required: false + default: true + minDiskFree: + description: + - The minimum disk free for the module. + type: dict + required: false + default: {value: 1, unit: '%'} + versioning: + description: + - The versioning for the module. + type: dict + required: false + default: {type: '', params: {}, cleanupIntervalS: 3600, fsPath: '', fsType: 'basic'} + copiers: + description: + - The number of copiers for the module. + type: int + required: false + default: 0 + pullerMaxPendingKiB: + description: + - The maximum pending puller size for the module in KiB. + type: int + required: false + default: 0 + hashers: + description: + - The number of hashers for the module. + type: int + required: false + default: 0 + order: + description: + - The order for the module. + type: str + required: false + default: random + ignoreDelete: + description: + - Whether to ignore delete for the module. + type: bool + required: false + default: false + scanProgressIntervalS: + description: + - The scan progress interval for the module in seconds. + type: int + required: false + default: 0 + pullerPauseS: + description: + - The puller pause for the module in seconds. + type: int + required: false + default: 0 + maxConflicts: + description: + - The maximum number of conflicts for the module. + type: int + required: false + default: 10 + disableSparseFiles: + description: + - Whether to disable sparse files for the module. + type: bool + required: false + default: false + disableTempIndexes: + description: + - Whether to disable temporary indexes for the module. + type: bool + required: false + default: false + paused: + description: + - Whether the module is paused. + type: bool + required: false + default: false + weakHashThresholdPct: + description: + - The weak hash threshold for the module in percentage. + type: int + required: false + default: 25 + markerName: + description: + - The marker name for the module. + type: str + required: false + default: .stfolder + copyOwnershipFromParent: + description: + - Whether to copy ownership from parent for the module. + type: bool + required: false + default: false + modTimeWindowS: + description: + - The modification time window for the module in seconds. + type: int + required: false + default: 0 + maxConcurrentWrites: + description: + - The maximum number of concurrent writes for the module. + type: int + required: false + default: 2 + disableFsync: + description: + - Whether to disable fsync for the module. + type: bool + required: false + default: false + blockPullOrder: + description: + - The block pull order for the module. + type: str + required: false + default: standard + copyRangeMethod: + description: + - The copy range method for the module. + type: str + required: false + default: standard + caseSensitiveFS: + description: + - Whether the filesystem is case sensitive for the module. + type: bool + required: false + default: false + junctionsAsDirs: + description: + - Whether to treat junctions as directories for the module. + type: bool + required: false + default: false + syncOwnership: + description: + - Whether to synchronize ownership for the module. + type: bool + required: false + default: false + sendOwnership: + description: + - Whether to send ownership for the module. + type: bool + required: false + default: false + syncXattrs: + description: + - Whether to synchronize extended attributes for the module. + type: bool + required: false + default: false + sendXattrs: + description: + - Whether to send extended attributes for the module. + type: bool + required: false + default: false + xattrFilter: + description: + - The extended attribute filter for the module. + type: dict + required: false + default: {entries: [], maxSingleEntrySize: 1024, maxTotalSize: 4096} + +author: + - Rafael Bodill (@rafi) +''' + +EXAMPLES = ''' +# Get/Update folder_defaults +- name: Get folder_defaults + become: yes + become_user: syncthing + community.syncthing.folder_defaults: + host: http://localhost + unix_socket: /run/syncthing/syncthing.sock + config_file: /var/lib/syncthing/.config/syncthing/config.xml + id: "default" + label: "default" + path: "/" + paused: false + register: folder_defaults +''' + +RETURN = ''' +folder_defaults: + description: The default configuration of the folder after the operation. + type: dict +changed: + description: Whether any changes were made. + type: bool +response: + description: The API response, in-case of an error. + type: dict +''' + +from ansible_collections.community.syncthing.plugins.module_utils.syncthing_api import SyncthingModule +import json + +def deep_equal(a, b): + return json.dumps(a, sort_keys=True) == json.dumps(b, sort_keys=True) + +def run_module(): + module_args = dict( + id=dict(type='str', required=False), + label=dict(type='str', required=False), + filesystemType=dict(type='str', required=False, default='basic'), + path=dict(type='str', required=False, default='~'), + type=dict(type='str', default='sendreceive', + choices=['sendreceive', 'sendonly', 'receiveonly']), + devices=dict(type='list', required=False, default=[]), + rescanIntervalS=dict(type='int', required=False, default=3600), + fsWatcherEnabled=dict(type='bool', required=False, default=True), + fsWatcherDelayS=dict(type='int', required=False, default=10), + ignorePerms=dict(type='bool', required=False, default=False), + autoNormalize=dict(type='bool', required=False, default=True), + minDiskFree=dict(type='dict', required=False, default=dict(value=1, unit='%')), + versioning=dict(type='dict', required=False, + default=dict(type='', params={}, cleanupIntervalS=3600, fsPath='', fsType='basic')), + copiers=dict(type='int', required=False, default=0), + pullerMaxPendingKiB=dict(type='int', required=False, default=0), + hashers=dict(type='int', required=False, default=0), + order=dict(type='str', required=False, default='random'), + ignoreDelete=dict(type='bool', required=False, default=False), + scanProgressIntervalS=dict(type='int', required=False, default=0), + pullerPauseS=dict(type='int', required=False, default=0), + maxConflicts=dict(type='int', required=False, default=10), + disableSparseFiles=dict(type='bool', required=False, default=False), + disableTempIndexes=dict(type='bool', required=False, default=False), + paused=dict(type='bool', required=False, default=False), + weakHashThresholdPct=dict(type='int', required=False, default=25), + markerName=dict(type='str', required=False, default='.stfolder'), + copyOwnershipFromParent=dict(type='bool', required=False, default=False), + modTimeWindowS=dict(type='int', required=False, default=0), + maxConcurrentWrites=dict(type='int', required=False, default=2), + disableFsync=dict(type='bool', required=False, default=False), + blockPullOrder=dict(type='str', required=False, default='standard'), + copyRangeMethod=dict(type='str', required=False, default='standard'), + caseSensitiveFS=dict(type='bool', required=False, default=False), + junctionsAsDirs=dict(type='bool', required=False, default=False), + syncOwnership=dict(type='bool', required=False, default=False), + sendOwnership=dict(type='bool', required=False, default=False), + syncXattrs=dict(type='bool', required=False, default=False), + sendXattrs=dict(type='bool', required=False, default=False), + xattrFilter=dict(type='dict', required=False, + default=dict(entries=[], maxSingleEntrySize=1024, maxTotalSize=4096)), + ) + + module = SyncthingModule( + api_url='/rest/config/defaults/folder', + argument_spec=module_args, + ) + + current_config = module.get_call() + + module_args_keys_list = list(module_args.keys()) + + changes = {} + + for key, value in module.params.items(): + # Check if the key is in module_args_keys_list + if key in module_args_keys_list: + # Check if the value is not None + if value is not None: + # Check if the value is different from the current_config + if not deep_equal(value, current_config.get(key)): + # If all conditions are met, add the key-value pair to changes + changes[key] = value + + if module.check_mode or len(changes.keys()) == 0: + module.result['folder_defaults'] = current_config + module.exit_json() + + module.patch_call(data=module.params) + module.result['folder_defaults'] = module.get_call() + module.result['changed'] = True + module.result['changes'] = changes + module.exit_json() + +def main(): + run_module() + +if __name__ == '__main__': + main()