|
|
|
@ -2,6 +2,7 @@
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
# (c) 2012, David "DaviXX" CHANIAL <david.chanial@gmail.com>
|
|
|
|
|
# (c) 2014, James Tanner <tanner.jc@gmail.com>
|
|
|
|
|
#
|
|
|
|
|
# This file is part of Ansible
|
|
|
|
|
#
|
|
|
|
@ -41,19 +42,9 @@ options:
|
|
|
|
|
aliases: [ 'val' ]
|
|
|
|
|
state:
|
|
|
|
|
description:
|
|
|
|
|
- Whether the entry should be present or absent.
|
|
|
|
|
- Whether the entry should be present or absent in the sysctl file.
|
|
|
|
|
choices: [ "present", "absent" ]
|
|
|
|
|
default: present
|
|
|
|
|
checks:
|
|
|
|
|
description:
|
|
|
|
|
- If C(none), no smart/facultative checks will be made. If
|
|
|
|
|
C(before), some checks are performed before any update (i.e. is
|
|
|
|
|
the sysctl key writable?). If C(after), some checks are performed
|
|
|
|
|
after an update (i.e. does kernel return the set value?). If
|
|
|
|
|
C(both), all of the smart checks (C(before) and C(after)) are
|
|
|
|
|
performed.
|
|
|
|
|
choices: [ "none", "before", "after", "both" ]
|
|
|
|
|
default: both
|
|
|
|
|
reload:
|
|
|
|
|
description:
|
|
|
|
|
- If C(yes), performs a I(/sbin/sysctl -p) if the C(sysctl_file) is
|
|
|
|
@ -66,6 +57,13 @@ options:
|
|
|
|
|
- Specifies the absolute path to C(sysctl.conf), if not C(/etc/sysctl.conf).
|
|
|
|
|
required: false
|
|
|
|
|
default: /etc/sysctl.conf
|
|
|
|
|
sysctl_set:
|
|
|
|
|
description:
|
|
|
|
|
- Verify token value with the sysctl command and set with -w if necessary
|
|
|
|
|
choices: [ "yes", "no" ]
|
|
|
|
|
required: false
|
|
|
|
|
version_added: 1.5
|
|
|
|
|
default: False
|
|
|
|
|
notes: []
|
|
|
|
|
requirements: []
|
|
|
|
|
author: David "DaviXX" CHANIAL <david.chanial@gmail.com>
|
|
|
|
@ -78,10 +76,14 @@ EXAMPLES = '''
|
|
|
|
|
# Remove kernel.panic entry from /etc/sysctl.conf
|
|
|
|
|
- sysctl: name=kernel.panic state=absent sysctl_file=/etc/sysctl.conf
|
|
|
|
|
|
|
|
|
|
# Set kernel.panic to 3 in /tmp/test_sysctl.conf, check if the sysctl key
|
|
|
|
|
# seems writable, but do not reload sysctl, and do not check kernel value
|
|
|
|
|
# after (not needed, because the real /etc/sysctl.conf was not updated)
|
|
|
|
|
- sysctl: name=kernel.panic value=3 sysctl_file=/tmp/test_sysctl.conf checks=before reload=no
|
|
|
|
|
# Set kernel.panic to 3 in /tmp/test_sysctl.conf
|
|
|
|
|
- sysctl: name=kernel.panic value=3 sysctl_file=/tmp/test_sysctl.conf reload=no
|
|
|
|
|
|
|
|
|
|
# Set ip fowarding on in /proc and do not reload the sysctl file
|
|
|
|
|
- sysctl: name="net.ipv4.ip_forward" value=1 sysctl_set=yes
|
|
|
|
|
|
|
|
|
|
# Set ip forwarding on in /proc and in the sysctl file and reload if necessary
|
|
|
|
|
- sysctl: name="net.ipv4.ip_forward" value=1 sysctl_set=yes state=present reload=yes
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
@ -90,137 +92,168 @@ import os
|
|
|
|
|
import tempfile
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
class SysctlModule(object):
|
|
|
|
|
|
|
|
|
|
def __init__(self, module):
|
|
|
|
|
self.module = module
|
|
|
|
|
self.args = self.module.params
|
|
|
|
|
|
|
|
|
|
self.sysctl_cmd = self.module.get_bin_path('sysctl', required=True)
|
|
|
|
|
self.sysctl_file = self.args['sysctl_file']
|
|
|
|
|
|
|
|
|
|
self.proc_value = None # current token value in proc fs
|
|
|
|
|
self.file_value = None # current token value in file
|
|
|
|
|
self.file_lines = [] # all lines in the file
|
|
|
|
|
self.file_values = {} # dict of token values
|
|
|
|
|
|
|
|
|
|
self.changed = False # will change occur
|
|
|
|
|
self.set_proc = False # does sysctl need to set value
|
|
|
|
|
self.write_file = False # does the sysctl file need to be reloaded
|
|
|
|
|
|
|
|
|
|
self.process()
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
# LOGIC
|
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
|
|
def process(self):
|
|
|
|
|
|
|
|
|
|
# Whitespace is bad
|
|
|
|
|
self.args['name'] = self.args['name'].strip()
|
|
|
|
|
self.args['value'] = self.args['value'].strip()
|
|
|
|
|
|
|
|
|
|
thisname = self.args['name']
|
|
|
|
|
|
|
|
|
|
# get the current proc fs value
|
|
|
|
|
self.proc_value = self.get_token_curr_value(thisname)
|
|
|
|
|
|
|
|
|
|
# get the currect sysctl file value
|
|
|
|
|
self.read_sysctl_file()
|
|
|
|
|
if thisname not in self.file_values:
|
|
|
|
|
self.file_values[thisname] = None
|
|
|
|
|
|
|
|
|
|
# update file contents with desired token/value
|
|
|
|
|
self.fix_lines()
|
|
|
|
|
|
|
|
|
|
# what do we need to do now?
|
|
|
|
|
if self.file_values[thisname] is None and self.args['state'] == "present":
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.write_file = True
|
|
|
|
|
elif self.file_values[thisname] != self.args['value']:
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.write_file = True
|
|
|
|
|
if self.args['sysctl_set']:
|
|
|
|
|
if self.proc_value is None:
|
|
|
|
|
self.changed = True
|
|
|
|
|
elif self.proc_value != self.args['value']:
|
|
|
|
|
self.changed = True
|
|
|
|
|
self.set_proc = True
|
|
|
|
|
|
|
|
|
|
# Do the work
|
|
|
|
|
if not self.module.check_mode:
|
|
|
|
|
if self.write_file:
|
|
|
|
|
self.write_sysctl()
|
|
|
|
|
if self.write_file and self.args['reload']:
|
|
|
|
|
self.reload_sysctl()
|
|
|
|
|
if self.set_proc:
|
|
|
|
|
self.set_token_value(self.args['name'], self.args['value'])
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
# SYSCTL COMMAND MANAGEMENT
|
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
|
|
def reload_sysctl(module, **sysctl_args):
|
|
|
|
|
# update needed ?
|
|
|
|
|
if not sysctl_args['reload']:
|
|
|
|
|
return 0, ''
|
|
|
|
|
# Use the sysctl command to find the current value
|
|
|
|
|
def get_token_curr_value(self, token):
|
|
|
|
|
thiscmd = "%s -e -n %s" % (self.sysctl_cmd, token)
|
|
|
|
|
rc,out,err = self.module.run_command(thiscmd)
|
|
|
|
|
if rc != 0:
|
|
|
|
|
return None
|
|
|
|
|
else:
|
|
|
|
|
return shlex.split(out)[-1]
|
|
|
|
|
|
|
|
|
|
# Use the sysctl command to set the current value
|
|
|
|
|
def set_token_value(self, token, value):
|
|
|
|
|
thiscmd = "%s -w %s=%s" % (self.sysctl_cmd, token, value)
|
|
|
|
|
rc,out,err = self.module.run_command(thiscmd)
|
|
|
|
|
if rc != 0:
|
|
|
|
|
self.module.fail_json(msg='setting %s failed: %s' (token, out + err))
|
|
|
|
|
else:
|
|
|
|
|
return rc
|
|
|
|
|
|
|
|
|
|
# Run sysctl -p
|
|
|
|
|
def reload_sysctl(self):
|
|
|
|
|
# do it
|
|
|
|
|
if get_platform().lower() == 'freebsd':
|
|
|
|
|
# freebsd doesn't support -p, so reload the sysctl service
|
|
|
|
|
rc,out,err = module.run_command('/etc/rc.d/sysctl reload')
|
|
|
|
|
rc,out,err = self.module.run_command('/etc/rc.d/sysctl reload')
|
|
|
|
|
else:
|
|
|
|
|
# system supports reloading via the -p flag to sysctl, so we'll use that
|
|
|
|
|
sysctl_cmd = module.get_bin_path('sysctl', required=True)
|
|
|
|
|
rc,out,err = module.run_command([sysctl_cmd, '-p', sysctl_args['sysctl_file']])
|
|
|
|
|
rc,out,err = self.module.run_command([self.sysctl_cmd, '-p', self.sysctl_file])
|
|
|
|
|
|
|
|
|
|
return rc,out+err
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
# SYSCTL FILE MANAGEMENT
|
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
|
|
# Get the token value from the sysctl file
|
|
|
|
|
def read_sysctl_file(self):
|
|
|
|
|
lines = open(self.sysctl_file, "r").readlines()
|
|
|
|
|
for line in lines:
|
|
|
|
|
line = line.strip()
|
|
|
|
|
self.file_lines.append(line)
|
|
|
|
|
|
|
|
|
|
# don't split empty lines or comments
|
|
|
|
|
if not line or line.startswith("#"):
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
def write_sysctl(module, lines, **sysctl_args):
|
|
|
|
|
k, v = line.split('=',1)
|
|
|
|
|
k = k.strip()
|
|
|
|
|
v = v.strip()
|
|
|
|
|
self.file_values[k] = v.strip()
|
|
|
|
|
|
|
|
|
|
# Fix the value in the sysctl file content
|
|
|
|
|
def fix_lines(self):
|
|
|
|
|
checked = []
|
|
|
|
|
self.fixed_lines = []
|
|
|
|
|
for line in self.file_lines:
|
|
|
|
|
if not line.strip() or line.strip().startswith("#"):
|
|
|
|
|
self.fixed_lines.append(line)
|
|
|
|
|
continue
|
|
|
|
|
tmpline = line.strip()
|
|
|
|
|
k, v = line.split('=',1)
|
|
|
|
|
k = k.strip()
|
|
|
|
|
v = v.strip()
|
|
|
|
|
if k not in checked:
|
|
|
|
|
checked.append(k)
|
|
|
|
|
if k == self.args['name']:
|
|
|
|
|
if self.args['state'] == "present":
|
|
|
|
|
new_line = "%s = %s\n" % (k, self.args['value'])
|
|
|
|
|
self.fixed_lines.append(new_line)
|
|
|
|
|
else:
|
|
|
|
|
new_line = "%s = %s\n" % (k, v)
|
|
|
|
|
self.fixed_lines.append(new_line)
|
|
|
|
|
|
|
|
|
|
if self.args['name'] not in checked and self.args['state'] == "present":
|
|
|
|
|
new_line = "%s = %s\n" % (self.args['name'], self.args['value'])
|
|
|
|
|
self.fixed_lines.append(new_line)
|
|
|
|
|
|
|
|
|
|
# Completely rewrite the sysctl file
|
|
|
|
|
def write_sysctl(self):
|
|
|
|
|
# open a tmp file
|
|
|
|
|
fd, tmp_path = tempfile.mkstemp('.conf', '.ansible_m_sysctl_', os.path.dirname(sysctl_args['sysctl_file']))
|
|
|
|
|
fd, tmp_path = tempfile.mkstemp('.conf', '.ansible_m_sysctl_', os.path.dirname(self.sysctl_file))
|
|
|
|
|
f = open(tmp_path,"w")
|
|
|
|
|
try:
|
|
|
|
|
for l in lines:
|
|
|
|
|
for l in self.fixed_lines:
|
|
|
|
|
f.write(l)
|
|
|
|
|
except IOError, e:
|
|
|
|
|
module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, str(e)))
|
|
|
|
|
self.module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, str(e)))
|
|
|
|
|
f.flush()
|
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
|
|
# replace the real one
|
|
|
|
|
module.atomic_move(tmp_path, sysctl_args['sysctl_file'])
|
|
|
|
|
self.module.atomic_move(tmp_path, self.sysctl_file)
|
|
|
|
|
|
|
|
|
|
# end
|
|
|
|
|
return sysctl_args
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
|
|
def sysctl_args_expand(**sysctl_args):
|
|
|
|
|
if get_platform().lower() == 'freebsd':
|
|
|
|
|
# FreeBSD does not use the /proc file system, and instead
|
|
|
|
|
# just uses the sysctl command to set the values
|
|
|
|
|
sysctl_args['key_path'] = None
|
|
|
|
|
else:
|
|
|
|
|
sysctl_args['key_path'] = sysctl_args['name'].replace('.' ,'/')
|
|
|
|
|
sysctl_args['key_path'] = '/proc/sys/' + sysctl_args['key_path']
|
|
|
|
|
return sysctl_args
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
|
|
def sysctl_args_collapse(**sysctl_args):
|
|
|
|
|
# go ahead
|
|
|
|
|
if sysctl_args.get('key_path') is not None:
|
|
|
|
|
del sysctl_args['key_path']
|
|
|
|
|
if sysctl_args['state'] == 'absent' and 'value' in sysctl_args:
|
|
|
|
|
del sysctl_args['value']
|
|
|
|
|
|
|
|
|
|
# end
|
|
|
|
|
return sysctl_args
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
|
|
def sysctl_check(module, current_step, **sysctl_args):
|
|
|
|
|
|
|
|
|
|
# no smart checks at this step ?
|
|
|
|
|
if sysctl_args['checks'] == 'none':
|
|
|
|
|
return 0, ''
|
|
|
|
|
if current_step == 'before' and sysctl_args['checks'] not in ['before', 'both']:
|
|
|
|
|
return 0, ''
|
|
|
|
|
if current_step == 'after' and sysctl_args['checks'] not in ['after', 'both']:
|
|
|
|
|
return 0, ''
|
|
|
|
|
|
|
|
|
|
# checking coherence
|
|
|
|
|
if sysctl_args['state'] == 'absent' and sysctl_args['value'] is not None:
|
|
|
|
|
return 1, 'value=x must not be supplied when state=absent'
|
|
|
|
|
|
|
|
|
|
if sysctl_args['state'] == 'present' and sysctl_args['value'] is None:
|
|
|
|
|
return 1, 'value=x must be supplied when state=present'
|
|
|
|
|
|
|
|
|
|
if not sysctl_args['reload'] and sysctl_args['checks'] in ['after', 'both']:
|
|
|
|
|
return 1, 'checks cannot be set to after or both if reload=no'
|
|
|
|
|
|
|
|
|
|
if sysctl_args['key_path'] is not None:
|
|
|
|
|
# getting file stat
|
|
|
|
|
if not os.access(sysctl_args['key_path'], os.F_OK):
|
|
|
|
|
return 1, 'key_path is not an existing file, key %s seems invalid' % sysctl_args['key_path']
|
|
|
|
|
if not os.access(sysctl_args['key_path'], os.R_OK):
|
|
|
|
|
return 1, 'key_path is not a readable file, key seems to be uncheckable'
|
|
|
|
|
|
|
|
|
|
# checks before
|
|
|
|
|
if current_step == 'before' and sysctl_args['checks'] in ['before', 'both']:
|
|
|
|
|
if sysctl_args['key_path'] is not None and not os.access(sysctl_args['key_path'], os.W_OK):
|
|
|
|
|
return 1, 'key_path is not a writable file, key seems to be read only'
|
|
|
|
|
return 0, ''
|
|
|
|
|
|
|
|
|
|
# checks after
|
|
|
|
|
if current_step == 'after' and sysctl_args['checks'] in ['after', 'both']:
|
|
|
|
|
if sysctl_args['value'] is not None:
|
|
|
|
|
if sysctl_args['key_path'] is not None:
|
|
|
|
|
# reading the virtual file
|
|
|
|
|
f = open(sysctl_args['key_path'],'r')
|
|
|
|
|
output = f.read()
|
|
|
|
|
f.close()
|
|
|
|
|
else:
|
|
|
|
|
# we're on a system without /proc (ie. freebsd), so just
|
|
|
|
|
# use the sysctl command to get the currently set value
|
|
|
|
|
sysctl_cmd = module.get_bin_path('sysctl', required=True)
|
|
|
|
|
rc,output,stderr = module.run_command("%s -n %s" % (sysctl_cmd, sysctl_args['name']))
|
|
|
|
|
if rc != 0:
|
|
|
|
|
return 1, 'failed to lookup the value via the sysctl command'
|
|
|
|
|
|
|
|
|
|
output = output.strip(' \t\n\r')
|
|
|
|
|
output = re.sub(r'\s+', ' ', output)
|
|
|
|
|
|
|
|
|
|
# normal case, found value must be equal to the submitted value, and
|
|
|
|
|
# we compare the exploded values to handle any whitepsace differences
|
|
|
|
|
if output.split() != sysctl_args['value'].split():
|
|
|
|
|
return 1, 'key seems not set to value even after update/sysctl, founded : <%s>, wanted : <%s>' % (output, sysctl_args['value'])
|
|
|
|
|
|
|
|
|
|
return 0, ''
|
|
|
|
|
else:
|
|
|
|
|
# no value was supplied, so we're checking to make sure
|
|
|
|
|
# the associated name is absent. We just fudge this since
|
|
|
|
|
# the sysctl isn't really gone, just removed from the conf
|
|
|
|
|
# file meaning it will be whatever the system default is
|
|
|
|
|
return 0, ''
|
|
|
|
|
|
|
|
|
|
# weird end
|
|
|
|
|
return 1, 'unexpected position reached'
|
|
|
|
|
|
|
|
|
|
# ==============================================================
|
|
|
|
|
# main
|
|
|
|
@ -233,110 +266,16 @@ def main():
|
|
|
|
|
name = dict(aliases=['key'], required=True),
|
|
|
|
|
value = dict(aliases=['val'], required=False),
|
|
|
|
|
state = dict(default='present', choices=['present', 'absent']),
|
|
|
|
|
checks = dict(default='both', choices=['none', 'before', 'after', 'both']),
|
|
|
|
|
reload = dict(default=True, type='bool'),
|
|
|
|
|
sysctl_set = dict(default=True, type='bool'),
|
|
|
|
|
sysctl_file = dict(default='/etc/sysctl.conf')
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
supports_check_mode=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# defaults
|
|
|
|
|
sysctl_args = {
|
|
|
|
|
'changed': False,
|
|
|
|
|
'name': module.params['name'],
|
|
|
|
|
'state': module.params['state'],
|
|
|
|
|
'checks': module.params['checks'],
|
|
|
|
|
'reload': module.params['reload'],
|
|
|
|
|
'value': module.params.get('value'),
|
|
|
|
|
'sysctl_file': module.params['sysctl_file']
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# prepare vars
|
|
|
|
|
sysctl_args = sysctl_args_expand(**sysctl_args)
|
|
|
|
|
if get_platform().lower() == 'freebsd':
|
|
|
|
|
# freebsd does not like spaces around the equal sign
|
|
|
|
|
pattern = "%s=%s\n"
|
|
|
|
|
else:
|
|
|
|
|
pattern = "%s = %s\n"
|
|
|
|
|
new_line = pattern % (sysctl_args['name'], sysctl_args['value'])
|
|
|
|
|
to_write = []
|
|
|
|
|
founded = False
|
|
|
|
|
|
|
|
|
|
# make checks before act
|
|
|
|
|
res,msg = sysctl_check(module, 'before', **sysctl_args)
|
|
|
|
|
if res != 0:
|
|
|
|
|
module.fail_json(msg='checks_before failed with: ' + msg)
|
|
|
|
|
|
|
|
|
|
if not os.access(sysctl_args['sysctl_file'], os.W_OK):
|
|
|
|
|
try:
|
|
|
|
|
f = open(sysctl_args['sysctl_file'],'w')
|
|
|
|
|
f.close()
|
|
|
|
|
except IOError, e:
|
|
|
|
|
module.fail_json(msg='unable to create supplied sysctl file (destination directory probably missing)')
|
|
|
|
|
|
|
|
|
|
# reading the file
|
|
|
|
|
for line in open(sysctl_args['sysctl_file'], 'r').readlines():
|
|
|
|
|
if not line.strip():
|
|
|
|
|
to_write.append(line)
|
|
|
|
|
continue
|
|
|
|
|
if line.strip().startswith('#'):
|
|
|
|
|
to_write.append(line)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# write line if not the one searched
|
|
|
|
|
ld = {}
|
|
|
|
|
ld['name'], ld['val'] = line.split('=',1)
|
|
|
|
|
ld['name'] = ld['name'].strip()
|
|
|
|
|
|
|
|
|
|
if ld['name'] != sysctl_args['name']:
|
|
|
|
|
to_write.append(line)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# should be absent ?
|
|
|
|
|
if sysctl_args['state'] == 'absent':
|
|
|
|
|
# not writing the founded line
|
|
|
|
|
# mark as changed
|
|
|
|
|
sysctl_args['changed'] = True
|
|
|
|
|
|
|
|
|
|
# should be present
|
|
|
|
|
if sysctl_args['state'] == 'present':
|
|
|
|
|
# is the founded line equal to the wanted one ?
|
|
|
|
|
ld['val'] = ld['val'].strip()
|
|
|
|
|
if ld['val'] == sysctl_args['value']:
|
|
|
|
|
# line is equal, writing it without update (but cancel repeats)
|
|
|
|
|
if sysctl_args['changed'] == False and founded == False:
|
|
|
|
|
to_write.append(line)
|
|
|
|
|
founded = True
|
|
|
|
|
else:
|
|
|
|
|
# update the line (but cancel repeats)
|
|
|
|
|
if sysctl_args['changed'] == False and founded == False:
|
|
|
|
|
to_write.append(new_line)
|
|
|
|
|
sysctl_args['changed'] = True
|
|
|
|
|
continue
|
|
|
|
|
result = SysctlModule(module)
|
|
|
|
|
|
|
|
|
|
# if not changed, but should be present, so we have to add it
|
|
|
|
|
if sysctl_args['state'] == 'present' and sysctl_args['changed'] == False and founded == False:
|
|
|
|
|
to_write.append(new_line)
|
|
|
|
|
sysctl_args['changed'] = True
|
|
|
|
|
|
|
|
|
|
# has changed ?
|
|
|
|
|
res = 0
|
|
|
|
|
if sysctl_args['changed'] == True:
|
|
|
|
|
sysctl_args = write_sysctl(module, to_write, **sysctl_args)
|
|
|
|
|
res,msg = reload_sysctl(module, **sysctl_args)
|
|
|
|
|
|
|
|
|
|
# make checks after act
|
|
|
|
|
res,msg = sysctl_check(module, 'after', **sysctl_args)
|
|
|
|
|
if res != 0:
|
|
|
|
|
module.fail_json(msg='checks_after failed with: ' + msg)
|
|
|
|
|
|
|
|
|
|
# look at the next link to avoid this workaround
|
|
|
|
|
# https://groups.google.com/forum/?fromgroups=#!topic/ansible-project/LMY-dwF6SQk
|
|
|
|
|
changed = sysctl_args['changed']
|
|
|
|
|
del sysctl_args['changed']
|
|
|
|
|
|
|
|
|
|
# end
|
|
|
|
|
sysctl_args = sysctl_args_collapse(**sysctl_args)
|
|
|
|
|
module.exit_json(changed=changed, **sysctl_args)
|
|
|
|
|
module.exit_json(changed=result.changed)
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
# import module snippets
|
|
|
|
|