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 SpaceQuotasResponse struct {
15	Count     int                   `json:"total_results"`
16	Pages     int                   `json:"total_pages"`
17	NextUrl   string                `json:"next_url"`
18	Resources []SpaceQuotasResource `json:"resources"`
19}
20
21type SpaceQuotasResource struct {
22	Meta   Meta       `json:"metadata"`
23	Entity SpaceQuota `json:"entity"`
24}
25
26type SpaceQuotaRequest struct {
27	Name                    string `json:"name"`
28	OrganizationGuid        string `json:"organization_guid"`
29	NonBasicServicesAllowed bool   `json:"non_basic_services_allowed"`
30	TotalServices           int    `json:"total_services"`
31	TotalRoutes             int    `json:"total_routes"`
32	MemoryLimit             int    `json:"memory_limit"`
33	InstanceMemoryLimit     int    `json:"instance_memory_limit"`
34	AppInstanceLimit        int    `json:"app_instance_limit"`
35	AppTaskLimit            int    `json:"app_task_limit"`
36	TotalServiceKeys        int    `json:"total_service_keys"`
37	TotalReservedRoutePorts int    `json:"total_reserved_route_ports"`
38}
39
40type SpaceQuota struct {
41	Guid                    string `json:"guid"`
42	CreatedAt               string `json:"created_at,omitempty"`
43	UpdatedAt               string `json:"updated_at,omitempty"`
44	Name                    string `json:"name"`
45	OrganizationGuid        string `json:"organization_guid"`
46	NonBasicServicesAllowed bool   `json:"non_basic_services_allowed"`
47	TotalServices           int    `json:"total_services"`
48	TotalRoutes             int    `json:"total_routes"`
49	MemoryLimit             int    `json:"memory_limit"`
50	InstanceMemoryLimit     int    `json:"instance_memory_limit"`
51	AppInstanceLimit        int    `json:"app_instance_limit"`
52	AppTaskLimit            int    `json:"app_task_limit"`
53	TotalServiceKeys        int    `json:"total_service_keys"`
54	TotalReservedRoutePorts int    `json:"total_reserved_route_ports"`
55	c                       *Client
56}
57
58func (c *Client) ListSpaceQuotasByQuery(query url.Values) ([]SpaceQuota, error) {
59	var spaceQuotas []SpaceQuota
60	requestUrl := "/v2/space_quota_definitions?" + query.Encode()
61	for {
62		spaceQuotasResp, err := c.getSpaceQuotasResponse(requestUrl)
63		if err != nil {
64			return []SpaceQuota{}, err
65		}
66		for _, space := range spaceQuotasResp.Resources {
67			space.Entity.Guid = space.Meta.Guid
68			space.Entity.CreatedAt = space.Meta.CreatedAt
69			space.Entity.UpdatedAt = space.Meta.UpdatedAt
70			space.Entity.c = c
71			spaceQuotas = append(spaceQuotas, space.Entity)
72		}
73		requestUrl = spaceQuotasResp.NextUrl
74		if requestUrl == "" {
75			break
76		}
77	}
78	return spaceQuotas, nil
79}
80
81func (c *Client) ListSpaceQuotas() ([]SpaceQuota, error) {
82	return c.ListSpaceQuotasByQuery(nil)
83}
84
85func (c *Client) GetSpaceQuotaByName(name string) (SpaceQuota, error) {
86	q := url.Values{}
87	q.Set("q", "name:"+name)
88	spaceQuotas, err := c.ListSpaceQuotasByQuery(q)
89	if err != nil {
90		return SpaceQuota{}, err
91	}
92	if len(spaceQuotas) != 1 {
93		return SpaceQuota{}, fmt.Errorf("Unable to find space quota " + name)
94	}
95	return spaceQuotas[0], nil
96}
97
98func (c *Client) getSpaceQuotasResponse(requestUrl string) (SpaceQuotasResponse, error) {
99	var spaceQuotasResp SpaceQuotasResponse
100	r := c.NewRequest("GET", requestUrl)
101	resp, err := c.DoRequest(r)
102	if err != nil {
103		return SpaceQuotasResponse{}, errors.Wrap(err, "Error requesting space quotas")
104	}
105	resBody, err := ioutil.ReadAll(resp.Body)
106	defer resp.Body.Close()
107	if err != nil {
108		return SpaceQuotasResponse{}, errors.Wrap(err, "Error reading space quotas body")
109	}
110	err = json.Unmarshal(resBody, &spaceQuotasResp)
111	if err != nil {
112		return SpaceQuotasResponse{}, errors.Wrap(err, "Error unmarshalling space quotas")
113	}
114	return spaceQuotasResp, nil
115}
116
117func (c *Client) AssignSpaceQuota(quotaGUID, spaceGUID string) error {
118	//Perform the PUT and check for errors
119	resp, err := c.DoRequest(c.NewRequest("PUT", fmt.Sprintf("/v2/space_quota_definitions/%s/spaces/%s", quotaGUID, spaceGUID)))
120	if err != nil {
121		return err
122	}
123	if resp.StatusCode != http.StatusCreated { //201
124		return fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
125	}
126	return nil
127}
128
129func (c *Client) CreateSpaceQuota(spaceQuote SpaceQuotaRequest) (*SpaceQuota, error) {
130	buf := bytes.NewBuffer(nil)
131	err := json.NewEncoder(buf).Encode(spaceQuote)
132	if err != nil {
133		return nil, err
134	}
135	r := c.NewRequestWithBody("POST", "/v2/space_quota_definitions", buf)
136	resp, err := c.DoRequest(r)
137	if err != nil {
138		return nil, err
139	}
140	if resp.StatusCode != http.StatusCreated {
141		return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
142	}
143	return c.handleSpaceQuotaResp(resp)
144}
145
146func (c *Client) UpdateSpaceQuota(spaceQuotaGUID string, spaceQuote SpaceQuotaRequest) (*SpaceQuota, error) {
147	buf := bytes.NewBuffer(nil)
148	err := json.NewEncoder(buf).Encode(spaceQuote)
149	if err != nil {
150		return nil, err
151	}
152	r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/space_quota_definitions/%s", spaceQuotaGUID), buf)
153	resp, err := c.DoRequest(r)
154	if err != nil {
155		return nil, err
156	}
157	if resp.StatusCode != http.StatusCreated {
158		return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
159	}
160	return c.handleSpaceQuotaResp(resp)
161}
162
163func (c *Client) handleSpaceQuotaResp(resp *http.Response) (*SpaceQuota, error) {
164	body, err := ioutil.ReadAll(resp.Body)
165	defer resp.Body.Close()
166	if err != nil {
167		return nil, err
168	}
169	var spaceQuotasResource SpaceQuotasResource
170	err = json.Unmarshal(body, &spaceQuotasResource)
171	if err != nil {
172		return nil, err
173	}
174	return c.mergeSpaceQuotaResource(spaceQuotasResource), nil
175}
176
177func (c *Client) mergeSpaceQuotaResource(spaceQuote SpaceQuotasResource) *SpaceQuota {
178	spaceQuote.Entity.Guid = spaceQuote.Meta.Guid
179	spaceQuote.Entity.CreatedAt = spaceQuote.Meta.CreatedAt
180	spaceQuote.Entity.UpdatedAt = spaceQuote.Meta.UpdatedAt
181	spaceQuote.Entity.c = c
182	return &spaceQuote.Entity
183}
184