github.com/gophercloud/gophercloud@v1.11.0/openstack/compute/v2/servers/requests.go (about) 1 package servers 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 8 "github.com/gophercloud/gophercloud" 9 "github.com/gophercloud/gophercloud/pagination" 10 ) 11 12 // ListOptsBuilder allows extensions to add additional parameters to the 13 // List request. 14 type ListOptsBuilder interface { 15 ToServerListQuery() (string, error) 16 } 17 18 // ListOpts allows the filtering and sorting of paginated collections through 19 // the API. Filtering is achieved by passing in struct field values that map to 20 // the server attributes you want to see returned. Marker and Limit are used 21 // for pagination. 22 type ListOpts struct { 23 // ChangesSince is a time/date stamp for when the server last changed status. 24 ChangesSince string `q:"changes-since"` 25 26 // Image is the name of the image in URL format. 27 Image string `q:"image"` 28 29 // Flavor is the name of the flavor in URL format. 30 Flavor string `q:"flavor"` 31 32 // IP is a regular expression to match the IPv4 address of the server. 33 IP string `q:"ip"` 34 35 // This requires the client to be set to microversion 2.5 or later, unless 36 // the user is an admin. 37 // IP is a regular expression to match the IPv6 address of the server. 38 IP6 string `q:"ip6"` 39 40 // Name of the server as a string; can be queried with regular expressions. 41 // Realize that ?name=bob returns both bob and bobb. If you need to match bob 42 // only, you can use a regular expression matching the syntax of the 43 // underlying database server implemented for Compute. 44 Name string `q:"name"` 45 46 // Status is the value of the status of the server so that you can filter on 47 // "ACTIVE" for example. 48 Status string `q:"status"` 49 50 // Host is the name of the host as a string. 51 Host string `q:"host"` 52 53 // Marker is a UUID of the server at which you want to set a marker. 54 Marker string `q:"marker"` 55 56 // Limit is an integer value for the limit of values to return. 57 Limit int `q:"limit"` 58 59 // AllTenants is a bool to show all tenants. 60 AllTenants bool `q:"all_tenants"` 61 62 // TenantID lists servers for a particular tenant. 63 // Setting "AllTenants = true" is required. 64 TenantID string `q:"tenant_id"` 65 66 // This requires the client to be set to microversion 2.83 or later, unless 67 // the user is an admin. 68 // UserID lists servers for a particular user. 69 UserID string `q:"user_id"` 70 71 // This requires the client to be set to microversion 2.26 or later. 72 // Tags filters on specific server tags. All tags must be present for the server. 73 Tags string `q:"tags"` 74 75 // This requires the client to be set to microversion 2.26 or later. 76 // TagsAny filters on specific server tags. At least one of the tags must be present for the server. 77 TagsAny string `q:"tags-any"` 78 79 // This requires the client to be set to microversion 2.26 or later. 80 // NotTags filters on specific server tags. All tags must be absent for the server. 81 NotTags string `q:"not-tags"` 82 83 // This requires the client to be set to microversion 2.26 or later. 84 // NotTagsAny filters on specific server tags. At least one of the tags must be absent for the server. 85 NotTagsAny string `q:"not-tags-any"` 86 87 // Display servers based on their availability zone (Admin only until microversion 2.82). 88 AvailabilityZone string `q:"availability_zone"` 89 } 90 91 // ToServerListQuery formats a ListOpts into a query string. 92 func (opts ListOpts) ToServerListQuery() (string, error) { 93 q, err := gophercloud.BuildQueryString(opts) 94 return q.String(), err 95 } 96 97 // ListSimple makes a request against the API to list servers accessible to you. 98 func ListSimple(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { 99 url := listURL(client) 100 if opts != nil { 101 query, err := opts.ToServerListQuery() 102 if err != nil { 103 return pagination.Pager{Err: err} 104 } 105 url += query 106 } 107 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 108 return ServerPage{pagination.LinkedPageBase{PageResult: r}} 109 }) 110 } 111 112 // List makes a request against the API to list servers details accessible to you. 113 func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { 114 url := listDetailURL(client) 115 if opts != nil { 116 query, err := opts.ToServerListQuery() 117 if err != nil { 118 return pagination.Pager{Err: err} 119 } 120 url += query 121 } 122 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 123 return ServerPage{pagination.LinkedPageBase{PageResult: r}} 124 }) 125 } 126 127 // CreateOptsBuilder allows extensions to add additional parameters to the 128 // Create request. 129 type CreateOptsBuilder interface { 130 ToServerCreateMap() (map[string]interface{}, error) 131 } 132 133 // Network is used within CreateOpts to control a new server's network 134 // attachments. 135 type Network struct { 136 // UUID of a network to attach to the newly provisioned server. 137 // Required unless Port is provided. 138 UUID string 139 140 // Port of a neutron network to attach to the newly provisioned server. 141 // Required unless UUID is provided. 142 Port string 143 144 // FixedIP specifies a fixed IPv4 address to be used on this network. 145 FixedIP string 146 147 // Tag may contain an optional device role tag for the server's virtual 148 // network interface. This can be used to identify network interfaces when 149 // multiple networks are connected to one server. 150 // 151 // Requires microversion 2.32 through 2.36 or 2.42 or later. 152 Tag string 153 } 154 155 // Personality is an array of files that are injected into the server at launch. 156 type Personality []*File 157 158 // File is used within CreateOpts and RebuildOpts to inject a file into the 159 // server at launch. 160 // File implements the json.Marshaler interface, so when a Create or Rebuild 161 // operation is requested, json.Marshal will call File's MarshalJSON method. 162 type File struct { 163 // Path of the file. 164 Path string 165 166 // Contents of the file. Maximum content size is 255 bytes. 167 Contents []byte 168 } 169 170 // MarshalJSON marshals the escaped file, base64 encoding the contents. 171 func (f *File) MarshalJSON() ([]byte, error) { 172 file := struct { 173 Path string `json:"path"` 174 Contents string `json:"contents"` 175 }{ 176 Path: f.Path, 177 Contents: base64.StdEncoding.EncodeToString(f.Contents), 178 } 179 return json.Marshal(file) 180 } 181 182 // CreateOpts specifies server creation parameters. 183 type CreateOpts struct { 184 // Name is the name to assign to the newly launched server. 185 Name string `json:"name" required:"true"` 186 187 // ImageRef is the ID or full URL to the image that contains the 188 // server's OS and initial state. 189 // Also optional if using the boot-from-volume extension. 190 ImageRef string `json:"imageRef"` 191 192 // FlavorRef is the ID or full URL to the flavor that describes the server's specs. 193 FlavorRef string `json:"flavorRef"` 194 195 // SecurityGroups lists the names of the security groups to which this server 196 // should belong. 197 SecurityGroups []string `json:"-"` 198 199 // UserData contains configuration information or scripts to use upon launch. 200 // Create will base64-encode it for you, if it isn't already. 201 UserData []byte `json:"-"` 202 203 // AvailabilityZone in which to launch the server. 204 AvailabilityZone string `json:"availability_zone,omitempty"` 205 206 // Networks dictates how this server will be attached to available networks. 207 // By default, the server will be attached to all isolated networks for the 208 // tenant. 209 // Starting with microversion 2.37 networks can also be an "auto" or "none" 210 // string. 211 Networks interface{} `json:"-"` 212 213 // Metadata contains key-value pairs (up to 255 bytes each) to attach to the 214 // server. 215 Metadata map[string]string `json:"metadata,omitempty"` 216 217 // Personality includes files to inject into the server at launch. 218 // Create will base64-encode file contents for you. 219 Personality Personality `json:"personality,omitempty"` 220 221 // ConfigDrive enables metadata injection through a configuration drive. 222 ConfigDrive *bool `json:"config_drive,omitempty"` 223 224 // AdminPass sets the root user password. If not set, a randomly-generated 225 // password will be created and returned in the response. 226 AdminPass string `json:"adminPass,omitempty"` 227 228 // AccessIPv4 specifies an IPv4 address for the instance. 229 AccessIPv4 string `json:"accessIPv4,omitempty"` 230 231 // AccessIPv6 specifies an IPv6 address for the instance. 232 AccessIPv6 string `json:"accessIPv6,omitempty"` 233 234 // Min specifies Minimum number of servers to launch. 235 Min int `json:"min_count,omitempty"` 236 237 // Max specifies Maximum number of servers to launch. 238 Max int `json:"max_count,omitempty"` 239 240 // Tags allows a server to be tagged with single-word metadata. 241 // Requires microversion 2.52 or later. 242 Tags []string `json:"tags,omitempty"` 243 } 244 245 // ToServerCreateMap assembles a request body based on the contents of a 246 // CreateOpts. 247 func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) { 248 b, err := gophercloud.BuildRequestBody(opts, "") 249 if err != nil { 250 return nil, err 251 } 252 253 if opts.UserData != nil { 254 var userData string 255 if _, err := base64.StdEncoding.DecodeString(string(opts.UserData)); err != nil { 256 userData = base64.StdEncoding.EncodeToString(opts.UserData) 257 } else { 258 userData = string(opts.UserData) 259 } 260 b["user_data"] = &userData 261 } 262 263 if len(opts.SecurityGroups) > 0 { 264 securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups)) 265 for i, groupName := range opts.SecurityGroups { 266 securityGroups[i] = map[string]interface{}{"name": groupName} 267 } 268 b["security_groups"] = securityGroups 269 } 270 271 switch v := opts.Networks.(type) { 272 case []Network: 273 if len(v) > 0 { 274 networks := make([]map[string]interface{}, len(v)) 275 for i, net := range v { 276 networks[i] = make(map[string]interface{}) 277 if net.UUID != "" { 278 networks[i]["uuid"] = net.UUID 279 } 280 if net.Port != "" { 281 networks[i]["port"] = net.Port 282 } 283 if net.FixedIP != "" { 284 networks[i]["fixed_ip"] = net.FixedIP 285 } 286 if net.Tag != "" { 287 networks[i]["tag"] = net.Tag 288 } 289 } 290 b["networks"] = networks 291 } 292 case string: 293 if v == "auto" || v == "none" { 294 b["networks"] = v 295 } else { 296 return nil, fmt.Errorf(`networks must be a slice of Network struct or a string with "auto" or "none" values, current value is %q`, v) 297 } 298 } 299 300 if opts.Min != 0 { 301 b["min_count"] = opts.Min 302 } 303 304 if opts.Max != 0 { 305 b["max_count"] = opts.Max 306 } 307 308 return map[string]interface{}{"server": b}, nil 309 } 310 311 // Create requests a server to be provisioned to the user in the current tenant. 312 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { 313 reqBody, err := opts.ToServerCreateMap() 314 if err != nil { 315 r.Err = err 316 return 317 } 318 resp, err := client.Post(listURL(client), reqBody, &r.Body, nil) 319 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 320 return 321 } 322 323 // Delete requests that a server previously provisioned be removed from your 324 // account. 325 func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { 326 resp, err := client.Delete(deleteURL(client, id), nil) 327 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 328 return 329 } 330 331 // ForceDelete forces the deletion of a server. 332 func ForceDelete(client *gophercloud.ServiceClient, id string) (r ActionResult) { 333 resp, err := client.Post(actionURL(client, id), map[string]interface{}{"forceDelete": ""}, nil, nil) 334 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 335 return 336 } 337 338 // Get requests details on a single server, by ID. 339 func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { 340 resp, err := client.Get(getURL(client, id), &r.Body, &gophercloud.RequestOpts{ 341 OkCodes: []int{200, 203}, 342 }) 343 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 344 return 345 } 346 347 // UpdateOptsBuilder allows extensions to add additional attributes to the 348 // Update request. 349 type UpdateOptsBuilder interface { 350 ToServerUpdateMap() (map[string]interface{}, error) 351 } 352 353 // UpdateOpts specifies the base attributes that may be updated on an existing 354 // server. 355 type UpdateOpts struct { 356 // Name changes the displayed name of the server. 357 // The server host name will *not* change. 358 // Server names are not constrained to be unique, even within the same tenant. 359 Name string `json:"name,omitempty"` 360 361 // AccessIPv4 provides a new IPv4 address for the instance. 362 AccessIPv4 string `json:"accessIPv4,omitempty"` 363 364 // AccessIPv6 provides a new IPv6 address for the instance. 365 AccessIPv6 string `json:"accessIPv6,omitempty"` 366 } 367 368 // ToServerUpdateMap formats an UpdateOpts structure into a request body. 369 func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) { 370 return gophercloud.BuildRequestBody(opts, "server") 371 } 372 373 // Update requests that various attributes of the indicated server be changed. 374 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { 375 b, err := opts.ToServerUpdateMap() 376 if err != nil { 377 r.Err = err 378 return 379 } 380 resp, err := client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 381 OkCodes: []int{200}, 382 }) 383 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 384 return 385 } 386 387 // ChangeAdminPassword alters the administrator or root password for a specified 388 // server. 389 func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword string) (r ActionResult) { 390 b := map[string]interface{}{ 391 "changePassword": map[string]string{ 392 "adminPass": newPassword, 393 }, 394 } 395 resp, err := client.Post(actionURL(client, id), b, nil, nil) 396 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 397 return 398 } 399 400 // RebootMethod describes the mechanisms by which a server reboot can be requested. 401 type RebootMethod string 402 403 // These constants determine how a server should be rebooted. 404 // See the Reboot() function for further details. 405 const ( 406 SoftReboot RebootMethod = "SOFT" 407 HardReboot RebootMethod = "HARD" 408 OSReboot = SoftReboot 409 PowerCycle = HardReboot 410 ) 411 412 // RebootOptsBuilder allows extensions to add additional parameters to the 413 // reboot request. 414 type RebootOptsBuilder interface { 415 ToServerRebootMap() (map[string]interface{}, error) 416 } 417 418 // RebootOpts provides options to the reboot request. 419 type RebootOpts struct { 420 // Type is the type of reboot to perform on the server. 421 Type RebootMethod `json:"type" required:"true"` 422 } 423 424 // ToServerRebootMap builds a body for the reboot request. 425 func (opts RebootOpts) ToServerRebootMap() (map[string]interface{}, error) { 426 return gophercloud.BuildRequestBody(opts, "reboot") 427 } 428 429 /* 430 Reboot requests that a given server reboot. 431 432 Two methods exist for rebooting a server: 433 434 HardReboot (aka PowerCycle) starts the server instance by physically cutting 435 power to the machine, or if a VM, terminating it at the hypervisor level. 436 It's done. Caput. Full stop. 437 Then, after a brief while, power is restored or the VM instance restarted. 438 439 SoftReboot (aka OSReboot) simply tells the OS to restart under its own 440 procedure. 441 E.g., in Linux, asking it to enter runlevel 6, or executing 442 "sudo shutdown -r now", or by asking Windows to rtart the machine. 443 */ 444 func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) (r ActionResult) { 445 b, err := opts.ToServerRebootMap() 446 if err != nil { 447 r.Err = err 448 return 449 } 450 resp, err := client.Post(actionURL(client, id), b, nil, nil) 451 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 452 return 453 } 454 455 // RebuildOptsBuilder allows extensions to provide additional parameters to the 456 // rebuild request. 457 type RebuildOptsBuilder interface { 458 ToServerRebuildMap() (map[string]interface{}, error) 459 } 460 461 // RebuildOpts represents the configuration options used in a server rebuild 462 // operation. 463 type RebuildOpts struct { 464 // AdminPass is the server's admin password 465 AdminPass string `json:"adminPass,omitempty"` 466 467 // ImageRef is the ID of the image you want your server to be provisioned on. 468 ImageRef string `json:"imageRef"` 469 470 // Name to set the server to 471 Name string `json:"name,omitempty"` 472 473 // AccessIPv4 [optional] provides a new IPv4 address for the instance. 474 AccessIPv4 string `json:"accessIPv4,omitempty"` 475 476 // AccessIPv6 [optional] provides a new IPv6 address for the instance. 477 AccessIPv6 string `json:"accessIPv6,omitempty"` 478 479 // Metadata [optional] contains key-value pairs (up to 255 bytes each) 480 // to attach to the server. 481 Metadata map[string]string `json:"metadata,omitempty"` 482 483 // Personality [optional] includes files to inject into the server at launch. 484 // Rebuild will base64-encode file contents for you. 485 Personality Personality `json:"personality,omitempty"` 486 } 487 488 // ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON 489 func (opts RebuildOpts) ToServerRebuildMap() (map[string]interface{}, error) { 490 b, err := gophercloud.BuildRequestBody(opts, "") 491 if err != nil { 492 return nil, err 493 } 494 495 return map[string]interface{}{"rebuild": b}, nil 496 } 497 498 // Rebuild will reprovision the server according to the configuration options 499 // provided in the RebuildOpts struct. 500 func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) (r RebuildResult) { 501 b, err := opts.ToServerRebuildMap() 502 if err != nil { 503 r.Err = err 504 return 505 } 506 resp, err := client.Post(actionURL(client, id), b, &r.Body, nil) 507 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 508 return 509 } 510 511 // ResizeOptsBuilder allows extensions to add additional parameters to the 512 // resize request. 513 type ResizeOptsBuilder interface { 514 ToServerResizeMap() (map[string]interface{}, error) 515 } 516 517 // ResizeOpts represents the configuration options used to control a Resize 518 // operation. 519 type ResizeOpts struct { 520 // FlavorRef is the ID of the flavor you wish your server to become. 521 FlavorRef string `json:"flavorRef" required:"true"` 522 } 523 524 // ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON 525 // request body for the Resize request. 526 func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) { 527 return gophercloud.BuildRequestBody(opts, "resize") 528 } 529 530 // Resize instructs the provider to change the flavor of the server. 531 // 532 // Note that this implies rebuilding it. 533 // 534 // Unfortunately, one cannot pass rebuild parameters to the resize function. 535 // When the resize completes, the server will be in VERIFY_RESIZE state. 536 // While in this state, you can explore the use of the new server's 537 // configuration. If you like it, call ConfirmResize() to commit the resize 538 // permanently. Otherwise, call RevertResize() to restore the old configuration. 539 func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) (r ActionResult) { 540 b, err := opts.ToServerResizeMap() 541 if err != nil { 542 r.Err = err 543 return 544 } 545 resp, err := client.Post(actionURL(client, id), b, nil, nil) 546 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 547 return 548 } 549 550 // ConfirmResize confirms a previous resize operation on a server. 551 // See Resize() for more details. 552 func ConfirmResize(client *gophercloud.ServiceClient, id string) (r ActionResult) { 553 resp, err := client.Post(actionURL(client, id), map[string]interface{}{"confirmResize": nil}, nil, &gophercloud.RequestOpts{ 554 OkCodes: []int{201, 202, 204}, 555 }) 556 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 557 return 558 } 559 560 // RevertResize cancels a previous resize operation on a server. 561 // See Resize() for more details. 562 func RevertResize(client *gophercloud.ServiceClient, id string) (r ActionResult) { 563 resp, err := client.Post(actionURL(client, id), map[string]interface{}{"revertResize": nil}, nil, nil) 564 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 565 return 566 } 567 568 // ResetMetadataOptsBuilder allows extensions to add additional parameters to 569 // the Reset request. 570 type ResetMetadataOptsBuilder interface { 571 ToMetadataResetMap() (map[string]interface{}, error) 572 } 573 574 // MetadataOpts is a map that contains key-value pairs. 575 type MetadataOpts map[string]string 576 577 // ToMetadataResetMap assembles a body for a Reset request based on the contents 578 // of a MetadataOpts. 579 func (opts MetadataOpts) ToMetadataResetMap() (map[string]interface{}, error) { 580 return map[string]interface{}{"metadata": opts}, nil 581 } 582 583 // ToMetadataUpdateMap assembles a body for an Update request based on the 584 // contents of a MetadataOpts. 585 func (opts MetadataOpts) ToMetadataUpdateMap() (map[string]interface{}, error) { 586 return map[string]interface{}{"metadata": opts}, nil 587 } 588 589 // ResetMetadata will create multiple new key-value pairs for the given server 590 // ID. 591 // Note: Using this operation will erase any already-existing metadata and 592 // create the new metadata provided. To keep any already-existing metadata, 593 // use the UpdateMetadatas or UpdateMetadata function. 594 func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) (r ResetMetadataResult) { 595 b, err := opts.ToMetadataResetMap() 596 if err != nil { 597 r.Err = err 598 return 599 } 600 resp, err := client.Put(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 601 OkCodes: []int{200}, 602 }) 603 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 604 return 605 } 606 607 // Metadata requests all the metadata for the given server ID. 608 func Metadata(client *gophercloud.ServiceClient, id string) (r GetMetadataResult) { 609 resp, err := client.Get(metadataURL(client, id), &r.Body, nil) 610 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 611 return 612 } 613 614 // UpdateMetadataOptsBuilder allows extensions to add additional parameters to 615 // the Create request. 616 type UpdateMetadataOptsBuilder interface { 617 ToMetadataUpdateMap() (map[string]interface{}, error) 618 } 619 620 // UpdateMetadata updates (or creates) all the metadata specified by opts for 621 // the given server ID. This operation does not affect already-existing metadata 622 // that is not specified by opts. 623 func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) (r UpdateMetadataResult) { 624 b, err := opts.ToMetadataUpdateMap() 625 if err != nil { 626 r.Err = err 627 return 628 } 629 resp, err := client.Post(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 630 OkCodes: []int{200}, 631 }) 632 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 633 return 634 } 635 636 // MetadatumOptsBuilder allows extensions to add additional parameters to the 637 // Create request. 638 type MetadatumOptsBuilder interface { 639 ToMetadatumCreateMap() (map[string]interface{}, string, error) 640 } 641 642 // MetadatumOpts is a map of length one that contains a key-value pair. 643 type MetadatumOpts map[string]string 644 645 // ToMetadatumCreateMap assembles a body for a Create request based on the 646 // contents of a MetadataumOpts. 647 func (opts MetadatumOpts) ToMetadatumCreateMap() (map[string]interface{}, string, error) { 648 if len(opts) != 1 { 649 err := gophercloud.ErrInvalidInput{} 650 err.Argument = "servers.MetadatumOpts" 651 err.Info = "Must have 1 and only 1 key-value pair" 652 return nil, "", err 653 } 654 metadatum := map[string]interface{}{"meta": opts} 655 var key string 656 for k := range metadatum["meta"].(MetadatumOpts) { 657 key = k 658 } 659 return metadatum, key, nil 660 } 661 662 // CreateMetadatum will create or update the key-value pair with the given key 663 // for the given server ID. 664 func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) (r CreateMetadatumResult) { 665 b, key, err := opts.ToMetadatumCreateMap() 666 if err != nil { 667 r.Err = err 668 return 669 } 670 resp, err := client.Put(metadatumURL(client, id, key), b, &r.Body, &gophercloud.RequestOpts{ 671 OkCodes: []int{200}, 672 }) 673 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 674 return 675 } 676 677 // Metadatum requests the key-value pair with the given key for the given 678 // server ID. 679 func Metadatum(client *gophercloud.ServiceClient, id, key string) (r GetMetadatumResult) { 680 resp, err := client.Get(metadatumURL(client, id, key), &r.Body, nil) 681 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 682 return 683 } 684 685 // DeleteMetadatum will delete the key-value pair with the given key for the 686 // given server ID. 687 func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) (r DeleteMetadatumResult) { 688 resp, err := client.Delete(metadatumURL(client, id, key), nil) 689 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 690 return 691 } 692 693 // ListAddresses makes a request against the API to list the servers IP 694 // addresses. 695 func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager { 696 return pagination.NewPager(client, listAddressesURL(client, id), func(r pagination.PageResult) pagination.Page { 697 return AddressPage{pagination.SinglePageBase(r)} 698 }) 699 } 700 701 // ListAddressesByNetwork makes a request against the API to list the servers IP 702 // addresses for the given network. 703 func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager { 704 return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), func(r pagination.PageResult) pagination.Page { 705 return NetworkAddressPage{pagination.SinglePageBase(r)} 706 }) 707 } 708 709 // CreateImageOptsBuilder allows extensions to add additional parameters to the 710 // CreateImage request. 711 type CreateImageOptsBuilder interface { 712 ToServerCreateImageMap() (map[string]interface{}, error) 713 } 714 715 // CreateImageOpts provides options to pass to the CreateImage request. 716 type CreateImageOpts struct { 717 // Name of the image/snapshot. 718 Name string `json:"name" required:"true"` 719 720 // Metadata contains key-value pairs (up to 255 bytes each) to attach to 721 // the created image. 722 Metadata map[string]string `json:"metadata,omitempty"` 723 } 724 725 // ToServerCreateImageMap formats a CreateImageOpts structure into a request 726 // body. 727 func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) { 728 return gophercloud.BuildRequestBody(opts, "createImage") 729 } 730 731 // CreateImage makes a request against the nova API to schedule an image to be 732 // created of the server 733 func CreateImage(client *gophercloud.ServiceClient, id string, opts CreateImageOptsBuilder) (r CreateImageResult) { 734 b, err := opts.ToServerCreateImageMap() 735 if err != nil { 736 r.Err = err 737 return 738 } 739 resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 740 OkCodes: []int{202}, 741 }) 742 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 743 return 744 } 745 746 // GetPassword makes a request against the nova API to get the encrypted 747 // administrative password. 748 func GetPassword(client *gophercloud.ServiceClient, serverId string) (r GetPasswordResult) { 749 resp, err := client.Get(passwordURL(client, serverId), &r.Body, nil) 750 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 751 return 752 } 753 754 // ShowConsoleOutputOptsBuilder is the interface types must satisfy in order to be 755 // used as ShowConsoleOutput options 756 type ShowConsoleOutputOptsBuilder interface { 757 ToServerShowConsoleOutputMap() (map[string]interface{}, error) 758 } 759 760 // ShowConsoleOutputOpts satisfies the ShowConsoleOutputOptsBuilder 761 type ShowConsoleOutputOpts struct { 762 // The number of lines to fetch from the end of console log. 763 // All lines will be returned if this is not specified. 764 Length int `json:"length,omitempty"` 765 } 766 767 // ToServerShowConsoleOutputMap formats a ShowConsoleOutputOpts structure into a request body. 768 func (opts ShowConsoleOutputOpts) ToServerShowConsoleOutputMap() (map[string]interface{}, error) { 769 return gophercloud.BuildRequestBody(opts, "os-getConsoleOutput") 770 } 771 772 // ShowConsoleOutput makes a request against the nova API to get console log from the server 773 func ShowConsoleOutput(client *gophercloud.ServiceClient, id string, opts ShowConsoleOutputOptsBuilder) (r ShowConsoleOutputResult) { 774 b, err := opts.ToServerShowConsoleOutputMap() 775 if err != nil { 776 r.Err = err 777 return 778 } 779 resp, err := client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 780 OkCodes: []int{200}, 781 }) 782 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 783 return 784 }