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  }