blob: 2313fd32b727ac01e54e60ce749e0a9833f0b009 [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"
David K. Bainbridgef430cd52019-05-28 15:00:35 -070024 "github.com/opencord/voltha-go/common/version"
Stephane Barbariea75791c2019-01-24 10:58:06 -050025 "github.com/opencord/voltha-go/db/kvstore"
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"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040028 ic "github.com/opencord/voltha-protos/go/inter_container"
Stephane Barbariea75791c2019-01-24 10:58:06 -050029 "os"
30 "os/signal"
31 "strconv"
32 "syscall"
33 "time"
34)
35
36type roCore struct {
37 kvClient kvstore.Client
38 config *config.ROCoreFlags
39 halted bool
40 exitChannel chan int
41 grpcServer *grpcserver.GrpcServer
42 core *c.Core
43 //For test
44 receiverChannels []<-chan *ic.InterContainerMessage
45}
46
47func init() {
48 log.AddPackage(log.JSON, log.DebugLevel, nil)
49}
50
51func newKVClient(storeType string, address string, timeout int) (kvstore.Client, error) {
52
53 log.Infow("kv-store-type", log.Fields{"store": storeType})
54 switch storeType {
55 case "consul":
56 return kvstore.NewConsulClient(address, timeout)
57 case "etcd":
58 return kvstore.NewEtcdClient(address, timeout)
59 }
60 return nil, errors.New("unsupported-kv-store")
61}
62
63func newROCore(cf *config.ROCoreFlags) *roCore {
64 var roCore roCore
65 roCore.config = cf
66 roCore.halted = false
67 roCore.exitChannel = make(chan int, 1)
68 roCore.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
69 return &roCore
70}
71
72func (ro *roCore) setKVClient() error {
73 addr := ro.config.KVStoreHost + ":" + strconv.Itoa(ro.config.KVStorePort)
74 client, err := newKVClient(ro.config.KVStoreType, addr, ro.config.KVStoreTimeout)
75 if err != nil {
76 ro.kvClient = nil
77 log.Error(err)
78 return err
79 }
80 ro.kvClient = client
81 return nil
82}
83
84func toString(value interface{}) (string, error) {
85 switch t := value.(type) {
86 case []byte:
87 return string(value.([]byte)), nil
88 case string:
89 return value.(string), nil
90 default:
91 return "", fmt.Errorf("unexpected-type-%T", t)
92 }
93}
94
95func (ro *roCore) start(ctx context.Context) {
96 log.Info("Starting RW Core components")
97
98 // Setup KV Client
99 log.Debugw("create-kv-client", log.Fields{"kvstore": ro.config.KVStoreType})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500100
101 if err := ro.setKVClient(); err != nil {
102 log.Fatalw("failed-to-connect-kv-client", log.Fields{"error": err})
103 return
104 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500105
106 // Create the core service
107 ro.core = c.NewCore(ro.config.InstanceID, ro.config, ro.kvClient)
108
109 // start the core
110 ro.core.Start(ctx)
111}
112
113func (ro *roCore) stop() {
114 // Stop leadership tracking
115 ro.halted = true
116
117 // send exit signal
118 ro.exitChannel <- 0
119
120 // Cleanup - applies only if we had a kvClient
121 if ro.kvClient != nil {
122 // Release all reservations
123 if err := ro.kvClient.ReleaseAllReservations(); err != nil {
124 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
125 }
126 // Close the DB connection
127 ro.kvClient.Close()
128 }
129
130 ro.core.Stop(nil)
131}
132
133func waitForExit() int {
134 signalChannel := make(chan os.Signal, 1)
135 signal.Notify(signalChannel,
136 syscall.SIGHUP,
137 syscall.SIGINT,
138 syscall.SIGTERM,
139 syscall.SIGQUIT)
140
141 exitChannel := make(chan int)
142
143 go func() {
144 s := <-signalChannel
145 switch s {
146 case syscall.SIGHUP,
147 syscall.SIGINT,
148 syscall.SIGTERM,
149 syscall.SIGQUIT:
150 log.Infow("closing-signal-received", log.Fields{"signal": s})
151 exitChannel <- 0
152 default:
153 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
154 exitChannel <- 1
155 }
156 }()
157
158 code := <-exitChannel
159 return code
160}
161
162func printBanner() {
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700163 fmt.Println()
164 fmt.Println(" ____ ___ ____ ")
165 fmt.Println("| _ \\ / _ \\ / ___|___ _ __ ___ ")
166 fmt.Println("| |_) | | | | | / _ \\| '__/ _ \\")
167 fmt.Println("| _ <| |_| | |__| (_) | | | __/")
168 fmt.Println("|_| \\_\\\\___/ \\____\\___/|_| \\___|")
169 fmt.Println()
170
171}
172
173func printVersion() {
174 fmt.Println("VOLTHA Read-Only Core")
175 fmt.Println(version.VersionInfo.String(" "))
Stephane Barbariea75791c2019-01-24 10:58:06 -0500176}
177
178func main() {
179 start := time.Now()
180
181 cf := config.NewROCoreFlags()
182 cf.ParseCommandArguments()
183
184 //// Setup logging
185
186 //Setup default logger - applies for packages that do not have specific logger set
187 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceId": cf.InstanceID}); err != nil {
188 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
189 }
190
191 // Update all loggers (provisionned via init) with a common field
192 if err := log.UpdateAllLoggers(log.Fields{"instanceId": cf.InstanceID}); err != nil {
193 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
194 }
195
196 log.SetPackageLogLevel("github.com/opencord/voltha-go/ro_core/core", log.DebugLevel)
197
198 defer log.CleanUp()
199
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700200 // Print verison / build information and exit
201 if cf.DisplayVersionOnly {
202 printVersion()
203 return
204 }
205
Stephane Barbariea75791c2019-01-24 10:58:06 -0500206 // Print banner if specified
207 if cf.Banner {
208 printBanner()
209 }
210
211 log.Infow("ro-core-config", log.Fields{"config": *cf})
212
213 ctx, cancel := context.WithCancel(context.Background())
214 defer cancel()
215
216 ro := newROCore(cf)
217 go ro.start(ctx)
218
219 code := waitForExit()
220 log.Infow("received-a-closing-signal", log.Fields{"code": code})
221
222 // Cleanup before leaving
223 ro.stop()
224
225 elapsed := time.Since(start)
226 log.Infow("ro-core-run-time", log.Fields{"core": ro.config.InstanceID, "time": elapsed / time.Second})
227}