Skip to content

Instantly share code, notes, and snippets.

@samdoran
Last active September 27, 2024 01:32
Show Gist options
  • Save samdoran/eb19f126acaa620133babca09106a2ed to your computer and use it in GitHub Desktop.
Save samdoran/eb19f126acaa620133babca09106a2ed to your computer and use it in GitHub Desktop.
Ansible module to set systemd default target
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Sam Doran
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = """
---
module: systemd_default
author:
- Sam Doran (@samdoran)
short_description: Configure the systemd default target
notes: []
description:
- Set the systemd default target and optionally apply it immediately.
options:
target:
description:
- Name of the target. Must be a valid target unit file on the remote system.
The '.target' file extension is optional. If a file extension is given, it must be '.target'.
type: str
required: yes
apply:
description: Whether or not to switch to the C(target) immediately.
type: bool
default: no
required: no
"""
EXAMPLES = """
- name: Set default target to graphical and switch to it immediately
systemd_default:
target: graphical.target
apply: yes
- name: Set default target to multi-user
systemd_default:
target: multi-user
"""
RETURN = """
previous_target:
description: Name of the default target before the module made changes
returned: always
type: string
sample: multi-user.target
target:
description: Name of the desired target.
returned: always
type: string
sample: graphical.target
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.process import get_bin_path
def normalize_target_name(module, target):
# Sanity check the file extension if one was provided
if len(target.split('.')) >= 2:
ext = target.split('.')[-1]
if ext != 'target':
module.fail_json("Invalid extension '{0}' on '{1}'".format(ext, target))
if target.split('.')[-1] != 'target':
return '{0}.target'.format(target)
return target
def list_targets(module, systemd_path):
cmd = [systemd_path, 'list-units', '--type', 'target', '--no-legend', '--no-block', '--no-pager', '--all']
rc, out, err = module.run_command(cmd)
if rc != 0:
module.fail_json("Unable to list available targets")
valid_targets = set()
for line in out.splitlines():
line = ' '.join(line.split(maxsplit=4))
unit, load, active, sub, description = line.split(maxsplit=4)
valid_targets.add(unit)
return valid_targets
def validate_target(module, target, systemd_path):
valid_targets = list_targets(module, systemd_path)
if target not in valid_targets:
module.fail_json("The specified target '{0}' is not a valid target on this system".format(target))
def get_current_default(module, systemd_path):
cmd = [systemd_path, 'get-default']
rc, out, err = module.run_command(cmd)
if rc != 0:
module.fail_json(msg='Unable to get current default target')
return out.rstrip('\n\r')
def set_default_target(module, target, systemd_path):
current_default = get_current_default(module, systemd_path)
changed = False
if current_default != target:
changed = True
if not module.check_mode:
set_cmd = [systemd_path, 'set-default', target]
rc, out, err = module.run_command(set_cmd)
if rc != 0:
module.fail_json("Failed to set default target to '{0}'".format(target))
return changed, current_default
def get_active_state(module, target, systemd_path):
status_cmd = [systemd_path, 'is-active', target]
rc, out, err = module.run_command(status_cmd)
return out.rstrip('\n\r')
def apply_target(module, target, systemd_path):
applied = False
current_state = get_active_state(module, target, systemd_path)
if current_state == 'active':
return applied
isolate_cmd = [systemd_path, 'isolate', target]
rc, out, err = module.run_command(isolate_cmd)
if rc != 0:
module.fail_json("Failed to apply target '{0}'".format(target))
applied = True
return applied
def main():
module = AnsibleModule(
argument_spec={
'target': {'type': 'str', 'required': True},
'apply': {'type': 'bool', 'default': False},
},
supports_check_mode=True,
)
try:
systemd_path = get_bin_path('systemctl')
except ValueError:
module.fail_json(msg="Unable to find 'systemctl'")
full_target_name = normalize_target_name(module, module.params['target'])
validate_target(module, full_target_name, systemd_path)
changed, current = set_default_target(module, full_target_name, systemd_path)
applied = False
if module.params['apply']:
applied = apply_target(module, full_target_name, systemd_path)
results = {
'changed': changed or applied,
'previous_target': current,
'target': full_target_name,
}
module.exit_json(**results)
if __name__ == '__main__':
main()
@kitizz
Copy link

kitizz commented Sep 27, 2024

A gentleman and a scholar, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment