Add images resource
diff --git a/acceptance/openstack/compute/02-images.go b/acceptance/openstack/compute/02-images.go
new file mode 100644
index 0000000..e88556c
--- /dev/null
+++ b/acceptance/openstack/compute/02-images.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "github.com/rackspace/gophercloud/openstack/compute/images"
+ "github.com/rackspace/gophercloud/openstack/identity"
+ "github.com/rackspace/gophercloud/openstack/utils"
+ "text/tabwriter"
+)
+
+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)
+ }
+
+ eps, err := findAllComputeEndpoints(sc)
+ if err != nil {
+ panic(err)
+ }
+
+ w := new(tabwriter.Writer)
+ w.Init(os.Stdout, 2, 8, 2, ' ', 0)
+ fmt.Fprintln(w, "ID\tRegion\tName\tStatus\tCreated\t")
+
+ region := os.Getenv("OS_REGION_NAME")
+ n := 0
+ for _, ep := range eps {
+ client := images.NewClient(ep.PublicURL, a, ao)
+
+ if (region != "") && (region != ep.Region) {
+ continue
+ }
+
+ listResults, err := images.List(client)
+ if err != nil {
+ panic(err)
+ }
+
+ imgs, err := images.GetImages(listResults)
+ if err != nil {
+ panic(err)
+ }
+
+ n = n + len(imgs)
+
+ for _, i := range imgs {
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", i.Id, ep.Region, i.Name, i.Status, i.Created)
+ }
+ }
+ w.Flush()
+ fmt.Printf("--------\n%d images listed.\n", n)
+}
+
+
+func findAllComputeEndpoints(sc *identity.ServiceCatalog) ([]identity.Endpoint, error) {
+ ces, err := sc.CatalogEntries()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ce := range ces {
+ if ce.Type == "compute" {
+ return ce.Endpoints, nil
+ }
+ }
+
+ return nil, fmt.Errorf("Compute endpoint not found.")
+}
+
diff --git a/openstack/compute/images/client.go b/openstack/compute/images/client.go
new file mode 100644
index 0000000..a7466bb
--- /dev/null
+++ b/openstack/compute/images/client.go
@@ -0,0 +1,35 @@
+package images
+
+import (
+ "github.com/rackspace/gophercloud/openstack/identity"
+)
+
+type Client struct {
+ endpoint string
+ authority identity.AuthResults
+ options identity.AuthOptions
+}
+
+func NewClient(e string, a identity.AuthResults, ao identity.AuthOptions) *Client {
+ return &Client{
+ endpoint: e,
+ authority: a,
+ options: ao,
+ }
+}
+
+func (c *Client) getListUrl() string {
+ return c.endpoint + "/images/detail"
+}
+
+func (c *Client) getListHeaders() (map[string]string, error) {
+ t, err := identity.GetToken(c.authority)
+ if err != nil {
+ return map[string]string{}, err
+ }
+
+ return map[string]string{
+ "X-Auth-Token": t.Id,
+ }, nil
+}
+
diff --git a/openstack/compute/images/images.go b/openstack/compute/images/images.go
new file mode 100644
index 0000000..d53edce
--- /dev/null
+++ b/openstack/compute/images/images.go
@@ -0,0 +1,47 @@
+package images
+
+import "github.com/mitchellh/mapstructure"
+
+// Image is used for JSON (un)marshalling.
+// It provides a description of an OS image.
+//
+// The Id field contains the image's unique identifier.
+// For example, this identifier will be useful for specifying which operating system to install on a new server instance.
+//
+// The MinDisk and MinRam fields specify the minimum resources a server must provide to be able to install the image.
+//
+// The Name field provides a human-readable moniker for the OS image.
+//
+// The Progress and Status fields indicate image-creation status.
+// Any usable image will have 100% progress.
+//
+// The Updated field indicates the last time this image was changed.
+type Image struct {
+ Created string
+ Id string
+ MinDisk int
+ MinRam int
+ Name string
+ Progress int
+ Status string
+ Updated string
+}
+
+func GetImages(lr ListResults) ([]Image, error) {
+ ia, ok := lr["images"]
+ if !ok {
+ return nil, ErrNotImplemented
+ }
+ ims := ia.([]interface{})
+
+ images := make([]Image, len(ims))
+ for i, im := range ims {
+ imageObj := im.(map[string]interface{})
+ err := mapstructure.Decode(imageObj, &images[i])
+ if err != nil {
+ return images, err
+ }
+ }
+ return images, nil
+}
+
diff --git a/openstack/compute/images/requests.go b/openstack/compute/images/requests.go
new file mode 100644
index 0000000..2aa4723
--- /dev/null
+++ b/openstack/compute/images/requests.go
@@ -0,0 +1,27 @@
+package images
+
+import (
+ "fmt"
+ "github.com/racker/perigee"
+)
+
+
+var ErrNotImplemented = fmt.Errorf("Images functionality not implemented.")
+
+type ListResults map[string]interface{}
+
+func List(c *Client) (ListResults, error) {
+ var lr ListResults
+
+ h, err := c.getListHeaders()
+ if err != nil {
+ return nil, err
+ }
+
+ err = perigee.Get(c.getListUrl(), perigee.Options{
+ Results: &lr,
+ MoreHeaders: h,
+ })
+ return lr, err
+}
+