blob: 519aedb9e549985c956243ba2ba3499d04fa0a1c [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"
27 "github.com/opencord/voltha-go/db/kvstore"
28 "github.com/opencord/voltha-go/kafka"
Girish Gowdru0c588b22019-04-23 23:24:56 -040029 ac "github.com/opencord/voltha-openolt-adapter/adaptercore"
30 "github.com/opencord/voltha-openolt-adapter/config"
manikkaraj kbf256be2019-03-25 00:13:48 +053031 ic "github.com/opencord/voltha-protos/go/inter_container"
32 "github.com/opencord/voltha-protos/go/voltha"
cuilin20187b2a8c32019-03-26 19:52:28 -070033 "os"
34 "os/signal"
35 "strconv"
36 "syscall"
37 "time"
38)
39
40type adapter struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070041 instanceID string
cuilin20187b2a8c32019-03-26 19:52:28 -070042 config *config.AdapterFlags
43 iAdapter adapters.IAdapter
44 kafkaClient kafka.Client
45 kvClient kvstore.Client
46 kip *kafka.InterContainerProxy
47 coreProxy *com.CoreProxy
48 adapterProxy *com.AdapterProxy
49 halted bool
50 exitChannel chan int
51 receiverChannels []<-chan *ic.InterContainerMessage
52}
53
54func init() {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070055 _, _ = log.AddPackage(log.JSON, log.DebugLevel, nil)
cuilin20187b2a8c32019-03-26 19:52:28 -070056}
57
58func newAdapter(cf *config.AdapterFlags) *adapter {
59 var a adapter
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070060 a.instanceID = cf.InstanceID
cuilin20187b2a8c32019-03-26 19:52:28 -070061 a.config = cf
62 a.halted = false
63 a.exitChannel = make(chan int, 1)
64 a.receiverChannels = make([]<-chan *ic.InterContainerMessage, 0)
65 return &a
66}
67
68func (a *adapter) start(ctx context.Context) {
69 log.Info("Starting Core Adapter components")
70 var err error
71
72 // Setup KV Client
73 log.Debugw("create-kv-client", log.Fields{"kvstore": a.config.KVStoreType})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070074 if err = a.setKVClient(); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -070075 log.Fatal("error-setting-kv-client")
76 }
77
78 // Setup Kafka Client
79 if a.kafkaClient, err = newKafkaClient("sarama", a.config.KafkaAdapterHost, a.config.KafkaAdapterPort); err != nil {
80 log.Fatal("Unsupported-common-client")
81 }
82
83 // Start the common InterContainer Proxy - retries indefinitely
84 if a.kip, err = a.startInterContainerProxy(-1); err != nil {
85 log.Fatal("error-starting-inter-container-proxy")
86 }
87
88 // Create the core proxy to handle requests to the Core
89 a.coreProxy = com.NewCoreProxy(a.kip, a.config.Topic, a.config.CoreTopic)
90
91 // Create the adaptor proxy to handle request between olt and onu
92 a.adapterProxy = com.NewAdapterProxy(a.kip, "brcm_openomci_onu", a.config.CoreTopic)
93
94 // Create the open OLT adapter
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070095 if a.iAdapter, err = a.startOpenOLT(ctx, a.kip, a.coreProxy, a.adapterProxy, a.config.OnuNumber,
96 a.config.KVStoreHost, a.config.KVStorePort, a.config.KVStoreType); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -070097 log.Fatal("error-starting-inter-container-proxy")
98 }
99
100 // Register the core request handler
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700101 if err = a.setupRequestHandler(a.instanceID, a.iAdapter); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700102 log.Fatal("error-setting-core-request-handler")
103 }
104
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700105 // Register this adapter to the Core - retries indefinitely
cuilin20187b2a8c32019-03-26 19:52:28 -0700106 if err = a.registerWithCore(-1); err != nil {
107 log.Fatal("error-registering-with-core")
108 }
109}
110
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700111func (a *adapter) stop() {
cuilin20187b2a8c32019-03-26 19:52:28 -0700112 // Stop leadership tracking
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700113 a.halted = true
cuilin20187b2a8c32019-03-26 19:52:28 -0700114
115 // send exit signal
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700116 a.exitChannel <- 0
cuilin20187b2a8c32019-03-26 19:52:28 -0700117
118 // Cleanup - applies only if we had a kvClient
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700119 if a.kvClient != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700120 // Release all reservations
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700121 if err := a.kvClient.ReleaseAllReservations(); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700122 log.Infow("fail-to-release-all-reservations", log.Fields{"error": err})
123 }
124 // Close the DB connection
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700125 a.kvClient.Close()
cuilin20187b2a8c32019-03-26 19:52:28 -0700126 }
127
128 // TODO: More cleanup
129}
130
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700131func newKVClient(storeType, address string, timeout int) (kvstore.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700132
133 log.Infow("kv-store-type", log.Fields{"store": storeType})
134 switch storeType {
135 case "consul":
136 return kvstore.NewConsulClient(address, timeout)
137 case "etcd":
138 return kvstore.NewEtcdClient(address, timeout)
139 }
140 return nil, errors.New("unsupported-kv-store")
141}
142
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700143func newKafkaClient(clientType, host string, port int) (kafka.Client, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700144
145 log.Infow("common-client-type", log.Fields{"client": clientType})
146 switch clientType {
147 case "sarama":
148 return kafka.NewSaramaClient(
149 kafka.Host(host),
150 kafka.Port(port),
151 kafka.ProducerReturnOnErrors(true),
152 kafka.ProducerReturnOnSuccess(true),
153 kafka.ProducerMaxRetries(6),
154 kafka.ProducerRetryBackoff(time.Millisecond*30)), nil
155 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700156
cuilin20187b2a8c32019-03-26 19:52:28 -0700157 return nil, errors.New("unsupported-client-type")
158}
159
160func (a *adapter) setKVClient() error {
161 addr := a.config.KVStoreHost + ":" + strconv.Itoa(a.config.KVStorePort)
162 client, err := newKVClient(a.config.KVStoreType, addr, a.config.KVStoreTimeout)
163 if err != nil {
164 a.kvClient = nil
165 log.Error(err)
166 return err
167 }
168 a.kvClient = client
169 return nil
170}
171
cuilin20187b2a8c32019-03-26 19:52:28 -0700172func (a *adapter) startInterContainerProxy(retries int) (*kafka.InterContainerProxy, error) {
173 log.Infow("starting-intercontainer-messaging-proxy", log.Fields{"host": a.config.KafkaAdapterHost,
174 "port": a.config.KafkaAdapterPort, "topic": a.config.Topic})
175 var err error
176 var kip *kafka.InterContainerProxy
177 if kip, err = kafka.NewInterContainerProxy(
178 kafka.InterContainerHost(a.config.KafkaAdapterHost),
179 kafka.InterContainerPort(a.config.KafkaAdapterPort),
180 kafka.MsgClient(a.kafkaClient),
181 kafka.DefaultTopic(&kafka.Topic{Name: a.config.Topic})); err != nil {
182 log.Errorw("fail-to-create-common-proxy", log.Fields{"error": err})
183 return nil, err
184 }
185 count := 0
186 for {
187 if err = kip.Start(); err != nil {
188 log.Warnw("error-starting-messaging-proxy", log.Fields{"error": err})
189 if retries == count {
190 return nil, err
191 }
192 count = +1
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700193 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700194 time.Sleep(2 * time.Second)
195 } else {
196 break
197 }
198 }
199
200 log.Info("common-messaging-proxy-created")
201 return kip, nil
202}
203
manikkaraj kbf256be2019-03-25 00:13:48 +0530204func (a *adapter) startOpenOLT(ctx context.Context, kip *kafka.InterContainerProxy, cp *com.CoreProxy, ap *com.AdapterProxy, onuNumber int, kvStoreHost string, kvStorePort int, KVStoreType string) (*ac.OpenOLT, error) {
cuilin20187b2a8c32019-03-26 19:52:28 -0700205 log.Info("starting-open-olt")
206 var err error
manikkaraj kbf256be2019-03-25 00:13:48 +0530207 sOLT := ac.NewOpenOLT(ctx, a.kip, cp, ap, onuNumber, kvStoreHost, kvStorePort, KVStoreType)
cuilin20187b2a8c32019-03-26 19:52:28 -0700208
209 if err = sOLT.Start(ctx); err != nil {
210 log.Fatalw("error-starting-messaging-proxy", log.Fields{"error": err})
211 return nil, err
212 }
213
214 log.Info("open-olt-started")
215 return sOLT, nil
216}
217
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700218func (a *adapter) setupRequestHandler(coreInstanceID string, iadapter adapters.IAdapter) error {
cuilin20187b2a8c32019-03-26 19:52:28 -0700219 log.Info("setting-request-handler")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700220 requestProxy := com.NewRequestHandlerProxy(coreInstanceID, iadapter, a.coreProxy)
cuilin20187b2a8c32019-03-26 19:52:28 -0700221 if err := a.kip.SubscribeWithRequestHandlerInterface(kafka.Topic{Name: a.config.Topic}, requestProxy); err != nil {
222 log.Errorw("request-handler-setup-failed", log.Fields{"error": err})
223 return err
224
225 }
226 log.Info("request-handler-setup-done")
227 return nil
228}
229
230func (a *adapter) registerWithCore(retries int) error {
231 log.Info("registering-with-core")
Girish Gowdru0c588b22019-04-23 23:24:56 -0400232 adapterDescription := &voltha.Adapter{Id: "openolt", // Unique name for the device type
233 Vendor: "simulation Enterprise Inc"}
234 types := []*voltha.DeviceType{{Id: "openolt",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700235 Adapter: "openolt", // Name of the adapter that handles device type
Girish Gowdru0c588b22019-04-23 23:24:56 -0400236 AcceptsBulkFlowUpdate: false, // Currently openolt adapter does not support bulk flow handling
237 AcceptsAddRemoveFlowUpdates: true}}
cuilin20187b2a8c32019-03-26 19:52:28 -0700238 deviceTypes := &voltha.DeviceTypes{Items: types}
239 count := 0
240 for {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700241 if err := a.coreProxy.RegisterAdapter(context.TODO(), adapterDescription, deviceTypes); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700242 log.Warnw("registering-with-core-failed", log.Fields{"error": err})
243 if retries == count {
244 return err
245 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700246 count++
247 // Take a nap before retrying
cuilin20187b2a8c32019-03-26 19:52:28 -0700248 time.Sleep(2 * time.Second)
249 } else {
250 break
251 }
252 }
253 log.Info("registered-with-core")
254 return nil
255}
256
257func waitForExit() int {
258 signalChannel := make(chan os.Signal, 1)
259 signal.Notify(signalChannel,
260 syscall.SIGHUP,
261 syscall.SIGINT,
262 syscall.SIGTERM,
263 syscall.SIGQUIT)
264
265 exitChannel := make(chan int)
266
267 go func() {
268 s := <-signalChannel
269 switch s {
270 case syscall.SIGHUP,
271 syscall.SIGINT,
272 syscall.SIGTERM,
273 syscall.SIGQUIT:
274 log.Infow("closing-signal-received", log.Fields{"signal": s})
275 exitChannel <- 0
276 default:
277 log.Infow("unexpected-signal-received", log.Fields{"signal": s})
278 exitChannel <- 1
279 }
280 }()
281
282 code := <-exitChannel
283 return code
284}
285
286func printBanner() {
287 fmt.Println(" ____ ____ _ _______ ")
288 fmt.Println(" / _ \\ / __\\| | |__ __|")
289 fmt.Println(" | | | |_ __ ___ _ __ | | | | | | | ")
290 fmt.Println(" | | | | '_\\ / _\\ '_\\ | | | | | | | ")
291 fmt.Println(" | |__| | |_) | __/ | | || |__| | |____| | ")
292 fmt.Println(" \\____/| .__/\\___|_| |_|\\____/|______|_| ")
293 fmt.Println(" | | ")
294 fmt.Println(" |_| ")
295 fmt.Println(" ")
296}
297
298func main() {
299 start := time.Now()
300
301 cf := config.NewAdapterFlags()
302 cf.ParseCommandArguments()
303
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700304 // Setup logging
cuilin20187b2a8c32019-03-26 19:52:28 -0700305
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700306 // Setup default logger - applies for packages that do not have specific logger set
307 if _, err := log.SetDefaultLogger(log.JSON, cf.LogLevel, log.Fields{"instanceID": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700308 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
309 }
310
311 // Update all loggers (provisionned via init) with a common field
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700312 if err := log.UpdateAllLoggers(log.Fields{"instanceID": cf.InstanceID}); err != nil {
cuilin20187b2a8c32019-03-26 19:52:28 -0700313 log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
314 }
315
316 log.SetPackageLogLevel("github.com/opencord/voltha-go/adapters/common", log.DebugLevel)
317
318 defer log.CleanUp()
319
320 // Print banner if specified
321 if cf.Banner {
322 printBanner()
323 }
324
325 log.Infow("config", log.Fields{"config": *cf})
326
327 ctx, cancel := context.WithCancel(context.Background())
328 defer cancel()
329
330 ad := newAdapter(cf)
331 go ad.start(ctx)
332
333 code := waitForExit()
334 log.Infow("received-a-closing-signal", log.Fields{"code": code})
335
336 // Cleanup before leaving
337 ad.stop()
338
339 elapsed := time.Since(start)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700340 log.Infow("run-time", log.Fields{"instanceID": ad.config.InstanceID, "time": elapsed / time.Second})
cuilin20187b2a8c32019-03-26 19:52:28 -0700341}