Merge pull request #167 from crawford/sshkeys

metadata-service: fix ssh key retrieval and application
This commit is contained in:
Alex Crawford 2014-06-30 18:08:04 -07:00
commit d8d3928978
2 changed files with 47 additions and 36 deletions

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"strings" "strings"
"github.com/coreos/coreos-cloudinit/pkg" "github.com/coreos/coreos-cloudinit/pkg"
@ -23,7 +24,7 @@ const (
BaseUrl = "http://169.254.169.254/" BaseUrl = "http://169.254.169.254/"
Ec2ApiVersion = "2009-04-04" Ec2ApiVersion = "2009-04-04"
Ec2UserdataUrl = BaseUrl + Ec2ApiVersion + "/user-data" Ec2UserdataUrl = BaseUrl + Ec2ApiVersion + "/user-data"
Ec2MetadataUrl = BaseUrl + Ec2ApiVersion + "/meta-data/" Ec2MetadataUrl = BaseUrl + Ec2ApiVersion + "/meta-data"
OpenstackApiVersion = "openstack/2012-08-10" OpenstackApiVersion = "openstack/2012-08-10"
OpenstackUserdataUrl = BaseUrl + OpenstackApiVersion + "/user_data" OpenstackUserdataUrl = BaseUrl + OpenstackApiVersion + "/user_data"
OpenstackMetadataUrl = BaseUrl + OpenstackApiVersion + "/meta_data.json" OpenstackMetadataUrl = BaseUrl + OpenstackApiVersion + "/meta_data.json"
@ -78,10 +79,45 @@ func fetchMetadata(client getter) ([]byte, error) {
return nil, err return nil, err
} }
attrs, err := fetchChildAttributes(client, Ec2MetadataUrl) attrs := make(map[string]interface{})
if keynames, err := fetchAttributes(client, fmt.Sprintf("%s/public-keys", Ec2MetadataUrl)); err == nil {
keyIDs := make(map[string]string)
for _, keyname := range keynames {
tokens := strings.SplitN(keyname, "=", 2)
if len(tokens) != 2 {
return nil, fmt.Errorf("malformed public key: %q\n", keyname)
}
keyIDs[tokens[1]] = tokens[0]
}
keys := make(map[string]string)
for name, id := range keyIDs {
sshkey, err := fetchAttribute(client, fmt.Sprintf("%s/public-keys/%s/openssh-key", Ec2MetadataUrl, id))
if err != nil { if err != nil {
return nil, err return nil, err
} }
keys[name] = sshkey
fmt.Printf("Found SSH key for %q\n", name)
}
attrs["public_keys"] = keys
} else if _, ok := err.(pkg.ErrNotFound); !ok {
return nil, err
}
if hostname, err := fetchAttribute(client, fmt.Sprintf("%s/hostname", Ec2MetadataUrl)); err == nil {
attrs["hostname"] = hostname
} else if _, ok := err.(pkg.ErrNotFound); !ok {
return nil, err
}
if content_path, err := fetchAttribute(client, fmt.Sprintf("%s/network_config/content_path", Ec2MetadataUrl)); err == nil {
attrs["network_config"] = map[string]string{
"content_path": content_path,
}
} else if _, ok := err.(pkg.ErrNotFound); !ok {
return nil, err
}
return json.Marshal(attrs) return json.Marshal(attrs)
} }
@ -93,37 +129,15 @@ func fetchAttributes(client getter, url string) ([]string, error) {
scanner := bufio.NewScanner(bytes.NewBuffer(resp)) scanner := bufio.NewScanner(bytes.NewBuffer(resp))
data := make([]string, 0) data := make([]string, 0)
for scanner.Scan() { for scanner.Scan() {
data = append(data, strings.Split(scanner.Text(), "=")[0]) data = append(data, scanner.Text())
} }
return data, scanner.Err() return data, scanner.Err()
} }
func fetchAttribute(client getter, url string) (interface{}, error) { func fetchAttribute(client getter, url string) (string, error) {
if attrs, err := fetchAttributes(client, url); err == nil && len(attrs) > 0 { if attrs, err := fetchAttributes(client, url); err == nil && len(attrs) > 0 {
return attrs[0], nil return attrs[0], nil
} else { } else {
return "", err return "", err
} }
} }
func fetchChildAttributes(client getter, url string) (interface{}, error) {
attrs := make(map[string]interface{})
attrList, err := fetchAttributes(client, url)
if err != nil {
return nil, err
}
for _, attr := range attrList {
var fetchFunc func(getter, string) (interface{}, error)
if strings.HasSuffix(attr, "/") {
fetchFunc = fetchChildAttributes
} else {
fetchFunc = fetchAttribute
}
if value, err := fetchFunc(client, url+attr); err == nil {
attrs[strings.TrimSuffix(attr, "/")] = value
} else {
return nil, err
}
}
return attrs, nil
}

View File

@ -137,15 +137,13 @@ func TestFetchMetadata(t *testing.T) {
}{ }{
{ {
metadata: map[string]string{ metadata: map[string]string{
"http://169.254.169.254/2009-04-04/meta-data/": "a\nb\nc/", "http://169.254.169.254/2009-04-04/meta-data/hostname": "host",
"http://169.254.169.254/2009-04-04/meta-data/c/": "d\ne/", "http://169.254.169.254/2009-04-04/meta-data/public-keys": "0=test1\n",
"http://169.254.169.254/2009-04-04/meta-data/c/e/": "f", "http://169.254.169.254/2009-04-04/meta-data/public-keys/0": "openssh-key",
"http://169.254.169.254/2009-04-04/meta-data/a": "1", "http://169.254.169.254/2009-04-04/meta-data/public-keys/0/openssh-key": "key",
"http://169.254.169.254/2009-04-04/meta-data/b": "2", "http://169.254.169.254/2009-04-04/meta-data/network_config/content_path": "path",
"http://169.254.169.254/2009-04-04/meta-data/c/d": "3",
"http://169.254.169.254/2009-04-04/meta-data/c/e/f": "4",
}, },
expect: []byte(`{"a":"1","b":"2","c":{"d":"3","e":{"f":"4"}}}`), expect: []byte(`{"hostname":"host","network_config":{"content_path":"path"},"public_keys":{"test1":"key"}}`),
}, },
{ {
metadata: map[string]string{ metadata: map[string]string{
@ -154,7 +152,6 @@ func TestFetchMetadata(t *testing.T) {
expect: []byte("test"), expect: []byte("test"),
}, },
{err: pkg.ErrTimeout{fmt.Errorf("test error")}}, {err: pkg.ErrTimeout{fmt.Errorf("test error")}},
{err: pkg.ErrNotFound{fmt.Errorf("test error")}},
} { } {
client := &TestHttpClient{tt.metadata, tt.err} client := &TestHttpClient{tt.metadata, tt.err}
metadata, err := fetchMetadata(client) metadata, err := fetchMetadata(client)