datasource: replace metadata map with struct

The loosely-typed metadata map is a load of crap. Make it a struct and
let the compiler help us out.
This commit is contained in:
Alex Crawford
2015-01-22 17:35:39 -08:00
parent d4c617fc23
commit 3e47c09b41
17 changed files with 248 additions and 276 deletions

View File

@@ -15,68 +15,46 @@
package initialize
import (
"encoding/json"
"sort"
"github.com/coreos/coreos-cloudinit/config"
"github.com/coreos/coreos-cloudinit/datasource"
)
// ParseMetaData parses a JSON blob in the OpenStack metadata service format,
// and converts it to a partially hydrated CloudConfig.
func ParseMetaData(contents string) (*config.CloudConfig, error) {
if len(contents) == 0 {
return nil, nil
}
var metadata struct {
SSHAuthorizedKeyMap map[string]string `json:"public_keys"`
Hostname string `json:"hostname"`
NetworkConfig struct {
ContentPath string `json:"content_path"`
} `json:"network_config"`
}
if err := json.Unmarshal([]byte(contents), &metadata); err != nil {
return nil, err
}
func ParseMetaData(metadata datasource.Metadata) *config.CloudConfig {
var cfg config.CloudConfig
if len(metadata.SSHAuthorizedKeyMap) > 0 {
cfg.SSHAuthorizedKeys = make([]string, 0, len(metadata.SSHAuthorizedKeyMap))
for _, name := range sortedKeys(metadata.SSHAuthorizedKeyMap) {
cfg.SSHAuthorizedKeys = append(cfg.SSHAuthorizedKeys, metadata.SSHAuthorizedKeyMap[name])
if len(metadata.SSHPublicKeys) > 0 {
cfg.SSHAuthorizedKeys = make([]string, 0, len(metadata.SSHPublicKeys))
for _, name := range sortedKeys(metadata.SSHPublicKeys) {
cfg.SSHAuthorizedKeys = append(cfg.SSHAuthorizedKeys, metadata.SSHPublicKeys[name])
}
}
cfg.Hostname = metadata.Hostname
cfg.NetworkConfigPath = metadata.NetworkConfig.ContentPath
return &cfg, nil
cfg.NetworkConfigPath = metadata.NetworkConfigPath
return &cfg
}
// ExtractIPsFromMetaData parses a JSON blob in the OpenStack metadata service
// format and returns a substitution map possibly containing private_ipv4,
// public_ipv4, private_ipv6, and public_ipv6 addresses.
func ExtractIPsFromMetadata(contents []byte) (map[string]string, error) {
var ips struct {
PublicIPv4 string `json:"public-ipv4"`
PrivateIPv4 string `json:"local-ipv4"`
PublicIPv6 string `json:"public-ipv6"`
PrivateIPv6 string `json:"local-ipv6"`
func ExtractIPsFromMetadata(metadata datasource.Metadata) map[string]string {
subs := map[string]string{}
if metadata.PrivateIPv4 != nil {
subs["$private_ipv4"] = metadata.PrivateIPv4.String()
}
if err := json.Unmarshal(contents, &ips); err != nil {
return nil, err
if metadata.PublicIPv4 != nil {
subs["$public_ipv4"] = metadata.PublicIPv4.String()
}
m := make(map[string]string)
if ips.PrivateIPv4 != "" {
m["$private_ipv4"] = ips.PrivateIPv4
if metadata.PrivateIPv6 != nil {
subs["$private_ipv6"] = metadata.PrivateIPv6.String()
}
if ips.PublicIPv4 != "" {
m["$public_ipv4"] = ips.PublicIPv4
if metadata.PublicIPv6 != nil {
subs["$public_ipv6"] = metadata.PublicIPv6.String()
}
if ips.PrivateIPv6 != "" {
m["$private_ipv6"] = ips.PrivateIPv6
}
if ips.PublicIPv6 != "" {
m["$public_ipv6"] = ips.PublicIPv6
}
return m, nil
return subs
}
func sortedKeys(m map[string]string) (keys []string) {

View File

@@ -15,71 +15,29 @@
package initialize
import (
"net"
"reflect"
"testing"
"github.com/coreos/coreos-cloudinit/config"
"github.com/coreos/coreos-cloudinit/datasource"
)
func TestParseMetadata(t *testing.T) {
for i, tt := range []struct {
in string
want *config.CloudConfig
err bool
}{
{"", nil, false},
{`garbage, invalid json`, nil, true},
{`{"foo": "bar"}`, &config.CloudConfig{}, false},
{`{"network_config": {"content_path": "asdf"}}`, &config.CloudConfig{NetworkConfigPath: "asdf"}, false},
{`{"hostname": "turkleton"}`, &config.CloudConfig{Hostname: "turkleton"}, false},
{`{"public_keys": {"jack": "jill", "bob": "alice"}}`, &config.CloudConfig{SSHAuthorizedKeys: []string{"alice", "jill"}}, false},
{`{"unknown": "thing", "hostname": "my_host", "public_keys": {"do": "re", "mi": "fa"}, "network_config": {"content_path": "/root", "blah": "zzz"}}`, &config.CloudConfig{SSHAuthorizedKeys: []string{"re", "fa"}, Hostname: "my_host", NetworkConfigPath: "/root"}, false},
} {
got, err := ParseMetaData(tt.in)
if tt.err != (err != nil) {
t.Errorf("case #%d: bad error state: got %t, want %t (err=%v)", i, (err != nil), tt.err, err)
}
if got == nil {
if tt.want != nil {
t.Errorf("case #%d: unexpected nil output", i)
}
} else if tt.want == nil {
t.Errorf("case #%d: unexpected non-nil output", i)
} else {
if !reflect.DeepEqual(*got, *tt.want) {
t.Errorf("case #%d: bad output:\ngot\n%v\nwant\n%v", i, *got, *tt.want)
}
}
}
}
func TestExtractIPsFromMetadata(t *testing.T) {
for i, tt := range []struct {
in []byte
err bool
in datasource.Metadata
out map[string]string
}{
{
[]byte(`{"public-ipv4": "12.34.56.78", "local-ipv4": "1.2.3.4", "public-ipv6": "1234::", "local-ipv6": "5678::"}`),
false,
datasource.Metadata{
PublicIPv4: net.ParseIP("12.34.56.78"),
PrivateIPv4: net.ParseIP("1.2.3.4"),
PublicIPv6: net.ParseIP("1234::"),
PrivateIPv6: net.ParseIP("5678::"),
},
map[string]string{"$public_ipv4": "12.34.56.78", "$private_ipv4": "1.2.3.4", "$public_ipv6": "1234::", "$private_ipv6": "5678::"},
},
{
[]byte(`{"local-ipv4": "127.0.0.1", "something_else": "don't care"}`),
false,
map[string]string{"$private_ipv4": "127.0.0.1"},
},
{
[]byte(`garbage`),
true,
nil,
},
} {
got, err := ExtractIPsFromMetadata(tt.in)
if (err != nil) != tt.err {
t.Errorf("bad error state (got %t, want %t)", err != nil, tt.err)
}
got := ExtractIPsFromMetadata(tt.in)
if !reflect.DeepEqual(got, tt.out) {
t.Errorf("case %d: got %s, want %s", i, got, tt.out)
}