Skip to content
Snippets Groups Projects
Unverified Commit ed2a6c02 authored by brianchennn's avatar brianchennn Committed by GitHub
Browse files

refactor and update util to use new log formatter setting (#37)

parent 248882bd
No related branches found
No related tags found
No related merge requests found
Showing
with 1260 additions and 896 deletions
...@@ -14,6 +14,9 @@ log/ ...@@ -14,6 +14,9 @@ log/
vendor/ vendor/
public/ public/
node_modules/
yarn.lock
# emacs/vim # emacs/vim
GPATH GPATH
GRTAGS GRTAGS
......
This diff is collapsed.
...@@ -2,11 +2,8 @@ package WebUI ...@@ -2,11 +2,8 @@ package WebUI
type FlowRule struct { type FlowRule struct {
Filter string `json:"filter,omitempty" yaml:"filter" bson:"filter" mapstructure:"filter"` Filter string `json:"filter,omitempty" yaml:"filter" bson:"filter" mapstructure:"filter"`
Precedence int `json:"precedence,omitempty" yaml:"precedence" bson:"precedence" mapstructure:"precedence"`
Snssai string `json:"snssai,omitempty" yaml:"snssai" bson:"snssai" mapstructure:"snssai"` Snssai string `json:"snssai,omitempty" yaml:"snssai" bson:"snssai" mapstructure:"snssai"`
Dnn string `json:"dnn,omitempty" yaml:"v" bson:"dnn" mapstructure:"dnn"` Dnn string `json:"dnn,omitempty" yaml:"dnn" bson:"dnn" mapstructure:"dnn"`
Var5QI int `json:"5qi,omitempty" yaml:"5qi" bson:"5qi" mapstructure:"5qi"` QFI int `json:"qfi,omitempty" yaml:"qfi" bson:"qfi" mapstructure:"qfi"`
MBRUL string `json:"mbrUL,omitempty" yaml:"mbrUL" bson:"mbrUL" mapstructure:"mbrUL"`
MBRDL string `json:"mbrDL,omitempty" yaml:"mbrDL" bson:"mbrDL" mapstructure:"mbrDL"`
GBRUL string `json:"gbrUL,omitempty" yaml:"gbrUL" bson:"gbrUL" mapstructure:"gbrUL"`
GBRDL string `json:"gbrDL,omitempty" yaml:"gbrDL" bson:"gbrDL" mapstructure:"gbrDL"`
} }
package WebUI
type QosFlow struct {
Snssai string `json:"snssai" yaml:"snssai" bson:"snssai" mapstructure:"snssai"`
Dnn string `json:"dnn" yaml:"dnn" bson:"dnn" mapstructure:"dnn"`
QFI uint8 `json:"qfi" yaml:"qfi" bson:"qfi" mapstructure:"qfi"`
Var5QI int `json:"5qi" yaml:"5qi" bson:"5qi" mapstructure:"5qi"`
MBRUL string `json:"mbrUL,omitempty" yaml:"mbrUL" bson:"mbrUL" mapstructure:"mbrUL"`
MBRDL string `json:"mbrDL,omitempty" yaml:"mbrDL" bson:"mbrDL" mapstructure:"mbrDL"`
GBRUL string `json:"gbrUL,omitempty" yaml:"gbrUL" bson:"gbrUL" mapstructure:"gbrUL"`
GBRDL string `json:"gbrDL,omitempty" yaml:"gbrDL" bson:"gbrDL" mapstructure:"gbrDL"`
}
...@@ -14,4 +14,5 @@ type SubsData struct { ...@@ -14,4 +14,5 @@ type SubsData struct {
AmPolicyData models.AmPolicyData `json:"AmPolicyData"` AmPolicyData models.AmPolicyData `json:"AmPolicyData"`
SmPolicyData models.SmPolicyData `json:"SmPolicyData"` SmPolicyData models.SmPolicyData `json:"SmPolicyData"`
FlowRules []FlowRule `json:"FlowRules"` FlowRules []FlowRule `json:"FlowRules"`
QosFlows []QosFlow `json:"QosFlows"`
} }
...@@ -3,4 +3,5 @@ package WebUI ...@@ -3,4 +3,5 @@ package WebUI
type SubsListIE struct { type SubsListIE struct {
PlmnID string `json:"plmnID"` PlmnID string `json:"plmnID"`
UeId string `json:"ueId"` UeId string `json:"ueId"`
Msisdn string `json:"msisdn"`
} }
...@@ -165,6 +165,13 @@ var routes = Routes{ ...@@ -165,6 +165,13 @@ var routes = Routes{
PostSubscriberByID, PostSubscriberByID,
}, },
{
"PostMultiSubscriber",
http.MethodPost,
"/subscriber/:ueId/:servingPlmnId/:userNumber",
PostSubscriberByID,
},
{ {
"PutSubscriberByID", "PutSubscriberByID",
http.MethodPut, http.MethodPut,
......
...@@ -7,32 +7,145 @@ ...@@ -7,32 +7,145 @@
package factory package factory
import ( import (
logger_util "github.com/free5gc/util/logger" "fmt"
"sync"
"github.com/asaskevich/govalidator"
"github.com/free5gc/webconsole/backend/logger"
)
const (
WebuiDefaultTLSKeyLogPath = "./log/webuisslkey.log"
WebuiDefaultCertPemPath = "./cert/webui.pem"
WebuiDefaultPrivateKeyPath = "./cert/webui.key"
WebuiDefaultConfigPath = "./config/webuicfg.yaml"
) )
type Config struct { type Config struct {
Info *Info `yaml:"info"` Info *Info `yaml:"info" valid:"required"`
Configuration *Configuration `yaml:"configuration"` Configuration *Configuration `yaml:"configuration" valid:"required"`
Logger *logger_util.Logger `yaml:"logger"` Logger *Logger `yaml:"logger" valid:"required"`
sync.RWMutex
}
func (c *Config) Validate() (bool, error) {
result, err := govalidator.ValidateStruct(c)
return result, appendInvalid(err)
} }
type Info struct { type Info struct {
Version string `yaml:"version,omitempty"` Version string `yaml:"version,omitempty" valid:"required,in(1.0.1)"`
Description string `yaml:"description,omitempty"` Description string `yaml:"description,omitempty" valid:"type(string)"`
} }
type Configuration struct { type Configuration struct {
WebServer *WebServer `yaml:"WebServer,omitempty"` WebServer *WebServer `yaml:"webServer,omitempty" valid:"optional"`
Mongodb *Mongodb `yaml:"mongodb"` Mongodb *Mongodb `yaml:"mongodb" valid:"required"`
}
type Logger struct {
Enable bool `yaml:"enable" valid:"type(bool)"`
Level string `yaml:"level" valid:"required,in(trace|debug|info|warn|error|fatal|panic)"`
ReportCaller bool `yaml:"reportCaller" valid:"type(bool)"`
} }
type WebServer struct { type WebServer struct {
Scheme string `yaml:"scheme"` Scheme string `yaml:"scheme" valid:"required"`
IP string `yaml:"ipv4Address"` IP string `yaml:"ipv4Address" valid:"required"`
PORT string `yaml:"port"` PORT string `yaml:"port" valid:"required"`
} }
type Mongodb struct { type Mongodb struct {
Name string `yaml:"name"` Name string `yaml:"name" valid:"required"`
Url string `yaml:"url"` Url string `yaml:"url" valid:"required"`
}
func appendInvalid(err error) error {
var errs govalidator.Errors
if err == nil {
return nil
}
es := err.(govalidator.Errors).Errors()
for _, e := range es {
errs = append(errs, fmt.Errorf("invalid %w", e))
}
return error(errs)
}
func (c *Config) SetLogEnable(enable bool) {
c.Lock()
defer c.Unlock()
if c.Logger == nil {
logger.CfgLog.Warnf("Logger should not be nil")
c.Logger = &Logger{
Enable: enable,
Level: "info",
}
} else {
c.Logger.Enable = enable
}
}
func (c *Config) SetLogLevel(level string) {
c.Lock()
defer c.Unlock()
if c.Logger == nil {
logger.CfgLog.Warnf("Logger should not be nil")
c.Logger = &Logger{
Level: level,
}
} else {
c.Logger.Level = level
}
}
func (c *Config) SetLogReportCaller(reportCaller bool) {
c.Lock()
defer c.Unlock()
if c.Logger == nil {
logger.CfgLog.Warnf("Logger should not be nil")
c.Logger = &Logger{
Level: "info",
ReportCaller: reportCaller,
}
} else {
c.Logger.ReportCaller = reportCaller
}
}
func (c *Config) GetLogEnable() bool {
c.RLock()
defer c.RUnlock()
if c.Logger == nil {
logger.CfgLog.Warnf("Logger should not be nil")
return false
}
return c.Logger.Enable
}
func (c *Config) GetLogLevel() string {
c.RLock()
defer c.RUnlock()
if c.Logger == nil {
logger.CfgLog.Warnf("Logger should not be nil")
return "info"
}
return c.Logger.Level
}
func (c *Config) GetLogReportCaller() bool {
c.RLock()
defer c.RUnlock()
if c.Logger == nil {
logger.CfgLog.Warnf("Logger should not be nil")
return false
}
return c.Logger.ReportCaller
} }
...@@ -8,22 +8,45 @@ import ( ...@@ -8,22 +8,45 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"github.com/asaskevich/govalidator"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/free5gc/webconsole/backend/logger"
) )
var WebUIConfig Config var WebuiConfig *Config
// TODO: Support configuration update from REST api // TODO: Support configuration update from REST api
func InitConfigFactory(f string) error { func InitConfigFactory(f string, cfg *Config) error {
if f == "" {
// Use default config path
f = WebuiDefaultConfigPath
}
if content, err := ioutil.ReadFile(f); err != nil { if content, err := ioutil.ReadFile(f); err != nil {
return fmt.Errorf("[Configuration] %+v", err) return fmt.Errorf("[Factory] %+v", err)
} else { } else {
WebUIConfig = Config{} logger.CfgLog.Infof("Read config from [%s]", f)
if yamlErr := yaml.Unmarshal(content, &cfg); yamlErr != nil {
if yamlErr := yaml.Unmarshal(content, &WebUIConfig); yamlErr != nil { return fmt.Errorf("[Factory] %+v", yamlErr)
return fmt.Errorf("[Configuration] %+v", yamlErr)
} }
} }
return nil return nil
} }
func ReadConfig(cfgPath string) (*Config, error) {
cfg := &Config{}
if err := InitConfigFactory(cfgPath, cfg); err != nil {
return nil, fmt.Errorf("ReadConfig [%s] Error: %+v", cfgPath, err)
}
if _, err := cfg.Validate(); err != nil {
validErrs := err.(govalidator.Errors).Errors()
for _, validErr := range validErrs {
logger.CfgLog.Errorf("%+v", validErr)
}
logger.CfgLog.Errorf("[-- PLEASE REFER TO SAMPLE CONFIG FILE COMMENTS --]")
return nil, fmt.Errorf("Config validate Error")
}
return cfg, nil
}
package logger package logger
import ( import (
"os"
"time"
formatter "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
logger_util "github.com/free5gc/util/logger" logger_util "github.com/free5gc/util/logger"
) )
var ( var (
log *logrus.Logger Log *logrus.Logger
AppLog *logrus.Entry NfLog *logrus.Entry
MainLog *logrus.Entry
InitLog *logrus.Entry InitLog *logrus.Entry
WebUILog *logrus.Entry ProcLog *logrus.Entry
ContextLog *logrus.Entry CtxLog *logrus.Entry
CfgLog *logrus.Entry
GinLog *logrus.Entry GinLog *logrus.Entry
) )
func init() { func init() {
log = logrus.New() fieldsOrder := []string{
log.SetReportCaller(false) logger_util.FieldNF,
logger_util.FieldCategory,
log.Formatter = &formatter.Formatter{ }
TimestampFormat: time.RFC3339Nano, Log = logger_util.New(fieldsOrder)
TrimMessages: true, NfLog = Log.WithField(logger_util.FieldNF, "WEBUI")
NoFieldsSpace: true, MainLog = NfLog.WithField(logger_util.FieldCategory, "Main")
HideKeys: true, InitLog = NfLog.WithField(logger_util.FieldCategory, "Init")
FieldsOrder: []string{"component", "category"}, ProcLog = NfLog.WithField(logger_util.FieldCategory, "Proc")
} CtxLog = NfLog.WithField(logger_util.FieldCategory, "CTX")
CfgLog = NfLog.WithField(logger_util.FieldCategory, "CFG")
AppLog = log.WithFields(logrus.Fields{"component": "WebUI", "category": "App"}) GinLog = NfLog.WithField(logger_util.FieldCategory, "GIN")
InitLog = log.WithFields(logrus.Fields{"component": "WebUI", "category": "Init"})
WebUILog = log.WithFields(logrus.Fields{"component": "WebUI", "category": "WebUI"})
ContextLog = log.WithFields(logrus.Fields{"component": "WebUI", "category": "Context"})
GinLog = log.WithFields(logrus.Fields{"component": "WebUI", "category": "GIN"})
}
func LogFileHook(logNfPath string, log5gcPath string) error {
if fullPath, err := logger_util.CreateFree5gcLogFile(log5gcPath); err == nil {
if fullPath != "" {
free5gcLogHook, hookErr := logger_util.NewFileHook(fullPath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0o666)
if hookErr != nil {
return hookErr
}
log.Hooks.Add(free5gcLogHook)
}
} else {
return err
}
if fullPath, err := logger_util.CreateNfLogFile(logNfPath, "webconsole.log"); err == nil {
selfLogHook, hookErr := logger_util.NewFileHook(fullPath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0o666)
if hookErr != nil {
return hookErr
}
log.Hooks.Add(selfLogHook)
} else {
return err
}
return nil
}
func SetLogLevel(level logrus.Level) {
log.SetLevel(level)
}
func SetReportCaller(enable bool) {
log.SetReportCaller(enable)
} }
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/free5gc/webconsole/backend/logger" "github.com/free5gc/webconsole/backend/logger"
) )
var webuiContext = WEBUIContext{} var webuiContext WEBUIContext
type WEBUIContext struct { type WEBUIContext struct {
NFProfiles []models.NfProfile NFProfiles []models.NfProfile
...@@ -22,18 +22,15 @@ type NfOamInstance struct { ...@@ -22,18 +22,15 @@ type NfOamInstance struct {
Uri string Uri string
} }
func init() {
}
func (context *WEBUIContext) UpdateNfProfiles() { func (context *WEBUIContext) UpdateNfProfiles() {
nfProfilesRaw, err := mongoapi.RestfulAPIGetMany("NfProfile", nil) nfProfilesRaw, err := mongoapi.RestfulAPIGetMany("NfProfile", nil)
if err != nil { if err != nil {
logger.ContextLog.Error(err) logger.CtxLog.Error(err)
return return
} }
var nfProfiles []models.NfProfile var nfProfiles []models.NfProfile
if err := timedecode.Decode(nfProfilesRaw, &nfProfiles); err != nil { if err := timedecode.Decode(nfProfilesRaw, &nfProfiles); err != nil {
logger.ContextLog.Error(err) logger.CtxLog.Error(err)
return return
} }
...@@ -105,7 +102,7 @@ func (context *WEBUIContext) GetOamUris(targetNfType models.NfType) (uris []stri ...@@ -105,7 +102,7 @@ func (context *WEBUIContext) GetOamUris(targetNfType models.NfType) (uris []stri
return return
} }
func WEBUI_Self() *WEBUIContext { func GetSelf() *WEBUIContext {
return &webuiContext return &webuiContext
} }
......
package webui_service package webui_service
import ( import (
"bufio" "io/ioutil"
"fmt" "os"
"os/exec"
"path/filepath"
"runtime/debug"
"sync"
"github.com/gin-contrib/cors" "github.com/gin-contrib/cors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/free5gc/util/mongoapi" "github.com/free5gc/util/mongoapi"
"github.com/free5gc/webconsole/backend/WebUI" "github.com/free5gc/webconsole/backend/WebUI"
...@@ -19,118 +14,70 @@ import ( ...@@ -19,118 +14,70 @@ import (
"github.com/free5gc/webconsole/backend/webui_context" "github.com/free5gc/webconsole/backend/webui_context"
) )
type WEBUI struct{} type WebuiApp struct {
cfg *factory.Config
type ( webuiCtx *webui_context.WEBUIContext
// Commands information.
Commands struct {
config string
public string
} }
)
var commands Commands func NewApp(cfg *factory.Config) (*WebuiApp, error) {
webui := &WebuiApp{cfg: cfg}
webui.SetLogEnable(cfg.GetLogEnable())
webui.SetLogLevel(cfg.GetLogLevel())
webui.SetReportCaller(cfg.GetLogReportCaller())
var cliCmd = []cli.Flag{ webui.webuiCtx = webui_context.GetSelf()
cli.StringFlag{ return webui, nil
Name: "public, p",
Usage: "Load public path from `FOLDER`",
},
cli.StringFlag{
Name: "config, c",
Usage: "Load configuration from `FILE`",
},
cli.StringFlag{
Name: "log, l",
Usage: "Output NF log to `FILE`",
},
cli.StringFlag{
Name: "log5gc, lc",
Usage: "Output free5gc log to `FILE`",
},
} }
var initLog *logrus.Entry func (a *WebuiApp) SetLogEnable(enable bool) {
logger.MainLog.Infof("Log enable is set to [%v]", enable)
func (*WEBUI) GetCliCmd() (flags []cli.Flag) { if enable && logger.Log.Out == os.Stderr {
return cliCmd return
} } else if !enable && logger.Log.Out == ioutil.Discard {
return
func (webui *WEBUI) Initialize(c *cli.Context) error {
commands = Commands{
config: c.String("config"),
public: c.String("public"),
}
initLog = logger.InitLog
if commands.config != "" {
if err := factory.InitConfigFactory(commands.config); err != nil {
return err
} }
a.cfg.SetLogEnable(enable)
if enable {
logger.Log.SetOutput(os.Stderr)
} else { } else {
if err := factory.InitConfigFactory("./config/webuicfg.yaml"); err != nil { logger.Log.SetOutput(ioutil.Discard)
return err
}
}
if commands.public != "" {
PublicPath = filepath.Clean(commands.public)
} }
webui.setLogLevel()
return nil
} }
func (webui *WEBUI) setLogLevel() { func (a *WebuiApp) SetLogLevel(level string) {
if factory.WebUIConfig.Logger == nil { lvl, err := logrus.ParseLevel(level)
initLog.Warnln("Webconsole config without log level setting!!!") if err != nil {
logger.MainLog.Warnf("Log level [%s] is invalid", level)
return return
} }
logger.MainLog.Infof("Log level is set to [%s]", level)
if factory.WebUIConfig.Logger.WEBUI != nil { if lvl == logger.Log.GetLevel() {
if factory.WebUIConfig.Logger.WEBUI.DebugLevel != "" { return
if level, err := logrus.ParseLevel(factory.WebUIConfig.Logger.WEBUI.DebugLevel); err != nil {
initLog.Warnf("WebUI Log level [%s] is invalid, set to [info] level",
factory.WebUIConfig.Logger.WEBUI.DebugLevel)
logger.SetLogLevel(logrus.InfoLevel)
} else {
initLog.Infof("WebUI Log level is set to [%s] level", level)
logger.SetLogLevel(level)
}
} else {
initLog.Warnln("WebUI Log level not set. Default set to [info] level")
logger.SetLogLevel(logrus.InfoLevel)
}
logger.SetReportCaller(factory.WebUIConfig.Logger.WEBUI.ReportCaller)
}
} }
a.cfg.SetLogLevel(level)
func (webui *WEBUI) FilterCli(c *cli.Context) (args []string) { logger.Log.SetLevel(lvl)
for _, flag := range webui.GetCliCmd() {
name := flag.GetName()
value := fmt.Sprint(c.Generic(name))
if value == "" {
continue
} }
args = append(args, "--"+name, value) func (a *WebuiApp) SetReportCaller(reportCaller bool) {
logger.MainLog.Infof("Report Caller is set to [%v]", reportCaller)
if reportCaller == logger.Log.ReportCaller {
return
} }
return args a.cfg.SetLogReportCaller(reportCaller)
logger.Log.SetReportCaller(reportCaller)
} }
func (webui *WEBUI) Start() { func (a *WebuiApp) Start(tlsKeyLogPath string) {
// get config file info from WebUIConfig // get config file info from WebUIConfig
mongodb := factory.WebUIConfig.Configuration.Mongodb mongodb := factory.WebuiConfig.Configuration.Mongodb
// Connect to MongoDB // Connect to MongoDB
if err := mongoapi.SetMongoDB(mongodb.Name, mongodb.Url); err != nil { if err := mongoapi.SetMongoDB(mongodb.Name, mongodb.Url); err != nil {
initLog.Errorf("Server start err: %+v", err) logger.InitLog.Errorf("Server start err: %+v", err)
return return
} }
initLog.Infoln("Server started") logger.InitLog.Infoln("Server started")
router := WebUI.NewRouter() router := WebUI.NewRouter()
...@@ -146,79 +93,10 @@ func (webui *WEBUI) Start() { ...@@ -146,79 +93,10 @@ func (webui *WEBUI) Start() {
MaxAge: 86400, MaxAge: 86400,
})) }))
self := webui_context.WEBUI_Self() self := webui_context.GetSelf()
self.UpdateNfProfiles() self.UpdateNfProfiles()
router.NoRoute(ReturnPublic()) router.NoRoute(ReturnPublic())
initLog.Infoln(router.Run(":5000")) logger.InitLog.Infoln(router.Run(":5000"))
}
func (webui *WEBUI) Exec(c *cli.Context) error {
initLog.Traceln("args:", c.String("webuicfg"))
args := webui.FilterCli(c)
initLog.Traceln("filter: ", args)
command := exec.Command("./webui", args...)
if err := webui.Initialize(c); err != nil {
return err
}
stdout, err := command.StdoutPipe()
if err != nil {
initLog.Fatalln(err)
}
wg := sync.WaitGroup{}
wg.Add(3)
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()))
}
}()
in := bufio.NewScanner(stdout)
for in.Scan() {
fmt.Println(in.Text())
}
wg.Done()
}()
stderr, err := command.StderrPipe()
if err != nil {
initLog.Fatalln(err)
}
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()))
}
}()
in := bufio.NewScanner(stderr)
for in.Scan() {
fmt.Println(in.Text())
}
wg.Done()
}()
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()))
}
}()
if errCmd := command.Start(); errCmd != nil {
fmt.Println("command.Start Fails!")
}
wg.Done()
}()
wg.Wait()
return err
} }
info: info:
version: 1.0.0 version: 1.0.1
description: WebUI initial local configuration description: WebUI initial local configuration
configuration: configuration:
...@@ -7,10 +7,7 @@ configuration: ...@@ -7,10 +7,7 @@ configuration:
name: free5gc # name of the mongodb name: free5gc # name of the mongodb
url: mongodb://localhost:27017 # a valid URL of the mongodb url: mongodb://localhost:27017 # a valid URL of the mongodb
# the kind of log output logger: # log output setting
# debugLevel: how detailed to output, value: trace, debug, info, warn, error, fatal, panic enable: true # true or false
# ReportCaller: enable the caller report or not, value: true or false level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
logger: reportCaller: false # enable the caller report or not, value: true or false
WEBUI:
debugLevel: info
ReportCaller: false
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
"private": true, "private": true,
"homepage": "", "homepage": "",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.15.2",
"autoprefixer": "7.1.2", "autoprefixer": "7.1.2",
"axios": "latest", "axios": "latest",
"babel-core": "6.26.3", "babel-core": "6.26.3",
...@@ -12,6 +13,7 @@ ...@@ -12,6 +13,7 @@
"babel-loader": "7.1.1", "babel-loader": "7.1.1",
"babel-preset-react-app": "^3.0.2", "babel-preset-react-app": "^3.0.2",
"babel-runtime": "6.26.0", "babel-runtime": "6.26.0",
"bootstrap": "~3.3.6",
"case-sensitive-paths-webpack-plugin": "2.4.0", "case-sensitive-paths-webpack-plugin": "2.4.0",
"chalk": "1.1.3", "chalk": "1.1.3",
"classnames": "^2.2.5", "classnames": "^2.2.5",
...@@ -60,7 +62,7 @@ ...@@ -60,7 +62,7 @@
"whatwg-fetch": "2.0.3" "whatwg-fetch": "2.0.3"
}, },
"devDependencies": { "devDependencies": {
"sass": "^1.50.0", "sass": "1.51.0",
"sass-loader": "^7.0.1", "sass-loader": "^7.0.1",
"webpack-dev-server": "2.9.7", "webpack-dev-server": "2.9.7",
"ws": "3.3.2" "ws": "3.3.2"
......
...@@ -4,10 +4,6 @@ ...@@ -4,10 +4,6 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000"> <meta name="theme-color" content="#000000">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:100,400,600,700" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.0/gh-fork-ribbon.min.css" />
<!-- <!--
manifest.json provides metadata used when your web app is added to the manifest.json provides metadata used when your web app is added to the
...@@ -38,6 +34,5 @@ ...@@ -38,6 +34,5 @@
Loading... Loading...
</div> </div>
<script src="https://unpkg.com/react-jsonschema-form/dist/react-jsonschema-form.js"></script>
</body> </body>
</html> </html>
...@@ -6,8 +6,8 @@ import checkImage from 'assets/images/radio-2.svg'; ...@@ -6,8 +6,8 @@ import checkImage from 'assets/images/radio-2.svg';
class Radio extends Component { class Radio extends Component {
componentWillReceiveProps(props) { static getDerivedStateFromProps(nextProps, prevState){
console.log(props); console.log(nextProps);
} }
render() { render() {
......
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker'; import {Provider} from 'react-redux';
import {HashRouter} from 'react-router-dom'; import {HashRouter} from 'react-router-dom';
import './assets/styles/base.scss';
import App from './pages/App'; import App from './pages/App';
import configureStore from './config/configureStore'; import configureStore from './config/configureStore';
import {Provider} from 'react-redux'; import registerServiceWorker from './registerServiceWorker';
// dependency CSS
import 'bootstrap/dist/css/bootstrap.min.css';
import '@fortawesome/fontawesome-free/css/all.min.css';
import './assets/styles/base.scss';
export const store = configureStore(); export const store = configureStore();
const rootElement = document.getElementById('root'); const rootElement = document.getElementById('root');
......
...@@ -16,6 +16,7 @@ let subModalSchema = { ...@@ -16,6 +16,7 @@ let subModalSchema = {
"K", "K",
"OPOPcSelect", "OPOPcSelect",
"OPOPc", "OPOPc",
"AMF",
"SQN", "SQN",
], ],
properties: { properties: {
...@@ -38,6 +39,12 @@ let subModalSchema = { ...@@ -38,6 +39,12 @@ let subModalSchema = {
pattern: "^[0-9]{10,15}$", pattern: "^[0-9]{10,15}$",
default: "208930000000003", default: "208930000000003",
}, },
msisdn: {
type: "string",
title: "MSISDN",
pattern: "^$|^[0-9]{5,15}$",
default: ""
},
authenticationMethod: { authenticationMethod: {
type: "string", type: "string",
title: "Authentication Method", title: "Authentication Method",
...@@ -62,6 +69,12 @@ let subModalSchema = { ...@@ -62,6 +69,12 @@ let subModalSchema = {
pattern: "^[A-Fa-f0-9]{32}$", pattern: "^[A-Fa-f0-9]{32}$",
default: "8e27b6af0e692e750f32667a3b14605d", default: "8e27b6af0e692e750f32667a3b14605d",
}, },
AMF: {
type: "string",
title: "Authentication Management Field (AMF)",
pattern: "^[A-Fa-f0-9]{4}$",
default: "8000",
},
SQN: { SQN: {
type: "string", type: "string",
title: "SQN", title: "SQN",
......
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
export default class Subscriber { export default class Subscriber {
id = ''; id = '';
plmn = ''; plmn = '';
msisdn = '';
constructor(id, plmn) { constructor(id, plmn, msisdn) {
this.id = id; this.id = id;
this.plmn = plmn; this.plmn = plmn;
} this.msisdn = msisdn;
};
} }
...@@ -29,28 +29,44 @@ class SubscriberOverview extends Component { ...@@ -29,28 +29,44 @@ class SubscriberOverview extends Component {
*/ */
async openEditSubscriber(subscriberId, plmn) { async openEditSubscriber(subscriberId, plmn) {
const subscriber = await ApiHelper.fetchSubscriberById(subscriberId, plmn); const subscriber = await ApiHelper.fetchSubscriberById(subscriberId, plmn);
let origiData = subscriber;
if (subscriber.FlowRules !== undefined && subscriber.FlowRules !== null) {
subscriber.FlowRules.forEach(FlowRule => {
let i = 0;
subscriber.QosFlows.forEach(QosFlow => {
if (QosFlow.snssai === FlowRule.snssai &&
QosFlow.dnn === FlowRule.dnn &&
QosFlow["5qi"] === FlowRule.qfi) {
if (origiData.QosFlows[i].flowRules === undefined) {
origiData.QosFlows[i].flowRules = [];
}
origiData.QosFlows[i].flowRules.push(Object.assign({ precedence: FlowRule.precedence, filter: FlowRule.filter }))
}
i++;
})
});
}
delete origiData.FlowRules;
this.setState({ this.setState({
subscriberModalOpen: true, subscriberModalOpen: true,
subscriberModalData: subscriber, subscriberModalData: origiData,
}); });
} }
async addSubscriber(subscriberData) { async addSubscriber(subscriberData) {
this.setState({ subscriberModalOpen: false }); this.setState({ subscriberModalOpen: false });
let userNumber = subscriberData["userNumber"]; let userNumber = subscriberData["userNumber"];
delete subscriberData["userNumber"];
let imsiLength = subscriberData["ueId"].length - 5
let imsi = subscriberData["ueId"].substr(5, imsiLength);
for(let i = 0; i < userNumber; i++){
let newImsi = (Number(imsi) + i).toString();
newImsi = newImsi.padStart(imsiLength, '0')
subscriberData["ueId"] = `imsi-${newImsi}`;
if (!await ApiHelper.createSubscriber(subscriberData)) { if (!await ApiHelper.createSubscriber(subscriberData)) {
if (userNumber > 1) {
alert("Error creating new multiple subscribers when create user");
}
else if (userNumber === 1) {
alert("Error creating new subscriber when create user"); alert("Error creating new subscriber when create user");
} }
ApiHelper.fetchSubscribers().then();
} }
delete subscriberData["userNumber"];
ApiHelper.fetchSubscribers().then();
} }
/** /**
...@@ -99,7 +115,8 @@ class SubscriberOverview extends Component { ...@@ -99,7 +115,8 @@ class SubscriberOverview extends Component {
<thead> <thead>
<tr> <tr>
<th style={{ width: 80 }}>PLMN</th> <th style={{ width: 80 }}>PLMN</th>
<th colSpan={2}>UE ID</th> <th>UE ID</th>
<th>MSISDN</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -107,6 +124,7 @@ class SubscriberOverview extends Component { ...@@ -107,6 +124,7 @@ class SubscriberOverview extends Component {
<tr key={subscriber.id}> <tr key={subscriber.id}>
<td>{subscriber.plmn}</td> <td>{subscriber.plmn}</td>
<td>{subscriber.id}</td> <td>{subscriber.id}</td>
<td>{subscriber.msisdn}</td>
<td style={{ textAlign: 'center' }}> <td style={{ textAlign: 'center' }}>
<Button variant="danger" onClick={this.deleteSubscriber.bind(this, subscriber)}>Delete</Button> <Button variant="danger" onClick={this.deleteSubscriber.bind(this, subscriber)}>Delete</Button>
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment