Exemplo n.º 1
0
    def run(self, request, class_path):
        if not request.user.has_perm("extras.run_job"):
            raise PermissionDenied(
                "This user does not have permission to run jobs.")

        job_class = self._get_job_class(class_path)
        job = job_class()

        input_serializer = serializers.JobInputSerializer(data=request.data)
        input_serializer.is_valid(raise_exception=True)

        data = input_serializer.data["data"] or {}
        commit = input_serializer.data["commit"]
        if commit is None:
            commit = getattr(job_class.Meta, "commit_default", True)

        try:
            job.validate_data(data)
        except FormsValidationError as e:
            # message_dict can only be accessed if ValidationError got a dict
            # in the constructor (saved as error_dict). Otherwise we get a list
            # of errors under messages
            return Response(
                {
                    "errors":
                    e.message_dict if hasattr(e, "error_dict") else e.messages
                },
                status=400)

        if not get_worker_count():
            raise CeleryWorkerNotRunningException()

        job_content_type = ContentType.objects.get(app_label="extras",
                                                   model="job")

        schedule = input_serializer.data.get("schedule")
        if schedule:
            schedule = self._create_schedule(schedule, data, commit, job,
                                             job_class, request)
        else:
            job_result = JobResult.enqueue_job(
                run_job,
                job.class_path,
                job_content_type,
                request.user,
                data=data,
                request=copy_safe_request(request),
                commit=commit,
            )
            job.result = job_result

        serializer = serializers.JobDetailSerializer(
            job, context={"request": request})

        return Response(serializer.data)
Exemplo n.º 2
0
    def sync(self, request, pk):
        """
        Enqueue pull git repository and refresh data.
        """
        if not request.user.has_perm("extras.change_gitrepository"):
            raise PermissionDenied("This user does not have permission to make changes to Git repositories.")

        if not get_worker_count():
            raise CeleryWorkerNotRunningException()

        repository = get_object_or_404(GitRepository, id=pk)
        enqueue_pull_git_repository_and_refresh_data(repository, request)
        return Response({"message": f"Repository {repository} sync job added to queue."})
Exemplo n.º 3
0
    def post(self, request, slug):
        if not request.user.has_perm("extras.change_gitrepository"):
            return HttpResponseForbidden()

        repository = get_object_or_404(GitRepository.objects.all(), slug=slug)

        # Allow execution only if a worker process is running.
        if not get_worker_count(request):
            messages.error(request, "Unable to run job: Celery worker process not running.")
        else:
            enqueue_pull_git_repository_and_refresh_data(repository, request)

        return redirect("extras:gitrepository_result", slug=slug)
Exemplo n.º 4
0
    def post(self, request, class_path):
        if not request.user.has_perm("extras.run_job"):
            return HttpResponseForbidden()

        job_class = get_job(class_path)
        if job_class is None:
            raise Http404
        job = job_class()
        grouping, module, class_name = class_path.split("/", 2)
        form = job.as_form(request.POST, request.FILES)

        # Allow execution only if a worker process is running.
        if not get_worker_count(request):
            messages.error(
                request,
                "Unable to run job: Celery worker process not running.")
        elif form.is_valid():
            # Run the job. A new JobResult is created.
            commit = form.cleaned_data.pop("_commit")

            job_content_type = ContentType.objects.get(app_label="extras",
                                                       model="job")
            job_result = JobResult.enqueue_job(
                run_job,
                job.class_path,
                job_content_type,
                request.user,
                data=job_class.serialize_data(form.cleaned_data),
                request=copy_safe_request(request),
                commit=commit,
            )

            return redirect("extras:job_jobresult", pk=job_result.pk)

        return render(
            request,
            "extras/job.html",
            {
                "grouping": grouping,
                "module": module,
                "job": job,
                "form": form,
            },
        )
Exemplo n.º 5
0
def _run_job(request, job_model, legacy_response=False):
    """An internal function providing logic shared between JobModelViewSet.run() and JobViewSet.run()."""
    if not request.user.has_perm("extras.run_job"):
        raise PermissionDenied("This user does not have permission to run jobs.")
    if not job_model.enabled:
        raise PermissionDenied("This job is not enabled to be run.")
    if not job_model.installed:
        raise MethodNotAllowed(request.method, detail="This job is not presently installed and cannot be run")

    job_class = job_model.job_class
    if job_class is None:
        raise MethodNotAllowed(request.method, detail="This job's source code could not be located and cannot be run")
    job = job_class()

    input_serializer = serializers.JobInputSerializer(data=request.data)
    input_serializer.is_valid(raise_exception=True)

    data = input_serializer.data["data"] or {}
    commit = input_serializer.data["commit"]
    if commit is None:
        commit = job_model.commit_default

    try:
        job.validate_data(data)
    except FormsValidationError as e:
        # message_dict can only be accessed if ValidationError got a dict
        # in the constructor (saved as error_dict). Otherwise we get a list
        # of errors under messages
        return Response({"errors": e.message_dict if hasattr(e, "error_dict") else e.messages}, status=400)

    if not get_worker_count():
        raise CeleryWorkerNotRunningException()

    job_content_type = get_job_content_type()
    schedule_data = input_serializer.data.get("schedule")

    # Default to a null JobResult.
    job_result = None

    # Assert that a job with `approval_required=True` has a schedule that enforces approval and
    # executes immediately.
    if schedule_data is None and job_model.approval_required:
        schedule_data = {"interval": JobExecutionType.TYPE_IMMEDIATELY}

    # Try to create a ScheduledJob, or...
    if schedule_data:
        schedule = _create_schedule(schedule_data, data, commit, job, job_model, request)
    else:
        schedule = None

    # ... If we can't create one, create a JobResult instead.
    if schedule is None:
        job_result = JobResult.enqueue_job(
            run_job,
            job.class_path,
            job_content_type,
            request.user,
            data=data,
            request=copy_safe_request(request),
            commit=commit,
        )
        job.result = job_result

    if legacy_response:
        # Old-style JobViewSet response - serialize the Job class in the response for some reason?
        serializer = serializers.JobClassDetailSerializer(job, context={"request": request})
        return Response(serializer.data)
    else:
        # New-style JobModelViewSet response - serialize the schedule or job_result as appropriate
        data = {"schedule": None, "job_result": None}
        if schedule:
            data["schedule"] = nested_serializers.NestedScheduledJobSerializer(
                schedule, context={"request": request}
            ).data
        if job_result:
            data["job_result"] = nested_serializers.NestedJobResultSerializer(
                job_result, context={"request": request}
            ).data
        return Response(data, status=status.HTTP_201_CREATED)