blob: 3a0e9668eca08c393203457759379700c250b11b [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"
24 "github.com/opencord/voltha-go/adapters"
25 com "github.com/opencord/voltha-go/adapters/common"
cuilin20187b2a8c32019-03-26 19:52:28 -070026 "github.com/opencord/voltha-go/common/log"
Matt Jeanneretf880eb62019-07-16 20:08:03 -040027 "github.com/opencord/voltha-go/common/version"
cuilin20187b2a8c32019-03-26 19:52:28 -070028 "github.com/opencord/voltha-go/db/kvstore"
29 "github.com/opencord/voltha-go/kafka"
Girish Gowdru0c588b22019-04-23 23:24:56 -040030 ac "github.com/opencord/voltha-openolt-adapter/adaptercore"
31 "github.com/opencord/voltha-openolt-adapter/config"
manikkaraj kbf256be2019-03-25 00:13:48 +053032 ic "github.com/opencord/voltha-protos/go/inter_container"
33 "github.com/opencord/voltha-protos/go/voltha"
cuilin20187b2a8c32019-03-26 19:52:28 -070034 "os"
35 "os/signal"
36 "strconv"
37 "syscall"
38 "time"
39)
40
41type adapter struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070042 instanceID string
cuilin20187b2a8c32019-03-26 19:52:28 -070043 config *config.AdapterFlags
44 iAdapter adapters.IAdapter
45 kafkaClient kafka.Client
46 kvClient kvstore.Client
47 kip *kafka.InterContainerProxy
48 coreProxy *com.CoreProxy
49 adapterProxy *com.AdapterProxy
Devmalya Paulfb990a52019-07-09 10:01:49 -040050 eventProxy *com.EventProxy
cuilin20187b2a8c32019-03-26 19:52:28 -070051 halted bool
52 exitChannel chan int
53 receiverChannels []<-chan *ic.InterContainerMessage
54}
55
56func init() {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070057 _, _ = log.AddPackage(log.JSON, log.DebugLevel, nil)
cuilin20187b2a8c32019-03-26 19:52:28 -070058}
59
60func newAdapter(cf *config.AdapterFlags) *adapter {
61 var a adapter
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070062 a.instanceID = cf.InstanceID
cuilin20187b2a8c32019-03-26 19:52:28 -070063 a.config = cf
64 a.halted = false
65 a.exitChannel = make(chan int, 1)
66 a.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
67 return &a
68}
69
70func (a *adapter) start(ctx context.Context) {
71 log.Info("Starting Core Adapter components")
72 var err error
73
74 // Setup KV Client
75 log.Debugw("create-kv-client", log.Fields{"kvstore": a.config.KVStoreType})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070076 if err = a.setKVClient(); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -070077 log.Fatal("error-setting-kv-client")
78 }
79
80 // Setup Kafka Client
81 if a.kafkaClient, err = newKafkaClient("sarama", a.config.KafkaAdapterHost, a.config.KafkaAdapterPort); err != nil {
82 log.Fatal("Unsupported-common-client")
83 }
84
85 // Start the common InterContainer Proxy - retries indefinitely
86 if a.kip, err = a.startInterContainerProxy(-1); err != nil {
87 log.Fatal("error-starting-inter-container-proxy")
88 }
89
90 // Create the core proxy to handle requests to the Core
91 a.coreProxy = com.NewCoreProxy(a.kip, a.config.Topic, a.config.CoreTopic)
92
93 // Create the adaptor proxy to handle request between olt and onu
94 a.adapterProxy = com.NewAdapterProxy(a.kip, "brcm_openomci_onu", a.config.CoreTopic)
95
Devmalya Paulfb990a52019-07-09 10:01:49 -040096 // Create the event proxy to post events to KAFKA
97 a.eventProxy = com.NewEventProxy(com.MsgClient(a.kafkaClient), com.MsgTopic(kafka.Topic{Name: a.config.EventTopic}))
98
cuilin20187b2a8c32019-03-26 19:52:28 -070099 // Create the open OLT adapter
Devmalya Paulfb990a52019-07-09 10:01:49 -0400100 if a.iAdapter, err = a.startOpenOLT(ctx, a.kip, a.coreProxy, a.adapterProxy, a.eventProxy, a.config.OnuNumber,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700101 a.config.KVStoreHost, a.config.KVStorePort, a.config.KVStoreType); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700102 log.Fatal("error-starting-inter-container-proxy")
103 }
104
105 // Register the core request handler
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700106 if err = a.setupRequestHandler(a.instanceID, a.iAdapter); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700107 log.Fatal("error-setting-core-request-handler")
108 }
109
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700110 // Register this adapter to the Core - retries indefinitely
cuilin20187b2a8c32019-03-26 19:52:28 -0700111 if err = a.registerWithCore(-1); err != nil {
112 log.Fatal("error-registering-with-core")
113 }
114}
115
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700116func (a *adapter) stop() {
cuilin20187b2a8c32019-03-26 19:52:28 -0700117 // Stop leadership tracking
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700118 a.halted = true
cuilin20187b2a8c32019-03-26 19:52:28 -0700119
120 // send exit signal
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700121 a.exitChannel <- 0
cuilin20187b2a8c32019-03-26 19:52:28 -0700122
123 // Cleanup - applies only if we had a kvClient
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700124 if a.kvClient != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700125 // Release all reservations
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700126 if err := a.kvClient.ReleaseAllReservations(); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700127 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
128 }
129 // Close the DB connection
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700130 a.kvClient.Close()
cuilin20187b2a8c32019-03-26 19:52:28 -0700131 }
132
133 // TODO: More cleanup
134}
135
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700136func newKVClient(storeType, address string, timeout int) (kvstore.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700137
138 log.Infow("kv-store-type", log.Fields{"store": storeType})
139 switch storeType {
140 case "consul":
141 return kvstore.NewConsulClient(address, timeout)
142 case "etcd":
143 return kvstore.NewEtcdClient(address, timeout)
144 }
145 return nil, errors.New("unsupported-kv-store")
146}
147
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700148func newKafkaClient(clientType, host string, port int) (kafka.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700149
150 log.Infow("common-client-type", log.Fields{"client": clientType})
151 switch clientType {
152 case "sarama":
153 return kafka.NewSaramaClient(
154 kafka.Host(host),
155 kafka.Port(port),
156 kafka.ProducerReturnOnErrors(true),
157 kafka.ProducerReturnOnSuccess(true),
158 kafka.ProducerMaxRetries(6),
Abhilash S.L3b494632019-07-16 15:51:09 +0530159 kafka.ProducerRetryBackoff(time.Millisecond*30),
160 kafka.MetadatMaxRetries(15)), nil
cuilin20187b2a8c32019-03-26 19:52:28 -0700161 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700162
cuilin20187b2a8c32019-03-26 19:52:28 -0700163 return nil, errors.New("unsupported-client-type")
164}
165
166func (a *adapter) setKVClient() error {
167 addr := a.config.KVStoreHost + ":" + strconv.Itoa(a.config.KVStorePort)
168 client, err := newKVClient(a.config.KVStoreType, addr, a.config.KVStoreTimeout)
169 if err != nil {
170 a.kvClient = nil
171 log.Error(err)
172 return err
173 }
174 a.kvClient = client
175 return nil
176}
177
cuilin20187b2a8c32019-03-26 19:52:28 -0700178func (a *adapter) startInterContainerProxy(retries int) (*kafka.InterContainerProxy, error) {
179 log.Infow("starting-intercontainer-messaging-proxy", log.Fields{"host": a.config.KafkaAdapterHost,
180 "port": a.config.KafkaAdapterPort, "topic": a.config.Topic})
181 var err error
182 var kip *kafka.InterContainerProxy
183 if kip, err = kafka.NewInterContainerProxy(
184 kafka.InterContainerHost(a.config.KafkaAdapterHost),
185 kafka.InterContainerPort(a.config.KafkaAdapterPort),
186 kafka.MsgClient(a.kafkaClient),
187 kafka.DefaultTopic(&kafka.Topic{Name: a.config.Topic})); err != nil {
188 log.Errorw("fail-to-create-common-proxy", log.Fields{"error": err})
189 return nil, err
190 }
191 count := 0
192 for {
193 if err = kip.Start(); err != nil {
194 log.Warnw("error-starting-messaging-proxy", log.Fields{"error": err})
195 if retries == count {
196 return nil, err
197 }
198 count = +1
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700199 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700200 time.Sleep(2 * time.Second)
201 } else {
202 break
203 }
204 }
205
206 log.Info("common-messaging-proxy-created")
207 return kip, nil
208}
209
Devmalya Paulfb990a52019-07-09 10:01:49 -0400210func (a *adapter) startOpenOLT(ctx context.Context, kip *kafka.InterContainerProxy, cp *com.CoreProxy, ap *com.AdapterProxy, ep *com.EventProxy, onuNumber int, kvStoreHost string, kvStorePort int, KVStoreType string) (*ac.OpenOLT, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700211 log.Info("starting-open-olt")
212 var err error
Devmalya Paulfb990a52019-07-09 10:01:49 -0400213 sOLT := ac.NewOpenOLT(ctx, a.kip, cp, ap, ep, onuNumber, kvStoreHost, kvStorePort, KVStoreType)
cuilin20187b2a8c32019-03-26 19:52:28 -0700214
215 if err = sOLT.Start(ctx); err != nil {
216 log.Fatalw("error-starting-messaging-proxy", log.Fields{"error": err})
217 return nil, err
218 }
219
220 log.Info("open-olt-started")
221 return sOLT, nil
222}
223
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700224func (a *adapter) setupRequestHandler(coreInstanceID string, iadapter adapters.IAdapter) error {
cuilin20187b2a8c32019-03-26 19:52:28 -0700225 log.Info("setting-request-handler")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700226 requestProxy := com.NewRequestHandlerProxy(coreInstanceID, iadapter, a.coreProxy)
cuilin20187b2a8c32019-03-26 19:52:28 -0700227 if err := a.kip.SubscribeWithRequestHandlerInterface(kafka.Topic{Name: a.config.Topic}, requestProxy); err != nil {
228 log.Errorw("request-handler-setup-failed", log.Fields{"error": err})
229 return err
230
231 }
232 log.Info("request-handler-setup-done")
233 return nil
234}
235
236func (a *adapter) registerWithCore(retries int) error {
237 log.Info("registering-with-core")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400238 adapterDescription := &voltha.Adapter{Id: "openolt", // Unique name for the device type
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400239 Vendor: "VOLTHA OpenOLT",
240 Version: version.VersionInfo.Version}
Girish Gowdru0c588b22019-04-23 23:24:56 -0400241 types := []*voltha.DeviceType{{Id: "openolt",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700242 Adapter: "openolt", // Name of the adapter that handles device type
Girish Gowdru0c588b22019-04-23 23:24:56 -0400243 AcceptsBulkFlowUpdate: false, // Currently openolt adapter does not support bulk flow handling
244 AcceptsAddRemoveFlowUpdates: true}}
cuilin20187b2a8c32019-03-26 19:52:28 -0700245 deviceTypes := &voltha.DeviceTypes{Items: types}
246 count := 0
247 for {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700248 if err := a.coreProxy.RegisterAdapter(context.TODO(), adapterDescription, deviceTypes); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700249 log.Warnw("registering-with-core-failed", log.Fields{"error": err})
250 if retries == count {
251 return err
252 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700253 count++
254 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700255 time.Sleep(2 * time.Second)
256 } else {
257 break
258 }
259 }
260 log.Info("registered-with-core")
261 return nil
262}
263
264func waitForExit() int {
265 signalChannel := make(chan os.Signal, 1)
266 signal.Notify(signalChannel,
267 syscall.SIGHUP,
268 syscall.SIGINT,
269 syscall.SIGTERM,
270 syscall.SIGQUIT)
271
272 exitChannel := make(chan int)
273
274 go func() {
275 s := <-signalChannel
276 switch s {
277 case syscall.SIGHUP,
278 syscall.SIGINT,
279 syscall.SIGTERM,
280 syscall.SIGQUIT:
281 log.Infow("closing-signal-received", log.Fields{"signal": s})
282 exitChannel <- 0
283 default:
284 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
285 exitChannel <- 1
286 }
287 }()
288
289 code := <-exitChannel
290 return code
291}
292
293func printBanner() {
294 fmt.Println(" ____ ____ _ _______ ")
295 fmt.Println(" / _ \\ / __\\| | |__ __|")
296 fmt.Println(" | | | |_ __ ___ _ __ | | | | | | | ")
297 fmt.Println(" | | | | '_\\ / _\\ '_\\ | | | | | | | ")
298 fmt.Println(" | |__| | |_) | __/ | | || |__| | |____| | ")
299 fmt.Println(" \\____/| .__/\\___|_| |_|\\____/|______|_| ")
300 fmt.Println(" | | ")
301 fmt.Println(" |_| ")
302 fmt.Println(" ")
303}
304
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400305func printVersion() {
306 fmt.Println("VOLTHA OpenOLT Adapter")
307 fmt.Println(version.VersionInfo.String(" "))
308}
309
cuilin20187b2a8c32019-03-26 19:52:28 -0700310func main() {
311 start := time.Now()
312
313 cf := config.NewAdapterFlags()
314 cf.ParseCommandArguments()
315
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700316 // Setup logging
cuilin20187b2a8c32019-03-26 19:52:28 -0700317
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700318 // Setup default logger - applies for packages that do not have specific logger set
319 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceID": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700320 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
321 }
322
323 // Update all loggers (provisionned via init) with a common field
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700324 if err := log.UpdateAllLoggers(log.Fields{"instanceID": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700325 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
326 }
327
328 log.SetPackageLogLevel("github.com/opencord/voltha-go/adapters/common", log.DebugLevel)
329
330 defer log.CleanUp()
331
Matt Jeanneretf880eb62019-07-16 20:08:03 -0400332 // Print version / build information and exit
333 if cf.DisplayVersionOnly {
334 printVersion()
335 return
336 }
337
cuilin20187b2a8c32019-03-26 19:52:28 -0700338 // Print banner if specified
339 if cf.Banner {
340 printBanner()
341 }
342
343 log.Infow("config", log.Fields{"config": *cf})
344
345 ctx, cancel := context.WithCancel(context.Background())
346 defer cancel()
347
348 ad := newAdapter(cf)
349 go ad.start(ctx)
350
351 code := waitForExit()
352 log.Infow("received-a-closing-signal", log.Fields{"code": code})
353
354 // Cleanup before leaving
355 ad.stop()
356
357 elapsed := time.Since(start)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700358 log.Infow("run-time", log.Fields{"instanceID": ad.config.InstanceID, "time": elapsed / time.Second})
cuilin20187b2a8c32019-03-26 19:52:28 -0700359}