2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
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
10 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
34 "github.com/spf13/viper"
37 type ReadyCB func(interface{})
38 type ShutdownCB func()
41 // XApp is an application instance
49 Subscription *Subscriber
53 readyCbParams interface{}
60 return Rmr != nil && Rmr.IsReady() && Sdl != nil && Sdl.IsReady()
63 func SetReadyCB(cb ReadyCB, params interface{}) {
65 readyCbParams = params
68 func XappReadyCb(params interface{}) {
69 Alarm = NewAlarmClient(viper.GetString("moId"), viper.GetString("name"))
71 readyCb(readyCbParams)
75 func SetShutdownCB(cb ShutdownCB) {
79 func XappShutdownCb() {
80 if err := doDeregister(); err != nil {
81 Logger.Info("xApp deregistration failed: %v, terminating ungracefully!", err)
83 Logger.Info("xApp deregistration successfull!")
86 if shutdownCb != nil {
93 time.Sleep(5 * time.Second)
94 if !IsHealthProbeReady() {
95 Logger.Info("Application='%s' is not ready yet, waiting ...", viper.GetString("name"))
99 Logger.Debug("Application='%s' is now up and ready, continue with registration ...", viper.GetString("name"))
100 if err := doRegister(); err == nil {
101 Logger.Info("Registration done, proceeding with startup ...")
107 func getService(host, service string) string {
108 appnamespace := os.Getenv("APP_NAMESPACE")
109 if appnamespace == "" {
110 appnamespace = DEFAULT_XAPP_NS
113 svc := fmt.Sprintf(service, strings.ToUpper(appnamespace), strings.ToUpper(host))
114 url := strings.Split(os.Getenv(strings.Replace(svc, "-", "_", -1)), "//")
116 Logger.Info("getService: %+v %+v", svc, url)
123 func getPltNamespace(envName, defVal string) string {
124 pltnamespace := os.Getenv("PLT_NAMESPACE")
125 if pltnamespace == "" {
126 pltnamespace = defVal
132 func doPost(pltNs, url string, msg []byte, status int) error {
133 resp, err := http.Post(fmt.Sprintf(url, pltNs, pltNs), "application/json", bytes.NewBuffer(msg))
134 if err != nil || resp == nil || resp.StatusCode != status {
135 Logger.Info("http.Post to '%s' failed with error: %v", fmt.Sprintf(url, pltNs, pltNs), err)
138 Logger.Info("Post to '%s' done, status:%v", fmt.Sprintf(url, pltNs, pltNs), resp.Status)
143 func doRegister() error {
144 host, _ := os.Hostname()
145 xappname := viper.GetString("name")
146 xappversion := viper.GetString("version")
147 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
149 httpEp, rmrEp := getService(host, SERVICE_HTTP), getService(host, SERVICE_RMR)
150 if httpEp == "" || rmrEp == "" {
151 Logger.Warn("Couldn't resolve service endpoints: httpEp=%s rmrEp=%s", httpEp, rmrEp)
155 requestBody, err := json.Marshal(map[string]string{
157 "httpEndpoint": httpEp,
158 "rmrEndpoint": rmrEp,
159 "appInstanceName": xappname,
160 "appVersion": xappversion,
161 "configPath": CONFIG_PATH,
165 Logger.Error("json.Marshal failed with error: %v", err)
169 return doPost(pltNs, REGISTER_PATH, requestBody, http.StatusCreated)
172 func doDeregister() error {
173 if !IsHealthProbeReady() {
177 name, _ := os.Hostname()
178 xappname := viper.GetString("name")
179 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
181 requestBody, err := json.Marshal(map[string]string{
183 "appInstanceName": xappname,
187 Logger.Error("json.Marshal failed with error: %v", err)
191 return doPost(pltNs, DEREGISTER_PATH, requestBody, http.StatusNoContent)
194 func InstallSignalHandler() {
196 // Signal handlers to really exit program.
197 // shutdownCb can hang until application has
198 // made all needed gracefull shutdown actions
199 // hardcoded limit for shutdown is 20 seconds
201 interrupt := make(chan os.Signal, 1)
202 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
203 //signal handler function
205 for range interrupt {
206 if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) {
210 sentry := make(chan struct{})
219 case <-time.After(time.Duration(timeout) * time.Second):
220 Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout)
222 Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout)
227 newCnt := atomic.AddInt32(&shutdownCnt, 1)
228 Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5)
230 Logger.Info("xapp-frame shutdown forced exit")
241 // Load xapp configuration
242 Logger = LoadConfig()
244 if viper.IsSet("controls.logger.level") {
245 Logger.SetLevel(viper.GetInt("controls.logger.level"))
247 Logger.SetLevel(viper.GetInt("logger.level"))
250 if !viper.IsSet("controls.logger.noFormat") || !viper.GetBool("controls.logger.noFormat") {
254 Resource = NewRouter()
255 Config = Configurator{}
256 Metric = NewMetrics(viper.GetString("metrics.url"), viper.GetString("metrics.namespace"), Resource.router)
257 Subscription = NewSubscriber(viper.GetString("controls.subscription.host"), viper.GetInt("controls.subscription.timeout"))
258 Sdl = NewSDLClient(viper.GetString("controls.db.namespace"))
259 Rnib = NewRNIBClient()
262 InstallSignalHandler()
265 func RunWithParams(c MessageConsumer, sdlcheck bool) {
268 Rmr.SetReadyCB(XappReadyCb, nil)
270 host := fmt.Sprintf(":%d", GetPortData("http").Port)
271 go http.ListenAndServe(host, Resource.router)
272 Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host))
282 func Run(c MessageConsumer) {
283 RunWithParams(c, true)