def _get_instances_by_region(self, regions, filters, strict_permissions): ''' :param regions: a list of regions in which to describe instances :param filters: a list of boto3 filter dictionaries :param strict_permissions: a boolean determining whether to fail or ignore 403 error codes :return A list of instance dictionaries ''' all_instances = [] for connection, region in self._boto3_conn(regions): try: # By default find non-terminated/terminating instances if not any([f['Name'] == 'instance-state-name' for f in filters]): filters.append({'Name': 'instance-state-name', 'Values': ['running', 'pending', 'stopping', 'stopped']}) paginator = connection.get_paginator('describe_instances') reservations = paginator.paginate(Filters=filters).build_full_result().get('Reservations') instances = [] for r in reservations: new_instances = r['Instances'] for instance in new_instances: instance.update(self._get_reservation_details(r)) if self.get_option('include_extra_api_calls'): instance.update(self._get_event_set_and_persistence(connection, instance['InstanceId'], instance.get('SpotInstanceRequestId'))) instances.extend(new_instances) except botocore.exceptions.ClientError as e: if e.response['ResponseMetadata']['HTTPStatusCode'] == 403 and not strict_permissions: instances = [] else: raise AssibleError("Failed to describe instances: %s" % to_native(e)) except botocore.exceptions.BotoCoreError as e: raise AssibleError("Failed to describe instances: %s" % to_native(e)) all_instances.extend(instances) return sorted(all_instances, key=lambda x: x['InstanceId'])
def _load_files(self, filename, validate_extensions=False): """ Loads a file and converts the output into a valid Python dict. Args: filename (str): The source file. Returns: Tuple (bool, str, dict) """ results = dict() failed = False err_msg = '' if validate_extensions and not self._is_valid_file_ext(filename): failed = True err_msg = ('{0} does not have a valid extension: {1}'.format( to_native(filename), ', '.join(self.valid_extensions))) else: b_data, show_content = self._loader._get_file_contents(filename) data = to_text(b_data, errors='surrogate_or_strict') self.show_content = show_content data = self._loader.load(data, file_name=filename, show_content=show_content) if not data: data = dict() if not isinstance(data, dict): failed = True err_msg = ('{0} must be stored as a dictionary/hash'.format( to_native(filename))) else: self.included_files.append(filename) results.update(data) return failed, err_msg, results
def makedirs_safe(path, mode=None): ''' A *potentially insecure* way to ensure the existence of a directory chain. The "safe" in this function's name refers only to its ability to ignore `EEXIST` in the case of multiple callers operating on the same part of the directory chain. This function is not safe to use under world-writable locations when the first level of the path to be created contains a predictable component. Always create a randomly-named element first if there is any chance the parent directory might be world-writable (eg, /tmp) to prevent symlink hijacking and potential disclosure or modification of sensitive file contents. :arg path: A byte or text string representing a directory chain to be created :kwarg mode: If given, the mode to set the directory to :raises AssibleError: If the directory cannot be created and does not already exist. :raises UnicodeDecodeError: if the path is not decodable in the utf-8 encoding. ''' rpath = unfrackpath(path) b_rpath = to_bytes(rpath) if not os.path.exists(b_rpath): try: if mode: os.makedirs(b_rpath, mode) else: os.makedirs(b_rpath) except OSError as e: if e.errno != EEXIST: raise AssibleError( "Unable to create local directories(%s): %s" % (to_native(rpath), to_native(e)))
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 _read_config_vars(self, name, **kwargs): """ Read configuration from variables passed to the module. """ config = {} entrust_api_specification_path = kwargs.get("entrust_api_specification_path") if not entrust_api_specification_path or (not entrust_api_specification_path.startswith("http") and not os.path.isfile(entrust_api_specification_path)): raise SessionConfigurationException( to_native( "Parameter provided for entrust_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format( entrust_api_specification_path ) ) ) for required_file in ["entrust_api_cert", "entrust_api_cert_key"]: file_path = kwargs.get(required_file) if not file_path or not os.path.isfile(file_path): raise SessionConfigurationException( to_native("Parameter provided for {0} of value '{1}' was not a valid file path.".format(required_file, file_path)) ) for required_var in ["entrust_api_user", "entrust_api_key"]: if not kwargs.get(required_var): raise SessionConfigurationException(to_native("Parameter provided for {0} was missing.".format(required_var))) config["entrust_api_cert"] = kwargs.get("entrust_api_cert") config["entrust_api_cert_key"] = kwargs.get("entrust_api_cert_key") config["entrust_api_specification_path"] = kwargs.get("entrust_api_specification_path") config["entrust_api_user"] = kwargs.get("entrust_api_user") config["entrust_api_key"] = kwargs.get("entrust_api_key") return config
def get_versioned_doclink(path): """ returns a versioned documentation link for the current Assible major.minor version; used to generate in-product warning/error links to the configured DOCSITE_ROOT_URL (eg, https://docs.assible.com/assible/2.8/somepath/doc.html) :param path: relative path to a document under docs/docsite/rst; :return: absolute URL to the specified doc for the current version of Assible """ path = to_native(path) try: base_url = C.config.get_config_value('DOCSITE_ROOT_URL') if not base_url.endswith('/'): base_url += '/' if path.startswith('/'): path = path[1:] split_ver = assible_version.split('.') if len(split_ver) < 3: raise RuntimeError('invalid version ({0})'.format(assible_version)) doc_version = '{0}.{1}'.format(split_ver[0], split_ver[1]) # check to see if it's a X.Y.0 non-rc prerelease or dev release, if so, assume devel (since the X.Y doctree # isn't published until beta-ish) if split_ver[2].startswith('0'): # exclude rc; we should have the X.Y doctree live by rc1 if any((pre in split_ver[2]) for pre in ['a', 'b']) or len(split_ver) > 3 and 'dev' in split_ver[3]: doc_version = 'devel' return '{0}{1}/{2}'.format(base_url, doc_version, path) except Exception as ex: return '(unable to create versioned doc link for path {0}: {1})'.format( path, to_native(ex))
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 fail_json_aws(self, exception, msg=None): """call fail_json with processed exception function for converting exceptions thrown by AWS SDK modules, botocore, boto3 and boto, into nice error messages. """ last_traceback = traceback.format_exc() # to_native is trusted to handle exceptions that str() could # convert to text. try: except_msg = to_native(exception.message) except AttributeError: except_msg = to_native(exception) if msg is not None: message = '{0}: {1}'.format(msg, except_msg) else: message = except_msg try: response = exception.response except AttributeError: response = None failure = dict(msg=message, exception=last_traceback, **self._gather_versions()) if response is not None: failure.update(**camel_dict_to_snake_dict(response)) self.fail_json(**failure)
def get_cache(module): '''Attempt to get the cache object and update till it works''' cache = None try: cache = apt.Cache() except SystemError as e: if '/var/lib/apt/lists/' in to_native(e).lower(): # update cache until files are fixed or retries exceeded retries = 0 while retries < 2: (rc, so, se) = module.run_command(['apt-get', 'update', '-q']) retries += 1 if rc == 0: break if rc != 0: module.fail_json( msg= 'Updating the cache to correct corrupt package lists failed:\n%s\n%s' % (to_native(e), so + se), rc=rc) # try again cache = apt.Cache() else: module.fail_json(msg=to_native(e)) return cache
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 get_system_boot_time(self, distribution): boot_time_command = self._get_value_from_facts( 'BOOT_TIME_COMMANDS', distribution, 'DEFAULT_BOOT_TIME_COMMAND') if self._task.args.get('boot_time_command'): boot_time_command = self._task.args.get('boot_time_command') try: check_type_str(boot_time_command, allow_conversion=False) except TypeError as e: raise AssibleError( "Invalid value given for 'boot_time_command': %s." % to_native(e)) display.debug( "{action}: getting boot time with command: '{command}'".format( action=self._task.action, command=boot_time_command)) command_result = self._low_level_execute_command( boot_time_command, sudoable=self.DEFAULT_SUDOABLE) if command_result['rc'] != 0: stdout = command_result['stdout'] stderr = command_result['stderr'] raise AssibleError( "{action}: failed to get host boot time info, rc: {rc}, stdout: {out}, stderr: {err}" .format(action=self._task.action, rc=command_result['rc'], out=to_native(stdout), err=to_native(stderr))) display.debug("{action}: last boot time: {boot}".format( action=self._task.action, boot=command_result['stdout'].strip())) return command_result['stdout'].strip()
def __init__(self, message="", obj=None, show_content=True, suppress_extended_error=False, orig_exc=None): super(AssibleError, self).__init__(message) # we import this here to prevent an import loop problem, # since the objects code also imports assible.errors from assible.parsing.yaml.objects import AssibleBaseYAMLObject self._obj = obj self._show_content = show_content if obj and isinstance(obj, AssibleBaseYAMLObject): extended_error = self._get_extended_error() if extended_error and not suppress_extended_error: self.message = '%s\n\n%s' % (to_native(message), to_native(extended_error)) else: self.message = '%s' % to_native(message) else: self.message = '%s' % to_native(message) if orig_exc: self.orig_exc = orig_exc
def get_permanent_hostname(self): name = 'UNKNOWN' if not os.path.isfile(self.HOSTNAME_FILE): try: open(self.HOSTNAME_FILE, "a").write("hostname=temporarystub\n") except IOError as e: self.module.fail_json(msg="failed to write file: %s" % to_native(e), exception=traceback.format_exc()) try: try: f = open(self.HOSTNAME_FILE, 'r') for line in f: line = line.strip() if line.startswith('hostname='): name = line[10:].strip('"') break except Exception as e: self.module.fail_json(msg="failed to read hostname: %s" % to_native(e), exception=traceback.format_exc()) finally: f.close() return name
def run_test_command(self, distribution, **kwargs): test_command = self._task.args.get( 'test_command', self._get_value_from_facts('TEST_COMMANDS', distribution, 'DEFAULT_TEST_COMMAND')) display.vvv("{action}: attempting post-reboot test command".format( action=self._task.action)) display.debug( "{action}: attempting post-reboot test command '{command}'".format( action=self._task.action, command=test_command)) try: command_result = self._low_level_execute_command( test_command, sudoable=self.DEFAULT_SUDOABLE) except Exception: # may need to reset the connection in case another reboot occurred # which has invalidated our connection try: self._connection.reset() except AttributeError: pass raise if command_result['rc'] != 0: msg = 'Test command failed: {err} {out}'.format( err=to_native(command_result['stderr']), out=to_native(command_result['stdout'])) raise RuntimeError(msg) display.vvv("{action}: system successfully rebooted".format( action=self._task.action))
def get_aws_account_id(module): """ Given AssibleAWSModule instance, get the active AWS account ID get_account_id tries too find out the account that we are working on. It's not guaranteed that this will be easy so we try in several different ways. Giving either IAM or STS privilages to the account should be enough to permit this. """ account_id = None try: sts_client = module.client('sts') account_id = sts_client.get_caller_identity().get('Account') # non-STS sessions may also get NoCredentialsError from this STS call, so # we must catch that too and try the IAM version except (ClientError, NoCredentialsError): try: iam_client = module.client('iam') account_id = iam_client.get_user()['User']['Arn'].split(':')[4] except ClientError as e: if (e.response['Error']['Code'] == 'AccessDenied'): except_msg = to_native(e) # don't match on `arn:aws` because of China region `arn:aws-cn` and similar account_id = except_msg.search(r"arn:\w+:iam::([0-9]{12,32}):\w+/").group(1) if account_id is None: module.fail_json_aws(e, msg="Could not get AWS account information") except Exception as e: module.fail_json( msg="Failed to get AWS account information, Try allowing sts:GetCallerIdentity or iam:GetUser permissions.", exception=traceback.format_exc() ) if not account_id: module.fail_json(msg="Failed while determining AWS account ID. Try allowing sts:GetCallerIdentity or iam:GetUser permissions.") return to_native(account_id)
def __getitem__(self, varname): if varname not in self._templar.available_variables: if varname in self._locals: return self._locals[varname] for i in self._extras: if varname in i: return i[varname] if varname in self._globals: return self._globals[varname] else: raise KeyError("undefined variable: %s" % varname) variable = self._templar.available_variables[varname] # HostVars is special, return it as-is, as is the special variable # 'vars', which contains the vars structure from assible.vars.hostvars import HostVars if isinstance(variable, dict) and varname == "vars" or isinstance( variable, HostVars) or hasattr(variable, '__UNSAFE__'): return variable else: value = None try: value = self._templar.template(variable) except AssibleUndefinedVariable as e: raise AssibleUndefinedVariable( "%s: %s" % (to_native(variable), e.message)) except Exception as e: msg = getattr(e, 'message', None) or to_native(e) raise AssibleError( "An unhandled exception occurred while templating '%s'. " "Error was a %s, original message: %s" % (to_native(variable), type(e), msg)) return value
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 connect_to_db(module, conn_params, autocommit=False, fail_on_conn=True): """Connect to a PostgreSQL database. Return psycopg2 connection object. Args: module (AssibleModule) -- object of assible.module_utils.basic.AssibleModule class conn_params (dict) -- dictionary with connection parameters Kwargs: autocommit (bool) -- commit automatically (default False) fail_on_conn (bool) -- fail if connection failed or just warn and return None (default True) """ ensure_required_libs(module) db_connection = None try: db_connection = psycopg2.connect(**conn_params) if autocommit: if LooseVersion(psycopg2.__version__) >= LooseVersion('2.4.2'): db_connection.set_session(autocommit=True) else: db_connection.set_isolation_level( psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) # Switch role, if specified: if module.params.get('session_role'): cursor = db_connection.cursor( cursor_factory=psycopg2.extras.DictCursor) try: cursor.execute('SET ROLE "%s"' % module.params['session_role']) except Exception as e: module.fail_json(msg="Could not switch role: %s" % to_native(e)) finally: cursor.close() except TypeError as e: if 'sslrootcert' in e.args[0]: module.fail_json(msg='Postgresql server must be at least ' 'version 8.4 to support sslrootcert') if fail_on_conn: module.fail_json(msg="unable to connect to database: %s" % to_native(e)) else: module.warn("PostgreSQL server is unavailable: %s" % to_native(e)) db_connection = None except Exception as e: if fail_on_conn: module.fail_json(msg="unable to connect to database: %s" % to_native(e)) else: module.warn("PostgreSQL server is unavailable: %s" % to_native(e)) db_connection = None return db_connection
def publish_collection(self, collection_path): """ Publishes a collection to a Galaxy server and returns the import task URI. :param collection_path: The path to the collection tarball to publish. :return: The import task URI that contains the import results. """ display.display("Publishing collection artifact '%s' to %s %s" % (collection_path, self.name, self.api_server)) b_collection_path = to_bytes(collection_path, errors='surrogate_or_strict') if not os.path.exists(b_collection_path): raise AssibleError( "The collection path specified '%s' does not exist." % to_native(collection_path)) elif not tarfile.is_tarfile(b_collection_path): raise AssibleError( "The collection path specified '%s' is not a tarball, use 'assible-galaxy collection " "build' to create a proper release artifact." % to_native(collection_path)) with open(b_collection_path, 'rb') as collection_tar: sha256 = secure_hash_s(collection_tar.read(), hash_func=hashlib.sha256) content_type, b_form_data = prepare_multipart({ 'sha256': sha256, 'file': { 'filename': b_collection_path, 'mime_type': 'application/octet-stream', }, }) headers = { 'Content-type': content_type, 'Content-length': len(b_form_data), } if 'v3' in self.available_api_versions: n_url = _urljoin(self.api_server, self.available_api_versions['v3'], 'artifacts', 'collections') + '/' else: n_url = _urljoin(self.api_server, self.available_api_versions['v2'], 'collections') + '/' resp = self._call_galaxy( n_url, args=b_form_data, headers=headers, method='POST', auth_required=True, error_context_msg='Error when publishing collection to %s (%s)' % (self.name, self.api_server)) return resp['task']
def hash_host_key(host, key): hmac_key = os.urandom(20) hashed_host = hmac.new(hmac_key, to_bytes(host), hashlib.sha1).digest() parts = key.strip().split() # @ indicates the optional marker field used for @cert-authority or @revoked i = 1 if parts[0][0] == '@' else 0 parts[i] = '|1|%s|%s' % (to_native( base64.b64encode(hmac_key)), to_native(base64.b64encode(hashed_host))) return ' '.join(parts)
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 removed_module( removed_in, msg='This module has been removed. The module documentation for' ' Assible-%(version)s may contain hints for porting'): """ This function is deprecated and should not be used. Instead the module should just be actually removed. This function is scheduled for removal for the 2.12 release. Returns module failure along with a message about the module being removed :arg removed_in: The version that the module was removed in :kwarg msg: Message to use in the module's failure message. The default says that the module has been removed and what version of the Assible documentation to search for porting help. Remove the actual code and instead have boilerplate like this:: from assible.module_utils.common.removed import removed_module if __name__ == '__main__': removed_module("2.4") """ results = { 'failed': True, 'deprecations': [ { 'msg': 'The removed_module function is deprecated', 'version': '2.12', }, ] } # Convert numbers into strings removed_in = to_native(removed_in) version = removed_in.split('.') try: numeric_minor = int(version[-1]) except Exception: last_version = None else: version = version[:-1] version.append(to_native(numeric_minor - 1)) last_version = '.'.join(version) if last_version is None: results['warnings'] = [ 'removed modules should specify the version they were removed in' ] results['msg'] = 'This module has been removed' else: results['msg'] = msg % {'version': last_version} print('\n{0}\n'.format(json.dumps(results))) sys.exit(1)
def boto3_conn(module, conn_type=None, resource=None, region=None, endpoint=None, **params): try: return _boto3_conn(conn_type=conn_type, resource=resource, region=region, endpoint=endpoint, **params) except ValueError as e: module.fail_json(msg="Couldn't connect to AWS: %s" % to_native(e)) except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError, botocore.exceptions.NoCredentialsError, botocore.exceptions.ConfigParseError) as e: module.fail_json(msg=to_native(e)) except botocore.exceptions.NoRegionError as e: module.fail_json(msg="The %s module requires a region and none was found in configuration, " "environment variables or module parameters" % module._name)
def write_file(module, url, dest, content, resp): # create a tempfile with some test content fd, tmpsrc = tempfile.mkstemp(dir=module.tmpdir) f = open(tmpsrc, 'wb') try: f.write(content) except Exception as e: os.remove(tmpsrc) msg = format_message("Failed to create temporary content file: %s" % to_native(e), resp) module.fail_json(msg=msg, **resp) f.close() checksum_src = None checksum_dest = None # raise an error if there is no tmpsrc file if not os.path.exists(tmpsrc): os.remove(tmpsrc) msg = format_message("Source '%s' does not exist" % tmpsrc, resp) module.fail_json(msg=msg, **resp) if not os.access(tmpsrc, os.R_OK): os.remove(tmpsrc) msg = format_message("Source '%s' not readable" % tmpsrc, resp) module.fail_json(msg=msg, **resp) checksum_src = module.sha1(tmpsrc) # check if there is no dest file if os.path.exists(dest): # raise an error if copy has no permission on dest if not os.access(dest, os.W_OK): os.remove(tmpsrc) msg = format_message("Destination '%s' not writable" % dest, resp) module.fail_json(msg=msg, **resp) if not os.access(dest, os.R_OK): os.remove(tmpsrc) msg = format_message("Destination '%s' not readable" % dest, resp) module.fail_json(msg=msg, **resp) checksum_dest = module.sha1(dest) else: if not os.access(os.path.dirname(dest), os.W_OK): os.remove(tmpsrc) msg = format_message("Destination dir '%s' not writable" % os.path.dirname(dest), resp) module.fail_json(msg=msg, **resp) if checksum_src != checksum_dest: try: shutil.copyfile(tmpsrc, dest) except Exception as e: os.remove(tmpsrc) msg = format_message("failed to copy %s to %s: %s" % (tmpsrc, dest, to_native(e)), resp) module.fail_json(msg=msg, **resp) os.remove(tmpsrc)
def to_uuid(string, namespace=UUID_NAMESPACE_ASSIBLE): uuid_namespace = namespace if not isinstance(uuid_namespace, uuid.UUID): try: uuid_namespace = uuid.UUID(namespace) except (AttributeError, ValueError) as e: raise AssibleFilterError("Invalid value '%s' for 'namespace': %s" % (to_native(namespace), to_native(e))) # uuid.uuid5() requires bytes on Python 2 and bytes or text or Python 3 return to_text( uuid.uuid5(uuid_namespace, to_native(string, errors='surrogate_or_strict')))
def _get_connection(self, credentials, region='us-east-1'): try: connection = boto3.session.Session(profile_name=self.boto_profile).client('ec2', region, **credentials) except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: if self.boto_profile: try: connection = boto3.session.Session(profile_name=self.boto_profile).client('ec2', region) except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: raise AssibleError("Insufficient credentials found: %s" % to_native(e)) else: raise AssibleError("Insufficient credentials found: %s" % to_native(e)) return connection
def path_exists(path): if to_native( path ) == '/root/.assible/collections/assible_collections/sandwiches/ham': return False elif to_native( path ) == '/usr/share/assible/collections/assible_collections/sandwiches/reuben': return False elif to_native(path) == 'nope': return False else: return True
def test_utf8_output(self, mocker, rc_am): rc_am._subprocess._output = {mocker.sentinel.stdout: SpecialBytesIO(u'Žarn§'.encode('utf-8'), fh=mocker.sentinel.stdout), mocker.sentinel.stderr: SpecialBytesIO(u'لرئيسية'.encode('utf-8'), fh=mocker.sentinel.stderr)} (rc, stdout, stderr) = rc_am.run_command('/bin/something_ugly') assert rc == 0 # module_utils function. On py3 it returns text and py2 it returns # bytes because it's returning native strings assert stdout == to_native(u'Žarn§') assert stderr == to_native(u'لرئيسية')
def complete_cd(self, text, line, begidx, endidx): mline = line.partition(' ')[2] offs = len(mline) - len(text) if self.cwd in ('all', '*', '\\'): completions = self.hosts + self.groups else: completions = [x.name for x in self.inventory.list_hosts(self.cwd)] return [ to_native(s)[offs:] for s in completions if to_native(s).startswith(to_native(mline)) ]
def parse(self, inventory, loader, path, cache=False): ''' parses the inventory file ''' super(InventoryModule, self).parse(inventory, loader, path, cache=cache) self._read_config_data(path) strict = self.get_option('strict') fact_cache = FactCache() try: # Go over hosts (less var copies) for host in inventory.hosts: # get available variables to templar hostvars = combine_vars( get_group_vars(inventory.hosts[host].get_groups()), inventory.hosts[host].get_vars()) if host in fact_cache: # adds facts if cache is active hostvars = combine_vars(hostvars, fact_cache[host]) # create composite vars self._set_composite_vars(self.get_option('compose'), hostvars, host, strict=strict) # refetch host vars in case new ones have been created above hostvars = combine_vars( get_group_vars(inventory.hosts[host].get_groups()), inventory.hosts[host].get_vars()) if host in self._cache: # adds facts if cache is active hostvars = combine_vars(hostvars, self._cache[host]) # constructed groups based on conditionals self._add_host_to_composed_groups(self.get_option('groups'), hostvars, host, strict=strict) # constructed groups based variable values self._add_host_to_keyed_groups(self.get_option('keyed_groups'), hostvars, host, strict=strict) except Exception as e: raise AssibleParserError("failed to parse %s: %s " % (to_native(path), to_native(e)))