Feature/filestorage availabilityzones list (#153)

* sfs: Add support for Availability Zone List

* sfs: Add acceptance tests for Availability zones List

* sfs: Fix review comments
diff --git a/openstack/sharedfilesystems/v2/availabilityzones/requests.go b/openstack/sharedfilesystems/v2/availabilityzones/requests.go
new file mode 100644
index 0000000..df10b85
--- /dev/null
+++ b/openstack/sharedfilesystems/v2/availabilityzones/requests.go
@@ -0,0 +1,13 @@
+package availabilityzones
+
+import (
+	"github.com/gophercloud/gophercloud"
+	"github.com/gophercloud/gophercloud/pagination"
+)
+
+// List will return the existing availability zones.
+func List(client *gophercloud.ServiceClient) pagination.Pager {
+	return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
+		return AvailabilityZonePage{pagination.SinglePageBase(r)}
+	})
+}
diff --git a/openstack/sharedfilesystems/v2/availabilityzones/results.go b/openstack/sharedfilesystems/v2/availabilityzones/results.go
new file mode 100644
index 0000000..83a76c1
--- /dev/null
+++ b/openstack/sharedfilesystems/v2/availabilityzones/results.go
@@ -0,0 +1,59 @@
+package availabilityzones
+
+import (
+	"encoding/json"
+	"time"
+
+	"github.com/gophercloud/gophercloud"
+	"github.com/gophercloud/gophercloud/pagination"
+)
+
+// AvailabilityZone contains all the information associated with an OpenStack
+// AvailabilityZone.
+type AvailabilityZone struct {
+	// The availability zone ID.
+	ID string `json:"id"`
+	// The name of the availability zone.
+	Name string `json:"name"`
+	// The date and time stamp when the availability zone was created.
+	CreatedAt time.Time `json:"-"`
+	// The date and time stamp when the availability zone was updated.
+	UpdatedAt time.Time `json:"-"`
+}
+
+type commonResult struct {
+	gophercloud.Result
+}
+
+// ListResult contains the response body and error from a List request.
+type AvailabilityZonePage struct {
+	pagination.SinglePageBase
+}
+
+// ExtractAvailabilityZones will get the AvailabilityZone objects out of the shareTypeAccessResult object.
+func ExtractAvailabilityZones(r pagination.Page) ([]AvailabilityZone, error) {
+	var a struct {
+		AvailabilityZone []AvailabilityZone `json:"availability_zones"`
+	}
+	err := (r.(AvailabilityZonePage)).ExtractInto(&a)
+	return a.AvailabilityZone, err
+}
+
+func (r *AvailabilityZone) UnmarshalJSON(b []byte) error {
+	type tmp AvailabilityZone
+	var s struct {
+		tmp
+		CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
+		UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"`
+	}
+	err := json.Unmarshal(b, &s)
+	if err != nil {
+		return err
+	}
+	*r = AvailabilityZone(s.tmp)
+
+	r.CreatedAt = time.Time(s.CreatedAt)
+	r.UpdatedAt = time.Time(s.UpdatedAt)
+
+	return nil
+}
diff --git a/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures.go b/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures.go
new file mode 100644
index 0000000..e5db8cd
--- /dev/null
+++ b/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures.go
@@ -0,0 +1,32 @@
+package testing
+
+import (
+	"fmt"
+	"net/http"
+	"testing"
+
+	th "github.com/gophercloud/gophercloud/testhelper"
+	fake "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+func MockListResponse(t *testing.T) {
+	th.Mux.HandleFunc("/os-availability-zone", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+        {
+            "availability_zones": [
+                {
+                    "name": "nova",
+                    "created_at": "2015-09-18T09:50:55.000000",
+                    "updated_at": null,
+                    "id": "388c983d-258e-4a0e-b1ba-10da37d766db"
+                }
+            ]
+        }`)
+	})
+}
diff --git a/openstack/sharedfilesystems/v2/availabilityzones/testing/requests_test.go b/openstack/sharedfilesystems/v2/availabilityzones/testing/requests_test.go
new file mode 100644
index 0000000..76c8574
--- /dev/null
+++ b/openstack/sharedfilesystems/v2/availabilityzones/testing/requests_test.go
@@ -0,0 +1,34 @@
+package testing
+
+import (
+	"testing"
+	"time"
+
+	"github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/availabilityzones"
+	th "github.com/gophercloud/gophercloud/testhelper"
+	"github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+// Verifies that availability zones can be listed correctly
+func TestList(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	MockListResponse(t)
+
+	allPages, err := availabilityzones.List(client.ServiceClient()).AllPages()
+	th.AssertNoErr(t, err)
+	actual, err := availabilityzones.ExtractAvailabilityZones(allPages)
+	th.AssertNoErr(t, err)
+	var nilTime time.Time
+	expected := []availabilityzones.AvailabilityZone{
+		{
+			Name:      "nova",
+			CreatedAt: time.Date(2015, 9, 18, 9, 50, 55, 0, time.UTC),
+			UpdatedAt: nilTime,
+			ID:        "388c983d-258e-4a0e-b1ba-10da37d766db",
+		},
+	}
+
+	th.CheckDeepEquals(t, expected, actual)
+}
diff --git a/openstack/sharedfilesystems/v2/availabilityzones/urls.go b/openstack/sharedfilesystems/v2/availabilityzones/urls.go
new file mode 100644
index 0000000..fb4cdcf
--- /dev/null
+++ b/openstack/sharedfilesystems/v2/availabilityzones/urls.go
@@ -0,0 +1,7 @@
+package availabilityzones
+
+import "github.com/gophercloud/gophercloud"
+
+func listURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL("os-availability-zone")
+}