blob: dc783024d49bd7d8a4bf2aa816a4f8d60e1c5a7d [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
114 ro.core = c.NewCore(ro.config.InstanceID, ro.config, ro.kvClient)
115
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
121 ro.core.Start(ctx)
122}
123
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000124func (ro *roCore) stop(ctx context.Context) {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500125 // Stop leadership tracking
126 ro.halted = true
127
128 // send exit signal
129 ro.exitChannel <- 0
130
131 // Cleanup - applies only if we had a kvClient
132 if ro.kvClient != nil {
133 // Release all reservations
134 if err := ro.kvClient.ReleaseAllReservations(); err != nil {
135 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
136 }
137 // Close the DB connection
138 ro.kvClient.Close()
139 }
140
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000141 ro.core.Stop(ctx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500142}
143
144func waitForExit() int {
145 signalChannel := make(chan os.Signal, 1)
146 signal.Notify(signalChannel,
147 syscall.SIGHUP,
148 syscall.SIGINT,
149 syscall.SIGTERM,
150 syscall.SIGQUIT)
151
152 exitChannel := make(chan int)
153
154 go func() {
155 s := <-signalChannel
156 switch s {
157 case syscall.SIGHUP,
158 syscall.SIGINT,
159 syscall.SIGTERM,
160 syscall.SIGQUIT:
161 log.Infow("closing-signal-received", log.Fields{"signal": s})
162 exitChannel <- 0
163 default:
164 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
165 exitChannel <- 1
166 }
167 }()
168
169 code := <-exitChannel
170 return code
171}
172
173func printBanner() {
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700174 fmt.Println()
175 fmt.Println(" ____ ___ ____ ")
176 fmt.Println("| _ \\ / _ \\ / ___|___ _ __ ___ ")
177 fmt.Println("| |_) | | | | | / _ \\| '__/ _ \\")
178 fmt.Println("| _ <| |_| | |__| (_) | | | __/")
179 fmt.Println("|_| \\_\\\\___/ \\____\\___/|_| \\___|")
180 fmt.Println()
181
182}
183
184func printVersion() {
185 fmt.Println("VOLTHA Read-Only Core")
186 fmt.Println(version.VersionInfo.String(" "))
Stephane Barbariea75791c2019-01-24 10:58:06 -0500187}
188
189func main() {
190 start := time.Now()
191
192 cf := config.NewROCoreFlags()
193 cf.ParseCommandArguments()
194
195 //// Setup logging
196
197 //Setup default logger - applies for packages that do not have specific logger set
npujar03b018e2019-11-13 15:29:36 +0530198 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceID": cf.InstanceID}); err != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500199 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
200 }
201
202 // Update all loggers (provisionned via init) with a common field
npujar03b018e2019-11-13 15:29:36 +0530203 if err := log.UpdateAllLoggers(log.Fields{"instanceID": cf.InstanceID}); err != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500204 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
205 }
206
207 log.SetPackageLogLevel("github.com/opencord/voltha-go/ro_core/core", log.DebugLevel)
208
npujar03b018e2019-11-13 15:29:36 +0530209 defer func() {
210 err := log.CleanUp()
211 if err != nil {
212 log.Errorw("unable-to-flush-any-buffered-log-entries", log.Fields{"error": err})
213 }
214 }()
Stephane Barbariea75791c2019-01-24 10:58:06 -0500215
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700216 // Print verison / build information and exit
217 if cf.DisplayVersionOnly {
218 printVersion()
219 return
220 }
221
Stephane Barbariea75791c2019-01-24 10:58:06 -0500222 // Print banner if specified
223 if cf.Banner {
224 printBanner()
225 }
226
227 log.Infow("ro-core-config", log.Fields{"config": *cf})
228
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000229 // Create the RO Core
230 ro := newROCore(cf)
231
Stephane Barbariea75791c2019-01-24 10:58:06 -0500232 ctx, cancel := context.WithCancel(context.Background())
233 defer cancel()
234
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000235 /*
236 * Create and start the liveness and readiness container management probes. This
237 * is done in the main function so just in case the main starts multiple other
238 * objects there can be a single probe end point for the process.
239 */
240 p := &probe.Probe{}
Kent Hagermanc4618832019-10-07 12:24:36 -0400241 go p.ListenAndServe(fmt.Sprintf("%s:%d", ro.config.ProbeHost, ro.config.ProbePort))
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000242
243 // Add the probe to the context to pass to all the services started
244 probeCtx := context.WithValue(ctx, probe.ProbeContextKey, p)
245
246 // Start the RO core
247 go ro.start(probeCtx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500248
249 code := waitForExit()
250 log.Infow("received-a-closing-signal", log.Fields{"code": code})
251
252 // Cleanup before leaving
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000253 ro.stop(probeCtx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500254
255 elapsed := time.Since(start)
256 log.Infow("ro-core-run-time", log.Fields{"core": ro.config.InstanceID, "time": elapsed / time.Second})
257}