Feature/filestorage sharetype getextraspecs (#146)

* sfs: Add support for share type Get Extra Specs

* sfs: Add acceptance tests for share type Get Extra Specs

* sfs: Fix comments
diff --git a/acceptance/openstack/sharedfilesystems/v2/sharetypes_test.go b/acceptance/openstack/sharedfilesystems/v2/sharetypes_test.go
index 8784764..e29e484 100644
--- a/acceptance/openstack/sharedfilesystems/v2/sharetypes_test.go
+++ b/acceptance/openstack/sharedfilesystems/v2/sharetypes_test.go
@@ -61,3 +61,28 @@
 
 	PrintShareType(t, shareType)
 }
+
+func TestShareTypeExtraSpecs(t *testing.T) {
+	client, err := clients.NewSharedFileSystemV2Client()
+	if err != nil {
+		t.Fatalf("Unable to create shared file system client: %v", err)
+	}
+
+	shareType, err := CreateShareType(t, client)
+	if err != nil {
+		t.Fatalf("Unable to create share type: %v", err)
+	}
+
+	extraSpecs, err := sharetypes.GetExtraSpecs(client, shareType.ID).Extract()
+	if err != nil {
+		t.Fatalf("Unable to retrieve share type: %s", shareType.Name)
+	}
+
+	if extraSpecs["driver_handles_share_servers"] != "True" {
+		t.Fatal("driver_handles_share_servers was expected to be true")
+	}
+
+	PrintShareType(t, shareType)
+
+	defer DeleteShareType(t, client, shareType)
+}
diff --git a/openstack/sharedfilesystems/v2/sharetypes/requests.go b/openstack/sharedfilesystems/v2/sharetypes/requests.go
index 38174fe..94f84b6 100644
--- a/openstack/sharedfilesystems/v2/sharetypes/requests.go
+++ b/openstack/sharedfilesystems/v2/sharetypes/requests.go
@@ -98,3 +98,9 @@
 	_, r.Err = client.Get(getDefaultURL(client), &r.Body, nil)
 	return
 }
+
+// GetExtraSpecs will retrieve the extra specifications for a given ShareType.
+func GetExtraSpecs(client *gophercloud.ServiceClient, id string) (r GetExtraSpecsResult) {
+	_, r.Err = client.Get(getExtraSpecsURL(client, id), &r.Body, nil)
+	return
+}
diff --git a/openstack/sharedfilesystems/v2/sharetypes/results.go b/openstack/sharedfilesystems/v2/sharetypes/results.go
index fa3a4e1..f4de532 100644
--- a/openstack/sharedfilesystems/v2/sharetypes/results.go
+++ b/openstack/sharedfilesystems/v2/sharetypes/results.go
@@ -68,3 +68,25 @@
 type GetDefaultResult struct {
 	commonResult
 }
+
+// ExtraSpecs contains all the information associated with extra specifications
+// for an Openstack ShareType.
+type ExtraSpecs map[string]interface{}
+
+type extraSpecsResult struct {
+	gophercloud.Result
+}
+
+// Extract will get the ExtraSpecs object out of the commonResult object.
+func (r extraSpecsResult) Extract() (ExtraSpecs, error) {
+	var s struct {
+		Specs ExtraSpecs `json:"extra_specs"`
+	}
+	err := r.ExtractInto(&s)
+	return s.Specs, err
+}
+
+// GetExtraSpecsResult contains the response body and error from a Get Extra Specs request.
+type GetExtraSpecsResult struct {
+	extraSpecsResult
+}
diff --git a/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures.go b/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures.go
index 58d9bb3..1666d11 100644
--- a/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures.go
+++ b/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures.go
@@ -164,3 +164,21 @@
         }`)
 	})
 }
+
+func MockGetExtraSpecsResponse(t *testing.T) {
+	th.Mux.HandleFunc("/types/shareTypeID/extra_specs", 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, `
+        {
+            "extra_specs": {
+                "snapshot_support": "True",
+                "driver_handles_share_servers": "True",
+				"my_custom_extra_spec": "False"
+            }
+        }`)
+	})
+}
diff --git a/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go b/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go
index 0518c02..ad1ad15 100644
--- a/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go
+++ b/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go
@@ -119,3 +119,18 @@
 	th.AssertNoErr(t, err)
 	th.CheckDeepEquals(t, &expected, actual)
 }
+
+// Verifies that it is possible to get the extra specifications for a share type
+func TestGetExtraSpecs(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	MockGetExtraSpecsResponse(t)
+
+	st, err := sharetypes.GetExtraSpecs(client.ServiceClient(), "shareTypeID").Extract()
+	th.AssertNoErr(t, err)
+
+	th.AssertEquals(t, st["snapshot_support"], "True")
+	th.AssertEquals(t, st["driver_handles_share_servers"], "True")
+	th.AssertEquals(t, st["my_custom_extra_spec"], "False")
+}
diff --git a/openstack/sharedfilesystems/v2/sharetypes/urls.go b/openstack/sharedfilesystems/v2/sharetypes/urls.go
index 7b1d2ca..ecd159e 100644
--- a/openstack/sharedfilesystems/v2/sharetypes/urls.go
+++ b/openstack/sharedfilesystems/v2/sharetypes/urls.go
@@ -17,3 +17,7 @@
 func getDefaultURL(c *gophercloud.ServiceClient) string {
 	return c.ServiceURL("types", "default")
 }
+
+func getExtraSpecsURL(c *gophercloud.ServiceClient, id string) string {
+	return c.ServiceURL("types", id, "extra_specs")
+}