def validate_config(): if config.inst_account_enabled: assert config.mailer_enabled, \ "The inst account forms plugin will not work without the mailer" assert config.inst_account_forms_path, \ "The inst account forms plugin requires inst_account_forms_path" if config.groups_enabled: assert 1 <= config.group_min_size <= config.group_max_size else: assert not any([assignment.is_group for assignment in config.assignments]), \ "Group assignments will not work if groups are not enabled." if config.dockergrader_apparmor_profile: _validate_apparmor_config(config.dockergrader_apparmor_profile) for assignment in config.assignments: if not assignment.manual_grading: assert get_job(assignment.name), "No job found for %s" % assignment.name for array_key in ["github_ta_usernames", "github_webhook_secrets"]: assert not isinstance(getattr(config, array_key), basestring) assert len(set([a.name for a in config.assignments])) == len(config.assignments)
def validate_config(): if config.inst_account_enabled: assert config.mailer_enabled, \ "The inst account forms plugin will not work without the mailer" assert config.inst_account_forms_path, \ "The inst account forms plugin requires inst_account_forms_path" if config.groups_enabled: assert 1 <= config.group_min_size <= config.group_max_size else: assert not any([assignment.is_group for assignment in config.assignments]), \ "Group assignments will not work if groups are not enabled." if config.dockergrader_apparmor_profile: _validate_apparmor_config(config.dockergrader_apparmor_profile) for assignment in config.assignments: if not assignment.manual_grading: assert get_job(assignment.name), "No job found for %s" % assignment.name for array_key in ["github_ta_usernames", "github_webhook_secrets"]: assert not isinstance(getattr(config, array_key), basestring) # The port number should be ommitted if it is the default HTTP/HTTPS port. assert not config.web_public_host.endswith(":80") assert not config.web_public_host.endswith(":443") assert not config.web_public_root == "/", "Set web_public_root to empty string instead." assert config.web_public_root == "" or config.web_public_root.startswith("/"), \ "If the web_public_root is not empty, always include the leading slash." assert not config.web_public_root.endswith("/"), "Remove trailing slash from web_public_root" assert len(set([a.name for a in config.assignments])) == len(config.assignments)
def validate_config(): if config.inst_account_enabled: assert config.mailer_enabled, \ "The inst account forms plugin will not work without the mailer" assert config.inst_account_forms_path, \ "The inst account forms plugin requires inst_account_forms_path" if config.groups_enabled: assert 1 <= config.group_min_size <= config.group_max_size else: assert not any([assignment.is_group for assignment in config.assignments]), \ "Group assignments will not work if groups are not enabled." if config.dockergrader_apparmor_profile: _validate_apparmor_config(config.dockergrader_apparmor_profile) for assignment in config.assignments: if not assignment.manual_grading: assert get_job( assignment.name), "No job found for %s" % assignment.name for array_key in ["github_ta_usernames", "github_webhook_secrets"]: assert not isinstance(getattr(config, array_key), basestring) assert len(set([a.name for a in config.assignments])) == len(config.assignments)
def _process_job(self, job): build_name = job.build_name with self.lock: self.status = build_name self.updated = now() # Mark the job as In Progress while True: try: with DbCursor() as c: c.execute('''SELECT source, `commit`, message, job, started FROM builds WHERE build_name = ? AND status = ? LIMIT 1''', [build_name, QUEUED]) row = c.fetchone() if row is None: self._log("Build %s was missing from the database. Skipping." % build_name) return source, commit, message, job_name, started = row owners = get_repo_owners(c, source) owner_emails = {owner: email for owner, (_, _, _, _, _, email) in get_users_by_ids(c, owners).items()} c.execute("UPDATE builds SET status = ?, updated = ? WHERE build_name = ?", [IN_PROGRESS, now_str(), build_name]) break except apsw.Error: self._log("Exception raised while setting status to IN_PROGRESS. Retrying...", exc=True) logging.exception("Failed to retrieve next dockergrader job") self._log("Started building %s" % build_name) try: # if the job doesn't exist for some reason, the resulting TypeError will be caught # and logged assignment = get_assignment_by_name(job_name) due_date = assignment.due_date job_handler = get_job(job_name) log, score = job_handler(source, commit) # Ignore any special encoding inside the log, and just treat it as a bytes log = buffer(log) min_score, max_score = assignment.min_score, assignment.max_score full_score = assignment.full_score if score < min_score or score > max_score: raise ValueError("A score of %s is not in the acceptable range of %f to %f" % (str(score), min_score, max_score)) except JobFailedError as e: self._log("Failed %s with JobFailedError" % build_name, exc=True) with DbCursor() as c: c.execute('''UPDATE builds SET status = ?, updated = ?, log = ? WHERE build_name = ?''', [FAILED, now_str(), str(e), build_name]) if config.mailer_enabled: try: for owner in owners: email = owner_emails.get(owner) if not email: continue subject = "%s failed to complete" % build_name send_template("build_failed", email, subject, build_name=build_name, job_name=job_name, source=source, commit=commit, message=message, error_message=str(e)) except Exception: self._log("Exception raised while reporting JobFailedError", exc=True) logging.exception("Exception raised while reporting JobFailedError") else: self._log("JobFailedError successfully reported via email") return except Exception as e: self._log("Exception raised while building %s" % build_name, exc=True) logging.exception("Internal error within build %s" % build_name) with DbCursor() as c: c.execute('''UPDATE builds SET status = ?, updated = ?, log = ? WHERE build_name = ?''', [FAILED, now_str(), "Build failed due to an internal error.", build_name]) return self._log("Autograder build %s complete (score: %s)" % (build_name, str(score))) while True: try: with DbCursor() as c: c.execute('''UPDATE builds SET status = ?, score = ?, updated = ?, log = ? WHERE build_name = ?''', [SUCCESS, score, now_str(), log, build_name]) slipunits = slip_units(due_date, started) affected_users = assign_grade_batch(c, owners, job_name, float(score), slipunits, build_name, "Automatic build.", "autograder", dont_lower=True) break except apsw.Error: self._log("Exception raised while assigning grades", exc=True) logging.exception("Failed to update build %s after build completed" % build_name) return if config.mailer_enabled: try: for owner in owners: email = owner_emails.get(owner) if not email: continue subject = "%s complete - score %s / %s" % (build_name, str(score), str(full_score)) if owner not in affected_users: subject += " (no effect on grade)" else: if slipunits == 1: subject += " (1 %s used)" % config.slip_unit_name_singular elif slipunits > 0: subject += " (%s slip %s used)" % (str(slipunits), config.slip_unit_name_plural) send_template("build_finished", email, subject, build_name=build_name, job_name=job_name, score=score, full_score=str(full_score), slipunits=slipunits, log=log, source=source, commit=commit, message=message, affected=(owner in affected_users)) except Exception: self._log("Exception raised while reporting grade", exc=True) logging.exception("Exception raised while reporting grade") else: self._log("Grade successfully reported via email")