blob: 7d2632dc620a5f65931c0e5d23927eb456bbd97a [file] [log] [blame]
Brian O'Connor6a37ea92017-08-03 22:45:59 -07001// Copyright 2016 Open Networking Foundation
David K. Bainbridgedf9df632016-07-07 18:47:46 -07002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
David K. Bainbridgef0da8732016-06-01 16:15:37 -070014package main
15
16import (
17 "bufio"
18 "encoding/json"
19 "github.com/gorilla/mux"
David K. Bainbridgef0da8732016-06-01 16:15:37 -070020 "net/http"
21 "strings"
22)
23
24type RequestInfo struct {
David K. Bainbridge97ee8052016-06-14 00:52:07 -070025 Id string `json:"id"`
26 Name string `json:"name"`
27 Ip string `json:"ip"`
28 Mac string `json:"mac"`
29 RoleSelector string `json:"role_selector"`
30 Role string `json:"role"`
31 Script string `json:"script"`
David K. Bainbridgef0da8732016-06-01 16:15:37 -070032}
33
34func (c *Context) GetRole(info *RequestInfo) (string, error) {
David K. Bainbridge97ee8052016-06-14 00:52:07 -070035 if info.Role != "" {
36 return info.Role, nil
37 } else if c.config.RoleSelectorURL == "" && info.RoleSelector == "" {
David K. Bainbridgef0da8732016-06-01 16:15:37 -070038 return c.config.DefaultRole, nil
39 }
David K. Bainbridge97ee8052016-06-14 00:52:07 -070040 selector := c.config.RoleSelectorURL
41 if info.RoleSelector != "" {
42 selector = info.RoleSelector
43 }
44
45 r, err := http.Get(selector)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070046 if err != nil {
47 return "", err
48 }
49
50 s := bufio.NewScanner(r.Body)
51 defer r.Body.Close()
52 role := strings.TrimSpace(s.Text())
53 if role == "" {
54 return c.config.DefaultRole, nil
55 }
56 return role, nil
57}
58
59func (c *Context) validateData(info *RequestInfo) bool {
60 if strings.TrimSpace(info.Id) == "" ||
61 strings.TrimSpace(info.Name) == "" ||
62 strings.TrimSpace(info.Ip) == "" ||
63 strings.TrimSpace(info.Mac) == "" {
64 return false
65 }
66 return true
67}
68
69func (c *Context) ProvisionRequestHandler(w http.ResponseWriter, r *http.Request) {
70 var info RequestInfo
71 decoder := json.NewDecoder(r.Body)
72 defer r.Body.Close()
David K. Bainbridged86d96d2016-06-01 17:28:46 -070073 if err := decoder.Decode(&info); err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070074 log.Errorf("Unable to decode request to provision : %s", err)
David K. Bainbridged86d96d2016-06-01 17:28:46 -070075 http.Error(w, err.Error(), http.StatusBadRequest)
76 return
77 }
David K. Bainbridge97ee8052016-06-14 00:52:07 -070078
David K. Bainbridged86d96d2016-06-01 17:28:46 -070079 if !c.validateData(&info) {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070080 log.Errorf("Provisioning request not valid for '%s'", info.Name)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070081 w.WriteHeader(http.StatusBadRequest)
82 return
83 }
84
David K. Bainbridgef0da8732016-06-01 16:15:37 -070085 role, err := c.GetRole(&info)
86 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070087 log.Errorf("unable to get provisioning role 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 }
David K. Bainbridgebe58a0d2016-06-22 15:43:02 -070091
92 // If the request has a script set, override the default configuration
93 script := c.config.Script
94 if info.Script != "" {
95 script = info.Script
96 }
97 err = c.dispatcher.Dispatch(&info, role, script)
David K. Bainbridgef0da8732016-06-01 16:15:37 -070098 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -070099 log.Errorf("unable to dispatch provisioning request for node '%s' : %s", info.Name, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700100 http.Error(w, err.Error(), http.StatusInternalServerError)
101 return
102 }
103
104 w.WriteHeader(http.StatusAccepted)
105}
106
107func (c *Context) ListRequestsHandler(w http.ResponseWriter, r *http.Request) {
108 list, err := c.storage.List()
109 bytes, err := json.Marshal(list)
110 if err != nil {
111 http.Error(w, err.Error(), http.StatusInternalServerError)
112 return
113 }
114 w.Write(bytes)
115}
116
David K. Bainbridge068e87d2016-06-30 13:53:19 -0700117func (c *Context) DeleteStatusHandler(w http.ResponseWriter, r *http.Request) {
118 vars := mux.Vars(r)
119 id, ok := vars["nodeid"]
120 if !ok || strings.TrimSpace(id) == "" {
121 w.WriteHeader(http.StatusBadRequest)
122 return
123 }
124
125 err := c.storage.Delete(id)
126 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -0700127 log.Errorf("Error while deleting status fo '%s' from storage : %s", id, err)
David K. Bainbridge068e87d2016-06-30 13:53:19 -0700128 http.Error(w, err.Error(), http.StatusInternalServerError)
129 return
130 }
131
132 w.WriteHeader(http.StatusOK)
133}
134
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700135func (c *Context) QueryStatusHandler(w http.ResponseWriter, r *http.Request) {
136 vars := mux.Vars(r)
137 id, ok := vars["nodeid"]
138 if !ok || strings.TrimSpace(id) == "" {
139 w.WriteHeader(http.StatusBadRequest)
140 return
141 }
142 s, err := c.storage.Get(id)
143 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -0700144 log.Errorf("Error while retrieving status for '%s' from strorage : %s", id, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700145 http.Error(w, err.Error(), http.StatusInternalServerError)
146 return
147 }
148 if s == nil {
149 w.WriteHeader(http.StatusNotFound)
150 return
151 }
152 bytes, err := json.Marshal(s)
153 if err != nil {
David K. Bainbridgea9c2e0a2016-07-01 18:33:50 -0700154 log.Errorf("Error while attempting to marshal status for '%s' from storage : %s", id, err)
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700155 http.Error(w, err.Error(), http.StatusInternalServerError)
156 return
157 }
David K. Bainbridge8352c592016-06-02 12:48:37 -0700158
159 switch s.Status {
160 case Pending, Running:
161 w.WriteHeader(http.StatusAccepted)
David K. Bainbridge97ee8052016-06-14 00:52:07 -0700162 case Failed, Complete:
David K. Bainbridge8352c592016-06-02 12:48:37 -0700163 w.WriteHeader(http.StatusOK)
164 default:
165 w.WriteHeader(http.StatusInternalServerError)
166 }
167
David K. Bainbridgef0da8732016-06-01 16:15:37 -0700168 w.Write(bytes)
169}