blob: 9a0f54b15c0b40893993611f8fcd4fc5fb2e561d [file] [log] [blame]
Jon Perritte7b86d12015-01-16 20:37:11 -07001package services
2
3import (
Jon Perrittb0ab0d12015-01-27 12:12:51 -07004 "fmt"
Jon Perrittb8713ad2015-01-21 15:02:58 -07005 "strings"
6
Jon Perritt27249f42016-02-18 10:35:59 -06007 "github.com/gophercloud/gophercloud"
8 "github.com/gophercloud/gophercloud/pagination"
Jon Perritte7b86d12015-01-16 20:37:11 -07009)
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)
Jon Perrittdb0ae142016-03-13 00:33:41 -060027 return q.String(), err
Jon Perritte7b86d12015-01-16 20:37:11 -070028}
29
30// List returns a Pager which allows you to iterate over a collection of
31// CDN services. It accepts a ListOpts struct, which allows for pagination via
32// marker and limit.
33func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
34 url := listURL(c)
35 if opts != nil {
36 query, err := opts.ToCDNServiceListQuery()
37 if err != nil {
38 return pagination.Pager{Err: err}
39 }
40 url += query
41 }
Jon Perrittdb0ae142016-03-13 00:33:41 -060042 return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
Jon Perritte7b86d12015-01-16 20:37:11 -070043 p := ServicePage{pagination.MarkerPageBase{PageResult: r}}
44 p.MarkerPageBase.Owner = p
45 return p
Jon Perrittdb0ae142016-03-13 00:33:41 -060046 })
Jon Perritte7b86d12015-01-16 20:37:11 -070047}
48
49// CreateOptsBuilder is the interface options structs have to satisfy in order
50// to be used in the main Create operation in this package. Since many
51// extensions decorate or modify the common logic, it is useful for them to
52// satisfy a basic interface in order for them to be used.
53type CreateOptsBuilder interface {
54 ToCDNServiceCreateMap() (map[string]interface{}, error)
55}
56
57// CreateOpts is the common options struct used in this package's Create
58// operation.
59type CreateOpts struct {
Jon Perrittdb0ae142016-03-13 00:33:41 -060060 // Specifies the name of the service. The minimum length for name is
Jon Perritte7b86d12015-01-16 20:37:11 -070061 // 3. The maximum length is 256.
Jon Perrittdb0ae142016-03-13 00:33:41 -060062 Name string `json:"name" required:"true"`
63 // Specifies a list of domains used by users to access their website.
64 Domains []Domain `json:"domains" required:"true"`
65 // Specifies a list of origin domains or IP addresses where the
Jon Perritte7b86d12015-01-16 20:37:11 -070066 // original assets are stored.
Jon Perrittdb0ae142016-03-13 00:33:41 -060067 Origins []Origin `json:"origins" required:"true"`
68 // Specifies the CDN provider flavor ID to use. For a list of
Jon Perritte7b86d12015-01-16 20:37:11 -070069 // flavors, see the operation to list the available flavors. The minimum
70 // length for flavor_id is 1. The maximum length is 256.
Jon Perrittdb0ae142016-03-13 00:33:41 -060071 FlavorID string `json:"flavor_id" required:"true"`
72 // Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
73 Caching []CacheRule `json:"caching,omitempty"`
74 // Specifies the restrictions that define who can access assets (content from the CDN cache).
75 Restrictions []Restriction `json:"restrictions,omitempty"`
Jon Perritte7b86d12015-01-16 20:37:11 -070076}
77
78// ToCDNServiceCreateMap casts a CreateOpts struct to a map.
79func (opts CreateOpts) ToCDNServiceCreateMap() (map[string]interface{}, error) {
Jon Perritte7b86d12015-01-16 20:37:11 -070080
Jon Perrittdb0ae142016-03-13 00:33:41 -060081 /*
82 for _, origin := range opts.Origins {
83 if origin.Rules == nil && len(opts.Origins) > 1 {
84 return nil, no("Origins[].Rules")
Jon Perritte7b86d12015-01-16 20:37:11 -070085 }
86 }
Jon Perrittdb0ae142016-03-13 00:33:41 -060087 */
Jon Perritte7b86d12015-01-16 20:37:11 -070088
Jon Perrittdb0ae142016-03-13 00:33:41 -060089 return gophercloud.BuildRequestBody(opts, "")
Jon Perritte7b86d12015-01-16 20:37:11 -070090}
91
92// Create accepts a CreateOpts struct and creates a new CDN service using the
93// values provided.
94func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
Jon Perrittdb0ae142016-03-13 00:33:41 -060095 var r CreateResult
96 b, err := opts.ToCDNServiceCreateMap()
Jon Perritte7b86d12015-01-16 20:37:11 -070097 if err != nil {
Jon Perrittdb0ae142016-03-13 00:33:41 -060098 r.Err = err
99 return r
Jon Perritte7b86d12015-01-16 20:37:11 -0700100 }
Jon Perritte7b86d12015-01-16 20:37:11 -0700101 // Send request to API
Jon Perrittdb0ae142016-03-13 00:33:41 -0600102 resp, err := c.Post(createURL(c), &b, nil, nil)
103 r.Header = resp.Header
104 r.Err = err
105 return r
Jon Perritte7b86d12015-01-16 20:37:11 -0700106}
107
Jon Perrittb8713ad2015-01-21 15:02:58 -0700108// Get retrieves a specific service based on its URL or its unique ID. For
109// example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
110// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
111// are valid options for idOrURL.
112func Get(c *gophercloud.ServiceClient, idOrURL string) GetResult {
113 var url string
114 if strings.Contains(idOrURL, "/") {
115 url = idOrURL
116 } else {
117 url = getURL(c, idOrURL)
118 }
119
Jon Perrittdb0ae142016-03-13 00:33:41 -0600120 var r GetResult
121 _, r.Err = c.Get(url, &r.Body, nil)
122 return r
Jon Perritte7b86d12015-01-16 20:37:11 -0700123}
124
Ash Wilsona623ff72015-01-28 15:50:37 -0500125// Path is a JSON pointer location that indicates which service parameter is being added, replaced,
126// or removed.
127type Path struct {
128 baseElement string
129}
130
Ash Wilson05280702015-01-29 11:19:25 -0500131func (p Path) renderRoot() string {
132 return "/" + p.baseElement
133}
134
Ash Wilsona623ff72015-01-28 15:50:37 -0500135func (p Path) renderDash() string {
136 return fmt.Sprintf("/%s/-", p.baseElement)
137}
138
139func (p Path) renderIndex(index int64) string {
140 return fmt.Sprintf("/%s/%d", p.baseElement, index)
141}
142
143var (
144 // PathDomains indicates that an update operation is to be performed on a Domain.
145 PathDomains = Path{baseElement: "domains"}
146
147 // PathOrigins indicates that an update operation is to be performed on an Origin.
148 PathOrigins = Path{baseElement: "origins"}
149
150 // PathCaching indicates that an update operation is to be performed on a CacheRule.
151 PathCaching = Path{baseElement: "caching"}
152)
153
Ash Wilson4ee05012015-01-28 16:13:43 -0500154type value interface {
Ash Wilsonb47ebed2015-01-29 11:08:41 -0500155 toPatchValue() interface{}
Ash Wilson4ee05012015-01-28 16:13:43 -0500156 appropriatePath() Path
Ash Wilson05280702015-01-29 11:19:25 -0500157 renderRootOr(func(p Path) string) string
Ash Wilson4ee05012015-01-28 16:13:43 -0500158}
159
Ash Wilson7b729532015-01-28 16:15:23 -0500160// Patch represents a single update to an existing Service. Multiple updates to a service can be
161// submitted at the same time.
162type Patch interface {
163 ToCDNServiceUpdateMap() map[string]interface{}
164}
165
Ash Wilson299363d2015-01-29 10:49:40 -0500166// Insertion is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to
167// a Service at a fixed index. Use an Append instead to append the new value to the end of its
168// collection. Pass it to the Update function as part of the Patch slice.
169type Insertion struct {
170 Index int64
Ash Wilson334277c2015-01-29 09:08:52 -0500171 Value value
172}
173
Ash Wilson299363d2015-01-29 10:49:40 -0500174// ToCDNServiceUpdateMap converts an Insertion into a request body fragment suitable for the
Ash Wilson334277c2015-01-29 09:08:52 -0500175// Update call.
Jon Perrittdb0ae142016-03-13 00:33:41 -0600176func (opts Insertion) ToCDNServiceUpdateMap() map[string]interface{} {
Ash Wilson299363d2015-01-29 10:49:40 -0500177 return map[string]interface{}{
178 "op": "add",
Jon Perrittdb0ae142016-03-13 00:33:41 -0600179 "path": opts.Value.renderRootOr(func(p Path) string { return p.renderIndex(opts.Index) }),
180 "value": opts.Value.toPatchValue(),
Ash Wilson299363d2015-01-29 10:49:40 -0500181 }
182}
183
184// Append is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to a
185// Service at the end of its respective collection. Use an Insertion instead to insert the value
186// at a fixed index within the collection. Pass this to the Update function as part of its
187// Patch slice.
188type Append struct {
189 Value value
190}
191
192// ToCDNServiceUpdateMap converts an Append into a request body fragment suitable for the
193// Update call.
194func (a Append) ToCDNServiceUpdateMap() map[string]interface{} {
Ash Wilson334277c2015-01-29 09:08:52 -0500195 return map[string]interface{}{
196 "op": "add",
Ash Wilson05280702015-01-29 11:19:25 -0500197 "path": a.Value.renderRootOr(func(p Path) string { return p.renderDash() }),
Ash Wilson334277c2015-01-29 09:08:52 -0500198 "value": a.Value.toPatchValue(),
199 }
200}
201
202// Replacement is a Patch that alters a specific service parameter (Domain, Origin, or CacheRule)
203// in-place by index. Pass it to the Update function as part of the Patch slice.
204type Replacement struct {
205 Value value
206 Index int64
207}
208
209// ToCDNServiceUpdateMap converts a Replacement into a request body fragment suitable for the
210// Update call.
211func (r Replacement) ToCDNServiceUpdateMap() map[string]interface{} {
212 return map[string]interface{}{
213 "op": "replace",
Ash Wilson05280702015-01-29 11:19:25 -0500214 "path": r.Value.renderRootOr(func(p Path) string { return p.renderIndex(r.Index) }),
Ash Wilson334277c2015-01-29 09:08:52 -0500215 "value": r.Value.toPatchValue(),
216 }
217}
218
Ash Wilsond842ae62015-01-29 13:11:50 -0500219// NameReplacement specifically updates the Service name. Pass it to the Update function as part
220// of the Patch slice.
221type NameReplacement struct {
222 NewName string
223}
224
225// ToCDNServiceUpdateMap converts a NameReplacement into a request body fragment suitable for the
226// Update call.
227func (r NameReplacement) ToCDNServiceUpdateMap() map[string]interface{} {
228 return map[string]interface{}{
229 "op": "replace",
230 "path": "/name",
231 "value": r.NewName,
232 }
233}
234
Ash Wilson334277c2015-01-29 09:08:52 -0500235// Removal is a Patch that requests the removal of a service parameter (Domain, Origin, or
236// CacheRule) by index. Pass it to the Update function as part of the Patch slice.
237type Removal struct {
238 Path Path
239 Index int64
Ash Wilsond842ae62015-01-29 13:11:50 -0500240 All bool
Ash Wilson334277c2015-01-29 09:08:52 -0500241}
242
243// ToCDNServiceUpdateMap converts a Removal into a request body fragment suitable for the
244// Update call.
Jon Perrittdb0ae142016-03-13 00:33:41 -0600245func (opts Removal) ToCDNServiceUpdateMap() map[string]interface{} {
246 b := map[string]interface{}{"op": "remove"}
247 if opts.All {
248 b["path"] = opts.Path.renderRoot()
Ash Wilsond842ae62015-01-29 13:11:50 -0500249 } else {
Jon Perrittdb0ae142016-03-13 00:33:41 -0600250 b["path"] = opts.Path.renderIndex(opts.Index)
Ash Wilson334277c2015-01-29 09:08:52 -0500251 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600252 return b
Ash Wilson334277c2015-01-29 09:08:52 -0500253}
254
Jon Perrittdb0ae142016-03-13 00:33:41 -0600255// UpdateOpts is a slice of Patches used to update a CDN service
Jon Perritt1bda9c12015-01-29 12:16:08 -0700256type UpdateOpts []Patch
257
Ash Wilson299363d2015-01-29 10:49:40 -0500258// Update accepts a slice of Patch operations (Insertion, Append, Replacement or Removal) and
259// updates an existing CDN service using the values provided. idOrURL can be either the service's
260// URL or its ID. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
Jon Perrittb8713ad2015-01-21 15:02:58 -0700261// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
262// are valid options for idOrURL.
Jon Perritt1bda9c12015-01-29 12:16:08 -0700263func Update(c *gophercloud.ServiceClient, idOrURL string, opts UpdateOpts) UpdateResult {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700264 var url string
265 if strings.Contains(idOrURL, "/") {
266 url = idOrURL
267 } else {
268 url = updateURL(c, idOrURL)
269 }
Jon Perritte7b86d12015-01-16 20:37:11 -0700270
Jon Perrittdb0ae142016-03-13 00:33:41 -0600271 b := make([]map[string]interface{}, len(opts))
Jon Perritt1bda9c12015-01-29 12:16:08 -0700272 for i, patch := range opts {
Jon Perrittdb0ae142016-03-13 00:33:41 -0600273 b[i] = patch.ToCDNServiceUpdateMap()
Jon Perritte7b86d12015-01-16 20:37:11 -0700274 }
275
Jon Perritta33da232016-03-02 04:43:08 -0600276 resp, err := c.Request("PATCH", url, &gophercloud.RequestOpts{
Jon Perrittdb0ae142016-03-13 00:33:41 -0600277 JSONBody: &b,
Ash Wilson4bf41a32015-02-12 15:52:44 -0500278 OkCodes: []int{202},
Jon Perritte7b86d12015-01-16 20:37:11 -0700279 })
Jon Perrittdb0ae142016-03-13 00:33:41 -0600280 var r UpdateResult
281 r.Header = resp.Header
282 r.Err = err
283 return r
Jon Perritte7b86d12015-01-16 20:37:11 -0700284}
285
Jon Perrittb8713ad2015-01-21 15:02:58 -0700286// Delete accepts a service's ID or its URL and deletes the CDN service
287// associated with it. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
288// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
289// are valid options for idOrURL.
290func Delete(c *gophercloud.ServiceClient, idOrURL string) DeleteResult {
291 var url string
292 if strings.Contains(idOrURL, "/") {
293 url = idOrURL
294 } else {
295 url = deleteURL(c, idOrURL)
296 }
297
Jon Perrittdb0ae142016-03-13 00:33:41 -0600298 var r DeleteResult
299 _, r.Err = c.Delete(url, nil)
300 return r
Jon Perritte7b86d12015-01-16 20:37:11 -0700301}