Skip to content
Snippets Groups Projects
Unverified Commit c5938bf9 authored by Ian Chen's avatar Ian Chen Committed by GitHub
Browse files

Merge pull request #78 from andy89923/feat/af-backend

Feature: Make webconsole backend register to NRF as AF
parents 3c7fdc45 e13246fa
No related branches found
No related tags found
No related merge requests found
......@@ -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")
}
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 {
......@@ -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
......@@ -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))
}
package webui_context
import (
"context"
"crypto/tls"
"encoding/json"
"io"
"net/http"
"github.com/free5gc/openapi/Nnrf_NFDiscovery"
"github.com/free5gc/openapi/models"
"github.com/free5gc/webconsole/backend/logger"
)
......@@ -16,39 +13,36 @@ type NfInstance struct {
NfInstances []models.NfProfile `json:"nfInstances"`
}
func NrfGetNfProfiles(requestUri string) ([]models.NfProfile, error) {
func SendSearchNFInstances(targetNfType models.NfType) ([]models.NfProfile, error) {
var nfProfiles []models.NfProfile
httpsClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, requestUri, nil)
ctx, _, err := GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF)
if err != nil {
logger.ConsumerLog.Errorln(err.Error())
return nfProfiles, err
}
resp, err := httpsClient.Do(req)
client := GetSelf().NFDiscoveryClient
localVarOptionals := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{}
result, res, err := client.
NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, models.NfType_AF, &localVarOptionals)
if err != nil {
return nfProfiles, err
logger.ConsumerLog.Errorf("SearchNFInstances failed: %+v", err)
}
defer func() {
if closeErr := resp.Body.Close(); closeErr != nil {
logger.CtxLog.Error(err)
if res != nil {
if resCloseErr := res.Body.Close(); resCloseErr != nil {
logger.ConsumerLog.Errorf("NFInstancesStoreApi response body cannot close: %+v", resCloseErr)
}
}
}()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nfProfiles, err
}
var nfInstance NfInstance
err = json.Unmarshal(body, &nfInstance)
if err != nil {
if res != nil && res.StatusCode == http.StatusTemporaryRedirect {
logger.ConsumerLog.Errorln("Temporary Redirect For Non NRF Consumer")
return nfProfiles, err
}
nfProfiles = result.NfInstances
return nfInstance.NfInstances, nil
return nfProfiles, nil
}
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
retryTime := 0
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)
retryTime += 1
if retryTime == 10 {
return fmt.Errorf("NF Register retry failed %+v times.", retryTime)
}
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++
}
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")
}
}
......@@ -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,34 @@ 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)
}()
go func() {
err := webui_context.SendNFRegistration()
if err != nil {
retry_err := webui_context.RetrySendNFRegistration(1)
if retry_err != nil {
logger.InitLog.Errorln(retry_err)
logger.InitLog.Warningln("The registration to NRF failed, resulting in limited functionalities.")
}
}
}()
router := WebUI.NewRouter()
WebUI.SetAdmin()
if err := WebUI.InitJwtKey(); err != nil {
......@@ -125,3 +152,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")
}
}
......@@ -23,6 +23,7 @@ require (
require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/antihax/optional v1.0.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
......@@ -45,6 +46,7 @@ require (
github.com/google/s2a-go v0.1.3 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
......@@ -53,6 +55,7 @@ require (
github.com/kr/fs v0.1.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
......@@ -81,6 +84,7 @@ require (
google.golang.org/grpc v1.56.3 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/h2non/gock.v1 v1.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment