From bc4e0e53bc1f40da373d8b147ca950745213a383 Mon Sep 17 00:00:00 2001 From: Mike Fedosin Date: Wed, 22 Jan 2020 13:46:11 +0100 Subject: [PATCH 1/2] Bump Ignition and Gophercloud The newest version includes important features, like HTTP headers support, that are required for the successful installation of OpenShift on OpenStack without Swift. --- Gopkg.lock | 14 +- Gopkg.toml | 2 +- .../ignition/config/shared/errors/errors.go | 20 +- .../ignition/config/util/parsingErrors.go | 2 +- .../coreos/ignition/config/v1/types/config.go | 8 + .../coreos/ignition/config/v2_0/append.go | 21 +- .../coreos/ignition/config/v2_1/append.go | 6 +- .../coreos/ignition/config/v2_1/types/url.go | 9 +- .../coreos/ignition/config/v2_2/types/url.go | 9 +- .../coreos/ignition/config/v2_4/types/ca.go | 58 ++++ .../ignition/config/v2_4/types/config.go | 91 ++++++ .../types/directory.go | 0 .../{v2_3_experimental => v2_4}/types/disk.go | 20 ++ .../{v2_3_experimental => v2_4}/types/file.go | 29 ++ .../types/filesystem.go | 0 .../types/link.go => v2_4/types/headers.go} | 26 +- .../types/ignition.go | 30 ++ .../{v2_3_experimental => v2_4}/types/mode.go | 0 .../{v2_3_experimental => v2_4}/types/node.go | 0 .../types/partition.go | 26 +- .../types/passwd.go | 0 .../{v2_3_experimental => v2_4}/types/path.go | 0 .../{v2_3_experimental => v2_4}/types/raid.go | 0 .../types/schema.go | 55 ++-- .../{v2_3_experimental => v2_4}/types/unit.go | 0 .../{v2_3_experimental => v2_4}/types/url.go | 9 +- .../types/verification.go | 0 .../config/v2_5_experimental/types/ca.go | 58 ++++ .../types/config.go | 2 +- .../types/directory.go} | 22 +- .../config/v2_5_experimental/types/disk.go | 164 +++++++++++ .../config/v2_5_experimental/types/file.go | 100 +++++++ .../v2_5_experimental/types/filesystem.go | 146 ++++++++++ .../config/v2_5_experimental/types/headers.go | 47 +++ .../v2_5_experimental/types/ignition.go | 82 ++++++ .../ca.go => v2_5_experimental/types/mode.go} | 13 +- .../config/v2_5_experimental/types/node.go | 73 +++++ .../v2_5_experimental/types/partition.go | 112 ++++++++ .../config/v2_5_experimental/types/passwd.go | 67 +++++ .../types/path.go} | 21 +- .../config/v2_5_experimental/types/raid.go | 57 ++++ .../config/v2_5_experimental/types/schema.go | 269 ++++++++++++++++++ .../config/v2_5_experimental/types/unit.go | 131 +++++++++ .../config/v2_5_experimental/types/url.go | 53 ++++ .../v2_5_experimental/types/verification.go | 77 +++++ .../imageservice/v2/imagedata/doc.go | 48 ++++ .../imageservice/v2/imagedata/requests.go | 39 +++ .../imageservice/v2/imagedata/results.go | 34 +++ .../imageservice/v2/imagedata/urls.go | 23 ++ 49 files changed, 1994 insertions(+), 79 deletions(-) create mode 100644 vendor/github.com/coreos/ignition/config/v2_4/types/ca.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_4/types/config.go rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/directory.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/disk.go (90%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/file.go (78%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/filesystem.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental/types/link.go => v2_4/types/headers.go} (56%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/ignition.go (75%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/mode.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/node.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/partition.go (77%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/passwd.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/path.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/raid.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/schema.go (83%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/unit.go (100%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/url.go (84%) rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_4}/types/verification.go (100%) create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ca.go rename vendor/github.com/coreos/ignition/config/{v2_3_experimental => v2_5_experimental}/types/config.go (99%) rename vendor/github.com/coreos/ignition/config/{v2_1/types/link.go => v2_5_experimental/types/directory.go} (66%) create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/disk.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/file.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/filesystem.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/headers.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ignition.go rename vendor/github.com/coreos/ignition/config/{v2_3_experimental/types/ca.go => v2_5_experimental/types/mode.go} (69%) create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/node.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/partition.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/passwd.go rename vendor/github.com/coreos/ignition/config/{v2_2/types/link.go => v2_5_experimental/types/path.go} (64%) create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/raid.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/schema.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/unit.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/url.go create mode 100644 vendor/github.com/coreos/ignition/config/v2_5_experimental/types/verification.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/doc.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/requests.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/results.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/urls.go diff --git a/Gopkg.lock b/Gopkg.lock index d13f46b94ac..7614795c12d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -215,7 +215,7 @@ version = "v18" [[projects]] - digest = "1:fb5b2aed0d774e210c1f2c0893e620cb3fa98957d3b925d0378f93b9613eb605" + digest = "1:b3ff820a2b867b5140ac8e6c84a1124affe7d671296b7648d06b61d0834617cf" name = "github.com/coreos/ignition" packages = [ "config/shared/errors", @@ -229,15 +229,16 @@ "config/v2_1/types", "config/v2_2", "config/v2_2/types", - "config/v2_3_experimental/types", + "config/v2_4/types", + "config/v2_5_experimental/types", "config/validate", "config/validate/astjson", "config/validate/astnode", "config/validate/report", ] pruneopts = "NUT" - revision = "76107251acd117c6d3e5b4dae2b47f82f944984b" - version = "v0.26.0" + revision = "7afbeba044a8bf5762609fbb5f352291eeb7ad9a" + version = "v0.35.0" [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" @@ -398,7 +399,7 @@ [[projects]] branch = "master" - digest = "1:67551c599e04b31fe799b4bd4de0e101d3c022057213ef7af014bdce5f525b18" + digest = "1:0989b632c84399624334e9ed9b8157319cf01d211140c0a4f78f780564caeeb0" name = "github.com/gophercloud/gophercloud" packages = [ ".", @@ -412,6 +413,7 @@ "openstack/identity/v2/tenants", "openstack/identity/v2/tokens", "openstack/identity/v3/tokens", + "openstack/imageservice/v2/imagedata", "openstack/imageservice/v2/images", "openstack/loadbalancer/v2/apiversions", "openstack/loadbalancer/v2/l7policies", @@ -1432,6 +1434,7 @@ "github.com/containers/image/pkg/sysregistriesv2", "github.com/coreos/ignition/config/util", "github.com/coreos/ignition/config/v2_2/types", + "github.com/coreos/ignition/config/v2_4/types", "github.com/ghodss/yaml", "github.com/golang/mock/gomock", "github.com/google/uuid", @@ -1441,6 +1444,7 @@ "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", "github.com/gophercloud/gophercloud/openstack/compute/v2/servers", "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata", "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images", "github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/apiversions", "github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers", diff --git a/Gopkg.toml b/Gopkg.toml index d8cb7176e93..b6bdad9cf5a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -27,7 +27,7 @@ required = [ [[constraint]] name = "github.com/coreos/ignition" - version = "0.26.0" + version = "0.35.0" [[constraint]] name = "github.com/libvirt/libvirt-go" diff --git a/vendor/github.com/coreos/ignition/config/shared/errors/errors.go b/vendor/github.com/coreos/ignition/config/shared/errors/errors.go index f2d1ddf2866..f2b47cf9079 100644 --- a/vendor/github.com/coreos/ignition/config/shared/errors/errors.go +++ b/vendor/github.com/coreos/ignition/config/shared/errors/errors.go @@ -64,6 +64,9 @@ var ( ErrUnrecognizedRaidLevel = errors.New("unrecognized raid level") ErrShouldNotExistWithOthers = errors.New("shouldExist specified false with other options also specified") ErrZeroesWithShouldNotExist = errors.New("shouldExist is false for a partition and other partition(s) has start or size 0") + ErrPartitionsUnitsMismatch = errors.New("cannot mix MBs and sectors within a disk") + ErrSizeDeprecated = errors.New("size is deprecated; use sizeMB instead") + ErrStartDeprecated = errors.New("start is deprecated; use startMB instead") // Passwd section errors ErrPasswdCreateDeprecated = errors.New("the create object has been deprecated in favor of user-level options") @@ -85,11 +88,18 @@ var ( ErrInvalidNetworkdDropinExt = errors.New("invalid networkd drop-in extension") // Misc errors - ErrInvalidScheme = errors.New("invalid url scheme") - ErrInvalidUrl = errors.New("unable to parse url") - ErrHashMalformed = errors.New("malformed hash specifier") - ErrHashWrongSize = errors.New("incorrect size for hash sum") - ErrHashUnrecognized = errors.New("unrecognized hash function") + ErrInvalidScheme = errors.New("invalid url scheme") + ErrInvalidUrl = errors.New("unable to parse url") + ErrEmptyHTTPHeaderName = errors.New("HTTP header name can't be empty") + ErrDuplicateHTTPHeaders = errors.New("all header names in the list must be unique") + ErrUnsupportedSchemeForHTTPHeaders = errors.New("cannot use HTTP headers with this source scheme") + ErrHashMalformed = errors.New("malformed hash specifier") + ErrHashWrongSize = errors.New("incorrect size for hash sum") + ErrHashUnrecognized = errors.New("unrecognized hash function") + ErrEngineConfiguration = errors.New("engine incorrectly configured") + + // AWS S3 specific errors + ErrInvalidS3ObjectVersionId = errors.New("invalid S3 object VersionId") ) // NewNoInstallSectionError produces an error indicating the given unit, named diff --git a/vendor/github.com/coreos/ignition/config/util/parsingErrors.go b/vendor/github.com/coreos/ignition/config/util/parsingErrors.go index 6b6b114dafc..d51fc1f3e02 100644 --- a/vendor/github.com/coreos/ignition/config/util/parsingErrors.go +++ b/vendor/github.com/coreos/ignition/config/util/parsingErrors.go @@ -19,7 +19,7 @@ import ( "errors" configErrors "github.com/coreos/ignition/config/shared/errors" - "github.com/coreos/ignition/config/v2_3_experimental/types" + "github.com/coreos/ignition/config/v2_5_experimental/types" "github.com/coreos/ignition/config/validate/report" json "github.com/ajeddeloh/go-json" diff --git a/vendor/github.com/coreos/ignition/config/v1/types/config.go b/vendor/github.com/coreos/ignition/config/v1/types/config.go index f9215699cbd..3a369e4f3e8 100644 --- a/vendor/github.com/coreos/ignition/config/v1/types/config.go +++ b/vendor/github.com/coreos/ignition/config/v1/types/config.go @@ -14,10 +14,18 @@ package types +import "github.com/coreos/go-semver/semver" + const ( Version = 1 ) +var ( + MaxVersion = semver.Version{ + Major: Version, + } +) + type Config struct { Version int `json:"ignitionVersion"` Storage Storage `json:"storage,omitempty"` diff --git a/vendor/github.com/coreos/ignition/config/v2_0/append.go b/vendor/github.com/coreos/ignition/config/v2_0/append.go index cee6bc412e2..b005734b1e8 100644 --- a/vendor/github.com/coreos/ignition/config/v2_0/append.go +++ b/vendor/github.com/coreos/ignition/config/v2_0/append.go @@ -36,11 +36,10 @@ func Append(oldConfig, newConfig types.Config) types.Config { // appendStruct is an internal helper function to AppendConfig. Given two values // of structures (assumed to be the same type), recursively iterate over every // field in the struct, appending slices, recursively appending structs, and -// overwriting old values with the new for all other types. Individual fields -// are able to override their merge strategy using the "merge" tag. Accepted -// values are "new" or "old": "new" uses the new value, "old" uses the old -// value. These are currently only used for "ignition.config" and -// "ignition.version". +// overwriting old values with the new for all other types. Some individual +// struct fields have alternate merge strategies, determined by the field name. +// Currently these fields are "ignition.version", which uses the old value, and +// "ignition.config" which uses the new value. func appendStruct(vOld, vNew reflect.Value) reflect.Value { tOld := vOld.Type() vRes := reflect.New(tOld) @@ -50,11 +49,11 @@ func appendStruct(vOld, vNew reflect.Value) reflect.Value { vfNew := vNew.Field(i) vfRes := vRes.Elem().Field(i) - switch tOld.Field(i).Tag.Get("merge") { - case "old": + switch tOld.Field(i).Name { + case "Version": vfRes.Set(vfOld) continue - case "new": + case "Config": vfRes.Set(vfNew) continue } @@ -65,7 +64,11 @@ func appendStruct(vOld, vNew reflect.Value) reflect.Value { case reflect.Slice: vfRes.Set(reflect.AppendSlice(vfOld, vfNew)) default: - vfRes.Set(vfNew) + if vfNew.Kind() == reflect.Ptr && vfNew.IsNil() { + vfRes.Set(vfOld) + } else { + vfRes.Set(vfNew) + } } } diff --git a/vendor/github.com/coreos/ignition/config/v2_1/append.go b/vendor/github.com/coreos/ignition/config/v2_1/append.go index b1517b73106..9c8821e132d 100644 --- a/vendor/github.com/coreos/ignition/config/v2_1/append.go +++ b/vendor/github.com/coreos/ignition/config/v2_1/append.go @@ -64,7 +64,11 @@ func appendStruct(vOld, vNew reflect.Value) reflect.Value { case reflect.Slice: vfRes.Set(reflect.AppendSlice(vfOld, vfNew)) default: - vfRes.Set(vfNew) + if vfNew.Kind() == reflect.Ptr && vfNew.IsNil() { + vfRes.Set(vfOld) + } else { + vfRes.Set(vfNew) + } } } diff --git a/vendor/github.com/coreos/ignition/config/v2_1/types/url.go b/vendor/github.com/coreos/ignition/config/v2_1/types/url.go index 0fdc4a170ef..648328acb17 100644 --- a/vendor/github.com/coreos/ignition/config/v2_1/types/url.go +++ b/vendor/github.com/coreos/ignition/config/v2_1/types/url.go @@ -32,7 +32,14 @@ func validateURL(s string) error { } switch u.Scheme { - case "http", "https", "oem", "tftp", "s3": + case "http", "https", "oem", "tftp": + return nil + case "s3": + 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 { diff --git a/vendor/github.com/coreos/ignition/config/v2_2/types/url.go b/vendor/github.com/coreos/ignition/config/v2_2/types/url.go index 2e90ff6d07b..11148fc0824 100644 --- a/vendor/github.com/coreos/ignition/config/v2_2/types/url.go +++ b/vendor/github.com/coreos/ignition/config/v2_2/types/url.go @@ -33,7 +33,14 @@ func validateURL(s string) error { } switch u.Scheme { - case "http", "https", "oem", "tftp", "s3": + case "http", "https", "oem", "tftp": + return nil + case "s3": + 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 { diff --git a/vendor/github.com/coreos/ignition/config/v2_4/types/ca.go b/vendor/github.com/coreos/ignition/config/v2_4/types/ca.go new file mode 100644 index 00000000000..5a1f7663bc5 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/ca.go @@ -0,0 +1,58 @@ +// Copyright 2018 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (c CaReference) ValidateSource() report.Report { + err := validateURL(c.Source) + if err != nil { + return report.ReportFromError(err, report.EntryError) + } + return report.Report{} +} + +func (c CaReference) ValidateHTTPHeaders() report.Report { + r := report.Report{} + + if len(c.HTTPHeaders) < 1 { + return r + } + + u, err := url.Parse(c.Source) + if err != nil { + r.Add(report.Entry{ + Message: errors.ErrInvalidUrl.Error(), + Kind: report.EntryError, + }) + return r + } + + switch u.Scheme { + case "http", "https": + default: + r.Add(report.Entry{ + Message: errors.ErrUnsupportedSchemeForHTTPHeaders.Error(), + Kind: report.EntryError, + }) + } + + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_4/types/config.go b/vendor/github.com/coreos/ignition/config/v2_4/types/config.go new file mode 100644 index 00000000000..c0e028fc721 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/config.go @@ -0,0 +1,91 @@ +// Copyright 2015 CoreOS, 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" + + "github.com/coreos/go-semver/semver" + + "github.com/coreos/ignition/config/validate/report" +) + +var ( + MaxVersion = semver.Version{ + Major: 2, + Minor: 4, + } +) + +func (c Config) Validate() report.Report { + r := report.Report{} + rules := []rule{ + checkFilesFilesystems, + checkDuplicateFilesystems, + } + + for _, rule := range rules { + rule(c, &r) + } + return r +} + +type rule func(cfg Config, report *report.Report) + +func checkNodeFilesystems(node Node, filesystems map[string]struct{}, nodeType string) report.Report { + r := report.Report{} + if node.Filesystem == "" { + // Filesystem was not specified. This is an error, but its handled in types.File's Validate, not here + return r + } + _, ok := filesystems[node.Filesystem] + if !ok { + r.Add(report.Entry{ + Kind: report.EntryWarning, + Message: fmt.Sprintf("%v %q references nonexistent filesystem %q. (This is ok if it is defined in a referenced config)", + nodeType, node.Path, node.Filesystem), + }) + } + return r +} + +func checkFilesFilesystems(cfg Config, r *report.Report) { + filesystems := map[string]struct{}{"root": {}} + for _, filesystem := range cfg.Storage.Filesystems { + filesystems[filesystem.Name] = struct{}{} + } + for _, file := range cfg.Storage.Files { + r.Merge(checkNodeFilesystems(file.Node, filesystems, "File")) + } + for _, link := range cfg.Storage.Links { + r.Merge(checkNodeFilesystems(link.Node, filesystems, "Link")) + } + for _, dir := range cfg.Storage.Directories { + r.Merge(checkNodeFilesystems(dir.Node, filesystems, "Directory")) + } +} + +func checkDuplicateFilesystems(cfg Config, r *report.Report) { + filesystems := map[string]struct{}{"root": {}} + for _, filesystem := range cfg.Storage.Filesystems { + if _, ok := filesystems[filesystem.Name]; ok { + r.Add(report.Entry{ + Kind: report.EntryWarning, + Message: fmt.Sprintf("Filesystem %q shadows exising filesystem definition", filesystem.Name), + }) + } + filesystems[filesystem.Name] = struct{}{} + } +} diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/directory.go b/vendor/github.com/coreos/ignition/config/v2_4/types/directory.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/directory.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/directory.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/disk.go b/vendor/github.com/coreos/ignition/config/v2_4/types/disk.go similarity index 90% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/disk.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/disk.go index ebffc2cd674..1430b0fde01 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/disk.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/disk.go @@ -59,6 +59,12 @@ func (n Disk) ValidatePartitions() report.Report { Kind: report.EntryError, }) } + if n.partitionsUnitsMismatch() { + r.Add(report.Entry{ + Message: errors.ErrPartitionsUnitsMismatch.Error(), + Kind: report.EntryError, + }) + } // Disks which have no errors at this point will likely succeed in sgdisk return r } @@ -142,3 +148,17 @@ func (n Disk) partitionsMixZeroesAndNonexistence() bool { } return hasZero && hasShouldNotExist } + +func (n Disk) partitionsUnitsMismatch() bool { + partsInMb := false + partsNotInMb := false + for _, p := range n.Partitions { + if p.Size != nil || p.Start != nil { + partsNotInMb = true + } + if p.SizeMiB != nil || p.StartMiB != nil { + partsInMb = true + } + } + return partsInMb && partsNotInMb +} diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/file.go b/vendor/github.com/coreos/ignition/config/v2_4/types/file.go similarity index 78% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/file.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/file.go index 1897dc42c80..d5ca8d18e68 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/file.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/file.go @@ -16,6 +16,7 @@ package types import ( "fmt" + "net/url" "github.com/coreos/ignition/config/shared/errors" "github.com/coreos/ignition/config/validate/report" @@ -69,3 +70,31 @@ func (fc FileContents) ValidateSource() report.Report { } return r } + +func (fc FileContents) ValidateHTTPHeaders() report.Report { + r := report.Report{} + + if len(fc.HTTPHeaders) < 1 { + return r + } + + u, err := url.Parse(fc.Source) + if err != nil { + r.Add(report.Entry{ + Message: errors.ErrInvalidUrl.Error(), + Kind: report.EntryError, + }) + return r + } + + switch u.Scheme { + case "http", "https": + default: + r.Add(report.Entry{ + Message: errors.ErrUnsupportedSchemeForHTTPHeaders.Error(), + Kind: report.EntryError, + }) + } + + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/filesystem.go b/vendor/github.com/coreos/ignition/config/v2_4/types/filesystem.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/filesystem.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/filesystem.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/link.go b/vendor/github.com/coreos/ignition/config/v2_4/types/headers.go similarity index 56% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/link.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/headers.go index f0284425282..8dd25ffd96e 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/link.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/headers.go @@ -1,4 +1,4 @@ -// Copyright 2017 CoreOS, Inc. +// 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. @@ -15,19 +15,33 @@ package types import ( + "fmt" + + "github.com/coreos/ignition/config/shared/errors" "github.com/coreos/ignition/config/validate/report" ) -func (s LinkEmbedded1) ValidateTarget() report.Report { +func (h HTTPHeaders) Validate() report.Report { r := report.Report{} - if !s.Hard { - err := validatePath(s.Target) - if err != nil { + found := make(map[string]struct{}) + for _, header := range h { + // Header name can't be empty + if header.Name == "" { + r.Add(report.Entry{ + Message: errors.ErrEmptyHTTPHeaderName.Error(), + Kind: report.EntryError, + }) + continue + } + // Header names must be unique + if _, ok := found[header.Name]; ok { r.Add(report.Entry{ - Message: err.Error(), + Message: fmt.Sprintf("Found duplicate HTTP header: %q", header.Name), Kind: report.EntryError, }) + continue } + found[header.Name] = struct{}{} } return r } diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/ignition.go b/vendor/github.com/coreos/ignition/config/v2_4/types/ignition.go similarity index 75% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/ignition.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/ignition.go index bddf4958338..de7c2027571 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/ignition.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/ignition.go @@ -15,6 +15,8 @@ package types import ( + "net/url" + "github.com/coreos/go-semver/semver" "github.com/coreos/ignition/config/shared/errors" @@ -33,6 +35,34 @@ func (c ConfigReference) ValidateSource() report.Report { return r } +func (c ConfigReference) ValidateHTTPHeaders() report.Report { + r := report.Report{} + + if len(c.HTTPHeaders) < 1 { + return r + } + + u, err := url.Parse(c.Source) + if err != nil { + r.Add(report.Entry{ + Message: errors.ErrInvalidUrl.Error(), + Kind: report.EntryError, + }) + return r + } + + switch u.Scheme { + case "http", "https": + default: + r.Add(report.Entry{ + Message: errors.ErrUnsupportedSchemeForHTTPHeaders.Error(), + Kind: report.EntryError, + }) + } + + return r +} + func (v Ignition) Semver() (*semver.Version, error) { return semver.NewVersion(v.Version) } diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/mode.go b/vendor/github.com/coreos/ignition/config/v2_4/types/mode.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/mode.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/mode.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/node.go b/vendor/github.com/coreos/ignition/config/v2_4/types/node.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/node.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/node.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/partition.go b/vendor/github.com/coreos/ignition/config/v2_4/types/partition.go similarity index 77% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/partition.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/partition.go index 4e962b6391a..dbe38adcbca 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/partition.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/partition.go @@ -28,9 +28,33 @@ const ( ) func (p Partition) Validate() report.Report { + r := report.Report{} + if (p.Start != nil || p.Size != nil) && (p.StartMiB != nil || p.SizeMiB != nil) { + r.Add(report.Entry{ + Message: errors.ErrPartitionsUnitsMismatch.Error(), + Kind: report.EntryError, + }) + } if p.ShouldExist != nil && !*p.ShouldExist && (p.Label != nil || p.TypeGUID != "" || p.GUID != "" || p.Start != nil || p.Size != nil) { - return report.ReportFromError(errors.ErrShouldNotExistWithOthers, report.EntryError) + r.Add(report.Entry{ + Message: errors.ErrShouldNotExistWithOthers.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (p Partition) ValidateSize() report.Report { + if p.Size != nil { + return report.ReportFromError(errors.ErrSizeDeprecated, report.EntryDeprecated) + } + return report.Report{} +} + +func (p Partition) ValidateStart() report.Report { + if p.Start != nil { + return report.ReportFromError(errors.ErrStartDeprecated, report.EntryDeprecated) } return report.Report{} } diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/passwd.go b/vendor/github.com/coreos/ignition/config/v2_4/types/passwd.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/passwd.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/passwd.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/path.go b/vendor/github.com/coreos/ignition/config/v2_4/types/path.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/path.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/path.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/raid.go b/vendor/github.com/coreos/ignition/config/v2_4/types/raid.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/raid.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/raid.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/schema.go b/vendor/github.com/coreos/ignition/config/v2_4/types/schema.go similarity index 83% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/schema.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/schema.go index 73424c546ef..4bf7ec84174 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/schema.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/schema.go @@ -3,7 +3,8 @@ package types // generated by "schematyper --package=types schema/ignition.json -o internal/config/types/schema.go --root-type=Config" -- DO NOT EDIT type CaReference struct { - Source string `json:"source,omitempty"` + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` + Source string `json:"source"` Verification Verification `json:"verification,omitempty"` } @@ -16,7 +17,8 @@ type Config struct { } type ConfigReference struct { - Source string `json:"source,omitempty"` + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` + Source string `json:"source"` Verification Verification `json:"verification,omitempty"` } @@ -39,7 +41,7 @@ type DirectoryEmbedded1 struct { } type Disk struct { - Device string `json:"device,omitempty"` + Device string `json:"device"` Partitions []Partition `json:"partitions,omitempty"` WipeTable bool `json:"wipeTable,omitempty"` } @@ -51,6 +53,7 @@ type File struct { type FileContents struct { Compression string `json:"compression,omitempty"` + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` Source string `json:"source,omitempty"` Verification Verification `json:"verification,omitempty"` } @@ -69,8 +72,16 @@ type Filesystem struct { type Group string +type HTTPHeader struct { + Name string `json:"name"` + Value string `json:"value"` +} + +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,omitempty"` @@ -88,13 +99,13 @@ type Link struct { type LinkEmbedded1 struct { Hard bool `json:"hard,omitempty"` - Target string `json:"target,omitempty"` + Target string `json:"target"` } type Mount struct { Create *Create `json:"create,omitempty"` - Device string `json:"device,omitempty"` - Format string `json:"format,omitempty"` + Device string `json:"device"` + Format string `json:"format"` Label *string `json:"label,omitempty"` Options []MountOption `json:"options,omitempty"` UUID *string `json:"uuid,omitempty"` @@ -109,20 +120,22 @@ type Networkd struct { type NetworkdDropin struct { Contents string `json:"contents,omitempty"` - Name string `json:"name,omitempty"` + Name string `json:"name"` } type Networkdunit struct { Contents string `json:"contents,omitempty"` Dropins []NetworkdDropin `json:"dropins,omitempty"` - Name string `json:"name,omitempty"` + Name string `json:"name"` } +type NoProxyItem string + type Node struct { - Filesystem string `json:"filesystem,omitempty"` + Filesystem string `json:"filesystem"` Group *NodeGroup `json:"group,omitempty"` Overwrite *bool `json:"overwrite,omitempty"` - Path string `json:"path,omitempty"` + Path string `json:"path"` User *NodeUser `json:"user,omitempty"` } @@ -142,7 +155,9 @@ type Partition struct { Number int `json:"number,omitempty"` ShouldExist *bool `json:"shouldExist,omitempty"` Size *int `json:"size,omitempty"` + SizeMiB *int `json:"sizeMiB,omitempty"` Start *int `json:"start,omitempty"` + StartMiB *int `json:"startMiB,omitempty"` TypeGUID string `json:"typeGuid,omitempty"` WipePartitionEntry bool `json:"wipePartitionEntry,omitempty"` } @@ -154,7 +169,7 @@ type Passwd struct { type PasswdGroup struct { Gid *int `json:"gid,omitempty"` - Name string `json:"name,omitempty"` + Name string `json:"name"` PasswordHash string `json:"passwordHash,omitempty"` System bool `json:"system,omitempty"` } @@ -164,7 +179,7 @@ type PasswdUser struct { Gecos string `json:"gecos,omitempty"` Groups []Group `json:"groups,omitempty"` HomeDir string `json:"homeDir,omitempty"` - Name string `json:"name,omitempty"` + Name string `json:"name"` NoCreateHome bool `json:"noCreateHome,omitempty"` NoLogInit bool `json:"noLogInit,omitempty"` NoUserGroup bool `json:"noUserGroup,omitempty"` @@ -176,10 +191,16 @@ type PasswdUser struct { 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,omitempty"` + Devices []Device `json:"devices"` + Level string `json:"level"` + Name string `json:"name"` Options []RaidOption `json:"options,omitempty"` Spares int `json:"spares,omitempty"` } @@ -207,7 +228,7 @@ type Systemd struct { type SystemdDropin struct { Contents string `json:"contents,omitempty"` - Name string `json:"name,omitempty"` + Name string `json:"name"` } type TLS struct { @@ -225,7 +246,7 @@ type Unit struct { Enable bool `json:"enable,omitempty"` Enabled *bool `json:"enabled,omitempty"` Mask bool `json:"mask,omitempty"` - Name string `json:"name,omitempty"` + Name string `json:"name"` } type Usercreate struct { diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/unit.go b/vendor/github.com/coreos/ignition/config/v2_4/types/unit.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/unit.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/unit.go diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/url.go b/vendor/github.com/coreos/ignition/config/v2_4/types/url.go similarity index 84% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/url.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/url.go index 2e90ff6d07b..11148fc0824 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/url.go +++ b/vendor/github.com/coreos/ignition/config/v2_4/types/url.go @@ -33,7 +33,14 @@ func validateURL(s string) error { } switch u.Scheme { - case "http", "https", "oem", "tftp", "s3": + case "http", "https", "oem", "tftp": + return nil + case "s3": + 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 { diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/verification.go b/vendor/github.com/coreos/ignition/config/v2_4/types/verification.go similarity index 100% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/verification.go rename to vendor/github.com/coreos/ignition/config/v2_4/types/verification.go diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ca.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ca.go new file mode 100644 index 00000000000..5a1f7663bc5 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ca.go @@ -0,0 +1,58 @@ +// Copyright 2018 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (c CaReference) ValidateSource() report.Report { + err := validateURL(c.Source) + if err != nil { + return report.ReportFromError(err, report.EntryError) + } + return report.Report{} +} + +func (c CaReference) ValidateHTTPHeaders() report.Report { + r := report.Report{} + + if len(c.HTTPHeaders) < 1 { + return r + } + + u, err := url.Parse(c.Source) + if err != nil { + r.Add(report.Entry{ + Message: errors.ErrInvalidUrl.Error(), + Kind: report.EntryError, + }) + return r + } + + switch u.Scheme { + case "http", "https": + default: + r.Add(report.Entry{ + Message: errors.ErrUnsupportedSchemeForHTTPHeaders.Error(), + Kind: report.EntryError, + }) + } + + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/config.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/config.go similarity index 99% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/config.go rename to vendor/github.com/coreos/ignition/config/v2_5_experimental/types/config.go index cfef0ed9dac..601330d2ce1 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/config.go +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/config.go @@ -25,7 +25,7 @@ import ( var ( MaxVersion = semver.Version{ Major: 2, - Minor: 3, + Minor: 5, PreRelease: "experimental", } ) diff --git a/vendor/github.com/coreos/ignition/config/v2_1/types/link.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/directory.go similarity index 66% rename from vendor/github.com/coreos/ignition/config/v2_1/types/link.go rename to vendor/github.com/coreos/ignition/config/v2_5_experimental/types/directory.go index f0284425282..9fdc732a644 100644 --- a/vendor/github.com/coreos/ignition/config/v2_1/types/link.go +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/directory.go @@ -15,19 +15,23 @@ package types import ( + "github.com/coreos/ignition/config/shared/errors" "github.com/coreos/ignition/config/validate/report" ) -func (s LinkEmbedded1) ValidateTarget() report.Report { +func (d Directory) ValidateMode() report.Report { r := report.Report{} - if !s.Hard { - err := validatePath(s.Target) - if err != nil { - r.Add(report.Entry{ - Message: err.Error(), - Kind: report.EntryError, - }) - } + if err := validateMode(d.Mode); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + if d.Mode == nil { + r.Add(report.Entry{ + Message: errors.ErrPermissionsUnset.Error(), + Kind: report.EntryWarning, + }) } return r } diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/disk.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/disk.go new file mode 100644 index 00000000000..1430b0fde01 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/disk.go @@ -0,0 +1,164 @@ +// Copyright 2016 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (n Disk) Validate() report.Report { + return report.Report{} +} + +func (n Disk) ValidateDevice() report.Report { + if len(n.Device) == 0 { + return report.ReportFromError(errors.ErrDiskDeviceRequired, report.EntryError) + } + if err := validatePath(string(n.Device)); err != nil { + return report.ReportFromError(err, report.EntryError) + } + return report.Report{} +} + +func (n Disk) ValidatePartitions() report.Report { + r := report.Report{} + if n.partitionNumbersCollide() { + r.Add(report.Entry{ + Message: errors.ErrPartitionNumbersCollide.Error(), + Kind: report.EntryError, + }) + } + if n.partitionsOverlap() { + r.Add(report.Entry{ + Message: errors.ErrPartitionsOverlap.Error(), + Kind: report.EntryError, + }) + } + if n.partitionsMisaligned() { + r.Add(report.Entry{ + Message: errors.ErrPartitionsMisaligned.Error(), + Kind: report.EntryError, + }) + } + if n.partitionsMixZeroesAndNonexistence() { + r.Add(report.Entry{ + Message: errors.ErrZeroesWithShouldNotExist.Error(), + Kind: report.EntryError, + }) + } + if n.partitionsUnitsMismatch() { + r.Add(report.Entry{ + Message: errors.ErrPartitionsUnitsMismatch.Error(), + Kind: report.EntryError, + }) + } + // Disks which have no errors at this point will likely succeed in sgdisk + return r +} + +// partitionNumbersCollide returns true if partition numbers in n.Partitions are not unique. +func (n Disk) partitionNumbersCollide() bool { + m := map[int][]Partition{} + for _, 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], p) + } + } + for _, n := range m { + if len(n) > 1 { + // TODO(vc): return information describing the collision for logging + return true + } + } + return false +} + +// 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.Size == 0 { + // a size of 0 means "fill available", just return the start as the end for those. + return *p.Start + } + return *p.Start + *p.Size - 1 +} + +// partitionsOverlap returns true if any explicitly dimensioned partitions overlap +func (n Disk) partitionsOverlap() bool { + 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.Start == nil || p.Size == nil || *p.Start == 0 { + continue + } + + for _, o := range n.Partitions { + if o.Start == nil || o.Size == nil || p == o || *o.Start == 0 { + continue + } + + // is p.Start within o? + if *p.Start >= *o.Start && *p.Start <= o.end() { + return true + } + + // is p.end() within o? + if p.end() >= *o.Start && p.end() <= o.end() { + return true + } + + // do p.Start and p.end() straddle o? + if *p.Start < *o.Start && p.end() > o.end() { + return true + } + } + } + return false +} + +// partitionsMisaligned returns true if any of the partitions don't start on a 2048-sector (1MiB) boundary. +func (n Disk) partitionsMisaligned() bool { + for _, p := range n.Partitions { + if p.Start != nil && ((*p.Start & (2048 - 1)) != 0) { + return true + } + } + return false +} + +func (n Disk) partitionsMixZeroesAndNonexistence() bool { + hasZero := false + hasShouldNotExist := false + for _, p := range n.Partitions { + hasShouldNotExist = hasShouldNotExist || (p.ShouldExist != nil && !*p.ShouldExist) + hasZero = hasZero || (p.Number == 0) + } + return hasZero && hasShouldNotExist +} + +func (n Disk) partitionsUnitsMismatch() bool { + partsInMb := false + partsNotInMb := false + for _, p := range n.Partitions { + if p.Size != nil || p.Start != nil { + partsNotInMb = true + } + if p.SizeMiB != nil || p.StartMiB != nil { + partsInMb = true + } + } + return partsInMb && partsNotInMb +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/file.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/file.go new file mode 100644 index 00000000000..d5ca8d18e68 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/file.go @@ -0,0 +1,100 @@ +// Copyright 2016 CoreOS, 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" + "net/url" + + "github.com/coreos/ignition/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (f File) Validate() report.Report { + if f.Overwrite != nil && *f.Overwrite && f.Append { + return report.ReportFromError(errors.ErrAppendAndOverwrite, report.EntryError) + } + return report.Report{} +} + +func (f File) ValidateMode() report.Report { + r := report.Report{} + if err := validateMode(f.Mode); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + if f.Mode == nil { + r.Add(report.Entry{ + Message: errors.ErrPermissionsUnset.Error(), + Kind: report.EntryWarning, + }) + } + return r +} + +func (fc FileContents) ValidateCompression() report.Report { + r := report.Report{} + switch fc.Compression { + case "", "gzip": + default: + r.Add(report.Entry{ + Message: errors.ErrCompressionInvalid.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (fc FileContents) ValidateSource() report.Report { + r := report.Report{} + err := validateURL(fc.Source) + if err != nil { + r.Add(report.Entry{ + Message: fmt.Sprintf("invalid url %q: %v", fc.Source, err), + Kind: report.EntryError, + }) + } + return r +} + +func (fc FileContents) ValidateHTTPHeaders() report.Report { + r := report.Report{} + + if len(fc.HTTPHeaders) < 1 { + return r + } + + u, err := url.Parse(fc.Source) + if err != nil { + r.Add(report.Entry{ + Message: errors.ErrInvalidUrl.Error(), + Kind: report.EntryError, + }) + return r + } + + switch u.Scheme { + case "http", "https": + default: + r.Add(report.Entry{ + Message: errors.ErrUnsupportedSchemeForHTTPHeaders.Error(), + Kind: report.EntryError, + }) + } + + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/filesystem.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/filesystem.go new file mode 100644 index 00000000000..2e847da69d0 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/filesystem.go @@ -0,0 +1,146 @@ +// Copyright 2016 CoreOS, 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" + + "github.com/coreos/ignition/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (f Filesystem) Validate() report.Report { + r := report.Report{} + if f.Mount == nil && f.Path == nil { + r.Add(report.Entry{ + Message: errors.ErrFilesystemNoMountPath.Error(), + Kind: report.EntryError, + }) + } + if f.Mount != nil { + if f.Path != nil { + r.Add(report.Entry{ + Message: errors.ErrFilesystemMountAndPath.Error(), + Kind: report.EntryError, + }) + } + if f.Mount.Create != nil { + if f.Mount.WipeFilesystem { + r.Add(report.Entry{ + Message: errors.ErrUsedCreateAndWipeFilesystem.Error(), + Kind: report.EntryError, + }) + } + if len(f.Mount.Options) > 0 { + r.Add(report.Entry{ + Message: errors.ErrUsedCreateAndMountOpts.Error(), + Kind: report.EntryError, + }) + } + r.Add(report.Entry{ + Message: errors.ErrWarningCreateDeprecated.Error(), + Kind: report.EntryWarning, + }) + } + } + return r +} + +func (f Filesystem) ValidatePath() report.Report { + r := report.Report{} + if f.Path != nil && validatePath(*f.Path) != nil { + r.Add(report.Entry{ + Message: fmt.Sprintf("filesystem %q: path not absolute", f.Name), + Kind: report.EntryError, + }) + } + return r +} + +func (m Mount) Validate() report.Report { + r := report.Report{} + switch m.Format { + case "ext4", "btrfs", "xfs", "swap", "vfat": + default: + r.Add(report.Entry{ + Message: errors.ErrFilesystemInvalidFormat.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (m Mount) ValidateDevice() report.Report { + r := report.Report{} + if err := validatePath(m.Device); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (m Mount) ValidateLabel() report.Report { + r := report.Report{} + if m.Label == nil { + return r + } + switch m.Format { + case "ext4": + if len(*m.Label) > 16 { + // source: man mkfs.ext4 + r.Add(report.Entry{ + Message: errors.ErrExt4LabelTooLong.Error(), + Kind: report.EntryError, + }) + } + case "btrfs": + if len(*m.Label) > 256 { + // source: man mkfs.btrfs + r.Add(report.Entry{ + Message: errors.ErrBtrfsLabelTooLong.Error(), + Kind: report.EntryError, + }) + } + case "xfs": + if len(*m.Label) > 12 { + // source: man mkfs.xfs + r.Add(report.Entry{ + Message: errors.ErrXfsLabelTooLong.Error(), + Kind: report.EntryError, + }) + } + 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(*m.Label) > 15 { + r.Add(report.Entry{ + Message: errors.ErrSwapLabelTooLong.Error(), + Kind: report.EntryError, + }) + } + case "vfat": + if len(*m.Label) > 11 { + // source: man mkfs.fat + r.Add(report.Entry{ + Message: errors.ErrVfatLabelTooLong.Error(), + Kind: report.EntryError, + }) + } + } + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/headers.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/headers.go new file mode 100644 index 00000000000..8dd25ffd96e --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/headers.go @@ -0,0 +1,47 @@ +// 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" + + "github.com/coreos/ignition/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (h HTTPHeaders) Validate() report.Report { + r := report.Report{} + found := make(map[string]struct{}) + for _, header := range h { + // Header name can't be empty + if header.Name == "" { + r.Add(report.Entry{ + Message: errors.ErrEmptyHTTPHeaderName.Error(), + Kind: report.EntryError, + }) + continue + } + // Header names must be unique + if _, ok := found[header.Name]; ok { + r.Add(report.Entry{ + Message: fmt.Sprintf("Found duplicate HTTP header: %q", header.Name), + Kind: report.EntryError, + }) + continue + } + found[header.Name] = struct{}{} + } + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ignition.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ignition.go new file mode 100644 index 00000000000..de7c2027571 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/ignition.go @@ -0,0 +1,82 @@ +// Copyright 2015 CoreOS, 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/go-semver/semver" + + "github.com/coreos/ignition/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (c ConfigReference) ValidateSource() report.Report { + r := report.Report{} + err := validateURL(c.Source) + if err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (c ConfigReference) ValidateHTTPHeaders() report.Report { + r := report.Report{} + + if len(c.HTTPHeaders) < 1 { + return r + } + + u, err := url.Parse(c.Source) + if err != nil { + r.Add(report.Entry{ + Message: errors.ErrInvalidUrl.Error(), + Kind: report.EntryError, + }) + return r + } + + switch u.Scheme { + case "http", "https": + default: + r.Add(report.Entry{ + Message: errors.ErrUnsupportedSchemeForHTTPHeaders.Error(), + Kind: report.EntryError, + }) + } + + return r +} + +func (v Ignition) Semver() (*semver.Version, error) { + return semver.NewVersion(v.Version) +} + +func (v Ignition) Validate() report.Report { + tv, err := v.Semver() + if err != nil { + return report.ReportFromError(errors.ErrInvalidVersion, report.EntryError) + } + if MaxVersion.Major > tv.Major { + return report.ReportFromError(errors.ErrOldVersion, report.EntryError) + } + if MaxVersion.LessThan(*tv) { + return report.ReportFromError(errors.ErrNewVersion, report.EntryError) + } + return report.Report{} +} diff --git a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/ca.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/mode.go similarity index 69% rename from vendor/github.com/coreos/ignition/config/v2_3_experimental/types/ca.go rename to vendor/github.com/coreos/ignition/config/v2_5_experimental/types/mode.go index 7440e1e2f3b..d06045d6753 100644 --- a/vendor/github.com/coreos/ignition/config/v2_3_experimental/types/ca.go +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/mode.go @@ -1,4 +1,4 @@ -// Copyright 2018 CoreOS, Inc. +// Copyright 2017 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,13 +15,12 @@ package types import ( - "github.com/coreos/ignition/config/validate/report" + "github.com/coreos/ignition/config/shared/errors" ) -func (c CaReference) ValidateSource() report.Report { - err := validateURL(c.Source) - if err != nil { - return report.ReportFromError(err, report.EntryError) +func validateMode(m *int) error { + if m != nil && (*m < 0 || *m > 07777) { + return errors.ErrFileIllegalMode } - return report.Report{} + return nil } diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/node.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/node.go new file mode 100644 index 00000000000..50badfdfb92 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/node.go @@ -0,0 +1,73 @@ +// Copyright 2016 CoreOS, 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/filepath" + + "github.com/coreos/ignition/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (n Node) ValidateFilesystem() report.Report { + r := report.Report{} + if n.Filesystem == "" { + r.Add(report.Entry{ + Message: errors.ErrNoFilesystem.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (n Node) ValidatePath() report.Report { + r := report.Report{} + if err := validatePath(n.Path); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (n Node) Depth() int { + count := 0 + for p := filepath.Clean(string(n.Path)); p != "/"; count++ { + p = filepath.Dir(p) + } + return count +} + +func (nu NodeUser) Validate() report.Report { + r := report.Report{} + if nu.ID != nil && nu.Name != "" { + r.Add(report.Entry{ + Message: errors.ErrBothIDAndNameSet.Error(), + Kind: report.EntryError, + }) + } + return r +} +func (ng NodeGroup) Validate() report.Report { + r := report.Report{} + if ng.ID != nil && ng.Name != "" { + r.Add(report.Entry{ + Message: errors.ErrBothIDAndNameSet.Error(), + Kind: report.EntryError, + }) + } + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/partition.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/partition.go new file mode 100644 index 00000000000..dbe38adcbca --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/partition.go @@ -0,0 +1,112 @@ +// Copyright 2016 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +const ( + guidRegexStr = "^(|[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12})$" +) + +func (p Partition) Validate() report.Report { + r := report.Report{} + if (p.Start != nil || p.Size != nil) && (p.StartMiB != nil || p.SizeMiB != nil) { + r.Add(report.Entry{ + Message: errors.ErrPartitionsUnitsMismatch.Error(), + Kind: report.EntryError, + }) + } + if p.ShouldExist != nil && !*p.ShouldExist && + (p.Label != nil || p.TypeGUID != "" || p.GUID != "" || p.Start != nil || p.Size != nil) { + r.Add(report.Entry{ + Message: errors.ErrShouldNotExistWithOthers.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (p Partition) ValidateSize() report.Report { + if p.Size != nil { + return report.ReportFromError(errors.ErrSizeDeprecated, report.EntryDeprecated) + } + return report.Report{} +} + +func (p Partition) ValidateStart() report.Report { + if p.Start != nil { + return report.ReportFromError(errors.ErrStartDeprecated, report.EntryDeprecated) + } + return report.Report{} +} + +func (p Partition) ValidateLabel() report.Report { + r := report.Report{} + if p.Label == nil { + return r + } + // 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 { + r.Add(report.Entry{ + Message: errors.ErrLabelTooLong.Error(), + Kind: report.EntryError, + }) + } + + // sgdisk uses colons for delimitting compound arguments and does not allow escaping them. + if strings.Contains(*p.Label, ":") { + r.Add(report.Entry{ + Message: errors.ErrLabelContainsColon.Error(), + Kind: report.EntryWarning, + }) + } + return r +} + +func (p Partition) ValidateTypeGUID() report.Report { + return validateGUID(p.TypeGUID) +} + +func (p Partition) ValidateGUID() report.Report { + return validateGUID(p.GUID) +} + +func validateGUID(guid string) report.Report { + r := report.Report{} + ok, err := regexp.MatchString(guidRegexStr, guid) + if err != nil { + r.Add(report.Entry{ + Message: fmt.Sprintf("error matching guid regexp: %v", err), + Kind: report.EntryError, + }) + } else if !ok { + r.Add(report.Entry{ + Message: errors.ErrDoesntMatchGUIDRegex.Error(), + Kind: report.EntryError, + }) + } + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/passwd.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/passwd.go new file mode 100644 index 00000000000..10508c56c06 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/passwd.go @@ -0,0 +1,67 @@ +// Copyright 2017 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (p PasswdUser) Validate() report.Report { + r := report.Report{} + if p.Create != nil { + r.Add(report.Entry{ + Message: errors.ErrPasswdCreateDeprecated.Error(), + Kind: report.EntryWarning, + }) + addErr := func(err error) { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + if p.Gecos != "" { + addErr(errors.ErrPasswdCreateAndGecos) + } + if len(p.Groups) > 0 { + addErr(errors.ErrPasswdCreateAndGroups) + } + if p.HomeDir != "" { + addErr(errors.ErrPasswdCreateAndHomeDir) + } + if p.NoCreateHome { + addErr(errors.ErrPasswdCreateAndNoCreateHome) + } + if p.NoLogInit { + addErr(errors.ErrPasswdCreateAndNoLogInit) + } + if p.NoUserGroup { + addErr(errors.ErrPasswdCreateAndNoUserGroup) + } + if p.PrimaryGroup != "" { + addErr(errors.ErrPasswdCreateAndPrimaryGroup) + } + if p.Shell != "" { + addErr(errors.ErrPasswdCreateAndShell) + } + if p.System { + addErr(errors.ErrPasswdCreateAndSystem) + } + if p.UID != nil { + addErr(errors.ErrPasswdCreateAndUID) + } + } + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_2/types/link.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/path.go similarity index 64% rename from vendor/github.com/coreos/ignition/config/v2_2/types/link.go rename to vendor/github.com/coreos/ignition/config/v2_5_experimental/types/path.go index f0284425282..780607c31ab 100644 --- a/vendor/github.com/coreos/ignition/config/v2_2/types/link.go +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/path.go @@ -1,4 +1,4 @@ -// Copyright 2017 CoreOS, Inc. +// Copyright 2016 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,19 +15,14 @@ package types import ( - "github.com/coreos/ignition/config/validate/report" + "path" + + "github.com/coreos/ignition/config/shared/errors" ) -func (s LinkEmbedded1) ValidateTarget() report.Report { - r := report.Report{} - if !s.Hard { - err := validatePath(s.Target) - if err != nil { - r.Add(report.Entry{ - Message: err.Error(), - Kind: report.EntryError, - }) - } +func validatePath(p string) error { + if !path.IsAbs(p) { + return errors.ErrPathRelative } - return r + return nil } diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/raid.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/raid.go new file mode 100644 index 00000000000..3aceaa9faa1 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/raid.go @@ -0,0 +1,57 @@ +// Copyright 2016 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/report" +) + +func (n Raid) ValidateLevel() report.Report { + r := report.Report{} + switch n.Level { + case "linear", "raid0", "0", "stripe": + if n.Spares != 0 { + r.Add(report.Entry{ + Message: errors.ErrSparesUnsupportedForLevel.Error(), + Kind: report.EntryError, + }) + } + case "raid1", "1", "mirror": + case "raid4", "4": + case "raid5", "5": + case "raid6", "6": + case "raid10", "10": + default: + r.Add(report.Entry{ + Message: errors.ErrUnrecognizedRaidLevel.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (n Raid) ValidateDevices() report.Report { + r := report.Report{} + for _, d := range n.Devices { + if err := validatePath(string(d)); err != nil { + r.Add(report.Entry{ + Message: errors.ErrPathRelative.Error(), + Kind: report.EntryError, + }) + } + } + return r +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/schema.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/schema.go new file mode 100644 index 00000000000..4bf7ec84174 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/schema.go @@ -0,0 +1,269 @@ +package types + +// generated by "schematyper --package=types schema/ignition.json -o internal/config/types/schema.go --root-type=Config" -- DO NOT EDIT + +type CaReference struct { + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` + Source string `json:"source"` + Verification Verification `json:"verification,omitempty"` +} + +type Config struct { + Ignition Ignition `json:"ignition"` + Networkd Networkd `json:"networkd,omitempty"` + Passwd Passwd `json:"passwd,omitempty"` + Storage Storage `json:"storage,omitempty"` + Systemd Systemd `json:"systemd,omitempty"` +} + +type ConfigReference struct { + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` + Source string `json:"source"` + Verification Verification `json:"verification,omitempty"` +} + +type Create struct { + Force bool `json:"force,omitempty"` + Options []CreateOption `json:"options,omitempty"` +} + +type CreateOption string + +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 File struct { + Node + FileEmbedded1 +} + +type FileContents struct { + Compression string `json:"compression,omitempty"` + HTTPHeaders HTTPHeaders `json:"httpHeaders,omitempty"` + Source string `json:"source,omitempty"` + Verification Verification `json:"verification,omitempty"` +} + +type FileEmbedded1 struct { + Append bool `json:"append,omitempty"` + Contents FileContents `json:"contents,omitempty"` + Mode *int `json:"mode,omitempty"` +} + +type Filesystem struct { + Mount *Mount `json:"mount,omitempty"` + Name string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` +} + +type Group string + +type HTTPHeader struct { + Name string `json:"name"` + Value string `json:"value"` +} + +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,omitempty"` +} + +type IgnitionConfig struct { + Append []ConfigReference `json:"append,omitempty"` + Replace *ConfigReference `json:"replace,omitempty"` +} + +type Link struct { + Node + LinkEmbedded1 +} + +type LinkEmbedded1 struct { + Hard bool `json:"hard,omitempty"` + Target string `json:"target"` +} + +type Mount struct { + Create *Create `json:"create,omitempty"` + Device string `json:"device"` + Format string `json:"format"` + Label *string `json:"label,omitempty"` + Options []MountOption `json:"options,omitempty"` + UUID *string `json:"uuid,omitempty"` + WipeFilesystem bool `json:"wipeFilesystem,omitempty"` +} + +type MountOption string + +type Networkd struct { + Units []Networkdunit `json:"units,omitempty"` +} + +type NetworkdDropin struct { + Contents string `json:"contents,omitempty"` + Name string `json:"name"` +} + +type Networkdunit struct { + Contents string `json:"contents,omitempty"` + Dropins []NetworkdDropin `json:"dropins,omitempty"` + Name string `json:"name"` +} + +type NoProxyItem string + +type Node struct { + Filesystem string `json:"filesystem"` + 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 Partition struct { + GUID string `json:"guid,omitempty"` + Label *string `json:"label,omitempty"` + Number int `json:"number,omitempty"` + ShouldExist *bool `json:"shouldExist,omitempty"` + Size *int `json:"size,omitempty"` + SizeMiB *int `json:"sizeMiB,omitempty"` + Start *int `json:"start,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"` + System bool `json:"system,omitempty"` +} + +type PasswdUser struct { + Create *Usercreate `json:"create,omitempty"` + 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"` + 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"` + Level string `json:"level"` + Name string `json:"name"` + Options []RaidOption `json:"options,omitempty"` + Spares int `json:"spares,omitempty"` +} + +type RaidOption string + +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"` + Raid []Raid `json:"raid,omitempty"` +} + +type Systemd struct { + Units []Unit `json:"units,omitempty"` +} + +type SystemdDropin struct { + Contents string `json:"contents,omitempty"` + Name string `json:"name"` +} + +type TLS struct { + CertificateAuthorities []CaReference `json:"certificateAuthorities,omitempty"` +} + +type Timeouts struct { + HTTPResponseHeaders *int `json:"httpResponseHeaders,omitempty"` + HTTPTotal *int `json:"httpTotal,omitempty"` +} + +type Unit struct { + Contents string `json:"contents,omitempty"` + Dropins []SystemdDropin `json:"dropins,omitempty"` + Enable bool `json:"enable,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Mask bool `json:"mask,omitempty"` + Name string `json:"name"` +} + +type Usercreate struct { + Gecos string `json:"gecos,omitempty"` + Groups []UsercreateGroup `json:"groups,omitempty"` + HomeDir string `json:"homeDir,omitempty"` + NoCreateHome bool `json:"noCreateHome,omitempty"` + NoLogInit bool `json:"noLogInit,omitempty"` + NoUserGroup bool `json:"noUserGroup,omitempty"` + PrimaryGroup string `json:"primaryGroup,omitempty"` + Shell string `json:"shell,omitempty"` + System bool `json:"system,omitempty"` + UID *int `json:"uid,omitempty"` +} + +type UsercreateGroup string + +type Verification struct { + Hash *string `json:"hash,omitempty"` +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/unit.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/unit.go new file mode 100644 index 00000000000..70fe1179a45 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/unit.go @@ -0,0 +1,131 @@ +// Copyright 2016 CoreOS, 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" + "path" + "strings" + + "github.com/coreos/go-systemd/unit" + + "github.com/coreos/ignition/config/shared/errors" + "github.com/coreos/ignition/config/shared/validations" + "github.com/coreos/ignition/config/validate/report" +) + +func (u Unit) ValidateContents() report.Report { + r := report.Report{} + opts, err := validateUnitContent(u.Contents) + if err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + + isEnabled := u.Enable || (u.Enabled != nil && *u.Enabled) + r.Merge(validations.ValidateInstallSection(u.Name, isEnabled, u.Contents == "", opts)) + + return r +} + +func (u Unit) ValidateName() report.Report { + r := report.Report{} + switch path.Ext(u.Name) { + case ".service", ".socket", ".device", ".mount", ".automount", ".swap", ".target", ".path", ".timer", ".snapshot", ".slice", ".scope": + default: + r.Add(report.Entry{ + Message: errors.ErrInvalidSystemdExt.Error(), + Kind: report.EntryError, + }) + } + return r +} + +func (d SystemdDropin) Validate() report.Report { + r := report.Report{} + + if _, err := validateUnitContent(d.Contents); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + + switch path.Ext(d.Name) { + case ".conf": + default: + r.Add(report.Entry{ + Message: errors.ErrInvalidSystemdDropinExt.Error(), + Kind: report.EntryError, + }) + } + + return r +} + +func (u Networkdunit) Validate() report.Report { + r := report.Report{} + + if _, err := validateUnitContent(u.Contents); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + + switch path.Ext(u.Name) { + case ".link", ".netdev", ".network": + default: + r.Add(report.Entry{ + Message: errors.ErrInvalidNetworkdExt.Error(), + Kind: report.EntryError, + }) + } + + return r +} + +func (d NetworkdDropin) Validate() report.Report { + r := report.Report{} + + if _, err := validateUnitContent(d.Contents); err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + } + + switch path.Ext(d.Name) { + case ".conf": + default: + r.Add(report.Entry{ + Message: errors.ErrInvalidNetworkdDropinExt.Error(), + Kind: report.EntryError, + }) + } + + return r +} + +func validateUnitContent(content string) ([]*unit.UnitOption, error) { + c := strings.NewReader(content) + opts, err := unit.Deserialize(c) + if err != nil { + return nil, fmt.Errorf("invalid unit content: %s", err) + } + return opts, nil +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/url.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/url.go new file mode 100644 index 00000000000..11148fc0824 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/url.go @@ -0,0 +1,53 @@ +// Copyright 2016 CoreOS, 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/vincent-petithory/dataurl" + + "github.com/coreos/ignition/config/shared/errors" +) + +func validateURL(s string) error { + // Empty url is valid, indicates an empty file + if s == "" { + return nil + } + u, err := url.Parse(s) + if err != nil { + return errors.ErrInvalidUrl + } + + switch u.Scheme { + case "http", "https", "oem", "tftp": + return nil + case "s3": + 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 + } +} diff --git a/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/verification.go b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/verification.go new file mode 100644 index 00000000000..51e7d1550a3 --- /dev/null +++ b/vendor/github.com/coreos/ignition/config/v2_5_experimental/types/verification.go @@ -0,0 +1,77 @@ +// Copyright 2016 CoreOS, 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/config/shared/errors" + "github.com/coreos/ignition/config/validate/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() report.Report { + r := report.Report{} + + if v.Hash == nil { + // The hash can be nil + return r + } + + function, sum, err := v.HashParts() + if err != nil { + r.Add(report.Entry{ + Message: err.Error(), + Kind: report.EntryError, + }) + return r + } + var hash crypto.Hash + switch function { + case "sha512": + hash = crypto.SHA512 + default: + r.Add(report.Entry{ + Message: errors.ErrHashUnrecognized.Error(), + Kind: report.EntryError, + }) + return r + } + + if len(sum) != hex.EncodedLen(hash.Size()) { + r.Add(report.Entry{ + Message: errors.ErrHashWrongSize.Error(), + Kind: report.EntryError, + }) + } + + return r +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/doc.go new file mode 100644 index 00000000000..0c12bf2e077 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/doc.go @@ -0,0 +1,48 @@ +/* +Package imagedata enables management of image data. + +Example to Upload Image Data + + imageID := "da3b75d9-3f4a-40e7-8a2c-bfab23927dea" + + imageData, err := os.Open("/path/to/image/file") + if err != nil { + panic(err) + } + defer imageData.Close() + + err = imagedata.Upload(imageClient, imageID, imageData).ExtractErr() + if err != nil { + panic(err) + } + +Example to Stage Image Data + + imageID := "da3b75d9-3f4a-40e7-8a2c-bfab23927dea" + + imageData, err := os.Open("/path/to/image/file") + if err != nil { + panic(err) + } + defer imageData.Close() + + err = imagedata.Stage(imageClient, imageID, imageData).ExtractErr() + if err != nil { + panic(err) + } + +Example to Download Image Data + + imageID := "da3b75d9-3f4a-40e7-8a2c-bfab23927dea" + + image, err := imagedata.Download(imageClient, imageID).Extract() + if err != nil { + panic(err) + } + + imageData, err := ioutil.ReadAll(image) + if err != nil { + panic(err) + } +*/ +package imagedata diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/requests.go new file mode 100644 index 00000000000..545c561f366 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/requests.go @@ -0,0 +1,39 @@ +package imagedata + +import ( + "io" + "net/http" + + "github.com/gophercloud/gophercloud" +) + +// Upload uploads an image file. +func Upload(client *gophercloud.ServiceClient, id string, data io.Reader) (r UploadResult) { + _, r.Err = client.Put(uploadURL(client, id), data, nil, &gophercloud.RequestOpts{ + MoreHeaders: map[string]string{"Content-Type": "application/octet-stream"}, + OkCodes: []int{204}, + }) + return +} + +// Stage performs PUT call on the existing image object in the Imageservice with +// the provided file. +// Existing image object must be in the "queued" status. +func Stage(client *gophercloud.ServiceClient, id string, data io.Reader) (r StageResult) { + _, r.Err = client.Put(stageURL(client, id), data, nil, &gophercloud.RequestOpts{ + MoreHeaders: map[string]string{"Content-Type": "application/octet-stream"}, + OkCodes: []int{204}, + }) + return +} + +// Download retrieves an image. +func Download(client *gophercloud.ServiceClient, id string) (r DownloadResult) { + var resp *http.Response + resp, r.Err = client.Get(downloadURL(client, id), nil, nil) + if resp != nil { + r.Body = resp.Body + r.Header = resp.Header + } + return +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/results.go new file mode 100644 index 00000000000..17a3f0e0f7e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/results.go @@ -0,0 +1,34 @@ +package imagedata + +import ( + "fmt" + "io" + + "github.com/gophercloud/gophercloud" +) + +// UploadResult is the result of an upload image operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type UploadResult struct { + gophercloud.ErrResult +} + +// StageResult is the result of a stage image operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type StageResult struct { + gophercloud.ErrResult +} + +// DownloadResult is the result of a download image operation. Call its Extract +// method to gain access to the image data. +type DownloadResult struct { + gophercloud.Result +} + +// Extract builds images model from io.Reader +func (r DownloadResult) Extract() (io.Reader, error) { + if r, ok := r.Body.(io.Reader); ok { + return r, nil + } + return nil, fmt.Errorf("Expected io.Reader but got: %T(%#v)", r.Body, r.Body) +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/urls.go new file mode 100644 index 00000000000..d9615ba7fb8 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata/urls.go @@ -0,0 +1,23 @@ +package imagedata + +import "github.com/gophercloud/gophercloud" + +const ( + rootPath = "images" + uploadPath = "file" + stagePath = "stage" +) + +// `imageDataURL(c,i)` is the URL for the binary image data for the +// image identified by ID `i` in the service `c`. +func uploadURL(c *gophercloud.ServiceClient, imageID string) string { + return c.ServiceURL(rootPath, imageID, uploadPath) +} + +func stageURL(c *gophercloud.ServiceClient, imageID string) string { + return c.ServiceURL(rootPath, imageID, stagePath) +} + +func downloadURL(c *gophercloud.ServiceClient, imageID string) string { + return uploadURL(c, imageID) +} From 52d52b98792d856505ddbb4b2a955b16618ed6ab Mon Sep 17 00:00:00 2001 From: Mike Fedosin Date: Wed, 22 Jan 2020 16:55:02 +0100 Subject: [PATCH 2/2] Swiftless OpenStack: store bootstrap ignition configs in Glance --- pkg/destroy/bootstrap/bootstrap.go | 5 +- pkg/destroy/openstack/glance.go | 40 ++++++++++ pkg/destroy/openstack/openstack.go | 4 + pkg/destroy/openstack/swift.go | 43 ----------- pkg/tfvars/openstack/bootstrap_ignition.go | 85 +++++++++++++--------- pkg/tfvars/openstack/openstack.go | 33 +++++---- 6 files changed, 118 insertions(+), 92 deletions(-) create mode 100644 pkg/destroy/openstack/glance.go delete mode 100644 pkg/destroy/openstack/swift.go diff --git a/pkg/destroy/bootstrap/bootstrap.go b/pkg/destroy/bootstrap/bootstrap.go index 22e73168b05..005bb20e610 100644 --- a/pkg/destroy/bootstrap/bootstrap.go +++ b/pkg/destroy/bootstrap/bootstrap.go @@ -74,9 +74,10 @@ func Destroy(dir string) (err error) { return errors.Wrap(err, "Terraform apply") } case openstack.Name: - err = osp.DeleteSwiftContainer(metadata.InfraID, metadata.OpenStack.Cloud) + imageName := metadata.InfraID + "-ignition" + err = osp.DeleteGlanceImage(imageName, metadata.OpenStack.Cloud) if err != nil { - return errors.Wrapf(err, "Failed to delete swift container %s", metadata.InfraID) + return errors.Wrapf(err, "Failed to delete glance image %s", imageName) } } diff --git a/pkg/destroy/openstack/glance.go b/pkg/destroy/openstack/glance.go new file mode 100644 index 00000000000..a94525934e4 --- /dev/null +++ b/pkg/destroy/openstack/glance.go @@ -0,0 +1,40 @@ +package openstack + +import ( + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" + "github.com/gophercloud/utils/openstack/clientconfig" +) + +// DeleteGlanceImage deletes the image with the specified name +func DeleteGlanceImage(name string, cloud string) error { + opts := clientconfig.ClientOpts{ + Cloud: cloud, + } + + conn, err := clientconfig.NewServiceClient("image", &opts) + if err != nil { + return err + } + + listOpts := images.ListOpts{ + Name: name, + } + + allPages, err := images.List(conn, listOpts).AllPages() + if err != nil { + return err + } + + allImages, err := images.ExtractImages(allPages) + if err != nil { + return err + } + + for _, image := range allImages { + err := images.Delete(conn, image.ID).ExtractErr() + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/destroy/openstack/openstack.go b/pkg/destroy/openstack/openstack.go index 818ac306d38..1cac0a8386c 100644 --- a/pkg/destroy/openstack/openstack.go +++ b/pkg/destroy/openstack/openstack.go @@ -544,6 +544,10 @@ func deleteContainers(opts *clientconfig.ClientOpts, filter Filter, logger logru conn, err := clientconfig.NewServiceClient("object-store", opts) if err != nil { + if _, ok := err.(*gophercloud.ErrEndpointNotFound); ok { + logger.Debug("Swift endpoint is not found") + return true, nil + } logger.Errorf("%v", err) return false, nil } diff --git a/pkg/destroy/openstack/swift.go b/pkg/destroy/openstack/swift.go deleted file mode 100644 index b390ab0ddcb..00000000000 --- a/pkg/destroy/openstack/swift.go +++ /dev/null @@ -1,43 +0,0 @@ -package openstack - -import ( - "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers" - "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects" - "github.com/gophercloud/utils/openstack/clientconfig" -) - -// DeleteSwiftContainer deletes a container and all of its objects. -func DeleteSwiftContainer(name string, cloud string) error { - opts := clientconfig.ClientOpts{ - Cloud: cloud, - } - - swiftClient, err := clientconfig.NewServiceClient("object-store", &opts) - if err != nil { - return err - } - - listOpts := objects.ListOpts{ - Full: false, - } - - allPages, err := objects.List(swiftClient, name, listOpts).AllPages() - if err != nil { - return err - } - - allObjects, err := objects.ExtractNames(allPages) - if err != nil { - return err - } - - for _, object := range allObjects { - _, err := objects.Delete(swiftClient, name, object, objects.DeleteOpts{}).Extract() - if err != nil { - return err - } - } - - _, err = containers.Delete(swiftClient, name).Extract() - return err -} diff --git a/pkg/tfvars/openstack/bootstrap_ignition.go b/pkg/tfvars/openstack/bootstrap_ignition.go index 3ff9190dba0..22f1794b8e9 100644 --- a/pkg/tfvars/openstack/bootstrap_ignition.go +++ b/pkg/tfvars/openstack/bootstrap_ignition.go @@ -6,59 +6,51 @@ import ( "fmt" "strings" - ignition "github.com/coreos/ignition/config/v2_2/types" - "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers" - "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects" + ignition "github.com/coreos/ignition/config/v2_4/types" + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/imagedata" + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" "github.com/gophercloud/utils/openstack/clientconfig" "github.com/sirupsen/logrus" "github.com/vincent-petithory/dataurl" - "k8s.io/apimachinery/pkg/util/rand" ) -// createBootstrapSwiftObject creates a container and object in swift with the bootstrap ignition config. -func createBootstrapSwiftObject(cloud string, bootstrapIgn string, clusterID string) (string, error) { - logrus.Debugln("Creating a Swift container for your bootstrap ignition...") +// Starting from OpenShift 4.4 we store bootstrap Ignition configs in Glance. + +// uploadBootstrapConfig uploads the bootstrap Ignition config in Glance and returns its location +func uploadBootstrapConfig(cloud string, bootstrapIgn string, clusterID string) (string, error) { + logrus.Debugln("Creating a Glance image for your bootstrap ignition config...") opts := clientconfig.ClientOpts{ Cloud: cloud, } - conn, err := clientconfig.NewServiceClient("object-store", &opts) + conn, err := clientconfig.NewServiceClient("image", &opts) if err != nil { return "", err } - containerCreateOpts := containers.CreateOpts{ - ContainerRead: ".r:*", - - // "kubernetes.io/cluster/${var.cluster_id}" = "owned" - Metadata: map[string]string{ - "Name": fmt.Sprintf("%s-ignition", clusterID), - "openshiftClusterID": clusterID, - }, + imageCreateOpts := images.CreateOpts{ + Name: fmt.Sprintf("%s-ignition", clusterID), + ContainerFormat: "bare", + DiskFormat: "raw", + Tags: []string{fmt.Sprintf("openshiftClusterID=%s", clusterID)}, + // TODO(mfedosin): add Description when gophercloud supports it. } - _, err = containers.Create(conn, clusterID, containerCreateOpts).Extract() + img, err := images.Create(conn, imageCreateOpts).Extract() if err != nil { return "", err } - logrus.Debugf("Container %s was created.", clusterID) - - logrus.Debugf("Creating a Swift object in container %s containing your bootstrap ignition...", clusterID) - objectCreateOpts := objects.CreateOpts{ - ContentType: "text/plain", - Content: strings.NewReader(bootstrapIgn), - DeleteAfter: 3600, - } - - objID := rand.String(16) + logrus.Debugf("Image %s was created.", img.Name) - _, err = objects.Create(conn, clusterID, objID, objectCreateOpts).Extract() - if err != nil { + logrus.Debugf("Uploading bootstrap config to the image %v with ID %v", img.Name, img.ID) + res := imagedata.Upload(conn, img.ID, strings.NewReader(bootstrapIgn)) + if res.Err != nil { return "", err } - logrus.Debugf("The object was created.") + logrus.Debugf("The config was uploaded.") - return objID, nil + // img.File contains location of the uploaded data + return img.File, nil } // To allow Ignition to download its config on the bootstrap machine from a location secured by a @@ -70,7 +62,7 @@ func createBootstrapSwiftObject(cloud string, bootstrapIgn string, clusterID str // generateIgnitionShim is used to generate an ignition file that contains a user ca bundle // in its Security section. -func generateIgnitionShim(userCA string, clusterID string, swiftObject string) (string, error) { +func generateIgnitionShim(userCA string, clusterID string, bootstrapConfigURL string, tokenID string) (string, error) { fileMode := 420 // Hostname Config @@ -100,6 +92,13 @@ func generateIgnitionShim(userCA string, clusterID string, swiftObject string) ( } } + headers := []ignition.HTTPHeader{ + { + Name: "X-Auth-Token", + Value: tokenID, + }, + } + ign := ignition.Config{ Ignition: ignition.Ignition{ Version: ignition.MaxVersion.String(), @@ -107,7 +106,8 @@ func generateIgnitionShim(userCA string, clusterID string, swiftObject string) ( Config: ignition.IgnitionConfig{ Append: []ignition.ConfigReference{ { - Source: swiftObject, + Source: bootstrapConfigURL, + HTTPHeaders: headers, }, }, }, @@ -126,3 +126,22 @@ func generateIgnitionShim(userCA string, clusterID string, swiftObject string) ( return string(data), nil } + +// getAuthToken fetches valid OpenStack authentication token ID +func getAuthToken(cloud string) (string, error) { + opts := &clientconfig.ClientOpts{ + Cloud: cloud, + } + + conn, err := clientconfig.NewServiceClient("identity", opts) + if err != nil { + return "", err + } + + token, err := conn.GetAuthResult().ExtractTokenID() + if err != nil { + return "", err + } + + return token, nil +} diff --git a/pkg/tfvars/openstack/openstack.go b/pkg/tfvars/openstack/openstack.go index d14855a7cab..95ee264b1f7 100644 --- a/pkg/tfvars/openstack/openstack.go +++ b/pkg/tfvars/openstack/openstack.go @@ -72,18 +72,23 @@ func TFVars(masterConfig *v1alpha1.OpenstackProviderSpec, cloud string, external } } - swiftPublicURL, err := getSwiftPublicURL(cloud) + glancePublicURL, err := getGlancePublicURL(cloud) if err != nil { return nil, err } - objectID, err := createBootstrapSwiftObject(cloud, bootstrapIgn, infraID) + configLocation, err := uploadBootstrapConfig(cloud, bootstrapIgn, infraID) if err != nil { return nil, err } - objectAddress := fmt.Sprintf("%s/%s/%s", swiftPublicURL, infraID, objectID) - userCAIgnition, err := generateIgnitionShim(userCA, infraID, objectAddress) + tokenID, err := getAuthToken(cloud) + if err != nil { + return nil, err + } + + bootstrapConfigURL := fmt.Sprintf("%s%s", glancePublicURL, configLocation) + userCAIgnition, err := generateIgnitionShim(userCA, infraID, bootstrapConfigURL, tokenID) if err != nil { return nil, err } @@ -133,7 +138,7 @@ func validateOverriddenImageName(imageName, cloud string) error { return nil } -// We need to obtain Swift public endpoint that will be used by Ignition to download bootstrap ignition files. +// We need to obtain Glance public endpoint that will be used by Ignition to download bootstrap ignition files. // By design this should be done by using https://www.terraform.io/docs/providers/openstack/d/identity_endpoint_v3.html // but OpenStack default policies forbid to use this API for regular users. // On the other hand when a user authenticates in OpenStack (i.e. gets a token), it includes the whole service @@ -143,21 +148,21 @@ func validateOverriddenImageName(imageName, cloud string) error { // We do next: // 1. In "getServiceCatalog" we authenticate in OpenStack (tokens.Create(..)), // parse the token and extract the service catalog: (ExtractServiceCatalog()) -// 2. In getSwiftPublicURL we iterate through the catalog and find "public" endpoint for "object-store". +// 2. In getGlancePublicURL we iterate through the catalog and find "public" endpoint for "image". -// getSwiftPublicURL obtains Swift public endpoint URL -func getSwiftPublicURL(cloud string) (string, error) { - var swiftPublicURL string +// getGlancePublicURL obtains Glance public endpoint URL +func getGlancePublicURL(cloud string) (string, error) { + var glancePublicURL string serviceCatalog, err := getServiceCatalog(cloud) if err != nil { return "", err } for _, svc := range serviceCatalog.Entries { - if svc.Type == "object-store" { + if svc.Type == "image" { for _, e := range svc.Endpoints { if e.Interface == "public" { - swiftPublicURL = e.URL + glancePublicURL = e.URL break } } @@ -165,11 +170,11 @@ func getSwiftPublicURL(cloud string) (string, error) { } } - if swiftPublicURL == "" { - return "", errors.Errorf("cannot retrieve Swift URL from the service catalog") + if glancePublicURL == "" { + return "", errors.Errorf("cannot retrieve Glance URL from the service catalog") } - return swiftPublicURL, nil + return glancePublicURL, nil } // getServiceCatalog fetches OpenStack service catalog with service endpoints