vendor: Vendor glide.yaml ct, Ignition, and dependencies

This commit is contained in:
Dalton Hubble
2017-11-06 14:13:54 -08:00
parent 2f4d5b95e4
commit 4bc5fcdc5e
39 changed files with 744 additions and 288 deletions

11
glide.lock generated
View File

@@ -1,16 +1,16 @@
hash: 9c2d24d482e4b591552c20d251b4620bdc2a12256564f8f18d7cb30b797bfd33
updated: 2017-08-08T13:27:35.465951914-07:00
hash: b404b094b7ff5d83fac658393148a51f2b3f74ce1026502524be71772c30e9b2
updated: 2017-11-06T13:24:02.819805752-08:00
imports:
- name: github.com/ajeddeloh/go-json
version: 73d058cf8437a1989030afe571eeab9f90eebbbd
- name: github.com/ajeddeloh/yaml
version: 1072abfea31191db507785e2e0c1b8d1440d35a5
version: 6b94386aeefd8c4b8470aee72bfca084c2f91da9
- name: github.com/alecthomas/units
version: 6b4e7dc5e3143b85ea77909c72caf89416fc2915
- name: github.com/camlistore/camlistore
version: 9106ce829629773474c689b34aacd7d3aaa99426
- name: github.com/coreos/container-linux-config-transpiler
version: d42f09a1374bc318d853b53e5a31148db68a4e2a
version: be4cb16b0aaf0f6b4fdf63b8b2a081397276bf0f
subpackages:
- config
- config/astyaml
@@ -32,7 +32,7 @@ imports:
- journal
- unit
- name: github.com/coreos/ignition
version: 11813c57bc05f30644bbae7891ae30a4a62e0b33
version: 01c039a5ce59acd39e5741713e59abfcb74d0782
subpackages:
- config
- config/types
@@ -44,6 +44,7 @@ imports:
- config/v2_1/types
- config/validate
- config/validate/astjson
- config/validate/astnode
- config/validate/report
- name: github.com/coreos/pkg
version: 66fe44ad037ccb80329115cb4db0dbe8e9beb03a

View File

@@ -1,13 +1,201 @@
Copyright 2011-2016 Canonical Ltd.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
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
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
http://www.apache.org/licenses/LICENSE-2.0
1. Definitions.
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.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@@ -120,7 +120,6 @@ func (p *parser) parse() *Node {
default:
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
}
panic("unreachable")
}
func (p *parser) Node(kind int) *Node {
@@ -191,6 +190,7 @@ type decoder struct {
aliases map[string]bool
mapType reflect.Type
terrors []string
strict bool
}
var (
@@ -200,8 +200,8 @@ var (
ifaceType = defaultMapType.Elem()
)
func newDecoder() *decoder {
d := &decoder{mapType: defaultMapType}
func newDecoder(strict bool) *decoder {
d := &decoder{mapType: defaultMapType, strict: strict}
d.aliases = make(map[string]bool)
return d
}
@@ -251,7 +251,7 @@ func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
//
// If n holds a null value, prepare returns before doing anything.
func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
if n.Tag == yaml_NULL_TAG || n.Kind == ScalarNode && n.Tag == "" && (n.Value == "null" || n.Value == "") {
if n.Tag == yaml_NULL_TAG || n.Kind == ScalarNode && n.Tag == "" && (n.Value == "null" || n.Value == "" && n.Implicit) {
return out, false, false
}
again := true
@@ -640,6 +640,8 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
value := reflect.New(elemType).Elem()
d.unmarshal(n.Children[i+1], value)
inlineMap.SetMapIndex(name, value)
} else if d.strict {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", n.Line+1, name.String(), out.Type()))
}
}
return true

View File

@@ -666,7 +666,6 @@ func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
return yaml_emitter_set_emitter_error(emitter,
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
}
return false
}
// Expect ALIAS.
@@ -995,7 +994,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
break_space = false
space_break = false
preceeded_by_whitespace = false
preceded_by_whitespace = false
followed_by_whitespace = false
previous_space = false
previous_break = false
@@ -1017,7 +1016,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
flow_indicators = true
}
preceeded_by_whitespace = true
preceded_by_whitespace = true
for i, w := 0, 0; i < len(value); i += w {
w = width(value[i])
followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
@@ -1048,7 +1047,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
block_indicators = true
}
case '#':
if preceeded_by_whitespace {
if preceded_by_whitespace {
flow_indicators = true
block_indicators = true
}
@@ -1089,7 +1088,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
}
// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
preceeded_by_whitespace = is_blankz(value, i)
preceded_by_whitespace = is_blankz(value, i)
}
emitter.scalar_data.multiline = line_breaks

View File

@@ -166,7 +166,6 @@ func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool
default:
panic("invalid parser state")
}
return false
}
// Parse the production:

View File

@@ -3,6 +3,7 @@ package yaml
import (
"encoding/base64"
"math"
"regexp"
"strconv"
"strings"
"unicode/utf8"
@@ -80,6 +81,8 @@ func resolvableTag(tag string) bool {
return false
}
var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
func resolve(tag string, in string) (rtag string, out interface{}) {
if !resolvableTag(tag) {
return tag, in
@@ -135,9 +138,11 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
if err == nil {
return yaml_INT_TAG, uintv
}
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
return yaml_FLOAT_TAG, floatv
if yamlStyleFloat.MatchString(plain) {
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
return yaml_FLOAT_TAG, floatv
}
}
if strings.HasPrefix(plain, "0b") {
intv, err := strconv.ParseInt(plain[2:], 2, 64)

View File

@@ -9,7 +9,7 @@ import (
// ************
//
// The following notes assume that you are familiar with the YAML specification
// (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in
// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in
// some cases we are less restrictive that it requires.
//
// The process of transforming a YAML stream into a sequence of events is
@@ -611,7 +611,7 @@ func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, co
if directive {
context = "while parsing a %TAG directive"
}
return yaml_parser_set_scanner_error(parser, context, context_mark, "did not find URI escaped octet")
return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
}
func trace(args ...interface{}) func() {
@@ -1944,7 +1944,7 @@ func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_ma
} else {
// It's either the '!' tag or not really a tag handle. If it's a %TAG
// directive, it's an error. If it's a tag token, it must be a part of URI.
if directive && !(s[0] == '!' && s[1] == 0) {
if directive && string(s) != "!" {
yaml_parser_set_scanner_tag_error(parser, directive,
start_mark, "did not find expected '!'")
return false
@@ -1959,6 +1959,7 @@ func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_ma
func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
//size_t length = head ? strlen((char *)head) : 0
var s []byte
hasTag := len(head) > 0
// Copy the head if needed.
//
@@ -2000,10 +2001,10 @@ func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
return false
}
hasTag = true
}
// Check if the tag is non-empty.
if len(s) == 0 {
if !hasTag {
yaml_parser_set_scanner_tag_error(parser, directive,
start_mark, "did not find expected tag URI")
return false

View File

@@ -77,8 +77,19 @@ type Marshaler interface {
// supported tag options.
//
func Unmarshal(in []byte, out interface{}) (err error) {
return unmarshal(in, out, false)
}
// UnmarshalStrict is like Unmarshal except that any fields that are found
// in the data that do not have corresponding struct members will result in
// an error.
func UnmarshalStrict(in []byte, out interface{}) (err error) {
return unmarshal(in, out, true)
}
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
defer handleErr(&err)
d := newDecoder()
d := newDecoder(strict)
p := newParser(in)
defer p.destroy()
node := p.parse()

View File

@@ -508,7 +508,7 @@ type yaml_parser_t struct {
problem string // Error description.
// The byte about which the problem occured.
// The byte about which the problem occurred.
problem_offset int
problem_value int
problem_mark yaml_mark_t

View File

@@ -20,7 +20,7 @@ import (
"strings"
yaml "github.com/ajeddeloh/yaml"
"github.com/coreos/ignition/config/validate"
"github.com/coreos/ignition/config/validate/astnode"
)
var (
@@ -59,7 +59,7 @@ func (n YamlNode) LiteralValue() interface{} {
return n.Value
}
func (n YamlNode) SliceChild(index int) (validate.AstNode, bool) {
func (n YamlNode) SliceChild(index int) (astnode.AstNode, bool) {
if n.Kind != yaml.SequenceNode {
return nil, false
}
@@ -74,12 +74,12 @@ func (n YamlNode) SliceChild(index int) (validate.AstNode, bool) {
}, true
}
func (n YamlNode) KeyValueMap() (map[string]validate.AstNode, bool) {
func (n YamlNode) KeyValueMap() (map[string]astnode.AstNode, bool) {
if n.Kind != yaml.MappingNode {
return nil, false
}
kvmap := map[string]validate.AstNode{}
kvmap := map[string]astnode.AstNode{}
for i := 0; i < len(n.Children); i += 2 {
key := *n.Children[i]
if n.tag == "json" {

View File

@@ -21,15 +21,16 @@ import (
"github.com/coreos/container-linux-config-transpiler/config/astyaml"
"github.com/coreos/container-linux-config-transpiler/config/platform"
"github.com/coreos/container-linux-config-transpiler/config/types"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
// Parse will convert a byte slice containing a Container Linux Config into a
// golang struct representing the config, the parse tree from parsing the yaml
// and a report of any warnings or errors that occurred during the parsing.
func Parse(data []byte) (types.Config, validate.AstNode, report.Report) {
func Parse(data []byte) (types.Config, astnode.AstNode, report.Report) {
var cfg types.Config
var r report.Report
@@ -38,7 +39,7 @@ func Parse(data []byte) (types.Config, validate.AstNode, report.Report) {
}
nodes := yaml.UnmarshalToNode(data)
var root validate.AstNode
var root astnode.AstNode
if nodes == nil {
r.Add(report.Entry{
Kind: report.EntryWarning,
@@ -67,7 +68,7 @@ func Parse(data []byte) (types.Config, validate.AstNode, report.Report) {
// ConvertAs2_0 also accepts a platform string, which can either be one of the
// platform strings defined in config/templating/templating.go or an empty
// string if [dynamic data](doc/dynamic-data.md) isn't used.
func ConvertAs2_0(in types.Config, p string, ast validate.AstNode) (ignTypes.Config, report.Report) {
func ConvertAs2_0(in types.Config, p string, ast astnode.AstNode) (ignTypes.Config, report.Report) {
if !platform.IsSupportedPlatform(p) {
r := report.Report{}
r.Add(report.Entry{

View File

@@ -15,13 +15,14 @@
package platform
const (
Azure = "azure"
DO = "digitalocean"
EC2 = "ec2"
GCE = "gce"
Packet = "packet"
OpenStackMetadata = "openstack-metadata"
VagrantVirtualbox = "vagrant-virtualbox"
Azure = "azure"
DO = "digitalocean"
EC2 = "ec2"
GCE = "gce"
Packet = "packet"
OpenStackMetadata = "openstack-metadata"
VagrantVirtualbox = "vagrant-virtualbox"
CloudStackConfigDrive = "cloudstack-configdrive"
)
var Platforms = []string{
@@ -32,6 +33,7 @@ var Platforms = []string{
Packet,
OpenStackMetadata,
VagrantVirtualbox,
CloudStackConfigDrive,
}
func IsSupportedPlatform(platform string) bool {

View File

@@ -73,6 +73,9 @@ var platformTemplatingMap = map[string]map[string]string{
fieldHostname: "COREOS_VAGRANT_VIRTUALBOX_HOSTNAME",
fieldV4Private: "COREOS_VAGRANT_VIRTUALBOX_PRIVATE_IPV4",
},
platform.CloudStackConfigDrive: {
fieldHostname: "CLOUDSTACK_LOCAL_HOSTNAME",
},
}
// HasTemplating returns whether or not any of the environment variables present

View File

@@ -19,13 +19,13 @@ import (
"fmt"
"reflect"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/report"
"github.com/coreos/container-linux-config-transpiler/config/platform"
"github.com/coreos/container-linux-config-transpiler/config/templating"
"github.com/coreos/container-linux-config-transpiler/config/types/util"
"github.com/coreos/ignition/config/validate"
"github.com/coreos/ignition/config/validate/astnode"
)
var (
@@ -36,18 +36,18 @@ var (
)
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, p string) (ignTypes.Config, report.Report, validate.AstNode) {
if p == platform.OpenStackMetadata {
out.Systemd.Units = append(out.Systemd.Units, ignTypes.SystemdUnit{
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, p string) (ignTypes.Config, report.Report, astnode.AstNode) {
if p == platform.OpenStackMetadata || p == platform.CloudStackConfigDrive {
out.Systemd.Units = append(out.Systemd.Units, ignTypes.Unit{
Name: "coreos-metadata.service",
DropIns: []ignTypes.SystemdUnitDropIn{{
Dropins: []ignTypes.Dropin{{
Name: "20-clct-provider-override.conf",
Contents: fmt.Sprintf("[Service]\nEnvironment=COREOS_METADATA_OPT_PROVIDER=--provider=%s", p),
}},
})
out.Systemd.Units = append(out.Systemd.Units, ignTypes.SystemdUnit{
out.Systemd.Units = append(out.Systemd.Units, ignTypes.Unit{
Name: "coreos-metadata-sshkeys@.service",
DropIns: []ignTypes.SystemdUnitDropIn{{
Dropins: []ignTypes.Dropin{{
Name: "20-clct-provider-override.conf",
Contents: fmt.Sprintf("[Service]\nEnvironment=COREOS_METADATA_OPT_PROVIDER=--provider=%s", p),
}},
@@ -130,7 +130,7 @@ func getCliArgs(e interface{}) []string {
// Get returns the value for key, where key is an int or string and n is a
// sequence node or mapping node, respectively.
func getNodeChild(n validate.AstNode, key interface{}) (validate.AstNode, error) {
func getNodeChild(n astnode.AstNode, key interface{}) (astnode.AstNode, error) {
if n == nil {
return nil, ErrNilNode
}
@@ -155,7 +155,7 @@ func getNodeChild(n validate.AstNode, key interface{}) (validate.AstNode, error)
}
// GetPath works like calling Get() repeatly with each argument.
func getNodeChildPath(n validate.AstNode, key ...interface{}) (validate.AstNode, error) {
func getNodeChildPath(n astnode.AstNode, key ...interface{}) (astnode.AstNode, error) {
if len(key) == 0 {
return n, nil
}

View File

@@ -17,8 +17,8 @@ package types
import (
"net/url"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -36,7 +36,8 @@ type Config struct {
}
type Ignition struct {
Config IgnitionConfig `yaml:"config"`
Config IgnitionConfig `yaml:"config"`
Timeouts Timeouts `yaml:"timeouts"`
}
type IgnitionConfig struct {
@@ -49,9 +50,16 @@ type ConfigReference struct {
Verification Verification `yaml:"verification"`
}
type Timeouts struct {
HTTPResponseHeaders *int `yaml:"http_response_headers"`
HTTPTotal *int `yaml:"http_total"`
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
r := report.Report{}
out.Ignition.Timeouts.HTTPResponseHeaders = in.Ignition.Timeouts.HTTPResponseHeaders
out.Ignition.Timeouts.HTTPTotal = in.Ignition.Timeouts.HTTPTotal
cfgNode, _ := getNodeChildPath(ast, "ignition", "config", "append")
for i, ref := range in.Ignition.Config.Append {
tmp, _ := getNodeChild(cfgNode, i)
@@ -78,8 +86,8 @@ func init() {
})
}
func convertConfigReference(in ConfigReference, ast validate.AstNode) (ignTypes.ConfigReference, report.Report) {
source, err := url.Parse(in.Source)
func convertConfigReference(in ConfigReference, ast astnode.AstNode) (ignTypes.ConfigReference, report.Report) {
_, err := url.Parse(in.Source)
if err != nil {
r := report.ReportFromError(err, report.EntryError)
if n, err := getNodeChild(ast, "source"); err == nil {
@@ -89,7 +97,7 @@ func convertConfigReference(in ConfigReference, ast validate.AstNode) (ignTypes.
}
return ignTypes.ConfigReference{
Source: ignTypes.Url(*source),
Source: in.Source,
Verification: convertVerification(in.Verification),
}, report.Report{}
}
@@ -98,11 +106,9 @@ func convertVerification(in Verification) ignTypes.Verification {
if in.Hash.Function == "" || in.Hash.Sum == "" {
return ignTypes.Verification{}
}
s := in.Hash.String()
return ignTypes.Verification{
&ignTypes.Hash{
Function: in.Hash.Function,
Sum: in.Hash.Sum,
},
Hash: &s,
}
}

View File

@@ -18,12 +18,13 @@ import (
"reflect"
"github.com/coreos/container-linux-config-transpiler/config/astyaml"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
type converterFor2_0 func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode)
type converterFor2_0 func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode)
var convertersFor2_0 []converterFor2_0
@@ -31,7 +32,7 @@ func register2_0(f converterFor2_0) {
convertersFor2_0 = append(convertersFor2_0, f)
}
func ConvertAs2_0(in Config, platform string, ast validate.AstNode) (ignTypes.Config, report.Report) {
func ConvertAs2_0(in Config, platform string, ast astnode.AstNode) (ignTypes.Config, report.Report) {
// convert our tree from having yaml tags to having json tags, so when Validate() is
// called on the tree, it can find the keys in the ignition structs (which are denoted
// by `json` tags)
@@ -42,7 +43,7 @@ func ConvertAs2_0(in Config, platform string, ast validate.AstNode) (ignTypes.Co
out := ignTypes.Config{
Ignition: ignTypes.Ignition{
Version: ignTypes.IgnitionVersion{Major: 2, Minor: 0},
Version: "2.1.0",
},
}

View File

@@ -18,8 +18,8 @@ import (
"fmt"
"github.com/alecthomas/units"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -27,6 +27,15 @@ const (
BYTES_PER_SECTOR = 512
)
var (
type_guid_map = map[string]string{
"raid_containing_root": "be9067b9-ea49-4f15-b4f6-f36f8c9e1818",
"linux_filesystem_data": "0fc63daf-8483-4772-8e79-3d69d8477de4",
"swap_partition": "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f",
"raid_partition": "a19d880f-05fc-4d3b-a006-743f0f84911e",
}
)
type Disk struct {
Device string `yaml:"device"`
WipeTable bool `yaml:"wipe_table"`
@@ -38,15 +47,16 @@ type Partition struct {
Number int `yaml:"number"`
Size string `yaml:"size"`
Start string `yaml:"start"`
GUID string `yaml:"guid"`
TypeGUID string `yaml:"type_guid"`
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
r := report.Report{}
for disk_idx, disk := range in.Storage.Disks {
newDisk := ignTypes.Disk{
Device: ignTypes.Path(disk.Device),
Device: disk.Device,
WipeTable: disk.WipeTable,
}
@@ -71,13 +81,17 @@ func init() {
// dont add invalid partitions
continue
}
if type_guid, ok := type_guid_map[partition.TypeGUID]; ok {
partition.TypeGUID = type_guid
}
newPart := ignTypes.Partition{
Label: ignTypes.PartitionLabel(partition.Label),
Label: partition.Label,
Number: partition.Number,
Size: size,
Start: start,
TypeGUID: ignTypes.PartitionTypeGUID(partition.TypeGUID),
GUID: partition.GUID,
TypeGUID: partition.TypeGUID,
}
newDisk.Partitions = append(newDisk.Partitions, newPart)
}
@@ -88,7 +102,7 @@ func init() {
})
}
func convertPartitionDimension(in string) (ignTypes.PartitionDimension, error) {
func convertPartitionDimension(in string) (int, error) {
if in == "" {
return 0, nil
}
@@ -106,5 +120,5 @@ func convertPartitionDimension(in string) (ignTypes.PartitionDimension, error) {
if b%BYTES_PER_SECTOR != 0 {
sectors++
}
return ignTypes.PartitionDimension(uint64(sectors)), nil
return int(sectors), nil
}

View File

@@ -18,8 +18,8 @@ import (
"fmt"
"strings"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -28,13 +28,13 @@ type Docker struct {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
if in.Docker != nil {
contents := fmt.Sprintf("[Service]\nEnvironment=\"DOCKER_OPTS=%s\"", strings.Join(in.Docker.Flags, " "))
out.Systemd.Units = append(out.Systemd.Units, ignTypes.SystemdUnit{
out.Systemd.Units = append(out.Systemd.Units, ignTypes.Unit{
Name: "docker.service",
Enable: true,
DropIns: []ignTypes.SystemdUnitDropIn{{
Dropins: []ignTypes.Dropin{{
Name: "20-clct-docker.conf",
Contents: contents,
}},

View File

@@ -19,8 +19,8 @@ import (
"fmt"
"github.com/coreos/go-semver/semver"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -119,16 +119,16 @@ func (etcd *Etcd) UnmarshalYAML(unmarshal func(interface{}) error) error {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
if in.Etcd != nil {
contents, err := etcdContents(*in.Etcd, platform)
if err != nil {
return ignTypes.Config{}, report.ReportFromError(err, report.EntryError), ast
}
out.Systemd.Units = append(out.Systemd.Units, ignTypes.SystemdUnit{
out.Systemd.Units = append(out.Systemd.Units, ignTypes.Unit{
Name: "etcd-member.service",
Enable: true,
DropIns: []ignTypes.SystemdUnitDropIn{{
Dropins: []ignTypes.Dropin{{
Name: "20-clct-etcd-member.conf",
Contents: contents,
}},

View File

@@ -19,19 +19,29 @@ import (
"github.com/coreos/container-linux-config-transpiler/config/astyaml"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
"github.com/vincent-petithory/dataurl"
)
type FileUser struct {
Id *int `yaml:"id"`
Name string `yaml:"name"`
}
type FileGroup struct {
Id *int `yaml:"id"`
Name string `yaml:"name"`
}
type File struct {
Filesystem string `yaml:"filesystem"`
Path string `yaml:"path"`
Mode int `yaml:"mode"`
Contents FileContents `yaml:"contents"`
User FileUser `yaml:"user"`
Group FileGroup `yaml:"group"`
Mode int `yaml:"mode"`
Contents FileContents `yaml:"contents"`
}
type FileContents struct {
@@ -45,34 +55,53 @@ type Remote struct {
Verification Verification `yaml:"verification"`
}
type FileUser struct {
Id int `yaml:"id"`
type Directory struct {
Filesystem string `yaml:"filesystem"`
Path string `yaml:"path"`
User FileUser `yaml:"user"`
Group FileGroup `yaml:"group"`
Mode int `yaml:"mode"`
}
type FileGroup struct {
Id int `yaml:"id"`
type Link struct {
Filesystem string `yaml:"filesystem"`
Path string `yaml:"path"`
User FileUser `yaml:"user"`
Group FileGroup `yaml:"group"`
Hard bool `yaml:"hard"`
Target string `yaml:"target"`
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
r := report.Report{}
files_node, _ := getNodeChildPath(ast, "storage", "files")
for i, file := range in.Storage.Files {
file_node, _ := getNodeChild(files_node, i)
newFile := ignTypes.File{
Filesystem: file.Filesystem,
Path: ignTypes.Path(file.Path),
Mode: ignTypes.FileMode(file.Mode),
User: ignTypes.FileUser{Id: file.User.Id},
Group: ignTypes.FileGroup{Id: file.Group.Id},
Node: ignTypes.Node{
Filesystem: file.Filesystem,
Path: file.Path,
User: ignTypes.NodeUser{
ID: file.User.Id,
Name: file.User.Name,
},
Group: ignTypes.NodeGroup{
ID: file.Group.Id,
Name: file.Group.Name,
},
},
FileEmbedded1: ignTypes.FileEmbedded1{
Mode: file.Mode,
},
}
if file.Contents.Inline != "" {
newFile.Contents = ignTypes.FileContents{
Source: ignTypes.Url{
Source: (&url.URL{
Scheme: "data",
Opaque: "," + dataurl.EscapeString(file.Contents.Inline),
},
}).String(),
}
}
@@ -81,7 +110,7 @@ func init() {
if err != nil {
// if invalid, record error and continue
convertReport := report.ReportFromError(err, report.EntryError)
if n, err := getNodeChildPath(file_node, "contents", "remote", "url"); err != nil {
if n, err := getNodeChildPath(file_node, "contents", "remote", "url"); err == nil {
line, col, _ := n.ValueLineCol(nil)
convertReport.AddPosition(line, col, "")
}
@@ -100,24 +129,60 @@ func init() {
newContentsAsYaml.ChangeKey("url", "source", url.(astyaml.YamlNode))
}
newFile.Contents = ignTypes.FileContents{Source: ignTypes.Url(*source)}
newFile.Contents = ignTypes.FileContents{Source: source.String()}
}
if newFile.Contents == (ignTypes.FileContents{}) {
newFile.Contents = ignTypes.FileContents{
Source: ignTypes.Url{
Scheme: "data",
Opaque: ",",
},
Source: "data:,",
}
}
newFile.Contents.Compression = ignTypes.Compression(file.Contents.Remote.Compression)
newFile.Contents.Compression = file.Contents.Remote.Compression
newFile.Contents.Verification = convertVerification(file.Contents.Remote.Verification)
out.Storage.Files = append(out.Storage.Files, newFile)
}
for _, dir := range in.Storage.Directories {
out.Storage.Directories = append(out.Storage.Directories, ignTypes.Directory{
Node: ignTypes.Node{
Filesystem: dir.Filesystem,
Path: dir.Path,
User: ignTypes.NodeUser{
ID: dir.User.Id,
Name: dir.User.Name,
},
Group: ignTypes.NodeGroup{
ID: dir.Group.Id,
Name: dir.Group.Name,
},
},
DirectoryEmbedded1: ignTypes.DirectoryEmbedded1{
Mode: dir.Mode,
},
})
}
for _, link := range in.Storage.Links {
out.Storage.Links = append(out.Storage.Links, ignTypes.Link{
Node: ignTypes.Node{
Filesystem: link.Filesystem,
Path: link.Path,
User: ignTypes.NodeUser{
ID: link.User.Id,
Name: link.User.Name,
},
Group: ignTypes.NodeGroup{
ID: link.Group.Id,
Name: link.Group.Name,
},
},
LinkEmbedded1: ignTypes.LinkEmbedded1{
Hard: link.Hard,
Target: link.Target,
},
})
}
return out, r, ast
})
}

View File

@@ -15,21 +15,25 @@
package types
import (
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
type Filesystem struct {
Name string `yaml:"name"`
Mount *Mount `yaml:"mount"`
Path string `yaml:"path"`
Name string `yaml:"name"`
Mount *Mount `yaml:"mount"`
Path *string `yaml:"path"`
}
type Mount struct {
Device string `yaml:"device"`
Format string `yaml:"format"`
Create *Create `yaml:"create"`
Device string `yaml:"device"`
Format string `yaml:"format"`
Create *Create `yaml:"create"`
WipeFilesystem bool `yaml:"wipe_filesystem"`
Label *string `yaml:"label"`
UUID *string `yaml:"uuid"`
Options []string `yaml:"options"`
}
type Create struct {
@@ -38,35 +42,52 @@ type Create struct {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
r := report.Report{}
for _, filesystem := range in.Storage.Filesystems {
newFilesystem := ignTypes.Filesystem{
Name: filesystem.Name,
Path: func(p ignTypes.Path) *ignTypes.Path {
if p == "" {
return nil
}
return &p
}(ignTypes.Path(filesystem.Path)),
Path: filesystem.Path,
}
if filesystem.Mount != nil {
newFilesystem.Mount = &ignTypes.FilesystemMount{
Device: ignTypes.Path(filesystem.Mount.Device),
Format: ignTypes.FilesystemFormat(filesystem.Mount.Format),
newFilesystem.Mount = &ignTypes.Mount{
Device: filesystem.Mount.Device,
Format: filesystem.Mount.Format,
WipeFilesystem: filesystem.Mount.WipeFilesystem,
Label: filesystem.Mount.Label,
UUID: filesystem.Mount.UUID,
Options: convertStringSliceToTypesMountOptionSlice(filesystem.Mount.Options),
}
if filesystem.Mount.Create != nil {
newFilesystem.Mount.Create = &ignTypes.FilesystemCreate{
newFilesystem.Mount.Create = &ignTypes.Create{
Force: filesystem.Mount.Create.Force,
Options: ignTypes.MkfsOptions(filesystem.Mount.Create.Options),
Options: convertStringSliceToTypesCreateOptionSlice(filesystem.Mount.Create.Options),
}
}
}
out.Storage.Filesystems = append(out.Storage.Filesystems, newFilesystem)
}
return out, report.Report{}, ast
return out, r, ast
})
}
// golang--
func convertStringSliceToTypesCreateOptionSlice(ss []string) []ignTypes.CreateOption {
var res []ignTypes.CreateOption
for _, s := range ss {
res = append(res, ignTypes.CreateOption(s))
}
return res
}
// golang--
func convertStringSliceToTypesMountOptionSlice(ss []string) []ignTypes.MountOption {
var res []ignTypes.MountOption
for _, s := range ss {
res = append(res, ignTypes.MountOption(s))
}
return res
}

View File

@@ -6,8 +6,8 @@ import (
"fmt"
"github.com/coreos/go-semver/semver"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -115,16 +115,16 @@ func (flannel *Flannel) UnmarshalYAML(unmarshal func(interface{}) error) error {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
if in.Flannel != nil {
contents, err := flannelContents(*in.Flannel, platform)
if err != nil {
return ignTypes.Config{}, report.ReportFromError(err, report.EntryError), ast
}
out.Systemd.Units = append(out.Systemd.Units, ignTypes.SystemdUnit{
out.Systemd.Units = append(out.Systemd.Units, ignTypes.Unit{
Name: "flanneld.service",
Enable: true,
DropIns: []ignTypes.SystemdUnitDropIn{{
Dropins: []ignTypes.Dropin{{
Name: "20-clct-flannel.conf",
Contents: contents,
}},

View File

@@ -33,24 +33,20 @@ var (
)
type Locksmith struct {
RebootStrategy RebootStrategy `yaml:"reboot_strategy" locksmith:"REBOOT_STRATEGY"`
WindowStart WindowStart `yaml:"window_start" locksmith:"LOCKSMITHD_REBOOT_WINDOW_START"`
WindowLength WindowLength `yaml:"window_length" locksmith:"LOCKSMITHD_REBOOT_WINDOW_LENGTH"`
Group string `yaml:"group" locksmith:"LOCKSMITHD_GROUP"`
EtcdEndpoints string `yaml:"etcd_endpoints" locksmith:"LOCKSMITHD_ENDPOINT"`
EtcdCAFile string `yaml:"etcd_cafile" locksmith:"LOCKSMITHD_ETCD_CAFILE"`
EtcdCertFile string `yaml:"etcd_certfile" locksmith:"LOCKSMITHD_ETCD_CERTFILE"`
EtcdKeyFile string `yaml:"etcd_keyfile" locksmith:"LOCKSMITHD_ETCD_KEYFILE"`
RebootStrategy string `yaml:"reboot_strategy" locksmith:"REBOOT_STRATEGY"`
WindowStart string `yaml:"window_start" locksmith:"LOCKSMITHD_REBOOT_WINDOW_START"`
WindowLength string `yaml:"window_length" locksmith:"LOCKSMITHD_REBOOT_WINDOW_LENGTH"`
Group string `yaml:"group" locksmith:"LOCKSMITHD_GROUP"`
EtcdEndpoints string `yaml:"etcd_endpoints" locksmith:"LOCKSMITHD_ENDPOINT"`
EtcdCAFile string `yaml:"etcd_cafile" locksmith:"LOCKSMITHD_ETCD_CAFILE"`
EtcdCertFile string `yaml:"etcd_certfile" locksmith:"LOCKSMITHD_ETCD_CERTFILE"`
EtcdKeyFile string `yaml:"etcd_keyfile" locksmith:"LOCKSMITHD_ETCD_KEYFILE"`
}
func (l Locksmith) configLines() []string {
return getArgs("%s=%q", "locksmith", l)
return getArgs("%s=%v", "locksmith", l)
}
type RebootStrategy string
type WindowStart string
type WindowLength string
func (l Locksmith) Validate() report.Report {
if (l.WindowStart != "" && l.WindowLength == "") || (l.WindowStart == "" && l.WindowLength != "") {
return report.ReportFromError(ErrMissingStartOrLength, report.EntryError)
@@ -58,8 +54,8 @@ func (l Locksmith) Validate() report.Report {
return report.Report{}
}
func (r RebootStrategy) Validate() report.Report {
switch strings.ToLower(string(r)) {
func (l Locksmith) ValidateRebootStrategy() report.Report {
switch strings.ToLower(l.RebootStrategy) {
case "reboot", "etcd-lock", "off":
return report.Report{}
default:
@@ -67,17 +63,17 @@ func (r RebootStrategy) Validate() report.Report {
}
}
func (s WindowStart) Validate() report.Report {
if s == "" {
func (l Locksmith) ValidateWindowStart() report.Report {
if l.WindowStart == "" {
return report.Report{}
}
var day string
var t string
_, err := fmt.Sscanf(string(s), "%s %s", &day, &t)
_, err := fmt.Sscanf(l.WindowStart, "%s %s", &day, &t)
if err != nil {
day = "not-present"
t = string(s)
t = l.WindowStart
}
switch strings.ToLower(day) {
@@ -95,11 +91,11 @@ func (s WindowStart) Validate() report.Report {
return report.Report{}
}
func (l WindowLength) Validate() report.Report {
if l == "" {
func (l Locksmith) ValidateWindowLength() report.Report {
if l.WindowLength == "" {
return report.Report{}
}
_, err := time.ParseDuration(string(l))
_, err := time.ParseDuration(l.WindowLength)
if err != nil {
return report.ReportFromError(ErrParsingLength, report.EntryError)
}

View File

@@ -15,8 +15,8 @@
package types
import (
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -30,10 +30,10 @@ type NetworkdUnit struct {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
for _, unit := range in.Networkd.Units {
out.Networkd.Units = append(out.Networkd.Units, ignTypes.NetworkdUnit{
Name: ignTypes.NetworkdUnitName(unit.Name),
out.Networkd.Units = append(out.Networkd.Units, ignTypes.Networkdunit{
Name: unit.Name,
Contents: unit.Contents,
})
}

View File

@@ -15,8 +15,8 @@
package types
import (
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -27,9 +27,19 @@ type Passwd struct {
type User struct {
Name string `yaml:"name"`
PasswordHash string `yaml:"password_hash"`
PasswordHash *string `yaml:"password_hash"`
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
Create *UserCreate `yaml:"create"`
UID *int `yaml:"uid"`
Gecos string `yaml:"gecos"`
HomeDir string `yaml:"home_dir"`
NoCreateHome bool `yaml:"no_create_home"`
PrimaryGroup string `yaml:"primary_group"`
Groups []string `yaml:"groups"`
NoUserGroup bool `yaml:"no_user_group"`
System bool `yaml:"system"`
NoLogInit bool `yaml:"no_log_init"`
Shell string `yaml:"shell"`
}
type UserCreate struct {
@@ -53,25 +63,32 @@ type Group struct {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
for _, user := range in.Passwd.Users {
if user.Name != "core" && user.Create == nil {
user.Create = &UserCreate{}
}
newUser := ignTypes.User{
newUser := ignTypes.PasswdUser{
Name: user.Name,
PasswordHash: user.PasswordHash,
SSHAuthorizedKeys: user.SSHAuthorizedKeys,
SSHAuthorizedKeys: convertStringSliceIntoTypesSSHAuthorizedKeySlice(user.SSHAuthorizedKeys),
UID: user.UID,
Gecos: user.Gecos,
HomeDir: user.HomeDir,
NoCreateHome: user.NoCreateHome,
PrimaryGroup: user.PrimaryGroup,
Groups: convertStringSliceIntoTypesPasswdUserGroupSlice(user.Groups),
NoUserGroup: user.NoUserGroup,
System: user.System,
NoLogInit: user.NoLogInit,
Shell: user.Shell,
}
if user.Create != nil {
newUser.Create = &ignTypes.UserCreate{
Uid: user.Create.Uid,
GECOS: user.Create.GECOS,
Homedir: user.Create.Homedir,
newUser.Create = &ignTypes.Usercreate{
UID: convertUintPointerToIntPointer(user.Create.Uid),
Gecos: user.Create.GECOS,
HomeDir: user.Create.Homedir,
NoCreateHome: user.Create.NoCreateHome,
PrimaryGroup: user.Create.PrimaryGroup,
Groups: user.Create.Groups,
Groups: convertStringSliceIntoTypesUsercreateGroupSlice(user.Create.Groups),
NoUserGroup: user.Create.NoUserGroup,
System: user.Create.System,
NoLogInit: user.Create.NoLogInit,
@@ -83,9 +100,9 @@ func init() {
}
for _, group := range in.Passwd.Groups {
out.Passwd.Groups = append(out.Passwd.Groups, ignTypes.Group{
out.Passwd.Groups = append(out.Passwd.Groups, ignTypes.PasswdGroup{
Name: group.Name,
Gid: group.Gid,
Gid: convertUintPointerToIntPointer(group.Gid),
PasswordHash: group.PasswordHash,
System: group.System,
})
@@ -93,3 +110,39 @@ func init() {
return out, report.Report{}, ast
})
}
// golang--
func convertStringSliceIntoTypesSSHAuthorizedKeySlice(ss []string) []ignTypes.SSHAuthorizedKey {
var res []ignTypes.SSHAuthorizedKey
for _, s := range ss {
res = append(res, ignTypes.SSHAuthorizedKey(s))
}
return res
}
// golang--
func convertStringSliceIntoTypesUsercreateGroupSlice(ss []string) []ignTypes.UsercreateGroup {
var res []ignTypes.UsercreateGroup
for _, s := range ss {
res = append(res, ignTypes.UsercreateGroup(s))
}
return res
}
// golang--
func convertStringSliceIntoTypesPasswdUserGroupSlice(ss []string) []ignTypes.PasswdUserGroup {
var res []ignTypes.PasswdUserGroup
for _, s := range ss {
res = append(res, ignTypes.PasswdUserGroup(s))
}
return res
}
// golang--
func convertUintPointerToIntPointer(u *uint) *int {
if u == nil {
return nil
}
x := int(*u)
return &x
}

View File

@@ -15,8 +15,8 @@
package types
import (
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -28,20 +28,26 @@ type Raid struct {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
for _, array := range in.Storage.Arrays {
newArray := ignTypes.Raid{
Name: array.Name,
Level: array.Level,
Spares: array.Spares,
Name: array.Name,
Level: array.Level,
Spares: array.Spares,
Devices: convertStringSliceToTypesDeviceSlice(array.Devices),
}
for _, device := range array.Devices {
newArray.Devices = append(newArray.Devices, ignTypes.Path(device))
}
out.Storage.Arrays = append(out.Storage.Arrays, newArray)
out.Storage.Raid = append(out.Storage.Raid, newArray)
}
return out, report.Report{}, ast
})
}
// golang--
func convertStringSliceToTypesDeviceSlice(ss []string) []ignTypes.Device {
var res []ignTypes.Device
for _, s := range ss {
res = append(res, ignTypes.Device(s))
}
return res
}

View File

@@ -19,4 +19,6 @@ type Storage struct {
Arrays []Raid `yaml:"raid"`
Filesystems []Filesystem `yaml:"filesystems"`
Files []File `yaml:"files"`
Directories []Directory `yaml:"directories"`
Links []Link `yaml:"links"`
}

View File

@@ -15,8 +15,8 @@
package types
import (
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -27,9 +27,10 @@ type Systemd struct {
type SystemdUnit struct {
Name string `yaml:"name"`
Enable bool `yaml:"enable"`
Enabled *bool `yaml:"enabled"`
Mask bool `yaml:"mask"`
Contents string `yaml:"contents"`
DropIns []SystemdUnitDropIn `yaml:"dropins"`
Dropins []SystemdUnitDropIn `yaml:"dropins"`
}
type SystemdUnitDropIn struct {
@@ -38,18 +39,19 @@ type SystemdUnitDropIn struct {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
for _, unit := range in.Systemd.Units {
newUnit := ignTypes.SystemdUnit{
Name: ignTypes.SystemdUnitName(unit.Name),
newUnit := ignTypes.Unit{
Name: unit.Name,
Enable: unit.Enable,
Enabled: unit.Enabled,
Mask: unit.Mask,
Contents: unit.Contents,
}
for _, dropIn := range unit.DropIns {
newUnit.DropIns = append(newUnit.DropIns, ignTypes.SystemdUnitDropIn{
Name: ignTypes.SystemdUnitDropInName(dropIn.Name),
for _, dropIn := range unit.Dropins {
newUnit.Dropins = append(newUnit.Dropins, ignTypes.Dropin{
Name: dropIn.Name,
Contents: dropIn.Contents,
})
}

View File

@@ -20,8 +20,8 @@ import (
"net/url"
"strings"
ignTypes "github.com/coreos/ignition/config/v2_0/types"
"github.com/coreos/ignition/config/validate"
ignTypes "github.com/coreos/ignition/config/v2_1/types"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
"github.com/vincent-petithory/dataurl"
)
@@ -59,7 +59,7 @@ func (s UpdateServer) Validate() report.Report {
}
func init() {
register2_0(func(in Config, ast validate.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, validate.AstNode) {
register2_0(func(in Config, ast astnode.AstNode, out ignTypes.Config, platform string) (ignTypes.Config, report.Report, astnode.AstNode) {
var contents string
if in.Update != nil {
if in.Update.Group != "" {
@@ -77,13 +77,17 @@ func init() {
}
if contents != "" {
out.Storage.Files = append(out.Storage.Files, ignTypes.File{
Filesystem: "root",
Path: "/etc/coreos/update.conf",
Mode: 0644,
Contents: ignTypes.FileContents{
Source: ignTypes.Url{
Scheme: "data",
Opaque: "," + dataurl.EscapeString(contents),
Node: ignTypes.Node{
Filesystem: "root",
Path: "/etc/coreos/update.conf",
},
FileEmbedded1: ignTypes.FileEmbedded1{
Mode: 0644,
Contents: ignTypes.FileContents{
Source: (&url.URL{
Scheme: "data",
Opaque: "," + dataurl.EscapeString(contents),
}).String(),
},
},
})

View File

@@ -22,3 +22,7 @@ type Hash struct {
Function string `yaml:"function"`
Sum string `yaml:"sum"`
}
func (h Hash) String() string {
return h.Function + "-" + h.Sum
}

View File

@@ -45,11 +45,19 @@ var (
// Parse parses the raw config into a types.Config struct and generates a report of any
// errors, warnings, info, and deprecations it encountered
func Parse(rawConfig []byte) (types.Config, report.Report, error) {
if isEmpty(rawConfig) {
return types.Config{}, report.Report{}, ErrEmpty
} else if isCloudConfig(rawConfig) {
return types.Config{}, report.Report{}, ErrCloudConfig
} else if isScript(rawConfig) {
return types.Config{}, report.Report{}, ErrScript
}
version, err := Version(rawConfig)
if err != nil && err != ErrVersionIndeterminable {
// If we can't determine the version, ignore this error so that in the
// default case of the switch statement we can check for empty configs,
// cloud configs, and other such things.
// If we can't determine the version, its probably invalid json and we want to fall through
// to handle that in ParseFromLatest, since it will generate the highlight string and report
// line and column.
return types.Config{}, report.ReportFromError(err, report.EntryError), err
}
switch version {
@@ -67,13 +75,18 @@ func Parse(rawConfig []byte) (types.Config, report.Report, error) {
case semver.Version{Major: 2, Minor: 0}:
return ParseFromV2_0(rawConfig)
default:
if isEmpty(rawConfig) {
return types.Config{}, report.Report{}, ErrEmpty
} else if isCloudConfig(rawConfig) {
return types.Config{}, report.Report{}, ErrCloudConfig
} else if isScript(rawConfig) {
return types.Config{}, report.Report{}, ErrScript
// It's not empty, it's not a cloud config, and it's not a script, but
// we can't determine the version of it (or it's 0.0.0, hooray golang
// zero values). We know it's not valid, but try to parse it anyway with
// ParseFromLatest to generate any parse errors.
config, rep, err := ParseFromLatest(rawConfig)
if err != nil || rep.IsFatal() {
return config, rep, err
}
// Somehow parsing succeeded without any errors or fatal reports. This
// should be an impossible state, but since we're in this part of the
// switch statement we know at the very least the version is invalid, so
// return that.
return types.Config{}, report.Report{}, ErrUnknownVersion
}
}

View File

@@ -45,24 +45,36 @@ func (c Config) Validate() report.Report {
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 {
if file.Filesystem == "" {
// Filesystem was not specified. This is an error, but its handled in types.File's Validate, not here
continue
}
_, ok := filesystems[file.Filesystem]
if !ok {
r.Add(report.Entry{
Kind: report.EntryWarning,
Message: fmt.Sprintf("File %q references nonexistent filesystem %q. (This is ok if it is defined in a referenced config)",
file.Path, file.Filesystem),
})
}
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"))
}
}

View File

@@ -62,7 +62,10 @@ func (n Disk) ValidatePartitions() report.Report {
func (n Disk) partitionNumbersCollide() bool {
m := map[int][]Partition{}
for _, p := range n.Partitions {
m[p.Number] = append(m[p.Number], p)
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 {

View File

@@ -60,7 +60,10 @@ func (n Disk) Validate() report.Report {
func (n Disk) partitionNumbersCollide() bool {
m := map[int][]Partition{}
for _, p := range n.Partitions {
m[p.Number] = append(m[p.Number], p)
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 {

View File

@@ -44,24 +44,36 @@ func (c Config) Validate() report.Report {
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 {
if file.Filesystem == "" {
// Filesystem was not specified. This is an error, but its handled in types.File's Validate, not here
continue
}
_, ok := filesystems[file.Filesystem]
if !ok {
r.Add(report.Entry{
Kind: report.EntryWarning,
Message: fmt.Sprintf("File %q references nonexistent filesystem %q. (This is ok if it is defined in a referenced config)",
file.Path, file.Filesystem),
})
}
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"))
}
}

View File

@@ -62,7 +62,10 @@ func (n Disk) ValidatePartitions() report.Report {
func (n Disk) partitionNumbersCollide() bool {
m := map[int][]Partition{}
for _, p := range n.Partitions {
m[p.Number] = append(m[p.Number], p)
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 {

View File

@@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package node
package astjson
import (
"io"
json "github.com/ajeddeloh/go-json"
"github.com/coreos/ignition/config/validate"
"github.com/coreos/ignition/config/validate/astnode"
"go4.org/errorutil"
)
@@ -40,16 +40,16 @@ func (n JsonNode) LiteralValue() interface{} {
return n.Value
}
func (n JsonNode) SliceChild(index int) (validate.AstNode, bool) {
func (n JsonNode) SliceChild(index int) (astnode.AstNode, bool) {
if slice, ok := n.Value.([]json.Node); ok {
return JsonNode(slice[index]), true
}
return JsonNode{}, false
}
func (n JsonNode) KeyValueMap() (map[string]validate.AstNode, bool) {
func (n JsonNode) KeyValueMap() (map[string]astnode.AstNode, bool) {
if kvmap, ok := n.Value.(map[string]json.Node); ok {
newKvmap := map[string]validate.AstNode{}
newKvmap := map[string]astnode.AstNode{}
for k, v := range kvmap {
newKvmap[k] = JsonNode(v)
}

View File

@@ -0,0 +1,45 @@
// 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 astnode
import (
"io"
)
// AstNode abstracts the differences between yaml and json nodes, providing a
// common interface
type AstNode interface {
// ValueLineCol returns the line, column, and highlight string of the value of
// this node in the source.
ValueLineCol(source io.ReadSeeker) (int, int, string)
// KeyLineCol returns the line, column, and highlight string of the key for the
// value of this node in the source.
KeyLineCol(source io.ReadSeeker) (int, int, string)
// LiteralValue returns the value of this node.
LiteralValue() interface{}
// SliceChild returns the child node at the index specified. If this node is not
// a slice node, an empty AstNode and false is returned.
SliceChild(index int) (AstNode, bool)
// KeyValueMap returns a map of keys and values. If this node is not a mapping
// node, nil and false are returned.
KeyValueMap() (map[string]AstNode, bool)
// Tag returns the struct tag used in the config structure used to unmarshal.
Tag() string
}

View File

@@ -20,6 +20,7 @@ import (
"reflect"
"strings"
"github.com/coreos/ignition/config/validate/astnode"
"github.com/coreos/ignition/config/validate/report"
)
@@ -27,36 +28,10 @@ type validator interface {
Validate() report.Report
}
// AstNode abstracts the differences between yaml and json nodes, providing a
// common interface
type AstNode interface {
// ValueLineCol returns the line, column, and highlight string of the value of
// this node in the source.
ValueLineCol(source io.ReadSeeker) (int, int, string)
// KeyLineCol returns the line, column, and highlight string of the key for the
// value of this node in the source.
KeyLineCol(source io.ReadSeeker) (int, int, string)
// LiteralValue returns the value of this node.
LiteralValue() interface{}
// SliceChild returns the child node at the index specified. If this node is not
// a slice node, an empty AstNode and false is returned.
SliceChild(index int) (AstNode, bool)
// KeyValueMap returns a map of keys and values. If this node is not a mapping
// node, nil and false are returned.
KeyValueMap() (map[string]AstNode, bool)
// Tag returns the struct tag used in the config structure used to unmarshal.
Tag() string
}
// Validate walks down a struct tree calling Validate on every node that implements it, building
// A report of all the errors, warnings, info, and deprecations it encounters. If checkUnusedKeys
// is true, Validate will generate warnings for unused keys in the ast, otherwise it will not.
func Validate(vObj reflect.Value, ast AstNode, source io.ReadSeeker, checkUnusedKeys bool) (r report.Report) {
func Validate(vObj reflect.Value, ast astnode.AstNode, source io.ReadSeeker, checkUnusedKeys bool) (r report.Report) {
if !vObj.IsValid() {
return
}
@@ -138,11 +113,11 @@ func getFields(vObj reflect.Value) []field {
return ret
}
func validateStruct(vObj reflect.Value, ast AstNode, source io.ReadSeeker, checkUnusedKeys bool) report.Report {
func validateStruct(vObj reflect.Value, ast astnode.AstNode, source io.ReadSeeker, checkUnusedKeys bool) report.Report {
r := report.Report{}
// isFromObject will be true if this struct was unmarshalled from a JSON object.
keys, isFromObject := map[string]AstNode{}, false
keys, isFromObject := map[string]astnode.AstNode{}, false
if ast != nil {
keys, isFromObject = ast.KeyValueMap()
}
@@ -154,8 +129,8 @@ func validateStruct(vObj reflect.Value, ast AstNode, source io.ReadSeeker, check
tags := []string{}
for _, f := range getFields(vObj) {
// Default to nil AstNode if the field's corrosponding node cannot be found.
var sub_node AstNode
// Default to nil astnode.AstNode if the field's corrosponding node cannot be found.
var sub_node astnode.AstNode
// Default to passing a nil source if the field's corrosponding node cannot be found.
// This ensures the line numbers reported from all sub-structs are 0 and will be changed by AddPosition
var src io.ReadSeeker
@@ -185,6 +160,10 @@ func validateStruct(vObj reflect.Value, ast AstNode, source io.ReadSeeker, check
// If there's a Validate<Name> func for the given field, call it
funct := vObj.MethodByName("Validate" + f.Type.Name)
if funct.IsValid() {
if sub_node != nil {
// if sub_node is non-nil, we can get better line/col info
line, col, _ = sub_node.ValueLineCol(src)
}
res := funct.Call(nil)
sub_report := res[0].Interface().(report.Report)
sub_report.AddPosition(line, col, "")