From 7fcc54015453484ea02a68e35d0450e43ee11db5 Mon Sep 17 00:00:00 2001 From: Alex Crawford Date: Mon, 30 Jun 2014 16:23:46 -0700 Subject: [PATCH] metadata-service: fix ssh key retrieval and application The metadata service wasn't properly fetching the ssh keys from metadata. Drop the key traversal in favor of explict key urls. --- datasource/metadata_service.go | 68 +++++++++++++++++------------ datasource/metadata_service_test.go | 15 +++---- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/datasource/metadata_service.go b/datasource/metadata_service.go index 8e7450e..4817a09 100644 --- a/datasource/metadata_service.go +++ b/datasource/metadata_service.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "encoding/json" + "fmt" "strings" "github.com/coreos/coreos-cloudinit/pkg" @@ -23,7 +24,7 @@ const ( BaseUrl = "http://169.254.169.254/" Ec2ApiVersion = "2009-04-04" Ec2UserdataUrl = BaseUrl + Ec2ApiVersion + "/user-data" - Ec2MetadataUrl = BaseUrl + Ec2ApiVersion + "/meta-data/" + Ec2MetadataUrl = BaseUrl + Ec2ApiVersion + "/meta-data" OpenstackApiVersion = "openstack/2012-08-10" OpenstackUserdataUrl = BaseUrl + OpenstackApiVersion + "/user_data" OpenstackMetadataUrl = BaseUrl + OpenstackApiVersion + "/meta_data.json" @@ -78,10 +79,45 @@ func fetchMetadata(client getter) ([]byte, error) { return nil, err } - attrs, err := fetchChildAttributes(client, Ec2MetadataUrl) - if err != nil { + 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 { + 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) } @@ -93,37 +129,15 @@ func fetchAttributes(client getter, url string) ([]string, error) { scanner := bufio.NewScanner(bytes.NewBuffer(resp)) data := make([]string, 0) for scanner.Scan() { - data = append(data, strings.Split(scanner.Text(), "=")[0]) + data = append(data, scanner.Text()) } 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 { return attrs[0], nil } else { 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 -} diff --git a/datasource/metadata_service_test.go b/datasource/metadata_service_test.go index 58ee298..e2aa4e3 100644 --- a/datasource/metadata_service_test.go +++ b/datasource/metadata_service_test.go @@ -137,15 +137,13 @@ func TestFetchMetadata(t *testing.T) { }{ { 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/c/": "d\ne/", - "http://169.254.169.254/2009-04-04/meta-data/c/e/": "f", - "http://169.254.169.254/2009-04-04/meta-data/a": "1", - "http://169.254.169.254/2009-04-04/meta-data/b": "2", - "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", + "http://169.254.169.254/2009-04-04/meta-data/hostname": "host", + "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/public-keys/0": "openssh-key", + "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/network_config/content_path": "path", }, - 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{ @@ -154,7 +152,6 @@ func TestFetchMetadata(t *testing.T) { expect: []byte("test"), }, {err: pkg.ErrTimeout{fmt.Errorf("test error")}}, - {err: pkg.ErrNotFound{fmt.Errorf("test error")}}, } { client := &TestHttpClient{tt.metadata, tt.err} metadata, err := fetchMetadata(client)