def put(self, pack_config_content, pack_ref, requester_user, show_secrets=False): """ Create a new config for a pack. Handles requests: POST /configs/<pack_ref> """ try: config_api = ConfigAPI(pack=pack_ref, values=vars(pack_config_content)) config_api.validate(validate_against_schema=True) except jsonschema.ValidationError as e: raise ValueValidationException(six.text_type(e)) except ValueValidationException as e: raise ValueValidationException(six.text_type(e)) self._dump_config_to_disk(config_api) config_db = ConfigsRegistrar.save_model(config_api) mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets) return ConfigAPI.from_model(config_db, mask_secrets=mask_secrets)
def _validate_parameters(action_params=None, runner_params=None): for param, action_param_meta in six.iteritems(action_params): if 'immutable' in action_param_meta: if param in runner_params: runner_param_meta = runner_params[param] if 'immutable' in runner_param_meta: msg = 'Param %s is declared immutable in runner. ' % param + \ 'Cannot override in action.' raise ValueValidationException(msg) if 'default' not in action_param_meta: msg = 'Immutable param %s requires a default value.' % param raise ValueValidationException(msg)
def _validate_parameters(action_ref, action_params=None, runner_params=None): position_params = {} for action_param, action_param_meta in six.iteritems(action_params): # Check if overridden runner parameters are permitted. if action_param in runner_params: for action_param_attr, value in six.iteritems(action_param_meta): util_schema.validate_runner_parameter_attribute_override( action_ref, action_param, action_param_attr, value, runner_params[action_param].get(action_param_attr), ) if "position" in action_param_meta: pos = action_param_meta["position"] param = position_params.get(pos, None) if param: msg = ( "Parameters %s and %s have same position %d." % (action_param, param, pos) + " Position values have to be unique." ) raise ValueValidationException(msg) else: position_params[pos] = action_param if "immutable" in action_param_meta: if action_param in runner_params: runner_param_meta = runner_params[action_param] if "immutable" in runner_param_meta: msg = ( "Param %s is declared immutable in runner. " % action_param + "Cannot override in action." ) raise ValueValidationException(msg) if ( "default" not in action_param_meta and "default" not in runner_param_meta ): msg = "Immutable param %s requires a default value." % action_param raise ValueValidationException(msg) else: if "default" not in action_param_meta: msg = "Immutable param %s requires a default value." % action_param raise ValueValidationException(msg) return _validate_position_values_contiguous(position_params)
def validate_criteria(criteria): if not isinstance(criteria, dict): raise ValueValidationException('Criteria should be a dict.') for key, value in six.iteritems(criteria): operator = value.get('type', None) if operator is None: raise ValueValidationException('Operator not specified for field: ' + key) if operator not in allowed_operators: raise ValueValidationException('For field: ' + key + ', operator ' + operator + ' not in list of allowed operators: ' + str(allowed_operators.keys())) pattern = value.get('pattern', None) if pattern is None: raise ValueValidationException('For field: ' + key + ', no pattern specified ' + 'for operator ' + operator)
def put(self, pack_uninstall_request, pack_ref): """ Create a new config for a pack. Handles requests: POST /configs/<pack_ref> """ try: config_api = ConfigAPI(pack=pack_ref, values=vars(pack_uninstall_request)) config_api.validate(validate_against_schema=True) except jsonschema.ValidationError as e: raise ValueValidationException(str(e)) config_content = yaml.safe_dump(config_api.values, default_flow_style=False) configs_path = os.path.join(cfg.CONF.system.base_path, 'configs/') config_path = os.path.join(configs_path, '%s.yaml' % config_api.pack) with open(config_path, 'w') as f: f.write(config_content) ConfigsRegistrar.save_model(config_api) return config_api
def validate_action(action_api, runner_type_db=None): """ :param runner_type_db: RunnerTypeDB object belonging to this action. If not provided, it's retrieved from the database. :type runner_type_db: :class:`RunnerTypeDB` """ if not runner_type_db: runner_db = get_runner_model(action_api) else: runner_db = runner_type_db # Check if pack is valid. if not _is_valid_pack(action_api.pack): packs_base_paths = get_packs_base_paths() packs_base_paths = ",".join(packs_base_paths) msg = ( 'Content pack "%s" is not found or doesn\'t contain actions directory. ' "Searched in: %s" % (action_api.pack, packs_base_paths) ) raise ValueValidationException(msg) # Check if parameters defined are valid. action_ref = ResourceReference.to_string_reference( pack=action_api.pack, name=action_api.name ) _validate_parameters(action_ref, action_api.parameters, runner_db.runner_parameters)
def validate_action(action_api): runner_db = None # Check if runner exists. try: runner_db = get_runnertype_by_name(action_api.runner_type) except StackStormDBObjectNotFoundError: msg = 'RunnerType %s is not found.' % action_api.runner_type raise ValueValidationException(msg) # Check if pack is valid. if not _is_valid_pack(action_api.pack): msg = 'Content pack %s does not exist in %s.' % ( action_api.pack, cfg.CONF.content.packs_base_path) raise ValueValidationException(msg) # Check if parameters defined are valid. _validate_parameters(action_api.parameters, runner_db.runner_parameters)
def _schedule_execution(self, liveaction, user=None, context_string=None, show_secrets=False): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = user LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if context_string: context = try_loads(context_string) if not isinstance(context, dict): raise ValueError( 'Unable to convert st2-context from the headers into JSON.' ) liveaction.context.update(context) # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) liveaction_db, actionexecution_db = action_service.create_request( liveaction_db) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except ParamException: # By this point the execution is already in the DB therefore need to mark it failed. _, e, tb = sys.exc_info() action_service.update_status(liveaction=liveaction_db, new_status=LIVEACTION_STATUS_FAILED, result={ 'error': str(e), 'traceback': ''.join( traceback.format_tb(tb, 20)) }) # Might be a good idea to return the actual ActionExecution rather than bubble up # the execption. raise ValueValidationException(str(e)) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request( liveaction_db, actionexecution_db) execution_api = ActionExecutionAPI.from_model( actionexecution_db, mask_secrets=(not show_secrets)) return Response(json=execution_api, status=http_client.CREATED)
def _get_runner_model(action_api): runner_db = None # Check if runner exists. try: runner_db = get_runnertype_by_name(action_api.runner_type) except StackStormDBObjectNotFoundError: msg = 'RunnerType %s is not found.' % action_api.runner_type raise ValueValidationException(msg) return runner_db
def validate_criteria(criteria): if not isinstance(criteria, dict): raise ValueValidationException("Criteria should be a dict.") for key, value in six.iteritems(criteria): operator = value.get("type", None) if operator is None: raise ValueValidationException( "Operator not specified for field: " + key) if operator not in allowed_operators: raise ValueValidationException( "For field: " + key + ", operator " + operator + " not in list of allowed operators: " + str(list(allowed_operators.keys()))) pattern = value.get("pattern", None) if pattern is None: raise ValueValidationException("For field: " + key + ", no pattern specified " + "for operator " + operator)
def validate_action(action_api): runner_db = _get_runner_model(action_api) # Check if pack is valid. if not _is_valid_pack(action_api.pack): msg = 'Content pack "%s" doesn\'t exist in any of the packs paths' % (action_api.pack) raise ValueValidationException(msg) # Check if parameters defined are valid. _validate_parameters(action_api.parameters, runner_db.runner_parameters)
def _validate_position_values_contiguous(position_params): if not position_params: return True positions = sorted(position_params.keys()) contiguous = positions == list(range(min(positions), max(positions) + 1)) if not contiguous: msg = "Positions supplied %s for parameters are not contiguous." % positions raise ValueValidationException(msg) return True
def validate_config_against_schema(config_schema, config_object, config_path, pack_name=None): """ Validate provided config dictionary against the provided config schema dictionary. """ # NOTE: Lazy improt to avoid performance overhead of importing this module when it's not used import jsonschema pack_name = pack_name or "unknown" schema = util_schema.get_schema_for_resource_parameters( parameters_schema=config_schema, allow_additional_properties=True) instance = config_object try: cleaned = util_schema.validate( instance=instance, schema=schema, cls=util_schema.CustomValidator, use_default=True, allow_default_none=True, ) for key in cleaned: if (jinja_utils.is_jinja_expression(value=cleaned.get(key)) and "decrypt_kv" in cleaned.get(key) and config_schema.get(key).get("secret")): raise ValueValidationException( 'Values specified as "secret: True" in config ' "schema are automatically decrypted by default. Use " 'of "decrypt_kv" jinja filter is not allowed for ' "such values. Please check the specified values in " "the config or the default values in the schema.") except jsonschema.ValidationError as e: attribute = getattr(e, "path", []) if isinstance(attribute, (tuple, list, Iterable)): attribute = [str(item) for item in attribute] attribute = ".".join(attribute) else: attribute = str(attribute) msg = 'Failed validating attribute "%s" in config for pack "%s" (%s): %s' % ( attribute, pack_name, config_path, six.text_type(e), ) raise jsonschema.ValidationError(msg) return cleaned
def get_runner_model(action_api): runner_db = None # Check if runner exists. try: runner_db = get_runnertype_by_name(action_api.runner_type) except StackStormDBObjectNotFoundError: msg = ( 'RunnerType %s is not found. If you are using old and deprecated runner name, you ' 'need to switch to a new one. For more information, please see ' 'https://docs.stackstorm.com/upgrade_notes.html#st2-v0-9' % (action_api.runner_type)) raise ValueValidationException(msg) return runner_db
def validate_action(action_api): runner_db = _get_runner_model(action_api) # Check if pack is valid. if not _is_valid_pack(action_api.pack): packs_base_paths = get_packs_base_paths() packs_base_paths = ','.join(packs_base_paths) msg = ( 'Content pack "%s" is not found or doesn\'t contain actions directory. ' 'Searched in: %s' % (action_api.pack, packs_base_paths)) raise ValueValidationException(msg) # Check if parameters defined are valid. _validate_parameters(action_api.parameters, runner_db.runner_parameters)
def _validate_parameters(action_ref, action_params=None, runner_params=None): for action_param, action_param_meta in six.iteritems(action_params): # Check if overridden runner parameters are permitted. if action_param in runner_params: for action_param_attr, value in six.iteritems(action_param_meta): util_schema.validate_runner_parameter_attribute_override( action_ref, action_param, action_param_attr, value, runner_params[action_param].get(action_param_attr)) if 'immutable' in action_param_meta: if action_param in runner_params: runner_param_meta = runner_params[action_param] if 'immutable' in runner_param_meta: msg = 'Param %s is declared immutable in runner. ' % action_param + \ 'Cannot override in action.' raise ValueValidationException(msg) if 'default' not in action_param_meta and 'default' not in runner_param_meta: msg = 'Immutable param %s requires a default value.' % action_param raise ValueValidationException(msg) else: if 'default' not in action_param_meta: msg = 'Immutable param %s requires a default value.' % action_param raise ValueValidationException(msg)
def _validate_parameters(action_ref, action_params=None, runner_params=None): position_params = {} for action_param, action_param_meta in six.iteritems(action_params): # Check if overridden runner parameters are permitted. if action_param in runner_params: for action_param_attr, value in six.iteritems(action_param_meta): util_schema.validate_runner_parameter_attribute_override( action_ref, action_param, action_param_attr, value, runner_params[action_param].get(action_param_attr)) if 'position' in action_param_meta: pos = action_param_meta['position'] param = position_params.get(pos, None) if param: msg = ('Parameters %s and %s have same position %d.' % (action_param, param, pos) + ' Position values have to be unique.') raise ValueValidationException(msg) else: position_params[pos] = action_param if 'immutable' in action_param_meta: if action_param in runner_params: runner_param_meta = runner_params[action_param] if 'immutable' in runner_param_meta: msg = 'Param %s is declared immutable in runner. ' % action_param + \ 'Cannot override in action.' raise ValueValidationException(msg) if 'default' not in action_param_meta and 'default' not in runner_param_meta: msg = 'Immutable param %s requires a default value.' % action_param raise ValueValidationException(msg) else: if 'default' not in action_param_meta: msg = 'Immutable param %s requires a default value.' % action_param raise ValueValidationException(msg) return _validate_position_values_contiguous(position_params)
def validate_not_part_of_system_pack(resource_db): """ Validate that the provided resource database object doesn't belong to a system level pack. If it does, ValueValidationException is thrown. :param resource_db: Resource database object to check. :type resource_db: ``object`` """ pack = getattr(resource_db, 'pack', None) if pack == SYSTEM_PACK_NAME: msg = 'Resources belonging to system level packs can\'t be manipulated' raise ValueValidationException(msg) return resource_db
def _schedule_execution(self, liveaction): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = get_requester() LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if 'st2-context' in pecan.request.headers and pecan.request.headers[ 'st2-context']: context = jsonify.try_loads(pecan.request.headers['st2-context']) if not isinstance(context, dict): raise ValueError( 'Unable to convert st2-context from the headers into JSON.' ) liveaction.context.update(context) # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) liveaction_db, actionexecution_db = action_service.create_request( liveaction_db) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except ParamException as e: raise ValueValidationException(str(e)) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request( liveaction_db, actionexecution_db) from_model_kwargs = self._get_from_model_kwargs_for_request( request=pecan.request) return ActionExecutionAPI.from_model(actionexecution_db, from_model_kwargs)
def validate_not_part_of_system_pack_by_name(pack_name): if pack_name in SYSTEM_PACK_NAMES: msg = "Resources belonging to system level packs can't be manipulated" raise ValueValidationException(msg)