diff --git a/backend/factory/config.go b/backend/factory/config.go index 6bdd2f27a1b5c7b6417439a46566d5eb5c0ed906..fc98705e3c3a1dc92d83ed2f98446fd5b3434db9 100644 --- a/backend/factory/config.go +++ b/backend/factory/config.go @@ -43,6 +43,7 @@ type Configuration struct { WebServer *WebServer `yaml:"webServer,omitempty" valid:"optional"` Mongodb *Mongodb `yaml:"mongodb" valid:"required"` NrfUri string `yaml:"nrfUri" valid:"required"` + NrfCertPem string `yaml:"nrfCertPem,omitempty" valid:"optional"` BillingServer *BillingServer `yaml:"billingServer,omitempty" valid:"required"` } diff --git a/backend/logger/logger.go b/backend/logger/logger.go index c811f2865b11c0110677134eebaa794c2f2f63c7..fcc57cb89c7d68b6590a469f2aa3a72a65135df9 100644 --- a/backend/logger/logger.go +++ b/backend/logger/logger.go @@ -19,6 +19,7 @@ var ( GinLog *logrus.Entry BillingLog *logrus.Entry FtpServerLog golog.Logger + ConsumerLog *logrus.Entry ) func init() { @@ -36,4 +37,5 @@ func init() { GinLog = NfLog.WithField(logger_util.FieldCategory, "GIN") BillingLog = NfLog.WithField(logger_util.FieldCategory, "BillingLog") FtpServerLog = adapter.NewWrap(BillingLog.Logger).With("component", "Billing", "category", "FTPServer") + ConsumerLog = NfLog.WithField(logger_util.FieldCategory, "Consumer") } diff --git a/backend/webui_context/context.go b/backend/webui_context/context.go index 174a121df79a59a6457fbee81c48aff19f0d14a8..4b5fa3d5e2b953b2240dc9a72f51514580aae4b9 100644 --- a/backend/webui_context/context.go +++ b/backend/webui_context/context.go @@ -3,17 +3,26 @@ package webui_context import ( "fmt" + "github.com/free5gc/openapi/Nnrf_NFManagement" "github.com/free5gc/openapi/models" "github.com/free5gc/webconsole/backend/billing" + "github.com/free5gc/webconsole/backend/factory" "github.com/free5gc/webconsole/backend/logger" + "github.com/google/uuid" ) var webuiContext WEBUIContext type WEBUIContext struct { + NfInstanceID string NFProfiles []models.NfProfile NFOamInstances []NfOamInstance BillingServer *billing.BillingDomain + + NrfUri string + NrfCertPem string + NFManagementClient *Nnrf_NFManagement.APIClient + OAuth2Required bool } type NfOamInstance struct { @@ -22,14 +31,22 @@ type NfOamInstance struct { Uri string } -var NrfUri string +func Init() { + webuiContext.NfInstanceID = uuid.New().String() + webuiContext.NrfUri = factory.WebuiConfig.Configuration.NrfUri + webuiContext.NrfCertPem = factory.WebuiConfig.Configuration.NrfCertPem + + ManagementConfig := Nnrf_NFManagement.NewConfiguration() + ManagementConfig.SetBasePath(GetSelf().NrfUri) + webuiContext.NFManagementClient = Nnrf_NFManagement.NewAPIClient(ManagementConfig) +} func NrfAmfUri() string { - return NrfUri + "/nnrf-disc/v1/nf-instances?target-nf-type=AMF&requester-nf-type=AMF" + return GetSelf().NrfUri + "/nnrf-disc/v1/nf-instances?target-nf-type=AMF&requester-nf-type=AMF" } func NrfSmfUri() string { - return NrfUri + "/nnrf-disc/v1/nf-instances?target-nf-type=SMF&requester-nf-type=AMF" + return GetSelf().NrfUri + "/nnrf-disc/v1/nf-instances?target-nf-type=SMF&requester-nf-type=AMF" } func (context *WEBUIContext) UpdateNfProfiles() { diff --git a/backend/webui_context/nrf.go b/backend/webui_context/nrf_discovery.go similarity index 100% rename from backend/webui_context/nrf.go rename to backend/webui_context/nrf_discovery.go diff --git a/backend/webui_context/nrf_management.go b/backend/webui_context/nrf_management.go new file mode 100644 index 0000000000000000000000000000000000000000..5df1f964bc5db00f6e72261344d9b25cd74c413a --- /dev/null +++ b/backend/webui_context/nrf_management.go @@ -0,0 +1,117 @@ +package webui_context + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" + "github.com/free5gc/webconsole/backend/logger" +) + +func SendNFRegistration() error { + profile := models.NfProfile{ + NfInstanceId: GetSelf().NfInstanceID, + NfType: models.NfType_AF, + NfStatus: models.NfStatus_REGISTERED, + } + + var nf models.NfProfile + var res *http.Response + var err error + + for { + nf, res, err = GetSelf(). + NFManagementClient. + NFInstanceIDDocumentApi. + RegisterNFInstance(context.TODO(), GetSelf().NfInstanceID, profile) + if err != nil || res == nil { + logger.ConsumerLog.Infof("Webconsole-AF register to NRF Error[%s]", err.Error()) + time.Sleep(2 * time.Second) + continue + } + defer func() { + if resCloseErr := res.Body.Close(); resCloseErr != nil { + logger.ConsumerLog.Errorf("RegisterNFInstance response body cannot close: %+v", resCloseErr) + } + }() + + status := res.StatusCode + if status == http.StatusOK { + // NFUpdate + break + } else if status == http.StatusCreated { + // NFRegister + resourceUri := res.Header.Get("Location") + GetSelf().NfInstanceID = resourceUri[strings.LastIndex(resourceUri, "/")+1:] + + oauth2 := false + if nf.CustomInfo != nil { + v, ok := nf.CustomInfo["oauth2"].(bool) + if ok { + oauth2 = v + logger.MainLog.Infoln("OAuth2 setting receive from NRF:", oauth2) + } + } + GetSelf().OAuth2Required = oauth2 + if oauth2 && GetSelf().NrfCertPem == "" { + logger.CfgLog.Error("OAuth2 enable but no nrfCertPem provided in config.") + } + break + } else { + logger.ConsumerLog.Infof("handler returned wrong status code %d", status) + } + } + + logger.InitLog.Infof("Webconsole-AF Registration to NRF success") + return nil +} + +func RetrySendNFRegistration(MaxRetry int) error { + retryCount := 0 + for retryCount < MaxRetry { + err := SendNFRegistration() + if err == nil { + return nil + } + logger.ConsumerLog.Warnf("Send NFRegistration Failed by %v", err) + retryCount++ + } + logger.ConsumerLog.Errorln("[AF] Retry NF Registration has meet maximum") + return fmt.Errorf("[AF] Retry NF Registration has meet maximum") +} + +func SendDeregisterNFInstance() (*models.ProblemDetails, error) { + logger.ConsumerLog.Infof("Send Deregister NFInstance") + + // ctx, pd, err := GetSelf().GetTokenCtx(models.ServiceName_NNRF_NFM, models.NfType_NRF) + // if err != nil { + // return pd, err + // } + + afSelf := GetSelf() + + res, err := afSelf. + NFManagementClient. + NFInstanceIDDocumentApi. + DeregisterNFInstance(context.Background(), afSelf.NfInstanceID) + if err == nil { + return nil, err + } else if res != nil { + defer func() { + if resCloseErr := res.Body.Close(); resCloseErr != nil { + logger.ConsumerLog.Errorf("DeregisterNFInstance response body cannot close: %+v", resCloseErr) + } + }() + if res.Status != err.Error() { + return nil, err + } + problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + return &problem, err + } else { + return nil, openapi.ReportError("server no response") + } +} diff --git a/backend/webui_service/webui_init.go b/backend/webui_service/webui_init.go index 71f53f2e9de8a6864f6a69b76a70ae5b0c09097a..01a58bf35d2002b0b8d34ad8034c6e26452d5576 100644 --- a/backend/webui_service/webui_init.go +++ b/backend/webui_service/webui_init.go @@ -3,7 +3,10 @@ package webui_service import ( "io/ioutil" "os" + "os/signal" + "runtime/debug" "sync" + "syscall" "github.com/gin-contrib/cors" "github.com/sirupsen/logrus" @@ -27,6 +30,7 @@ func NewApp(cfg *factory.Config) (*WebuiApp, error) { webui.SetLogLevel(cfg.GetLogLevel()) webui.SetReportCaller(cfg.GetLogReportCaller()) + webui_context.Init() webui.webuiCtx = webui_context.GetSelf() return webui, nil } @@ -80,11 +84,32 @@ func (a *WebuiApp) Start(tlsKeyLogPath string) { return } - nrfUri := factory.WebuiConfig.Configuration.NrfUri - webui_context.NrfUri = nrfUri - logger.InitLog.Infoln("Server started") + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) + go func() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + <-signalChannel + a.Terminate() + os.Exit(0) + }() + + err := webui_context.SendNFRegistration() + if err != nil { + retry_err := webui_context.RetrySendNFRegistration(10) + if retry_err != nil { + logger.InitLog.Errorln(retry_err) + return + } + } + router := WebUI.NewRouter() WebUI.SetAdmin() if err := WebUI.InitJwtKey(); err != nil { @@ -125,3 +150,17 @@ func (a *WebuiApp) Start(tlsKeyLogPath string) { wg.Wait() } + +func (a *WebuiApp) Terminate() { + logger.InitLog.Infoln("Terminating WebUI-AF...") + + // Deregister with NRF + problemDetails, err := webui_context.SendDeregisterNFInstance() + if problemDetails != nil { + logger.InitLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.InitLog.Errorf("Deregister NF instance Error[%+v]", err) + } else { + logger.InitLog.Infof("Deregister from NRF successfully") + } +} diff --git a/config/webuicfg.yaml b/config/webuicfg.yaml index 4496ea00d1ac1b586973baba5f248aea6744fee9..e35022f692c0b01f6a97bbf761c3f4e4a580f536 100644 --- a/config/webuicfg.yaml +++ b/config/webuicfg.yaml @@ -7,6 +7,7 @@ configuration: name: free5gc # name of the mongodb url: mongodb://localhost:27017 # a valid URL of the mongodb nrfUri: http://127.0.0.10:8000 # a valid URI of NRF + nrfCertPem: cert/nrf.pem webServer: scheme: http ipv4Address: 0.0.0.0