ansible: _remote_chmod() / _fixup_perms2() can be called sometimes.

It's used at least by the copy module, even though the result is still
mostly a no-op. _remote_chmod() doesn't accept octal mode, it accepts
symbolic mode. So implement a symbolic parser in helpers.py.
pull/107/head
David Wilson 7 years ago
parent c8cb320832
commit f649318707

@ -197,8 +197,8 @@ class Connection(ansible.plugins.connection.ConnectionBase):
:returns: :returns:
(return code, stdout bytes, stderr bytes) (return code, stdout bytes, stderr bytes)
""" """
return self.py_call(ansible_mitogen.helpers.exec_command, return self.call(ansible_mitogen.helpers.exec_command,
cast(cmd), cast(in_data)) cast(cmd), cast(in_data))
def fetch_file(self, in_path, out_path): def fetch_file(self, in_path, out_path):
""" """
@ -210,8 +210,8 @@ class Connection(ansible.plugins.connection.ConnectionBase):
:param str out_path: :param str out_path:
Local filesystem path to write. Local filesystem path to write.
""" """
output = self.py_call(ansible_mitogen.helpers.read_path, output = self.call(ansible_mitogen.helpers.read_path,
cast(in_path)) cast(in_path))
ansible_mitogen.helpers.write_path(out_path, output) ansible_mitogen.helpers.write_path(out_path, output)
def put_file(self, in_path, out_path): def put_file(self, in_path, out_path):
@ -224,5 +224,5 @@ class Connection(ansible.plugins.connection.ConnectionBase):
:param str out_path: :param str out_path:
Remote filesystem path to write. Remote filesystem path to write.
""" """
self.py_call(ansible_mitogen.helpers.write_path, cast(out_path), self.call(ansible_mitogen.helpers.write_path, cast(out_path),
ansible_mitogen.helpers.read_path(in_path)) ansible_mitogen.helpers.read_path(in_path))

@ -26,8 +26,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import json import json
import operator
import os import os
import pwd import pwd
import re
import stat
import subprocess import subprocess
import time import time
@ -165,3 +168,59 @@ def write_path(path, s):
Writes bytes `s` to a filesystem `path`. Writes bytes `s` to a filesystem `path`.
""" """
open(path, 'wb').write(s) open(path, 'wb').write(s)
CHMOD_CLAUSE_PAT = re.compile(r'([uoga]?)([+\-=])([ugo]|[rwx]*)')
CHMOD_MASKS = {
'u': stat.S_IRWXU,
'g': stat.S_IRWXG,
'o': stat.S_IRWXO,
'a': (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO),
}
CHMOD_BITS = {
'u': {'r':stat.S_IRUSR, 'w':stat.S_IWUSR, 'x':stat.S_IXUSR},
'g': {'r':stat.S_IRGRP, 'w':stat.S_IWGRP, 'x':stat.S_IXGRP},
'o': {'r':stat.S_IROTH, 'w':stat.S_IWOTH, 'x':stat.S_IXOTH},
'a': {
'r': (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH),
'w': (stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH),
'x': (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
}
}
def or_(it):
return reduce(operator.or_, it, 0)
def apply_mode_spec(spec, mode):
for clause in spec.split(','):
match = CHMOD_CLAUSE_PAT.match(clause)
who, op, perms = match.groups()
mask = CHMOD_MASKS[who]
bits = CHMOD_BITS[who]
for ch in who or 'a':
cur_perm_bits = mode & mask
new_perm_bits = or_(bits[p] for p in perms)
mode &= ~mask
if op == '=':
mode |= new_perm_bits
elif op == '+':
mode |= new_perm_bits | cur_per_bits
else:
mode |= cur_perm_bits & ~new_perm_bits
return mode
def set_file_mode(path, spec):
"""
Update the permissions of a file using the same syntax as chmod(1).
"""
mode = os.stat(path).st_mode
if spec.is_digit():
new_mode = int(spec, 8)
else:
new_mode = apply_mode_spec(spec, mode)
os.chmod(path, new_mode)

@ -117,11 +117,14 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase):
def _fixup_perms2(self, remote_paths, remote_user=None, execute=True): def _fixup_perms2(self, remote_paths, remote_user=None, execute=True):
# replaces 83 lines # replaces 83 lines
assert False, "_fixup_perms2() should never be called." if not execute:
return self._remote_chmod(remote_paths, mode='u+x')
# Do nothing unless request was to set the execute bit.
return self.COMMAND_RESULT.copy()
def _remote_chmod(self, paths, mode, sudoable=False): def _remote_chmod(self, paths, mode, sudoable=False):
return self.fake_shell(lambda: mitogen.master.Select.all( return self.fake_shell(lambda: mitogen.master.Select.all(
self._connection.call_async(os.chmod, path, mode) self._connection.call_async(helpers.set_file_mode, path, mode)
for path in paths for path in paths
)) ))

Loading…
Cancel
Save