From b4708fa88e2782cf6ad45e622eca3684494cc54c Mon Sep 17 00:00:00 2001 From: Yasmin Valim Date: Sat, 9 Nov 2024 22:11:52 -0300 Subject: [PATCH] Add translation v35 to v34 --- go.mod | 2 + translate/v35tov34/v35tov34.go | 97 +++++ translate_test.go | 368 ++++++++++++++++++ .../ignition/v2/config/v3_5/types/cex.go | 33 ++ .../ignition/v2/config/v3_5/types/clevis.go | 49 +++ .../ignition/v2/config/v3_5/types/config.go | 64 +++ .../ignition/v2/config/v3_5/types/device.go | 25 ++ .../v2/config/v3_5/types/directory.go | 26 ++ .../ignition/v2/config/v3_5/types/disk.go | 135 +++++++ .../ignition/v2/config/v3_5/types/file.go | 43 ++ .../v2/config/v3_5/types/filesystem.go | 106 +++++ .../ignition/v2/config/v3_5/types/headers.go | 65 ++++ .../ignition/v2/config/v3_5/types/ignition.go | 49 +++ .../ignition/v2/config/v3_5/types/kargs.go | 22 ++ .../ignition/v2/config/v3_5/types/luks.go | 82 ++++ .../ignition/v2/config/v3_5/types/mode.go | 26 ++ .../ignition/v2/config/v3_5/types/node.go | 59 +++ .../v2/config/v3_5/types/partition.go | 91 +++++ .../ignition/v2/config/v3_5/types/passwd.go | 23 ++ .../ignition/v2/config/v3_5/types/path.go | 42 ++ .../ignition/v2/config/v3_5/types/proxy.go | 49 +++ .../ignition/v2/config/v3_5/types/raid.go | 62 +++ .../ignition/v2/config/v3_5/types/resource.go | 91 +++++ .../ignition/v2/config/v3_5/types/schema.go | 264 +++++++++++++ .../ignition/v2/config/v3_5/types/storage.go | 115 ++++++ .../ignition/v2/config/v3_5/types/systemd.go | 61 +++ .../ignition/v2/config/v3_5/types/tang.go | 65 ++++ .../ignition/v2/config/v3_5/types/tls.go | 27 ++ .../ignition/v2/config/v3_5/types/unit.go | 68 ++++ .../ignition/v2/config/v3_5/types/url.go | 83 ++++ .../v2/config/v3_5/types/verification.go | 71 ++++ vendor/modules.txt | 2 + 32 files changed, 2365 insertions(+) create mode 100644 translate/v35tov34/v35tov34.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/cex.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/clevis.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/config.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/device.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/directory.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/disk.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/file.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/filesystem.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/headers.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/ignition.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/kargs.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/luks.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/mode.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/node.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/partition.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/passwd.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/path.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/proxy.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/raid.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/resource.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/schema.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/storage.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/systemd.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/tang.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/tls.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/unit.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/url.go create mode 100644 vendor/github.com/coreos/ignition/v2/config/v3_5/types/verification.go diff --git a/go.mod b/go.mod index ec3c9ab..1f0391f 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/coreos/ign-converter go 1.18 +replace github.com/coreos/ign-converter/translate/v34tov35 => ./translate/v35tov34 + require ( github.com/clarketm/json v1.17.1 github.com/coreos/ignition v0.35.0 diff --git a/translate/v35tov34/v35tov34.go b/translate/v35tov34/v35tov34.go new file mode 100644 index 0000000..12572ea --- /dev/null +++ b/translate/v35tov34/v35tov34.go @@ -0,0 +1,97 @@ +// Copyright 2020 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 v35tov34 + +import ( + "fmt" + "reflect" + + "github.com/coreos/ignition/v2/config/translate" + "github.com/coreos/ignition/v2/config/v3_4/types" + + old_types "github.com/coreos/ignition/v2/config/v3_5/types" + "github.com/coreos/ignition/v2/config/validate" +) + +// Copy of github.com/coreos/ignition/v2/config/v3_4/translate/translate.go +// with the types & old_types imports reversed (the referenced file translates +// from 3.4 -> 3.5 but as a result only touches fields that are understood by +// the 3.4 spec). +func translateIgnition(old old_types.Ignition) (ret types.Ignition) { + // use a new translator so we don't recurse infinitely + translate.NewTranslator().Translate(&old, &ret) + ret.Version = types.MaxVersion.String() + return +} +func translateLuks(old old_types.Luks) (ret types.Luks) { + tr := translate.NewTranslator() + tr.AddCustomTranslator(translateTang) + tr.Translate(&old.Clevis, &ret.Clevis) + tr.Translate(&old.Device, &ret.Device) + tr.Translate(&old.KeyFile, &ret.KeyFile) + tr.Translate(&old.Label, &ret.Label) + tr.Translate(&old.Name, &ret.Name) + tr.Translate(&old.OpenOptions, &ret.OpenOptions) + tr.Translate(&old.Options, &ret.Options) + tr.Translate(&old.Discard, &ret.Discard) + tr.Translate(&old.UUID, &ret.UUID) + tr.Translate(&old.WipeVolume, &ret.WipeVolume) + return +} +func translateTang(old old_types.Tang) (ret types.Tang) { + tr := translate.NewTranslator() + tr.Translate(&old.Thumbprint, &ret.Thumbprint) + tr.Translate(&old.URL, &ret.URL) + return +} +func translateConfig(old old_types.Config) (ret types.Config) { + tr := translate.NewTranslator() + tr.AddCustomTranslator(translateIgnition) + tr.AddCustomTranslator(translateLuks) + tr.Translate(&old, &ret) + return +} + +// end copied Ignition v3_5/translate block + +// Translate translates Ignition spec config v3.5 to spec v3.4 +func Translate(cfg old_types.Config) (types.Config, error) { + rpt := validate.ValidateWithContext(cfg, nil) + if rpt.IsFatal() { + return types.Config{}, fmt.Errorf("invalid input config:\n%s", rpt.String()) + } + + err := checkValue(reflect.ValueOf(cfg)) + if err != nil { + return types.Config{}, err + } + + res := translateConfig(cfg) + + // Sanity check the returned config + oldrpt := validate.ValidateWithContext(res, nil) + if oldrpt.IsFatal() { + return types.Config{}, fmt.Errorf("converted spec has unexpected fatal error:\n%s", oldrpt.String()) + } + return res, nil +} + +func checkValue(v reflect.Value) error { + // v3.5 introduced Cex type + if v.Type() == reflect.TypeOf(old_types.Cex{}) { + return fmt.Errorf("invalid input config: 'Cex' type is not supported in spec v3.4") + } + + return nil +} diff --git a/translate_test.go b/translate_test.go index a8ae52f..c03eb17 100644 --- a/translate_test.go +++ b/translate_test.go @@ -25,6 +25,7 @@ import ( types3_2 "github.com/coreos/ignition/v2/config/v3_2/types" types3_3 "github.com/coreos/ignition/v2/config/v3_3/types" types3_4 "github.com/coreos/ignition/v2/config/v3_4/types" + types3_5 "github.com/coreos/ignition/v2/config/v3_5/types" "github.com/stretchr/testify/assert" @@ -38,6 +39,7 @@ import ( "github.com/coreos/ign-converter/translate/v32tov31" "github.com/coreos/ign-converter/translate/v33tov32" "github.com/coreos/ign-converter/translate/v34tov33" + "github.com/coreos/ign-converter/translate/v35tov34" "github.com/coreos/ign-converter/util" ) @@ -1855,6 +1857,344 @@ var ( }, } + downtranslateConfig3_4 = types3_5.Config{ + Ignition: types3_5.Ignition{ + Version: "3.5.0", + Config: types3_5.IgnitionConfig{ + Merge: []types3_5.Resource{ + { + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + }, + }, + Replace: types3_5.Resource{ + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + }, + }, + Timeouts: types3_5.Timeouts{ + HTTPResponseHeaders: util.IntP(5), + HTTPTotal: util.IntP(10), + }, + Security: types3_5.Security{ + TLS: types3_5.TLS{ + CertificateAuthorities: []types3_5.Resource{ + { + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + }, + }, + }, + }, + Proxy: types3_5.Proxy{ + HTTPProxy: util.StrP("https://proxy.example.net/"), + HTTPSProxy: util.StrP("https://secure.proxy.example.net/"), + NoProxy: []types3_5.NoProxyItem{ + "www.example.net", + "www.example2.net", + }, + }, + }, + Storage: types3_5.Storage{ + Disks: []types3_5.Disk{ + { + Device: "/dev/sda", + WipeTable: util.BoolP(true), + Partitions: []types3_5.Partition{ + { + Label: util.StrP("var"), + Number: 1, + SizeMiB: util.IntP(5000), + StartMiB: util.IntP(2048), + TypeGUID: &aUUID, + GUID: &aUUID, + WipePartitionEntry: util.BoolP(true), + ShouldExist: util.BoolP(true), + }, + }, + }, + }, + Raid: []types3_5.Raid{ + { + Name: "array", + Level: util.StrP("raid10"), + Devices: []types3_5.Device{"/dev/sdb", "/dev/sdc"}, + Spares: util.IntP(1), + Options: []types3_5.RaidOption{"foobar"}, + }, + }, + Filesystems: []types3_5.Filesystem{ + { + Path: util.StrP("/var"), + Device: "/dev/disk/by-partlabel/var", + Format: util.StrP("xfs"), + WipeFilesystem: util.BoolP(true), + Label: util.StrP("var"), + UUID: &aUUID, + Options: []types3_5.FilesystemOption{"rw"}, + }, + }, + Files: []types3_5.File{ + { + Node: types3_5.Node{ + Path: "/var/varfile", + Overwrite: util.BoolPStrict(false), + User: types3_5.NodeUser{ + ID: util.IntP(1000), + }, + Group: types3_5.NodeGroup{ + Name: util.StrP("groupname"), + }, + }, + FileEmbedded1: types3_5.FileEmbedded1{ + Mode: util.IntP(420), + Append: []types3_5.Resource{ + { + Compression: util.StrP("gzip"), + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + HTTPHeaders: types3_5.HTTPHeaders{ + types3_5.HTTPHeader{ + Name: "Authorization", + Value: util.StrP("Basic YWxhZGRpbjpvcGVuc2VzYW1l"), + }, + types3_5.HTTPHeader{ + Name: "User-Agent", + Value: util.StrP("Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)"), + }, + }, + }, + }, + }, + }, + { + Node: types3_5.Node{ + Path: "/empty", + Overwrite: util.BoolPStrict(false), + }, + FileEmbedded1: types3_5.FileEmbedded1{ + Mode: util.IntP(420), + Contents: types3_5.Resource{ + Source: util.StrPStrict(""), + }, + }, + }, + }, + Directories: []types3_5.Directory{ + { + Node: types3_5.Node{ + Path: "/rootdir", + Overwrite: util.BoolP(true), + User: types3_5.NodeUser{ + ID: util.IntP(1000), + }, + Group: types3_5.NodeGroup{ + Name: util.StrP("groupname"), + }, + }, + DirectoryEmbedded1: types3_5.DirectoryEmbedded1{ + Mode: util.IntP(420), + }, + }, + }, + Links: []types3_5.Link{ + { + Node: types3_5.Node{ + Path: "/rootlink", + Overwrite: util.BoolP(true), + User: types3_5.NodeUser{ + ID: util.IntP(1000), + }, + Group: types3_5.NodeGroup{ + Name: util.StrP("groupname"), + }, + }, + LinkEmbedded1: types3_5.LinkEmbedded1{ + Hard: util.BoolP(false), + Target: util.StrP("/foobar"), + }, + }, + }, + }, + } + + nonexhaustiveConfig3_5 = types3_5.Config{ + Ignition: types3_5.Ignition{ + Version: "3.5.0", + Config: types3_5.IgnitionConfig{ + Merge: []types3_5.Resource{ + { + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + }, + }, + Replace: types3_5.Resource{ + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + }, + }, + Timeouts: types3_5.Timeouts{ + HTTPResponseHeaders: util.IntP(5), + HTTPTotal: util.IntP(10), + }, + Security: types3_5.Security{ + TLS: types3_5.TLS{ + CertificateAuthorities: []types3_5.Resource{ + { + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + }, + }, + }, + }, + Proxy: types3_5.Proxy{ + HTTPProxy: util.StrP("https://proxy.example.net/"), + HTTPSProxy: util.StrP("https://secure.proxy.example.net/"), + NoProxy: []types3_5.NoProxyItem{ + "www.example.net", + "www.example2.net", + }, + }, + }, + Storage: types3_5.Storage{ + Disks: []types3_5.Disk{ + { + Device: "/dev/sda", + WipeTable: util.BoolP(true), + Partitions: []types3_5.Partition{ + { + Label: util.StrP("var"), + Number: 1, + SizeMiB: util.IntP(5000), + StartMiB: util.IntP(2048), + TypeGUID: &aUUID, + GUID: &aUUID, + WipePartitionEntry: util.BoolP(true), + ShouldExist: util.BoolP(true), + }, + }, + }, + }, + Raid: []types3_5.Raid{ + { + Name: "array", + Level: util.StrP("raid10"), + Devices: []types3_5.Device{"/dev/sdb", "/dev/sdc"}, + Spares: util.IntP(1), + Options: []types3_5.RaidOption{"foobar"}, + }, + }, + Filesystems: []types3_5.Filesystem{ + { + Path: util.StrP("/var"), + Device: "/dev/disk/by-partlabel/var", + Format: util.StrP("xfs"), + WipeFilesystem: util.BoolP(true), + Label: util.StrP("var"), + UUID: &aUUID, + Options: []types3_5.FilesystemOption{"rw"}, + }, + }, + Files: []types3_5.File{ + { + Node: types3_5.Node{ + Path: "/var/varfile", + Overwrite: util.BoolPStrict(false), + User: types3_5.NodeUser{ + ID: util.IntP(1000), + }, + Group: types3_5.NodeGroup{ + Name: util.StrP("groupname"), + }, + }, + FileEmbedded1: types3_5.FileEmbedded1{ + Mode: util.IntP(420), + Append: []types3_5.Resource{ + { + Compression: util.StrP("gzip"), + Source: util.StrP("https://example.com"), + Verification: types3_5.Verification{ + Hash: &aSha512Hash, + }, + HTTPHeaders: types3_5.HTTPHeaders{ + types3_5.HTTPHeader{ + Name: "Authorization", + Value: util.StrP("Basic YWxhZGRpbjpvcGVuc2VzYW1l"), + }, + types3_5.HTTPHeader{ + Name: "User-Agent", + Value: util.StrP("Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)"), + }, + }, + }, + }, + }, + }, + { + Node: types3_5.Node{ + Path: "/empty", + Overwrite: util.BoolPStrict(false), + }, + FileEmbedded1: types3_5.FileEmbedded1{ + Mode: util.IntP(420), + Contents: types3_5.Resource{ + Source: util.StrPStrict(""), + }, + }, + }, + }, + Directories: []types3_5.Directory{ + { + Node: types3_5.Node{ + Path: "/rootdir", + Overwrite: util.BoolP(true), + User: types3_5.NodeUser{ + ID: util.IntP(1000), + }, + Group: types3_5.NodeGroup{ + Name: util.StrP("groupname"), + }, + }, + DirectoryEmbedded1: types3_5.DirectoryEmbedded1{ + Mode: util.IntP(420), + }, + }, + }, + Links: []types3_5.Link{ + { + Node: types3_5.Node{ + Path: "/rootlink", + Overwrite: util.BoolP(true), + User: types3_5.NodeUser{ + ID: util.IntP(1000), + }, + Group: types3_5.NodeGroup{ + Name: util.StrP("groupname"), + }, + }, + LinkEmbedded1: types3_5.LinkEmbedded1{ + Hard: util.BoolP(false), + Target: util.StrP("/foobar"), + }, + }, + }, + }, + } + downtranslateConfig3_3 = types3_3.Config{ Ignition: types3_3.Ignition{ Version: "3.3.0", @@ -2554,6 +2894,34 @@ func TestTranslate3_4to3_3(t *testing.T) { }) assert.Error(t, err) } +func TestTranslate3_5to3_4(t *testing.T) { + emptyConfig := types3_5.Config{ + Ignition: types3_5.Ignition{ + Version: "3.5.0", + }, + } + + _, err := v35tov34.Translate(emptyConfig) + if err != nil { + t.Fatalf("Failed translation: %v", err) + } + + res, err := v35tov34.Translate(nonexhaustiveConfig3_4) + if err != nil { + t.Fatalf("Failed translation: %v", err) + } + assert.Equal(t, downtranslateConfig3_3, res) + + // Translation with unsupported `Cex` type + _, err = v35tov34.Translate(types3_5.Config{ + Ignition: types3_5.Ignition{ + Version: "3.5.0", + }, + }) + assert.Error(t, err) + assert.ErrorContains(t, err, "'Cex' type is not supported in spec v3.4") + +} func TestRemoveDuplicateFilesUnitsUsers2_3(t *testing.T) { mode := 420 diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/cex.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/cex.go new file mode 100644 index 0000000..b34f5f5 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/cex.go @@ -0,0 +1,33 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (cm Cex) IsPresent() bool { + return util.IsTrue(cm.Enabled) +} + +func (cx Cex) Validate(c path.ContextPath) (r report.Report) { + if !util.IsTrue(cx.Enabled) { + return + } + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/clevis.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/clevis.go new file mode 100644 index 0000000..68887d4 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/clevis.go @@ -0,0 +1,49 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (c Clevis) IsPresent() bool { + return util.NotEmpty(c.Custom.Pin) || + len(c.Tang) > 0 || + util.IsTrue(c.Tpm2) || + c.Threshold != nil && *c.Threshold != 0 +} + +func (cu ClevisCustom) Validate(c path.ContextPath) (r report.Report) { + if util.NilOrEmpty(cu.Pin) && util.NilOrEmpty(cu.Config) && !util.IsTrue(cu.NeedsNetwork) { + return + } + if util.NotEmpty(cu.Pin) { + switch *cu.Pin { + case "tpm2", "tang", "sss": + default: + r.AddOnError(c.Append("pin"), errors.ErrUnknownClevisPin) + } + } else { + r.AddOnError(c.Append("pin"), errors.ErrClevisPinRequired) + } + if util.NilOrEmpty(cu.Config) { + r.AddOnError(c.Append("config"), errors.ErrClevisConfigRequired) + } + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/config.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/config.go new file mode 100644 index 0000000..659657b --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/config.go @@ -0,0 +1,64 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/go-semver/semver" + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +var ( + MaxVersion = semver.Version{ + Major: 3, + Minor: 5, + } +) + +func (cfg Config) Validate(c path.ContextPath) (r report.Report) { + systemdPath := "/etc/systemd/system/" + unitPaths := map[string]struct{}{} + for _, unit := range cfg.Systemd.Units { + if !util.NilOrEmpty(unit.Contents) { + pathString := systemdPath + unit.Name + unitPaths[pathString] = struct{}{} + } + for _, dropin := range unit.Dropins { + if !util.NilOrEmpty(dropin.Contents) { + pathString := systemdPath + unit.Name + ".d/" + dropin.Name + unitPaths[pathString] = struct{}{} + } + } + } + for i, f := range cfg.Storage.Files { + if _, exists := unitPaths[f.Path]; exists { + r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsSystemd) + } + } + for i, d := range cfg.Storage.Directories { + if _, exists := unitPaths[d.Path]; exists { + r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsSystemd) + } + } + for i, l := range cfg.Storage.Links { + if _, exists := unitPaths[l.Path]; exists { + r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsSystemd) + } + } + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/device.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/device.go new file mode 100644 index 0000000..a10ce97 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/device.go @@ -0,0 +1,25 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (d Device) Validate(c path.ContextPath) (r report.Report) { + r.AddOnError(c, validatePath(string(d))) + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/directory.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/directory.go new file mode 100644 index 0000000..f6f0684 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/directory.go @@ -0,0 +1,26 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (d Directory) Validate(c path.ContextPath) (r report.Report) { + r.Merge(d.Node.Validate(c)) + r.AddOnError(c.Append("mode"), validateMode(d.Mode)) + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/disk.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/disk.go new file mode 100644 index 0000000..8caf849 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/disk.go @@ -0,0 +1,135 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (d Disk) Key() string { + return d.Device +} + +func (n Disk) Validate(c path.ContextPath) (r report.Report) { + if len(n.Device) == 0 { + r.AddOnError(c.Append("device"), errors.ErrDiskDeviceRequired) + return + } + r.AddOnError(c.Append("device"), validatePath(n.Device)) + + if collides, p := n.partitionNumbersCollide(); collides { + r.AddOnError(c.Append("partitions", p), errors.ErrPartitionNumbersCollide) + } + if overlaps, p := n.partitionsOverlap(); overlaps { + r.AddOnError(c.Append("partitions", p), errors.ErrPartitionsOverlap) + } + if n.partitionsMixZeroesAndNonexistence() { + r.AddOnError(c.Append("partitions"), errors.ErrZeroesWithShouldNotExist) + } + if collides, p := n.partitionLabelsCollide(); collides { + r.AddOnError(c.Append("partitions", p), errors.ErrDuplicateLabels) + } + return +} + +// partitionNumbersCollide returns true if partition numbers in n.Partitions are not unique. It also returns the +// index of the colliding partition +func (n Disk) partitionNumbersCollide() (bool, int) { + m := map[int][]int{} // from partition number to index into array + for i, p := range n.Partitions { + if p.Number != 0 { + // a number of 0 means next available number, multiple devices can specify this + m[p.Number] = append(m[p.Number], i) + } + } + for _, n := range m { + if len(n) > 1 { + // TODO(vc): return information describing the collision for logging + return true, n[1] + } + } + return false, 0 +} + +func (d Disk) partitionLabelsCollide() (bool, int) { + m := map[string]struct{}{} + for i, p := range d.Partitions { + if p.Label != nil { + // a number of 0 means next available number, multiple devices can specify this + if _, exists := m[*p.Label]; exists { + return true, i + } + m[*p.Label] = struct{}{} + } + } + return false, 0 +} + +// end returns the last sector of a partition. Only used by partitionsOverlap. Requires non-nil Start and Size. +func (p Partition) end() int { + if *p.SizeMiB == 0 { + // a size of 0 means "fill available", just return the start as the end for those. + return *p.StartMiB + } + return *p.StartMiB + *p.SizeMiB - 1 +} + +// partitionsOverlap returns true if any explicitly dimensioned partitions overlap. It also returns the index of +// the overlapping partition +func (n Disk) partitionsOverlap() (bool, int) { + for _, p := range n.Partitions { + // Starts of 0 are placed by sgdisk into the "largest available block" at that time. + // We aren't going to check those for overlap since we don't have the disk geometry. + if p.StartMiB == nil || p.SizeMiB == nil || *p.StartMiB == 0 { + continue + } + + for i, o := range n.Partitions { + if o.StartMiB == nil || o.SizeMiB == nil || p == o || *o.StartMiB == 0 { + continue + } + + // is p.StartMiB within o? + if *p.StartMiB >= *o.StartMiB && *p.StartMiB <= o.end() { + return true, i + } + + // is p.end() within o? + if p.end() >= *o.StartMiB && p.end() <= o.end() { + return true, i + } + + // do p.StartMiB and p.end() straddle o? + if *p.StartMiB < *o.StartMiB && p.end() > o.end() { + return true, i + } + } + } + return false, 0 +} + +func (n Disk) partitionsMixZeroesAndNonexistence() bool { + hasZero := false + hasShouldNotExist := false + for _, p := range n.Partitions { + hasShouldNotExist = hasShouldNotExist || util.IsFalse(p.ShouldExist) + hasZero = hasZero || (p.Number == 0) + } + return hasZero && hasShouldNotExist +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/file.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/file.go new file mode 100644 index 0000000..9b71bb2 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/file.go @@ -0,0 +1,43 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (f File) Validate(c path.ContextPath) (r report.Report) { + r.Merge(f.Node.Validate(c)) + r.AddOnError(c.Append("mode"), validateMode(f.Mode)) + r.AddOnError(c.Append("overwrite"), f.validateOverwrite()) + return +} + +func (f File) validateOverwrite() error { + if util.IsTrue(f.Overwrite) && f.Contents.Source == nil { + return errors.ErrOverwriteAndNilSource + } + return nil +} + +func (f FileEmbedded1) IgnoreDuplicates() map[string]struct{} { + return map[string]struct{}{ + "Append": {}, + } +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/filesystem.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/filesystem.go new file mode 100644 index 0000000..c722b36 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/filesystem.go @@ -0,0 +1,106 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (f Filesystem) Key() string { + return f.Device +} + +func (f Filesystem) IgnoreDuplicates() map[string]struct{} { + return map[string]struct{}{ + "Options": {}, + "MountOptions": {}, + } +} + +func (f Filesystem) Validate(c path.ContextPath) (r report.Report) { + r.AddOnError(c.Append("path"), f.validatePath()) + r.AddOnError(c.Append("device"), validatePath(f.Device)) + r.AddOnError(c.Append("format"), f.validateFormat()) + r.AddOnError(c.Append("label"), f.validateLabel()) + return +} + +func (f Filesystem) validatePath() error { + return validatePathNilOK(f.Path) +} + +func (f Filesystem) validateFormat() error { + if util.NilOrEmpty(f.Format) { + if util.NotEmpty(f.Path) || + util.NotEmpty(f.Label) || + util.NotEmpty(f.UUID) || + util.IsTrue(f.WipeFilesystem) || + len(f.MountOptions) != 0 || + len(f.Options) != 0 { + return errors.ErrFormatNilWithOthers + } + } else { + switch *f.Format { + case "ext4", "btrfs", "xfs", "swap", "vfat", "none": + default: + return errors.ErrFilesystemInvalidFormat + } + } + return nil +} + +func (f Filesystem) validateLabel() error { + if util.NilOrEmpty(f.Label) { + return nil + } + if util.NilOrEmpty(f.Format) { + return errors.ErrLabelNeedsFormat + } + + switch *f.Format { + case "ext4": + if len(*f.Label) > 16 { + // source: man mkfs.ext4 + return errors.ErrExt4LabelTooLong + } + case "btrfs": + if len(*f.Label) > 256 { + // source: man mkfs.btrfs + return errors.ErrBtrfsLabelTooLong + } + case "xfs": + if len(*f.Label) > 12 { + // source: man mkfs.xfs + return errors.ErrXfsLabelTooLong + } + case "swap": + // mkswap's man page does not state a limit on label size, but through + // experimentation it appears that mkswap will truncate long labels to + // 15 characters, so let's enforce that. + if len(*f.Label) > 15 { + return errors.ErrSwapLabelTooLong + } + case "vfat": + if len(*f.Label) > 11 { + // source: man mkfs.fat + return errors.ErrVfatLabelTooLong + } + } + return nil +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/headers.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/headers.go new file mode 100644 index 0000000..be1aada --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/headers.go @@ -0,0 +1,65 @@ +// Copyright 2020 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 types + +import ( + "net/http" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +// Parse generates standard net/http headers from the data in HTTPHeaders +func (hs HTTPHeaders) Parse() (http.Header, error) { + headers := http.Header{} + for _, header := range hs { + if header.Name == "" { + return nil, errors.ErrEmptyHTTPHeaderName + } + if header.Value == nil || string(*header.Value) == "" { + return nil, errors.ErrInvalidHTTPHeader + } + headers.Add(header.Name, string(*header.Value)) + } + return headers, nil +} + +func (h HTTPHeader) Validate(c path.ContextPath) (r report.Report) { + r.AddOnError(c.Append("name"), h.validateName()) + r.AddOnError(c.Append("value"), h.validateValue()) + return +} + +func (h HTTPHeader) validateName() error { + if h.Name == "" { + return errors.ErrEmptyHTTPHeaderName + } + return nil +} + +func (h HTTPHeader) validateValue() error { + if h.Value == nil { + return nil + } + if string(*h.Value) == "" { + return errors.ErrInvalidHTTPHeader + } + return nil +} + +func (h HTTPHeader) Key() string { + return h.Name +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/ignition.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/ignition.go new file mode 100644 index 0000000..190445b --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/ignition.go @@ -0,0 +1,49 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/go-semver/semver" + + "github.com/coreos/ignition/v2/config/shared/errors" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (v Ignition) Semver() (*semver.Version, error) { + return semver.NewVersion(v.Version) +} + +func (ic IgnitionConfig) Validate(c path.ContextPath) (r report.Report) { + for i, res := range ic.Merge { + r.AddOnError(c.Append("merge", i), res.validateRequiredSource()) + } + return +} + +func (v Ignition) Validate(c path.ContextPath) (r report.Report) { + c = c.Append("version") + tv, err := v.Semver() + if err != nil { + r.AddOnError(c, errors.ErrInvalidVersion) + return + } + + if MaxVersion != *tv { + r.AddOnError(c, errors.ErrUnknownVersion) + } + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/kargs.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/kargs.go new file mode 100644 index 0000000..42c2940 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/kargs.go @@ -0,0 +1,22 @@ +// 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 types + +func (k KernelArguments) MergedKeys() map[string]string { + return map[string]string{ + "ShouldExist": "KernelArgument", + "ShouldNotExist": "KernelArgument", + } +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/luks.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/luks.go new file mode 100644 index 0000000..e4c1d68 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/luks.go @@ -0,0 +1,82 @@ +// Copyright 2020 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 types + +import ( + "strings" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (l Luks) Key() string { + return l.Name +} + +func (l Luks) IgnoreDuplicates() map[string]struct{} { + return map[string]struct{}{ + "Options": {}, + } +} + +func (l Luks) Validate(c path.ContextPath) (r report.Report) { + if strings.Contains(l.Name, "/") { + r.AddOnError(c.Append("name"), errors.ErrLuksNameContainsSlash) + } + r.AddOnError(c.Append("label"), l.validateLabel()) + if util.NilOrEmpty(l.Device) { + r.AddOnError(c.Append("device"), errors.ErrDiskDeviceRequired) + } else { + r.AddOnError(c.Append("device"), validatePath(*l.Device)) + } + + if util.NotEmpty(l.Clevis.Custom.Pin) && (len(l.Clevis.Tang) > 0 || util.IsTrue(l.Clevis.Tpm2) || (l.Clevis.Threshold != nil && *l.Clevis.Threshold != 0)) { + r.AddOnError(c.Append("clevis"), errors.ErrClevisCustomWithOthers) + } + + // fail if a key file is provided and is not valid + if err := validateURLNilOK(l.KeyFile.Source); err != nil { + r.AddOnError(c.Append("keys"), errors.ErrInvalidLuksKeyFile) + } + + // fail if Cex use with Clevis + if l.Clevis.IsPresent() && l.Cex.IsPresent() { + r.AddOnError(c.Append("cex"), errors.ErrCexWithClevis) + } + + // fail if key file is provided along with Cex + if l.Cex.IsPresent() && util.NotEmpty(l.KeyFile.Source) { + r.AddOnError(c.Append("cex"), errors.ErrCexWithKeyFile) + } + + return +} + +func (l Luks) validateLabel() error { + if util.NilOrEmpty(l.Label) { + return nil + } + + if len(*l.Label) > 47 { + // LUKS2_LABEL_L has a maximum length of 48 (including the null terminator) + // https://gitlab.com/cryptsetup/cryptsetup/-/blob/1633f030e89ad2f11ae649ba9600997a41abd3fc/lib/luks2/luks2.h#L86 + return errors.ErrLuksLabelTooLong + } + + return nil +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/mode.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/mode.go new file mode 100644 index 0000000..9eb7573 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/mode.go @@ -0,0 +1,26 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" +) + +func validateMode(m *int) error { + if m != nil && (*m < 0 || *m > 07777) { + return errors.ErrFileIllegalMode + } + return nil +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/node.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/node.go new file mode 100644 index 0000000..248276e --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/node.go @@ -0,0 +1,59 @@ +// Copyright 2020 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 types + +import ( + "path" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + vpath "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (n Node) Key() string { + return n.Path +} + +func (n Node) Validate(c vpath.ContextPath) (r report.Report) { + r.AddOnError(c.Append("path"), validatePath(n.Path)) + return +} + +func (n Node) Depth() int { + count := 0 + for p := path.Clean(string(n.Path)); p != "/"; count++ { + p = path.Dir(p) + } + return count +} + +func validateIDorName(id *int, name *string) error { + if id != nil && util.NotEmpty(name) { + return errors.ErrBothIDAndNameSet + } + return nil +} + +func (nu NodeUser) Validate(c vpath.ContextPath) (r report.Report) { + r.AddOnError(c, validateIDorName(nu.ID, nu.Name)) + return +} + +func (ng NodeGroup) Validate(c vpath.ContextPath) (r report.Report) { + r.AddOnError(c, validateIDorName(ng.ID, ng.Name)) + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/partition.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/partition.go new file mode 100644 index 0000000..1b2d97e --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/partition.go @@ -0,0 +1,91 @@ +// Copyright 2020 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 types + +import ( + "fmt" + "regexp" + "strings" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +const ( + guidRegexStr = "^(|[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12})$" +) + +var ( + guidRegex = regexp.MustCompile(guidRegexStr) +) + +func (p Partition) Key() string { + if p.Number != 0 { + return fmt.Sprintf("number:%d", p.Number) + } else if p.Label != nil { + return fmt.Sprintf("label:%s", *p.Label) + } else { + return "" + } +} + +func (p Partition) Validate(c path.ContextPath) (r report.Report) { + if util.IsFalse(p.ShouldExist) && + (p.Label != nil || util.NotEmpty(p.TypeGUID) || util.NotEmpty(p.GUID) || p.StartMiB != nil || p.SizeMiB != nil) { + r.AddOnError(c, errors.ErrShouldNotExistWithOthers) + } + if p.Number == 0 && p.Label == nil { + r.AddOnError(c, errors.ErrNeedLabelOrNumber) + } + + r.AddOnError(c.Append("label"), p.validateLabel()) + r.AddOnError(c.Append("guid"), validateGUID(p.GUID)) + r.AddOnError(c.Append("typeGuid"), validateGUID(p.TypeGUID)) + return +} + +func (p Partition) validateLabel() error { + if p.Label == nil { + return nil + } + // http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries: + // 56 (0x38) 72 bytes Partition name (36 UTF-16LE code units) + + // XXX(vc): note GPT calls it a name, we're using label for consistency + // with udev naming /dev/disk/by-partlabel/*. + if len(*p.Label) > 36 { + return errors.ErrLabelTooLong + } + + // sgdisk uses colons for delimitting compound arguments and does not allow escaping them. + if strings.Contains(*p.Label, ":") { + return errors.ErrLabelContainsColon + } + return nil +} + +func validateGUID(guidPointer *string) error { + if guidPointer == nil { + return nil + } + guid := *guidPointer + if ok := guidRegex.MatchString(guid); !ok { + return errors.ErrDoesntMatchGUIDRegex + } + return nil +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/passwd.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/passwd.go new file mode 100644 index 0000000..4060a2a --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/passwd.go @@ -0,0 +1,23 @@ +// Copyright 2020 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 types + +func (p PasswdUser) Key() string { + return p.Name +} + +func (g PasswdGroup) Key() string { + return g.Name +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/path.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/path.go new file mode 100644 index 0000000..131e300 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/path.go @@ -0,0 +1,42 @@ +// Copyright 2020 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 types + +import ( + "path" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" +) + +func validatePath(p string) error { + if p == "" { + return errors.ErrNoPath + } + if !path.IsAbs(p) { + return errors.ErrPathRelative + } + if path.Clean(p) != p { + return errors.ErrDirtyPath + } + return nil +} + +func validatePathNilOK(p *string) error { + if util.NilOrEmpty(p) { + return nil + } + return validatePath(*p) +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/proxy.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/proxy.go new file mode 100644 index 0000000..d48d210 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/proxy.go @@ -0,0 +1,49 @@ +// Copyright 2020 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 types + +import ( + "net/url" + + "github.com/coreos/ignition/v2/config/shared/errors" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (p Proxy) Validate(c path.ContextPath) (r report.Report) { + validateProxyURL(p.HTTPProxy, c.Append("httpProxy"), &r, true) + validateProxyURL(p.HTTPSProxy, c.Append("httpsProxy"), &r, false) + return +} + +func validateProxyURL(s *string, p path.ContextPath, r *report.Report, httpOk bool) { + if s == nil { + return + } + u, err := url.Parse(*s) + if err != nil { + r.AddOnError(p, errors.ErrInvalidUrl) + return + } + + if u.Scheme != "https" && u.Scheme != "http" { + r.AddOnError(p, errors.ErrInvalidProxy) + return + } + if u.Scheme == "http" && !httpOk { + r.AddOnWarn(p, errors.ErrInsecureProxy) + } +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/raid.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/raid.go new file mode 100644 index 0000000..9d69aa3 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/raid.go @@ -0,0 +1,62 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (r Raid) Key() string { + return r.Name +} + +func (r Raid) IgnoreDuplicates() map[string]struct{} { + return map[string]struct{}{ + "Options": {}, + } +} + +func (ra Raid) Validate(c path.ContextPath) (r report.Report) { + r.AddOnError(c.Append("level"), ra.validateLevel()) + if len(ra.Devices) == 0 { + r.AddOnError(c.Append("devices"), errors.ErrRaidDevicesRequired) + } + return +} + +func (r Raid) validateLevel() error { + if util.NilOrEmpty(r.Level) { + return errors.ErrRaidLevelRequired + } + switch *r.Level { + case "linear", "raid0", "0", "stripe": + if r.Spares != nil && *r.Spares != 0 { + return errors.ErrSparesUnsupportedForLevel + } + case "raid1", "1", "mirror": + case "raid4", "4": + case "raid5", "5": + case "raid6", "6": + case "raid10", "10": + default: + return errors.ErrUnrecognizedRaidLevel + } + + return nil +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/resource.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/resource.go new file mode 100644 index 0000000..68da6c7 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/resource.go @@ -0,0 +1,91 @@ +// Copyright 2020 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 types + +import ( + "net/url" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (res Resource) Key() string { + if res.Source == nil { + return "" + } + return *res.Source +} + +func (res Resource) Validate(c path.ContextPath) (r report.Report) { + r.AddOnError(c.Append("compression"), res.validateCompression()) + r.AddOnError(c.Append("verification", "hash"), res.validateVerification()) + r.AddOnError(c.Append("source"), validateURLNilOK(res.Source)) + r.AddOnError(c.Append("httpHeaders"), res.validateSchemeForHTTPHeaders()) + return +} + +func (res Resource) validateCompression() error { + if res.Compression != nil { + switch *res.Compression { + case "", "gzip": + default: + return errors.ErrCompressionInvalid + } + } + return nil +} + +func (res Resource) validateVerification() error { + if res.Verification.Hash != nil && res.Source == nil { + return errors.ErrVerificationAndNilSource + } + return nil +} + +func (res Resource) validateSchemeForHTTPHeaders() error { + if len(res.HTTPHeaders) < 1 { + return nil + } + + if util.NilOrEmpty(res.Source) { + return errors.ErrInvalidUrl + } + + u, err := url.Parse(*res.Source) + if err != nil { + return errors.ErrInvalidUrl + } + + switch u.Scheme { + case "http", "https": + return nil + default: + return errors.ErrUnsupportedSchemeForHTTPHeaders + } +} + +// Ensure that the Source is specified and valid. This is not called by +// Resource.Validate() because some structs that embed Resource don't +// require Source to be specified. Containing structs that require Source +// should call this function from their Validate(). +func (res Resource) validateRequiredSource() error { + if util.NilOrEmpty(res.Source) { + return errors.ErrSourceRequired + } + return validateURL(*res.Source) +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/schema.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/schema.go new file mode 100644 index 0000000..6c8c42f --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/schema.go @@ -0,0 +1,264 @@ +package types + +// generated by "schematyper --package=types config/v3_5/schema/ignition.json -o config/v3_5/types/schema.go --root-type=Config" -- DO NOT EDIT + +type Cex struct { + Enabled *bool `json:"enabled,omitempty"` +} + +type Clevis struct { + Custom ClevisCustom `json:"custom,omitempty"` + Tang []Tang `json:"tang,omitempty"` + Threshold *int `json:"threshold,omitempty"` + Tpm2 *bool `json:"tpm2,omitempty"` +} + +type ClevisCustom struct { + Config *string `json:"config,omitempty"` + NeedsNetwork *bool `json:"needsNetwork,omitempty"` + Pin *string `json:"pin,omitempty"` +} + +type Config struct { + Ignition Ignition `json:"ignition"` + KernelArguments KernelArguments `json:"kernelArguments,omitempty"` + Passwd Passwd `json:"passwd,omitempty"` + Storage Storage `json:"storage,omitempty"` + Systemd Systemd `json:"systemd,omitempty"` +} + +type Device string + +type Directory struct { + Node + DirectoryEmbedded1 +} + +type DirectoryEmbedded1 struct { + Mode *int `json:"mode,omitempty"` +} + +type Disk struct { + Device string `json:"device"` + Partitions []Partition `json:"partitions,omitempty"` + WipeTable *bool `json:"wipeTable,omitempty"` +} + +type Dropin struct { + Contents *string `json:"contents,omitempty"` + Name string `json:"name"` +} + +type File struct { + Node + FileEmbedded1 +} + +type FileEmbedded1 struct { + Append []Resource `json:"append,omitempty"` + Contents Resource `json:"contents,omitempty"` + Mode *int `json:"mode,omitempty"` +} + +type Filesystem struct { + Device string `json:"device"` + Format *string `json:"format,omitempty"` + Label *string `json:"label,omitempty"` + MountOptions []MountOption `json:"mountOptions,omitempty"` + Options []FilesystemOption `json:"options,omitempty"` + Path *string `json:"path,omitempty"` + UUID *string `json:"uuid,omitempty"` + WipeFilesystem *bool `json:"wipeFilesystem,omitempty"` +} + +type FilesystemOption string + +type Group string + +type HTTPHeader struct { + Name string `json:"name"` + Value *string `json:"value,omitempty"` +} + +type HTTPHeaders []HTTPHeader + +type Ignition struct { + Config IgnitionConfig `json:"config,omitempty"` + Proxy Proxy `json:"proxy,omitempty"` + Security Security `json:"security,omitempty"` + Timeouts Timeouts `json:"timeouts,omitempty"` + Version string `json:"version"` +} + +type IgnitionConfig struct { + Merge []Resource `json:"merge,omitempty"` + Replace Resource `json:"replace,omitempty"` +} + +type KernelArgument string + +type KernelArguments struct { + ShouldExist []KernelArgument `json:"shouldExist,omitempty"` + ShouldNotExist []KernelArgument `json:"shouldNotExist,omitempty"` +} + +type Link struct { + Node + LinkEmbedded1 +} + +type LinkEmbedded1 struct { + Hard *bool `json:"hard,omitempty"` + Target *string `json:"target,omitempty"` +} + +type Luks struct { + Cex Cex `json:"cex,omitempty"` + Clevis Clevis `json:"clevis,omitempty"` + Device *string `json:"device,omitempty"` + Discard *bool `json:"discard,omitempty"` + KeyFile Resource `json:"keyFile,omitempty"` + Label *string `json:"label,omitempty"` + Name string `json:"name"` + OpenOptions []OpenOption `json:"openOptions,omitempty"` + Options []LuksOption `json:"options,omitempty"` + UUID *string `json:"uuid,omitempty"` + WipeVolume *bool `json:"wipeVolume,omitempty"` +} + +type LuksOption string + +type MountOption string + +type NoProxyItem string + +type Node struct { + Group NodeGroup `json:"group,omitempty"` + Overwrite *bool `json:"overwrite,omitempty"` + Path string `json:"path"` + User NodeUser `json:"user,omitempty"` +} + +type NodeGroup struct { + ID *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` +} + +type NodeUser struct { + ID *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` +} + +type OpenOption string + +type Partition struct { + GUID *string `json:"guid,omitempty"` + Label *string `json:"label,omitempty"` + Number int `json:"number,omitempty"` + Resize *bool `json:"resize,omitempty"` + ShouldExist *bool `json:"shouldExist,omitempty"` + SizeMiB *int `json:"sizeMiB,omitempty"` + StartMiB *int `json:"startMiB,omitempty"` + TypeGUID *string `json:"typeGuid,omitempty"` + WipePartitionEntry *bool `json:"wipePartitionEntry,omitempty"` +} + +type Passwd struct { + Groups []PasswdGroup `json:"groups,omitempty"` + Users []PasswdUser `json:"users,omitempty"` +} + +type PasswdGroup struct { + Gid *int `json:"gid,omitempty"` + Name string `json:"name"` + PasswordHash *string `json:"passwordHash,omitempty"` + ShouldExist *bool `json:"shouldExist,omitempty"` + System *bool `json:"system,omitempty"` +} + +type PasswdUser struct { + Gecos *string `json:"gecos,omitempty"` + Groups []Group `json:"groups,omitempty"` + HomeDir *string `json:"homeDir,omitempty"` + Name string `json:"name"` + NoCreateHome *bool `json:"noCreateHome,omitempty"` + NoLogInit *bool `json:"noLogInit,omitempty"` + NoUserGroup *bool `json:"noUserGroup,omitempty"` + PasswordHash *string `json:"passwordHash,omitempty"` + PrimaryGroup *string `json:"primaryGroup,omitempty"` + SSHAuthorizedKeys []SSHAuthorizedKey `json:"sshAuthorizedKeys,omitempty"` + Shell *string `json:"shell,omitempty"` + ShouldExist *bool `json:"shouldExist,omitempty"` + System *bool `json:"system,omitempty"` + UID *int `json:"uid,omitempty"` +} + +type Proxy struct { + HTTPProxy *string `json:"httpProxy,omitempty"` + HTTPSProxy *string `json:"httpsProxy,omitempty"` + NoProxy []NoProxyItem `json:"noProxy,omitempty"` +} + +type Raid struct { + Devices []Device `json:"devices,omitempty"` + Level *string `json:"level,omitempty"` + Name string `json:"name"` + Options []RaidOption `json:"options,omitempty"` + Spares *int `json:"spares,omitempty"` +} + +type RaidOption string + +type Resource struct { + Compression *string `json:"compression,omitempty"` + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` + Source *string `json:"source,omitempty"` + Verification Verification `json:"verification,omitempty"` +} + +type SSHAuthorizedKey string + +type Security struct { + TLS TLS `json:"tls,omitempty"` +} + +type Storage struct { + Directories []Directory `json:"directories,omitempty"` + Disks []Disk `json:"disks,omitempty"` + Files []File `json:"files,omitempty"` + Filesystems []Filesystem `json:"filesystems,omitempty"` + Links []Link `json:"links,omitempty"` + Luks []Luks `json:"luks,omitempty"` + Raid []Raid `json:"raid,omitempty"` +} + +type Systemd struct { + Units []Unit `json:"units,omitempty"` +} + +type TLS struct { + CertificateAuthorities []Resource `json:"certificateAuthorities,omitempty"` +} + +type Tang struct { + Advertisement *string `json:"advertisement,omitempty"` + Thumbprint *string `json:"thumbprint,omitempty"` + URL string `json:"url,omitempty"` +} + +type Timeouts struct { + HTTPResponseHeaders *int `json:"httpResponseHeaders,omitempty"` + HTTPTotal *int `json:"httpTotal,omitempty"` +} + +type Unit struct { + Contents *string `json:"contents,omitempty"` + Dropins []Dropin `json:"dropins,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Mask *bool `json:"mask,omitempty"` + Name string `json:"name"` +} + +type Verification struct { + Hash *string `json:"hash,omitempty"` +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/storage.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/storage.go new file mode 100644 index 0000000..20cb730 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/storage.go @@ -0,0 +1,115 @@ +// Copyright 2020 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 types + +import ( + "path" + "strings" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + vpath "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (s Storage) MergedKeys() map[string]string { + return map[string]string{ + "Directories": "Node", + "Files": "Node", + "Links": "Node", + } +} + +func (s Storage) Validate(c vpath.ContextPath) (r report.Report) { + s.validateDirectories(c, &r) + s.validateFiles(c, &r) + s.validateLinks(c, &r) + s.validateFilesystems(c, &r) + return +} + +func (s Storage) validateDirectories(c vpath.ContextPath, r *report.Report) { + for i, d := range s.Directories { + for _, l := range s.Links { + if strings.HasPrefix(d.Path, l.Path+"/") { + r.AddOnError(c.Append("directories", i), errors.ErrDirectoryUsedSymlink) + } + } + } +} + +func (s Storage) validateFiles(c vpath.ContextPath, r *report.Report) { + for i, f := range s.Files { + for _, l := range s.Links { + if strings.HasPrefix(f.Path, l.Path+"/") { + r.AddOnError(c.Append("files", i), errors.ErrFileUsedSymlink) + } + } + } +} + +func (s Storage) validateLinks(c vpath.ContextPath, r *report.Report) { + for i, l1 := range s.Links { + for _, l2 := range s.Links { + if strings.HasPrefix(l1.Path, l2.Path+"/") { + r.AddOnError(c.Append("links", i), errors.ErrLinkUsedSymlink) + } + } + if util.NilOrEmpty(l1.Target) { + r.AddOnError(c.Append("links", i, "target"), errors.ErrLinkTargetRequired) + continue + } + if !util.IsTrue(l1.Hard) { + continue + } + target := path.Clean(*l1.Target) + if !path.IsAbs(target) { + target = path.Join(l1.Path, *l1.Target) + } + for _, d := range s.Directories { + if target == d.Path { + r.AddOnError(c.Append("links", i), errors.ErrHardLinkToDirectory) + } + } + ownerCheck := func(ok bool, path vpath.ContextPath) { + if !ok { + r.AddOnWarn(path, errors.ErrHardLinkSpecifiesOwner) + } + } + ownerCheck(l1.User.ID == nil, c.Append("links", i, "user", "id")) + ownerCheck(l1.User.Name == nil, c.Append("links", i, "user", "name")) + ownerCheck(l1.Group.ID == nil, c.Append("links", i, "group", "id")) + ownerCheck(l1.Group.Name == nil, c.Append("links", i, "group", "name")) + } +} + +func (s Storage) validateFilesystems(c vpath.ContextPath, r *report.Report) { + disks := make(map[string]Disk) + for _, d := range s.Disks { + disks[d.Device] = d + } + + for i, f := range s.Filesystems { + disk, exist := disks[f.Device] + if exist { + if len(disk.Partitions) > 0 { + r.AddOnWarn(c.Append("filesystems", i, "device"), errors.ErrPartitionsOverwritten) + } else if !util.IsTrue(f.WipeFilesystem) && util.IsTrue(disk.WipeTable) { + r.AddOnWarn(c.Append("filesystems", i, "device"), errors.ErrFilesystemImplicitWipe) + } + } + } +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/systemd.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/systemd.go new file mode 100644 index 0000000..ac521ba --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/systemd.go @@ -0,0 +1,61 @@ +// Copyright 2022 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 types + +import ( + "regexp" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/shared/parse" + "github.com/coreos/ignition/v2/config/util" + + vpath "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (s Systemd) Validate(c vpath.ContextPath) (r report.Report) { + units := make(map[string]Unit) + checkInstanceUnit := regexp.MustCompile(`^(.+?)@(.+?)\.service$`) + for _, d := range s.Units { + units[d.Name] = d + } + for index, unit := range s.Units { + if checkInstanceUnit.MatchString(unit.Name) && util.IsTrue(unit.Enabled) { + instUnitSlice := checkInstanceUnit.FindSubmatch([]byte(unit.Name)) + instantiableUnit := string(instUnitSlice[1]) + "@.service" + if _, ok := units[instantiableUnit]; ok && util.NotEmpty(units[instantiableUnit].Contents) { + foundInstallSection := false + // we're doing a separate validation pass on each unit to identify + // if an instantiable unit has the install section. So logging an + // `AddOnError` will produce duplicate errors on bad unit contents + // because we're already doing that while validating a unit separately. + opts, err := parse.ParseUnitContents(units[instantiableUnit].Contents) + if err != nil { + continue + } + for _, section := range opts { + if section.Section == "Install" { + foundInstallSection = true + break + } + } + if !foundInstallSection { + r.AddOnWarn(c.Append("units", index, "contents"), errors.NewNoInstallSectionForInstantiableUnitError(instantiableUnit, unit.Name)) + } + } + } + } + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/tang.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/tang.go new file mode 100644 index 0000000..1839d6c --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/tang.go @@ -0,0 +1,65 @@ +// Copyright 2020 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 types + +import ( + "encoding/json" + "net/url" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (t Tang) Key() string { + return t.URL +} + +func (t Tang) Validate(c path.ContextPath) (r report.Report) { + r.AddOnError(c.Append("url"), validateTangURL(t.URL)) + if util.NilOrEmpty(t.Thumbprint) { + r.AddOnError(c.Append("thumbprint"), errors.ErrTangThumbprintRequired) + } + r.AddOnError(c.Append("advertisement"), validateTangAdvertisement(t.Advertisement)) + return +} + +func validateTangURL(s string) error { + u, err := url.Parse(s) + if err != nil { + return errors.ErrInvalidUrl + } + + switch u.Scheme { + case "http", "https": + return nil + default: + return errors.ErrInvalidScheme + } +} + +func validateTangAdvertisement(s *string) error { + if util.NotEmpty(s) { + var adv any + err := json.Unmarshal([]byte(*s), &adv) + if err != nil { + return errors.ErrInvalidTangAdvertisement + } + } + + return nil +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/tls.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/tls.go new file mode 100644 index 0000000..8890e39 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/tls.go @@ -0,0 +1,27 @@ +// Copyright 2020 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 types + +import ( + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (tls TLS) Validate(c path.ContextPath) (r report.Report) { + for i, ca := range tls.CertificateAuthorities { + r.AddOnError(c.Append("certificateAuthorities", i), ca.validateRequiredSource()) + } + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/unit.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/unit.go new file mode 100644 index 0000000..c5ee1e8 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/unit.go @@ -0,0 +1,68 @@ +// Copyright 2020 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 types + +import ( + "path" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/shared/parse" + "github.com/coreos/ignition/v2/config/shared/validations" + "github.com/coreos/ignition/v2/config/util" + + cpath "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (u Unit) Key() string { + return u.Name +} + +func (d Dropin) Key() string { + return d.Name +} + +func (u Unit) Validate(c cpath.ContextPath) (r report.Report) { + r.AddOnError(c.Append("name"), validateName(u.Name)) + c = c.Append("contents") + opts, err := parse.ParseUnitContents(u.Contents) + r.AddOnError(c, err) + + r.AddOnWarn(c, validations.ValidateInstallSection(u.Name, util.IsTrue(u.Enabled), util.NilOrEmpty(u.Contents), opts)) + + return +} + +func validateName(name string) error { + switch path.Ext(name) { + case ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice", ".scope": + default: + return errors.ErrInvalidSystemdExt + } + return nil +} + +func (d Dropin) Validate(c cpath.ContextPath) (r report.Report) { + _, err := parse.ParseUnitContents(d.Contents) + r.AddOnError(c.Append("contents"), err) + + switch path.Ext(d.Name) { + case ".conf": + default: + r.AddOnError(c.Append("name"), errors.ErrInvalidSystemdDropinExt) + } + + return +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/url.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/url.go new file mode 100644 index 0000000..3ca189d --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/url.go @@ -0,0 +1,83 @@ +// Copyright 2020 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 types + +import ( + "net/url" + "strings" + + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/vincent-petithory/dataurl" + + "github.com/coreos/ignition/v2/config/shared/errors" + "github.com/coreos/ignition/v2/config/util" +) + +func validateURL(s string) error { + u, err := url.Parse(s) + if err != nil { + return errors.ErrInvalidUrl + } + + switch u.Scheme { + case "http", "https", "tftp", "gs": + return nil + case "s3": + if v, ok := u.Query()["versionId"]; ok { + if len(v) == 0 || v[0] == "" { + return errors.ErrInvalidS3ObjectVersionId + } + } + return nil + case "arn": + fullURL := u.Scheme + ":" + u.Opaque + if !arn.IsARN(fullURL) { + return errors.ErrInvalidS3ARN + } + s3arn, err := arn.Parse(fullURL) + if err != nil { + return err + } + if s3arn.Service != "s3" { + return errors.ErrInvalidS3ARN + } + urlSplit := strings.Split(fullURL, "/") + if strings.HasPrefix(s3arn.Resource, "accesspoint/") && len(urlSplit) < 3 { + return errors.ErrInvalidS3ARN + } else if len(urlSplit) < 2 { + return errors.ErrInvalidS3ARN + } + if v, ok := u.Query()["versionId"]; ok { + if len(v) == 0 || v[0] == "" { + return errors.ErrInvalidS3ObjectVersionId + } + } + return nil + case "data": + if _, err := dataurl.DecodeString(s); err != nil { + return err + } + return nil + default: + return errors.ErrInvalidScheme + } +} + +func validateURLNilOK(s *string) error { + if util.NilOrEmpty(s) { + return nil + } + return validateURL(*s) +} diff --git a/vendor/github.com/coreos/ignition/v2/config/v3_5/types/verification.go b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/verification.go new file mode 100644 index 0000000..5def6f0 --- /dev/null +++ b/vendor/github.com/coreos/ignition/v2/config/v3_5/types/verification.go @@ -0,0 +1,71 @@ +// Copyright 2020 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 types + +import ( + "crypto" + "encoding/hex" + "strings" + + "github.com/coreos/ignition/v2/config/shared/errors" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +// HashParts will return the sum and function (in that order) of the hash stored +// in this Verification, or an error if there is an issue during parsing. +func (v Verification) HashParts() (string, string, error) { + if v.Hash == nil { + // The hash can be nil + return "", "", nil + } + parts := strings.SplitN(*v.Hash, "-", 2) + if len(parts) != 2 { + return "", "", errors.ErrHashMalformed + } + + return parts[0], parts[1], nil +} + +func (v Verification) Validate(c path.ContextPath) (r report.Report) { + c = c.Append("hash") + if v.Hash == nil { + // The hash can be nil + return + } + + function, sum, err := v.HashParts() + if err != nil { + r.AddOnError(c, err) + return + } + var hash crypto.Hash + switch function { + case "sha512": + hash = crypto.SHA512 + case "sha256": + hash = crypto.SHA256 + default: + r.AddOnError(c, errors.ErrHashUnrecognized) + return + } + + if len(sum) != hex.EncodedLen(hash.Size()) { + r.AddOnError(c, errors.ErrHashWrongSize) + } + + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 078a64a..104cd7c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -57,6 +57,7 @@ github.com/coreos/ignition/v2/config/v3_1/types github.com/coreos/ignition/v2/config/v3_2/types github.com/coreos/ignition/v2/config/v3_3/types github.com/coreos/ignition/v2/config/v3_4/types +github.com/coreos/ignition/v2/config/v3_5/types github.com/coreos/ignition/v2/config/validate # github.com/coreos/vcontext v0.0.0-20230201181013-d72178a18687 ## explicit; go 1.18 @@ -83,3 +84,4 @@ go4.org/errorutil # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 +# github.com/coreos/ign-converter/translate/v34tov35 => ./translate/v35tov34