def __init__(self, event, context): """ Initializes handler. :param event: Event to handle :param context: Context if run within Lambda environment """ self._context = context self._event = event self._action_tracking = TaskTrackingTable(context) self.action_id = self._event[tracking.TASK_TR_ID] self.task = self._event[tracking.TASK_TR_NAME] self.action = self._event[tracking.TASK_TR_ACTION] self.test_completion_method = getattr( actions.get_action_class(self.action), handlers.COMPLETION_METHOD, None) self.action_parameters = json.loads( self._event.get(tracking.TASK_TR_PARAMETERS, "{}")) self.action_resources = json.loads( self._event.get(tracking.TASK_TR_RESOURCES, "{}")) self.dryrun = self._event.get(tracking.TASK_TR_DRYRUN) self.debug = self._event.get(tracking.TASK_TR_DEBUG) self.started_at = float(self._event.get(tracking.TASK_TR_STARTED_TS, 0)) self.start_result = self._event.get(tracking.TASK_TR_START_RESULT, None) self.session = AwsService.get_session( self._event.get(tracking.TASK_TR_ASSUMED_ROLE)) self.stack_name = os.getenv(handlers.ENV_STACK_NAME) self.stack_id = os.getenv(handlers.ENV_STACK_ID) self.action = event[tracking.TASK_TR_ACTION] self.action_properties = actions.get_action_properties(self.action) self.action_class = actions.get_action_class(self.action) self._stack_resources = None self.timeout = self._event.get(tracking.TASK_TR_TIMEOUT) self.execution_log_stream = self._event.get( tracking.TASK_TR_EXECUTION_LOGSTREAM) # setup logging if self.execution_log_stream is None: dt = datetime.utcnow() self.execution_log_stream = LOG_STREAM.format( self._event[tracking.TASK_TR_NAME], dt.year, dt.month, dt.day, dt.hour, dt.minute, self.action_id) else: self.execution_log_stream = self.execution_log_stream debug = event[tracking.TASK_TR_DEBUG] self._logger = Logger(logstream=self.execution_log_stream, buffersize=40 if debug else 20, context=context, debug=debug)
def _get_action_concurrency_key(self, item): """ Gets the concurrency key for a tasks action :param item: The task item :return: The concurrency key for the tasks action """ action = item[handlers.TASK_TR_ACTION] # get the name of the optional method to return the concurrency key action_class = actions.get_action_class(action) concurrency_key_method = getattr( action_class, handlers.ACTION_CONCURRENCY_KEY_METHOD, None) # prepare parameters for calling static function that returns the concurrency key if concurrency_key_method is not None: get_key_params = { actions.ACTION_PARAM_RESOURCES: handlers.get_item_resource_data(item, self._context), actions.ACTION_PARAM_ACCOUNT: item[handlers.TASK_TR_ACCOUNT], actions.ACTION_PARAM_STACK: os.getenv(handlers.ENV_STACK_NAME), actions.ACTION_PARAM_STACK_ID: os.getenv(handlers.ENV_STACK_ID), actions.ACTION_PARAM_TASK_ID: item[handlers.TASK_TR_ID], actions.ACTION_PARAM_TASK: item[handlers.TASK_TR_NAME] } get_key_params.update(item.get(handlers.TASK_TR_PARAMETERS)) return concurrency_key_method(get_key_params) else: # if this method is not available for action then use the name of the action as the key return action
def build_template(self, action_name): """ Build a cloudformation template for the action to create tasks for that action :param action_name: name of the action :return: template as dictionary """ self.action_name = action_name self.action_properties = actions.get_action_properties(self.action_name) self.action_class = actions.get_action_class(self.action_name) self.has_completion_logic = getattr(self.action_class, handlers.COMPLETION_METHOD, None) self.has_cross_account_parameter = self.action_properties.get(actions.ACTION_CROSS_ACCOUNT, True) self.is_regional_service = services.get_service_class(self.action_properties[actions.ACTION_SERVICE]).is_regional() self.has_regions_parameter = self.is_regional_service and self.action_properties.get(actions.ACTION_MULTI_REGION, True) self.use_intervals = actions.ACTION_TRIGGER_INTERVAL[0] in self.action_properties.get(actions.ACTION_TRIGGERS, actions.ACTION_TRIGGER_BOTH) self.interval_min = self.action_properties.get(actions.ACTION_MIN_INTERVAL_MIN, 0) self.use_events = actions.ACTION_TRIGGER_EVENTS[0] in self.action_properties.get(actions.ACTION_TRIGGERS, actions.ACTION_TRIGGER_BOTH) self._setup_template() self._setup_common_parameters() self._setup_action_parameters() self._setup_resources() self._setup_outputs() for p in self._template_parameters: description = self._template_parameters[p]["Description"] if description not in ["", None] and not description.endswith("."): self._template_parameters[p]["Description"] += "." return self._template
def action_class_parameter_check(parameters, name): # get the class that implements the action and test if there is a static method for additional checks of the parameters action_class = actions.get_action_class(name) validate_params_method = getattr( action_class, actions.ACTION_VALIDATE_PARAMETERS_METHOD, None) # if the method exists then validate the parameters using the business logic for that class if validate_params_method is not None: return validate_params_method(parameters) return parameters
def __init__(self, event, context): """ Initializes handler. :param event: Event to handle :param context: Context if run within Lambda environment """ self._context = context self._event = event self.action_id = self._event[handlers.TASK_TR_ID] self.task = self._event[handlers.TASK_TR_NAME] self.task_timezone = self._event.get(handlers.TASK_TR_TIMEZONE, None) self.has_completion = self._event[handlers.TASK_TR_HAS_COMPLETION] self.action_parameters = self._event.get(handlers.TASK_TR_PARAMETERS, {}) self.dryrun = self._event.get(handlers.TASK_TR_DRYRUN) self.interval = self._event.get(handlers.TASK_TR_INTERVAL, None) self.metrics = self._event.get(handlers.TASK_TR_METRICS, False) self.debug = self._event.get(handlers.TASK_TR_DEBUG) self.started_at = int(self._event.get(handlers.TASK_TR_STARTED_TS, 0)) self.start_result = self._event.get(handlers.TASK_TR_START_RESULT, None) self.session = services.get_session( self._event.get(handlers.TASK_TR_ASSUMED_ROLE)) self.stack_name = os.getenv(handlers.ENV_STACK_NAME) self.stack_id = os.getenv(handlers.ENV_STACK_ID) self.action = event[handlers.TASK_TR_ACTION] self.tagfilter = event.get(handlers.TASK_TR_TAGFILTER, "") self.action_properties = actions.get_action_properties(self.action) self.action_class = actions.get_action_class(self.action) self._stack_resources = None self.timeout = int( self._event[handlers.TASK_TR_TIMEOUT]) * 60 if self._event.get( handlers.TASK_TR_TIMEOUT, None) not in [None, "None"] else 0 self.execution_log_stream = self._event.get( handlers.TASK_TR_EXECUTION_LOGSTREAM) self.assumed_role = self._event.get(handlers.TASK_TR_ASSUMED_ROLE, None) self.events = self._event.get(handlers.TASK_TR_EVENTS, {}) if isinstance(self.events, str): self.events = json.loads( self._event.get(handlers.TASK_TR_EVENTS, "{}").replace("u'", '"').replace("'", '"')) self._action_resources = None self._s3_client = None self._action_instance = None self._action_class = None self._action_arguments = None self._timer = None self._timeout_event = None self.__logger = None self.__action_tracking = None
def setup_tasks_metrics(task, action_name, task_level_metrics, logger=None, context=None): with TaskMetrics(dt=datetime.utcnow(), logger=logger, context=context) as metrics: task_class = actions.get_action_class(action_name) # number of submitted task instances for task metrics.put_task_state_metrics( task_name=task, metric_state_name=METRICS_STATUS_NAMES[handlers.STATUS_PENDING], count=0, task_level=task_level_metrics) # init metrics for results for s in [ handlers.STATUS_STARTED, handlers.STATUS_COMPLETED, handlers.STATUS_FAILED ]: metrics.put_task_state_metrics( task_name=task, metric_state_name=METRICS_STATUS_NAMES[s], count=0, task_level=task_level_metrics) # init metrics for tasks with completion handling if getattr(task_class, handlers.COMPLETION_METHOD, None) is not None: metrics.put_task_state_metrics( task_name=task, metric_state_name=METRICS_STATUS_NAMES[ handlers.STATUS_WAIT_FOR_COMPLETION], count=0, task_level=task_level_metrics) metrics.put_task_state_metrics( task_name=task, metric_state_name=METRICS_STATUS_NAMES[ handlers.STATUS_TIMED_OUT], count=0, task_level=task_level_metrics) # init metrics for tasks with concurrency handling if getattr(task_class, handlers.ACTION_CONCURRENCY_KEY_METHOD, None) is not None: metrics.put_task_state_metrics( task_name=task, metric_state_name=METRICS_STATUS_NAMES[ handlers.STATUS_WAITING], count=0, task_level=task_level_metrics)
def build_template(self, action_name): """ Build a cloudformation template for the action to create tasks for that action :param action_name: name of the action :return: template as dictionary """ self.action_name = action_name self.action_properties = actions.get_action_properties(self.action_name) self.action_class = actions.get_action_class(self.action_name) self.has_timeout_parameter = getattr(self.action_class, handlers.COMPLETION_METHOD, None) self.has_cross_account_parameter = self.action_properties.get(actions.ACTION_CROSS_ACCOUNT, True) self.is_regional_service = services.get_service_class(self.action_properties[actions.ACTION_SERVICE]).is_regional() self.has_regions_parameter = self.is_regional_service and self.action_properties.get(actions.ACTION_MULTI_REGION, True) self._setup_template() self._setup_common_parameters() self._setup_action_parameters() self._setup_resources() return self._template
def __init__(self, event, context): self._context = context self._event = event self.task = event[handlers.HANDLER_EVENT_TASK] # setup logging classname = self.__class__.__name__ dt = datetime.utcnow() logstream = LOG_STREAM.format(classname, self.task[handlers.TASK_NAME], dt.year, dt.month, dt.day) debug = event[handlers.HANDLER_EVENT_TASK].get(handlers.TASK_DEBUG, False) self._logger = Logger(logstream=logstream, context=context, buffersize=40 if debug else 20, debug=debug) self._sts = None self._dynamodb = boto3.client("dynamodb") self.select_args = event.get(handlers.HANDLER_SELECT_ARGUMENTS, {}) self.task_dt = event[handlers.HANDLER_EVENT_TASK_DT] self.action_properties = actions.get_action_properties( self.task[handlers.TASK_ACTION]) self.action_class = actions.get_action_class( self.task[handlers.TASK_ACTION]) self.task_parameters = self.task.get(handlers.TASK_PARAMETERS, {}) self.aggregation_level = self.action_properties.get( actions.ACTION_AGGREGATION, actions.ACTION_AGGREGATION_RESOURCE) self.service = self.action_properties[actions.ACTION_SERVICE] self.resource_name = self.action_properties[actions.ACTION_RESOURCES] self.keep_tags = self.action_properties.get( actions.ACTION_KEEP_RESOURCE_TAGS, True) self.source = self._event.get(handlers.HANDLER_EVENT_SOURCE, handlers.UNKNOWN_SOURCE)
def verify_timeout(action_name, timeout): completion_method = getattr(actions.get_action_class(action_name), handlers.COMPLETION_METHOD, None) if completion_method is None and timeout is not None: raise ValueError(ERR_TIMEOUT_NOT_ALLOWED.format(action_name)) if completion_method is None: return None if timeout is None: action_properties = actions.get_action_properties(action_name) return action_properties.get( actions.ACTION_COMPLETION_TIMEOUT_MINUTES, actions.DEFAULT_COMPLETION_TIMEOUT_MINUTES_DEFAULT) try: result = int(str(timeout).partition(".")[0]) if result > 0: return result else: raise ValueError(ERR_TIMEOUT_MUST_BE_GREATER_0.format(result)) except ValueError as ex: raise ValueError(ERR_INVALID_NUMERIC_TIMEOUT.format(timeout, ex))
def add_task_action(self, task, assumed_role, action_resources, task_datetime, source, task_group=None): item = { handlers.TASK_TR_ID: str(uuid.uuid4()), handlers.TASK_TR_NAME: task[handlers.TASK_NAME], handlers.TASK_TR_ACTION: task[handlers.TASK_ACTION], handlers.TASK_TR_CREATED: datetime.now().isoformat(), handlers.TASK_TR_CREATED_TS: time.time(), handlers.TASK_TR_SOURCE: source, handlers.TASK_TR_DT: task_datetime, handlers.TASK_TR_STATUS: handlers.STATUS_PENDING, handlers.TASK_TR_DEBUG: task[handlers.TASK_DEBUG], handlers.TASK_TR_NOTIFICATIONS: task[handlers.TASK_NOTIFICATIONS], handlers.TASK_TR_HAS_COMPLETION: getattr(actions.get_action_class(task[handlers.TASK_ACTION]), handlers.COMPLETION_METHOD, None) is not None, handlers.TASK_TR_METRICS: task[handlers.TASK_METRICS], handlers.TASK_TR_DRYRUN: task[handlers.TASK_DRYRUN], handlers.TASK_TR_INTERNAL: task[handlers.TASK_INTERNAL], handlers.TASK_INTERVAL: task[handlers.TASK_INTERVAL], handlers.TASK_TR_TIMEOUT: task[handlers.TASK_TIMEOUT], handlers.TASK_TR_TIMEZONE: task[handlers.TASK_TIMEZONE], handlers.TASK_TR_STARTED_TS: int(time.time()), handlers.TASK_TR_EXECUTE_SIZE: task[handlers.TASK_EXECUTE_SIZE], handlers.TASK_TR_SELECT_SIZE: task[handlers.TASK_SELECT_SIZE], handlers.TASK_TR_COMPLETION_SIZE: task[handlers.TASK_COMPLETION_SIZE], handlers.TASK_TR_TAGFILTER: task[handlers.TASK_TAG_FILTER], handlers.TASK_TR_EVENTS: task.get(handlers.TASK_EVENTS, {}), handlers.TASK_TR_RUN_LOCAL: True, handlers.TASK_TR_GROUP: task_group } if assumed_role not in [None, ""]: item[handlers.TASK_TR_ASSUMED_ROLE] = assumed_role item[handlers.TASK_TR_ACCOUNT] = services.account_from_role_arn( assumed_role) else: item[handlers.TASK_TR_ACCOUNT] = os.getenv( handlers.ENV_OPS_AUTOMATOR_ACCOUNT) if len(task[handlers.TASK_PARAMETERS]) > 0: item[handlers.TASK_TR_PARAMETERS] = task[handlers.TASK_PARAMETERS] parameters = item.get(handlers.TASK_TR_PARAMETERS, None) if parameters is not None: item[handlers.TASK_TR_PARAMETERS] = parameters # check if the class has a field or static method that returns true if the action class needs completion # this way we can make completion dependent of parameter values has_completion = getattr( actions.get_action_class(task[handlers.TASK_ACTION]), actions.ACTION_PARAM_HAS_COMPLETION, None) if has_completion is not None: # if it is static method call it passing the task parameters if isinstance(has_completion, types.FunctionType): has_completion = has_completion(parameters) else: # if it does not have this method test if the class has an us_complete method has_completion = getattr( actions.get_action_class(task[handlers.TASK_ACTION]), handlers.COMPLETION_METHOD, None) is not None item[handlers.TASK_TR_HAS_COMPLETION] = has_completion item[handlers.TASK_TR_RESOURCES] = action_resources self._task_items.append(self.dynamo_safe_attribute_types(item)) return item
def __init__(self, event, context, logger=None, tracking_store=None): def log_stream_name(): classname = self.__class__.__name__ dt = datetime.utcnow() account = self._event.get(handlers.HANDLER_SELECT_ARGUMENTS, {}).get(handlers.HANDLER_EVENT_ACCOUNT, "") regions = self._event.get(handlers.HANDLER_SELECT_ARGUMENTS, {}).get(handlers.HANDLER_EVENT_REGIONS, []) if account is not None and len(regions) > 0: account_and_region = "-".join([account, regions[0]]) + "-" else: region = "" if self.sub_task is not None: account = "" if self._this_account: if len(self._accounts) == 0: account = os.getenv( handlers.ENV_OPS_AUTOMATOR_ACCOUNT) elif len(self._accounts) == 1: account = self._accounts[0] region = self._regions[0] if len( self._regions) == 1 else "" if account != "": if region not in ["", None]: account_and_region = "-".join([account, region]) + "-" else: account_and_region = account else: account_and_region = "" return LOG_STREAM.format(classname, self.task[handlers.TASK_NAME], account_and_region, dt.year, dt.month, dt.day) self._context = context self._event = event self.task = event[handlers.HANDLER_EVENT_TASK] self.sub_task = event.get(handlers.HANDLER_EVENT_SUB_TASK, None) self.use_custom_select = event.get( handlers.HANDLER_EVENT_CUSTOM_SELECT, True) # the job id is used to correlate all generated tasks for the selected resources self.task_group = self._event.get(handlers.HANDLER_EVENT_TASK_GROUP, None) if self.task_group is None: self.task_group = str(uuid.uuid4()) debug = event[handlers.HANDLER_EVENT_TASK].get(handlers.TASK_DEBUG, False) if logger is None: self._logger = QueuedLogger(logstream=log_stream_name(), context=context, buffersize=50 if debug else 20, debug=debug) else: self._logger = logger self._sts = None self.select_args = event.get(handlers.HANDLER_SELECT_ARGUMENTS, {}) self.task_dt = event[handlers.HANDLER_EVENT_TASK_DT] self.action_properties = actions.get_action_properties( self.task[handlers.TASK_ACTION]) self.action_class = actions.get_action_class( self.task[handlers.TASK_ACTION]) self.task_parameters = self.task.get(handlers.TASK_PARAMETERS, {}) self.metrics = self.task.get(handlers.TASK_METRICS, False) self.service = self.action_properties[actions.ACTION_SERVICE] self.keep_tags = self.action_properties.get( actions.ACTION_KEEP_RESOURCE_TAGS, True) self.source = self._event.get(handlers.HANDLER_EVENT_SOURCE, handlers.UNKNOWN_SOURCE) self.run_local = handlers.running_local(self._context) self._timer = None self._timeout_event = self._timeout_event = threading.Event() self.aggregation_level = self.action_properties.get( actions.ACTION_AGGREGATION, actions.ACTION_AGGREGATION_RESOURCE) if self.aggregation_level is not None and isinstance( self.aggregation_level, types.FunctionType): self.aggregation_level = self.aggregation_level( self.task_parameters) self.batch_size = self.action_properties.get(actions.ACTION_BATCH_SIZE) if self.batch_size is not None and isinstance(self.batch_size, types.FunctionType): self.batch_size = self.batch_size(self.task_parameters) self.actions_tracking = TaskTrackingTable( self._context, logger=self._logger) if tracking_store is None else tracking_store
def add_task_action(self, task, assumed_role, action_resources, task_datetime, source, task_group=None): item = { handlers.TASK_TR_ID: str(uuid.uuid4()), handlers.TASK_TR_NAME: task[handlers.TASK_NAME], handlers.TASK_TR_ACTION: task[handlers.TASK_ACTION], handlers.TASK_TR_CREATED: datetime.now().isoformat(), handlers.TASK_TR_CREATED_TS: int(time()), handlers.TASK_TR_SOURCE: source, handlers.TASK_TR_DT: task_datetime, handlers.TASK_TR_STATUS: handlers.STATUS_PENDING, handlers.TASK_TR_DEBUG: task[handlers.TASK_DEBUG], handlers.TASK_TR_NOTIFICATIONS: task[handlers.TASK_NOTIFICATIONS], handlers.TASK_TR_METRICS: task[handlers.TASK_METRICS], handlers.TASK_TR_DRYRUN: task[handlers.TASK_DRYRUN], handlers.TASK_TR_INTERNAL: task[handlers.TASK_INTERNAL], handlers.TASK_TR_INTERVAL: task[handlers.TASK_INTERVAL], handlers.TASK_TR_TIMEZONE: task[handlers.TASK_TIMEZONE], handlers.TASK_TR_TIMEOUT: task[handlers.TASK_TIMEOUT], handlers.TASK_TR_STARTED_TS: int(time()), handlers.TASK_TR_EXECUTE_SIZE: task[handlers.TASK_EXECUTE_SIZE], handlers.TASK_TR_SELECT_SIZE: task[handlers.TASK_SELECT_SIZE], handlers.TASK_TR_EVENTS: task.get(handlers.TASK_EVENTS, {}), handlers.TASK_TR_COMPLETION_SIZE: task[handlers.TASK_COMPLETION_SIZE], handlers.TASK_TR_TAGFILTER: task[handlers.TASK_TAG_FILTER], handlers.TASK_TR_GROUP: task_group, handlers.TASK_TR_SERVICE: task[handlers.TASK_SERVICE], handlers.TASK_TR_RESOURCE_TYPE: task[handlers.TASK_RESOURCE_TYPE] } item[handlers.TASK_TR_RUN_LOCAL] = self._run_local if assumed_role is not None: item[handlers.TASK_TR_ASSUMED_ROLE] = assumed_role item[handlers.TASK_TR_ACCOUNT] = services.account_from_role_arn(assumed_role) else: item[handlers.TASK_TR_ACCOUNT] = self.account if len(task[handlers.TASK_PARAMETERS]) > 0: item[handlers.TASK_TR_PARAMETERS] = task[handlers.TASK_PARAMETERS] parameters = item.get(handlers.TASK_TR_PARAMETERS, None) if parameters is not None: item[handlers.TASK_TR_PARAMETERS] = parameters # check if the class has a field or static method that returns true if the action class needs completion # this way we can make completion dependent of parameter values has_completion = getattr(actions.get_action_class(task[handlers.TASK_ACTION]), actions.ACTION_PARAM_HAS_COMPLETION, None) if has_completion is not None: # if it is static method call it passing the task parameters if isinstance(has_completion, types.FunctionType): has_completion = has_completion(parameters) else: # if it does not have this method test if the class has an us_complete method has_completion = getattr(actions.get_action_class(task[handlers.TASK_ACTION]), handlers.COMPLETION_METHOD, None) is not None item[handlers.TASK_TR_HAS_COMPLETION] = has_completion resource_data_str = safe_json(action_resources) encrypted = self._resource_encryption_key not in [None, ""] item[handlers.TASK_TR_ENCRYPTED_RESOURCES] = encrypted if encrypted: resource_data_str = base64.b64encode(self.kms_client.encrypt_with_retries( KeyId=self._resource_encryption_key, Plaintext=resource_data_str)["CiphertextBlob"]) if len(resource_data_str) < int(os.getenv(handlers.ENV_RESOURCE_TO_S3_SIZE, 16)) * 1024: if encrypted: item[handlers.TASK_TR_RESOURCES] = action_resources if not encrypted else resource_data_str else: item[handlers.TASK_TR_RESOURCES] = as_dynamo_safe_types(action_resources) else: bucket = os.getenv(handlers.ENV_RESOURCE_BUCKET) key = "{}.json".format(item[handlers.TASK_TR_ID]) try: self.s3_client.put_object_with_retries(Body=resource_data_str, Bucket=bucket, Key=key) except Exception as ex: raise_exception(ERR_WRITING_RESOURCES, bucket, key, item[handlers.TASK_TR_ID], ex) item[handlers.TASK_TR_S3_RESOURCES] = True self._new_action_items.append(item) return item
def __init__(self, action_name, tested_region=None, test_region=None, action_stack_name=None, logger=None, task_list_tag_name=None, debug=False): self.debug = debug self.logger = logger if logger is not None else ConsoleLogger( debug=self.debug) if getattr(self.logger, "test") is None: setattr(self.logger, "test", getattr(self.logger, "info")) self.context = None self.action_name = action_name self.action_class = actions.get_action_class(self.action_name) self.action_properties = actions.get_action_properties( self.action_name) self.tested_region = tested_region if tested_region is not None else boto3.Session( ).region_name self.test_region = test_region if test_region is not None else boto3.Session( ).region_name if task_list_tag_name is not None: os.environ[handlers.ENV_AUTOMATOR_TAG_NAME] = task_list_tag_name self.interval = None os.environ[ handlers.ENV_OPS_AUTOMATOR_ACCOUNT] = services.get_aws_account() if action_stack_name is None: self.action_stack_name = testing.action_stack_name( self.action_name) else: self.action_stack_name = action_stack_name self._action_stack = None os.environ[handlers.ENV_STACK_NAME] = self.action_stack_name actions.set_report_output_provider(create_output_writer) self._action_stack_resources = None self._assumed_role = None self._tested_account = None self._session = None self._cloudformation_client = None self._action_stack_template = None self._events = None self._tag_filter = None self.results = None self.parameters = None self.task_name = None self.action_select_parameters = None self.run_after_select = None self.max_concurrency = None self.concurrency_key = None self.log_subject = None self.run_in_regions = None self.run_after_select = None self.executed_tasks = []
def handle_request(self): """ Handles action execute requests, creates an instance of the required action class and executes the action on the resources passed in the event. :return: """ # get class of the action, this class is needed by the _logger property self._action_class = actions.get_action_class(self.action) try: self._action_arguments = { actions.ACTION_PARAM_CONTEXT: self._context, actions.ACTION_PARAM_EVENT: self._event, actions.ACTION_PARAM_SESSION: self.session, actions.ACTION_PARAM_RESOURCES: self.action_resources, actions.ACTION_PARAM_INTERVAL: self.interval, actions.ACTION_PARAM_DEBUG: self.debug, actions.ACTION_PARAM_DRYRUN: self.dryrun, actions.ACTION_PARAM_TASK_ID: self.action_id, actions.ACTION_PARAM_TASK: self.task, actions.ACTION_PARAM_TASK_TIMEZONE: self.task_timezone, actions.ACTION_PARAM_STACK: self.stack_name, actions.ACTION_PARAM_STACK_ID: self.stack_id, actions.ACTION_PARAM_STACK_RESOURCES: self.stack_resources, actions.ACTION_PARAM_ASSUMED_ROLE: self.assumed_role, actions.ACTION_PARAM_STARTED_AT: self.started_at, actions.ACTION_PARAM_TAGFILTER: self.tagfilter, actions.ACTION_PARAM_TIMEOUT: self.timeout, actions.ACTION_PARAM_TAG_FILTER: self.tagfilter, actions.ACTION_PARAM_EVENTS: self.events } # called after initialization other arguments as it is using these to construct the logger self._action_arguments[actions.ACTION_PARAM_LOGGER] = self._logger if self._context is not None: self._timeout_event = threading.Event() self._action_arguments[ actions.ACTION_PARAM_TIMEOUT_EVENT] = self._timeout_event # create the instance of the action class self._action_instance = self._action_class(self._action_arguments, self.action_parameters) self._logger.info(INF_START_EXEC, self._event[handlers.HANDLER_EVENT_ACTION], self.action_id) if self._event[ handlers. HANDLER_EVENT_ACTION] == handlers.HANDLER_ACTION_EXECUTE: return self._handle_task_execution() elif self._event[ handlers. HANDLER_EVENT_ACTION] == handlers.HANDLER_ACTION_TEST_COMPLETION: return self._handle_test_task_completion() raise Exception( ERR_INVALID_ACTION.format( self._event[handlers.HANDLER_EVENT_ACTION])) except Exception as ex: self._logger.error(ERR_EXECUTION_TASK, self._event[handlers.HANDLER_EVENT_ACTION], self.task, str(ex), ("\n" + full_stack()) if self.debug else "") self._action_tracking.update_task( action_id=self.action_id, task=self.task, task_metrics=self.metrics, status=handlers.STATUS_FAILED, status_data={handlers.TASK_TR_ERROR: str(ex)}) finally: self._logger.info(INF_FINISH_EXEC, self._event[handlers.HANDLER_EVENT_ACTION], self.action_id) self._logger.flush()