blob: b203bec8c9faf8605f3bdd433f15bcb79a2099f2 [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 */
npujar03b018e2019-11-13 15:29:36 +053016
Stephane Barbariea75791c2019-01-24 10:58:06 -050017package main
18
19import (
20 "context"
21 "errors"
22 "fmt"
Stephane Barbariea75791c2019-01-24 10:58:06 -050023 "os"
24 "os/signal"
25 "strconv"
26 "syscall"
27 "time"
npujar03b018e2019-11-13 15:29:36 +053028
29 "github.com/opencord/voltha-go/ro_core/config"
30 c "github.com/opencord/voltha-go/ro_core/core"
31 "github.com/opencord/voltha-lib-go/v2/pkg/db/kvstore"
32 "github.com/opencord/voltha-lib-go/v2/pkg/log"
33 "github.com/opencord/voltha-lib-go/v2/pkg/probe"
34 "github.com/opencord/voltha-lib-go/v2/pkg/version"
35 ic "github.com/opencord/voltha-protos/v2/go/inter_container"
Stephane Barbariea75791c2019-01-24 10:58:06 -050036)
37
38type roCore struct {
39 kvClient kvstore.Client
40 config *config.ROCoreFlags
41 halted bool
42 exitChannel chan int
Stephane Barbariea75791c2019-01-24 10:58:06 -050043 core *c.Core
44 //For test
45 receiverChannels []<-chan *ic.InterContainerMessage
46}
47
48func init() {
npujar03b018e2019-11-13 15:29:36 +053049 _, err := log.AddPackage(log.JSON, log.DebugLevel, nil)
50 if err != nil {
51 log.Errorw("unable-to-register-package-to-the-log-map", log.Fields{"error": err})
52 }
Stephane Barbariea75791c2019-01-24 10:58:06 -050053}
54
55func newKVClient(storeType string, address string, timeout int) (kvstore.Client, error) {
56
57 log.Infow("kv-store-type", log.Fields{"store": storeType})
58 switch storeType {
59 case "consul":
60 return kvstore.NewConsulClient(address, timeout)
61 case "etcd":
62 return kvstore.NewEtcdClient(address, timeout)
63 }
64 return nil, errors.New("unsupported-kv-store")
65}
66
67func newROCore(cf *config.ROCoreFlags) *roCore {
68 var roCore roCore
69 roCore.config = cf
70 roCore.halted = false
71 roCore.exitChannel = make(chan int, 1)
72 roCore.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
73 return &roCore
74}
75
76func (ro *roCore) setKVClient() error {
77 addr := ro.config.KVStoreHost + ":" + strconv.Itoa(ro.config.KVStorePort)
78 client, err := newKVClient(ro.config.KVStoreType, addr, ro.config.KVStoreTimeout)
79 if err != nil {
80 ro.kvClient = nil
81 log.Error(err)
82 return err
83 }
84 ro.kvClient = client
85 return nil
86}
87
Stephane Barbariea75791c2019-01-24 10:58:06 -050088func (ro *roCore) start(ctx context.Context) {
89 log.Info("Starting RW Core components")
90
Hardik Windlassdc63dde2019-09-30 07:15:13 +000091 // If the context has a probe then fetch it and register our services
92 var p *probe.Probe
93 if value := ctx.Value(probe.ProbeContextKey); value != nil {
94 if _, ok := value.(*probe.Probe); ok {
95 p = value.(*probe.Probe)
96 p.RegisterService(
97 "kv-store",
98 "device-manager",
99 "logical-device-manager",
100 "grpc-service",
101 )
102 }
103 }
104
Stephane Barbariea75791c2019-01-24 10:58:06 -0500105 // Setup KV Client
106 log.Debugw("create-kv-client", log.Fields{"kvstore": ro.config.KVStoreType})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500107
108 if err := ro.setKVClient(); err != nil {
109 log.Fatalw("failed-to-connect-kv-client", log.Fields{"error": err})
110 return
111 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500112
113 // Create the core service
Thomas Lee Se5a44012019-11-07 20:32:24 +0530114 ro.core = c.NewCore(ctx, ro.config.InstanceID, ro.config, ro.kvClient)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500115
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000116 if p != nil {
Girish Kumar91482642019-11-08 11:38:03 +0000117 p.UpdateStatus("kv-store", probe.ServiceStatusPrepared)
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000118 }
119
Stephane Barbariea75791c2019-01-24 10:58:06 -0500120 // start the core
Thomas Lee Se5a44012019-11-07 20:32:24 +0530121 if err := ro.core.Start(ctx); err != nil {
122 log.Fatalf("failed-to-start-rocore", log.Fields{"error": err})
123 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500124}
125
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000126func (ro *roCore) stop(ctx context.Context) {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500127 // Stop leadership tracking
128 ro.halted = true
129
130 // send exit signal
131 ro.exitChannel <- 0
132
133 // Cleanup - applies only if we had a kvClient
134 if ro.kvClient != nil {
135 // Release all reservations
136 if err := ro.kvClient.ReleaseAllReservations(); err != nil {
137 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
138 }
139 // Close the DB connection
140 ro.kvClient.Close()
141 }
142
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000143 ro.core.Stop(ctx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500144}
145
146func waitForExit() int {
147 signalChannel := make(chan os.Signal, 1)
148 signal.Notify(signalChannel,
149 syscall.SIGHUP,
150 syscall.SIGINT,
151 syscall.SIGTERM,
152 syscall.SIGQUIT)
153
154 exitChannel := make(chan int)
155
156 go func() {
157 s := <-signalChannel
158 switch s {
159 case syscall.SIGHUP,
160 syscall.SIGINT,
161 syscall.SIGTERM,
162 syscall.SIGQUIT:
163 log.Infow("closing-signal-received", log.Fields{"signal": s})
164 exitChannel <- 0
165 default:
166 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
167 exitChannel <- 1
168 }
169 }()
170
171 code := <-exitChannel
172 return code
173}
174
175func printBanner() {
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700176 fmt.Println()
177 fmt.Println(" ____ ___ ____ ")
178 fmt.Println("| _ \\ / _ \\ / ___|___ _ __ ___ ")
179 fmt.Println("| |_) | | | | | / _ \\| '__/ _ \\")
180 fmt.Println("| _ <| |_| | |__| (_) | | | __/")
181 fmt.Println("|_| \\_\\\\___/ \\____\\___/|_| \\___|")
182 fmt.Println()
183
184}
185
186func printVersion() {
187 fmt.Println("VOLTHA Read-Only Core")
188 fmt.Println(version.VersionInfo.String(" "))
Stephane Barbariea75791c2019-01-24 10:58:06 -0500189}
190
191func main() {
192 start := time.Now()
193
194 cf := config.NewROCoreFlags()
195 cf.ParseCommandArguments()
196
197 //// Setup logging
198
199 //Setup default logger - applies for packages that do not have specific logger set
npujar03b018e2019-11-13 15:29:36 +0530200 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceID": cf.InstanceID}); err != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500201 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
202 }
203
204 // Update all loggers (provisionned via init) with a common field
npujar03b018e2019-11-13 15:29:36 +0530205 if err := log.UpdateAllLoggers(log.Fields{"instanceID": cf.InstanceID}); err != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500206 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
207 }
208
209 log.SetPackageLogLevel("github.com/opencord/voltha-go/ro_core/core", log.DebugLevel)
210
npujar03b018e2019-11-13 15:29:36 +0530211 defer func() {
212 err := log.CleanUp()
213 if err != nil {
214 log.Errorw("unable-to-flush-any-buffered-log-entries", log.Fields{"error": err})
215 }
216 }()
Stephane Barbariea75791c2019-01-24 10:58:06 -0500217
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700218 // Print verison / build information and exit
219 if cf.DisplayVersionOnly {
220 printVersion()
221 return
222 }
223
Stephane Barbariea75791c2019-01-24 10:58:06 -0500224 // Print banner if specified
225 if cf.Banner {
226 printBanner()
227 }
228
229 log.Infow("ro-core-config", log.Fields{"config": *cf})
230
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000231 // Create the RO Core
232 ro := newROCore(cf)
233
Stephane Barbariea75791c2019-01-24 10:58:06 -0500234 ctx, cancel := context.WithCancel(context.Background())
235 defer cancel()
236
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000237 /*
238 * Create and start the liveness and readiness container management probes. This
239 * is done in the main function so just in case the main starts multiple other
240 * objects there can be a single probe end point for the process.
241 */
242 p := &probe.Probe{}
Kent Hagermanc4618832019-10-07 12:24:36 -0400243 go p.ListenAndServe(fmt.Sprintf("%s:%d", ro.config.ProbeHost, ro.config.ProbePort))
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000244
245 // Add the probe to the context to pass to all the services started
246 probeCtx := context.WithValue(ctx, probe.ProbeContextKey, p)
247
248 // Start the RO core
249 go ro.start(probeCtx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500250
251 code := waitForExit()
252 log.Infow("received-a-closing-signal", log.Fields{"code": code})
253
254 // Cleanup before leaving
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000255 ro.stop(probeCtx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500256
257 elapsed := time.Since(start)
258 log.Infow("ro-core-run-time", log.Fields{"core": ro.config.InstanceID, "time": elapsed / time.Second})
259}