blob: bb93de426444ddaf1211ef0dfd66c28c7bc7b86f [file] [log] [blame]
David K. Bainbridgef0da8732016-06-01 16:15:37 -07001package main
2
3import (
4 "bufio"
5 "encoding/json"
6 "github.com/gorilla/mux"
David K. Bainbridgef0da8732016-06-01 16:15:37 -07007 "net/http"
8 "strings"
9)
10
11type RequestInfo struct {
David K. Bainbridge97ee8052016-06-14 00:52:07 -070012 Id string `json:"id"`
13 Name string `json:"name"`
14 Ip string `json:"ip"`
15 Mac string `json:"mac"`
16 RoleSelector string `json:"role_selector"`
17 Role string `json:"role"`
18 Script string `json:"script"`
David K. Bainbridgef0da8732016-06-01 16:15:37 -070019}
20
21func (c *Context) GetRole(info *RequestInfo) (string, error) {
David K. Bainbridge97ee8052016-06-14 00:52:07 -070022 if info.Role != "" {
23 return info.Role, nil
24 } else if c.config.RoleSelectorURL == "" && info.RoleSelector == "" {
David K. Bainbridgef0da8732016-06-01 16:15:37 -070025 return c.config.DefaultRole, nil
26 }
David K. Bainbridge97ee8052016-06-14 00:52:07 -070027 selector := c.config.RoleSelectorURL
28 if info.RoleSelector != "" {
29 selector = info.RoleSelector
30 }
31
32 r, err := http.Get(selector)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070033 if err != nil {
34 return "", err
35 }
36
37 s := bufio.NewScanner(r.Body)
38 defer r.Body.Close()
39 role := strings.TrimSpace(s.Text())
40 if role == "" {
41 return c.config.DefaultRole, nil
42 }
43 return role, nil
44}
45
46func (c *Context) validateData(info *RequestInfo) bool {
47 if strings.TrimSpace(info.Id) == "" ||
48 strings.TrimSpace(info.Name) == "" ||
49 strings.TrimSpace(info.Ip) == "" ||
50 strings.TrimSpace(info.Mac) == "" {
51 return false
52 }
53 return true
54}
55
56func (c *Context) ProvisionRequestHandler(w http.ResponseWriter, r *http.Request) {
57 var info RequestInfo
58 decoder := json.NewDecoder(r.Body)
59 defer r.Body.Close()
David K. Bainbridged86d96d2016-06-01 17:28:46 -070060 if err := decoder.Decode(&info); err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070061 log.Errorf("Unable to decode request to provision : %s", err)
David K. Bainbridged86d96d2016-06-01 17:28:46 -070062 http.Error(w, err.Error(), http.StatusBadRequest)
63 return
64 }
David K. Bainbridge97ee8052016-06-14 00:52:07 -070065
David K. Bainbridged86d96d2016-06-01 17:28:46 -070066 if !c.validateData(&info) {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070067 log.Errorf("Provisioning request not valid for '%s'", info.Name)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070068 w.WriteHeader(http.StatusBadRequest)
69 return
70 }
71
David K. Bainbridgef0da8732016-06-01 16:15:37 -070072 role, err := c.GetRole(&info)
73 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070074 log.Errorf("unable to get provisioning role for node '%s' : %s", info.Name, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070075 http.Error(w, err.Error(), http.StatusInternalServerError)
76 return
77 }
David K. Bainbridgebe58a0d2016-06-22 15:43:02 -070078
79 // If the request has a script set, override the default configuration
80 script := c.config.Script
81 if info.Script != "" {
82 script = info.Script
83 }
84 err = c.dispatcher.Dispatch(&info, role, script)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070085 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070086 log.Errorf("unable to dispatch provisioning request for node '%s' : %s", info.Name, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070087 http.Error(w, err.Error(), http.StatusInternalServerError)
88 return
89 }
90
91 w.WriteHeader(http.StatusAccepted)
92}
93
94func (c *Context) ListRequestsHandler(w http.ResponseWriter, r *http.Request) {
95 list, err := c.storage.List()
96 bytes, err := json.Marshal(list)
97 if err != nil {
98 http.Error(w, err.Error(), http.StatusInternalServerError)
99 return
100 }
101 w.Write(bytes)
102}
103
David K. Bainbridge068e87d2016-06-30 13:53:19 -0700104func (c *Context) DeleteStatusHandler(w http.ResponseWriter, r *http.Request) {
105 vars := mux.Vars(r)
106 id, ok := vars["nodeid"]
107 if !ok || strings.TrimSpace(id) == "" {
108 w.WriteHeader(http.StatusBadRequest)
109 return
110 }
111
112 err := c.storage.Delete(id)
113 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -0700114 log.Errorf("Error while deleting status fo '%s' from storage : %s", id, err)
David K. Bainbridge068e87d2016-06-30 13:53:19 -0700115 http.Error(w, err.Error(), http.StatusInternalServerError)
116 return
117 }
118
119 w.WriteHeader(http.StatusOK)
120}
121
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700122func (c *Context) QueryStatusHandler(w http.ResponseWriter, r *http.Request) {
123 vars := mux.Vars(r)
124 id, ok := vars["nodeid"]
125 if !ok || strings.TrimSpace(id) == "" {
126 w.WriteHeader(http.StatusBadRequest)
127 return
128 }
129 s, err := c.storage.Get(id)
130 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -0700131 log.Errorf("Error while retrieving status for '%s' from strorage : %s", id, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700132 http.Error(w, err.Error(), http.StatusInternalServerError)
133 return
134 }
135 if s == nil {
136 w.WriteHeader(http.StatusNotFound)
137 return
138 }
139 bytes, err := json.Marshal(s)
140 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -0700141 log.Errorf("Error while attempting to marshal status for '%s' from storage : %s", id, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700142 http.Error(w, err.Error(), http.StatusInternalServerError)
143 return
144 }
David K. Bainbridge8352c592016-06-02 12:48:37 -0700145
146 switch s.Status {
147 case Pending, Running:
148 w.WriteHeader(http.StatusAccepted)
David K. Bainbridge97ee8052016-06-14 00:52:07 -0700149 case Failed, Complete:
David K. Bainbridge8352c592016-06-02 12:48:37 -0700150 w.WriteHeader(http.StatusOK)
151 default:
152 w.WriteHeader(http.StatusInternalServerError)
153 }
154
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700155 w.Write(bytes)
156}