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 })
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"]))
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)
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 })
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 })