Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Make webconsole backend register to NRF as AF #78

Merged
merged 4 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var (
GinLog *logrus.Entry
BillingLog *logrus.Entry
FtpServerLog golog.Logger
ConsumerLog *logrus.Entry
)

func init() {
Expand All @@ -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")
}
45 changes: 37 additions & 8 deletions backend/webui_context/context.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
package webui_context

import (
"context"
"fmt"

"github.com/google/uuid"

"github.com/free5gc/openapi/Nnrf_NFDiscovery"
"github.com/free5gc/openapi/Nnrf_NFManagement"
"github.com/free5gc/openapi/models"
"github.com/free5gc/openapi/oauth"
"github.com/free5gc/webconsole/backend/billing"
"github.com/free5gc/webconsole/backend/factory"
"github.com/free5gc/webconsole/backend/logger"
)

var webuiContext WEBUIContext

type WEBUIContext struct {
NfInstanceID string
NFProfiles []models.NfProfile
NFOamInstances []NfOamInstance
BillingServer *billing.BillingDomain

NrfUri string
OAuth2Required bool

NFManagementClient *Nnrf_NFManagement.APIClient
NFDiscoveryClient *Nnrf_NFDiscovery.APIClient
}

type NfOamInstance struct {
Expand All @@ -22,27 +36,30 @@ type NfOamInstance struct {
Uri string
}

var NrfUri string
func Init() {
webuiContext.NfInstanceID = uuid.New().String()
webuiContext.NrfUri = factory.WebuiConfig.Configuration.NrfUri

func NrfAmfUri() string {
return NrfUri + "/nnrf-disc/v1/nf-instances?target-nf-type=AMF&requester-nf-type=AMF"
}
ManagementConfig := Nnrf_NFManagement.NewConfiguration()
ManagementConfig.SetBasePath(GetSelf().NrfUri)
webuiContext.NFManagementClient = Nnrf_NFManagement.NewAPIClient(ManagementConfig)

func NrfSmfUri() string {
return NrfUri + "/nnrf-disc/v1/nf-instances?target-nf-type=SMF&requester-nf-type=AMF"
NFDiscovryConfig := Nnrf_NFDiscovery.NewConfiguration()
NFDiscovryConfig.SetBasePath(GetSelf().NrfUri)
webuiContext.NFDiscoveryClient = Nnrf_NFDiscovery.NewAPIClient(NFDiscovryConfig)
}

func (context *WEBUIContext) UpdateNfProfiles() {
var nfProfiles []models.NfProfile

nfProfiles, err := NrfGetNfProfiles(NrfAmfUri())
nfProfiles, err := SendSearchNFInstances(models.NfType_AMF)
if err != nil {
logger.CtxLog.Error(err)
return
}
context.NFProfiles = append(context.NFProfiles, nfProfiles...)

nfProfiles, err = NrfGetNfProfiles(NrfSmfUri())
nfProfiles, err = SendSearchNFInstances(models.NfType_SMF)
if err != nil {
logger.CtxLog.Error(err)
return
Expand Down Expand Up @@ -132,3 +149,15 @@ func getSbiUri(scheme models.UriScheme, ipv4Address string, port int32) (uri str
}
return
}

func (c *WEBUIContext) GetTokenCtx(serviceName models.ServiceName, targetNF models.NfType) (
context.Context, *models.ProblemDetails, error,
) {
if !c.OAuth2Required {
return context.TODO(), nil, nil
}

logger.ConsumerLog.Infoln("GetTokenCtx:", targetNF, serviceName)
return oauth.GetTokenCtx(models.NfType_AF, targetNF,
c.NfInstanceID, c.NrfUri, string(serviceName))
}
54 changes: 0 additions & 54 deletions backend/webui_context/nrf.go

This file was deleted.

46 changes: 46 additions & 0 deletions backend/webui_context/nrf_discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package webui_context

import (
"net/http"

"github.com/free5gc/openapi/Nnrf_NFDiscovery"
"github.com/free5gc/openapi/models"
"github.com/free5gc/webconsole/backend/logger"
)

type NfInstance struct {
ValidityPeriod int `json:"validityPeriod"`
NfInstances []models.NfProfile `json:"nfInstances"`
}

func SendSearchNFInstances(targetNfType models.NfType) ([]models.NfProfile, error) {
var nfProfiles []models.NfProfile

ctx, _, err := GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF)
if err != nil {
logger.ConsumerLog.Errorln(err.Error())
return nfProfiles, err
}

client := GetSelf().NFDiscoveryClient
localVarOptionals := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{}

result, res, err := client.
NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, models.NfType_AF, &localVarOptionals)
if err != nil {
logger.ConsumerLog.Errorf("SearchNFInstances failed: %+v", err)
}
defer func() {
if resCloseErr := res.Body.Close(); resCloseErr != nil {
logger.ConsumerLog.Errorf("NFInstancesStoreApi response body cannot close: %+v", resCloseErr)
}
}()

if res != nil && res.StatusCode == http.StatusTemporaryRedirect {
logger.ConsumerLog.Errorln("Temporary Redirect For Non NRF Consumer")
return nfProfiles, err
}
nfProfiles = result.NfInstances

return nfProfiles, nil
}
117 changes: 117 additions & 0 deletions backend/webui_context/nrf_management.go
Original file line number Diff line number Diff line change
@@ -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,
CustomInfo: map[string]interface{}{
"AfType": "webconsole",
},
}

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
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(ctx, 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")
}
}
45 changes: 42 additions & 3 deletions backend/webui_service/webui_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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")
}
}
Loading
Loading