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 run(self): """Run the assible command Subclasses must implement this method. It does the actual work of running an Assible command. """ self.parse() display.vv(to_text(opt_help.version(self.parser.prog))) if C.CONFIG_FILE: display.v(u"Using %s as config file" % to_text(C.CONFIG_FILE)) else: display.v(u"No config file found; using defaults") # warn about deprecated config options for deprecated in C.config.DEPRECATED: name = deprecated[0] why = deprecated[1]['why'] if 'alternatives' in deprecated[1]: alt = ', use %s instead' % deprecated[1]['alternatives'] else: alt = '' ver = deprecated[1].get('version') date = deprecated[1].get('date') collection_name = deprecated[1].get('collection_name') display.deprecated("%s option, %s %s" % (name, why, alt), version=ver, date=date, collection_name=collection_name)
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 to_safe_group_name(name, replacer="_", force=False, silent=False): # Converts 'bad' characters in a string to underscores (or provided replacer) so they can be used as Assible hosts or groups warn = '' if name: # when deserializing we might not have name yet invalid_chars = C.INVALID_VARIABLE_NAMES.findall(name) if invalid_chars: msg = 'invalid character(s) "%s" in group name (%s)' % (to_text( set(invalid_chars)), to_text(name)) if C.TRANSFORM_INVALID_GROUP_CHARS not in ('never', 'ignore') or force: name = C.INVALID_VARIABLE_NAMES.sub(replacer, name) if not (silent or C.TRANSFORM_INVALID_GROUP_CHARS == 'silently'): display.vvvv('Replacing ' + msg) warn = 'Invalid characters were found in group names and automatically replaced, use -vvvv to see details' else: if C.TRANSFORM_INVALID_GROUP_CHARS == 'never': display.vvvv('Not replacing %s' % msg) warn = 'Invalid characters were found in group names but not replaced, use -vvvv to see details' if warn: display.warning(warn) return name
def get_defaults_flag(module): connection = get_connection(module) try: out = connection.get_defaults_flag() except ConnectionError as exc: module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) return to_text(out, errors="surrogate_then_replace").strip()
def get_config(module, flags=None): flags = to_list(flags) section_filter = False if flags and "section" in flags[-1]: section_filter = True flag_str = " ".join(flags) try: return _DEVICE_CONFIGS[flag_str] except KeyError: connection = get_connection(module) try: out = connection.get_config(flags=flags) except ConnectionError as exc: if section_filter: # Some ios devices don't understand `| section foo` out = get_config(module, flags=flags[:-1]) else: module.fail_json( msg=to_text(exc, errors="surrogate_then_replace")) cfg = to_text(out, errors="surrogate_then_replace").strip() _DEVICE_CONFIGS[flag_str] = cfg return cfg
def _encode_script(self, script, as_list=False, strict_mode=True, preserve_rc=True): '''Convert a PowerShell script to a single base64-encoded command.''' script = to_text(script) if script == u'-': cmd_parts = _common_args + ['-Command', '-'] else: if strict_mode: script = u'Set-StrictMode -Version Latest\r\n%s' % script # try to propagate exit code if present- won't work with begin/process/end-style scripts (ala put_file) # NB: the exit code returned may be incorrect in the case of a successful command followed by an invalid command if preserve_rc: script = u'%s\r\nIf (-not $?) { If (Get-Variable LASTEXITCODE -ErrorAction SilentlyContinue) { exit $LASTEXITCODE } Else { exit 1 } }\r\n'\ % script script = '\n'.join( [x.strip() for x in script.splitlines() if x.strip()]) encoded_script = to_text( base64.b64encode(script.encode('utf-16-le')), 'utf-8') cmd_parts = _common_args + ['-EncodedCommand', encoded_script] if as_list: return cmd_parts return ' '.join(cmd_parts)
def get_distribution(self, task_vars): # FIXME: only execute the module if we don't already have the facts we need distribution = {} display.debug( '{action}: running setup module to get distribution'.format( action=self._task.action)) module_output = self._execute_module( task_vars=task_vars, module_name='assible.legacy.setup', module_args={'gather_subset': 'min'}) try: if module_output.get('failed', False): raise AssibleError( 'Failed to determine system distribution. {0}, {1}'.format( to_native(module_output['module_stdout']).strip(), to_native(module_output['module_stderr']).strip())) distribution['name'] = module_output['assible_facts'][ 'assible_distribution'].lower() distribution['version'] = to_text( module_output['assible_facts'] ['assible_distribution_version'].split('.')[0]) distribution['family'] = to_text( module_output['assible_facts']['assible_os_family'].lower()) display.debug("{action}: distribution: {dist}".format( action=self._task.action, dist=distribution)) return distribution except KeyError as ke: raise AssibleError( 'Failed to get distribution information. Missing "{0}" in output.' .format(ke.args[0]))
def default(self, o): if getattr(o, '__ENCRYPTED__', False): # vault object if self._vault_to_text: value = to_text(o, errors='surrogate_or_strict') else: value = { '__assible_vault': to_text(o._ciphertext, errors='surrogate_or_strict', nonstring='strict') } elif getattr(o, '__UNSAFE__', False): # unsafe object, this will never be triggered, see ``AssibleJSONEncoder.iterencode`` value = { '__assible_unsafe': to_text(o, errors='surrogate_or_strict', nonstring='strict') } elif isinstance(o, Mapping): # hostvars and other objects value = dict(o) elif isinstance(o, (datetime.date, datetime.datetime)): # date object value = o.isoformat() else: # use default encoder value = super(AssibleJSONEncoder, self).default(o) return value
def __init__(self, message="", obj=None, show_content=True, suppress_extended_error=False, orig_exc=None, paths=None, file_name=None): self.file_name = file_name self.paths = paths if message: message += "\n" if self.file_name: message += "Could not find or access '%s'" % to_text( self.file_name) else: message += "Could not find file" if self.paths and isinstance(self.paths, Sequence): searched = to_text('\n\t'.join(self.paths)) if message: message += "\n" message += "Searched in:\n\t%s" % searched message += " on the Assible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option" super(AssibleFileNotFound, self).__init__(message=message, obj=obj, show_content=show_content, suppress_extended_error=suppress_extended_error, orig_exc=orig_exc)
def _create_zip_tempfile(self, files, directories): tmpdir = tempfile.mkdtemp(dir=C.DEFAULT_LOCAL_TMP) zip_file_path = os.path.join(tmpdir, "win_copy.zip") zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_STORED, True) # encoding the file/dir name with base64 so Windows can unzip a unicode # filename and get the right name, Windows doesn't handle unicode names # very well for directory in directories: directory_path = to_bytes(directory['src'], errors='surrogate_or_strict') archive_path = to_bytes(directory['dest'], errors='surrogate_or_strict') encoded_path = to_text(base64.b64encode(archive_path), errors='surrogate_or_strict') zip_file.write(directory_path, encoded_path, zipfile.ZIP_DEFLATED) for file in files: file_path = to_bytes(file['src'], errors='surrogate_or_strict') archive_path = to_bytes(file['dest'], errors='surrogate_or_strict') encoded_path = to_text(base64.b64encode(archive_path), errors='surrogate_or_strict') zip_file.write(file_path, encoded_path, zipfile.ZIP_DEFLATED) return zip_file_path
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 send_callback(self, method_name, *args, **kwargs): for callback_plugin in [self._stdout_callback ] + self._callback_plugins: # a plugin that set self.disabled to True will not be called # see osx_say.py example for such a plugin if getattr(callback_plugin, 'disabled', False): continue # a plugin can opt in to implicit tasks (such as meta). It does this # by declaring self.wants_implicit_tasks = True. wants_implicit_tasks = getattr(callback_plugin, 'wants_implicit_tasks', False) # try to find v2 method, fallback to v1 method, ignore callback if no method found methods = [] for possible in [method_name, 'v2_on_any']: gotit = getattr(callback_plugin, possible, None) if gotit is None: gotit = getattr(callback_plugin, possible.replace('v2_', ''), None) if gotit is not None: methods.append(gotit) # send clean copies new_args = [] # If we end up being given an implicit task, we'll set this flag in # the loop below. If the plugin doesn't care about those, then we # check and continue to the next iteration of the outer loop. is_implicit_task = False for arg in args: # FIXME: add play/task cleaners if isinstance(arg, TaskResult): new_args.append(arg.clean_copy()) # elif isinstance(arg, Play): # elif isinstance(arg, Task): else: new_args.append(arg) if isinstance(arg, Task) and arg.implicit: is_implicit_task = True if is_implicit_task and not wants_implicit_tasks: continue for method in methods: try: method(*new_args, **kwargs) except Exception as e: # TODO: add config toggle to make this fatal or not? display.warning( u"Failure using method (%s) in callback plugin (%s): %s" % (to_text(method_name), to_text(callback_plugin), to_text(e))) from traceback import format_tb from sys import exc_info display.vvv('Callback Exception: \n' + ' '.join(format_tb(exc_info()[2])))
def has_changed(self, want_dict, current_dict, only_keys=None, skip_diff_for_keys=None): result = False for key, value in want_dict.items(): # Optionally limit by a list of keys if only_keys and key not in only_keys: continue # Skip None values if value is None: continue if key in current_dict: if isinstance(value, (int, float, long, complex)): # ensure we compare the same type if isinstance(value, int): current_dict[key] = int(current_dict[key]) elif isinstance(value, float): current_dict[key] = float(current_dict[key]) elif isinstance(value, long): current_dict[key] = long(current_dict[key]) elif isinstance(value, complex): current_dict[key] = complex(current_dict[key]) if value != current_dict[key]: if skip_diff_for_keys and key not in skip_diff_for_keys: self.result['diff']['before'][key] = current_dict[ key] self.result['diff']['after'][key] = value result = True else: before_value = to_text(current_dict[key]) after_value = to_text(value) if self.case_sensitive_keys and key in self.case_sensitive_keys: if before_value != after_value: if skip_diff_for_keys and key not in skip_diff_for_keys: self.result['diff']['before'][ key] = before_value self.result['diff']['after'][key] = after_value result = True # Test for diff in case insensitive way elif before_value.lower() != after_value.lower(): if skip_diff_for_keys and key not in skip_diff_for_keys: self.result['diff']['before'][key] = before_value self.result['diff']['after'][key] = after_value result = True else: if skip_diff_for_keys and key not in skip_diff_for_keys: self.result['diff']['before'][key] = None self.result['diff']['after'][key] = to_text(value) result = True return result
def _encode_token(username, password): token = "%s:%s" % (to_text(username, errors='surrogate_or_strict'), to_text(password, errors='surrogate_or_strict', nonstring='passthru') or '') b64_val = base64.b64encode( to_bytes(token, encoding='utf-8', errors='surrogate_or_strict')) return to_text(b64_val)
def ensure_subnet_present(conn, module): subnet = get_matching_subnet(conn, module, module.params['vpc_id'], module.params['cidr']) changed = False # Initialize start so max time does not exceed the specified wait_timeout for multiple operations start_time = time.time() if subnet is None: if not module.check_mode: subnet = create_subnet(conn, module, module.params['vpc_id'], module.params['cidr'], ipv6_cidr=module.params['ipv6_cidr'], az=module.params['az'], start_time=start_time) changed = True # Subnet will be None when check_mode is true if subnet is None: return {'changed': changed, 'subnet': {}} if module.params['wait']: handle_waiter(conn, module, 'subnet_exists', {'SubnetIds': [subnet['id']]}, start_time) if module.params['ipv6_cidr'] != subnet.get('ipv6_cidr_block'): if ensure_ipv6_cidr_block(conn, module, subnet, module.params['ipv6_cidr'], module.check_mode, start_time): changed = True if module.params['map_public'] != subnet['map_public_ip_on_launch']: ensure_map_public(conn, module, subnet, module.params['map_public'], module.check_mode, start_time) changed = True if module.params['assign_instances_ipv6'] != subnet.get( 'assign_ipv6_address_on_creation'): ensure_assign_ipv6_on_create(conn, module, subnet, module.params['assign_instances_ipv6'], module.check_mode, start_time) changed = True if module.params['tags'] != subnet['tags']: stringified_tags_dict = dict( (to_text(k), to_text(v)) for k, v in module.params['tags'].items()) if ensure_tags(conn, module, subnet, stringified_tags_dict, module.params['purge_tags'], start_time): changed = True subnet = get_matching_subnet(conn, module, module.params['vpc_id'], module.params['cidr']) if not module.check_mode and module.params['wait']: # GET calls are not monotonic for map_public_ip_on_launch and assign_ipv6_address_on_creation # so we only wait for those if necessary just before returning the subnet subnet = ensure_final_subnet(conn, module, subnet, start_time) return {'changed': changed, 'subnet': subnet}
def response(self, result=None): response = self.header() if isinstance(result, binary_type): result = to_text(result) if not isinstance(result, text_type): response["result_type"] = "pickle" result = to_text(cPickle.dumps(result, protocol=0)) response['result'] = result return response
def run(self, tmp=None, task_vars=None): if task_vars is None: task_vars = dict() if 'msg' in self._task.args and 'var' in self._task.args: return { "failed": True, "msg": "'msg' and 'var' are incompatible options" } result = super(ActionModule, self).run(tmp, task_vars) del tmp # tmp no longer has any effect # get task verbosity verbosity = int(self._task.args.get('verbosity', 0)) if verbosity <= self._display.verbosity: if 'msg' in self._task.args: result['msg'] = self._task.args['msg'] elif 'var' in self._task.args: try: results = self._templar.template(self._task.args['var'], convert_bare=True, fail_on_undefined=True) if results == self._task.args['var']: # if results is not str/unicode type, raise an exception if not isinstance(results, string_types): raise AssibleUndefinedVariable # If var name is same as result, try to template it results = self._templar.template( "{{" + results + "}}", convert_bare=True, fail_on_undefined=True) except AssibleUndefinedVariable as e: results = u"VARIABLE IS NOT DEFINED!" if self._display.verbosity > 0: results += u": %s" % to_text(e) if isinstance(self._task.args['var'], (list, dict)): # If var is a list or dict, use the type as key to display result[to_text(type(self._task.args['var']))] = results else: result[self._task.args['var']] = results else: result['msg'] = 'Hello world!' # force flag to make debug output module always verbose result['_assible_verbose_always'] = True else: result['skipped_reason'] = "Verbosity threshold not met." result['skipped'] = True result['failed'] = False return result
def test_install_collection_with_download(galaxy_server, collection_artifact, monkeypatch): collection_tar = collection_artifact[1] output_path = os.path.join(os.path.split(collection_tar)[0], b'output') collection_path = os.path.join(output_path, b'assible_namespace', b'collection') mock_display = MagicMock() monkeypatch.setattr(Display, 'display', mock_display) mock_download = MagicMock() mock_download.return_value = collection_tar monkeypatch.setattr(collection, '_download_file', mock_download) monkeypatch.setattr(galaxy_server, '_available_api_versions', {'v2': 'v2/'}) temp_path = os.path.join(os.path.split(collection_tar)[0], b'temp') os.makedirs(temp_path) meta = api.CollectionVersionMetadata('assible_namespace', 'collection', '0.1.0', 'https://downloadme.com', 'myhash', {}) req = collection.CollectionRequirement('assible_namespace', 'collection', None, galaxy_server, ['0.1.0'], '*', False, metadata=meta) req.install(to_text(output_path), temp_path) # Ensure the temp directory is empty, nothing is left behind assert os.listdir(temp_path) == [] actual_files = os.listdir(collection_path) actual_files.sort() assert actual_files == [ b'FILES.json', b'MANIFEST.json', b'README.md', b'docs', b'playbooks', b'plugins', b'roles', b'runme.sh' ] assert mock_display.call_count == 2 assert mock_display.mock_calls[0][1][0] == "Installing 'assible_namespace.collection:0.1.0' to '%s'" \ % to_text(collection_path) assert mock_display.mock_calls[1][1][ 0] == "assible_namespace.collection (0.1.0) was installed successfully" assert mock_download.call_count == 1 assert mock_download.mock_calls[0][1][0] == 'https://downloadme.com' assert mock_download.mock_calls[0][1][1] == temp_path assert mock_download.mock_calls[0][1][2] == 'myhash' assert mock_download.mock_calls[0][1][3] is True
def handle_request(self, request): request = json.loads(to_text(request, errors='surrogate_then_replace')) method = request.get('method') if method.startswith('rpc.') or method.startswith('_'): error = self.invalid_request() return json.dumps(error) args, kwargs = request.get('params') setattr(self, '_identifier', request.get('id')) rpc_method = None for obj in self._objects: rpc_method = getattr(obj, method, None) if rpc_method: break if not rpc_method: error = self.method_not_found() response = json.dumps(error) else: try: result = rpc_method(*args, **kwargs) except ConnectionError as exc: display.vvv(traceback.format_exc()) try: error = self.error(code=exc.code, message=to_text(exc)) except AttributeError: error = self.internal_error(data=to_text(exc)) response = json.dumps(error) except Exception as exc: display.vvv(traceback.format_exc()) error = self.internal_error(data=to_text(exc, errors='surrogate_then_replace')) response = json.dumps(error) else: if isinstance(result, dict) and 'jsonrpc' in result: response = result else: response = self.response(result) try: response = json.dumps(response) except Exception as exc: display.vvv(traceback.format_exc()) error = self.internal_error(data=to_text(exc, errors='surrogate_then_replace')) response = json.dumps(error) delattr(self, '_identifier') return response
def do_until_success_or_timeout(self, action, reboot_timeout, action_desc, distribution, action_kwargs=None): max_end_time = datetime.utcnow() + timedelta(seconds=reboot_timeout) if action_kwargs is None: action_kwargs = {} fail_count = 0 max_fail_sleep = 12 while datetime.utcnow() < max_end_time: try: action(distribution=distribution, **action_kwargs) if action_desc: display.debug('{action}: {desc} success'.format( action=self._task.action, desc=action_desc)) return except Exception as e: if isinstance(e, AssibleConnectionFailure): try: self._connection.reset() except AssibleConnectionFailure: pass # Use exponential backoff with a max timout, plus a little bit of randomness random_int = random.randint(0, 1000) / 1000 fail_sleep = 2**fail_count + random_int if fail_sleep > max_fail_sleep: fail_sleep = max_fail_sleep + random_int if action_desc: try: error = to_text(e).splitlines()[-1] except IndexError as e: error = to_text(e) display.debug( "{action}: {desc} fail '{err}', retrying in {sleep:.4} seconds..." .format(action=self._task.action, desc=action_desc, err=error, sleep=fail_sleep)) fail_count += 1 time.sleep(fail_sleep) raise TimedOutException( 'Timed out waiting for {desc} (timeout={timeout})'.format( desc=action_desc, timeout=reboot_timeout))
def get_config(module, flags=None, format=None): flags = [] if flags is None else flags global _DEVICE_CONFIGS if _DEVICE_CONFIGS != {}: return _DEVICE_CONFIGS else: connection = get_connection(module) try: out = connection.get_config(flags=flags, format=format) except ConnectionError as exc: module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) cfg = to_text(out, errors="surrogate_then_replace").strip() _DEVICE_CONFIGS = cfg return cfg
def path_dwim(self, given): ''' make relative paths work like folks expect. ''' given = unquote(given) given = to_text(given, errors='surrogate_or_strict') if given.startswith(to_text(os.path.sep)) or given.startswith(u'~'): path = given else: basedir = to_text(self._basedir, errors='surrogate_or_strict') path = os.path.join(basedir, given) return unfrackpath(path, follow=False)
def _gen_candidate_chars(characters): '''Generate a string containing all valid chars as defined by ``characters`` :arg characters: A list of character specs. The character specs are shorthand names for sets of characters like 'digits', 'ascii_letters', or 'punctuation' or a string to be included verbatim. The values of each char spec can be: * a name of an attribute in the 'strings' module ('digits' for example). The value of the attribute will be added to the candidate chars. * a string of characters. If the string isn't an attribute in 'string' module, the string will be directly added to the candidate chars. For example:: characters=['digits', '?|']`` will match ``string.digits`` and add all ascii digits. ``'?|'`` will add the question mark and pipe characters directly. Return will be the string:: u'0123456789?|' ''' chars = [] for chars_spec in characters: # getattr from string expands things like "ascii_letters" and "digits" # into a set of characters. chars.append( to_text(getattr(string, to_native(chars_spec), chars_spec), errors='strict')) chars = u''.join(chars).replace(u'"', u'').replace(u"'", u'') return chars
def get_memory_facts(self): memory_facts = {} # Get free memory. vmstat output looks like: # procs memory page disks traps cpu # r b w avm fre flt re pi po fr sr wd0 fd0 int sys cs us sy id # 0 0 0 47512 28160 51 0 0 0 0 0 1 0 116 89 17 0 1 99 rc, out, err = self.module.run_command("/usr/bin/vmstat") if rc == 0: memory_facts['memfree_mb'] = int( out.splitlines()[-1].split()[4]) // 1024 memory_facts['memtotal_mb'] = int( self.sysctl['hw.usermem']) // 1024 // 1024 # Get swapctl info. swapctl output looks like: # total: 69268 1K-blocks allocated, 0 used, 69268 available # And for older OpenBSD: # total: 69268k bytes allocated = 0k used, 69268k available rc, out, err = self.module.run_command("/sbin/swapctl -sk") if rc == 0: swaptrans = {ord(u'k'): None, ord(u'm'): None, ord(u'g'): None} data = to_text(out, errors='surrogate_or_strict').split() memory_facts['swapfree_mb'] = int( data[-2].translate(swaptrans)) // 1024 memory_facts['swaptotal_mb'] = int( data[1].translate(swaptrans)) // 1024 return memory_facts
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 _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 _loop_entries(self, container, entry_list): ''' repeat code for value entry assignment ''' value = None origin = None for entry in entry_list: name = entry.get('name') try: temp_value = container.get(name, None) except UnicodeEncodeError: self.WARNINGS.add(u'value for config entry {0} contains invalid characters, ignoring...'.format(to_text(name))) continue if temp_value is not None: # only set if entry is defined in container # inline vault variables should be converted to a text string if isinstance(temp_value, AssibleVaultEncryptedUnicode): temp_value = to_text(temp_value, errors='surrogate_or_strict') value = temp_value origin = name # deal with deprecation of setting source, if used if 'deprecated' in entry: self.DEPRECATED.append((entry['name'], entry['deprecated'])) return value, origin
def __init__(self, loader=None, inventory=None, version_info=None): self._nonpersistent_fact_cache = defaultdict(dict) self._vars_cache = defaultdict(dict) self._extra_vars = defaultdict(dict) self._host_vars_files = defaultdict(dict) self._group_vars_files = defaultdict(dict) self._inventory = inventory self._loader = loader self._hostvars = None self._omit_token = '__omit_place_holder__%s' % sha1( os.urandom(64)).hexdigest() self._options_vars = load_options_vars(version_info) # If the basedir is specified as the empty string then it results in cwd being used. # This is not a safe location to load vars from. basedir = self._options_vars.get('basedir', False) self.safe_basedir = bool(basedir is False or basedir) # load extra vars self._extra_vars = load_extra_vars(loader=self._loader) # load fact cache try: self._fact_cache = FactCache() except AssibleError as e: # bad cache plugin is not fatal error # fallback to a dict as in memory cache display.warning(to_text(e)) self._fact_cache = {}
def parse_kv(args, check_raw=False): ''' Convert a string of key/value items to a dict. If any free-form params are found and the check_raw option is set to True, they will be added to a new parameter called '_raw_params'. If check_raw is not enabled, they will simply be ignored. ''' args = to_text(args, nonstring='passthru') options = {} if args is not None: try: vargs = split_args(args) except IndexError as e: raise AssibleParserError("Unable to parse argument string", orig_exc=e) except ValueError as ve: if 'no closing quotation' in str(ve).lower(): raise AssibleParserError( "error parsing argument string, try quoting the entire line.", orig_exc=ve) else: raise raw_params = [] for orig_x in vargs: x = _decode_escapes(orig_x) if "=" in x: pos = 0 try: while True: pos = x.index('=', pos + 1) if pos > 0 and x[pos - 1] != '\\': break except ValueError: # ran out of string, but we must have some escaped equals, # so replace those and append this to the list of raw params raw_params.append(x.replace('\\=', '=')) continue k = x[:pos] v = x[pos + 1:] # FIXME: make the retrieval of this list of shell/command # options a function, so the list is centralized if check_raw and k not in ('creates', 'removes', 'chdir', 'executable', 'warn'): raw_params.append(orig_x) else: options[k.strip()] = unquote(v.strip()) else: raw_params.append(orig_x) # recombine the free-form params, if any were found, and assign # them to a special option for use later by the shell/command module if len(raw_params) > 0: options[u'_raw_params'] = join_args(raw_params) return options