def _test_default_resolver(self, import_url, rules, expected_urls_to_resolve=[], expected_failure=False, partial_err_msg=None): urls_to_resolve = [] def mock_urlopen(url): urls_to_resolve.append(url) if url in [ORIGINAL_V1_URL, ORIGINAL_V2_URL, INVALID_V1_URL]: raise urllib2.URLError('invalid url: {0}'.format(url)) elif url == ILLEGAL_URL: raise ValueError('unknown url type: {0}'.format(url)) elif url in [VALID_V1_URL, VALID_V2_URL]: return mock.MagicMock() resolver = DefaultImportResolver(rules=rules) with mock.patch('urllib2.urlopen', new=mock_urlopen): try: resolver.resolve(import_url=import_url) if expected_failure: err_msg = 'resolve should have been failed' if partial_err_msg: err_msg = '{0} with error message that contains: {1}'\ .format(err_msg, partial_err_msg) raise AssertionError(err_msg) except DSLParsingLogicException, ex: if not expected_failure: raise ex if partial_err_msg: self.assertIn(partial_err_msg, str(ex))
def _test_default_resolver(self, import_url, rules, expected_urls_to_resolve=[], expected_failure=False, partial_err_msg=None): urls_to_resolve = [] number_of_attempts = [] class mock_requests_get(object): def __init__(self, url, timeout): self.status_code = 200 self.text = 200 number_of_attempts.append(1) if url not in urls_to_resolve: urls_to_resolve.append(url) if url in [ORIGINAL_V1_URL, ORIGINAL_V2_URL, INVALID_V1_URL]: raise requests.URLRequired( 'invalid url: {0}'.format(url)) elif url == ILLEGAL_URL: raise requests.URLRequired( 'unknown url type: {0}'.format( url)) elif url in [VALID_V1_URL, VALID_V2_URL]: return None elif url == TIMEOUT_URL: raise requests.ConnectionError( 'Timeout while trying to import') elif url == BAD_RESPONSE_CODE_URL: self.status_code = 404 self.text = 404 elif url == RETRY_URL: if len(number_of_attempts) < DEFAULT_NUMBER_RETRIES: raise requests.ConnectionError( 'Timeout while trying to import') else: return None resolver = DefaultImportResolver(rules=rules) with mock.patch('requests.get', new=mock_requests_get, create=True): with mock.patch( 'dsl_parser.import_resolver.abstract_import_resolver.' 'DEFAULT_RETRY_DELAY', new=RETRY_DELAY): try: resolver.resolve(import_url=import_url) if expected_failure: err_msg = 'resolve should have been failed' if partial_err_msg: err_msg = \ '{0} with error message that contains: {1}'\ .format(err_msg, partial_err_msg) raise AssertionError(err_msg) except DSLParsingLogicException, ex: if not expected_failure: raise ex if partial_err_msg: self.assertIn(partial_err_msg, str(ex))
def _test_default_resolver(self, import_url, rules, expected_urls_to_resolve=[], expected_failure=False, partial_err_msg=None, fallback=False): urls_to_resolve = [] number_of_attempts = [] class mock_requests_get(object): def __init__(self, url, timeout): self.status_code = 200 self.text = 200 number_of_attempts.append(1) if url not in urls_to_resolve: urls_to_resolve.append(url) if url in [ORIGINAL_V1_URL, ORIGINAL_V2_URL, INVALID_V1_URL]: raise requests.URLRequired('invalid url: {0}'.format(url)) elif url == ILLEGAL_URL: raise requests.URLRequired( 'unknown url type: {0}'.format(url)) elif url in [VALID_V1_URL, VALID_V2_URL]: return None elif url == TIMEOUT_URL: raise requests.ConnectionError( 'Timeout while trying to import') elif url == BAD_RESPONSE_CODE_URL: self.status_code = 404 self.text = 404 elif url == RETRY_URL: if len(number_of_attempts) < MAX_NUMBER_RETRIES: raise requests.ConnectionError( 'Timeout while trying to import') else: return None resolver = DefaultImportResolver(rules=rules, fallback=fallback) with mock.patch('requests.get', new=mock_requests_get, create=True): with mock.patch( 'dsl_parser.import_resolver.abstract_import_resolver.' 'DEFAULT_RETRY_DELAY', new=RETRY_DELAY): try: resolver.resolve(import_url=import_url) if expected_failure: err_msg = 'resolve should have been failed' if partial_err_msg: err_msg = \ '{0} with error message that contains: {1}'\ .format(err_msg, partial_err_msg) raise AssertionError(err_msg) except DSLParsingLogicException, ex: if not expected_failure: raise ex if partial_err_msg: self.assertIn(partial_err_msg, str(ex))
def _test_using_import_resolver(self, command, blueprint_path, mocked_module, mock_get_resolver): cfy.invoke('cfy init -r') # create an import resolver parameters = { 'rules': [{'rule1prefix': 'rule1replacement'}] } resolver = DefaultImportResolver(**parameters) # set the return value of mock_get_resolver - # this is the resolver we expect to be passed to # the parse_from_path method. mock_get_resolver.return_value = resolver # run the cli command and check that # parse_from_path was called with the expected resolver cli_command = 'cfy {0} {1}'.format(command, blueprint_path) kwargs = { 'dsl_file_path': blueprint_path, 'resolver': resolver, 'validate_version': True } self.assert_method_called( cli_command, mocked_module, 'parse_from_path', kwargs=kwargs) cfy.purge_dot_cloudify()
def _resolve_blueprint_imports(dsl_location, dsl_string, resolver, resources_base_path, validate_version): """ Goes over all the blueprint's imports and constructs a merged blueprint from them. """ parsed_dsl_holder = utils.load_yaml(raw_yaml=dsl_string, error_message='Failed to parse DSL', filename=dsl_location) if not resolver: resolver = DefaultImportResolver() # validate version schema and extract actual version used result = parser.parse(parsed_dsl_holder, element_cls=blueprint.BlueprintVersionExtractor, inputs={'validate_version': validate_version}, strict=False) version = result['plan_version'] # handle imports result = parser.parse(value=parsed_dsl_holder, inputs={ 'main_blueprint_holder': parsed_dsl_holder, 'resources_base_path': resources_base_path, 'blueprint_location': dsl_location, 'version': version, 'resolver': resolver, 'validate_version': validate_version }, element_cls=blueprint.BlueprintImporter, strict=False) return result['resource_base'],\ result['merged_blueprint']
def test_specified_default_class_path_no_params(self): resolver_configuration = { RESOLVER_IMPLEMENTATION_KEY: default_resolver_class_path } self._test_create_import_resolver( resolver_configuration=resolver_configuration, expected_resolver=DefaultImportResolver(), expected_params_name=DEFAULT_RESLOVER_RULES_KEY)
def test_illegal_default_resolver_rules_type(self): # wrong rules configuration - string instead of list params = {'rules': 'this should be a list'} try: DefaultImportResolver(**params) except DefaultResolverValidationException as ex: self.assertIn( 'The `rules` parameter must be a list but it is of type str', str(ex))
def test_illegal_default_resolver_parameters(self): # illegal initialization of the default resolver params = {'wrong_param_name': ''} try: DefaultImportResolver(**params) except TypeError as ex: self.assertIn( 'got an unexpected keyword argument \'wrong_param_name\'', str(ex))
def test_get_default_resolver_illegal_rule_size(self): # wrong rule dictionary size - should be only one pair of key, value rules = [{'rule1_1': 'rule1_value1', 'rule1_2': 'rule1_value2'}] params = {'rules': rules} try: DefaultImportResolver(**params) except DefaultResolverValidationException as ex: self.assertIn( 'Each rule must be a dictionary with one (key,value) ' 'pair but the rule {0} has 2 keys'.format(rules), str(ex))
def parse_from_path(self, dsl_path, resources_base_path=None, resolver=None): if not resolver: resolver = DefaultImportResolver( rules=self._local_resolver_rules()) return dsl_parse_from_path(dsl_path, resources_base_path, resolver=resolver)
def test_specified_params_no_class_path(self): parameters = { DEFAULT_RESLOVER_RULES_KEY: [{ 'rules1key': 'rules1value' }] } resolver_configuration = {RESLOVER_PARAMETERS_KEY: parameters} self._test_create_import_resolver( resolver_configuration=resolver_configuration, expected_resolver=DefaultImportResolver(**parameters), expected_params_name=DEFAULT_RESLOVER_RULES_KEY)
def test_illegal_default_resolver_rule_type(self): # wrong rule type - should be dictionary rule = 'this should be a dict' rules = [rule] params = {'rules': rules} try: DefaultImportResolver(**params) except DefaultResolverValidationException as ex: self.assertIn( 'Each rule must be a dictionary but the rule ' '[{0}] is of type {1}'.format(rule, type(rule).__name__), str(ex))
def parse(self, dsl_string, resources_base_path=None, dsl_version=BASIC_VERSION_SECTION_DSL_1_0, resolver=None, validate_version=True): # add dsl version if missing if DSL_VERSION_PREFIX not in dsl_string: dsl_string = dsl_version + dsl_string if not resolver: resolver = DefaultImportResolver() return dsl_parse(dsl_string, resources_base_path=resources_base_path, resolver=resolver, validate_version=validate_version)
def create_import_resolver(resolver_configuration): if resolver_configuration: resolver_class_path = resolver_configuration.get( RESOLVER_IMPLEMENTATION_KEY) parameters = resolver_configuration.get(RESLOVER_PARAMETERS_KEY, {}) if parameters and not isinstance(parameters, dict): raise ResolverInstantiationError( 'Invalid parameters supplied for the resolver ({0}): ' 'parameters must be a dictionary and not {1}'.format( resolver_class_path or 'DefaultImportResolver', type(parameters).__name__)) try: if resolver_class_path: # custom import resolver return get_class_instance(resolver_class_path, parameters) else: # default import resolver return DefaultImportResolver(**parameters) except Exception as ex: raise ResolverInstantiationError( 'Failed to instantiate resolver ({0}). {1}'.format( resolver_class_path or 'DefaultImportResolver', str(ex))) return DefaultImportResolver()
def _parse(dsl_string, resources_base_path, dsl_location=None, resolver=None, validate_version=True, additional_resource_sources=()): parsed_dsl_holder = utils.load_yaml(raw_yaml=dsl_string, error_message='Failed to parse DSL', filename=dsl_location) if not resolver: resolver = DefaultImportResolver() # validate version schema and extract actual version used result = parser.parse(parsed_dsl_holder, element_cls=blueprint.BlueprintVersionExtractor, inputs={'validate_version': validate_version}, strict=False) version = result['plan_version'] # handle imports result = parser.parse(value=parsed_dsl_holder, inputs={ 'main_blueprint_holder': parsed_dsl_holder, 'resources_base_path': resources_base_path, 'blueprint_location': dsl_location, 'version': version, 'resolver': resolver, 'validate_version': validate_version }, element_cls=blueprint.BlueprintImporter, strict=False) resource_base = [result['resource_base']] if additional_resource_sources: resource_base.extend(additional_resource_sources) merged_blueprint_holder = result['merged_blueprint'] # parse blueprint plan = parser.parse(value=merged_blueprint_holder, inputs={ 'resource_base': resource_base, 'validate_version': validate_version }, element_cls=blueprint.Blueprint) functions.validate_functions(plan) return plan
def test_marking(self): main_yaml = self.BASIC_VERSION_SECTION_DSL_1_3 + """ imports: - http://www.getcloudify.org/spec/cloudify/4.5/types.yaml node_types: test_type: properties: prop1: default: value """ resolver = DefaultImportResolver() merged_blueprint = parse_from_import_blueprint( dsl_location=None, dsl_string=main_yaml, resolver=resolver, resources_base_path=None) _, node_types = merged_blueprint.get_item(constants.NODE_TYPES) _, root_type = node_types.get_item('cloudify.nodes.Root') _, test_type = node_types.get_item('test_type') self.assertEqual(root_type.is_cloudify_type, True) self.assertEqual(test_type.is_cloudify_type, False)
def test_no_configuration_specified(self): self._test_create_import_resolver( expected_resolver=DefaultImportResolver(), expected_params_name=DEFAULT_RESLOVER_RULES_KEY)
def test_parse_dsl_from_file_bad_path(self): self.assertRaises(EnvironmentError, parse_from_path, 'fake-file.yaml', DefaultImportResolver())
'parameters must be a dictionary and not {1}' .format(resolver_class_path or 'DefaultImportResolver', type(parameters).__name__)) try: if resolver_class_path: # custom import resolver return get_class_instance(resolver_class_path, parameters) else: # default import resolver return DefaultImportResolver(**parameters) except Exception, ex: raise ResolverInstantiationError( 'Failed to instantiate resolver ({0}). {1}' .format(resolver_class_path or 'DefaultImportResolver', str(ex))) return DefaultImportResolver() def get_class_instance(class_path, properties): """Returns an instance of a class from a string formatted as module:class the given *args, **kwargs are passed to the instance's __init__""" if not properties: properties = {} try: cls = get_class(class_path) instance = cls(**properties) except Exception as e: exc_type, exc, traceback = sys.exc_info() raise RuntimeError('Failed to instantiate {0}, error: {1}' .format(class_path, e)), None, traceback