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 ->
45 type ReadyCB func(interface{})
46 type ShutdownCB func()
49 // XApp is an application instance
52 SdlStorage *SDLStorage
58 Subscription *Subscriber
62 readyCbParams interface{}
69 return Rmr != nil && Rmr.IsReady() && SdlStorage != nil && SdlStorage.IsReady()
72 func SetReadyCB(cb ReadyCB, params interface{}) {
74 readyCbParams = params
77 func XappReadyCb(params interface{}) {
78 //Alarm = NewAlarmClient(viper.GetString("moId"), viper.GetString("name"))
80 readyCb(readyCbParams)
84 func SetShutdownCB(cb ShutdownCB) {
88 func XappShutdownCb() {
89 if err := doDeregister(); err != nil {
90 Logger.Info("xApp deregistration failed: %v, terminating ungracefully!", err)
92 Logger.Info("xApp deregistration successfull!")
95 if shutdownCb != nil {
100 func registerXapp() {
102 time.Sleep(5 * time.Second)
103 if !IsHealthProbeReady() {
104 Logger.Info("Application='%s' is not ready yet, waiting ...", viper.GetString("name"))
108 Logger.Debug("Application='%s' is now up and ready, continue with registration ...", viper.GetString("name"))
109 if err := doRegister(); err == nil {
110 Logger.Info("Registration done, proceeding with startup ...")
116 func getService(host, service string) string {
117 appnamespace := os.Getenv("APP_NAMESPACE")
118 if appnamespace == "" {
119 appnamespace = DEFAULT_XAPP_NS
122 svc := fmt.Sprintf(service, strings.ToUpper(appnamespace), strings.ToUpper(host))
123 url := strings.Split(os.Getenv(strings.Replace(svc, "-", "_", -1)), "//")
125 Logger.Info("getService: %+v %+v", svc, url)
132 func getPltNamespace(envName, defVal string) string {
133 pltnamespace := os.Getenv("PLT_NAMESPACE")
134 if pltnamespace == "" {
135 pltnamespace = defVal
141 func doPost(pltNs, url string, msg []byte, status int) error {
142 resp, err := http.Post(fmt.Sprintf(url, pltNs, pltNs), "application/json", bytes.NewBuffer(msg))
143 if err != nil || resp == nil || resp.StatusCode != status {
144 Logger.Info("http.Post to '%s' failed with error: %v", fmt.Sprintf(url, pltNs, pltNs), err)
147 Logger.Info("Post to '%s' done, status:%v", fmt.Sprintf(url, pltNs, pltNs), resp.Status)
152 func doRegister() error {
153 host, _ := os.Hostname()
154 xappname := viper.GetString("name")
155 xappversion := viper.GetString("version")
156 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
158 httpEp, rmrEp := getService(host, SERVICE_HTTP), getService(host, SERVICE_RMR)
159 if httpEp == "" || rmrEp == "" {
160 Logger.Warn("Couldn't resolve service endpoints: httpEp=%s rmrEp=%s", httpEp, rmrEp)
164 requestBody, err := json.Marshal(map[string]string{
166 "httpEndpoint": httpEp,
167 "rmrEndpoint": rmrEp,
168 "appInstanceName": xappname,
169 "appVersion": xappversion,
170 "configPath": CONFIG_PATH,
174 Logger.Error("json.Marshal failed with error: %v", err)
178 return doPost(pltNs, REGISTER_PATH, requestBody, http.StatusCreated)
181 func doDeregister() error {
182 if !IsHealthProbeReady() {
186 name, _ := os.Hostname()
187 xappname := viper.GetString("name")
188 pltNs := getPltNamespace("PLT_NAMESPACE", DEFAULT_PLT_NS)
190 requestBody, err := json.Marshal(map[string]string{
192 "appInstanceName": xappname,
196 Logger.Error("json.Marshal failed with error: %v", err)
200 return doPost(pltNs, DEREGISTER_PATH, requestBody, http.StatusNoContent)
203 func InstallSignalHandler() {
205 // Signal handlers to really exit program.
206 // shutdownCb can hang until application has
207 // made all needed gracefull shutdown actions
208 // hardcoded limit for shutdown is 20 seconds
210 interrupt := make(chan os.Signal, 1)
211 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
212 //signal handler function
214 for range interrupt {
215 if atomic.CompareAndSwapInt32(&shutdownFlag, 0, 1) {
219 sentry := make(chan struct{})
228 case <-time.After(time.Duration(timeout) * time.Second):
229 Logger.Info("xapp-frame shutdown callback took more than %d seconds", timeout)
231 Logger.Info("xapp-frame shutdown callback handled within %d seconds", timeout)
236 newCnt := atomic.AddInt32(&shutdownCnt, 1)
237 Logger.Info("xapp-frame shutdown already ongoing. Forced exit counter %d/%d ", newCnt, 5)
239 Logger.Info("xapp-frame shutdown forced exit")
250 // Load xapp configuration
251 Logger = LoadConfig()
253 if viper.IsSet("controls.logger.level") {
254 Logger.SetLevel(viper.GetInt("controls.logger.level"))
256 Logger.SetLevel(viper.GetInt("logger.level"))
259 if !viper.IsSet("controls.logger.noFormat") || !viper.GetBool("controls.logger.noFormat") {
263 Resource = NewRouter()
264 Config = Configurator{}
265 Metric = NewMetrics(viper.GetString("metrics.url"), viper.GetString("metrics.namespace"), Resource.router)
266 Subscription = NewSubscriber(viper.GetString("controls.subscription.host"), viper.GetInt("controls.subscription.timeout"))
267 SdlStorage = NewSdlStorage()
268 Sdl = NewSDLClient(viper.GetString("controls.db.namespace"))
269 Rnib = GetNewRnibClient(SdlStorage.db)
272 InstallSignalHandler()
275 func getIpAdress() string {
277 itf, err := net.InterfaceByName(os.Getenv("INTERFACE_NAME"))
279 Logger.Info("Interface name is not able to resolve " + err.Error())
282 item, err := itf.Addrs()
284 Logger.Info("IP address is not able to resolve " + err.Error())
287 for _, addr := range item {
288 switch v := addr.(type) {
290 if !v.IP.IsLinkLocalUnicast() {
298 func RunWithParams(c MessageConsumer, sdlcheck bool) {
301 Rmr.SetReadyCB(XappReadyCb, nil)
302 ipString := getIpAdress()
304 if ipString == "<nil>" {
305 host = fmt.Sprintf(":%d", GetPortData("http").Port)
307 host = fmt.Sprintf("%s:%d", ipString, GetPortData("http").Port)
309 go http.ListenAndServe(host, Resource.router)
310 Logger.Info(fmt.Sprintf("Xapp started, listening on: %s", host))
313 SdlStorage.TestConnection(viper.GetString("controls.db.namespace"))
320 func Run(c MessageConsumer) {
321 RunWithParams(c, true)