blob: 45cbf531a91e82a98752b4046d978b51de64bf6e [file] [log] [blame]
cuilin20187b2a8c32019-03-26 19:52:28 -07001/*
cbabu116b73f2019-12-10 17:56:32 +05302* Copyright 2018-present Open Networking Foundation
cuilin20187b2a8c32019-03-26 19:52:28 -07003
cbabu116b73f2019-12-10 17:56:32 +05304* 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
cuilin20187b2a8c32019-03-26 19:52:28 -07007
cbabu116b73f2019-12-10 17:56:32 +05308* http://www.apache.org/licenses/LICENSE-2.0
cuilin20187b2a8c32019-03-26 19:52:28 -07009
cbabu116b73f2019-12-10 17:56:32 +053010* 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.
cuilin20187b2a8c32019-03-26 19:52:28 -070015 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070016
17//Package main invokes the application
cuilin20187b2a8c32019-03-26 19:52:28 -070018package main
19
20import (
21 "context"
22 "errors"
23 "fmt"
kdarapu381c6902019-07-31 18:23:16 +053024 "os"
25 "os/signal"
26 "strconv"
27 "syscall"
28 "time"
29
Esin Karamanccb714b2019-11-29 15:02:06 +000030 "github.com/opencord/voltha-lib-go/v3/pkg/adapters/adapterif"
kdarapu381c6902019-07-31 18:23:16 +053031
Esin Karamanccb714b2019-11-29 15:02:06 +000032 "github.com/opencord/voltha-lib-go/v3/pkg/adapters"
33 com "github.com/opencord/voltha-lib-go/v3/pkg/adapters/common"
divyadesaia37f78b2020-02-07 12:41:22 +000034 conf "github.com/opencord/voltha-lib-go/v3/pkg/config"
Esin Karamanccb714b2019-11-29 15:02:06 +000035 "github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
36 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
37 "github.com/opencord/voltha-lib-go/v3/pkg/log"
38 "github.com/opencord/voltha-lib-go/v3/pkg/probe"
Scott Bakerdbd960e2020-02-28 08:57:51 -080039 "github.com/opencord/voltha-lib-go/v3/pkg/version"
40 "github.com/opencord/voltha-openolt-adapter/internal/pkg/config"
41 ac "github.com/opencord/voltha-openolt-adapter/internal/pkg/core"
Esin Karamanccb714b2019-11-29 15:02:06 +000042 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
43 "github.com/opencord/voltha-protos/v3/go/voltha"
cuilin20187b2a8c32019-03-26 19:52:28 -070044)
45
46type adapter struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070047 instanceID string
cuilin20187b2a8c32019-03-26 19:52:28 -070048 config *config.AdapterFlags
49 iAdapter adapters.IAdapter
50 kafkaClient kafka.Client
51 kvClient kvstore.Client
npujarec5762e2020-01-01 14:08:48 +053052 kip kafka.InterContainerProxy
kdarapu381c6902019-07-31 18:23:16 +053053 coreProxy adapterif.CoreProxy
54 adapterProxy adapterif.AdapterProxy
55 eventProxy adapterif.EventProxy
cuilin20187b2a8c32019-03-26 19:52:28 -070056 halted bool
57 exitChannel chan int
58 receiverChannels []<-chan *ic.InterContainerMessage
59}
60
cuilin20187b2a8c32019-03-26 19:52:28 -070061func newAdapter(cf *config.AdapterFlags) *adapter {
62 var a adapter
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070063 a.instanceID = cf.InstanceID
cuilin20187b2a8c32019-03-26 19:52:28 -070064 a.config = cf
65 a.halted = false
66 a.exitChannel = make(chan int, 1)
67 a.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
68 return &a
69}
70
71func (a *adapter) start(ctx context.Context) {
Girish Kumar2ad402b2020-03-20 19:45:12 +000072 logger.Info("Starting Core Adapter components")
cuilin20187b2a8c32019-03-26 19:52:28 -070073 var err error
74
Rohan Agrawal828bf4e2019-10-22 10:13:19 +000075 var p *probe.Probe
76 if value := ctx.Value(probe.ProbeContextKey); value != nil {
77 if _, ok := value.(*probe.Probe); ok {
78 p = value.(*probe.Probe)
79 p.RegisterService(
80 "message-bus",
81 "kv-store",
82 "container-proxy",
83 "core-request-handler",
84 "register-with-core",
85 )
86 }
87 }
88
cuilin20187b2a8c32019-03-26 19:52:28 -070089 // Setup KV Client
Girish Kumar2ad402b2020-03-20 19:45:12 +000090 logger.Debugw("create-kv-client", log.Fields{"kvstore": a.config.KVStoreType})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070091 if err = a.setKVClient(); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +000092 logger.Fatalw("error-setting-kv-client", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -070093 }
94
Rohan Agrawal828bf4e2019-10-22 10:13:19 +000095 if p != nil {
96 p.UpdateStatus("kv-store", probe.ServiceStatusRunning)
97 }
98
divyadesaia37f78b2020-02-07 12:41:22 +000099 // Setup Log Config
100 cm := conf.NewConfigManager(a.kvClient, a.config.KVStoreType, a.config.KVStoreHost, a.config.KVStorePort, a.config.KVStoreTimeout)
divyadesaid26f6b12020-03-19 06:30:28 +0000101 go conf.StartLogLevelConfigProcessing(cm, ctx)
divyadesaia37f78b2020-02-07 12:41:22 +0000102
cuilin20187b2a8c32019-03-26 19:52:28 -0700103 // Setup Kafka Client
104 if a.kafkaClient, err = newKafkaClient("sarama", a.config.KafkaAdapterHost, a.config.KafkaAdapterPort); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000105 logger.Fatalw("Unsupported-common-client", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700106 }
107
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000108 if p != nil {
109 p.UpdateStatus("message-bus", probe.ServiceStatusRunning)
110 }
111
Matteo Scandolo3ad5d2b2020-04-02 17:02:04 -0700112 // setup endpointManager
113
cuilin20187b2a8c32019-03-26 19:52:28 -0700114 // Start the common InterContainer Proxy - retries indefinitely
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000115 if a.kip, err = a.startInterContainerProxy(ctx, -1); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000116 logger.Fatal("error-starting-inter-container-proxy")
cuilin20187b2a8c32019-03-26 19:52:28 -0700117 }
118
119 // Create the core proxy to handle requests to the Core
120 a.coreProxy = com.NewCoreProxy(a.kip, a.config.Topic, a.config.CoreTopic)
121
122 // Create the adaptor proxy to handle request between olt and onu
Matteo Scandolo3ad5d2b2020-04-02 17:02:04 -0700123 a.adapterProxy = com.NewAdapterProxy(a.kip, "brcm_openomci_onu", a.config.CoreTopic, cm.Backend)
cuilin20187b2a8c32019-03-26 19:52:28 -0700124
Devmalya Paulfb990a52019-07-09 10:01:49 -0400125 // Create the event proxy to post events to KAFKA
126 a.eventProxy = com.NewEventProxy(com.MsgClient(a.kafkaClient), com.MsgTopic(kafka.Topic{Name: a.config.EventTopic}))
127
cuilin20187b2a8c32019-03-26 19:52:28 -0700128 // Create the open OLT adapter
Girish Kumarf26e4882020-03-05 06:49:10 +0000129 if a.iAdapter, err = a.startOpenOLT(ctx, a.kip, a.coreProxy, a.adapterProxy, a.eventProxy, a.config); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000130 logger.Fatalw("error-starting-openolt", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700131 }
132
133 // Register the core request handler
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000134 if err = a.setupRequestHandler(ctx, a.instanceID, a.iAdapter); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000135 logger.Fatalw("error-setting-core-request-handler", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700136 }
137
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700138 // Register this adapter to the Core - retries indefinitely
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000139 if err = a.registerWithCore(ctx, -1); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000140 logger.Fatal("error-registering-with-core")
cuilin20187b2a8c32019-03-26 19:52:28 -0700141 }
cbabu95f21522019-11-13 14:25:18 +0100142
cbabu116b73f2019-12-10 17:56:32 +0530143 // check the readiness and liveliness and update the probe status
144 a.checkServicesReadiness(ctx)
cbabu95f21522019-11-13 14:25:18 +0100145}
146
147/**
148This function checks the liveliness and readiness of the kakfa and kv-client services
149and update the status in the probe.
150*/
cbabu116b73f2019-12-10 17:56:32 +0530151func (a *adapter) checkServicesReadiness(ctx context.Context) {
152 // checks the kafka readiness
153 go a.checkKafkaReadiness(ctx)
154
155 // checks the kv-store readiness
156 go a.checkKvStoreReadiness(ctx)
157}
158
159/**
160This function checks the liveliness and readiness of the kv-store service
161and update the status in the probe.
162*/
163func (a *adapter) checkKvStoreReadiness(ctx context.Context) {
164 // dividing the live probe interval by 2 to get updated status every 30s
165 timeout := a.config.LiveProbeInterval / 2
166 kvStoreChannel := make(chan bool, 1)
167
168 // Default false to check the liveliness.
169 kvStoreChannel <- false
cbabu95f21522019-11-13 14:25:18 +0100170 for {
cbabu116b73f2019-12-10 17:56:32 +0530171 timeoutTimer := time.NewTimer(timeout)
172 select {
173 case liveliness := <-kvStoreChannel:
174 if !liveliness {
175 // kv-store not reachable or down, updating the status to not ready state
176 probe.UpdateStatusFromContext(ctx, "kv-store", probe.ServiceStatusNotReady)
177 timeout = a.config.NotLiveProbeInterval
178 } else {
179 // kv-store is reachable , updating the status to running state
180 probe.UpdateStatusFromContext(ctx, "kv-store", probe.ServiceStatusRunning)
181 timeout = a.config.LiveProbeInterval / 2
182 }
183 // Check if the timer has expired or not
184 if !timeoutTimer.Stop() {
185 <-timeoutTimer.C
186 }
187 case <-timeoutTimer.C:
Girish Kumarbeadc112020-02-26 18:41:02 +0000188 // Check the status of the kv-store. Use timeout of 2 seconds to avoid forever blocking
Girish Kumar2ad402b2020-03-20 19:45:12 +0000189 logger.Info("kv-store liveliness-recheck")
Girish Kumarbeadc112020-02-26 18:41:02 +0000190 timeoutCtx, cancelFunc := context.WithTimeout(ctx, 2*time.Second)
191
192 kvStoreChannel <- a.kvClient.IsConnectionUp(timeoutCtx)
193 // Cleanup cancel func resources
194 cancelFunc()
cbabu95f21522019-11-13 14:25:18 +0100195 }
cbabu116b73f2019-12-10 17:56:32 +0530196 }
197}
198
199/**
200This function checks the liveliness and readiness of the kafka service
201and update the status in the probe.
202*/
203func (a *adapter) checkKafkaReadiness(ctx context.Context) {
204 livelinessChannel := a.kafkaClient.EnableLivenessChannel(true)
Scott Baker86fce9a2019-12-12 09:47:17 -0800205 healthinessChannel := a.kafkaClient.EnableHealthinessChannel(true)
cbabu116b73f2019-12-10 17:56:32 +0530206 timeout := a.config.LiveProbeInterval
Scott Bakere701b862020-02-20 16:19:16 -0800207 failed := false
cbabu116b73f2019-12-10 17:56:32 +0530208 for {
209 timeoutTimer := time.NewTimer(timeout)
210
211 select {
Scott Baker86fce9a2019-12-12 09:47:17 -0800212 case healthiness := <-healthinessChannel:
213 if !healthiness {
Scott Bakere701b862020-02-20 16:19:16 -0800214 // This will eventually cause K8s to restart the container, and will do
215 // so in a way that allows cleanup to continue, rather than an immediate
216 // panic and exit here.
217 probe.UpdateStatusFromContext(ctx, "message-bus", probe.ServiceStatusFailed)
218 failed = true
219 }
220 // Check if the timer has expired or not
221 if !timeoutTimer.Stop() {
222 <-timeoutTimer.C
Scott Baker86fce9a2019-12-12 09:47:17 -0800223 }
cbabu116b73f2019-12-10 17:56:32 +0530224 case liveliness := <-livelinessChannel:
Scott Bakere701b862020-02-20 16:19:16 -0800225 if failed {
226 // Failures of the message bus are permanent and can't ever be recovered from,
227 // so make sure we never inadvertently reset a failed state back to unready.
228 } else if !liveliness {
cbabu116b73f2019-12-10 17:56:32 +0530229 // kafka not reachable or down, updating the status to not ready state
230 probe.UpdateStatusFromContext(ctx, "message-bus", probe.ServiceStatusNotReady)
231 timeout = a.config.NotLiveProbeInterval
232 } else {
233 // kafka is reachable , updating the status to running state
234 probe.UpdateStatusFromContext(ctx, "message-bus", probe.ServiceStatusRunning)
235 timeout = a.config.LiveProbeInterval
236 }
237 // Check if the timer has expired or not
238 if !timeoutTimer.Stop() {
239 <-timeoutTimer.C
240 }
241 case <-timeoutTimer.C:
Girish Kumar2ad402b2020-03-20 19:45:12 +0000242 logger.Info("kafka-proxy-liveness-recheck")
cbabu116b73f2019-12-10 17:56:32 +0530243 // send the liveness probe in a goroutine; we don't want to deadlock ourselves as
244 // the liveness probe may wait (and block) writing to our channel.
245 err := a.kafkaClient.SendLiveness()
246 if err != nil {
247 // Catch possible error case if sending liveness after Sarama has been stopped.
Girish Kumar2ad402b2020-03-20 19:45:12 +0000248 logger.Warnw("error-kafka-send-liveness", log.Fields{"error": err})
cbabu116b73f2019-12-10 17:56:32 +0530249 }
cbabu95f21522019-11-13 14:25:18 +0100250 }
cbabu95f21522019-11-13 14:25:18 +0100251 }
cuilin20187b2a8c32019-03-26 19:52:28 -0700252}
253
npujarec5762e2020-01-01 14:08:48 +0530254func (a *adapter) stop(ctx context.Context) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700255 // Stop leadership tracking
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700256 a.halted = true
cuilin20187b2a8c32019-03-26 19:52:28 -0700257
258 // send exit signal
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700259 a.exitChannel <- 0
cuilin20187b2a8c32019-03-26 19:52:28 -0700260
261 // Cleanup - applies only if we had a kvClient
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700262 if a.kvClient != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700263 // Release all reservations
npujarec5762e2020-01-01 14:08:48 +0530264 if err := a.kvClient.ReleaseAllReservations(ctx); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000265 logger.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700266 }
267 // Close the DB connection
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700268 a.kvClient.Close()
cuilin20187b2a8c32019-03-26 19:52:28 -0700269 }
270
Scott Bakere701b862020-02-20 16:19:16 -0800271 if a.kip != nil {
272 a.kip.Stop()
273 }
274
cuilin20187b2a8c32019-03-26 19:52:28 -0700275 // TODO: More cleanup
276}
277
Neha Sharmacc656962020-04-14 14:26:11 +0000278func newKVClient(storeType, address string, timeout time.Duration) (kvstore.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700279
Girish Kumar2ad402b2020-03-20 19:45:12 +0000280 logger.Infow("kv-store-type", log.Fields{"store": storeType})
cuilin20187b2a8c32019-03-26 19:52:28 -0700281 switch storeType {
282 case "consul":
283 return kvstore.NewConsulClient(address, timeout)
284 case "etcd":
Scott Bakered4a8e72020-04-17 11:10:20 -0700285 return kvstore.NewEtcdClient(address, timeout, log.FatalLevel)
cuilin20187b2a8c32019-03-26 19:52:28 -0700286 }
287 return nil, errors.New("unsupported-kv-store")
288}
289
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700290func newKafkaClient(clientType, host string, port int) (kafka.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700291
Girish Kumar2ad402b2020-03-20 19:45:12 +0000292 logger.Infow("common-client-type", log.Fields{"client": clientType})
cuilin20187b2a8c32019-03-26 19:52:28 -0700293 switch clientType {
294 case "sarama":
295 return kafka.NewSaramaClient(
296 kafka.Host(host),
297 kafka.Port(port),
298 kafka.ProducerReturnOnErrors(true),
299 kafka.ProducerReturnOnSuccess(true),
300 kafka.ProducerMaxRetries(6),
Abhilash S.L3b494632019-07-16 15:51:09 +0530301 kafka.ProducerRetryBackoff(time.Millisecond*30),
302 kafka.MetadatMaxRetries(15)), nil
cuilin20187b2a8c32019-03-26 19:52:28 -0700303 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700304
cuilin20187b2a8c32019-03-26 19:52:28 -0700305 return nil, errors.New("unsupported-client-type")
306}
307
308func (a *adapter) setKVClient() error {
309 addr := a.config.KVStoreHost + ":" + strconv.Itoa(a.config.KVStorePort)
310 client, err := newKVClient(a.config.KVStoreType, addr, a.config.KVStoreTimeout)
311 if err != nil {
312 a.kvClient = nil
cuilin20187b2a8c32019-03-26 19:52:28 -0700313 return err
314 }
315 a.kvClient = client
divyadesaia37f78b2020-02-07 12:41:22 +0000316
cuilin20187b2a8c32019-03-26 19:52:28 -0700317 return nil
318}
319
npujarec5762e2020-01-01 14:08:48 +0530320func (a *adapter) startInterContainerProxy(ctx context.Context, retries int) (kafka.InterContainerProxy, error) {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000321 logger.Infow("starting-intercontainer-messaging-proxy", log.Fields{"host": a.config.KafkaAdapterHost,
cuilin20187b2a8c32019-03-26 19:52:28 -0700322 "port": a.config.KafkaAdapterPort, "topic": a.config.Topic})
323 var err error
npujarec5762e2020-01-01 14:08:48 +0530324 kip := kafka.NewInterContainerProxy(
cuilin20187b2a8c32019-03-26 19:52:28 -0700325 kafka.InterContainerHost(a.config.KafkaAdapterHost),
326 kafka.InterContainerPort(a.config.KafkaAdapterPort),
327 kafka.MsgClient(a.kafkaClient),
npujarec5762e2020-01-01 14:08:48 +0530328 kafka.DefaultTopic(&kafka.Topic{Name: a.config.Topic}))
cuilin20187b2a8c32019-03-26 19:52:28 -0700329 count := 0
330 for {
331 if err = kip.Start(); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000332 logger.Warnw("error-starting-messaging-proxy", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700333 if retries == count {
334 return nil, err
335 }
336 count = +1
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700337 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700338 time.Sleep(2 * time.Second)
339 } else {
340 break
341 }
342 }
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000343 probe.UpdateStatusFromContext(ctx, "container-proxy", probe.ServiceStatusRunning)
Girish Kumar2ad402b2020-03-20 19:45:12 +0000344 logger.Info("common-messaging-proxy-created")
cuilin20187b2a8c32019-03-26 19:52:28 -0700345 return kip, nil
346}
347
npujarec5762e2020-01-01 14:08:48 +0530348func (a *adapter) startOpenOLT(ctx context.Context, kip kafka.InterContainerProxy,
Abhilash Laxmeshwarf9942e92020-01-07 15:32:44 +0530349 cp adapterif.CoreProxy, ap adapterif.AdapterProxy, ep adapterif.EventProxy,
350 cfg *config.AdapterFlags) (*ac.OpenOLT, error) {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000351 logger.Info("starting-open-olt")
cuilin20187b2a8c32019-03-26 19:52:28 -0700352 var err error
Abhilash Laxmeshwarf9942e92020-01-07 15:32:44 +0530353 sOLT := ac.NewOpenOLT(ctx, a.kip, cp, ap, ep, cfg)
cuilin20187b2a8c32019-03-26 19:52:28 -0700354
355 if err = sOLT.Start(ctx); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700356 return nil, err
357 }
358
Girish Kumar2ad402b2020-03-20 19:45:12 +0000359 logger.Info("open-olt-started")
cuilin20187b2a8c32019-03-26 19:52:28 -0700360 return sOLT, nil
361}
362
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000363func (a *adapter) setupRequestHandler(ctx context.Context, coreInstanceID string, iadapter adapters.IAdapter) error {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000364 logger.Info("setting-request-handler")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700365 requestProxy := com.NewRequestHandlerProxy(coreInstanceID, iadapter, a.coreProxy)
cuilin20187b2a8c32019-03-26 19:52:28 -0700366 if err := a.kip.SubscribeWithRequestHandlerInterface(kafka.Topic{Name: a.config.Topic}, requestProxy); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700367 return err
368
369 }
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000370 probe.UpdateStatusFromContext(ctx, "core-request-handler", probe.ServiceStatusRunning)
Girish Kumar2ad402b2020-03-20 19:45:12 +0000371 logger.Info("request-handler-setup-done")
cuilin20187b2a8c32019-03-26 19:52:28 -0700372 return nil
373}
374
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000375func (a *adapter) registerWithCore(ctx context.Context, retries int) error {
Matteo Scandolo3ad5d2b2020-04-02 17:02:04 -0700376 adapterID := fmt.Sprintf("openolt_%d", a.config.CurrentReplica)
377 logger.Infow("registering-with-core", log.Fields{
378 "adapterID": adapterID,
379 "currentReplica": a.config.CurrentReplica,
380 "totalReplicas": a.config.TotalReplicas,
381 })
382 adapterDescription := &voltha.Adapter{
383 Id: adapterID, // Unique name for the device type
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400384 Vendor: "VOLTHA OpenOLT",
Matteo Scandolo3ad5d2b2020-04-02 17:02:04 -0700385 Version: version.VersionInfo.Version,
386 // TODO once we'll be ready to support multiple versions of the OpenOLT adapter
387 // the Endpoint will have to change to `openolt_<currentReplica`>
serkant.uluderya5e3528d2020-05-22 19:31:07 -0700388 Endpoint: a.config.Topic,
Matteo Scandolo3ad5d2b2020-04-02 17:02:04 -0700389 Type: "openolt",
390 CurrentReplica: int32(a.config.CurrentReplica),
391 TotalReplicas: int32(a.config.TotalReplicas),
392 }
393 types := []*voltha.DeviceType{{
394 Id: "openolt",
395 Adapter: "openolt", // Type of the adapter that handles device type
Girish Gowdru0c588b22019-04-23 23:24:56 -0400396 AcceptsBulkFlowUpdate: false, // Currently openolt adapter does not support bulk flow handling
397 AcceptsAddRemoveFlowUpdates: true}}
cuilin20187b2a8c32019-03-26 19:52:28 -0700398 deviceTypes := &voltha.DeviceTypes{Items: types}
399 count := 0
400 for {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700401 if err := a.coreProxy.RegisterAdapter(context.TODO(), adapterDescription, deviceTypes); err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000402 logger.Warnw("registering-with-core-failed", log.Fields{"error": err})
cuilin20187b2a8c32019-03-26 19:52:28 -0700403 if retries == count {
404 return err
405 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700406 count++
407 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700408 time.Sleep(2 * time.Second)
409 } else {
410 break
411 }
412 }
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000413 probe.UpdateStatusFromContext(ctx, "register-with-core", probe.ServiceStatusRunning)
Girish Kumar2ad402b2020-03-20 19:45:12 +0000414 logger.Info("registered-with-core")
cuilin20187b2a8c32019-03-26 19:52:28 -0700415 return nil
416}
417
418func waitForExit() int {
419 signalChannel := make(chan os.Signal, 1)
420 signal.Notify(signalChannel,
421 syscall.SIGHUP,
422 syscall.SIGINT,
423 syscall.SIGTERM,
424 syscall.SIGQUIT)
425
426 exitChannel := make(chan int)
427
428 go func() {
429 s := <-signalChannel
430 switch s {
431 case syscall.SIGHUP,
432 syscall.SIGINT,
433 syscall.SIGTERM,
434 syscall.SIGQUIT:
Girish Kumar2ad402b2020-03-20 19:45:12 +0000435 logger.Infow("closing-signal-received", log.Fields{"signal": s})
cuilin20187b2a8c32019-03-26 19:52:28 -0700436 exitChannel <- 0
437 default:
Girish Kumar2ad402b2020-03-20 19:45:12 +0000438 logger.Infow("unexpected-signal-received", log.Fields{"signal": s})
cuilin20187b2a8c32019-03-26 19:52:28 -0700439 exitChannel <- 1
440 }
441 }()
442
443 code := <-exitChannel
444 return code
445}
446
447func printBanner() {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800448 fmt.Println(` ____ ____ _ _______ `)
449 fmt.Println(` / _ \ / __ \| | |__ __|`)
450 fmt.Println(` | | | |_ __ ___ _ __ | | | | | | | `)
451 fmt.Println(` | | | | '_ \ / _ \ '_ \ | | | | | | | `)
452 fmt.Println(` | |__| | |_) | __/ | | || |__| | |____| | `)
453 fmt.Println(` \____/| .__/ \___|_| |_| \____/|______|_| `)
454 fmt.Println(` | | `)
455 fmt.Println(` |_| `)
456 fmt.Println(` `)
cuilin20187b2a8c32019-03-26 19:52:28 -0700457}
458
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400459func printVersion() {
460 fmt.Println("VOLTHA OpenOLT Adapter")
461 fmt.Println(version.VersionInfo.String(" "))
462}
463
cuilin20187b2a8c32019-03-26 19:52:28 -0700464func main() {
465 start := time.Now()
466
467 cf := config.NewAdapterFlags()
468 cf.ParseCommandArguments()
469
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700470 // Setup logging
cuilin20187b2a8c32019-03-26 19:52:28 -0700471
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000472 logLevel, err := log.StringToLogLevel(cf.LogLevel)
473 if err != nil {
Girish Kumar2ad402b2020-03-20 19:45:12 +0000474 logger.Fatalf("Cannot setup logging, %s", err)
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000475 }
Rohan Agrawal2488f192020-01-31 09:26:55 +0000476
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700477 // Setup default logger - applies for packages that do not have specific logger set
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000478 if _, err := log.SetDefaultLogger(log.JSON, logLevel, log.Fields{"instanceId": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700479 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
480 }
481
482 // Update all loggers (provisionned via init) with a common field
Hardik Windlassb9c869b2019-10-10 08:34:32 +0000483 if err := log.UpdateAllLoggers(log.Fields{"instanceId": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700484 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
485 }
486
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000487 log.SetAllLogLevel(logLevel)
Rohan Agrawal93bced32020-02-11 10:16:01 +0000488
Matteo Scandolo8f2b9572020-02-28 15:35:23 -0800489 realMain()
490
cuilin20187b2a8c32019-03-26 19:52:28 -0700491 defer log.CleanUp()
492
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400493 // Print version / build information and exit
494 if cf.DisplayVersionOnly {
495 printVersion()
496 return
497 }
498
cuilin20187b2a8c32019-03-26 19:52:28 -0700499 // Print banner if specified
500 if cf.Banner {
501 printBanner()
502 }
503
Girish Kumar2ad402b2020-03-20 19:45:12 +0000504 logger.Infow("config", log.Fields{"config": *cf})
cuilin20187b2a8c32019-03-26 19:52:28 -0700505
506 ctx, cancel := context.WithCancel(context.Background())
507 defer cancel()
508
509 ad := newAdapter(cf)
Rohan Agrawal828bf4e2019-10-22 10:13:19 +0000510
511 p := &probe.Probe{}
512 go p.ListenAndServe(fmt.Sprintf("%s:%d", ad.config.ProbeHost, ad.config.ProbePort))
513
514 probeCtx := context.WithValue(ctx, probe.ProbeContextKey, p)
515
516 go ad.start(probeCtx)
cuilin20187b2a8c32019-03-26 19:52:28 -0700517
518 code := waitForExit()
Girish Kumar2ad402b2020-03-20 19:45:12 +0000519 logger.Infow("received-a-closing-signal", log.Fields{"code": code})
cuilin20187b2a8c32019-03-26 19:52:28 -0700520
521 // Cleanup before leaving
npujarec5762e2020-01-01 14:08:48 +0530522 ad.stop(ctx)
cuilin20187b2a8c32019-03-26 19:52:28 -0700523
524 elapsed := time.Since(start)
Girish Kumar2ad402b2020-03-20 19:45:12 +0000525 logger.Infow("run-time", log.Fields{"instanceId": ad.config.InstanceID, "time": elapsed / time.Second})
cuilin20187b2a8c32019-03-26 19:52:28 -0700526}