Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute v2: Add Live Migration Action #728

Merged
merged 6 commits into from
Jan 21, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions acceptance/clients/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package clients
import (
"fmt"
"os"
"strconv"
"strings"

"github.com/gophercloud/gophercloud"
Expand Down Expand Up @@ -42,6 +43,9 @@ type AcceptanceTestChoices struct {

// DBDatastoreTypeID is the datastore type version for DB tests.
DBDatastoreVersion string

// LiveMigrate indicates ability to run multi-node migration tests
LiveMigrate bool
}

// AcceptanceTestChoicesFromEnv populates a ComputeChoices struct from environment variables.
Expand All @@ -56,6 +60,7 @@ func AcceptanceTestChoicesFromEnv() (*AcceptanceTestChoices, error) {
shareNetworkID := os.Getenv("OS_SHARE_NETWORK_ID")
dbDatastoreType := os.Getenv("OS_DB_DATASTORE_TYPE")
dbDatastoreVersion := os.Getenv("OS_DB_DATASTORE_VERSION")
liveMigrate := os.Getenv("OS_LIVE_MIGRATE")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be easier to do this:

var liveMigrate bool
if v := os.Getenv("OS_LIVE_MIGRATE"); v != "" {
  liveMigrate = true
}

Copy link
Contributor Author

@dstdfx dstdfx Jan 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jtopjian Unfortunately I can't test it on my environment


missing := make([]string, 0, 3)
if imageID == "" {
Expand Down Expand Up @@ -84,6 +89,8 @@ func AcceptanceTestChoicesFromEnv() (*AcceptanceTestChoices, error) {
notDistinct = "OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE must be distinct."
}

LiveMigrate, _ := strconv.ParseBool(liveMigrate)

if len(missing) > 0 || notDistinct != "" {
text := "You're missing some important setup:\n"
if len(missing) > 0 {
Expand All @@ -106,6 +113,7 @@ func AcceptanceTestChoicesFromEnv() (*AcceptanceTestChoices, error) {
ShareNetworkID: shareNetworkID,
DBDatastoreType: dbDatastoreType,
DBDatastoreVersion: dbDatastoreVersion,
LiveMigrate: LiveMigrate,
}, nil
}

Expand Down
37 changes: 37 additions & 0 deletions acceptance/openstack/compute/v2/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,40 @@ func TestMigrate(t *testing.T) {
t.Fatalf("Error during migration: %v", err)
}
}

func TestLiveMigrate(t *testing.T) {
choices, err := clients.AcceptanceTestChoicesFromEnv()
if err != nil {
t.Fatal(err)
}

if !choices.LiveMigrate {
t.Skip()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

t.Skip("Testing of live migration is disabled")

}

client, err := clients.NewComputeV2Client()
if err != nil {
t.Fatalf("Unable to create a compute client: %v", err)
}

server, err := CreateServer(t, client)
if err != nil {
t.Fatalf("Unable to create server: %v", err)
}
defer DeleteServer(t, client, server)

t.Logf("Attempting to migrate server %s", server.ID)

blockMigration := false
diskOverCommit := false

liveMigrateOpts := migrate.LiveMigrateOpts{
BlockMigration: &blockMigration,
DiskOverCommit: &diskOverCommit,
}

err = migrate.LiveMigrate(client, server.ID, liveMigrateOpts).ExtractErr()
if err != nil {
t.Fatalf("Error during live migration: %v", err)
}
}
19 changes: 18 additions & 1 deletion openstack/compute/v2/extensions/migrate/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@
Package migrate provides functionality to migrate servers that have been
provisioned by the OpenStack Compute service.

Example to Migrate a Server
Example of Migrate Server (migrate Action)

serverID := "b16ba811-199d-4ffd-8839-ba96c1185a67"
err := migrate.Migrate(computeClient, serverID).ExtractErr()
if err != nil {
panic(err)
}

Example of Live-Migrate Server (os-migrateLive Action)

serverID := "b16ba811-199d-4ffd-8839-ba96c1185a67"
host := "01c0cadef72d47e28a672a76060d492c"
blockMigration := false

migrationOpts := migrate.LiveMigrateOpts{
Host: &host,
BlockMigration: &blockMigration,
}

err := migrate.LiveMigrate(computeClient, serverID, migrationOpts).ExtractErr()
if err != nil {
panic(err)
}

*/
package migrate
39 changes: 39 additions & 0 deletions openstack/compute/v2/extensions/migrate/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,42 @@ func Migrate(client *gophercloud.ServiceClient, id string) (r MigrateResult) {
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"migrate": nil}, nil, nil)
return
}

// LiveMigrateOptsBuilder allows extensions to add additional parameters to the
// LiveMigrate request.
type LiveMigrateOptsBuilder interface {
ToLiveMigrateMap() (map[string]interface{}, error)
}

// LiveMigrateOpts specifies parameters of live migrate action.
type LiveMigrateOpts struct {
// The host to which to migrate the server.
// If this parameter is None, the scheduler chooses a host.
Host *string `json:"host"`
Copy link
Contributor

@jtopjian jtopjian Jan 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so you can specify "" as a valid host value? Is that different than if host was omitted from the request body?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jtopjian It will be "valid", but I reckon that "host" has to be always in the request body according to this line.
Moreover there's no clear mention as for migrate-server-migrate-action

If you specify null or don’t specify this parameter, the scheduler chooses a host.

I might be wrong please correct me.


// Set to True to migrate local disks by using block migration.
// If the source or destination host uses shared storage and you set
// this value to True, the live migration fails.
BlockMigration *bool `json:"block_migration,omitempty"`

// Set to True to enable over commit when the destination host is checked
// for available disk space. Set to False to disable over commit. This setting
// affects only the libvirt virt driver.
DiskOverCommit *bool `json:"disk_over_commit,omitempty"`
}

// ToLiveMigrateMap constructs a request body from LiveMigrateOpts.
func (opts LiveMigrateOpts) ToLiveMigrateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "os-migrateLive")
}

// LiveMigrate will initiate a live-migration (without rebooting) of the instance to another host.
func LiveMigrate(client *gophercloud.ServiceClient, id string, opts LiveMigrateOptsBuilder) (r MigrateResult) {
b, err := opts.ToLiveMigrateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
return
}
15 changes: 15 additions & 0 deletions openstack/compute/v2/extensions/migrate/testing/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,18 @@ func mockMigrateResponse(t *testing.T, id string) {
w.WriteHeader(http.StatusAccepted)
})
}

func mockLiveMigrateResponse(t *testing.T, id string) {
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
th.TestJSONRequest(t, r, `{
"os-migrateLive": {
"host": "01c0cadef72d47e28a672a76060d492c",
"block_migration": false,
"disk_over_commit": true
}
}`)
w.WriteHeader(http.StatusAccepted)
})
}
20 changes: 20 additions & 0 deletions openstack/compute/v2/extensions/migrate/testing/requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,23 @@ func TestMigrate(t *testing.T) {
err := migrate.Migrate(client.ServiceClient(), serverID).ExtractErr()
th.AssertNoErr(t, err)
}

func TestLiveMigrate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()

mockLiveMigrateResponse(t, serverID)

host := "01c0cadef72d47e28a672a76060d492c"
blockMigration := false
diskOverCommit := true

migrationOpts := migrate.LiveMigrateOpts{
Host: &host,
BlockMigration: &blockMigration,
DiskOverCommit: &diskOverCommit,
}

err := migrate.LiveMigrate(client.ServiceClient(), serverID, migrationOpts).ExtractErr()
th.AssertNoErr(t, err)
}