예제 #1
0
    def test_get_blocked_jobs(self):
        """Tests calling RecipeHandler.get_blocked_jobs()"""

        handler = RecipeHandler(self.recipe, self.recipe_jobs)
        blocked_jobs = handler.get_blocked_jobs()
        blocked_job_ids = set()
        for blocked_job in blocked_jobs:
            blocked_job_ids.add(blocked_job.id)

        self.assertSetEqual(blocked_job_ids, {self.job_fa_co_b.id, self.job_qu_ca_a.id, self.job_qu_ca_b.id})
예제 #2
0
    def test_get_blocked_jobs(self):
        """Tests calling RecipeHandler.get_blocked_jobs()"""

        handler = RecipeHandler(self.recipe, self.recipe_jobs)
        blocked_jobs = handler.get_blocked_jobs()
        blocked_job_ids = set()
        for blocked_job in blocked_jobs:
            blocked_job_ids.add(blocked_job.id)

        self.assertSetEqual(
            blocked_job_ids,
            {self.job_fa_co_b.id, self.job_qu_ca_a.id, self.job_qu_ca_b.id})
예제 #3
0
    def create_recipe(self,
                      recipe_type,
                      data,
                      event,
                      superseded_recipe=None,
                      delta=None,
                      superseded_jobs=None):
        """Creates a new recipe for the given type and returns a recipe handler for it. All jobs for the recipe will
        also be created. If the new recipe is superseding an old recipe, superseded_recipe, delta, and superseded_jobs
        must be provided and the caller must have obtained a model lock on all job models in superseded_jobs and on the
        superseded_recipe model. All database changes occur in an atomic transaction.

        :param recipe_type: The type of the recipe to create
        :type recipe_type: :class:`recipe.models.RecipeType`
        :param data: The recipe data to run on, should be None if superseded_recipe is provided
        :type data: :class:`recipe.data.recipe_data.RecipeData`
        :param event: The event that triggered the creation of this recipe
        :type event: :class:`trigger.models.TriggerEvent`
        :param superseded_recipe: The recipe that the created recipe is superseding, possibly None
        :type superseded_recipe: :class:`recipe.models.Recipe`
        :param delta: If not None, represents the changes between the old recipe to supersede and the new recipe
        :type delta: :class:`recipe.handlers.graph_delta.RecipeGraphDelta`
        :param superseded_jobs: If not None, represents the job models (stored by job name) of the old recipe to
            supersede. This mapping must include all jobs created by the previous recipe, not just the ones that will
            actually be replaced by the new recipe definition.
        :type superseded_jobs: {string: :class:`job.models.Job`}
        :returns: A handler for the new recipe
        :rtype: :class:`recipe.handlers.handler.RecipeHandler`

        :raises :class:`recipe.exceptions.CreateRecipeError`: If general recipe parameters are invalid
        :raises :class:`recipe.exceptions.SupersedeError`: If the superseded parameters are invalid
        :raises :class:`recipe.exceptions.ReprocessError`: If recipe cannot be reprocessed
        :raises :class:`recipe.configuration.data.exceptions.InvalidRecipeData`: If the recipe data is invalid
        """

        if not recipe_type.is_active:
            raise CreateRecipeError('Recipe type is no longer active')
        if event is None:
            raise CreateRecipeError(
                'Event that triggered recipe creation is required')

        recipe = Recipe()
        recipe.recipe_type = recipe_type
        recipe.recipe_type_rev = RecipeTypeRevision.objects.get_revision(
            recipe_type.id, recipe_type.revision_num)
        recipe.event = event
        recipe_definition = recipe.get_recipe_definition()
        when = timezone.now()

        if superseded_recipe:
            # Mark superseded recipe
            superseded_recipe.is_superseded = True
            superseded_recipe.superseded = when
            superseded_recipe.save()

            # Use data from superseded recipe
            data = superseded_recipe.get_recipe_data()
            if not delta:
                raise SupersedeError('Cannot supersede a recipe without delta')

            # New recipe references superseded recipe
            root_id = superseded_recipe.root_superseded_recipe_id
            if not root_id:
                root_id = superseded_recipe.id
            recipe.root_superseded_recipe_id = root_id
            recipe.superseded_recipe = superseded_recipe
        else:
            if delta:
                raise SupersedeError(
                    'delta must be provided with a superseded recipe')

        # Validate recipe data and save recipe
        recipe_definition.validate_data(data)
        recipe.data = data.get_dict()
        recipe.save()

        # Save models for each recipe input file
        recipe_files = []
        for input_file_id in data.get_input_file_ids():
            recipe_file = RecipeFile()
            recipe_file.recipe_id = recipe.id
            recipe_file.scale_file_id = input_file_id
            recipe_file.created = recipe.created
            recipe_files.append(recipe_file)
        RecipeFile.objects.bulk_create(recipe_files)

        # Create recipe jobs and link them to the recipe
        recipe_jobs = self._create_recipe_jobs(recipe, event, when, delta,
                                               superseded_jobs)
        handler = RecipeHandler(recipe, recipe_jobs)
        # Block any new jobs that need to be blocked
        jobs_to_blocked = handler.get_blocked_jobs()
        if jobs_to_blocked:
            Job.objects.update_status(jobs_to_blocked, 'BLOCKED', when)
        return handler