Mohamed Abukar | 2e78e42 | 2019-06-02 11:45:52 +0300 | [diff] [blame] | 1 | /* |
| 2 | ================================================================================== |
| 3 | Copyright (c) 2019 AT&T Intellectual Property. |
| 4 | Copyright (c) 2019 Nokia |
| 5 | |
| 6 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | you may not use this file except in compliance with the License. |
| 8 | You may obtain a copy of the License at |
| 9 | |
| 10 | http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | |
| 12 | Unless required by applicable law or agreed to in writing, software |
| 13 | distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | See the License for the specific language governing permissions and |
| 16 | limitations under the License. |
| 17 | ================================================================================== |
| 18 | */ |
| 19 | |
| 20 | package xapp |
| 21 | |
| 22 | import ( |
| 23 | "fmt" |
| 24 | "github.com/spf13/viper" |
| 25 | "net/http" |
Juha Hyttinen | 5406626 | 2020-09-16 10:37:28 +0300 | [diff] [blame] | 26 | "os" |
| 27 | "os/signal" |
| 28 | "sync/atomic" |
| 29 | "syscall" |
| 30 | "time" |
Mohamed Abukar | 2e78e42 | 2019-06-02 11:45:52 +0300 | [diff] [blame] | 31 | ) |
| 32 | |
Mohamed Abukar | 192518d | 2019-06-11 18:06:50 +0300 | [diff] [blame] | 33 | type ReadyCB func(interface{}) |
Juha Hyttinen | 5406626 | 2020-09-16 10:37:28 +0300 | [diff] [blame] | 34 | type ShutdownCB func() |
Mohamed Abukar | 349a098 | 2019-06-08 18:15:42 +0300 | [diff] [blame] | 35 | |
Mohamed Abukar | 2e78e42 | 2019-06-02 11:45:52 +0300 | [diff] [blame] | 36 | var ( |
| 37 | // XApp is an application instance |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 38 | Rmr *RMRClient |
| 39 | Sdl *SDLClient |
| 40 | Rnib *RNIBClient |
| 41 | Resource *Router |
| 42 | Metric *Metrics |
| 43 | Logger *Log |
| 44 | Config Configurator |
Mohamed Abukar | 5120ec1 | 2020-02-04 11:01:24 +0200 | [diff] [blame] | 45 | Subscription *Subscriber |
Mohamed Abukar | 8dcedb4 | 2020-03-10 13:20:56 +0200 | [diff] [blame] | 46 | Alarm *AlarmClient |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 47 | readyCb ReadyCB |
| 48 | readyCbParams interface{} |
Juha Hyttinen | 5406626 | 2020-09-16 10:37:28 +0300 | [diff] [blame] | 49 | shutdownCb ShutdownCB |
| 50 | shutdownFlag int32 |
| 51 | shutdownCnt int32 |
Mohamed Abukar | 2e78e42 | 2019-06-02 11:45:52 +0300 | [diff] [blame] | 52 | ) |
| 53 | |
Mohamed Abukar | 775722c | 2019-06-10 16:41:57 +0300 | [diff] [blame] | 54 | func IsReady() bool { |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 55 | return Rmr != nil && Rmr.IsReady() && Sdl != nil && Sdl.IsReady() |
Mohamed Abukar | 775722c | 2019-06-10 16:41:57 +0300 | [diff] [blame] | 56 | } |
| 57 | |
Mohamed Abukar | 192518d | 2019-06-11 18:06:50 +0300 | [diff] [blame] | 58 | func SetReadyCB(cb ReadyCB, params interface{}) { |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 59 | readyCb = cb |
| 60 | readyCbParams = params |
| 61 | } |
| 62 | |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 63 | func XappReadyCb(params interface{}) { |
| 64 | Alarm = NewAlarmClient(viper.GetString("moId"), viper.GetString("name")) |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 65 | if readyCb != nil { |
| 66 | readyCb(readyCbParams) |
| 67 | } |
Mohamed Abukar | 775722c | 2019-06-10 16:41:57 +0300 | [diff] [blame] | 68 | } |
| 69 | |
Juha Hyttinen | 5406626 | 2020-09-16 10:37:28 +0300 | [diff] [blame] | 70 | func SetShutdownCB(cb ShutdownCB) { |
| 71 | shutdownCb = cb |
| 72 | } |
| 73 | |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 74 | func InstallSignalHandler() { |
Juha Hyttinen | 5406626 | 2020-09-16 10:37:28 +0300 | [diff] [blame] | 75 | // |
| 76 | // Signal handlers to really exit program. |
| 77 | // shutdownCb can hang until application has |
| 78 | // made all needed gracefull shutdown actions |
| 79 | // hardcoded limit for shutdown is 20 seconds |
| 80 | // |
| 81 | interrupt := make(chan os.Signal, 1) |
| 82 | signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) |
| 83 | //signal handler function |
| 84 | go func() { |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 85 | for range interrupt { |
Juha Hyttinen | 5406626 | 2020-09-16 10:37:28 +0300 | [diff] [blame] | 86 | if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) { |
| 87 | // close function |
| 88 | go func() { |
| 89 | timeout := int(20) |
| 90 | sentry := make(chan struct{}) |
| 91 | defer close(sentry) |
| 92 | |
| 93 | // close callback |
| 94 | go func() { |
| 95 | if shutdownCb != nil { |
| 96 | shutdownCb() |
| 97 | } |
| 98 | sentry <- struct{}{} |
| 99 | }() |
| 100 | select { |
| 101 | case <-time.After(time.Duration(timeout) * time.Second): |
| 102 | Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout) |
| 103 | case <-sentry: |
| 104 | Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout) |
| 105 | } |
| 106 | os.Exit(0) |
| 107 | }() |
| 108 | } else { |
| 109 | newCnt := atomic.AddInt32(&shutdownCnt, 1) |
| 110 | Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5) |
| 111 | if newCnt >= 5 { |
| 112 | Logger.Info("xapp-frame shutdown forced exit") |
| 113 | os.Exit(0) |
| 114 | } |
| 115 | continue |
| 116 | } |
| 117 | |
| 118 | } |
| 119 | }() |
Mohamed Abukar | 2e78e42 | 2019-06-02 11:45:52 +0300 | [diff] [blame] | 120 | } |
| 121 | |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 122 | func init() { |
| 123 | // Load xapp configuration |
| 124 | Logger = LoadConfig() |
| 125 | |
Mohamed Abukar | 827a641 | 2020-11-12 10:02:41 +0200 | [diff] [blame^] | 126 | if viper.IsSet("controls.logger.level") { |
| 127 | Logger.SetLevel(viper.GetInt("controls.logger.level")) |
| 128 | } else { |
| 129 | Logger.SetLevel(viper.GetInt("logger.level")) |
| 130 | } |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 131 | Resource = NewRouter() |
| 132 | Config = Configurator{} |
| 133 | Metric = NewMetrics(viper.GetString("metrics.url"), viper.GetString("metrics.namespace"), Resource.router) |
| 134 | Subscription = NewSubscriber(viper.GetString("subscription.host"), viper.GetInt("subscription.timeout")) |
Mohamed Abukar | 827a641 | 2020-11-12 10:02:41 +0200 | [diff] [blame^] | 135 | Sdl = NewSDLClient(viper.GetString("controls.db.namespace")) |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 136 | Rnib = NewRNIBClient() |
| 137 | |
| 138 | InstallSignalHandler() |
| 139 | } |
| 140 | |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 141 | func RunWithParams(c MessageConsumer, sdlcheck bool) { |
| 142 | Rmr = NewRMRClient() |
Mohamed Abukar | b8b191f | 2020-11-07 11:22:56 +0200 | [diff] [blame] | 143 | Rmr.SetReadyCB(XappReadyCb, nil) |
| 144 | |
| 145 | host := fmt.Sprintf(":%d", GetPortData("http").Port) |
| 146 | go http.ListenAndServe(host, Resource.router) |
| 147 | Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host)) |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 148 | if sdlcheck { |
| 149 | Sdl.TestConnection() |
| 150 | } |
Mohamed Abukar | 2e78e42 | 2019-06-02 11:45:52 +0300 | [diff] [blame] | 151 | Rmr.Start(c) |
| 152 | } |
Juha Hyttinen | f49009a | 2019-11-26 10:28:14 +0200 | [diff] [blame] | 153 | |
| 154 | func Run(c MessageConsumer) { |
| 155 | RunWithParams(c, true) |
| 156 | } |