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 ==================================================================================
36 "github.com/spf13/viper"
39 // For testing purpose go version 1.13 ->
46 type ReadyCB func(interface{})
47 type ShutdownCB func()
50 // XApp is an application instance
53 SdlStorage *SDLStorage
59 Subscription *Subscriber
63 readyCbParams interface{}
70 return Rmr != nil && Rmr.IsReady() && SdlStorage != nil && SdlStorage.IsReady()
73 func SetReadyCB(cb ReadyCB, params interface{}) {
75 readyCbParams = params
78 func XappReadyCb(params interface{}) {
79 Alarm = NewAlarmClient(viper.GetString("moId"), viper.GetString("name"))
81 readyCb(readyCbParams)
85 func SetShutdownCB(cb ShutdownCB) {
89 func XappShutdownCb() {
90 if err := doDeregister(); err != nil {
91 Logger.Info("xApp deregistration failed: %v, terminating ungracefully!", err)
93 Logger.Info("xApp deregistration successfull!")
96 if shutdownCb != nil {
101 func registerXapp() {
103 time.Sleep(5 * time.Second)
104 if !IsHealthProbeReady() {
105 Logger.Info("Application='%s' is not ready yet, waiting ...", viper.GetString("name"))
109 Logger.Debug("Application='%s' is now up and ready, continue with registration ...", viper.GetString("name"))
110 if err := doRegister(); err == nil {
111 Logger.Info("Registration done, proceeding with startup ...")
117 func getService(host, service string) string {
118 appnamespace := os.Getenv("APP_NAMESPACE")
119 if appnamespace == "" {
120 appnamespace = DEFAULT_XAPP_NS
123 svc := fmt.Sprintf(service, strings.ToUpper(appnamespace), strings.ToUpper(host))
124 url := strings.Split(os.Getenv(strings.Replace(svc, "-", "_", -1)), "//")
126 Logger.Info("getService: %+v %+v", svc, url)
133 func getPltNamespace(envName, defVal string) string {
134 pltnamespace := os.Getenv("PLT_NAMESPACE")
135 if pltnamespace == "" {
136 pltnamespace = defVal
142 func doPost(pltNs, url string, msg []byte, status int) error {
143 resp, err := http.Post(fmt.Sprintf(url, pltNs, pltNs), "application/json", bytes.NewBuffer(msg))
144 if err != nil || resp == nil || resp.StatusCode != status {
145 Logger.Info("http.Post to '%s' failed with error: %v", fmt.Sprintf(url, pltNs, pltNs), err)
148 Logger.Info("Post to '%s' done, status:%v", fmt.Sprintf(url, pltNs, pltNs), resp.Status)
153 func doRegister() error {
154 host, _ := os.Hostname()
155 xappname := viper.GetString("name")
156 xappversion := viper.GetString("version")
157 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
159 httpEp, rmrEp := getService(host, SERVICE_HTTP), getService(host, SERVICE_RMR)
160 if httpEp == "" || rmrEp == "" {
161 Logger.Warn("Couldn't resolve service endpoints: httpEp=%s rmrEp=%s", httpEp, rmrEp)
165 requestBody, err := json.Marshal(map[string]string{
167 "httpEndpoint": httpEp,
168 "rmrEndpoint": rmrEp,
169 "appInstanceName": xappname,
170 "appVersion": xappversion,
171 "configPath": CONFIG_PATH,
175 Logger.Error("json.Marshal failed with error: %v", err)
179 return doPost(pltNs, REGISTER_PATH, requestBody, http.StatusCreated)
182 func doDeregister() error {
183 if !IsHealthProbeReady() {
187 name, _ := os.Hostname()
188 xappname := viper.GetString("name")
189 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
191 requestBody, err := json.Marshal(map[string]string{
193 "appInstanceName": xappname,
197 Logger.Error("json.Marshal failed with error: %v", err)
201 return doPost(pltNs, DEREGISTER_PATH, requestBody, http.StatusNoContent)
204 func InstallSignalHandler() {
206 // Signal handlers to really exit program.
207 // shutdownCb can hang until application has
208 // made all needed gracefull shutdown actions
209 // hardcoded limit for shutdown is 20 seconds
211 interrupt := make(chan os.Signal, 1)
212 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
213 //signal handler function
215 for range interrupt {
216 if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) {
220 sentry := make(chan struct{})
229 case <-time.After(time.Duration(timeout) * time.Second):
230 Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout)
232 Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout)
237 newCnt := atomic.AddInt32(&shutdownCnt, 1)
238 Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5)
240 Logger.Info("xapp-frame shutdown forced exit")
251 // Load xapp configuration
252 Logger = LoadConfig()
254 if viper.IsSet("controls.logger.level") {
255 Logger.SetLevel(viper.GetInt("controls.logger.level"))
257 Logger.SetLevel(viper.GetInt("logger.level"))
260 if !viper.IsSet("controls.logger.noFormat") || !viper.GetBool("controls.logger.noFormat") {
264 Resource = NewRouter()
265 Config = Configurator{}
266 Metric = NewMetrics(viper.GetString("metrics.url"), viper.GetString("metrics.namespace"), Resource.router)
267 Subscription = NewSubscriber(viper.GetString("controls.subscription.host"), viper.GetInt("controls.subscription.timeout"))
268 SdlStorage = NewSdlStorage()
269 Sdl = NewSDLClient(viper.GetString("controls.db.namespace"))
270 Rnib = GetNewRnibClient(SdlStorage.db)
273 InstallSignalHandler()
276 func getIpAdress() string {
278 itf, err := net.InterfaceByName(os.Getenv("INTERFACE_NAME"))
280 Logger.Info("Interface name is not able to resolve " + err.Error())
283 item, err := itf.Addrs()
285 Logger.Info("IP address is not able to resolve " + err.Error())
288 for _, addr := range item {
289 switch v := addr.(type) {
291 if !v.IP.IsLinkLocalUnicast() {
299 func RunWithParams(c MessageConsumer, sdlcheck bool) {
302 Rmr.SetReadyCB(XappReadyCb, nil)
303 ipString := getIpAdress()
305 if ipString == "<nil>" {
306 host = fmt.Sprintf(":%d", GetPortData("http").Port)
308 host = fmt.Sprintf("%s:%d", ipString, GetPortData("http").Port)
310 go http.ListenAndServe(host, Resource.router)
311 Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host))
314 SdlStorage.TestConnection(viper.GetString("controls.db.namespace"))
321 func Run(c MessageConsumer) {
322 RunWithParams(c, true)