diff --git a/initialize/config.go b/initialize/config.go index 3fdc318..e754f5b 100644 --- a/initialize/config.go +++ b/initialize/config.go @@ -43,10 +43,35 @@ type CloudConfig struct { ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"` } +type warner func(format string, v ...interface{}) + +func warnOnUnrecognizedKeys(contents string, warn warner) { + // Generate a map of all understood cloud config options + var cc map[string]interface{} + b, _ := goyaml.Marshal(&CloudConfig{}) + goyaml.Unmarshal(b, &cc) + // Now unmarshal the entire provided contents + var c map[string]interface{} + goyaml.Unmarshal([]byte(contents), &c) + // Check that every key in the contents exists in the cloud config + for k, _ := range c { + if _, ok := cc[k]; !ok { + warn("Warning: unrecognized key %q in provided cloud config - ignoring section", k) + } + } +} + +// NewCloudConfig instantiates a new CloudConfig from the given contents (a +// string of YAML), returning any error encountered. It will ignore unknown +// fields but log encountering them. func NewCloudConfig(contents string) (*CloudConfig, error) { var cfg CloudConfig err := goyaml.Unmarshal([]byte(contents), &cfg) - return &cfg, err + if err != nil { + return &cfg, err + } + warnOnUnrecognizedKeys(contents, log.Printf) + return &cfg, nil } func (cc CloudConfig) String() string { diff --git a/initialize/config_test.go b/initialize/config_test.go index a26af64..0ba0a8f 100644 --- a/initialize/config_test.go +++ b/initialize/config_test.go @@ -1,10 +1,50 @@ package initialize import ( + "fmt" "strings" "testing" ) +func TestCloudConfigUnknownKeys(t *testing.T) { + contents := ` +coreos: + etcd: + discovery: "https://discovery.etcd.io/827c73219eeb2fa5530027c37bf18877" +unknown: + dunno: + something +foo: + bar +hostname: + foo +` + cfg, err := NewCloudConfig(contents) + if err != nil { + t.Fatalf("error instantiating CloudConfig with unknown keys: %v", err) + } + if cfg.Hostname != "foo" { + t.Fatalf("hostname not correctly set when invalid keys are present") + } + if len(cfg.Coreos.Etcd) < 1 { + t.Fatalf("etcd section not correctly set when invalid keys are present") + } + + var warnings string + catchWarn := func(f string, v ...interface{}) { + warnings += fmt.Sprintf(f, v...) + } + + warnOnUnrecognizedKeys(contents, catchWarn) + + if !strings.Contains(warnings, "foo") { + t.Errorf("warnings did not catch unrecognized key foo") + } + if !strings.Contains(warnings, "unknown") { + t.Errorf("warnings did not catch unrecognized key unknown") + } +} + // Assert that the parsing of a cloud config file "generally works" func TestCloudConfigEmpty(t *testing.T) { cfg, err := NewCloudConfig("")