config: deprecate - in favor of _ for key names

In all of the YAML tags, - has been replaced with _. normalizeConfig() and
normalizeKeys() have also been added to perform the normalization of the input
cloud-config.

As part of the normalization process, falsey values are converted to "false".
The "off" update strategy is no exception and as a result the "off" update
strategy has been changed to "false".
This commit is contained in:
Alex Crawford 2014-11-03 12:09:52 -08:00
parent e9bda98b54
commit d02aa18839
9 changed files with 119 additions and 61 deletions

View File

@ -50,10 +50,13 @@ type CloudConfig struct {
// fields but log encountering them.
func NewCloudConfig(contents string) (*CloudConfig, error) {
var cfg CloudConfig
err := yaml.Unmarshal([]byte(contents), &cfg)
ncontents, err := normalizeConfig(contents)
if err != nil {
return &cfg, err
}
if err = yaml.Unmarshal(ncontents, &cfg); err != nil {
return &cfg, err
}
warnOnUnrecognizedKeys(contents, log.Printf)
return &cfg, nil
}
@ -212,3 +215,31 @@ func warnOnUnrecognizedKeys(contents string, warn warner) {
}
}
}
func normalizeConfig(config string) ([]byte, error) {
var cfg map[interface{}]interface{}
if err := yaml.Unmarshal([]byte(config), &cfg); err != nil {
return nil, err
}
return yaml.Marshal(normalizeKeys(cfg))
}
func normalizeKeys(m map[interface{}]interface{}) map[interface{}]interface{} {
for k, v := range m {
if m, ok := m[k].(map[interface{}]interface{}); ok {
normalizeKeys(m)
}
if s, ok := m[k].([]interface{}); ok {
for _, e := range s {
if m, ok := e.(map[interface{}]interface{}); ok {
normalizeKeys(m)
}
}
}
delete(m, k)
m[strings.Replace(fmt.Sprint(k), "-", "_", -1)] = v
}
return m
}

View File

@ -200,7 +200,7 @@ coreos:
etcd:
discovery: "https://discovery.etcd.io/827c73219eeb2fa5530027c37bf18877"
update:
reboot-strategy: reboot
reboot_strategy: reboot
units:
- name: 50-eth0.network
runtime: yes
@ -217,9 +217,9 @@ coreos:
oem:
id: rackspace
name: Rackspace Cloud Servers
version-id: 168.0.0
home-url: https://www.rackspace.com/cloud/servers/
bug-report-url: https://github.com/coreos/coreos-overlay
version_id: 168.0.0
home_url: https://www.rackspace.com/cloud/servers/
bug_report_url: https://github.com/coreos/coreos-overlay
ssh_authorized_keys:
- foobar
- foobaz
@ -354,18 +354,18 @@ func TestCloudConfigUsers(t *testing.T) {
users:
- name: elroy
passwd: somehash
ssh-authorized-keys:
ssh_authorized_keys:
- somekey
gecos: arbitrary comment
homedir: /home/place
no-create-home: yes
primary-group: things
no_create_home: yes
primary_group: things
groups:
- ping
- pong
no-user-group: true
no_user_group: true
system: y
no-log-init: True
no_log_init: True
`
cfg, err := NewCloudConfig(contents)
if err != nil {
@ -404,11 +404,11 @@ users:
}
if !user.NoCreateHome {
t.Errorf("Failed to parse no-create-home field")
t.Errorf("Failed to parse no_create_home field")
}
if user.PrimaryGroup != "things" {
t.Errorf("Failed to parse primary-group field, got %q", user.PrimaryGroup)
t.Errorf("Failed to parse primary_group field, got %q", user.PrimaryGroup)
}
if len(user.Groups) != 2 {
@ -423,7 +423,7 @@ users:
}
if !user.NoUserGroup {
t.Errorf("Failed to parse no-user-group field")
t.Errorf("Failed to parse no_user_group field")
}
if !user.System {
@ -431,7 +431,7 @@ users:
}
if !user.NoLogInit {
t.Errorf("Failed to parse no-log-init field")
t.Errorf("Failed to parse no_log_init field")
}
}
@ -440,7 +440,7 @@ func TestCloudConfigUsersGithubUser(t *testing.T) {
contents := `
users:
- name: elroy
coreos-ssh-import-github: bcwaldon
coreos_ssh_import_github: bcwaldon
`
cfg, err := NewCloudConfig(contents)
if err != nil {
@ -466,7 +466,7 @@ func TestCloudConfigUsersSSHImportURL(t *testing.T) {
contents := `
users:
- name: elroy
coreos-ssh-import-url: https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys
coreos_ssh_import_url: https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys
`
cfg, err := NewCloudConfig(contents)
if err != nil {
@ -487,3 +487,30 @@ users:
t.Errorf("ssh import url is %q, expected 'https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys'", user.SSHImportURL)
}
}
func TestNormalizeKeys(t *testing.T) {
for _, tt := range []struct {
in string
out string
}{
{"my_key_name: the-value\n", "my_key_name: the-value\n"},
{"my-key_name: the-value\n", "my_key_name: the-value\n"},
{"my-key-name: the-value\n", "my_key_name: the-value\n"},
{"a:\n- key_name: the-value\n", "a:\n- key_name: the-value\n"},
{"a:\n- key-name: the-value\n", "a:\n- key_name: the-value\n"},
{"a:\n b:\n - key_name: the-value\n", "a:\n b:\n - key_name: the-value\n"},
{"a:\n b:\n - key-name: the-value\n", "a:\n b:\n - key_name: the-value\n"},
{"coreos:\n update:\n reboot-strategy: off\n", "coreos:\n update:\n reboot_strategy: false\n"},
} {
out, err := normalizeConfig(tt.in)
if err != nil {
t.Fatalf("bad error (%q): want nil, got %s", tt.in, err)
}
if string(out) != tt.out {
t.Fatalf("bad normalization (%q): want %q, got %q", tt.in, tt.out, out)
}
}
}

View File

@ -18,31 +18,31 @@ package config
type Etcd struct {
Addr string `yaml:"addr" env:"ETCD_ADDR"`
BindAddr string `yaml:"bind-addr" env:"ETCD_BIND_ADDR"`
CAFile string `yaml:"ca-file" env:"ETCD_CA_FILE"`
CertFile string `yaml:"cert-file" env:"ETCD_CERT_FILE"`
ClusterActiveSize string `yaml:"cluster-active-size" env:"ETCD_CLUSTER_ACTIVE_SIZE"`
ClusterRemoveDelay string `yaml:"cluster-remove-delay" env:"ETCD_CLUSTER_REMOVE_DELAY"`
ClusterSyncInterval string `yaml:"cluster-sync-interval" env:"ETCD_CLUSTER_SYNC_INTERVAL"`
BindAddr string `yaml:"bind_addr" env:"ETCD_BIND_ADDR"`
CAFile string `yaml:"ca_file" env:"ETCD_CA_FILE"`
CertFile string `yaml:"cert_file" env:"ETCD_CERT_FILE"`
ClusterActiveSize string `yaml:"cluster_active_size" env:"ETCD_CLUSTER_ACTIVE_SIZE"`
ClusterRemoveDelay string `yaml:"cluster_remove_delay" env:"ETCD_CLUSTER_REMOVE_DELAY"`
ClusterSyncInterval string `yaml:"cluster_sync_interval" env:"ETCD_CLUSTER_SYNC_INTERVAL"`
Cors string `yaml:"cors" env:"ETCD_CORS"`
CPUProfileFile string `yaml:"cpu-profile-file" env:"ETCD_CPU_PROFILE_FILE"`
DataDir string `yaml:"data-dir" env:"ETCD_DATA_DIR"`
CPUProfileFile string `yaml:"cpu_profile_file" env:"ETCD_CPU_PROFILE_FILE"`
DataDir string `yaml:"data_dir" env:"ETCD_DATA_DIR"`
Discovery string `yaml:"discovery" env:"ETCD_DISCOVERY"`
HTTPReadTimeout string `yaml:"http-read-timeout" env:"ETCD_HTTP_READ_TIMEOUT"`
HTTPWriteTimeout string `yaml:"http-write-timeout" env:"ETCD_HTTP_WRITE_TIMEOUT"`
KeyFile string `yaml:"key-file" env:"ETCD_KEY_FILE"`
MaxClusterSize string `yaml:"max-cluster-size" env:"ETCD_MAX_CLUSTER_SIZE"`
MaxResultBuffer string `yaml:"max-result-buffer" env:"ETCD_MAX_RESULT_BUFFER"`
MaxRetryAttempts string `yaml:"max-retry-attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
HTTPReadTimeout string `yaml:"http_read_timeout" env:"ETCD_HTTP_READ_TIMEOUT"`
HTTPWriteTimeout string `yaml:"http_write_timeout" env:"ETCD_HTTP_WRITE_TIMEOUT"`
KeyFile string `yaml:"key_file" env:"ETCD_KEY_FILE"`
MaxClusterSize string `yaml:"max_cluster_size" env:"ETCD_MAX_CLUSTER_SIZE"`
MaxResultBuffer string `yaml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"`
MaxRetryAttempts string `yaml:"max_retry_attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
Name string `yaml:"name" env:"ETCD_NAME"`
PeerAddr string `yaml:"peer-addr" env:"ETCD_PEER_ADDR"`
PeerBindAddr string `yaml:"peer-bind-addr" env:"ETCD_PEER_BIND_ADDR"`
PeerCAFile string `yaml:"peer-ca-file" env:"ETCD_PEER_CA_FILE"`
PeerCertFile string `yaml:"peer-cert-file" env:"ETCD_PEER_CERT_FILE"`
PeerKeyFile string `yaml:"peer-key-file" env:"ETCD_PEER_KEY_FILE"`
PeerAddr string `yaml:"peer_addr" env:"ETCD_PEER_ADDR"`
PeerBindAddr string `yaml:"peer_bind_addr" env:"ETCD_PEER_BIND_ADDR"`
PeerCAFile string `yaml:"peer_ca_file" env:"ETCD_PEER_CA_FILE"`
PeerCertFile string `yaml:"peer_cert_file" env:"ETCD_PEER_CERT_FILE"`
PeerKeyFile string `yaml:"peer_key_file" env:"ETCD_PEER_KEY_FILE"`
Peers string `yaml:"peers" env:"ETCD_PEERS"`
PeersFile string `yaml:"peers-file" env:"ETCD_PEERS_FILE"`
PeersFile string `yaml:"peers_file" env:"ETCD_PEERS_FILE"`
Snapshot string `yaml:"snapshot" env:"ETCD_SNAPSHOT"`
Verbose string `yaml:"verbose" env:"ETCD_VERBOSE"`
VeryVerbose string `yaml:"very-verbose" env:"ETCD_VERY_VERBOSE"`
VeryVerbose string `yaml:"very_verbose" env:"ETCD_VERY_VERBOSE"`
}

View File

@ -17,14 +17,14 @@
package config
type Fleet struct {
AgentTTL string `yaml:"agent-ttl" env:"FLEET_AGENT_TTL"`
EngineReconcileInterval string `yaml:"engine-reconcile-interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"`
EtcdCAFile string `yaml:"etcd-cafile" env:"FLEET_ETCD_CAFILE"`
EtcdCertFile string `yaml:"etcd-certfile" env:"FLEET_ETCD_CERTFILE"`
EtcdKeyFile string `yaml:"etcd-keyfile" env:"FLEET_ETCD_KEYFILE"`
EtcdRequestTimeout string `yaml:"etcd-request-timeout" env:"FLEET_ETCD_REQUEST_TIMEOUT"`
EtcdServers string `yaml:"etcd-servers" env:"FLEET_ETCD_SERVERS"`
AgentTTL string `yaml:"agent_ttl" env:"FLEET_AGENT_TTL"`
EngineReconcileInterval string `yaml:"engine_reconcile_interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"`
EtcdCAFile string `yaml:"etcd_cafile" env:"FLEET_ETCD_CAFILE"`
EtcdCertFile string `yaml:"etcd_certfile" env:"FLEET_ETCD_CERTFILE"`
EtcdKeyFile string `yaml:"etcd_keyfile" env:"FLEET_ETCD_KEYFILE"`
EtcdRequestTimeout string `yaml:"etcd_request_timeout" env:"FLEET_ETCD_REQUEST_TIMEOUT"`
EtcdServers string `yaml:"etcd_servers" env:"FLEET_ETCD_SERVERS"`
Metadata string `yaml:"metadata" env:"FLEET_METADATA"`
PublicIP string `yaml:"public-ip" env:"FLEET_PUBLIC_IP"`
PublicIP string `yaml:"public_ip" env:"FLEET_PUBLIC_IP"`
Verbosity string `yaml:"verbosity" env:"FLEET_VERBOSITY"`
}

View File

@ -19,7 +19,7 @@ package config
type OEM struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
VersionID string `yaml:"version-id"`
HomeURL string `yaml:"home-url"`
BugReportURL string `yaml:"bug-report-url"`
VersionID string `yaml:"version_id"`
HomeURL string `yaml:"home_url"`
BugReportURL string `yaml:"bug_report_url"`
}

View File

@ -17,7 +17,7 @@
package config
type Update struct {
RebootStrategy string `yaml:"reboot-strategy" env:"REBOOT_STRATEGY" valid:"best-effort,etcd-lock,reboot,off"`
RebootStrategy string `yaml:"reboot_strategy" env:"REBOOT_STRATEGY" valid:"best-effort,etcd-lock,reboot,false"`
Group string `yaml:"group" env:"GROUP"`
Server string `yaml:"server" env:"SERVER"`
}

View File

@ -19,15 +19,15 @@ package config
type User struct {
Name string `yaml:"name"`
PasswordHash string `yaml:"passwd"`
SSHAuthorizedKeys []string `yaml:"ssh-authorized-keys"`
SSHImportGithubUser string `yaml:"coreos-ssh-import-github"`
SSHImportURL string `yaml:"coreos-ssh-import-url"`
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
SSHImportGithubUser string `yaml:"coreos_ssh_import_github"`
SSHImportURL string `yaml:"coreos_ssh_import_url"`
GECOS string `yaml:"gecos"`
Homedir string `yaml:"homedir"`
NoCreateHome bool `yaml:"no-create-home"`
PrimaryGroup string `yaml:"primary-group"`
NoCreateHome bool `yaml:"no_create_home"`
PrimaryGroup string `yaml:"primary_group"`
Groups []string `yaml:"groups"`
NoUserGroup bool `yaml:"no-user-group"`
NoUserGroup bool `yaml:"no_user_group"`
System bool `yaml:"system"`
NoLogInit bool `yaml:"no-log-init"`
NoLogInit bool `yaml:"no_log_init"`
}

View File

@ -126,7 +126,7 @@ func (uc Update) Units() []Unit {
Runtime: true,
}}
if uc.Update.RebootStrategy == "off" {
if uc.Update.RebootStrategy == "false" {
ls.Command = "stop"
ls.Mask = true
}

View File

@ -73,7 +73,7 @@ func TestUpdateUnits(t *testing.T) {
}}},
},
{
config: config.Update{RebootStrategy: "off"},
config: config.Update{RebootStrategy: "false"},
units: []Unit{{config.Unit{
Name: "locksmithd.service",
Command: "stop",
@ -101,7 +101,7 @@ func TestUpdateFile(t *testing.T) {
},
{
config: config.Update{RebootStrategy: "wizzlewazzle"},
err: errors.New("invalid value \"wizzlewazzle\" for option \"RebootStrategy\" (valid options: \"best-effort,etcd-lock,reboot,off\")"),
err: errors.New("invalid value \"wizzlewazzle\" for option \"RebootStrategy\" (valid options: \"best-effort,etcd-lock,reboot,false\")"),
},
{
config: config.Update{Group: "master", Server: "http://foo.com"},
@ -136,9 +136,9 @@ func TestUpdateFile(t *testing.T) {
}},
},
{
config: config.Update{RebootStrategy: "off"},
config: config.Update{RebootStrategy: "false"},
file: &File{config.File{
Content: "REBOOT_STRATEGY=off\n",
Content: "REBOOT_STRATEGY=false\n",
Path: "etc/coreos/update.conf",
RawFilePermissions: "0644",
}},