def register_lookup_handler(lookup_type, handler_or_path): """Register a lookup handler. Args: lookup_type (str): Name to register the handler under. handler_or_path (Union[Callable, str]): A function or a path to a handler. """ handler = handler_or_path if isinstance(handler_or_path, string_types): handler = load_object_from_string(handler_or_path) CFNGIN_LOOKUP_HANDLERS[lookup_type] = handler if not isinstance(handler, type): # Hander is a not a new-style handler logger = logging.getLogger(__name__) logger.warning( "Registering lookup `%s`: Please upgrade to use the " "new style of Lookups.", lookup_type) warnings.warn( # For some reason, this does not show up... # Leaving it in anyway "Lookup `%s`: Please upgrade to use the new style of Lookups" "." % lookup_type, DeprecationWarning, stacklevel=2, )
def test_load_object_from_string(): """Test load object from string.""" tests = (("string.Template", string.Template), ("os.path.basename", os.path.basename), ("string.ascii_letters", string.ascii_letters)) for test in tests: assert load_object_from_string(test[0]) is test[1]
def test_load_object_from_string(): """Test load object from string.""" tests = (("string.Template", string.Template), ("os.path.basename", os.path.basename), ("string.ascii_letters", string.ascii_letters)) for test in tests: assert load_object_from_string(test[0]) is test[1] obj_path = 'tests.fixtures.mock_hooks.GLOBAL_VALUE' # check value from os.environ assert load_object_from_string(obj_path, try_reload=True) == 'us-east-1' with environ({'AWS_DEFAULT_REGION': 'us-west-2'}): # check value from os.environ after changing it to ensure reload assert load_object_from_string(obj_path, try_reload=True) == 'us-west-2'
def blueprint(self): """Return the blueprint associated with this stack.""" if not self._blueprint: kwargs = {} blueprint_class = None if self.definition.class_path: class_path = self.definition.class_path blueprint_class = load_object_from_string(class_path) if not hasattr(blueprint_class, "rendered"): raise AttributeError("Stack class %s does not have a " "\"rendered\" " "attribute." % (class_path, )) elif self.definition.template_path: blueprint_class = RawTemplateBlueprint kwargs["raw_template_path"] = self.definition.template_path else: raise AttributeError("Stack does not have a defined class or " "template path.") self._blueprint = blueprint_class( name=self.name, context=self.context, mappings=self.mappings, description=self.definition.description, **kwargs) return self._blueprint
def register_lookup_handler(lookup_type, handler_or_path): # type: (str, Union[Type[LookupHandler], str]) -> None """Register a lookup handler. Args: lookup_type: Name to register the handler under handler_or_path: a function or a path to a handler """ handler = handler_or_path if isinstance(handler_or_path, string_types): handler = load_object_from_string(handler_or_path) RUNWAY_LOOKUP_HANDLERS[lookup_type] = handler
def test_load_object_from_string_reload_conditions(mock_six): """Test load_object_from_string reload conditions.""" mock_six.moves.reload_module.return_value = MagicMock() builtin_test = 'sys.version_info' mock_hook = 'tests.fixtures.mock_hooks.GLOBAL_VALUE' try: del sys.modules['tests.fixtures.mock_hooks'] except: # noqa pylint: disable=bare-except pass load_object_from_string(builtin_test, try_reload=False) mock_six.moves.reload_module.assert_not_called() load_object_from_string(builtin_test, try_reload=True) mock_six.moves.reload_module.assert_not_called() load_object_from_string(mock_hook, try_reload=True) mock_six.moves.reload_module.assert_not_called() load_object_from_string(mock_hook, try_reload=True) mock_six.moves.reload_module.assert_called_once()
def __call__(self): # pylint: disable=arguments-differ """Run when the class instance is called directly.""" # Use the context property of the baseclass, if present. # If not, default to a basic context. try: ctx = self.context except AttributeError: ctx = Context(config=self.config, environment={"environment": "test"}) configvars = self.stack.variables or {} variables = [ Variable(k, v, "cfngin") for k, v in configvars.items() ] blueprint_class = load_object_from_string( self.stack.class_path) blueprint = blueprint_class(self.stack.name, ctx) blueprint.resolve_variables(variables or []) blueprint.setup_parameters() blueprint.create_template() self.assertRenderedBlueprint(blueprint)
def register_lookup_handler(lookup_type, handler_or_path): """Register a lookup handler. Args: lookup_type (str): Name to register the handler under. handler_or_path (Union[Callable, str]): A function or a path to a handler. """ handler = handler_or_path LOGGER.debug("registering CFNgin lookup: %s=%s", lookup_type, handler_or_path) if isinstance(handler_or_path, string_types): handler = load_object_from_string(handler_or_path) CFNGIN_LOOKUP_HANDLERS[lookup_type] = handler if not isinstance(handler, type): # Hander is a not a new-style handler LOGGER.warning( 'lookup "%s" uses a deprecated format; to learn how to write ' "lookups visit %s/page/cfngin/lookups.html#writing-a-custom-lookup", lookup_type, DOC_SITE, )
def handle_hooks(stage, hooks, provider, context): # pylint: disable=too-many-statements """Handle pre/post_build hooks. These are pieces of code that we want to run before/after the builder builds the stacks. Args: stage (str): The current stage (pre_run, post_run, etc). hooks (List[:class:`runway.cfngin.config.Hook`]): Hooks to execute. provider (:class:`runway.cfngin.providers.base.BaseProvider`): Provider instance. context (:class:`runway.cfngin.context.Context`): Context instance. """ if not hooks: LOGGER.debug("No %s hooks defined.", stage) return hook_paths = [] for i, hook in enumerate(hooks): try: hook_paths.append(hook.path) except KeyError: raise ValueError("%s hook #%d missing path." % (stage, i)) LOGGER.info("Executing %s hooks: %s", stage, ", ".join(hook_paths)) stage = stage.replace('build', 'deploy') # TODO remove after full rename for hook in hooks: data_key = hook.data_key required = hook.required if not hook.enabled: LOGGER.debug("hook with method %s is disabled, skipping", hook.path) continue try: method = load_object_from_string(hook.path, try_reload=True) except (AttributeError, ImportError): LOGGER.exception("Unable to load method at %s:", hook.path) if required: raise continue if isinstance(hook.args, dict): args = [Variable(k, v) for k, v in hook.args.items()] try: # handling for output or similar being used in pre_build resolve_variables(args, context, provider) except FailedVariableLookup: if 'pre' in stage: LOGGER.error('Lookups that change the order of ' 'execution, like "output", can only be ' 'used in "post_*" hooks. Please ' 'ensure that the hook being used does ' 'not rely on a stack, hook_data, or ' 'context that does not exist yet.') raise kwargs = {v.name: v.value for v in args} else: kwargs = hook.args or {} try: if isinstance(method, FunctionType): result = method(context=context, provider=provider, **kwargs) else: result = getattr( method(context=context, provider=provider, **kwargs), stage)() except Exception: # pylint: disable=broad-except LOGGER.exception("Method %s threw an exception:", hook.path) if required: raise continue if not result: if required: LOGGER.error("Required hook %s failed. Return value: %s", hook.path, result) sys.exit(1) LOGGER.warning("Non-required hook %s failed. Return value: %s", hook.path, result) else: if isinstance(result, collections.Mapping): if data_key: LOGGER.debug( "Adding result for hook %s to context in " "data_key %s.", hook.path, data_key) context.set_hook_data(data_key, result) else: LOGGER.debug( "Hook %s returned result data, but no data " "key set, so ignoring.", hook.path)
def handle_hooks(stage, hooks, provider, context): """Handle pre/post_build hooks. These are pieces of code that we want to run before/after the builder builds the stacks. Args: stage (str): The current stage (pre_run, post_run, etc). hooks (List[:class:`runway.cfngin.config.Hook`]): Hooks to execute. provider (:class:`runway.cfngin.providers.base.BaseProvider`): Provider instance. context (:class:`runway.cfngin.context.Context`): Context instance. """ if not hooks: LOGGER.debug("No %s hooks defined.", stage) return hook_paths = [] for i, hook in enumerate(hooks): try: hook_paths.append(hook.path) except KeyError: raise ValueError("%s hook #%d missing path." % (stage, i)) LOGGER.info("Executing %s hooks: %s", stage, ", ".join(hook_paths)) for hook in hooks: data_key = hook.data_key required = hook.required kwargs = hook.args or {} enabled = hook.enabled if not enabled: LOGGER.debug("hook with method %s is disabled, skipping", hook.path) continue try: method = load_object_from_string(hook.path) except (AttributeError, ImportError): LOGGER.exception("Unable to load method at %s:", hook.path) if required: raise continue try: result = method(context=context, provider=provider, **kwargs) except Exception: # pylint: disable=broad-except LOGGER.exception("Method %s threw an exception:", hook.path) if required: raise continue if not result: if required: LOGGER.error("Required hook %s failed. Return value: %s", hook.path, result) sys.exit(1) LOGGER.warning("Non-required hook %s failed. Return value: %s", hook.path, result) else: if isinstance(result, collections.Mapping): if data_key: LOGGER.debug( "Adding result for hook %s to context in " "data_key %s.", hook.path, data_key) context.set_hook_data(data_key, result) else: LOGGER.debug( "Hook %s returned result data, but no data " "key set, so ignoring.", hook.path)