func (api *Api) Logout(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") session := Session{} var errl error = nil if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 400) return } mutex.Lock() if err := api.db.Delete(&session).Error; err != nil { rest.Error(w, err.Error(), 400) mutex.Unlock() return } mutex.Unlock() logit("User '" + login + "' logged out") api.LogActivity(session.Id, "User '"+login+"' logged out") w.WriteJson("Success") }
func (api *Api) DeleteEnv(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Delete id := 0 if id, errl = strconv.Atoi(r.PathParam("id")); errl != nil { rest.Error(w, "Invalid id.", 400) return } env := Env{} mutex.Lock() if api.db.First(&env, id).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record not found.", 400) return } mutex.Unlock() mutex.Lock() if err := api.db.Delete(&env).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() dc := Dc{} mutex.Lock() api.db.First(&dc, env.DcId) mutex.Unlock() text := fmt.Sprintf("Deleted environment '%s->%s'.", dc.SysName, env.SysName) api.LogActivity(session.Id, text) w.WriteJson("Success") }
func (api *Api) GetAllEnvCaps(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } //session := Session{} var errl error = nil //if session,errl = api.CheckLogin( login, guid ); errl != nil { if _, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) qs := r.URL.Query() // Query string - map[string][]string envcaps := []EnvCap{} if len(qs["code"]) > 0 { srch := qs["code"][0] mutex.Lock() api.db.Order("code").Find(&envcaps, "code = ?", srch) mutex.Unlock() } else { mutex.Lock() err := api.db.Order("Code").Find(&envcaps) mutex.Unlock() if err.Error != nil { if !err.RecordNotFound() { rest.Error(w, err.Error.Error(), 500) return } } } // Create a slice of maps from users struct // to selectively copy database fields for display u := make([]map[string]interface{}, len(envcaps)) for i := range envcaps { u[i] = make(map[string]interface{}) u[i]["Id"] = envcaps[i].Id u[i]["Code"] = envcaps[i].Code u[i]["Desc"] = envcaps[i].Desc } // Too much noise //api.LogActivity( session.Id, "Sent list of users" ) w.WriteJson(&u) }
func (api *Api) AddPerm(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already permData := Perm{} if err := r.DecodeJsonPayload(&permData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if permData.UserId == 0 { rest.Error(w, "Incorrect data format received.", 400) return } perm := Perm{} mutex.Lock() if !api.db.Find(&perm, "env_id = ? and user_id = ?", permData.EnvId, permData.UserId).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Add perm mutex.Lock() if err := api.db.Save(&permData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() text := fmt.Sprintf("Added new environment permission. PermID = '%d'.", permData.Id) api.LogActivity(session.Id, text) w.WriteJson(permData) }
func (api *Api) AddEnvCap(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already EnvCapData := EnvCap{} if err := r.DecodeJsonPayload(&EnvCapData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(EnvCapData.Code) == 0 || len(EnvCapData.Desc) == 0 { rest.Error(w, "A required field is empty.", 400) return } EnvCap := EnvCap{} mutex.Lock() if !api.db.Find(&EnvCap, "code = ?", EnvCapData.Code).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Add EnvCap mutex.Lock() if err := api.db.Save(&EnvCapData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() text := fmt.Sprintf("Added new EnvCap, '%s'.", EnvCapData.Code) api.LogActivity(session.Id, text) w.WriteJson(EnvCapData) }
func (api *Api) DeletePlugin(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Delete id := 0 if id, errl = strconv.Atoi(r.PathParam("id")); errl != nil { rest.Error(w, "Invalid id.", 400) return } plugin := Plugin{} mutex.Lock() if api.db.First(&plugin, id).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record not found.", 400) return } mutex.Unlock() mutex.Lock() if err := api.db.Delete(&plugin).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } if err := api.db.Where("plugin_id = ?", plugin.Id). Delete(File{}).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Deleted plugin '"+plugin.Name+"'.") w.WriteJson("Success") }
func (api *Api) AddRepo(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already repoData := Repo{} if err := r.DecodeJsonPayload(&repoData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(repoData.Url) == 0 { rest.Error(w, "Incorrect data format received.", 400) return } repo := Repo{} mutex.Lock() if !api.db.Find(&repo, "Url = ?", repoData.Url). RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Add repo mutex.Lock() if err := api.db.Save(&repoData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Added new repo '"+repoData.Url+"'.") w.WriteJson(repoData) }
func (api *Api) AddJob(w rest.ResponseWriter, r *rest.Request) { // Decode json post data into JobIn struct logit(fmt.Sprintf("Connection from %s", r.RemoteAddr)) job := JobIn{} if err := r.DecodeJsonPayload(&job); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if job.JobID == 0 { rest.Error(w, "Incorrect data format received.", 400) return } // Check the password matches if job.Key != config.WorkerKey { rest.Error(w, "Invalid key", 400) return } // Add the job to the job list api.AppendJob(job) if api.Guid() == "" { api.loginmutex.Lock() if err := api.Login(); err != nil { // Can't send this error to the Manager so must return it here logit(fmt.Sprintf("Error: %s", err.Error())) rest.Error(w, err.Error(), 400) api.loginmutex.Unlock() return } api.loginmutex.Unlock() } if err := api.sendStatus(job, JobOut{ Status: STATUS_NOTSTARTED, StatusReason: "About to start job", StatusPercent: 0, Errors: 0, }); err != nil { logit(fmt.Sprintf("Error: %s", err.Error())) } w.WriteJson(job) //a := fmt.Sprintf("%#v",job) //logit(a) go api.execCmd(job) }
func (api *Api) DeleteJob(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login == "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Delete id := 0 if id, errl = strconv.Atoi(r.PathParam("id")); errl != nil { rest.Error(w, "Invalid id.", 400) return } job := Job{} mutex.Lock() if api.db.First(&job, id).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record not found.", 400) return } mutex.Unlock() mutex.Lock() if err := api.db.Delete(&job).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, fmt.Sprintf("Deleted job %d.", job.Id)) w.WriteJson(&job) }
func (api *Api) AddOutputLine(w rest.ResponseWriter, r *rest.Request) { login := r.PathParam("login") guid := r.PathParam("GUID") // Admin is not allowed if login == "admin" { rest.Error(w, "Not allowed", 400) return } // Check credentials //session := Session{} var errl error if _, errl = api.CheckLoginNoExpiry(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } //defer api.TouchSession( guid ) outputLineData := OutputLine{} if err := r.DecodeJsonPayload(&outputLineData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if outputLineData.JobId == 0 { rest.Error(w, "Incorrect data format received.", 400) return } // Add OutputLine mutex.Lock() if err := api.db.Save(&outputLineData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() //text := "" //fmt.Sprintf( text,"%d",outputLineData.JobId ) //api.LogActivity( session.Id, "Started outputLine logging for job '"+ // text+"'." ) w.WriteJson("Success") }
func (api *Api) DeleteOutputLine(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Admin is not allowed if login == "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Delete id := 0 if id, errl = strconv.Atoi(r.PathParam("id")); errl != nil { rest.Error(w, "Invalid id.", 400) return } outputline := OutputLine{} mutex.Lock() if err := api.db.Where("job_id = ?", id).Delete(&outputline).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, fmt.Sprintf("Deleted outputlines for job %d.", id)) w.WriteJson("Success") }
func (api *Api) DeleteJob(w rest.ResponseWriter, r *rest.Request) { // Decode json post data into JobIn struct logit(fmt.Sprintf("Connection from %s", r.RemoteAddr)) job := JobIn{} if err := r.DecodeJsonPayload(&job); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if job.JobID == 0 { rest.Error(w, "Incorrect data format received.", 400) return } // Check the password matches if job.Key != config.WorkerKey { rest.Error(w, "Invalid key", 400) return } oldjob, err := api.FindJob(job.JobID) if err != nil { rest.Error(w, "Job not found", 400) return } // So status can be updated correctly api.SetUserCancel(oldjob.JobID) // Kill the whole process group (-pid) syscall.Kill(int(oldjob.Pid)*-1, syscall.SIGKILL) // RemoveJob is done if the Wait fails in execCmd (exec.go) // And wait will fail 'cos we just killed it. // //api.RemoveJob( oldjob.JobID ) w.WriteJson(job) }
func (api *Api) GetAllEnvs(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Anyone can view envs //session := Session{} var errl error = nil //if session,errl = api.CheckLogin( login, guid ); errl != nil { if _, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) envs := []Env{} qs := r.URL.Query() // Query string - map[string][]string if login == "admin" { if len(qs["sys_name"]) > 0 { srch := qs["sys_name"][0] if len(qs["dc_id"]) > 0 { dcid := qs["dc_id"][0] mutex.Lock() api.db.Order("sys_name").Find(&envs, "sys_name = ? and dc_id = ?", srch, dcid) mutex.Unlock() } else { mutex.Lock() api.db.Order("sys_name").Find(&envs, "sys_name = ?", srch) mutex.Unlock() } /* if api.db.Order("sys_name"). Find(&envs, "sys_name = ?", srch).RecordNotFound() { rest.Error(w, "No results.", 400) return } */ } else { mutex.Lock() err := api.db.Order("dc_id,sys_name").Find(&envs) mutex.Unlock() if err.Error != nil { if !err.RecordNotFound() { rest.Error(w, err.Error.Error(), 500) return } } } } else { //Not admin // Only return readable/writeable envs for the current user additional_where := "" if len(qs["env_id"]) > 0 { additional_where = "AND envs.id = " + qs["env_id"][0] } if len(qs["writeable"]) > 0 { // only writeable envs mutex.Lock() api.db.Where("envs.id in (SELECT perms.env_id from perms "+ "LEFT JOIN users on users.id=perms.user_id "+ "WHERE users.login=? and perms.writeable=1) "+ additional_where, login).Find(&envs) mutex.Unlock() } else { // readable or writeable envs mutex.Lock() api.db.Where("envs.id in (SELECT perms.env_id from perms "+ "LEFT JOIN users on users.id=perms.user_id "+ "WHERE users.login=? and perms.enabled=1) "+ additional_where, login).Find(&envs) mutex.Unlock() } } // Create a slice of maps from users struct // to selectively copy database fields for display u := make([]map[string]interface{}, len(envs)) for i := range envs { u[i] = make(map[string]interface{}) u[i]["Id"] = envs[i].Id u[i]["DispName"] = envs[i].DispName u[i]["SysName"] = envs[i].SysName //u[i]["WorkerIp"] = envs[i].WorkerIp //u[i]["WorkerPort"] = envs[i].WorkerPort u[i]["WorkerUrl"] = envs[i].WorkerUrl if login == "admin" { u[i]["WorkerKey"] = envs[i].WorkerKey } u[i]["CreatedAt"] = envs[i].CreatedAt dc := Dc{} mutex.Lock() api.db.Model(&envs[i]).Related(&dc) mutex.Unlock() u[i]["DcSysName"] = dc.SysName u[i]["DcDispName"] = dc.DispName u[i]["DcId"] = dc.Id } // Too much noise //api.LogActivity( session.Id, "Sent list of users" ) w.WriteJson(&u) }
func (api *Api) ShowJobs(w rest.ResponseWriter, r *rest.Request) { w.WriteJson(api.Jobs()) }
// GetAllUsers processes "GET /users" queries. // func (api *Api) GetAllUsers(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } //session := Session{} var errl error = nil //if session,errl = api.CheckLogin( login, guid ); errl != nil { if _, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) users := []User{} qs := r.URL.Query() // map[string][]string if len(qs["login"]) > 0 { srch := qs["login"][0] mutex.Lock() if api.db.Order("login"). Find(&users, "login = ?", srch).RecordNotFound() { mutex.Unlock() rest.Error(w, "No results.", 400) return } mutex.Unlock() } else { mutex.Lock() if api.db.Order("login").Find(&users).RecordNotFound() { mutex.Unlock() rest.Error(w, "Empty Table.", 400) return } mutex.Unlock() } // Create a slice of maps from users struct // to selectively copy database fields for display u := make([]map[string]interface{}, len(users)) for i := range users { u[i] = make(map[string]interface{}) u[i]["Id"] = users[i].Id u[i]["Login"] = users[i].Login u[i]["Forename"] = users[i].Forename u[i]["Surname"] = users[i].Surname u[i]["Enabled"] = users[i].Enabled u[i]["CreatedAt"] = users[i].CreatedAt u[i]["Email"] = users[i].Email } // Too much noise //api.LogActivity( session.Id, "Sent list of users" ) w.WriteJson(&u) }
// UpdateUser processes "PUT /users" queries. // func (api *Api) UpdateUser(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Ensure user exists id := r.PathParam("id") // Check that the id string is a number if _, err := strconv.Atoi(id); err != nil { rest.Error(w, "Invalid id.", 400) return } // Load data from db, then ... user := User{} mutex.Lock() if api.db.Find(&user, id).RecordNotFound() { mutex.Unlock() //rest.Error(w, err.Error(), 400) rest.Error(w, "Record not found.", 400) return } mutex.Unlock() // FIXME: DecodeJsonPayload(&somethingelse) then // merge with 'user' manually. This will remove // the 'password can't begin with $' limitation. // ... overwrite any sent fields if err := r.DecodeJsonPayload(&user); err != nil { //rest.Error(w, err.Error(), 400) rest.Error(w, "Invalid data format received.", 400) return } // Add user if !strings.HasPrefix(user.Passhash, "$") { c := &Crypt{} c.Pass = []byte(user.Passhash) c.Crypt() user.Passhash = string(c.Hash) } // Force the use of the path id over an id in the payload Id, _ := strconv.Atoi(id) user.Id = int64(Id) mutex.Lock() if err := api.db.Save(&user).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Updated user details for '"+user.Login+"'.") w.WriteJson(user) }
// AddUser processes "POST /users" queries. // func (api *Api) AddUser(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already userData := User{} if err := r.DecodeJsonPayload(&userData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(userData.Login) == 0 { rest.Error(w, "Incorrect data format received.", 400) return } user := User{} mutex.Lock() if !api.db.Find(&user, "login = ?", userData.Login).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Add user if len(userData.Passhash) == 0 { rest.Error(w, "Empty password not allowed.", 400) return } c := &Crypt{} c.Pass = []byte(userData.Passhash) c.Crypt() userData.Passhash = string(c.Hash) mutex.Lock() if err := api.db.Save(&userData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Added new user '"+userData.Login+"'.") w.WriteJson(userData) }
func (api *Api) UpdatePlugin(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Ensure user exists id := r.PathParam("id") // Check that the id string is a number if _, err := strconv.Atoi(id); err != nil { rest.Error(w, "Invalid id.", 400) return } // Load data from db, then ... plugin := Plugin{} mutex.Lock() if api.db.Find(&plugin, id).RecordNotFound() { mutex.Unlock() //rest.Error(w, err.Error(), 400) rest.Error(w, "Record not found.", 400) return } mutex.Unlock() // ... overwrite any sent fields if err := r.DecodeJsonPayload(&plugin); err != nil { //rest.Error(w, err.Error(), 400) rest.Error(w, "Invalid data format received.", 400) return } // Force the use of the path id over an id in the payload Id, _ := strconv.Atoi(id) plugin.Id = int64(Id) // Make sure parent exists pluginSrch := Plugin{} mutex.Lock() if len(plugin.Parent) > 0 && api.db.Find(&pluginSrch, "name = ?", plugin.Parent).RecordNotFound() { mutex.Unlock() rest.Error(w, "Parent not found.", 400) return } mutex.Unlock() if pluginSrch.Id == plugin.Id { rest.Error(w, "Cannot be a parent of itself.", 400) return } mutex.Lock() if err := api.db.Save(&plugin).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Updated plugin details for '"+plugin.Name+"'.") w.WriteJson("Success") }
func (api *Api) UpdateJob(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Admin is not allowed if login == "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Ensure user exists id := r.PathParam("id") // Check that the id string is a number if _, err := strconv.Atoi(id); err != nil { rest.Error(w, "Invalid id.", 400) return } // Load data from db, then ... job := Job{} mutex.Lock() if api.db.Find(&job, id).RecordNotFound() { mutex.Unlock() //rest.Error(w, err.Error(), 400) rest.Error(w, "Job ID not found.", 400) return } mutex.Unlock() // ... overwrite any sent fields if err := r.DecodeJsonPayload(&job); err != nil { //rest.Error(w, err.Error(), 400) rest.Error(w, "Invalid data format received.", 400) return } // Force the use of the path id over an id in the payload Id, _ := strconv.Atoi(id) job.Id = int64(Id) mutex.Lock() if err := api.db.Save(&job).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, fmt.Sprintf("Updated job details for jobId %d.", job.Id)) w.WriteJson(job) }
func (api *Api) AddScript(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already scriptData := Script{} if err := r.DecodeJsonPayload(&scriptData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(scriptData.Source) == 0 { rest.Error(w, "Incorrect data format received.", 400) return } script := Script{} mutex.Lock() if !api.db.Find(&script, "name = ?", scriptData.Name).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Work out type: // Write to disk then use unix 'file -b' (brief) if err := ioutil.WriteFile(os.TempDir()+"/obdi_scriptcheck", scriptData.Source, 0644); err != nil { scriptData.Type = "Unknown type of script" } else { runCmd := exec.Command("file", "-b", os.TempDir()+"/obdi_scriptcheck") output, err := runCmd.Output() if err != nil { scriptData.Type = "Unknown type of script" } else { scriptData.Type = string(output) } } // Add script mutex.Lock() if err := api.db.Save(&scriptData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() // Try to start the script text := fmt.Sprintf("Added new script, %s.", scriptData.Name) api.LogActivity(session.Id, text) scriptData.Source = []byte{} w.WriteJson(scriptData) }
func (api *Api) KillJob(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login == "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Delete id := 0 if id, errl = strconv.Atoi(r.PathParam("id")); errl != nil { rest.Error(w, "Invalid id.", 400) return } job := Job{} mutex.Lock() if api.db.First(&job, id).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record not found.", 400) return } mutex.Unlock() env := Env{} mutex.Lock() api.db.Model(&job).Related(&env) mutex.Unlock() if env.WorkerUrl == "" || env.WorkerKey == "" { txt := "WorkerUrl or WorkerKey not set for the target environment" rest.Error(w, txt, 400) return } type Jobkill struct { JobID int64 Key string } data := Jobkill{ JobID: job.Id, Key: env.WorkerKey, } // Encode jsondata, err := json.Marshal(data) if err != nil { txt := fmt.Sprintf( "Error sending kill command to worker, JSON Encode:", err.Error()) rest.Error(w, txt, 400) return } // POST to worker resp, err := DELETE(jsondata, env.WorkerUrl, "jobs") if err != nil { txt := "Could not send kill command to worker. ('" + err.Error() + "')" rest.Error(w, txt, 400) return } defer resp.Body.Close() if resp.StatusCode != 200 { var body []byte if b, err := ioutil.ReadAll(resp.Body); err != nil { txt := fmt.Sprintf("Error reading Body ('%s').", err.Error()) rest.Error(w, txt, 400) return } else { body = b } type myErr struct { Error string } errstr := myErr{} if err := json.Unmarshal(body, &errstr); err != nil { txt := fmt.Sprintf("Error decoding JSON ('%s')"+ ". Check the Worker URL.", err.Error()) rest.Error(w, txt, 400) return } txt := "Sending Kill failed. Worker said: '" + errstr.Error + "'" rest.Error(w, txt, 400) return } api.LogActivity(session.Id, fmt.Sprintf("Killed job %d.", job.Id)) w.WriteJson(&job) }
func (api *Api) GetAllOutputLines(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Admin is not allowed if login == "admin" { rest.Error(w, "Not allowed", 400) return } //session := Session{} var errl error = nil //if session,errl = api.CheckLogin( login, guid ); errl != nil { if _, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) outputlines := []OutputLine{} qs := r.URL.Query() // Query string - map[string][]string if len(qs["job_id"]) > 0 { srch := qs["job_id"][0] if len(qs["top"]) > 0 { mutex.Lock() api.db.Order("serial").Limit(qs["top"][0]).Find(&outputlines, "job_id = ?", srch) mutex.Unlock() } else if len(qs["bottom"]) > 0 { mutex.Lock() // TODO last X lines but *in* order api.db.Order("serial desc").Limit(qs["bottom"][0]). Find(&outputlines, "job_id = ?", srch) mutex.Unlock() } else { mutex.Lock() api.db.Order("serial").Find(&outputlines, "job_id = ?", srch) mutex.Unlock() } } else { mutex.Lock() err := api.db.Order("serial").Find(&outputlines) mutex.Unlock() if err.Error != nil { if !err.RecordNotFound() { rest.Error(w, err.Error.Error(), 500) return } } } // Create a slice of maps from users struct // to selectively copy database fields for display u := make([]map[string]interface{}, len(outputlines)) for i := range outputlines { u[i] = make(map[string]interface{}) u[i]["Id"] = outputlines[i].Id u[i]["Serial"] = outputlines[i].Serial u[i]["JobId"] = outputlines[i].JobId u[i]["Text"] = outputlines[i].Text } // Too much noise //api.LogActivity( session.Id, "Sent list of users" ) w.WriteJson(&u) }
func (api *Api) AddDcCapMap(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already dcCapMapData := DcCapMap{} if err := r.DecodeJsonPayload(&dcCapMapData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if dcCapMapData.DcId == 0 || dcCapMapData.DcCapId == 0 { rest.Error(w, "A required field is empty.", 400) return } dcCapMap := DcCapMap{} mutex.Lock() if !api.db.Find(&dcCapMap, "dc_id = ? and dc_cap_id = ?", dcCapMapData.DcId, dcCapMapData.DcCapId).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Check that DcId and DcCapId exist dc := Dc{} mutex.Lock() if api.db.Find(&dc, dcCapMapData.DcId).RecordNotFound() { mutex.Unlock() rest.Error(w, "Invalid data centre id.", 400) return } mutex.Unlock() dcCap := DcCap{} mutex.Lock() if api.db.Find(&dcCap, dcCapMapData.DcCapId).RecordNotFound() { mutex.Unlock() rest.Error(w, "Invalid data centre capability id.", 400) return } mutex.Unlock() // Add DcCapMap mutex.Lock() if err := api.db.Save(&dcCapMapData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() text := fmt.Sprintf("Added new DcCapMap, '%d'.", dcCapMapData.Id) api.LogActivity(session.Id, text) w.WriteJson(dcCapMapData) }
func (api *Api) GetAllPlugins(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Anyone can view plugins /* if login != "admin" { rest.Error(w, "Not allowed", 400) return } */ //session := Session{} var errl error = nil //if session,errl = api.CheckLogin( login, guid ); errl != nil { if _, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) plugins := []Plugin{} qs := r.URL.Query() // Query string - map[string][]string if len(qs["name"]) > 0 { srch := qs["name"][0] mutex.Lock() api.db.Order("name").Find(&plugins, "name = ?", srch) mutex.Unlock() /* if api.db.Order("name"). Find(&plugins, "name = ?", srch).RecordNotFound() { rest.Error(w, "No results.", 400) return } */ } else { // No results is not an error mutex.Lock() err := api.db.Order("name").Find(&plugins) mutex.Unlock() if err.Error != nil { if !err.RecordNotFound() { rest.Error(w, err.Error.Error(), 500) return } } } // Create a slice of maps from users struct // to selectively copy database fields for display u := make([]map[string]interface{}, len(plugins)) for i := range plugins { u[i] = make(map[string]interface{}) u[i]["Id"] = plugins[i].Id u[i]["Name"] = plugins[i].Name u[i]["Desc"] = plugins[i].Desc u[i]["Parent"] = plugins[i].Parent u[i]["HasView"] = plugins[i].HasView u[i]["CreatedAt"] = plugins[i].CreatedAt // UpdatedAt doesn't get updated 'cos we use Save // //u[i]["UpdatedAt"] = plugins[i].CreatedAt } // Too much noise //api.LogActivity( session.Id, "Sent list of users" ) w.WriteJson(&u) }
// DoLogin processes "POST /login" queries. // // Checks login name and passhash stored in database. // If correct then 200 header and GUID are sent. // any previous sessions for that user are closed. // new session entry is made in session table. // If not correct then 400 header with error message. // func (api *Api) DoLogin(w rest.ResponseWriter, r *rest.Request) { // Get the Login and Password userData := struct{ Login, Password string }{} if err := r.DecodeJsonPayload(&userData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(userData.Login) == 0 || len(userData.Password) == 0 { rest.Error(w, "Incorrect data format received.", 400) return } //fmt.Printf( "\n%#v\n", userData ) // Get passhash for login from database user := User{} mutex.Lock() if api.db.Where(User{Login: userData.Login}). First(&user).RecordNotFound() { rest.Error(w, "User or password error.", 400) mutex.Unlock() return } mutex.Unlock() // Check password against hash c := &Crypt{} c.Pass = []byte(userData.Password) c.Hash = []byte(user.Passhash) if err := c.Check(); err != nil { rest.Error(w, "User or password error.", 400) return } // The user's password matches. // Delete old session(s) and create a new one. guid := NewGUID() session := Session{} for { session = Session{} mutex.Lock() if api.db.Where(Session{UserId: user.Id}). First(&session).RecordNotFound() { session = Session{ Guid: guid, UserId: user.Id, } if err := api.db.Save(&session).Error; err != nil { rest.Error(w, err.Error(), 400) mutex.Unlock() return } mutex.Unlock() break } else { if err := api.db.Delete(&session).Error; err != nil { rest.Error(w, err.Error(), 400) mutex.Unlock() return } } mutex.Unlock() } logit("User '" + user.Login + "' logged in") api.LogActivity(session.Id, "User '"+user.Login+"' logged in.") w.WriteJson(struct{ GUID string }{guid}) }
func (api *Api) UpdateScript(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Ensure user exists id := r.PathParam("id") // Check that the id string is a number if _, err := strconv.Atoi(id); err != nil { rest.Error(w, "Invalid id.", 400) return } // Load data from db, then ... script := Script{} mutex.Lock() if api.db.Find(&script, id).RecordNotFound() { mutex.Unlock() //rest.Error(w, err.Error(), 400) rest.Error(w, "Record not found.", 400) return } mutex.Unlock() // ... overwrite any sent fields if err := r.DecodeJsonPayload(&script); err != nil { //rest.Error(w, err.Error(), 400) rest.Error(w, "Invalid data format received.", 400) return } script_srch := Script{} mutex.Lock() if !api.db.Find(&script_srch, "name = ? and id != ?", script.Name, script.Id).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Work out type: // Write to disk then use unix 'file -b' (brief) if len(script.Source) > 0 { if err := ioutil.WriteFile(os.TempDir()+"/obdi_scriptcheck", script.Source, 0644); err != nil { script.Type = "Write file failed. Type of script unknown. (" + err.Error() + ")" } else { runCmd := exec.Command("file", "-b", os.TempDir()+"/obdi_scriptcheck") output, err := runCmd.Output() if err != nil { script.Type = "Unix 'file' failed. Type of script unknown." + " (" + err.Error() + ")" } else { script.Type = string(output) } } } // Force the use of the path id over an id in the payload Id, _ := strconv.Atoi(id) script.Id = int64(Id) mutex.Lock() if err := api.db.Save(&script).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Updated data centre details for '"+script.Name+"'.") w.WriteJson(script) }
func (api *Api) UpdateEnvCap(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Ensure user exists id := r.PathParam("id") // Check that the id string is a number if _, err := strconv.Atoi(id); err != nil { rest.Error(w, "Invalid id.", 400) return } // Load data from db, then ... EnvCap := EnvCap{} mutex.Lock() if api.db.Find(&EnvCap, id).RecordNotFound() { mutex.Unlock() //rest.Error(w, err.Error(), 400) rest.Error(w, "Record not found.", 400) return } mutex.Unlock() // ... overwrite any sent fields if err := r.DecodeJsonPayload(&EnvCap); err != nil { //rest.Error(w, err.Error(), 400) rest.Error(w, "Invalid data format received.", 400) return } // Force the use of the path id over an id in the payload Id, _ := strconv.Atoi(id) EnvCap.Id = int64(Id) mutex.Lock() if err := api.db.Save(&EnvCap).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() text := fmt.Sprintf("Updated EnvCap, '%s'.", EnvCap.Code) api.LogActivity(session.Id, text) w.WriteJson("Success") }
func (api *Api) GetAllScripts(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Anyone can read the list of scripts /* if login != "admin" { rest.Error(w, "Not allowed", 400) return }*/ //session := Session{} var errl error = nil //if session,errl = api.CheckLogin( login, guid ); errl != nil { if _, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) scripts := []Script{} qs := r.URL.Query() // Query string - map[string][]string if len(qs["id"]) > 0 { srch := qs["id"][0] mutex.Lock() api.db.Order("id").Find(&scripts, "id = ?", srch) mutex.Unlock() /* if api.db.Order("id"). Find(&scripts, "id = ?", srch).RecordNotFound() { rest.Error(w, "No results.", 400) return } */ } else if len(qs["name"]) > 0 { srch := qs["name"][0] mutex.Lock() api.db.Order("name").Find(&scripts, "name = ?", srch) mutex.Unlock() /* if api.db.Order("name"). Find(&scripts, "name = ?", srch).RecordNotFound() { rest.Error(w, "No results.", 400) return } */ } else { // No results is not an error mutex.Lock() err := api.db.Order("id").Find(&scripts) mutex.Unlock() if err.Error != nil { if !err.RecordNotFound() { rest.Error(w, err.Error.Error(), 500) return } } } // Create a slice of maps from users struct // to selectively copy database fields for display u := make([]map[string]interface{}, len(scripts)) for i := range scripts { u[i] = make(map[string]interface{}) u[i]["Id"] = scripts[i].Id u[i]["Name"] = scripts[i].Name u[i]["Desc"] = scripts[i].Desc // 'Source' doesn't go through Unmarshall so // is output as base64, good. Use nosource to // exclude this field. if len(qs["nosource"]) == 0 { u[i]["Source"] = scripts[i].Source } u[i]["Type"] = scripts[i].Type } // Too much noise //api.LogActivity( session.Id, "Sent list of users" ) w.WriteJson(&u) }
func (api *Api) AddEnv(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already envData := Env{} if err := r.DecodeJsonPayload(&envData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(envData.SysName) == 0 { rest.Error(w, "Incorrect data format received.", 400) return } env := Env{} mutex.Lock() if !api.db.Find(&env, "sys_name = ? and dc_id = ?", envData.SysName, envData.DcId).RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Add env mutex.Lock() if err := api.db.Save(&envData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() dc := Dc{} mutex.Lock() api.db.First(&dc, envData.DcId) mutex.Unlock() text := fmt.Sprintf("Added new environment '%s->%s'.", dc.SysName, envData.SysName) api.LogActivity(session.Id, text) w.WriteJson(envData) }
func (api *Api) AddPlugin(w rest.ResponseWriter, r *rest.Request) { // Check credentials login := r.PathParam("login") guid := r.PathParam("GUID") // Only admin is allowed if login != "admin" { rest.Error(w, "Not allowed", 400) return } session := Session{} var errl error if session, errl = api.CheckLogin(login, guid); errl != nil { rest.Error(w, errl.Error(), 401) return } defer api.TouchSession(guid) // Can't add if it exists already pluginData := Plugin{} if err := r.DecodeJsonPayload(&pluginData); err != nil { rest.Error(w, "Invalid data format received.", 400) return } else if len(pluginData.Name) == 0 { rest.Error(w, "Incorrect data format received.", 400) return } plugin := Plugin{} mutex.Lock() if !api.db.Find(&plugin, "name = ?", pluginData.Name). RecordNotFound() { mutex.Unlock() rest.Error(w, "Record exists.", 400) return } mutex.Unlock() // Make sure parent exists mutex.Lock() if len(pluginData.Parent) > 0 && api.db.Find(&plugin, "name = ?", pluginData.Parent).RecordNotFound() { mutex.Unlock() rest.Error(w, "Parent not found.", 400) return } mutex.Unlock() // Add plugin mutex.Lock() if err := api.db.Save(&pluginData).Error; err != nil { mutex.Unlock() rest.Error(w, err.Error(), 400) return } mutex.Unlock() api.LogActivity(session.Id, "Added new plugin '"+pluginData.Name+"'.") w.WriteJson(pluginData) }