blob: 5bc6e5781099984ab581e9d0bcd007ffac9bcfaf [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. Bainbridge97ee8052016-06-14 00:52:07 -07007 "log"
David K. Bainbridgef0da8732016-06-01 16:15:37 -07008 "net/http"
9 "strings"
10)
11
12type RequestInfo struct {
David K. Bainbridge97ee8052016-06-14 00:52:07 -070013 Id string `json:"id"`
14 Name string `json:"name"`
15 Ip string `json:"ip"`
16 Mac string `json:"mac"`
17 RoleSelector string `json:"role_selector"`
18 Role string `json:"role"`
19 Script string `json:"script"`
David K. Bainbridgef0da8732016-06-01 16:15:37 -070020}
21
22func (c *Context) GetRole(info *RequestInfo) (string, error) {
David K. Bainbridge97ee8052016-06-14 00:52:07 -070023 if info.Role != "" {
24 return info.Role, nil
25 } else if c.config.RoleSelectorURL == "" && info.RoleSelector == "" {
David K. Bainbridgef0da8732016-06-01 16:15:37 -070026 return c.config.DefaultRole, nil
27 }
David K. Bainbridge97ee8052016-06-14 00:52:07 -070028 selector := c.config.RoleSelectorURL
29 if info.RoleSelector != "" {
30 selector = info.RoleSelector
31 }
32
33 r, err := http.Get(selector)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070034 if err != nil {
35 return "", err
36 }
37
38 s := bufio.NewScanner(r.Body)
39 defer r.Body.Close()
40 role := strings.TrimSpace(s.Text())
41 if role == "" {
42 return c.config.DefaultRole, nil
43 }
44 return role, nil
45}
46
47func (c *Context) validateData(info *RequestInfo) bool {
48 if strings.TrimSpace(info.Id) == "" ||
49 strings.TrimSpace(info.Name) == "" ||
50 strings.TrimSpace(info.Ip) == "" ||
51 strings.TrimSpace(info.Mac) == "" {
52 return false
53 }
54 return true
55}
56
57func (c *Context) ProvisionRequestHandler(w http.ResponseWriter, r *http.Request) {
58 var info RequestInfo
59 decoder := json.NewDecoder(r.Body)
60 defer r.Body.Close()
David K. Bainbridged86d96d2016-06-01 17:28:46 -070061 if err := decoder.Decode(&info); err != nil {
David K. Bainbridge3ee76412016-06-15 18:56:08 -070062 log.Printf("[error] Unable to decode request to provision : %s", err)
David K. Bainbridged86d96d2016-06-01 17:28:46 -070063 http.Error(w, err.Error(), http.StatusBadRequest)
64 return
65 }
David K. Bainbridge97ee8052016-06-14 00:52:07 -070066
David K. Bainbridged86d96d2016-06-01 17:28:46 -070067 if !c.validateData(&info) {
David K. Bainbridge546cdc32016-06-29 15:30:22 -070068 log.Printf("[error] Provisioning request not valid for '%s'", info.Name)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070069 w.WriteHeader(http.StatusBadRequest)
70 return
71 }
72
David K. Bainbridgef0da8732016-06-01 16:15:37 -070073 role, err := c.GetRole(&info)
74 if err != nil {
David K. Bainbridge3ee76412016-06-15 18:56:08 -070075 log.Printf("[error] unable to get provisioning role for node '%s' : %s", info.Name, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070076 http.Error(w, err.Error(), http.StatusInternalServerError)
77 return
78 }
David K. Bainbridgebe58a0d2016-06-22 15:43:02 -070079
80 // If the request has a script set, override the default configuration
81 script := c.config.Script
82 if info.Script != "" {
83 script = info.Script
84 }
85 err = c.dispatcher.Dispatch(&info, role, script)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070086 if err != nil {
David K. Bainbridge546cdc32016-06-29 15:30:22 -070087 log.Printf("[error] unable to dispatch provisioning request for node '%s' : %s", info.Name, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070088 http.Error(w, err.Error(), http.StatusInternalServerError)
89 return
90 }
91
92 w.WriteHeader(http.StatusAccepted)
93}
94
95func (c *Context) ListRequestsHandler(w http.ResponseWriter, r *http.Request) {
96 list, err := c.storage.List()
97 bytes, err := json.Marshal(list)
98 if err != nil {
99 http.Error(w, err.Error(), http.StatusInternalServerError)
100 return
101 }
102 w.Write(bytes)
103}
104
105func (c *Context) QueryStatusHandler(w http.ResponseWriter, r *http.Request) {
106 vars := mux.Vars(r)
107 id, ok := vars["nodeid"]
108 if !ok || strings.TrimSpace(id) == "" {
109 w.WriteHeader(http.StatusBadRequest)
110 return
111 }
112 s, err := c.storage.Get(id)
113 if err != nil {
David K. Bainbridge97ee8052016-06-14 00:52:07 -0700114 log.Printf("[warn] Error while retrieving status for '%s' from strorage : %s", id, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700115 http.Error(w, err.Error(), http.StatusInternalServerError)
116 return
117 }
118 if s == nil {
119 w.WriteHeader(http.StatusNotFound)
120 return
121 }
122 bytes, err := json.Marshal(s)
123 if err != nil {
David K. Bainbridge97ee8052016-06-14 00:52:07 -0700124 log.Printf("[error] Error while attempting to marshal status for '%s' from storage : %s", id, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700125 http.Error(w, err.Error(), http.StatusInternalServerError)
126 return
127 }
David K. Bainbridge8352c592016-06-02 12:48:37 -0700128
129 switch s.Status {
130 case Pending, Running:
131 w.WriteHeader(http.StatusAccepted)
David K. Bainbridge97ee8052016-06-14 00:52:07 -0700132 case Failed, Complete:
David K. Bainbridge8352c592016-06-02 12:48:37 -0700133 w.WriteHeader(http.StatusOK)
134 default:
135 w.WriteHeader(http.StatusInternalServerError)
136 }
137
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700138 w.Write(bytes)
139}