def post(self, request): """Creates a new recipe type and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') version = rest_util.parse_string(request, 'version') title = rest_util.parse_string(request, 'title', default_value=name) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition') # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') is_active = trigger_rule_dict['is_active'] if 'is_active' in trigger_rule_dict else True # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for new recipe type: %s', name) raise BadParameter(unicode(ex)) try: with transaction.atomic(): # Validate the recipe definition recipe_def = RecipeDefinition(definition_dict) # Attempt to create the trigger rule trigger_rule = None if rule_handler and 'configuration' in trigger_rule_dict: trigger_rule = rule_handler.create_trigger_rule(trigger_rule_dict['configuration'], name, is_active) # Create the recipe type recipe_type = RecipeType.objects.create_recipe_type(name, version, title, description, recipe_def, trigger_rule) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule, InvalidRecipeConnection) as ex: logger.exception('Unable to create new recipe type: %s', name) raise BadParameter(unicode(ex)) # Fetch the full recipe type with details try: recipe_type = RecipeType.objects.get_details(recipe_type.id) except RecipeType.DoesNotExist: raise Http404 url = urlresolvers.reverse('recipe_type_details_view', args=[recipe_type.id]) serializer = RecipeTypeDetailsSerializer(recipe_type) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url))
def post(self, request): """Validates a new recipe type and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') version = rest_util.parse_string(request, 'version') title = rest_util.parse_string(request, 'title', default_value=name) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition') # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for recipe validation: %s', name) raise BadParameter(unicode(ex)) # Attempt to look up the trigger rule configuration trigger_config = None if rule_handler and 'configuration' in trigger_rule_dict: try: trigger_config = rule_handler.create_configuration(trigger_rule_dict['configuration']) except InvalidTriggerRule as ex: logger.exception('Invalid trigger rule configuration for recipe validation: %s', name) raise BadParameter(unicode(ex)) # Validate the recipe definition try: recipe_def = RecipeDefinition(definition_dict) warnings = RecipeType.objects.validate_recipe_type(name, title, version, description, recipe_def, trigger_config) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule, InvalidRecipeConnection) as ex: logger.exception('Unable to validate new recipe type: %s', name) raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results})
def post(self, request): """Validates a new batch and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ recipe_type_id = rest_util.parse_int(request, 'recipe_type_id') # Make sure the recipe type exists try: recipe_type = RecipeType.objects.get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise BadParameter('Unknown recipe type: %i' % recipe_type_id) # Validate the batch definition definition_dict = rest_util.parse_dict(request, 'definition') definition = None try: if definition_dict: definition = BatchDefinition(definition_dict) except InvalidDefinition as ex: raise BadParameter('Batch definition invalid: %s' % unicode(ex)) # Get a rough estimate of how many recipes will be affected old_recipes = Batch.objects.get_matched_recipes(recipe_type, definition) return Response({ 'recipe_count': old_recipes.count(), 'warnings': [], })
def create(self, request): """Creates a new Strike process and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) configuration = rest_util.parse_dict(request, 'configuration') try: strike = Strike.objects.create_strike(name, title, description, configuration) except InvalidStrikeConfiguration as ex: raise BadParameter('Strike configuration invalid: %s' % unicode(ex)) # Fetch the full strike process with details try: strike = Strike.objects.get_details(strike.id) except Strike.DoesNotExist: raise Http404 serializer = StrikeDetailsSerializer(strike) strike_url = urlresolvers.reverse('strike_details_view', args=[strike.id]) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=strike_url))
def patch(self, request, strike_id): """Edits an existing Strike process and returns the updated details :param request: the HTTP GET request :type request: :class:`rest_framework.request.Request` :param strike_id: The ID of the Strike process :type strike_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) configuration = rest_util.parse_dict(request, 'configuration', required=False) try: Strike.objects.edit_strike(strike_id, title, description, configuration) strike = Strike.objects.get_details(strike_id) except Strike.DoesNotExist: raise Http404 except InvalidStrikeConfiguration as ex: logger.exception('Unable to edit Strike process: %s', strike_id) raise BadParameter(unicode(ex)) serializer = self.get_serializer(strike) return Response(serializer.data)
def post(self, request): """Validates a new Strike process and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') configuration = rest_util.parse_dict(request, 'configuration') rest_util.parse_string(request, 'title', required=False) rest_util.parse_string(request, 'description', required=False) # Validate the Strike configuration try: config = StrikeConfiguration(configuration) warnings = config.validate() except InvalidStrikeConfiguration as ex: logger.exception('Unable to validate new Strike process: %s', name) raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results})
def post(self, request): """Creates a new job, places it on the queue, and returns the new job information in JSON form :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ job_type_id = rest_util.parse_int(request, 'job_type_id') job_data = rest_util.parse_dict(request, 'job_data', {}) try: job_type = JobType.objects.get(pk=job_type_id) except JobType.DoesNotExist: raise Http404 try: job_id, job_exe_id = Queue.objects.queue_new_job_for_user(job_type, job_data) except InvalidData: return Response('Invalid job information.', status=status.HTTP_400_BAD_REQUEST) job_details = Job.objects.get_details(job_id) serializer = JobDetailsSerializer(job_details, context={'request': request}) job_exe_url = urlresolvers.reverse('job_execution_details_view', args=[job_exe_id]) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=job_exe_url))
def post(self, request): """Queue a recipe and returns the new job information in JSON form :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ recipe_type_id = rest_util.parse_int(request, 'recipe_type_id') recipe_data = rest_util.parse_dict(request, 'recipe_data', {}) try: recipe_type = RecipeType.objects.get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise Http404 try: recipe_id = Queue.objects.queue_new_recipe_for_user(recipe_type, recipe_data) except InvalidData: return Response('Invalid recipe information.', status=status.HTTP_400_BAD_REQUEST) recipe_details = Recipe.objects.get_details(recipe_id) serializer = RecipeDetailsSerializer(recipe_details, context={'request': request}) recipe_url = urlresolvers.reverse('recipe_details_view', args=[recipe_id]) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=recipe_url))
def patch(self, request, workspace_id): """Edits an existing workspace and returns the updated details :param request: the HTTP GET request :type request: :class:`rest_framework.request.Request` :param workspace_id: The ID for the workspace. :type workspace_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ title = rest_util.parse_string(request, "title", required=False) description = rest_util.parse_string(request, "description", required=False) json_config = rest_util.parse_dict(request, "json_config", required=False) base_url = rest_util.parse_string(request, "base_url", required=False) is_active = rest_util.parse_string(request, "is_active", required=False) try: Workspace.objects.edit_workspace(workspace_id, title, description, json_config, base_url, is_active) workspace = Workspace.objects.get_details(workspace_id) except Workspace.DoesNotExist: raise Http404 except InvalidWorkspaceConfiguration as ex: logger.exception("Unable to edit workspace: %s", workspace_id) raise BadParameter(unicode(ex)) serializer = self.get_serializer(workspace) return Response(serializer.data)
def post(self, request): """Validates a new workspace and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, "name") json_config = rest_util.parse_dict(request, "json_config") rest_util.parse_string(request, "title", required=False) rest_util.parse_string(request, "description", required=False) rest_util.parse_string(request, "base_url", required=False) rest_util.parse_string(request, "is_active", required=False) # Validate the workspace configuration try: warnings = Workspace.objects.validate_workspace(name, json_config) except InvalidWorkspaceConfiguration as ex: logger.exception("Unable to validate new workspace: %s", name) raise BadParameter(unicode(ex)) results = [{"id": w.key, "details": w.details} for w in warnings] return Response({"warnings": results})
def post(self, request): """Queue a recipe and returns the new job information in JSON form :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ recipe_type_id = rest_util.parse_int(request, 'recipe_type_id') recipe_data = rest_util.parse_dict(request, 'recipe_data', {}) try: recipe_type = RecipeType.objects.get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise Http404 try: handler = Queue.objects.queue_new_recipe_for_user(recipe_type, RecipeData(recipe_data)) except InvalidRecipeData as err: return Response('Invalid recipe data: ' + unicode(err), status=status.HTTP_400_BAD_REQUEST) try: recipe = Recipe.objects.get_details(handler.recipe.id) except Recipe.DoesNotExist: raise Http404 serializer = self.get_serializer(recipe) recipe_url = reverse('recipe_details_view', args=[recipe.id], request=request) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=recipe_url))
def patch(self, request, job_type_id): '''Modify job type info with a subset of fields :param request: the HTTP GET request :type request: :class:`rest_framework.request.Request` :param job_type_id: The ID for the job type. :type job_type_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user ''' # Validate that no extra fields are included rest_util.check_update(request, [u'error_mapping', u'is_paused']) # Validate JSON error_mapping = rest_util.parse_dict(request, u'error_mapping', required=False) is_paused = rest_util.parse_bool(request, u'is_paused', required=False) if error_mapping is not None: try: ErrorInterface(error_mapping) except InvalidInterfaceDefinition: return Response(u'Input failed schema validation.', status=status.HTTP_400_BAD_REQUEST) try: if error_mapping is not None: JobType.objects.update_error_mapping(error_mapping, job_type_id) if is_paused is not None: Queue.objects.update_job_type_pause(job_type_id, is_paused) job_type = JobType.objects.get_details(job_type_id) serializer = JobTypeDetailsSerializer(job_type) return Response(serializer.data, status=status.HTTP_200_OK) except JobType.DoesNotExist: raise Http404
def create(self, request): """Creates a new Workspace and returns it in JSON form :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, "name") title = rest_util.parse_string(request, "title", required=False) description = rest_util.parse_string(request, "description", required=False) json_config = rest_util.parse_dict(request, "json_config") base_url = rest_util.parse_string(request, "base_url", required=False) is_active = rest_util.parse_bool(request, "is_active", default_value=True, required=False) try: workspace = Workspace.objects.create_workspace(name, title, description, json_config, base_url, is_active) except InvalidWorkspaceConfiguration as ex: logger.exception("Unable to create new workspace: %s", name) raise BadParameter(unicode(ex)) # Fetch the full workspace with details try: workspace = Workspace.objects.get_details(workspace.id) except Workspace.DoesNotExist: raise Http404 serializer = WorkspaceDetailsSerializer(workspace) workspace_url = reverse("workspace_details_view", args=[workspace.id], request=request) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=workspace_url))
def test_parse_dict(self): '''Tests parsing a dictionary.''' result = { 'name': 'value', } request = MagicMock(Request) request.QUERY_PARAMS = QueryDict('', mutable=True) request.QUERY_PARAMS.update({ 'test': result, }) self.assertDictEqual(rest_util.parse_dict(request, 'test'), result)
def test_parse_dict(self): """Tests parsing a dictionary.""" result = { 'name': 'value', } request = MagicMock(Request) request.query_params = QueryDict('', mutable=True) request.query_params.update({ 'test': result, }) self.assertDictEqual(rest_util.parse_dict(request, 'test'), result)
def post(self, request): '''Validates job and recipe configuration to make sure it can be imported. :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user ''' import_dict = rest_util.parse_dict(request, 'import') try: warnings = importer.validate_config(import_dict) except InvalidConfiguration as ex: logger.exception('Unable to validate import configuration.') raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results}, status=status.HTTP_200_OK)
def post(self, request): """Imports job and recipe configuration and updates the corresponding models. :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ import_dict = rest_util.parse_dict(request, 'import') try: warnings = importer.import_config(import_dict) except InvalidConfiguration as ex: logger.exception('Unable to import configuration.') raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results})
def post(self, request): '''Creates a new Strike process and returns its ID in JSON form :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user ''' name = rest_util.parse_string(request, 'name') title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) configuration = rest_util.parse_dict(request, 'configuration') try: strike = Strike.objects.create_strike_process(name, title, description, configuration) except InvalidStrikeConfiguration: raise BadParameter('Configuration failed to validate.') return Response({'strike_id': strike.id})
def create(self, request): """Creates a new batch and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ recipe_type_id = rest_util.parse_int(request, 'recipe_type_id') title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) # Make sure the recipe type exists try: recipe_type = RecipeType.objects.get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise BadParameter('Unknown recipe type: %i' % recipe_type_id) # Validate the batch definition definition_dict = rest_util.parse_dict(request, 'definition') definition = None try: if definition_dict: definition = BatchDefinition(definition_dict) except InvalidDefinition as ex: raise BadParameter('Batch definition invalid: %s' % unicode(ex)) # Create the batch batch = Batch.objects.create_batch(recipe_type, definition, title=title, description=description) # Fetch the full batch with details try: batch = Batch.objects.get_details(batch.id) except Batch.DoesNotExist: raise Http404 url = reverse('batch_details_view', args=[batch.id], request=request) serializer = BatchDetailsSerializer(batch) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url))
def post(self, request): '''Validates a new recipe type and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user ''' name = rest_util.parse_string(request, u'name') version = rest_util.parse_string(request, u'version') description = rest_util.parse_string(request, u'description', '') definition = rest_util.parse_dict(request, u'definition') try: recipe_def = RecipeDefinition(definition) warnings = RecipeType.objects.validate_recipe_type(name, version, description, recipe_def) except InvalidDefinition as ex: logger.exception('Unable to validate new recipe type: %s', name) raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({u'warnings': results}, status=status.HTTP_200_OK)
def post(self, request): '''Creates a new recipe type and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user ''' name = rest_util.parse_string(request, u'name') version = rest_util.parse_string(request, u'version') title = rest_util.parse_string(request, u'title') description = rest_util.parse_string(request, u'description', '') definition = rest_util.parse_dict(request, u'definition') try: recipe_def = RecipeDefinition(definition) recipe_type = RecipeType.objects.create_recipe_type(name, version, title, description, recipe_def, None) except InvalidDefinition: logger.exception('Unable to create new recipe type: %s', name) raise BadParameter('Invalid recipe type definition') url = urlresolvers.reverse('recipe_type_details_view', args=[recipe_type.id]) return Response({u'id': recipe_type.id}, status=status.HTTP_201_CREATED, headers=dict(location=url))
def _create_v6(self, request): """Creates a new recipe type and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ title = rest_util.parse_string(request, 'title', required=True) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition', required=True) basename = title_to_basename(title) if basename == 'validation': logger.exception('Unable to create recipe type named "validation"') raise BadParameter( unicode('Unable to create recipe type named "validation"')) existing_recipes = RecipeType.objects.filter(name=basename) if existing_recipes.count() > 0: logger.exception( 'Existing recipe types found for %s - will not re-create.', basename) raise BadParameter( unicode( 'Existing recipe types found for %s - will not re-create. Please change the title or patch the existing recipe type.' % basename)) name = title_to_name(self.queryset, title) try: with transaction.atomic(): # Validate the recipe definition recipe_def = RecipeDefinitionV6( definition=definition_dict, do_validate=True).get_definition() # Create the recipe type recipe_type = RecipeType.objects.create_recipe_type_v6( name, title, description, recipe_def) except InvalidDefinition as ex: logger.exception('Unable to create new recipe type: %s', name) raise BadParameter(unicode(ex)) # Fetch the full recipe type with details try: recipe_type = RecipeType.objects.get_details_v6(recipe_type.name) except RecipeType.DoesNotExist: raise Http404 url = reverse('recipe_type_details_view', args=[recipe_type.name], request=request) serializer = RecipeTypeDetailsSerializerV6(recipe_type) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url))
def _post_v6(self, request, recipe_id): """Schedules a recipe for reprocessing and returns it in JSON form :param request: the HTTP GET request :type request: :class:`rest_framework.request.Request` :param recipe_id: The id of the recipe :type recipe_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ forced_nodes_json = rest_util.parse_dict(request, 'forced_nodes', required=True) revision_num = rest_util.parse_dict(request, 'revision_num', required=False) try: forced_nodes = ForcedNodesV6(forced_nodes_json, do_validate=True) except InvalidDiff as ex: logger.exception('Unable to reprocess recipe. Invalid input: %s', forced_nodes_json) raise BadParameter(unicode(ex)) try: recipe = Recipe.objects.select_related('recipe_type').get( id=recipe_id) if revision_num: recipe.recipe_type_rev = RecipeTypeRevision.objects.get_revision( recipe.recipe_type.name, revision_num) else: revision_num = recipe.recipe_type.revision_num recipe.recipe_type_rev = RecipeTypeRevision.objects.get_revision( recipe.recipe_type.name, recipe.recipe_type.revision_num) except Recipe.DoesNotExist: raise Http404 except RecipeTypeRevision.DoesNotExist: raise Http404 if recipe.is_superseded: raise BadParameter('Cannot reprocess a superseded recipe') validation = recipe.recipe_type_rev.validate_forced_nodes( forced_nodes_json) if not validation.is_valid: raise BadParameter( 'Unable to reprocess recipe. Errors in validating forced_nodes: %s' % validation.errors) if validation.warnings: logger.warning('Warnings encountered when reprocessing: %s' % validation.warnings) event = TriggerEvent.objects.create_trigger_event( 'USER', None, {'user': '******'}, now()) root_recipe_id = recipe.root_superseded_recipe_id if recipe.root_superseded_recipe_id else recipe.id recipe_type_name = recipe.recipe_type.name # Execute all of the messages to perform the reprocess messages = create_reprocess_messages( [root_recipe_id], recipe_type_name, revision_num, event.id, forced_nodes=forced_nodes.get_forced_nodes()) CommandMessageManager().send_messages(messages) return Response(status=status.HTTP_202_ACCEPTED)
def post(self, request): """Validates a new recipe type and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') version = rest_util.parse_string(request, 'version') title = rest_util.parse_string(request, 'title', default_value=name) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition') # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter( 'Trigger type and configuration are required together.') # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler( trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception( 'Invalid trigger type for recipe validation: %s', name) raise BadParameter(unicode(ex)) # Attempt to look up the trigger rule configuration trigger_config = None if rule_handler and 'configuration' in trigger_rule_dict: try: trigger_config = rule_handler.create_configuration( trigger_rule_dict['configuration']) except InvalidTriggerRule as ex: logger.exception( 'Invalid trigger rule configuration for recipe validation: %s', name) raise BadParameter(unicode(ex)) # Validate the recipe definition try: recipe_def = RecipeDefinition(definition_dict) warnings = RecipeType.objects.validate_recipe_type( name, title, version, description, recipe_def, trigger_config) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule, InvalidRecipeConnection) as ex: logger.exception('Unable to validate new recipe type: %s', name) raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results})
def post(self, request): """Validates a new job type and returns any warnings discovered :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') version = rest_util.parse_string(request, 'version') # Validate the job interface interface_dict = rest_util.parse_dict(request, 'interface') interface = None try: if interface_dict: interface = JobInterface(interface_dict) except InvalidInterfaceDefinition as ex: raise BadParameter('Job type interface invalid: %s' % unicode(ex)) # Validate the error mapping error_dict = rest_util.parse_dict(request, 'error_mapping', required=False) error_mapping = None try: if error_dict: error_mapping = ErrorInterface(error_dict) except InvalidInterfaceDefinition as ex: raise BadParameter('Job type error mapping invalid: %s' % unicode(ex)) # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for job validation: %s', name) raise BadParameter(unicode(ex)) # Attempt to look up the trigger rule configuration trigger_config = None if rule_handler and 'configuration' in trigger_rule_dict: try: trigger_config = rule_handler.create_configuration(trigger_rule_dict['configuration']) except InvalidTriggerRule as ex: logger.exception('Invalid trigger rule configuration for job validation: %s', name) raise BadParameter(unicode(ex)) try: from recipe.configuration.definition.exceptions import InvalidDefinition except: logger.exception('Failed to import higher level recipe application.') pass # Validate the job interface try: warnings = JobType.objects.validate_job_type(name, version, interface, error_mapping, trigger_config) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule) as ex: logger.exception('Unable to validate new job type: %s', name) raise BadParameter(unicode(ex)) results = [{'id': w.key, 'details': w.details} for w in warnings] return Response({'warnings': results})
def create_all_v6(self, request): """Creates or edits a dataset - including the dataset members - and returns a link to the detail URL""" title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) definition = rest_util.parse_dict(request, 'definition', required=True) template = rest_util.parse_dict(request, 'data_template', required=False) dry_run = rest_util.parse_bool(request, 'dry_run', default_value=False) # file filters data_started = rest_util.parse_timestamp(request, 'data_started', required=False) data_ended = rest_util.parse_timestamp(request, 'data_ended', required=False) rest_util.check_time_range(data_started, data_ended) created_started = rest_util.parse_timestamp(request, 'created_started', required=False) created_ended = rest_util.parse_timestamp(request, 'created_ended', required=False) rest_util.check_time_range(created_started, created_ended) source_started = rest_util.parse_timestamp(request, 'source_started', required=False) source_ended = rest_util.parse_timestamp(request, 'source_ended', required=False) rest_util.check_time_range(source_started, source_ended) source_sensor_classes = rest_util.parse_string_list( request, 'source_sensor_class', required=False) source_sensors = rest_util.parse_string_list(request, 'source_sensor', required=False) source_collections = rest_util.parse_string_list(request, 'source_collection', required=False) source_tasks = rest_util.parse_string_list(request, 'source_task', required=False) mod_started = rest_util.parse_timestamp(request, 'modified_started', required=False) mod_ended = rest_util.parse_timestamp(request, 'modified_ended', required=False) rest_util.check_time_range(mod_started, mod_ended) job_type_ids = rest_util.parse_int_list(request, 'job_type_id', required=False) job_type_names = rest_util.parse_string_list(request, 'job_type_name', required=False) job_ids = rest_util.parse_int_list(request, 'job_id', required=False) file_names = rest_util.parse_string_list(request, 'file_name', required=False) file_name_search = rest_util.parse_string(request, 'file_name_search', required=False) job_outputs = rest_util.parse_string_list(request, 'job_output', required=False) recipe_ids = rest_util.parse_int_list(request, 'recipe_id', required=False) recipe_type_ids = rest_util.parse_int_list(request, 'recipe_type_id', required=False) recipe_nodes = rest_util.parse_string_list(request, 'recipe_node', required=False) batch_ids = rest_util.parse_int_list(request, 'batch_id', required=False) file_types = rest_util.parse_string_list(request, 'file_type', required=False) order = rest_util.parse_string_list(request, 'order', required=False) media_type = rest_util.parse_string_list(request, 'media_type', required=False) data = rest_util.parse_dict_list(request, 'data', required=False) data_list = [] # validate the definition & create the dataset try: dataset_def = DataSetDefinitionV6( definition=definition, do_validate=True).get_definition() except InvalidDataSetDefinition as ex: message = 'DataSet definition is invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) try: dataset = DataSet.objects.create_dataset_v6( dataset_def, title=title, description=description) except Exception as ex: message = 'Unable to create new dataset' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) try: dataset = DataSet.objects.get_details_v6(dataset.id) except DataSet.DoesNotExist: raise Http404 if not data and not template: url = reverse('dataset_details_view', args=[dataset.id], request=request) serializer = DataSetDetailsSerializerV6(dataset) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url)) # Try and find the data if data: try: for d in data: data = DataV6(data=d, do_validate=True).get_data() data_list.append(data) except InvalidData as ex: message = 'Data is invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) elif template: try: data_list = DataSetMember.objects.build_data_list( template=template, data_started=data_started, data_ended=data_ended, created_started=created_started, created_ended=created_ended, source_started=source_started, source_ended=source_ended, source_sensor_classes=source_sensor_classes, source_sensors=source_sensors, source_collections=source_collections, source_tasks=source_tasks, mod_started=mod_started, mod_ended=mod_ended, job_type_ids=job_type_ids, job_type_names=job_type_names, job_ids=job_ids, file_names=file_names, file_name_search=file_name_search, job_outputs=job_outputs, recipe_ids=recipe_ids, recipe_type_ids=recipe_type_ids, recipe_nodes=recipe_nodes, batch_ids=batch_ids, order=order, file_type=file_types, media_type=media_type) except InvalidData as ex: message = 'Data is invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) if not data_list: resp_dict = { 'No Results': 'No files found from filters and/or no data provided' } return Response(resp_dict) validation = DataSetMember.objects.validate_data_list( dataset_def=dataset_def, data_list=data_list) members = [] if validation.is_valid and not dry_run: members = DataSetMember.objects.create_dataset_members( dataset=dataset, data_list=data_list) dataset = DataSet.objects.get(id=dataset.id) serializer = DataSetDetailsSerializerV6(dataset) url = reverse('dataset_details_view', args=[dataset.id], request=request) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url)) elif not validation.is_valid: raise BadParameter('%s: %s' % ('Error(s) validating data against dataset', [e.to_dict() for e in validation.errors])) resp_dict = [] for dl in data_list: resp_dict.append(convert_data_to_v6_json(dl).get_dict()) return Response(resp_dict)
def test_parse_dict_optional(self): """Tests parsing an optional dict with no default value.""" request = MagicMock(Request) request.query_params = QueryDict('', mutable=True) self.assertDictEqual(rest_util.parse_dict(request, 'test', required=False), {})
def patch(self, request, job_type_id): """Edits an existing job type and returns the updated details :param request: the HTTP GET request :type request: :class:`rest_framework.request.Request` :param job_type_id: The ID for the job type. :type job_type_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ # Validate the job interface interface_dict = rest_util.parse_dict(request, 'interface', required=False) interface = None try: if interface_dict: interface = JobInterface(interface_dict) except InvalidInterfaceDefinition as ex: raise BadParameter('Job type interface invalid: %s' % unicode(ex)) # Validate the error mapping error_dict = rest_util.parse_dict(request, 'error_mapping', required=False) error_mapping = None try: if error_dict: error_mapping = ErrorInterface(error_dict) error_mapping.validate() except InvalidInterfaceDefinition as ex: raise BadParameter('Job type error mapping invalid: %s' % unicode(ex)) # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') is_active = trigger_rule_dict['is_active'] if 'is_active' in trigger_rule_dict else True remove_trigger_rule = rest_util.has_params(request, 'trigger_rule') and not trigger_rule_dict # Fetch the current job type model try: job_type = JobType.objects.select_related('trigger_rule').get(pk=job_type_id) except JobType.DoesNotExist: raise Http404 # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for job type: %i', job_type_id) raise BadParameter(unicode(ex)) # Extract the fields that should be updated as keyword arguments extra_fields = {} base_fields = {'name', 'version', 'interface', 'trigger_rule', 'error_mapping'} for key, value in request.data.iteritems(): if key not in base_fields and key not in JobType.UNEDITABLE_FIELDS: extra_fields[key] = value try: from recipe.configuration.definition.exceptions import InvalidDefinition except: logger.exception('Failed to import higher level recipe application.') pass try: with transaction.atomic(): # Attempt to create the trigger rule trigger_rule = None if rule_handler and 'configuration' in trigger_rule_dict: trigger_rule = rule_handler.create_trigger_rule(trigger_rule_dict['configuration'], job_type.name, is_active) # Update the active state separately if that is only given trigger field if not trigger_rule and job_type.trigger_rule and 'is_active' in trigger_rule_dict: job_type.trigger_rule.is_active = is_active job_type.trigger_rule.save() # Edit the job type JobType.objects.edit_job_type(job_type_id, interface, trigger_rule, remove_trigger_rule, error_mapping, **extra_fields) except (InvalidJobField, InvalidTriggerType, InvalidTriggerRule, InvalidConnection, InvalidDefinition, ValueError) as ex: logger.exception('Unable to update job type: %i', job_type_id) raise BadParameter(unicode(ex)) # Fetch the full job type with details try: job_type = JobType.objects.get_details(job_type.id) except JobType.DoesNotExist: raise Http404 serializer = self.get_serializer(job_type) return Response(serializer.data)
def post(self, request): '''Creates a new JobType and returns its ID in JSON form :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user ''' name = rest_util.parse_string(request, u'name') version = rest_util.parse_string(request, u'version') title = rest_util.parse_string(request, u'title', default_value=u'Unknown Job Type') description = rest_util.parse_string(request, u'description') category = rest_util.parse_string(request, u'category', default_value=u'unknown') author_name = rest_util.parse_string(request, u'author_name', required=False) author_url = rest_util.parse_string(request, u'author_url', required=False) is_system = False is_long_running = False is_active = rest_util.parse_bool(request, u'is_active', default_value=True) is_operational = rest_util.parse_bool(request, u'is_operational', default_value=True) is_paused = rest_util.parse_bool(request, u'is_paused', default_value=False) requires_cleanup = True uses_docker = True docker_privileged = rest_util.parse_bool(request, u'docker_privileged', default_value=False) docker_image = rest_util.parse_string(request, u'docker_image') interface = rest_util.parse_dict(request, u'interface') error_mapping = rest_util.parse_dict(request, u'error_mapping', default_value={}) priority = rest_util.parse_int(request, u'priority', default_value=260) timeout = rest_util.parse_int(request, u'timeout', default_value=1800) max_tries = rest_util.parse_int(request, u'max_tries', default_value=3) cpus_required = rest_util.parse_float(request, u'cpus_required', default_value=1) mem_required = rest_util.parse_float(request, u'mem_required', default_value=5120) disk_out_const_required = rest_util.parse_float(request, u'disk_out_const_required', default_value=0) disk_out_mult_required = rest_util.parse_float(request, u'disk_out_mult_required', default_value=0) icon_code = rest_util.parse_string(request, u'icon_code', default_value=u'f013') try: try: job_type = JobType.objects.get(name=name, version=version) job_type.description = description job_type.docker_image = docker_image job_type.interface = interface job_type.priority = priority job_type.timeout = timeout job_type.max_tries = max_tries job_type.cpus_required = cpus_required job_type.mem_required = mem_required job_type.disk_out_const_required = disk_out_const_required except JobType.DoesNotExist: job_type = JobType.objects.create_job_type(name, version, description, docker_image, interface, priority, timeout, max_tries, cpus_required, mem_required, disk_out_const_required, None) job_type.title = title job_type.category = category job_type.author_name = author_name job_type.author_url = author_url job_type.is_system = is_system job_type.is_long_running = is_long_running job_type.is_active = is_active job_type.is_operational = is_operational job_type.is_paused = is_paused job_type.requires_cleanup = requires_cleanup job_type.uses_docker = uses_docker job_type.docker_privileged = docker_privileged job_type.error_mapping = error_mapping job_type.icon_code = icon_code job_type.disk_out_mult_required = disk_out_mult_required job_type.save() except InvalidInterfaceDefinition: raise rest_util.BadParameter('Interface definition failed to validate.') return Response({'job_type_id': job_type.id}, status=status.HTTP_200_OK)
def create(self, request): """Creates a new job type and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') version = rest_util.parse_string(request, 'version') # Validate the job interface interface_dict = rest_util.parse_dict(request, 'interface') interface = None try: if interface_dict: interface = JobInterface(interface_dict) except InvalidInterfaceDefinition as ex: raise BadParameter('Job type interface invalid: %s' % unicode(ex)) # Validate the error mapping error_dict = rest_util.parse_dict(request, 'error_mapping', required=False) error_mapping = None try: if error_dict: error_mapping = ErrorInterface(error_dict) error_mapping.validate() except InvalidInterfaceDefinition as ex: raise BadParameter('Job type error mapping invalid: %s' % unicode(ex)) # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') is_active = trigger_rule_dict['is_active'] if 'is_active' in trigger_rule_dict else True # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for new job type: %s', name) raise BadParameter(unicode(ex)) # Extract the fields that should be updated as keyword arguments extra_fields = {} base_fields = {'name', 'version', 'interface', 'trigger_rule', 'error_mapping'} for key, value in request.data.iteritems(): if key not in base_fields and key not in JobType.UNEDITABLE_FIELDS: extra_fields[key] = value try: with transaction.atomic(): # Attempt to create the trigger rule trigger_rule = None if rule_handler and 'configuration' in trigger_rule_dict: trigger_rule = rule_handler.create_trigger_rule(trigger_rule_dict['configuration'], name, is_active) # Create the job type job_type = JobType.objects.create_job_type(name, version, interface, trigger_rule, error_mapping, **extra_fields) except (InvalidJobField, InvalidTriggerType, InvalidTriggerRule, InvalidConnection, ValueError) as ex: logger.exception('Unable to create new job type: %s', name) raise BadParameter(unicode(ex)) # Fetch the full job type with details try: job_type = JobType.objects.get_details(job_type.id) except JobType.DoesNotExist: raise Http404 url = urlresolvers.reverse('job_type_details_view', args=[job_type.id]) serializer = JobTypeDetailsSerializer(job_type) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url))
def test_parse_dict_optional(self): '''Tests parsing an optional dict with no default value.''' request = MagicMock(Request) request.QUERY_PARAMS = QueryDict('', mutable=True) self.assertDictEqual(rest_util.parse_dict(request, 'test', required=False), {})
def patch(self, request, recipe_type_id): """Edits an existing recipe type and returns the updated details :param request: the HTTP PATCH request :type request: :class:`rest_framework.request.Request` :param recipe_type_id: The ID for the recipe type. :type recipe_type_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition', required=False) # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') is_active = trigger_rule_dict['is_active'] if 'is_active' in trigger_rule_dict else True remove_trigger_rule = rest_util.has_params(request, 'trigger_rule') and not trigger_rule_dict # Fetch the current recipe type model try: recipe_type = RecipeType.objects.select_related('trigger_rule').get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise Http404 # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for recipe type: %i', recipe_type_id) raise BadParameter(unicode(ex)) try: with transaction.atomic(): # Validate the recipe definition recipe_def = None if definition_dict: recipe_def = RecipeDefinition(definition_dict) # Attempt to create the trigger rule trigger_rule = None if rule_handler and 'configuration' in trigger_rule_dict: trigger_rule = rule_handler.create_trigger_rule(trigger_rule_dict['configuration'], recipe_type.name, is_active) # Update the active state separately if that is only given trigger field if not trigger_rule and recipe_type.trigger_rule and 'is_active' in trigger_rule_dict: recipe_type.trigger_rule.is_active = is_active recipe_type.trigger_rule.save() # Edit the recipe type RecipeType.objects.edit_recipe_type(recipe_type_id, title, description, recipe_def, trigger_rule, remove_trigger_rule) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule, InvalidRecipeConnection) as ex: logger.exception('Unable to update recipe type: %i', recipe_type_id) raise BadParameter(unicode(ex)) # Fetch the full recipe type with details try: recipe_type = RecipeType.objects.get_details(recipe_type_id) except RecipeType.DoesNotExist: raise Http404 serializer = self.get_serializer(recipe_type) return Response(serializer.data)
def test_parse_dict_optional(self): """Tests parsing an optional dict with no default value.""" request = MagicMock(Request) request.query_params = QueryDict('', mutable=True) self.assertDictEqual( rest_util.parse_dict(request, 'test', required=False), {})
def create_v6(self, request): """Creates or edits a Seed job type and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ # Optional icon code value icon_code = rest_util.parse_string(request, 'icon_code', required=False) # Optional is published value is_published = rest_util.parse_string(request, 'is_published', required=False) # Optional max scheduled value max_scheduled = rest_util.parse_int(request, 'max_scheduled', required=False) # Require docker image value docker_image = rest_util.parse_string(request, 'docker_image', required=True) # Validate the job interface / manifest manifest_dict = rest_util.parse_dict(request, 'manifest', required=True) # If editing an existing job type, automatically update recipes containing said job type auto_update = rest_util.parse_bool(request, 'auto_update', required=False) manifest = None try: manifest = SeedManifest(manifest_dict, do_validate=True) except InvalidSeedManifestDefinition as ex: message = 'Seed Manifest invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) # Validate the job configuration and pull out secrets configuration_dict = rest_util.parse_dict(request, 'configuration', required=False) configuration = None if configuration_dict: try: configuration = JobConfigurationV6(configuration_dict, do_validate=True).get_configuration() except InvalidJobConfiguration as ex: message = 'Job type configuration invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) # Check for invalid fields fields = {'icon_code', 'is_published', 'max_scheduled', 'docker_image', 'configuration', 'manifest', 'auto_update'} for key, value in request.data.iteritems(): if key not in fields: raise InvalidJobField name = manifest_dict['job']['name'] version = manifest_dict['job']['jobVersion'] existing_job_type = JobType.objects.filter(name=name, version=version).first() if not existing_job_type: try: # Create the job type job_type = JobType.objects.create_job_type_v6(icon_code=icon_code, is_published=is_published, max_scheduled=max_scheduled, docker_image=docker_image, manifest=manifest, configuration=configuration) except (InvalidJobField, InvalidSecretsConfiguration, ValueError) as ex: message = 'Unable to create new job type' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) except InvalidSeedManifestDefinition as ex: message = 'Job type manifest invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) except InvalidJobConfiguration as ex: message = 'Job type configuration invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) else: try: JobType.objects.edit_job_type_v6(job_type_id=existing_job_type.id, manifest=manifest, docker_image=docker_image, icon_code=icon_code, is_active=None, is_paused=None, max_scheduled=max_scheduled, is_published=is_published, configuration=configuration, auto_update=auto_update) except (InvalidJobField, InvalidSecretsConfiguration, ValueError, InvalidInterfaceDefinition) as ex: logger.exception('Unable to update job type: %i', existing_job_type.id) raise BadParameter(unicode(ex)) except InvalidSeedManifestDefinition as ex: message = 'Job type manifest invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) except InvalidJobConfiguration as ex: message = 'Job type configuration invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) # Fetch the full job type with details try: job_type = JobType.objects.get_details_v6(name, version) except JobType.DoesNotExist: raise Http404 url = reverse('job_type_details_view', args=[job_type.name, job_type.version], request=request) serializer = JobTypeDetailsSerializerV6(job_type) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url))
def post_v6(self, request, dataset_id): """ Adds a datsetmember to the dataset :param request: the HTTP request :type request: :class:`rest_framework.request.Request` :param dataset_id: The id of the dataset :type dataset_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ template = rest_util.parse_dict(request, 'data_template', required=False) dry_run = rest_util.parse_bool(request, 'dry_run', default_value=False) #file filters data_started = rest_util.parse_timestamp(request, 'data_started', required=False) data_ended = rest_util.parse_timestamp(request, 'data_ended', required=False) rest_util.check_time_range(data_started, data_ended) created_started = rest_util.parse_timestamp(request, 'created_started', required=False) created_ended = rest_util.parse_timestamp(request, 'created_ended', required=False) rest_util.check_time_range(created_started, created_ended) source_started = rest_util.parse_timestamp(request, 'source_started', required=False) source_ended = rest_util.parse_timestamp(request, 'source_ended', required=False) rest_util.check_time_range(source_started, source_ended) source_sensor_classes = rest_util.parse_string_list( request, 'source_sensor_class', required=False) source_sensors = rest_util.parse_string_list(request, 'source_sensor', required=False) source_collections = rest_util.parse_string_list(request, 'source_collection', required=False) source_tasks = rest_util.parse_string_list(request, 'source_task', required=False) mod_started = rest_util.parse_timestamp(request, 'modified_started', required=False) mod_ended = rest_util.parse_timestamp(request, 'modified_ended', required=False) rest_util.check_time_range(mod_started, mod_ended) job_type_ids = rest_util.parse_int_list(request, 'job_type_id', required=False) job_type_names = rest_util.parse_string_list(request, 'job_type_name', required=False) job_ids = rest_util.parse_int_list(request, 'job_id', required=False) file_names = rest_util.parse_string_list(request, 'file_name', required=False) job_outputs = rest_util.parse_string_list(request, 'job_output', required=False) recipe_ids = rest_util.parse_int_list(request, 'recipe_id', required=False) recipe_type_ids = rest_util.parse_int_list(request, 'recipe_type_id', required=False) recipe_nodes = rest_util.parse_string_list(request, 'recipe_node', required=False) batch_ids = rest_util.parse_int_list(request, 'batch_id', required=False) file_type = rest_util.parse_string_list(request, 'file_type', required=False) media_type = rest_util.parse_string_list(request, 'media_type', required=False) order = rest_util.parse_string_list(request, 'order', required=False) data = rest_util.parse_dict_list(request, 'data', required=False) data_list = [] try: if data: for d in data: data = DataV6(data=d, do_validate=True).get_data() data_list.append(data) else: data_list = DataSetMember.objects.build_data_list( template=template, data_started=data_started, data_ended=data_ended, created_started=created_started, created_ended=created_ended, source_started=source_started, source_ended=source_ended, source_sensor_classes=source_sensor_classes, source_sensors=source_sensors, source_collections=source_collections, source_tasks=source_tasks, mod_started=mod_started, mod_ended=mod_ended, job_type_ids=job_type_ids, job_type_names=job_type_names, job_ids=job_ids, file_names=file_names, job_outputs=job_outputs, recipe_ids=recipe_ids, recipe_type_ids=recipe_type_ids, recipe_nodes=recipe_nodes, batch_ids=batch_ids, order=order, file_type=file_type, media_type=media_type) except InvalidData as ex: message = 'Data is invalid' logger.exception(message) raise BadParameter('%s: %s' % (message, unicode(ex))) if not data_list: resp_dict = { 'No Results': 'No files found from filters and/or no data provided' } return Response(resp_dict) try: dataset = DataSet.objects.get(pk=dataset_id) except DataSet.DoesNotExist: raise Http404 validation = DataSetMember.objects.validate_data_list( dataset_def=dataset.get_definition(), data_list=data_list) members = [] if validation.is_valid and not dry_run: members = DataSetMember.objects.create_dataset_members( dataset=dataset, data_list=data_list) serializer = DataSetMemberSerializerV6(members, many=True) return Response(serializer.data, status=status.HTTP_201_CREATED) elif not validation.is_valid: raise BadParameter('%s: %s' % ('Error(s) validating data against dataset', [e.to_dict() for e in validation.errors])) resp_dict = [] for dl in data_list: resp_dict.append(convert_data_to_v6_json(dl).get_dict()) return Response(resp_dict)
def patch(self, request, recipe_type_id): """Edits an existing recipe type and returns the updated details :param request: the HTTP PATCH request :type request: :class:`rest_framework.request.Request` :param recipe_type_id: The ID for the recipe type. :type recipe_type_id: int encoded as a str :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ title = rest_util.parse_string(request, 'title', required=False) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition', required=False) # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter('Trigger type and configuration are required together.') is_active = trigger_rule_dict['is_active'] if 'is_active' in trigger_rule_dict else True remove_trigger_rule = rest_util.has_params(request, 'trigger_rule') and not trigger_rule_dict # Fetch the current recipe type model try: recipe_type = RecipeType.objects.select_related('trigger_rule').get(pk=recipe_type_id) except RecipeType.DoesNotExist: raise Http404 # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler(trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception('Invalid trigger type for recipe type: %i', recipe_type_id) raise BadParameter(unicode(ex)) try: with transaction.atomic(): # Validate the recipe definition recipe_def = None if definition_dict: recipe_def = RecipeDefinitionSunset.create(definition_dict) # Attempt to create the trigger rule trigger_rule = None if rule_handler and 'configuration' in trigger_rule_dict: trigger_rule = rule_handler.create_trigger_rule(trigger_rule_dict['configuration'], recipe_type.name, is_active) # Update the active state separately if that is only given trigger field if not trigger_rule and recipe_type.trigger_rule and 'is_active' in trigger_rule_dict: recipe_type.trigger_rule.is_active = is_active recipe_type.trigger_rule.save() # Edit the recipe type RecipeType.objects.edit_recipe_type(recipe_type_id, title, description, recipe_def, trigger_rule, remove_trigger_rule) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule, InvalidRecipeConnection) as ex: logger.exception('Unable to update recipe type: %i', recipe_type_id) raise BadParameter(unicode(ex)) # Fetch the full recipe type with details try: recipe_type = RecipeType.objects.get_details(recipe_type_id) except RecipeType.DoesNotExist: raise Http404 serializer = self.get_serializer(recipe_type) return Response(serializer.data)
def post(self, request): """Creates a new recipe type and returns a link to the detail URL :param request: the HTTP POST request :type request: :class:`rest_framework.request.Request` :rtype: :class:`rest_framework.response.Response` :returns: the HTTP response to send back to the user """ name = rest_util.parse_string(request, 'name') version = rest_util.parse_string(request, 'version') title = rest_util.parse_string(request, 'title', default_value=name) description = rest_util.parse_string(request, 'description', required=False) definition_dict = rest_util.parse_dict(request, 'definition') # Check for optional trigger rule parameters trigger_rule_dict = rest_util.parse_dict(request, 'trigger_rule', required=False) if (('type' in trigger_rule_dict and 'configuration' not in trigger_rule_dict) or ('type' not in trigger_rule_dict and 'configuration' in trigger_rule_dict)): raise BadParameter( 'Trigger type and configuration are required together.') is_active = trigger_rule_dict[ 'is_active'] if 'is_active' in trigger_rule_dict else True # Attempt to look up the trigger handler for the type rule_handler = None if trigger_rule_dict and 'type' in trigger_rule_dict: try: rule_handler = trigger_handler.get_trigger_rule_handler( trigger_rule_dict['type']) except InvalidTriggerType as ex: logger.exception( 'Invalid trigger type for new recipe type: %s', name) raise BadParameter(unicode(ex)) try: with transaction.atomic(): # Validate the recipe definition recipe_def = RecipeDefinition(definition_dict) # Attempt to create the trigger rule trigger_rule = None if rule_handler and 'configuration' in trigger_rule_dict: trigger_rule = rule_handler.create_trigger_rule( trigger_rule_dict['configuration'], name, is_active) # Create the recipe type recipe_type = RecipeType.objects.create_recipe_type( name, version, title, description, recipe_def, trigger_rule) except (InvalidDefinition, InvalidTriggerType, InvalidTriggerRule, InvalidRecipeConnection) as ex: logger.exception('Unable to create new recipe type: %s', name) raise BadParameter(unicode(ex)) # Fetch the full recipe type with details try: recipe_type = RecipeType.objects.get_details(recipe_type.id) except RecipeType.DoesNotExist: raise Http404 url = reverse('recipe_type_details_view', args=[recipe_type.id], request=request) serializer = RecipeTypeDetailsSerializer(recipe_type) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=dict(location=url))