1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/plugins/modules/system/sysrc.py
David Lundgren aa33ac349c
New sysrc module for managing rc files on FreeBSD ()
* New sysrc module for managing rc files on FreeBSD

* Updated sysrc module, docs and tests per reviews

* Refactored the check_mode to be in the methods and not main

Also updated tests

* Fixed a duplicate "name" key in the sysrc test

* Remove debugging output

* Add changelog fragment

* Remove changelog fragment

* Make sure tests actually run in CI.

* Update failing test due to bad path to jail

* Create and remove testjail for tests

* Fix and cleanup tests

* Set the correct path to the testjail

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-01-16 14:14:23 +01:00

251 lines
7 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2019 David Lundgren <dlundgren@syberisle.net>
#
# 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 = r'''
---
author:
- David Lundgren (@dlundgren)
module: sysrc
short_description: Manage FreeBSD using sysrc
version_added: '2.0.0'
description:
- Manages C(/etc/rc.conf) for FreeBSD.
options:
name:
description:
- Name of variable in C(/etc/rc.conf) to manage.
type: str
required: true
value:
description:
- The value to set when I(state=present).
- The value to add when I(state=value_present).
- The value to remove when I(state=value_absent).
type: str
state:
description:
- Use I(present) to add the variable.
- Use I(absent) to remove the variable.
- Use I(value_present) to add the value to the existing variable.
- Use I(value_absent) to remove the value from the existing variable.
type: str
default: "present"
choices: [ absent, present, value_present, value_absent ]
path:
description:
- Path to file to use instead of C(/etc/rc.conf).
type: str
default: "/etc/rc.conf"
delim:
description:
- Delimiter to be used instead of C( ).
- Only used when I(state=value_present) or I(state=value_absent).
default: " "
type: str
jail:
description:
- Name or ID of the jail to operate on.
type: str
notes:
- The C(name) cannot contain periods as sysrc does not support OID style names.
'''
EXAMPLES = r'''
---
# enable mysql in the /etc/rc.conf
- name: Configure mysql pid file
community.general.sysrc:
name: mysql_pidfile
value: "/var/run/mysqld/mysqld.pid"
# enable accf_http kld in the boot loader
- name: Enable accf_http kld
community.general.sysrc:
name: accf_http_load
state: present
value: "YES"
path: /boot/loader.conf
# add gif0 to cloned_interfaces
- name: Add gif0 interface
community.general.sysrc:
name: cloned_interfaces
state: value_present
value: "gif0"
# enable nginx on a jail
- name: Enable nginx in test jail
community.general.sysrc:
name: nginx_enable
value: "YES"
jail: testjail
'''
RETURN = r'''
changed:
description: Return changed for sysrc actions.
returned: always
type: bool
sample: true
'''
from ansible.module_utils.basic import AnsibleModule
import re
class Sysrc(object):
def __init__(self, module, name, value, path, delim, jail):
self.module = module
self.name = name
self.changed = False
self.value = value
self.path = path
self.delim = delim
self.jail = jail
self.sysrc = module.get_bin_path('sysrc', True)
def has_unknown_variable(self, out, err):
# newer versions of sysrc use stderr instead of stdout
return err.find("unknown variable") > 0 or out.find("unknown variable") > 0
def exists(self):
# sysrc doesn't really use exit codes
(rc, out, err) = self.run_sysrc(self.name)
if self.value is None:
regex = "%s: " % re.escape(self.name)
else:
regex = "%s: %s$" % (re.escape(self.name), re.escape(self.value))
return not self.has_unknown_variable(out, err) and re.match(regex, out) is not None
def contains(self):
(rc, out, err) = self.run_sysrc('-n', self.name)
if self.has_unknown_variable(out, err):
return False
return self.value in out.strip().split(self.delim)
def present(self):
if self.exists():
return
if self.module.check_mode:
self.changed = True
return
(rc, out, err) = self.run_sysrc("%s=%s" % (self.name, self.value))
if out.find("%s:" % self.name) == 0 and re.search("-> %s$" % re.escape(self.value), out) is not None:
self.changed = True
def absent(self):
if not self.exists():
return
# inversed since we still need to mark as changed
if not self.module.check_mode:
(rc, out, err) = self.run_sysrc('-x', self.name)
if self.has_unknown_variable(out, err):
return
self.changed = True
def value_present(self):
if self.contains():
return
if self.module.check_mode:
self.changed = True
return
setstring = '%s+=%s%s' % (self.name, self.delim, self.value)
(rc, out, err) = self.run_sysrc(setstring)
if out.find("%s:" % self.name) == 0:
values = out.split(' -> ')[1].strip().split(self.delim)
if self.value in values:
self.changed = True
def value_absent(self):
if not self.contains():
return
if self.module.check_mode:
self.changed = True
return
setstring = '%s-=%s%s' % (self.name, self.delim, self.value)
(rc, out, err) = self.run_sysrc(setstring)
if out.find("%s:" % self.name) == 0:
values = out.split(' -> ')[1].strip().split(self.delim)
if self.value not in values:
self.changed = True
def run_sysrc(self, *args):
cmd = [self.sysrc, '-f', self.path]
if self.jail:
cmd += ['-j', self.jail]
cmd.extend(args)
(rc, out, err) = self.module.run_command(cmd)
return (rc, out, err)
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
value=dict(type='str', default=None),
state=dict(type='str', default='present', choices=['absent', 'present', 'value_present', 'value_absent']),
path=dict(type='str', default='/etc/rc.conf'),
delim=dict(type='str', default=' '),
jail=dict(type='str', default=None),
),
supports_check_mode=True,
)
name = module.params.pop('name')
# OID style names are not supported
if not re.match('^[a-zA-Z0-9_]+$', name):
module.fail_json(
msg="Name may only contain alpha-numeric and underscore characters"
)
value = module.params.pop('value')
state = module.params.pop('state')
path = module.params.pop('path')
delim = module.params.pop('delim')
jail = module.params.pop('jail')
result = dict(
name=name,
state=state,
value=value,
path=path,
delim=delim,
jail=jail
)
rc_value = Sysrc(module, name, value, path, delim, jail)
if state == 'present':
rc_value.present()
elif state == 'absent':
rc_value.absent()
elif state == 'value_present':
rc_value.value_present()
elif state == 'value_absent':
rc_value.value_absent()
result['changed'] = rc_value.changed
module.exit_json(**result)
if __name__ == '__main__':
main()