blob: c0329d6cb68d9269f2f87de5ff306f7bb2150e09 [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 Perrittdb0ae142016-03-13 00:33:41 -060080 return gophercloud.BuildRequestBody(opts, "")
Jon Perritte7b86d12015-01-16 20:37:11 -070081}
82
83// Create accepts a CreateOpts struct and creates a new CDN service using the
84// values provided.
Jon Perritt3860b512016-03-29 12:01:48 -050085func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
Jon Perrittdb0ae142016-03-13 00:33:41 -060086 b, err := opts.ToCDNServiceCreateMap()
Jon Perritte7b86d12015-01-16 20:37:11 -070087 if err != nil {
Jon Perrittdb0ae142016-03-13 00:33:41 -060088 r.Err = err
89 return r
Jon Perritte7b86d12015-01-16 20:37:11 -070090 }
Jon Perrittdb0ae142016-03-13 00:33:41 -060091 resp, err := c.Post(createURL(c), &b, nil, nil)
92 r.Header = resp.Header
93 r.Err = err
Jon Perritte7b86d12015-01-16 20:37:11 -070094}
95
Jon Perrittb8713ad2015-01-21 15:02:58 -070096// Get retrieves a specific service based on its URL or its unique ID. For
97// example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
98// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
99// are valid options for idOrURL.
Jon Perritt3860b512016-03-29 12:01:48 -0500100func Get(c *gophercloud.ServiceClient, idOrURL string) (r GetResult) {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700101 var url string
102 if strings.Contains(idOrURL, "/") {
103 url = idOrURL
104 } else {
105 url = getURL(c, idOrURL)
106 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600107 _, r.Err = c.Get(url, &r.Body, nil)
Jon Perritte7b86d12015-01-16 20:37:11 -0700108}
109
Ash Wilsona623ff72015-01-28 15:50:37 -0500110// Path is a JSON pointer location that indicates which service parameter is being added, replaced,
111// or removed.
112type Path struct {
113 baseElement string
114}
115
Ash Wilson05280702015-01-29 11:19:25 -0500116func (p Path) renderRoot() string {
117 return "/" + p.baseElement
118}
119
Ash Wilsona623ff72015-01-28 15:50:37 -0500120func (p Path) renderDash() string {
121 return fmt.Sprintf("/%s/-", p.baseElement)
122}
123
124func (p Path) renderIndex(index int64) string {
125 return fmt.Sprintf("/%s/%d", p.baseElement, index)
126}
127
128var (
129 // PathDomains indicates that an update operation is to be performed on a Domain.
130 PathDomains = Path{baseElement: "domains"}
131
132 // PathOrigins indicates that an update operation is to be performed on an Origin.
133 PathOrigins = Path{baseElement: "origins"}
134
135 // PathCaching indicates that an update operation is to be performed on a CacheRule.
136 PathCaching = Path{baseElement: "caching"}
137)
138
Ash Wilson4ee05012015-01-28 16:13:43 -0500139type value interface {
Ash Wilsonb47ebed2015-01-29 11:08:41 -0500140 toPatchValue() interface{}
Ash Wilson4ee05012015-01-28 16:13:43 -0500141 appropriatePath() Path
Ash Wilson05280702015-01-29 11:19:25 -0500142 renderRootOr(func(p Path) string) string
Ash Wilson4ee05012015-01-28 16:13:43 -0500143}
144
Ash Wilson7b729532015-01-28 16:15:23 -0500145// Patch represents a single update to an existing Service. Multiple updates to a service can be
146// submitted at the same time.
147type Patch interface {
148 ToCDNServiceUpdateMap() map[string]interface{}
149}
150
Ash Wilson299363d2015-01-29 10:49:40 -0500151// Insertion is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to
152// a Service at a fixed index. Use an Append instead to append the new value to the end of its
153// collection. Pass it to the Update function as part of the Patch slice.
154type Insertion struct {
155 Index int64
Ash Wilson334277c2015-01-29 09:08:52 -0500156 Value value
157}
158
Ash Wilson299363d2015-01-29 10:49:40 -0500159// ToCDNServiceUpdateMap converts an Insertion into a request body fragment suitable for the
Ash Wilson334277c2015-01-29 09:08:52 -0500160// Update call.
Jon Perrittdb0ae142016-03-13 00:33:41 -0600161func (opts Insertion) ToCDNServiceUpdateMap() map[string]interface{} {
Ash Wilson299363d2015-01-29 10:49:40 -0500162 return map[string]interface{}{
163 "op": "add",
Jon Perrittdb0ae142016-03-13 00:33:41 -0600164 "path": opts.Value.renderRootOr(func(p Path) string { return p.renderIndex(opts.Index) }),
165 "value": opts.Value.toPatchValue(),
Ash Wilson299363d2015-01-29 10:49:40 -0500166 }
167}
168
169// Append is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to a
170// Service at the end of its respective collection. Use an Insertion instead to insert the value
171// at a fixed index within the collection. Pass this to the Update function as part of its
172// Patch slice.
173type Append struct {
174 Value value
175}
176
177// ToCDNServiceUpdateMap converts an Append into a request body fragment suitable for the
178// Update call.
179func (a Append) ToCDNServiceUpdateMap() map[string]interface{} {
Ash Wilson334277c2015-01-29 09:08:52 -0500180 return map[string]interface{}{
181 "op": "add",
Ash Wilson05280702015-01-29 11:19:25 -0500182 "path": a.Value.renderRootOr(func(p Path) string { return p.renderDash() }),
Ash Wilson334277c2015-01-29 09:08:52 -0500183 "value": a.Value.toPatchValue(),
184 }
185}
186
187// Replacement is a Patch that alters a specific service parameter (Domain, Origin, or CacheRule)
188// in-place by index. Pass it to the Update function as part of the Patch slice.
189type Replacement struct {
190 Value value
191 Index int64
192}
193
194// ToCDNServiceUpdateMap converts a Replacement into a request body fragment suitable for the
195// Update call.
196func (r Replacement) ToCDNServiceUpdateMap() map[string]interface{} {
197 return map[string]interface{}{
198 "op": "replace",
Ash Wilson05280702015-01-29 11:19:25 -0500199 "path": r.Value.renderRootOr(func(p Path) string { return p.renderIndex(r.Index) }),
Ash Wilson334277c2015-01-29 09:08:52 -0500200 "value": r.Value.toPatchValue(),
201 }
202}
203
Ash Wilsond842ae62015-01-29 13:11:50 -0500204// NameReplacement specifically updates the Service name. Pass it to the Update function as part
205// of the Patch slice.
206type NameReplacement struct {
207 NewName string
208}
209
210// ToCDNServiceUpdateMap converts a NameReplacement into a request body fragment suitable for the
211// Update call.
212func (r NameReplacement) ToCDNServiceUpdateMap() map[string]interface{} {
213 return map[string]interface{}{
214 "op": "replace",
215 "path": "/name",
216 "value": r.NewName,
217 }
218}
219
Ash Wilson334277c2015-01-29 09:08:52 -0500220// Removal is a Patch that requests the removal of a service parameter (Domain, Origin, or
221// CacheRule) by index. Pass it to the Update function as part of the Patch slice.
222type Removal struct {
223 Path Path
224 Index int64
Ash Wilsond842ae62015-01-29 13:11:50 -0500225 All bool
Ash Wilson334277c2015-01-29 09:08:52 -0500226}
227
228// ToCDNServiceUpdateMap converts a Removal into a request body fragment suitable for the
229// Update call.
Jon Perrittdb0ae142016-03-13 00:33:41 -0600230func (opts Removal) ToCDNServiceUpdateMap() map[string]interface{} {
231 b := map[string]interface{}{"op": "remove"}
232 if opts.All {
233 b["path"] = opts.Path.renderRoot()
Ash Wilsond842ae62015-01-29 13:11:50 -0500234 } else {
Jon Perrittdb0ae142016-03-13 00:33:41 -0600235 b["path"] = opts.Path.renderIndex(opts.Index)
Ash Wilson334277c2015-01-29 09:08:52 -0500236 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600237 return b
Ash Wilson334277c2015-01-29 09:08:52 -0500238}
239
Jon Perrittdb0ae142016-03-13 00:33:41 -0600240// UpdateOpts is a slice of Patches used to update a CDN service
Jon Perritt1bda9c12015-01-29 12:16:08 -0700241type UpdateOpts []Patch
242
Ash Wilson299363d2015-01-29 10:49:40 -0500243// Update accepts a slice of Patch operations (Insertion, Append, Replacement or Removal) and
244// updates an existing CDN service using the values provided. idOrURL can be either the service's
245// URL or its ID. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
Jon Perrittb8713ad2015-01-21 15:02:58 -0700246// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
247// are valid options for idOrURL.
Jon Perritt3860b512016-03-29 12:01:48 -0500248func Update(c *gophercloud.ServiceClient, idOrURL string, opts UpdateOpts) (r UpdateResult) {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700249 var url string
250 if strings.Contains(idOrURL, "/") {
251 url = idOrURL
252 } else {
253 url = updateURL(c, idOrURL)
254 }
Jon Perritte7b86d12015-01-16 20:37:11 -0700255
Jon Perrittdb0ae142016-03-13 00:33:41 -0600256 b := make([]map[string]interface{}, len(opts))
Jon Perritt1bda9c12015-01-29 12:16:08 -0700257 for i, patch := range opts {
Jon Perrittdb0ae142016-03-13 00:33:41 -0600258 b[i] = patch.ToCDNServiceUpdateMap()
Jon Perritte7b86d12015-01-16 20:37:11 -0700259 }
260
Jon Perritta33da232016-03-02 04:43:08 -0600261 resp, err := c.Request("PATCH", url, &gophercloud.RequestOpts{
Jon Perrittdb0ae142016-03-13 00:33:41 -0600262 JSONBody: &b,
Ash Wilson4bf41a32015-02-12 15:52:44 -0500263 OkCodes: []int{202},
Jon Perritte7b86d12015-01-16 20:37:11 -0700264 })
Jon Perrittdb0ae142016-03-13 00:33:41 -0600265 r.Header = resp.Header
266 r.Err = err
Jon Perritte7b86d12015-01-16 20:37:11 -0700267}
268
Jon Perrittb8713ad2015-01-21 15:02:58 -0700269// Delete accepts a service's ID or its URL and deletes the CDN service
270// associated with it. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
271// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
272// are valid options for idOrURL.
Jon Perritt3860b512016-03-29 12:01:48 -0500273func Delete(c *gophercloud.ServiceClient, idOrURL string) (r DeleteResult) {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700274 var url string
275 if strings.Contains(idOrURL, "/") {
276 url = idOrURL
277 } else {
278 url = deleteURL(c, idOrURL)
279 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600280 _, r.Err = c.Delete(url, nil)
Jon Perritte7b86d12015-01-16 20:37:11 -0700281}