more error types for compute v2
diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go
index c6d3a8e..488829e 100644
--- a/openstack/compute/v2/servers/requests.go
+++ b/openstack/compute/v2/servers/requests.go
@@ -4,7 +4,6 @@
 	"encoding/base64"
 	"encoding/json"
 	"errors"
-	"fmt"
 
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
@@ -175,7 +174,7 @@
 	ConfigDrive bool
 
 	// AdminPass [optional] sets the root user password. If not set, a randomly-generated
-	// password will be created and returned in the response.
+	// password will be created and returned in the rponse.
 	AdminPass string
 
 	// AccessIPv4 [optional] specifies an IPv4 address for the instance.
@@ -252,10 +251,16 @@
 	// If ImageRef isn't provided, use ImageName to ascertain the image ID.
 	if opts.ImageRef == "" {
 		if opts.ImageName == "" {
-			return nil, errors.New("One and only one of ImageRef and ImageName must be provided.")
+			err := ErrNeitherImageIDNorImageNameProvided{}
+			err.Function = "servers.CreateOpts.ToServerCreateMap"
+			err.Argument = "ImageRef/ImageName"
+			return nil, err
 		}
 		if opts.ServiceClient == nil {
-			return nil, errors.New("A service client must be provided to find an image ID by name.")
+			err := ErrNoClientProvidedForIDByName{}
+			err.Function = "servers.CreateOpts.ToServerCreateMap"
+			err.Argument = "ServiceClient"
+			return nil, err
 		}
 		imageID, err := images.IDFromName(opts.ServiceClient, opts.ImageName)
 		if err != nil {
@@ -267,10 +272,16 @@
 	// If FlavorRef isn't provided, use FlavorName to ascertain the flavor ID.
 	if opts.FlavorRef == "" {
 		if opts.FlavorName == "" {
-			return nil, errors.New("One and only one of FlavorRef and FlavorName must be provided.")
+			err := ErrNeitherFlavorIDNorFlavorNameProvided{}
+			err.Function = "servers.CreateOpts.ToServerCreateMap"
+			err.Argument = "FlavorRef/FlavorName"
+			return nil, err
 		}
 		if opts.ServiceClient == nil {
-			return nil, errors.New("A service client must be provided to find a flavor ID by name.")
+			err := ErrNoClientProvidedForIDByName{}
+			err.Argument = "ServiceClient"
+			err.Function = "servers.CreateOpts.ToServerCreateMap"
+			return nil, err
 		}
 		flavorID, err := flavors.IDFromName(opts.ServiceClient, opts.FlavorName)
 		if err != nil {
@@ -284,23 +295,23 @@
 
 // Create requests a server to be provisioned to the user in the current tenant.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
+	var r CreateResult
 
 	reqBody, err := opts.ToServerCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
 
-	_, res.Err = client.Post(listURL(client), reqBody, &res.Body, nil)
-	return res
+	_, r.Err = client.Post(listURL(client), reqBody, &r.Body, nil)
+	return r
 }
 
 // Delete requests that a server previously provisioned be removed from your account.
 func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(deleteURL(client, id), nil)
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(deleteURL(client, id), nil)
+	return r
 }
 
 func ForceDelete(client *gophercloud.ServiceClient, id string) ActionResult {
@@ -308,19 +319,19 @@
 		ForceDelete string `json:"forceDelete"`
 	}
 
-	var res ActionResult
-	_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
-	return res
+	var r ActionResult
+	_, r.Err = client.Post(actionURL(client, id), req, nil, nil)
+	return r
 
 }
 
 // Get requests details on a single server, by ID.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var result GetResult
-	_, result.Err = client.Get(getURL(client, id), &result.Body, &gophercloud.RequestOpts{
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200, 203},
 	})
-	return result
+	return r
 }
 
 // UpdateOptsBuilder allows extensions to add additional attributes to the Update request.
@@ -359,12 +370,12 @@
 
 // Update requests that various attributes of the indicated server be changed.
 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
-	var result UpdateResult
-	reqBody := opts.ToServerUpdateMap()
-	_, result.Err = client.Put(updateURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
+	var r UpdateResult
+	b := opts.ToServerUpdateMap()
+	_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return result
+	return r
 }
 
 // ChangeAdminPassword alters the administrator or root password for a specified server.
@@ -377,35 +388,9 @@
 
 	req.ChangePassword.AdminPass = newPassword
 
-	var res ActionResult
-	_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
-	return res
-}
-
-// ErrArgument errors occur when an argument supplied to a package function
-// fails to fall within acceptable values.  For example, the Reboot() function
-// expects the "how" parameter to be one of HardReboot or SoftReboot.  These
-// constants are (currently) strings, leading someone to wonder if they can pass
-// other string values instead, perhaps in an effort to break the API of their
-// provider.  Reboot() returns this error in this situation.
-//
-// Function identifies which function was called/which function is generating
-// the error.
-// Argument identifies which formal argument was responsible for producing the
-// error.
-// Value provides the value as it was passed into the function.
-type ErrArgument struct {
-	Function, Argument string
-	Value              interface{}
-}
-
-// Error yields a useful diagnostic for debugging purposes.
-func (e *ErrArgument) Error() string {
-	return fmt.Sprintf("Bad argument in call to %s, formal parameter %s, value %#v", e.Function, e.Argument, e.Value)
-}
-
-func (e *ErrArgument) String() string {
-	return e.Error()
+	var r ActionResult
+	_, r.Err = client.Post(actionURL(client, id), req, nil, nil)
+	return r
 }
 
 // RebootMethod describes the mechanisms by which a server reboot can be requested.
@@ -420,36 +405,53 @@
 	PowerCycle              = HardReboot
 )
 
+type RebootOptsBuilder interface {
+	ToServerRebootMap() (map[string]interface{}, error)
+}
+
+type RebootOpts struct {
+	Type RebootMethod
+}
+
+func (opts *RebootOpts) ToServerRebootMap() (map[string]interface{}, error) {
+	if (opts.Type != SoftReboot) && (opts.Type != HardReboot) {
+		err := &gophercloud.ErrInvalidInput{}
+		err.Argument = "servers.RebootOpts.Type"
+		err.Value = opts.Type
+		err.Function = "servers.Reboot"
+		return nil, err
+	}
+
+	reqBody := map[string]interface{}{
+		"reboot": map[string]interface{}{
+			"type": string(opts.Type),
+		},
+	}
+
+	return reqBody, nil
+}
+
 // Reboot requests that a given server reboot.
 // Two methods exist for rebooting a server:
 //
-// HardReboot (aka PowerCycle) restarts the server instance by physically cutting power to the machine, or if a VM,
+// HardReboot (aka PowerCycle) rtarts the server instance by physically cutting power to the machine, or if a VM,
 // terminating it at the hypervisor level.
 // It's done. Caput. Full stop.
-// Then, after a brief while, power is restored or the VM instance restarted.
+// Then, after a brief while, power is rtored or the VM instance rtarted.
 //
-// SoftReboot (aka OSReboot) simply tells the OS to restart under its own procedures.
-// E.g., in Linux, asking it to enter runlevel 6, or executing "sudo shutdown -r now", or by asking Windows to restart the machine.
-func Reboot(client *gophercloud.ServiceClient, id string, how RebootMethod) ActionResult {
-	var res ActionResult
+// SoftReboot (aka OSReboot) simply tells the OS to rtart under its own procedur.
+// E.g., in Linux, asking it to enter runlevel 6, or executing "sudo shutdown -r now", or by asking Windows to rtart the machine.
+func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) ActionResult {
+	var r ActionResult
 
-	if (how != SoftReboot) && (how != HardReboot) {
-		res.Err = &ErrArgument{
-			Function: "Reboot",
-			Argument: "how",
-			Value:    how,
-		}
-		return res
+	reqBody, err := opts.ToServerRebootMap()
+	if err != nil {
+		r.Err = err
+		return r
 	}
 
-	reqBody := struct {
-		C map[string]string `json:"reboot"`
-	}{
-		map[string]string{"type": string(how)},
-	}
-
-	_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
-	return res
+	_, r.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
+	return r
 }
 
 // RebuildOptsBuilder is an interface that allows extensions to override the
@@ -490,11 +492,17 @@
 	server := make(map[string]interface{})
 
 	if opts.AdminPass == "" {
-		err = fmt.Errorf("AdminPass is required")
+		err := ErrNoAdminPassProvided{}
+		err.Function = "servers.ToServerRebuildMap"
+		err.Argument = "AdminPass"
+		return nil, err
 	}
 
 	if opts.ImageID == "" {
-		err = fmt.Errorf("ImageID is required")
+		err := ErrNoImageIDProvided{}
+		err.Function = "servers.ToServerRebuildMap"
+		err.Argument = "ImageID"
+		return nil, err
 	}
 
 	if err != nil {
@@ -530,21 +538,24 @@
 // Rebuild will reprovision the server according to the configuration options
 // provided in the RebuildOpts struct.
 func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) RebuildResult {
-	var result RebuildResult
+	var r RebuildResult
 
 	if id == "" {
-		result.Err = fmt.Errorf("ID is required")
-		return result
+		err := ErrNoIDProvided{}
+		err.Function = "servers.Rebuild"
+		err.Argument = "id"
+		r.Err = err
+		return r
 	}
 
-	reqBody, err := opts.ToServerRebuildMap()
+	b, err := opts.ToServerRebuildMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
 
-	_, result.Err = client.Post(actionURL(client, id), reqBody, &result.Body, nil)
-	return result
+	_, r.Err = client.Post(actionURL(client, id), b, &r.Body, nil)
+	return r
 }
 
 // ResizeOptsBuilder is an interface that allows extensions to override the default structure of
@@ -571,42 +582,68 @@
 
 // Resize instructs the provider to change the flavor of the server.
 // Note that this implies rebuilding it.
-// Unfortunately, one cannot pass rebuild parameters to the resize function.
-// When the resize completes, the server will be in RESIZE_VERIFY state.
+// Unfortunately, one cannot pass rebuild parameters to the rize function.
+// When the rize completes, the server will be in RESIZE_VERIFY state.
 // While in this state, you can explore the use of the new server's configuration.
-// If you like it, call ConfirmResize() to commit the resize permanently.
-// Otherwise, call RevertResize() to restore the old configuration.
+// If you like it, call ConfirmResize() to commit the rize permanently.
+// Otherwise, call RevertResize() to rtore the old configuration.
 func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) ActionResult {
-	var res ActionResult
-	reqBody, err := opts.ToServerResizeMap()
-	if err != nil {
-		res.Err = err
-		return res
+	var r ActionResult
+
+	if id == "" {
+		err := ErrNoIDProvided{}
+		err.Function = "servers.Resize"
+		err.Argument = "id"
+		r.Err = err
+		return r
 	}
 
-	_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
-	return res
+	b, err := opts.ToServerResizeMap()
+	if err != nil {
+		r.Err = err
+		return r
+	}
+
+	_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
+	return r
 }
 
-// ConfirmResize confirms a previous resize operation on a server.
+// ConfirmResize confirms a previous rize operation on a server.
 // See Resize() for more details.
 func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
-	var res ActionResult
+	var r ActionResult
 
-	reqBody := map[string]interface{}{"confirmResize": nil}
-	_, res.Err = client.Post(actionURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
+	if id == "" {
+		err := ErrNoIDProvided{}
+		err.Function = "servers.ConfirmResize"
+		err.Argument = "id"
+		r.Err = err
+		return r
+	}
+
+	b := map[string]interface{}{"confirmResize": nil}
+	_, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
 		OkCodes: []int{201, 202, 204},
 	})
-	return res
+	return r
 }
 
-// RevertResize cancels a previous resize operation on a server.
+// RevertResize cancels a previous rize operation on a server.
 // See Resize() for more details.
 func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
-	var res ActionResult
-	reqBody := map[string]interface{}{"revertResize": nil}
-	_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
-	return res
+	var r ActionResult
+
+	if id == "" {
+		err := ErrNoIDProvided{}
+		err.Function = "servers.RevertResize"
+		err.Argument = "id"
+		r.Err = err
+		return r
+	}
+
+	b := map[string]interface{}{"revertResize": nil}
+	_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
+	return r
 }
 
 // RescueOptsBuilder is an interface that allows extensions to override the
@@ -635,23 +672,27 @@
 
 // Rescue instructs the provider to place the server into RESCUE mode.
 func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder) RescueResult {
-	var result RescueResult
+	var r RescueResult
 
 	if id == "" {
-		result.Err = fmt.Errorf("ID is required")
-		return result
-	}
-	reqBody, err := opts.ToServerRescueMap()
-	if err != nil {
-		result.Err = err
-		return result
+		err := ErrNoIDProvided{}
+		err.Function = "servers.Rebuild"
+		err.Argument = "id"
+		r.Err = err
+		return r
 	}
 
-	_, result.Err = client.Post(actionURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
+	b, err := opts.ToServerRescueMap()
+	if err != nil {
+		r.Err = err
+		return r
+	}
+
+	_, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
 
-	return result
+	return r
 }
 
 // ResetMetadataOptsBuilder allows extensions to add additional parameters to the
@@ -678,23 +719,23 @@
 // the new metadata provided. To keep any already-existing metadata, use the
 // UpdateMetadatas or UpdateMetadata function.
 func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) ResetMetadataResult {
-	var res ResetMetadataResult
+	var r ResetMetadataResult
 	metadata, err := opts.ToMetadataResetMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-	_, res.Err = client.Put(metadataURL(client, id), metadata, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(metadataURL(client, id), metadata, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // Metadata requests all the metadata for the given server ID.
 func Metadata(client *gophercloud.ServiceClient, id string) GetMetadataResult {
-	var res GetMetadataResult
-	_, res.Err = client.Get(metadataURL(client, id), &res.Body, nil)
-	return res
+	var r GetMetadataResult
+	_, r.Err = client.Get(metadataURL(client, id), &r.Body, nil)
+	return r
 }
 
 // UpdateMetadataOptsBuilder allows extensions to add additional parameters to the
@@ -707,16 +748,16 @@
 // This operation does not affect already-existing metadata that is not specified
 // by opts.
 func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) UpdateMetadataResult {
-	var res UpdateMetadataResult
+	var r UpdateMetadataResult
 	metadata, err := opts.ToMetadataUpdateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-	_, res.Err = client.Post(metadataURL(client, id), metadata, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(metadataURL(client, id), metadata, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // MetadatumOptsBuilder allows extensions to add additional parameters to the
@@ -743,33 +784,33 @@
 
 // CreateMetadatum will create or update the key-value pair with the given key for the given server ID.
 func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) CreateMetadatumResult {
-	var res CreateMetadatumResult
+	var r CreateMetadatumResult
 	metadatum, key, err := opts.ToMetadatumCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
 
-	_, res.Err = client.Put(metadatumURL(client, id, key), metadatum, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(metadatumURL(client, id, key), metadatum, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // Metadatum requests the key-value pair with the given key for the given server ID.
 func Metadatum(client *gophercloud.ServiceClient, id, key string) GetMetadatumResult {
-	var res GetMetadatumResult
-	_, res.Err = client.Request("GET", metadatumURL(client, id, key), &gophercloud.RequestOpts{
-		JSONResponse: &res.Body,
+	var r GetMetadatumResult
+	_, r.Err = client.Request("GET", metadatumURL(client, id, key), &gophercloud.RequestOpts{
+		JSONResponse: &r.Body,
 	})
-	return res
+	return r
 }
 
 // DeleteMetadatum will delete the key-value pair with the given key for the given server ID.
 func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) DeleteMetadatumResult {
-	var res DeleteMetadatumResult
-	_, res.Err = client.Delete(metadatumURL(client, id, key), nil)
-	return res
+	var r DeleteMetadatumResult
+	_, r.Err = client.Delete(metadatumURL(client, id, key), nil)
+	return r
 }
 
 // ListAddresses makes a request against the API to list the servers IP addresses.
@@ -805,7 +846,10 @@
 	var err error
 	img := make(map[string]interface{})
 	if opts.Name == "" {
-		return nil, fmt.Errorf("Cannot create a server image without a name")
+		err := gophercloud.ErrMissingInput{}
+		err.Function = "servers.CreateImageOpts.ToServerCreateImageMap"
+		err.Argument = "CreateImageOpts.Name"
+		return nil, err
 	}
 	img["name"] = opts.Name
 	if opts.Metadata != nil {
@@ -818,49 +862,63 @@
 
 // CreateImage makes a request against the nova API to schedule an image to be created of the server
 func CreateImage(client *gophercloud.ServiceClient, serverID string, opts CreateImageOptsBuilder) CreateImageResult {
-	var res CreateImageResult
-	reqBody, err := opts.ToServerCreateImageMap()
+	var r CreateImageResult
+	b, err := opts.ToServerCreateImageMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-	response, err := client.Post(actionURL(client, serverID), reqBody, nil, &gophercloud.RequestOpts{
+	resp, err := client.Post(actionURL(client, serverID), b, nil, &gophercloud.RequestOpts{
 		OkCodes: []int{202},
 	})
-	res.Err = err
-	res.Header = response.Header
-	return res
+	r.Err = err
+	r.Header = resp.Header
+	return r
 }
 
 // IDFromName is a convienience function that returns a server's ID given its name.
 func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
-	serverCount := 0
-	serverID := ""
+	count := 0
+	id := ""
 	if name == "" {
-		return "", fmt.Errorf("A server name must be provided.")
+		err := &gophercloud.ErrMissingInput{}
+		err.Function = "servers.IDFromName"
+		err.Argument = "name"
+		return "", err
 	}
-	pager := List(client, nil)
-	pager.EachPage(func(page pagination.Page) (bool, error) {
-		serverList, err := ExtractServers(page)
-		if err != nil {
-			return false, err
-		}
 
-		for _, s := range serverList {
-			if s.Name == name {
-				serverCount++
-				serverID = s.ID
-			}
-		}
-		return true, nil
-	})
+	allPages, err := List(client, nil).AllPages()
+	if err != nil {
+		return "", err
+	}
 
-	switch serverCount {
+	all, err := ExtractServers(allPages)
+	if err != nil {
+		return "", err
+	}
+
+	for _, f := range all {
+		if f.Name == name {
+			count++
+			id = f.ID
+		}
+	}
+
+	switch count {
 	case 0:
-		return "", fmt.Errorf("Unable to find server: %s", name)
+		err := &gophercloud.ErrResourceNotFound{}
+		err.Function = "servers.IDFromName"
+		err.ResourceType = "server"
+		err.Name = name
+		return "", err
 	case 1:
-		return serverID, nil
+		return id, nil
 	default:
-		return "", fmt.Errorf("Found %d servers matching %s", serverCount, name)
+		err := &gophercloud.ErrMultipleResourcesFound{}
+		err.Function = "servers.IDFromName"
+		err.ResourceType = "server"
+		err.Name = name
+		err.Count = count
+		return "", err
 	}
 }