blob: 71f5d6692ae2e7801f786d25b4c78288069867b6 [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"
Stephane Barbariea75791c2019-01-24 10:58:06 -050022 "github.com/opencord/voltha-go/ro_core/config"
23 c "github.com/opencord/voltha-go/ro_core/core"
Scott Bakercb7c88a2019-10-16 18:32:48 -070024 "github.com/opencord/voltha-lib-go/pkg/db/kvstore"
25 grpcserver "github.com/opencord/voltha-lib-go/pkg/grpc"
26 "github.com/opencord/voltha-lib-go/pkg/log"
27 "github.com/opencord/voltha-lib-go/pkg/probe"
28 "github.com/opencord/voltha-lib-go/pkg/version"
Kent Hagerman0ab4cb22019-04-24 13:13:35 -040029 ic "github.com/opencord/voltha-protos/go/inter_container"
Stephane Barbariea75791c2019-01-24 10:58:06 -050030 "os"
31 "os/signal"
32 "strconv"
33 "syscall"
34 "time"
35)
36
37type roCore struct {
38 kvClient kvstore.Client
39 config *config.ROCoreFlags
40 halted bool
41 exitChannel chan int
42 grpcServer *grpcserver.GrpcServer
43 core *c.Core
44 //For test
45 receiverChannels []<-chan *ic.InterContainerMessage
46}
47
48func init() {
49 log.AddPackage(log.JSON, log.DebugLevel, nil)
50}
51
52func newKVClient(storeType string, address string, timeout int) (kvstore.Client, error) {
53
54 log.Infow("kv-store-type", log.Fields{"store": storeType})
55 switch storeType {
56 case "consul":
57 return kvstore.NewConsulClient(address, timeout)
58 case "etcd":
59 return kvstore.NewEtcdClient(address, timeout)
60 }
61 return nil, errors.New("unsupported-kv-store")
62}
63
64func newROCore(cf *config.ROCoreFlags) *roCore {
65 var roCore roCore
66 roCore.config = cf
67 roCore.halted = false
68 roCore.exitChannel = make(chan int, 1)
69 roCore.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
70 return &roCore
71}
72
73func (ro *roCore) setKVClient() error {
74 addr := ro.config.KVStoreHost + ":" + strconv.Itoa(ro.config.KVStorePort)
75 client, err := newKVClient(ro.config.KVStoreType, addr, ro.config.KVStoreTimeout)
76 if err != nil {
77 ro.kvClient = nil
78 log.Error(err)
79 return err
80 }
81 ro.kvClient = client
82 return nil
83}
84
85func toString(value interface{}) (string, error) {
86 switch t := value.(type) {
87 case []byte:
88 return string(value.([]byte)), nil
89 case string:
90 return value.(string), nil
91 default:
92 return "", fmt.Errorf("unexpected-type-%T", t)
93 }
94}
95
96func (ro *roCore) start(ctx context.Context) {
97 log.Info("Starting RW Core components")
98
Hardik Windlassdc63dde2019-09-30 07:15:13 +000099 // If the context has a probe then fetch it and register our services
100 var p *probe.Probe
101 if value := ctx.Value(probe.ProbeContextKey); value != nil {
102 if _, ok := value.(*probe.Probe); ok {
103 p = value.(*probe.Probe)
104 p.RegisterService(
105 "kv-store",
106 "device-manager",
107 "logical-device-manager",
108 "grpc-service",
109 )
110 }
111 }
112
Stephane Barbariea75791c2019-01-24 10:58:06 -0500113 // Setup KV Client
114 log.Debugw("create-kv-client", log.Fields{"kvstore": ro.config.KVStoreType})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500115
116 if err := ro.setKVClient(); err != nil {
117 log.Fatalw("failed-to-connect-kv-client", log.Fields{"error": err})
118 return
119 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500120
121 // Create the core service
122 ro.core = c.NewCore(ro.config.InstanceID, ro.config, ro.kvClient)
123
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000124 if p != nil {
125 p.UpdateStatus("kv-store", probe.ServiceStatusRunning)
126 }
127
Stephane Barbariea75791c2019-01-24 10:58:06 -0500128 // start the core
129 ro.core.Start(ctx)
130}
131
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000132func (ro *roCore) stop(ctx context.Context) {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500133 // Stop leadership tracking
134 ro.halted = true
135
136 // send exit signal
137 ro.exitChannel <- 0
138
139 // Cleanup - applies only if we had a kvClient
140 if ro.kvClient != nil {
141 // Release all reservations
142 if err := ro.kvClient.ReleaseAllReservations(); err != nil {
143 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
144 }
145 // Close the DB connection
146 ro.kvClient.Close()
147 }
148
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000149 ro.core.Stop(ctx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500150}
151
152func waitForExit() int {
153 signalChannel := make(chan os.Signal, 1)
154 signal.Notify(signalChannel,
155 syscall.SIGHUP,
156 syscall.SIGINT,
157 syscall.SIGTERM,
158 syscall.SIGQUIT)
159
160 exitChannel := make(chan int)
161
162 go func() {
163 s := <-signalChannel
164 switch s {
165 case syscall.SIGHUP,
166 syscall.SIGINT,
167 syscall.SIGTERM,
168 syscall.SIGQUIT:
169 log.Infow("closing-signal-received", log.Fields{"signal": s})
170 exitChannel <- 0
171 default:
172 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
173 exitChannel <- 1
174 }
175 }()
176
177 code := <-exitChannel
178 return code
179}
180
181func printBanner() {
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700182 fmt.Println()
183 fmt.Println(" ____ ___ ____ ")
184 fmt.Println("| _ \\ / _ \\ / ___|___ _ __ ___ ")
185 fmt.Println("| |_) | | | | | / _ \\| '__/ _ \\")
186 fmt.Println("| _ <| |_| | |__| (_) | | | __/")
187 fmt.Println("|_| \\_\\\\___/ \\____\\___/|_| \\___|")
188 fmt.Println()
189
190}
191
192func printVersion() {
193 fmt.Println("VOLTHA Read-Only Core")
194 fmt.Println(version.VersionInfo.String(" "))
Stephane Barbariea75791c2019-01-24 10:58:06 -0500195}
196
197func main() {
198 start := time.Now()
199
200 cf := config.NewROCoreFlags()
201 cf.ParseCommandArguments()
202
203 //// Setup logging
204
205 //Setup default logger - applies for packages that do not have specific logger set
206 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceId": cf.InstanceID}); err != nil {
207 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
208 }
209
210 // Update all loggers (provisionned via init) with a common field
211 if err := log.UpdateAllLoggers(log.Fields{"instanceId": cf.InstanceID}); err != nil {
212 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
213 }
214
215 log.SetPackageLogLevel("github.com/opencord/voltha-go/ro_core/core", log.DebugLevel)
216
217 defer log.CleanUp()
218
David K. Bainbridgef430cd52019-05-28 15:00:35 -0700219 // Print verison / build information and exit
220 if cf.DisplayVersionOnly {
221 printVersion()
222 return
223 }
224
Stephane Barbariea75791c2019-01-24 10:58:06 -0500225 // Print banner if specified
226 if cf.Banner {
227 printBanner()
228 }
229
230 log.Infow("ro-core-config", log.Fields{"config": *cf})
231
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000232 // Create the RO Core
233 ro := newROCore(cf)
234
Stephane Barbariea75791c2019-01-24 10:58:06 -0500235 ctx, cancel := context.WithCancel(context.Background())
236 defer cancel()
237
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000238 /*
239 * Create and start the liveness and readiness container management probes. This
240 * is done in the main function so just in case the main starts multiple other
241 * objects there can be a single probe end point for the process.
242 */
243 p := &probe.Probe{}
Kent Hagermanc4618832019-10-07 12:24:36 -0400244 go p.ListenAndServe(fmt.Sprintf("%s:%d", ro.config.ProbeHost, ro.config.ProbePort))
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000245
246 // Add the probe to the context to pass to all the services started
247 probeCtx := context.WithValue(ctx, probe.ProbeContextKey, p)
248
249 // Start the RO core
250 go ro.start(probeCtx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500251
252 code := waitForExit()
253 log.Infow("received-a-closing-signal", log.Fields{"code": code})
254
255 // Cleanup before leaving
Hardik Windlassdc63dde2019-09-30 07:15:13 +0000256 ro.stop(probeCtx)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500257
258 elapsed := time.Since(start)
259 log.Infow("ro-core-run-time", log.Fields{"core": ro.config.InstanceID, "time": elapsed / time.Second})
260}