Adding quotas operations
diff --git a/openstack/networking/v2/extensions/quotas/requests.go b/openstack/networking/v2/extensions/quotas/requests.go
index d03c081..f16c440 100755
--- a/openstack/networking/v2/extensions/quotas/requests.go
+++ b/openstack/networking/v2/extensions/quotas/requests.go
@@ -1 +1,85 @@
 package quotas
+
+import (
+	"github.com/racker/perigee"
+	"github.com/rackspace/gophercloud"
+)
+
+func Get(c *gophercloud.ServiceClient) GetResult {
+	var res GetResult
+	_, err := perigee.Request("GET", rootURL(c), perigee.Options{
+		Results:     &res.resp,
+		MoreHeaders: c.Provider.AuthenticatedHeaders(),
+	})
+	res.err = err
+	return res
+}
+
+type UpdateOpts struct {
+	Subnet        *int
+	Router        *int
+	Network       *int
+	FloatingIP    *int
+	Port          *int
+	HealthMonitor *int
+	SecGroupRule  *int
+	SecGroup      *int
+	VIP           *int
+	Member        *int
+	Pool          *int
+}
+
+func Update(c *gophercloud.ServiceClient, opts UpdateOpts) UpdateResult {
+	type quota struct {
+		Subnet        *int `json:"subnet,omitempty"`
+		Router        *int `json:"router,omitempty"`
+		Network       *int `json:"network,omitempty"`
+		FloatingIP    *int `json:"floatingip,omitempty"`
+		Port          *int `json:"port,omitempty"`
+		HealthMonitor *int `json:"health_monitor,omitempty"`
+		SecGroupRule  *int `json:"security_group_rule,omitempty"`
+		VIP           *int `json:"vip,omitempty"`
+		SecGroup      *int `json:"security_group,omitempty"`
+		Member        *int `json:"member,omitempty"`
+		Pool          *int `json:"pool,omitempty"`
+	}
+
+	type request struct {
+		Quota quota `json:"quota"`
+	}
+
+	reqBody := request{Quota: quota{
+		Subnet:        opts.Subnet,
+		Router:        opts.Router,
+		Network:       opts.Network,
+		FloatingIP:    opts.FloatingIP,
+		Port:          opts.Port,
+		HealthMonitor: opts.HealthMonitor,
+		SecGroupRule:  opts.SecGroupRule,
+		VIP:           opts.VIP,
+		SecGroup:      opts.SecGroup,
+		Member:        opts.Member,
+		Pool:          opts.Pool,
+	}}
+
+	var res UpdateResult
+	_, err := perigee.Request("PUT", rootURL(c), perigee.Options{
+		MoreHeaders: c.Provider.AuthenticatedHeaders(),
+		ReqBody:     &reqBody,
+		Results:     &res.resp,
+		OkCodes:     []int{200},
+	})
+	res.err = err
+
+	return res
+}
+
+func Reset(c *gophercloud.ServiceClient) DeleteResult {
+	var res DeleteResult
+	_, err := perigee.Request("DELETE", rootURL(c), perigee.Options{
+		MoreHeaders: c.Provider.AuthenticatedHeaders(),
+		OkCodes:     []int{204},
+	})
+	res.err = err
+	return res
+}
diff --git a/openstack/networking/v2/extensions/quotas/requests_test.go b/openstack/networking/v2/extensions/quotas/requests_test.go
index 16c7def..1157c49 100755
--- a/openstack/networking/v2/extensions/quotas/requests_test.go
+++ b/openstack/networking/v2/extensions/quotas/requests_test.go
@@ -1,15 +1,116 @@
 package quotas
 
-import "testing"
+import (
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/rackspace/gophercloud"
+	th "github.com/rackspace/gophercloud/testhelper"
+)
+
+const tokenID = "123"
+
+func serviceClient() *gophercloud.ServiceClient {
+	return &gophercloud.ServiceClient{
+		Provider: &gophercloud.ProviderClient{TokenID: tokenID},
+		Endpoint: th.Endpoint(),
+	}
+}
 
 func TestGet(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
+	th.Mux.HandleFunc("/v2.0/quotas", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+    "quota": {
+        "subnet": 10,
+        "router": 10,
+        "port": 50,
+        "network": 10,
+        "floatingip": 50
+    }
+}
+      `)
+	})
+
+	qs, err := Get(serviceClient()).Extract()
+	th.AssertNoErr(t, err)
+
+	th.AssertEquals(t, qs.Subnet, 10)
+	th.AssertEquals(t, qs.Router, 10)
+	th.AssertEquals(t, qs.Port, 50)
+	th.AssertEquals(t, qs.Network, 10)
+	th.AssertEquals(t, qs.FloatingIP, 50)
 }
 
 func TestUpdate(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
+	th.Mux.HandleFunc("/v2.0/quotas", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PUT")
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
+		th.TestHeader(t, r, "Content-Type", "application/json")
+		th.TestHeader(t, r, "Accept", "application/json")
+		th.TestJSONRequest(t, r, `
+{
+    "quota": {
+        "subnet": 40,
+        "router": 40,
+        "network": 10,
+        "floatingip": 30,
+        "port": 30
+    }
+}
+			`)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+    "quota": {
+        "subnet": 40,
+        "router": 40,
+        "network": 10,
+        "floatingip": 30,
+        "port": 30
+    }
+}
+    `)
+	})
+
+	i10, i30, i40 := 10, 30, 40
+	opts := UpdateOpts{Subnet: &i40, Router: &i40, Network: &i10, FloatingIP: &i30, Port: &i30}
+	qs, err := Update(serviceClient(), opts).Extract()
+	th.AssertNoErr(t, err)
+
+	th.AssertEquals(t, qs.Subnet, 40)
+	th.AssertEquals(t, qs.Router, 40)
+	th.AssertEquals(t, qs.Port, 30)
+	th.AssertEquals(t, qs.Network, 10)
+	th.AssertEquals(t, qs.FloatingIP, 30)
 }
 
 func TestReset(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
 
+	th.Mux.HandleFunc("/v2.0/quotas", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "DELETE")
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	res := Reset(serviceClient())
+	th.AssertNoErr(t, res.err)
 }
diff --git a/openstack/networking/v2/extensions/quotas/results.go b/openstack/networking/v2/extensions/quotas/results.go
index d03c081..5c73e57 100755
--- a/openstack/networking/v2/extensions/quotas/results.go
+++ b/openstack/networking/v2/extensions/quotas/results.go
@@ -1 +1,62 @@
 package quotas
+
+import (
+	"fmt"
+
+	"github.com/mitchellh/mapstructure"
+)
+
+type Quota struct {
+	Subnet     int `json:"subnet"`
+	Router     int `json:"router"`
+	Port       int `json:"port"`
+	Network    int `json:"network"`
+	FloatingIP int `json:"floatingip"`
+}
+
+type commonResult struct {
+	resp map[string]interface{}
+	err  error
+}
+
+type GetResult commonResult
+
+func (r GetResult) Extract() (*Quota, error) {
+	if r.err != nil {
+		return nil, r.err
+	}
+
+	var res struct {
+		Quota *Quota `json:"quota"`
+	}
+
+	err := mapstructure.Decode(r.resp, &res)
+	if err != nil {
+		return nil, fmt.Errorf("Error decoding Neutron quotas: %v", err)
+	}
+
+	return res.Quota, nil
+}
+
+type UpdateResult struct {
+	commonResult
+}
+
+func (r UpdateResult) Extract() (*Quota, error) {
+	if r.err != nil {
+		return nil, r.err
+	}
+
+	var res struct {
+		Quota *Quota `json:"quota"`
+	}
+
+	err := mapstructure.Decode(r.resp, &res)
+	if err != nil {
+		return nil, fmt.Errorf("Error decoding Neutron quotas: %v", err)
+	}
+
+	return res.Quota, nil
+}
+
+type DeleteResult commonResult
diff --git a/openstack/networking/v2/extensions/quotas/urls.go b/openstack/networking/v2/extensions/quotas/urls.go
index d03c081..a933a7d 100755
--- a/openstack/networking/v2/extensions/quotas/urls.go
+++ b/openstack/networking/v2/extensions/quotas/urls.go
@@ -1 +1,9 @@
 package quotas
+
+import "github.com/rackspace/gophercloud"
+
+const version = "v2.0"
+
+func rootURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL(version, "quotas")
+}
diff --git a/openstack/networking/v2/extensions/quotas/urls_tests.go b/openstack/networking/v2/extensions/quotas/urls_tests.go
index d03c081..e75ff1b 100755
--- a/openstack/networking/v2/extensions/quotas/urls_tests.go
+++ b/openstack/networking/v2/extensions/quotas/urls_tests.go
@@ -1 +1,20 @@
 package quotas
+
+import (
+	"testing"
+
+	"github.com/rackspace/gophercloud"
+	th "github.com/rackspace/gophercloud/testhelper"
+)
+
+const endpoint = "http://localhost:57909/"
+
+func endpointClient() *gophercloud.ServiceClient {
+	return &gophercloud.ServiceClient{Endpoint: endpoint}
+}
+
+func TestRootURL(t *testing.T) {
+	expected := endpoint + "v2.0/quotas"
+	actual := rootURL(endpointClient())
+	th.AssertEquals(t, expected, actual)
+}