diff --git a/changelogs/fragments/6206-dconf-booleans.yml b/changelogs/fragments/6206-dconf-booleans.yml new file mode 100644 index 0000000000..92c4c930cb --- /dev/null +++ b/changelogs/fragments/6206-dconf-booleans.yml @@ -0,0 +1,2 @@ +minor_changes: + - "dconf - be forgiving about boolean values: convert them to GVariant booleans automatically (https://github.com/ansible-collections/community.general/pull/6206)." diff --git a/plugins/modules/dconf.py b/plugins/modules/dconf.py index b5ece96ec1..9777102b0e 100644 --- a/plugins/modules/dconf.py +++ b/plugins/modules/dconf.py @@ -70,13 +70,18 @@ options: description: - A dconf key to modify or read from the dconf database. value: - type: str + type: raw required: false description: - Value to set for the specified dconf key. Value should be specified in GVariant format. Due to complexity of this format, it is best to have a look at existing values in the dconf database. - Required for I(state=present). + - Although the type is specified as "raw", it should typically be + specified as a string. However, boolean values in particular are + handled properly even when specified as booleans rather than strings + (in fact, handling booleans properly is why the type of this parameter + is "raw"). state: type: str required: false @@ -155,6 +160,7 @@ except ImportError: HAS_PSUTIL = False from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils.common.text.converters import to_native class DBusWrapper(object): @@ -288,6 +294,10 @@ class DconfPreference(object): Returns True if the two values are equal. """ + if canonical_value is None: + # It's unset in dconf database, so anything the user is trying to + # set is a change. + return False try: variant1 = Variant.parse(None, canonical_value) variant2 = Variant.parse(variant1.get_type(), user_value) @@ -349,7 +359,7 @@ class DconfPreference(object): rc, out, err = dbus_wrapper.run_command(command) if rc != 0: - self.module.fail_json(msg='dconf failed while write the value with error: %s' % err, + self.module.fail_json(msg='dconf failed while writing key %s, value %s with error: %s' % (key, value, err), out=out, err=err) @@ -401,11 +411,24 @@ def main(): argument_spec=dict( state=dict(default='present', choices=['present', 'absent', 'read']), key=dict(required=True, type='str', no_log=False), - value=dict(required=False, default=None, type='str'), + # Converted to str below after special handling of bool. + value=dict(required=False, default=None, type='raw'), ), supports_check_mode=True ) + # Try to be forgiving about the user specifying a boolean as the value, or + # more accurately about the fact that YAML and Ansible are quite insistent + # about converting strings that look like booleans into booleans. Convert + # the boolean into a string of the type dconf will understand. Any type for + # the value other than boolean is just converted into a string directly. + if module.params['value'] is not None: + if isinstance(module.params['value'], bool): + module.params['value'] = 'true' if module.params['value'] else 'false' + else: + module.params['value'] = to_native( + module.params['value'], errors='surrogate_or_strict') + if Variant is None: module.warn( 'WARNING: The gi.repository Python library is not available; '