// POST: /job func (cr *JobController) Create(cx *goweb.Context) { // Log Request and check for Auth LogRequest(cx.Request) // Parse uploaded form params, files, err := ParseMultipartForm(cx.Request) if err != nil { if err.Error() == "request Content-Type isn't multipart/form-data" { cx.RespondWithErrorMessage("No job file is submitted", http.StatusBadRequest) } else { // Some error other than request encoding. Theoretically // could be a lost db connection between user lookup and parsing. // Blame the user, Its probaby their fault anyway. logger.Error("Error parsing form: " + err.Error()) cx.RespondWithError(http.StatusBadRequest) } return } _, has_upload := files["upload"] _, has_awf := files["awf"] if !has_upload && !has_awf { cx.RespondWithErrorMessage("No job script or awf is submitted", http.StatusBadRequest) return } //send job submission request and get back an assigned job number (jid) var jid string jid, err = core.QMgr.JobRegister() if err != nil { logger.Error("Err@job_Create:GetNextJobNum: " + err.Error()) cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest) return } var job *core.Job job, err = core.CreateJobUpload(params, files, jid) if err != nil { logger.Error("Err@job_Create:CreateJobUpload: " + err.Error()) cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest) return } if token, err := request.RetrieveToken(cx.Request); err == nil { job.SetDataToken(token) } core.QMgr.EnqueueTasksByJobId(job.Id, job.TaskList()) //log event about job submission (JB) logger.Event(event.JOB_SUBMISSION, "jobid="+job.Id+";jid="+job.Jid+";name="+job.Info.Name+";project="+job.Info.Project) cx.RespondWithData(job) return }
// PUT: /job/{id} -> used for job manipulation func (cr *JobController) Update(id string, cx *goweb.Context) { // Log Request and check for Auth LogRequest(cx.Request) // Try to authenticate user. u, err := request.Authenticate(cx.Request) if err != nil && err.Error() != e.NoAuth { cx.RespondWithErrorMessage(err.Error(), http.StatusUnauthorized) return } // If no auth was provided, and anonymous write is allowed, use the public user if u == nil { if conf.ANON_WRITE == true { u = &user.User{Uuid: "public"} } else { cx.RespondWithErrorMessage(e.NoAuth, http.StatusUnauthorized) return } } // Load job by id job, err := core.LoadJob(id) if err != nil { if err == mgo.ErrNotFound { cx.RespondWithNotFound() } else { // In theory the db connection could be lost between // checking user and load but seems unlikely. // logger.Error("Err@job_Read:LoadJob: " + id + ":" + err.Error()) cx.RespondWithErrorMessage("job not found:"+id, http.StatusBadRequest) } return } // User must have write permissions on job or be job owner or be an admin rights := job.Acl.Check(u.Uuid) if job.Acl.Owner != u.Uuid && rights["write"] == false && u.Admin == false { cx.RespondWithErrorMessage(e.UnAuth, http.StatusUnauthorized) return } // Gather query params query := &Query{Li: cx.Request.URL.Query()} if query.Has("resume") { // to resume a suspended job if err := core.QMgr.ResumeSuspendedJob(id); err != nil { cx.RespondWithErrorMessage("fail to resume job: "+id+" "+err.Error(), http.StatusBadRequest) return } cx.RespondWithData("job resumed: " + id) return } if query.Has("suspend") { // to suspend an in-progress job if err := core.QMgr.SuspendJob(id, "manually suspended", ""); err != nil { cx.RespondWithErrorMessage("fail to suspend job: "+id+" "+err.Error(), http.StatusBadRequest) return } cx.RespondWithData("job suspended: " + id) return } if query.Has("resubmit") || query.Has("reregister") { // to re-submit a job from mongodb if err := core.QMgr.ResubmitJob(id); err != nil { cx.RespondWithErrorMessage("fail to resubmit job: "+id+" "+err.Error(), http.StatusBadRequest) return } cx.RespondWithData("job resubmitted: " + id) return } if query.Has("recompute") { // to recompute a job from task i, the successive/downstream tasks of i will all be computed stage := query.Value("recompute") if stage == "" { cx.RespondWithErrorMessage("lacking stage id from which the recompute starts", http.StatusBadRequest) return } if err := core.QMgr.RecomputeJob(id, stage); err != nil { cx.RespondWithErrorMessage("fail to recompute job: "+id+" "+err.Error(), http.StatusBadRequest) return } cx.RespondWithData("job recompute started: " + id) return } if query.Has("clientgroup") { // change the clientgroup attribute of the job newgroup := query.Value("clientgroup") if newgroup == "" { cx.RespondWithErrorMessage("lacking clientgroup name", http.StatusBadRequest) return } if err := core.QMgr.UpdateGroup(id, newgroup); err != nil { cx.RespondWithErrorMessage("failed to update group for job: "+id+" "+err.Error(), http.StatusBadRequest) return } cx.RespondWithData("job group updated: " + id + " to " + newgroup) return } if query.Has("priority") { // change the priority attribute of the job priority_str := query.Value("priority") if priority_str == "" { cx.RespondWithErrorMessage("lacking priority value", http.StatusBadRequest) return } priority, err := strconv.Atoi(priority_str) if err != nil { cx.RespondWithErrorMessage("priority value must be an integer"+err.Error(), http.StatusBadRequest) return } if err := core.QMgr.UpdatePriority(id, priority); err != nil { cx.RespondWithErrorMessage("failed to set the priority for job: "+id+" "+err.Error(), http.StatusBadRequest) return } cx.RespondWithData("job priority updated: " + id + " to " + priority_str) return } if query.Has("settoken") { // set data token token, err := request.RetrieveToken(cx.Request) if err != nil { cx.RespondWithErrorMessage("fail to retrieve token for job, pls set token in header: "+id+" "+err.Error(), http.StatusBadRequest) return } job, err := core.LoadJob(id) if err != nil { if err == mgo.ErrNotFound { cx.RespondWithNotFound() } else { logger.Error("Err@job_Read:LoadJob: " + id + ":" + err.Error()) cx.RespondWithErrorMessage("job not found:"+id, http.StatusBadRequest) } return } job.SetDataToken(token) cx.RespondWithData("data token set for job: " + id) return } cx.RespondWithData("requested job operation not supported") return }
// POST: /job func (cr *JobController) Create(cx *goweb.Context) { // Log Request and check for Auth LogRequest(cx.Request) // Try to authenticate user. u, err := request.Authenticate(cx.Request) if err != nil && err.Error() != e.NoAuth { cx.RespondWithErrorMessage(err.Error(), http.StatusUnauthorized) return } // If no auth was provided, and anonymous write is allowed, use the public user if u == nil { if conf.ANON_WRITE == true { u = &user.User{Uuid: "public"} } else { cx.RespondWithErrorMessage(e.NoAuth, http.StatusUnauthorized) return } } // Parse uploaded form _, files, err := ParseMultipartForm(cx.Request) if err != nil { if err.Error() == "request Content-Type isn't multipart/form-data" { cx.RespondWithErrorMessage("No job file is submitted", http.StatusBadRequest) } else { // Some error other than request encoding. Theoretically // could be a lost db connection between user lookup and parsing. // Blame the user, Its probaby their fault anyway. logger.Error("Error parsing form: " + err.Error()) cx.RespondWithError(http.StatusBadRequest) } return } _, has_import := files["import"] _, has_upload := files["upload"] _, has_awf := files["awf"] var job *core.Job if has_import { // import a job document job, err = core.CreateJobImport(u, files["import"]) if err != nil { logger.Error("Err@job_Create:CreateJobImport: " + err.Error()) cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest) return } logger.Event(event.JOB_IMPORT, "jobid="+job.Id+";name="+job.Info.Name+";project="+job.Info.Project+";user="******"No job script or awf is submitted", http.StatusBadRequest) return } else { // create new uploaded job job, err = core.CreateJobUpload(u, files) if err != nil { logger.Error("Err@job_Create:CreateJobUpload: " + err.Error()) cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest) return } logger.Event(event.JOB_SUBMISSION, "jobid="+job.Id+";name="+job.Info.Name+";project="+job.Info.Project+";user="+job.Info.User) } if token, err := request.RetrieveToken(cx.Request); err == nil { job.SetDataToken(token) } // don't enqueue imports if !has_import { core.QMgr.EnqueueTasksByJobId(job.Id, job.TaskList()) } cx.RespondWithData(job) return }
// PUT: /job/{id} -> used for job manipulation func (cr *JobController) Update(id string, cx *goweb.Context) { // Log Request and check for Auth LogRequest(cx.Request) // Gather query params query := &Query{Li: cx.Request.URL.Query()} if query.Has("resume") { // to resume a suspended job if err := core.QMgr.ResumeSuspendedJob(id); err != nil { cx.RespondWithErrorMessage("fail to resume job: "+id+" "+err.Error(), http.StatusBadRequest) } cx.RespondWithData("job resumed: " + id) return } if query.Has("suspend") { // to suspend an in-progress job if err := core.QMgr.SuspendJob(id, "manually suspended"); err != nil { cx.RespondWithErrorMessage("fail to suspend job: "+id+" "+err.Error(), http.StatusBadRequest) } cx.RespondWithData("job suspended: " + id) return } if query.Has("resubmit") { // to re-submit a job from mongodb if err := core.QMgr.ResubmitJob(id); err != nil { cx.RespondWithErrorMessage("fail to resubmit job: "+id+" "+err.Error(), http.StatusBadRequest) } cx.RespondWithData("job resubmitted: " + id) return } if query.Has("recompute") { // to recompute a job from task i, the successive/downstream tasks of i will all be computed stage := query.Value("recompute") if stage == "" { cx.RespondWithErrorMessage("lacking stage id from which the recompute starts", http.StatusBadRequest) } if err := core.QMgr.RecomputeJob(id, stage); err != nil { cx.RespondWithErrorMessage("fail to recompute job: "+id+" "+err.Error(), http.StatusBadRequest) } cx.RespondWithData("job recompute started: " + id) return } if query.Has("clientgroup") { // change the clientgroup attribute of the job newgroup := query.Value("clientgroup") if newgroup == "" { cx.RespondWithErrorMessage("lacking groupname", http.StatusBadRequest) } if err := core.QMgr.UpdateGroup(id, newgroup); err != nil { cx.RespondWithErrorMessage("fail to update group for job: "+id+" "+err.Error(), http.StatusBadRequest) } cx.RespondWithData("job group updated: " + id + " to " + newgroup) return } if query.Has("settoken") { // set data token token, err := request.RetrieveToken(cx.Request) if err != nil { cx.RespondWithErrorMessage("fail to retrieve token for job: "+id+" "+err.Error(), http.StatusBadRequest) return } job, err := core.LoadJob(id) if err != nil { if err.Error() == e.MongoDocNotFound { cx.RespondWithNotFound() } else { logger.Error("Err@job_Read:LoadJob: " + id + ":" + err.Error()) cx.RespondWithErrorMessage("job not found:"+id, http.StatusBadRequest) } return } job.SetDataToken(token) cx.RespondWithData("data token set for job: " + id) return } cx.RespondWithData("requested job operation not supported") return }