github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/openstack/compute/v2/servers/requests.go (about)

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