Compute Limits (#121)
* Compute Limits
This commit adds support for the limits API. It includes the ability
to query limits for the currently scoped user as well as to query the
limits for a specific tenant.
* Clarifying RAM measurement
* Removing ExtractAbsolute. Renaming ExtractLimits to Extract
diff --git a/openstack/compute/v2/extensions/limits/requests.go b/openstack/compute/v2/extensions/limits/requests.go
new file mode 100644
index 0000000..70324b8
--- /dev/null
+++ b/openstack/compute/v2/extensions/limits/requests.go
@@ -0,0 +1,39 @@
+package limits
+
+import (
+ "github.com/gophercloud/gophercloud"
+)
+
+// GetOptsBuilder allows extensions to add additional parameters to the
+// Get request.
+type GetOptsBuilder interface {
+ ToLimitsQuery() (string, error)
+}
+
+// GetOpts enables retrieving limits by a specific tenant.
+type GetOpts struct {
+ // The tenant ID to retrieve limits for
+ TenantID string `q:"tenant_id"`
+}
+
+// ToLimitsQuery formats a GetOpts into a query string.
+func (opts GetOpts) ToLimitsQuery() (string, error) {
+ q, err := gophercloud.BuildQueryString(opts)
+ return q.String(), err
+}
+
+// Get returns the limits about the currently scoped tenant.
+func Get(client *gophercloud.ServiceClient, opts GetOptsBuilder) (r GetResult) {
+ url := getURL(client)
+ if opts != nil {
+ query, err := opts.ToLimitsQuery()
+ if err != nil {
+ r.Err = err
+ return
+ }
+ url += query
+ }
+
+ _, r.Err = client.Get(url, &r.Body, nil)
+ return
+}
diff --git a/openstack/compute/v2/extensions/limits/results.go b/openstack/compute/v2/extensions/limits/results.go
new file mode 100644
index 0000000..95b794d
--- /dev/null
+++ b/openstack/compute/v2/extensions/limits/results.go
@@ -0,0 +1,90 @@
+package limits
+
+import (
+ "github.com/gophercloud/gophercloud"
+)
+
+// Limits is a struct that contains the response of a limit query.
+type Limits struct {
+ // Absolute contains the limits and usage information.
+ Absolute Absolute `json:"absolute"`
+}
+
+// Usage is a struct that contains the current resource usage and limits
+// of a tenant.
+type Absolute struct {
+ // MaxTotalCores is the number of cores available to a tenant.
+ MaxTotalCores int `json:"maxTotalCores"`
+
+ // MaxImageMeta is the amount of image metadata available to a tenant.
+ MaxImageMeta int `json:"maxImageMeta"`
+
+ // MaxServerMeta is the amount of server metadata available to a tenant.
+ MaxServerMeta int `json:"maxServerMeta"`
+
+ // MaxPersonality is the amount of personality/files available to a tenant.
+ MaxPersonality int `json:"maxPersonality"`
+
+ // MaxPersonalitySize is the personality file size available to a tenant.
+ MaxPersonalitySize int `json:"maxPersonalitySize"`
+
+ // MaxTotalKeypairs is the total keypairs available to a tenant.
+ MaxTotalKeypairs int `json:maxTotalKeypairs"`
+
+ // MaxSecurityGroups is the number of security groups available to a tenant.
+ MaxSecurityGroups int `json:"maxSecurityGroups"`
+
+ // MaxSecurityGroupRules is the number of security group rules available to
+ // a tenant.
+ MaxSecurityGroupRules int `json:"maxSecurityGroupRules"`
+
+ // MaxServerGroups is the number of server groups available to a tenant.
+ MaxServerGroups int `json:"maxServerGroups"`
+
+ // MaxServerGroupMembers is the number of server group members available
+ // to a tenant.
+ MaxServerGroupMembers int `json:"maxServerGroupMembers"`
+
+ // MaxTotalFloatingIps is the number of floating IPs available to a tenant.
+ MaxTotalFloatingIps int `json:"maxTotalFloatingIps"`
+
+ // MaxTotalInstances is the number of instances/servers available to a tenant.
+ MaxTotalInstances int `json:"maxTotalInstances"`
+
+ // MaxTotalRAMSize is the total amount of RAM available to a tenant measured
+ // in megabytes (MB).
+ MaxTotalRAMSize int `json:"maxTotalRAMSize"`
+
+ // TotalCoresUsed is the number of cores currently in use.
+ TotalCoresUsed int `json:"totalCoresUsed"`
+
+ // TotalInstancesUsed is the number of instances/servers in use.
+ TotalInstancesUsed int `json:"totalInstancesUsed"`
+
+ // TotalFloatingIpsUsed is the number of floating IPs in use.
+ TotalFloatingIpsUsed int `json:"totalFloatingIpsUsed"`
+
+ // TotalRAMUsed is the total RAM/memory in use measured in megabytes (MB).
+ TotalRAMUsed int `json:"totalRAMUsed"`
+
+ // TotalSecurityGroupsUsed is the total number of security groups in use.
+ TotalSecurityGroupsUsed int `json:"totalSecurityGroupsUsed"`
+
+ // TotalServerGroupsUsed is the total number of server groups in use.
+ TotalServerGroupsUsed int `json:"totalServerGroupsUsed"`
+}
+
+// Extract interprets a limits result as a Limits.
+func (r GetResult) Extract() (*Limits, error) {
+ var s struct {
+ Limits *Limits `json:"limits"`
+ }
+ err := r.ExtractInto(&s)
+ return s.Limits, err
+}
+
+// GetResult is the response from a Get operation. Call its ExtractAbsolute
+// method to interpret it as an Absolute.
+type GetResult struct {
+ gophercloud.Result
+}
diff --git a/openstack/compute/v2/extensions/limits/testing/fixtures.go b/openstack/compute/v2/extensions/limits/testing/fixtures.go
new file mode 100644
index 0000000..9ec24a9
--- /dev/null
+++ b/openstack/compute/v2/extensions/limits/testing/fixtures.go
@@ -0,0 +1,80 @@
+package testing
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/limits"
+ th "github.com/gophercloud/gophercloud/testhelper"
+ "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+// GetOutput is a sample response to a Get call.
+const GetOutput = `
+{
+ "limits": {
+ "rate": [],
+ "absolute": {
+ "maxServerMeta": 128,
+ "maxPersonality": 5,
+ "totalServerGroupsUsed": 0,
+ "maxImageMeta": 128,
+ "maxPersonalitySize": 10240,
+ "maxTotalKeypairs": 100,
+ "maxSecurityGroupRules": 20,
+ "maxServerGroups": 10,
+ "totalCoresUsed": 1,
+ "totalRAMUsed": 2048,
+ "totalInstancesUsed": 1,
+ "maxSecurityGroups": 10,
+ "totalFloatingIpsUsed": 0,
+ "maxTotalCores": 20,
+ "maxServerGroupMembers": 10,
+ "maxTotalFloatingIps": 10,
+ "totalSecurityGroupsUsed": 1,
+ "maxTotalInstances": 10,
+ "maxTotalRAMSize": 51200
+ }
+ }
+}
+`
+
+// LimitsResult is the result of the limits in GetOutput.
+var LimitsResult = limits.Limits{
+ limits.Absolute{
+ MaxServerMeta: 128,
+ MaxPersonality: 5,
+ TotalServerGroupsUsed: 0,
+ MaxImageMeta: 128,
+ MaxPersonalitySize: 10240,
+ MaxTotalKeypairs: 100,
+ MaxSecurityGroupRules: 20,
+ MaxServerGroups: 10,
+ TotalCoresUsed: 1,
+ TotalRAMUsed: 2048,
+ TotalInstancesUsed: 1,
+ MaxSecurityGroups: 10,
+ TotalFloatingIpsUsed: 0,
+ MaxTotalCores: 20,
+ MaxServerGroupMembers: 10,
+ MaxTotalFloatingIps: 10,
+ TotalSecurityGroupsUsed: 1,
+ MaxTotalInstances: 10,
+ MaxTotalRAMSize: 51200,
+ },
+}
+
+const TenantID = "555544443333222211110000ffffeeee"
+
+// HandleGetSuccessfully configures the test server to respond to a Get request
+// for a limit.
+func HandleGetSuccessfully(t *testing.T) {
+ th.Mux.HandleFunc("/limits", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ fmt.Fprintf(w, GetOutput)
+ })
+}
diff --git a/openstack/compute/v2/extensions/limits/testing/requests_test.go b/openstack/compute/v2/extensions/limits/testing/requests_test.go
new file mode 100644
index 0000000..9c8456c
--- /dev/null
+++ b/openstack/compute/v2/extensions/limits/testing/requests_test.go
@@ -0,0 +1,23 @@
+package testing
+
+import (
+ "testing"
+
+ "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/limits"
+ th "github.com/gophercloud/gophercloud/testhelper"
+ "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+func TestGet(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleGetSuccessfully(t)
+
+ getOpts := limits.GetOpts{
+ TenantID: TenantID,
+ }
+
+ actual, err := limits.Get(client.ServiceClient(), getOpts).Extract()
+ th.AssertNoErr(t, err)
+ th.CheckDeepEquals(t, &LimitsResult, actual)
+}
diff --git a/openstack/compute/v2/extensions/limits/urls.go b/openstack/compute/v2/extensions/limits/urls.go
new file mode 100644
index 0000000..edd97e4
--- /dev/null
+++ b/openstack/compute/v2/extensions/limits/urls.go
@@ -0,0 +1,11 @@
+package limits
+
+import (
+ "github.com/gophercloud/gophercloud"
+)
+
+const resourcePath = "limits"
+
+func getURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL(resourcePath)
+}