From 437e16ca71a709dbc08495934fae7be63f302c02 Mon Sep 17 00:00:00 2001 From: Ivan Kozlovic Date: Thu, 30 May 2019 15:24:39 -0600 Subject: [PATCH 1/2] Added a function to allow ignoring top-level unknown config option This will be required for NATS Streaming server since streaming allows user to have NATS and Streaming specific options in same file. Signed-off-by: Ivan Kozlovic --- server/opts.go | 16 +++++++++++++++- server/opts_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/server/opts.go b/server/opts.go index b799c18a..904cf295 100644 --- a/server/opts.go +++ b/server/opts.go @@ -27,6 +27,7 @@ import ( "regexp" "strconv" "strings" + "sync/atomic" "time" "github.com/nats-io/jwt" @@ -34,6 +35,19 @@ import ( "github.com/nats-io/nkeys" ) +var allowUnknownTopLevelField = int32(0) + +// AllowUnknownTopLevelConfigurationField sets if the processing of a +// configuration file returns an error if it finds an unknown top-level +// configuration option. +func AllowUnknownTopLevelConfigurationField(allow bool) { + var val int32 + if allow { + val = int32(1) + } + atomic.StoreInt32(&allowUnknownTopLevelField, val) +} + // ClusterOpts are options for clusters. // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. @@ -693,7 +707,7 @@ func (o *Options) ProcessConfigFile(configFile string) error { case "reconnect_error_reports": o.ReconnectErrorReports = int(v.(int64)) default: - if !tk.IsUsedVariable() { + if au := atomic.LoadInt32(&allowUnknownTopLevelField); au == 0 && !tk.IsUsedVariable() { err := &unknownConfigFieldErr{ field: k, configErr: configErr{ diff --git a/server/opts_test.go b/server/opts_test.go index 070acd8e..95bb05b1 100644 --- a/server/opts_test.go +++ b/server/opts_test.go @@ -1819,3 +1819,44 @@ func TestLargeMaxPayload(t *testing.T) { t.Fatalf("Expected an error from too large of a max_payload entry") } } + +func TestHandleUnknownTopLevelConfigurationField(t *testing.T) { + conf := createConfFile(t, []byte(` + port: 1234 + streaming { + id: "me" + } + `)) + defer os.Remove(conf) + + // Verify that we get an error because of unknown "streaming" field. + opts := &Options{} + if err := opts.ProcessConfigFile(conf); err == nil || !strings.Contains(err.Error(), "streaming") { + t.Fatal("Expected error, got none") + } + + // Verify that if that is set, we get no error + AllowUnknownTopLevelConfigurationField(true) + defer AllowUnknownTopLevelConfigurationField(false) + + if err := opts.ProcessConfigFile(conf); err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if opts.Port != 1234 { + t.Fatalf("Port was not parsed correctly: %v", opts.Port) + } + + // Verify that ignore works only on top level fields. + changeCurrentConfigContentWithNewContent(t, conf, []byte(` + port: 1234 + cluster { + non_top_level_unknown_field: 123 + } + streaming { + id: "me" + } + `)) + if err := opts.ProcessConfigFile(conf); err == nil || !strings.Contains(err.Error(), "non_top_level") { + t.Fatal("Expected error, got none") + } +} From 451d4bb05c4633b9157fa401ec79279c31c6b536 Mon Sep 17 00:00:00 2001 From: Ivan Kozlovic Date: Thu, 30 May 2019 16:25:37 -0600 Subject: [PATCH 2/2] Change name of public function Signed-off-by: Ivan Kozlovic --- server/opts.go | 11 ++++++----- server/opts_test.go | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/server/opts.go b/server/opts.go index 904cf295..33d48a06 100644 --- a/server/opts.go +++ b/server/opts.go @@ -37,12 +37,13 @@ import ( var allowUnknownTopLevelField = int32(0) -// AllowUnknownTopLevelConfigurationField sets if the processing of a -// configuration file returns an error if it finds an unknown top-level -// configuration option. -func AllowUnknownTopLevelConfigurationField(allow bool) { +// NoErrOnUnknownFields can be used to change the behavior the processing +// of a configuration file. By default, an error is reported if unknown +// fields are found. If `noError` is set to true, no error will be reported +// if top-level unknown fields are found. +func NoErrOnUnknownFields(noError bool) { var val int32 - if allow { + if noError { val = int32(1) } atomic.StoreInt32(&allowUnknownTopLevelField, val) diff --git a/server/opts_test.go b/server/opts_test.go index 95bb05b1..5986e889 100644 --- a/server/opts_test.go +++ b/server/opts_test.go @@ -1836,8 +1836,8 @@ func TestHandleUnknownTopLevelConfigurationField(t *testing.T) { } // Verify that if that is set, we get no error - AllowUnknownTopLevelConfigurationField(true) - defer AllowUnknownTopLevelConfigurationField(false) + NoErrOnUnknownFields(true) + defer NoErrOnUnknownFields(false) if err := opts.ProcessConfigFile(conf); err != nil { t.Fatalf("Unexpected error: %v", err)