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 AnsibleError( "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 AnsibleError( "{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 _check_type_str(self, value, param=None, prefix=''): opts = { 'error': False, 'warn': False, 'ignore': True } # Ignore, warn, or error when converting to a string. allow_conversion = opts.get(self._string_conversion_action, True) try: return check_type_str(value, allow_conversion) except TypeError: common_msg = 'quote the entire value to ensure it does not change.' from_msg = '{0!r}'.format(value) to_msg = '{0!r}'.format(to_text(value)) if param is not None: if prefix: param = '{0}{1}'.format(prefix, param) from_msg = '{0}: {1!r}'.format(param, value) to_msg = '{0}: {1!r}'.format(param, to_text(value)) if self._string_conversion_action == 'error': msg = common_msg.capitalize() raise TypeError(to_native(msg)) elif self._string_conversion_action == 'warn': msg = ('The value "{0}" (type {1.__class__.__name__}) was converted to "{2}" (type string). ' 'If this does not look like what you expect, {3}').format(from_msg, value, to_msg, common_msg) self.warn(to_native(msg)) return to_native(value, errors='surrogate_or_strict')
def check_type_access_endpoint(endpoint: 'Any') -> str: ''' >>> check_type_access_endpoint('/me') '/me' >>> check_type_access_endpoint('/me/api/application') '/me/api/application' >>> check_type_access_endpoint('/me/api/application/*') '/me/api/application/*' >>> check_type_access_endpoint({}) '%7B%7D' >>> check_type_access_endpoint(0.3) '0.3' >>> import warnings >>> warnings.simplefilter("ignore") >>> check_type_access_endpoint('/test-with/{{ ansible_value | default(default_value) }}') '/test-with/%7B%7B%20ansible_value%20%7C%20default%28default_value%29%20%7D%7D' >>> warnings.simplefilter("error") >>> check_type_access_endpoint('/test-with/{{ ansible_value | default(default_value) }}') Traceback (most recent call last): ... UserWarning: endpoint has brackets ''' endpoint = check_type_str(endpoint) if '{{' in endpoint and '}}' in endpoint: warn("endpoint has brackets", UserWarning) endpoint = urlquote(endpoint, safe='*/') return endpoint
def check_type_access_method(method: 'Any') -> str: ''' >>> check_type_access_method('GET') 'GET' >>> check_type_access_method('poSt') 'POST' >>> check_type_access_method('invalid') Traceback (most recent call last): ... ValueError: INVALID must be one of (GET,POST,PUT,DELETE) >>> check_type_access_method({}) Traceback (most recent call last): ... ValueError: {} must be one of (GET,POST,PUT,DELETE) >>> check_type_access_method(0.3) Traceback (most recent call last): ... ValueError: 0.3 must be one of (GET,POST,PUT,DELETE) ''' method = check_type_str(method).upper() if method not in ovh.API_READ_WRITE: raise ValueError('%s must be one of (%s)' % (method, ','.join(ovh.API_READ_WRITE))) return method
def get_shutdown_command_args(self, distribution): reboot_command = self._task.args.get('reboot_command') if reboot_command is not None: try: reboot_command = check_type_str(reboot_command, allow_conversion=False) except TypeError as e: raise AnsibleError( "Invalid value given for 'reboot_command': %s." % to_native(e)) # No args were provided try: return reboot_command.split(' ', 1)[1] except IndexError: return '' else: args = self._get_value_from_facts('SHUTDOWN_COMMAND_ARGS', distribution, 'DEFAULT_SHUTDOWN_COMMAND_ARGS') # Convert seconds to minutes. If less that 60, set it to 0. delay_min = self.pre_reboot_delay // 60 reboot_message = self._task.args.get('msg', self.DEFAULT_REBOOT_MESSAGE) return args.format(delay_sec=self.pre_reboot_delay, delay_min=delay_min, message=reboot_message)
def process_playbook_values(self): ''' Get playbook values and perform input validation ''' argument_spec = dict( vrf=dict(type='str', default='management'), connect_ssh_port=dict(type='int', default=22), file_system=dict(type='str', default='bootflash:'), file_pull=dict(type='bool', default=False), file_pull_timeout=dict(type='int', default=300), file_pull_compact=dict(type='bool', default=False), file_pull_kstack=dict(type='bool', default=False), local_file=dict(type='path'), local_file_directory=dict(type='path'), remote_file=dict(type='path'), remote_scp_server=dict(type='str'), remote_scp_server_user=dict(type='str'), remote_scp_server_password=dict(no_log=True), ) playvals = {} # Process key value pairs from playbook task for key in argument_spec.keys(): playvals[key] = self._task.args.get(key, argument_spec[key].get('default')) if playvals[key] is None: continue option_type = argument_spec[key].get('type', 'str') try: if option_type == 'str': playvals[key] = validation.check_type_str(playvals[key]) elif option_type == 'int': playvals[key] = validation.check_type_int(playvals[key]) elif option_type == 'bool': playvals[key] = validation.check_type_bool(playvals[key]) elif option_type == 'path': playvals[key] = validation.check_type_path(playvals[key]) else: raise AnsibleError('Unrecognized type <{0}> for playbook parameter <{1}>'.format(option_type, key)) except (TypeError, ValueError) as e: raise AnsibleError("argument %s is of type %s and we were unable to convert to %s: %s" % (key, type(playvals[key]), option_type, to_native(e))) # Validate playbook dependencies if playvals['file_pull']: if playvals.get('remote_file') is None: raise AnsibleError('Playbook parameter <remote_file> required when <file_pull> is True') if playvals.get('remote_scp_server') is None: raise AnsibleError('Playbook parameter <remote_scp_server> required when <file_pull> is True') if playvals['remote_scp_server'] or \ playvals['remote_scp_server_user']: if None in (playvals['remote_scp_server'], playvals['remote_scp_server_user']): params = '<remote_scp_server>, <remote_scp_server_user>' raise AnsibleError('Playbook parameters {0} must be set together'.format(params)) return playvals
def get_shutdown_command(self, task_vars, distribution): reboot_command = self._task.args.get('reboot_command') if reboot_command is not None: try: reboot_command = check_type_str(reboot_command, allow_conversion=False) except TypeError as e: raise AnsibleError( "Invalid value given for 'reboot_command': %s." % to_native(e)) shutdown_bin = reboot_command.split(' ', 1)[0] else: shutdown_bin = self._get_value_from_facts( 'SHUTDOWN_COMMANDS', distribution, 'DEFAULT_SHUTDOWN_COMMAND') if shutdown_bin[0] == '/': return shutdown_bin else: default_search_paths = [ '/sbin', '/bin', '/usr/sbin', '/usr/bin', '/usr/local/sbin' ] search_paths = self._task.args.get('search_paths', default_search_paths) try: # Convert bare strings to a list search_paths = check_type_list(search_paths) except TypeError: err_msg = "'search_paths' must be a string or flat list of strings, got {0}" raise AnsibleError(err_msg.format(search_paths)) display.debug( '{action}: running find module looking in {paths} to get path for "{command}"' .format(action=self._task.action, command=shutdown_bin, paths=search_paths)) find_result = self._execute_module( task_vars=task_vars, # prevent collection search by calling with ansible.legacy (still allows library/ override of find) module_name='ansible.legacy.find', module_args={ 'paths': search_paths, 'patterns': [shutdown_bin], 'file_type': 'any' }) full_path = [x['path'] for x in find_result['files']] if not full_path: raise AnsibleError( 'Unable to find command "{0}" in search paths: {1}'.format( shutdown_bin, search_paths)) return full_path[0]
def ensure_type(value, type_name): if type_name == 'str': return check_type_str(value) if type_name == 'list': return check_type_list(value) if type_name == 'dict': return check_type_dict(value) if type_name == 'bool': return check_type_bool(value) if type_name == 'int': return check_type_int(value) if type_name == 'float': return check_type_float(value) return value
def _get_option(self, name, type_name, default=None, accept_none=False): value = self._task.args.get(name) if value is None: if accept_none: return value elif default is not None: value = default else: raise Exception("Option %s must be specified" % name) checkers = { 'str': lambda v: check_type_str(v, allow_conversion=False), 'bool': check_type_bool, } try: return checkers[type_name](value) except TypeError as e: msg = "Value for option %s" % name msg += " is of type %s and we were unable to convert to %s: %s" % ( type(value), type_name, to_native(e)) raise Exception(msg)
def __init__(self): arg_spec = dict( port=dict( type='int', required=True, ), address=dict( type=str, required=False, default='0.0.0.0' ), response_body=dict( type=lambda v: check_type_str(v).encode('utf-8'), required=False, default='Success', no_log=True, ), response_headers=dict( type=dict, required=False, no_log=True, default={ "Content-Type": self.default_content_type, "Server": "Ansible - holyhole.ovh.wait_for_request", }, ), response_status=dict( type=int, required=False, default=HTTPStatus.OK, ), ) self.request: 'Optional[BaseHTTPRequestHandler]' = None self.module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True) self.exec()
def _process_option_proxies(self): '''check if 'proxies' option is dict or str and set it appropriately''' proxies_opt = self._options.get_option('proxies') if proxies_opt is None: return try: # if it can be interpreted as dict # do it proxies = check_type_dict(proxies_opt) except TypeError: # if it can't be interpreted as dict proxy = check_type_str(proxies_opt) # but can be interpreted as str # use this str as http and https proxy proxies = { 'http': proxy, 'https': proxy, } # record the new/interpreted value for 'proxies' option self._options.set_option('proxies', proxies)
def process_playbook_values(self): """ Get playbook values and perform input validation """ argument_spec = dict( vrf=dict(type="str", default="management"), connect_ssh_port=dict(type="int", default=22), file_system=dict(type="str", default="bootflash:"), file_pull=dict(type="bool", default=False), file_pull_timeout=dict(type="int", default=300), file_pull_protocol=dict( type="str", default="scp", choices=["scp", "sftp", "http", "https", "tftp", "ftp"], ), file_pull_compact=dict(type="bool", default=False), file_pull_kstack=dict(type="bool", default=False), local_file=dict(type="path"), local_file_directory=dict(type="path"), remote_file=dict(type="path"), remote_scp_server=dict(type="str"), remote_scp_server_user=dict(type="str"), remote_scp_server_password=dict(no_log=True), ) playvals = {} # Process key value pairs from playbook task for key in argument_spec.keys(): playvals[key] = self._task.args.get( key, argument_spec[key].get("default")) if playvals[key] is None: continue option_type = argument_spec[key].get("type", "str") try: if option_type == "str": playvals[key] = validation.check_type_str(playvals[key]) elif option_type == "int": playvals[key] = validation.check_type_int(playvals[key]) elif option_type == "bool": playvals[key] = validation.check_type_bool(playvals[key]) elif option_type == "path": playvals[key] = validation.check_type_path(playvals[key]) else: raise AnsibleError( "Unrecognized type <{0}> for playbook parameter <{1}>". format(option_type, key)) except (TypeError, ValueError) as e: raise AnsibleError( "argument %s is of type %s and we were unable to convert to %s: %s" % (key, type(playvals[key]), option_type, to_native(e))) if "choices" in argument_spec[key] and playvals[ key] not in argument_spec[key].get("choices"): raise AnsibleError( "argument {0} with value {1} is not valid. Allowed values are {2}" .format( key, playvals[key], ", ".join(argument_spec[key].get("choices")), )) # Validate playbook dependencies if playvals["file_pull"]: if playvals.get("remote_file") is None: raise AnsibleError( "Playbook parameter <remote_file> required when <file_pull> is True" ) if playvals.get("remote_scp_server") is None: raise AnsibleError( "Playbook parameter <remote_scp_server> required when <file_pull> is True" ) if playvals["remote_scp_server"] or playvals["remote_scp_server_user"]: if None in ( playvals["remote_scp_server"], playvals["remote_scp_server_user"], ): params = "<remote_scp_server>, <remote_scp_server_user>" raise AnsibleError( "Playbook parameters {0} must be set together".format( params)) return playvals
def test_check_type_str_no_conversion(value, expected): with pytest.raises(TypeError) as e: check_type_str(value, allow_conversion=False) assert 'is not a string and conversion is not allowed' in to_native(e.value)
def test_check_type_str(value, expected): assert expected == check_type_str(value)