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

refactor: NSSF app, sbi, processor, consumer #24

Merged
merged 32 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e8eac91
refactor: sbi server
yccodr Apr 24, 2024
8210039
refactor: processor as route handler
yccodr Apr 25, 2024
d866a36
fix: nil dereference
yccodr Apr 25, 2024
99a72d3
fix: ci complains
yccodr Apr 25, 2024
9bbfecf
refactor: interface design
yccodr Apr 25, 2024
6f939e0
test: nssaiavailability `NfInstanceDelete`
yccodr Apr 25, 2024
e9e39ad
feat: graceful shutdown sbi server
yccodr Apr 25, 2024
155556c
fix: loop dependency on nssf app interface
yccodr Apr 29, 2024
fdee497
fix: missing oauth check
yccodr Apr 29, 2024
5838a20
fix: Init NSSF context
andy89923 Apr 29, 2024
cfe9ecd
chore: change logger to align with the right context
yccodr Apr 29, 2024
e6953eb
refactor: add services only when they are configured
yccodr Apr 29, 2024
25fe2c1
Revert "fix: loop dependency on nssf app interface"
yccodr Apr 30, 2024
db71e05
refactor: general app interface
yccodr May 8, 2024
01f38b7
refactor: app statr interface
yccodr May 8, 2024
6d27b3a
refactor: consumer
yccodr May 8, 2024
8a74e48
fix: should not access nssf context before assignment
yccodr May 9, 2024
4488ffb
feat: register procedure graceful shutdown
yccodr May 9, 2024
7f4cf20
fix: init nssf context with wrong function
yccodr May 9, 2024
b00f843
refactor: align naming of route handler
yccodr May 9, 2024
0ed8569
refactor: processor architecture that aligns with other nf repo
yccodr May 10, 2024
4700f68
refactor: nssf context init function
yccodr May 10, 2024
d666c0b
fix: duplicate processor
yccodr May 20, 2024
18cbb37
fix: magic number
yccodr May 20, 2024
54d7510
fix: possibly -1 in index range
yccodr May 20, 2024
f0b8da4
fix: linter complains
yccodr May 20, 2024
277815f
fix: instantiate processor in `NewApp()`
yccodr Jun 4, 2024
d1e1d5f
chore: add comment
yccodr Jun 11, 2024
5827322
chore: fix typo
yccodr Jun 12, 2024
d04c2e4
refactor: create context before `NewApp`
yccodr Jun 14, 2024
0e29e65
fix(nsselection): if `tai` and `homePlmnId` are both missing, return 400
yccodr Jun 14, 2024
201cb73
fix: prevent `app.Terminate()` being called twice
yccodr Jun 25, 2024
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
5 changes: 3 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ func action(cliCtx *cli.Context) error {
}
factory.NssfConfig = cfg

nssf, err := service.NewApp(cfg)
nssf, err := service.NewApp(cfg, tlsKeyLogPath)
if err != nil {
return err
}
NSSF = nssf

nssf.Start(tlsKeyLogPath)
nssf.Start()
nssf.Wait()

return nil
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.8.1
github.com/urfave/cli v1.22.5
go.uber.org/mock v0.4.0
gopkg.in/yaml.v2 v2.4.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
Expand Down
2 changes: 2 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func InitNssfContext() {
nssfContext.Name = nssfConfig.Configuration.NssfName
}

nssfContext.NfId = uuid.New().String()
nssfContext.Name = "NSSF"
nssfContext.UriScheme = nssfConfig.Configuration.Sbi.Scheme
nssfContext.RegisterIPv4 = nssfConfig.Configuration.Sbi.RegisterIPv4
nssfContext.SBIPort = nssfConfig.Configuration.Sbi.Port
Expand Down
235 changes: 235 additions & 0 deletions internal/sbi/api_nssaiavailability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package sbi

import (
"net/http"
"strings"

"github.com/gin-gonic/gin"

"github.com/free5gc/nssf/internal/logger"
"github.com/free5gc/nssf/internal/plugin"
"github.com/free5gc/nssf/internal/util"
"github.com/free5gc/openapi"
"github.com/free5gc/openapi/models"
)

func (s *Server) getNssaiAvailabilityRoutes() []Route {
return []Route{
{
"Health Check",
strings.ToUpper("Get"),
"/",
func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"status": "Service Available"})
},
},

{
"NSSAIAvailabilityDelete",
strings.ToUpper("Delete"),
"/nssai-availability/:nfId",
s.NSSAIAvailabilityDelete,
},

{
"NSSAIAvailabilityPatch",
strings.ToUpper("Patch"),
"/nssai-availability/:nfId",
s.NSSAIAvailabilityPatch,
},

{
"NSSAIAvailabilityPut",
strings.ToUpper("Put"),
"/nssai-availability/:nfId",
s.NSSAIAvailabilityPut,
},

// Regular expressions for route matching should be unique in Gin package
// 'subscriptions' would conflict with existing wildcard ':nfId'
// Simply replace 'subscriptions' with ':nfId' and check if ':nfId' is 'subscriptions' in handler function
{
"NSSAIAvailabilityUnsubscribe",
strings.ToUpper("Delete"),
// "/nssai-availability/subscriptions/:subscriptionId",
"/nssai-availability/:nfId/:subscriptionId",
s.NSSAIAvailabilityUnsubscribeDelete,
},

{
"NSSAIAvailabilityPost",
strings.ToUpper("Post"),
"/nssai-availability/subscriptions",
s.NSSAIAvailabilityPost,
},
}
}

// NSSAIAvailabilityDelete - Deletes an already existing S-NSSAIs per TA
// provided by the NF service consumer (e.g AMF)
func (s *Server) NSSAIAvailabilityDelete(c *gin.Context) {
logger.NssaiavailLog.Infof("Handle NSSAIAvailabilityDelete")

nfId := c.Params.ByName("nfId")

if nfId == "" {
problemDetails := &models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "UNSPECIFIED", // TODO: Check if this is the correct cause
}

util.GinProblemJson(c, problemDetails)
return
}

s.Processor().NssaiAvailabilityNfInstanceDelete(c, nfId)
}

// NSSAIAvailabilityPatch - Updates an already existing S-NSSAIs per TA
// provided by the NF service consumer (e.g AMF)
func (s *Server) NSSAIAvailabilityPatch(c *gin.Context) {
logger.NssaiavailLog.Infof("Handle NSSAIAvailabilityPatch")

nfId := c.Params.ByName("nfId")

if nfId == "" {
problemDetails := &models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "UNSPECIFIED", // TODO: Check if this is the correct cause
}

util.GinProblemJson(c, problemDetails)
return
}

var patchDocument plugin.PatchDocument

requestBody, err := c.GetRawData()
if err != nil {
problemDetails := &models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause: "SYSTEM_FAILURE",
}

util.GinProblemJson(c, problemDetails)
return
}

if err = openapi.Deserialize(&patchDocument, requestBody, "application/json"); err != nil {
problemDetails := &models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "UNSPECIFIED", // TODO: Check if this is the correct cause
}

logger.SBILog.Errorf("Error deserializing patch document: %+v", err)
util.GinProblemJson(c, problemDetails)
return
}

// TODO: Request NfProfile of NfId from NRF
// Check if NfId is valid AMF and obtain AMF Set ID
// If NfId is invalid, return ProblemDetails with code 404 Not Found
// If NF consumer is not authorized to update NSSAI availability, return ProblemDetails with code 403 Forbidden

s.Processor().NssaiAvailabilityNfInstancePatch(c, patchDocument, nfId)
}

// NSSAIAvailabilityPut - Updates/replaces the NSSF
// with the S-NSSAIs the NF service consumer (e.g AMF) supports per TA
func (s *Server) NSSAIAvailabilityPut(c *gin.Context) {
logger.NssaiavailLog.Infof("Handle NSSAIAvailabilityPut")

nfId := c.Params.ByName("nfId")

if nfId == "" {
problemDetails := &models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "UNSPECIFIED", // TODO: Check if this is the correct cause
}

util.GinProblemJson(c, problemDetails)
return
}

var nssaiAvailabilityInfo models.NssaiAvailabilityInfo
data, err := c.GetRawData()
if err != nil {
problemDetails := &models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause: "SYSTEM_FAILURE",
}

util.GinProblemJson(c, problemDetails)
return
}

if err = openapi.Deserialize(&nssaiAvailabilityInfo, data, "application/json"); err != nil {
problemDetails := &models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "UNSPECIFIED", // TODO: Check if this is the correct cause
}

logger.SBILog.Errorf("Error deserializing NSSAI availability info: %+v", err)
util.GinProblemJson(c, problemDetails)
return
}

s.Processor().NssaiAvailabilityNfInstanceUpdate(c, nssaiAvailabilityInfo, nfId)
}

func (s *Server) NSSAIAvailabilityPost(c *gin.Context) {
var createData models.NssfEventSubscriptionCreateData

requestBody, err := c.GetRawData()
if err != nil {
problemDetail := &models.ProblemDetails{
Title: "System failure",
Status: http.StatusInternalServerError,
Detail: err.Error(),
Cause: "SYSTEM_FAILURE",
}
logger.NssaiavailLog.Errorf("Get Request Body error: %+v", err)

util.GinProblemJson(c, problemDetail)
return
}

err = openapi.Deserialize(&createData, requestBody, "application/json")
if err != nil {
problemDetail := "[Request Body] " + err.Error()
rsp := &models.ProblemDetails{
Title: "Malformed request syntax",
Status: http.StatusBadRequest,
Detail: problemDetail,
}
logger.NssaiavailLog.Errorln(problemDetail)

util.GinProblemJson(c, rsp)
return
}

s.Processor().NssaiAvailabilitySubscriptionCreate(c, createData)
}

func (s *Server) NSSAIAvailabilityUnsubscribeDelete(c *gin.Context) {
// Due to conflict of route matching, 'subscriptions' in the route is replaced with the existing wildcard ':nfId'
nfID := c.Param("nfId")
if nfID != "subscriptions" {
c.JSON(http.StatusNotFound, gin.H{})
logger.NssaiavailLog.Infof("404 Not Found")
return
}

subscriptionId := c.Params.ByName("subscriptionId")
if subscriptionId == "" {
problemDetails := &models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "UNSPECIFIED", // TODO: Check if this is the correct cause
}

util.GinProblemJson(c, problemDetails)
return
}

s.Processor().NssaiAvailabilitySubscriptionUnsubscribe(c, subscriptionId)
}
37 changes: 37 additions & 0 deletions internal/sbi/api_nsselection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package sbi

import (
"net/http"
"strings"

"github.com/gin-gonic/gin"

"github.com/free5gc/nssf/internal/logger"
)

func (s *Server) getNsSelectionRoutes() []Route {
return []Route{
{
"Helth Check",
yccodr marked this conversation as resolved.
Show resolved Hide resolved
strings.ToUpper("Get"),
"/",
func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"status": "Service Available"})
},
},

{
"NSSelectionGet",
strings.ToUpper("Get"),
"/network-slice-information",
s.NetworkSliceInformationGet,
},
}
}

func (s *Server) NetworkSliceInformationGet(c *gin.Context) {
logger.NsselLog.Infof("Handle NSSelectionGet")

query := c.Request.URL.Query()
s.Processor().NSSelectionSliceInformationGet(c, query)
}
25 changes: 25 additions & 0 deletions internal/sbi/consumer/consumer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package consumer

import (
"github.com/free5gc/nssf/pkg/app"
"github.com/free5gc/openapi/Nnrf_NFManagement"
)

type Consumer struct {
app.NssfApp

*NrfService
}

func NewConsumer(nssf app.NssfApp) *Consumer {
configuration := Nnrf_NFManagement.NewConfiguration()
configuration.SetBasePath(nssf.Context().NrfUri)
nrfService := &NrfService{
nrfNfMgmtClient: Nnrf_NFManagement.NewAPIClient(configuration),
}

return &Consumer{
NssfApp: nssf,
NrfService: nrfService,
}
}
Loading
Loading