1package cfclient
2
3import (
4	"bytes"
5	"encoding/json"
6	"fmt"
7	"io/ioutil"
8	"net/http"
9	"net/url"
10
11	"github.com/pkg/errors"
12)
13
14type OrgQuotasResponse struct {
15	Count     int                 `json:"total_results"`
16	Pages     int                 `json:"total_pages"`
17	NextUrl   string              `json:"next_url"`
18	Resources []OrgQuotasResource `json:"resources"`
19}
20
21type OrgQuotasResource struct {
22	Meta   Meta     `json:"metadata"`
23	Entity OrgQuota `json:"entity"`
24}
25
26type OrgQuotaRequest struct {
27	Name                    string `json:"name"`
28	NonBasicServicesAllowed bool   `json:"non_basic_services_allowed"`
29	TotalServices           int    `json:"total_services"`
30	TotalRoutes             int    `json:"total_routes"`
31	TotalPrivateDomains     int    `json:"total_private_domains"`
32	MemoryLimit             int    `json:"memory_limit"`
33	TrialDBAllowed          bool   `json:"trial_db_allowed"`
34	InstanceMemoryLimit     int    `json:"instance_memory_limit"`
35	AppInstanceLimit        int    `json:"app_instance_limit"`
36	AppTaskLimit            int    `json:"app_task_limit"`
37	TotalServiceKeys        int    `json:"total_service_keys"`
38	TotalReservedRoutePorts int    `json:"total_reserved_route_ports"`
39}
40
41type OrgQuota struct {
42	Guid                    string `json:"guid"`
43	Name                    string `json:"name"`
44	CreatedAt               string `json:"created_at,omitempty"`
45	UpdatedAt               string `json:"updated_at,omitempty"`
46	NonBasicServicesAllowed bool   `json:"non_basic_services_allowed"`
47	TotalServices           int    `json:"total_services"`
48	TotalRoutes             int    `json:"total_routes"`
49	TotalPrivateDomains     int    `json:"total_private_domains"`
50	MemoryLimit             int    `json:"memory_limit"`
51	TrialDBAllowed          bool   `json:"trial_db_allowed"`
52	InstanceMemoryLimit     int    `json:"instance_memory_limit"`
53	AppInstanceLimit        int    `json:"app_instance_limit"`
54	AppTaskLimit            int    `json:"app_task_limit"`
55	TotalServiceKeys        int    `json:"total_service_keys"`
56	TotalReservedRoutePorts int    `json:"total_reserved_route_ports"`
57	c                       *Client
58}
59
60func (c *Client) ListOrgQuotasByQuery(query url.Values) ([]OrgQuota, error) {
61	var orgQuotas []OrgQuota
62	requestUrl := "/v2/quota_definitions?" + query.Encode()
63	for {
64		orgQuotasResp, err := c.getOrgQuotasResponse(requestUrl)
65		if err != nil {
66			return []OrgQuota{}, err
67		}
68		for _, org := range orgQuotasResp.Resources {
69			org.Entity.Guid = org.Meta.Guid
70			org.Entity.CreatedAt = org.Meta.CreatedAt
71			org.Entity.UpdatedAt = org.Meta.UpdatedAt
72			org.Entity.c = c
73			orgQuotas = append(orgQuotas, org.Entity)
74		}
75		requestUrl = orgQuotasResp.NextUrl
76		if requestUrl == "" {
77			break
78		}
79	}
80	return orgQuotas, nil
81}
82
83func (c *Client) ListOrgQuotas() ([]OrgQuota, error) {
84	return c.ListOrgQuotasByQuery(nil)
85}
86
87func (c *Client) GetOrgQuotaByName(name string) (OrgQuota, error) {
88	q := url.Values{}
89	q.Set("q", "name:"+name)
90	orgQuotas, err := c.ListOrgQuotasByQuery(q)
91	if err != nil {
92		return OrgQuota{}, err
93	}
94	if len(orgQuotas) != 1 {
95		return OrgQuota{}, fmt.Errorf("Unable to find org quota " + name)
96	}
97	return orgQuotas[0], nil
98}
99
100func (c *Client) getOrgQuotasResponse(requestUrl string) (OrgQuotasResponse, error) {
101	var orgQuotasResp OrgQuotasResponse
102	r := c.NewRequest("GET", requestUrl)
103	resp, err := c.DoRequest(r)
104	if err != nil {
105		return OrgQuotasResponse{}, errors.Wrap(err, "Error requesting org quotas")
106	}
107	resBody, err := ioutil.ReadAll(resp.Body)
108	defer resp.Body.Close()
109	if err != nil {
110		return OrgQuotasResponse{}, errors.Wrap(err, "Error reading org quotas body")
111	}
112	err = json.Unmarshal(resBody, &orgQuotasResp)
113	if err != nil {
114		return OrgQuotasResponse{}, errors.Wrap(err, "Error unmarshalling org quotas")
115	}
116	return orgQuotasResp, nil
117}
118
119func (c *Client) CreateOrgQuota(orgQuote OrgQuotaRequest) (*OrgQuota, error) {
120	buf := bytes.NewBuffer(nil)
121	err := json.NewEncoder(buf).Encode(orgQuote)
122	if err != nil {
123		return nil, err
124	}
125	r := c.NewRequestWithBody("POST", "/v2/quota_definitions", buf)
126	resp, err := c.DoRequest(r)
127	if err != nil {
128		return nil, err
129	}
130	if resp.StatusCode != http.StatusCreated {
131		return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
132	}
133	return c.handleOrgQuotaResp(resp)
134}
135
136func (c *Client) UpdateOrgQuota(orgQuotaGUID string, orgQuota OrgQuotaRequest) (*OrgQuota, error) {
137	buf := bytes.NewBuffer(nil)
138	err := json.NewEncoder(buf).Encode(orgQuota)
139	if err != nil {
140		return nil, err
141	}
142	r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/quota_definitions/%s", orgQuotaGUID), buf)
143	resp, err := c.DoRequest(r)
144	if err != nil {
145		return nil, err
146	}
147	if resp.StatusCode != http.StatusCreated {
148		return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
149	}
150	return c.handleOrgQuotaResp(resp)
151}
152
153func (c *Client) DeleteOrgQuota(guid string, async bool) error {
154	resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/quota_definitions/%s?async=%t", guid, async)))
155	if err != nil {
156		return err
157	}
158	if (async && (resp.StatusCode != http.StatusAccepted)) || (!async && (resp.StatusCode != http.StatusNoContent)) {
159		return errors.Wrapf(err, "Error deleting organization %s, response code: %d", guid, resp.StatusCode)
160	}
161	return nil
162}
163
164func (c *Client) handleOrgQuotaResp(resp *http.Response) (*OrgQuota, error) {
165	body, err := ioutil.ReadAll(resp.Body)
166	defer resp.Body.Close()
167	if err != nil {
168		return nil, err
169	}
170	var orgQuotasResource OrgQuotasResource
171	err = json.Unmarshal(body, &orgQuotasResource)
172	if err != nil {
173		return nil, err
174	}
175	return c.mergeOrgQuotaResource(orgQuotasResource), nil
176}
177
178func (c *Client) mergeOrgQuotaResource(orgQuotaResource OrgQuotasResource) *OrgQuota {
179	orgQuotaResource.Entity.Guid = orgQuotaResource.Meta.Guid
180	orgQuotaResource.Entity.CreatedAt = orgQuotaResource.Meta.CreatedAt
181	orgQuotaResource.Entity.UpdatedAt = orgQuotaResource.Meta.UpdatedAt
182	orgQuotaResource.Entity.c = c
183	return &orgQuotaResource.Entity
184}
185