Browse code

fix missing attribs with dirct module execution (#53875)

* fix missing attribs with dirct module execution
* also make remote tmp handling smarter
update tests
* set default if attrib does not exist
* add simple test

Brian Coca authored on 2019/04/04 22:59:52
Showing 8 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+bugfixes:
1
+    - ensure we always have internal module attributes set, even if not being passed (fixes using modules as script)
... ...
@@ -27,8 +27,6 @@ FILE_ATTRIBUTES = {
27 27
     'Z': 'compresseddirty',
28 28
 }
29 29
 
30
-PASS_BOOLS = ('no_log', 'debug', 'diff')
31
-
32 30
 # Ansible modules can be written in any language.
33 31
 # The functions available here can be used to do many common tasks,
34 32
 # to simplify development of Python modules.
... ...
@@ -157,6 +155,7 @@ from ansible.module_utils.common.parameters import (
157 157
     list_deprecations,
158 158
     list_no_log_values,
159 159
     PASS_VARS,
160
+    PASS_BOOLS,
160 161
 )
161 162
 
162 163
 from ansible.module_utils.six import (
... ...
@@ -711,8 +710,10 @@ class AnsibleModule(object):
711 711
         if self._tmpdir is None:
712 712
             basedir = None
713 713
 
714
-            basedir = os.path.expanduser(os.path.expandvars(self._remote_tmp))
715
-            if not os.path.exists(basedir):
714
+            if self._remote_tmp is not None:
715
+                basedir = os.path.expanduser(os.path.expandvars(self._remote_tmp))
716
+
717
+            if basedir is not None and not os.path.exists(basedir):
716 718
                 try:
717 719
                     os.makedirs(basedir, mode=0o700)
718 720
                 except (OSError, IOError) as e:
... ...
@@ -1441,20 +1442,27 @@ class AnsibleModule(object):
1441 1441
         if legal_inputs is None:
1442 1442
             legal_inputs = self._legal_inputs
1443 1443
 
1444
-        for (k, v) in list(param.items()):
1444
+        for k in list(param.keys()):
1445 1445
 
1446 1446
             if check_invalid_arguments and k not in legal_inputs:
1447 1447
                 unsupported_parameters.add(k)
1448
-            elif k.startswith('_ansible_'):
1449
-                # handle setting internal properties from internal ansible vars
1450
-                key = k.replace('_ansible_', '')
1451
-                if key in PASS_BOOLS:
1452
-                    setattr(self, PASS_VARS[key], self.boolean(v))
1448
+
1449
+        for k in PASS_VARS:
1450
+            # handle setting internal properties from internal ansible vars
1451
+            param_key = '_ansible_%s' % k
1452
+            if param_key in param:
1453
+                if k in PASS_BOOLS:
1454
+                    setattr(self, PASS_VARS[k][0], self.boolean(param[param_key]))
1453 1455
                 else:
1454
-                    setattr(self, PASS_VARS[key], v)
1456
+                    setattr(self, PASS_VARS[k][0], param[param_key])
1455 1457
 
1456
-                # clean up internal params:
1457
-                del self.params[k]
1458
+                # clean up internal top level params:
1459
+                if param_key in self.params:
1460
+                    del self.params[param_key]
1461
+            else:
1462
+                # use defaults if not already set
1463
+                if not hasattr(self, PASS_VARS[k][0]):
1464
+                    setattr(self, PASS_VARS[k][0], PASS_VARS[k][1])
1458 1465
 
1459 1466
         if unsupported_parameters:
1460 1467
             msg = "Unsupported parameters for (%s) module: %s" % (self._name, ', '.join(sorted(list(unsupported_parameters))))
... ...
@@ -18,24 +18,28 @@ from ansible.module_utils.six import (
18 18
 # Python2 & 3 way to get NoneType
19 19
 NoneType = type(None)
20 20
 
21
+# if adding boolean attribute, also add to PASS_BOOL
22
+# some of this dupes defaults from controller config
21 23
 PASS_VARS = {
22
-    'check_mode': 'check_mode',
23
-    'debug': '_debug',
24
-    'diff': '_diff',
25
-    'keep_remote_files': '_keep_remote_files',
26
-    'module_name': '_name',
27
-    'no_log': 'no_log',
28
-    'remote_tmp': '_remote_tmp',
29
-    'selinux_special_fs': '_selinux_special_fs',
30
-    'shell_executable': '_shell',
31
-    'socket': '_socket_path',
32
-    'string_conversion_action': '_string_conversion_action',
33
-    'syslog_facility': '_syslog_facility',
34
-    'tmpdir': '_tmpdir',
35
-    'verbosity': '_verbosity',
36
-    'version': 'ansible_version',
24
+    'check_mode': ('check_mode', False),
25
+    'debug': ('_debug', False),
26
+    'diff': ('_diff', False),
27
+    'keep_remote_files': ('_keep_remote_files', False),
28
+    'module_name': ('_name', None),
29
+    'no_log': ('no_log', False),
30
+    'remote_tmp': ('_remote_tmp', None),
31
+    'selinux_special_fs': ('_selinux_special_fs', ['fuse', 'nfs', 'vboxsf', 'ramfs', '9p']),
32
+    'shell_executable': ('_shell', '/bin/sh'),
33
+    'socket': ('_socket_path', None),
34
+    'string_conversion_action': ('_string_conversion_action', 'warn'),
35
+    'syslog_facility': ('_syslog_facility', 'INFO'),
36
+    'tmpdir': ('_tmpdir', None),
37
+    'verbosity': ('_verbosity', 0),
38
+    'version': ('ansible_version', '0.0'),
37 39
 }
38 40
 
41
+PASS_BOOLS = ('check_mode', 'debug', 'diff', 'keep_remote_files', 'no_log')
42
+
39 43
 
40 44
 def _return_datastructure_name(obj):
41 45
     """ Return native stringified values from datastructures.
42 46
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+shippable/posix/group3
0 1
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+{ "ANSIBLE_MODULE_ARGS": {} }
0 1
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+#!/usr/bin/python
1
+
2
+from ansible.module_utils.basic import AnsibleModule
3
+
4
+module = AnsibleModule(argument_spec=dict())
5
+
6
+module.exit_json(**{'tempdir': module._remote_tmp})
0 7
new file mode 100755
... ...
@@ -0,0 +1,6 @@
0
+#!/usr/bin/env bash
1
+
2
+set -eux
3
+
4
+# test running module directly
5
+python.py library/test.py args.json
... ...
@@ -20,7 +20,7 @@ def patch_ansible_module(request, mocker):
20 20
         if '_ansible_remote_tmp' not in request.param['ANSIBLE_MODULE_ARGS']:
21 21
             request.param['ANSIBLE_MODULE_ARGS']['_ansible_remote_tmp'] = '/tmp'
22 22
         if '_ansible_keep_remote_files' not in request.param['ANSIBLE_MODULE_ARGS']:
23
-            request.param['ANSIBLE_MODULE_ARGS']['_ansible_keep_remote_files'] = '/tmp'
23
+            request.param['ANSIBLE_MODULE_ARGS']['_ansible_keep_remote_files'] = False
24 24
         args = json.dumps(request.param)
25 25
     else:
26 26
         raise Exception('Malformed data to the patch_ansible_module pytest fixture')