blob: af7ca2eeec44a02e57401198e6624f2503dd09c5 [file] [log] [blame]
cuilin20187b2a8c32019-03-26 19:52:28 -07001/*
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 */
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"
kdarapub67f49c2019-07-31 18:23:16 +053024 "os"
25 "os/signal"
26 "strconv"
27 "syscall"
28 "time"
29
30 "github.com/opencord/voltha-go/adapters/adapterif"
31
cuilin20187b2a8c32019-03-26 19:52:28 -070032 "github.com/opencord/voltha-go/adapters"
33 com "github.com/opencord/voltha-go/adapters/common"
cuilin20187b2a8c32019-03-26 19:52:28 -070034 "github.com/opencord/voltha-go/common/log"
35 "github.com/opencord/voltha-go/db/kvstore"
36 "github.com/opencord/voltha-go/kafka"
Girish Gowdru0c588b22019-04-23 23:24:56 -040037 ac "github.com/opencord/voltha-openolt-adapter/adaptercore"
38 "github.com/opencord/voltha-openolt-adapter/config"
Matt Jeanneret0c9ae282019-07-18 18:14:28 -040039 "github.com/opencord/voltha-openolt-adapter/config/version"
manikkaraj kbf256be2019-03-25 00:13:48 +053040 ic "github.com/opencord/voltha-protos/go/inter_container"
41 "github.com/opencord/voltha-protos/go/voltha"
cuilin20187b2a8c32019-03-26 19:52:28 -070042)
43
44type adapter struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070045 instanceID string
cuilin20187b2a8c32019-03-26 19:52:28 -070046 config *config.AdapterFlags
47 iAdapter adapters.IAdapter
48 kafkaClient kafka.Client
49 kvClient kvstore.Client
50 kip *kafka.InterContainerProxy
kdarapub67f49c2019-07-31 18:23:16 +053051 coreProxy adapterif.CoreProxy
52 adapterProxy adapterif.AdapterProxy
53 eventProxy adapterif.EventProxy
cuilin20187b2a8c32019-03-26 19:52:28 -070054 halted bool
55 exitChannel chan int
56 receiverChannels []<-chan *ic.InterContainerMessage
57}
58
59func init() {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070060 _, _ = log.AddPackage(log.JSON, log.DebugLevel, nil)
cuilin20187b2a8c32019-03-26 19:52:28 -070061}
62
63func newAdapter(cf *config.AdapterFlags) *adapter {
64 var a adapter
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070065 a.instanceID = cf.InstanceID
cuilin20187b2a8c32019-03-26 19:52:28 -070066 a.config = cf
67 a.halted = false
68 a.exitChannel = make(chan int, 1)
69 a.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
70 return &a
71}
72
73func (a *adapter) start(ctx context.Context) {
74 log.Info("Starting Core Adapter components")
75 var err error
76
77 // Setup KV Client
78 log.Debugw("create-kv-client", log.Fields{"kvstore": a.config.KVStoreType})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070079 if err = a.setKVClient(); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -070080 log.Fatal("error-setting-kv-client")
81 }
82
83 // Setup Kafka Client
84 if a.kafkaClient, err = newKafkaClient("sarama", a.config.KafkaAdapterHost, a.config.KafkaAdapterPort); err != nil {
85 log.Fatal("Unsupported-common-client")
86 }
87
88 // Start the common InterContainer Proxy - retries indefinitely
89 if a.kip, err = a.startInterContainerProxy(-1); err != nil {
90 log.Fatal("error-starting-inter-container-proxy")
91 }
92
93 // Create the core proxy to handle requests to the Core
94 a.coreProxy = com.NewCoreProxy(a.kip, a.config.Topic, a.config.CoreTopic)
95
96 // Create the adaptor proxy to handle request between olt and onu
97 a.adapterProxy = com.NewAdapterProxy(a.kip, "brcm_openomci_onu", a.config.CoreTopic)
98
Devmalya Paulfb990a52019-07-09 10:01:49 -040099 // Create the event proxy to post events to KAFKA
100 a.eventProxy = com.NewEventProxy(com.MsgClient(a.kafkaClient), com.MsgTopic(kafka.Topic{Name: a.config.EventTopic}))
101
cuilin20187b2a8c32019-03-26 19:52:28 -0700102 // Create the open OLT adapter
kdarapub67f49c2019-07-31 18:23:16 +0530103 if a.iAdapter, err = a.startOpenOLT(ctx, a.kip, a.coreProxy, a.adapterProxy, a.eventProxy,
104 a.config.OnuNumber,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700105 a.config.KVStoreHost, a.config.KVStorePort, a.config.KVStoreType); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700106 log.Fatal("error-starting-inter-container-proxy")
107 }
108
109 // Register the core request handler
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700110 if err = a.setupRequestHandler(a.instanceID, a.iAdapter); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700111 log.Fatal("error-setting-core-request-handler")
112 }
113
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700114 // Register this adapter to the Core - retries indefinitely
cuilin20187b2a8c32019-03-26 19:52:28 -0700115 if err = a.registerWithCore(-1); err != nil {
116 log.Fatal("error-registering-with-core")
117 }
118}
119
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700120func (a *adapter) stop() {
cuilin20187b2a8c32019-03-26 19:52:28 -0700121 // Stop leadership tracking
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700122 a.halted = true
cuilin20187b2a8c32019-03-26 19:52:28 -0700123
124 // send exit signal
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700125 a.exitChannel <- 0
cuilin20187b2a8c32019-03-26 19:52:28 -0700126
127 // Cleanup - applies only if we had a kvClient
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700128 if a.kvClient != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700129 // Release all reservations
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700130 if err := a.kvClient.ReleaseAllReservations(); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700131 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
132 }
133 // Close the DB connection
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700134 a.kvClient.Close()
cuilin20187b2a8c32019-03-26 19:52:28 -0700135 }
136
137 // TODO: More cleanup
138}
139
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700140func newKVClient(storeType, address string, timeout int) (kvstore.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700141
142 log.Infow("kv-store-type", log.Fields{"store": storeType})
143 switch storeType {
144 case "consul":
145 return kvstore.NewConsulClient(address, timeout)
146 case "etcd":
147 return kvstore.NewEtcdClient(address, timeout)
148 }
149 return nil, errors.New("unsupported-kv-store")
150}
151
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700152func newKafkaClient(clientType, host string, port int) (kafka.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700153
154 log.Infow("common-client-type", log.Fields{"client": clientType})
155 switch clientType {
156 case "sarama":
157 return kafka.NewSaramaClient(
158 kafka.Host(host),
159 kafka.Port(port),
160 kafka.ProducerReturnOnErrors(true),
161 kafka.ProducerReturnOnSuccess(true),
162 kafka.ProducerMaxRetries(6),
Abhilash S.L3b494632019-07-16 15:51:09 +0530163 kafka.ProducerRetryBackoff(time.Millisecond*30),
164 kafka.MetadatMaxRetries(15)), nil
cuilin20187b2a8c32019-03-26 19:52:28 -0700165 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700166
cuilin20187b2a8c32019-03-26 19:52:28 -0700167 return nil, errors.New("unsupported-client-type")
168}
169
170func (a *adapter) setKVClient() error {
171 addr := a.config.KVStoreHost + ":" + strconv.Itoa(a.config.KVStorePort)
172 client, err := newKVClient(a.config.KVStoreType, addr, a.config.KVStoreTimeout)
173 if err != nil {
174 a.kvClient = nil
175 log.Error(err)
176 return err
177 }
178 a.kvClient = client
179 return nil
180}
181
cuilin20187b2a8c32019-03-26 19:52:28 -0700182func (a *adapter) startInterContainerProxy(retries int) (*kafka.InterContainerProxy, error) {
183 log.Infow("starting-intercontainer-messaging-proxy", log.Fields{"host": a.config.KafkaAdapterHost,
184 "port": a.config.KafkaAdapterPort, "topic": a.config.Topic})
185 var err error
186 var kip *kafka.InterContainerProxy
187 if kip, err = kafka.NewInterContainerProxy(
188 kafka.InterContainerHost(a.config.KafkaAdapterHost),
189 kafka.InterContainerPort(a.config.KafkaAdapterPort),
190 kafka.MsgClient(a.kafkaClient),
191 kafka.DefaultTopic(&kafka.Topic{Name: a.config.Topic})); err != nil {
192 log.Errorw("fail-to-create-common-proxy", log.Fields{"error": err})
193 return nil, err
194 }
195 count := 0
196 for {
197 if err = kip.Start(); err != nil {
198 log.Warnw("error-starting-messaging-proxy", log.Fields{"error": err})
199 if retries == count {
200 return nil, err
201 }
202 count = +1
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700203 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700204 time.Sleep(2 * time.Second)
205 } else {
206 break
207 }
208 }
209
210 log.Info("common-messaging-proxy-created")
211 return kip, nil
212}
213
kdarapub67f49c2019-07-31 18:23:16 +0530214func (a *adapter) startOpenOLT(ctx context.Context, kip *kafka.InterContainerProxy,
215 cp adapterif.CoreProxy, ap adapterif.AdapterProxy, ep adapterif.EventProxy, onuNumber int, kvStoreHost string,
216 kvStorePort int, KVStoreType string) (*ac.OpenOLT, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700217 log.Info("starting-open-olt")
218 var err error
Devmalya Paulfb990a52019-07-09 10:01:49 -0400219 sOLT := ac.NewOpenOLT(ctx, a.kip, cp, ap, ep, onuNumber, kvStoreHost, kvStorePort, KVStoreType)
cuilin20187b2a8c32019-03-26 19:52:28 -0700220
221 if err = sOLT.Start(ctx); err != nil {
222 log.Fatalw("error-starting-messaging-proxy", log.Fields{"error": err})
223 return nil, err
224 }
225
226 log.Info("open-olt-started")
227 return sOLT, nil
228}
229
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700230func (a *adapter) setupRequestHandler(coreInstanceID string, iadapter adapters.IAdapter) error {
cuilin20187b2a8c32019-03-26 19:52:28 -0700231 log.Info("setting-request-handler")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700232 requestProxy := com.NewRequestHandlerProxy(coreInstanceID, iadapter, a.coreProxy)
cuilin20187b2a8c32019-03-26 19:52:28 -0700233 if err := a.kip.SubscribeWithRequestHandlerInterface(kafka.Topic{Name: a.config.Topic}, requestProxy); err != nil {
234 log.Errorw("request-handler-setup-failed", log.Fields{"error": err})
235 return err
236
237 }
238 log.Info("request-handler-setup-done")
239 return nil
240}
241
242func (a *adapter) registerWithCore(retries int) error {
243 log.Info("registering-with-core")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400244 adapterDescription := &voltha.Adapter{Id: "openolt", // Unique name for the device type
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400245 Vendor: "VOLTHA OpenOLT",
246 Version: version.VersionInfo.Version}
Girish Gowdru0c588b22019-04-23 23:24:56 -0400247 types := []*voltha.DeviceType{{Id: "openolt",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700248 Adapter: "openolt", // Name of the adapter that handles device type
Girish Gowdru0c588b22019-04-23 23:24:56 -0400249 AcceptsBulkFlowUpdate: false, // Currently openolt adapter does not support bulk flow handling
250 AcceptsAddRemoveFlowUpdates: true}}
cuilin20187b2a8c32019-03-26 19:52:28 -0700251 deviceTypes := &voltha.DeviceTypes{Items: types}
252 count := 0
253 for {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700254 if err := a.coreProxy.RegisterAdapter(context.TODO(), adapterDescription, deviceTypes); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700255 log.Warnw("registering-with-core-failed", log.Fields{"error": err})
256 if retries == count {
257 return err
258 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700259 count++
260 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700261 time.Sleep(2 * time.Second)
262 } else {
263 break
264 }
265 }
266 log.Info("registered-with-core")
267 return nil
268}
269
270func waitForExit() int {
271 signalChannel := make(chan os.Signal, 1)
272 signal.Notify(signalChannel,
273 syscall.SIGHUP,
274 syscall.SIGINT,
275 syscall.SIGTERM,
276 syscall.SIGQUIT)
277
278 exitChannel := make(chan int)
279
280 go func() {
281 s := <-signalChannel
282 switch s {
283 case syscall.SIGHUP,
284 syscall.SIGINT,
285 syscall.SIGTERM,
286 syscall.SIGQUIT:
287 log.Infow("closing-signal-received", log.Fields{"signal": s})
288 exitChannel <- 0
289 default:
290 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
291 exitChannel <- 1
292 }
293 }()
294
295 code := <-exitChannel
296 return code
297}
298
299func printBanner() {
300 fmt.Println(" ____ ____ _ _______ ")
301 fmt.Println(" / _ \\ / __\\| | |__ __|")
302 fmt.Println(" | | | |_ __ ___ _ __ | | | | | | | ")
303 fmt.Println(" | | | | '_\\ / _\\ '_\\ | | | | | | | ")
304 fmt.Println(" | |__| | |_) | __/ | | || |__| | |____| | ")
305 fmt.Println(" \\____/| .__/\\___|_| |_|\\____/|______|_| ")
306 fmt.Println(" | | ")
307 fmt.Println(" |_| ")
308 fmt.Println(" ")
309}
310
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400311func printVersion() {
312 fmt.Println("VOLTHA OpenOLT Adapter")
313 fmt.Println(version.VersionInfo.String(" "))
314}
315
cuilin20187b2a8c32019-03-26 19:52:28 -0700316func main() {
317 start := time.Now()
318
319 cf := config.NewAdapterFlags()
320 cf.ParseCommandArguments()
321
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700322 // Setup logging
cuilin20187b2a8c32019-03-26 19:52:28 -0700323
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700324 // Setup default logger - applies for packages that do not have specific logger set
325 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceID": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700326 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
327 }
328
329 // Update all loggers (provisionned via init) with a common field
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700330 if err := log.UpdateAllLoggers(log.Fields{"instanceID": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700331 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
332 }
333
334 log.SetPackageLogLevel("github.com/opencord/voltha-go/adapters/common", log.DebugLevel)
335
336 defer log.CleanUp()
337
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400338 // Print version / build information and exit
339 if cf.DisplayVersionOnly {
340 printVersion()
341 return
342 }
343
cuilin20187b2a8c32019-03-26 19:52:28 -0700344 // Print banner if specified
345 if cf.Banner {
346 printBanner()
347 }
348
349 log.Infow("config", log.Fields{"config": *cf})
350
351 ctx, cancel := context.WithCancel(context.Background())
352 defer cancel()
353
354 ad := newAdapter(cf)
355 go ad.start(ctx)
356
357 code := waitForExit()
358 log.Infow("received-a-closing-signal", log.Fields{"code": code})
359
360 // Cleanup before leaving
361 ad.stop()
362
363 elapsed := time.Since(start)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700364 log.Infow("run-time", log.Fields{"instanceID": ad.config.InstanceID, "time": elapsed / time.Second})
cuilin20187b2a8c32019-03-26 19:52:28 -0700365}