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.Debug("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(xappname, SERVICE_HTTP), getService(xappname, SERVICE_RMR)
160 httpEp, rmrEp := getService(host, SERVICE_HTTP), getService(host, SERVICE_RMR)
161 if httpEp == "" || rmrEp == "" {
162 Logger.Warn("Couldn't resolve service endpoints: httpEp=%s rmrEp=%s", httpEp, rmrEp)
166 requestBody, err := json.Marshal(map[string]string{
168 "httpEndpoint": httpEp,
169 "rmrEndpoint": rmrEp,
170 "appInstanceName": xappname,
171 "appVersion": xappversion,
172 "configPath": CONFIG_PATH,
176 Logger.Error("json.Marshal failed with error: %v", err)
180 return doPost(pltNs, REGISTER_PATH, requestBody, http.StatusCreated)
183 func doDeregister() error {
184 if !IsHealthProbeReady() {
188 name, _ := os.Hostname()
189 xappname := viper.GetString("name")
190 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
192 requestBody, err := json.Marshal(map[string]string{
194 "appInstanceName": xappname,
198 Logger.Error("json.Marshal failed with error: %v", err)
202 return doPost(pltNs, DEREGISTER_PATH, requestBody, http.StatusNoContent)
205 func InstallSignalHandler() {
207 // Signal handlers to really exit program.
208 // shutdownCb can hang until application has
209 // made all needed gracefull shutdown actions
210 // hardcoded limit for shutdown is 20 seconds
212 interrupt := make(chan os.Signal, 1)
213 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
214 //signal handler function
216 for range interrupt {
217 if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) {
221 sentry := make(chan struct{})
230 case <-time.After(time.Duration(timeout) * time.Second):
231 Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout)
233 Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout)
238 newCnt := atomic.AddInt32(&shutdownCnt, 1)
239 Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5)
241 Logger.Info("xapp-frame shutdown forced exit")
252 // Load xapp configuration
253 Logger = LoadConfig()
255 if viper.IsSet("controls.logger.level") {
256 Logger.SetLevel(viper.GetInt("controls.logger.level"))
258 Logger.SetLevel(viper.GetInt("logger.level"))
261 if !viper.IsSet("controls.logger.noFormat") || !viper.GetBool("controls.logger.noFormat") {
265 Resource = NewRouter()
266 Config = Configurator{}
267 Metric = NewMetrics(viper.GetString("metrics.url"), viper.GetString("metrics.namespace"), Resource.router)
268 Subscription = NewSubscriber(viper.GetString("controls.subscription.host"), viper.GetInt("controls.subscription.timeout"))
269 SdlStorage = NewSdlStorage()
270 Sdl = NewSDLClient(viper.GetString("controls.db.namespace"))
271 Rnib = GetNewRnibClient(SdlStorage.db)
274 InstallSignalHandler()
277 func getIpAdress() string {
279 itf, err := net.InterfaceByName(os.Getenv("INTERFACE_NAME"))
281 Logger.Info("Interface name is not able to resolve " + err.Error())
284 item, err := itf.Addrs()
286 Logger.Info("IP address is not able to resolve " + err.Error())
289 for _, addr := range item {
290 switch v := addr.(type) {
292 if !v.IP.IsLinkLocalUnicast() {
300 func RunWithParams(c MessageConsumer, sdlcheck bool) {
303 Rmr.SetReadyCB(XappReadyCb, nil)
304 ipString := getIpAdress()
306 if ipString == "<nil>" {
307 host = fmt.Sprintf(":%d", GetPortData("http").Port)
309 host = fmt.Sprintf("[%s]:%d", ipString, GetPortData("http").Port)
311 go http.ListenAndServe(host, Resource.router)
312 Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host))
315 SdlStorage.TestConnection(viper.GetString("controls.db.namespace"))
322 func Run(c MessageConsumer) {
323 RunWithParams(c, true)