def absent(module, dest, regexp, line, backup): b_dest = to_bytes(dest, errors='surrogate_or_strict') if not os.path.exists(b_dest): module.exit_json(changed=False, msg="file not present") msg = '' diff = {'before': '', 'after': '', 'before_header': '%s (content)' % dest, 'after_header': '%s (content)' % dest} with open(b_dest, 'rb') as f: b_lines = f.readlines() if module._diff: diff['before'] = to_native(b''.join(b_lines)) if regexp is not None: bre_c = re.compile(to_bytes(regexp, errors='surrogate_or_strict')) found = [] b_line = to_bytes(line, errors='surrogate_or_strict') def matcher(b_cur_line): if regexp is not None: match_found = bre_c.search(b_cur_line) else: match_found = b_line == b_cur_line.rstrip(b'\r\n') if match_found: found.append(b_cur_line) return not match_found b_lines = [l for l in b_lines if matcher(l)] changed = len(found) > 0 if module._diff: diff['after'] = to_native(b''.join(b_lines)) backupdest = "" if changed and not module.check_mode: if backup: backupdest = module.backup_local(dest) write_changes(module, b_lines, dest) if changed: msg = "%s line(s) removed" % len(found) attr_diff = {} msg, changed = check_file_attrs(module, changed, msg, attr_diff) attr_diff['before_header'] = '%s (file attributes)' % dest attr_diff['after_header'] = '%s (file attributes)' % dest difflist = [diff, attr_diff] module.exit_json(changed=changed, found=len(found), msg=msg, backup=backupdest, diff=difflist)
def test_plugins_connection_ssh_put_file(self, mock_ospe, mock_sleep): pc = PlayContext() new_stdin = StringIO() conn = connection_loader.get('ssh', pc, new_stdin) conn._build_command = MagicMock() conn._bare_run = MagicMock() mock_ospe.return_value = True conn._build_command.return_value = 'some command to run' conn._bare_run.return_value = (0, '', '') conn.host = "some_host" C.ASSIBLE_SSH_RETRIES = 9 # Test with C.DEFAULT_SCP_IF_SSH set to smart # Test when SFTP works C.DEFAULT_SCP_IF_SSH = 'smart' expected_in_data = b' '.join((b'put', to_bytes(shlex_quote('/path/to/in/file')), to_bytes(shlex_quote('/path/to/dest/file')))) + b'\n' conn.put_file('/path/to/in/file', '/path/to/dest/file') conn._bare_run.assert_called_with('some command to run', expected_in_data, checkrc=False) # Test when SFTP doesn't work but SCP does conn._bare_run.side_effect = [(1, 'stdout', 'some errors'), (0, '', '')] conn.put_file('/path/to/in/file', '/path/to/dest/file') conn._bare_run.assert_called_with('some command to run', None, checkrc=False) conn._bare_run.side_effect = None # test with C.DEFAULT_SCP_IF_SSH enabled C.DEFAULT_SCP_IF_SSH = True conn.put_file('/path/to/in/file', '/path/to/dest/file') conn._bare_run.assert_called_with('some command to run', None, checkrc=False) conn.put_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩') conn._bare_run.assert_called_with('some command to run', None, checkrc=False) # test with C.DEFAULT_SCP_IF_SSH disabled C.DEFAULT_SCP_IF_SSH = False expected_in_data = b' '.join((b'put', to_bytes(shlex_quote('/path/to/in/file')), to_bytes(shlex_quote('/path/to/dest/file')))) + b'\n' conn.put_file('/path/to/in/file', '/path/to/dest/file') conn._bare_run.assert_called_with('some command to run', expected_in_data, checkrc=False) expected_in_data = b' '.join((b'put', to_bytes(shlex_quote('/path/to/in/file/with/unicode-fö〩')), to_bytes(shlex_quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n' conn.put_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩') conn._bare_run.assert_called_with('some command to run', expected_in_data, checkrc=False) # test that a non-zero rc raises an error conn._bare_run.return_value = (1, 'stdout', 'some errors') self.assertRaises(AssibleError, conn.put_file, '/path/to/bad/file', '/remote/path/to/file') # test that a not-found path raises an error mock_ospe.return_value = False conn._bare_run.return_value = (0, 'stdout', '') self.assertRaises(AssibleFileNotFound, conn.put_file, '/path/to/bad/file', '/remote/path/to/file')
def run_cmd(cmd, live=False, readsize=10): # readsize = 10 # On python2, shlex needs byte strings if PY2: cmd = to_bytes(cmd, errors='surrogate_or_strict') cmdargs = shlex.split(cmd) # subprocess should be passed byte strings. (on python2.6 it must be # passed byte strtings) cmdargs = [to_bytes(a, errors='surrogate_or_strict') for a in cmdargs] p = subprocess.Popen(cmdargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = b'' stderr = b'' rpipes = [p.stdout, p.stderr] while True: rfd, wfd, efd = select.select(rpipes, [], rpipes, 1) if p.stdout in rfd: dat = os.read(p.stdout.fileno(), readsize) if live: # On python3, stdout has a codec to go from text type to bytes if PY3: sys.stdout.buffer.write(dat) else: sys.stdout.write(dat) stdout += dat if dat == b'': rpipes.remove(p.stdout) if p.stderr in rfd: dat = os.read(p.stderr.fileno(), readsize) stderr += dat if live: # On python3, stdout has a codec to go from text type to bytes if PY3: sys.stdout.buffer.write(dat) else: sys.stdout.write(dat) if dat == b'': rpipes.remove(p.stderr) # only break out if we've emptied the pipes, or there is nothing to # read from and the process has finished. if (not rpipes or not rfd) and p.poll() is not None: break # Calling wait while there are still pipes to read can cause a lock elif not rpipes and p.poll() is None: p.wait() return p.returncode, stdout, stderr
def check_password_prompt(self, b_output): ''' checks if the expected password prompt exists in b_output ''' prompts = self.get_option( 'prompt_l10n') or self.SU_PROMPT_LOCALIZATIONS b_password_string = b"|".join( (br'(\w+\'s )?' + to_bytes(p)) for p in prompts) # Colon or unicode fullwidth colon b_password_string = b_password_string + to_bytes(u' ?(:|:) ?') b_su_prompt_localizations_re = re.compile(b_password_string, flags=re.IGNORECASE) return bool(b_su_prompt_localizations_re.match(b_output))
def _get_cache_prefix(self, path): ''' create predictable unique prefix for plugin/inventory ''' m = hashlib.sha1() m.update(to_bytes(self.NAME, errors='surrogate_or_strict')) d1 = m.hexdigest() n = hashlib.sha1() n.update(to_bytes(path, errors='surrogate_or_strict')) d2 = n.hexdigest() return 's_'.join([d1[:5], d2[:5]])
def test_parse_subprocess_err_code_fail(self): self.popen_result.stdout = to_bytes(u"fooébar", errors='surrogate_escape') self.popen_result.stderr = to_bytes(u"dummyédata") self.popen_result.returncode = 1 with pytest.raises(AssibleError) as e: self.inventory_module.parse(self.inventory, self.loader, '/foo/bar/foobar.py') assert e.value.message == to_native( "Inventory script (/foo/bar/foobar.py) had an execution error: " "dummyédata\n ")
def send_command(self, command=None, prompt=None, answer=None, sendonly=False, newline=True, prompt_retry_check=False, check_all=False): """Executes a command over the device connection This method will execute a command over the device connection and return the results to the caller. This method will also perform logging of any commands based on the `nolog` argument. :param command: The command to send over the connection to the device :param prompt: A single regex pattern or a sequence of patterns to evaluate the expected prompt from the command :param answer: The answer to respond with if the prompt is matched. :param sendonly: Bool value that will send the command but not wait for a result. :param newline: Bool value that will append the newline character to the command :param prompt_retry_check: Bool value for trying to detect more prompts :param check_all: Bool value to indicate if all the values in prompt sequence should be matched or any one of given prompt. :returns: The output from the device after executing the command """ kwargs = { 'command': to_bytes(command), 'sendonly': sendonly, 'newline': newline, 'prompt_retry_check': prompt_retry_check, 'check_all': check_all } if prompt is not None: if isinstance(prompt, list): kwargs['prompt'] = [to_bytes(p) for p in prompt] else: kwargs['prompt'] = to_bytes(prompt) if answer is not None: if isinstance(answer, list): kwargs['answer'] = [to_bytes(p) for p in answer] else: kwargs['answer'] = to_bytes(answer) resp = self._connection.send(**kwargs) if not self.response_logging: self.history.append(('*****', '*****')) else: self.history.append((kwargs['command'], resp)) return resp
def b_token_file(request, tmp_path_factory): b_test_dir = to_bytes(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Token')) b_token_path = os.path.join(b_test_dir, b"token.yml") token = getattr(request, 'param', None) if token: with open(b_token_path, 'wb') as token_fd: token_fd.write(b"token: %s" % to_bytes(token)) orig_token_path = C.GALAXY_TOKEN_PATH C.GALAXY_TOKEN_PATH = to_text(b_token_path) try: yield b_token_path finally: C.GALAXY_TOKEN_PATH = orig_token_path
def test_tmpdir_property(self, monkeypatch, args, expected, stat_exists): makedirs = {'called': False} def mock_mkdtemp(prefix, dir): return os.path.join(dir, prefix) def mock_makedirs(path, mode): makedirs['called'] = True makedirs['path'] = path makedirs['mode'] = mode return monkeypatch.setattr(tempfile, 'mkdtemp', mock_mkdtemp) monkeypatch.setattr(os.path, 'exists', lambda x: stat_exists) monkeypatch.setattr(os, 'makedirs', mock_makedirs) monkeypatch.setattr(shutil, 'rmtree', lambda x: None) monkeypatch.setattr( basic, '_ASSIBLE_ARGS', to_bytes(json.dumps({'ASSIBLE_MODULE_ARGS': args}))) with patch('time.time', return_value=42): am = basic.AssibleModule(argument_spec={}) actual_tmpdir = am.tmpdir assert actual_tmpdir == expected # verify subsequent calls always produces the same tmpdir assert am.tmpdir == actual_tmpdir if not stat_exists: assert makedirs['called'] expected = os.path.expanduser(os.path.expandvars(am._remote_tmp)) assert makedirs['path'] == expected assert makedirs['mode'] == 0o700
def _parse_config_file(self, cfile=None): ''' return flat configuration settings from file(s) ''' # TODO: take list of files with merge/nomerge if cfile is None: cfile = self._config_file ftype = get_config_type(cfile) if cfile is not None: if ftype == 'ini': self._parsers[cfile] = configparser.ConfigParser() with open(to_bytes(cfile), 'rb') as f: try: cfg_text = to_text(f.read(), errors='surrogate_or_strict') except UnicodeError as e: raise AssibleOptionsError("Error reading config file(%s) because the config file was not utf8 encoded: %s" % (cfile, to_native(e))) try: if PY3: self._parsers[cfile].read_string(cfg_text) else: cfg_file = io.StringIO(cfg_text) self._parsers[cfile].readfp(cfg_file) except configparser.Error as e: raise AssibleOptionsError("Error reading config file (%s): %s" % (cfile, to_native(e))) # FIXME: this should eventually handle yaml config files # elif ftype == 'yaml': # with open(cfile, 'rb') as config_stream: # self._parsers[cfile] = yaml.safe_load(config_stream) else: raise AssibleOptionsError("Unsupported configuration file type: %s" % to_native(ftype))
def run(self, terms, variables=None, **kwargs): ret = [] for term in terms: term_file = os.path.basename(term) found_paths = [] if term_file != term: found_paths.append( self.find_file_in_search_path(variables, 'files', os.path.dirname(term))) else: # no dir, just file, so use paths and 'files' paths instead if 'assible_search_path' in variables: paths = variables['assible_search_path'] else: paths = [self.get_basedir(variables)] for p in paths: found_paths.append(os.path.join(p, 'files')) found_paths.append(p) for dwimmed_path in found_paths: if dwimmed_path: globbed = glob.glob( to_bytes(os.path.join(dwimmed_path, term_file), errors='surrogate_or_strict')) ret.extend( to_text(g, errors='surrogate_or_strict') for g in globbed if os.path.isfile(g)) if ret: break return ret
def ensure_absent(path): b_path = to_bytes(path, errors='surrogate_or_strict') prev_state = get_state(b_path) result = {} if prev_state != 'absent': diff = initial_diff(path, 'absent', prev_state) if not module.check_mode: if prev_state == 'directory': try: shutil.rmtree(b_path, ignore_errors=False) except Exception as e: raise AssibleModuleError(results={'msg': "rmtree failed: %s" % to_native(e)}) else: try: os.unlink(b_path) except OSError as e: if e.errno != errno.ENOENT: # It may already have been removed raise AssibleModuleError(results={'msg': "unlinking failed: %s " % to_native(e), 'path': path}) result.update({'path': path, 'changed': True, 'diff': diff, 'state': 'absent'}) else: result.update({'path': path, 'changed': False, 'state': 'absent'}) return result
def secure_hash_s(data, hash_func=sha1): ''' Return a secure hash hex digest of data. ''' digest = hash_func() data = to_bytes(data, errors='surrogate_or_strict') digest.update(data) return digest.hexdigest()
def update_play_context(self, pc_data): """Updates the play context information for the connection""" pc_data = to_bytes(pc_data) if PY3: pc_data = cPickle.loads(pc_data, encoding="bytes") else: pc_data = cPickle.loads(pc_data) play_context = PlayContext() play_context.deserialize(pc_data) self.queue_message("vvvv", "updating play_context for connection") if self._play_context.become ^ play_context.become: if play_context.become is True: auth_pass = play_context.become_pass self._terminal.on_become(passwd=auth_pass) self.queue_message("vvvv", "authorizing connection") else: self._terminal.on_unbecome() self.queue_message("vvvv", "deauthorizing connection") self._play_context = play_context if hasattr(self, "reset_history"): self.reset_history() if hasattr(self, "disable_response_logging"): self.disable_response_logging()
def initial_diff(path, state, prev_state): diff = {'before': {'path': path}, 'after': {'path': path}, } if prev_state != state: diff['before']['state'] = prev_state diff['after']['state'] = state if state == 'absent' and prev_state == 'directory': walklist = { 'directories': [], 'files': [], } b_path = to_bytes(path, errors='surrogate_or_strict') for base_path, sub_folders, files in os.walk(b_path): for folder in sub_folders: folderpath = os.path.join(base_path, folder) walklist['directories'].append(folderpath) for filename in files: filepath = os.path.join(base_path, filename) walklist['files'].append(filepath) diff['before']['path_content'] = walklist return diff
def verify_file(self, host_list): valid = False b_path = to_bytes(host_list, errors='surrogate_or_strict') if not os.path.exists(b_path) and ',' in host_list: valid = True return valid
def _load_file(self, file_name): if not file_name or not isinstance(file_name, string_types): raise AssibleParserError("Invalid filename: '%s'" % to_native(file_name)) b_file_name = to_bytes(self.loader.path_dwim(file_name)) if not self.loader.path_exists(b_file_name): raise AssibleFileNotFound("Unable to retrieve file contents", file_name=file_name) try: (b_data, private) = self.loader._get_file_contents(file_name) return toml.loads(to_text(b_data, errors='surrogate_or_strict')) except toml.TomlDecodeError as e: raise AssibleParserError( 'TOML file (%s) is invalid: %s' % (file_name, to_native(e)), orig_exc=e ) except (IOError, OSError) as e: raise AssibleParserError( "An error occurred while trying to read the file '%s': %s" % (file_name, to_native(e)), orig_exc=e ) except Exception as e: raise AssibleParserError( "An unexpected error occurred while parsing the file '%s': %s" % (file_name, to_native(e)), orig_exc=e )
def on_become(self, passwd=None): if self._get_prompt().endswith(b"#"): return cmd = {u"command": u"enable"} if passwd: # Note: python-3.5 cannot combine u"" and r"" together. Thus make # an r string and use to_text to ensure it's text on both py2 and py3. cmd[u"prompt"] = to_text(r"[\r\n]?(?:.*)?[Pp]assword: ?$", errors="surrogate_or_strict") cmd[u"answer"] = passwd cmd[u"prompt_retry_check"] = True try: self._exec_cli_command( to_bytes(json.dumps(cmd), errors="surrogate_or_strict")) prompt = self._get_prompt() if prompt is None or not prompt.endswith(b"#"): raise AssibleConnectionFailure( "failed to elevate privilege to enable mode still at prompt [%s]" % prompt) except AssibleConnectionFailure as e: prompt = self._get_prompt() raise AssibleConnectionFailure( "unable to elevate privilege to enable mode, at prompt [%s] with error: %s" % (prompt, e.message))
def check_password_prompt(self, b_output): ''' checks if the expected password prompt exists in b_output ''' if self.prompt: b_prompt = to_bytes(self.prompt).strip() return any(l.strip().startswith(b_prompt) for l in b_output.splitlines()) return False
def generate_assible_template_vars(path, dest_path=None): b_path = to_bytes(path) try: template_uid = pwd.getpwuid(os.stat(b_path).st_uid).pw_name except (KeyError, TypeError): template_uid = os.stat(b_path).st_uid temp_vars = { 'template_host': to_text(os.uname()[1]), 'template_path': path, 'template_mtime': datetime.datetime.fromtimestamp(os.path.getmtime(b_path)), 'template_uid': to_text(template_uid), 'template_fullpath': os.path.abspath(path), 'template_run_date': datetime.datetime.now(), 'template_destpath': to_native(dest_path) if dest_path else None, } managed_default = C.DEFAULT_MANAGED_STR managed_str = managed_default.format( host=temp_vars['template_host'], uid=temp_vars['template_uid'], file=temp_vars['template_path'], ) temp_vars['assible_managed'] = to_text( time.strftime(to_native(managed_str), time.localtime(os.path.getmtime(b_path)))) return temp_vars
def search_roles(self, search, **kwargs): search_url = _urljoin(self.api_server, self.available_api_versions['v1'], "search", "roles", "?") if search: search_url += '&autocomplete=' + to_text(urlquote( to_bytes(search))) tags = kwargs.get('tags', None) platforms = kwargs.get('platforms', None) page_size = kwargs.get('page_size', None) author = kwargs.get('author', None) if tags and isinstance(tags, string_types): tags = tags.split(',') search_url += '&tags_autocomplete=' + '+'.join(tags) if platforms and isinstance(platforms, string_types): platforms = platforms.split(',') search_url += '&platforms_autocomplete=' + '+'.join(platforms) if page_size: search_url += '&page_size=%s' % page_size if author: search_url += '&username_autocomplete=%s' % author data = self._call_galaxy(search_url) return data
def lookup_role_by_name(self, role_name, notify=True): """ Find a role by name. """ role_name = to_text(urlquote(to_bytes(role_name))) try: parts = role_name.split(".") user_name = ".".join(parts[0:-1]) role_name = parts[-1] if notify: display.display("- downloading role '%s', owned by %s" % (role_name, user_name)) except Exception: raise AssibleError( "Invalid role name (%s). Specify role as format: username.rolename" % role_name) url = _urljoin(self.api_server, self.available_api_versions['v1'], "roles", "?owner__username=%s&name=%s" % (user_name, role_name)) data = self._call_galaxy(url) if len(data["results"]) != 0: return data["results"][0] return None
def _get_session(self): if not self.session: self.session = requests.session() self.session.auth = HTTPBasicAuth( self.get_option('user'), to_bytes(self.get_option('password'))) self.session.verify = self.get_option('validate_certs') return self.session
def test_build_requirement_from_path_with_manifest(version, collection_artifact): manifest_path = os.path.join(collection_artifact[0], b'MANIFEST.json') manifest_value = json.dumps({ 'collection_info': { 'namespace': 'namespace', 'name': 'name', 'version': version, 'dependencies': { 'assible_namespace.collection': '*' } } }) with open(manifest_path, 'wb') as manifest_obj: manifest_obj.write(to_bytes(manifest_value)) actual = collection.CollectionRequirement.from_path( collection_artifact[0], True) # While the folder name suggests a different collection, we treat MANIFEST.json as the source of truth. assert actual.namespace == u'namespace' assert actual.name == u'name' assert actual.b_path == collection_artifact[0] assert actual.api is None assert actual.skip is True assert actual.versions == set([to_text(version)]) assert actual.latest_version == to_text(version) assert actual.dependencies == {'assible_namespace.collection': '*'}
def _get_file_contents(self, file_name): ''' Reads the file contents from the given file name If the contents are vault-encrypted, it will decrypt them and return the decrypted data :arg file_name: The name of the file to read. If this is a relative path, it will be expanded relative to the basedir :raises AssibleFileNotFound: if the file_name does not refer to a file :raises AssibleParserError: if we were unable to read the file :return: Returns a byte string of the file contents ''' if not file_name or not isinstance(file_name, (binary_type, text_type)): raise AssibleParserError("Invalid filename: '%s'" % to_native(file_name)) b_file_name = to_bytes(self.path_dwim(file_name)) # This is what we really want but have to fix unittests to make it pass # if not os.path.exists(b_file_name) or not os.path.isfile(b_file_name): if not self.path_exists(b_file_name): raise AssibleFileNotFound("Unable to retrieve file contents", file_name=file_name) try: with open(b_file_name, 'rb') as f: data = f.read() return self._decrypt_if_vault_data(data, b_file_name) except (IOError, OSError) as e: raise AssibleParserError( "an error occurred while trying to read the file '%s': %s" % (file_name, to_native(e)), orig_exc=e)
def subset(self, subset_pattern): """ Limits inventory results to a subset of inventory that matches a given pattern, such as to select a given geographic of numeric slice amongst a previous 'hosts' selection that only select roles, or vice versa. Corresponds to --limit parameter to assible-playbook """ if subset_pattern is None: self._subset = None else: subset_patterns = split_host_pattern(subset_pattern) results = [] # allow Unix style @filename data for x in subset_patterns: if not x: continue if x[0] == "@": b_limit_file = to_bytes(x[1:]) if not os.path.exists(b_limit_file): raise AssibleError(u'Unable to find limit file %s' % b_limit_file) with open(b_limit_file) as fd: results.extend([ to_text(l.strip()) for l in fd.read().split("\n") ]) else: results.append(to_text(x)) self._subset = results
def group_exists(self): # The grp module does not distinguish between local and directory accounts. # It's output cannot be used to determine whether or not a group exists locally. # It returns True if the group exists locally or in the directory, so instead # look in the local GROUP file for an existing account. if self.local: if not os.path.exists(self.GROUPFILE): self.module.fail_json( msg= "'local: true' specified but unable to find local group file {0} to parse." .format(self.GROUPFILE)) exists = False name_test = '{0}:'.format(self.name) with open(self.GROUPFILE, 'rb') as f: reversed_lines = f.readlines()[::-1] for line in reversed_lines: if line.startswith(to_bytes(name_test)): exists = True break if not exists: self.module.warn( "'local: true' specified and group was not found in {file}. " "The local group may already exist if the local group database exists somewhere other than {file}." .format(file=self.GROUPFILE)) return exists else: try: if grp.getgrnam(self.name): return True except KeyError: return False
def _parse_clixml(data, stream="Error"): """ Takes a byte string like '#< CLIXML\r\n<Objs...' and extracts the stream message encoded in the XML data. CLIXML is used by PowerShell to encode multiple objects in stderr. """ lines = [] # There are some scenarios where the stderr contains a nested CLIXML element like # '<# CLIXML\r\n<# CLIXML\r\n<Objs>...</Objs><Objs>...</Objs>'. # Parse each individual <Objs> element and add the error strings to our stderr list. # https://github.com/assible/assible/issues/69550 while data: end_idx = data.find(b"</Objs>") + 7 current_element = data[data.find(b"<Objs "):end_idx] data = data[end_idx:] clixml = ET.fromstring(current_element) namespace_match = re.match(r'{(.*)}', clixml.tag) namespace = "{%s}" % namespace_match.group( 1) if namespace_match else "" strings = clixml.findall("./%sS" % namespace) lines.extend([ e.text.replace('_x000D__x000A_', '') for e in strings if e.attrib.get('S') == stream ]) return to_bytes('\r\n'.join(lines))
def stdin(mocker, request): old_args = assible.module_utils.basic._ASSIBLE_ARGS assible.module_utils.basic._ASSIBLE_ARGS = None old_argv = sys.argv sys.argv = ['assible_unittest'] if isinstance(request.param, string_types): args = request.param elif isinstance(request.param, MutableMapping): if 'ASSIBLE_MODULE_ARGS' not in request.param: request.param = {'ASSIBLE_MODULE_ARGS': request.param} if '_assible_remote_tmp' not in request.param['ASSIBLE_MODULE_ARGS']: request.param['ASSIBLE_MODULE_ARGS']['_assible_remote_tmp'] = '/tmp' if '_assible_keep_remote_files' not in request.param['ASSIBLE_MODULE_ARGS']: request.param['ASSIBLE_MODULE_ARGS']['_assible_keep_remote_files'] = False args = json.dumps(request.param) else: raise Exception('Malformed data to the stdin pytest fixture') fake_stdin = BytesIO(to_bytes(args, errors='surrogate_or_strict')) if PY3: mocker.patch('assible.module_utils.basic.sys.stdin', mocker.MagicMock()) mocker.patch('assible.module_utils.basic.sys.stdin.buffer', fake_stdin) else: mocker.patch('assible.module_utils.basic.sys.stdin', fake_stdin) yield fake_stdin assible.module_utils.basic._ASSIBLE_ARGS = old_args sys.argv = old_argv
def test_set_cwd_unreadable_use_home(self, monkeypatch): '''cwd and instance tmpdir are unreadable, use home''' def mock_getcwd(): return '/tmp' def mock_access(path, perm): if path in ['/tmp', '/tmp2'] and perm == 4: return False return True def mock_expandvars(var): if var == '$HOME': return '/home/foobar' return var def mock_gettempdir(): return '/tmp/testdir' def mock_chdir(path): if path == '/tmp': raise Exception() return monkeypatch.setattr(os, 'getcwd', mock_getcwd) monkeypatch.setattr(os, 'chdir', mock_chdir) monkeypatch.setattr(os, 'access', mock_access) monkeypatch.setattr(os.path, 'expandvars', mock_expandvars) monkeypatch.setattr(basic, '_ASSIBLE_ARGS', to_bytes(json.dumps({'ASSIBLE_MODULE_ARGS': {}}))) with patch('time.time', return_value=42): am = basic.AssibleModule(argument_spec={}) am._tmpdir = '/tmp2' result = am._set_cwd() assert result == '/home/foobar'