blob: 66fe628f6832123a10fc87431f80c9111ff0fbdf [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
270 f := func() (bool) {
271 var rtrn bool = firstRun
272 firstRun = false
273 return rtrn
274 }
275 var funcs = template.FuncMap{"isFirst": f}
276 // Slurp up the template file.
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400277 tplt, err := ioutil.ReadFile(ec.envoyConfigTemplate)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400278 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400279 log.Fatal("ERROR reading the template file, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400280 }
281 //fmt.Println(string(tplt))
282 configTemplate, err := template.New("config").Funcs(funcs).Parse(string(tplt));
283 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400284 log.Fatal("Unexpected error loading the Envoy template, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400285 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400286 outFile,err := os.Create(ec.envoyConfig)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400287 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400288 log.Fatal("Unexpected error opening the Envoy config file for write, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400289 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400290 if err = configTemplate.Execute(outFile, ecv); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400291 log.Fatal("Unexpected error executing the Envoy config template, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400292 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400293 //cfgFile, err := ioutil.ReadFile(ec.envoyConfig)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400294 //if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400295 // log.Fatal("ERROR reading the config file, aborting: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400296 // panic(err)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400297 //}
298 //fmt.Println(string(cfgFile))
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400299 return
300}
301
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400302func (ec * EnvoyControl) parseAssignment(jsonString []byte) (vCluster []VolthaClusterEntry, err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400303 var f interface{}
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400304 var vc VolthaClusterEntry
305 //var isErr bool
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400306
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400307 log.Printf("Parsing %s", string(jsonString))
308 //err = json.Unmarshal(jsonString, &f)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400309 err = json.Unmarshal(jsonString, &f)
310 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400311 log.Fatal("Unable to parse json record %s : %s", jsonString, err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400312 } else {
313 m := f.(map[string]interface{})
314 for k, v := range m {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400315 isErr := false
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400316 vc.Prefix = k
317 //log.Printf("Processing key %s\n", k)
318 switch vv := v.(type) {
319 case map[string]interface{}:
320 for i, u := range vv {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400321 //log.Printf("Processing key %sn", i)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400322 switch uu := u.(type) {
323 case string:
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400324 if i == ec.vcoreHostIpName {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400325 vc.Host = uu
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400326 } else if i == ec.vcoreIdName {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400327 vc.Id = uu
328 } else {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400329 log.Printf("WARNING: unexpected descriptor,%s", i)
330 isErr = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400331 }
332 default:
333 log.Printf("WARNING: unexpected type, ")
334 log.Println(i, u)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400335 isErr = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400336 }
337 }
338 default:
339 log.Printf("WARNING: unexpected type, ")
340 log.Println(k, v)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400341 isErr = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400342 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400343 if ! isErr {
344 vCluster = append(vCluster, vc)
345 }
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400346 }
347 }
348 log.Println("Parsing complete")
349 return
350}
351
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400352func (ec * EnvoyControl) prepareEnvoyConfig(kvp * consulapi.KVPair, ecv * EnvoyConfigVars) (err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400353 var vCluster []VolthaClusterEntry
354
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400355 ecv.HttpPort = ec.envoyHttpPort
356 ecv.HttpsPort = ec.envoyHttpsPort
357 ecv.GrpcPort = ec.envoyGrpcPort
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400358 ecv.VolthaVip = ec.ipAddrs[ec.vcoreSvcName][0] + ":" + ec.vcorePort
359
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400360 // Extract all values from the KV record
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400361 // In the future, the values should all be compared to what we currently have
362 vCluster, err = ec.parseAssignment([]byte(kvp.Value))
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400363 if err == nil {
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400364 ec.vc = vCluster // For future use to determine if there's been a real change
365 //templateValues["VolthaRR"] = []string{}
366 ecv.VolthaRR = []string{}
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400367 for i := range vCluster {
368 //log.Printf("Processing %s\n", vCluster[i].Host)
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400369 //templateValues["VolthaRR"] = append(templateValues["VolthaRR"].([]string), vCluster[i].Host)
370 ecv.VolthaRR = append(ecv.VolthaRR, vCluster[i].Host + ":" + ec.vcorePort)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400371 }
372 } else {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400373 log.Fatal("Couldn't parse the KV record %s: %s", string(kvp.Value), err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400374 }
375 return
376}
377
378func (ec * EnvoyControl) runEnvoy(kvp * consulapi.KVPair) {
379 var err error
380 var ecv EnvoyConfigVars
381
382 if err = ec.prepareEnvoyConfig(kvp, &ecv); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400383 log.Fatal("Error preparing envoy config variables, aborting: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400384 }
385
386 // Now that we have the data loaded, update the envoy config and start envoy
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400387 ec.updateEnvoyConfig(&ecv)
388 go ec.startEnvoy()
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400389}
390
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400391func (ec * EnvoyControl) readConsulKey(key string, qo * consulapi.QueryOptions) (kvp * consulapi.KVPair, meta * consulapi.QueryMeta, err error) {
392
393 kv := ec.consul.KV()
394 // Get the initial values of the assignment key which contains individual
395 // voltha core IP addresses. This may be empty until voltha populates it
396 // so it must be checked
397 kvp, meta, err = kv.Get(ec.assignmentKey, qo)
398 for i := 0; i < ec.retries; i++ {
399 if err != nil {
400 fmt.Println(err)
401 log.Printf("Unable to read assignment consul key, retry %d", i+1)
402 time.Sleep(time.Duration(ec.waitTime) * time.Second)
403 kvp, meta, err = kv.Get(ec.assignmentKey, qo)
404 } else if kvp != nil && len(string(kvp.Value)) > 10 {
405 // A valid read, return
406 break
407 } else {
408 log.Printf("Voltha assignment key invalid, retry %d", i+1)
409 time.Sleep(time.Duration(ec.waitTime) * time.Second)
410 kvp, meta, err = kv.Get(ec.assignmentKey, qo)
411 }
412 if i == ec.retries {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400413 log.Fatal("Failed to read the assignment key after %d retries, aborting: %s", ec.retries, err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400414 }
415 }
416 return
417}
418
419func (ec * EnvoyControl) runMonitorEnvoy() {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400420 var err error
421 var qo consulapi.QueryOptions
422
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400423 // Get the initial values of the assignment key which contains individual
424 // voltha core IP addresses. This may be empty until voltha populates it
425 // so it must be checked
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400426 kvp, meta, err := ec.readConsulKey(ec.assignmentKey, nil)
427 log.Printf("Starting Envoy")
428 ec.runEnvoy(kvp)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400429
430 for {
431 qo.WaitIndex = meta.LastIndex
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400432 qo.RequireConsistent = true
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400433 for {
434 if qo.WaitIndex != meta.LastIndex {
435 break
436 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400437 kvp, meta, err = ec.readConsulKey(ec.assignmentKey, &qo)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400438 if err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400439 log.Fatal("Unable to read assignment consul key: %s\n", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400440 } else {
441 log.Println(string(kvp.Value))
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400442 log.Printf("meta.LastIndex = %d", meta.LastIndex)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400443 }
444 }
445 // Fell through, the index has changed thus the key has changed
446
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400447 log.Printf("Starting Envoy")
448 ec.runEnvoy(kvp)
449 log.Printf("meta.LastIndex = %d", meta.LastIndex)
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400450 }
451}
452
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400453func (ec * EnvoyControl) ParseCommandArguments() {
454 flag.StringVar(&(ec.assignmentKey), "assignment-key", ec.assignmentKey,
455 "The key for the voltha assignment value in consul")
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400456
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400457 flag.StringVar(&( ec.envoyConfigTemplate),"envoy-cfg-template", ec.envoyConfigTemplate,
458 "The path to envoy's configuration template")
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400459
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400460 flag.StringVar(&( ec.envoyConfigTemplateBoth),"envoy-cfg-template-both", ec.envoyConfigTemplateBoth,
461 "The path to envoy's configuration template for both http and https")
462
463 flag.StringVar(&( ec.envoyConfigTemplateNoHttps),"envoy-cfg-template-no-https", ec.envoyConfigTemplateNoHttps,
464 "The path to envoy's configuration template with no https")
465
466 flag.StringVar(&( ec.envoyConfigTemplateNoHttp),"envoy-cfg-template-no-http", ec.envoyConfigTemplateNoHttp,
467 "The path to envoy's configuration template with no http")
468
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400469 flag.StringVar(&(ec.envoyConfig), "envoy-config", ec.envoyConfig,
470 "The path to envoy's configuration file" )
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400471
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400472 flag.StringVar(&(ec.vcoreSvcName), "vcore-svc-name", ec.vcoreSvcName,
473 "The service name of the voltha core service")
474
475 flag.StringVar(&(ec.consulSvcName),"consul-svc-nme", ec.consulSvcName,
476 "The service name of the consul service")
477
478 flag.StringVar(&(ec.vcorePort), "vcore-port", ec.vcorePort,
479 "The port where the vcore's GRPC service can be found")
480
481 flag.StringVar(&(ec.consulPort), "consul-port", ec.consulPort,
482 "The port where the consul service api can be found")
483
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400484 flag.StringVar(&(ec.envoyHttpPort), "http-port", ec.envoyHttpPort,
485 "The port where the http front-end is served ")
486
487 flag.StringVar(&(ec.envoyHttpsPort), "https-port", ec.envoyHttpsPort,
488 "The port where the https front-end is served ")
489
490 flag.StringVar(&(ec.envoyGrpcPort), "grpc-port", ec.envoyGrpcPort,
491 "The port where the grpc front-end is served ")
492
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400493 flag.IntVar(&(ec.retries), "retries", ec.retries,
494 "The number of times to retry name lookups and connect requests before failing")
495
496 flag.IntVar(&(ec.waitTime), "wait-time", ec.waitTime,
497 "The number of seconds to wait between retries")
498
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400499 flag.BoolVar(&(ec.httpDisabled), "disable-http", ec.httpDisabled,
500 "Disables the http front-end")
501
502 flag.BoolVar(&(ec.httpsDisabled), "disable-https", ec.httpsDisabled,
503 "Disables ths https front-end")
504
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400505 flag.Parse()
506}
507
508func (ec * EnvoyControl) Initialize() (err error) {
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400509 // Resolve consul's virtual ip address
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400510 if err = ec.resolveServiceAddress(ec.consulSvcName); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400511 log.Fatal("Can't proceed without consul's vIP address: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400512 }
513
514 // Resolve voltha's virtual ip address
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400515 if err = ec.resolveServiceAddress(ec.vcoreSvcName); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400516 log.Fatal("Can't proceed without voltha's vIP address: %s", err.Error())
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400517 }
518
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400519 if err = ec.consulConnect(ec.consulSvcName, ec.consulPort); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400520 log.Fatal("error creating consul client aborting: %s", err.Error())
521 }
522
523 if ec.httpDisabled == true && ec.httpsDisabled == true {
524 log.Printf("Cowardly refusing to disable both http and https, leavign them both enabled\n")
525 } else if ec.httpDisabled == true {
526 log.Printf("Diasabling http\n")
527 ec.envoyConfigTemplate = ec.envoyConfigTemplateNoHttp
528 } else if ec.httpsDisabled == true {
529 log.Printf("Diasabling https\n")
530 ec.envoyConfigTemplate = ec.envoyConfigTemplateNoHttps
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400531 }
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400532
533 return
534}
535
536func main() {
537
538 var err error
539 var ec * EnvoyControl
540
541 ec = NewEnvoyControl()
542 ec.ParseCommandArguments()
543 if err = ec.Initialize(); err != nil {
Sergio Slobodrian6570c742017-08-07 23:11:33 -0400544 log.Fatal("Envoy control initialization failed, aboring: %s", err.Error())
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400545 }
546
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400547
548 // Start envoy and monitor changes to the KV store to reload
549 // consul's config. This never returns unless somethign crashes.
Sergio Slobodrian8dec8de2017-07-20 12:45:07 -0400550 ec.runMonitorEnvoy()
551 log.Fatal("Monitor returned, this shouldn't happen")
Sergio Slobodrianbe829272017-07-17 14:45:45 -0400552}