Merge pull request #188 from crawford/configdrive
configdrive: Use the EC2 metadata over OpenStack
This commit is contained in:
		| @@ -7,11 +7,12 @@ import ( | ||||
| ) | ||||
|  | ||||
| type configDrive struct { | ||||
| 	root string | ||||
| 	root     string | ||||
| 	readFile func(filename string) ([]byte, error) | ||||
| } | ||||
|  | ||||
| func NewConfigDrive(root string) *configDrive { | ||||
| 	return &configDrive{path.Join(root, "openstack")} | ||||
| 	return &configDrive{root, ioutil.ReadFile} | ||||
| } | ||||
|  | ||||
| func (cd *configDrive) IsAvailable() bool { | ||||
| @@ -24,23 +25,38 @@ func (cd *configDrive) AvailabilityChanges() bool { | ||||
| } | ||||
|  | ||||
| func (cd *configDrive) ConfigRoot() string { | ||||
| 	return cd.root | ||||
| 	return cd.openstackRoot() | ||||
| } | ||||
|  | ||||
| // FetchMetadata attempts to retrieve metadata from ec2/2009-04-04/meta_data.json. | ||||
| func (cd *configDrive) FetchMetadata() ([]byte, error) { | ||||
| 	return cd.readFile("meta_data.json") | ||||
| 	return cd.tryReadFile(path.Join(cd.ec2Root(), "meta_data.json")) | ||||
| } | ||||
|  | ||||
| // FetchUserdata attempts to retrieve the userdata from ec2/2009-04-04/user_data. | ||||
| // If no data is found, it will attempt to read from openstack/latest/user_data. | ||||
| func (cd *configDrive) FetchUserdata() ([]byte, error) { | ||||
| 	return cd.readFile("user_data") | ||||
| 	bytes, err := cd.tryReadFile(path.Join(cd.ec2Root(), "user_data")) | ||||
| 	if bytes == nil && err == nil { | ||||
| 		bytes, err = cd.tryReadFile(path.Join(cd.openstackRoot(), "user_data")) | ||||
| 	} | ||||
| 	return bytes, err | ||||
| } | ||||
|  | ||||
| func (cd *configDrive) Type() string { | ||||
| 	return "cloud-drive" | ||||
| } | ||||
|  | ||||
| func (cd *configDrive) readFile(filename string) ([]byte, error) { | ||||
| 	data, err := ioutil.ReadFile(path.Join(cd.root, "latest", filename)) | ||||
| func (cd *configDrive) ec2Root() string { | ||||
| 	return path.Join(cd.root, "ec2", Ec2ApiVersion) | ||||
| } | ||||
|  | ||||
| func (cd *configDrive) openstackRoot() string { | ||||
| 	return path.Join(cd.root, "openstack", "latest") | ||||
| } | ||||
|  | ||||
| func (cd *configDrive) tryReadFile(filename string) ([]byte, error) { | ||||
| 	data, err := cd.readFile(filename) | ||||
| 	if os.IsNotExist(err) { | ||||
| 		err = nil | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										114
									
								
								datasource/configdrive_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								datasource/configdrive_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| package datasource | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| type mockFilesystem []string | ||||
|  | ||||
| func (m mockFilesystem) readFile(filename string) ([]byte, error) { | ||||
| 	for _, file := range m { | ||||
| 		if file == filename { | ||||
| 			return []byte(filename), nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, os.ErrNotExist | ||||
| } | ||||
|  | ||||
| func TestCDFetchMetadata(t *testing.T) { | ||||
| 	for _, tt := range []struct { | ||||
| 		root     string | ||||
| 		filename string | ||||
| 		files    mockFilesystem | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"", | ||||
| 			mockFilesystem{}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"/ec2/2009-04-04/meta_data.json", | ||||
| 			mockFilesystem([]string{"/ec2/2009-04-04/meta_data.json"}), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/media/configdrive", | ||||
| 			"/media/configdrive/ec2/2009-04-04/meta_data.json", | ||||
| 			mockFilesystem([]string{"/media/configdrive/ec2/2009-04-04/meta_data.json"}), | ||||
| 		}, | ||||
| 	} { | ||||
| 		cd := configDrive{tt.root, tt.files.readFile} | ||||
| 		filename, err := cd.FetchMetadata() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("bad error for %q: want %q, got %q", tt, nil, err) | ||||
| 		} | ||||
| 		if string(filename) != tt.filename { | ||||
| 			t.Fatalf("bad path for %q: want %q, got %q", tt, tt.filename, filename) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCDFetchUserdata(t *testing.T) { | ||||
| 	for _, tt := range []struct { | ||||
| 		root     string | ||||
| 		filename string | ||||
| 		files    mockFilesystem | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"", | ||||
| 			mockFilesystem{}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"/ec2/2009-04-04/user_data", | ||||
| 			mockFilesystem([]string{"/ec2/2009-04-04/user_data"}), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"/openstack/latest/user_data", | ||||
| 			mockFilesystem([]string{"/openstack/latest/user_data"}), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"/ec2/2009-04-04/user_data", | ||||
| 			mockFilesystem([]string{"/openstack/latest/user_data", "/ec2/2009-04-04/user_data"}), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/media/configdrive", | ||||
| 			"/media/configdrive/ec2/2009-04-04/user_data", | ||||
| 			mockFilesystem([]string{"/media/configdrive/ec2/2009-04-04/user_data"}), | ||||
| 		}, | ||||
| 	} { | ||||
| 		cd := configDrive{tt.root, tt.files.readFile} | ||||
| 		filename, err := cd.FetchUserdata() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("bad error for %q: want %q, got %q", tt, nil, err) | ||||
| 		} | ||||
| 		if string(filename) != tt.filename { | ||||
| 			t.Fatalf("bad path for %q: want %q, got %q", tt, tt.filename, filename) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCDConfigRoot(t *testing.T) { | ||||
| 	for _, tt := range []struct { | ||||
| 		root       string | ||||
| 		configRoot string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"/", | ||||
| 			"/openstack/latest", | ||||
| 		}, | ||||
| 		{ | ||||
| 			"/media/configdrive", | ||||
| 			"/media/configdrive/openstack/latest", | ||||
| 		}, | ||||
| 	} { | ||||
| 		cd := configDrive{tt.root, nil} | ||||
| 		if configRoot := cd.ConfigRoot(); configRoot != tt.configRoot { | ||||
| 			t.Fatalf("bad config root for %q: want %q, got %q", tt, tt.configRoot, configRoot) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,5 +1,10 @@ | ||||
| package datasource | ||||
|  | ||||
| const ( | ||||
| 	Ec2ApiVersion       = "2009-04-04" | ||||
| 	OpenstackApiVersion = "2012-08-10" | ||||
| ) | ||||
|  | ||||
| type Datasource interface { | ||||
| 	IsAvailable() bool | ||||
| 	AvailabilityChanges() bool | ||||
|   | ||||
| @@ -22,11 +22,9 @@ import ( | ||||
|  | ||||
| const ( | ||||
| 	BaseUrl              = "http://169.254.169.254/" | ||||
| 	Ec2ApiVersion        = "2009-04-04" | ||||
| 	Ec2UserdataUrl       = BaseUrl + Ec2ApiVersion + "/user-data" | ||||
| 	Ec2MetadataUrl       = BaseUrl + Ec2ApiVersion + "/meta-data" | ||||
| 	OpenstackApiVersion  = "openstack/2012-08-10" | ||||
| 	OpenstackUserdataUrl = BaseUrl + OpenstackApiVersion + "/user_data" | ||||
| 	OpenstackUserdataUrl = BaseUrl + "openstack/" + OpenstackApiVersion + "/user_data" | ||||
| ) | ||||
|  | ||||
| type metadataService struct{} | ||||
|   | ||||
| @@ -25,7 +25,7 @@ func (t *TestHttpClient) GetRetry(url string) ([]byte, error) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFetchAttributes(t *testing.T) { | ||||
| func TestMSFetchAttributes(t *testing.T) { | ||||
| 	for _, s := range []struct { | ||||
| 		metadata map[string]string | ||||
| 		err      error | ||||
| @@ -77,7 +77,7 @@ func TestFetchAttributes(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFetchAttribute(t *testing.T) { | ||||
| func TestMSFetchAttribute(t *testing.T) { | ||||
| 	for _, s := range []struct { | ||||
| 		metadata map[string]string | ||||
| 		err      error | ||||
| @@ -129,7 +129,7 @@ func TestFetchAttribute(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFetchMetadata(t *testing.T) { | ||||
| func TestMSFetchMetadata(t *testing.T) { | ||||
| 	for _, tt := range []struct { | ||||
| 		metadata map[string]string | ||||
| 		err      error | ||||
|   | ||||
		Reference in New Issue
	
	Block a user