blob: f80c77e766c08de5f3650b76681fe809d38d70db [file] [log] [blame]
Stephane Barbariea75791c2019-01-24 10:58:06 -05001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package main
17
18import (
19 "context"
20 "errors"
21 "fmt"
22 grpcserver "github.com/opencord/voltha-go/common/grpc"
23 "github.com/opencord/voltha-go/common/log"
24 "github.com/opencord/voltha-go/db/kvstore"
William Kurkiandaa6bb22019-03-07 12:26:28 -050025 ic "github.com/opencord/voltha-protos/go/inter_container"
Stephane Barbariea75791c2019-01-24 10:58:06 -050026 "github.com/opencord/voltha-go/ro_core/config"
27 c "github.com/opencord/voltha-go/ro_core/core"
28 "os"
29 "os/signal"
30 "strconv"
31 "syscall"
32 "time"
33)
34
35type roCore struct {
36 kvClient kvstore.Client
37 config *config.ROCoreFlags
38 halted bool
39 exitChannel chan int
40 grpcServer *grpcserver.GrpcServer
41 core *c.Core
42 //For test
43 receiverChannels []<-chan *ic.InterContainerMessage
44}
45
46func init() {
47 log.AddPackage(log.JSON, log.DebugLevel, nil)
48}
49
50func newKVClient(storeType string, address string, timeout int) (kvstore.Client, error) {
51
52 log.Infow("kv-store-type", log.Fields{"store": storeType})
53 switch storeType {
54 case "consul":
55 return kvstore.NewConsulClient(address, timeout)
56 case "etcd":
57 return kvstore.NewEtcdClient(address, timeout)
58 }
59 return nil, errors.New("unsupported-kv-store")
60}
61
62func newROCore(cf *config.ROCoreFlags) *roCore {
63 var roCore roCore
64 roCore.config = cf
65 roCore.halted = false
66 roCore.exitChannel = make(chan int, 1)
67 roCore.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
68 return &roCore
69}
70
71func (ro *roCore) setKVClient() error {
72 addr := ro.config.KVStoreHost + ":" + strconv.Itoa(ro.config.KVStorePort)
73 client, err := newKVClient(ro.config.KVStoreType, addr, ro.config.KVStoreTimeout)
74 if err != nil {
75 ro.kvClient = nil
76 log.Error(err)
77 return err
78 }
79 ro.kvClient = client
80 return nil
81}
82
83func toString(value interface{}) (string, error) {
84 switch t := value.(type) {
85 case []byte:
86 return string(value.([]byte)), nil
87 case string:
88 return value.(string), nil
89 default:
90 return "", fmt.Errorf("unexpected-type-%T", t)
91 }
92}
93
94func (ro *roCore) start(ctx context.Context) {
95 log.Info("Starting RW Core components")
96
97 // Setup KV Client
98 log.Debugw("create-kv-client", log.Fields{"kvstore": ro.config.KVStoreType})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -050099
100 if err := ro.setKVClient(); err != nil {
101 log.Fatalw("failed-to-connect-kv-client", log.Fields{"error": err})
102 return
103 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500104
105 // Create the core service
106 ro.core = c.NewCore(ro.config.InstanceID, ro.config, ro.kvClient)
107
108 // start the core
109 ro.core.Start(ctx)
110}
111
112func (ro *roCore) stop() {
113 // Stop leadership tracking
114 ro.halted = true
115
116 // send exit signal
117 ro.exitChannel <- 0
118
119 // Cleanup - applies only if we had a kvClient
120 if ro.kvClient != nil {
121 // Release all reservations
122 if err := ro.kvClient.ReleaseAllReservations(); err != nil {
123 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
124 }
125 // Close the DB connection
126 ro.kvClient.Close()
127 }
128
129 ro.core.Stop(nil)
130}
131
132func waitForExit() int {
133 signalChannel := make(chan os.Signal, 1)
134 signal.Notify(signalChannel,
135 syscall.SIGHUP,
136 syscall.SIGINT,
137 syscall.SIGTERM,
138 syscall.SIGQUIT)
139
140 exitChannel := make(chan int)
141
142 go func() {
143 s := <-signalChannel
144 switch s {
145 case syscall.SIGHUP,
146 syscall.SIGINT,
147 syscall.SIGTERM,
148 syscall.SIGQUIT:
149 log.Infow("closing-signal-received", log.Fields{"signal": s})
150 exitChannel <- 0
151 default:
152 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
153 exitChannel <- 1
154 }
155 }()
156
157 code := <-exitChannel
158 return code
159}
160
161func printBanner() {
162 fmt.Println(" ")
163 fmt.Println(" ______ ______ ")
164 fmt.Println("| _ \\ \\ / / ___|___ _ __ ___ ")
165 fmt.Println("| |_) \\ \\ /\\ / / | / _ \\| '__/ _ \\ ")
166 fmt.Println("| _ < \\ V V /| |__| (_) | | | __/ ")
167 fmt.Println("|_| \\_\\ \\_/\\_/ \\____\\___/|_| \\___| ")
168 fmt.Println(" ")
169}
170
171func main() {
172 start := time.Now()
173
174 cf := config.NewROCoreFlags()
175 cf.ParseCommandArguments()
176
177 //// Setup logging
178
179 //Setup default logger - applies for packages that do not have specific logger set
180 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceId": cf.InstanceID}); err != nil {
181 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
182 }
183
184 // Update all loggers (provisionned via init) with a common field
185 if err := log.UpdateAllLoggers(log.Fields{"instanceId": cf.InstanceID}); err != nil {
186 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
187 }
188
189 log.SetPackageLogLevel("github.com/opencord/voltha-go/ro_core/core", log.DebugLevel)
190
191 defer log.CleanUp()
192
193 // Print banner if specified
194 if cf.Banner {
195 printBanner()
196 }
197
198 log.Infow("ro-core-config", log.Fields{"config": *cf})
199
200 ctx, cancel := context.WithCancel(context.Background())
201 defer cancel()
202
203 ro := newROCore(cf)
204 go ro.start(ctx)
205
206 code := waitForExit()
207 log.Infow("received-a-closing-signal", log.Fields{"code": code})
208
209 // Cleanup before leaving
210 ro.stop()
211
212 elapsed := time.Since(start)
213 log.Infow("ro-core-run-time", log.Fields{"core": ro.config.InstanceID, "time": elapsed / time.Second})
214}