Compare commits

...

7 commits

Author SHA1 Message Date
mubashirusman
c19573d79e
Merge 7e1b76c46e into a85108e25e 2024-09-20 10:05:53 +02:00
softwarefactory-project-zuul[bot]
a85108e25e
Merge pull request #570 from saito-hideki/pr/AAP-29225
Fixed to set ACLs on paths mounted with NFSv4 correctly

SUMMARY
Fixed to set ACLs on paths mounted with NFSv4 correctly.

Fixed #240

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
ansible.posix.acl
ADDITIONAL INFORMATION
None
2024-09-20 05:44:24 +00:00
Hideki Saito
c353e43a90
Fixed to set ACLs on paths mounted with NFSv4 correctly
* Fixed #240

Signed-off-by: Hideki Saito <saito@fgrep.org>
2024-09-20 10:10:15 +09:00
MubashirUsman
7e1b76c46e write sysctl reverted 2024-05-19 17:47:12 +02:00
MubashirUsman
505a4aaa09 system_wide in defining module 2024-05-19 17:29:02 +02:00
MubashirUsman
d70d2aaaa7 read sysctl_dir files 2024-05-19 16:29:36 +02:00
MubashirUsman
806ff5c1a3 added sysctl_dirs variable and system_wide var 2024-05-19 13:54:43 +02:00
3 changed files with 79 additions and 30 deletions

View file

@ -0,0 +1,3 @@
---
bugfixes:
- acl - Fixed to set ACLs on paths mounted with NFS version 4 correctly (https://github.com/ansible-collections/ansible.posix/issues/240).

View file

@ -75,6 +75,10 @@ options:
use_nfsv4_acls:
description:
- Use NFSv4 ACLs instead of POSIX ACLs.
- This feature uses C(nfs4_setfacl) and C(nfs4_getfacl). The behavior depends on those implementation.
And currently it only supports C(A) in ACE, so C(D) must be replaced with the appropriate C(A).
- Permission is set as optimised ACLs by the system. You can check the actual ACLs that has been set using the return value.
- More info C(man nfs4_setfacl)
type: bool
default: false
recalculate_mask:
@ -179,7 +183,7 @@ def split_entry(entry):
def build_entry(etype, entity, permissions=None, use_nfsv4_acls=False):
'''Builds and returns an entry string. Does not include the permissions bit if they are not provided.'''
if use_nfsv4_acls:
return ':'.join([etype, entity, permissions, 'allow'])
return ':'.join(['A', 'g' if etype == 'group' else '', entity, permissions + 'tcy'])
if permissions:
return etype + ':' + entity + ':' + permissions
@ -187,22 +191,27 @@ def build_entry(etype, entity, permissions=None, use_nfsv4_acls=False):
return etype + ':' + entity
def build_command(module, mode, path, follow, default, recursive, recalculate_mask, entry=''):
def build_command(module, mode, path, follow, default, recursive, recalculate_mask, use_nfsv4_acls, entry=''):
'''Builds and returns a getfacl/setfacl command.'''
if mode == 'set':
cmd = [module.get_bin_path('setfacl', True)]
cmd.extend(['-m', entry])
cmd = [module.get_bin_path('nfs4_setfacl' if use_nfsv4_acls else 'setfacl', True)]
cmd.extend(['-a' if use_nfsv4_acls else '-m', entry])
elif mode == 'rm':
cmd = [module.get_bin_path('setfacl', True)]
cmd = [module.get_bin_path('nfs4_setfacl' if use_nfsv4_acls else 'setfacl', True)]
cmd.extend(['-x', entry])
else: # mode == 'get'
cmd = [module.get_bin_path('getfacl', True)]
# prevents absolute path warnings and removes headers
if platform.system().lower() == 'linux':
cmd.append('--omit-header')
if use_nfsv4_acls:
# use nfs4_getfacl instead of getfacl if use_nfsv4_acls is True
cmd = [module.get_bin_path('nfs4_getfacl', True)]
else:
cmd = [module.get_bin_path('getfacl', True)]
cmd.append('--absolute-names')
cmd.append('--omit-header')
if recursive:
if recursive and not use_nfsv4_acls:
cmd.append('--recursive')
if recalculate_mask == 'mask' and mode in ['set', 'rm']:
@ -210,7 +219,7 @@ def build_command(module, mode, path, follow, default, recursive, recalculate_ma
elif recalculate_mask == 'no_mask' and mode in ['set', 'rm']:
cmd.append('--no-mask')
if not follow:
if not follow and not use_nfsv4_acls:
if platform.system().lower() == 'linux':
cmd.append('--physical')
elif platform.system().lower() == 'freebsd':
@ -223,24 +232,34 @@ def build_command(module, mode, path, follow, default, recursive, recalculate_ma
return cmd
def acl_changed(module, cmd):
def acl_changed(module, cmd, entry, use_nfsv4_acls=False):
'''Returns true if the provided command affects the existing ACLs, false otherwise.'''
# FreeBSD do not have a --test flag, so by default, it is safer to always say "true"
# To check the ACL changes, use the output of setfacl or nfs4_setfacl with '--test'.
# FreeBSD do not have a --test flag, so by default, it is safer to always say "true".
if platform.system().lower() == 'freebsd':
return True
cmd = cmd[:] # lists are mutables so cmd would be overwritten without this
cmd.insert(1, '--test')
lines = run_acl(module, cmd)
counter = 0
for line in lines:
if not line.endswith('*,*'):
return True
if line.endswith('*,*') and not use_nfsv4_acls:
return False
# if use_nfsv4_acls and entry is listed
if use_nfsv4_acls and entry == line:
counter += 1
# The current 'nfs4_setfacl --test' lists a new entry,
# which will be added at the top of list, followed by the existing entries.
# So if the entry has already been registered, the entry should be find twice.
if counter == 2:
return False
return True
def run_acl(module, cmd, check_rc=True):
'''Runs the provided command and returns the output as a list of lines.'''
try:
(rc, out, err) = module.run_command(cmd, check_rc=check_rc)
except Exception as e:
@ -313,7 +332,7 @@ def main():
module.fail_json(msg="'recalculate_mask' MUST NOT be set to 'mask' or 'no_mask' when 'state=query'.")
if not entry:
if state == 'absent' and permissions:
if state == 'absent' and permissions and not use_nfsv4_acls:
module.fail_json(msg="'permissions' MUST NOT be set when 'state=absent'.")
if state == 'absent' and not entity:
@ -350,21 +369,24 @@ def main():
entry = build_entry(etype, entity, permissions, use_nfsv4_acls)
command = build_command(
module, 'set', path, follow,
default, recursive, recalculate_mask, entry
default, recursive, recalculate_mask, use_nfsv4_acls, entry
)
changed = acl_changed(module, command)
changed = acl_changed(module, command, entry, use_nfsv4_acls)
if changed and not module.check_mode:
run_acl(module, command)
msg = "%s is present" % entry
elif state == 'absent':
if use_nfsv4_acls:
entry = build_entry(etype, entity, permissions, use_nfsv4_acls)
else:
entry = build_entry(etype, entity, use_nfsv4_acls)
command = build_command(
module, 'rm', path, follow,
default, recursive, recalculate_mask, entry
default, recursive, recalculate_mask, use_nfsv4_acls, entry
)
changed = acl_changed(module, command)
changed = acl_changed(module, command, entry, use_nfsv4_acls)
if changed and not module.check_mode:
run_acl(module, command, False)
@ -375,7 +397,10 @@ def main():
acl = run_acl(
module,
build_command(module, 'get', path, follow, default, recursive, recalculate_mask)
build_command(
module, 'get', path, follow, default, recursive,
recalculate_mask, use_nfsv4_acls
)
)
module.exit_json(changed=changed, msg=msg, acl=acl)

View file

@ -101,6 +101,7 @@ import os
import platform
import re
import tempfile
import glob
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import string_types
@ -114,12 +115,24 @@ class SysctlModule(object):
# success or failure.
LANG_ENV = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C'}
# We define a variable to keep all the directories to be read, equivalent to
# (/sbin/sysctl --system) option
SYSCTL_DIRS = [
'/etc/sysctl.d/*.conf',
'/run/sysctl.d/*.conf',
'/usr/local/lib/sysctl.d/*.conf',
'/usr/lib/sysctl.d/*.conf',
'/lib/sysctl.d/*.conf',
'/etc/sysctl.conf'
]
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.system_Wide = self.args['system_Wide']
self.proc_value = None # current token value in proc fs
self.file_value = None # current token value in file
@ -298,6 +311,13 @@ class SysctlModule(object):
# so return here and do not continue to the error processing below
# https://github.com/ansible/ansible/issues/58158
return
else:
if self.system_Wide:
for sysctl_file in self.SYSCTL_DIRS:
for conf_file in glob.glob(sysctl_file):
rc, out, err = self.module.run_command([self.sysctl_cmd, '-p', conf_file], environ_update=self.LANG_ENV)
if rc != 0 or self._stderr_failed(err):
self.module.fail_json(msg="Failed to reload sysctl: %s" % to_native(out) + to_native(err))
else:
# system supports reloading via the -p flag to sysctl, so we'll use that
sysctl_args = [self.sysctl_cmd, '-p', self.sysctl_file]
@ -394,7 +414,8 @@ def main():
reload=dict(default=True, type='bool'),
sysctl_set=dict(default=False, type='bool'),
ignoreerrors=dict(default=False, type='bool'),
sysctl_file=dict(default='/etc/sysctl.conf', type='path')
sysctl_file=dict(default='/etc/sysctl.conf', type='path'),
system_wide=dict(default=False, type='bool'), # system_wide parameter
),
supports_check_mode=True,
required_if=[('state', 'present', ['value'])],