1package tasks 2 3import ( 4 "net/http" 5 "strconv" 6 "time" 7 8 log "github.com/Sirupsen/logrus" 9 "github.com/ansible-semaphore/semaphore/db" 10 11 "github.com/ansible-semaphore/semaphore/util" 12 "github.com/gorilla/context" 13 "github.com/masterminds/squirrel" 14) 15 16// AddTask inserts a task into the database and returns a header or returns error 17func AddTask(w http.ResponseWriter, r *http.Request) { 18 project := context.Get(r, "project").(db.Project) 19 user := context.Get(r, "user").(*db.User) 20 21 var taskObj db.Task 22 if err := util.Bind(w, r, &taskObj); err != nil { 23 return 24 } 25 26 taskObj.Created = time.Now() 27 taskObj.Status = "waiting" 28 taskObj.UserID = &user.ID 29 30 if err := db.Mysql.Insert(&taskObj); err != nil { 31 util.LogErrorWithFields(err, log.Fields{"error": "Bad request. Cannot create new task"}) 32 w.WriteHeader(http.StatusBadRequest) 33 return 34 } 35 36 pool.register <- &task{ 37 task: taskObj, 38 projectID: project.ID, 39 } 40 41 objType := taskTypeID 42 desc := "Task ID " + strconv.Itoa(taskObj.ID) + " queued for running" 43 if err := (db.Event{ 44 ProjectID: &project.ID, 45 ObjectType: &objType, 46 ObjectID: &taskObj.ID, 47 Description: &desc, 48 }.Insert()); err != nil { 49 util.LogErrorWithFields(err, log.Fields{"error": "Cannot write new event to database"}) 50 } 51 52 util.WriteJSON(w, http.StatusCreated, taskObj) 53} 54 55// GetTasksList returns a list of tasks for the current project in desc order to limit or error 56func GetTasksList(w http.ResponseWriter, r *http.Request, limit uint64) { 57 project := context.Get(r, "project").(db.Project) 58 59 q := squirrel.Select("task.*, tpl.playbook as tpl_playbook, user.name as user_name, tpl.alias as tpl_alias"). 60 From("task"). 61 Join("project__template as tpl on task.template_id=tpl.id"). 62 LeftJoin("user on task.user_id=user.id"); 63 64 if tpl := context.Get(r, "template"); tpl != nil { 65 q = q.Where("tpl.project_id=? AND task.template_id=?", project.ID, tpl.(db.Template).ID) 66 } else { 67 q = q.Where("tpl.project_id=?", project.ID) 68 } 69 70 q = q.OrderBy("task.created desc, id desc") 71 72 if limit > 0 { 73 q = q.Limit(limit) 74 } 75 76 query, args, _ := q.ToSql() 77 78 var tasks []struct { 79 db.Task 80 81 TemplatePlaybook string `db:"tpl_playbook" json:"tpl_playbook"` 82 TemplateAlias string `db:"tpl_alias" json:"tpl_alias"` 83 UserName *string `db:"user_name" json:"user_name"` 84 } 85 if _, err := db.Mysql.Select(&tasks, query, args...); err != nil { 86 util.LogErrorWithFields(err, log.Fields{"error": "Bad request. Cannot get tasks list from database"}) 87 w.WriteHeader(http.StatusBadRequest) 88 return 89 } 90 91 util.WriteJSON(w, http.StatusOK, tasks) 92} 93 94// GetAllTasks returns all tasks for the current project 95func GetAllTasks(w http.ResponseWriter, r *http.Request) { 96 GetTasksList(w, r, 0) 97} 98 99// GetLastTasks returns the hundred most recent tasks 100func GetLastTasks(w http.ResponseWriter, r *http.Request) { 101 GetTasksList(w, r, 200) 102} 103 104// GetTask returns a task based on its id 105func GetTask(w http.ResponseWriter, r *http.Request) { 106 task := context.Get(r, taskTypeID).(db.Task) 107 util.WriteJSON(w, http.StatusOK, task) 108} 109 110// GetTaskMiddleware is middleware that gets a task by id and sets the context to it or panics 111func GetTaskMiddleware(next http.Handler) http.Handler { 112 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 113 taskID, err := util.GetIntParam("task_id", w, r) 114 if err != nil { 115 panic(err) 116 } 117 118 var task db.Task 119 if err := db.Mysql.SelectOne(&task, "select * from task where id=?", taskID); err != nil { 120 panic(err) 121 } 122 123 context.Set(r, taskTypeID, task) 124 next.ServeHTTP(w, r) 125 }) 126} 127 128// GetTaskOutput returns the logged task output by id and writes it as json or returns error 129func GetTaskOutput(w http.ResponseWriter, r *http.Request) { 130 task := context.Get(r, taskTypeID).(db.Task) 131 132 var output []db.TaskOutput 133 if _, err := db.Mysql.Select(&output, "select task_id, task, time, output from task__output where task_id=? order by time asc", task.ID); err != nil { 134 util.LogErrorWithFields(err, log.Fields{"error": "Bad request. Cannot get task output from database"}) 135 w.WriteHeader(http.StatusBadRequest) 136 return 137 } 138 139 util.WriteJSON(w, http.StatusOK, output) 140} 141 142// RemoveTask removes a task from the database 143func RemoveTask(w http.ResponseWriter, r *http.Request) { 144 task := context.Get(r, taskTypeID).(db.Task) 145 editor := context.Get(r, "user").(*db.User) 146 147 if !editor.Admin { 148 log.Warn(editor.Username + " is not permitted to delete task logs") 149 w.WriteHeader(http.StatusUnauthorized) 150 return 151 } 152 153 statements := []string{ 154 "delete from task__output where task_id=?", 155 "delete from task where id=?", 156 } 157 158 for _, statement := range statements { 159 _, err := db.Mysql.Exec(statement, task.ID) 160 if err != nil { 161 util.LogErrorWithFields(err, log.Fields{"error": "Bad request. Cannot delete task from database"}) 162 w.WriteHeader(http.StatusBadRequest) 163 return 164 } 165 } 166 167 w.WriteHeader(http.StatusNoContent) 168} 169