blob: 2a004f66647e701b2f349ef2fc63c2b05ebf40a8 [file] [log] [blame]
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -08001package servers
2
3import (
4 "github.com/racker/perigee"
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -07005 "fmt"
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -08006)
7
8// ListResult abstracts the raw results of making a List() request against the
9// API. As OpenStack extensions may freely alter the response bodies of
10// structures returned to the client, you may only safely access the data
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080011// provided through separate, type-safe accessors or methods.
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080012type ListResult map[string]interface{}
13
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -070014// ServerResult abstracts a single server description,
15// as returned by the OpenStack provider.
16// As OpenStack extensions may freely alter the response bodies of the
17// structures returned to the client,
18// you may only safely access the data provided through
19// separate, type-safe accessors or methods.
Samuel A. Falvo IIce000732014-02-13 18:53:53 -080020type ServerResult map[string]interface{}
21
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080022// List makes a request against the API to list servers accessible to you.
23func List(c *Client) (ListResult, error) {
24 var lr ListResult
25
26 h, err := c.getListHeaders()
27 if err != nil {
28 return nil, err
29 }
30
31 err = perigee.Get(c.getListUrl(), perigee.Options{
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080032 Results: &lr,
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080033 MoreHeaders: h,
34 })
35 return lr, err
36}
37
Samuel A. Falvo IIce000732014-02-13 18:53:53 -080038// Create requests a server to be provisioned to the user in the current tenant.
39func Create(c *Client, opts map[string]interface{}) (ServerResult, error) {
40 var sr ServerResult
41
42 h, err := c.getCreateHeaders()
43 if err != nil {
44 return nil, err
45 }
46
47 err = perigee.Post(c.getCreateUrl(), perigee.Options{
48 Results: &sr,
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080049 ReqBody: map[string]interface{}{
Samuel A. Falvo IIce000732014-02-13 18:53:53 -080050 "server": opts,
51 },
52 MoreHeaders: h,
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080053 OkCodes: []int{202},
Samuel A. Falvo IIce000732014-02-13 18:53:53 -080054 })
55 return sr, err
56}
57
58// Delete requests that a server previously provisioned be removed from your account.
59func Delete(c *Client, id string) error {
60 h, err := c.getDeleteHeaders()
61 if err != nil {
62 return err
63 }
64
65 err = perigee.Delete(c.getDeleteUrl(id), perigee.Options{
66 MoreHeaders: h,
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080067 OkCodes: []int{204},
Samuel A. Falvo IIce000732014-02-13 18:53:53 -080068 })
69 return err
70}
71
72// GetDetail requests details on a single server, by ID.
73func GetDetail(c *Client, id string) (ServerResult, error) {
74 var sr ServerResult
75
76 h, err := c.getDetailHeaders()
77 if err != nil {
78 return nil, err
79 }
80
81 err = perigee.Get(c.getDetailUrl(id), perigee.Options{
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080082 Results: &sr,
Samuel A. Falvo IIce000732014-02-13 18:53:53 -080083 MoreHeaders: h,
84 })
85 return sr, err
86}
87
Samuel A. Falvo II22d3b772014-02-13 19:27:05 -080088// Update requests that various attributes of the indicated server be changed.
89func Update(c *Client, id string, opts map[string]interface{}) (ServerResult, error) {
90 var sr ServerResult
91
92 h, err := c.getUpdateHeaders()
93 if err != nil {
94 return nil, err
95 }
96
97 err = perigee.Put(c.getUpdateUrl(id), perigee.Options{
98 Results: &sr,
99 ReqBody: map[string]interface{}{
100 "server": opts,
101 },
102 MoreHeaders: h,
103 })
104 return sr, err
105}
Samuel A. Falvo IIca5f9a32014-03-11 17:52:58 -0700106
107// ChangeAdminPassword alters the administrator or root password for a specified
108// server.
109func ChangeAdminPassword(c *Client, id, newPassword string) error {
110 h, err := c.getActionHeaders()
111 if err != nil {
112 return err
113 }
114
115 err = perigee.Post(c.getActionUrl(id), perigee.Options{
116 ReqBody: struct{C map[string]string `json:"changePassword"`}{
117 map[string]string{"adminPass": newPassword},
118 },
119 MoreHeaders: h,
120 OkCodes: []int{202},
121 })
122 return err
123}
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700124
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700125// ErrArgument errors occur when an argument supplied to a package function
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700126// fails to fall within acceptable values. For example, the Reboot() function
127// expects the "how" parameter to be one of HardReboot or SoftReboot. These
128// constants are (currently) strings, leading someone to wonder if they can pass
129// other string values instead, perhaps in an effort to break the API of their
130// provider. Reboot() returns this error in this situation.
131//
132// Function identifies which function was called/which function is generating
133// the error.
134// Argument identifies which formal argument was responsible for producing the
135// error.
136// Value provides the value as it was passed into the function.
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700137type ErrArgument struct {
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700138 Function, Argument string
139 Value interface{}
140}
141
142// Error yields a useful diagnostic for debugging purposes.
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700143func (e *ErrArgument) Error() string {
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700144 return fmt.Sprintf("Bad argument in call to %s, formal parameter %s, value %#v", e.Function, e.Argument, e.Value)
145}
146
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700147func (e *ErrArgument) String() string {
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700148 return e.Error()
149}
150
151// These constants determine how a server should be rebooted.
152// See the Reboot() function for further details.
153const (
154 SoftReboot = "SOFT"
155 HardReboot = "HARD"
156 OSReboot = SoftReboot
157 PowerCycle = HardReboot
158)
159
160// Reboot requests that a given server reboot.
161// Two methods exist for rebooting a server:
162//
163// HardReboot (aka PowerCycle) -- restarts the server instance by physically
164// cutting power to the machine, or if a VM, terminating it at the hypervisor
165// level. It's done. Caput. Full stop. Then, after a brief while, power is
166// restored or the VM instance restarted.
167//
168// SoftReboot (aka OSReboot). This approach simply tells the OS to restart
169// under its own procedures. E.g., in Linux, asking it to enter runlevel 6,
170// or executing "sudo shutdown -r now", or by wasking Windows to restart the
171// machine.
172func Reboot(c *Client, id, how string) error {
173 if (how != SoftReboot) && (how != HardReboot) {
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700174 return &ErrArgument{
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700175 Function: "Reboot",
176 Argument: "how",
177 Value: how,
178 }
179 }
180
181 h, err := c.getActionHeaders()
182 if err != nil {
183 return err
184 }
185
186 err = perigee.Post(c.getActionUrl(id), perigee.Options{
187 ReqBody: struct{C map[string]string `json:"reboot"`}{
188 map[string]string{"type": how},
189 },
190 MoreHeaders: h,
191 OkCodes: []int{202},
192 })
193 return err
194}
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700195
196// Rebuild requests that the Openstack provider reprovision the
197// server. The rebuild will need to know the server's name and
198// new image reference or ID. In addition, and unlike building
199// a server with Create(), you must provide an administrator
200// password.
201//
202// Additional options may be specified with the additional map.
203// This function treats a nil map the same as an empty map.
204//
205// Rebuild returns a server result as though you had called
206// GetDetail() on the server's ID. The information, however,
207// refers to the new server, not the old.
208func Rebuild(c *Client, id, name, password, imageRef string, additional map[string]interface{}) (ServerResult, error) {
209 var sr ServerResult
210
211 if id == "" {
212 return sr, &ErrArgument{
213 Function: "Rebuild",
214 Argument: "id",
215 Value: "",
216 }
217 }
218
219 if name == "" {
220 return sr, &ErrArgument{
221 Function: "Rebuild",
222 Argument: "name",
223 Value: "",
224 }
225 }
226
227 if password == "" {
228 return sr, &ErrArgument{
229 Function: "Rebuild",
230 Argument: "password",
231 Value: "",
232 }
233 }
234
235 if imageRef == "" {
236 return sr, &ErrArgument{
237 Function: "Rebuild",
238 Argument: "imageRef",
239 Value: "",
240 }
241 }
242
243 if additional == nil {
244 additional = make(map[string]interface{}, 0)
245 }
246
247 additional["name"] = name
248 additional["imageRef"] = imageRef
249 additional["adminPass"] = password
250
251 h, err := c.getActionHeaders()
252 if err != nil {
253 return sr, err
254 }
255
256 err = perigee.Post(c.getActionUrl(id), perigee.Options{
257 ReqBody: struct{R map[string]interface{} `json:"rebuild"`}{
258 additional,
259 },
260 Results: &sr,
261 MoreHeaders: h,
262 OkCodes: []int{202},
263 })
264 return sr, err
265}
266
267// Resize instructs the provider to change the flavor of the server.
268// Note that this implies rebuilding it. Unfortunately, one cannot pass rebuild parameters to the resize function.
269// When the resize completes, the server will be in RESIZE_VERIFY state.
270// While in this state, you can explore the use of the new server's configuration.
271// If you like it, call ConfirmResize() to commit the resize permanently.
272// Otherwise, call RevertResize() to restore the old configuration.
273func Resize(c *Client, id, flavorRef string) error {
274 h, err := c.getActionHeaders()
275 if err != nil {
276 return err
277 }
278
279 err = perigee.Post(c.getActionUrl(id), perigee.Options{
280 ReqBody: struct{R map[string]interface{} `json:"resize"`}{
281 map[string]interface{}{"flavorRef": flavorRef},
282 },
283 MoreHeaders: h,
284 OkCodes: []int{202},
285 })
286 return err
287}
288
289// ConfirmResize confirms a previous resize operation on a server.
290// See Resize() for more details.
291func ConfirmResize(c *Client, id string) error {
292 h, err := c.getActionHeaders()
293 if err != nil {
294 return err
295 }
296
297 err = perigee.Post(c.getActionUrl(id), perigee.Options{
298 ReqBody: map[string]interface{}{"confirmResize": nil},
299 MoreHeaders: h,
300 OkCodes: []int{204},
301 })
302 return err
303}
304
305// RevertResize cancels a previous resize operation on a server.
306// See Resize() for more details.
307func RevertResize(c *Client, id string) error {
308 h, err := c.getActionHeaders()
309 if err != nil {
310 return err
311 }
312
313 err = perigee.Post(c.getActionUrl(id), perigee.Options{
314 ReqBody: map[string]interface{}{"revertResize": nil},
315 MoreHeaders: h,
316 OkCodes: []int{202},
317 })
318 return err
319}