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 ==================================================================================
35 "github.com/spf13/viper"
38 // For testing purpose go version 1.13 ->
44 type ReadyCB func(interface{})
45 type ShutdownCB func()
48 // XApp is an application instance
51 SdlStorage *SDLStorage
57 Subscription *Subscriber
61 readyCbParams interface{}
68 return Rmr != nil && Rmr.IsReady() && SdlStorage != nil && SdlStorage.IsReady()
71 func SetReadyCB(cb ReadyCB, params interface{}) {
73 readyCbParams = params
76 func XappReadyCb(params interface{}) {
77 Alarm = NewAlarmClient(viper.GetString("moId"), viper.GetString("name"))
79 readyCb(readyCbParams)
83 func SetShutdownCB(cb ShutdownCB) {
87 func XappShutdownCb() {
88 if err := doDeregister(); err != nil {
89 Logger.Info("xApp deregistration failed: %v, terminating ungracefully!", err)
91 Logger.Info("xApp deregistration successfull!")
94 if shutdownCb != nil {
101 time.Sleep(5 * time.Second)
102 if !IsHealthProbeReady() {
103 Logger.Info("Application='%s' is not ready yet, waiting ...", viper.GetString("name"))
107 Logger.Debug("Application='%s' is now up and ready, continue with registration ...", viper.GetString("name"))
108 if err := doRegister(); err == nil {
109 Logger.Info("Registration done, proceeding with startup ...")
115 func getService(host, service string) string {
116 appnamespace := os.Getenv("APP_NAMESPACE")
117 if appnamespace == "" {
118 appnamespace = DEFAULT_XAPP_NS
121 svc := fmt.Sprintf(service, strings.ToUpper(appnamespace), strings.ToUpper(host))
122 url := strings.Split(os.Getenv(strings.Replace(svc, "-", "_", -1)), "//")
124 Logger.Info("getService: %+v %+v", svc, url)
131 func getPltNamespace(envName, defVal string) string {
132 pltnamespace := os.Getenv("PLT_NAMESPACE")
133 if pltnamespace == "" {
134 pltnamespace = defVal
140 func doPost(pltNs, url string, msg []byte, status int) error {
141 resp, err := http.Post(fmt.Sprintf(url, pltNs, pltNs), "application/json", bytes.NewBuffer(msg))
142 if err != nil || resp == nil || resp.StatusCode != status {
143 Logger.Info("http.Post to '%s' failed with error: %v", fmt.Sprintf(url, pltNs, pltNs), err)
146 Logger.Info("Post to '%s' done, status:%v", fmt.Sprintf(url, pltNs, pltNs), resp.Status)
151 func doRegister() error {
152 host, _ := os.Hostname()
153 xappname := viper.GetString("name")
154 xappversion := viper.GetString("version")
155 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
157 httpEp, rmrEp := getService(host, SERVICE_HTTP), getService(host, SERVICE_RMR)
158 if httpEp == "" || rmrEp == "" {
159 Logger.Warn("Couldn't resolve service endpoints: httpEp=%s rmrEp=%s", httpEp, rmrEp)
163 requestBody, err := json.Marshal(map[string]string{
165 "httpEndpoint": httpEp,
166 "rmrEndpoint": rmrEp,
167 "appInstanceName": xappname,
168 "appVersion": xappversion,
169 "configPath": CONFIG_PATH,
173 Logger.Error("json.Marshal failed with error: %v", err)
177 return doPost(pltNs, REGISTER_PATH, requestBody, http.StatusCreated)
180 func doDeregister() error {
181 if !IsHealthProbeReady() {
185 name, _ := os.Hostname()
186 xappname := viper.GetString("name")
187 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
189 requestBody, err := json.Marshal(map[string]string{
191 "appInstanceName": xappname,
195 Logger.Error("json.Marshal failed with error: %v", err)
199 return doPost(pltNs, DEREGISTER_PATH, requestBody, http.StatusNoContent)
202 func InstallSignalHandler() {
204 // Signal handlers to really exit program.
205 // shutdownCb can hang until application has
206 // made all needed gracefull shutdown actions
207 // hardcoded limit for shutdown is 20 seconds
209 interrupt := make(chan os.Signal, 1)
210 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
211 //signal handler function
213 for range interrupt {
214 if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) {
218 sentry := make(chan struct{})
227 case <-time.After(time.Duration(timeout) * time.Second):
228 Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout)
230 Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout)
235 newCnt := atomic.AddInt32(&shutdownCnt, 1)
236 Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5)
238 Logger.Info("xapp-frame shutdown forced exit")
249 // Load xapp configuration
250 Logger = LoadConfig()
252 if viper.IsSet("controls.logger.level") {
253 Logger.SetLevel(viper.GetInt("controls.logger.level"))
255 Logger.SetLevel(viper.GetInt("logger.level"))
258 if !viper.IsSet("controls.logger.noFormat") || !viper.GetBool("controls.logger.noFormat") {
262 Resource = NewRouter()
263 Config = Configurator{}
264 Metric = NewMetrics(viper.GetString("metrics.url"), viper.GetString("metrics.namespace"), Resource.router)
265 Subscription = NewSubscriber(viper.GetString("controls.subscription.host"), viper.GetInt("controls.subscription.timeout"))
266 SdlStorage = NewSdlStorage()
267 Sdl = NewSDLClient(viper.GetString("controls.db.namespace"))
268 Rnib = NewRNIBClient()
271 InstallSignalHandler()
274 func RunWithParams(c MessageConsumer, sdlcheck bool) {
277 Rmr.SetReadyCB(XappReadyCb, nil)
279 host := fmt.Sprintf(":%d", GetPortData("http").Port)
280 go http.ListenAndServe(host, Resource.router)
281 Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host))
284 SdlStorage.TestConnection(viper.GetString("controls.db.namespace"))
291 func Run(c MessageConsumer) {
292 RunWithParams(c, true)