blob: f88df190a09038597e0a1ebb3034a58aa656bfe9 [file] [log] [blame]
Jon Perritte7b86d12015-01-16 20:37:11 -07001package services
2
3import (
Jon Perrittb8713ad2015-01-21 15:02:58 -07004 "strings"
5
Jon Perritte7b86d12015-01-16 20:37:11 -07006 "github.com/racker/perigee"
7 "github.com/rackspace/gophercloud"
8 "github.com/rackspace/gophercloud/pagination"
9)
10
11// ListOptsBuilder allows extensions to add additional parameters to the
12// List request.
13type ListOptsBuilder interface {
14 ToCDNServiceListQuery() (string, error)
15}
16
17// ListOpts allows the filtering and sorting of paginated collections through
18// the API. Marker and Limit are used for pagination.
19type ListOpts struct {
20 Marker string `q:"marker"`
21 Limit int `q:"limit"`
22}
23
24// ToCDNServiceListQuery formats a ListOpts into a query string.
25func (opts ListOpts) ToCDNServiceListQuery() (string, error) {
26 q, err := gophercloud.BuildQueryString(opts)
27 if err != nil {
28 return "", err
29 }
30 return q.String(), nil
31}
32
33// List returns a Pager which allows you to iterate over a collection of
34// CDN services. It accepts a ListOpts struct, which allows for pagination via
35// marker and limit.
36func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
37 url := listURL(c)
38 if opts != nil {
39 query, err := opts.ToCDNServiceListQuery()
40 if err != nil {
41 return pagination.Pager{Err: err}
42 }
43 url += query
44 }
45
46 createPage := func(r pagination.PageResult) pagination.Page {
47 p := ServicePage{pagination.MarkerPageBase{PageResult: r}}
48 p.MarkerPageBase.Owner = p
49 return p
50 }
51
52 pager := pagination.NewPager(c, url, createPage)
53 return pager
54}
55
56// CreateOptsBuilder is the interface options structs have to satisfy in order
57// to be used in the main Create operation in this package. Since many
58// extensions decorate or modify the common logic, it is useful for them to
59// satisfy a basic interface in order for them to be used.
60type CreateOptsBuilder interface {
61 ToCDNServiceCreateMap() (map[string]interface{}, error)
62}
63
64// CreateOpts is the common options struct used in this package's Create
65// operation.
66type CreateOpts struct {
67 // REQUIRED. Specifies the name of the service. The minimum length for name is
68 // 3. The maximum length is 256.
69 Name string
70 // REQUIRED. Specifies a list of domains used by users to access their website.
71 Domains []Domain
72 // REQUIRED. Specifies a list of origin domains or IP addresses where the
73 // original assets are stored.
74 Origins []Origin
75 // REQUIRED. Specifies the CDN provider flavor ID to use. For a list of
76 // flavors, see the operation to list the available flavors. The minimum
77 // length for flavor_id is 1. The maximum length is 256.
78 FlavorID string
79 // OPTIONAL. Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
Jon Perritt0bd23732015-01-19 20:58:57 -070080 Caching []CacheRule
Jon Perritte7b86d12015-01-16 20:37:11 -070081 // OPTIONAL. Specifies the restrictions that define who can access assets (content from the CDN cache).
82 Restrictions []Restriction
83}
84
85// ToCDNServiceCreateMap casts a CreateOpts struct to a map.
86func (opts CreateOpts) ToCDNServiceCreateMap() (map[string]interface{}, error) {
87 s := make(map[string]interface{})
88
89 if opts.Name == "" {
90 return nil, no("Name")
91 }
92 s["name"] = opts.Name
93
94 if opts.Domains == nil {
95 return nil, no("Domains")
96 }
97 for _, domain := range opts.Domains {
98 if domain.Domain == "" {
99 return nil, no("Domains[].Domain")
100 }
101 }
102 s["domains"] = opts.Domains
103
104 if opts.Origins == nil {
105 return nil, no("Origins")
106 }
107 for _, origin := range opts.Origins {
108 if origin.Origin == "" {
109 return nil, no("Origins[].Origin")
110 }
Jon Perrittb8713ad2015-01-21 15:02:58 -0700111 if origin.Rules == nil && len(opts.Origins) > 1 {
Jon Perritte7b86d12015-01-16 20:37:11 -0700112 return nil, no("Origins[].Rules")
113 }
114 for _, rule := range origin.Rules {
115 if rule.Name == "" {
116 return nil, no("Origins[].Rules[].Name")
117 }
118 if rule.RequestURL == "" {
119 return nil, no("Origins[].Rules[].RequestURL")
120 }
121 }
122 }
123 s["origins"] = opts.Origins
124
125 if opts.FlavorID == "" {
126 return nil, no("FlavorID")
127 }
128 s["flavor_id"] = opts.FlavorID
129
130 if opts.Caching != nil {
131 for _, cache := range opts.Caching {
132 if cache.Name == "" {
133 return nil, no("Caching[].Name")
134 }
135 if cache.Rules != nil {
136 for _, rule := range cache.Rules {
137 if rule.Name == "" {
138 return nil, no("Caching[].Rules[].Name")
139 }
140 if rule.RequestURL == "" {
141 return nil, no("Caching[].Rules[].RequestURL")
142 }
143 }
144 }
145 }
146 s["caching"] = opts.Caching
147 }
148
149 if opts.Restrictions != nil {
150 for _, restriction := range opts.Restrictions {
151 if restriction.Name == "" {
152 return nil, no("Restrictions[].Name")
153 }
154 if restriction.Rules != nil {
155 for _, rule := range restriction.Rules {
156 if rule.Name == "" {
157 return nil, no("Restrictions[].Rules[].Name")
158 }
159 }
160 }
161 }
162 s["restrictions"] = opts.Restrictions
163 }
164
165 return s, nil
166}
167
168// Create accepts a CreateOpts struct and creates a new CDN service using the
169// values provided.
170func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
171 var res CreateResult
172
173 reqBody, err := opts.ToCDNServiceCreateMap()
174 if err != nil {
175 res.Err = err
176 return res
177 }
178
179 // Send request to API
Jon Perrittd21966f2015-01-20 19:22:45 -0700180 resp, err := perigee.Request("POST", createURL(c), perigee.Options{
Jon Perritte7b86d12015-01-16 20:37:11 -0700181 MoreHeaders: c.AuthenticatedHeaders(),
182 ReqBody: &reqBody,
183 OkCodes: []int{202},
184 })
Jon Perrittd21966f2015-01-20 19:22:45 -0700185 res.Header = resp.HttpResponse.Header
186 res.Err = err
Jon Perritte7b86d12015-01-16 20:37:11 -0700187 return res
188}
189
Jon Perrittb8713ad2015-01-21 15:02:58 -0700190// Get retrieves a specific service based on its URL or its unique ID. For
191// example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
192// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
193// are valid options for idOrURL.
194func Get(c *gophercloud.ServiceClient, idOrURL string) GetResult {
195 var url string
196 if strings.Contains(idOrURL, "/") {
197 url = idOrURL
198 } else {
199 url = getURL(c, idOrURL)
200 }
201
Jon Perritte7b86d12015-01-16 20:37:11 -0700202 var res GetResult
Jon Perrittb8713ad2015-01-21 15:02:58 -0700203 _, res.Err = perigee.Request("GET", url, perigee.Options{
Jon Perritte7b86d12015-01-16 20:37:11 -0700204 MoreHeaders: c.AuthenticatedHeaders(),
205 Results: &res.Body,
206 OkCodes: []int{200},
207 })
208 return res
209}
210
211// UpdateOptsBuilder is the interface options structs have to satisfy in order
212// to be used in the main Update operation in this package. Since many
213// extensions decorate or modify the common logic, it is useful for them to
214// satisfy a basic interface in order for them to be used.
215type UpdateOptsBuilder interface {
Jon Perritt608d3a52015-01-19 10:38:30 -0700216 ToCDNServiceUpdateMap() ([]map[string]interface{}, error)
Jon Perritte7b86d12015-01-16 20:37:11 -0700217}
218
219// Op represents an update operation.
220type Op string
221
222var (
223 // Add is a constant used for performing a "add" operation when updating.
224 Add Op = "add"
225 // Remove is a constant used for performing a "remove" operation when updating.
226 Remove Op = "remove"
227 // Replace is a constant used for performing a "replace" operation when updating.
228 Replace Op = "replace"
229)
230
231// UpdateOpts represents the attributes used when updating an existing CDN service.
232type UpdateOpts []UpdateOpt
233
234// UpdateOpt represents a single update to an existing service. Multiple updates
235// to a service can be submitted at the same time. See UpdateOpts.
236type UpdateOpt struct {
237 // Specifies the update operation to perform.
Jon Perrittd21966f2015-01-20 19:22:45 -0700238 Op Op `json:"op"`
Jon Perritte7b86d12015-01-16 20:37:11 -0700239 // Specifies the JSON Pointer location within the service's JSON representation
240 // of the service parameter being added, replaced or removed.
Jon Perrittd21966f2015-01-20 19:22:45 -0700241 Path string `json:"path"`
Jon Perritte7b86d12015-01-16 20:37:11 -0700242 // Specifies the actual value to be added or replaced. It is not required for
243 // the remove operation.
Jon Perrittd21966f2015-01-20 19:22:45 -0700244 Value map[string]interface{} `json:"value,omitempty"`
Jon Perritte7b86d12015-01-16 20:37:11 -0700245}
246
247// ToCDNServiceUpdateMap casts an UpdateOpts struct to a map.
Jon Perritt608d3a52015-01-19 10:38:30 -0700248func (opts UpdateOpts) ToCDNServiceUpdateMap() ([]map[string]interface{}, error) {
249 s := make([]map[string]interface{}, len(opts))
Jon Perritte7b86d12015-01-16 20:37:11 -0700250
251 for i, opt := range opts {
252 if opt.Op == "" {
253 return nil, no("Op")
254 }
255 if opt.Path == "" {
256 return nil, no("Path")
257 }
258 if opt.Op != Remove && opt.Value == nil {
259 return nil, no("Value")
260 }
Jon Perrittd21966f2015-01-20 19:22:45 -0700261 s[i] = map[string]interface{}{
Jon Perrittb8713ad2015-01-21 15:02:58 -0700262 "op": opt.Op,
263 "path": opt.Path,
Jon Perrittd21966f2015-01-20 19:22:45 -0700264 "value": opt.Value,
265 }
Jon Perritte7b86d12015-01-16 20:37:11 -0700266 }
267
268 return s, nil
269}
270
271// Update accepts a UpdateOpts struct and updates an existing CDN service using
Jon Perrittb8713ad2015-01-21 15:02:58 -0700272// the values provided. idOrURL can be either the service's URL or its ID. For
273// example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
274// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
275// are valid options for idOrURL.
276func Update(c *gophercloud.ServiceClient, idOrURL string, opts UpdateOptsBuilder) UpdateResult {
277 var url string
278 if strings.Contains(idOrURL, "/") {
279 url = idOrURL
280 } else {
281 url = updateURL(c, idOrURL)
282 }
Jon Perritte7b86d12015-01-16 20:37:11 -0700283
Jon Perrittb8713ad2015-01-21 15:02:58 -0700284 var res UpdateResult
Jon Perritte7b86d12015-01-16 20:37:11 -0700285 reqBody, err := opts.ToCDNServiceUpdateMap()
286 if err != nil {
287 res.Err = err
288 return res
289 }
290
Jon Perrittb8713ad2015-01-21 15:02:58 -0700291 resp, err := perigee.Request("PATCH", url, perigee.Options{
Jon Perritte7b86d12015-01-16 20:37:11 -0700292 MoreHeaders: c.AuthenticatedHeaders(),
293 ReqBody: &reqBody,
294 OkCodes: []int{202},
295 })
Jon Perrittd21966f2015-01-20 19:22:45 -0700296 res.Header = resp.HttpResponse.Header
297 res.Err = err
Jon Perritte7b86d12015-01-16 20:37:11 -0700298 return res
299}
300
Jon Perrittb8713ad2015-01-21 15:02:58 -0700301// Delete accepts a service's ID or its URL and deletes the CDN service
302// associated with it. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
303// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
304// are valid options for idOrURL.
305func Delete(c *gophercloud.ServiceClient, idOrURL string) DeleteResult {
306 var url string
307 if strings.Contains(idOrURL, "/") {
308 url = idOrURL
309 } else {
310 url = deleteURL(c, idOrURL)
311 }
312
Jon Perritte7b86d12015-01-16 20:37:11 -0700313 var res DeleteResult
Jon Perrittb8713ad2015-01-21 15:02:58 -0700314 _, res.Err = perigee.Request("DELETE", url, perigee.Options{
Jon Perritte7b86d12015-01-16 20:37:11 -0700315 MoreHeaders: c.AuthenticatedHeaders(),
316 OkCodes: []int{202},
317 })
318 return res
319}