def update_workflow_definition(identifier, values, session=None): wf_def = get_workflow_definition(identifier) if wf_def.project_id != security.get_project_id(): raise exc.NotAllowedException( "Can not update workflow of other tenants. " "[workflow_identifier=%s]" % identifier) if wf_def.is_system: raise exc.InvalidActionException( "Attempt to modify a system workflow: %s" % identifier) if wf_def.scope == 'public' and values['scope'] == 'private': cron_triggers = _get_associated_cron_triggers(identifier) try: [get_cron_trigger(name) for name in cron_triggers] except exc.NotFoundException: raise exc.NotAllowedException( "Can not update scope of workflow that has triggers " "associated in other tenants." "[workflow_identifier=%s]" % identifier) wf_def.update(values.copy()) return wf_def
def __init__(self, action_def, action_ex=None, task_ex=None, task_ctx=None, wf_ctx=None): self.action_spec = spec_parser.get_action_spec(action_def.spec) base_action_def = lookup_utils.find_action_definition_by_name( self.action_spec.get_base() ) if not base_action_def: raise exc.InvalidActionException( "Failed to find action [action_name=%s]" % self.action_spec.get_base() ) base_action_def = self._gather_base_actions( action_def, base_action_def ) super(AdHocAction, self).__init__( base_action_def, action_ex, task_ex ) self.adhoc_action_def = action_def self.task_ctx = task_ctx or {} self.wf_ctx = wf_ctx or {}
def resolve_action_definition(action_spec_name, wf_name=None, wf_spec_name=None): """Resolve action definition accounting for ad-hoc action namespacing. :param action_spec_name: Action name according to a spec. :param wf_name: Workflow name. :param wf_spec_name: Workflow name according to a spec. :return: Action definition (python or ad-hoc). """ action_db = None if wf_name and wf_name != wf_spec_name: # If workflow belongs to a workbook then check # action within the same workbook (to be able to # use short names within workbooks). # If it doesn't exist then use a name from spec # to find an action in DB. wb_name = wf_name.rstrip(wf_spec_name)[:-1] action_full_name = "%s.%s" % (wb_name, action_spec_name) action_db = db_api.load_action_definition(action_full_name) if not action_db: action_db = db_api.load_action_definition(action_spec_name) if not action_db: raise exc.InvalidActionException( "Failed to find action [action_name=%s]" % action_spec_name) return action_db
def resolve_action_definition(action_spec_name, wf_name=None, wf_spec_name=None): action_db = None if wf_name and wf_name != wf_spec_name: # If workflow belongs to a workbook then check # action within the same workbook (to be able to # use short names within workbooks). # If it doesn't exist then use a name from spec # to find an action in DB. wb_name = wf_name.rstrip(wf_spec_name)[:-1] action_full_name = "%s.%s" % (wb_name, action_spec_name) action_db = db_api.load_action_definition(action_full_name) if not action_db: action_db = db_api.load_action_definition(action_spec_name) if not action_db: raise exc.InvalidActionException( "Failed to find action [action_name=%s]" % action_spec_name ) return action_db
def _visit_hierarchy(self, callback): callback_result = callback(self, None) action_spec = self.spec visited = {self.name} while action_spec: base_name = action_spec.get_base() if base_name in visited: raise ValueError('Found a cycle in an ad-hoc action chain ' '[action_name=%s, duplicate_action_name=%s]' % (self.name, base_name)) visited.add(base_name) system_provider = action_service.get_system_action_provider() base_action_desc = system_provider.find(base_name, self.namespace) if base_action_desc is None: raise exc.InvalidActionException( "Failed to find base action [action_name=%s namespace=%s] " % (base_name, self.namespace)) # For every ad-hoc action in the hierarchy invoke the callback. callback_result = callback(base_action_desc, callback_result) if isinstance(base_action_desc, AdHocActionDescriptor): action_spec = base_action_desc.spec else: action_spec = None return callback_result
def __init__(self, action_def, action_ex=None, task_ex=None, task_ctx=None, wf_ctx=None): self.action_spec = spec_parser.get_action_spec(action_def.spec) try: base_action_def = db_api.get_action_definition( self.action_spec.get_base() ) except exc.DBEntityNotFoundError: raise exc.InvalidActionException( "Failed to find action [action_name=%s]" % self.action_spec.get_base() ) base_action_def = self._gather_base_actions( action_def, base_action_def ) super(AdHocAction, self).__init__( base_action_def, action_ex, task_ex ) self.adhoc_action_def = action_def self.task_ctx = task_ctx or {} self.wf_ctx = wf_ctx or {}
def build_action_by_name(action_name, namespace=''): action_desc = action_service.get_system_action_provider().find( action_name, namespace=namespace) if action_desc is None: raise exc.InvalidActionException( "Failed to find action [action_name=%s]" % action_name) return actions.RegularAction(action_desc)
def create_or_update_action(action_spec, definition, scope): action = db_api.load_action_definition(action_spec.get_name()) if action and action.is_system: raise exc.InvalidActionException( "Attempt to modify a system action: %s" % action.name) values = _get_action_values(action_spec, definition, scope) return db_api.create_or_update_action_definition(values['name'], values)
def update_action(action_spec, definition, scope, identifier=None): action = db_api.load_action_definition(action_spec.get_name()) if action and action.is_system: raise exc.InvalidActionException( "Attempt to modify a system action: %s" % action.name) values = _get_action_values(action_spec, definition, scope) return db_api.update_action_definition( identifier if identifier else values['name'], values)
def schedule(self, input_dict, target, index=0, desc='', safe_rerun=False, timeout=None): assert not self.action_ex self.action_desc.check_parameters(input_dict) wf_ex = self.task_ex.workflow_execution if self.task_ex else None wf_ctx = data_flow.ContextView( self.task_ctx, data_flow.get_workflow_environment_dict(wf_ex), wf_ex.context if wf_ex else {}) try: action = self.action_desc.instantiate(input_dict, wf_ctx) except Exception: raise exc.InvalidActionException( 'Failed to instantiate an action' ' [action_desc=%s, input_dict=%s]' % (self.action_desc, input_dict)) # Assign the action execution ID here to minimize database calls. # Otherwise, the input property of the action execution DB object needs # to be updated with the action execution ID after the action execution # DB object is created. action_ex_id = utils.generate_unicode_uuid() self._create_action_execution(input_dict, self._prepare_runtime_context( index, safe_rerun), desc=desc, action_ex_id=action_ex_id, is_sync=action.is_sync()) def _run_action(): executor = exe.get_executor(cfg.CONF.executor.type) return executor.run_action( action, self.action_ex.id if self.action_ex is not None else None, safe_rerun, self._prepare_execution_context(), target=target, timeout=timeout) # Register an asynchronous command to run the action # on an executor outside of the main DB transaction. post_tx_queue.register_operation(_run_action)
def _build_action(action_ex): if isinstance(action_ex, models.WorkflowExecution): return actions.WorkflowAction(wf_name=action_ex.name, action_ex=action_ex) action_desc = action_service.get_system_action_provider().find( action_ex.name, action_ex.workflow_namespace) if action_desc is None: raise exc.InvalidActionException( "Failed to find action [action_name=%s]" % action_ex.name) return actions.RegularAction(action_desc, action_ex)
def check_db_obj_access(db_obj): """Check accessibility to db object.""" ctx = context.ctx() is_admin = ctx.is_admin if not is_admin and db_obj.project_id != security.get_project_id(): raise exc.NotAllowedException( "Can not access %s resource of other projects, ID: %s" % (db_obj.__class__.__name__, db_obj.id)) if not is_admin and hasattr(db_obj, 'is_system') and db_obj.is_system: raise exc.InvalidActionException( "Can not modify a system %s resource, ID: %s" % (db_obj.__class__.__name__, db_obj.id))
def _gather_base_actions(self, action_def, base_action_def): """Find all base ad-hoc actions and store them. An ad-hoc action may be based on another ad-hoc action and this works recursively, so that the base action can also be based on an ad-hoc action. Using the same base action more than once in this action hierarchy is not allowed to avoid infinite loops. The method stores the list of ad-hoc actions. :param action_def: Action definition :type action_def: ActionDefinition :param base_action_def: Original base action definition :type base_action_def: ActionDefinition :return: The definition of the base system action :rtype: ActionDefinition """ self.adhoc_action_defs = [action_def] original_base_name = self.action_spec.get_name() action_names = set([original_base_name]) base = base_action_def while not base.is_system and base.name not in action_names: action_names.add(base.name) self.adhoc_action_defs.append(base) base_name = base.spec['base'] try: base = db_api.get_action_definition(base_name, namespace=base.namespace) except exc.DBEntityNotFoundError: raise exc.InvalidActionException( "Failed to find action [action_name=%s namespace=%s] " % (base_name, base.namespace) ) # if the action is repeated if base.name in action_names: raise ValueError( 'An ad-hoc action cannot use twice the same action, %s is ' 'used at least twice' % base.name ) return base
def run(self, input_dict, target, index=0, desc='', save=True, safe_rerun=False, timeout=None): assert not self.action_ex self.action_desc.check_parameters(input_dict) try: action = self.action_desc.instantiate(input_dict, {}) except Exception: raise exc.InvalidActionException( 'Failed to instantiate an action' ' [action_desc=%s, input_dict=%s]' % (self.action_desc, input_dict)) # Assign the action execution ID here to minimize database calls. # Otherwise, the input property of the action execution DB object needs # to be updated with the action execution ID after the action execution # DB object is created. action_ex_id = utils.generate_unicode_uuid() if save: self._create_action_execution(input_dict, self._prepare_runtime_context( index, safe_rerun), desc=desc, action_ex_id=action_ex_id, is_sync=action.is_sync()) executor = exe.get_executor(cfg.CONF.executor.type) return executor.run_action( action, self.action_ex.id if self.action_ex is not None else None, safe_rerun, self._prepare_execution_context(), target=target, async_=False, timeout=timeout)
def update_workflow_definition(identifier, values, session=None): wf_def = get_workflow_definition(identifier) if wf_def.project_id != security.get_project_id(): raise exc.NotAllowedException( "Can not update workflow of other tenants. " "[workflow_identifier=%s]" % identifier ) if wf_def.is_system: raise exc.InvalidActionException( "Attempt to modify a system workflow: %s" % identifier ) if wf_def.scope == 'public' and values['scope'] == 'private': # Check cron triggers. cron_triggers = get_cron_triggers(insecure=True, workflow_id=wf_def.id) for c_t in cron_triggers: if c_t.project_id != wf_def.project_id: raise exc.NotAllowedException( "Can not update scope of workflow that has cron triggers " "associated in other tenants. [workflow_identifier=%s]" % identifier ) # Check event triggers. event_triggers = get_event_triggers( insecure=True, workflow_id=wf_def.id ) for e_t in event_triggers: if e_t.project_id != wf_def.project_id: raise exc.NotAllowedException( "Can not update scope of workflow that has event triggers " "associated in other tenants. [workflow_identifier=%s]" % identifier ) wf_def.update(values.copy()) return wf_def