From 681ac97457ea71f28583dc24639af4dab24c20db Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 30 Apr 2021 13:36:34 -0400 Subject: [PATCH 1/3] config/* : minor cleanup --- config/v3_0/config.go | 6 +----- config/v3_1/config.go | 6 +----- config/v3_2/config.go | 6 +----- config/v3_3_experimental/config.go | 6 +----- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/config/v3_0/config.go b/config/v3_0/config.go index 38b50bbb3..2b0d685ba 100644 --- a/config/v3_0/config.go +++ b/config/v3_0/config.go @@ -33,7 +33,7 @@ func Merge(parent, child types.Config) types.Config { // Parse parses the raw config into a types.Config struct and generates a report of any // errors, warnings, info, and deprecations it encountered func Parse(rawConfig []byte) (types.Config, report.Report, error) { - if isEmpty(rawConfig) { + if len(rawConfig) == 0 { return types.Config{}, report.Report{}, errors.ErrEmpty } @@ -55,7 +55,3 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } - -func isEmpty(userdata []byte) bool { - return len(userdata) == 0 -} diff --git a/config/v3_1/config.go b/config/v3_1/config.go index 0d0ec6793..71419e0d6 100644 --- a/config/v3_1/config.go +++ b/config/v3_1/config.go @@ -33,7 +33,7 @@ func Merge(parent, child types.Config) types.Config { // Parse parses the raw config into a types.Config struct and generates a report of any // errors, warnings, info, and deprecations it encountered func Parse(rawConfig []byte) (types.Config, report.Report, error) { - if isEmpty(rawConfig) { + if len(rawConfig) == 0 { return types.Config{}, report.Report{}, errors.ErrEmpty } @@ -55,7 +55,3 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } - -func isEmpty(userdata []byte) bool { - return len(userdata) == 0 -} diff --git a/config/v3_2/config.go b/config/v3_2/config.go index 8d0abbcce..8eef36703 100644 --- a/config/v3_2/config.go +++ b/config/v3_2/config.go @@ -33,7 +33,7 @@ func Merge(parent, child types.Config) types.Config { // Parse parses the raw config into a types.Config struct and generates a report of any // errors, warnings, info, and deprecations it encountered func Parse(rawConfig []byte) (types.Config, report.Report, error) { - if isEmpty(rawConfig) { + if len(rawConfig) == 0 { return types.Config{}, report.Report{}, errors.ErrEmpty } @@ -55,7 +55,3 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } - -func isEmpty(userdata []byte) bool { - return len(userdata) == 0 -} diff --git a/config/v3_3_experimental/config.go b/config/v3_3_experimental/config.go index 969d3c569..674833d16 100644 --- a/config/v3_3_experimental/config.go +++ b/config/v3_3_experimental/config.go @@ -33,7 +33,7 @@ func Merge(parent, child types.Config) types.Config { // Parse parses the raw config into a types.Config struct and generates a report of any // errors, warnings, info, and deprecations it encountered func Parse(rawConfig []byte) (types.Config, report.Report, error) { - if isEmpty(rawConfig) { + if len(rawConfig) == 0 { return types.Config{}, report.Report{}, errors.ErrEmpty } @@ -55,7 +55,3 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } - -func isEmpty(userdata []byte) bool { - return len(userdata) == 0 -} From da9652ec10377d36536177b9542e9667b130dce3 Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 30 Apr 2021 16:06:06 -0400 Subject: [PATCH 2/3] config/*: refactor config.go's Parse() to use GetConfigVersion --- config/config.go | 24 +++-------------------- config/util/config.go | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 config/util/config.go diff --git a/config/config.go b/config/config.go index 8106e8c8c..4c6fb9056 100644 --- a/config/config.go +++ b/config/config.go @@ -29,35 +29,17 @@ import ( trans_exp "github.com/coreos/ignition/v2/config/v3_3_experimental/translate" types_exp "github.com/coreos/ignition/v2/config/v3_3_experimental/types" - "github.com/coreos/go-semver/semver" "github.com/coreos/vcontext/report" ) -type versionStub struct { - Ignition struct { - Version string - } -} - // Parse parses a config of any supported version and returns the equivalent config at the latest // supported version. func Parse(raw []byte) (types_exp.Config, report.Report, error) { - if len(raw) == 0 { - return types_exp.Config{}, report.Report{}, errors.ErrEmpty - } - - stub := versionStub{} - rpt, err := util.HandleParseErrors(raw, &stub) + version, r, err := util.GetConfigVersion(raw) if err != nil { - return types_exp.Config{}, rpt, err - } - - version, err := semver.NewVersion(stub.Ignition.Version) - if err != nil { - return types_exp.Config{}, report.Report{}, errors.ErrInvalidVersion + return types_exp.Config{}, r, err } - - switch *version { + switch version { case types_exp.MaxVersion: return v3_3_experimental.Parse(raw) case types_3_2.MaxVersion: diff --git a/config/util/config.go b/config/util/config.go new file mode 100644 index 000000000..85cd7fa7c --- /dev/null +++ b/config/util/config.go @@ -0,0 +1,45 @@ +// Copyright 2021 Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package util + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + + "github.com/coreos/go-semver/semver" + "github.com/coreos/vcontext/report" +) + +type versionStub struct { + Ignition struct { + Version string + } +} + +// GetConfigVersion parses the version from the given raw config +func GetConfigVersion(raw []byte) (semver.Version, report.Report, error) { + if len(raw) == 0 { + return semver.Version{}, report.Report{}, errors.ErrEmpty + } + + stub := versionStub{} + if rpt, err := HandleParseErrors(raw, &stub); err != nil { + return semver.Version{}, rpt, err + } + + version, err := semver.NewVersion(stub.Ignition.Version) + if err != nil { + return semver.Version{}, report.Report{}, errors.ErrInvalidVersion + } + return *version, report.Report{}, nil +} From 500c68426fa1e1581b521138956012ebf765892b Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 30 Apr 2021 16:34:15 -0400 Subject: [PATCH 3/3] config/*: add export functions for parsing any config version < N Closes https://github.com/coreos/ignition/issues/1190 This change helps external callers to import the package for the most recent version that they support and returns the desired config by calling a function that accepts any config version up to and including that version. --- config/config.go | 51 +------------------------ config/v3_0/config.go | 16 ++++++++ config/v3_0/config_test.go | 32 ++++++++++++++++ config/v3_1/config.go | 21 ++++++++++ config/v3_1/config_test.go | 29 ++++++++++++++ config/v3_2/config.go | 21 ++++++++++ config/v3_2/config_test.go | 33 ++++++++++++++++ config/v3_3_experimental/config.go | 21 ++++++++++ config/v3_3_experimental/config_test.go | 37 ++++++++++++++++++ 9 files changed, 212 insertions(+), 49 deletions(-) diff --git a/config/config.go b/config/config.go index 4c6fb9056..095f3c7b8 100644 --- a/config/config.go +++ b/config/config.go @@ -15,18 +15,7 @@ package config import ( - "github.com/coreos/ignition/v2/config/shared/errors" - "github.com/coreos/ignition/v2/config/util" - "github.com/coreos/ignition/v2/config/v3_0" - types_3_0 "github.com/coreos/ignition/v2/config/v3_0/types" - "github.com/coreos/ignition/v2/config/v3_1" - trans_3_1 "github.com/coreos/ignition/v2/config/v3_1/translate" - types_3_1 "github.com/coreos/ignition/v2/config/v3_1/types" - "github.com/coreos/ignition/v2/config/v3_2" - trans_3_2 "github.com/coreos/ignition/v2/config/v3_2/translate" - types_3_2 "github.com/coreos/ignition/v2/config/v3_2/types" - "github.com/coreos/ignition/v2/config/v3_3_experimental" - trans_exp "github.com/coreos/ignition/v2/config/v3_3_experimental/translate" + exp "github.com/coreos/ignition/v2/config/v3_3_experimental" types_exp "github.com/coreos/ignition/v2/config/v3_3_experimental/types" "github.com/coreos/vcontext/report" @@ -35,41 +24,5 @@ import ( // Parse parses a config of any supported version and returns the equivalent config at the latest // supported version. func Parse(raw []byte) (types_exp.Config, report.Report, error) { - version, r, err := util.GetConfigVersion(raw) - if err != nil { - return types_exp.Config{}, r, err - } - switch version { - case types_exp.MaxVersion: - return v3_3_experimental.Parse(raw) - case types_3_2.MaxVersion: - return exp_from_3_2(v3_2.Parse(raw)) - case types_3_1.MaxVersion: - return exp_from_3_2(v3_2_from_3_1(v3_1.Parse(raw))) - case types_3_0.MaxVersion: - return exp_from_3_2(v3_2_from_3_1(v3_1_from_3_0(v3_0.Parse(raw)))) - default: - return types_exp.Config{}, report.Report{}, errors.ErrUnknownVersion - } -} - -func exp_from_3_2(cfg types_3_2.Config, r report.Report, err error) (types_exp.Config, report.Report, error) { - if err != nil { - return types_exp.Config{}, r, err - } - return trans_exp.Translate(cfg), r, nil -} - -func v3_2_from_3_1(cfg types_3_1.Config, r report.Report, err error) (types_3_2.Config, report.Report, error) { - if err != nil { - return types_3_2.Config{}, r, err - } - return trans_3_2.Translate(cfg), r, nil -} - -func v3_1_from_3_0(cfg types_3_0.Config, r report.Report, err error) (types_3_1.Config, report.Report, error) { - if err != nil { - return types_3_1.Config{}, r, err - } - return trans_3_1.Translate(cfg), r, nil + return exp.ParseCompatibleVersion(raw) } diff --git a/config/v3_0/config.go b/config/v3_0/config.go index 2b0d685ba..ca32f7ad4 100644 --- a/config/v3_0/config.go +++ b/config/v3_0/config.go @@ -55,3 +55,19 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } + +// ParseCompatibleVersion parses the raw config of version 3.0.0 into +// a 3.0 types.Config struct and generates a report of any errors, warnings, +// info, and deprecations it encountered +func ParseCompatibleVersion(raw []byte) (types.Config, report.Report, error) { + version, rpt, err := util.GetConfigVersion(raw) + if err != nil { + return types.Config{}, rpt, err + } + + if version == types.MaxVersion { + return Parse(raw) + } + + return types.Config{}, report.Report{}, errors.ErrUnknownVersion +} diff --git a/config/v3_0/config_test.go b/config/v3_0/config_test.go index 2d5320744..ef0b78d01 100644 --- a/config/v3_0/config_test.go +++ b/config/v3_0/config_test.go @@ -101,6 +101,31 @@ func TestParse(t *testing.T) { }, } + testsCompt := []struct { + in in + out out + }{ + { + in: in{config: []byte(`{"ignition": {"version": "3.0.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.1.0"}}`)}, + out: out{err: errors.ErrUnknownVersion}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.2.0"}}`)}, + out: out{err: errors.ErrUnknownVersion}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.3.0-experimental"}}`)}, + out: out{err: errors.ErrUnknownVersion}, + }, + { + in: in{config: []byte{}}, + out: out{err: errors.ErrEmpty}, + }, + } for i, test := range tests { config, report, err := Parse(test.in.config) if test.out.err != err { @@ -108,4 +133,11 @@ func TestParse(t *testing.T) { } assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) } + for i, test := range testsCompt { + config, report, err := ParseCompatibleVersion(test.in.config) + if test.out.err != err { + t.Errorf("#%d: bad error: want %v, got %v, report: %+v", i, test.out.err, err, report) + } + assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) + } } diff --git a/config/v3_1/config.go b/config/v3_1/config.go index 71419e0d6..a40ae56cd 100644 --- a/config/v3_1/config.go +++ b/config/v3_1/config.go @@ -18,6 +18,8 @@ import ( "github.com/coreos/ignition/v2/config/merge" "github.com/coreos/ignition/v2/config/shared/errors" "github.com/coreos/ignition/v2/config/util" + prev "github.com/coreos/ignition/v2/config/v3_0" + "github.com/coreos/ignition/v2/config/v3_1/translate" "github.com/coreos/ignition/v2/config/v3_1/types" "github.com/coreos/ignition/v2/config/validate" @@ -55,3 +57,22 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } + +// ParseCompatibleVersion parses the raw config of version 3.1.0 or lesser +// into a 3.1 types.Config struct and generates a report of any errors, warnings, +// info, and deprecations it encountered +func ParseCompatibleVersion(raw []byte) (types.Config, report.Report, error) { + version, rpt, err := util.GetConfigVersion(raw) + if err != nil { + return types.Config{}, rpt, err + } + + if version == types.MaxVersion { + return Parse(raw) + } + prevCfg, r, err := prev.ParseCompatibleVersion(raw) + if err != nil { + return types.Config{}, r, err + } + return translate.Translate(prevCfg), r, nil +} diff --git a/config/v3_1/config_test.go b/config/v3_1/config_test.go index bb46a88cd..e4e199fea 100644 --- a/config/v3_1/config_test.go +++ b/config/v3_1/config_test.go @@ -121,6 +121,28 @@ func TestParse(t *testing.T) { }, } + testsCompt := []struct { + in in + out out + }{ + { + in: in{config: []byte(`{"ignition": {"version": "3.2.0"}}`)}, + out: out{err: errors.ErrUnknownVersion}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.0.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.1.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte{}}, + out: out{err: errors.ErrEmpty}, + }, + } + for i, test := range tests { config, report, err := Parse(test.in.config) if test.out.err != err { @@ -128,4 +150,11 @@ func TestParse(t *testing.T) { } assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) } + for i, test := range testsCompt { + config, report, err := ParseCompatibleVersion(test.in.config) + if test.out.err != err { + t.Errorf("#%d: bad error: want %v, got %v, report: %+v", i, test.out.err, err, report) + } + assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) + } } diff --git a/config/v3_2/config.go b/config/v3_2/config.go index 8eef36703..f5550d99c 100644 --- a/config/v3_2/config.go +++ b/config/v3_2/config.go @@ -18,6 +18,8 @@ import ( "github.com/coreos/ignition/v2/config/merge" "github.com/coreos/ignition/v2/config/shared/errors" "github.com/coreos/ignition/v2/config/util" + prev "github.com/coreos/ignition/v2/config/v3_1" + "github.com/coreos/ignition/v2/config/v3_2/translate" "github.com/coreos/ignition/v2/config/v3_2/types" "github.com/coreos/ignition/v2/config/validate" @@ -55,3 +57,22 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } + +// ParseCompatibleVersion parses the raw config of version 3.2.0 or lesser +// into a 3.2 types.Config struct and generates a report of any errors, warnings, +// info, and deprecations it encountered +func ParseCompatibleVersion(raw []byte) (types.Config, report.Report, error) { + version, rpt, err := util.GetConfigVersion(raw) + if err != nil { + return types.Config{}, rpt, err + } + + if version == types.MaxVersion { + return Parse(raw) + } + prevCfg, r, err := prev.ParseCompatibleVersion(raw) + if err != nil { + return types.Config{}, report.Report{}, err + } + return translate.Translate(prevCfg), r, nil +} diff --git a/config/v3_2/config_test.go b/config/v3_2/config_test.go index 46779dcea..96f29d467 100644 --- a/config/v3_2/config_test.go +++ b/config/v3_2/config_test.go @@ -129,6 +129,32 @@ func TestParse(t *testing.T) { }, } + testsCompt := []struct { + in in + out out + }{ + { + in: in{config: []byte(`{"ignition": {"version": "3.2.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.0.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.1.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.3.0-experimental"}}`)}, + out: out{err: errors.ErrUnknownVersion}, + }, + { + in: in{config: []byte{}}, + out: out{err: errors.ErrEmpty}, + }, + } + for i, test := range tests { config, report, err := Parse(test.in.config) if test.out.err != err { @@ -136,4 +162,11 @@ func TestParse(t *testing.T) { } assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) } + for i, test := range testsCompt { + config, report, err := ParseCompatibleVersion(test.in.config) + if test.out.err != err { + t.Errorf("#%d: bad error: want %v, got %v, report: %+v", i, test.out.err, err, report) + } + assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) + } } diff --git a/config/v3_3_experimental/config.go b/config/v3_3_experimental/config.go index 674833d16..4f5415132 100644 --- a/config/v3_3_experimental/config.go +++ b/config/v3_3_experimental/config.go @@ -18,6 +18,8 @@ import ( "github.com/coreos/ignition/v2/config/merge" "github.com/coreos/ignition/v2/config/shared/errors" "github.com/coreos/ignition/v2/config/util" + prev "github.com/coreos/ignition/v2/config/v3_2" + "github.com/coreos/ignition/v2/config/v3_3_experimental/translate" "github.com/coreos/ignition/v2/config/v3_3_experimental/types" "github.com/coreos/ignition/v2/config/validate" @@ -55,3 +57,22 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) { return config, rpt, nil } + +// ParseCompatibleVersion parses the raw config of version 3.3.0-experimental or +// lesser into a 3.3-exp types.Config struct and generates a report of any errors, +// warnings, info, and deprecations it encountered +func ParseCompatibleVersion(raw []byte) (types.Config, report.Report, error) { + version, rpt, err := util.GetConfigVersion(raw) + if err != nil { + return types.Config{}, rpt, err + } + + if version == types.MaxVersion { + return Parse(raw) + } + prevCfg, r, err := prev.ParseCompatibleVersion(raw) + if err != nil { + return types.Config{}, report.Report{}, err + } + return translate.Translate(prevCfg), r, nil +} diff --git a/config/v3_3_experimental/config_test.go b/config/v3_3_experimental/config_test.go index a9dd45e97..a6fec71d9 100644 --- a/config/v3_3_experimental/config_test.go +++ b/config/v3_3_experimental/config_test.go @@ -133,6 +133,36 @@ func TestParse(t *testing.T) { }, } + testsCompt := []struct { + in in + out out + }{ + { + in: in{config: []byte(`{"ignition": {"version": "3.2.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.0.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.1.0"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.3.0-experimental"}}`)}, + out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}}, + }, + { + in: in{config: []byte(`{"ignition": {"version": "3.4.0"}}`)}, + out: out{err: errors.ErrUnknownVersion}, + }, + { + in: in{config: []byte{}}, + out: out{err: errors.ErrEmpty}, + }, + } + for i, test := range tests { config, report, err := Parse(test.in.config) if test.out.err != err { @@ -140,4 +170,11 @@ func TestParse(t *testing.T) { } assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) } + for i, test := range testsCompt { + config, report, err := ParseCompatibleVersion(test.in.config) + if test.out.err != err { + t.Errorf("#%d: bad error: want %v, got %v, report: %+v", i, test.out.err, err, report) + } + assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report) + } }