mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-08-03 12:44:22 -07:00
Merge 588eb3c52b
into de0618b843
This commit is contained in:
commit
8c7afa05ca
2 changed files with 102 additions and 8 deletions
2
changelogs/fragments/10432-dconf-load-subpath.yml
Normal file
2
changelogs/fragments/10432-dconf-load-subpath.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- dconf - adds support of ``load`` to populate a subpath from file (https://github.com/ansible-collections/community.general/pull/10432).
|
|
@ -61,10 +61,16 @@ options:
|
||||||
description:
|
description:
|
||||||
- Value to set for the specified dconf key. Value should be specified in GVariant format. Due to complexity of this
|
- 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.
|
format, it is best to have a look at existing values in the dconf database.
|
||||||
- Required for O(state=present).
|
- One of O(value) and O(path) are required for O(state=present).
|
||||||
- Although the type is specified as "raw", it should typically be specified as a string. However, boolean values in
|
- 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
|
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").
|
is why the type of this parameter is "raw").
|
||||||
|
path:
|
||||||
|
type: path
|
||||||
|
description:
|
||||||
|
- Remote path to the configuration to apply.
|
||||||
|
- One of O(value) and O(path) are required for O(state=present).
|
||||||
|
|
||||||
state:
|
state:
|
||||||
type: str
|
type: str
|
||||||
required: false
|
required: false
|
||||||
|
@ -122,12 +128,20 @@ EXAMPLES = r"""
|
||||||
key: "/org/cinnamon/desktop-effects"
|
key: "/org/cinnamon/desktop-effects"
|
||||||
value: "false"
|
value: "false"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: Load terminal profile in Gnome
|
||||||
|
community.general.dconf:
|
||||||
|
key: "/org/gnome/terminal/legacy/profiles/:"
|
||||||
|
path: "/tmp/solarized_dark.dump"
|
||||||
|
state: present
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from ansible.module_utils.six.moves.configparser import ConfigParser
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils.common.respawn import (
|
from ansible.module_utils.common.respawn import (
|
||||||
has_respawned,
|
has_respawned,
|
||||||
|
@ -224,7 +238,7 @@ class DBusWrapper(object):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def run_command(self, command):
|
def run_command(self, command, data=None):
|
||||||
"""
|
"""
|
||||||
Runs the specified command within a functional D-Bus session. Command is
|
Runs the specified command within a functional D-Bus session. Command is
|
||||||
effectively passed-on to AnsibleModule.run_command() method, with
|
effectively passed-on to AnsibleModule.run_command() method, with
|
||||||
|
@ -233,19 +247,21 @@ class DBusWrapper(object):
|
||||||
:param command: Command to run, including parameters. Each element of the list should be a string.
|
:param command: Command to run, including parameters. Each element of the list should be a string.
|
||||||
:type module: list
|
:type module: list
|
||||||
|
|
||||||
|
:kw data: If given, information to write to the stdin of the command
|
||||||
|
|
||||||
:returns: tuple(result_code, standard_output, standard_error) -- Result code, standard output, and standard error from running the command.
|
:returns: tuple(result_code, standard_output, standard_error) -- Result code, standard output, and standard error from running the command.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.dbus_session_bus_address is None:
|
if self.dbus_session_bus_address is None:
|
||||||
self.module.debug("Using dbus-run-session wrapper for running commands.")
|
self.module.debug("Using dbus-run-session wrapper for running commands.")
|
||||||
command = [self.dbus_run_session_cmd] + command
|
command = [self.dbus_run_session_cmd] + command
|
||||||
rc, out, err = self.module.run_command(command)
|
rc, out, err = self.module.run_command(command, data=data)
|
||||||
|
|
||||||
if self.dbus_session_bus_address is None and rc == 127:
|
if self.dbus_session_bus_address is None and rc == 127:
|
||||||
self.module.fail_json(msg="Failed to run passed-in command, dbus-run-session faced an internal error: %s" % err)
|
self.module.fail_json(msg="Failed to run passed-in command, dbus-run-session faced an internal error: %s" % err)
|
||||||
else:
|
else:
|
||||||
extra_environment = {'DBUS_SESSION_BUS_ADDRESS': self.dbus_session_bus_address}
|
extra_environment = {'DBUS_SESSION_BUS_ADDRESS': self.dbus_session_bus_address}
|
||||||
rc, out, err = self.module.run_command(command, environ_update=extra_environment)
|
rc, out, err = self.module.run_command(command, data=data, environ_update=extra_environment)
|
||||||
|
|
||||||
return rc, out, err
|
return rc, out, err
|
||||||
|
|
||||||
|
@ -390,6 +406,71 @@ class DconfPreference(object):
|
||||||
# Value was changed.
|
# Value was changed.
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def load(self, key, path):
|
||||||
|
"""
|
||||||
|
Load the config file in specified path.
|
||||||
|
|
||||||
|
if an error occurs, a call will be made to AnsibleModule.fail_json.
|
||||||
|
|
||||||
|
:param key: dconf directory for which the config should be set.
|
||||||
|
:type key: str
|
||||||
|
|
||||||
|
:param path: Remote configuration path to set for the specified dconf path.
|
||||||
|
:type value: str
|
||||||
|
|
||||||
|
:returns: bool -- True if a change was made, False if no change was required.
|
||||||
|
"""
|
||||||
|
def _create_dconf_key(root, sub_dir, key):
|
||||||
|
# Root should end with '/'
|
||||||
|
if sub_dir == "/":
|
||||||
|
# No sub directory
|
||||||
|
return "%s%s" % (root, key)
|
||||||
|
return "%s%s/%s" % (root, sub_dir, key)
|
||||||
|
|
||||||
|
# Ensure key refers to a directory, as required by dconf
|
||||||
|
root_dir = key
|
||||||
|
if not root_dir.endswith('/'):
|
||||||
|
root_dir += '/'
|
||||||
|
|
||||||
|
# Read config to check if change is needed and passing to command line
|
||||||
|
try:
|
||||||
|
with open(path, 'r') as fd:
|
||||||
|
raw_config = fd.read()
|
||||||
|
except IOError as ex:
|
||||||
|
self.module.fail_json(msg='Failed while reading configuration file %s with error: %s' % (path, ex))
|
||||||
|
|
||||||
|
# Parse configuration file
|
||||||
|
config = ConfigParser()
|
||||||
|
try:
|
||||||
|
config.read_string(raw_config)
|
||||||
|
except Exception as e:
|
||||||
|
self.module.fail_json(msg='Failed while parsing config with error: %s' % e)
|
||||||
|
|
||||||
|
# For each sub-directory, check if at least one change is needed
|
||||||
|
changed = any(
|
||||||
|
not self.variants_are_equal(self.read(_create_dconf_key(root_dir, sub_dir, k)), v)
|
||||||
|
for sub_dir in config.sections()
|
||||||
|
for k, v in config[sub_dir].items()
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.check_mode or not changed:
|
||||||
|
return changed
|
||||||
|
|
||||||
|
# Set-up command to run. Since DBus is needed for write operation, wrap
|
||||||
|
# dconf command dbus-launch.
|
||||||
|
command = [self.dconf_bin, 'load', root_dir]
|
||||||
|
|
||||||
|
# Run the command and fetch standard return code, stdout, and stderr.
|
||||||
|
dbus_wrapper = DBusWrapper(self.module)
|
||||||
|
rc, out, err = dbus_wrapper.run_command(command, data=raw_config)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
self.module.fail_json(msg='dconf failed while load config %s, root dir %s with error: %s' % (path, root_dir, err),
|
||||||
|
out=out,
|
||||||
|
err=err)
|
||||||
|
# Value was changed.
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Setup the Ansible module
|
# Setup the Ansible module
|
||||||
|
@ -398,11 +479,15 @@ def main():
|
||||||
state=dict(default='present', choices=['present', 'absent', 'read']),
|
state=dict(default='present', choices=['present', 'absent', 'read']),
|
||||||
key=dict(required=True, type='str', no_log=False),
|
key=dict(required=True, type='str', no_log=False),
|
||||||
# Converted to str below after special handling of bool.
|
# Converted to str below after special handling of bool.
|
||||||
value=dict(required=False, default=None, type='raw'),
|
value=dict(type='raw'),
|
||||||
|
path=dict(type='path'),
|
||||||
),
|
),
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
required_if=[
|
required_if=[
|
||||||
('state', 'present', ['value']),
|
('state', 'present', ['value', 'path'], True),
|
||||||
|
],
|
||||||
|
mutually_exclusive=[
|
||||||
|
['value', 'path'],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -459,11 +544,18 @@ def main():
|
||||||
|
|
||||||
# Process based on different states.
|
# Process based on different states.
|
||||||
if module.params['state'] == 'read':
|
if module.params['state'] == 'read':
|
||||||
|
# TODO: Handle this case when 'state=present' and 'key' is the only one
|
||||||
value = dconf.read(module.params['key'])
|
value = dconf.read(module.params['key'])
|
||||||
module.exit_json(changed=False, value=value)
|
module.exit_json(changed=False, value=value)
|
||||||
elif module.params['state'] == 'present':
|
elif module.params['state'] == 'present':
|
||||||
changed = dconf.write(module.params['key'], module.params['value'])
|
if module.params['path']:
|
||||||
module.exit_json(changed=changed)
|
# Use 'dconf load' to propagate multiple entries from the root given by 'key'
|
||||||
|
changed = dconf.load(module.params['key'], module.params['path'])
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
elif module.params['value']:
|
||||||
|
# Use 'dconf write' to modify the key
|
||||||
|
changed = dconf.write(module.params['key'], module.params['value'])
|
||||||
|
module.exit_json(changed=changed)
|
||||||
elif module.params['state'] == 'absent':
|
elif module.params['state'] == 'absent':
|
||||||
changed = dconf.reset(module.params['key'])
|
changed = dconf.reset(module.params['key'])
|
||||||
module.exit_json(changed=changed)
|
module.exit_json(changed=changed)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue