blob: a64271a3d291af840a59dcdb3a948500741d4d03 [file] [log] [blame]
Sergio Slobodrianbe829272017-07-17 14:45:45 -04001package main // import "ciena.com/envoyd"
2
3import (
4 "os"
5 "os/exec"
6 "fmt"
7 "log"
8 "strconv"
9 "time"
10 "net"
11 "io/ioutil"
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040012 "io"
Sergio Slobodrianbe829272017-07-17 14:45:45 -040013 "text/template"
14 "encoding/json"
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040015 "sync"
16 "flag"
17 "bufio"
Sergio Slobodrianbe829272017-07-17 14:45:45 -040018 consulapi "github.com/hashicorp/consul/api"
19)
20
21// DATA STRUCTURES
22
Sergio Slobodrianbe829272017-07-17 14:45:45 -040023//Client provides an interface for getting data out of Consul
24type Client interface {
25// Get a Service from consulapi
26 Service(string, string) ([]string, error)
27// Register a service with local agent
28 Register(string, int) error
29// Deregister a service with local agent
30 DeRegister(string) error
31}
32
33type client struct {
34 consulapi *consulapi.Client
35}
36
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040037type EnvoyConfigVars struct {
38 VolthaVip string
39 VolthaRR []string
Sergio Slobodrian6570c742017-08-07 23:11:33 -040040 vcorePort string
41 HttpPort string
42 HttpsPort string
43 GrpcPort string
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040044}
45
46type VolthaClusterEntry struct {
47 Prefix string
48 Id string
49 Host string
50}
51
Sergio Slobodrianbe829272017-07-17 14:45:45 -040052// This struct is not used yet
53// TODO: Update the daemon to use this structure to for a
54// more object oriented implementation
55type EnvoyControl struct {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040056 // Command line parameters
57 assignmentKey string
58 envoyConfigTemplate string
Sergio Slobodrian6570c742017-08-07 23:11:33 -040059 envoyConfigTemplateBoth string
60 envoyConfigTemplateNoHttps string
61 envoyConfigTemplateNoHttp string
62 envoyHttpPort string
63 envoyHttpsPort string
64 httpDisabled bool
65 httpsDisabled bool
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040066 envoyConfig string
67 vcoreSvcName string
68 consulSvcName string
69 vcorePort string
Sergio Slobodrian6570c742017-08-07 23:11:33 -040070 envoyGrpcPort string
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040071 consulPort string
72 retries int
Sergio Slobodrianbe829272017-07-17 14:45:45 -040073 waitTime int
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040074 // Runtime variables
75 consul * consulapi.Client
76 vcoreHostIpName string
77 vcoreIdName string
Sergio Slobodrianbe829272017-07-17 14:45:45 -040078 vc []VolthaClusterEntry
Sergio Slobodrianbe829272017-07-17 14:45:45 -040079 ipAddrs map[string][]string
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040080 restartEpoch int
81 reLock sync.Mutex // Exclusive access to the restartEpoch
Sergio Slobodrianbe829272017-07-17 14:45:45 -040082}
83
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040084
85func NewEnvoyControl() (ec * EnvoyControl) {
86 var envCtrl EnvoyControl = EnvoyControl { // Default values
87 // Command line parameters
88 assignmentKey: "service/voltha/data/core/assignment",
89 envoyConfigTemplate: "/envoy/voltha-grpc-proxy.template.json",
Sergio Slobodrian6570c742017-08-07 23:11:33 -040090 envoyConfigTemplateBoth: "/envoy/voltha-grpc-proxy.template.json",
91 envoyConfigTemplateNoHttps: "/envoy/voltha-grpc-proxy-no-https.template.json",
92 envoyConfigTemplateNoHttp: "/envoy/voltha-grpc-proxy-no-http.template.json",
93 envoyHttpsPort: "8443",
94 envoyHttpPort: "8882",
95 envoyGrpcPort: "50555",
96 httpDisabled: false,
97 httpsDisabled: false,
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -040098 envoyConfig: "/envoy/voltha-grpc-proxy.json",
99 //envoyLogFile: "/envoy/voltha_access_log.log",
100 vcoreSvcName: "vcore",
101 consulSvcName: "consul",
102 vcorePort: "50556",
103 consulPort: "8500",
104 retries: 10,
105 waitTime: 2,
106 // Runtime variables
107 vcoreHostIpName: "host",
108 vcoreIdName: "id",
109 ipAddrs: make(map[string][]string),
110 restartEpoch: 0,
111 }
112 ec = &envCtrl
113 return
114}
115
116func (ec * EnvoyControl) resolveServiceAddress(serviceName string) (err error) {
117 for i := 0; i < ec.retries; i++ {
118 ec.ipAddrs[serviceName], err = net.LookupHost(serviceName)
119 if err != nil {
120 log.Printf("%s name resolution failed %d time(s) retrying...", serviceName, i+1)
121 } else {
122 //fmt.Printf("%s address = %s\n",serviceName, addrs[0])
123 break
124 }
125 time.Sleep(time.Duration(ec.waitTime) * time.Second)
126 }
127 if err != nil {
128 log.Printf("%s name resolution failed %d times gving up", serviceName, ec.retries)
129 }
130 return
131}
132
133func (ec * EnvoyControl) consulConnect(serviceName string, port string) (err error) {
134 // Fire up a consul client and get the kv store
135 cConfig := consulapi.DefaultNonPooledConfig()
136 cConfig.Address = ec.ipAddrs[serviceName][0] + ":" + port
137 ec.consul, err = consulapi.NewClient(cConfig)
138 if err != nil {
139 log.Fatal("error creating consul client aborting")
140 return
141 }
142 return
143}
144
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400145
146//NewConsul returns a Client interface for given consulapi address
147func NewConsulClient(addr string) (*client, error) {
148 config := consulapi.DefaultConfig()
149 config.Address = addr
150 c, err := consulapi.NewClient(config)
151 if err != nil {
152 return nil, err
153 }
154 return &client{consulapi: c}, nil
155}
156
157// Register a service with consulapi local agent
158func (c *client) Register(name string, port int) error {
159 reg := &consulapi.AgentServiceRegistration{
160 ID: name,
161 Name: name,
162 Port: port,
163 }
164 return c.consulapi.Agent().ServiceRegister(reg)
165}
166
167// DeRegister a service with consulapi local agent
168func (c *client) DeRegister(id string) error {
169 return c.consulapi.Agent().ServiceDeregister(id)
170}
171
172// Service return a service
173func (c *client) Service(service, tag string) ([]*consulapi.ServiceEntry, *consulapi.QueryMeta, error) {
174 passingOnly := true
175 addrs, meta, err := c.consulapi.Health().Service(service, tag, passingOnly, nil)
176 if len(addrs) == 0 && err == nil {
177 return nil, nil, fmt.Errorf("service ( %s ) was not found", service)
178 }
179 if err != nil {
180 return nil, nil, err
181 }
182 return addrs, meta, nil
183}
184
185// Starts envoy with the current restartEpoch
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400186func (ec * EnvoyControl) startEnvoy() {
187 var curEpoch int
188 var err error
189 var count int
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400190
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400191 ec.reLock.Lock() // Make sure we've got exclusive access to the variable
192 cmd := exec.Command("/usr/local/bin/envoy", "--restart-epoch", strconv.Itoa(ec.restartEpoch),
193 "--config-path", ec.envoyConfig, "--parent-shutdown-time-s", "10")
194
195 curEpoch = ec.restartEpoch
196 ec.restartEpoch += 1
197 ec.reLock.Unlock() // Done, release the lock.
198
199 stderr, err := cmd.StderrPipe()
200 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400201 log.Fatal("Couldn't attach to stderr running envoy command: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400202 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400203 stdout, err := cmd.StdoutPipe()
204 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400205 log.Fatal("Couldn't attach to stdout running envoy command: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400206 }
207 so := bufio.NewReader(stdout)
208 se := bufio.NewReader(stderr)
209
210 if err = cmd.Start(); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400211 log.Fatal("Error starting envoy: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400212 }
213 log.Printf("Envoy(%d) started", curEpoch)
214 soEof := false
215 seEof := false
216
217 data := make([]byte, 80)
218 log.Printf("Log forwarding for envoy(%d) started", curEpoch)
219 for {
220 data = make([]byte, 80)
221 count, err = so.Read(data)
222 log.Printf("ENVOY_LOG(%d): %s", curEpoch, string(data))
223 if err == io.EOF {
224 if seEof == true {
225 break
226 } else {
227 soEof = true
228 }
229 } else if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400230 log.Fatal("Attempt to read envoy standard out failed: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400231 } else if count > 0 {
232 log.Printf("ENVOY_LOG(%d)(%d): %s",curEpoch,count,string(data))
233 }
234 data = make([]byte, 80)
235 count, err = se.Read(data)
236 if err == io.EOF {
237 if soEof == true {
238 break
239 } else {
240 seEof = true
241 }
242 } else if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400243 log.Fatal("Attempt to read envoy standard err failed: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400244 } else if count > 0 {
245 log.Printf("ENVOY_LOG(%d)(%d): %s",curEpoch,count,string(data))
246 }
247 }
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400248 log.Printf("Waiting on envoy %d to exit", curEpoch)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400249 if err = cmd.Wait(); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400250 log.Fatal("Envoy %d exited with an unexpected exit code: %s", curEpoch, err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400251 }
252 log.Printf("Envoy %d exited", curEpoch)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400253 // Check if this was the primary envoy, if so
254 // something went terribly wrong, panic to force
255 // forcefully exit.
256 ec.reLock.Lock()
257 if ec.restartEpoch == (curEpoch + 1) {
258 ec.reLock.Unlock()
259 log.Fatal("Last running envoy exited, aborting!")
260 panic("This should never happen")
261 }
262 ec.reLock.Unlock()
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400263
264}
265
266// This function will use the provided templete file to generate
267// the targetfile substituting
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400268func (ec * EnvoyControl) updateEnvoyConfig(ecv * EnvoyConfigVars) (err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400269 var firstRun bool = true
Sergio Slobodrian19628742017-09-05 19:52:54 -0400270 var firstRun2 bool = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400271 f := func() (bool) {
272 var rtrn bool = firstRun
273 firstRun = false
274 return rtrn
275 }
Sergio Slobodrian19628742017-09-05 19:52:54 -0400276 g := func() (bool) {
277 var rtrn bool = firstRun2
278 firstRun2 = false
279 return rtrn
280 }
281 var funcs = template.FuncMap{"isFirst": f, "isFirst2": g}
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400282 // Slurp up the template file.
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400283 tplt, err := ioutil.ReadFile(ec.envoyConfigTemplate)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400284 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400285 log.Fatal("ERROR reading the template file, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400286 }
287 //fmt.Println(string(tplt))
288 configTemplate, err := template.New("config").Funcs(funcs).Parse(string(tplt));
289 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400290 log.Fatal("Unexpected error loading the Envoy template, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400291 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400292 outFile,err := os.Create(ec.envoyConfig)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400293 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400294 log.Fatal("Unexpected error opening the Envoy config file for write, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400295 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400296 if err = configTemplate.Execute(outFile, ecv); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400297 log.Fatal("Unexpected error executing the Envoy config template, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400298 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400299 //cfgFile, err := ioutil.ReadFile(ec.envoyConfig)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400300 //if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400301 // log.Fatal("ERROR reading the config file, aborting: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400302 // panic(err)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400303 //}
304 //fmt.Println(string(cfgFile))
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400305 return
306}
307
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400308func (ec * EnvoyControl) parseAssignment(jsonString []byte) (vCluster []VolthaClusterEntry, err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400309 var f interface{}
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400310 var vc VolthaClusterEntry
311 //var isErr bool
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400312
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400313 log.Printf("Parsing %s", string(jsonString))
314 //err = json.Unmarshal(jsonString, &f)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400315 err = json.Unmarshal(jsonString, &f)
316 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400317 log.Fatal("Unable to parse json record %s : %s", jsonString, err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400318 } else {
319 m := f.(map[string]interface{})
320 for k, v := range m {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400321 isErr := false
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400322 vc.Prefix = k
323 //log.Printf("Processing key %s\n", k)
324 switch vv := v.(type) {
325 case map[string]interface{}:
326 for i, u := range vv {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400327 //log.Printf("Processing key %sn", i)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400328 switch uu := u.(type) {
329 case string:
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400330 if i == ec.vcoreHostIpName {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400331 vc.Host = uu
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400332 } else if i == ec.vcoreIdName {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400333 vc.Id = uu
334 } else {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400335 log.Printf("WARNING: unexpected descriptor,%s", i)
336 isErr = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400337 }
338 default:
339 log.Printf("WARNING: unexpected type, ")
340 log.Println(i, u)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400341 isErr = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400342 }
343 }
344 default:
345 log.Printf("WARNING: unexpected type, ")
346 log.Println(k, v)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400347 isErr = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400348 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400349 if ! isErr {
350 vCluster = append(vCluster, vc)
351 }
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400352 }
353 }
354 log.Println("Parsing complete")
355 return
356}
357
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400358func (ec * EnvoyControl) prepareEnvoyConfig(kvp * consulapi.KVPair, ecv * EnvoyConfigVars) (err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400359 var vCluster []VolthaClusterEntry
360
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400361 ecv.HttpPort = ec.envoyHttpPort
362 ecv.HttpsPort = ec.envoyHttpsPort
363 ecv.GrpcPort = ec.envoyGrpcPort
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400364 ecv.VolthaVip = ec.ipAddrs[ec.vcoreSvcName][0] + ":" + ec.vcorePort
365
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400366 // Extract all values from the KV record
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400367 // In the future, the values should all be compared to what we currently have
368 vCluster, err = ec.parseAssignment([]byte(kvp.Value))
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400369 if err == nil {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400370 ec.vc = vCluster // For future use to determine if there's been a real change
371 //templateValues["VolthaRR"] = []string{}
372 ecv.VolthaRR = []string{}
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400373 for i := range vCluster {
374 //log.Printf("Processing %s\n", vCluster[i].Host)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400375 //templateValues["VolthaRR"] = append(templateValues["VolthaRR"].([]string), vCluster[i].Host)
376 ecv.VolthaRR = append(ecv.VolthaRR, vCluster[i].Host + ":" + ec.vcorePort)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400377 }
378 } else {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400379 log.Fatal("Couldn't parse the KV record %s: %s", string(kvp.Value), err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400380 }
381 return
382}
383
384func (ec * EnvoyControl) runEnvoy(kvp * consulapi.KVPair) {
385 var err error
386 var ecv EnvoyConfigVars
387
388 if err = ec.prepareEnvoyConfig(kvp, &ecv); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400389 log.Fatal("Error preparing envoy config variables, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400390 }
391
392 // Now that we have the data loaded, update the envoy config and start envoy
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400393 ec.updateEnvoyConfig(&ecv)
394 go ec.startEnvoy()
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400395}
396
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400397func (ec * EnvoyControl) readConsulKey(key string, qo * consulapi.QueryOptions) (kvp * consulapi.KVPair, meta * consulapi.QueryMeta, err error) {
398
399 kv := ec.consul.KV()
400 // Get the initial values of the assignment key which contains individual
401 // voltha core IP addresses. This may be empty until voltha populates it
402 // so it must be checked
403 kvp, meta, err = kv.Get(ec.assignmentKey, qo)
404 for i := 0; i < ec.retries; i++ {
405 if err != nil {
406 fmt.Println(err)
407 log.Printf("Unable to read assignment consul key, retry %d", i+1)
408 time.Sleep(time.Duration(ec.waitTime) * time.Second)
409 kvp, meta, err = kv.Get(ec.assignmentKey, qo)
410 } else if kvp != nil && len(string(kvp.Value)) > 10 {
411 // A valid read, return
412 break
413 } else {
414 log.Printf("Voltha assignment key invalid, retry %d", i+1)
415 time.Sleep(time.Duration(ec.waitTime) * time.Second)
416 kvp, meta, err = kv.Get(ec.assignmentKey, qo)
417 }
418 if i == ec.retries {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400419 log.Fatal("Failed to read the assignment key after %d retries, aborting: %s", ec.retries, err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400420 }
421 }
422 return
423}
424
425func (ec * EnvoyControl) runMonitorEnvoy() {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400426 var err error
427 var qo consulapi.QueryOptions
428
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400429 // Get the initial values of the assignment key which contains individual
430 // voltha core IP addresses. This may be empty until voltha populates it
431 // so it must be checked
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400432 kvp, meta, err := ec.readConsulKey(ec.assignmentKey, nil)
433 log.Printf("Starting Envoy")
434 ec.runEnvoy(kvp)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400435
436 for {
437 qo.WaitIndex = meta.LastIndex
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400438 qo.RequireConsistent = true
Sergio Slobodrian19628742017-09-05 19:52:54 -0400439 //qo.AllowStale = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400440 for {
441 if qo.WaitIndex != meta.LastIndex {
442 break
443 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400444 kvp, meta, err = ec.readConsulKey(ec.assignmentKey, &qo)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400445 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400446 log.Fatal("Unable to read assignment consul key: %s\n", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400447 } else {
448 log.Println(string(kvp.Value))
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400449 log.Printf("meta.LastIndex = %d", meta.LastIndex)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400450 }
451 }
452 // Fell through, the index has changed thus the key has changed
453
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400454 log.Printf("Starting Envoy")
455 ec.runEnvoy(kvp)
456 log.Printf("meta.LastIndex = %d", meta.LastIndex)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400457 }
458}
459
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400460func (ec * EnvoyControl) ParseCommandArguments() {
461 flag.StringVar(&(ec.assignmentKey), "assignment-key", ec.assignmentKey,
462 "The key for the voltha assignment value in consul")
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400463
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400464 flag.StringVar(&( ec.envoyConfigTemplate),"envoy-cfg-template", ec.envoyConfigTemplate,
465 "The path to envoy's configuration template")
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400466
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400467 flag.StringVar(&( ec.envoyConfigTemplateBoth),"envoy-cfg-template-both", ec.envoyConfigTemplateBoth,
468 "The path to envoy's configuration template for both http and https")
469
470 flag.StringVar(&( ec.envoyConfigTemplateNoHttps),"envoy-cfg-template-no-https", ec.envoyConfigTemplateNoHttps,
471 "The path to envoy's configuration template with no https")
472
473 flag.StringVar(&( ec.envoyConfigTemplateNoHttp),"envoy-cfg-template-no-http", ec.envoyConfigTemplateNoHttp,
474 "The path to envoy's configuration template with no http")
475
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400476 flag.StringVar(&(ec.envoyConfig), "envoy-config", ec.envoyConfig,
477 "The path to envoy's configuration file" )
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400478
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400479 flag.StringVar(&(ec.vcoreSvcName), "vcore-svc-name", ec.vcoreSvcName,
480 "The service name of the voltha core service")
481
482 flag.StringVar(&(ec.consulSvcName),"consul-svc-nme", ec.consulSvcName,
483 "The service name of the consul service")
484
485 flag.StringVar(&(ec.vcorePort), "vcore-port", ec.vcorePort,
486 "The port where the vcore's GRPC service can be found")
487
488 flag.StringVar(&(ec.consulPort), "consul-port", ec.consulPort,
489 "The port where the consul service api can be found")
490
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400491 flag.StringVar(&(ec.envoyHttpPort), "http-port", ec.envoyHttpPort,
492 "The port where the http front-end is served ")
493
494 flag.StringVar(&(ec.envoyHttpsPort), "https-port", ec.envoyHttpsPort,
495 "The port where the https front-end is served ")
496
497 flag.StringVar(&(ec.envoyGrpcPort), "grpc-port", ec.envoyGrpcPort,
498 "The port where the grpc front-end is served ")
499
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400500 flag.IntVar(&(ec.retries), "retries", ec.retries,
501 "The number of times to retry name lookups and connect requests before failing")
502
503 flag.IntVar(&(ec.waitTime), "wait-time", ec.waitTime,
504 "The number of seconds to wait between retries")
505
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400506 flag.BoolVar(&(ec.httpDisabled), "disable-http", ec.httpDisabled,
507 "Disables the http front-end")
508
509 flag.BoolVar(&(ec.httpsDisabled), "disable-https", ec.httpsDisabled,
510 "Disables ths https front-end")
511
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400512 flag.Parse()
513}
514
515func (ec * EnvoyControl) Initialize() (err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400516 // Resolve consul's virtual ip address
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400517 if err = ec.resolveServiceAddress(ec.consulSvcName); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400518 log.Fatal("Can't proceed without consul's vIP address: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400519 }
520
521 // Resolve voltha's virtual ip address
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400522 if err = ec.resolveServiceAddress(ec.vcoreSvcName); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400523 log.Fatal("Can't proceed without voltha's vIP address: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400524 }
525
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400526 if err = ec.consulConnect(ec.consulSvcName, ec.consulPort); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400527 log.Fatal("error creating consul client aborting: %s", err.Error())
528 }
529
530 if ec.httpDisabled == true && ec.httpsDisabled == true {
531 log.Printf("Cowardly refusing to disable both http and https, leavign them both enabled\n")
532 } else if ec.httpDisabled == true {
533 log.Printf("Diasabling http\n")
534 ec.envoyConfigTemplate = ec.envoyConfigTemplateNoHttp
535 } else if ec.httpsDisabled == true {
536 log.Printf("Diasabling https\n")
537 ec.envoyConfigTemplate = ec.envoyConfigTemplateNoHttps
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400538 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400539
540 return
541}
542
543func main() {
544
545 var err error
546 var ec * EnvoyControl
547
548 ec = NewEnvoyControl()
549 ec.ParseCommandArguments()
550 if err = ec.Initialize(); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400551 log.Fatal("Envoy control initialization failed, aboring: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400552 }
553
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400554
555 // Start envoy and monitor changes to the KV store to reload
556 // consul's config. This never returns unless somethign crashes.
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400557 ec.runMonitorEnvoy()
558 log.Fatal("Monitor returned, this shouldn't happen")
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400559}