blob: 1b8d3e3cc394e347ffeb5602c0488a34c5753fd1 [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
Tinoj Joseph1d108322022-07-13 10:07:39 +053036 "voltha-go-controller/log"
Akash Sonidedc8ee2023-03-03 11:51:49 +053037
38 "github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
Naveen Sampath04696f72022-06-13 15:19:14 +053039 "github.com/opencord/voltha-lib-go/v7/pkg/probe"
40)
41
42// VgcInfo structure
43type VgcInfo struct {
vinokuma926cb3e2023-03-29 11:41:06 +053044 kvClient kvstore.Client
Naveen Sampath04696f72022-06-13 15:19:14 +053045 Name string
46 Version string
Naveen Sampath04696f72022-06-13 15:19:14 +053047}
48
49var vgcInfo = VgcInfo{Name: "VGC"}
50var dbHandler *database.Database
51
52func printBanner() {
53 fmt.Println("## ## ###### ###### ")
54 fmt.Println("## ## ## ## ## ## ")
55 fmt.Println("## ## ## ## ")
56 fmt.Println("## ## ## #### ## ")
57 fmt.Println(" ## ## ## ## ## ")
58 fmt.Println(" ## ## ## ## ## ## ")
59 fmt.Println(" ### ###### ###### ")
60}
61
62func stop(ctx context.Context, kvClient kvstore.Client, vpa *vpagent.VPAgent) {
63 // Cleanup - applies only if we had a kvClient
64 if kvClient != nil {
65 // Release all reservations
66 if err := kvClient.ReleaseAllReservations(ctx); err != nil {
67 logger.Infow(ctx, "fail-to-release-all-reservations", log.Fields{"error": err})
68 }
69 // Close the DB connection
70 kvClient.Close(ctx)
71 }
72 //Closet voltha connection
73 vpa.CloseConnectionToVoltha()
Naveen Sampath04696f72022-06-13 15:19:14 +053074}
75
Akash Sonidedc8ee2023-03-03 11:51:49 +053076func newKVClient(ctx context.Context, storeType, address string, timeout int) (kvstore.Client, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +053077 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)
Akash Sonidedc8ee2023-03-03 11:51:49 +053081 case "etcd":
82 return kvstore.NewEtcdClient(ctx, address, time.Duration(timeout), log.ErrorLevel)
Naveen Sampath04696f72022-06-13 15:19:14 +053083 }
84 return nil, errors.New("unsupported-kv-store")
85}
86
87// waitUntilKVStoreReachableOrMaxTries will wait until it can connect to a KV store or until maxtries has been reached
88func waitUntilKVStoreReachableOrMaxTries(ctx context.Context, config *VGCFlags) error {
89 count := 0
90 for {
91 if !vgcInfo.kvClient.IsConnectionUp(ctx) {
92 logger.Infow(ctx, "KV-store-unreachable", log.Fields{"KVStoreType": config.KVStoreType, "Address": config.KVStoreEndPoint})
93 if config.ConnectionMaxRetries != -1 {
94 if count >= config.ConnectionMaxRetries {
95 logger.Errorw(ctx, "kv store unreachable", log.Fields{})
96 return errors.New("kv store unreachable")
97 }
98 }
99 count++
100 // Take a nap before retrying
101 time.Sleep(time.Duration(config.ConnectionRetryDelay) * time.Second)
102 logger.Infow(ctx, "retry-KV-store-connectivity", log.Fields{"retryCount": count,
103 "maxRetries": config.ConnectionMaxRetries, "retryInterval": config.ConnectionRetryDelay})
Naveen Sampath04696f72022-06-13 15:19:14 +0530104 } else {
105 break
106 }
107 }
108 return nil
109}
110
111func main() {
vinokuma926cb3e2023-03-29 11:41:06 +0530112 // Environment variables processing
Naveen Sampath04696f72022-06-13 15:19:14 +0530113 config := newVGCFlags()
114 config.parseEnvironmentVariables()
115
116 if config.Banner {
117 printBanner()
118 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530119 // Create a context adding the status update channel
120 p := &probe.Probe{}
vinokuma926cb3e2023-03-29 11:41:06 +0530121 ctx = context.WithValue(context.Background(), probe.ProbeContextKey, p)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530122
Naveen Sampath04696f72022-06-13 15:19:14 +0530123 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
vinokuma926cb3e2023-03-29 11:41:06 +0530128 var logLevel log.LevelLog
Naveen Sampath04696f72022-06-13 15:19:14 +0530129 var err error
vinokuma926cb3e2023-03-29 11:41:06 +0530130 var dblogLevel string
Naveen Sampath04696f72022-06-13 15:19:14 +0530131 if logLevel, err = log.StringToLogLevel(config.LogLevel); err != nil {
132 logLevel = log.DebugLevel
133 }
vinokuma926cb3e2023-03-29 11:41:06 +0530134 if err = log.SetDefaultLogger(ctx, int(logLevel), log.Fields{"instanceId": config.InstanceID}); err != nil {
Akash Sonidedc8ee2023-03-03 11:51:49 +0530135 logger.With(ctx, log.Fields{"error": err}, "Cannot setup logging")
136 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530137
Naveen Sampath04696f72022-06-13 15:19:14 +0530138 // Update all loggers (provisionned via init) with a common field
vinokuma926cb3e2023-03-29 11:41:06 +0530139 if err = log.UpdateAllLoggers(log.Fields{"instanceId": config.InstanceID}); err != nil {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530140 logger.With(ctx, log.Fields{"error": err}, "Cannot setup logging")
Naveen Sampath04696f72022-06-13 15:19:14 +0530141 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530142 log.SetAllLogLevel(int(logLevel))
Naveen Sampath04696f72022-06-13 15:19:14 +0530143
Akash Sonidedc8ee2023-03-03 11:51:49 +0530144 if vgcInfo.kvClient, err = newKVClient(ctx, config.KVStoreType, config.KVStoreEndPoint, config.KVStoreTimeout); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530145 logger.Errorw(ctx, "KVClient Establishment Failure", log.Fields{"Reason": err})
146 }
147
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530148 if dbHandler, err = db.Initialize(ctx, config.KVStoreType, config.KVStoreEndPoint, config.KVStoreTimeout); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530149 logger.Errorw(ctx, "unable-to-connect-to-db", log.Fields{"error": err})
150 return
151 }
152
153 db.SetDatabase(dbHandler)
154 logger.Infow(ctx, "verifying-KV-store-connectivity", log.Fields{"host": config.KVStoreHost,
155 "port": config.KVStorePort, "retries": config.ConnectionMaxRetries,
156 "retryInterval": config.ConnectionRetryDelay})
157
Naveen Sampath04696f72022-06-13 15:19:14 +0530158 err = waitUntilKVStoreReachableOrMaxTries(ctx, config)
159 if err != nil {
160 logger.Fatalw(ctx, "Unable-to-connect-to-KV-store", log.Fields{"KVStoreType": config.KVStoreType, "Address": config.KVStoreEndPoint})
161 }
162
163 logger.Info(ctx, "KV-store-reachable")
164 //Read if log-level is stored in DB
vinokuma926cb3e2023-03-29 11:41:06 +0530165 if dblogLevel, err = dbHandler.Get(ctx, db.GetKeyPath(db.LogLevelPath)); err == nil {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530166 logger.Infow(ctx, "Read log-level from db", log.Fields{"logLevel": logLevel})
vinokuma926cb3e2023-03-29 11:41:06 +0530167 storedLogLevel, _ := log.StringToLogLevel(dblogLevel)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530168 log.SetAllLogLevel(int(storedLogLevel))
169 log.SetDefaultLogLevel(int(storedLogLevel))
Naveen Sampath04696f72022-06-13 15:19:14 +0530170 }
171
172 // Check if Data Migration is required
173 // Migration has to be done before Initialzing the Kafka
174 if app.CheckIfMigrationRequired(ctx) {
175 logger.Debug(ctx, "Migration Initiated")
176 app.InitiateDataMigration(ctx)
177 }
178
179 defer func() {
vinokuma926cb3e2023-03-29 11:41:06 +0530180 err = log.CleanUp()
Naveen Sampath04696f72022-06-13 15:19:14 +0530181 if err != nil {
182 logger.Errorw(ctx, "unable-to-flush-any-buffered-log-entries", log.Fields{"error": err})
183 }
184 }()
185
186 // TODO: Wrap it up properly and monitor the KV store to check for faults
187
188 /*
189 * Create and start the liveness and readiness container management probes. This
190 * is done in the main function so just in case the main starts multiple other
191 * objects there can be a single probe end point for the process.
192 */
193 go p.ListenAndServe(ctx, config.ProbeEndPoint)
194
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530195 app.GetApplication().ReadAllFromDb(ctx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530196 app.GetApplication().InitStaticConfig()
197 app.GetApplication().SetVendorID(config.VendorID)
198 ofca := controller.NewController(ctx, app.GetApplication())
Tinoj Josephaf37ce82022-12-28 11:59:43 +0530199 controller.GetController().SetDeviceTableSyncDuration(config.DeviceSyncDuration)
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530200 controller.GetController().SetMaxFlowRetryDuration(config.MaxFlowRetryDuration)
201 controller.GetController().SetMaxFlowRetryAttempts()
Naveen Sampath04696f72022-06-13 15:19:14 +0530202 vpa, err1 := vpagent.NewVPAgent(&vpagent.VPAgent{
203 VolthaAPIEndPoint: config.VolthaAPIEndPoint,
204 DeviceListRefreshInterval: time.Duration(config.DeviceListRefreshInterval) * time.Second,
205 ConnectionMaxRetries: config.ConnectionMaxRetries,
206 ConnectionRetryDelay: time.Duration(config.ConnectionRetryDelay) * time.Second,
207 VPClientAgent: ofca,
208 })
209 if err1 != nil {
210 logger.Fatalw(ctx, "failed-to-create-vpagent",
211 log.Fields{
212 "error": err})
213 }
214 // starts go routine which verifies dhcp server connectivity for requests
215 app.StartDhcpServerHandler()
216 logger.Error(ctx, "Trigger Rest Server...")
217 go nbi.RestStart()
218 go vpa.Run(ctx)
219 //FIXME: Need to enhance CLI to use in docker environment
220 //go ProcessCli()
221 //go handler.MsgHandler()
222 //go app.StartCollector()
223 waitForExit()
224 app.StopTimer()
225 stop(ctx, vgcInfo.kvClient, vpa)
226}
227
228func waitForExit() int {
229 signalChannel := make(chan os.Signal, 1)
230 signal.Notify(signalChannel,
231 syscall.SIGHUP,
232 syscall.SIGINT,
233 syscall.SIGTERM,
234 syscall.SIGQUIT)
235
236 exitChannel := make(chan int)
237
238 go func() {
239 s := <-signalChannel
240 switch s {
241 case syscall.SIGHUP,
242 syscall.SIGINT,
243 syscall.SIGTERM,
244 syscall.SIGQUIT:
245 logger.Infow(ctx, "closing-signal-received", log.Fields{"signal": s})
246 exitChannel <- 0
247 default:
248 logger.Infow(ctx, "unexpected-signal-received", log.Fields{"signal": s})
249 exitChannel <- 1
250 }
251 }()
252
253 code := <-exitChannel
254 return code
255}