blob: 65c284561ae5c4b1592926145b4a07205b3291b5 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14 */
15
16package main
17
18import (
19 "context"
20 "errors"
21 "fmt"
22 "os"
23 "os/signal"
24 "syscall"
25 "time"
26
27 pc "voltha-go-controller/infra/pprofcontroller"
28
29 "voltha-go-controller/database"
30 db "voltha-go-controller/database"
31 app "voltha-go-controller/internal/pkg/application"
32 "voltha-go-controller/internal/pkg/controller"
33 "voltha-go-controller/internal/pkg/vpagent"
34 "voltha-go-controller/voltha-go-controller/nbi"
35
36 "github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
Tinoj Joseph1d108322022-07-13 10:07:39 +053037 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053038 "github.com/opencord/voltha-lib-go/v7/pkg/probe"
39)
40
41// VgcInfo structure
42type VgcInfo struct {
43 Name string
44 Version string
45 kvClient kvstore.Client
46}
47
48var vgcInfo = VgcInfo{Name: "VGC"}
49var dbHandler *database.Database
50
51func printBanner() {
52 fmt.Println("## ## ###### ###### ")
53 fmt.Println("## ## ## ## ## ## ")
54 fmt.Println("## ## ## ## ")
55 fmt.Println("## ## ## #### ## ")
56 fmt.Println(" ## ## ## ## ## ")
57 fmt.Println(" ## ## ## ## ## ## ")
58 fmt.Println(" ### ###### ###### ")
59}
60
61func stop(ctx context.Context, kvClient kvstore.Client, vpa *vpagent.VPAgent) {
62 // Cleanup - applies only if we had a kvClient
63 if kvClient != nil {
64 // Release all reservations
65 if err := kvClient.ReleaseAllReservations(ctx); err != nil {
66 logger.Infow(ctx, "fail-to-release-all-reservations", log.Fields{"error": err})
67 }
68 // Close the DB connection
69 kvClient.Close(ctx)
70 }
71 //Closet voltha connection
72 vpa.CloseConnectionToVoltha()
73
74}
75
76func newKVClient(storeType, address string, timeout int) (kvstore.Client, error) {
77 logger.Infow(ctx, "kv-store-type", log.Fields{"store": storeType})
78 switch storeType {
79 case "redis":
80 return kvstore.NewRedisClient(address, time.Duration(timeout), false)
81 }
82 return nil, errors.New("unsupported-kv-store")
83}
84
85// waitUntilKVStoreReachableOrMaxTries will wait until it can connect to a KV store or until maxtries has been reached
86func waitUntilKVStoreReachableOrMaxTries(ctx context.Context, config *VGCFlags) error {
87 count := 0
88 for {
89 if !vgcInfo.kvClient.IsConnectionUp(ctx) {
90 logger.Infow(ctx, "KV-store-unreachable", log.Fields{"KVStoreType": config.KVStoreType, "Address": config.KVStoreEndPoint})
91 if config.ConnectionMaxRetries != -1 {
92 if count >= config.ConnectionMaxRetries {
93 logger.Errorw(ctx, "kv store unreachable", log.Fields{})
94 return errors.New("kv store unreachable")
95 }
96 }
97 count++
98 // Take a nap before retrying
99 time.Sleep(time.Duration(config.ConnectionRetryDelay) * time.Second)
100 logger.Infow(ctx, "retry-KV-store-connectivity", log.Fields{"retryCount": count,
101 "maxRetries": config.ConnectionMaxRetries, "retryInterval": config.ConnectionRetryDelay})
102
103 } else {
104 break
105 }
106 }
107 return nil
108}
109
110func main() {
111 // Enviornment variables processing
112 config := newVGCFlags()
113 config.parseEnvironmentVariables()
114
115 if config.Banner {
116 printBanner()
117 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530118 // Create a context adding the status update channel
119 p := &probe.Probe{}
120 ctx := context.WithValue(context.Background(), probe.ProbeContextKey, p)
121
Naveen Sampath04696f72022-06-13 15:19:14 +0530122
123 pc.Init()
124
125 // Setup logging for the program
126 // Read the loglevel configured first
127 // Setup default logger - applies for packages that do not have specific logger set
128 var logLevel log.LogLevel
129 var err error
130 if logLevel, err = log.StringToLogLevel(config.LogLevel); err != nil {
131 logLevel = log.DebugLevel
132 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530133 if err := log.SetDefaultLogger(ctx, int(logLevel), log.Fields{"instanceId": config.InstanceID}); err != nil {
134 logger.With(ctx, log.Fields{"error": err}, "Cannot setup logging")
135 }
136
Naveen Sampath04696f72022-06-13 15:19:14 +0530137 // Update all loggers (provisionned via init) with a common field
138 if err := log.UpdateAllLoggers(log.Fields{"instanceId": config.InstanceID}); err != nil {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530139 logger.With(ctx, log.Fields{"error": err}, "Cannot setup logging")
Naveen Sampath04696f72022-06-13 15:19:14 +0530140 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530141 log.SetAllLogLevel(int(logLevel))
Naveen Sampath04696f72022-06-13 15:19:14 +0530142
143 if vgcInfo.kvClient, err = newKVClient(config.KVStoreType, config.KVStoreEndPoint, config.KVStoreTimeout); err != nil {
144 logger.Errorw(ctx, "KVClient Establishment Failure", log.Fields{"Reason": err})
145 }
146
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530147 if dbHandler, err = db.Initialize(ctx, config.KVStoreType, config.KVStoreEndPoint, config.KVStoreTimeout); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530148 logger.Errorw(ctx, "unable-to-connect-to-db", log.Fields{"error": err})
149 return
150 }
151
152 db.SetDatabase(dbHandler)
153 logger.Infow(ctx, "verifying-KV-store-connectivity", log.Fields{"host": config.KVStoreHost,
154 "port": config.KVStorePort, "retries": config.ConnectionMaxRetries,
155 "retryInterval": config.ConnectionRetryDelay})
156
Naveen Sampath04696f72022-06-13 15:19:14 +0530157 err = waitUntilKVStoreReachableOrMaxTries(ctx, config)
158 if err != nil {
159 logger.Fatalw(ctx, "Unable-to-connect-to-KV-store", log.Fields{"KVStoreType": config.KVStoreType, "Address": config.KVStoreEndPoint})
160 }
161
162 logger.Info(ctx, "KV-store-reachable")
163 //Read if log-level is stored in DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530164 if logLevel, err := dbHandler.Get(ctx, db.GetKeyPath(db.LogLevelPath)); err == nil {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530165 logger.Infow(ctx, "Read log-level from db", log.Fields{"logLevel": logLevel})
Naveen Sampath04696f72022-06-13 15:19:14 +0530166 storedLogLevel, _ := log.StringToLogLevel(logLevel)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530167 log.SetAllLogLevel(int(storedLogLevel))
168 log.SetDefaultLogLevel(int(storedLogLevel))
Naveen Sampath04696f72022-06-13 15:19:14 +0530169 }
170
171 // Check if Data Migration is required
172 // Migration has to be done before Initialzing the Kafka
173 if app.CheckIfMigrationRequired(ctx) {
174 logger.Debug(ctx, "Migration Initiated")
175 app.InitiateDataMigration(ctx)
176 }
177
178 defer func() {
179 err := log.CleanUp()
180 if err != nil {
181 logger.Errorw(ctx, "unable-to-flush-any-buffered-log-entries", log.Fields{"error": err})
182 }
183 }()
184
185 // TODO: Wrap it up properly and monitor the KV store to check for faults
186
187 /*
188 * Create and start the liveness and readiness container management probes. This
189 * is done in the main function so just in case the main starts multiple other
190 * objects there can be a single probe end point for the process.
191 */
192 go p.ListenAndServe(ctx, config.ProbeEndPoint)
193
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530194 app.GetApplication().ReadAllFromDb(ctx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530195 app.GetApplication().InitStaticConfig()
196 app.GetApplication().SetVendorID(config.VendorID)
197 ofca := controller.NewController(ctx, app.GetApplication())
Tinoj Josephaf37ce82022-12-28 11:59:43 +0530198 controller.GetController().SetDeviceTableSyncDuration(config.DeviceSyncDuration)
Naveen Sampath04696f72022-06-13 15:19:14 +0530199 vpa, err1 := vpagent.NewVPAgent(&vpagent.VPAgent{
200 VolthaAPIEndPoint: config.VolthaAPIEndPoint,
201 DeviceListRefreshInterval: time.Duration(config.DeviceListRefreshInterval) * time.Second,
202 ConnectionMaxRetries: config.ConnectionMaxRetries,
203 ConnectionRetryDelay: time.Duration(config.ConnectionRetryDelay) * time.Second,
204 VPClientAgent: ofca,
205 })
206 if err1 != nil {
207 logger.Fatalw(ctx, "failed-to-create-vpagent",
208 log.Fields{
209 "error": err})
210 }
211 // starts go routine which verifies dhcp server connectivity for requests
212 app.StartDhcpServerHandler()
213 logger.Error(ctx, "Trigger Rest Server...")
214 go nbi.RestStart()
215 go vpa.Run(ctx)
216 //FIXME: Need to enhance CLI to use in docker environment
217 //go ProcessCli()
218 //go handler.MsgHandler()
219 //go app.StartCollector()
220 waitForExit()
221 app.StopTimer()
222 stop(ctx, vgcInfo.kvClient, vpa)
223}
224
225func waitForExit() int {
226 signalChannel := make(chan os.Signal, 1)
227 signal.Notify(signalChannel,
228 syscall.SIGHUP,
229 syscall.SIGINT,
230 syscall.SIGTERM,
231 syscall.SIGQUIT)
232
233 exitChannel := make(chan int)
234
235 go func() {
236 s := <-signalChannel
237 switch s {
238 case syscall.SIGHUP,
239 syscall.SIGINT,
240 syscall.SIGTERM,
241 syscall.SIGQUIT:
242 logger.Infow(ctx, "closing-signal-received", log.Fields{"signal": s})
243 exitChannel <- 0
244 default:
245 logger.Infow(ctx, "unexpected-signal-received", log.Fields{"signal": s})
246 exitChannel <- 1
247 }
248 }()
249
250 code := <-exitChannel
251 return code
252}