Merge pull request #167 from crawford/sshkeys
metadata-service: fix ssh key retrieval and application
This commit is contained in:
		| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user