diff --git a/consumer/nf_managemant.go b/consumer/nf_managemant.go index 0d1d577..3ef0b6f 100644 --- a/consumer/nf_managemant.go +++ b/consumer/nf_managemant.go @@ -74,7 +74,7 @@ func BuildNFInstance(context *udr_context.UDRContext) models.NfProfile { return profile } -func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfile) (string, string, error) { +var SendRegisterNFInstance = func(nrfUri, nfInstanceId string, profile models.NfProfile) (models.NfProfile, string, string, error) { // Set client and set url configuration := Nnrf_NFManagement.NewConfiguration() configuration.SetBasePath(nrfUri) @@ -83,7 +83,7 @@ func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfil var retrieveNfInstanceId string for { - _, res, err := client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), nfInstanceId, profile) + prof, res, err := client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), nfInstanceId, profile) if err != nil || res == nil { // TODO : add log fmt.Println(fmt.Errorf("UDR register to NRF Error[%s]", err.Error())) @@ -99,13 +99,13 @@ func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfil status := res.StatusCode if status == http.StatusOK { // NFUpdate - return resouceNrfUri, retrieveNfInstanceId, err + return prof, resouceNrfUri, retrieveNfInstanceId, err } else if status == http.StatusCreated { // NFRegister resourceUri := res.Header.Get("Location") resouceNrfUri = resourceUri[:strings.Index(resourceUri, "/nnrf-nfm/")] retrieveNfInstanceId = resourceUri[strings.LastIndex(resourceUri, "/")+1:] - return resouceNrfUri, retrieveNfInstanceId, err + return prof, resouceNrfUri, retrieveNfInstanceId, err } else { fmt.Println("handler returned wrong status code", status) fmt.Println("NRF return wrong status code", status) @@ -144,3 +144,33 @@ func SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err erro } return } + +var SendUpdateNFInstance = func(patchItem []models.PatchItem) (nfProfile models.NfProfile, problemDetails *models.ProblemDetails, err error) { + logger.ConsumerLog.Debugf("Send Update NFInstance") + + udrSelf := udr_context.UDR_Self() + configuration := Nnrf_NFManagement.NewConfiguration() + configuration.SetBasePath(udrSelf.NrfUri) + client := Nnrf_NFManagement.NewAPIClient(configuration) + + var res *http.Response + nfProfile, res, err = client.NFInstanceIDDocumentApi.UpdateNFInstance(context.Background(), udrSelf.NfId, patchItem) + if err == nil { + return + } else if res != nil { + defer func() { + if resCloseErr := res.Body.Close(); resCloseErr != nil { + logger.ConsumerLog.Errorf("UpdateNFInstance response cannot close: %+v", resCloseErr) + } + }() + if res.Status != err.Error() { + logger.ConsumerLog.Errorf("UpdateNFInstance received error response: %v", res.Status) + return + } + problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return +} diff --git a/service/init.go b/service/init.go index 40c0f54..ef4787a 100644 --- a/service/init.go +++ b/service/init.go @@ -15,7 +15,9 @@ import ( "os/signal" "sync" "syscall" + "time" + "github.com/omec-project/openapi/models" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -26,6 +28,7 @@ import ( "github.com/omec-project/path_util" pathUtilLogger "github.com/omec-project/path_util/logger" "github.com/omec-project/udr/consumer" + "github.com/omec-project/udr/context" udr_context "github.com/omec-project/udr/context" "github.com/omec-project/udr/datarepository" "github.com/omec-project/udr/factory" @@ -39,7 +42,8 @@ type UDR struct{} type ( // Config information. Config struct { - udrcfg string + udrcfg string + heartBeatTimer string } ) @@ -58,6 +62,11 @@ var udrCLi = []cli.Flag{ var initLog *logrus.Entry +var ( + KeepAliveTimer *time.Timer + KeepAliveTimerMutex sync.Mutex +) + func init() { initLog = logger.InitLog } @@ -303,6 +312,75 @@ func (udr *UDR) configUpdateDb() { } } +func (udr *UDR) StartKeepAliveTimer(nfProfile models.NfProfile) { + KeepAliveTimerMutex.Lock() + defer KeepAliveTimerMutex.Unlock() + udr.StopKeepAliveTimer() + if nfProfile.HeartBeatTimer == 0 { + nfProfile.HeartBeatTimer = 60 + } + logger.InitLog.Infof("Started KeepAlive Timer: %v sec", nfProfile.HeartBeatTimer) + //AfterFunc starts timer and waits for KeepAliveTimer to elapse and then calls udr.UpdateNF function + KeepAliveTimer = time.AfterFunc(time.Duration(nfProfile.HeartBeatTimer)*time.Second, udr.UpdateNF) +} + +func (udr *UDR) StopKeepAliveTimer() { + if KeepAliveTimer != nil { + logger.InitLog.Infof("Stopped KeepAlive Timer.") + KeepAliveTimer.Stop() + KeepAliveTimer = nil + } +} + +func (udr *UDR) BuildAndSendRegisterNFInstance() (prof models.NfProfile, err error) { + self := context.UDR_Self() + profile := consumer.BuildNFInstance(self) + initLog.Infof("Pcf Profile Registering to NRF: %v", profile) + //Indefinite attempt to register until success + profile, _, self.NfId, err = consumer.SendRegisterNFInstance(self.NrfUri, self.NfId, profile) + return profile, err +} + +//UpdateNF is the callback function, this is called when keepalivetimer elapsed +func (udr *UDR) UpdateNF() { + KeepAliveTimerMutex.Lock() + defer KeepAliveTimerMutex.Unlock() + if KeepAliveTimer == nil { + initLog.Warnf("KeepAlive timer has been stopped.") + return + } + //setting default value 30 sec + var heartBeatTimer int32 = 60 + pitem := models.PatchItem{ + Op: "replace", + Path: "/nfStatus", + Value: "REGISTERED", + } + var patchItem []models.PatchItem + patchItem = append(patchItem, pitem) + nfProfile, problemDetails, err := consumer.SendUpdateNFInstance(patchItem) + if problemDetails != nil { + initLog.Errorf("UDR update to NRF ProblemDetails[%v]", problemDetails) + //5xx response from NRF, 404 Not Found, 400 Bad Request + if (problemDetails.Status/100) == 5 || + problemDetails.Status == 404 || problemDetails.Status == 400 { + //register with NRF full profile + nfProfile, err = udr.BuildAndSendRegisterNFInstance() + } + } else if err != nil { + initLog.Errorf("UDR update to NRF Error[%s]", err.Error()) + nfProfile, err = udr.BuildAndSendRegisterNFInstance() + } + + if nfProfile.HeartBeatTimer != 0 { + // use hearbeattimer value with received timer value from NRF + heartBeatTimer = nfProfile.HeartBeatTimer + } + logger.InitLog.Debugf("Restarted KeepAlive Timer: %v sec", heartBeatTimer) + //restart timer with received HeartBeatTimer value + KeepAliveTimer = time.AfterFunc(time.Duration(heartBeatTimer)*time.Second, udr.UpdateNF) +} + func (udr *UDR) registerNF() { for msg := range factory.ConfigPodTrigger { initLog.Infof("Minimum configuration from config pod available %v", msg) @@ -310,9 +388,12 @@ func (udr *UDR) registerNF() { profile := consumer.BuildNFInstance(self) var newNrfUri string var err error + var prof models.NfProfile // send registration with updated PLMN Ids. - newNrfUri, self.NfId, err = consumer.SendRegisterNFInstance(self.NrfUri, profile.NfInstanceId, profile) + prof, newNrfUri, self.NfId, err = consumer.SendRegisterNFInstance(self.NrfUri, profile.NfInstanceId, profile) if err == nil { + udr.StartKeepAliveTimer(prof) + logger.CfgLog.Infof("Sent Register NF Instance with updated profile") self.NrfUri = newNrfUri } else { initLog.Errorf("Send Register NFInstance Error[%s]", err.Error())