From f615f1c77d0bd59211bda011784cd49f7ac2904b Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Tue, 26 Mar 2024 10:40:02 +0800 Subject: [PATCH 1/8] feat(resolv): preliminary completion of the development and testing of the `resolve` V3 version, as well as the update of the `bifrost` service to the `resolve` V3 version. BREAKING CHANGE: replacing the nginx configuration resolving library from version `V2` to `V3`. To migrate the code follow the example below: Before: ```go import ( "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration" ) nginxConfFromPath, err := configuration.NewConfigurationFromPath(configAbsPath) nginxConfFromJsonBytes, err := configuration.NewConfigurationFromJsonBytes(configJsonBytes) ``` After: ```go import ( "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" ) nginxConfFromPath, err := configuration.NewNginxConfigFromFS(configAbsPath) nginxConfFromJsonBytes, err := configuration.NewNginxConfigFromJsonBytes(configJsonBytes) ``` Example for querying and inserting context: ```go import ( "fmt" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" ) conf, err := configuration.NewNginxConfigFromJsonBytes(jsondata) if err != nil { t.Fatal(err) } for _, pos := range conf.Main().QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp)).Target(). QueryByKeyWords(context.NewKeyWords(context_type.TypeServer)).Target(). QueryAllByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetStringMatchingValue("server_name test1.com")) { // query `server` context, its server name is "test1.com" server, _ := pos.Position() if server.QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexpMatchingValue("^listen 80$")).Target().Error() != nil { // query `server` context, its listen port is 80 continue } // query the "proxy_pass" `directive` context, which is in `if` context(value: "($http_api_name != '')") and `location` context(value: "/test1-location") ctx, idx := server.QueryByKeyWords(context.NewKeyWords(context_type.TypeLocation).SetRegexpMatchingValue(`^/test1-location$`)).Target(). QueryByKeyWords(context.NewKeyWords(context_type.TypeIf).SetRegexpMatchingValue(`^\(\$http_api_name != ''\)$`)).Target(). QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetStringMatchingValue("proxy_pass")).Position() // insert an inline comment after the "proxy_pass" `directive` context err = ctx.Insert(local.NewComment(fmt.Sprintf("[%s]test comments", time.Now().String()), true), idx+1).Error() if err != nil { return err } } ``` Examples for building nginx context object: ```go import ( "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" ) // new main context newMainContext, err := local.NewMain("/usr/local/nginx/conf/nginx.conf") // new directive context newDirective := local.NewDirective("some_directive", "some params") // new comment context newComment := local.NewComment("some comments", false) // new other context newConfig := local.NewContext(context_type.TypeConfig, "conf.d/location.conf") newInclude := local.NewContext(context_type.TypeInclude, "conf.d/*.conf") newHttp := local.NewContext(context_type.TypeHttp, "") ... ``` --- configs/bifrost.yml | 31 +- go.mod | 1 + go.sum | 2 + internal/bifrost/app.go | 6 +- internal/bifrost/logger.go | 17 + .../bifrost/middleware/logging/logging.go | 4 +- internal/bifrost/options/options.go | 5 +- internal/bifrost/router.go | 4 +- internal/bifrost/run.go | 10 + internal/bifrost/server.go | 18 +- internal/bifrost/store/v1/nginx/nginx.go | 51 +- .../store/v1/nginx/web_server_config.go | 6 +- .../store/v1/nginx/web_server_log_watcher.go | 8 +- .../store/v1/nginx/web_server_statistics.go | 4 +- .../store/v1/nginx/web_server_status.go | 8 +- .../transport/v1/fake/web_server_config.go | 8 +- .../transport/v1/handler/web_server_config.go | 8 +- .../v1/handler/web_server_log_watcher.go | 4 +- .../v1/handler/web_server_statistics.go | 4 +- .../transport/v1/handler/web_server_status.go | 4 +- internal/pkg/code/bifrost.go | 3 + internal/pkg/file_watcher/config.go | 5 +- internal/pkg/file_watcher/shunt_pipe.go | 5 +- internal/pkg/file_watcher/watcher.go | 19 +- internal/pkg/logger/config.go | 58 ++ internal/pkg/logger/logger.go | 35 ++ internal/pkg/monitor/monitor.go | 27 +- internal/pkg/options/logger_options.go | 144 +++++ .../pkg/options/secure_serving_options.go | 4 +- .../pkg/options/web_server_config_options.go | 50 +- internal/pkg/server/config.go | 5 +- internal/pkg/server/genericgrpcserver.go | 98 +-- pkg/app/app.go | 299 --------- pkg/app/cmd.go | 113 ---- pkg/app/cmd_linux.go | 7 - pkg/app/cmd_windows.go | 15 - pkg/app/config.go | 69 --- pkg/app/flag.go | 21 - pkg/app/help.go | 52 -- pkg/app/options.go | 28 - .../bifrost/v1/service/web_server_config.go | 4 +- pkg/client/grpc_health_v1/client.go | 5 +- pkg/client/grpc_health_v1/endpoint.go | 11 +- pkg/log/v1/README.md | 134 ---- pkg/log/v1/context.go | 32 - pkg/log/v1/distribution/logger.go | 166 ----- pkg/log/v1/encoder.go | 15 - pkg/log/v1/example/example.go | 65 -- pkg/log/v1/klog/logger.go | 61 -- pkg/log/v1/log.go | 570 ------------------ pkg/log/v1/logrus/hook.go | 59 -- pkg/log/v1/logrus/logger.go | 17 - pkg/log/v1/options.go | 144 ----- pkg/log/v1/types.go | 90 --- pkg/resolv/V2/utils/files_funcs.go | 38 +- pkg/resolv/V3/nginx/config.go | 37 ++ pkg/resolv/V3/nginx/configuration/config.go | 89 +++ .../context/local/basic_context.go | 2 +- .../configuration/context/local/include.go | 4 +- .../nginx/configuration/context/position.go | 11 + .../V3/nginx/configuration/nginx_config.go | 154 +++++ .../configuration/nginx_config_manager.go | 307 ++++++++++ .../nginx_config_statistician.go | 151 +++++ .../nginx/configuration/nginx_config_test.go | 329 ++++++++++ .../utils/config_fingerprintor.go | 79 +++ .../configuration/utils/files_funces_linux.go | 17 + .../utils/files_funcs_windows.go | 24 + pkg/resolv/V3/nginx/nginx.go | 53 ++ test/grpc_client/bifrost/example_server.go | 16 +- test/resolve/nginx/V2/example_config_test.go | 143 +++++ test/resolve/nginx/V2/test_nginx.conf | 0 71 files changed, 1913 insertions(+), 2174 deletions(-) create mode 100644 internal/bifrost/logger.go create mode 100644 internal/pkg/logger/config.go create mode 100644 internal/pkg/logger/logger.go create mode 100644 internal/pkg/options/logger_options.go delete mode 100644 pkg/app/app.go delete mode 100644 pkg/app/cmd.go delete mode 100644 pkg/app/cmd_linux.go delete mode 100644 pkg/app/cmd_windows.go delete mode 100644 pkg/app/config.go delete mode 100644 pkg/app/flag.go delete mode 100644 pkg/app/help.go delete mode 100644 pkg/app/options.go delete mode 100644 pkg/log/v1/README.md delete mode 100644 pkg/log/v1/context.go delete mode 100644 pkg/log/v1/distribution/logger.go delete mode 100644 pkg/log/v1/encoder.go delete mode 100644 pkg/log/v1/example/example.go delete mode 100644 pkg/log/v1/klog/logger.go delete mode 100644 pkg/log/v1/log.go delete mode 100644 pkg/log/v1/logrus/hook.go delete mode 100644 pkg/log/v1/logrus/logger.go delete mode 100644 pkg/log/v1/options.go delete mode 100644 pkg/log/v1/types.go create mode 100644 pkg/resolv/V3/nginx/config.go create mode 100644 pkg/resolv/V3/nginx/configuration/config.go create mode 100644 pkg/resolv/V3/nginx/configuration/nginx_config.go create mode 100644 pkg/resolv/V3/nginx/configuration/nginx_config_manager.go create mode 100644 pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go create mode 100644 pkg/resolv/V3/nginx/configuration/nginx_config_test.go create mode 100644 pkg/resolv/V3/nginx/configuration/utils/config_fingerprintor.go create mode 100644 pkg/resolv/V3/nginx/configuration/utils/files_funces_linux.go create mode 100644 pkg/resolv/V3/nginx/configuration/utils/files_funcs_windows.go create mode 100644 pkg/resolv/V3/nginx/nginx.go create mode 100644 test/resolve/nginx/V2/example_config_test.go create mode 100644 test/resolve/nginx/V2/test_nginx.conf diff --git a/configs/bifrost.yml b/configs/bifrost.yml index f018d1d..1ae00b6 100644 --- a/configs/bifrost.yml +++ b/configs/bifrost.yml @@ -21,7 +21,7 @@ web-server-configs: logs-dir-path: "/usr/local/nginx/logs" # WebServer 日志存放路径 backup-dir: "" # WebServer 配置文件自动备份路径,为空时将使用`config-path`文件的目录路径作为备份目录路径 backup-cycle: 1 # WebServer 配置文件自动备份周期时长,单位(天),为0时不启用自动备份 - backup-save-time: 7 # WebServer 配置文件自动备份归档保存时长,单位(天),为0时不启用自动备份 + backups-retention-duration: 7 # WebServer 配置文件自动备份归档保存时长,单位(天),为0时不启用自动备份 # 注册中心配置 # RA: # 注册中心地址配置 @@ -30,4 +30,31 @@ web-server-configs: # 日志配置 log: - output-paths: "logs/bifrost.log" +# 启用开发模式 +# development: false + +# 禁用日志输出 +# disable-caller: false + +# 禁用日志追踪 +# disable-stracktrace: false + +# 启用代色彩的日志记录 +# enable-color: false + +# 错误日志最低级别, 默认为“warn” +# error-level: warn + +# 错误日志输出路径,默认为“logs/biforst-error.log” +# error-output-paths: +# - logs/bifrost-error.log + +# 日志输出格式,支持“console”,“json”,默认为“console” +# format: console + +# Info日志最低级别,默认为“info” +# info-level: info + +# Info日志输出路径,默认为“logs/bifrost.log” +# info-output-paths: +# - logs/bifrost.log diff --git a/go.mod b/go.mod index 41a0314..9a8595a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/ClessLi/bifrost go 1.21 require ( + github.com/ClessLi/component-base v1.0.6 github.com/ClessLi/skirnir v0.0.0-20201204082302-47fe98943ef8 github.com/apsdehal/go-logger v0.0.0-20190515212710-b0d6ccfee0e6 github.com/dominikbraun/graph v0.23.0 diff --git a/go.sum b/go.sum index 7bb4131..f5bb929 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ClessLi/component-base v1.0.6 h1:6Bdqh53bJ9IRBf/G7G/PEpE8rvIbUZUY/XQo+0PlG+A= +github.com/ClessLi/component-base v1.0.6/go.mod h1:2vzmQ2v95oQHoLfqkPl9mCEHF6mHfYfsL+tgDFamcUA= github.com/ClessLi/skirnir v0.0.0-20201204082302-47fe98943ef8 h1:/pm3l5Ko8ipAkz4X/ILBOMyuQvWadZoJv1hMKXJ/or0= github.com/ClessLi/skirnir v0.0.0-20201204082302-47fe98943ef8/go.mod h1:qPwqPahJKSqS2PvLyA2wQpDhmViqUL/qxZQJXscn7To= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= diff --git a/internal/bifrost/app.go b/internal/bifrost/app.go index 434dfeb..37aa449 100644 --- a/internal/bifrost/app.go +++ b/internal/bifrost/app.go @@ -3,8 +3,7 @@ package bifrost import ( "github.com/ClessLi/bifrost/internal/bifrost/config" "github.com/ClessLi/bifrost/internal/bifrost/options" - "github.com/ClessLi/bifrost/pkg/app" - log "github.com/ClessLi/bifrost/pkg/log/v1" + "github.com/ClessLi/component-base/pkg/app" ) const commandDesc = `The Bifrost is used to parse the nginx configuration file @@ -30,9 +29,6 @@ func NewApp(basename string) *app.App { func run(opts *options.Options) app.RunFunc { return func(basename string) error { - log.Init(opts.Log) - defer log.Flush() - // init auth api client // auth.Init(opts.AuthAPIClient) diff --git a/internal/bifrost/logger.go b/internal/bifrost/logger.go new file mode 100644 index 0000000..a92c33a --- /dev/null +++ b/internal/bifrost/logger.go @@ -0,0 +1,17 @@ +package bifrost + +import ( + "github.com/ClessLi/bifrost/internal/bifrost/config" + "github.com/ClessLi/bifrost/internal/pkg/logger" +) + +func createLogger(cfg *config.Config) (*logger.Logger, error) { + c := logger.NewConfig() + + err := cfg.Log.ApplyTo(c) + if err != nil { + return nil, err + } + + return c.Complete().NewLogger() +} diff --git a/internal/bifrost/middleware/logging/logging.go b/internal/bifrost/middleware/logging/logging.go index cc07df2..67f536f 100644 --- a/internal/bifrost/middleware/logging/logging.go +++ b/internal/bifrost/middleware/logging/logging.go @@ -1,12 +1,12 @@ package logging import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" kitlog "github.com/go-kit/kit/log" svcv1 "github.com/ClessLi/bifrost/internal/bifrost/service/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) var ( @@ -37,7 +37,7 @@ func (l *loggingService) WebServerLogWatcher() svcv1.WebServerLogWatcherService func New(svc svcv1.ServiceFactory) svcv1.ServiceFactory { once.Do(func() { - logger = log.K() + logger = logV1.K() limit = 100 }) diff --git a/internal/bifrost/options/options.go b/internal/bifrost/options/options.go index f345638..b14216e 100644 --- a/internal/bifrost/options/options.go +++ b/internal/bifrost/options/options.go @@ -7,7 +7,6 @@ import ( genericoptions "github.com/ClessLi/bifrost/internal/pkg/options" "github.com/ClessLi/bifrost/internal/pkg/server" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type Options struct { @@ -19,7 +18,7 @@ type Options struct { WebServerConfigsOptions *genericoptions.WebServerConfigsOptions `json:"web-server-configs" mapstructure:"web-server-configs"` MonitorOptions *genericoptions.MonitorOptions `json:"monitor" mapstructure:"monitor"` WebServerLogWatcherOptions *genericoptions.WebServerLogWatcherOptions `json:"web-server-log-watcher" mapstructure:"web-server-log-watcher"` - Log *log.Options `json:"log" mapstructure:"log"` + Log *genericoptions.LoggerOptions `json:"log" mapstructure:"log"` } func NewOptions() *Options { @@ -32,7 +31,7 @@ func NewOptions() *Options { WebServerConfigsOptions: genericoptions.NewWebServerConfigsOptions(), MonitorOptions: genericoptions.NewMonitorOptions(), WebServerLogWatcherOptions: genericoptions.NewWebServerLogWatcherOptions(), - Log: log.NewOptions(), + Log: genericoptions.NewLoggerOptions(), } } diff --git a/internal/bifrost/router.go b/internal/bifrost/router.go index cd262a7..8cb78a2 100644 --- a/internal/bifrost/router.go +++ b/internal/bifrost/router.go @@ -1,6 +1,7 @@ package bifrost import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "time" epv1 "github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1" @@ -11,7 +12,6 @@ import ( handlerv1 "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/handler" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/options" genericgrpcserver "github.com/ClessLi/bifrost/internal/pkg/server" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) func initRouter(server *genericgrpcserver.GenericGRPCServer) { @@ -29,7 +29,7 @@ func initService() svcv1.ServiceFactory { func initMiddleware(svc *svcv1.ServiceFactory) { middlewaresIns := middleware.GetMiddlewares() for name, m := range middlewaresIns { - log.Infof("Install middleware: %s", name) + logV1.Infof("Install middleware: %s", name) *svc = m(*svc) } } diff --git a/internal/bifrost/run.go b/internal/bifrost/run.go index cdbcadc..798531d 100644 --- a/internal/bifrost/run.go +++ b/internal/bifrost/run.go @@ -3,6 +3,16 @@ package bifrost import "github.com/ClessLi/bifrost/internal/bifrost/config" func Run(cfg *config.Config) error { + l, err := createLogger(cfg) + if err != nil { + return err + } + err = l.Init() + if err != nil { + return err + } + defer l.Flush() + server, err := createBifrostServer(cfg) if err != nil { return err diff --git a/internal/bifrost/server.go b/internal/bifrost/server.go index 4a2f240..07a92a2 100644 --- a/internal/bifrost/server.go +++ b/internal/bifrost/server.go @@ -1,6 +1,7 @@ package bifrost import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/marmotedu/iam/pkg/shutdown" "github.com/marmotedu/iam/pkg/shutdown/shutdownmanagers/posixsignal" @@ -9,7 +10,6 @@ import ( storev1nginx "github.com/ClessLi/bifrost/internal/bifrost/store/v1/nginx" genericoptions "github.com/ClessLi/bifrost/internal/pkg/options" genericgrpcserver "github.com/ClessLi/bifrost/internal/pkg/server" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type bifrostServer struct { @@ -25,7 +25,7 @@ type preparedBifrostServer struct { } func createBifrostServer(cfg *config.Config) (*bifrostServer, error) { - log.Debug("create bifrost server...") + logV1.Debug("create bifrost server...") gs := shutdown.New() gs.AddShutdownManager(posixsignal.NewPosixSignalManager()) @@ -51,7 +51,7 @@ func createBifrostServer(cfg *config.Config) (*bifrostServer, error) { } func (b *bifrostServer) PrepareRun() preparedBifrostServer { - log.Debug("prepare run...") + logV1.Debug("prepare run...") b.initStore() initRouter(b.genericGRPCServer) b.gs.AddShutdownCallback(shutdown.ShutdownFunc(func(string) error { @@ -69,26 +69,26 @@ func (b *bifrostServer) PrepareRun() preparedBifrostServer { } func (p preparedBifrostServer) Run() error { - log.Debug("prepareBifrostServer run...") + logV1.Debug("prepareBifrostServer run...") if err := p.gs.Start(); err != nil { - log.Fatalf("start shutdown manager failed: %s", err.Error()) + logV1.Fatalf("start shutdown manager failed: %s", err.Error()) } - log.Infof("the generic gRPC server is going to run...") + logV1.Infof("the generic gRPC server is going to run...") return p.genericGRPCServer.Run() } func (b *bifrostServer) initStore() { - log.Debug("bifrost server init store...") + logV1.Debug("bifrost server init store...") storeIns, err := storev1nginx.GetNginxStoreFactory(b.webSvrConfigsOpts, b.monitorOpts, b.webSvrLogWatcherOpts) if err != nil { - log.Fatalf("init nginx store failed: %+v", err) + logV1.Fatalf("init nginx store failed: %+v", err) } storev1.SetClient(storeIns) } func buildGenericConfig(cfg *config.Config) (genericConfig *genericgrpcserver.Config, lastErr error) { - log.Debug("build generic config, apply all options to generic config") + logV1.Debug("build generic config, apply all options to generic config") genericConfig = genericgrpcserver.NewConfig() if lastErr = cfg.GenericServerRunOptions.ApplyTo(genericConfig); lastErr != nil { diff --git a/internal/bifrost/store/v1/nginx/nginx.go b/internal/bifrost/store/v1/nginx/nginx.go index 342d738..08cc5fb 100644 --- a/internal/bifrost/store/v1/nginx/nginx.go +++ b/internal/bifrost/store/v1/nginx/nginx.go @@ -1,7 +1,10 @@ package nginx import ( + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" + "time" "github.com/marmotedu/errors" @@ -9,8 +12,7 @@ import ( "github.com/ClessLi/bifrost/internal/pkg/file_watcher" "github.com/ClessLi/bifrost/internal/pkg/monitor" genericoptions "github.com/ClessLi/bifrost/internal/pkg/options" - log "github.com/ClessLi/bifrost/pkg/log/v1" - "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx" ) const ( @@ -18,10 +20,10 @@ const ( ) type webServerStore struct { - cms nginx.ConfigsManager - m monitor.Monitor - wm *file_watcher.WatcherManager - logsDirs map[string]string + configsManger nginx.ConfigsManager + monitor monitor.Monitor + watcherManager *file_watcher.WatcherManager + logsDirs map[string]string } func (w *webServerStore) WebServerStatus() storev1.WebServerStatusStore { @@ -42,9 +44,9 @@ func (w *webServerStore) WebServerLogWatcher() storev1.WebServerLogWatcher { func (w *webServerStore) Close() error { return errors.NewAggregate([]error{ - w.cms.Stop(), - w.m.Stop(), - w.wm.StopAll(), + w.configsManger.Stop(5 * time.Minute), + w.monitor.Stop(), + w.watcherManager.StopAll(), }) } @@ -65,31 +67,28 @@ func GetNginxStoreFactory( } var err error - var cms nginx.ConfigsManager + var configsManager nginx.ConfigsManager var m monitor.Monitor once.Do(func() { // init and start config managers and log watcher manager - cmsOpts := nginx.ConfigsManagerOptions{Options: make([]nginx.ConfigManagerOptions, 0)} + cmConf := &nginx.Config{ManagersConfig: make(map[string]*configuration.ManagerConfig)} svrLogsDirs := make(map[string]string) for _, itemOpts := range webSvrConfOpts.WebServerConfigs { if itemOpts.ServerType == nginxServer { - cmsOpts.Options = append(cmsOpts.Options, nginx.ConfigManagerOptions{ - ServerName: itemOpts.ServerName, - MainConfigPath: itemOpts.ConfigPath, - ServerBinPath: itemOpts.VerifyExecPath, - BackupDir: itemOpts.BackupDir, - BackupCycle: itemOpts.BackupCycle, - BackupSaveTime: itemOpts.BackupSaveTime, - }) + itemOpts.ApplyToNginx(cmConf) } svrLogsDirs[itemOpts.ServerName] = itemOpts.LogsDirPath } - cms, err = nginx.New(cmsOpts) + cmCompletedConf, err := cmConf.Complete() + if err != nil { + return + } + configsManager, err = cmCompletedConf.NewConfigsManager() if err != nil { return } - err = cms.Start() + err = configsManager.Start() if err != nil { return } @@ -114,7 +113,7 @@ func GetNginxStoreFactory( go func() { if err := m.Start(); err != nil { //nolint:govet - log.Fatal(err.Error()) + logV1.Fatal(err.Error()) return } @@ -122,10 +121,10 @@ func GetNginxStoreFactory( // build nginx store factory nginxStoreFactory = &webServerStore{ - cms: cms, - m: m, - wm: wm, - logsDirs: svrLogsDirs, + configsManger: configsManager, + monitor: m, + watcherManager: wm, + logsDirs: svrLogsDirs, } }) diff --git a/internal/bifrost/store/v1/nginx/web_server_config.go b/internal/bifrost/store/v1/nginx/web_server_config.go index 977a16b..fe7a39a 100644 --- a/internal/bifrost/store/v1/nginx/web_server_config.go +++ b/internal/bifrost/store/v1/nginx/web_server_config.go @@ -8,11 +8,11 @@ import ( v1 "github.com/ClessLi/bifrost/api/bifrost/v1" storev1 "github.com/ClessLi/bifrost/internal/bifrost/store/v1" "github.com/ClessLi/bifrost/internal/pkg/code" - "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" ) type webServerConfigStore struct { - configs map[string]configuration.Configuration + configs map[string]configuration.NginxConfig } func (w *webServerConfigStore) GetServerNames(ctx context.Context) (*v1.ServerNames, error) { @@ -51,5 +51,5 @@ func (w *webServerConfigStore) Update(ctx context.Context, config *v1.WebServerC var _ storev1.WebServerConfigStore = &webServerConfigStore{} func newNginxConfigStore(store *webServerStore) storev1.WebServerConfigStore { - return &webServerConfigStore{configs: store.cms.GetConfigs()} + return &webServerConfigStore{configs: store.configsManger.GetConfigs()} } diff --git a/internal/bifrost/store/v1/nginx/web_server_log_watcher.go b/internal/bifrost/store/v1/nginx/web_server_log_watcher.go index f499b68..8b68269 100644 --- a/internal/bifrost/store/v1/nginx/web_server_log_watcher.go +++ b/internal/bifrost/store/v1/nginx/web_server_log_watcher.go @@ -2,12 +2,12 @@ package nginx import ( "context" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "path/filepath" "regexp" "time" "github.com/marmotedu/errors" - "github.com/marmotedu/iam/pkg/log" v1 "github.com/ClessLi/bifrost/api/bifrost/v1" "github.com/ClessLi/bifrost/internal/pkg/code" @@ -53,7 +53,7 @@ func (w *webServerLogWatcherStore) Watch( select { case fOutputC <- data: case <-time.After(time.Second * 30): - log.Warnf("send filtered data timeout(30s)") + logV1.Warnf("send filtered data timeout(30s)") return } @@ -79,7 +79,7 @@ func filterOutput(data []byte, pattern string) (bool, error) { } match, err := regexp.Match(pattern, data) if err != nil { - log.Warnf("web server log watch error. %s", err.Error()) + logV1.Warnf("web server log watch error. %s", err.Error()) return true, err } @@ -92,7 +92,7 @@ func filterOutput(data []byte, pattern string) (bool, error) { func newWebServerLogWatcherStore(store *webServerStore) *webServerLogWatcherStore { return &webServerLogWatcherStore{ - watcherManager: store.wm, + watcherManager: store.watcherManager, webServerLogsDirs: store.logsDirs, } } diff --git a/internal/bifrost/store/v1/nginx/web_server_statistics.go b/internal/bifrost/store/v1/nginx/web_server_statistics.go index b9ced51..223c5fa 100644 --- a/internal/bifrost/store/v1/nginx/web_server_statistics.go +++ b/internal/bifrost/store/v1/nginx/web_server_statistics.go @@ -8,7 +8,7 @@ import ( v1 "github.com/ClessLi/bifrost/api/bifrost/v1" storev1 "github.com/ClessLi/bifrost/internal/bifrost/store/v1" "github.com/ClessLi/bifrost/internal/pkg/code" - "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" ) type webServerStatisticsStore struct { @@ -27,7 +27,7 @@ var _ storev1.WebServerStatisticsStore = &webServerStatisticsStore{} func newNginxStatisticsStore(store *webServerStore) storev1.WebServerStatisticsStore { statisticians := make(map[string]configuration.Statistician) - for servername, config := range store.cms.GetConfigs() { + for servername, config := range store.configsManger.GetConfigs() { statisticians[servername] = configuration.NewStatistician(config) } diff --git a/internal/bifrost/store/v1/nginx/web_server_status.go b/internal/bifrost/store/v1/nginx/web_server_status.go index a8dabbb..a4a8bec 100644 --- a/internal/bifrost/store/v1/nginx/web_server_status.go +++ b/internal/bifrost/store/v1/nginx/web_server_status.go @@ -2,6 +2,7 @@ package nginx import ( "context" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "time" "github.com/marmotedu/component-base/pkg/version" @@ -9,7 +10,6 @@ import ( v1 "github.com/ClessLi/bifrost/api/bifrost/v1" "github.com/ClessLi/bifrost/internal/pkg/monitor" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) const webServerStatusTimeFormatLayout = "2006/01/02 15:04:05" @@ -40,15 +40,15 @@ func newWebServerStatusStore(store *webServerStore) *webServerStatusStore { var os string platform, _, release, err := host.PlatformInformation() if err != nil { - log.Warnf("Failed to get platform information. %s", err.Error()) + logV1.Warnf("Failed to get platform information. %s", err.Error()) os = "unknown" } else { os = platform + " " + release } return &webServerStatusStore{ - m: store.m, - webServerInfosFunc: store.cms.GetServerInfos, + m: store.monitor, + webServerInfosFunc: store.configsManger.GetServerInfos, os: os, bifrostVersion: version.GitVersion, } diff --git a/internal/bifrost/transport/v1/fake/web_server_config.go b/internal/bifrost/transport/v1/fake/web_server_config.go index 17ba2fe..72ffa6a 100644 --- a/internal/bifrost/transport/v1/fake/web_server_config.go +++ b/internal/bifrost/transport/v1/fake/web_server_config.go @@ -2,24 +2,24 @@ package fake import ( "context" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "io" "github.com/marmotedu/errors" pbv1 "github.com/ClessLi/bifrost/api/protobuf-spec/bifrostpb/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type webServerConfig struct{} func (w webServerConfig) GetServerNames(ctx context.Context, null *pbv1.Null) (*pbv1.ServerNames, error) { - log.Info("get web server names") + logV1.Info("get web server names") return &pbv1.ServerNames{Names: []*pbv1.ServerName{{Name: "test1"}, {Name: "test2"}}}, nil } func (w webServerConfig) Get(servername *pbv1.ServerName, stream pbv1.WebServerConfig_GetServer) error { - log.Infof("get web server config %s", servername.Name) + logV1.Infof("get web server config %s", servername.Name) return nil } @@ -30,7 +30,7 @@ func (w webServerConfig) Update(stream pbv1.WebServerConfig_UpdateServer) error return err } - log.Infof("update web server config %s", conf.GetServerName()) + logV1.Infof("update web server config %s", conf.GetServerName()) return nil } diff --git a/internal/bifrost/transport/v1/handler/web_server_config.go b/internal/bifrost/transport/v1/handler/web_server_config.go index 9ca270b..2e57b2e 100644 --- a/internal/bifrost/transport/v1/handler/web_server_config.go +++ b/internal/bifrost/transport/v1/handler/web_server_config.go @@ -1,6 +1,7 @@ package handler import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" "github.com/go-kit/kit/transport/grpc" @@ -8,7 +9,6 @@ import ( epv1 "github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/decoder" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/encoder" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type WebServerConfigHandlers interface { @@ -38,7 +38,7 @@ func (wsc *webServerConfigHandlers) HandlerGetServerNames() grpc.Handler { } }) if wsc.singletonHandlerGetServerNames == nil { - log.Fatal("web server config handler `GetServerNames` is nil") + logV1.Fatal("web server config handler `GetServerNames` is nil") return nil } @@ -53,7 +53,7 @@ func (wsc *webServerConfigHandlers) HandlerGet() grpc.Handler { } }) if wsc.singletonHandlerGet == nil { - log.Fatal("web server config handler `Get` is nil") + logV1.Fatal("web server config handler `Get` is nil") return nil } @@ -68,7 +68,7 @@ func (wsc *webServerConfigHandlers) HandlerUpdate() grpc.Handler { } }) if wsc.singletonHandlerUpdate == nil { - log.Fatal("web server config handler `Update` is nil") + logV1.Fatal("web server config handler `Update` is nil") return nil } diff --git a/internal/bifrost/transport/v1/handler/web_server_log_watcher.go b/internal/bifrost/transport/v1/handler/web_server_log_watcher.go index 71956ab..ea0d367 100644 --- a/internal/bifrost/transport/v1/handler/web_server_log_watcher.go +++ b/internal/bifrost/transport/v1/handler/web_server_log_watcher.go @@ -1,6 +1,7 @@ package handler import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" "github.com/go-kit/kit/transport/grpc" @@ -8,7 +9,6 @@ import ( epv1 "github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/decoder" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/encoder" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type WebServerLogWatcherHandlers interface { @@ -33,7 +33,7 @@ func (lw *webServerLogWatcherHandlers) HandlerWatch() grpc.Handler { }) if lw.singletonHandlerWatch == nil { - log.Fatal("web server log watcher handler `Watch` is nil") + logV1.Fatal("web server log watcher handler `Watch` is nil") return nil } diff --git a/internal/bifrost/transport/v1/handler/web_server_statistics.go b/internal/bifrost/transport/v1/handler/web_server_statistics.go index 6915d73..2c655d5 100644 --- a/internal/bifrost/transport/v1/handler/web_server_statistics.go +++ b/internal/bifrost/transport/v1/handler/web_server_statistics.go @@ -1,6 +1,7 @@ package handler //nolint:dupl import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" "github.com/go-kit/kit/transport/grpc" @@ -8,7 +9,6 @@ import ( epv1 "github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/decoder" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/encoder" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type WebServerStatisticsHandlers interface { @@ -33,7 +33,7 @@ func (wss *webServerStatisticsHandlers) HandlerGet() grpc.Handler { }) if wss.singletonHandlerGet == nil { - log.Fatal("web server statistics handler `Get` is nil") + logV1.Fatal("web server statistics handler `Get` is nil") return nil } diff --git a/internal/bifrost/transport/v1/handler/web_server_status.go b/internal/bifrost/transport/v1/handler/web_server_status.go index 00673ff..be16795 100644 --- a/internal/bifrost/transport/v1/handler/web_server_status.go +++ b/internal/bifrost/transport/v1/handler/web_server_status.go @@ -1,6 +1,7 @@ package handler //nolint:dupl import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" "github.com/go-kit/kit/transport/grpc" @@ -8,7 +9,6 @@ import ( epv1 "github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/decoder" "github.com/ClessLi/bifrost/internal/bifrost/transport/v1/encoder" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type WebServerStatusHandlers interface { @@ -32,7 +32,7 @@ func (w *webServerStatusHandlers) HandlerGet() grpc.Handler { } }) if w.singletonHandlerGet == nil { - log.Fatal("web server status handler `Get` is nil") + logV1.Fatal("web server status handler `Get` is nil") return nil } diff --git a/internal/pkg/code/bifrost.go b/internal/pkg/code/bifrost.go index 2e252a2..1ccd1e6 100644 --- a/internal/pkg/code/bifrost.go +++ b/internal/pkg/code/bifrost.go @@ -51,6 +51,9 @@ const ( // V3ErrInvalidOperation - 500: Invalid operation. V3ErrInvalidOperation + + // V3ErrContextNotFound - 500: queried context not found. + V3ErrContextNotFound ) // bifrost: statistics errors. diff --git a/internal/pkg/file_watcher/config.go b/internal/pkg/file_watcher/config.go index d3b28ff..d156452 100644 --- a/internal/pkg/file_watcher/config.go +++ b/internal/pkg/file_watcher/config.go @@ -2,13 +2,12 @@ package file_watcher import ( "context" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "os" "path/filepath" "time" "github.com/marmotedu/errors" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type Config struct { @@ -64,7 +63,7 @@ func (cc *CompletedConfig) NewFileWatcher(firstOutputCtx context.Context) (*File go func() { err := watcher.Start() if err != nil { - log.Warnf(err.Error()) + logV1.Warnf(err.Error()) } }() diff --git a/internal/pkg/file_watcher/shunt_pipe.go b/internal/pkg/file_watcher/shunt_pipe.go index 345a1a1..9b23de6 100644 --- a/internal/pkg/file_watcher/shunt_pipe.go +++ b/internal/pkg/file_watcher/shunt_pipe.go @@ -2,12 +2,11 @@ package file_watcher import ( "context" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" "time" "github.com/marmotedu/errors" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type ShuntPipe interface { @@ -125,7 +124,7 @@ func (s *shuntPipe) Start() error { return } if !outputPipe.IsClosed() { - log.Warnf("panic transferring data to output pipe. %s", pInfo) + logV1.Warnf("panic transferring data to output pipe. %s", pInfo) outputPipe.Close() } }() diff --git a/internal/pkg/file_watcher/watcher.go b/internal/pkg/file_watcher/watcher.go index c528a3c..5806374 100644 --- a/internal/pkg/file_watcher/watcher.go +++ b/internal/pkg/file_watcher/watcher.go @@ -2,14 +2,13 @@ package file_watcher import ( "context" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "os" "sync" "time" "github.com/hpcloud/tail" "github.com/marmotedu/errors" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type FileWatcher struct { @@ -38,13 +37,13 @@ func (f *FileWatcher) Start() error { go func() { err := f.shuntPipe.Start() if err != nil { - log.Warnf("file '%s' watching error. %s", f.filePath, err.Error()) + logV1.Warnf("file '%s' watching error. %s", f.filePath, err.Error()) } }() - log.Debugf("tail '%s' starting...", f.filePath) + logV1.Debugf("tail '%s' starting...", f.filePath) t, err := tail.TailFile(f.filePath, tail.Config{ - Logger: log.StdInfoLogger(), + Logger: logV1.StdInfoLogger(), Location: &tail.SeekInfo{ Offset: 0, Whence: os.SEEK_END, @@ -60,9 +59,9 @@ func (f *FileWatcher) Start() error { // defer to stop tail defer func(t *tail.Tail) { - log.Debugf("tail '%s' stopping...", f.filePath) + logV1.Debugf("tail '%s' stopping...", f.filePath) if err = t.Stop(); err != nil { - log.Warnf("tail stop error. %s", err.Error()) + logV1.Warnf("tail stop error. %s", err.Error()) } }(t) @@ -73,9 +72,9 @@ func (f *FileWatcher) Start() error { return } if !f.shuntPipe.IsClosed() { - log.Warnf("panic transferring data to shunt pipe. %s", pInfo) + logV1.Warnf("panic transferring data to shunt pipe. %s", pInfo) if err = f.shuntPipe.Close(); err != nil { - log.Warnf("failed to stop shunt pipe. %s", err.Error()) + logV1.Warnf("failed to stop shunt pipe. %s", err.Error()) } } }() @@ -91,7 +90,7 @@ func (f *FileWatcher) Start() error { return err } case <-f.ctx.Done(): // FileWatcher Close method has been called - log.Debugf("watching file '%s' completed") + logV1.Debugf("watching file '%s' completed") return nil default: // sleep 1ms and return to loop with shut pipe closed check diff --git a/internal/pkg/logger/config.go b/internal/pkg/logger/config.go new file mode 100644 index 0000000..3b0e8f9 --- /dev/null +++ b/internal/pkg/logger/config.go @@ -0,0 +1,58 @@ +package logger + +import ( + v1log "github.com/ClessLi/component-base/pkg/log/v1" + "path/filepath" +) + +type Config struct { + InfoLogOpts *v1log.Options + ErrLogOpts *v1log.Options +} + +func NewConfig() *Config { + return &Config{ + InfoLogOpts: v1log.NewOptions(), + ErrLogOpts: v1log.NewOptions(), + } +} + +type CompletedConfig struct { + *Config +} + +func (c *Config) Complete() CompletedConfig { + return CompletedConfig{c} +} + +func (c CompletedConfig) NewLogger() (*Logger, error) { + return &Logger{ + initFunc: func() error { + // 创建日志目录 + for _, infoOutputPath := range c.InfoLogOpts.OutputPaths { + if infoOutputPath == "stdout" || infoOutputPath == "stderr" { + continue + } + err := createLogDir(filepath.Dir(infoOutputPath)) + if err != nil { + return err + } + } + for _, errorOutputPath := range c.ErrLogOpts.OutputPaths { + if errorOutputPath == "stdout" || errorOutputPath == "stderr" { + continue + } + err := createLogDir(filepath.Dir(errorOutputPath)) + if err != nil { + return err + } + } + + v1log.Init(c.InfoLogOpts, c.ErrLogOpts) + return nil + }, + flush: func() { + v1log.Flush() + }, + }, nil +} diff --git a/internal/pkg/logger/logger.go b/internal/pkg/logger/logger.go new file mode 100644 index 0000000..3db1b7d --- /dev/null +++ b/internal/pkg/logger/logger.go @@ -0,0 +1,35 @@ +package logger + +import ( + "github.com/marmotedu/errors" + "os" +) + +type Logger struct { + initFunc func() error + flush func() +} + +func (l *Logger) Init() error { + return l.initFunc() +} + +func (l *Logger) Flush() { + l.flush() +} + +func createLogDir(dirpath string) error { + if info, err := os.Stat(dirpath); os.IsNotExist(err) { + err := os.MkdirAll(dirpath, os.ModePerm) + if err != nil { + return err + } + } else if os.IsExist(err) && !info.IsDir() { + return errors.Errorf("The path '%s' is exist, and it's not a directory", dirpath) + } else if os.IsExist(err) && info.IsDir() { + return nil + } else { + return err + } + return nil +} diff --git a/internal/pkg/monitor/monitor.go b/internal/pkg/monitor/monitor.go index ee1c213..7f48bc4 100644 --- a/internal/pkg/monitor/monitor.go +++ b/internal/pkg/monitor/monitor.go @@ -3,6 +3,7 @@ package monitor import ( "context" "fmt" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "sync" "time" @@ -10,8 +11,6 @@ import ( "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/disk" "github.com/shirou/gopsutil/mem" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) const ( @@ -102,12 +101,12 @@ func (m *monitor) Start() error { go func() { syncWork, syncCancel := context.WithCancel(m.ctx) defer syncCancel() - log.Info("start to sync system information") + logV1.Info("start to sync system information") syncTicker := time.NewTicker(syncDuration) for { select { case <-syncWork.Done(): - log.Info("sync system information stopped") + logV1.Info("sync system information stopped") return case <-syncTicker.C: @@ -126,17 +125,17 @@ func (m *monitor) Stop() error { timeoutC, cancel := context.WithTimeout(m.ctx, time.Second*10) defer cancel() go func() { - log.Info("monitoring stopping...") + logV1.Info("monitoring stopping...") m.cancel() - log.Debugf("monitoring stop complete.") + logV1.Debugf("monitoring stop complete.") }() select { case <-m.ctx.Done(): - log.Info("monitoring stopped") + logV1.Info("monitoring stopped") return m.ctx.Err() case <-timeoutC.Done(): - log.Errorf("monitoring stop timeout") + logV1.Errorf("monitoring stop timeout") return timeoutC.Err() } @@ -151,7 +150,7 @@ func (m *monitor) Report() SystemInfo { func (m *monitor) infoSync(ctx context.Context) { if m.cannotSync { - log.Error("infoSync() call blocked!!") + logV1.Error("infoSync() call blocked!!") return } @@ -170,12 +169,12 @@ func (m *monitor) infoSync(ctx context.Context) { m.cachemu.Lock() defer m.cachemu.Unlock() *m.cache = sysinfo - log.Infof("system info sync to cache succeeded.") + logV1.Infof("system info sync to cache succeeded.") done() }() select { case <-timeout.Done(): - log.Warn("system info sync to cache timeout!") + logV1.Warn("system info sync to cache timeout!") return case <-work.Done(): @@ -186,10 +185,10 @@ func (m *monitor) watch(cycle, interval time.Duration) error { var err error defer func() { if err != nil { - log.Warn(err.Error()) + logV1.Warn(err.Error()) err = m.Stop() if err != nil { - log.Error(err.Error()) + logV1.Error(err.Error()) } } }() @@ -201,7 +200,7 @@ func (m *monitor) watch(cycle, interval time.Duration) error { for { select { case <-m.ctx.Done(): - log.Info("watching completed.") + logV1.Info("watching completed.") return m.ctx.Err() case <-intervalTicker.C: diff --git a/internal/pkg/options/logger_options.go b/internal/pkg/options/logger_options.go new file mode 100644 index 0000000..e8544e9 --- /dev/null +++ b/internal/pkg/options/logger_options.go @@ -0,0 +1,144 @@ +package options + +import ( + "fmt" + "github.com/ClessLi/bifrost/internal/pkg/logger" + "github.com/spf13/pflag" + "go.uber.org/zap/zapcore" + "path/filepath" + "strings" + "time" +) + +const ( + flagInfoLevel = "log.info-level" + flagErrorLevel = "log.error-level" + flagDisableCaller = "log.disable-caller" + flagDisableStacktrace = "log.disable-stacktrace" + flagFormat = "log.format" + flagEnableColor = "log.enable-color" + flagInfoOutputPaths = "log.info-output-paths" + flagErrorOutputPaths = "log.error-output-paths" + flagInnerErrorOutputPaths = "log.inner-error-output-paths" + flagDevelopment = "log.development" + flagName = "log.name" + + consoleFormat = "console" + jsonFormat = "json" + + defaultLogBaseDir = "logs" + defaultInfoLogFileName = "bifrost.log" + defaultErrorLogFileName = "bifrost_error.log" +) + +type LoggerOptions struct { + Name string `json:"name" mapstructure:"name"` + InfoOutputPaths []string `json:"info-output-paths" mapstructure:"info-output-paths"` + ErrorOutputPaths []string `json:"error-output-paths" mapstructure:"error-output-paths"` + InnerErrorOutputPaths []string `json:"inner-error-output-paths" mapstructure:"inner-error-output-paths"` + InfoLevel string `json:"info-level" mapstructure:"info-level"` + ErrorLevel string `json:"error-level" mapstucture:"error-level"` + Format string `json:"format" mapstructure:"format"` + DisableCaller bool `json:"disable-caller" mapstructure:"disable-caller"` + DisableStacktrace bool `json:"disable-stacktrace" mapstructure:"disable-stacktrace"` + EnableColor bool `json:"enable-color" mapstructure:"enable-color"` + Development bool `json:"development" mapstructure:"development"` +} + +func NewLoggerOptions() *LoggerOptions { + opts := &LoggerOptions{ + InfoLevel: zapcore.InfoLevel.String(), + ErrorLevel: zapcore.WarnLevel.String(), + DisableCaller: false, + DisableStacktrace: false, + Format: consoleFormat, + EnableColor: false, + Development: false, + InfoOutputPaths: []string{filepath.Join(defaultLogBaseDir, defaultInfoLogFileName)}, + ErrorOutputPaths: []string{filepath.Join(defaultLogBaseDir, defaultErrorLogFileName)}, + InnerErrorOutputPaths: []string{"stderr"}, + } + + return opts +} + +func (o *LoggerOptions) Validate() []error { + var errs []error + var zapLevel zapcore.Level + // validate Info log + if err := zapLevel.UnmarshalText([]byte(o.InfoLevel)); err != nil { + errs = append(errs, err) + } + + format := strings.ToLower(o.Format) + if format != consoleFormat && format != jsonFormat { + errs = append(errs, fmt.Errorf("not a valid log format: %q", o.Format)) + } + + // validate Error log + if err := zapLevel.UnmarshalText([]byte(o.ErrorLevel)); err != nil { + errs = append(errs, err) + } + + return errs +} + +func (o *LoggerOptions) AddFlags(fs *pflag.FlagSet) { + // Add Info log flags + fs.StringVar(&o.InfoLevel, flagInfoLevel, o.InfoLevel, "Minimum Info log output `LEVEL`.") + fs.BoolVar(&o.DisableCaller, flagDisableCaller, o.DisableCaller, "Disable output of caller information in the log.") + fs.BoolVar(&o.DisableStacktrace, flagDisableStacktrace, + o.DisableStacktrace, "Disable the log to record a stack trace for all messages at or above panic level.") + fs.StringVar(&o.Format, flagFormat, o.Format, "Log output `FORMAT`, support plain or json format.") + fs.BoolVar(&o.EnableColor, flagEnableColor, o.EnableColor, "Enable output ansi colors in plain format logs.") + fs.StringSliceVar(&o.InfoOutputPaths, flagInfoOutputPaths, o.InfoOutputPaths, "Output paths of Info log.") + fs.StringSliceVar(&o.InnerErrorOutputPaths, flagInnerErrorOutputPaths, o.InnerErrorOutputPaths, "Inner Error output paths of log.") + fs.BoolVar( + &o.Development, + flagDevelopment, + o.Development, + "Development puts the logger in development mode, which changes "+ + "the behavior of DPanicLevel and takes stacktraces more liberally.", + ) + fs.StringVar(&o.Name, flagName, o.Name, "The name of the logger.") + + // Add Error log flags + fs.StringVar(&o.ErrorLevel, flagErrorLevel, o.ErrorLevel, "Minimum Error log output `LEVEL`.") + + fs.StringSliceVar(&o.ErrorOutputPaths, flagErrorOutputPaths, o.ErrorOutputPaths, "Output paths of Error log.") +} + +func (o *LoggerOptions) Complete() error { + defaultLogSecondLevelDir := time.Now().Format("20060102") + if o.InfoOutputPaths == nil || (len(o.InfoOutputPaths) == 1 && o.InfoOutputPaths[0] == "stdout") { + o.InfoOutputPaths = append(o.InfoOutputPaths, filepath.Join(defaultLogBaseDir, defaultLogSecondLevelDir, defaultInfoLogFileName)) + } + if o.ErrorOutputPaths == nil || (len(o.ErrorOutputPaths) == 1 && o.ErrorOutputPaths[0] == "stdout") { + o.ErrorOutputPaths = []string{filepath.Join(defaultLogBaseDir, defaultLogSecondLevelDir, defaultErrorLogFileName)} + } + + return nil +} + +func (o *LoggerOptions) ApplyTo(conf *logger.Config) error { + conf.InfoLogOpts.Format = o.Format + conf.InfoLogOpts.Name = o.Name + conf.InfoLogOpts.ErrorOutputPaths = o.InnerErrorOutputPaths + conf.InfoLogOpts.Level = o.InfoLevel + conf.InfoLogOpts.EnableColor = o.EnableColor + conf.InfoLogOpts.Development = o.Development + conf.InfoLogOpts.DisableCaller = o.DisableCaller + conf.InfoLogOpts.DisableStacktrace = o.DisableStacktrace + conf.InfoLogOpts.OutputPaths = o.InfoOutputPaths + + conf.ErrLogOpts.Format = o.Format + conf.ErrLogOpts.ErrorOutputPaths = nil + conf.ErrLogOpts.Level = o.ErrorLevel + conf.ErrLogOpts.EnableColor = o.EnableColor + conf.ErrLogOpts.Development = o.Development + conf.ErrLogOpts.DisableCaller = o.DisableCaller + conf.ErrLogOpts.DisableStacktrace = o.DisableStacktrace + conf.ErrLogOpts.OutputPaths = o.ErrorOutputPaths + + return nil +} diff --git a/internal/pkg/options/secure_serving_options.go b/internal/pkg/options/secure_serving_options.go index 7befbd0..2f1863c 100644 --- a/internal/pkg/options/secure_serving_options.go +++ b/internal/pkg/options/secure_serving_options.go @@ -2,13 +2,13 @@ package options import ( "fmt" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "net" "path" "github.com/spf13/pflag" "github.com/ClessLi/bifrost/internal/pkg/server" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) // SecureServingOptions contains configuration items related to TLS server startup. @@ -59,7 +59,7 @@ func NewSecureServingOptions() *SecureServingOptions { // ApplyTo applies the run options to the method receiver and returns self. func (s *SecureServingOptions) ApplyTo(c *server.Config) error { if s == nil || s.BindPort == 0 { - log.Debug("secure serving is disabled.") + logV1.Debug("secure serving is disabled.") c.SecureServing = nil return nil diff --git a/internal/pkg/options/web_server_config_options.go b/internal/pkg/options/web_server_config_options.go index b0553e1..0183317 100644 --- a/internal/pkg/options/web_server_config_options.go +++ b/internal/pkg/options/web_server_config_options.go @@ -1,32 +1,32 @@ package options import ( + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" + "github.com/marmotedu/errors" + "github.com/spf13/pflag" "os" "path/filepath" "strings" - - "github.com/marmotedu/errors" - "github.com/spf13/pflag" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type WebServerConfigOptions struct { - ServerName string `json:"server-name" mapstructure:"server-name"` - ServerType string `json:"server-type" mapstructure:"server-type"` - ConfigPath string `json:"config-path" mapstructure:"config-path"` - VerifyExecPath string `json:"verify-exec-path" mapstructure:"verify-exec-path"` - LogsDirPath string `json:"logs-dir-path" mapstructure:"logs-dir-path"` - BackupDir string `json:"backup-dir" mapstructure:"backup-dir"` - BackupCycle int `json:"backup-cycle" mapstructure:"backup-cycle"` - BackupSaveTime int `json:"backup-save-time" mapstructure:"backup-save-time"` + ServerName string `json:"server-name" mapstructure:"server-name"` + ServerType string `json:"server-type" mapstructure:"server-type"` + ConfigPath string `json:"config-path" mapstructure:"config-path"` + VerifyExecPath string `json:"verify-exec-path" mapstructure:"verify-exec-path"` + LogsDirPath string `json:"logs-dir-path" mapstructure:"logs-dir-path"` + BackupDir string `json:"backup-dir" mapstructure:"backup-dir"` + BackupCycle int `json:"backup-cycle" mapstructure:"backup-cycle"` + BackupsRetentionDuration int `json:"backups-retention-duration" mapstructure:"backups-retention-duration"` } func NewWebServerConfigOptions() *WebServerConfigOptions { return &WebServerConfigOptions{ - ServerType: "nginx", - BackupCycle: 1, - BackupSaveTime: 7, + ServerType: "nginx", + BackupCycle: 1, + BackupsRetentionDuration: 7, } } @@ -61,8 +61,8 @@ func (c *WebServerConfigOptions) AddFlags(fs *pflag.FlagSet) { "Set the web server configuration backup cycle. The unit is daily."+ " Set zero to disable backup.") - fs.IntVar(&c.BackupSaveTime, "web-server-config.backup-save-time", c.BackupSaveTime, ""+ - "Set the save time of the web server configuration backup file."+ + fs.IntVar(&c.BackupsRetentionDuration, "web-server-config.backups-retention-duration", c.BackupsRetentionDuration, ""+ + "Set the retention duration of the web server configuration backup files."+ " The unit is daily."+ " Set zero to disable backup.") } @@ -123,6 +123,18 @@ func (c *WebServerConfigOptions) Validate() []error { return errs } +func (c *WebServerConfigOptions) ApplyToNginx(config *nginx.Config) { + config.ManagersConfig[c.ServerName] = &configuration.ManagerConfig{ + NginxMainConfigAbsPath: c.ConfigPath, + // NginxHome: c.ServerHome, + NginxBinFilePath: c.VerifyExecPath, + BackupCycleDays: c.BackupCycle, + BackupRetentionDays: c.BackupsRetentionDuration, + BackupDir: c.BackupDir, + // BackupPrefix: c.BackupPrefix, + } +} + type WebServerConfigsOptions struct { WebServerConfigs []*WebServerConfigOptions `json:"items" mapstructure:"items"` } @@ -142,7 +154,7 @@ func (cs *WebServerConfigsOptions) Validate() []error { suberrs := c.Validate() if len(suberrs) > 0 { aErr := errors.NewAggregate(suberrs) - log.Errorf("failed to validate the %dst web server config options, cased by %v", i+1, aErr) + logV1.Errorf("failed to validate the %dst web server config options, cased by %v", i+1, aErr) errs = append(errs, errors.Wrapf(aErr, "failed to validate the %dst web server config options.", i+1)) } } diff --git a/internal/pkg/server/config.go b/internal/pkg/server/config.go index 350f53e..13fa3f1 100644 --- a/internal/pkg/server/config.go +++ b/internal/pkg/server/config.go @@ -4,6 +4,7 @@ package server import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "net" "path/filepath" "strconv" @@ -12,8 +13,6 @@ import ( "github.com/marmotedu/component-base/pkg/util/homedir" "github.com/spf13/viper" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) const ( @@ -148,6 +147,6 @@ func LoadConfig(cfg string, defaultName string) { // If a config file is found, read it in. if err := viper.ReadInConfig(); err != nil { - log.Warnf("WARNING: viper failed to discover and load the configuration file: %s", err.Error()) + logV1.Warnf("WARNING: viper failed to discover and load the configuration file: %s", err.Error()) } } diff --git a/internal/pkg/server/genericgrpcserver.go b/internal/pkg/server/genericgrpcserver.go index c6f210c..0022dde 100644 --- a/internal/pkg/server/genericgrpcserver.go +++ b/internal/pkg/server/genericgrpcserver.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "net" "strings" "time" @@ -19,9 +20,7 @@ import ( "github.com/ClessLi/bifrost/internal/pkg/service_register" healthzclient_v1 "github.com/ClessLi/bifrost/pkg/client/grpc_health_v1" - //"github.com/ClessLi/bifrost/internal/pkg/middleware". - log "github.com/ClessLi/bifrost/pkg/log/v1" ) // GenericGRPCServer contains state for a bifrost api server. @@ -60,7 +59,7 @@ type GenericGRPCServer struct { func (s *GenericGRPCServer) Setup() { if s.SecureServingInfo == nil && s.InsecureServingInfo == nil { - log.Fatal("Failed to setup generic gRPC server, no serving information is available for setup.") + logV1.Fatal("Failed to setup generic gRPC server, no serving information is available for setup.") return } @@ -70,12 +69,12 @@ func (s *GenericGRPCServer) Setup() { s.SecureServingInfo.CertKey.KeyFile, ) if err != nil { - log.Fatal(err.Error()) + logV1.Fatal(err.Error()) return } s.secureServer = grpc.NewServer(grpc.MaxSendMsgSize(s.ChunkSize), grpc.Creds(cerds)) - log.Infof("Secure server initialization succeeded. Chunk size: %d.", s.ChunkSize) + logV1.Infof("Secure server initialization succeeded. Chunk size: %d.", s.ChunkSize) if s.healthz { s.secureSvrHealthz = health.NewServer() } @@ -85,7 +84,7 @@ func (s *GenericGRPCServer) Setup() { // TODO: Checking mechanism of gRPC server max send msg size // s.insecureServer = grpc.NewServer(grpc.MaxSendMsgSize(s.ChunkSize)) s.insecureServer = grpc.NewServer() - log.Infof("Insecure server initialization succeeded. Chunk size: %d.", s.ChunkSize) + logV1.Infof("Insecure server initialization succeeded. Chunk size: %d.", s.ChunkSize) if s.healthz { s.insecureSvrHealthz = health.NewServer() } @@ -114,15 +113,15 @@ func (s *GenericGRPCServer) InstallServices() { // check healthz handler if s.healthz { if s.insecureServer != nil { - log.Debug("Register health server for insecure gRPC server...") + logV1.Debug("Register health server for insecure gRPC server...") grpc_health_v1.RegisterHealthServer(s.insecureServer, s.insecureSvrHealthz) - log.Debug("Registered health server for insecure gRPC server succeeded.") + logV1.Debug("Registered health server for insecure gRPC server succeeded.") } if s.secureServer != nil { - log.Debug("Register health server for secure gRPC server...") + logV1.Debug("Register health server for secure gRPC server...") grpc_health_v1.RegisterHealthServer(s.secureServer, s.secureSvrHealthz) - log.Debug("Registered health server for secure gRPC server succeeded.") + logV1.Debug("Registered health server for secure gRPC server succeeded.") } } } @@ -132,13 +131,13 @@ func (s *GenericGRPCServer) InstallRAClient() { var err error s.registryClient, err = discover.NewKitConsulRegistryClient(s.RAInfo.Host, uint16(s.RAInfo.Port)) if err != nil { - log.Fatal(err.Error()) + logV1.Fatal(err.Error()) return } id, err := uuid.NewV4() if err != nil { - log.Fatalf(err.Error()) + logV1.Fatalf(err.Error()) return } @@ -156,13 +155,13 @@ func (s *GenericGRPCServer) RegisterServices(registers map[string]service_regist bindPort uint16, ) { if svcRegister == nil { - log.Warn("service register is nil") + logV1.Warn("service register is nil") return } svcRegister(grpcSvr, healthSvr) if s.registryClient != nil { - log.Debugf("Register service `%s` to RA for gRPC server...", svcname+"-"+s.instanceSuffixID) + logV1.Debugf("Register service `%s` to RA for gRPC server...", svcname+"-"+s.instanceSuffixID) s.registryClient.Register( svcname, @@ -170,13 +169,13 @@ func (s *GenericGRPCServer) RegisterServices(registers map[string]service_regist bindHost, bindPort, nil, - log.K(), + logV1.K(), ) } } for svcname, register := range registers { if s.InsecureServingInfo != nil { - log.Debugf("Register service `%s` for insecure gRPC server...", svcname) + logV1.Debugf("Register service `%s` for insecure gRPC server...", svcname) f( svcname, s.insecureServer, @@ -187,7 +186,7 @@ func (s *GenericGRPCServer) RegisterServices(registers map[string]service_regist ) } if s.SecureServingInfo != nil { - log.Debugf("Register service `%s` for secure gRPC server...", svcname) + logV1.Debugf("Register service `%s` for secure gRPC server...", svcname) f( svcname, s.secureServer, @@ -205,13 +204,13 @@ func (s *GenericGRPCServer) RegisterServices(registers map[string]service_regist func initGenericGRPCServer(s *GenericGRPCServer) { // do some setup - log.Debug("Setup generic gRPC server...") + logV1.Debug("Setup generic gRPC server...") s.Setup() - log.Debug("Install RA client for generic gRPC server...") + logV1.Debug("Install RA client for generic gRPC server...") s.InstallRAClient() - log.Debug("Install middlewares for generic gRPC server...") + logV1.Debug("Install middlewares for generic gRPC server...") s.InstallMiddlewares() - log.Debug("Install services for generic gRPC server...") + logV1.Debug("Install services for generic gRPC server...") s.InstallServices() } @@ -221,19 +220,19 @@ func (s *GenericGRPCServer) Run() error { // Initializing the server in a goroutine so that // it won't block the graceful shutdown handling below - log.Debugf("Goroutine start the insecure gRPC server...") + logV1.Debugf("Goroutine start the insecure gRPC server...") // TODO: fix duplicate code for insecure server and secure server startup eg.Go(func() error { //nolint:dupl if s.InsecureServingInfo == nil { - log.Info("Pass start insecure server") + logV1.Info("Pass start insecure server") return nil } - log.Infof("Start to listening the incoming requests on address: %s", s.InsecureServingInfo.Address()) + logV1.Infof("Start to listening the incoming requests on address: %s", s.InsecureServingInfo.Address()) lis, err := net.Listen("tcp", s.InsecureServingInfo.Address()) if err != nil { - log.Errorf( + logV1.Errorf( "Failed to listen the incoming requests on address: %s, %s", s.InsecureServingInfo.Address(), err.Error(), @@ -248,27 +247,27 @@ func (s *GenericGRPCServer) Run() error { } if err = s.insecureServer.Serve(lis); err != nil && !errors.Is(err, grpc.ErrServerStopped) { - log.Errorf("Failed to serve the insecure server, %s", err.Error()) + logV1.Errorf("Failed to serve the insecure server, %s", err.Error()) return err } - log.Infof("Server on %s stopped", s.InsecureServingInfo.Address()) + logV1.Infof("Server on %s stopped", s.InsecureServingInfo.Address()) return nil }) - log.Debugf("Goroutine start the secure gRPC server...") + logV1.Debugf("Goroutine start the secure gRPC server...") eg.Go(func() error { //nolint:dupl if s.SecureServingInfo == nil { - log.Info("Pass start secure server") + logV1.Info("Pass start secure server") return nil } - log.Infof("Start to listening the incoming requests on https address: %s", s.SecureServingInfo.Address()) + logV1.Infof("Start to listening the incoming requests on https address: %s", s.SecureServingInfo.Address()) lis, err := net.Listen("tcp", s.SecureServingInfo.Address()) if err != nil { - log.Errorf( + logV1.Errorf( "Failed to listen the incoming requests on address: %s, %s", s.SecureServingInfo.Address(), err.Error(), @@ -282,12 +281,12 @@ func (s *GenericGRPCServer) Run() error { defer s.secureSvrHealthz.Shutdown() } if err = s.secureServer.Serve(lis); err != nil && !errors.Is(err, grpc.ErrServerStopped) { - log.Errorf("Failed to serve the secure server, %s", err.Error()) + logV1.Errorf("Failed to serve the secure server, %s", err.Error()) return err } - log.Infof("Server on %s stopped", s.SecureServingInfo.Address()) + logV1.Infof("Server on %s stopped", s.SecureServingInfo.Address()) return nil }) @@ -296,14 +295,14 @@ func (s *GenericGRPCServer) Run() error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if s.healthz { - log.Debugf("Start to run the health check...") + logV1.Debugf("Start to run the health check...") if err := s.ping(ctx); err != nil { return err } } if err := eg.Wait(); err != nil { - log.Errorf("%+v", err.Error()) + logV1.Errorf("%+v", err.Error()) return err } @@ -320,7 +319,7 @@ func (s *GenericGRPCServer) Close() { if s.registryClient != nil { for _, servicename := range s.registeredService { - s.registryClient.DeRegister(servicename+"-"+s.instanceSuffixID, log.K()) + s.registryClient.DeRegister(servicename+"-"+s.instanceSuffixID, logV1.K()) } } @@ -329,7 +328,7 @@ func (s *GenericGRPCServer) Close() { if s.healthz { s.secureSvrHealthz.Shutdown() } - log.Info("Secure server has been stopped!") + logV1.Info("Secure server has been stopped!") } if s.insecureServer != nil { @@ -337,16 +336,17 @@ func (s *GenericGRPCServer) Close() { if s.healthz { s.insecureSvrHealthz.Shutdown() } - log.Info("Insecure server has been stopped!") + logV1.Info("Insecure server has been stopped!") } } // ping pings the http server to make sure the router is working. +// //nolint:funlen,gocognit func (s *GenericGRPCServer) ping(ctx context.Context) error { healthzClients := make(map[string]*healthzclient_v1.Client) if s.InsecureServingInfo != nil { - log.Debugf("initialization insecure server health check...") + logV1.Debugf("initialization insecure server health check...") var address string if strings.Contains(s.InsecureServingInfo.Address(), "0.0.0.0") { address = fmt.Sprintf("127.0.0.1:%s", strings.Split(s.InsecureServingInfo.Address(), ":")[1]) @@ -362,7 +362,7 @@ func (s *GenericGRPCServer) ping(ctx context.Context) error { defer func(client *healthzclient_v1.Client) { err := client.Close() if err != nil { - log.Warn(err.Error()) + logV1.Warn(err.Error()) } }(client) @@ -370,7 +370,7 @@ func (s *GenericGRPCServer) ping(ctx context.Context) error { } if s.SecureServingInfo != nil { //nolint:nestif - log.Debugf("initialization secure server health check...") + logV1.Debugf("initialization secure server health check...") var address string if strings.Contains(s.SecureServingInfo.Address(), "0.0.0.0") { address = fmt.Sprintf("127.0.0.1:%s", strings.Split(s.SecureServingInfo.Address(), ":")[1]) @@ -392,7 +392,7 @@ func (s *GenericGRPCServer) ping(ctx context.Context) error { defer func(client *healthzclient_v1.Client) { err := client.Close() if err != nil { - log.Warn(err.Error()) + logV1.Warn(err.Error()) } }(client) @@ -410,13 +410,13 @@ func (s *GenericGRPCServer) ping(ctx context.Context) error { status, err := client.Check(ctx, svcname) if err != nil { - log.Info(err.Error()) + logV1.Info(err.Error()) healthzOK[tag+" "+svcname] = false continue } healthzOK[tag+" "+svcname] = true - log.Infof("The '%s' %s-service state is: %v", svcname, tag, healthzclient_v1.StatusString(status)) + logV1.Infof("The '%s' %s-service state is: %v", svcname, tag, healthzclient_v1.StatusString(status)) } } @@ -424,26 +424,26 @@ func (s *GenericGRPCServer) ping(ctx context.Context) error { for tSvcname, ok := range healthzOK { if !ok { allOK = false - log.Debugf("service `%s` is not healthy.", tSvcname) + logV1.Debugf("service `%s` is not healthy.", tSvcname) } } if allOK { - log.Infof("all services are healthy!") + logV1.Infof("all services are healthy!") return nil } // Sleep for a second to continue the next ping. - log.Info("Waiting for the router, retry in 1 second.") + logV1.Info("Waiting for the router, retry in 1 second.") time.Sleep(1 * time.Second) select { case <-ctx.Done(): - log.Fatal("can not check grpc server health within the specified time interval.") + logV1.Fatal("can not check grpc server health within the specified time interval.") default: if len(healthzClients) == 0 { - log.Fatal("can not check grpc server health") + logV1.Fatal("can not check grpc server health") } } } diff --git a/pkg/app/app.go b/pkg/app/app.go deleted file mode 100644 index 6e24c8f..0000000 --- a/pkg/app/app.go +++ /dev/null @@ -1,299 +0,0 @@ -package app - -import ( - "fmt" - "os" - - "github.com/fatih/color" - cliflag "github.com/marmotedu/component-base/pkg/cli/flag" - "github.com/marmotedu/component-base/pkg/cli/globalflag" - "github.com/marmotedu/component-base/pkg/term" - "github.com/marmotedu/component-base/pkg/version" - "github.com/marmotedu/component-base/pkg/version/verflag" - "github.com/marmotedu/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - log "github.com/ClessLi/bifrost/pkg/log/v1" -) - -var ( - progressMessage = color.GreenString("==>") - //nolint: deadcode,unused,varcheck - usageTemplate = fmt.Sprintf(`%s{{if .Runnable}} - %s{{end}}{{if .HasAvailableSubCommands}} - %s{{end}}{{if gt (len .Aliases) 0}} - -%s - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -%s -{{.Example}}{{end}}{{if .HasAvailableSubCommands}} - -%s{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - %s {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -%s -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -%s -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -%s{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "%s --help" for more information about a command.{{end}} -`, - color.CyanString("Usage:"), - color.GreenString("{{.UseLine}}"), - color.GreenString("{{.CommandPath}} [command]"), - color.CyanString("Aliases:"), - color.CyanString("Examples:"), - color.CyanString("Available Commands:"), - color.GreenString("{{rpad .Name .NamePadding }}"), - color.CyanString("Flags:"), - color.CyanString("Global Flags:"), - color.CyanString("Additional help topics:"), - color.GreenString("{{.CommandPath}} [command]"), - ) -) - -// App is the main structure of a cli application. -// It is recommended that an app be created with the app.NewApp() function. -type App struct { - basename string - name string - description string - options CliOptions - runFunc RunFunc - silence bool - noVersion bool - noConfig bool - commands []*Command - args cobra.PositionalArgs - cmd *cobra.Command -} - -// Option defines optional parameters for initializing the application -// structure. -type Option func(*App) - -// WithOptions to open the application's function to read from the command line -// or read parameters from the configuration file. -func WithOptions(opt CliOptions) Option { - return func(a *App) { - a.options = opt - } -} - -type RunFunc func(basename string) error - -// WithRunFunc is used to set the application startup callback function option. -func WithRunFunc(run RunFunc) Option { - return func(a *App) { - a.runFunc = run - } -} - -// WithDescription is used to set the description of the application. -func WithDescription(desc string) Option { - return func(a *App) { - a.description = desc - } -} - -// WithSilence sets the application to silent mode, in which the program startup -// information, configuration information, and version information are not -// printed in the console. -func WithSilence() Option { - return func(a *App) { - a.silence = true - } -} - -// WithNoVersion set the application does not provide version flag. -func WithNoVersion() Option { - return func(a *App) { - a.noVersion = true - } -} - -// WithNoConfig set the application does not provide config flag. -func WithNoConfig() Option { - return func(a *App) { - a.noConfig = true - } -} - -// WithValidArgs set the validation function to valid non-flag arguments. -func WithValidArgs(args cobra.PositionalArgs) Option { - return func(a *App) { - a.args = args - } -} - -// WithDefaultValidArgs set default validation function to valid non-flag arguments. -func WithDefaultValidArgs() Option { - return func(a *App) { - a.args = func(cmd *cobra.Command, args []string) error { - for _, arg := range args { - if len(arg) > 0 { - return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args) - } - } - - return nil - } - } -} - -func NewApp(name, basename string, opts ...Option) *App { - a := &App{ - name: name, - basename: basename, - } - - for _, opt := range opts { - opt(a) - } - - a.buildCommand() - - return a -} - -func (a *App) buildCommand() { - cmd := cobra.Command{ - Use: FormatBasename(a.basename), - Short: a.name, - Long: a.description, - // stop printing usage when the command errors - SilenceUsage: true, - SilenceErrors: true, - Args: a.args, - } - - cmd.SetOut(os.Stdout) - cmd.SetErr(os.Stderr) - cmd.Flags().SortFlags = true - cliflag.InitFlags(cmd.Flags()) - - if len(a.commands) > 0 { - for _, command := range a.commands { - cmd.AddCommand(command.cobraCommand()) - } - cmd.SetHelpCommand(helpCommand(a.name)) - } - if a.runFunc != nil { - cmd.RunE = a.runCommand - } - - var namedFlagSets cliflag.NamedFlagSets - if a.options != nil { - namedFlagSets = a.options.Flags() - fs := cmd.Flags() - for _, f := range namedFlagSets.FlagSets { - fs.AddFlagSet(f) - } - - usageFmt := "Usage:\n %s\n" - cols, _, _ := term.TerminalSize(cmd.OutOrStdout()) - cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { - fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine()) - cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols) - }) - cmd.SetUsageFunc(func(cmd *cobra.Command) error { - fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine()) - cliflag.PrintSections(cmd.OutOrStderr(), namedFlagSets, cols) - - return nil - }) - } - - if !a.noVersion { // has version flag - verflag.AddFlags(namedFlagSets.FlagSet("global")) - } - if !a.noConfig { // has config flag - addConfigFlag(a.basename, namedFlagSets.FlagSet("global")) - } - globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name()) - - a.cmd = &cmd -} - -// Run is used to launch the application. -func (a *App) Run() { - if err := a.cmd.Execute(); err != nil { - fmt.Printf("%v %#+v\n", color.RedString("Error:"), err) - os.Exit(1) - } -} - -// Command returns cobra command instance inside the application. -func (a *App) Command() *cobra.Command { - return a.cmd -} - -func (a *App) runCommand(cmd *cobra.Command, args []string) error { - printWorkingDir() - cliflag.PrintFlags(cmd.Flags()) - if !a.noVersion { // has version flag - // display application version information - verflag.PrintAndExitIfRequested() - } - - if !a.noConfig { // has config flag - if err := viper.BindPFlags(cmd.Flags()); err != nil { - return err - } - - if err := viper.Unmarshal(a.options); err != nil { - return err - } - } - - if !a.silence { // is not silence - log.Infof("%v Starting %s ...", progressMessage, a.name) - if !a.noVersion { // has version flag - log.Infof("%v Version: `%s`", progressMessage, version.Get().ToJSON()) - } - if !a.noConfig { // has config flag - log.Infof("%v Config file used: `%s`", progressMessage, viper.ConfigFileUsed()) - } - } - if a.options != nil { - if err := a.applyOptionRules(); err != nil { - return err - } - } - // run application - if a.runFunc != nil { - return a.runFunc(a.basename) - } - - return nil -} - -func (a *App) applyOptionRules() error { - if completableOptions, ok := a.options.(CompletableOptions); ok { - if err := completableOptions.Complete(); err != nil { - return err - } - } - - if errs := a.options.Validate(); len(errs) != 0 { - return errors.NewAggregate(errs) - } - - if printableOptions, ok := a.options.(PrintableOptions); ok && !a.silence { - log.Infof("%v Config: `%s`", progressMessage, printableOptions.String()) - } - - return nil -} - -// printWorkingDir a function that prints the working directory to the log. -func printWorkingDir() { - wd, _ := os.Getwd() - log.Infof("%v WorkingDir: %s", progressMessage, wd) -} diff --git a/pkg/app/cmd.go b/pkg/app/cmd.go deleted file mode 100644 index f4431a8..0000000 --- a/pkg/app/cmd.go +++ /dev/null @@ -1,113 +0,0 @@ -package app - -import ( - "fmt" - "os" - - "github.com/fatih/color" - "github.com/spf13/cobra" -) - -// Command is a sub command structure of a cli application. -// It is recommended that a command be created with the app.NewCommand() -// function. -type Command struct { - usage string - desc string - options CliOptions - commands []*Command - runFunc RunCommandFunc -} - -// CommandOption defines optional parameters for initializing the command -// structure. -type CommandOption func(*Command) - -// WithCommandOptions to open the application's function to read from the -// command line. -func WithCommandOptions(opt CliOptions) CommandOption { - return func(c *Command) { - c.options = opt - } -} - -// RunCommandFunc defines the application's command startup callback function. -type RunCommandFunc func(args []string) error - -// WithCommandRunFunc is used to set the application's command startup callback -// function option. -func WithCommandRunFunc(run RunCommandFunc) CommandOption { - return func(c *Command) { - c.runFunc = run - } -} - -// NewCommand creates a new sub command instance based on the given command name -// and other options. -func NewCommand(usage string, desc string, opts ...CommandOption) *Command { - c := &Command{ - usage: usage, - desc: desc, - } - - for _, opt := range opts { - opt(c) - } - - return c -} - -// AddCommand adds sub command to the current command. -func (c *Command) AddCommand(cmd *Command) { - c.commands = append(c.commands, cmd) -} - -// AddCommands adds multiple sub commands to the current command. -func (c *Command) AddCommands(cmds ...*Command) { - c.commands = append(c.commands, cmds...) -} - -func (c *Command) cobraCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: c.usage, - Short: c.desc, - } - cmd.SetOut(os.Stdout) - cmd.SetErr(os.Stderr) - cmd.Flags().SortFlags = false - if len(c.commands) > 0 { - for _, command := range c.commands { - cmd.AddCommand(command.cobraCommand()) - } - } - if c.runFunc != nil { - cmd.Run = c.runCommand - } - if c.options != nil { - for _, f := range c.options.Flags().FlagSets { - cmd.Flags().AddFlagSet(f) - } - } - addHelpCommandFlag(c.usage, cmd.Flags()) - - return cmd -} - -func (c *Command) runCommand(cmd *cobra.Command, args []string) { - if c.runFunc != nil { - if err := c.runFunc(args); err != nil { - fmt.Printf("%v %v\n", color.RedString("Error:"), err) - os.Exit(1) - } - } -} - -// AddCommand adds sub command to the application. -func (a *App) AddCommand(cmd *Command) { - a.commands = append(a.commands, cmd) -} - -// AddCommands adds multiple sub commands to the application. -func (a *App) AddCommands(cmds ...*Command) { - a.commands = append(a.commands, cmds...) -} diff --git a/pkg/app/cmd_linux.go b/pkg/app/cmd_linux.go deleted file mode 100644 index be3fc42..0000000 --- a/pkg/app/cmd_linux.go +++ /dev/null @@ -1,7 +0,0 @@ -package app - -// FormatBasename is formatted as an executable file name under different -// operating systems according to the given name. -func FormatBasename(basename string) string { - return basename -} diff --git a/pkg/app/cmd_windows.go b/pkg/app/cmd_windows.go deleted file mode 100644 index 2456408..0000000 --- a/pkg/app/cmd_windows.go +++ /dev/null @@ -1,15 +0,0 @@ -package app - -import ( - "strings" -) - -// FormatBasename is formatted as an executable file name under different -// operating systems according to the given name. -func FormatBasename(basename string) string { - // Make case-insensitive and strip executable suffix if present - basename = strings.ToLower(basename) - basename = strings.TrimSuffix(basename, ".exe") - - return basename -} diff --git a/pkg/app/config.go b/pkg/app/config.go deleted file mode 100644 index 53ed601..0000000 --- a/pkg/app/config.go +++ /dev/null @@ -1,69 +0,0 @@ -package app - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/gosuri/uitable" - "github.com/marmotedu/component-base/pkg/util/homedir" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/spf13/viper" -) - -const configFlagName = "config" - -var cfgFile string - -//nolint: gochecknoinits -func init() { - pflag.StringVarP(&cfgFile, "config", "c", cfgFile, "Read configuration from specified `FILE`, "+ - "support JSON, TOML, YAML, HCL, or Java properties formats.") -} - -// addConfigFlag adds flags for a specific server to the specified FlagSet -// object. -func addConfigFlag(basename string, fs *pflag.FlagSet) { - fs.AddFlag(pflag.Lookup(configFlagName)) - - viper.AutomaticEnv() - viper.SetEnvPrefix(strings.Replace(strings.ToUpper(basename), "-", "_", -1)) - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) - - cobra.OnInitialize(func() { - if cfgFile != "" { - viper.SetConfigFile(cfgFile) - } else { - viper.AddConfigPath(".") - - if names := strings.Split(basename, "-"); len(names) > 1 { - viper.AddConfigPath(filepath.Join(homedir.HomeDir(), "."+names[0])) - } - - viper.SetConfigName(basename) - } - - if err := viper.ReadInConfig(); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Error: failed to read configuration file(%s): %v\n", cfgFile, err) - os.Exit(1) - } - }) -} - -//nolint: deadcode,unused -func printConfig() { - keys := viper.AllKeys() - if len(keys) > 0 { - fmt.Printf("%v Configuration items:\n", progressMessage) - table := uitable.New() - table.Separator = " " - table.MaxColWidth = 80 - table.RightAlign(0) - for _, k := range keys { - table.AddRow(fmt.Sprintf("%s:", k), viper.Get(k)) - } - fmt.Printf("%v", table) - } -} diff --git a/pkg/app/flag.go b/pkg/app/flag.go deleted file mode 100644 index fb206e9..0000000 --- a/pkg/app/flag.go +++ /dev/null @@ -1,21 +0,0 @@ -package app - -import ( - "strings" - - "github.com/spf13/pflag" -) - -//nolint: deadcode,unused,varcheck -func initFlag() { - pflag.CommandLine.SetNormalizeFunc(WordSepNormalizeFunc) -} - -// WordSepNormalizeFunc changes all flags that contain "_" separators. -func WordSepNormalizeFunc(_ *pflag.FlagSet, name string) pflag.NormalizedName { - if strings.Contains(name, "_") { - return pflag.NormalizedName(strings.Replace(name, "_", "-", -1)) - } - - return pflag.NormalizedName(name) -} diff --git a/pkg/app/help.go b/pkg/app/help.go deleted file mode 100644 index 9a426c8..0000000 --- a/pkg/app/help.go +++ /dev/null @@ -1,52 +0,0 @@ -package app - -import ( - "fmt" - "strings" - - "github.com/fatih/color" - "github.com/spf13/cobra" - "github.com/spf13/pflag" -) - -const ( - flagHelp = "help" - flagHelpShorthand = "H" -) - -func helpCommand(name string) *cobra.Command { - return &cobra.Command{ - Use: "help [command]", - Short: "Help about any command.", - Long: `Help provides help for any command in the application. -Simply type ` + name + ` help [path to command] for full details.`, - Run: func(c *cobra.Command, args []string) { - cmd, _, e := c.Root().Find(args) - if cmd == nil || e != nil { - c.Printf("Unknown help topic %#q\n", args) - _ = c.Root().Usage() - } else { - cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown - _ = cmd.Help() - } - }, - } -} - -// addHelpFlag adds flags for a specific application to the specified FlagSet -// object. -//nolint: deadcode,unused,varcheck -func addHelpFlag(name string, fs *pflag.FlagSet) { - fs.BoolP(flagHelp, flagHelpShorthand, false, fmt.Sprintf("Help for %s.", name)) -} - -// addHelpCommandFlag adds flags for a specific command of application to the -// specified FlagSet object. -func addHelpCommandFlag(usage string, fs *pflag.FlagSet) { - fs.BoolP( - flagHelp, - flagHelpShorthand, - false, - fmt.Sprintf("Help for the %s command.", color.GreenString(strings.Split(usage, " ")[0])), - ) -} diff --git a/pkg/app/options.go b/pkg/app/options.go deleted file mode 100644 index bebcc3c..0000000 --- a/pkg/app/options.go +++ /dev/null @@ -1,28 +0,0 @@ -package app - -import ( - cliflag "github.com/marmotedu/component-base/pkg/cli/flag" -) - -// CliOptions abstracts configuration options for reading parameters from the -// command line. -type CliOptions interface { - Flags() (fss cliflag.NamedFlagSets) - Validate() []error -} - -// ConfigurableOptions abstracts configuration options for reading parameters -// from a configuration file. -type ConfigurableOptions interface { - ApplyFlags() []error -} - -// CompletableOptions abstracts configuration options which can completed. -type CompletableOptions interface { - Complete() error -} - -// PrintableOptions abstracts configuration options which can printed. -type PrintableOptions interface { - String() string -} diff --git a/pkg/client/bifrost/v1/service/web_server_config.go b/pkg/client/bifrost/v1/service/web_server_config.go index 0e48ba4..9918bbe 100644 --- a/pkg/client/bifrost/v1/service/web_server_config.go +++ b/pkg/client/bifrost/v1/service/web_server_config.go @@ -1,11 +1,11 @@ package service import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/marmotedu/errors" v1 "github.com/ClessLi/bifrost/api/bifrost/v1" epv1 "github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type WebServerConfigService interface { @@ -56,7 +56,7 @@ func (w *webServerConfigService) Update(servername string, config []byte) error if err != nil { return err } - log.Infof("Update result: %s", resp.(*v1.Response).Message) + logV1.Infof("Update result: %s", resp.(*v1.Response).Message) return nil } diff --git a/pkg/client/grpc_health_v1/client.go b/pkg/client/grpc_health_v1/client.go index a04119d..d2544e1 100644 --- a/pkg/client/grpc_health_v1/client.go +++ b/pkg/client/grpc_health_v1/client.go @@ -1,12 +1,11 @@ package grpc_health_v1 import ( + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/ClessLi/skirnir/pkg/discover" kitzaplog "github.com/go-kit/kit/log/zap" "github.com/marmotedu/errors" "google.golang.org/grpc" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type Client struct { @@ -24,7 +23,7 @@ func NewClientFromConsul(consulHost string, consulPort uint16, opts ...grpc.Dial } relay, err := discoveryClient.DiscoverServicesClient( "com.github.ClessLi.api.bifrost", - kitzaplog.NewZapSugarLogger(log.ZapLogger(), log.InfoLevel), + kitzaplog.NewZapSugarLogger(logV1.ZapLogger(), logV1.InfoLevel), factory, ) if err != nil { diff --git a/pkg/client/grpc_health_v1/endpoint.go b/pkg/client/grpc_health_v1/endpoint.go index 489078a..690a907 100644 --- a/pkg/client/grpc_health_v1/endpoint.go +++ b/pkg/client/grpc_health_v1/endpoint.go @@ -3,14 +3,13 @@ package grpc_health_v1 import ( "context" "errors" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "io" "github.com/go-kit/kit/endpoint" grpctransport "github.com/go-kit/kit/transport/grpc" "google.golang.org/grpc" "google.golang.org/grpc/health/grpc_health_v1" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type endpoints struct { @@ -43,11 +42,11 @@ func (e *endpoints) Watch(ctx context.Context, service string) (<-chan HealthSta for { select { case <-ctx.Done(): - log.Info("health watch connect closed by client") + logV1.Info("health watch connect closed by client") close(statusC) err := c.CloseSend() if err != nil { - log.Warnf(err.Error()) + logV1.Warnf(err.Error()) } return @@ -55,11 +54,11 @@ func (e *endpoints) Watch(ctx context.Context, service string) (<-chan HealthSta s, err := c.Recv() if err != nil { if errors.Is(err, io.EOF) { - log.Info("health watch connect closed by server") + logV1.Info("health watch connect closed by server") return } - log.Error(err.Error()) + logV1.Error(err.Error()) return } diff --git a/pkg/log/v1/README.md b/pkg/log/v1/README.md deleted file mode 100644 index 4ff0cef..0000000 --- a/pkg/log/v1/README.md +++ /dev/null @@ -1,134 +0,0 @@ - -# ClessLi/log - -`ClessLi/log`是一个生产可用的日志包,基于 `zap` 包封装。除了实现 `Go` 日志包的基本功能外,还实现了很多高级功能,`ClessLi/log`具有如下特性: - -- 支持自定义配置。 -- 支持文件名和行号。 -- 支持日志级别 `Debug`、`Info`、`Warn`、`Error`、`Panic`、`Fatal`。 -- 支持输出到本地文件和标准输出。 -- 支持 JSON 和 TEXT 格式的日志输出,支持自定义日志格式。 -- 支持颜色输出。 -- 兼容标准的 `log` 包。 -- 高性能。 -- 支持结构化日志记录。 -- **兼容标准库 `log` 包和 `glog`**。 -- **支持Context(业务定制)** -## Usage/Examples - -### 一个简单的示例 - -创建一个 `example_v2.go` 文件,内容如下: - -```go -import log "github.com/ClessLi/ansible-role-manager/pkg/log/v2" - -func main() { - defer log.Flush() - - // Debug、Info(with field)、Warnf、Errorw使用 - log.Debug("this is a debug message") - log.Info("this is a info message", log.Int32("int_key", 10)) - log.Warnf("this is a formatted %s message", "warn") -} -``` - -执行代码: - -```bash -$ go run example_v2.go -``` - -上述代码使用 `ClessLi/log` 包默认的全局 `logger`,分别在 `Debug` 、`Info` 和 `Warn` 级别打印了一条日志。 - -### 初始化日志包 - -可以使用 `Init` 来初始化一个日志包,如下: - -```go -// logger配置 -opts := &log.Options{ - Level: "debug", - Format: "console", - EnableColor: true, - EnableCaller: true, - OutputPaths: []string{"test.log", "stdout"}, - ErrorOutputPaths: []string{"error.log"}, -} -// 初始化全局logger -log.Init(opts) -``` - -Format 支持 `console` 和 `json` 2 种格式: -- console:输出为 text 格式。例如:`2020-12-05 08:12:02.324 DEBUG example/example.go:43 This is a debug message` -- json:输出为 json 格式,例如:`{"level":"debug","time":"2020-12-05 08:12:54.113","caller":"example/example.go:43","msg":"This is a debug message"}` - -OutputPaths,可以设置日志输出: -- stdout:输出到标准输出。 -- stderr:输出到标准错误输出。 -- /var/log/test.log:输出到文件。 - -支持同时输出到多个输出。 - -EnableColor 为 `true` 开启颜色输出,为 `false` 关闭颜色输出。 - -### 结构化日志输出 - -`ClessLi/log` 也支持结构化日志打印,例如: - -```go -log.Info("This is a info message", log.Int32("int_key", 10)) -log.Infow("Message printed with Errorw", "X-Request-ID", "fbf54504-64da-4088-9b86-67824a7fb508") -``` -对应的输出结果为: - -``` -2020-12-05 08:16:18.749 INFO example/example.go:44 This is a info message {"int_key": 10} -2020-12-05 08:16:18.749 ERROR example/example.go:46 Message printed with Errorw {"X-Request-ID": "fbf54504-64da-4088-9b86-67824a7fb508"} -``` - -log.Info 这类函数需要指定具体的类型,以最大化的 提高日志的性能。log.Infow 这类函数,不用指定具体的类型,底层使用了反射,性能会差些。建议用在低频调用的函数中。 - -## 支持V level - -创建 `v_level.go`,内容如下: - -```go -package main - -import ( - log "github.com/ClessLi/ansible-role-manager/pkg/log/v2" -) - -func main() { - defer log.Flush() - - log.V(0).Info("This is a V level message") - log.V(0).Infow("This is a V level message with fields", "X-Request-ID", "7a7b9f24-4cae-4b2a-9464-69088b45b904") -} -``` - -执行如上代码: - -```bash -$ go run v_level.go -2020-12-05 08:20:37.763 info example/v_level.go:10 This is a V level message -2020-12-05 08:20:37.763 info example/v_level.go:11 This is a V level message with fields {"X-Request-ID": "7a7b9f24-4cae-4b2a-9464-69088b45b904"} -``` - -## 完整的示例 - -一个完整的示例请参考[example_v2.go](../example/example_v2.go)。 - -## Acknowledgements - - - [Awesome Readme Templates](https://awesomeopensource.com/project/elangosundar/awesome-README-templates) - - [Awesome README](https://github.com/matiassingers/awesome-readme) - - [How to write a Good readme](https://bulldogjob.com/news/449-how-to-write-a-good-readme-for-your-github-project) - - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - - \ No newline at end of file diff --git a/pkg/log/v1/context.go b/pkg/log/v1/context.go deleted file mode 100644 index f665c18..0000000 --- a/pkg/log/v1/context.go +++ /dev/null @@ -1,32 +0,0 @@ -package v1 - -import ( - "context" -) - -type key int - -const ( - logContextKey key = iota -) - -// WithContext returns a copy of context in which the log value is set. -func WithContext(ctx context.Context) context.Context { - return std.WithContext(ctx) -} - -func (l *zapLogger) WithContext(ctx context.Context) context.Context { - return context.WithValue(ctx, logContextKey, l) -} - -// FromContext returns the value of the log key on the ctx. -func FromContext(ctx context.Context) Logger { - if ctx != nil { - logger := ctx.Value(logContextKey) - if logger != nil { - return logger.(Logger) - } - } - - return WithName("Unknown-Context") -} diff --git a/pkg/log/v1/distribution/logger.go b/pkg/log/v1/distribution/logger.go deleted file mode 100644 index 7ce3afd..0000000 --- a/pkg/log/v1/distribution/logger.go +++ /dev/null @@ -1,166 +0,0 @@ -package distribution - -import ( - "fmt" - - "github.com/sirupsen/logrus" - "go.uber.org/zap" - - logruslogger "github.com/ClessLi/bifrost/pkg/log/v1/logrus" -) - -// Logger is a logger which compatible to logrus/std log/prometheus. -// it implements Print() Println() Printf() Dbug() Debugln() Debugf() Info() Infoln() Infof() Warn() Warnln() Warnf() -// Error() Errorln() Errorf() Fatal() Fataln() Fatalf() Panic() Panicln() Panicf() With() WithField() WithFields(). -type Logger struct { - logger *zap.Logger - logrusLogger *logrus.Logger -} - -// NewLogger create the field logger object by giving zap logger. -func NewLogger(logger *zap.Logger) *Logger { - return &Logger{ - logger: logger, - logrusLogger: logruslogger.NewLogger(logger), - } -} - -// Print logs a message at level Print on the compatibleLogger. -func (l *Logger) Print(args ...interface{}) { - l.logger.Info(fmt.Sprint(args...)) -} - -// Println logs a message at level Print on the compatibleLogger. -func (l *Logger) Println(args ...interface{}) { - l.logger.Info(fmt.Sprint(args...)) -} - -// Printf logs a message at level Print on the compatibleLogger. -func (l *Logger) Printf(format string, args ...interface{}) { - l.logger.Info(fmt.Sprintf(format, args...)) -} - -// Trace logs a message at level Trace on the compatibleLogger. -func (l *Logger) Trace(args ...interface{}) { - l.logger.Debug(fmt.Sprint(args...)) -} - -// Traceln logs a message at level Trace on the compatibleLogger. -func (l *Logger) Traceln(args ...interface{}) { - l.logger.Debug(fmt.Sprint(args...)) -} - -// Tracef logs a message at level Trace on the compatibleLogger. -func (l *Logger) Tracef(format string, args ...interface{}) { - l.logger.Debug(fmt.Sprintf(format, args...)) -} - -// Debug logs a message at level Debug on the compatibleLogger. -func (l *Logger) Debug(args ...interface{}) { - l.logger.Debug(fmt.Sprint(args...)) -} - -// Debugln logs a message at level Debug on the compatibleLogger. -func (l *Logger) Debugln(args ...interface{}) { - l.logger.Debug(fmt.Sprint(args...)) -} - -// Debugf logs a message at level Debug on the compatibleLogger. -func (l *Logger) Debugf(format string, args ...interface{}) { - l.logger.Debug(fmt.Sprintf(format, args...)) -} - -// Info logs a message at level Info on the compatibleLogger. -func (l *Logger) Info(args ...interface{}) { - l.logger.Info(fmt.Sprint(args...)) -} - -// Infoln logs a message at level Info on the compatibleLogger. -func (l *Logger) Infoln(args ...interface{}) { - l.logger.Info(fmt.Sprint(args...)) -} - -// Infof logs a message at level Info on the compatibleLogger. -func (l *Logger) Infof(format string, args ...interface{}) { - l.logger.Info(fmt.Sprintf(format, args...)) -} - -// Warn logs a message at level Warn on the compatibleLogger. -func (l *Logger) Warn(args ...interface{}) { - l.logger.Warn(fmt.Sprint(args...)) -} - -// Warnln logs a message at level Warn on the compatibleLogger. -func (l *Logger) Warnln(args ...interface{}) { - l.logger.Warn(fmt.Sprint(args...)) -} - -// Warnf logs a message at level Warn on the compatibleLogger. -func (l *Logger) Warnf(format string, args ...interface{}) { - l.logger.Warn(fmt.Sprintf(format, args...)) -} - -// Warning logs a message at level Warn on the compatibleLogger. -func (l *Logger) Warning(args ...interface{}) { - l.logger.Warn(fmt.Sprint(args...)) -} - -// Warningln logs a message at level Warning on the compatibleLogger. -func (l *Logger) Warningln(args ...interface{}) { - l.logger.Warn(fmt.Sprint(args...)) -} - -// Warningf logs a message at level Warning on the compatibleLogger. -func (l *Logger) Warningf(format string, args ...interface{}) { - l.logger.Warn(fmt.Sprintf(format, args...)) -} - -// Error logs a message at level Error on the compatibleLogger. -func (l *Logger) Error(args ...interface{}) { - l.logger.Error(fmt.Sprint(args...)) -} - -// Errorln logs a message at level Error on the compatibleLogger. -func (l *Logger) Errorln(args ...interface{}) { - l.logger.Error(fmt.Sprint(args...)) -} - -// Errorf logs a message at level Error on the compatibleLogger. -func (l *Logger) Errorf(format string, args ...interface{}) { - l.logger.Error(fmt.Sprintf(format, args...)) -} - -// Fatal logs a message at level Fatal on the compatibleLogger. -func (l *Logger) Fatal(args ...interface{}) { - l.logger.Fatal(fmt.Sprint(args...)) -} - -// Fatalln logs a message at level Fatal on the compatibleLogger. -func (l *Logger) Fatalln(args ...interface{}) { - l.logger.Fatal(fmt.Sprint(args...)) -} - -// Fatalf logs a message at level Fatal on the compatibleLogger. -func (l *Logger) Fatalf(format string, args ...interface{}) { - l.logger.Fatal(fmt.Sprintf(format, args...)) -} - -// Panic logs a message at level Painc on the compatibleLogger. -func (l *Logger) Panic(args ...interface{}) { - l.logger.Panic(fmt.Sprint(args...)) -} - -// Panicln logs a message at level Painc on the compatibleLogger. -func (l *Logger) Panicln(args ...interface{}) { - l.logger.Panic(fmt.Sprint(args...)) -} - -// Panicf logs a message at level Painc on the compatibleLogger. -func (l *Logger) Panicf(format string, args ...interface{}) { - l.logger.Panic(fmt.Sprintf(format, args...)) -} - -// WithError return a logger with an error field. -func (l *Logger) WithError(err error) *logrus.Entry { - return logrus.NewEntry(l.logrusLogger).WithError(err) -} diff --git a/pkg/log/v1/encoder.go b/pkg/log/v1/encoder.go deleted file mode 100644 index 64100be..0000000 --- a/pkg/log/v1/encoder.go +++ /dev/null @@ -1,15 +0,0 @@ -package v1 - -import ( - "time" - - "go.uber.org/zap/zapcore" -) - -func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString(t.Format("2006-01-02 15:04:05.000")) -} - -func milliSecondsDurationEncoder(d time.Duration, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendFloat64(float64(d) / float64(time.Millisecond)) -} diff --git a/pkg/log/v1/example/example.go b/pkg/log/v1/example/example.go deleted file mode 100644 index 19121c6..0000000 --- a/pkg/log/v1/example/example.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "context" - "flag" - - log "github.com/ClessLi/bifrost/pkg/log/v1" -) - -var ( - h bool - - level int - format string -) - -func main() { - flag.BoolVar(&h, "h", false, "Print this help.") - flag.IntVar(&level, "l", 0, "Log level.") - flag.StringVar(&format, "f", "console", "log output format.") - - flag.Parse() - - if h { - flag.Usage() - - return - } - - // logger配置 - opts := &log.Options{ - Level: "debug", - Format: "console", - EnableColor: true, - DisableCaller: true, - OutputPaths: []string{"test.log", "stdout"}, - ErrorOutputPaths: []string{"error.log", "stderr"}, - } - // 初始化全局logger - log.Init(opts) - defer log.Flush() - - // Debug、Info(with field)、Warnf、Errorw使用 - log.Debug("This is a debug message") - log.Info("This is a info message", log.Int32("int_key", 10)) - log.Warnf("This is a formatted %s message", "warn") - log.Errorw("Message printed with Errorw", "X-Request-ID", "fbf54504-64da-4088-9b86-67824a7fb508") - - // WithValues使用 - lv := log.WithValues("X-Request-ID", "7a7b9f24-4cae-4b2a-9464-69088b45b904") - lv.Infow("Info message printed with [WithValues] logger") - lv.Infow("Debug message printed with [WithValues] logger") - - // Context使用 - ctx := lv.WithContext(context.Background()) - lc := log.FromContext(ctx) - lc.Info("Message printed with [WithContext] logger") - - ln := lv.WithName("test") - ln.Info("Message printed with [WithName] logger") - - // V level使用 - log.V(1).Info("This is a V level message") - log.V(1).Infow("This is a V level message with fields", "X-Request-ID", "7a7b9f24-4cae-4b2a-9464-69088b45b904") -} diff --git a/pkg/log/v1/klog/logger.go b/pkg/log/v1/klog/logger.go deleted file mode 100644 index b6c6dce..0000000 --- a/pkg/log/v1/klog/logger.go +++ /dev/null @@ -1,61 +0,0 @@ -package klog - -import ( - "flag" - - "go.uber.org/zap" - "k8s.io/klog" -) - -// InitLogger init klog by zap logger. -func InitLogger(zapLogger *zap.Logger) { - fs := flag.NewFlagSet("klog", flag.ExitOnError) - klog.InitFlags(fs) - defer klog.Flush() - klog.SetOutputBySeverity("INFO", &infoLogger{logger: zapLogger}) - klog.SetOutputBySeverity("WARNING", &warnLogger{logger: zapLogger}) - klog.SetOutputBySeverity("FATAL", &fatalLogger{logger: zapLogger}) - klog.SetOutputBySeverity("ERROR", &errorLogger{logger: zapLogger}) - _ = fs.Set("skip_headers", "true") - _ = fs.Set("logtostderr", "false") -} - -type infoLogger struct { - logger *zap.Logger -} - -func (l *infoLogger) Write(p []byte) (n int, err error) { - l.logger.Info(string(p[:len(p)-1])) - - return len(p), nil -} - -type warnLogger struct { - logger *zap.Logger -} - -func (l *warnLogger) Write(p []byte) (n int, err error) { - l.logger.Warn(string(p[:len(p)-1])) - - return len(p), nil -} - -type fatalLogger struct { - logger *zap.Logger -} - -func (l *fatalLogger) Write(p []byte) (n int, err error) { - l.logger.Fatal(string(p[:len(p)-1])) - - return len(p), nil -} - -type errorLogger struct { - logger *zap.Logger -} - -func (l *errorLogger) Write(p []byte) (n int, err error) { - l.logger.Error(string(p[:len(p)-1])) - - return len(p), nil -} diff --git a/pkg/log/v1/log.go b/pkg/log/v1/log.go deleted file mode 100644 index c81f2b1..0000000 --- a/pkg/log/v1/log.go +++ /dev/null @@ -1,570 +0,0 @@ -package v1 - -import ( - "context" - "fmt" - "log" - "sync" - - kitlog "github.com/go-kit/kit/log" - kitzaplog "github.com/go-kit/kit/log/zap" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - - "github.com/ClessLi/bifrost/pkg/log/v1/klog" -) - -// InfoLogger represents the ability to log non-error messages, at a particular verbosity. -type InfoLogger interface { - // Info logs a non-error message with the given key/value pairs as context. - // - // The msg argument should be used to add some constant description to - // the log line. The key/value pairs can then be used to add additional - // variable information. The key/value pairs should alternate string - // keys and arbitrary values. - Info(msg string, fields ...Field) - Infof(format string, v ...interface{}) - Infow(msg string, keysAndValues ...interface{}) - - KigLogger() kitlog.Logger - - // Enabled tests whether this InfoLogger is enabled. For example, - // commandline flags might be used to set the logging verbosity and disable - // some info logs. - Enabled() bool -} - -// Logger represents the ability to log messages, both errors and not. -type Logger interface { - // All Loggers implement InfoLogger. Calling InfoLogger methods directly on - // a Logger value is equivalent to calling them on a V(0) InfoLogger. For - // example, logger.Info() produces the same result as logger.V(0).Info. - InfoLogger - - Debug(msg string, fields ...Field) - Debugf(format string, v ...interface{}) - Debugw(msg string, keysAndValues ...interface{}) - - Warn(msg string, fields ...Field) - Warnf(format string, v ...interface{}) - Warnw(msg string, keysAndValues ...interface{}) - - Error(msg string, fields ...Field) - Errorf(format string, v ...interface{}) - Errorw(msg string, keysAndValues ...interface{}) - - Panic(msg string, fields ...Field) - Panicf(format string, v ...interface{}) - Panicw(msg string, keysAndValues ...interface{}) - - Fatal(msg string, fields ...Field) - Fatalf(format string, v ...interface{}) - Fatalw(msg string, keysAndValues ...interface{}) - - // V returns an InfoLogger value for a specific verbosity level. A higher - // verbosity level means a log message is less important. It's illegal to - // pass a log level less than zero. - V(level int) InfoLogger - - Write(p []byte) (n int, err error) - - // WithValues adds some key-value pairs of context to a logger. - // See Info for documentation on how key/value pairs work. - WithValues(keysAndValues ...interface{}) Logger - - // WithName adds a new element to the logger's name. - // Successive calls with WithName continue to append - // suffixes to the logger's name. It's strongly recommended - // that name segments contain only letters, digits, and hyphens - // (see the package documentation for more information). - WithName(name string) Logger - - // WithContext returns a copy of context in which the log value is set. - WithContext(ctx context.Context) context.Context - - // Flush calls the underlying Core's Sync method, flushing any buffered - // log entries. Applications should take care to call Sync before exiting. - Flush() -} - -var _ Logger = &zapLogger{} - -// noopInfoLogger is a logr.InfoLogger that's always disabled, and does nothing. -type noopInfoLogger struct{} - -func (l *noopInfoLogger) Enabled() bool { return false } -func (l *noopInfoLogger) Info(_ string, _ ...Field) {} -func (l *noopInfoLogger) Infof(_ string, _ ...interface{}) {} -func (l *noopInfoLogger) Infow(_ string, _ ...interface{}) {} -func (l *noopInfoLogger) KigLogger() kitlog.Logger { return nil } - -var disabledInfoLogger = &noopInfoLogger{} - -// NB: right now, we always use the equivalent of sugared logging. -// This is necessary, since logr doesn't define non-suggared types, -// and using zap-specific non-suggared types would make uses tied -// directly to Zap. - -var _ InfoLogger = &infoLogger{} - -// infoLogger is a logr.InfoLogger that uses Zap to log at a particular -// level. The level has already been converted to a Zap level, which -// is to say that `logrLevel = -1*zapLevel`. -type infoLogger struct { - level zapcore.Level - log *zap.Logger -} - -func (l *infoLogger) Enabled() bool { return true } -func (l *infoLogger) Info(msg string, fields ...Field) { - if checkedEntry := l.log.Check(l.level, msg); checkedEntry != nil { - checkedEntry.Write(fields...) - } -} - -func (l *infoLogger) Infof(format string, args ...interface{}) { - if checkedEntry := l.log.Check(l.level, fmt.Sprintf(format, args...)); checkedEntry != nil { - checkedEntry.Write() - } -} - -func (l *infoLogger) Infow(msg string, keysAndValues ...interface{}) { - if checkedEntry := l.log.Check(l.level, msg); checkedEntry != nil { - checkedEntry.Write(handleFields(l.log, keysAndValues)...) - } -} - -func (l *infoLogger) KigLogger() kitlog.Logger { - return kitzaplog.NewZapSugarLogger(l.log, l.level) -} - -// zapLogger is a logr.Logger that uses Zap to log. -type zapLogger struct { - // NB: this looks very similar to zap.SugaredLogger, but - // deals with our desire to have multiple verbosity levels. - zapLogger *zap.Logger - infoLogger -} - -// handleFields converts a bunch of arbitrary key-value pairs into Zap fields. It takes -// additional pre-converted Zap fields, for use with automatically attached fields, like -// `error`. -func handleFields(l *zap.Logger, args []interface{}, additional ...zap.Field) []zap.Field { - // a slightly modified version of zap.SugaredLogger.sweetenFields - if len(args) == 0 { - // fast-return if we have no suggared fields. - return additional - } - - // unlike Zap, we can be pretty sure users aren't passing structured - // fields (since logr has no concept of that), so guess that we need a - // little less space. - fields := make([]zap.Field, 0, len(args)/2+len(additional)) - for i := 0; i < len(args); { - // check just in case for strongly-typed Zap fields, which is illegal (since - // it breaks implementation agnosticism), so we can give a better error message. - if _, ok := args[i].(zap.Field); ok { - l.DPanic("strongly-typed Zap Field passed to logr", zap.Any("zap field", args[i])) - - break - } - - // make sure this isn't a mismatched key - if i == len(args)-1 { - l.DPanic("odd number of arguments passed as key-value pairs for logging", zap.Any("ignored key", args[i])) - - break - } - - // process a key-value pair, - // ensuring that the key is a string - key, val := args[i], args[i+1] - keyStr, isString := key.(string) - if !isString { - // if the key isn't a string, DPanic and stop logging - l.DPanic( - "non-string key argument passed to logging, ignoring all later arguments", - zap.Any("invalid key", key), - ) - - break - } - - fields = append(fields, zap.Any(keyStr, val)) - i += 2 - } - - return append(fields, additional...) -} - -var ( - std = New(NewOptions()) - mu sync.Mutex -) - -// Init initializes logger with specified options. -func Init(opts *Options) { - mu.Lock() - defer mu.Unlock() - std = New(opts) -} - -// New create logger by opts which can custmoized by command arguments. -func New(opts *Options) *zapLogger { - if opts == nil { - opts = NewOptions() - } - - var zapLevel zapcore.Level - if err := zapLevel.UnmarshalText([]byte(opts.Level)); err != nil { - zapLevel = zapcore.InfoLevel - } - encodeLevel := zapcore.CapitalLevelEncoder - // when output to local path, with color is forbidden - if opts.Format == consoleFormat && opts.EnableColor { - encodeLevel = zapcore.CapitalColorLevelEncoder - } - - encoderConfig := zapcore.EncoderConfig{ - MessageKey: "message", - LevelKey: "level", - TimeKey: "timestamp", - NameKey: "logger", - CallerKey: "caller", - StacktraceKey: "stacktrace", - LineEnding: zapcore.DefaultLineEnding, - EncodeLevel: encodeLevel, - EncodeTime: timeEncoder, - EncodeDuration: milliSecondsDurationEncoder, - EncodeCaller: zapcore.ShortCallerEncoder, - } - - loggerConfig := &zap.Config{ - Level: zap.NewAtomicLevelAt(zapLevel), - Development: opts.Development, - DisableCaller: opts.DisableCaller, - DisableStacktrace: opts.DisableStacktrace, - Sampling: &zap.SamplingConfig{ - Initial: 100, - Thereafter: 100, - }, - Encoding: opts.Format, - EncoderConfig: encoderConfig, - OutputPaths: opts.OutputPaths, - ErrorOutputPaths: opts.ErrorOutputPaths, - } - - var err error - l, err := loggerConfig.Build(zap.AddStacktrace(zapcore.PanicLevel), zap.AddCallerSkip(1)) - if err != nil { - panic(err) - } - logger := &zapLogger{ - zapLogger: l.Named(opts.Name), - infoLogger: infoLogger{ - log: l, - level: zap.InfoLevel, - }, - } - klog.InitLogger(l) - zap.RedirectStdLog(l) - - return logger -} - -// StdLogger returns global std logger. -func StdLogger() *zapLogger { - return std -} - -// StdErrLogger returns logger of standard library which writes to supplied zap -// logger at error level. -func StdErrLogger() *log.Logger { - if std == nil { - return nil - } - if l, err := zap.NewStdLogAt(std.zapLogger, zapcore.ErrorLevel); err == nil { - return l - } - - return nil -} - -// StdInfoLogger returns logger of standard library which writes to supplied zap -// logger at info level. -func StdInfoLogger() *log.Logger { - if std == nil { - return nil - } - if l, err := zap.NewStdLogAt(std.zapLogger, zapcore.InfoLevel); err == nil { - return l - } - - return nil -} - -// V return a leveled InfoLogger. -func V(level int) InfoLogger { return std.V(level) } - -func (l *zapLogger) V(level int) InfoLogger { - lvl := zapcore.Level(-1 * level) - if l.zapLogger.Core().Enabled(lvl) { - return &infoLogger{ - level: lvl, - log: l.zapLogger, - } - } - - return disabledInfoLogger -} - -func (l *zapLogger) Write(p []byte) (n int, err error) { - l.zapLogger.Info(string(p)) - - return len(p), nil -} - -// WithValues creates a child logger and adds Zap fields to it. -func WithValues(keysAndValues ...interface{}) Logger { return std.WithValues(keysAndValues...) } - -func (l *zapLogger) WithValues(keysAndValues ...interface{}) Logger { - newLogger := l.zapLogger.With(handleFields(l.zapLogger, keysAndValues)...) - - return NewLogger(newLogger) -} - -// WithName adds a new path segment to the logger's name. Segments are joined by -// periods. By default, Loggers are unnamed. -func WithName(s string) Logger { return std.WithName(s) } - -func (l *zapLogger) WithName(name string) Logger { - newLogger := l.zapLogger.Named(name) - - return NewLogger(newLogger) -} - -// Flush calls the underlying Core's Sync method, flushing any buffered -// log entries. Applications should take care to call Sync before exiting. -func Flush() { std.Flush() } - -func (l *zapLogger) Flush() { - _ = l.zapLogger.Sync() -} - -// NewLogger creates a new logr.Logger using the given Zap Logger to log. -func NewLogger(l *zap.Logger) Logger { - return &zapLogger{ - zapLogger: l, - infoLogger: infoLogger{ - log: l, - level: zap.InfoLevel, - }, - } -} - -// ZapLogger used for other log wrapper such as klog. -func ZapLogger() *zap.Logger { - return std.zapLogger -} - -// CheckIntLevel used for other log wrapper such as klog which return if logging a -// message at the specified level is enabled. -func CheckIntLevel(level int32) bool { - var lvl zapcore.Level - if level < 5 { - lvl = zapcore.InfoLevel - } else { - lvl = zapcore.DebugLevel - } - checkEntry := std.zapLogger.Check(lvl, "") - - return checkEntry != nil -} - -// Debug method output debug level log. -func Debug(msg string, fields ...Field) { - std.zapLogger.Debug(msg, fields...) -} - -func (l *zapLogger) Debug(msg string, fields ...Field) { - l.zapLogger.Debug(msg, fields...) -} - -// Debugf method output debug level log. -func Debugf(format string, v ...interface{}) { - std.zapLogger.Sugar().Debugf(format, v...) -} - -func (l *zapLogger) Debugf(format string, v ...interface{}) { - l.zapLogger.Sugar().Debugf(format, v...) -} - -// Debugw method output debug level log. -func Debugw(msg string, keysAndValues ...interface{}) { - std.zapLogger.Sugar().Debugw(msg, keysAndValues...) -} - -func (l *zapLogger) Debugw(msg string, keysAndValues ...interface{}) { - l.zapLogger.Sugar().Debugw(msg, keysAndValues...) -} - -// Info method output info level log. -func Info(msg string, fields ...Field) { - std.zapLogger.Info(msg, fields...) -} - -func (l *zapLogger) Info(msg string, fields ...Field) { - l.zapLogger.Info(msg, fields...) -} - -// Infof method output info level log. -func Infof(format string, v ...interface{}) { - std.zapLogger.Sugar().Infof(format, v...) -} - -func (l *zapLogger) Infof(format string, v ...interface{}) { - l.zapLogger.Sugar().Infof(format, v...) -} - -// Infow method output info level log. -func Infow(msg string, keysAndValues ...interface{}) { - std.zapLogger.Sugar().Infow(msg, keysAndValues...) -} - -func (l *zapLogger) Infow(msg string, keysAndValues ...interface{}) { - l.zapLogger.Sugar().Infow(msg, keysAndValues...) -} - -// Warn method output warning level log. -func Warn(msg string, fields ...Field) { - std.zapLogger.Warn(msg, fields...) -} - -func (l *zapLogger) Warn(msg string, fields ...Field) { - l.zapLogger.Warn(msg, fields...) -} - -// Warnf method output warning level log. -func Warnf(format string, v ...interface{}) { - std.zapLogger.Sugar().Warnf(format, v...) -} - -func (l *zapLogger) Warnf(format string, v ...interface{}) { - l.zapLogger.Sugar().Warnf(format, v...) -} - -// Warnw method output warning level log. -func Warnw(msg string, keysAndValues ...interface{}) { - std.zapLogger.Sugar().Warnw(msg, keysAndValues...) -} - -func (l *zapLogger) Warnw(msg string, keysAndValues ...interface{}) { - l.zapLogger.Sugar().Warnw(msg, keysAndValues...) -} - -// Error method output error level log. -func Error(msg string, fields ...Field) { - std.zapLogger.Error(msg, fields...) -} - -func (l *zapLogger) Error(msg string, fields ...Field) { - l.zapLogger.Error(msg, fields...) -} - -// Errorf method output error level log. -func Errorf(format string, v ...interface{}) { - std.zapLogger.Sugar().Errorf(format, v...) -} - -func (l *zapLogger) Errorf(format string, v ...interface{}) { - l.zapLogger.Sugar().Errorf(format, v...) -} - -// Errorw method output error level log. -func Errorw(msg string, keysAndValues ...interface{}) { - std.zapLogger.Sugar().Errorw(msg, keysAndValues...) -} - -func (l *zapLogger) Errorw(msg string, keysAndValues ...interface{}) { - l.zapLogger.Sugar().Errorw(msg, keysAndValues...) -} - -// Panic method output panic level log and shutdown application. -func Panic(msg string, fields ...Field) { - std.zapLogger.Panic(msg, fields...) -} - -func (l *zapLogger) Panic(msg string, fields ...Field) { - l.zapLogger.Panic(msg, fields...) -} - -// Panicf method output panic level log and shutdown application. -func Panicf(format string, v ...interface{}) { - std.zapLogger.Sugar().Panicf(format, v...) -} - -func (l *zapLogger) Panicf(format string, v ...interface{}) { - l.zapLogger.Sugar().Panicf(format, v...) -} - -// Panicw method output panic level log. -func Panicw(msg string, keysAndValues ...interface{}) { - std.zapLogger.Sugar().Panicw(msg, keysAndValues...) -} - -func (l *zapLogger) Panicw(msg string, keysAndValues ...interface{}) { - l.zapLogger.Sugar().Panicw(msg, keysAndValues...) -} - -// Fatal method output fatal level log. -func Fatal(msg string, fields ...Field) { - std.zapLogger.Fatal(msg, fields...) -} - -func (l *zapLogger) Fatal(msg string, fields ...Field) { - l.zapLogger.Fatal(msg, fields...) -} - -// Fatalf method output fatal level log. -func Fatalf(format string, v ...interface{}) { - std.zapLogger.Sugar().Fatalf(format, v...) -} - -func (l *zapLogger) Fatalf(format string, v ...interface{}) { - l.zapLogger.Sugar().Fatalf(format, v...) -} - -// Fatalw method output Fatalw level log. -func Fatalw(msg string, keysAndValues ...interface{}) { - std.zapLogger.Sugar().Fatalw(msg, keysAndValues...) -} - -func (l *zapLogger) Fatalw(msg string, keysAndValues ...interface{}) { - l.zapLogger.Sugar().Fatalw(msg, keysAndValues...) -} - -// L method output with specified context value. -func L(ctx context.Context) *zapLogger { - return std.L(ctx) -} - -func (l *zapLogger) L(ctx context.Context) *zapLogger { - lg := l.clone() - - requestID, _ := ctx.Value(KeyRequestID).(string) - username, _ := ctx.Value(KeyUsername).(string) - lg.zapLogger = lg.zapLogger.With(zap.String(KeyRequestID, requestID), zap.String(KeyUsername, username)) - - return lg -} - -//nolint:predeclared -func (l *zapLogger) clone() *zapLogger { - copy := *l - - return © -} - -func K() kitlog.Logger { - return std.clone().KigLogger() -} diff --git a/pkg/log/v1/logrus/hook.go b/pkg/log/v1/logrus/hook.go deleted file mode 100644 index ef1b25f..0000000 --- a/pkg/log/v1/logrus/hook.go +++ /dev/null @@ -1,59 +0,0 @@ -package logrus - -import ( - "runtime" - - "github.com/sirupsen/logrus" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -type hook struct { - logger *zap.Logger -} - -func (h *hook) Levels() []logrus.Level { - return logrus.AllLevels -} - -func (h *hook) Fire(entry *logrus.Entry) error { - fields := make([]zap.Field, 0, 10) - - for key, value := range entry.Data { - if key == logrus.ErrorKey { - fields = append(fields, zap.Error(value.(error))) - } else { - fields = append(fields, zap.Any(key, value)) - } - } - - switch entry.Level { - case logrus.PanicLevel: - h.Write(zapcore.PanicLevel, entry.Message, fields, entry.Caller) - case logrus.FatalLevel: - h.Write(zapcore.FatalLevel, entry.Message, fields, entry.Caller) - case logrus.ErrorLevel: - h.Write(zapcore.ErrorLevel, entry.Message, fields, entry.Caller) - case logrus.WarnLevel: - h.Write(zapcore.WarnLevel, entry.Message, fields, entry.Caller) - case logrus.InfoLevel: - h.Write(zapcore.InfoLevel, entry.Message, fields, entry.Caller) - case logrus.DebugLevel, logrus.TraceLevel: - h.Write(zapcore.DebugLevel, entry.Message, fields, entry.Caller) - } - - return nil -} - -func (h *hook) Write(lvl zapcore.Level, msg string, fields []zap.Field, caller *runtime.Frame) { - if ce := h.logger.Check(lvl, msg); ce != nil { - if caller != nil { - ce.Caller = zapcore.NewEntryCaller(caller.PC, caller.File, caller.Line, caller.PC != 0) - } - ce.Write(fields...) - } -} - -func newHook(logger *zap.Logger) logrus.Hook { - return &hook{logger: logger} -} diff --git a/pkg/log/v1/logrus/logger.go b/pkg/log/v1/logrus/logger.go deleted file mode 100644 index 7aff60d..0000000 --- a/pkg/log/v1/logrus/logger.go +++ /dev/null @@ -1,17 +0,0 @@ -package logrus - -import ( - "io/ioutil" - - "github.com/sirupsen/logrus" - "go.uber.org/zap" -) - -// NewLogger create a logrus logger, add hook to it and return it. -func NewLogger(zapLogger *zap.Logger) *logrus.Logger { - logger := logrus.New() - logger.SetOutput(ioutil.Discard) - logger.AddHook(newHook(zapLogger)) - - return logger -} diff --git a/pkg/log/v1/options.go b/pkg/log/v1/options.go deleted file mode 100644 index a5fa7fb..0000000 --- a/pkg/log/v1/options.go +++ /dev/null @@ -1,144 +0,0 @@ -package v1 - -import ( - "fmt" - "strings" - - "github.com/marmotedu/component-base/pkg/json" - "github.com/spf13/pflag" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -const ( - flagLevel = "log.level" - flagDisableCaller = "log.disable-caller" - flagDisableStacktrace = "log.disable-stacktrace" - flagFormat = "log.format" - flagEnableColor = "log.enable-color" - flagOutputPaths = "log.output-paths" - flagErrorOutputPaths = "log.error-output-paths" - flagDevelopment = "log.development" - flagName = "log.name" - - consoleFormat = "console" - jsonFormat = "json" -) - -// Options contains configuration items related to log. -type Options struct { - OutputPaths []string `json:"output-paths" mapstructure:"output-paths"` - ErrorOutputPaths []string `json:"error-output-paths" mapstructure:"error-output-paths"` - Level string `json:"level" mapstructure:"level"` - Format string `json:"format" mapstructure:"format"` - DisableCaller bool `json:"disable-caller" mapstructure:"disable-caller"` - DisableStacktrace bool `json:"disable-stacktrace" mapstructure:"disable-stacktrace"` - EnableColor bool `json:"enable-color" mapstructure:"enable-color"` - Development bool `json:"development" mapstructure:"development"` - Name string `json:"name" mapstructure:"name"` -} - -// NewOptions creates an Options object with default parameters. -func NewOptions() *Options { - return &Options{ - Level: zapcore.InfoLevel.String(), - DisableCaller: false, - DisableStacktrace: false, - Format: consoleFormat, - EnableColor: false, - Development: false, - OutputPaths: []string{"stdout"}, - ErrorOutputPaths: []string{"stderr"}, - } -} - -// Validate validate the options fields. -func (o *Options) Validate() []error { - var errs []error - - var zapLevel zapcore.Level - if err := zapLevel.UnmarshalText([]byte(o.Level)); err != nil { - errs = append(errs, err) - } - - format := strings.ToLower(o.Format) - if format != consoleFormat && format != jsonFormat { - errs = append(errs, fmt.Errorf("not a valid log format: %q", o.Format)) - } - - return errs -} - -// AddFlags adds flags for log to the specified FlagSet object. -func (o *Options) AddFlags(fs *pflag.FlagSet) { - fs.StringVar(&o.Level, flagLevel, o.Level, "Minimum log output `LEVEL`.") - fs.BoolVar(&o.DisableCaller, flagDisableCaller, o.DisableCaller, "Disable output of caller information in the log.") - fs.BoolVar(&o.DisableStacktrace, flagDisableStacktrace, - o.DisableStacktrace, "Disable the log to record a stack trace for all messages at or above panic level.") - fs.StringVar(&o.Format, flagFormat, o.Format, "Log output `FORMAT`, support plain or json format.") - fs.BoolVar(&o.EnableColor, flagEnableColor, o.EnableColor, "Enable output ansi colors in plain format logs.") - fs.StringSliceVar(&o.OutputPaths, flagOutputPaths, o.OutputPaths, "Output paths of log.") - fs.StringSliceVar(&o.ErrorOutputPaths, flagErrorOutputPaths, o.ErrorOutputPaths, "Error output paths of log.") - fs.BoolVar( - &o.Development, - flagDevelopment, - o.Development, - "Development puts the logger in development mode, which changes "+ - "the behavior of DPanicLevel and takes stacktraces more liberally.", - ) - fs.StringVar(&o.Name, flagName, o.Name, "The name of the logger.") -} - -func (o *Options) String() string { - data, _ := json.Marshal(o) - - return string(data) -} - -// Build constructs a global zap logger from the Config and Options. -func (o *Options) Build() error { - var zapLevel zapcore.Level - if err := zapLevel.UnmarshalText([]byte(o.Level)); err != nil { - zapLevel = zapcore.InfoLevel - } - encodeLevel := zapcore.CapitalLevelEncoder - if o.Format == consoleFormat && o.EnableColor { - encodeLevel = zapcore.CapitalColorLevelEncoder - } - - zc := &zap.Config{ - Level: zap.NewAtomicLevelAt(zapLevel), - Development: o.Development, - DisableCaller: o.DisableCaller, - DisableStacktrace: o.DisableStacktrace, - Sampling: &zap.SamplingConfig{ - Initial: 100, - Thereafter: 100, - }, - Encoding: o.Format, - EncoderConfig: zapcore.EncoderConfig{ - MessageKey: "message", - LevelKey: "level", - TimeKey: "timestamp", - NameKey: "logger", - CallerKey: "caller", - StacktraceKey: "stacktrace", - LineEnding: zapcore.DefaultLineEnding, - EncodeLevel: encodeLevel, - EncodeTime: timeEncoder, - EncodeDuration: milliSecondsDurationEncoder, - EncodeCaller: zapcore.ShortCallerEncoder, - EncodeName: zapcore.FullNameEncoder, - }, - OutputPaths: o.OutputPaths, - ErrorOutputPaths: o.ErrorOutputPaths, - } - logger, err := zc.Build(zap.AddStacktrace(zapcore.PanicLevel)) - if err != nil { - return err - } - zap.RedirectStdLog(logger.Named(o.Name)) - zap.ReplaceGlobals(logger) - - return nil -} diff --git a/pkg/log/v1/types.go b/pkg/log/v1/types.go deleted file mode 100644 index a768182..0000000 --- a/pkg/log/v1/types.go +++ /dev/null @@ -1,90 +0,0 @@ -package v1 - -import ( - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// Defines common log fields. -const ( - KeyRequestID string = "requestID" - KeyUsername string = "username" -) - -// Field is an alias for the field structure in the underlying log frame. -type Field = zapcore.Field - -// Level is an alias for the level structure in the underlying log frame. -type Level = zapcore.Level - -var ( - // DebugLevel logs are typically voluminous, and are usually disabled in - // production. - DebugLevel = zapcore.DebugLevel - // InfoLevel is the default logging priority. - InfoLevel = zapcore.InfoLevel - // WarnLevel logs are more important than Info, but don't need individual - // human review. - WarnLevel = zapcore.WarnLevel - // ErrorLevel logs are high-priority. If an application is running smoothly, - // it shouldn't generate any error-level logs. - ErrorLevel = zapcore.ErrorLevel - // PanicLevel logs a message, then panics. - PanicLevel = zapcore.PanicLevel - // FatalLevel logs a message, then calls os.Exit(1). - FatalLevel = zapcore.FatalLevel -) - -// Alias for zap type functions. -var ( - Any = zap.Any - Array = zap.Array - Object = zap.Object - Binary = zap.Binary - Bool = zap.Bool - Bools = zap.Bools - ByteString = zap.ByteString - ByteStrings = zap.ByteStrings - Complex64 = zap.Complex64 - Complex64s = zap.Complex64s - Complex128 = zap.Complex128 - Complex128s = zap.Complex128s - Duration = zap.Duration - Durations = zap.Durations - Err = zap.Error - Errors = zap.Errors - Float32 = zap.Float32 - Float32s = zap.Float32s - Float64 = zap.Float64 - Float64s = zap.Float64s - Int = zap.Int - Ints = zap.Ints - Int8 = zap.Int8 - Int8s = zap.Int8s - Int16 = zap.Int16 - Int16s = zap.Int16s - Int32 = zap.Int32 - Int32s = zap.Int32s - Int64 = zap.Int64 - Int64s = zap.Int64s - Namespace = zap.Namespace - Reflect = zap.Reflect - Stack = zap.Stack - String = zap.String - Stringer = zap.Stringer - Strings = zap.Strings - Time = zap.Time - Times = zap.Times - Uint = zap.Uint - Uints = zap.Uints - Uint8 = zap.Uint8 - Uint8s = zap.Uint8s - Uint16 = zap.Uint16 - Uint16s = zap.Uint16s - Uint32 = zap.Uint32 - Uint32s = zap.Uint32s - Uint64 = zap.Uint64 - Uint64s = zap.Uint64s - Uintptr = zap.Uintptr - Uintptrs = zap.Uintptrs -) diff --git a/pkg/resolv/V2/utils/files_funcs.go b/pkg/resolv/V2/utils/files_funcs.go index df2ca3f..93e47fc 100644 --- a/pkg/resolv/V2/utils/files_funcs.go +++ b/pkg/resolv/V2/utils/files_funcs.go @@ -3,6 +3,7 @@ package utils import ( "bytes" "fmt" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "io/ioutil" "os" "path/filepath" @@ -12,8 +13,6 @@ import ( "time" "github.com/marmotedu/errors" - - log "github.com/ClessLi/bifrost/pkg/log/v1" ) const backupDateLayout = `20060102` @@ -49,14 +48,17 @@ func GetBackupFileName(backupPrefix string, now time.Time) string { // CheckAndCleanBackups 检查归档目录下归档文件是否需要清理及是否可以进行归档操作的函数 // // 参数: -// backupPrefix: 归档文件前缀名 -// backupDir: 归档文件目录路径 -// retentionTime: 归档文件保存时间,单位天 -// backupCycleTime: 归档操作周期,单位天 -// now: 当前检查时间 +// +// backupPrefix: 归档文件前缀名 +// backupDir: 归档文件目录路径 +// retentionTime: 归档文件保存时间,单位天 +// backupCycleTime: 归档操作周期,单位天 +// now: 当前检查时间 +// // 返回值: -// true: 需要归档操作; false: 不需要归档 -// 错误 +// +// true: 需要归档操作; false: 不需要归档 +// 错误 func CheckAndCleanBackups( backupPrefix, backupDir string, retentionTime, backupCycleTime int, @@ -91,12 +93,12 @@ func CheckAndCleanBackups( // 判断是否需要清理,并清理过期归档 if bakDate.Unix() < saveDate.Unix() { - log.Infof("cleaning up expired archive '%s'", baks[i]) + logV1.Infof("cleaning up expired archive '%s'", baks[i]) rmErr := os.Remove(baks[i]) if rmErr != nil { return false, errors.Wrapf(rmErr, "failed to clean up expired archive '%s'", baks[i]) } - log.Infof("successfully cleaned up expired archive '%s'", baks[i]) + logV1.Infof("successfully cleaned up expired archive '%s'", baks[i]) } // 判断该归档是否是最新归档,是反馈不需归档,并退出循环 @@ -111,8 +113,9 @@ func CheckAndCleanBackups( // GetPid, 查询pid文件并返回pid // 返回值: -// pid -// 错误 +// +// pid +// 错误 func GetPid(path string) (int, error) { // 判断pid文件是否存在 if _, err := os.Stat(path); err == nil || os.IsExist(err) { // 存在 @@ -141,10 +144,13 @@ func GetPid(path string) (int, error) { // ReadFile, 读取文件函数 // 参数: -// path: 文件路径字符串 +// +// path: 文件路径字符串 +// // 返回值: -// 文件数据 -// 错误 +// +// 文件数据 +// 错误 func ReadFile(path string) ([]byte, error) { f, err := os.Open(path) if err != nil { diff --git a/pkg/resolv/V3/nginx/config.go b/pkg/resolv/V3/nginx/config.go new file mode 100644 index 0000000..970363d --- /dev/null +++ b/pkg/resolv/V3/nginx/config.go @@ -0,0 +1,37 @@ +package nginx + +import ( + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" + "github.com/marmotedu/errors" +) + +type Config struct { + ManagersConfig map[string]*configuration.ManagerConfig +} + +func (c *Config) Complete() (*CompletedConfig, error) { + var errs []error + var err error + cc := &CompletedConfig{make(map[string]*configuration.CompletedManagerConfig)} + + for svrname, config := range c.ManagersConfig { + cc.ManagersConfig[svrname], err = config.Complete() + errs = append(errs, err) + } + return cc, errors.NewAggregate(errs) +} + +type CompletedConfig struct { + ManagersConfig map[string]*configuration.CompletedManagerConfig +} + +func (cc *CompletedConfig) NewConfigsManager() (ConfigsManager, error) { + var errs []error + var err error + m := &configsManager{make(map[string]configuration.NginxConfigManager)} + for svrname, config := range cc.ManagersConfig { + m.managerMap[svrname], err = config.NewNginxConfigManager() + errs = append(errs, err) + } + return m, errors.NewAggregate(errs) +} diff --git a/pkg/resolv/V3/nginx/configuration/config.go b/pkg/resolv/V3/nginx/configuration/config.go new file mode 100644 index 0000000..a07133f --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/config.go @@ -0,0 +1,89 @@ +package configuration + +import ( + "path/filepath" + "strings" + "sync" + "time" +) + +type ManagerConfig struct { + NginxMainConfigAbsPath string + NginxHome string + NginxBinFilePath string + RegularlyTaskCycleDelay time.Duration + BackupCycleDays int + BackupRetentionDays int + BackupDir string + BackupPrefix string + BackupTimeZone *time.Location +} + +func (c *ManagerConfig) Complete() (*CompletedManagerConfig, error) { + // completing check nginx main config file path + absPath, err := filepath.Abs(c.NginxMainConfigAbsPath) + if err != nil { + return nil, err + } + + // completing nginx home and nginx bin file path + if len(strings.TrimSpace(c.NginxHome)) == 0 && len(strings.TrimSpace(c.NginxBinFilePath)) == 0 { + c.NginxHome = filepath.Dir(filepath.Dir(absPath)) + c.NginxBinFilePath = filepath.Join(c.NginxHome, "sbin", "nginx") + } else if len(strings.TrimSpace(c.NginxHome)) > 0 { + c.NginxBinFilePath = filepath.Join(c.NginxHome, "sbin", "nginx") + } else if len(strings.TrimSpace(c.NginxBinFilePath)) > 0 { + c.NginxHome = filepath.Dir(filepath.Dir(c.NginxBinFilePath)) + } + + // completing regularly task cycle delay time + if c.RegularlyTaskCycleDelay < time.Second*10 { + c.RegularlyTaskCycleDelay = time.Second * 10 + } + + // completing nginx config backup options + if c.BackupCycleDays <= 0 { + c.BackupCycleDays = 1 + } + + if c.BackupRetentionDays <= 0 { + c.BackupRetentionDays = 7 + } + + if len(strings.TrimSpace(c.BackupPrefix)) == 0 { + c.BackupPrefix = "nginx.conf" + } + + if c.BackupTimeZone == nil { + c.BackupTimeZone = time.Local + } + + return &CompletedManagerConfig{c}, err +} + +type CompletedManagerConfig struct { + *ManagerConfig +} + +func (cc *CompletedManagerConfig) NewNginxConfigManager() (NginxConfigManager, error) { + c, err := NewNginxConfigFromFS(cc.NginxMainConfigAbsPath) + if err != nil { + return nil, err + } + return &nginxConfigManager{ + configuration: c, + nginxHome: cc.NginxHome, + nginxBinFilePath: cc.NginxBinFilePath, + regularlyTaskCycleDelay: cc.RegularlyTaskCycleDelay, + regularlyTaskSignalChan: make(chan int), + backupOpts: backupOption{ + backupCycleDays: cc.BackupCycleDays, + backupRetentionDays: cc.BackupRetentionDays, + backupDir: cc.BackupDir, + backupPrefix: cc.BackupPrefix, + backupTimeZone: cc.BackupTimeZone, + }, + wg: new(sync.WaitGroup), + isRunning: false, + }, nil +} diff --git a/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go b/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go index df07e39..464c65b 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go @@ -135,7 +135,7 @@ func (b *BasicContext) QueryByKeyWords(kw context.KeyWords) context.Pos { } } } - return context.NullPos() + return context.NotFoundPos() } func (b *BasicContext) QueryAllByKeyWords(kw context.KeyWords) []context.Pos { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/include.go b/pkg/resolv/V3/nginx/configuration/context/local/include.go index 0e49169..8e6f9bb 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/include.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/include.go @@ -164,11 +164,11 @@ func (i *Include) ChildConfig(fullpath string) (*Config, error) { func (i *Include) QueryByKeyWords(kw context.KeyWords) context.Pos { for _, child := range i.Configs { pos := child.QueryByKeyWords(kw) - if pos != context.NullPos() { + if pos != context.NotFoundPos() { return pos } } - return context.NullPos() + return context.NotFoundPos() } func (i *Include) QueryAllByKeyWords(kw context.KeyWords) []context.Pos { diff --git a/pkg/resolv/V3/nginx/configuration/context/position.go b/pkg/resolv/V3/nginx/configuration/context/position.go index a2ef46a..8367701 100644 --- a/pkg/resolv/V3/nginx/configuration/context/position.go +++ b/pkg/resolv/V3/nginx/configuration/context/position.go @@ -1,5 +1,10 @@ package context +import ( + "github.com/ClessLi/bifrost/internal/pkg/code" + "github.com/marmotedu/errors" +) + type Pos interface { Position() (Context, int) Target() Context @@ -42,3 +47,9 @@ var nullPos = &errPos{nullContext} func NullPos() Pos { return nullPos } + +var notFoundPos = &errPos{ErrContext(errors.WithCode(code.V3ErrContextNotFound, "queried context not found")).(*ErrorContext)} + +func NotFoundPos() Pos { + return notFoundPos +} diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config.go b/pkg/resolv/V3/nginx/configuration/nginx_config.go new file mode 100644 index 0000000..bb92219 --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/nginx_config.go @@ -0,0 +1,154 @@ +package configuration + +import ( + "bytes" + "encoding/json" + "github.com/ClessLi/bifrost/internal/pkg/code" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" + utilsV3 "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/utils" + "github.com/marmotedu/errors" + "strings" + "sync" + "time" +) + +type NginxConfig interface { + Main() context.Context + UpdateFromJsonBytes(data []byte) error + UpdatedTimestamp() time.Time + TextLines() []string + Json() []byte + Dump() map[string]*bytes.Buffer +} + +type nginxConfig struct { + mainContext *local.Main + timestamp time.Time + rwLocker *sync.RWMutex +} + +func (n *nginxConfig) Main() context.Context { + n.rwLocker.RLock() + defer n.rwLocker.RUnlock() + return n.mainContext +} + +func (n *nginxConfig) UpdateFromJsonBytes(data []byte) error { + m, err := local.JsonLoader(data).Load() + if err != nil { + return err + } + // write lock operation in renewMainContext() + return n.renewMainContext(m) +} + +func (n *nginxConfig) UpdatedTimestamp() time.Time { + n.rwLocker.RLock() + defer n.rwLocker.RUnlock() + return n.timestamp +} + +func (n *nginxConfig) TextLines() []string { + n.rwLocker.RLock() + defer n.rwLocker.RUnlock() + lines, _ := n.mainContext.ConfigLines(false) + return lines +} + +func (n *nginxConfig) Json() []byte { + n.rwLocker.RLock() + defer n.rwLocker.RUnlock() + data, err := json.Marshal(n.mainContext) + if err != nil { + return nil + } + return data +} + +func (n *nginxConfig) Dump() map[string]*bytes.Buffer { + n.rwLocker.RLock() + defer n.rwLocker.RUnlock() + return dumpMainContext(n.mainContext) +} + +func (n *nginxConfig) renewMainContext(m *local.Main) error { + oldFP := utilsV3.NewConfigFingerprinterWithTimestamp(n.Dump(), time.Time{}) + newFP := utilsV3.NewConfigFingerprinterWithTimestamp(dumpMainContext(m), time.Time{}) + n.rwLocker.Lock() + defer n.rwLocker.Unlock() + if !oldFP.Diff(newFP) { + return errors.WithCode(code.ErrSameConfigFingerprint, "same config fingerprint") + } + n.mainContext = m + n.timestamp = time.Now() + return nil +} + +func NewNginxConfigFromJsonBytes(data []byte) (NginxConfig, error) { + m, err := local.JsonLoader(data).Load() + if err != nil { + return nil, err + } + return newNginxConfig(m) +} + +func NewNginxConfigFromFS(filepath string) (NginxConfig, error) { + m, t, err := loadMainContextFromFS(filepath) + if err != nil { + return nil, err + } + return newNginxConfigWithTimestamp(m, t) +} + +func loadMainContextFromFS(filepath string) (*local.Main, time.Time, error) { + timestamp := time.UnixMicro(0) + m, err := local.FileLoader(filepath).Load() + if err != nil { + return nil, timestamp, err + } + for _, config := range m.Topology() { + tt, err := utilsV3.FileModifyTime(config.FullPath()) + if err != nil { + return nil, timestamp, err + } + if tt.After(timestamp) { + timestamp = *tt + } + } + return m, timestamp, nil +} + +func dumpMainContext(m *local.Main) map[string]*bytes.Buffer { + if m == nil { + return nil + } + dumps := make(map[string]*bytes.Buffer) + for _, config := range m.Topology() { + lines, err := config.ConfigLines(true) + if err != nil { + return nil + } + buff := bytes.NewBuffer([]byte{}) + for _, line := range lines { + buff.WriteString(line + "\n") + } + dumps[strings.TrimSpace(config.FullPath())] = buff + } + return dumps +} + +func newNginxConfigWithTimestamp(maincontext *local.Main, timestamp time.Time) (NginxConfig, error) { + if maincontext == nil { + return nil, errors.WithCode(code.V3ErrInvalidContext, "new nginx config with a nil main context") + } + return &nginxConfig{ + mainContext: maincontext, + rwLocker: new(sync.RWMutex), + timestamp: timestamp, + }, nil +} + +func newNginxConfig(maincontext *local.Main) (NginxConfig, error) { + return newNginxConfigWithTimestamp(maincontext, time.Now()) +} diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go b/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go new file mode 100644 index 0000000..ebe1f9b --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go @@ -0,0 +1,307 @@ +package configuration + +import ( + "bytes" + v1 "github.com/ClessLi/bifrost/api/bifrost/v1" + "github.com/ClessLi/bifrost/internal/pkg/code" + utilsV2 "github.com/ClessLi/bifrost/pkg/resolv/V2/utils" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" + utilsV3 "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/utils" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" + "github.com/marmotedu/errors" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + "time" +) + +type NginxConfigManager interface { + Start() error + Stop(timeout time.Duration) error + NginxConfig() NginxConfig + ServerStatus() v1.State + ServerVersion() string +} + +type nginxConfigManager struct { + configuration NginxConfig + nginxHome string + nginxBinFilePath string + regularlyTaskCycleDelay time.Duration + regularlyTaskSignalChan chan int + backupOpts backupOption + wg *sync.WaitGroup + isRunning bool +} + +type backupOption struct { + backupCycleDays int + backupRetentionDays int + backupDir string + backupPrefix string + backupTimeZone *time.Location +} + +func (m *nginxConfigManager) Start() error { + if m.isRunning { + return errors.WithCode(code.ErrConfigManagerIsRunning, "nginx config manager is already running") + } + m.wg.Add(1) + go func() { + defer func() { + m.isRunning = false + }() + defer m.wg.Done() + err := m.regularlyRefreshAndBackup(m.regularlyTaskSignalChan) + if err != nil { + logV1.Errorf("regularly refresh and backup task start error. %+v", err) + } + }() + return nil +} + +func (m *nginxConfigManager) Stop(timeout time.Duration) error { + if !m.isRunning { + return errors.WithCode(code.ErrConfigManagerIsNotRunning, "nginx config manager is not running") + } + defer m.wg.Wait() + select { + case <-time.After(timeout): + return errors.Errorf("stop nginx config manager time out for more than %d seconds", int(timeout/time.Second)) + case m.regularlyTaskSignalChan <- 9: + m.isRunning = false + return nil + } +} + +func (m *nginxConfigManager) NginxConfig() NginxConfig { + return m.configuration +} + +func (m *nginxConfigManager) ServerStatus() (state v1.State) { + state = v1.UnknownState + svrPidFilePath := filepath.Join("logs", "nginx.pid") + pidCtx := m.configuration.Main().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective, `pid\s+.*`, true, true)).Target() + if pidCtx.Error() == nil { + pidCtxKV := strings.Split(pidCtx.Value(), " ") + if len(pidCtxKV) == 2 { + svrPidFilePath = pidCtxKV[1] + } + } + if !filepath.IsAbs(svrPidFilePath) { + nginxHomeAbsDir, err := filepath.Abs(m.nginxHome) + if err != nil { + return + } + svrPidFilePath = filepath.Join(nginxHomeAbsDir, svrPidFilePath) + } + + pid, err := utilsV2.GetPid(svrPidFilePath) + if err != nil { + return v1.Abnormal + } + _, err = os.FindProcess(pid) + if err != nil { + return v1.Abnormal + } + return v1.Normal +} + +func (m *nginxConfigManager) ServerVersion() (version string) { + version = "unknown" + cmd := m.serverBinCMD("-v") + stdoutPipe, err := cmd.StderrPipe() + if err != nil { + return + } + err = cmd.Run() + if err != nil { + return + } + buff := bytes.NewBuffer([]byte{}) + _, err = buff.ReadFrom(stdoutPipe) + if err != nil { + return + } + return strings.TrimRight(buff.String(), "\n") +} + +func (m *nginxConfigManager) backup() error { + // 开始备份 + // 归档日期初始化 + now := time.Now().In(m.backupOpts.backupTimeZone) + backupName := utilsV2.GetBackupFileName(m.backupOpts.backupPrefix, now) + archiveDir, err := filepath.Abs(m.NginxConfig().Main().(*local.Main).MainConfig().BaseDir()) + if err != nil { + return errors.Wrap(err, "failed to format archive directory") + } + archivePath := filepath.Join(archiveDir, backupName) + + // 确认是否为指定归档路径 + var isSpecialBackupDir bool + backupDir := m.backupOpts.backupDir + if backupDir != "" { + isSpecialBackupDir = true + backupDir, err = filepath.Abs(backupDir) + if err != nil { + return err + } + } else { + backupDir = archiveDir + } + + // 判断是否需要备份 + needBackup, err := utilsV2.CheckAndCleanBackups(m.backupOpts.backupPrefix, backupDir, m.backupOpts.backupRetentionDays, m.backupOpts.backupCycleDays, now) + if err != nil { + logV1.Warn("failed to check and clean backups, " + err.Error()) + return err + } + + if !needBackup { + return nil + } + + var configPaths []string + for _, config := range m.NginxConfig().Main().(*local.Main).Topology() { + configPaths = append(configPaths, config.FullPath()) + } + + // 压缩归档 + logV1.Info("start backup configs") + err = utilsV2.TarGZ(archivePath, configPaths) + if err != nil { + logV1.Warn("failed to backup configs, " + err.Error()) + return err + } + + // 根据需要调整归档路径 + if isSpecialBackupDir { + backupPath := filepath.Join(backupDir, backupName) + err = os.Rename(archivePath, backupPath) + } + logV1.Info("complete configs backup") + return err +} + +func (m *nginxConfigManager) refresh() error { + fsMain, fsFingerprinter, err := m.load() + if err != nil { + return err + } + + if fsFingerprinter.Diff(utilsV3.NewConfigFingerprinter(m.configuration.Dump())) { + + } + + if fsFingerprinter.NewerThan(m.configuration.UpdatedTimestamp()) { + err := m.configuration.(*nginxConfig).renewMainContext(fsMain) + if err != nil && !errors.IsCode(err, code.ErrSameConfigFingerprint) { + return err + } + } else { + // 清理本地磁盘上配置 + var fsConfigPaths []string + for _, config := range fsMain.Topology() { + fsConfigPaths = append(fsConfigPaths, config.FullPath()) + } + err = utilsV2.RemoveFiles(fsConfigPaths) + if err != nil { + return err + } + + // 回写内存配置到本地磁盘 + err = m.saveWithCheck() + if err != nil { // 保存异常,则回退 + var memConfigPaths []string + for _, config := range m.configuration.Main().(*local.Main).Topology() { + memConfigPaths = append(memConfigPaths, config.FullPath()) + } + + err = utilsV2.RemoveFiles(memConfigPaths) + if err != nil { + logV1.Errorf("remove failure update configs failed. %+v", err) + } + + // 回退为原本地磁盘上配置 + err = m.configuration.(*nginxConfig).renewMainContext(fsMain) + if err != nil && !errors.IsCode(err, code.ErrSameConfigFingerprint) { + logV1.Errorf("roll back nginx config failed. %+v", err) + return err + } + return m.saveWithCheck() + } + } + return nil +} + +func (m *nginxConfigManager) regularlyRefreshAndBackup(signalChan chan int) error { + // regularly backup is disabled, when c.backupCycleDays or c.backupRetentionDays is less equal zero. + backupIsDisabled := m.backupOpts.backupCycleDays <= 0 || m.backupOpts.backupRetentionDays <= 0 + + ticker := time.NewTicker(m.regularlyTaskCycleDelay) + for { + // 等待触发 + select { + case <-ticker.C: + case signal := <-signalChan: + if signal == 9 { + return nil + } + } + err := m.refresh() + if err != nil { + logV1.Errorf("refresh nginx config failed, cased by: %+v", err) + } + + if !backupIsDisabled { + err = m.backup() + if err != nil { + logV1.Errorf("backup nginx config failed, cased by: %+v", err) + } + } + } +} + +func (m *nginxConfigManager) serverBinCMD(arg ...string) *exec.Cmd { + arg = append(arg, "-c", m.configuration.Main().(*local.Main).MainConfig().FullPath()) + return exec.Command(m.nginxBinFilePath, arg...) +} + +func (m *nginxConfigManager) save() error { + dumps := m.configuration.Dump() + for file, dumpbuff := range dumps { + err := os.WriteFile(file, dumpbuff.Bytes(), 0600) + if err != nil { + return err + } + } + return nil +} + +func (m *nginxConfigManager) check() error { + cmd := m.serverBinCMD("-t") + cmd.Stderr = os.Stderr + + return cmd.Run() +} + +func (m *nginxConfigManager) saveWithCheck() error { + err := m.save() + if err != nil { + return err + } + return m.check() +} + +func (m *nginxConfigManager) load() (*local.Main, utilsV3.ConfigFingerprinter, error) { + localMain, timestamp, err := loadMainContextFromFS(m.configuration.Main().Value()) + if err != nil { + return nil, nil, err + } + fingerprinter := utilsV3.NewConfigFingerprinterWithTimestamp(dumpMainContext(localMain), timestamp) + return localMain, fingerprinter, nil +} diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go new file mode 100644 index 0000000..e6b717a --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go @@ -0,0 +1,151 @@ +package configuration + +import ( + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" + "regexp" + "strconv" + + "github.com/marmotedu/errors" + + v1 "github.com/ClessLi/bifrost/api/bifrost/v1" + "github.com/ClessLi/bifrost/internal/pkg/code" + utilsV2 "github.com/ClessLi/bifrost/pkg/resolv/V2/utils" +) + +var ( + RegPortValue = regexp.MustCompile(`^listen\s*(\d+)\s*\S*$`) + RegServerNameValue = regexp.MustCompile(`^server_name\s*(.+)$`) +) + +type HttpInfo struct { + ServerCount int + ServerPortCount map[string][]int + PortCount []int +} + +type StreamInfo struct { + PortCount []int +} + +type Statistician interface { + HttpInfo() HttpInfo + StreamInfo() StreamInfo + Statistics() *v1.Statistics +} + +type statistician struct { + configuration NginxConfig +} + +func (s *statistician) HttpInfo() HttpInfo { + serverCount, serverPortCount := HttpServers(s.configuration.Main()) + + return HttpInfo{ + ServerCount: serverCount, + ServerPortCount: serverPortCount, + PortCount: HttpPorts(s.configuration.Main()), + } +} + +func (s *statistician) StreamInfo() StreamInfo { + + return StreamInfo{ + PortCount: StreamServers(s.configuration.Main()), + } +} + +func (s *statistician) Statistics() *v1.Statistics { + httpInfo := s.HttpInfo() + streamInfo := s.StreamInfo() + + return &v1.Statistics{ + HttpSvrsNum: httpInfo.ServerCount, + HttpSvrs: httpInfo.ServerPortCount, + HttpPorts: httpInfo.PortCount, + StreamSvrsNum: len(streamInfo.PortCount), + StreamPorts: streamInfo.PortCount, + } +} + +func NewStatistician(c NginxConfig) Statistician { + return &statistician{configuration: c} +} + +func Port(ctx context.Context) int { + portDirective := ctx.QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective, "listen .*", true, true)).Target() + if portDirective.Error() != nil { + return -1 + } + port, err := strconv.Atoi(portDirective.(*local.Directive).Params) + if err != nil { + return -1 + } + + return port +} + +func Ports(contexts []context.Context) []int { + ports := make([]int, 0) + for _, ctx := range contexts { + port := Port(ctx) + if port > 0 { + ports = utilsV2.SortInsertUniqInt(ports, port) + } + } + + return ports +} + +func HttpPorts(ctx context.Context) []int { + httpServerPoses := ctx. + QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp, "", false, true)).Target(). + QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer, "", false, true)) + httpServers := make([]context.Context, 0) + for _, pos := range httpServerPoses { + httpServers = append(httpServers, pos.Target()) + } + + return Ports(httpServers) +} + +func HttpServers(ctx context.Context) (int, map[string][]int) { + serverCount := 0 + httpServerPoses := ctx. + QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp, "", false, true)).Target(). + QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer, "", false, true)) + + serverPortCount := make(map[string][]int) + for _, pos := range httpServerPoses { + serverCount++ + servernameDirective := pos.Target().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective, "^server_name .*", true, true)).Target() + if servernameDirective.Error() != nil { + if !errors.IsCode(servernameDirective.Error(), code.V3ErrContextNotFound) { + return 0, nil + } + + continue + } + servername := servernameDirective.(*local.Directive).Params + serverport := Port(pos.Target().Father()) + if serverport > 0 { + serverPortCount[servername] = append(serverPortCount[servername], serverport) + } + } + + return serverCount, serverPortCount +} + +func StreamServers(ctx context.Context) []int { + streamServerPoses := ctx. + QueryByKeyWords(context.NewKeyWords(context_type.TypeStream, "", false, true)).Target(). + QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer, "", false, true)) + + streamServers := make([]context.Context, 0) + for _, pos := range streamServerPoses { + streamServers = append(streamServers, pos.Target()) + } + + return Ports(streamServers) +} diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_test.go b/pkg/resolv/V3/nginx/configuration/nginx_config_test.go new file mode 100644 index 0000000..4901c32 --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_test.go @@ -0,0 +1,329 @@ +package configuration + +import ( + "bytes" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" + "reflect" + "sync" + "testing" +) + +func TestNewNginxConfigFromJsonBytes(t *testing.T) { + type args struct { + data []byte + } + tests := []struct { + name string + args args + want NginxConfig + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewNginxConfigFromJsonBytes(tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("NewNginxConfigFromJsonBytes() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewNginxConfigFromJsonBytes() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewNginxConfigFromPath(t *testing.T) { + type args struct { + filepath string + } + tests := []struct { + name string + args args + want NginxConfig + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewNginxConfigFromFS(tt.args.filepath) + if (err != nil) != tt.wantErr { + t.Errorf("NewNginxConfigFromFS() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewNginxConfigFromFS() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_dumpMainContext(t *testing.T) { + type args struct { + m *local.Main + } + tests := []struct { + name string + args args + want map[string]*bytes.Buffer + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := dumpMainContext(tt.args.m); !reflect.DeepEqual(got, tt.want) { + t.Errorf("dumpMainContext() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_newNginxConfig(t *testing.T) { + type args struct { + maincontext *local.Main + } + tests := []struct { + name string + args args + want NginxConfig + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := newNginxConfig(tt.args.maincontext) + if (err != nil) != tt.wantErr { + t.Errorf("newNginxConfig() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("newNginxConfig() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_nginxConfig_Dump(t *testing.T) { + type fields struct { + mainContext *local.Main + rwLocker *sync.RWMutex + } + tests := []struct { + name string + fields fields + want map[string]*bytes.Buffer + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &nginxConfig{ + mainContext: tt.fields.mainContext, + rwLocker: tt.fields.rwLocker, + } + if got := n.Dump(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Dump() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_nginxConfig_Json(t *testing.T) { + type fields struct { + mainContext *local.Main + rwLocker *sync.RWMutex + } + tests := []struct { + name string + fields fields + want []byte + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &nginxConfig{ + mainContext: tt.fields.mainContext, + rwLocker: tt.fields.rwLocker, + } + if got := n.Json(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Json() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_nginxConfig_Main(t *testing.T) { + type fields struct { + mainContext *local.Main + rwLocker *sync.RWMutex + } + tests := []struct { + name string + fields fields + want context.Context + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &nginxConfig{ + mainContext: tt.fields.mainContext, + rwLocker: tt.fields.rwLocker, + } + if got := n.Main(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Main() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_nginxConfig_TextLines(t *testing.T) { + type fields struct { + mainContext *local.Main + rwLocker *sync.RWMutex + } + tests := []struct { + name string + fields fields + want []string + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &nginxConfig{ + mainContext: tt.fields.mainContext, + rwLocker: tt.fields.rwLocker, + } + if got := n.TextLines(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("TextLines() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_nginxConfig_UpdateFromJsonBytes(t *testing.T) { + type fields struct { + mainContext *local.Main + rwLocker *sync.RWMutex + } + type args struct { + data []byte + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "normal test", + fields: fields{ + mainContext: local.NewContext(context_type.TypeMain, "C:\\test\\test.conf").(*local.Main), + rwLocker: new(sync.RWMutex), + }, + args: args{data: []byte( + `{ + "main-config": "C:\\test\\test.conf", + "configs": + { + "C:\\test\\test.conf": + [ + { + "http": + { + "params": + [ + { + "inline": true, "comments": "test comment" + }, + { + "server": + { + "params": + [ + { + "directive": "server_name", "params": "testserver" + }, + { + "location": {"value": "~ /test"} + }, + { + "include": + { + "value": "conf.d\\include*conf", + "params": ["conf.d\\include.location1.conf", "conf.d\\include.location2.conf"] + } + } + ] + } + } + ] + } + } + ], + "conf.d\\include.location1.conf": + [ + { + "location": {"value": "~ /test1"} + } + ], + "conf.d\\include.location2.conf": + [ + { + "location": {"value": "^~ /test2"} + } + ] + } +}`, + )}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &nginxConfig{ + mainContext: tt.fields.mainContext, + rwLocker: tt.fields.rwLocker, + } + if err := n.UpdateFromJsonBytes(tt.args.data); (err != nil) != tt.wantErr { + t.Errorf("UpdateFromJsonBytes() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_nginxConfig_renewMainContext(t *testing.T) { + type fields struct { + mainContext *local.Main + rwLocker *sync.RWMutex + } + type args struct { + m *local.Main + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &nginxConfig{ + mainContext: tt.fields.mainContext, + rwLocker: tt.fields.rwLocker, + } + if err := n.renewMainContext(tt.args.m); (err != nil) != tt.wantErr { + t.Errorf("renewMainContext() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/resolv/V3/nginx/configuration/utils/config_fingerprintor.go b/pkg/resolv/V3/nginx/configuration/utils/config_fingerprintor.go new file mode 100644 index 0000000..a3b1108 --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/utils/config_fingerprintor.go @@ -0,0 +1,79 @@ +package utils + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "sync" + "time" +) + +type ConfigFingerprinter interface { + Diff(fingerprinter ConfigFingerprinter) bool + NewerThan(timestamp time.Time) bool + Renew(fingerprinter ConfigFingerprinter) +} + +type configFingerprinter struct { + fingerprints map[string]string + timestamp time.Time + locker *sync.Mutex +} + +func (f *configFingerprinter) Diff(fingerprinter ConfigFingerprinter) bool { + if fp, is := fingerprinter.(*configFingerprinter); is && len(fp.fingerprints) == len(f.fingerprints) { + for filename, fingerprint := range fp.fingerprints { + if localFingerprint, ok := f.fingerprints[filename]; ok && + localFingerprint == fingerprint { + continue + } + return true + } + return false + } + return true +} + +func (f *configFingerprinter) NewerThan(timestamp time.Time) bool { + return f.timestamp.After(timestamp) +} + +func (f *configFingerprinter) Renew(fingerprinter ConfigFingerprinter) { + if !f.Diff(fingerprinter) { + return + } + f.locker.Lock() + defer f.locker.Unlock() + defer func() { + f.timestamp = time.Now() + }() + if fp, is := fingerprinter.(*configFingerprinter); is { + f.fingerprints = make(map[string]string) + + for name, fingerprint := range fp.fingerprints { + f.fingerprints[name] = fingerprint + } + } +} + +func (f *configFingerprinter) setFingerprint(filename string, data []byte) { + hash := sha256.New() + hash.Write(data) + f.fingerprints[filename] = hex.EncodeToString(hash.Sum(nil)) +} + +func NewConfigFingerprinter(buffMap map[string]*bytes.Buffer) ConfigFingerprinter { + return NewConfigFingerprinterWithTimestamp(buffMap, time.Now()) +} + +func NewConfigFingerprinterWithTimestamp(buffMap map[string]*bytes.Buffer, timestamp time.Time) ConfigFingerprinter { + cf := &configFingerprinter{ + fingerprints: make(map[string]string), + locker: new(sync.Mutex), + timestamp: timestamp, + } + for s, buff := range buffMap { + cf.setFingerprint(s, buff.Bytes()) + } + return cf +} diff --git a/pkg/resolv/V3/nginx/configuration/utils/files_funces_linux.go b/pkg/resolv/V3/nginx/configuration/utils/files_funces_linux.go new file mode 100644 index 0000000..e7a2e67 --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/utils/files_funces_linux.go @@ -0,0 +1,17 @@ +package utils + +import ( + "github.com/marmotedu/errors" + "syscall" + "time" +) + +func FileModifyTime(filepath string) (*time.Time, error) { + var fs syscall.Stat_t + err := syscall.Stat(filepath, &fs) + if err != nil && !errors.Is(err, syscall.EINTR) { + return nil, err + } + tt := time.Unix(fs.Mtim.Sec, fs.Mtim.Nsec) + return &tt, nil +} diff --git a/pkg/resolv/V3/nginx/configuration/utils/files_funcs_windows.go b/pkg/resolv/V3/nginx/configuration/utils/files_funcs_windows.go new file mode 100644 index 0000000..1426c9d --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/utils/files_funcs_windows.go @@ -0,0 +1,24 @@ +package utils + +import ( + "syscall" + "time" +) + +func FileModifyTime(filepath string) (*time.Time, error) { + filename16, err := syscall.UTF16PtrFromString(filepath) + if err != nil { + return nil, err + } + h, err := syscall.CreateFile(filename16, 0, 0, nil, syscall.OPEN_EXISTING, uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS), 0) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(h) + var i syscall.ByHandleFileInformation + if err := syscall.GetFileInformationByHandle(h, &i); err != nil { + return nil, err + } + tt := time.Unix(0, i.LastWriteTime.Nanoseconds()) + return &tt, nil +} diff --git a/pkg/resolv/V3/nginx/nginx.go b/pkg/resolv/V3/nginx/nginx.go new file mode 100644 index 0000000..8b54f26 --- /dev/null +++ b/pkg/resolv/V3/nginx/nginx.go @@ -0,0 +1,53 @@ +package nginx + +import ( + v1 "github.com/ClessLi/bifrost/api/bifrost/v1" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" + "github.com/marmotedu/errors" + "time" +) + +type ConfigsManager interface { + Start() error + Stop(timeout time.Duration) error + GetConfigs() map[string]configuration.NginxConfig + GetServerInfos() []*v1.WebServerInfo +} + +type configsManager struct { + managerMap map[string]configuration.NginxConfigManager +} + +func (m *configsManager) Start() error { + var errs []error + for _, manager := range m.managerMap { + errs = append(errs, manager.Start()) + } + return errors.NewAggregate(errs) +} + +func (m *configsManager) Stop(timeout time.Duration) error { + var errs []error + for _, manager := range m.managerMap { + errs = append(errs, manager.Stop(timeout)) + } + return errors.NewAggregate(errs) +} + +func (m *configsManager) GetConfigs() (configs map[string]configuration.NginxConfig) { + for svrname, manager := range m.managerMap { + configs[svrname] = manager.NginxConfig() + } + return +} + +func (m *configsManager) GetServerInfos() (infos []*v1.WebServerInfo) { + for svrname, manager := range m.managerMap { + infos = append(infos, &v1.WebServerInfo{ + Name: svrname, + Status: manager.ServerStatus(), + Version: manager.ServerVersion(), + }) + } + return +} diff --git a/test/grpc_client/bifrost/example_server.go b/test/grpc_client/bifrost/example_server.go index b8513bb..4698077 100644 --- a/test/grpc_client/bifrost/example_server.go +++ b/test/grpc_client/bifrost/example_server.go @@ -36,14 +36,14 @@ func exampleServerRun() error { opts.WebServerConfigsOptions.WebServerConfigs = append( opts.WebServerConfigsOptions.WebServerConfigs, &options.WebServerConfigOptions{ - ServerName: "example test", - ServerType: "nginx", - ConfigPath: "../../nginx/conf/nginx.conf", - VerifyExecPath: "../../nginx/sbin/nginx.sh", - LogsDirPath: "../../nginx/logs", - BackupDir: "", - BackupCycle: 1, - BackupSaveTime: 1, + ServerName: "example test", + ServerType: "nginx", + ConfigPath: "../../nginx/conf/nginx.conf", + VerifyExecPath: "../../nginx/sbin/nginx.sh", + LogsDirPath: "../../nginx/logs", + BackupDir: "", + BackupCycle: 1, + BackupsRetentionDuration: 1, }, ) diff --git a/test/resolve/nginx/V2/example_config_test.go b/test/resolve/nginx/V2/example_config_test.go new file mode 100644 index 0000000..137d5ec --- /dev/null +++ b/test/resolve/nginx/V2/example_config_test.go @@ -0,0 +1,143 @@ +package V2 + +import ( + "fmt" + "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration" + "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration/parser" + "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/parser_type" + "testing" +) + +func TestExampleConfig(t *testing.T) { + // config可以来自bifrost客户端请求获取的json数据进行解析 + c, err := configuration.NewConfigurationFromPath("test_nginx.conf") + if err != nil { + t.Fatal(err) + } + + // http context可以来自config检索结果 + httpCTX := parser.NewContext("", parser_type.TypeHttp, c.Self().GetIndention()) // 使用config对象的indention作为原始缩进 + + // 插入http context至config + err = c.Self().(parser.Context).Insert(httpCTX, 0) + if err != nil { + t.Fatal(err) + } + + // 创建server context + srvCTX := parser.NewContext("", parser_type.TypeServer, httpCTX.GetIndention().NextIndention()) // 使用http context的下级缩进 + // 插入server context至http context + err = httpCTX.Insert(srvCTX, 0) + if err != nil { + t.Fatal(err) + } + + // 插入server context的server_name和listen字段 + err = srvCTX.Insert(parser.NewKey("server_name", "example.com", srvCTX.GetIndention().NextIndention()), 0) // 使用server context的下级缩进,插入为server context首个子parser + if err != nil { + t.Fatal(err) + } + err = srvCTX.Insert(parser.NewComment("Server Context首个字段", true, srvCTX.GetIndention().NextIndention()), srvCTX.Len()) + if err != nil { + t.Fatal(err) + } + err = srvCTX.Insert(parser.NewKey("listen", "80", srvCTX.GetIndention().NextIndention()), srvCTX.Len()) // 使用server context的下级缩进,插入到server context末尾 + if err != nil { + t.Fatal(err) + } + err = srvCTX.Insert(parser.NewComment("Server Context第二个字段", true, srvCTX.GetIndention().NextIndention()), srvCTX.Len()) + if err != nil { + t.Fatal(err) + } + err = srvCTX.Insert(parser.NewComment("Location Context", false, srvCTX.GetIndention().NextIndention()), srvCTX.Len()) + if err != nil { + t.Fatal(err) + } + + // 创建location context + locationCTX := parser.NewContext("/", parser_type.TypeLocation, srvCTX.GetIndention().NextIndention()) // 使用server context的下级缩进 + // 插入到server context末尾 + err = srvCTX.Insert(locationCTX, srvCTX.Len()) + if err != nil { + t.Fatal(err) + } + + err = locationCTX.Insert(parser.NewComment("Location Context自定义字段", false, locationCTX.GetIndention().NextIndention()), 0) + if err != nil { + t.Fatal(err) + } + // 插入location context的指定字段 + err = locationCTX.Insert(parser.NewKey("root", "index.html", locationCTX.GetIndention().NextIndention()), locationCTX.Len()) // 使用location context的下级缩进,插入到location context末尾 + if err != nil { + t.Fatal(err) + } + + fmt.Println(string(c.View())) + + // 以Configuration接口插入配置 + // 创建server2 context + srv2CTX := parser.NewContext("", parser_type.TypeServer, c.Self().GetIndention().NextIndention()) // 使用config对象的第二级缩进 + // 插入server2 context的server_name和listen字段 + err = srv2CTX.Insert(parser.NewKey("server_name", "baidu.com", srv2CTX.GetIndention().NextIndention()), 0) // 使用server2 context的下级缩进,插入为server2 context首个子parser + if err != nil { + t.Fatal(err) + } + err = srv2CTX.Insert(parser.NewKey("listen", "80", srv2CTX.GetIndention().NextIndention()), srv2CTX.Len()) // 使用server2 context的下级缩进,插入到server2 context末尾 + if err != nil { + t.Fatal(err) + } + + // 创建location2 context + location2CTX := parser.NewContext("/", parser_type.TypeLocation, srv2CTX.GetIndention().NextIndention()) // 使用server context的下级缩进 + // 插入到server2 context末尾 + err = srv2CTX.Insert(location2CTX, srv2CTX.Len()) + if err != nil { + t.Fatal(err) + } + + // 插入location context的指定字段 + err = location2CTX.Insert(parser.NewKey("aaa", "bbbb", location2CTX.GetIndention().NextIndention()), location2CTX.Len()) // 使用location context的下级缩进,插入到location context末尾 + if err != nil { + t.Fatal(err) + } + + // Configuration.InsertByKeyword,目前只支持插入到检索到的Queryer对象前。 + // Configuration接口和Queryer接口是为了方便同事的快速检索和快速操作各配置对象而设置的,功能会存在局限性,该接口更适合检索和操作config整体数据,及简单的增、删、改 + // 建议使用Configuration.Self方法,将Configuration转换为Parser接口对象后,再按Parser/Context接口对象来进行更精准的操作 + err = c.InsertByKeyword(srv2CTX, "server") + if err != nil { + t.Fatal(err) + } + + t.Log("通过Configuration接口插入后") + fmt.Println("\n" + string(c.View())) + + srvnameKW, err := parser.NewKeyWords(parser_type.TypeKey, false, "server_name baidu.com") + if err != nil { + t.Fatal(err) + } + lisKW, err := parser.NewKeyWords(parser_type.TypeKey, false, "listen 80") + if err != nil { + t.Fatal(err) + } + s, _ := c.Self().(parser.Context).Query(srvnameKW) + if s != nil { + ctx, i := s.Query(lisKW) + err = ctx.Modify(parser.NewKey("listen", "443", ctx.GetIndention().NextIndention()), i) + if err != nil { + t.Fatal(err) + } + err = ctx.Insert(parser.NewKey("ssl", "on", ctx.GetIndention().NextIndention()), i+1) + if err != nil { + t.Fatal(err) + } + err = ctx.Insert(parser.NewComment("修改http为https", false, ctx.GetIndention().NextIndention()), i) + if err != nil { + t.Fatal(err) + } + } + + fmt.Println("\n" + string(c.View())) + t.Log("complete!") + +} diff --git a/test/resolve/nginx/V2/test_nginx.conf b/test/resolve/nginx/V2/test_nginx.conf new file mode 100644 index 0000000..e69de29 From df0fa1d71a298cbc72b9919432a62041ef0a7c49 Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Tue, 26 Mar 2024 17:35:10 +0800 Subject: [PATCH 2/8] test(resolv): preliminary completion of interactive debugging between the `bifrost` server and client, as well as related known bug fixes. --- internal/bifrost/store/v1/nginx/nginx.go | 5 ++-- pkg/client/bifrost/v1/transport/transport.go | 10 ++++---- pkg/graph/graph.go | 5 ++-- .../configuration/configuration_manager.go | 18 +++++++-------- pkg/resolv/V2/nginx/nginx.go | 6 ++--- .../nginx/configuration/context/key_words.go | 23 +++++++++++++++---- .../context/local/basic_context_test.go | 4 ++-- .../configuration/context/local/comment.go | 2 +- .../configuration/context/local/config.go | 9 +++++++- .../configuration/context/local/consts.go | 4 ++-- .../context/local/include_test.go | 4 ++-- .../configuration/context/local/loader.go | 22 +++++++++--------- .../context/local/loader_test.go | 3 ++- .../nginx/configuration/context/local/vars.go | 5 ++-- .../V3/nginx/configuration/nginx_config.go | 2 ++ .../configuration/nginx_config_manager.go | 7 +++--- .../nginx_config_statistician.go | 16 ++++++------- pkg/resolv/V3/nginx/nginx.go | 2 ++ test/config_test/simple_nginx.conf | 2 +- test/grpc_client/bifrost/client_test.go | 20 ++++++++++------ test/grpc_client/bifrost/example_server.go | 13 +++++++---- 21 files changed, 110 insertions(+), 72 deletions(-) diff --git a/internal/bifrost/store/v1/nginx/nginx.go b/internal/bifrost/store/v1/nginx/nginx.go index 08cc5fb..a084c6f 100644 --- a/internal/bifrost/store/v1/nginx/nginx.go +++ b/internal/bifrost/store/v1/nginx/nginx.go @@ -79,7 +79,8 @@ func GetNginxStoreFactory( } svrLogsDirs[itemOpts.ServerName] = itemOpts.LogsDirPath } - cmCompletedConf, err := cmConf.Complete() + var cmCompletedConf *nginx.CompletedConfig + cmCompletedConf, err = cmConf.Complete() if err != nil { return } @@ -130,7 +131,7 @@ func GetNginxStoreFactory( if nginxStoreFactory == nil || err != nil { return nil, errors.Errorf( //nolint:govet - "failed to get nginx store factory, nginx store factory: %+v, err: %w", + "failed to get nginx store factory, nginx store factory: %+v, err: %+v", nginxStoreFactory, err, ) diff --git a/pkg/client/bifrost/v1/transport/transport.go b/pkg/client/bifrost/v1/transport/transport.go index d56e5a7..02b3a07 100644 --- a/pkg/client/bifrost/v1/transport/transport.go +++ b/pkg/client/bifrost/v1/transport/transport.go @@ -3,12 +3,12 @@ package transport import ( "sync" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/go-kit/kit/endpoint" "google.golang.org/grpc" "github.com/ClessLi/bifrost/pkg/client/bifrost/v1/transport/decoder" "github.com/ClessLi/bifrost/pkg/client/bifrost/v1/transport/encoder" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) type Client interface { @@ -60,7 +60,7 @@ func (t *transport) WebServerConfig() WebServerConfigTransport { } }) if t.singletonWSCTXP == nil { - log.Fatal("web server config transport client is nil") + logV1.Fatal("web server config transport client is nil") return nil } @@ -75,7 +75,7 @@ func (t *transport) WebServerStatistics() WebServerStatisticsTransport { } }) if t.singletonWSSTXP == nil { - log.Fatal("web server statistics transport client is nil") + logV1.Fatal("web server statistics transport client is nil") return nil } @@ -90,7 +90,7 @@ func (t *transport) WebServerStatus() WebServerStatusTransport { } }) if t.singletonWSStatusTXP == nil { - log.Fatal("web server status transport client is nil") + logV1.Fatal("web server status transport client is nil") return nil } @@ -105,7 +105,7 @@ func (t *transport) WebServerLogWatcher() WebServerLogWatcherTransport { } }) if t.singletonWSLWTXP == nil { - log.Fatal("web server log watcher transport client is nil") + logV1.Fatal("web server log watcher transport client is nil") return nil } diff --git a/pkg/graph/graph.go b/pkg/graph/graph.go index 8dc9a11..47b31eb 100644 --- a/pkg/graph/graph.go +++ b/pkg/graph/graph.go @@ -1,7 +1,8 @@ package graph import ( - log "github.com/ClessLi/bifrost/pkg/log/v1" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" + "github.com/ClessLi/bifrost/pkg/queue" ) @@ -114,7 +115,7 @@ func (g *Graph) topologicalSortByKahn() error { } else { err := topoGraph.AddEdge(currentVertex.id, id) if err != nil { - log.Warnf("graph add edge error: %w", err) + logV1.Warnf("graph add edge error: %w", err) return nil //nolint:nilerr } diff --git a/pkg/resolv/V2/nginx/configuration/configuration_manager.go b/pkg/resolv/V2/nginx/configuration/configuration_manager.go index e043926..411c18a 100644 --- a/pkg/resolv/V2/nginx/configuration/configuration_manager.go +++ b/pkg/resolv/V2/nginx/configuration/configuration_manager.go @@ -11,12 +11,12 @@ import ( "sync" "time" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/marmotedu/errors" "github.com/wxnacy/wgo/arrays" v1 "github.com/ClessLi/bifrost/api/bifrost/v1" "github.com/ClessLi/bifrost/internal/pkg/code" - log "github.com/ClessLi/bifrost/pkg/log/v1" "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration/parser" "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/loader" "github.com/ClessLi/bifrost/pkg/resolv/V2/utils" @@ -181,7 +181,7 @@ func (c *configManager) regularlyBackup(duration time.Duration, signalChan chan // 判断是否需要备份 needBackup, err := utils.CheckAndCleanBackups(backupPrefix, c.backupDir, c.backupSaveTime, c.backupCycle, now) if err != nil { - log.Warn("failed to check and clean backups, " + err.Error()) + logV1.Warn("failed to check and clean backups, " + err.Error()) backupErr = err continue @@ -193,11 +193,11 @@ func (c *configManager) regularlyBackup(duration time.Duration, signalChan chan // 压缩归档 c.rwLocker.RLock() - log.Info("start backup configs") + logV1.Info("start backup configs") err = utils.TarGZ(archivePath, c.configPaths) c.rwLocker.RUnlock() if err != nil { - log.Warn("failed to backup configs, " + err.Error()) + logV1.Warn("failed to backup configs, " + err.Error()) backupErr = err continue @@ -208,7 +208,7 @@ func (c *configManager) regularlyBackup(duration time.Duration, signalChan chan backupPath := filepath.Join(c.backupDir, backupName) backupErr = os.Rename(archivePath, backupPath) } - log.Info("complete configs backup") + logV1.Info("complete configs backup") } return backupErr @@ -348,7 +348,7 @@ func (c configManager) save() ([]string, error) { for s, bytes := range dumps { // 判断是否为单元测试 if len(os.Args) > 3 && os.Args[1] == "-test.v" && os.Args[2] == "-test.run" { - log.Infof("%s: %s", s, string(bytes)) + logV1.Infof("%s: %s", s, string(bytes)) continue } @@ -398,19 +398,19 @@ func (c *configManager) Start() error { go func() { err := c.regularlyBackup(time.Minute*5, c.backupSignalChan) if err != nil { - log.Errorf("regularly backup error. %+v", err) + logV1.Errorf("regularly backup error. %+v", err) } }() go func() { err := c.regularlyReload(time.Second*30, c.reloadSignalChan) if err != nil { - log.Errorf("regularly reload error. %+v", err) + logV1.Errorf("regularly reload error. %+v", err) } }() go func() { err := c.regularlySave(time.Second*10, c.saveSignalChan) if err != nil { - log.Errorf("regularly save error. %+v", err) + logV1.Errorf("regularly save error. %+v", err) } }() c.isRunning = true diff --git a/pkg/resolv/V2/nginx/nginx.go b/pkg/resolv/V2/nginx/nginx.go index 1ebdc6e..8972a38 100644 --- a/pkg/resolv/V2/nginx/nginx.go +++ b/pkg/resolv/V2/nginx/nginx.go @@ -3,10 +3,10 @@ package nginx import ( "sync" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/marmotedu/errors" v1 "github.com/ClessLi/bifrost/api/bifrost/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration" "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/loader" ) @@ -30,7 +30,7 @@ func newConfigManager(options ConfigManagerOptions) (configuration.ConfigManager if err != nil { return nil, err } - log.Debugf("init nginx config(Size: %d): \n\n%s", len(conf.View()), conf.View()) + logV1.Debugf("init nginx config(Size: %d): \n\n%s", len(conf.View()), conf.View()) return configuration.NewNginxConfigurationManager( loader.NewLoader(), @@ -61,7 +61,7 @@ func (c *configsManager) Start() error { if err != nil { for _, servername := range isStarted { if err = c.cms[servername].Stop(); err != nil { - log.Warnf("failed to stop %s nginx config manager, err: %w", servername, err) + logV1.Warnf("failed to stop %s nginx config manager, err: %w", servername, err) } } } diff --git a/pkg/resolv/V3/nginx/configuration/context/key_words.go b/pkg/resolv/V3/nginx/configuration/context/key_words.go index f084945..02635bb 100644 --- a/pkg/resolv/V3/nginx/configuration/context/key_words.go +++ b/pkg/resolv/V3/nginx/configuration/context/key_words.go @@ -10,6 +10,8 @@ type KeyWords interface { Match(ctx Context) bool Cascaded() bool SetCascaded(cascaded bool) KeyWords + SetStringMatchingValue(value string) KeyWords + SetRegexMatchingValue(value string) KeyWords } type keywords struct { @@ -47,11 +49,22 @@ func (k *keywords) SetCascaded(cascaded bool) KeyWords { return k } -func NewKeyWords(ctxtype context_type.ContextType, matching string, isregex, iscascaded bool) KeyWords { +func (k *keywords) SetStringMatchingValue(value string) KeyWords { + k.isRegex = false + k.matchingValue = value + return k +} + +func (k *keywords) SetRegexMatchingValue(value string) KeyWords { + k.isRegex = true + k.matchingValue = value + return k +} + +func NewKeyWords(ctxtype context_type.ContextType) KeyWords { return &keywords{ - matchingType: ctxtype, - matchingValue: matching, - isRegex: isregex, - isCascaded: iscascaded, + matchingType: ctxtype, + isRegex: false, + isCascaded: true, } } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go b/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go index 3d70da2..37d8527 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go @@ -1019,7 +1019,7 @@ func TestBasicContext_QueryAllByKeyWords(t *testing.T) { headStringFunc: testContext.headStringFunc, tailStringFunc: testContext.tailStringFunc, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation, "test", true, true)}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue("test")}, want: []context.Pos{ context.SetPos(testFather, 0), context.SetPos(testFather, 2), @@ -1079,7 +1079,7 @@ func TestBasicContext_QueryByKeyWords(t *testing.T) { headStringFunc: testContext.headStringFunc, tailStringFunc: testContext.tailStringFunc, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation, "test", true, true)}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue("test")}, want: context.SetPos(testFather, 0), }, } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/comment.go b/pkg/resolv/V3/nginx/configuration/context/local/comment.go index 6dcc0e0..f42bf49 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/comment.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/comment.go @@ -105,7 +105,7 @@ func registerCommentParseFunc() error { matchIndexes := RegCommentHead.FindIndex(data[*idx:]) cmt := NewComment( string(subMatch[2]), - !strings.Contains(string(subMatch[1]), "\n") && *idx != 0, + !RegLineBreak.Match(subMatch[1]) && *idx != 0, ) *idx += matchIndexes[len(matchIndexes)-1] - 1 diff --git a/pkg/resolv/V3/nginx/configuration/context/local/config.go b/pkg/resolv/V3/nginx/configuration/context/local/config.go index 2e2551f..f849141 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/config.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/config.go @@ -61,12 +61,19 @@ func (c *Config) SetFather(ctx context.Context) error { func (c *Config) ConfigLines(isDumping bool) ([]string, error) { lines := make([]string, 0) - for _, child := range c.Children { + for idx, child := range c.Children { clines, err := child.ConfigLines(isDumping) if err != nil { return nil, err } if clines != nil { + if child.Type() == context_type.TypeInlineComment && len(lines) > 0 && + c.Child(idx-1).Type() != context_type.TypeComment && + c.Child(idx-1).Type() != context_type.TypeInlineComment { + lines[len(lines)-1] += INDENT + clines[0] + continue + } + for _, cline := range clines { lines = append(lines, cline) } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/consts.go b/pkg/resolv/V3/nginx/configuration/context/local/consts.go index 107f454..8a4b673 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/consts.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/consts.go @@ -4,8 +4,8 @@ const ( DoubleQuotes = `\s*"[^"]*"` SingleQuotes = `\s*'[^']*'` Normal = `\s*[^;\s#]+` - Abnormal = `^[\n\t\f ]*;.*` - LineBreak = `\n` + Abnormal = `^[\n\r\t\f ]*;.*` + LineBreak = `[\n\r]` S1 = DoubleQuotes + `|` + SingleQuotes + `|` + Normal S = `^\s*(` + S1 + `)\s+((?:` + S1 + `)+)\s*;` ) diff --git a/pkg/resolv/V3/nginx/configuration/context/local/include_test.go b/pkg/resolv/V3/nginx/configuration/context/local/include_test.go index 10288c5..dfa7f41 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/include_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/include_test.go @@ -812,7 +812,7 @@ func TestInclude_QueryAllByKeyWords(t *testing.T) { Configs: testInclude.Configs, fatherContext: testInclude.fatherContext, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation, "test", true, true)}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue("test")}, want: []context.Pos{ context.SetPos(aFather, 0), context.SetPos(bFather, 1), @@ -887,7 +887,7 @@ func TestInclude_QueryByKeyWords(t *testing.T) { Configs: testInclude.Configs, fatherContext: testInclude.fatherContext, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation, "test", false, true)}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetStringMatchingValue("test")}, want: context.SetPos(aFather, 0), }, } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/loader.go b/pkg/resolv/V3/nginx/configuration/context/local/loader.go index 9a20296..478a4a9 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/loader.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/loader.go @@ -70,14 +70,14 @@ func (f *fileLoader) Load() (*Main, error) { func (f *fileLoader) load(config *Config) error { data, err := os.ReadFile(configHash(config)) if err != nil { - return err + return errors.Wrap(err, "read file failed") } idx := 0 stackIdx := len(f.contextStack.contexts) err = f.contextStack.push(config) if err != nil { - return err + return errors.Wrap(err, "push config context to stack failed") } for { @@ -89,13 +89,13 @@ func (f *fileLoader) load(config *Config) error { err = parseErrLine(data, &idx, config) if err != nil { - return err + return errors.Wrap(err, "has parsed an error line") } if parseBraceEnd(data, &idx) { _, err = f.contextStack.pop() if err != nil { - return err + return errors.Wrap(err, "quit context from stack failed") } continue } @@ -105,27 +105,27 @@ func (f *fileLoader) load(config *Config) error { if ctx != context.NullContext() { father, err := f.contextStack.current() if err != nil { - return err + return errors.Wrap(err, "get father context failed") } err = father.Insert(ctx, father.Len()).Error() if err != nil { - return err + return errors.Wrap(err, "insert context failed") } err = f.contextStack.push(ctx) if err != nil { - return err + return errors.Wrap(err, "push context to stack failed") } isParsed = true // load include configs if ctx.Type() == context_type.TypeInclude { err = f.loadInclude(ctx.(*Include)) if err != nil { - return err + return errors.Wrap(err, "load include configs failed") } _, err = f.contextStack.pop() if err != nil { - return err + return errors.Wrap(err, "quit context from stack failed") } } break @@ -140,11 +140,11 @@ func (f *fileLoader) load(config *Config) error { if ctx != context.NullContext() { father, err := f.contextStack.current() if err != nil { - return err + return errors.Wrap(err, "get father context failed") } err = father.Insert(ctx, father.Len()).Error() if err != nil { - return err + return errors.Wrap(err, "insert context failed") } isParsed = true break diff --git a/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go b/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go index 759e2af..c13cd5f 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go @@ -217,10 +217,11 @@ func Test_fileLoader_Load(t *testing.T) { simpleMain. Insert(NewComment("user nobody;", false), 0). Insert(NewDirective("worker_processes", "1"), 1). + Insert(NewComment("inline comments", true), 2). Insert( NewContext(context_type.TypeEvents, ""). Insert(NewDirective("worker_connections", "1024"), 0), - 2, + 3, ) type fields struct { mainConfigAbsPath string diff --git a/pkg/resolv/V3/nginx/configuration/context/local/vars.go b/pkg/resolv/V3/nginx/configuration/context/local/vars.go index 46e9df6..dc7deec 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/vars.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/vars.go @@ -9,7 +9,7 @@ import ( var ( // regexps - RegCommentHead = regexp.MustCompile(`^(\s*)#+[ \r\t\f]*(.*?)\n`) + RegCommentHead = regexp.MustCompile(`^(\s*)#+[ \t\f]*([^\r\n]*?)` + LineBreak + `+`) RegDirectiveWithValue = regexp.MustCompile(S) RegDirectiveWithoutValue = regexp.MustCompile(`^\s*(` + Normal + `)\s*;`) RegEventsHead = regexp.MustCompile(`^\s*events\s*{`) @@ -23,9 +23,10 @@ var ( RegStreamHead = regexp.MustCompile(`^\s*stream\s*{`) RegTypesHead = regexp.MustCompile(`^\s*types\s*{`) RegUpstreamHead = regexp.MustCompile(`^\s*upstream\s*([^;]*?)\s*{`) - RegBlankLine = regexp.MustCompile(`^\n\s*` + LineBreak + `$`) + RegBlankLine = regexp.MustCompile(`^` + LineBreak + `\s*` + LineBreak + `$`) RegBraceEnd = regexp.MustCompile(`^\s*}`) RegErrorHeed = regexp.MustCompile(Abnormal) + RegLineBreak = regexp.MustCompile(LineBreak) // json unmarshal regexps JsonUnmarshalRegCommentHead = regexp.MustCompile(`^\s*{[^{]*"comments"\s*:\s*"`) diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config.go b/pkg/resolv/V3/nginx/configuration/nginx_config.go index bb92219..4a6dc85 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config.go @@ -7,6 +7,7 @@ import ( "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" utilsV3 "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/utils" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" "github.com/marmotedu/errors" "strings" "sync" @@ -96,6 +97,7 @@ func NewNginxConfigFromJsonBytes(data []byte) (NginxConfig, error) { func NewNginxConfigFromFS(filepath string) (NginxConfig, error) { m, t, err := loadMainContextFromFS(filepath) if err != nil { + logV1.Warnf("load nginx config failed: %w", err) return nil, err } return newNginxConfigWithTimestamp(m, t) diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go b/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go index ebe1f9b..f84107f 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go @@ -85,7 +85,7 @@ func (m *nginxConfigManager) NginxConfig() NginxConfig { func (m *nginxConfigManager) ServerStatus() (state v1.State) { state = v1.UnknownState svrPidFilePath := filepath.Join("logs", "nginx.pid") - pidCtx := m.configuration.Main().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective, `pid\s+.*`, true, true)).Target() + pidCtx := m.configuration.Main().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue(`pid\s+.*`)).Target() if pidCtx.Error() == nil { pidCtxKV := strings.Split(pidCtx.Value(), " ") if len(pidCtxKV) == 2 { @@ -193,8 +193,9 @@ func (m *nginxConfigManager) refresh() error { return err } - if fsFingerprinter.Diff(utilsV3.NewConfigFingerprinter(m.configuration.Dump())) { - + if !fsFingerprinter.Diff(utilsV3.NewConfigFingerprinter(m.configuration.Dump())) { + // 指纹一致不做刷新 + return nil } if fsFingerprinter.NewerThan(m.configuration.UpdatedTimestamp()) { diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go index e6b717a..ff686a4 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go @@ -74,7 +74,7 @@ func NewStatistician(c NginxConfig) Statistician { } func Port(ctx context.Context) int { - portDirective := ctx.QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective, "listen .*", true, true)).Target() + portDirective := ctx.QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("listen .*")).Target() if portDirective.Error() != nil { return -1 } @@ -100,8 +100,8 @@ func Ports(contexts []context.Context) []int { func HttpPorts(ctx context.Context) []int { httpServerPoses := ctx. - QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp, "", false, true)).Target(). - QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer, "", false, true)) + QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp)).Target(). + QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer)) httpServers := make([]context.Context, 0) for _, pos := range httpServerPoses { httpServers = append(httpServers, pos.Target()) @@ -113,13 +113,13 @@ func HttpPorts(ctx context.Context) []int { func HttpServers(ctx context.Context) (int, map[string][]int) { serverCount := 0 httpServerPoses := ctx. - QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp, "", false, true)).Target(). - QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer, "", false, true)) + QueryByKeyWords(context.NewKeyWords(context_type.TypeHttp)).Target(). + QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer)) serverPortCount := make(map[string][]int) for _, pos := range httpServerPoses { serverCount++ - servernameDirective := pos.Target().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective, "^server_name .*", true, true)).Target() + servernameDirective := pos.Target().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("^server_name .*")).Target() if servernameDirective.Error() != nil { if !errors.IsCode(servernameDirective.Error(), code.V3ErrContextNotFound) { return 0, nil @@ -139,8 +139,8 @@ func HttpServers(ctx context.Context) (int, map[string][]int) { func StreamServers(ctx context.Context) []int { streamServerPoses := ctx. - QueryByKeyWords(context.NewKeyWords(context_type.TypeStream, "", false, true)).Target(). - QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer, "", false, true)) + QueryByKeyWords(context.NewKeyWords(context_type.TypeStream)).Target(). + QueryAllByKeyWords(context.NewKeyWords(context_type.TypeServer)) streamServers := make([]context.Context, 0) for _, pos := range streamServerPoses { diff --git a/pkg/resolv/V3/nginx/nginx.go b/pkg/resolv/V3/nginx/nginx.go index 8b54f26..a5fddc6 100644 --- a/pkg/resolv/V3/nginx/nginx.go +++ b/pkg/resolv/V3/nginx/nginx.go @@ -35,6 +35,7 @@ func (m *configsManager) Stop(timeout time.Duration) error { } func (m *configsManager) GetConfigs() (configs map[string]configuration.NginxConfig) { + configs = make(map[string]configuration.NginxConfig) for svrname, manager := range m.managerMap { configs[svrname] = manager.NginxConfig() } @@ -42,6 +43,7 @@ func (m *configsManager) GetConfigs() (configs map[string]configuration.NginxCon } func (m *configsManager) GetServerInfos() (infos []*v1.WebServerInfo) { + infos = make([]*v1.WebServerInfo, 0) for svrname, manager := range m.managerMap { infos = append(infos, &v1.WebServerInfo{ Name: svrname, diff --git a/test/config_test/simple_nginx.conf b/test/config_test/simple_nginx.conf index 3e64a09..65c253f 100644 --- a/test/config_test/simple_nginx.conf +++ b/test/config_test/simple_nginx.conf @@ -1,5 +1,5 @@ # user nobody; -worker_processes 1; +worker_processes 1; # inline comments events { worker_connections 1024; } diff --git a/test/grpc_client/bifrost/client_test.go b/test/grpc_client/bifrost/client_test.go index 05c60b9..e94fbdc 100644 --- a/test/grpc_client/bifrost/client_test.go +++ b/test/grpc_client/bifrost/client_test.go @@ -7,13 +7,12 @@ import ( "testing" "time" - v1 "github.com/ClessLi/bifrost/api/bifrost/v1" - healthzclient_v1 "github.com/ClessLi/bifrost/pkg/client/grpc_health_v1" - "github.com/ClessLi/bifrost/pkg/resolv/V2/nginx/configuration" - "google.golang.org/grpc" + v1 "github.com/ClessLi/bifrost/api/bifrost/v1" bifrost_cliv1 "github.com/ClessLi/bifrost/pkg/client/bifrost/v1" + healthzclient_v1 "github.com/ClessLi/bifrost/pkg/client/grpc_health_v1" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration" ) func TestRun(t *testing.T) { @@ -106,11 +105,18 @@ func TestBifrostClient(t *testing.T) { if err != nil { t.Fatalf(err.Error()) } - conf, err := configuration.NewConfigurationFromJsonBytes(jsondata) + conf, err := configuration.NewNginxConfigFromJsonBytes(jsondata) if err != nil { t.Fatalf(err.Error()) } - t.Logf("get config len: %d", len(conf.View())) + lines, err := conf.Main().ConfigLines(false) + if err != nil { + t.Fatalf(err.Error()) + } + t.Logf("get config lines len: %d", len(lines)) + for _, line := range lines { + t.Log(line) + } //fmt.Printf("config %s:\n\n%s", servername, conf.View()) t.Logf("before jsondata len: %d, after jasondata len: %d", len(jsondata), len(conf.Json())) @@ -118,7 +124,7 @@ func TestBifrostClient(t *testing.T) { if err != nil { t.Fatalf(err.Error()) } - t.Logf("statistics %s:\n\n%v", servername, statistics) + t.Logf("statistics %s:\n\n%+v", servername, statistics) logC, lwCancel, err := client.WebServerLogWatcher().Watch(&v1.WebServerLogWatchRequest{ ServerName: &v1.ServerName{Name: servername}, diff --git a/test/grpc_client/bifrost/example_server.go b/test/grpc_client/bifrost/example_server.go index 4698077..c2be9c0 100644 --- a/test/grpc_client/bifrost/example_server.go +++ b/test/grpc_client/bifrost/example_server.go @@ -2,17 +2,17 @@ package bifrost import ( "fmt" + "path/filepath" "time" "github.com/ClessLi/bifrost/internal/bifrost" "github.com/ClessLi/bifrost/internal/bifrost/config" bifrost_opts "github.com/ClessLi/bifrost/internal/bifrost/options" "github.com/ClessLi/bifrost/internal/pkg/options" - log "github.com/ClessLi/bifrost/pkg/log/v1" ) const ( - localhostIP = "192.168.220.1" + localhostIP = "192.168.121.1" testPort = 12321 ) @@ -32,13 +32,17 @@ func exampleServerRun() error { opts.MonitorOptions.CycleTime = time.Second * 5 opts.MonitorOptions.FrequencyPerCycle = 5 + absConfigPath, err := filepath.Abs("../../nginx/conf/nginx.conf") + if err != nil { + return err + } opts.WebServerConfigsOptions.WebServerConfigs = make([]*options.WebServerConfigOptions, 0) opts.WebServerConfigsOptions.WebServerConfigs = append( opts.WebServerConfigsOptions.WebServerConfigs, &options.WebServerConfigOptions{ ServerName: "example test", ServerType: "nginx", - ConfigPath: "../../nginx/conf/nginx.conf", + ConfigPath: absConfigPath, VerifyExecPath: "../../nginx/sbin/nginx.sh", LogsDirPath: "../../nginx/logs", BackupDir: "", @@ -50,8 +54,7 @@ func exampleServerRun() error { opts.WebServerLogWatcherOptions.WatchTimeout = time.Second * 50 opts.WebServerLogWatcherOptions.MaxConnections = 1024 - opts.Log.Level = "debug" - log.Init(opts.Log) + opts.Log.InfoLevel = "debug" return bifrost.Run(&config.Config{Options: opts}) } From 28fce7e84fc07f959ebe8658389505aa6752e453 Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Wed, 27 Mar 2024 12:49:20 +0800 Subject: [PATCH 3/8] docs(code): complete error code update. --- docs/guide/zh-CN/api/error_code_generated.md | 103 ++++++++++-------- internal/pkg/code/bifrost.go | 28 ++--- internal/pkg/code/code_generated.go | 9 +- .../V3/nginx/configuration/context/errors.go | 18 +-- .../context/local/basic_context.go | 28 ++--- .../context/local/basic_context_test.go | 36 +++--- .../configuration/context/local/comment.go | 8 +- .../configuration/context/local/config.go | 22 ++-- .../context/local/context_test.go | 6 +- .../configuration/context/local/directive.go | 10 +- .../context/local/directive_test.go | 8 +- .../configuration/context/local/include.go | 28 ++--- .../context/local/include_test.go | 8 +- .../nginx/configuration/context/position.go | 2 +- .../V3/nginx/configuration/nginx_config.go | 2 +- .../nginx_config_statistician.go | 2 +- 16 files changed, 166 insertions(+), 152 deletions(-) diff --git a/docs/guide/zh-CN/api/error_code_generated.md b/docs/guide/zh-CN/api/error_code_generated.md index cf6ed4c..a86b11d 100644 --- a/docs/guide/zh-CN/api/error_code_generated.md +++ b/docs/guide/zh-CN/api/error_code_generated.md @@ -12,52 +12,59 @@ ## 错误码列表 Bifrost 系统支持的错误码列表如下: -| Identifier | Code | HTTP Code | Description | -| ---------- | ---- | --------- | ----------- | -| ErrSuccess | 100001 | 200 | OK | -| ErrUnknown | 100002 | 500 | Internal server error | -| ErrBind | 100003 | 400 | Error occurred while binding the request body to the struct | -| ErrValidation | 100004 | 400 | Validation failed | -| ErrTokenInvalid | 100005 | 401 | Token invalid | -| ErrPageNotFound | 100006 | 404 | Page not found | -| ErrRequestTimeout | 100007 | 408 | Request timeout | -| ErrDatabase | 100101 | 500 | Database error | -| ErrDataRepository | 100201 | 500 | Data Repository error | -| ErrEncrypt | 100301 | 401 | Error occurred while encrypting the user password | -| ErrSignatureInvalid | 100302 | 401 | Signature is invalid | -| ErrExpired | 100303 | 401 | Token expired | -| ErrInvalidAuthHeader | 100304 | 401 | Invalid authorization header | -| ErrMissingHeader | 100305 | 401 | The `Authorization` header was empty | -| ErrUserOrPasswordIncorrect | 100306 | 401 | User or Password was incorrect | -| ErrPermissionDenied | 100307 | 403 | Permission denied | -| ErrAuthnClientInitFailed | 100308 | 500 | The `Authentication` client initialization failed | -| ErrAuthClientNotInit | 100309 | 500 | The `Authentication` and `Authorization` client not initialized | -| ErrConnToAuthServerFailed | 100310 | 500 | Failed to connect to `Authentication` and `Authorization` server | -| ErrEncodingFailed | 100401 | 500 | Encoding failed due to an error with the data | -| ErrDecodingFailed | 100402 | 500 | Decoding failed due to an error with the data | -| ErrInvalidJSON | 100403 | 500 | Data is not valid JSON | -| ErrEncodingJSON | 100404 | 500 | JSON data could not be encoded | -| ErrDecodingJSON | 100405 | 500 | JSON data could not be decoded | -| ErrInvalidYaml | 100406 | 500 | Data is not valid Yaml | -| ErrEncodingYaml | 100407 | 500 | Yaml data could not be encoded | -| ErrDecodingYaml | 100408 | 500 | Yaml data could not be decoded | -| ErrConfigurationTypeMismatch | 110001 | 500 | Configuration type mismatch | -| ErrSameConfigFingerprint | 110002 | 500 | Same config fingerprint | -| ErrSameConfigFingerprints | 110003 | 500 | Same config fingerprint between files and configuration | -| ErrConfigManagerIsRunning | 110004 | 500 | Config manager is running | -| ErrConfigManagerIsNotRunning | 110005 | 500 | Config manager is not running | -| ErrConfigurationNotFound | 110006 | 400 | Web server configuration not found | -| ErrParserNotFound | 110007 | 500 | Parser not found | -| ErrUnknownKeywordString | 110008 | 500 | Unknown keyword string | -| ErrInvalidConfig | 110009 | 500 | Invalid parser.Config | -| ErrParseFailed | 110010 | 500 | Config parse failed | -| ErrStopMonitoringTimeout | 110201 | 500 | Stop monitoring timeout | -| ErrMonitoringServiceSuspension | 110202 | 500 | Monitoring service suspension | -| ErrMonitoringStarted | 110203 | 500 | Monitoring is already started | -| ErrLogsDirPath | 110301 | 500 | Logs dir is not exist or is not a directory | -| ErrLogBufferIsNotExist | 110302 | 500 | Log buffer is not exist | -| ErrLogBufferIsExist | 110303 | 500 | Log buffer is already exist | -| ErrLogIsLocked | 110304 | 500 | Log is locked | -| ErrLogIsUnlocked | 110305 | 500 | Log is unlocked | -| ErrUnknownLockError | 110306 | 500 | Unknown lock error | +| Identifier | Code | HTTP Code | Description | +|--------------------------------|--------|-----------|------------------------------------------------------------------| +| ErrSuccess | 100001 | 200 | OK | +| ErrUnknown | 100002 | 500 | Internal server error | +| ErrBind | 100003 | 400 | Error occurred while binding the request body to the struct | +| ErrValidation | 100004 | 400 | Validation failed | +| ErrTokenInvalid | 100005 | 401 | Token invalid | +| ErrPageNotFound | 100006 | 404 | Page not found | +| ErrRequestTimeout | 100007 | 408 | Request timeout | +| ErrDatabase | 100101 | 500 | Database error | +| ErrDataRepository | 100201 | 500 | Data Repository error | +| ErrEncrypt | 100301 | 401 | Error occurred while encrypting the user password | +| ErrSignatureInvalid | 100302 | 401 | Signature is invalid | +| ErrExpired | 100303 | 401 | Token expired | +| ErrInvalidAuthHeader | 100304 | 401 | Invalid authorization header | +| ErrMissingHeader | 100305 | 401 | The `Authorization` header was empty | +| ErrUserOrPasswordIncorrect | 100306 | 401 | User or Password was incorrect | +| ErrPermissionDenied | 100307 | 403 | Permission denied | +| ErrAuthnClientInitFailed | 100308 | 500 | The `Authentication` client initialization failed | +| ErrAuthClientNotInit | 100309 | 500 | The `Authentication` and `Authorization` client not initialized | +| ErrConnToAuthServerFailed | 100310 | 500 | Failed to connect to `Authentication` and `Authorization` server | +| ErrEncodingFailed | 100401 | 500 | Encoding failed due to an error with the data | +| ErrDecodingFailed | 100402 | 500 | Decoding failed due to an error with the data | +| ErrInvalidJSON | 100403 | 500 | Data is not valid JSON | +| ErrEncodingJSON | 100404 | 500 | JSON data could not be encoded | +| ErrDecodingJSON | 100405 | 500 | JSON data could not be decoded | +| ErrInvalidYaml | 100406 | 500 | Data is not valid Yaml | +| ErrEncodingYaml | 100407 | 500 | Yaml data could not be encoded | +| ErrDecodingYaml | 100408 | 500 | Yaml data could not be decoded | +| ErrConfigurationTypeMismatch | 110001 | 500 | Configuration type mismatch | +| ErrSameConfigFingerprint | 110002 | 500 | Same config fingerprint | +| ErrSameConfigFingerprints | 110003 | 500 | Same config fingerprint between files and configuration | +| ErrConfigManagerIsRunning | 110004 | 500 | Config manager is running | +| ErrConfigManagerIsNotRunning | 110005 | 500 | Config manager is not running | +| ErrConfigurationNotFound | 110006 | 400 | Web server configuration not found | +| ErrParserNotFound | 110007 | 500 | Parser not found | +| ErrUnknownKeywordString | 110008 | 500 | Unknown keyword string | +| ErrInvalidConfig | 110009 | 500 | Invalid parser.Config | +| ErrParseFailed | 110010 | 500 | Config parse failed | +| ErrV3ContextIndexOutOfRange | 110011 | 500 | Index of the Context's children is out of range | +| ErrV3NullContextPosition | 110012 | 500 | Null Context position | +| ErrV3SetFatherContextFailed | 110013 | 500 | Set father Context failed | +| ErrV3OperationOnErrorContext | 110014 | 500 | Performing operations on Error Context | +| ErrV3InvalidContext | 110015 | 500 | Invalid Context | +| ErrV3InvalidOperation | 110016 | 500 | Invalid operation | +| ErrV3ContextNotFound | 110017 | 500 | Queried context not found | +| ErrStopMonitoringTimeout | 110201 | 500 | Stop monitoring timeout | +| ErrMonitoringServiceSuspension | 110202 | 500 | Monitoring service suspension | +| ErrMonitoringStarted | 110203 | 500 | Monitoring is already started | +| ErrLogsDirPath | 110301 | 500 | Logs dir is not exist or is not a directory | +| ErrLogBufferIsNotExist | 110302 | 500 | Log buffer is not exist | +| ErrLogBufferIsExist | 110303 | 500 | Log buffer is already exist | +| ErrLogIsLocked | 110304 | 500 | Log is locked | +| ErrLogIsUnlocked | 110305 | 500 | Log is unlocked | +| ErrUnknownLockError | 110306 | 500 | Unknown lock error | diff --git a/internal/pkg/code/bifrost.go b/internal/pkg/code/bifrost.go index 1ccd1e6..fe53599 100644 --- a/internal/pkg/code/bifrost.go +++ b/internal/pkg/code/bifrost.go @@ -34,26 +34,26 @@ const ( // ErrParseFailed - 500: Config parse failed. ErrParseFailed - // V3ErrContextIndexOutOfRange - 500: Index of the Context's children is out of range. - V3ErrContextIndexOutOfRange + // ErrV3ContextIndexOutOfRange - 500: Index of the Context's children is out of range. + ErrV3ContextIndexOutOfRange - // V3ErrNullContextPosition - 500: Null Context position. - V3ErrNullContextPosition + // ErrV3NullContextPosition - 500: Null Context position. + ErrV3NullContextPosition - // V3ErrSetFatherContextFailed - 500: Set father Context failed. - V3ErrSetFatherContextFailed + // ErrV3SetFatherContextFailed - 500: Set father Context failed. + ErrV3SetFatherContextFailed - // V3ErrOperationOnErrorContext - 500: Performing operations on Error Context. - V3ErrOperationOnErrorContext + // ErrV3OperationOnErrorContext - 500: Performing operations on Error Context. + ErrV3OperationOnErrorContext - // V3ErrInvalidContext - 500: Invalid Context. - V3ErrInvalidContext + // ErrV3InvalidContext - 500: Invalid Context. + ErrV3InvalidContext - // V3ErrInvalidOperation - 500: Invalid operation. - V3ErrInvalidOperation + // ErrV3InvalidOperation - 500: Invalid operation. + ErrV3InvalidOperation - // V3ErrContextNotFound - 500: queried context not found. - V3ErrContextNotFound + // ErrV3ContextNotFound - 500: Queried context not found. + ErrV3ContextNotFound ) // bifrost: statistics errors. diff --git a/internal/pkg/code/code_generated.go b/internal/pkg/code/code_generated.go index 3fbf3f5..2e60607 100644 --- a/internal/pkg/code/code_generated.go +++ b/internal/pkg/code/code_generated.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. -// Code generated by `codegen -type=int -fullname=Bifrost F:\GO_Project\src\bifrost/internal/pkg/code`; DO NOT EDIT. +// Code generated by `codegen -type=int -fullname=Bifrost`; DO NOT EDIT. package code @@ -45,6 +45,13 @@ func init() { register(ErrUnknownKeywordString, 500, "Unknown keyword string") register(ErrInvalidConfig, 500, "Invalid parser.Config") register(ErrParseFailed, 500, "Config parse failed") + register(ErrV3ContextIndexOutOfRange, 500, "Index of the Context's children is out of range") + register(ErrV3NullContextPosition, 500, "Null Context position") + register(ErrV3SetFatherContextFailed, 500, "Set father Context failed") + register(ErrV3OperationOnErrorContext, 500, "Performing operations on Error Context") + register(ErrV3InvalidContext, 500, "Invalid Context") + register(ErrV3InvalidOperation, 500, "Invalid operation") + register(ErrV3ContextNotFound, 500, "Queried context not found") register(ErrStopMonitoringTimeout, 500, "Stop monitoring timeout") register(ErrMonitoringServiceSuspension, 500, "Monitoring service suspension") register(ErrMonitoringStarted, 500, "Monitoring is already started") diff --git a/pkg/resolv/V3/nginx/configuration/context/errors.go b/pkg/resolv/V3/nginx/configuration/context/errors.go index d334f10..2351194 100644 --- a/pkg/resolv/V3/nginx/configuration/context/errors.go +++ b/pkg/resolv/V3/nginx/configuration/context/errors.go @@ -11,15 +11,15 @@ const () var ( ErrIndexOutOfRange = errors.New("index out of range") ErrInsertParserTypeError = errors.New("insert parser type error") - ErrInsertIntoErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "insert context into an error context") - ErrRemoveFromErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "remove context from an error context") - ErrModifyFromErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "modify context from an error context") - ErrSetValueToErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "set value to an error context") - ErrSetFatherToErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "set father to an error context") - ErrGetFatherFromErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "get father from an error context") - ErrGetChildFromErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "get child from an error context") - ErrParseConfigFromErrorContext = errors.WithCode(code.V3ErrOperationOnErrorContext, "parse config from an error context") - ErrNullPosition = errors.WithCode(code.V3ErrNullContextPosition, "null position") + ErrInsertIntoErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "insert context into an error context") + ErrRemoveFromErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "remove context from an error context") + ErrModifyFromErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "modify context from an error context") + ErrSetValueToErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "set value to an error context") + ErrSetFatherToErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "set father to an error context") + ErrGetFatherFromErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "get father from an error context") + ErrGetChildFromErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "get child from an error context") + ErrParseConfigFromErrorContext = errors.WithCode(code.ErrV3OperationOnErrorContext, "parse config from an error context") + ErrNullPosition = errors.WithCode(code.ErrV3NullContextPosition, "null position") ErrNullContext = errors.New("null context") ) diff --git a/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go b/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go index 464c65b..78503a9 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/basic_context.go @@ -24,12 +24,12 @@ type BasicContext struct { func (b *BasicContext) Insert(ctx context.Context, idx int) context.Context { // negative index if idx < 0 { - return context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", idx)) + return context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", idx)) } // refuse to insert nil if ctx == nil { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert nil")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")) } // refuse to insert error context and config context @@ -37,15 +37,15 @@ func (b *BasicContext) Insert(ctx context.Context, idx int) context.Context { case context_type.TypeErrContext: errctx, ok := ctx.(*context.ErrorContext) if ok { - return errctx.AppendError(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert error context")) + return errctx.AppendError(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert error context")) } - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert invalid context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert invalid context")) case context_type.TypeConfig: _, ok := ctx.(*Config) if ok { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert config context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert config context")) } - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert invalid context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert invalid context")) } if idx >= b.Len() { @@ -61,7 +61,7 @@ func (b *BasicContext) Insert(ctx context.Context, idx int) context.Context { // set father for inserted ctx err := ctx.SetFather(b.self) if err != nil { - return context.ErrContext(errors.WithCode(code.V3ErrSetFatherContextFailed, err.Error())) + return context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, err.Error())) } return b.self @@ -70,14 +70,14 @@ func (b *BasicContext) Insert(ctx context.Context, idx int) context.Context { func (b *BasicContext) Remove(idx int) context.Context { // negative index if idx < 0 { - return context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", idx)) + return context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", idx)) } if idx < b.Len() { // release father ctx err := b.Children[idx].SetFather(context.NullContext()) if err != nil { - return context.ErrContext(errors.WithCode(code.V3ErrSetFatherContextFailed, err.Error())) + return context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, err.Error())) } b.Children = append(b.Children[:idx], b.Children[idx+1:]...) @@ -88,16 +88,16 @@ func (b *BasicContext) Remove(idx int) context.Context { func (b *BasicContext) Modify(ctx context.Context, idx int) context.Context { // refuse to modify to nil if ctx == nil { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to nil")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to nil")) } // refuse to modify to error context if ctx.Type() == context_type.TypeErrContext { errctx, ok := ctx.(*context.ErrorContext) if ok { - return errctx.AppendError(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to error context")) + return errctx.AppendError(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to error context")) } - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to invalid context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to invalid context")) } // if the context before and after modification is the same, no modification will be made @@ -114,7 +114,7 @@ func (b *BasicContext) Father() context.Context { func (b *BasicContext) Child(idx int) context.Context { if idx >= b.Len() || idx < 0 { - return context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", idx)) + return context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", idx)) } return b.Children[idx] } @@ -204,7 +204,7 @@ func (b *BasicContext) ConfigLines(isDumping bool) ([]string, error) { } for idx, child := range b.Children { if child == nil { - return nil, errors.WithCode(code.V3ErrInvalidOperation, "child(index:%d) is nil", idx) + return nil, errors.WithCode(code.ErrV3InvalidOperation, "child(index:%d) is nil", idx) } clines, err := child.ConfigLines(isDumping) if err != nil { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go b/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go index 37d8527..b5ddc9d 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go @@ -33,13 +33,13 @@ func TestBasicContext_Child(t *testing.T) { name: "negative index", fields: fields{Children: []context.Context{context.NullContext()}}, args: args{idx: -1}, - want: context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", -1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), }, { name: "index larger than children's length", fields: fields{Children: []context.Context{context.NullContext()}}, args: args{idx: 1}, - want: context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", 1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", 1)), }, { name: "null context child", @@ -609,7 +609,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: nil, idx: -1, }, - want: context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", -1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), }, { name: "insert nil", @@ -618,7 +618,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: nil, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert nil")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), }, { name: "insert null context", @@ -627,7 +627,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: context.NullContext(), idx: 0, }, - want: context.NullContext().(*context.ErrorContext).AppendError(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert error context")), + want: context.NullContext().(*context.ErrorContext).AppendError(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert error context")), }, { name: "insert error context", @@ -636,7 +636,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: context.ErrContext(errors.New("test error")), idx: 0, }, - want: context.ErrContext(errors.New("test error")).(*context.ErrorContext).AppendError(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert error context")), + want: context.ErrContext(errors.New("test error")).(*context.ErrorContext).AppendError(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert error context")), }, { name: "insert invalid error context", @@ -645,7 +645,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: &Location{BasicContext{ContextType: context_type.TypeErrContext}}, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert invalid context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert invalid context")), }, { name: "insert config context", @@ -654,7 +654,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: NewContext(context_type.TypeConfig, "test.conf"), idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert config context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert config context")), }, { name: "insert invalid config context", @@ -663,7 +663,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: &Http{BasicContext{ContextType: context_type.TypeConfig}}, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert invalid context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert invalid context")), }, { name: "insert normal context into index within range", @@ -711,7 +711,7 @@ func TestBasicContext_Insert(t *testing.T) { ctx: &Config{BasicContext: BasicContext{ContextType: context_type.TypeConfig}}, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrSetFatherContextFailed, "cannot set father for Config Context")), + want: context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, "cannot set father for Config Context")), }, } for _, tt := range tests { @@ -828,7 +828,7 @@ func TestBasicContext_Modify(t *testing.T) { ctx: nil, idx: -1, }, - want: context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", -1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), wantModified: false, }, { @@ -838,7 +838,7 @@ func TestBasicContext_Modify(t *testing.T) { ctx: nil, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to nil")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to nil")), wantModified: false, }, { @@ -848,7 +848,7 @@ func TestBasicContext_Modify(t *testing.T) { ctx: context.NullContext(), idx: 0, }, - want: context.NullContext().(*context.ErrorContext).AppendError(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to error context")), + want: context.NullContext().(*context.ErrorContext).AppendError(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to error context")), wantModified: false, }, { @@ -859,7 +859,7 @@ func TestBasicContext_Modify(t *testing.T) { idx: 0, }, want: context.ErrContext(errors.New("test error")).(*context.ErrorContext). - AppendError(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to error context")), + AppendError(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to error context")), wantModified: false, }, { @@ -869,7 +869,7 @@ func TestBasicContext_Modify(t *testing.T) { ctx: &Location{BasicContext{ContextType: context_type.TypeErrContext}}, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to modify to invalid context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to modify to invalid context")), wantModified: false, }, { @@ -920,7 +920,7 @@ func TestBasicContext_Modify(t *testing.T) { ctx: NewContext(context_type.TypeLocation, "~ /test4"), idx: hasErrChildCtx.Len() - 1, }, - want: context.ErrContext(errors.WithCode(code.V3ErrSetFatherContextFailed, context.NullContext().(*context.ErrorContext). + want: context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, context.NullContext().(*context.ErrorContext). AppendError(context.ErrSetFatherToErrorContext).Error().Error())).(*context.ErrorContext). AppendError(context.ErrInsertIntoErrorContext), wantModified: false, @@ -1131,7 +1131,7 @@ func TestBasicContext_Remove(t *testing.T) { args: args{ idx: -1, }, - want: context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", -1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), wantRemovedCtx: nil, }, { @@ -1175,7 +1175,7 @@ func TestBasicContext_Remove(t *testing.T) { args: args{ idx: hasErrChildCtx.Len() - 1, }, - want: context.ErrContext(errors.WithCode(code.V3ErrSetFatherContextFailed, context.NullContext().(*context.ErrorContext). + want: context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, context.NullContext().(*context.ErrorContext). AppendError(context.ErrSetFatherToErrorContext).Error().Error())).(*context.ErrorContext). AppendError(context.ErrInsertIntoErrorContext), wantRemovedCtx: hasErrChildCtx.Child(hasErrChildCtx.Len() - 1), diff --git a/pkg/resolv/V3/nginx/configuration/context/local/comment.go b/pkg/resolv/V3/nginx/configuration/context/local/comment.go index f42bf49..0c135c2 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/comment.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/comment.go @@ -16,15 +16,15 @@ type Comment struct { } func (c *Comment) Insert(ctx context.Context, idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "comment cannot insert context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "comment cannot insert context")) } func (c *Comment) Remove(idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "comment cannot remove context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "comment cannot remove context")) } func (c *Comment) Modify(ctx context.Context, idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "comment cannot modify context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "comment cannot modify context")) } func (c *Comment) Father() context.Context { @@ -32,7 +32,7 @@ func (c *Comment) Father() context.Context { } func (c *Comment) Child(idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "comment has no context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "comment has no context")) } func (c *Comment) QueryByKeyWords(kw context.KeyWords) context.Pos { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/config.go b/pkg/resolv/V3/nginx/configuration/context/local/config.go index f849141..c0941ce 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/config.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/config.go @@ -53,7 +53,7 @@ func (c *Config) SetValue(v string) error { func (c *Config) SetFather(ctx context.Context) error { if _, ok := ctx.(*Main); !ok { - return errors.WithCode(code.V3ErrInvalidOperation, "the set father is not Main Context") + return errors.WithCode(code.ErrV3InvalidOperation, "the set father is not Main Context") } c.father = ctx return nil @@ -85,26 +85,26 @@ func (c *Config) ConfigLines(isDumping bool) ([]string, error) { func (c *Config) checkIncludedConfigs(configs []*Config) error { if c.ConfigPath == nil { - return errors.WithCode(code.V3ErrInvalidOperation, "this config has not been banded with a `ConfigPath`"+ + return errors.WithCode(code.ErrV3InvalidOperation, "this config has not been banded with a `ConfigPath`"+ " and other configs cannot be inserted into this config") } fatherMain, ok := c.Father().(*Main) if !ok || fatherMain.ConfigGraph == nil { - return errors.WithCode(code.V3ErrInvalidOperation, "this config has not been added to a certain graph"+ + return errors.WithCode(code.ErrV3InvalidOperation, "this config has not been added to a certain graph"+ " and other configs cannot be inserted into this config") } if configs == nil { - return errors.WithCode(code.V3ErrInvalidContext, "null config") + return errors.WithCode(code.ErrV3InvalidContext, "null config") } for _, config := range configs { if config == nil { - return errors.WithCode(code.V3ErrInvalidContext, "config with no ConfigPath") + return errors.WithCode(code.ErrV3InvalidContext, "config with no ConfigPath") } if config.ConfigPath != nil { if _, ok := config.ConfigPath.(*context.RelConfigPath); ok && config.ConfigPath.BaseDir() != fatherMain.MainConfig().BaseDir() { - return errors.WithCode(code.V3ErrInvalidContext, + return errors.WithCode(code.ErrV3InvalidContext, "he relative target directory(%s) of the included configuration file does not match the directory(%s) where the main configuration file is located", config.BaseDir(), fatherMain.MainConfig().BaseDir()) } @@ -270,7 +270,7 @@ func configHash(t *Config) string { func (c *configGraph) AddEdge(src, dst *Config) error { if src == nil || dst == nil || configHash(src) == "" || configHash(dst) == "" { - return errors.WithCode(code.V3ErrInvalidContext, "source or destination config is nil") + return errors.WithCode(code.ErrV3InvalidContext, "source or destination config is nil") } err := c.setFatherFor(src) if err != nil { @@ -319,10 +319,10 @@ func (c *configGraph) removeConfig(config *Config) error { func (c *configGraph) setFatherFor(config *Config) error { if config == nil { - return errors.WithCode(code.V3ErrInvalidContext, "added config is nil") + return errors.WithCode(code.ErrV3InvalidContext, "added config is nil") } if config.isInGraph() && config.Father() != c.MainConfig().Father() { - return errors.WithCode(code.V3ErrInvalidContext, "%s config is in another config graph", configHash(config)) + return errors.WithCode(code.ErrV3InvalidContext, "%s config is in another config graph", configHash(config)) } return config.SetFather(c.MainConfig().Father()) } @@ -413,10 +413,10 @@ func newMain(abspath string) (*Main, error) { func newConfigGraph(mainConfig *Config) (ConfigGraph, error) { if mainConfig.ConfigPath == nil { - return nil, errors.WithCode(code.V3ErrInvalidContext, "main config's ConfigPath is nil") + return nil, errors.WithCode(code.ErrV3InvalidContext, "main config's ConfigPath is nil") } if mainConfig.isInGraph() { - return nil, errors.WithCode(code.V3ErrInvalidContext, "main config(%s) is in another config graph", configHash(mainConfig)) + return nil, errors.WithCode(code.ErrV3InvalidContext, "main config(%s) is in another config graph", configHash(mainConfig)) } g := graph.New(configHash, graph.PreventCycles(), graph.Directed()) err := g.AddVertex(mainConfig) diff --git a/pkg/resolv/V3/nginx/configuration/context/local/context_test.go b/pkg/resolv/V3/nginx/configuration/context/local/context_test.go index 90ead70..783ce2c 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/context_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/context_test.go @@ -207,7 +207,7 @@ func TestMain_Insert(t *testing.T) { ctx: nil, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert nil")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), }, { name: "return main context itself", @@ -361,7 +361,7 @@ func TestMain_Modify(t *testing.T) { ctx: nil, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "refuse to insert nil")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), }, { name: "return main context itself", @@ -454,7 +454,7 @@ func TestMain_Remove(t *testing.T) { name: "error context result", fields: testMain, args: args{idx: -1}, - want: context.ErrContext(errors.WithCode(code.V3ErrContextIndexOutOfRange, "index(%d) out of range", -1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), }, { name: "return main itself", diff --git a/pkg/resolv/V3/nginx/configuration/context/local/directive.go b/pkg/resolv/V3/nginx/configuration/context/local/directive.go index af64a87..c001eb2 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/directive.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/directive.go @@ -16,15 +16,15 @@ type Directive struct { } func (d *Directive) Insert(ctx context.Context, idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive cannot insert context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive cannot insert context")) } func (d *Directive) Remove(idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive cannot remove context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive cannot remove context")) } func (d *Directive) Modify(ctx context.Context, idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive cannot modify context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive cannot modify context")) } func (d *Directive) Father() context.Context { @@ -32,7 +32,7 @@ func (d *Directive) Father() context.Context { } func (d *Directive) Child(idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive has no child context")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive has no child context")) } func (d *Directive) QueryByKeyWords(kw context.KeyWords) context.Pos { @@ -54,7 +54,7 @@ func (d *Directive) Clone() context.Context { func (d *Directive) SetValue(v string) error { kv := strings.SplitN(strings.TrimSpace(v), " ", 2) if len(strings.TrimSpace(kv[0])) == 0 { - return errors.WithCode(code.V3ErrInvalidOperation, "set value for directive failed, cased by: split null value") + return errors.WithCode(code.ErrV3InvalidOperation, "set value for directive failed, cased by: split null value") } d.Name = strings.TrimSpace(kv[0]) if len(kv) == 2 { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/directive_test.go b/pkg/resolv/V3/nginx/configuration/context/local/directive_test.go index 41fa1fa..261bf18 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/directive_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/directive_test.go @@ -26,7 +26,7 @@ func TestDirective_Child(t *testing.T) { }{ { name: "has no child", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive has no child context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive has no child context")), }, } for _, tt := range tests { @@ -242,7 +242,7 @@ func TestDirective_Insert(t *testing.T) { }{ { name: "cannot insert child", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive cannot insert context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive cannot insert context")), }, } for _, tt := range tests { @@ -307,7 +307,7 @@ func TestDirective_Modify(t *testing.T) { }{ { name: "cannot modify child", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive cannot modify context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive cannot modify context")), }, } for _, tt := range tests { @@ -409,7 +409,7 @@ func TestDirective_Remove(t *testing.T) { }{ { name: "cannot remove child", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "directive cannot remove context")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "directive cannot remove context")), }, } for _, tt := range tests { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/include.go b/pkg/resolv/V3/nginx/configuration/context/local/include.go index 8e6f9bb..f300b11 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/include.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/include.go @@ -42,9 +42,9 @@ func (i *Include) FatherConfig() (*Config, error) { for !ok { switch fatherCtx.Type() { case context_type.TypeErrContext: - return nil, fatherCtx.(*context.ErrorContext).AppendError(errors.WithCode(code.V3ErrInvalidContext, "found an error config context")).Error() + return nil, fatherCtx.(*context.ErrorContext).AppendError(errors.WithCode(code.ErrV3InvalidContext, "found an error config context")).Error() case context_type.TypeMain: - return nil, errors.WithCode(code.V3ErrInvalidContext, "found an Main context") + return nil, errors.WithCode(code.ErrV3InvalidContext, "found an Main context") } if fatherCtx.Type() == context_type.TypeErrContext { @@ -56,12 +56,12 @@ func (i *Include) FatherConfig() (*Config, error) { } func (i *Include) Insert(ctx context.Context, idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot insert by index")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot insert by index")) } func (i *Include) InsertConfig(configs ...*Config) error { if configs == nil { - return errors.WithCode(code.V3ErrInvalidContext, "null config") + return errors.WithCode(code.ErrV3InvalidContext, "null config") } // find father config @@ -71,13 +71,13 @@ func (i *Include) InsertConfig(configs ...*Config) error { } fatherMain, ok := fatherConfig.Father().(*Main) if !ok { - return errors.WithCode(code.V3ErrInvalidContext, "this include context is not bound to a main context") + return errors.WithCode(code.ErrV3InvalidContext, "this include context is not bound to a main context") } includingConfigs := make([]*Config, 0) for _, config := range configs { if config == nil { - return errors.WithCode(code.V3ErrInvalidContext, "nil config") + return errors.WithCode(code.ErrV3InvalidContext, "nil config") } // match config path if config.ConfigPath == nil { @@ -106,12 +106,12 @@ func (i *Include) InsertConfig(configs ...*Config) error { } func (i *Include) Remove(idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot remove by index")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot remove by index")) } func (i *Include) RemoveConfig(configs ...*Config) error { if configs == nil { - return errors.WithCode(code.V3ErrInvalidContext, "null config") + return errors.WithCode(code.ErrV3InvalidContext, "null config") } // find father config fatherConfig, err := i.FatherConfig() @@ -135,12 +135,12 @@ func (i *Include) RemoveConfig(configs ...*Config) error { } func (i *Include) Modify(ctx context.Context, idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot modify by index")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot modify by index")) } func (i *Include) ModifyConfig(configs ...*Config) error { if configs == nil { - return errors.WithCode(code.V3ErrInvalidContext, "null config") + return errors.WithCode(code.ErrV3InvalidContext, "null config") } return errors.NewAggregate([]error{i.RemoveConfig(configs...), i.InsertConfig(configs...)}) } @@ -150,7 +150,7 @@ func (i *Include) Father() context.Context { } func (i *Include) Child(idx int) context.Context { - return context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot get child config by index")) + return context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot get child config by index")) } func (i *Include) ChildConfig(fullpath string) (*Config, error) { @@ -188,7 +188,7 @@ func (i *Include) Clone() context.Context { } func (i *Include) SetValue(v string) error { - return errors.WithCode(code.V3ErrInvalidOperation, "cannot set include context's value") + return errors.WithCode(code.ErrV3InvalidOperation, "cannot set include context's value") } func (i *Include) SetFather(ctx context.Context) error { @@ -237,10 +237,10 @@ func (i *Include) ConfigLines(isDumping bool) ([]string, error) { func (i *Include) matchConfigPath(path string) error { isMatch, err := filepath.Match(i.Value(), path) if err != nil { - return errors.WithCode(code.V3ErrInvalidContext, "pattern(%s) match included config(%s) failed, cased by: %v", i.ContextValue, path, err) + return errors.WithCode(code.ErrV3InvalidContext, "pattern(%s) match included config(%s) failed, cased by: %v", i.ContextValue, path, err) } if !isMatch { - return errors.WithCode(code.V3ErrInvalidContext, "pattern(%s) cannot match included config(%s)", i.ContextValue, path) + return errors.WithCode(code.ErrV3InvalidContext, "pattern(%s) cannot match included config(%s)", i.ContextValue, path) } return nil } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/include_test.go b/pkg/resolv/V3/nginx/configuration/context/local/include_test.go index dfa7f41..2cfc7c6 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/include_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/include_test.go @@ -26,7 +26,7 @@ func TestInclude_Child(t *testing.T) { }{ { name: "error context", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot get child config by index")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot get child config by index")), }, } for _, tt := range tests { @@ -405,7 +405,7 @@ func TestInclude_Insert(t *testing.T) { }{ { name: "return error context", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot insert by index")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot insert by index")), }, } for _, tt := range tests { @@ -610,7 +610,7 @@ func TestInclude_Modify(t *testing.T) { }{ { name: "return error context", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot modify by index")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot modify by index")), }, } for _, tt := range tests { @@ -922,7 +922,7 @@ func TestInclude_Remove(t *testing.T) { }{ { name: "return error context", - want: context.ErrContext(errors.WithCode(code.V3ErrInvalidOperation, "include cannot remove by index")), + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "include cannot remove by index")), }, } for _, tt := range tests { diff --git a/pkg/resolv/V3/nginx/configuration/context/position.go b/pkg/resolv/V3/nginx/configuration/context/position.go index 8367701..a5e7288 100644 --- a/pkg/resolv/V3/nginx/configuration/context/position.go +++ b/pkg/resolv/V3/nginx/configuration/context/position.go @@ -48,7 +48,7 @@ func NullPos() Pos { return nullPos } -var notFoundPos = &errPos{ErrContext(errors.WithCode(code.V3ErrContextNotFound, "queried context not found")).(*ErrorContext)} +var notFoundPos = &errPos{ErrContext(errors.WithCode(code.ErrV3ContextNotFound, "queried context not found")).(*ErrorContext)} func NotFoundPos() Pos { return notFoundPos diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config.go b/pkg/resolv/V3/nginx/configuration/nginx_config.go index 4a6dc85..2f2cf2a 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config.go @@ -142,7 +142,7 @@ func dumpMainContext(m *local.Main) map[string]*bytes.Buffer { func newNginxConfigWithTimestamp(maincontext *local.Main, timestamp time.Time) (NginxConfig, error) { if maincontext == nil { - return nil, errors.WithCode(code.V3ErrInvalidContext, "new nginx config with a nil main context") + return nil, errors.WithCode(code.ErrV3InvalidContext, "new nginx config with a nil main context") } return &nginxConfig{ mainContext: maincontext, diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go index ff686a4..e6044d3 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go @@ -121,7 +121,7 @@ func HttpServers(ctx context.Context) (int, map[string][]int) { serverCount++ servernameDirective := pos.Target().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("^server_name .*")).Target() if servernameDirective.Error() != nil { - if !errors.IsCode(servernameDirective.Error(), code.V3ErrContextNotFound) { + if !errors.IsCode(servernameDirective.Error(), code.ErrV3ContextNotFound) { return 0, nil } From aee24bc6c19d2dc4c07058d0190ecfa5db40d6b1 Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Wed, 27 Mar 2024 17:09:21 +0800 Subject: [PATCH 4/8] test: preliminary completion of testing the "nginx configuration" data update operation in the interaction between the `bifrost` server and client. --- .../configuration/context/local/comment.go | 2 +- .../configuration/context/local/config.go | 4 +- .../configuration/context/local/directive.go | 2 +- test/grpc_client/bifrost/client_test.go | 47 +++++++++++++++++++ test/grpc_client/bifrost/example_server.go | 2 +- test/grpc_client/bifrost/vars_linux.go | 3 ++ test/grpc_client/bifrost/vars_windows.go | 3 ++ test/nginx/conf/nginx.conf | 6 +-- test/nginx/sbin/nginx.bat | 3 ++ 9 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 test/grpc_client/bifrost/vars_linux.go create mode 100644 test/grpc_client/bifrost/vars_windows.go create mode 100644 test/nginx/sbin/nginx.bat diff --git a/pkg/resolv/V3/nginx/configuration/context/local/comment.go b/pkg/resolv/V3/nginx/configuration/context/local/comment.go index 0c135c2..4e22c09 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/comment.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/comment.go @@ -9,7 +9,7 @@ import ( ) type Comment struct { - Comments string `json:"comments,omitempty"` + Comments string `json:"comments"` Inline bool `json:"inline,omitempty"` fatherContext context.Context diff --git a/pkg/resolv/V3/nginx/configuration/context/local/config.go b/pkg/resolv/V3/nginx/configuration/context/local/config.go index c0941ce..1985f25 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/config.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/config.go @@ -12,8 +12,8 @@ import ( ) type Config struct { - BasicContext // `json:"config"` - context.ConfigPath // `json:"-"` + BasicContext + context.ConfigPath } func (c *Config) MarshalJSON() ([]byte, error) { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/directive.go b/pkg/resolv/V3/nginx/configuration/context/local/directive.go index c001eb2..5f60af8 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/directive.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/directive.go @@ -9,7 +9,7 @@ import ( ) type Directive struct { - Name string `json:"directive,omitempty"` + Name string `json:"directive"` Params string `json:"params,omitempty"` fatherContext context.Context diff --git a/test/grpc_client/bifrost/client_test.go b/test/grpc_client/bifrost/client_test.go index e94fbdc..d84fb89 100644 --- a/test/grpc_client/bifrost/client_test.go +++ b/test/grpc_client/bifrost/client_test.go @@ -3,6 +3,9 @@ package bifrost import ( "context" "fmt" + nginx_ctx "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" "sync" "testing" "time" @@ -154,3 +157,47 @@ func TestBifrostClient(t *testing.T) { } wg.Wait() } + +func TestBifrostClientOperation(t *testing.T) { + client, err := bifrost_cliv1.New(serverAddress(), grpc.WithInsecure(), grpc.WithTimeout(time.Second)) + if err != nil { + t.Fatal(err) + } + + defer client.Close() + + servernames, err := client.WebServerConfig().GetServerNames() + if err != nil { + t.Fatal(err) + } + + for _, servername := range servernames { + jsondata, err := client.WebServerConfig().Get(servername) + if err != nil { + t.Fatal(err) + } + conf, err := configuration.NewNginxConfigFromJsonBytes(jsondata) + if err != nil { + t.Fatal(err) + } + for _, pos := range conf.Main().QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeHttp)).Target(). + QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeServer)).Target(). + QueryAllByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetStringMatchingValue("server_name test1.com")) { + server, _ := pos.Position() + if server.QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("^listen 80$")).Target().Error() != nil { + continue + } + ctx, idx := server.QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue(`^/test1-location$`)).Target(). + QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeIf).SetRegexMatchingValue(`^\(\$http_api_name != ''\)$`)).Target(). + QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetStringMatchingValue("proxy_pass")).Position() + err = ctx.Insert(local.NewComment(fmt.Sprintf("[%s]test comments", time.Now().String()), true), idx+1).Error() + if err != nil { + t.Fatal(err) + } + } + err = client.WebServerConfig().Update(servername, conf.Json()) + if err != nil { + t.Fatal(err) + } + } +} diff --git a/test/grpc_client/bifrost/example_server.go b/test/grpc_client/bifrost/example_server.go index c2be9c0..3cd630a 100644 --- a/test/grpc_client/bifrost/example_server.go +++ b/test/grpc_client/bifrost/example_server.go @@ -43,7 +43,7 @@ func exampleServerRun() error { ServerName: "example test", ServerType: "nginx", ConfigPath: absConfigPath, - VerifyExecPath: "../../nginx/sbin/nginx.sh", + VerifyExecPath: verifyExecPath, LogsDirPath: "../../nginx/logs", BackupDir: "", BackupCycle: 1, diff --git a/test/grpc_client/bifrost/vars_linux.go b/test/grpc_client/bifrost/vars_linux.go new file mode 100644 index 0000000..24c8a0f --- /dev/null +++ b/test/grpc_client/bifrost/vars_linux.go @@ -0,0 +1,3 @@ +package bifrost + +var verifyExecPath = "../../nginx/sbin/nginx.sh" diff --git a/test/grpc_client/bifrost/vars_windows.go b/test/grpc_client/bifrost/vars_windows.go new file mode 100644 index 0000000..985aea6 --- /dev/null +++ b/test/grpc_client/bifrost/vars_windows.go @@ -0,0 +1,3 @@ +package bifrost + +var verifyExecPath = "..\\..\\nginx\\sbin\\nginx.bat" diff --git a/test/nginx/conf/nginx.conf b/test/nginx/conf/nginx.conf index 5db4418..191a4c7 100644 --- a/test/nginx/conf/nginx.conf +++ b/test/nginx/conf/nginx.conf @@ -35,13 +35,13 @@ http { } # error_page 404 /404.html; # redirect server error pages to the static page /50x.html - # + # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 - # + # # location ~ \.php$ { # proxy_pass http://127.0.0.1; # } @@ -62,7 +62,7 @@ http { # } } # another virtual host using mix of IP-, name-, and port-based configuration - # + # # server { # listen 8000; # listen somename:8080; diff --git a/test/nginx/sbin/nginx.bat b/test/nginx/sbin/nginx.bat new file mode 100644 index 0000000..88d4717 --- /dev/null +++ b/test/nginx/sbin/nginx.bat @@ -0,0 +1,3 @@ +ECHO OFF +ECHO "pass" +exit 0 \ No newline at end of file From 04a1b13ad46000e555f50954c23e1838e8bab989 Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Thu, 28 Mar 2024 17:24:34 +0800 Subject: [PATCH 5/8] chore: chage `Logger` package. --- internal/bifrost/transport/v1/fake/web_server_log_watcher.go | 4 ++-- internal/bifrost/transport/v1/fake/web_server_statistics.go | 4 ++-- internal/bifrost/transport/v1/fake/web_server_status.go | 4 ++-- internal/pkg/file_watcher/watcher_manager_test.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/bifrost/transport/v1/fake/web_server_log_watcher.go b/internal/bifrost/transport/v1/fake/web_server_log_watcher.go index c82dae3..f542f5b 100644 --- a/internal/bifrost/transport/v1/fake/web_server_log_watcher.go +++ b/internal/bifrost/transport/v1/fake/web_server_log_watcher.go @@ -2,13 +2,13 @@ package fake import ( pbv1 "github.com/ClessLi/bifrost/api/protobuf-spec/bifrostpb/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" ) type webServerLogWatcher struct{} func (w webServerLogWatcher) Watch(request *pbv1.LogWatchRequest, stream pbv1.WebServerLogWatcher_WatchServer) error { - log.Infof("watch web server log '%s'", request.ServerName) + logV1.Infof("watch web server log '%s'", request.ServerName) return nil } diff --git a/internal/bifrost/transport/v1/fake/web_server_statistics.go b/internal/bifrost/transport/v1/fake/web_server_statistics.go index 959a992..de619d8 100644 --- a/internal/bifrost/transport/v1/fake/web_server_statistics.go +++ b/internal/bifrost/transport/v1/fake/web_server_statistics.go @@ -2,13 +2,13 @@ package fake import ( pbv1 "github.com/ClessLi/bifrost/api/protobuf-spec/bifrostpb/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" ) type webServerStatistics struct{} func (w webServerStatistics) Get(servername *pbv1.ServerName, stream pbv1.WebServerStatistics_GetServer) error { - log.Infof("get %s web server statistics", servername.Name) + logV1.Infof("get %s web server statistics", servername.Name) return nil } diff --git a/internal/bifrost/transport/v1/fake/web_server_status.go b/internal/bifrost/transport/v1/fake/web_server_status.go index 32f169c..4a468b9 100644 --- a/internal/bifrost/transport/v1/fake/web_server_status.go +++ b/internal/bifrost/transport/v1/fake/web_server_status.go @@ -2,13 +2,13 @@ package fake import ( pbv1 "github.com/ClessLi/bifrost/api/protobuf-spec/bifrostpb/v1" - log "github.com/ClessLi/bifrost/pkg/log/v1" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" ) type webServerStatus struct{} func (w webServerStatus) Get(null *pbv1.Null, stream pbv1.WebServerStatus_GetServer) error { - log.Infof("get web server status") + logV1.Infof("get web server status") return nil } diff --git a/internal/pkg/file_watcher/watcher_manager_test.go b/internal/pkg/file_watcher/watcher_manager_test.go index c675b29..824ea43 100644 --- a/internal/pkg/file_watcher/watcher_manager_test.go +++ b/internal/pkg/file_watcher/watcher_manager_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - log "github.com/ClessLi/bifrost/pkg/log/v1" + logV1 "github.com/ClessLi/component-base/pkg/log/v1" ) func TestWatcherManager_Watch(t *testing.T) { @@ -59,7 +59,7 @@ func TestWatcherManager_Watch(t *testing.T) { select { case data := <-got: if data == nil { - log.Infof("watch stopped") + logV1.Infof("watch stopped") return } t.Logf("%s", data) From bc4c19af86f59b3f7eaebeff180adcc969d96453 Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Thu, 28 Mar 2024 17:26:21 +0800 Subject: [PATCH 6/8] feat(resolv): interface the `Main` Context. --- .../nginx/configuration/context/key_words.go | 9 +- .../context/local/basic_context_test.go | 40 +- .../configuration/context/local/config.go | 36 +- .../context/local/config_graph_test.go | 2 +- .../context/local/config_test.go | 725 +++++++++--------- .../configuration/context/local/context.go | 135 ---- .../context/local/context_test.go | 560 -------------- .../configuration/context/local/include.go | 6 +- .../context/local/include_test.go | 42 +- .../context/local/json_unmarshaler.go | 14 +- .../context/local/json_unmarshaler_test.go | 42 +- .../configuration/context/local/loader.go | 16 +- .../context/local/loader_test.go | 29 +- .../context/local/main_context.go | 161 ++++ .../context/local/main_context_test.go | 629 +++++++++++++++ .../V3/nginx/configuration/nginx_config.go | 23 +- .../configuration/nginx_config_manager.go | 12 +- .../nginx_config_statistician.go | 10 +- .../nginx/configuration/nginx_config_test.go | 27 +- test/grpc_client/bifrost/client_test.go | 6 +- 20 files changed, 1316 insertions(+), 1208 deletions(-) create mode 100644 pkg/resolv/V3/nginx/configuration/context/local/main_context.go create mode 100644 pkg/resolv/V3/nginx/configuration/context/local/main_context_test.go diff --git a/pkg/resolv/V3/nginx/configuration/context/key_words.go b/pkg/resolv/V3/nginx/configuration/context/key_words.go index 02635bb..1499405 100644 --- a/pkg/resolv/V3/nginx/configuration/context/key_words.go +++ b/pkg/resolv/V3/nginx/configuration/context/key_words.go @@ -6,12 +6,17 @@ import ( "strings" ) +const ( + RegexpMatchingListenPortValue = `^listen\s*(\d+)\s*\S*$` + RegexpMatchingServerNameValue = `^server_name\s*(.+)$` +) + type KeyWords interface { Match(ctx Context) bool Cascaded() bool SetCascaded(cascaded bool) KeyWords SetStringMatchingValue(value string) KeyWords - SetRegexMatchingValue(value string) KeyWords + SetRegexpMatchingValue(value string) KeyWords } type keywords struct { @@ -55,7 +60,7 @@ func (k *keywords) SetStringMatchingValue(value string) KeyWords { return k } -func (k *keywords) SetRegexMatchingValue(value string) KeyWords { +func (k *keywords) SetRegexpMatchingValue(value string) KeyWords { k.isRegex = true k.matchingValue = value return k diff --git a/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go b/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go index b5ddc9d..bb6ff03 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/basic_context_test.go @@ -123,10 +123,13 @@ func TestBasicContext_ConfigLines(t *testing.T) { _3levelctx := NewContext(context_type.TypeHttp, "").Insert(NewContext(context_type.TypeServer, "").Insert(NewDirective("server_name", "testserver"), 0), 0) includeCtx := NewContext(context_type.TypeInclude, "conf.d/*.conf").(*Include) - withIncludeCtx := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert(NewContext(context_type.TypeHttp, ""). - Insert(includeCtx, 0), - 0) + withIncludeCtx, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + withIncludeCtx.Insert(NewContext(context_type.TypeHttp, ""). + Insert(includeCtx, 0), + 0) configPath, err := context.NewRelConfigPath("C:\\test", "conf.d\\server.conf") if err != nil { t.Fatal(err) @@ -708,10 +711,10 @@ func TestBasicContext_Insert(t *testing.T) { tailStringFunc: testCtx.(*Server).tailStringFunc, }, args: args{ - ctx: &Config{BasicContext: BasicContext{ContextType: context_type.TypeConfig}}, + ctx: &Main{}, idx: 0, }, - want: context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, "cannot set father for Config Context")), + want: context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, "cannot set father for MainContext")), }, } for _, tt := range tests { @@ -825,10 +828,10 @@ func TestBasicContext_Modify(t *testing.T) { name: "modify negative index", fields: fields{Children: make([]context.Context, 0)}, args: args{ - ctx: nil, + ctx: NewDirective("test", ""), idx: -1, }, - want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)).(*context.ErrorContext).AppendError(context.ErrInsertIntoErrorContext), wantModified: false, }, { @@ -1019,7 +1022,7 @@ func TestBasicContext_QueryAllByKeyWords(t *testing.T) { headStringFunc: testContext.headStringFunc, tailStringFunc: testContext.tailStringFunc, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue("test")}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexpMatchingValue("test")}, want: []context.Pos{ context.SetPos(testFather, 0), context.SetPos(testFather, 2), @@ -1079,9 +1082,23 @@ func TestBasicContext_QueryByKeyWords(t *testing.T) { headStringFunc: testContext.headStringFunc, tailStringFunc: testContext.tailStringFunc, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue("test")}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexpMatchingValue("test")}, want: context.SetPos(testFather, 0), }, + { + name: "has not been matched context", + fields: fields{ + ContextType: testContext.ContextType, + ContextValue: testContext.ContextValue, + Children: testContext.Children, + father: testContext.father, + self: testContext.self, + headStringFunc: testContext.headStringFunc, + tailStringFunc: testContext.tailStringFunc, + }, + args: args{kw: context.NewKeyWords(context_type.TypeComment)}, + want: context.NotFoundPos(), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1176,8 +1193,7 @@ func TestBasicContext_Remove(t *testing.T) { idx: hasErrChildCtx.Len() - 1, }, want: context.ErrContext(errors.WithCode(code.ErrV3SetFatherContextFailed, context.NullContext().(*context.ErrorContext). - AppendError(context.ErrSetFatherToErrorContext).Error().Error())).(*context.ErrorContext). - AppendError(context.ErrInsertIntoErrorContext), + AppendError(context.ErrSetFatherToErrorContext).Error().Error())), wantRemovedCtx: hasErrChildCtx.Child(hasErrChildCtx.Len() - 1), }, } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/config.go b/pkg/resolv/V3/nginx/configuration/context/local/config.go index 1985f25..aed4d03 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/config.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/config.go @@ -24,8 +24,8 @@ func (c *Config) isInGraph() bool { if c.ConfigPath == nil { return false } - fatherMain, ok := c.Father().(*Main) - if !ok || fatherMain.ConfigGraph == nil { + fatherMain, ok := c.Father().(MainContext) + if !ok || fatherMain.graph() == nil { return false } _, err := fatherMain.GetConfig(configHash(c)) @@ -52,7 +52,7 @@ func (c *Config) SetValue(v string) error { } func (c *Config) SetFather(ctx context.Context) error { - if _, ok := ctx.(*Main); !ok { + if _, ok := ctx.(MainContext); !ok { return errors.WithCode(code.ErrV3InvalidOperation, "the set father is not Main Context") } c.father = ctx @@ -89,8 +89,8 @@ func (c *Config) checkIncludedConfigs(configs []*Config) error { " and other configs cannot be inserted into this config") } - fatherMain, ok := c.Father().(*Main) - if !ok || fatherMain.ConfigGraph == nil { + fatherMain, ok := c.Father().(MainContext) + if !ok || fatherMain.graph() == nil { return errors.WithCode(code.ErrV3InvalidOperation, "this config has not been added to a certain graph"+ " and other configs cannot be inserted into this config") } @@ -121,7 +121,7 @@ func (c *Config) includeConfig(configs ...*Config) ([]*Config, error) { } var errs []error - fatherMain := c.Father().(*Main) + fatherMain := c.Father().(MainContext) for _, config := range configs { if config.isInGraph() && config.Father() != fatherMain { @@ -170,7 +170,7 @@ func (c *Config) removeIncludedConfig(configs ...*Config) ([]*Config, error) { } var errs []error - fatherMain := c.Father().(*Main) + fatherMain := c.Father().(MainContext) for _, config := range configs { // get cache from graph cache, err := fatherMain.GetConfig(configHash(config)) @@ -189,7 +189,7 @@ func (c *Config) modifyPathInGraph(path string) error { if !c.isInGraph() { return nil } - fatherMain := c.Father().(*Main) + fatherMain := c.Father().(MainContext) targetConfigPath, err := newConfigPath(fatherMain, path) if err != nil { @@ -391,26 +391,6 @@ func (c *configGraph) RenewConfigPath(fullpath string) error { return c.graph.RemoveVertex(fullpath) } -func newMain(abspath string) (*Main, error) { - confpath, err := context.NewAbsConfigPath(abspath) - if err != nil { - return nil, err - } - config := &Config{ - BasicContext: newBasicContext(context_type.TypeConfig, nullHeadString, nullTailString), - ConfigPath: confpath, - } - config.self = config - config.ContextValue = abspath - g, err := newConfigGraph(config) - if err != nil { // Temporarily unable to be covered for testing - return nil, err - } - m := &Main{ConfigGraph: g} - m.MainConfig().father = m - return m, nil -} - func newConfigGraph(mainConfig *Config) (ConfigGraph, error) { if mainConfig.ConfigPath == nil { return nil, errors.WithCode(code.ErrV3InvalidContext, "main config's ConfigPath is nil") diff --git a/pkg/resolv/V3/nginx/configuration/context/local/config_graph_test.go b/pkg/resolv/V3/nginx/configuration/context/local/config_graph_test.go index f696ec0..80a0614 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/config_graph_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/config_graph_test.go @@ -6,7 +6,7 @@ import ( ) func TestModifyConfigPathInGraph(t *testing.T) { - testMain, err := newMain("C:\\test\\nginx.conf") + testMain, err := NewMain("C:\\test\\nginx.conf") if err != nil { t.Fatal(err) } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/config_test.go b/pkg/resolv/V3/nginx/configuration/context/local/config_test.go index d5e75de..65ee3dd 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/config_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/config_test.go @@ -9,21 +9,24 @@ import ( ) func TestConfig_Clone(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) testCloneChildren := make([]context.Context, 0) for _, child := range testMain.MainConfig().Children { testCloneChildren = append(testCloneChildren, child.Clone()) @@ -87,21 +90,24 @@ func TestConfig_Clone(t *testing.T) { } func TestConfig_ConfigLines(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) type fields struct { BasicContext BasicContext ConfigPath context.ConfigPath @@ -153,7 +159,10 @@ func TestConfig_ConfigLines(t *testing.T) { } func TestConfig_Father(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf") + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } type fields struct { BasicContext BasicContext ConfigPath context.ConfigPath @@ -259,6 +268,10 @@ func TestConfig_MarshalJSON(t *testing.T) { } func TestConfig_SetFather(t *testing.T) { + testMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } type fields struct { BasicContext BasicContext ConfigPath context.ConfigPath @@ -284,7 +297,7 @@ func TestConfig_SetFather(t *testing.T) { { name: "normal test", fields: fields{BasicContext: BasicContext{father: context.NullContext()}}, - args: args{ctx: NewContext(context_type.TypeMain, "C:\\test\\test.conf")}, + args: args{ctx: testMain}, wantErr: false, }, } @@ -303,22 +316,25 @@ func TestConfig_SetFather(t *testing.T) { func TestConfig_SetValue(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) if err != nil { t.Fatal(err) } @@ -364,7 +380,7 @@ func TestConfig_SetValue(t *testing.T) { BasicContext: tt.fields.BasicContext, ConfigPath: tt.fields.ConfigPath, } - cache, err := c.Father().(*Main).GetConfig(configHash(c)) + cache, err := c.Father().(MainContext).GetConfig(configHash(c)) if err != nil { t.Fatal(err) } @@ -377,22 +393,25 @@ func TestConfig_SetValue(t *testing.T) { func TestConfig_includeConfig(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig( + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "C:\\test\\existing.conf").(*Config), NewContext(context_type.TypeConfig, "a.conf").(*Config), NewContext(context_type.TypeConfig, "b.conf").(*Config), @@ -406,12 +425,12 @@ func TestConfig_includeConfig(t *testing.T) { } nullPathConfig := NewContext(context_type.TypeConfig, "").(*Config) nullPathConfig.ConfigPath = &context.AbsConfigPath{} - err = testMain.ConfigGraph.(*configGraph).graph.AddVertex(nullPathConfig) + err = testMain.graph().(*configGraph).graph.AddVertex(nullPathConfig) if err != nil { t.Fatal(err) } nullPathConfig.father = testMain - err = testMain.ConfigGraph.(*configGraph).graph.AddEdge("", existingConfig.FullPath()) + err = testMain.graph().(*configGraph).graph.AddEdge("", existingConfig.FullPath()) if err != nil { t.Fatal(err) } @@ -431,9 +450,9 @@ func TestConfig_includeConfig(t *testing.T) { } // different main config - diffTestMain := NewContext(context_type.TypeMain, "C:\\test2\\nginx.conf").(*Main) + diffTestMain, _ := NewMain("C:\\test2\\nginx.conf") // main with invalid value - invalidTestMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + invalidTestMain, _ := NewMain("C:\\test\\nginx.conf") invalidTestMainCP := invalidTestMain.MainConfig().ConfigPath invalidTestMain.MainConfig().ConfigPath = nil newcpFailedConfig := NewContext(context_type.TypeConfig, "test\\test2.conf").(*Config) @@ -609,7 +628,7 @@ func TestConfig_includeConfig(t *testing.T) { if len(got) != len(want) { return false } - father, ok := c.Father().(*Main) + father, ok := c.Father().(MainContext) if !ok && len(got) != 0 { t.Errorf("father context is not main context") return false @@ -635,21 +654,24 @@ func TestConfig_includeConfig(t *testing.T) { func TestConfig_isInGraph(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) nilGraphConfig := NewContext(context_type.TypeConfig, "nilgraph").(*Config) nilGraphConfig.ConfigPath, _ = newConfigPath(testMain, nilGraphConfig.Value()) @@ -663,7 +685,7 @@ func TestConfig_isInGraph(t *testing.T) { inGraphConfig := NewContext(context_type.TypeConfig, "ingraph").(*Config) inGraphConfig.ConfigPath, _ = newConfigPath(testMain, inGraphConfig.Value()) inGraphConfig.SetFather(testMain) - err := inGraphConfig.Father().(*Main).AddConfig(inGraphConfig) + err = inGraphConfig.Father().(MainContext).AddConfig(inGraphConfig) if err != nil { t.Fatal(err) } @@ -725,22 +747,25 @@ func TestConfig_isInGraph(t *testing.T) { func TestConfig_modifyPathInGraph(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig( + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "a.conf").(*Config), NewContext(context_type.TypeConfig, "b.conf").(*Config), ) @@ -816,22 +841,25 @@ func TestConfig_modifyPathInGraph(t *testing.T) { func TestConfig_removeIncludedConfig(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig( + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "C:\\test\\existing.conf").(*Config), NewContext(context_type.TypeConfig, "a.conf").(*Config), NewContext(context_type.TypeConfig, "b.conf").(*Config), @@ -849,7 +877,7 @@ func TestConfig_removeIncludedConfig(t *testing.T) { } // different main config - diffTestMain := NewContext(context_type.TypeMain, "C:\\test2\\nginx.conf").(*Main) + diffTestMain, _ := NewMain("C:\\test2\\nginx.conf") // different graph config diffGraphConfig := NewContext(context_type.TypeConfig, "C:\\test\\test2.conf").(*Config) _, err = diffTestMain.MainConfig().includeConfig(diffGraphConfig) @@ -952,22 +980,25 @@ func TestConfig_removeIncludedConfig(t *testing.T) { func Test_configGraph_AddConfig(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) if err != nil { t.Fatal(err) } @@ -989,19 +1020,19 @@ func Test_configGraph_AddConfig(t *testing.T) { }{ { name: "add nil config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{config: nil}, wantErr: true, }, { name: "add an already exist config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{config: aConfig}, wantErr: true, }, { name: "normal test", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{config: bConfig}, wantErr: false, }, @@ -1018,22 +1049,25 @@ func Test_configGraph_AddConfig(t *testing.T) { func Test_configGraph_AddEdge(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig( + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "a.conf").(*Config), NewContext(context_type.TypeConfig, "b.conf").(*Config), ) @@ -1049,7 +1083,7 @@ func Test_configGraph_AddEdge(t *testing.T) { t.Fatal(err) } - otherMain := NewContext(context_type.TypeMain, "C:\\test1\\nginx.conf").(*Main) + otherMain, _ := NewMain("C:\\test1\\nginx.conf") _, err = otherMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "other.conf").(*Config), ) @@ -1079,7 +1113,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }{ { name: "nil source config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: nil, dst: aConfig, @@ -1088,7 +1122,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "nil destination config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: aConfig, dst: nil, @@ -1097,7 +1131,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "source config with null config path", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: nullpathConfig, dst: aConfig, @@ -1106,7 +1140,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "destination config with null config path", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: aConfig, dst: nullpathConfig, @@ -1115,7 +1149,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "source config is exclude from the graph", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: excludeConfig, dst: aConfig, @@ -1124,7 +1158,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "destination config is exclude from the graph", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: aConfig, dst: excludeConfig, @@ -1133,7 +1167,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "source config is in the other graph", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: inOtherGraphConfig, dst: aConfig, @@ -1142,7 +1176,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "destination config is in the other graph", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: aConfig, dst: inOtherGraphConfig, @@ -1151,7 +1185,7 @@ func Test_configGraph_AddEdge(t *testing.T) { }, { name: "normal test", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: aConfig, dst: bConfig, @@ -1171,22 +1205,25 @@ func Test_configGraph_AddEdge(t *testing.T) { func Test_configGraph_GetConfig(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig( + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "a.conf").(*Config), ) if err != nil { @@ -1208,14 +1245,14 @@ func Test_configGraph_GetConfig(t *testing.T) { }{ { name: "wrong config path", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{fullpath: "wrong/config/path.conf"}, want: nil, wantErr: true, }, { name: "normal test", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{fullpath: "C:\\test\\a.conf"}, want: aConfig, wantErr: false, @@ -1263,21 +1300,24 @@ func Test_configGraph_MainConfig(t *testing.T) { func Test_configGraph_RemoveEdge(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) a, _ := testMain.GetConfig("C:\\test\\a.conf") a.includeConfig(NewContext(context_type.TypeConfig, "b.conf").(*Config)) @@ -1297,7 +1337,7 @@ func Test_configGraph_RemoveEdge(t *testing.T) { }{ { name: "removed edge not found", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: b, dst: notInGraphConfig, @@ -1306,7 +1346,7 @@ func Test_configGraph_RemoveEdge(t *testing.T) { }, { name: "destination has edge", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: a, dst: b, @@ -1315,7 +1355,7 @@ func Test_configGraph_RemoveEdge(t *testing.T) { }, { name: "remove edge and destination", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{ src: b, dst: c, @@ -1335,22 +1375,25 @@ func Test_configGraph_RemoveEdge(t *testing.T) { func Test_configGraph_RenewConfigPath(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) - _, err := testMain.MainConfig().includeConfig( + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) + _, err = testMain.MainConfig().includeConfig( NewContext(context_type.TypeConfig, "a.conf").(*Config), NewContext(context_type.TypeConfig, "2exist.conf").(*Config), NewContext(context_type.TypeConfig, "inedge.conf").(*Config), @@ -1396,25 +1439,25 @@ func Test_configGraph_RenewConfigPath(t *testing.T) { }{ { name: "not exist config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{fullpath: "notexist.conf"}, wantErr: true, }, { name: "need not renew config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{fullpath: configHash(testMain.MainConfig())}, wantErr: false, }, { name: "renew to exist config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{fullpath: "C:\\test\\2exist.conf"}, wantErr: true, }, { name: "normal test", - fields: testMain.ConfigGraph, + fields: testMain.graph(), args: args{fullpath: "C:\\test\\test.conf"}, wantErr: false, }, @@ -1431,21 +1474,24 @@ func Test_configGraph_RenewConfigPath(t *testing.T) { func Test_configGraph_Topology(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) a, _ := testMain.GetConfig("C:\\test\\a.conf") a.includeConfig(NewContext(context_type.TypeConfig, "b.conf").(*Config)) @@ -1456,7 +1502,7 @@ func Test_configGraph_Topology(t *testing.T) { d, _ := testMain.GetConfig("C:\\test\\d.conf") e := NewContext(context_type.TypeConfig, "e.conf").(*Config) e.ConfigPath, _ = newConfigPath(testMain, e.Value()) - err := testMain.AddConfig(e) + err = testMain.AddConfig(e) if err != nil { t.Fatal(err) } @@ -1476,7 +1522,7 @@ func Test_configGraph_Topology(t *testing.T) { }{ { name: "generate only one tree starting from the main config", - fields: testMain.ConfigGraph, + fields: testMain.graph(), want: []*Config{testMain.MainConfig(), a, b, c, d}, }, } @@ -1492,21 +1538,24 @@ func Test_configGraph_Topology(t *testing.T) { func Test_configGraph_removeConfig(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) a, _ := testMain.GetConfig("C:\\test\\a.conf") a.includeConfig(NewContext(context_type.TypeConfig, "b.conf").(*Config)) @@ -1515,7 +1564,7 @@ func Test_configGraph_removeConfig(t *testing.T) { c, _ := testMain.GetConfig("C:\\test\\c.conf") c.includeConfig(NewContext(context_type.TypeConfig, "d.conf").(*Config)) d, _ := testMain.GetConfig("C:\\test\\d.conf") - err := testMain.ConfigGraph.(*configGraph).graph.RemoveEdge(configHash(c), configHash(d)) + err = testMain.graph().(*configGraph).graph.RemoveEdge(configHash(c), configHash(d)) if err != nil { t.Fatal(err) } @@ -1544,19 +1593,19 @@ func Test_configGraph_removeConfig(t *testing.T) { }{ { name: "normal test", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{d}, wantErr: false, }, { name: "config has no in edge but out edges", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{e}, wantErr: true, }, { name: "config has edges", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{a}, wantErr: true, }, @@ -1573,26 +1622,29 @@ func Test_configGraph_removeConfig(t *testing.T) { func Test_configGraph_setFatherFor(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) testMain.MainConfig().includeConfig(NewContext(context_type.TypeConfig, "a.conf").(*Config)) a, _ := testMain.GetConfig("C:\\test\\a.conf") - diffMain := NewContext(context_type.TypeMain, "C:\\test2\\nginx.conf").(*Main) + diffMain, _ := NewMain("C:\\test2\\nginx.conf") diffGraphConfig := NewContext(context_type.TypeConfig, "different_graph.conf").(*Config) - _, err := diffMain.MainConfig().includeConfig(diffGraphConfig) + _, err = diffMain.MainConfig().includeConfig(diffGraphConfig) if err != nil { t.Fatal(err) } @@ -1607,30 +1659,30 @@ func Test_configGraph_setFatherFor(t *testing.T) { }{ { name: "nil config", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), wantErr: true, }, { name: "config in the other graph", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{diffGraphConfig}, wantErr: true, }, { name: "config clone", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{a.Clone().(*Config)}, wantErr: false, }, { name: "same graph config", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{a}, wantErr: false, }, { name: "new config", - fields: testMain.ConfigGraph.(*configGraph), + fields: testMain.graph().(*configGraph), args: args{NewContext(context_type.TypeConfig, "new.conf").(*Config)}, wantErr: false, }, @@ -1647,21 +1699,24 @@ func Test_configGraph_setFatherFor(t *testing.T) { func Test_configHash(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf "). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ), + 0, + ) type args struct { t *Config } @@ -1696,8 +1751,11 @@ func Test_configHash(t *testing.T) { func Test_newConfigPath(t *testing.T) { // main config - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) - relPathMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + relPathMain, _ := NewMain("C:\\test\\nginx.conf") relPathMain.MainConfig().ConfigPath = &context.RelConfigPath{} absCP, _ := context.NewAbsConfigPath("D:\\test\\test.conf") relCP, _ := context.NewRelConfigPath(testMain.MainConfig().ConfigPath.BaseDir(), "relative.conf") @@ -1722,7 +1780,7 @@ func Test_newConfigPath(t *testing.T) { { name: "null new config path", args: args{ - configgraph: relPathMain.ConfigGraph, + configgraph: relPathMain.graph(), newconfigpath: "", }, wantErr: true, @@ -1730,7 +1788,7 @@ func Test_newConfigPath(t *testing.T) { { name: "config paths are relative path in graph's main config and input", args: args{ - configgraph: relPathMain.ConfigGraph, + configgraph: relPathMain.graph(), newconfigpath: "test.config", }, wantErr: true, @@ -1738,7 +1796,7 @@ func Test_newConfigPath(t *testing.T) { { name: "absolut path", args: args{ - configgraph: testMain.ConfigGraph, + configgraph: testMain.graph(), newconfigpath: "D:\\test\\test.conf", }, want: absCP, @@ -1746,7 +1804,7 @@ func Test_newConfigPath(t *testing.T) { { name: "relative path", args: args{ - configgraph: testMain.ConfigGraph, + configgraph: testMain.graph(), newconfigpath: "relative.conf", }, want: relCP, @@ -1766,68 +1824,6 @@ func Test_newConfigPath(t *testing.T) { } } -func Test_newMain(t *testing.T) { - confpath, err := context.NewAbsConfigPath("C:\\test\\nginx.conf") - if err != nil { - t.Fatal(err) - } - testMainConfig := &Config{ - BasicContext: newBasicContext(context_type.TypeConfig, nullHeadString, nullTailString), - ConfigPath: confpath, - } - testMainConfig.self = testMainConfig - testMainConfig.ContextValue = "C:\\test\\nginx.conf" - mg, err := newConfigGraph(testMainConfig) - if err != nil { - t.Fatal(err) - } - testMain := &Main{mg} - testMain.MainConfig().father = testMain - type args struct { - abspath string - } - tests := []struct { - name string - args args - want *Main - wantErr bool - }{ - { - name: "not a absolute path", - args: args{abspath: "not/absolute/path"}, - want: nil, - wantErr: true, - }, - { - name: "normal test", - args: args{abspath: "C:\\test\\nginx.conf"}, - want: testMain, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := newMain(tt.args.abspath) - if (err != nil) != tt.wantErr { - t.Errorf("newMain() error = %v, wantErr %v", err, tt.wantErr) - return - } - isSameFather := func(got, want *Config) bool { - return got.father.Type() == want.father.Type() && got.father.Value() == want.father.Value() - } - if (got == nil) != (tt.want == nil) || - (got != nil && - (!reflect.DeepEqual(got.MainConfig().ConfigPath, tt.want.MainConfig().ConfigPath) || - !reflect.DeepEqual(got.MainConfig().BasicContext.ContextValue, tt.want.MainConfig().BasicContext.ContextValue) || - !reflect.DeepEqual(got.MainConfig().BasicContext.ContextType, tt.want.MainConfig().BasicContext.ContextType) || - !reflect.DeepEqual(got.MainConfig().BasicContext.Children, tt.want.MainConfig().BasicContext.Children) || - !isSameFather(got.MainConfig(), tt.want.MainConfig()))) { - t.Errorf("newMain() got = %v, want %v", got, tt.want) - } - }) - } -} - func Test_registerConfigBuilder(t *testing.T) { tests := []struct { name string @@ -1845,14 +1841,17 @@ func Test_registerConfigBuilder(t *testing.T) { } func Test_newConfigGraph(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } cloneMain := testMain.Clone().(*Main) cloneMain.MainConfig().ConfigPath = nil cloneMain.ConfigGraph = &configGraph{mainConfig: cloneMain.MainConfig()} newMainConf := NewContext(context_type.TypeConfig, "C:\\test\\newmain.conf").(*Config) newMainConf.ConfigPath, _ = context.NewAbsConfigPath(newMainConf.Value()) newGraph := graph.New(configHash, graph.PreventCycles(), graph.Directed()) - err := newGraph.AddVertex(newMainConf) + err = newGraph.AddVertex(newMainConf) if err != nil { t.Fatal(err) } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/context.go b/pkg/resolv/V3/nginx/configuration/context/local/context.go index 399bc25..7defea8 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/context.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/context.go @@ -1,7 +1,6 @@ package local import ( - "encoding/json" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" "github.com/marmotedu/errors" @@ -120,139 +119,6 @@ func buildHeadAndTailStringFuncs(options context.BuildOptions) (func(context_typ return head, tail } -type Main struct { - ConfigGraph -} - -func (m *Main) MarshalJSON() ([]byte, error) { - if m.ConfigGraph == nil || m.ConfigGraph.MainConfig() == nil || !m.ConfigGraph.MainConfig().isInGraph() { - return nil, errors.New("Main Context is not completed") - } - marshalCtx := struct { - MainConfig string `json:"main-config"` - Configs map[string]*Config `json:"configs"` - }{ - MainConfig: m.MainConfig().Value(), - Configs: make(map[string]*Config), - } - - for _, config := range m.ConfigGraph.Topology() { - marshalCtx.Configs[config.Value()] = config - } - - return json.Marshal(marshalCtx) -} - -func (m *Main) Father() context.Context { - return m -} - -func (m *Main) Child(idx int) context.Context { - return m.MainConfig().Child(idx) -} - -func (m *Main) SetValue(v string) error { - if len(m.Topology()) > 1 { - return errors.New("cannot set value for Main Context with non empty graph") - } - return m.MainConfig().SetValue(v) -} - -func (m *Main) SetFather(ctx context.Context) error { - return errors.New("cannot set father for Main Context") -} - -func (m *Main) HasChild() bool { - return m.MainConfig().HasChild() -} - -func (m *Main) Len() int { - return m.MainConfig().Len() -} - -func (m *Main) Value() string { - return m.MainConfig().Value() -} - -func (m *Main) Error() error { - return nil -} - -func (m *Main) ConfigLines(isDumping bool) ([]string, error) { - return m.MainConfig().ConfigLines(isDumping) -} - -func (m *Main) Insert(ctx context.Context, idx int) context.Context { - if got := m.MainConfig().Insert(ctx, idx); got == m.MainConfig().self { - return m - } else { - return got - } -} - -func (m *Main) Remove(idx int) context.Context { - if got := m.MainConfig().Remove(idx); got == m.MainConfig().self { - return m - } else { - return got - } -} - -func (m *Main) Modify(ctx context.Context, idx int) context.Context { - if got := m.MainConfig().Modify(ctx, idx); got == m.MainConfig().self { - return m - } else { - return got - } -} - -func (m *Main) QueryByKeyWords(kw context.KeyWords) context.Pos { - gotPos := m.MainConfig().QueryByKeyWords(kw) - if got, idx := gotPos.Position(); got == m.MainConfig().self { - return context.SetPos(m, idx) - } - return gotPos -} - -func (m *Main) QueryAllByKeyWords(kw context.KeyWords) []context.Pos { - gotPoses := m.MainConfig().QueryAllByKeyWords(kw) - for i, pos := range gotPoses { - if got, idx := pos.Position(); got == m.MainConfig().self { - gotPoses[i] = context.SetPos(m, idx) - } - } - return gotPoses -} - -func (m *Main) Clone() context.Context { - cloneConfigPath, err := context.NewAbsConfigPath(m.Value()) - if err != nil { - return context.ErrContext(err) - } - cloneConfig := m.MainConfig().Clone().(*Config) - cloneConfig.ConfigPath = cloneConfigPath - g, err := newConfigGraph(cloneConfig) - if err != nil { - return context.ErrContext(err) - } - return &Main{ConfigGraph: g} -} - -func (m *Main) Type() context_type.ContextType { - return context_type.TypeMain -} - -func registerMainBuilder() error { - builderMap[context_type.TypeMain] = func(value string) context.Context { - main, err := newMain(value) - if err != nil { - return context.ErrContext(err) - } - return main - } - return nil -} - type Events struct { BasicContext `json:"events"` } @@ -623,7 +489,6 @@ func registerContextBuilders() error { errs := make([]error, 0) errs = append(errs, registerConfigBuilder(), - registerMainBuilder(), registerIncludeBuild(), registerEventsBuilder(), registerGeoBuilder(), diff --git a/pkg/resolv/V3/nginx/configuration/context/local/context_test.go b/pkg/resolv/V3/nginx/configuration/context/local/context_test.go index 783ce2c..276805e 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/context_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/context_test.go @@ -1,10 +1,8 @@ package local import ( - "github.com/ClessLi/bifrost/internal/pkg/code" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" - "github.com/marmotedu/errors" "reflect" "testing" ) @@ -36,548 +34,6 @@ func TestBuildBasicContextConfig_BasicContext(t *testing.T) { } } -func TestMain_Child(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - type args struct { - idx int - } - tests := []struct { - name string - fields fields - args args - want context.Context - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.Child(tt.args.idx); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Child() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_Clone(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want context.Context - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.Clone(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Clone() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_ConfigLines(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - type args struct { - isDumping bool - } - tests := []struct { - name string - fields fields - args args - want []string - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - got, err := m.ConfigLines(tt.args.isDumping) - if (err != nil) != tt.wantErr { - t.Errorf("ConfigLines() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("ConfigLines() got = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_Error(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if err := m.Error(); (err != nil) != tt.wantErr { - t.Errorf("Error() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestMain_Father(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want context.Context - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.Father(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Father() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_HasChild(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.HasChild(); got != tt.want { - t.Errorf("HasChild() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_Insert(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf").(*Main) - type args struct { - ctx context.Context - idx int - } - tests := []struct { - name string - fields *Main - args args - want context.Context - }{ - { - name: "error context result", - fields: testMain, - args: args{ - ctx: nil, - idx: 0, - }, - want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), - }, - { - name: "return main context itself", - fields: testMain, - args: args{ - ctx: NewDirective("test", ""), - idx: 0, - }, - want: testMain, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := tt.fields - if got := m.Insert(tt.args.ctx, tt.args.idx); !reflect.DeepEqual(got, tt.want) { - if got.Type() != tt.want.Type() || (got.Type() == context_type.TypeErrContext && got.Error().Error() != tt.want.Error().Error()) { - t.Errorf("Insert() = %v, want %v", got, tt.want) - } - } - }) - } -} - -func TestMain_Len(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.Len(); got != tt.want { - t.Errorf("Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_MarshalJSON(t *testing.T) { - testIncludes := NewContext(context_type.TypeInclude, "conf.d\\include*conf").(*Include) - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ). - Insert(testIncludes, 2), - 1, - ), - 0, - ).(*Main) - var err error - location1conf := NewContext(context_type.TypeConfig, "conf.d\\include.location1.conf"). - Insert(NewContext(context_type.TypeLocation, "~ /test1"), 0).(*Config) - location1conf.ConfigPath, err = newConfigPath(testMain.ConfigGraph, location1conf.Value()) - if err != nil { - t.Fatal(err) - } - location2conf := NewContext(context_type.TypeConfig, "conf.d\\include.location2.conf"). - Insert(NewContext(context_type.TypeLocation, "^~ /test2"), 0).(*Config) - location2conf.ConfigPath, err = newConfigPath(testMain.ConfigGraph, location1conf.Value()) - if err != nil { - t.Fatal(err) - } - err = testIncludes.InsertConfig(location1conf, location2conf) - if err != nil { - t.Fatal(err) - } - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want []byte - wantErr bool - }{ - { - name: "empty main", - fields: fields{ConfigGraph: NewContext(context_type.TypeMain, "C:\\test\\test.conf").(*Main).ConfigGraph}, - want: []byte(`{"main-config":"C:\\test\\test.conf","configs":{"C:\\test\\test.conf":[]}}`), - wantErr: false, - }, - { - name: "normal test", - fields: fields{ConfigGraph: testMain.ConfigGraph}, - want: []byte( - `{"main-config":"C:\\test\\test.conf",` + - `"configs":{"C:\\test\\test.conf":[{` + - `"http":{"params":[{"comments":"test comment","inline":true},` + - `{"server":{"params":[{"directive":"server_name","params":"testserver"},` + - `{"location":{"value":"~ /test"}},` + - `{"include":{"value":"conf.d\\include*conf","params":["conf.d\\include.location1.conf","conf.d\\include.location2.conf"]}}` + - `]}}` + - `]}` + - `}],` + - `"conf.d\\include.location1.conf":[{"location":{"value":"~ /test1"}}],` + - `"conf.d\\include.location2.conf":[{"location":{"value":"^~ /test2"}}]` + - `}` + - `}`, - ), - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - got, err := m.MarshalJSON() - if (err != nil) != tt.wantErr { - t.Errorf("MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("MarshalJSON() got = %s, want %s", got, tt.want) - } - }) - } -} - -func TestMain_Modify(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf").(*Main) - type args struct { - ctx context.Context - idx int - } - tests := []struct { - name string - fields *Main - args args - want context.Context - }{ - { - name: "error context result", - fields: testMain, - args: args{ - ctx: nil, - idx: 0, - }, - want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), - }, - { - name: "return main context itself", - fields: testMain, - args: args{ - ctx: NewDirective("test", ""), - idx: 0, - }, - want: testMain, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := tt.fields - if got := m.Modify(tt.args.ctx, tt.args.idx); !reflect.DeepEqual(got, tt.want) { - if got.Type() != tt.want.Type() || (got.Type() == context_type.TypeErrContext && got.Error().Error() != tt.want.Error().Error()) { - t.Errorf("Modify() = %v, want %v", got, tt.want) - } - } - }) - } -} - -func TestMain_QueryAllByKeyWords(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - type args struct { - kw context.KeyWords - } - tests := []struct { - name string - fields fields - args args - want []context.Pos - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.QueryAllByKeyWords(tt.args.kw); !reflect.DeepEqual(got, tt.want) { - t.Errorf("QueryAllByKeyWords() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_QueryByKeyWords(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - type args struct { - kw context.KeyWords - } - tests := []struct { - name string - fields fields - args args - want context.Pos - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.QueryByKeyWords(tt.args.kw); !reflect.DeepEqual(got, tt.want) { - t.Errorf("QueryByKeyWords() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_Remove(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf").(*Main) - type args struct { - idx int - } - tests := []struct { - name string - fields *Main - args args - want context.Context - }{ - { - name: "error context result", - fields: testMain, - args: args{idx: -1}, - want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), - }, - { - name: "return main itself", - fields: testMain, - args: args{idx: 0}, - want: testMain, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := tt.fields - if got := m.Remove(tt.args.idx); !reflect.DeepEqual(got, tt.want) { - if got.Type() != tt.want.Type() || (got.Type() == context_type.TypeErrContext && got.Error().Error() != tt.want.Error().Error()) { - t.Errorf("Remove() = %v, want %v", got, tt.want) - } - } - }) - } -} - -func TestMain_SetFather(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - type args struct { - ctx context.Context - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if err := m.SetFather(tt.args.ctx); (err != nil) != tt.wantErr { - t.Errorf("SetFather() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestMain_SetValue(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - type args struct { - v string - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if err := m.SetValue(tt.args.v); (err != nil) != tt.wantErr { - t.Errorf("SetValue() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestMain_Type(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want context_type.ContextType - }{ - { - name: "main context type", - want: context_type.TypeMain, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.Type(); got != tt.want { - t.Errorf("Type() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMain_Value(t *testing.T) { - type fields struct { - ConfigGraph ConfigGraph - } - tests := []struct { - name string - fields fields - want string - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - m := &Main{ - ConfigGraph: tt.fields.ConfigGraph, - } - if got := m.Value(); got != tt.want { - t.Errorf("Value() = %v, want %v", got, tt.want) - } - }) - } -} - func TestNewContext(t *testing.T) { type args struct { contextType context_type.ContextType @@ -1002,22 +458,6 @@ func Test_registerLocationParseFunc(t *testing.T) { } } -func Test_registerMainBuilder(t *testing.T) { - tests := []struct { - name string - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := registerMainBuilder(); (err != nil) != tt.wantErr { - t.Errorf("registerMainBuilder() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - func Test_registerMapBuilder(t *testing.T) { tests := []struct { name string diff --git a/pkg/resolv/V3/nginx/configuration/context/local/include.go b/pkg/resolv/V3/nginx/configuration/context/local/include.go index f300b11..fa3e97d 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/include.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/include.go @@ -47,8 +47,6 @@ func (i *Include) FatherConfig() (*Config, error) { return nil, errors.WithCode(code.ErrV3InvalidContext, "found an Main context") } - if fatherCtx.Type() == context_type.TypeErrContext { - } fatherCtx = fatherCtx.Father() fatherConfig, ok = fatherCtx.(*Config) } @@ -69,7 +67,7 @@ func (i *Include) InsertConfig(configs ...*Config) error { if err != nil { return err } - fatherMain, ok := fatherConfig.Father().(*Main) + fatherMain, ok := fatherConfig.Father().(MainContext) if !ok { return errors.WithCode(code.ErrV3InvalidContext, "this include context is not bound to a main context") } @@ -81,7 +79,7 @@ func (i *Include) InsertConfig(configs ...*Config) error { } // match config path if config.ConfigPath == nil { - config.ConfigPath, err = newConfigPath(fatherMain.ConfigGraph, config.Value()) + config.ConfigPath, err = newConfigPath(fatherMain.graph(), config.Value()) if err != nil { return err } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/include_test.go b/pkg/resolv/V3/nginx/configuration/context/local/include_test.go index 2cfc7c6..9c1e7c7 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/include_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/include_test.go @@ -289,7 +289,10 @@ func TestInclude_Father(t *testing.T) { } func TestInclude_FatherConfig(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } testInclude := NewContext(context_type.TypeInclude, "*.conf").(*Include) testMain.Insert( NewContext(context_type.TypeHttp, ""). @@ -328,7 +331,7 @@ func TestInclude_FatherConfig(t *testing.T) { }, { name: "found a father main context", - fields: fields{fatherContext: NewContext(context_type.TypeMain, "C:\\test\\test.conf")}, + fields: fields{fatherContext: testMain}, want: nil, wantErr: true, }, @@ -423,7 +426,10 @@ func TestInclude_Insert(t *testing.T) { } func TestInclude_InsertConfig(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } testInclude := NewContext(context_type.TypeInclude, "*.conf").(*Include) testMain.Insert( NewContext(context_type.TypeHttp, ""). @@ -628,7 +634,10 @@ func TestInclude_Modify(t *testing.T) { } func TestInclude_ModifyConfig(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } testInclude := NewContext(context_type.TypeInclude, "*.conf").(*Include) testMain.Insert( NewContext(context_type.TypeHttp, ""). @@ -644,7 +653,7 @@ func TestInclude_ModifyConfig(t *testing.T) { absConfig.ConfigPath, _ = newConfigPath(testMain, absConfig.ContextValue) notMatchConfig := NewContext(context_type.TypeConfig, "test\\test.conf").(*Config) notMatchConfig.ConfigPath, _ = newConfigPath(testMain, notMatchConfig.ContextValue) - err := testInclude.InsertConfig(relConfig, absConfig) + err = testInclude.InsertConfig(relConfig, absConfig) if err != nil { t.Fatal(err) } @@ -759,7 +768,10 @@ func TestInclude_ModifyConfig(t *testing.T) { } func TestInclude_QueryAllByKeyWords(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } testInclude := NewContext(context_type.TypeInclude, "*.conf").(*Include) testMain.Insert( NewContext(context_type.TypeHttp, ""). @@ -773,7 +785,7 @@ func TestInclude_QueryAllByKeyWords(t *testing.T) { aConfig.ConfigPath, _ = newConfigPath(testMain, aConfig.ContextValue) bConfig := NewContext(context_type.TypeConfig, "C:\\test\\b.conf").(*Config) bConfig.ConfigPath, _ = newConfigPath(testMain, bConfig.ContextValue) - err := testInclude.InsertConfig(aConfig, bConfig) + err = testInclude.InsertConfig(aConfig, bConfig) if err != nil { t.Fatal(err) } @@ -812,7 +824,7 @@ func TestInclude_QueryAllByKeyWords(t *testing.T) { Configs: testInclude.Configs, fatherContext: testInclude.fatherContext, }, - args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue("test")}, + args: args{kw: context.NewKeyWords(context_type.TypeLocation).SetRegexpMatchingValue("test")}, want: []context.Pos{ context.SetPos(aFather, 0), context.SetPos(bFather, 1), @@ -834,7 +846,10 @@ func TestInclude_QueryAllByKeyWords(t *testing.T) { } func TestInclude_QueryByKeyWords(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } testInclude := NewContext(context_type.TypeInclude, "*.conf").(*Include) testMain.Insert( NewContext(context_type.TypeHttp, ""). @@ -848,7 +863,7 @@ func TestInclude_QueryByKeyWords(t *testing.T) { aConfig.ConfigPath, _ = newConfigPath(testMain, aConfig.ContextValue) bConfig := NewContext(context_type.TypeConfig, "C:\\test\\b.conf").(*Config) bConfig.ConfigPath, _ = newConfigPath(testMain, bConfig.ContextValue) - err := testInclude.InsertConfig(aConfig, bConfig) + err = testInclude.InsertConfig(aConfig, bConfig) if err != nil { t.Fatal(err) } @@ -940,7 +955,10 @@ func TestInclude_Remove(t *testing.T) { } func TestInclude_RemoveConfig(t *testing.T) { - testMain := NewContext(context_type.TypeMain, "C:\\test\\nginx.conf").(*Main) + testMain, err := NewMain("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } testInclude := NewContext(context_type.TypeInclude, "*.conf").(*Include) testMain.Insert( NewContext(context_type.TypeHttp, ""). @@ -956,7 +974,7 @@ func TestInclude_RemoveConfig(t *testing.T) { absConfig.ConfigPath, _ = newConfigPath(testMain, absConfig.ContextValue) notMatchConfig := NewContext(context_type.TypeConfig, "test\\test.conf").(*Config) notMatchConfig.ConfigPath, _ = newConfigPath(testMain, notMatchConfig.ContextValue) - err := testInclude.InsertConfig(relConfig, absConfig) + err = testInclude.InsertConfig(relConfig, absConfig) if err != nil { t.Fatal(err) } diff --git a/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler.go b/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler.go index dc0cce5..197358c 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler.go @@ -293,7 +293,7 @@ func registerUpstreamJsonUnmarshalerBuilder() error { type mainUnmarshaler struct { unmarshalContext *jsonUnmarshalMain - completedMain *Main + completedMain MainContext } func (m *mainUnmarshaler) UnmarshalJSON(bytes []byte) error { @@ -301,18 +301,14 @@ func (m *mainUnmarshaler) UnmarshalJSON(bytes []byte) error { if err != nil { return err } - mainCtx := NewContext(context_type.TypeMain, m.unmarshalContext.MainConfig) - if err = mainCtx.Error(); err != nil { + main, err := NewMain(m.unmarshalContext.MainConfig) + if err != nil { return err } - main, ok := mainCtx.(*Main) - if !ok { - return errors.New("failed to build main context") - } m.completedMain = main - toBeUnmarshalledConfigs := make(map[string]*jsonUnmarshalConfig, 0) + toBeUnmarshalledConfigs := make(map[string]*jsonUnmarshalConfig) for value, rawMessages := range m.unmarshalContext.Configs { var configHashString string if value != m.unmarshalContext.MainConfig { @@ -347,7 +343,7 @@ func (m *mainUnmarshaler) UnmarshalJSON(bytes []byte) error { } unmarshaler := &jsonUnmarshaler{ unmarshalContext: unmarshalConfig, - configGraph: m.completedMain.ConfigGraph, + configGraph: m.completedMain.graph(), completedContext: cache, } for _, childRaw := range unmarshaler.unmarshalContext.GetChildren() { diff --git a/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler_test.go b/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler_test.go index 80f5a99..27ce2eb 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/json_unmarshaler_test.go @@ -323,25 +323,27 @@ func Test_jsonUnmarshalDirective_Type(t *testing.T) { func Test_jsonUnmarshaler_UnmarshalJSON(t *testing.T) { testTargetFatherCtx := NewContext(context_type.TypeServer, "") - testMain := NewContext(context_type.TypeMain, "C:\\test\\test.conf"). - Insert( - NewContext(context_type.TypeHttp, ""). - Insert(NewComment("test comment", true), 0). - Insert( - NewContext(context_type.TypeServer, ""). - Insert(NewDirective("server_name", "testserver"), 0). - Insert( - NewContext(context_type.TypeLocation, "~ /test"), - 1, - ), - 1, - ). - Insert(testTargetFatherCtx, 2), - 0, - ).(*Main) + testMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ), + 1, + ). + Insert(testTargetFatherCtx, 2), + 0, + ) testIncludedConfig := NewContext(context_type.TypeConfig, "conf.d\\proxy.conf").(*Config) - var err error - testIncludedConfig.ConfigPath, err = newConfigPath(testMain.ConfigGraph, testIncludedConfig.Value()) + testIncludedConfig.ConfigPath, err = newConfigPath(testMain.graph(), testIncludedConfig.Value()) if err != nil { t.Fatal(err) } @@ -369,7 +371,7 @@ func Test_jsonUnmarshaler_UnmarshalJSON(t *testing.T) { name: "normal test", fields: fields{ unmarshalContext: &jsonUnmarshalLocation{jsonUnmarshalContext{contextType: context_type.TypeLocation}}, - configGraph: testMain.ConfigGraph, + configGraph: testMain.graph(), completedContext: context.NullContext(), fatherContext: testTargetFatherCtx, }, @@ -479,7 +481,7 @@ func Test_jsonUnmarshaler_unmarshalInclude(t *testing.T) { func Test_mainUnmarshaler_UnmarshalJSON(t *testing.T) { type fields struct { unmarshalContext *jsonUnmarshalMain - completedMain *Main + completedMain MainContext } type args struct { bytes []byte diff --git a/pkg/resolv/V3/nginx/configuration/context/local/loader.go b/pkg/resolv/V3/nginx/configuration/context/local/loader.go index 478a4a9..71f5492 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/loader.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/loader.go @@ -13,7 +13,7 @@ import ( ) type Loader interface { - Load() (*Main, error) + Load() (MainContext, error) } type parseFunc func(data []byte, idx *int) context.Context @@ -23,7 +23,7 @@ type jsonLoader struct { jsonBytes []byte } -func (j *jsonLoader) Load() (*Main, error) { +func (j *jsonLoader) Load() (MainContext, error) { err := json.Unmarshal(j.jsonBytes, j.unmarshaler) if err != nil { return nil, err @@ -44,23 +44,17 @@ type fileLoader struct { contextStack *contextStack } -func (f *fileLoader) Load() (*Main, error) { +func (f *fileLoader) Load() (MainContext, error) { if !filepath.IsAbs(f.mainConfigAbsPath) { return nil, errors.Errorf("%s is not a absolute path", f.mainConfigAbsPath) } - mainCtx := NewContext(context_type.TypeMain, f.mainConfigAbsPath) - err := mainCtx.Error() + main, err := NewMain(f.mainConfigAbsPath) if err != nil { return nil, err } - main, ok := mainCtx.(*Main) - if !ok { - return nil, errors.New("failed to build main context") - } - - f.configGraph = main.ConfigGraph + f.configGraph = main.graph() err = f.load(main.MainConfig()) diff --git a/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go b/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go index c13cd5f..ec47a48 100644 --- a/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go +++ b/pkg/resolv/V3/nginx/configuration/context/local/loader_test.go @@ -213,7 +213,10 @@ func Test_contextStack_push(t *testing.T) { } func Test_fileLoader_Load(t *testing.T) { - simpleMain := NewContext(context_type.TypeMain, filepath.Join(os.Getenv("GOPATH"), "src/bifrost", "test/config_test/simple_nginx.conf")).(*Main) + simpleMain, err := NewMain(filepath.Join(os.Getenv("GOPATH"), "src/bifrost", "test/config_test/simple_nginx.conf")) + if err != nil { + t.Fatal(err) + } simpleMain. Insert(NewComment("user nobody;", false), 0). Insert(NewDirective("worker_processes", "1"), 1). @@ -231,7 +234,7 @@ func Test_fileLoader_Load(t *testing.T) { tests := []struct { name string fields fields - want *Main + want MainContext wantErr bool }{ { @@ -302,7 +305,10 @@ func Test_fileLoader_load(t *testing.T) { if err != nil { t.Fatal(err) } - includeMain := NewContext(context_type.TypeMain, filepath.Join(os.Getenv("GOPATH"), "src/bifrost", "test/config_test/include_nginx.conf")).(*Main) + includeMain, err := NewMain(filepath.Join(os.Getenv("GOPATH"), "src/bifrost", "test/config_test/include_nginx.conf")) + if err != nil { + t.Fatal(err) + } type fields struct { mainConfigAbsPath string configGraph ConfigGraph @@ -366,7 +372,10 @@ func Test_fileLoader_load(t *testing.T) { } func Test_fileLoader_loadInclude(t *testing.T) { - simpleMain := NewContext(context_type.TypeMain, filepath.Join(os.Getenv("GOPATH"), "src/bifrost", "test/config_test/simple_nginx.conf")).(*Main) + simpleMain, err := NewMain(filepath.Join(os.Getenv("GOPATH"), "src/bifrost", "test/config_test/simple_nginx.conf")) + if err != nil { + t.Fatal(err) + } type fields struct { mainConfigAbsPath string configGraph ConfigGraph @@ -396,7 +405,7 @@ func Test_fileLoader_loadInclude(t *testing.T) { name: "absolute path include", fields: fields{ mainConfigAbsPath: simpleMain.Value(), - configGraph: simpleMain.ConfigGraph, + configGraph: simpleMain.graph(), contextStack: newContextStack(), }, args: args{include: absPathInclude}, @@ -406,7 +415,7 @@ func Test_fileLoader_loadInclude(t *testing.T) { name: "relative path include", fields: fields{ mainConfigAbsPath: simpleMain.Value(), - configGraph: simpleMain.ConfigGraph, + configGraph: simpleMain.graph(), contextStack: newContextStack(), }, args: args{include: relPathInclude}, @@ -416,7 +425,7 @@ func Test_fileLoader_loadInclude(t *testing.T) { name: "no match absolute path include", fields: fields{ mainConfigAbsPath: simpleMain.Value(), - configGraph: simpleMain.ConfigGraph, + configGraph: simpleMain.graph(), contextStack: newContextStack(), }, args: args{include: NewContext(context_type.TypeInclude, noMatchAbsPath).(*Include)}, @@ -426,7 +435,7 @@ func Test_fileLoader_loadInclude(t *testing.T) { name: "no match relative path include", fields: fields{ mainConfigAbsPath: simpleMain.Value(), - configGraph: simpleMain.ConfigGraph, + configGraph: simpleMain.graph(), contextStack: newContextStack(), }, args: args{include: NewContext(context_type.TypeInclude, noMatchRelPath).(*Include)}, @@ -436,7 +445,7 @@ func Test_fileLoader_loadInclude(t *testing.T) { name: "cycle include", fields: fields{ mainConfigAbsPath: simpleMain.Value(), - configGraph: simpleMain.ConfigGraph, + configGraph: simpleMain.graph(), contextStack: newContextStack(), }, args: args{include: cycleInclude}, @@ -465,7 +474,7 @@ func Test_jsonLoader_Load(t *testing.T) { tests := []struct { name string fields fields - want *Main + want MainContext wantErr bool }{ // TODO: Add test cases. diff --git a/pkg/resolv/V3/nginx/configuration/context/local/main_context.go b/pkg/resolv/V3/nginx/configuration/context/local/main_context.go new file mode 100644 index 0000000..86633a3 --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/context/local/main_context.go @@ -0,0 +1,161 @@ +package local + +import ( + "encoding/json" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" + "github.com/marmotedu/errors" +) + +type MainContext interface { + context.Context + ConfigGraph + + graph() ConfigGraph +} + +type Main struct { + ConfigGraph +} + +func (m *Main) graph() ConfigGraph { + return m.ConfigGraph +} + +func (m *Main) MarshalJSON() ([]byte, error) { + if m.ConfigGraph == nil || m.ConfigGraph.MainConfig() == nil || !m.ConfigGraph.MainConfig().isInGraph() { + return nil, errors.New("MainContext is not completed") + } + marshalCtx := struct { + MainConfig string `json:"main-config"` + Configs map[string]*Config `json:"configs"` + }{ + MainConfig: m.MainConfig().Value(), + Configs: make(map[string]*Config), + } + + for _, config := range m.ConfigGraph.Topology() { + marshalCtx.Configs[config.Value()] = config + } + + return json.Marshal(marshalCtx) +} + +func (m *Main) Father() context.Context { + return m +} + +func (m *Main) Child(idx int) context.Context { + return m.MainConfig().Child(idx) +} + +func (m *Main) SetValue(v string) error { + if len(m.Topology()) > 1 { + return errors.New("cannot set value for MainContext with non empty graph") + } + return m.MainConfig().SetValue(v) +} + +func (m *Main) SetFather(ctx context.Context) error { + return errors.New("cannot set father for MainContext") +} + +func (m *Main) HasChild() bool { + return m.MainConfig().HasChild() +} + +func (m *Main) Len() int { + return m.MainConfig().Len() +} + +func (m *Main) Value() string { + return m.MainConfig().Value() +} + +func (m *Main) Error() error { + return nil +} + +func (m *Main) ConfigLines(isDumping bool) ([]string, error) { + return m.MainConfig().ConfigLines(isDumping) +} + +func (m *Main) Insert(ctx context.Context, idx int) context.Context { + if got := m.MainConfig().Insert(ctx, idx); got == m.MainConfig().self { + return m + } else { + return got + } +} + +func (m *Main) Remove(idx int) context.Context { + if got := m.MainConfig().Remove(idx); got == m.MainConfig().self { + return m + } else { + return got + } +} + +func (m *Main) Modify(ctx context.Context, idx int) context.Context { + if got := m.MainConfig().Modify(ctx, idx); got == m.MainConfig().self { + return m + } else { + return got + } +} + +func (m *Main) QueryByKeyWords(kw context.KeyWords) context.Pos { + gotPos := m.MainConfig().QueryByKeyWords(kw) + if got, idx := gotPos.Position(); got == m.MainConfig().self { + return context.SetPos(m, idx) + } + return gotPos +} + +func (m *Main) QueryAllByKeyWords(kw context.KeyWords) []context.Pos { + gotPoses := m.MainConfig().QueryAllByKeyWords(kw) + for i, pos := range gotPoses { + if got, idx := pos.Position(); got == m.MainConfig().self { + gotPoses[i] = context.SetPos(m, idx) + } + } + return gotPoses +} + +func (m *Main) Clone() context.Context { + cloneConfigPath, err := context.NewAbsConfigPath(m.Value()) + if err != nil { + return context.ErrContext(err) + } + cloneConfig := m.MainConfig().Clone().(*Config) + cloneConfig.ConfigPath = cloneConfigPath + g, err := newConfigGraph(cloneConfig) + if err != nil { + return context.ErrContext(err) + } + return &Main{ConfigGraph: g} +} + +func NewMain(abspath string) (MainContext, error) { + confpath, err := context.NewAbsConfigPath(abspath) + if err != nil { + return nil, err + } + config := &Config{ + BasicContext: newBasicContext(context_type.TypeConfig, nullHeadString, nullTailString), + ConfigPath: confpath, + } + config.self = config + config.ContextValue = abspath + g, err := newConfigGraph(config) + if err != nil { // Temporarily unable to be covered for testing + return nil, err + } + m := &Main{ConfigGraph: g} + m.MainConfig().father = m + return m, nil +} + +func (m *Main) Type() context_type.ContextType { + return context_type.TypeMain +} diff --git a/pkg/resolv/V3/nginx/configuration/context/local/main_context_test.go b/pkg/resolv/V3/nginx/configuration/context/local/main_context_test.go new file mode 100644 index 0000000..c0a7d20 --- /dev/null +++ b/pkg/resolv/V3/nginx/configuration/context/local/main_context_test.go @@ -0,0 +1,629 @@ +package local + +import ( + "github.com/ClessLi/bifrost/internal/pkg/code" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" + "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" + "github.com/marmotedu/errors" + "reflect" + "testing" +) + +func TestMain_Child(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + type args struct { + idx int + } + tests := []struct { + name string + fields fields + args args + want context.Context + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.Child(tt.args.idx); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Child() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_Clone(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want context.Context + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.Clone(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Clone() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_ConfigLines(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + type args struct { + isDumping bool + } + tests := []struct { + name string + fields fields + args args + want []string + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + got, err := m.ConfigLines(tt.args.isDumping) + if (err != nil) != tt.wantErr { + t.Errorf("ConfigLines() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ConfigLines() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_Error(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if err := m.Error(); (err != nil) != tt.wantErr { + t.Errorf("Error() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestMain_Father(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want context.Context + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.Father(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Father() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_HasChild(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.HasChild(); got != tt.want { + t.Errorf("HasChild() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_Insert(t *testing.T) { + testMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } + type args struct { + ctx context.Context + idx int + } + tests := []struct { + name string + fields MainContext + args args + want context.Context + }{ + { + name: "error context result", + fields: testMain, + args: args{ + ctx: nil, + idx: 0, + }, + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), + }, + { + name: "return main context itself", + fields: testMain, + args: args{ + ctx: NewDirective("test", ""), + idx: 0, + }, + want: testMain, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := tt.fields + if got := m.Insert(tt.args.ctx, tt.args.idx); !reflect.DeepEqual(got, tt.want) { + if got.Type() != tt.want.Type() || (got.Type() == context_type.TypeErrContext && got.Error().Error() != tt.want.Error().Error()) { + t.Errorf("Insert() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestMain_Len(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.Len(); got != tt.want { + t.Errorf("Len() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_MarshalJSON(t *testing.T) { + testIncludes := NewContext(context_type.TypeInclude, "conf.d\\include*conf").(*Include) + emptyMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } + testMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } + testMain.Insert( + NewContext(context_type.TypeHttp, ""). + Insert(NewComment("test comment", true), 0). + Insert( + NewContext(context_type.TypeServer, ""). + Insert(NewDirective("server_name", "testserver"), 0). + Insert( + NewContext(context_type.TypeLocation, "~ /test"), + 1, + ). + Insert(testIncludes, 2), + 1, + ), + 0, + ) + location1conf := NewContext(context_type.TypeConfig, "conf.d\\include.location1.conf"). + Insert(NewContext(context_type.TypeLocation, "~ /test1"), 0).(*Config) + location1conf.ConfigPath, err = newConfigPath(testMain.graph(), location1conf.Value()) + if err != nil { + t.Fatal(err) + } + location2conf := NewContext(context_type.TypeConfig, "conf.d\\include.location2.conf"). + Insert(NewContext(context_type.TypeLocation, "^~ /test2"), 0).(*Config) + location2conf.ConfigPath, err = newConfigPath(testMain.graph(), location1conf.Value()) + if err != nil { + t.Fatal(err) + } + err = testIncludes.InsertConfig(location1conf, location2conf) + if err != nil { + t.Fatal(err) + } + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want []byte + wantErr bool + }{ + { + name: "empty main", + fields: fields{ConfigGraph: emptyMain.graph()}, + want: []byte(`{"main-config":"C:\\test\\test.conf","configs":{"C:\\test\\test.conf":[]}}`), + wantErr: false, + }, + { + name: "normal test", + fields: fields{ConfigGraph: testMain.graph()}, + want: []byte( + `{"main-config":"C:\\test\\test.conf",` + + `"configs":{"C:\\test\\test.conf":[{` + + `"http":{"params":[{"comments":"test comment","inline":true},` + + `{"server":{"params":[{"directive":"server_name","params":"testserver"},` + + `{"location":{"value":"~ /test"}},` + + `{"include":{"value":"conf.d\\include*conf","params":["conf.d\\include.location1.conf","conf.d\\include.location2.conf"]}}` + + `]}}` + + `]}` + + `}],` + + `"conf.d\\include.location1.conf":[{"location":{"value":"~ /test1"}}],` + + `"conf.d\\include.location2.conf":[{"location":{"value":"^~ /test2"}}]` + + `}` + + `}`, + ), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + got, err := m.MarshalJSON() + if (err != nil) != tt.wantErr { + t.Errorf("MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("MarshalJSON() got = %s, want %s", got, tt.want) + } + }) + } +} + +func TestMain_Modify(t *testing.T) { + testMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } + type args struct { + ctx context.Context + idx int + } + tests := []struct { + name string + fields MainContext + args args + want context.Context + }{ + { + name: "error context result", + fields: testMain, + args: args{ + ctx: nil, + idx: 0, + }, + want: context.ErrContext(errors.WithCode(code.ErrV3InvalidOperation, "refuse to insert nil")), + }, + { + name: "return main context itself", + fields: testMain, + args: args{ + ctx: NewDirective("test", ""), + idx: 0, + }, + want: testMain, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := tt.fields + if got := m.Modify(tt.args.ctx, tt.args.idx); !reflect.DeepEqual(got, tt.want) { + if got.Type() != tt.want.Type() || (got.Type() == context_type.TypeErrContext && got.Error().Error() != tt.want.Error().Error()) { + t.Errorf("Modify() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestMain_QueryAllByKeyWords(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + type args struct { + kw context.KeyWords + } + tests := []struct { + name string + fields fields + args args + want []context.Pos + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.QueryAllByKeyWords(tt.args.kw); !reflect.DeepEqual(got, tt.want) { + t.Errorf("QueryAllByKeyWords() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_QueryByKeyWords(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + type args struct { + kw context.KeyWords + } + tests := []struct { + name string + fields fields + args args + want context.Pos + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.QueryByKeyWords(tt.args.kw); !reflect.DeepEqual(got, tt.want) { + t.Errorf("QueryByKeyWords() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_Remove(t *testing.T) { + testMain, err := NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } + type args struct { + idx int + } + tests := []struct { + name string + fields MainContext + args args + want context.Context + }{ + { + name: "error context result", + fields: testMain, + args: args{idx: -1}, + want: context.ErrContext(errors.WithCode(code.ErrV3ContextIndexOutOfRange, "index(%d) out of range", -1)), + }, + { + name: "return main itself", + fields: testMain, + args: args{idx: 0}, + want: testMain, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := tt.fields + if got := m.Remove(tt.args.idx); !reflect.DeepEqual(got, tt.want) { + if got.Type() != tt.want.Type() || (got.Type() == context_type.TypeErrContext && got.Error().Error() != tt.want.Error().Error()) { + t.Errorf("Remove() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestMain_SetFather(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + type args struct { + ctx context.Context + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if err := m.SetFather(tt.args.ctx); (err != nil) != tt.wantErr { + t.Errorf("SetFather() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestMain_SetValue(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + type args struct { + v string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if err := m.SetValue(tt.args.v); (err != nil) != tt.wantErr { + t.Errorf("SetValue() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestMain_Type(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want context_type.ContextType + }{ + { + name: "main context type", + want: context_type.TypeMain, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.Type(); got != tt.want { + t.Errorf("Type() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMain_Value(t *testing.T) { + type fields struct { + ConfigGraph ConfigGraph + } + tests := []struct { + name string + fields fields + want string + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Main{ + ConfigGraph: tt.fields.ConfigGraph, + } + if got := m.Value(); got != tt.want { + t.Errorf("Value() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_NewMain(t *testing.T) { + confpath, err := context.NewAbsConfigPath("C:\\test\\nginx.conf") + if err != nil { + t.Fatal(err) + } + testMainConfig := &Config{ + BasicContext: newBasicContext(context_type.TypeConfig, nullHeadString, nullTailString), + ConfigPath: confpath, + } + testMainConfig.self = testMainConfig + testMainConfig.ContextValue = "C:\\test\\nginx.conf" + mg, err := newConfigGraph(testMainConfig) + if err != nil { + t.Fatal(err) + } + testMain := &Main{mg} + testMain.MainConfig().father = testMain + type args struct { + abspath string + } + tests := []struct { + name string + args args + want MainContext + wantErr bool + }{ + { + name: "not a absolute path", + args: args{abspath: "not/absolute/path"}, + want: nil, + wantErr: true, + }, + { + name: "normal test", + args: args{abspath: "C:\\test\\nginx.conf"}, + want: testMain, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewMain(tt.args.abspath) + if (err != nil) != tt.wantErr { + t.Errorf("NewMain() error = %v, wantErr %v", err, tt.wantErr) + return + } + isSameFather := func(got, want *Config) bool { + return got.father.Type() == want.father.Type() && got.father.Value() == want.father.Value() + } + if (got == nil) != (tt.want == nil) || + (got != nil && + (!reflect.DeepEqual(got.MainConfig().ConfigPath, tt.want.MainConfig().ConfigPath) || + !reflect.DeepEqual(got.MainConfig().BasicContext.ContextValue, tt.want.MainConfig().BasicContext.ContextValue) || + !reflect.DeepEqual(got.MainConfig().BasicContext.ContextType, tt.want.MainConfig().BasicContext.ContextType) || + !reflect.DeepEqual(got.MainConfig().BasicContext.Children, tt.want.MainConfig().BasicContext.Children) || + !isSameFather(got.MainConfig(), tt.want.MainConfig()))) { + t.Errorf("NewMain() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config.go b/pkg/resolv/V3/nginx/configuration/nginx_config.go index 2f2cf2a..f28cacc 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "github.com/ClessLi/bifrost/internal/pkg/code" - "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" utilsV3 "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/utils" logV1 "github.com/ClessLi/component-base/pkg/log/v1" @@ -15,7 +14,7 @@ import ( ) type NginxConfig interface { - Main() context.Context + Main() local.MainContext UpdateFromJsonBytes(data []byte) error UpdatedTimestamp() time.Time TextLines() []string @@ -24,12 +23,12 @@ type NginxConfig interface { } type nginxConfig struct { - mainContext *local.Main + mainContext local.MainContext timestamp time.Time rwLocker *sync.RWMutex } -func (n *nginxConfig) Main() context.Context { +func (n *nginxConfig) Main() local.MainContext { n.rwLocker.RLock() defer n.rwLocker.RUnlock() return n.mainContext @@ -73,7 +72,7 @@ func (n *nginxConfig) Dump() map[string]*bytes.Buffer { return dumpMainContext(n.mainContext) } -func (n *nginxConfig) renewMainContext(m *local.Main) error { +func (n *nginxConfig) renewMainContext(m local.MainContext) error { oldFP := utilsV3.NewConfigFingerprinterWithTimestamp(n.Dump(), time.Time{}) newFP := utilsV3.NewConfigFingerprinterWithTimestamp(dumpMainContext(m), time.Time{}) n.rwLocker.Lock() @@ -103,7 +102,7 @@ func NewNginxConfigFromFS(filepath string) (NginxConfig, error) { return newNginxConfigWithTimestamp(m, t) } -func loadMainContextFromFS(filepath string) (*local.Main, time.Time, error) { +func loadMainContextFromFS(filepath string) (local.MainContext, time.Time, error) { timestamp := time.UnixMicro(0) m, err := local.FileLoader(filepath).Load() if err != nil { @@ -121,7 +120,7 @@ func loadMainContextFromFS(filepath string) (*local.Main, time.Time, error) { return m, timestamp, nil } -func dumpMainContext(m *local.Main) map[string]*bytes.Buffer { +func dumpMainContext(m local.MainContext) map[string]*bytes.Buffer { if m == nil { return nil } @@ -140,17 +139,17 @@ func dumpMainContext(m *local.Main) map[string]*bytes.Buffer { return dumps } -func newNginxConfigWithTimestamp(maincontext *local.Main, timestamp time.Time) (NginxConfig, error) { - if maincontext == nil { +func newNginxConfigWithTimestamp(m local.MainContext, timestamp time.Time) (NginxConfig, error) { + if m == nil { return nil, errors.WithCode(code.ErrV3InvalidContext, "new nginx config with a nil main context") } return &nginxConfig{ - mainContext: maincontext, + mainContext: m, rwLocker: new(sync.RWMutex), timestamp: timestamp, }, nil } -func newNginxConfig(maincontext *local.Main) (NginxConfig, error) { - return newNginxConfigWithTimestamp(maincontext, time.Now()) +func newNginxConfig(m local.MainContext) (NginxConfig, error) { + return newNginxConfigWithTimestamp(m, time.Now()) } diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go b/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go index f84107f..bce55fb 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_manager.go @@ -85,7 +85,7 @@ func (m *nginxConfigManager) NginxConfig() NginxConfig { func (m *nginxConfigManager) ServerStatus() (state v1.State) { state = v1.UnknownState svrPidFilePath := filepath.Join("logs", "nginx.pid") - pidCtx := m.configuration.Main().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue(`pid\s+.*`)).Target() + pidCtx := m.configuration.Main().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexpMatchingValue(`pid\s+.*`)).Target() if pidCtx.Error() == nil { pidCtxKV := strings.Split(pidCtx.Value(), " ") if len(pidCtxKV) == 2 { @@ -135,7 +135,7 @@ func (m *nginxConfigManager) backup() error { // 归档日期初始化 now := time.Now().In(m.backupOpts.backupTimeZone) backupName := utilsV2.GetBackupFileName(m.backupOpts.backupPrefix, now) - archiveDir, err := filepath.Abs(m.NginxConfig().Main().(*local.Main).MainConfig().BaseDir()) + archiveDir, err := filepath.Abs(m.NginxConfig().Main().MainConfig().BaseDir()) if err != nil { return errors.Wrap(err, "failed to format archive directory") } @@ -166,7 +166,7 @@ func (m *nginxConfigManager) backup() error { } var configPaths []string - for _, config := range m.NginxConfig().Main().(*local.Main).Topology() { + for _, config := range m.NginxConfig().Main().Topology() { configPaths = append(configPaths, config.FullPath()) } @@ -218,7 +218,7 @@ func (m *nginxConfigManager) refresh() error { err = m.saveWithCheck() if err != nil { // 保存异常,则回退 var memConfigPaths []string - for _, config := range m.configuration.Main().(*local.Main).Topology() { + for _, config := range m.configuration.Main().Topology() { memConfigPaths = append(memConfigPaths, config.FullPath()) } @@ -268,7 +268,7 @@ func (m *nginxConfigManager) regularlyRefreshAndBackup(signalChan chan int) erro } func (m *nginxConfigManager) serverBinCMD(arg ...string) *exec.Cmd { - arg = append(arg, "-c", m.configuration.Main().(*local.Main).MainConfig().FullPath()) + arg = append(arg, "-c", m.configuration.Main().MainConfig().FullPath()) return exec.Command(m.nginxBinFilePath, arg...) } @@ -298,7 +298,7 @@ func (m *nginxConfigManager) saveWithCheck() error { return m.check() } -func (m *nginxConfigManager) load() (*local.Main, utilsV3.ConfigFingerprinter, error) { +func (m *nginxConfigManager) load() (local.MainContext, utilsV3.ConfigFingerprinter, error) { localMain, timestamp, err := loadMainContextFromFS(m.configuration.Main().Value()) if err != nil { return nil, nil, err diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go index e6044d3..594c09a 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_statistician.go @@ -4,7 +4,6 @@ import ( "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" - "regexp" "strconv" "github.com/marmotedu/errors" @@ -14,11 +13,6 @@ import ( utilsV2 "github.com/ClessLi/bifrost/pkg/resolv/V2/utils" ) -var ( - RegPortValue = regexp.MustCompile(`^listen\s*(\d+)\s*\S*$`) - RegServerNameValue = regexp.MustCompile(`^server_name\s*(.+)$`) -) - type HttpInfo struct { ServerCount int ServerPortCount map[string][]int @@ -74,7 +68,7 @@ func NewStatistician(c NginxConfig) Statistician { } func Port(ctx context.Context) int { - portDirective := ctx.QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("listen .*")).Target() + portDirective := ctx.QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexpMatchingValue(context.RegexpMatchingListenPortValue)).Target() if portDirective.Error() != nil { return -1 } @@ -119,7 +113,7 @@ func HttpServers(ctx context.Context) (int, map[string][]int) { serverPortCount := make(map[string][]int) for _, pos := range httpServerPoses { serverCount++ - servernameDirective := pos.Target().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("^server_name .*")).Target() + servernameDirective := pos.Target().QueryByKeyWords(context.NewKeyWords(context_type.TypeDirective).SetRegexpMatchingValue(context.RegexpMatchingServerNameValue)).Target() if servernameDirective.Error() != nil { if !errors.IsCode(servernameDirective.Error(), code.ErrV3ContextNotFound) { return 0, nil diff --git a/pkg/resolv/V3/nginx/configuration/nginx_config_test.go b/pkg/resolv/V3/nginx/configuration/nginx_config_test.go index 4901c32..2f181a4 100644 --- a/pkg/resolv/V3/nginx/configuration/nginx_config_test.go +++ b/pkg/resolv/V3/nginx/configuration/nginx_config_test.go @@ -4,7 +4,6 @@ import ( "bytes" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context" "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context/local" - "github.com/ClessLi/bifrost/pkg/resolv/V3/nginx/configuration/context_type" "reflect" "sync" "testing" @@ -64,7 +63,7 @@ func TestNewNginxConfigFromPath(t *testing.T) { func Test_dumpMainContext(t *testing.T) { type args struct { - m *local.Main + m local.MainContext } tests := []struct { name string @@ -84,7 +83,7 @@ func Test_dumpMainContext(t *testing.T) { func Test_newNginxConfig(t *testing.T) { type args struct { - maincontext *local.Main + m local.MainContext } tests := []struct { name string @@ -96,7 +95,7 @@ func Test_newNginxConfig(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := newNginxConfig(tt.args.maincontext) + got, err := newNginxConfig(tt.args.m) if (err != nil) != tt.wantErr { t.Errorf("newNginxConfig() error = %v, wantErr %v", err, tt.wantErr) return @@ -110,7 +109,7 @@ func Test_newNginxConfig(t *testing.T) { func Test_nginxConfig_Dump(t *testing.T) { type fields struct { - mainContext *local.Main + mainContext local.MainContext rwLocker *sync.RWMutex } tests := []struct { @@ -135,7 +134,7 @@ func Test_nginxConfig_Dump(t *testing.T) { func Test_nginxConfig_Json(t *testing.T) { type fields struct { - mainContext *local.Main + mainContext local.MainContext rwLocker *sync.RWMutex } tests := []struct { @@ -160,7 +159,7 @@ func Test_nginxConfig_Json(t *testing.T) { func Test_nginxConfig_Main(t *testing.T) { type fields struct { - mainContext *local.Main + mainContext local.MainContext rwLocker *sync.RWMutex } tests := []struct { @@ -185,7 +184,7 @@ func Test_nginxConfig_Main(t *testing.T) { func Test_nginxConfig_TextLines(t *testing.T) { type fields struct { - mainContext *local.Main + mainContext local.MainContext rwLocker *sync.RWMutex } tests := []struct { @@ -209,8 +208,12 @@ func Test_nginxConfig_TextLines(t *testing.T) { } func Test_nginxConfig_UpdateFromJsonBytes(t *testing.T) { + testMain, err := local.NewMain("C:\\test\\test.conf") + if err != nil { + t.Fatal(err) + } type fields struct { - mainContext *local.Main + mainContext local.MainContext rwLocker *sync.RWMutex } type args struct { @@ -225,7 +228,7 @@ func Test_nginxConfig_UpdateFromJsonBytes(t *testing.T) { { name: "normal test", fields: fields{ - mainContext: local.NewContext(context_type.TypeMain, "C:\\test\\test.conf").(*local.Main), + mainContext: testMain, rwLocker: new(sync.RWMutex), }, args: args{data: []byte( @@ -301,11 +304,11 @@ func Test_nginxConfig_UpdateFromJsonBytes(t *testing.T) { func Test_nginxConfig_renewMainContext(t *testing.T) { type fields struct { - mainContext *local.Main + mainContext local.MainContext rwLocker *sync.RWMutex } type args struct { - m *local.Main + m local.MainContext } tests := []struct { name string diff --git a/test/grpc_client/bifrost/client_test.go b/test/grpc_client/bifrost/client_test.go index d84fb89..68cdc9c 100644 --- a/test/grpc_client/bifrost/client_test.go +++ b/test/grpc_client/bifrost/client_test.go @@ -184,11 +184,11 @@ func TestBifrostClientOperation(t *testing.T) { QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeServer)).Target(). QueryAllByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetStringMatchingValue("server_name test1.com")) { server, _ := pos.Position() - if server.QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetRegexMatchingValue("^listen 80$")).Target().Error() != nil { + if server.QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetRegexpMatchingValue("^listen 80$")).Target().Error() != nil { continue } - ctx, idx := server.QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeLocation).SetRegexMatchingValue(`^/test1-location$`)).Target(). - QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeIf).SetRegexMatchingValue(`^\(\$http_api_name != ''\)$`)).Target(). + ctx, idx := server.QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeLocation).SetRegexpMatchingValue(`^/test1-location$`)).Target(). + QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeIf).SetRegexpMatchingValue(`^\(\$http_api_name != ''\)$`)).Target(). QueryByKeyWords(nginx_ctx.NewKeyWords(context_type.TypeDirective).SetStringMatchingValue("proxy_pass")).Position() err = ctx.Insert(local.NewComment(fmt.Sprintf("[%s]test comments", time.Now().String()), true), idx+1).Error() if err != nil { From f844cac9c51613ae6af7ce307c59589e64c472cb Mon Sep 17 00:00:00 2001 From: clessli <37110067+ClessLi@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:37:26 +0800 Subject: [PATCH 7/8] ci(workflows): Update go.yml update `go-version` to 1.21 --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 305a013..002829b 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.15 + go-version: 1.21 - name: bifrost-auth Build Test run: go build -v -race From dcc675f90069baad0c3e0d7616013ef2b696b80a Mon Sep 17 00:00:00 2001 From: ClessLi <316600949@qq.com> Date: Fri, 29 Mar 2024 19:30:51 +0800 Subject: [PATCH 8/8] ci: support `go-version` 1.21. --- scripts/make-rules/golang.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/make-rules/golang.mk b/scripts/make-rules/golang.mk index 308c0aa..812260a 100644 --- a/scripts/make-rules/golang.mk +++ b/scripts/make-rules/golang.mk @@ -3,7 +3,7 @@ # GO := go -GO_SUPPORTED_VERSIONS ?= 1.13|1.14|1.15|1.16|1.17 +GO_SUPPORTED_VERSIONS ?= 1.13|1.14|1.15|1.16|1.17|1.21 GO_LDFLAGS += -X $(VERSION_PACKAGE).GitVersion=$(VERSION) \ -X $(VERSION_PACKAGE).GitCommit=$(GIT_COMMIT) \ -X $(VERSION_PACKAGE).GitTreeState=$(GIT_TREE_STATE) \