| package main |
| |
| import ( |
| "bufio" |
| "encoding/json" |
| "github.com/gorilla/mux" |
| "net/http" |
| "strings" |
| ) |
| |
| type RequestInfo struct { |
| Id string `json:"id"` |
| Name string `json:"name"` |
| Ip string `json:"ip"` |
| Mac string `json:"mac"` |
| RoleSelector string `json:"role_selector"` |
| Role string `json:"role"` |
| Script string `json:"script"` |
| } |
| |
| func (c *Context) GetRole(info *RequestInfo) (string, error) { |
| if info.Role != "" { |
| return info.Role, nil |
| } else if c.config.RoleSelectorURL == "" && info.RoleSelector == "" { |
| return c.config.DefaultRole, nil |
| } |
| selector := c.config.RoleSelectorURL |
| if info.RoleSelector != "" { |
| selector = info.RoleSelector |
| } |
| |
| r, err := http.Get(selector) |
| if err != nil { |
| return "", err |
| } |
| |
| s := bufio.NewScanner(r.Body) |
| defer r.Body.Close() |
| role := strings.TrimSpace(s.Text()) |
| if role == "" { |
| return c.config.DefaultRole, nil |
| } |
| return role, nil |
| } |
| |
| func (c *Context) validateData(info *RequestInfo) bool { |
| if strings.TrimSpace(info.Id) == "" || |
| strings.TrimSpace(info.Name) == "" || |
| strings.TrimSpace(info.Ip) == "" || |
| strings.TrimSpace(info.Mac) == "" { |
| return false |
| } |
| return true |
| } |
| |
| func (c *Context) ProvisionRequestHandler(w http.ResponseWriter, r *http.Request) { |
| var info RequestInfo |
| decoder := json.NewDecoder(r.Body) |
| defer r.Body.Close() |
| if err := decoder.Decode(&info); err != nil { |
| log.Errorf("Unable to decode request to provision : %s", err) |
| http.Error(w, err.Error(), http.StatusBadRequest) |
| return |
| } |
| |
| if !c.validateData(&info) { |
| log.Errorf("Provisioning request not valid for '%s'", info.Name) |
| w.WriteHeader(http.StatusBadRequest) |
| return |
| } |
| |
| role, err := c.GetRole(&info) |
| if err != nil { |
| log.Errorf("unable to get provisioning role for node '%s' : %s", info.Name, err) |
| http.Error(w, err.Error(), http.StatusInternalServerError) |
| return |
| } |
| |
| // If the request has a script set, override the default configuration |
| script := c.config.Script |
| if info.Script != "" { |
| script = info.Script |
| } |
| err = c.dispatcher.Dispatch(&info, role, script) |
| if err != nil { |
| log.Errorf("unable to dispatch provisioning request for node '%s' : %s", info.Name, err) |
| http.Error(w, err.Error(), http.StatusInternalServerError) |
| return |
| } |
| |
| w.WriteHeader(http.StatusAccepted) |
| } |
| |
| func (c *Context) ListRequestsHandler(w http.ResponseWriter, r *http.Request) { |
| list, err := c.storage.List() |
| bytes, err := json.Marshal(list) |
| if err != nil { |
| http.Error(w, err.Error(), http.StatusInternalServerError) |
| return |
| } |
| w.Write(bytes) |
| } |
| |
| func (c *Context) DeleteStatusHandler(w http.ResponseWriter, r *http.Request) { |
| vars := mux.Vars(r) |
| id, ok := vars["nodeid"] |
| if !ok || strings.TrimSpace(id) == "" { |
| w.WriteHeader(http.StatusBadRequest) |
| return |
| } |
| |
| err := c.storage.Delete(id) |
| if err != nil { |
| log.Errorf("Error while deleting status fo '%s' from storage : %s", id, err) |
| http.Error(w, err.Error(), http.StatusInternalServerError) |
| return |
| } |
| |
| w.WriteHeader(http.StatusOK) |
| } |
| |
| func (c *Context) QueryStatusHandler(w http.ResponseWriter, r *http.Request) { |
| vars := mux.Vars(r) |
| id, ok := vars["nodeid"] |
| if !ok || strings.TrimSpace(id) == "" { |
| w.WriteHeader(http.StatusBadRequest) |
| return |
| } |
| s, err := c.storage.Get(id) |
| if err != nil { |
| log.Errorf("Error while retrieving status for '%s' from strorage : %s", id, err) |
| http.Error(w, err.Error(), http.StatusInternalServerError) |
| return |
| } |
| if s == nil { |
| w.WriteHeader(http.StatusNotFound) |
| return |
| } |
| bytes, err := json.Marshal(s) |
| if err != nil { |
| log.Errorf("Error while attempting to marshal status for '%s' from storage : %s", id, err) |
| http.Error(w, err.Error(), http.StatusInternalServerError) |
| return |
| } |
| |
| switch s.Status { |
| case Pending, Running: |
| w.WriteHeader(http.StatusAccepted) |
| case Failed, Complete: |
| w.WriteHeader(http.StatusOK) |
| default: |
| w.WriteHeader(http.StatusInternalServerError) |
| } |
| |
| w.Write(bytes) |
| } |