This repository was archived by the owner on Aug 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 179
Boot from volume #259
Merged
Merged
Boot from volume #259
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
654fb0e
boot from volume base code
jrperritt 4149d7c
additionally return 'error' from 'ToCreateServerMap'
jrperritt d9a4bf7
create map from 'CreateOptsBuilder'; rackspace boot from volume; unte…
jrperritt 8dd49db
don't put extension params in 'CreateOpts' if unset; working rackspac…
jrperritt 485b8aa
fix for isJSONEquals
jrperritt 6171022
document UUID and SourceType as required; rackspace unit test
jrperritt 0b09d1d
openstack acceptance test
jrperritt 01686cd
BlockDevice -> []BlockDevice in CreateOpts
jrperritt aafafd5
move BlockDevice bit in server creation above manual map manipulation
jrperritt 9880cb6
fix merge conflicts; don't add relics of 'git mergetool'
jrperritt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // +build acceptance | ||
|
|
||
| package v2 | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" | ||
| "github.com/rackspace/gophercloud/openstack/compute/v2/servers" | ||
| th "github.com/rackspace/gophercloud/testhelper" | ||
| "github.com/smashwilson/gophercloud/acceptance/tools" | ||
| ) | ||
|
|
||
| func TestBootFromVolume(t *testing.T) { | ||
| client, err := newClient() | ||
| th.AssertNoErr(t, err) | ||
|
|
||
| if testing.Short() { | ||
| t.Skip("Skipping test that requires server creation in short mode.") | ||
| } | ||
|
|
||
| choices, err := ComputeChoicesFromEnv() | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| name := tools.RandomString("Gophercloud-", 8) | ||
| t.Logf("Creating server [%s].", name) | ||
|
|
||
| bd := []bootfromvolume.BlockDevice{ | ||
| bootfromvolume.BlockDevice{ | ||
| UUID: choices.ImageID, | ||
| SourceType: bootfromvolume.Image, | ||
| VolumeSize: 10, | ||
| }, | ||
| } | ||
|
|
||
| serverCreateOpts := servers.CreateOpts{ | ||
| Name: name, | ||
| FlavorRef: "3", | ||
| } | ||
| server, err := bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{ | ||
| serverCreateOpts, | ||
| bd, | ||
| }).Extract() | ||
| th.AssertNoErr(t, err) | ||
| t.Logf("Created server: %+v\n", server) | ||
| //defer deleteServer(t, client, server) | ||
| t.Logf("Deleting server [%s]...", name) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // +build acceptance | ||
|
|
||
| package v2 | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| osBFV "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" | ||
| "github.com/rackspace/gophercloud/rackspace/compute/v2/bootfromvolume" | ||
| "github.com/rackspace/gophercloud/rackspace/compute/v2/servers" | ||
| th "github.com/rackspace/gophercloud/testhelper" | ||
| "github.com/smashwilson/gophercloud/acceptance/tools" | ||
| ) | ||
|
|
||
| func TestBootFromVolume(t *testing.T) { | ||
| client, err := newClient() | ||
| th.AssertNoErr(t, err) | ||
|
|
||
| if testing.Short() { | ||
| t.Skip("Skipping test that requires server creation in short mode.") | ||
| } | ||
|
|
||
| options, err := optionsFromEnv() | ||
| th.AssertNoErr(t, err) | ||
|
|
||
| name := tools.RandomString("Gophercloud-", 8) | ||
| t.Logf("Creating server [%s].", name) | ||
|
|
||
| bd := []osBFV.BlockDevice{ | ||
| osBFV.BlockDevice{ | ||
| UUID: options.imageID, | ||
| SourceType: osBFV.Image, | ||
| VolumeSize: 10, | ||
| }, | ||
| } | ||
|
|
||
| server, err := bootfromvolume.Create(client, servers.CreateOpts{ | ||
| Name: name, | ||
| FlavorRef: "performance1-1", | ||
| BlockDevice: bd, | ||
| }).Extract() | ||
| th.AssertNoErr(t, err) | ||
| t.Logf("Created server: %+v\n", server) | ||
| //defer deleteServer(t, client, server) | ||
| t.Logf("Deleting server [%s]...", name) | ||
| } |
111 changes: 111 additions & 0 deletions
111
openstack/compute/v2/extensions/bootfromvolume/requests.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| package bootfromvolume | ||
|
|
||
| import ( | ||
| "errors" | ||
| "strconv" | ||
|
|
||
| "github.com/rackspace/gophercloud" | ||
| "github.com/rackspace/gophercloud/openstack/compute/v2/servers" | ||
|
|
||
| "github.com/racker/perigee" | ||
| ) | ||
|
|
||
| // SourceType represents the type of medium being used to create the volume. | ||
| type SourceType string | ||
|
|
||
| const ( | ||
| Volume SourceType = "volume" | ||
| Snapshot SourceType = "snapshot" | ||
| Image SourceType = "image" | ||
| ) | ||
|
|
||
| // BlockDevice is a structure with options for booting a server instance | ||
| // from a volume. The volume may be created from an image, snapshot, or another | ||
| // volume. | ||
| type BlockDevice struct { | ||
| // BootIndex [optional] is the boot index. It defaults to 0. | ||
| BootIndex int `json:"boot_index"` | ||
|
|
||
| // DeleteOnTermination [optional] specifies whether or not to delete the attached volume | ||
| // when the server is deleted. Defaults to `false`. | ||
| DeleteOnTermination bool `json:"delete_on_termination"` | ||
|
|
||
| // DestinationType [optional] is the type that gets created. Possible values are "volume" | ||
| // and "local". | ||
| DestinationType string `json:"destination_type"` | ||
|
|
||
| // SourceType [required] must be one of: "volume", "snapshot", "image". | ||
| SourceType SourceType `json:"source_type"` | ||
|
|
||
| // UUID [required] is the unique identifier for the volume, snapshot, or image (see above) | ||
| UUID string `json:"uuid"` | ||
|
|
||
| // VolumeSize [optional] is the size of the volume to create (in gigabytes). | ||
| VolumeSize int `json:"volume_size"` | ||
| } | ||
|
|
||
| // CreateOptsExt is a structure that extends the server `CreateOpts` structure | ||
| // by allowing for a block device mapping. | ||
| type CreateOptsExt struct { | ||
| servers.CreateOptsBuilder | ||
| BlockDevice []BlockDevice `json:"block_device_mapping_v2,omitempty"` | ||
| } | ||
|
|
||
| // ToServerCreateMap adds the block device mapping option to the base server | ||
| // creation options. | ||
| func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) { | ||
| base, err := opts.CreateOptsBuilder.ToServerCreateMap() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if len(opts.BlockDevice) == 0 { | ||
| return nil, errors.New("Required fields UUID and SourceType not set.") | ||
| } | ||
|
|
||
| serverMap := base["server"].(map[string]interface{}) | ||
|
|
||
| blockDevice := make([]map[string]interface{}, len(opts.BlockDevice)) | ||
|
|
||
| for i, bd := range opts.BlockDevice { | ||
| if string(bd.SourceType) == "" { | ||
| return nil, errors.New("SourceType must be one of: volume, image, snapshot.") | ||
| } | ||
|
|
||
| blockDevice[i] = make(map[string]interface{}) | ||
|
|
||
| blockDevice[i]["source_type"] = bd.SourceType | ||
| blockDevice[i]["boot_index"] = strconv.Itoa(bd.BootIndex) | ||
| blockDevice[i]["delete_on_termination"] = strconv.FormatBool(bd.DeleteOnTermination) | ||
| blockDevice[i]["volume_size"] = strconv.Itoa(bd.VolumeSize) | ||
| if bd.UUID != "" { | ||
| blockDevice[i]["uuid"] = bd.UUID | ||
| } | ||
| if bd.DestinationType != "" { | ||
| blockDevice[i]["destination_type"] = bd.DestinationType | ||
| } | ||
|
|
||
| } | ||
| serverMap["block_device_mapping_v2"] = blockDevice | ||
|
|
||
| return base, nil | ||
| } | ||
|
|
||
| // Create requests the creation of a server from the given block device mapping. | ||
| func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) servers.CreateResult { | ||
| var res servers.CreateResult | ||
|
|
||
| reqBody, err := opts.ToServerCreateMap() | ||
| if err != nil { | ||
| res.Err = err | ||
| return res | ||
| } | ||
|
|
||
| _, res.Err = perigee.Request("POST", createURL(client), perigee.Options{ | ||
| MoreHeaders: client.AuthenticatedHeaders(), | ||
| ReqBody: reqBody, | ||
| Results: &res.Body, | ||
| OkCodes: []int{200, 202}, | ||
| }) | ||
| return res | ||
| } |
51 changes: 51 additions & 0 deletions
51
openstack/compute/v2/extensions/bootfromvolume/requests_test.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package bootfromvolume | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/rackspace/gophercloud/openstack/compute/v2/servers" | ||
| th "github.com/rackspace/gophercloud/testhelper" | ||
| ) | ||
|
|
||
| func TestCreateOpts(t *testing.T) { | ||
| base := servers.CreateOpts{ | ||
| Name: "createdserver", | ||
| ImageRef: "asdfasdfasdf", | ||
| FlavorRef: "performance1-1", | ||
| } | ||
|
|
||
| ext := CreateOptsExt{ | ||
| CreateOptsBuilder: base, | ||
| BlockDevice: []BlockDevice{ | ||
| BlockDevice{ | ||
| UUID: "123456", | ||
| SourceType: Image, | ||
| DestinationType: "volume", | ||
| VolumeSize: 10, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| expected := ` | ||
| { | ||
| "server": { | ||
| "name": "createdserver", | ||
| "imageRef": "asdfasdfasdf", | ||
| "flavorRef": "performance1-1", | ||
| "block_device_mapping_v2":[ | ||
| { | ||
| "uuid":"123456", | ||
| "source_type":"image", | ||
| "destination_type":"volume", | ||
| "boot_index": "0", | ||
| "delete_on_termination": "false", | ||
| "volume_size": "10" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| ` | ||
| actual, err := ext.ToServerCreateMap() | ||
| th.AssertNoErr(t, err) | ||
| th.CheckJSONEquals(t, expected, actual) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package bootfromvolume | ||
|
|
||
| import ( | ||
| os "github.com/rackspace/gophercloud/openstack/compute/v2/servers" | ||
| ) | ||
|
|
||
| // CreateResult temporarily contains the response from a Create call. | ||
| type CreateResult struct { | ||
| os.CreateResult | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package bootfromvolume | ||
|
|
||
| import "github.com/rackspace/gophercloud" | ||
|
|
||
| func createURL(c *gophercloud.ServiceClient) string { | ||
| return c.ServiceURL("os-volumes_boot") | ||
| } |
16 changes: 16 additions & 0 deletions
16
openstack/compute/v2/extensions/bootfromvolume/urls_test.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package bootfromvolume | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| th "github.com/rackspace/gophercloud/testhelper" | ||
| "github.com/rackspace/gophercloud/testhelper/client" | ||
| ) | ||
|
|
||
| func TestCreateURL(t *testing.T) { | ||
| th.SetupHTTP() | ||
| defer th.TeardownHTTP() | ||
| c := client.ServiceClient() | ||
|
|
||
| th.CheckEquals(t, c.Endpoint+"os-volumes_boot", createURL(c)) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,17 +41,24 @@ type CreateOptsExt struct { | |
| servers.CreateOptsBuilder | ||
|
|
||
| // DiskConfig [optional] controls how the created server's disk is partitioned. | ||
| DiskConfig DiskConfig | ||
| DiskConfig DiskConfig `json:"OS-DCF:diskConfig,omitempty"` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 💯 🙇 |
||
| } | ||
|
|
||
| // ToServerCreateMap adds the diskconfig option to the base server creation options. | ||
| func (opts CreateOptsExt) ToServerCreateMap() map[string]interface{} { | ||
| base := opts.CreateOptsBuilder.ToServerCreateMap() | ||
| func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 💯 x2 |
||
| base, err := opts.CreateOptsBuilder.ToServerCreateMap() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if string(opts.DiskConfig) == "" { | ||
| return base, nil | ||
| } | ||
|
|
||
| serverMap := base["server"].(map[string]interface{}) | ||
| serverMap["OS-DCF:diskConfig"] = string(opts.DiskConfig) | ||
|
|
||
| return base | ||
| return base, nil | ||
| } | ||
|
|
||
| // RebuildOptsExt adds a DiskConfig option to the base RebuildOpts. | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, is there a reason for this type? If it doesn't have its own
Extractmethod or anything, I just returnos.CreateResultdirectly, instead.