Implement first function of cloud compute API
diff --git a/acceptance/openstack/compute/01-servers.go b/acceptance/openstack/compute/01-servers.go
new file mode 100644
index 0000000..9a729ff
--- /dev/null
+++ b/acceptance/openstack/compute/01-servers.go
@@ -0,0 +1,66 @@
+package main
+
+import (
+	"fmt"
+	"github.com/rackspace/gophercloud/openstack/compute/servers"
+	"github.com/rackspace/gophercloud/openstack/identity"
+	"github.com/rackspace/gophercloud/openstack/utils"
+)
+
+func main() {
+	ao, err := utils.AuthOptions()
+	if err != nil {
+		panic(err)
+	}
+
+	a, err := identity.Authenticate(ao)
+	if err != nil {
+		panic(err)
+	}
+
+	sc, err := identity.GetServiceCatalog(a)
+	if err != nil {
+		panic(err)
+	}
+
+	ep, err := findAnyComputeEndpoint(sc)
+	if err != nil {
+		panic(err)
+	}
+
+	client := servers.NewClient(ep, a, ao)
+
+	listResults, err := servers.List(client)
+	if err != nil {
+		panic(err)
+	}
+
+	svrs, err := servers.GetServers(listResults)
+	if err != nil {
+		panic(err)
+	}
+
+	for _, s := range svrs {
+		fmt.Printf("ID(%s)\n", s.Id)
+		fmt.Printf("    Name(%s)\n", s.Name)
+		fmt.Printf("    IPv4(%s)\n    IPv6(%s)\n", s.AccessIPv4, s.AccessIPv6)
+	}
+	fmt.Printf("--------\n%d servers listed.\n", len(svrs))
+}
+
+
+func findAnyComputeEndpoint(sc *identity.ServiceCatalog) (string, error) {
+	ces, err := sc.CatalogEntries()
+	if err != nil {
+		return "", err
+	}
+
+	for _, ce := range ces {
+		if ce.Type == "compute" {
+			return ce.Endpoints[0].PublicURL, nil
+		}
+	}
+
+	return "", fmt.Errorf("Compute endpoint not found.")
+}
+
diff --git a/openstack/compute/servers/client.go b/openstack/compute/servers/client.go
new file mode 100644
index 0000000..a59a339
--- /dev/null
+++ b/openstack/compute/servers/client.go
@@ -0,0 +1,52 @@
+package servers
+
+import (
+	"fmt"
+	"github.com/rackspace/gophercloud/openstack/identity"
+)
+
+// Client abstracts the connection information needed to make API requests for OpenStack compute endpoints.
+type Client struct {
+	endpoint	string
+	authority	identity.AuthResults
+	options		identity.AuthOptions
+	token		*identity.Token
+}
+
+// NewClient creates a new Client structure to use when issuing requests to the server.
+func NewClient(e string, a identity.AuthResults, o identity.AuthOptions) *Client {
+	return &Client{
+		endpoint:	e,
+		authority:	a,
+		options:	o,
+	}
+}
+
+func (c *Client) getListUrl() string {
+	return fmt.Sprintf("%s/servers/detail", c.endpoint)
+}
+
+func (c *Client) getListHeaders() (map[string]string, error) {
+	t, err := c.getAuthToken()
+	if err != nil {
+		return map[string]string{}, err
+	}
+
+	return map[string]string{
+		"X-Auth-Token": t,
+	}, nil
+}
+
+func (c *Client) getAuthToken() (string, error) {
+	var err error
+
+	if c.token == nil {
+		c.token, err = identity.GetToken(c.authority)
+		if err != nil {
+			return "", err
+		}
+	}
+
+	return c.token.Id, err
+}
+
diff --git a/openstack/compute/servers/doc.go b/openstack/compute/servers/doc.go
new file mode 100644
index 0000000..c5c6777
--- /dev/null
+++ b/openstack/compute/servers/doc.go
@@ -0,0 +1,3 @@
+// The servers package provides convenient access to standard, OpenStack-defined compute services.
+package servers
+
diff --git a/openstack/compute/servers/requests.go b/openstack/compute/servers/requests.go
new file mode 100644
index 0000000..0c49159
--- /dev/null
+++ b/openstack/compute/servers/requests.go
@@ -0,0 +1,28 @@
+package servers
+
+import (
+	"github.com/racker/perigee"
+)
+
+// ListResult abstracts the raw results of making a List() request against the
+// API.  As OpenStack extensions may freely alter the response bodies of
+// structures returned to the client, you may only safely access the data
+// provided through separate, type-safe accessors or methods. 
+type ListResult map[string]interface{}
+
+// List makes a request against the API to list servers accessible to you.
+func List(c *Client) (ListResult, error) {
+	var lr ListResult
+
+	h, err := c.getListHeaders()
+	if err != nil {
+		return nil, err
+	}
+
+	err = perigee.Get(c.getListUrl(), perigee.Options{
+		Results: &lr,
+		MoreHeaders: h,
+	})
+	return lr, err
+}
+
diff --git a/openstack/compute/servers/servers.go b/openstack/compute/servers/servers.go
new file mode 100644
index 0000000..7061993
--- /dev/null
+++ b/openstack/compute/servers/servers.go
@@ -0,0 +1,77 @@
+package servers
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"fmt"
+)
+
+// ErrNotImplemented indicates a failure to discover a feature of the response from the API.
+// E.g., a missing server field, a missing extension, etc.
+var ErrNotImplemented = fmt.Errorf("Compute Servers feature not implemented.")
+
+// Server exposes only the standard OpenStack fields corresponding to a given server on the user's account.
+//
+// Id uniquely identifies this server amongst all other servers, including those not accessible to the current tenant.
+//
+// TenantId identifies the tenant owning this server resource.
+//
+// UserId uniquely identifies the user account owning the tenant.
+//
+// Name contains the human-readable name for the server.
+//
+// Updated and Created contain ISO-8601 timestamps of when the state of the server last changed, and when it was created.
+//
+// Status contains the current operational status of the server, such as IN_PROGRESS or ACTIVE.
+//
+// Progress ranges from 0..100.  A request made against the server completes only once Progress reaches 100.
+//
+// AccessIPv4 and AccessIPv6 contain the IP addresses of the server, suitable for remote access for administration.
+//
+// Image refers to a JSON object, which itself indicates the OS image used to deploy the server.
+//
+// Flavor refers to a JSON object, which itself indicates the hardware configuration of the deployed server.
+//
+// Addresses includes a list of all IP addresses assigned to the server, keyed by pool.
+//
+// Metadata includes a list of all user-specified key-value pairs attached to the server.
+//
+// Links includes HTTP references to the itself, useful for passing along to other APIs that might want a server reference.
+type Server struct {
+	Id string
+	TenantId string `mapstructure:tenant_id`
+	UserId string `mapstructure:user_id`
+	Name string
+	Updated string
+	Created string
+	HostId string
+	Status string
+	Progress int
+	AccessIPv4 string
+	AccessIPv6 string
+	Image map[string]interface{}
+	Flavor map[string]interface{}
+	Addresses map[string]interface{}
+	Metadata map[string]interface{}
+	Links []interface{}
+}
+
+// GetServers interprets the result of a List() call, producing a slice of Server entities.
+func GetServers(lr ListResult) ([]Server, error) {
+	sa, ok := lr["servers"]
+	if !ok {
+		return nil, ErrNotImplemented
+	}
+	serversArray := sa.([]interface{})
+
+	servers := make([]Server, len(serversArray))
+	for i, so := range serversArray {
+		serverObj := so.(map[string]interface{})
+		err := mapstructure.Decode(serverObj, &servers[i])
+		if err != nil {
+			return servers, err
+		}
+	}
+
+	return servers, nil
+}
+
diff --git a/openstack/compute/servers/servers_test.go b/openstack/compute/servers/servers_test.go
new file mode 100644
index 0000000..8a58a46
--- /dev/null
+++ b/openstack/compute/servers/servers_test.go
@@ -0,0 +1,189 @@
+package servers
+
+import (
+	"testing"
+	"encoding/json"
+)
+
+// Taken from: http://docs.openstack.org/api/openstack-compute/2/content/List_Servers-d1e2078.html
+const goodListServersResult = `{
+"servers": [
+{
+"id": "52415800-8b69-11e0-9b19-734f6af67565",
+"tenant_id": "1234",
+"user_id": "5678",
+"name": "sample-server",
+"updated": "2010-10-10T12:00:00Z",
+"created": "2010-08-10T12:00:00Z",
+"hostId": "e4d909c290d0fb1ca068ffaddf22cbd0",
+"status": "BUILD",
+"progress": 60,
+"accessIPv4" : "67.23.10.132",
+"accessIPv6" : "::babe:67.23.10.132",
+"image" : {
+"id": "52415800-8b69-11e0-9b19-734f6f006e54",
+"links": [
+{
+"rel": "self",
+"href": "http://servers.api.openstack.org/v2/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
+},
+{
+"rel": "bookmark",
+"href": "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
+}
+]
+},
+"flavor" : {
+"id": "52415800-8b69-11e0-9b19-734f216543fd",
+"links": [
+{
+"rel": "self",
+"href": "http://servers.api.openstack.org/v2/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd"
+},
+{
+"rel": "bookmark",
+"href": "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd"
+}
+]
+},
+"addresses": {
+"public" : [
+{
+"version": 4,
+"addr": "67.23.10.132"
+},
+{
+"version": 6,
+"addr": "::babe:67.23.10.132"
+},
+{
+"version": 4,
+"addr": "67.23.10.131"
+},
+{
+"version": 6,
+"addr": "::babe:4317:0A83"
+}
+],
+"private" : [
+{
+"version": 4,
+"addr": "10.176.42.16"
+},
+{
+"version": 6,
+"addr": "::babe:10.176.42.16"
+}
+]
+},
+"metadata": {
+"Server Label": "Web Head 1",
+"Image Version": "2.1"
+},
+"links": [
+{
+"rel": "self",
+"href": "http://servers.api.openstack.org/v2/1234/servers/52415800-8b69-11e0-9b19-734f6af67565"
+},
+{
+"rel": "bookmark",
+"href": "http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734f6af67565"
+}
+]
+},
+{
+"id": "52415800-8b69-11e0-9b19-734f1f1350e5",
+"user_id": "5678",
+"name": "sample-server2",
+"tenant_id": "1234",
+"updated": "2010-10-10T12:00:00Z",
+"created": "2010-08-10T12:00:00Z",
+"hostId": "9e107d9d372bb6826bd81d3542a419d6",
+"status": "ACTIVE",
+"accessIPv4" : "67.23.10.133",
+"accessIPv6" : "::babe:67.23.10.133",
+"image" : {
+"id": "52415800-8b69-11e0-9b19-734f5736d2a2",
+"links": [
+{
+"rel": "self",
+"href": "http://servers.api.openstack.org/v2/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
+},
+{
+"rel": "bookmark",
+"href": "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
+}
+]
+},
+"flavor" : {
+"id": "52415800-8b69-11e0-9b19-734f216543fd",
+"links": [
+{
+"rel": "self",
+"href": "http://servers.api.openstack.org/v2/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd"
+},
+{
+"rel": "bookmark",
+"href": "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd"
+}
+]
+},
+"addresses": {
+"public" : [
+{
+"version": 4,
+"addr": "67.23.10.133"
+},
+{
+"version": 6,
+"addr": "::babe:67.23.10.133"
+}
+],
+"private" : [
+{
+"version": 4,
+"addr": "10.176.42.17"
+},
+{
+"version": 6,
+"addr": "::babe:10.176.42.17"
+}
+]
+},
+"metadata": {
+"Server Label": "DB 1"
+},
+"links": [
+{
+"rel": "self",
+"href": "http://servers.api.openstack.org/v2/1234/servers/52415800-8b69-11e0-9b19-734f1f1350e5"
+},
+{
+"rel": "bookmark",
+"href": "http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734f1f1350e5"
+}
+]
+}
+]
+}`
+
+func TestGetServer(t *testing.T) {
+	var listResults map[string]interface{}
+	err := json.Unmarshal([]byte(goodListServersResult), &listResults)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	svrs, err := GetServers(listResults)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if len(svrs) != 2 {
+		t.Errorf("Expected 2 servers; got %d", len(svrs))
+		return
+	}
+}
+