blob: b0460f04201e6e077b027ff898b306fe0043d56c [file] [log] [blame]
David K. Bainbridgedf9df632016-07-07 18:47:46 -07001// Copyright 2016 Open Networking Laboratory
2//
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.
gunjan56e19d272016-07-07 14:23:26 -070014package main
15
16import (
17 "encoding/json"
gunjan5c79837e2016-07-09 03:31:27 -070018 "errors"
gunjan56e19d272016-07-07 14:23:26 -070019 "fmt"
gunjan5c79837e2016-07-09 03:31:27 -070020 "github.com/gorilla/mux"
21 "github.com/kelseyhightower/envconfig"
gunjan56e19d272016-07-07 14:23:26 -070022 "io/ioutil"
gunjan5c79837e2016-07-09 03:31:27 -070023 "log"
gunjan56e19d272016-07-07 14:23:26 -070024 "net/http"
25 "os"
26 "strings"
27 "text/template"
28)
29
gunjan516a9b442016-08-11 13:51:19 -070030var unmarshalError = errors.New("Error Unmarshaling the JSON Data\n")
31
gunjan5c79837e2016-07-09 03:31:27 -070032type Config struct {
33 Port string `default:"8181"`
34 IP string `default:"127.0.0.1"`
gunjan5d6ca1772016-07-20 18:11:04 -070035 SwitchCount int `default:"0"`
36 HostCount int `default:"0"`
gunjan5c79837e2016-07-09 03:31:27 -070037 Username string `default:"karaf"`
38 Password string `default:"karaf"`
39 LogLevel string `default:"warning" envconfig:"LOG_LEVEL"`
40 LogFormat string `default:"text" envconfig:"LOG_FORMAT"`
41 ConfigServerPort string `default:"1337"`
42 ConfigServerIP string `default:"127.0.0.1"`
43}
44
gunjan56e19d272016-07-07 14:23:26 -070045type hosts struct {
46 Host []struct {
47 Mac string `json:"mac"`
48 IpAddresses []string `json:"ipAddresses"`
49 Location struct {
50 ElementID string `json:"elementId`
51 Port string `json:"port"`
52 } `json:"location"`
53 Comma string
54 Gateway string
55 } `json:"hosts"`
56}
57
58type devices struct {
59 Device []struct {
60 Id string `json:"id"`
61 ChassisId string `json:"chassisId"`
62 Annotations struct {
63 ManagementAddress string `json:"managementAddress"`
64 } `json:"annotations"`
65 Comma string `default:","`
66 } `json:"devices"`
67}
68
69type onosLinks struct {
gunjan5c79837e2016-07-09 03:31:27 -070070 Links []struct {
71 Src struct {
72 Port string `json:"port"`
73 Device string `json:"device"`
74 } `json:"src"`
75 Dst struct {
76 Port string `json:"port"`
77 Device string `json:"device"`
78 } `json:"dst"`
79 } `json:"links"`
gunjan56e19d272016-07-07 14:23:26 -070080}
81
82type linkStructJSON struct {
83 Val string
84 Comma string
85}
86
gunjan5c79837e2016-07-09 03:31:27 -070087type ConfigParam struct {
gunjan516a9b442016-08-11 13:51:19 -070088 SwitchCount int `json:"switchcount"`
89 HostCount int `json:"hostcount"`
90 ONOSIP string `json:"onosip"`
gunjan5c79837e2016-07-09 03:31:27 -070091}
92
93var c Config
94
gunjan56e19d272016-07-07 14:23:26 -070095func main() {
gunjan5c79837e2016-07-09 03:31:27 -070096
97 err := envconfig.Process("CONFIGGEN", &c)
98 if err != nil {
99 log.Fatalf("[ERROR] Unable to parse configuration options : %s", err)
100 }
101
102 router := mux.NewRouter()
103 router.HandleFunc("/config/", ConfigGenHandler).Methods("POST")
104 http.Handle("/", router)
105
106 fmt.Println("Config Generator server listening at: " + c.ConfigServerIP + ":" + c.ConfigServerPort)
107
108 http.ListenAndServe(c.ConfigServerIP+":"+c.ConfigServerPort, nil)
109
110}
111
112func ConfigGenHandler(w http.ResponseWriter, r *http.Request) {
113 var para ConfigParam
114
115 decoder := json.NewDecoder(r.Body)
116 defer r.Body.Close()
117 if err := decoder.Decode(&para); err != nil {
118 fmt.Errorf("Unable to decode request to provision : %s", err)
119 http.Error(w, err.Error(), http.StatusBadRequest)
120 return
121 }
122
123 c.HostCount = para.HostCount
124 c.SwitchCount = para.SwitchCount
gunjan516a9b442016-08-11 13:51:19 -0700125 c.IP = para.ONOSIP
gunjan5c79837e2016-07-09 03:31:27 -0700126
127 onos := "http://" + c.Username + ":" + c.Password + "@" + c.IP + ":" + c.Port
gunjan56e19d272016-07-07 14:23:26 -0700128
129 err := os.Remove("network-cfg.json")
130 if err != nil {
gunjan5c79837e2016-07-09 03:31:27 -0700131 log.Println("Warning: no file called network-cfg.json (ignore if this is the first run)")
gunjan56e19d272016-07-07 14:23:26 -0700132 }
gunjan5c79837e2016-07-09 03:31:27 -0700133 err = generateDevicesJSON(onos)
134 if err != nil {
gunjan516a9b442016-08-11 13:51:19 -0700135 w.WriteHeader(http.StatusInternalServerError)
gunjan5c79837e2016-07-09 03:31:27 -0700136 fmt.Fprintf(w, err.Error())
137 return
138 }
gunjan516a9b442016-08-11 13:51:19 -0700139 err = generateLinkJSON(onos)
140 if err != nil {
141 w.WriteHeader(http.StatusInternalServerError)
142 fmt.Fprintf(w, err.Error())
143 return
144 }
gunjan5c79837e2016-07-09 03:31:27 -0700145 err = generateHostJSON(onos)
146 if err != nil {
gunjan516a9b442016-08-11 13:51:19 -0700147 w.WriteHeader(http.StatusInternalServerError)
gunjan5c79837e2016-07-09 03:31:27 -0700148 fmt.Fprintf(w, err.Error())
149 return
150 }
gunjan56e19d272016-07-07 14:23:26 -0700151
152 fmt.Println("Config file generated: network-cfg.json")
153
gunjan5c79837e2016-07-09 03:31:27 -0700154 data, err := ioutil.ReadFile("network-cfg.json")
155 check(err)
156
157 w.WriteHeader(http.StatusAccepted)
158 fmt.Fprintf(w, string(data))
159
gunjan56e19d272016-07-07 14:23:26 -0700160}
161
162func writeToFile(object interface{}, t string) {
163 f, err := os.OpenFile("network-cfg.json", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
164 if err != nil {
165 panic(err)
166 }
167
168 defer f.Close()
169
170 tpl, err := template.ParseFiles(t)
171 check(err)
172 err = tpl.Execute(f, object)
173 check(err)
174}
175
gunjan5c79837e2016-07-09 03:31:27 -0700176func generateDevicesJSON(onos string) error {
gunjan516a9b442016-08-11 13:51:19 -0700177 ds, err := getData(onos + "/onos/v1/devices")
178 if err != nil {
179 return err
180 }
gunjan56e19d272016-07-07 14:23:26 -0700181
182 var d devices
gunjan516a9b442016-08-11 13:51:19 -0700183 err = json.Unmarshal(ds, &d)
184 if err != nil {
185 return unmarshalError
186 }
gunjan56e19d272016-07-07 14:23:26 -0700187
gunjan5c79837e2016-07-09 03:31:27 -0700188 if len(d.Device) != c.SwitchCount {
189 _ = os.Remove("network-cfg.json")
190 log.Println("[INFO] Cleaning up unfinished config file")
191 e := fmt.Sprintf("[ERROR] Number of switches configured don't match actual switches connected to the controller. Configured: %d, connected: %d", c.SwitchCount, len(d.Device))
192 log.Println(e)
193 return errors.New(e)
194 }
195
gunjan56e19d272016-07-07 14:23:26 -0700196 for k, _ := range d.Device {
197 d.Device[k].Comma = ","
198 if k >= len(d.Device)-1 {
199 d.Device[k].Comma = ""
200 }
201 }
202
203 writeToFile(d.Device, "devices.tpl")
gunjan5c79837e2016-07-09 03:31:27 -0700204 return nil
gunjan56e19d272016-07-07 14:23:26 -0700205
206}
207
gunjan5c79837e2016-07-09 03:31:27 -0700208func generateHostJSON(onos string) error {
gunjan516a9b442016-08-11 13:51:19 -0700209 hs, err := getData(onos + "/onos/v1/hosts")
210 if err != nil {
211 return err
212 }
gunjan56e19d272016-07-07 14:23:26 -0700213 var h hosts
gunjan516a9b442016-08-11 13:51:19 -0700214 err = json.Unmarshal(hs, &h)
215 if err != nil {
216 return unmarshalError
217 }
gunjan56e19d272016-07-07 14:23:26 -0700218
gunjan5c79837e2016-07-09 03:31:27 -0700219 if len(h.Host) != c.HostCount {
220 _ = os.Remove("network-cfg.json")
221 log.Println("[INFO] Cleaning up unfinished config file")
222 e := fmt.Sprintf("[ERROR] Number of hosts configured don't match actual hosts visible to the controller. Configured: %d, connected: %d", c.HostCount, len(h.Host))
223 log.Println(e)
224 return errors.New(e)
225 }
226
gunjan56e19d272016-07-07 14:23:26 -0700227 for k, _ := range h.Host {
228
229 h.Host[k].Comma = ","
230 if k >= len(h.Host)-1 {
231 h.Host[k].Comma = ""
232 }
233
234 parts := strings.Split(h.Host[k].IpAddresses[0], ".")
235 ip := ""
236 for _, v := range parts[:len(parts)-1] {
237 ip = ip + v + "."
238 }
239 h.Host[k].Gateway = ip
240 }
241
242 writeToFile(h.Host, "ports.tpl")
243
244 writeToFile(h.Host, "hosts.tpl")
gunjan5c79837e2016-07-09 03:31:27 -0700245 return nil
gunjan56e19d272016-07-07 14:23:26 -0700246
247}
248
gunjan516a9b442016-08-11 13:51:19 -0700249func generateLinkJSON(onos string) error {
gunjan56e19d272016-07-07 14:23:26 -0700250
gunjan516a9b442016-08-11 13:51:19 -0700251 links, err := getData(onos + "/onos/v1/links")
252 if err != nil {
253 return err
254 }
gunjan56e19d272016-07-07 14:23:26 -0700255
256 var l onosLinks
gunjan516a9b442016-08-11 13:51:19 -0700257 err = json.Unmarshal(links, &l)
258 if err != nil {
259 return unmarshalError
260 }
gunjan56e19d272016-07-07 14:23:26 -0700261
262 var in []linkStructJSON
263
264 for k, v := range l.Links {
265
266 comma := ","
267 val := fmt.Sprint(v.Src.Device + "/" + v.Src.Port + "-" + v.Dst.Device + "/" + v.Dst.Port)
268 if k >= len(l.Links)-1 {
269 comma = ""
270 }
271
272 tmp := linkStructJSON{val, comma}
273 in = append(in, tmp)
274
275 }
276
277 writeToFile(in, "links.tpl")
278
gunjan516a9b442016-08-11 13:51:19 -0700279 return nil
280
gunjan56e19d272016-07-07 14:23:26 -0700281}
282
gunjan516a9b442016-08-11 13:51:19 -0700283func getData(url string) ([]byte, error) {
gunjan56e19d272016-07-07 14:23:26 -0700284
285 resp, err := http.Get(url)
gunjan516a9b442016-08-11 13:51:19 -0700286 if err != nil {
287 return nil, errors.New("Error getting data from the URL\n")
288 }
gunjan56e19d272016-07-07 14:23:26 -0700289
290 defer resp.Body.Close()
291
292 body, err := ioutil.ReadAll(resp.Body)
gunjan516a9b442016-08-11 13:51:19 -0700293 if err != nil {
294 return nil, errors.New("Error reading data from response body\n")
295 }
gunjan56e19d272016-07-07 14:23:26 -0700296
gunjan516a9b442016-08-11 13:51:19 -0700297 return body, nil
gunjan56e19d272016-07-07 14:23:26 -0700298
299}
300
301func check(e error) {
302 if e != nil {
303 panic(e)
304 }
305}