blob: 4c0c6266066f2fc7645879663ac42bcf872bf2fc [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
jrperritt29ae6b32016-04-13 12:59:37 -050094 return
Jon Perritte7b86d12015-01-16 20:37:11 -070095}
96
Jon Perrittb8713ad2015-01-21 15:02:58 -070097// Get retrieves a specific service based on its URL or its unique ID. For
98// example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
99// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
100// are valid options for idOrURL.
Jon Perritt3860b512016-03-29 12:01:48 -0500101func Get(c *gophercloud.ServiceClient, idOrURL string) (r GetResult) {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700102 var url string
103 if strings.Contains(idOrURL, "/") {
104 url = idOrURL
105 } else {
106 url = getURL(c, idOrURL)
107 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600108 _, r.Err = c.Get(url, &r.Body, nil)
jrperritt29ae6b32016-04-13 12:59:37 -0500109 return
Jon Perritte7b86d12015-01-16 20:37:11 -0700110}
111
Ash Wilsona623ff72015-01-28 15:50:37 -0500112// Path is a JSON pointer location that indicates which service parameter is being added, replaced,
113// or removed.
114type Path struct {
115 baseElement string
116}
117
Ash Wilson05280702015-01-29 11:19:25 -0500118func (p Path) renderRoot() string {
119 return "/" + p.baseElement
120}
121
Ash Wilsona623ff72015-01-28 15:50:37 -0500122func (p Path) renderDash() string {
123 return fmt.Sprintf("/%s/-", p.baseElement)
124}
125
126func (p Path) renderIndex(index int64) string {
127 return fmt.Sprintf("/%s/%d", p.baseElement, index)
128}
129
130var (
131 // PathDomains indicates that an update operation is to be performed on a Domain.
132 PathDomains = Path{baseElement: "domains"}
133
134 // PathOrigins indicates that an update operation is to be performed on an Origin.
135 PathOrigins = Path{baseElement: "origins"}
136
137 // PathCaching indicates that an update operation is to be performed on a CacheRule.
138 PathCaching = Path{baseElement: "caching"}
139)
140
Ash Wilson4ee05012015-01-28 16:13:43 -0500141type value interface {
Ash Wilsonb47ebed2015-01-29 11:08:41 -0500142 toPatchValue() interface{}
Ash Wilson4ee05012015-01-28 16:13:43 -0500143 appropriatePath() Path
Ash Wilson05280702015-01-29 11:19:25 -0500144 renderRootOr(func(p Path) string) string
Ash Wilson4ee05012015-01-28 16:13:43 -0500145}
146
Ash Wilson7b729532015-01-28 16:15:23 -0500147// Patch represents a single update to an existing Service. Multiple updates to a service can be
148// submitted at the same time.
149type Patch interface {
150 ToCDNServiceUpdateMap() map[string]interface{}
151}
152
Ash Wilson299363d2015-01-29 10:49:40 -0500153// Insertion is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to
154// a Service at a fixed index. Use an Append instead to append the new value to the end of its
155// collection. Pass it to the Update function as part of the Patch slice.
156type Insertion struct {
157 Index int64
Ash Wilson334277c2015-01-29 09:08:52 -0500158 Value value
159}
160
Ash Wilson299363d2015-01-29 10:49:40 -0500161// ToCDNServiceUpdateMap converts an Insertion into a request body fragment suitable for the
Ash Wilson334277c2015-01-29 09:08:52 -0500162// Update call.
Jon Perrittdb0ae142016-03-13 00:33:41 -0600163func (opts Insertion) ToCDNServiceUpdateMap() map[string]interface{} {
Ash Wilson299363d2015-01-29 10:49:40 -0500164 return map[string]interface{}{
165 "op": "add",
Jon Perrittdb0ae142016-03-13 00:33:41 -0600166 "path": opts.Value.renderRootOr(func(p Path) string { return p.renderIndex(opts.Index) }),
167 "value": opts.Value.toPatchValue(),
Ash Wilson299363d2015-01-29 10:49:40 -0500168 }
169}
170
171// Append is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to a
172// Service at the end of its respective collection. Use an Insertion instead to insert the value
173// at a fixed index within the collection. Pass this to the Update function as part of its
174// Patch slice.
175type Append struct {
176 Value value
177}
178
179// ToCDNServiceUpdateMap converts an Append into a request body fragment suitable for the
180// Update call.
181func (a Append) ToCDNServiceUpdateMap() map[string]interface{} {
Ash Wilson334277c2015-01-29 09:08:52 -0500182 return map[string]interface{}{
183 "op": "add",
Ash Wilson05280702015-01-29 11:19:25 -0500184 "path": a.Value.renderRootOr(func(p Path) string { return p.renderDash() }),
Ash Wilson334277c2015-01-29 09:08:52 -0500185 "value": a.Value.toPatchValue(),
186 }
187}
188
189// Replacement is a Patch that alters a specific service parameter (Domain, Origin, or CacheRule)
190// in-place by index. Pass it to the Update function as part of the Patch slice.
191type Replacement struct {
192 Value value
193 Index int64
194}
195
196// ToCDNServiceUpdateMap converts a Replacement into a request body fragment suitable for the
197// Update call.
198func (r Replacement) ToCDNServiceUpdateMap() map[string]interface{} {
199 return map[string]interface{}{
200 "op": "replace",
Ash Wilson05280702015-01-29 11:19:25 -0500201 "path": r.Value.renderRootOr(func(p Path) string { return p.renderIndex(r.Index) }),
Ash Wilson334277c2015-01-29 09:08:52 -0500202 "value": r.Value.toPatchValue(),
203 }
204}
205
Ash Wilsond842ae62015-01-29 13:11:50 -0500206// NameReplacement specifically updates the Service name. Pass it to the Update function as part
207// of the Patch slice.
208type NameReplacement struct {
209 NewName string
210}
211
212// ToCDNServiceUpdateMap converts a NameReplacement into a request body fragment suitable for the
213// Update call.
214func (r NameReplacement) ToCDNServiceUpdateMap() map[string]interface{} {
215 return map[string]interface{}{
216 "op": "replace",
217 "path": "/name",
218 "value": r.NewName,
219 }
220}
221
Ash Wilson334277c2015-01-29 09:08:52 -0500222// Removal is a Patch that requests the removal of a service parameter (Domain, Origin, or
223// CacheRule) by index. Pass it to the Update function as part of the Patch slice.
224type Removal struct {
225 Path Path
226 Index int64
Ash Wilsond842ae62015-01-29 13:11:50 -0500227 All bool
Ash Wilson334277c2015-01-29 09:08:52 -0500228}
229
230// ToCDNServiceUpdateMap converts a Removal into a request body fragment suitable for the
231// Update call.
Jon Perrittdb0ae142016-03-13 00:33:41 -0600232func (opts Removal) ToCDNServiceUpdateMap() map[string]interface{} {
233 b := map[string]interface{}{"op": "remove"}
234 if opts.All {
235 b["path"] = opts.Path.renderRoot()
Ash Wilsond842ae62015-01-29 13:11:50 -0500236 } else {
Jon Perrittdb0ae142016-03-13 00:33:41 -0600237 b["path"] = opts.Path.renderIndex(opts.Index)
Ash Wilson334277c2015-01-29 09:08:52 -0500238 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600239 return b
Ash Wilson334277c2015-01-29 09:08:52 -0500240}
241
Jon Perrittdb0ae142016-03-13 00:33:41 -0600242// UpdateOpts is a slice of Patches used to update a CDN service
Jon Perritt1bda9c12015-01-29 12:16:08 -0700243type UpdateOpts []Patch
244
Ash Wilson299363d2015-01-29 10:49:40 -0500245// Update accepts a slice of Patch operations (Insertion, Append, Replacement or Removal) and
246// updates an existing CDN service using the values provided. idOrURL can be either the service's
247// URL or its ID. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
Jon Perrittb8713ad2015-01-21 15:02:58 -0700248// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
249// are valid options for idOrURL.
Jon Perritt3860b512016-03-29 12:01:48 -0500250func Update(c *gophercloud.ServiceClient, idOrURL string, opts UpdateOpts) (r UpdateResult) {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700251 var url string
252 if strings.Contains(idOrURL, "/") {
253 url = idOrURL
254 } else {
255 url = updateURL(c, idOrURL)
256 }
Jon Perritte7b86d12015-01-16 20:37:11 -0700257
Jon Perrittdb0ae142016-03-13 00:33:41 -0600258 b := make([]map[string]interface{}, len(opts))
Jon Perritt1bda9c12015-01-29 12:16:08 -0700259 for i, patch := range opts {
Jon Perrittdb0ae142016-03-13 00:33:41 -0600260 b[i] = patch.ToCDNServiceUpdateMap()
Jon Perritte7b86d12015-01-16 20:37:11 -0700261 }
262
Jon Perritta33da232016-03-02 04:43:08 -0600263 resp, err := c.Request("PATCH", url, &gophercloud.RequestOpts{
Jon Perrittdb0ae142016-03-13 00:33:41 -0600264 JSONBody: &b,
Ash Wilson4bf41a32015-02-12 15:52:44 -0500265 OkCodes: []int{202},
Jon Perritte7b86d12015-01-16 20:37:11 -0700266 })
Jon Perrittdb0ae142016-03-13 00:33:41 -0600267 r.Header = resp.Header
268 r.Err = err
jrperritt29ae6b32016-04-13 12:59:37 -0500269 return
Jon Perritte7b86d12015-01-16 20:37:11 -0700270}
271
Jon Perrittb8713ad2015-01-21 15:02:58 -0700272// Delete accepts a service's ID or its URL and deletes the CDN service
273// associated with it. For 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.
Jon Perritt3860b512016-03-29 12:01:48 -0500276func Delete(c *gophercloud.ServiceClient, idOrURL string) (r DeleteResult) {
Jon Perrittb8713ad2015-01-21 15:02:58 -0700277 var url string
278 if strings.Contains(idOrURL, "/") {
279 url = idOrURL
280 } else {
281 url = deleteURL(c, idOrURL)
282 }
Jon Perrittdb0ae142016-03-13 00:33:41 -0600283 _, r.Err = c.Delete(url, nil)
jrperritt29ae6b32016-04-13 12:59:37 -0500284 return
Jon Perritte7b86d12015-01-16 20:37:11 -0700285}