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