Beispiel #1
0
def _acceptSubmission(request, course, exercise, post_url, sdir):
    '''
    Queues the submission for grading.
    '''

    # Backup synchronous grading.
    if not settings.CELERY_BROKER:
        LOGGER.warning("No queue configured")
        from grader.runactions import runactions
        r = runactions(course, exercise, sdir, get_uid(request), int(request.GET.get("ordinal_number", 1)))
        html = template_to_str(course, exercise, "", r["template"], r["result"])
        return render_template(request, course, exercise, post_url,
            "access/async_accepted.html", {
                "synchronous": True,
                "accepted": True,
                "max_points": r["result"].get("max_points", 1),
                "points": r["result"].get("points", 0),
                "feedback": html,
            })

    if "submission_url" in request.GET:
        surl = request.GET["submission_url"]
        surl_missing = False
    else:
        LOGGER.warning("submission_url missing from a request")
        surl = request.build_absolute_uri(reverse('test-result'))
        surl_missing = True

    # Queue grader.
    tasks.grade.delay(course["key"], exercise["key"],
        translation.get_language(), surl, sdir, get_uid(request),
        int(request.GET.get("ordinal_number", 1)))

    _acceptSubmission.counter += 1
    qlen = queue_length()
    LOGGER.debug("Submission of %s/%s, queue counter %d, queue length %d",
        course["key"], exercise["key"], _acceptSubmission.counter, qlen)
    if qlen >= settings.QUEUE_ALERT_LENGTH:
        LOGGER.error("Queue alert, length: %d", qlen)

    return render_template(request, course, exercise, post_url,
        "access/async_accepted.html", {
            "accepted": True,
            "wait": True,
            "missing_url": surl_missing,
            "queue": qlen
        })
Beispiel #2
0
    def handle(self, *args, **options):

        config = ConfigParser()

        # Check arguments.
        if len(args) < 1 or "/" not in args[0]:
            raise CommandError("Required arguments missing: course_key/exercise_key")
        course_key, exercise_key = args[0].split("/", 1)

        # Get exercise configuration.
        (course, exercise) = config.exercise_entry(course_key, exercise_key)
        if course is None:
            raise CommandError("Course not found for key: %s" % (course_key))
        if exercise is None:
            raise CommandError("Exercise not found for key: %s/%s" % (course_key, exercise_key))
        self.stdout.write('Exercise configuration retrieved.')

        # Check exercise type.
        if not "actions" in exercise:
            raise CommandError("Cannot grade: exercise does not configure asynchronous actions")

        # Create submission.
        sdir = create_submission_dir(course, exercise)
        if len(args) == 1:
            os.makedirs(sdir + "/user")
        for n in range(1, len(args)):
            name = args[n]

            # Copy individual files.
            if os.path.isfile(name):
                submit_path = submission_file_path(sdir, os.path.basename(name))
                shutil.copy2(name, submit_path)

            # Copy a directory.
            elif os.path.isdir(name):
                if len(args) != 2:
                    raise CommandError("Can only submit one directory or multiple files.")
                shutil.copytree(name, sdir + "/user", True)

            else:
                raise CommandError("Submit file not found: %s" % (name))

        # Run actions.
        r = runactions(course, exercise, sdir)
        self.stdout.write("Response body:")
        self.stdout.write(template_to_str(course, exercise, "", r["template"], r["result"]))
Beispiel #3
0
def grade(course_key, exercise_key, lang, submission_url, submission_dir):
    '''
    Grades the submission using configured grading actions.

    @type course_key: C{str}
    @param course: a course key
    @type exercise: C{str}
    @param exercise: an exercise key
    @type lang: C{str}
    @param lang: a language code
    @type submission_url: C{str}
    @param submission_url: a submission URL where grader should POST result
    @type submission_dir: C{str}
    @param submission_dir: a submission directory where submitted files are stored
    '''
    translation.activate(lang)
    (course, exercise) = config.exercise_entry(course_key, exercise_key, lang=lang)
    if course is None or exercise is None:
        LOGGER.error("Unknown exercise \"%s/%s\" for \"%s\"", course_key, exercise_key, submission_url)
        post_system_error(submission_url, course)

    try:
        LOGGER.debug("Grading \"%s/%s\" for \"%s\"", course_key, exercise_key, submission_url)
        r = runactions(course, exercise, submission_dir)
        if r["result"]["error"]:
            level = 40 if r["result"]["error"] == "error" else 30
            LOGGER.log(level, "Grading \"%s/%s\" for \"%s\" failed. "
                "Expected success for the last action:\n\n%s\n\n%s",
                course_key, exercise_key, submission_url,
                r["result"]["tests"][-1]["out"],
                r["result"]["tests"][-1]["err"])
        else:
            LOGGER.debug("Finished grading with points: %d/%d",
                r["result"]["points"], r["result"]["max_points"])
        post_result(submission_url, course, exercise, r["template"], r["result"])

    except SoftTimeLimitExceeded:
        LOGGER.error("Grading timeout \"%s/%s\" for \"%s\"", course_key, exercise_key, submission_url)
        post_result(submission_url, course, exercise, "access/task_timeout.html", { "error": True })

    except Exception:
        LOGGER.exception("Grading error \"%s/%s\" for \"%s\"", course_key, exercise_key, submission_url)
        post_system_error(submission_url, course, exercise)
Beispiel #4
0
def _acceptSubmission(request, course, exercise, post_url, sdir):
    '''
    Queues the submission for grading.
    '''
    uids = get_uid(request)
    attempt = int(request.GET.get("ordinal_number", 1))
    container_flag = settings.CONTAINER_MODE and "container" in exercise

    # Backup synchronous grading.
    if not container_flag and not settings.CELERY_BROKER:
        LOGGER.warning("No queue configured")
        from grader.runactions import runactions
        r = runactions(course, exercise, sdir, uids, attempt)
        html = template_to_str(course, exercise, "", r["template"],
                               r["result"])
        return render_template(
            request, course, exercise, post_url, "access/async_accepted.html",
            {
                "synchronous": True,
                "accepted": True,
                "max_points": r["result"].get("max_points", 1),
                "points": r["result"].get("points", 0),
                "feedback": html,
            })

    if "submission_url" in request.GET:
        surl = request.GET["submission_url"]
        surl_missing = False
    else:
        LOGGER.warning("submission_url missing from a request")
        surl = request.build_absolute_uri(reverse('test-result'))
        surl_missing = True

    _acceptSubmission.counter += 1

    # Order container for grading.
    if container_flag:
        c = _requireContainer(exercise)

        course_extra = {
            "key": course["key"],
            "name": course["name"],
        }
        exercise_extra = {
            "key": exercise["key"],
            "title": exercise.get("title", None),
        }
        if exercise.get("personalized", False):
            exercise_extra["personalized_exercise"] \
                = select_generated_exercise_instance(course, exercise, uids, attempt)
            if settings.ENABLE_PERSONAL_DIRECTORIES:
                exercise_extra["personal_directory"] \
                    = user_personal_directory_path(course, exercise, uids)

        sid = os.path.basename(sdir)
        write_submission_meta(sid, {
            "url": surl,
            "dir": sdir,
        })
        r = invoke([
            settings.CONTAINER_SCRIPT,
            sid,
            request.scheme + "://" + request.get_host(),
            c["image"],
            os.path.join(DIR, course["key"], c["mount"]),
            sdir,
            c["cmd"],
            json.dumps(course_extra),
            json.dumps(exercise_extra),
        ])
        LOGGER.debug("Container order exit=%d out=%s err=%s", r["code"],
                     r["out"], r["err"])
        qlen = 1

    # Queue in celery & rabbitmq for chroot sandbox actions.
    else:
        tasks.grade.delay(course["key"], exercise["key"],
                          translation.get_language(), surl, sdir, uids,
                          attempt)
        qlen = queue_length()
        LOGGER.debug("Submission of %s/%s, queue counter %d, queue length %d",
                     course["key"], exercise["key"], _acceptSubmission.counter,
                     qlen)
        if qlen >= settings.QUEUE_ALERT_LENGTH:
            LOGGER.error("Queue alert, length: %d", qlen)

    return render_template(request, course, exercise, post_url,
                           "access/async_accepted.html", {
                               "accepted": True,
                               "wait": True,
                               "missing_url": surl_missing,
                               "queue": qlen
                           })
Beispiel #5
0
def _acceptSubmission(request, course, exercise, post_url, sdir):
    '''
    Queues the submission for grading.
    '''
    uids = get_uid(request)
    attempt = int(request.GET.get("ordinal_number", 1))
    container_flag = settings.CONTAINER_MODE and "container" in exercise

    # Backup synchronous grading.
    if not container_flag and not settings.CELERY_BROKER:
        LOGGER.warning("No queue configured")
        from grader.runactions import runactions
        r = runactions(course, exercise, sdir, uids, attempt)
        html = template_to_str(course, exercise, "", r["template"], r["result"])
        return render_template(request, course, exercise, post_url,
            "access/async_accepted.html", {
                "synchronous": True,
                "accepted": True,
                "max_points": r["result"].get("max_points", 1),
                "points": r["result"].get("points", 0),
                "feedback": html,
            })

    if "submission_url" in request.GET:
        surl = request.GET["submission_url"]
        surl_missing = False
    else:
        LOGGER.warning("submission_url missing from a request")
        surl = request.build_absolute_uri(reverse('test-result'))
        surl_missing = True

    _acceptSubmission.counter += 1

    # Order container for grading.
    if container_flag:
        c = _requireContainer(exercise)

        course_extra = {
            "key": course["key"],
            "name": course["name"],
        }
        exercise_extra = {
            "key": exercise["key"],
            "title": exercise.get("title", None),
            "resources": c.get("resources", {}), # Unofficial param, implemented differently later
            "require_constant_environment": c.get("require_constant_environment", False) # Unofficial param, implemented differently later
        }
        if exercise.get("personalized", False):
            exercise_extra["personalized_exercise"] \
                = select_generated_exercise_instance(course, exercise, uids, attempt)
            if settings.ENABLE_PERSONAL_DIRECTORIES:
                exercise_extra["personal_directory"] \
                    = user_personal_directory_path(course, exercise, uids)

        sid = os.path.basename(sdir)
        write_submission_meta(sid, {
            "url": surl,
            "dir": sdir,
            "course_key": course["key"],
            "exercise_key": exercise["key"],
            "lang": translation.get_language(),
        })
        r = invoke([
            settings.CONTAINER_SCRIPT,
            sid,
            request.scheme + "://" + request.get_host(),
            c["image"],
            os.path.join(DIR, course["key"], c["mount"]),
            sdir,
            c["cmd"],
            json.dumps(course_extra),
            json.dumps(exercise_extra),
        ])
        LOGGER.debug("Container order exit=%d out=%s err=%s",
            r["code"], r["out"], r["err"])
        qlen = 1

    # Queue in celery & rabbitmq for chroot sandbox actions.
    else:
        tasks.grade.delay(course["key"], exercise["key"],
            translation.get_language(), surl, sdir, uids, attempt)
        qlen = queue_length()
        LOGGER.debug("Submission of %s/%s, queue counter %d, queue length %d",
            course["key"], exercise["key"], _acceptSubmission.counter, qlen)
        if qlen >= settings.QUEUE_ALERT_LENGTH:
            LOGGER.error("Queue alert, length: %d", qlen)

    return render_template(request, course, exercise, post_url,
        "access/async_accepted.html", {
            "accepted": True,
            "wait": True,
            "missing_url": surl_missing,
            "queue": qlen
        })