github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/service/host.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "net/http" 6 "strconv" 7 "strings" 8 9 "github.com/evergreen-ci/evergreen" 10 "github.com/evergreen-ci/evergreen/model/event" 11 "github.com/evergreen-ci/evergreen/model/host" 12 "github.com/evergreen-ci/evergreen/model/task" 13 "github.com/evergreen-ci/evergreen/model/user" 14 "github.com/evergreen-ci/evergreen/util" 15 "github.com/gorilla/mux" 16 "github.com/pkg/errors" 17 ) 18 19 var ( 20 validUpdateToStatuses = []string{ 21 evergreen.HostRunning, 22 evergreen.HostQuarantined, 23 evergreen.HostDecommissioned, 24 } 25 ) 26 27 const ( 28 IncludeSpawnedHosts = "includeSpawnedHosts" 29 ) 30 31 type uiParams struct { 32 Action string `json:"action"` 33 34 // the host ids for which an action applies 35 HostIds []string `json:"host_ids"` 36 37 // for the update status option 38 Status string `json:"status"` 39 } 40 41 func (uis *UIServer) hostPage(w http.ResponseWriter, r *http.Request) { 42 projCtx := MustHaveProjectContext(r) 43 44 vars := mux.Vars(r) 45 id := vars["host_id"] 46 47 h, err := host.FindOne(host.ById(id)) 48 if err != nil { 49 uis.LoggedError(w, r, http.StatusInternalServerError, err) 50 return 51 } 52 53 if h == nil { 54 http.Error(w, "Host not found", http.StatusNotFound) 55 return 56 } 57 58 events, err := event.Find(event.AllLogCollection, event.MostRecentHostEvents(id, 50)) 59 if err != nil { 60 uis.LoggedError(w, r, http.StatusInternalServerError, err) 61 return 62 } 63 runningTask := &task.Task{} 64 if h.RunningTask != "" { 65 runningTask, err = task.FindOne(task.ById(h.RunningTask)) 66 if err != nil { 67 uis.LoggedError(w, r, http.StatusInternalServerError, err) 68 return 69 } 70 } 71 72 flashes := PopFlashes(uis.CookieStore, r, w) 73 uis.WriteHTML(w, http.StatusOK, struct { 74 Flashes []interface{} 75 Events []event.Event 76 Host *host.Host 77 RunningTask *task.Task 78 User *user.DBUser 79 ProjectData projectContext 80 }{flashes, events, h, runningTask, GetUser(r), projCtx}, 81 "base", "host.html", "base_angular.html", "menu.html") 82 } 83 84 func (uis *UIServer) hostsPage(w http.ResponseWriter, r *http.Request) { 85 projCtx := MustHaveProjectContext(r) 86 87 includeSpawnedHosts, _ := strconv.ParseBool(r.FormValue(IncludeSpawnedHosts)) 88 hosts, err := getHostsData(includeSpawnedHosts) 89 if err != nil { 90 uis.LoggedError(w, r, http.StatusInternalServerError, err) 91 return 92 } 93 94 flashes := PopFlashes(uis.CookieStore, r, w) 95 uis.WriteHTML(w, http.StatusOK, struct { 96 Flashes []interface{} 97 Hosts *hostsData 98 IncludeSpawnedHosts bool 99 User *user.DBUser 100 ProjectData projectContext 101 }{flashes, hosts, includeSpawnedHosts, GetUser(r), projCtx}, 102 "base", "hosts.html", "base_angular.html", "menu.html") 103 } 104 105 func (uis *UIServer) modifyHost(w http.ResponseWriter, r *http.Request) { 106 _ = MustHaveUser(r) 107 108 vars := mux.Vars(r) 109 id := vars["host_id"] 110 111 host, err := host.FindOne(host.ById(id)) 112 if err != nil { 113 uis.LoggedError(w, r, http.StatusInternalServerError, err) 114 return 115 } 116 117 if host == nil { 118 http.Error(w, "Host not found", http.StatusNotFound) 119 return 120 } 121 122 opts := &uiParams{} 123 124 if err = util.ReadJSONInto(util.NewRequestReader(r), opts); err != nil { 125 uis.LoggedError(w, r, http.StatusBadRequest, err) 126 return 127 } 128 129 // determine what action needs to be taken 130 switch opts.Action { 131 case "updateStatus": 132 currentStatus := host.Status 133 newStatus := opts.Status 134 if !util.SliceContains(validUpdateToStatuses, newStatus) { 135 http.Error(w, fmt.Sprintf("'%v' is not a valid status", newStatus), http.StatusBadRequest) 136 return 137 } 138 err := host.SetStatus(newStatus) 139 if err != nil { 140 uis.LoggedError(w, r, http.StatusInternalServerError, errors.Wrap(err, "Error updating host")) 141 return 142 } 143 msg := NewSuccessFlash(fmt.Sprintf("Host status successfully updated from '%v' to '%v'", currentStatus, host.Status)) 144 PushFlash(uis.CookieStore, r, w, msg) 145 uis.WriteJSON(w, http.StatusOK, "Successfully updated host status") 146 default: 147 uis.WriteJSON(w, http.StatusBadRequest, fmt.Sprintf("Unrecognized action: %v", opts.Action)) 148 } 149 } 150 151 func (uis *UIServer) modifyHosts(w http.ResponseWriter, r *http.Request) { 152 _ = MustHaveUser(r) 153 154 opts := &uiParams{} 155 156 if err := util.ReadJSONInto(util.NewRequestReader(r), opts); err != nil { 157 http.Error(w, err.Error(), http.StatusBadRequest) 158 return 159 } 160 161 hostIds := opts.HostIds 162 if len(hostIds) == 1 && strings.TrimSpace(hostIds[0]) == "" { 163 http.Error(w, "No host ID's found in request", http.StatusBadRequest) 164 return 165 } 166 167 // fetch all relevant hosts 168 hosts, err := host.Find(host.ByIds(hostIds)) 169 170 if err != nil { 171 uis.LoggedError(w, r, http.StatusInternalServerError, errors.Wrap(err, "Error finding hosts")) 172 return 173 } 174 if len(hosts) == 0 { 175 http.Error(w, "No matching hosts found.", http.StatusBadRequest) 176 return 177 } 178 179 // determine what action needs to be taken 180 switch opts.Action { 181 case "updateStatus": 182 newStatus := opts.Status 183 if !util.SliceContains(validUpdateToStatuses, newStatus) { 184 http.Error(w, fmt.Sprintf("Invalid status: %v", opts.Status), http.StatusBadRequest) 185 return 186 } 187 numHostsUpdated := 0 188 189 for _, host := range hosts { 190 err := host.SetStatus(newStatus) 191 if err != nil { 192 uis.LoggedError(w, r, http.StatusInternalServerError, errors.Wrap(err, "Error updating host")) 193 return 194 } 195 numHostsUpdated += 1 196 } 197 msg := NewSuccessFlash(fmt.Sprintf("%v host(s) status successfully updated to '%v'", 198 numHostsUpdated, newStatus)) 199 PushFlash(uis.CookieStore, r, w, msg) 200 return 201 default: 202 http.Error(w, fmt.Sprintf("Unrecognized action: %v", opts.Action), http.StatusBadRequest) 203 return 204 } 205 }