@ -81,7 +81,7 @@ EXAMPLES = '''
sysctl_file : / tmp / test_sysctl . conf
sysctl_file : / tmp / test_sysctl . conf
reload : no
reload : no
# Set ip forwarding on in /proc and do not reload the sysctl file
# Set ip forwarding on in /proc and verify token value with the sysctl command
- sysctl :
- sysctl :
name : net . ipv4 . ip_forward
name : net . ipv4 . ip_forward
value : 1
value : 1
@ -99,6 +99,7 @@ EXAMPLES = '''
# ==============================================================
# ==============================================================
import os
import os
import re
import tempfile
import tempfile
from ansible . module_utils . basic import get_platform , AnsibleModule
from ansible . module_utils . basic import get_platform , AnsibleModule
@ -109,6 +110,10 @@ from ansible.module_utils._text import to_native
class SysctlModule ( object ) :
class SysctlModule ( object ) :
# We have to use LANG=C because we are capturing STDERR of sysctl to detect
# success or failure.
LANG_ENV = { ' LANG ' : ' C ' , ' LC_ALL ' : ' C ' , ' LC_MESSAGES ' : ' C ' }
def __init__ ( self , module ) :
def __init__ ( self , module ) :
self . module = module
self . module = module
self . args = self . module . params
self . args = self . module . params
@ -215,6 +220,14 @@ class SysctlModule(object):
else :
else :
return value
return value
def _stderr_failed ( self , err ) :
# sysctl can fail to set a value even if it returns an exit status 0
# (https://bugzilla.redhat.com/show_bug.cgi?id=1264080). That's why we
# also have to check stderr for errors. For now we will only fail on
# specific errors defined by the regex below.
errors_regex = r ' ^sysctl: setting key " [^ " ]+ " : (Invalid argument|Read-only file system)$ '
return re . search ( errors_regex , err , re . MULTILINE ) is not None
# ==============================================================
# ==============================================================
# SYSCTL COMMAND MANAGEMENT
# SYSCTL COMMAND MANAGEMENT
# ==============================================================
# ==============================================================
@ -226,7 +239,7 @@ class SysctlModule(object):
thiscmd = " %s -n %s " % ( self . sysctl_cmd , token )
thiscmd = " %s -n %s " % ( self . sysctl_cmd , token )
else :
else :
thiscmd = " %s -e -n %s " % ( self . sysctl_cmd , token )
thiscmd = " %s -e -n %s " % ( self . sysctl_cmd , token )
rc , out , err = self . module . run_command ( thiscmd )
rc , out , err = self . module . run_command ( thiscmd , environ_update = self . LANG_ENV )
if rc != 0 :
if rc != 0 :
return None
return None
else :
else :
@ -250,8 +263,8 @@ class SysctlModule(object):
if self . args [ ' ignoreerrors ' ] :
if self . args [ ' ignoreerrors ' ] :
ignore_missing = ' -e '
ignore_missing = ' -e '
thiscmd = " %s %s -w %s = %s " % ( self . sysctl_cmd , ignore_missing , token , value )
thiscmd = " %s %s -w %s = %s " % ( self . sysctl_cmd , ignore_missing , token , value )
rc , out , err = self . module . run_command ( thiscmd )
rc , out , err = self . module . run_command ( thiscmd , environ_update = self . LANG_ENV )
if rc != 0 :
if rc != 0 or self . _stderr_failed ( err ) :
self . module . fail_json ( msg = ' setting %s failed: %s ' % ( token , out + err ) )
self . module . fail_json ( msg = ' setting %s failed: %s ' % ( token , out + err ) )
else :
else :
return rc
return rc
@ -261,7 +274,7 @@ class SysctlModule(object):
# do it
# do it
if self . platform == ' freebsd ' :
if self . platform == ' freebsd ' :
# freebsd doesn't support -p, so reload the sysctl service
# freebsd doesn't support -p, so reload the sysctl service
rc , out , err = self . module . run_command ( ' /etc/rc.d/sysctl reload ' )
rc , out , err = self . module . run_command ( ' /etc/rc.d/sysctl reload ' , environ_update = self . LANG_ENV )
elif self . platform == ' openbsd ' :
elif self . platform == ' openbsd ' :
# openbsd doesn't support -p and doesn't have a sysctl service,
# openbsd doesn't support -p and doesn't have a sysctl service,
# so we have to set every value with its own sysctl call
# so we have to set every value with its own sysctl call
@ -279,9 +292,9 @@ class SysctlModule(object):
if self . args [ ' ignoreerrors ' ] :
if self . args [ ' ignoreerrors ' ] :
sysctl_args . insert ( 1 , ' -e ' )
sysctl_args . insert ( 1 , ' -e ' )
rc , out , err = self . module . run_command ( sysctl_args )
rc , out , err = self . module . run_command ( sysctl_args , environ_update = self . LANG_ENV )
if rc != 0 :
if rc != 0 or self . _stderr_failed ( err ) :
self . module . fail_json ( msg = " Failed to reload sysctl: %s " % str ( out ) + str ( err ) )
self . module . fail_json ( msg = " Failed to reload sysctl: %s " % str ( out ) + str ( err ) )
# ==============================================================
# ==============================================================