Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit c1072a1

Browse files
author
Russell Troxel
committed
add admin actions extension
1 parent 6fbd243 commit c1072a1

File tree

4 files changed

+305
-0
lines changed

4 files changed

+305
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/*
2+
Package provides access to the "Admin Actions" of the Compute API,
3+
including migrations, live-migrations, reset-state, etc.
4+
*/
5+
package adminactions
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// +build fixtures
2+
3+
package adminactions
4+
5+
import (
6+
"net/http"
7+
"testing"
8+
9+
th "github.com/rackspace/gophercloud/testhelper"
10+
"github.com/rackspace/gophercloud/testhelper/client"
11+
)
12+
13+
func mockCreateBackupResponse(t *testing.T, id string) {
14+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
15+
th.TestMethod(t, r, "POST")
16+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
17+
th.TestJSONRequest(t, r, `{"createBackup": {"name": "Backup 1", "backup_type": "daily", "rotation": 1}}`)
18+
w.WriteHeader(http.StatusAccepted)
19+
})
20+
}
21+
22+
func mockInjectNetworkInfoResponse(t *testing.T, id string) {
23+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
24+
th.TestMethod(t, r, "POST")
25+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
26+
th.TestJSONRequest(t, r, `{"injectNetworkInfo": ""}`)
27+
w.WriteHeader(http.StatusAccepted)
28+
})
29+
}
30+
31+
func mockMigrateResponse(t *testing.T, id string) {
32+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
33+
th.TestMethod(t, r, "POST")
34+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
35+
th.TestJSONRequest(t, r, `{"migrate": ""}`)
36+
w.WriteHeader(http.StatusAccepted)
37+
})
38+
}
39+
40+
const liveMigrateRequest = `{"os-migrateLive": {"host": "", "disk_over_commit": false, "block_migration": true}}`
41+
const targetLiveMigrateRequest = `{"os-migrateLive": {"host": "target-compute", "disk_over_commit": false, "block_migration": true}}`
42+
43+
func mockLiveMigrateResponse(t *testing.T, id string) {
44+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
45+
th.TestMethod(t, r, "POST")
46+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
47+
th.TestJSONRequest(t, r, liveMigrateRequest)
48+
w.WriteHeader(http.StatusAccepted)
49+
})
50+
}
51+
52+
func mockTargetLiveMigrateResponse(t *testing.T, id string) {
53+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
54+
th.TestMethod(t, r, "POST")
55+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
56+
th.TestJSONRequest(t, r, targetLiveMigrateRequest)
57+
w.WriteHeader(http.StatusAccepted)
58+
})
59+
}
60+
61+
func mockResetNetworkResponse(t *testing.T, id string) {
62+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
63+
th.TestMethod(t, r, "POST")
64+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
65+
th.TestJSONRequest(t, r, `{"resetNetwork": ""}`)
66+
w.WriteHeader(http.StatusAccepted)
67+
})
68+
}
69+
70+
func mockResetStateResponse(t *testing.T, id string) {
71+
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
72+
th.TestMethod(t, r, "POST")
73+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
74+
th.TestJSONRequest(t, r, `{"os-resetState": {"state": "active"}}`)
75+
w.WriteHeader(http.StatusAccepted)
76+
})
77+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package adminactions
2+
3+
import "github.com/rackspace/gophercloud"
4+
5+
func actionURL(client *gophercloud.ServiceClient, id string) string {
6+
return client.ServiceURL("servers", id, "action")
7+
}
8+
9+
type CreateBackupOpts struct {
10+
// Name: required, name of the backup.
11+
Name string
12+
13+
// BackupType: required, type of the backup, such as "daily".
14+
BackupType string
15+
16+
// Rotation: the number of backups to retain.
17+
Rotation int
18+
}
19+
20+
// ToBackupCreateMap assembles a request body based on the contents of a CreateOpts.
21+
func (opts CreateBackupOpts) ToCreateBackupMap() (map[string]interface{}, error) {
22+
backup := make(map[string]interface{})
23+
24+
if opts.Name != "" {
25+
backup["name"] = opts.Name
26+
}
27+
if opts.BackupType != "" {
28+
backup["backup_type"] = opts.BackupType
29+
}
30+
backup["rotation"] = opts.Rotation
31+
32+
return map[string]interface{}{"createBackup": backup}, nil
33+
}
34+
35+
// ResetNetwork is the admin operation to create a backup of a Compute Server.
36+
func CreateBackup(client *gophercloud.ServiceClient, id string, opts CreateBackupOpts) gophercloud.ErrResult {
37+
var res gophercloud.ErrResult
38+
39+
req, err := opts.ToCreateBackupMap()
40+
if err != nil {
41+
res.Err = err
42+
return res
43+
}
44+
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
45+
return res
46+
47+
}
48+
49+
// InjectNetworkInfo is the admin operation which injects network info into a Compute Server.
50+
func InjectNetworkInfo(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
51+
var req struct {
52+
InjectNetworkInfo string `json:"injectNetworkInfo"`
53+
}
54+
55+
var res gophercloud.ErrResult
56+
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
57+
return res
58+
}
59+
60+
// Migrate is the admin operation to migrate a Compute Server.
61+
func Migrate(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
62+
var req struct {
63+
Migrate string `json:"migrate"`
64+
}
65+
66+
var res gophercloud.ErrResult
67+
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
68+
return res
69+
}
70+
71+
type LiveMigrateOpts struct {
72+
// Host: optional, If you omit this parameter, the scheduler chooses a host.
73+
Host string
74+
75+
// BlockMigration: defaults to false. Set to true to migrate local disks
76+
// by using block migration. If the source or destination host uses shared storage
77+
// and you set this value to true, the live migration fails.
78+
BlockMigration bool
79+
80+
//DiskOverCommit: defaults to false. Set to true to enable over commit when the
81+
// destination host is checked for available disk space.
82+
DiskOverCommit bool
83+
}
84+
85+
// ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
86+
func (opts LiveMigrateOpts) ToLiveMigrateMap() (map[string]interface{}, error) {
87+
migration := make(map[string]interface{})
88+
89+
migration["host"] = opts.Host
90+
migration["block_migration"] = opts.BlockMigration
91+
migration["disk_over_commit"] = opts.DiskOverCommit
92+
93+
return map[string]interface{}{"os-migrateLive": migration}, nil
94+
}
95+
96+
// ResetNetwork is the admin operation to reset the network on a Compute Server.
97+
func LiveMigrate(client *gophercloud.ServiceClient, id string, opts LiveMigrateOpts) gophercloud.ErrResult {
98+
var res gophercloud.ErrResult
99+
100+
req, err := opts.ToLiveMigrateMap()
101+
if err != nil {
102+
res.Err = err
103+
return res
104+
}
105+
106+
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
107+
return res
108+
109+
}
110+
111+
// ResetNetwork is the admin operation to reset the network on a Compute Server.
112+
func ResetNetwork(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
113+
var req struct {
114+
ResetNetwork string `json:"resetNetwork"`
115+
}
116+
117+
var res gophercloud.ErrResult
118+
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
119+
return res
120+
}
121+
122+
// ResetState is the admin operation to reset the state of a server.
123+
func ResetState(client *gophercloud.ServiceClient, id string, state string) gophercloud.ErrResult {
124+
var res gophercloud.ErrResult
125+
var req struct {
126+
ResetState struct {
127+
State string `json:"state"`
128+
} `json:"os-resetState"`
129+
}
130+
req.ResetState.State = state
131+
132+
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
133+
return res
134+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package adminactions
2+
3+
import (
4+
"testing"
5+
6+
th "github.com/rackspace/gophercloud/testhelper"
7+
"github.com/rackspace/gophercloud/testhelper/client"
8+
)
9+
10+
const serverID = "adef1234"
11+
12+
func TestCreateBackup(t *testing.T) {
13+
th.SetupHTTP()
14+
defer th.TeardownHTTP()
15+
16+
mockCreateBackupResponse(t, serverID)
17+
18+
err := CreateBackup(client.ServiceClient(), serverID, CreateBackupOpts{
19+
Name: "Backup 1",
20+
BackupType: "daily",
21+
Rotation: 1,
22+
}).ExtractErr()
23+
th.AssertNoErr(t, err)
24+
}
25+
26+
func TestInjectNetworkInfo(t *testing.T) {
27+
th.SetupHTTP()
28+
defer th.TeardownHTTP()
29+
30+
mockInjectNetworkInfoResponse(t, serverID)
31+
32+
err := InjectNetworkInfo(client.ServiceClient(), serverID).ExtractErr()
33+
th.AssertNoErr(t, err)
34+
}
35+
36+
func TestMigrate(t *testing.T) {
37+
th.SetupHTTP()
38+
defer th.TeardownHTTP()
39+
40+
mockMigrateResponse(t, serverID)
41+
42+
err := Migrate(client.ServiceClient(), serverID).ExtractErr()
43+
th.AssertNoErr(t, err)
44+
}
45+
46+
func TestLiveMigrate(t *testing.T) {
47+
th.SetupHTTP()
48+
defer th.TeardownHTTP()
49+
50+
mockLiveMigrateResponse(t, serverID)
51+
52+
err := LiveMigrate(client.ServiceClient(), serverID, LiveMigrateOpts{
53+
BlockMigration: true,
54+
}).ExtractErr()
55+
th.AssertNoErr(t, err)
56+
}
57+
58+
func TestTargetLiveMigrate(t *testing.T) {
59+
th.SetupHTTP()
60+
defer th.TeardownHTTP()
61+
62+
mockTargetLiveMigrateResponse(t, serverID)
63+
64+
err := LiveMigrate(client.ServiceClient(), serverID, LiveMigrateOpts{
65+
Host: "target-compute",
66+
BlockMigration: true,
67+
}).ExtractErr()
68+
th.AssertNoErr(t, err)
69+
}
70+
71+
func TestResetNetwork(t *testing.T) {
72+
th.SetupHTTP()
73+
defer th.TeardownHTTP()
74+
75+
mockResetNetworkResponse(t, serverID)
76+
77+
err := ResetNetwork(client.ServiceClient(), serverID).ExtractErr()
78+
th.AssertNoErr(t, err)
79+
}
80+
81+
func TestResetState(t *testing.T) {
82+
th.SetupHTTP()
83+
defer th.TeardownHTTP()
84+
85+
mockResetStateResponse(t, serverID)
86+
87+
err := ResetState(client.ServiceClient(), serverID, "active").ExtractErr()
88+
th.AssertNoErr(t, err)
89+
}

0 commit comments

Comments
 (0)