blob: 8fa1e6dbe2218a23963da5e29af58e19a28d68f4 [file] [log] [blame]
Jamie Hannaford89f9af22014-09-17 12:21:48 +02001package subnets
Jamie Hannaford0708c002014-09-17 16:08:49 +02002
3import (
Jon Perritt7ab13282015-06-28 18:47:19 -06004 "fmt"
5
Jamie Hannaford0708c002014-09-17 16:08:49 +02006 "github.com/rackspace/gophercloud"
Jamie Hannaford0708c002014-09-17 16:08:49 +02007 "github.com/rackspace/gophercloud/pagination"
8)
9
Jamie Hannaforda2976ab2014-10-09 10:32:58 +020010// AdminState gives users a solid type to work with for create and update
11// operations. It is recommended that users use the `Up` and `Down` enums.
12type AdminState *bool
13
14// Convenience vars for AdminStateUp values.
15var (
16 iTrue = true
17 iFalse = false
18
19 Up AdminState = &iTrue
20 Down AdminState = &iFalse
21)
22
Jon Perritt04851d32014-10-14 02:07:13 -050023// ListOptsBuilder allows extensions to add additional parameters to the
24// List request.
25type ListOptsBuilder interface {
Jon Perritt26780d52014-10-14 11:35:58 -050026 ToSubnetListQuery() (string, error)
Jon Perritt04851d32014-10-14 02:07:13 -050027}
28
Jamie Hannaford686c4962014-09-23 10:46:20 +020029// ListOpts allows the filtering and sorting of paginated collections through
30// the API. Filtering is achieved by passing in struct field values that map to
31// the subnet attributes you want to see returned. SortKey allows you to sort
32// by a particular subnet attribute. SortDir sets the direction, and is either
33// `asc' or `desc'. Marker and Limit are used for pagination.
Jamie Hannaford0708c002014-09-17 16:08:49 +020034type ListOpts struct {
Jamie Hannaford5c6e9962014-10-02 10:34:14 +020035 Name string `q:"name"`
36 EnableDHCP *bool `q:"enable_dhcp"`
37 NetworkID string `q:"network_id"`
38 TenantID string `q:"tenant_id"`
39 IPVersion int `q:"ip_version"`
40 GatewayIP string `q:"gateway_ip"`
41 CIDR string `q:"cidr"`
42 ID string `q:"id"`
43 Limit int `q:"limit"`
44 Marker string `q:"marker"`
45 SortKey string `q:"sort_key"`
46 SortDir string `q:"sort_dir"`
Jamie Hannaford0708c002014-09-17 16:08:49 +020047}
48
Jon Perritt26780d52014-10-14 11:35:58 -050049// ToSubnetListQuery formats a ListOpts into a query string.
50func (opts ListOpts) ToSubnetListQuery() (string, error) {
Jon Perritt04851d32014-10-14 02:07:13 -050051 q, err := gophercloud.BuildQueryString(opts)
52 if err != nil {
53 return "", err
54 }
55 return q.String(), nil
56}
57
Jamie Hannaford686c4962014-09-23 10:46:20 +020058// List returns a Pager which allows you to iterate over a collection of
59// subnets. It accepts a ListOpts struct, which allows you to filter and sort
60// the returned collection for greater efficiency.
61//
62// Default policy settings return only those subnets that are owned by the tenant
Alex Gaynora6d5f9f2014-10-27 10:52:32 -070063// who submits the request, unless the request is submitted by a user with
Jamie Hannaford686c4962014-09-23 10:46:20 +020064// administrative rights.
Jon Perritt04851d32014-10-14 02:07:13 -050065func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
66 url := listURL(c)
67 if opts != nil {
Jon Perritt26780d52014-10-14 11:35:58 -050068 query, err := opts.ToSubnetListQuery()
Jon Perritt04851d32014-10-14 02:07:13 -050069 if err != nil {
70 return pagination.Pager{Err: err}
71 }
72 url += query
Jamie Hannaford92523e32014-10-02 11:08:36 +020073 }
Jamie Hannaford0708c002014-09-17 16:08:49 +020074
Ash Wilsonb8b16f82014-10-20 10:19:49 -040075 return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
76 return SubnetPage{pagination.LinkedPageBase{PageResult: r}}
Jamie Hannaford0708c002014-09-17 16:08:49 +020077 })
78}
79
Jamie Hannaford686c4962014-09-23 10:46:20 +020080// Get retrieves a specific subnet based on its unique ID.
Jamie Hannafordd9036422014-09-23 17:50:24 +020081func Get(c *gophercloud.ServiceClient, id string) GetResult {
82 var res GetResult
Jamie Hannaford059e1502015-03-24 16:20:32 +010083 _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
Jamie Hannafordd9036422014-09-23 17:50:24 +020084 return res
Jamie Hannaford0708c002014-09-17 16:08:49 +020085}
Jamie Hannaford63631432014-09-18 11:40:09 +020086
Jamie Hannaford686c4962014-09-23 10:46:20 +020087// Valid IP types
Jamie Hannaford63631432014-09-18 11:40:09 +020088const (
89 IPv4 = 4
90 IPv6 = 6
91)
92
Jon Perritt04851d32014-10-14 02:07:13 -050093// CreateOptsBuilder is the interface options structs have to satisfy in order
94// to be used in the main Create operation in this package. Since many
95// extensions decorate or modify the common logic, it is useful for them to
96// satisfy a basic interface in order for them to be used.
97type CreateOptsBuilder interface {
98 ToSubnetCreateMap() (map[string]interface{}, error)
99}
100
Jamie Hannaford686c4962014-09-23 10:46:20 +0200101// CreateOpts represents the attributes used when creating a new subnet.
Jamie Hannaford965ae702014-09-22 14:58:19 +0200102type CreateOpts struct {
Jamie Hannaford63631432014-09-18 11:40:09 +0200103 // Required
104 NetworkID string
105 CIDR string
106 // Optional
107 Name string
108 TenantID string
109 AllocationPools []AllocationPool
110 GatewayIP string
Joe Topjianf92ae6c2016-04-06 21:24:43 -0600111 NoGateway bool
Jamie Hannaford63631432014-09-18 11:40:09 +0200112 IPVersion int
Jamie Hannaford63631432014-09-18 11:40:09 +0200113 EnableDHCP *bool
Jamie Hannaford965ae702014-09-22 14:58:19 +0200114 DNSNameservers []string
Jamie Hannaford5d93f562014-10-09 10:53:32 +0200115 HostRoutes []HostRoute
Jamie Hannaford63631432014-09-18 11:40:09 +0200116}
117
Jon Perritt04851d32014-10-14 02:07:13 -0500118// ToSubnetCreateMap casts a CreateOpts struct to a map.
119func (opts CreateOpts) ToSubnetCreateMap() (map[string]interface{}, error) {
120 s := make(map[string]interface{})
Jamie Hannafordd9036422014-09-23 17:50:24 +0200121
Jamie Hannaford63631432014-09-18 11:40:09 +0200122 if opts.NetworkID == "" {
Jon Perritt04851d32014-10-14 02:07:13 -0500123 return nil, errNetworkIDRequired
Jamie Hannaford63631432014-09-18 11:40:09 +0200124 }
125 if opts.CIDR == "" {
Jon Perritt04851d32014-10-14 02:07:13 -0500126 return nil, errCIDRRequired
Jamie Hannaford63631432014-09-18 11:40:09 +0200127 }
128 if opts.IPVersion != 0 && opts.IPVersion != IPv4 && opts.IPVersion != IPv6 {
Jon Perritt04851d32014-10-14 02:07:13 -0500129 return nil, errInvalidIPType
Jamie Hannaford63631432014-09-18 11:40:09 +0200130 }
131
Joe Topjian2524d112016-04-07 15:41:39 +0000132 // Both GatewayIP and NoGateway should not be set
133 if opts.GatewayIP != "" && opts.NoGateway {
134 return nil, errInvalidGatewayConfig
135 }
136
Jon Perritt04851d32014-10-14 02:07:13 -0500137 s["network_id"] = opts.NetworkID
138 s["cidr"] = opts.CIDR
Jamie Hannaford63631432014-09-18 11:40:09 +0200139
Jon Perritt04851d32014-10-14 02:07:13 -0500140 if opts.EnableDHCP != nil {
141 s["enable_dhcp"] = &opts.EnableDHCP
142 }
143 if opts.Name != "" {
144 s["name"] = opts.Name
145 }
146 if opts.GatewayIP != "" {
147 s["gateway_ip"] = opts.GatewayIP
Joe Topjianf92ae6c2016-04-06 21:24:43 -0600148 } else if opts.NoGateway {
149 s["gateway_ip"] = nil
Jon Perritt04851d32014-10-14 02:07:13 -0500150 }
151 if opts.TenantID != "" {
152 s["tenant_id"] = opts.TenantID
153 }
Jamie Hannaford63631432014-09-18 11:40:09 +0200154 if opts.IPVersion != 0 {
Jon Perritt04851d32014-10-14 02:07:13 -0500155 s["ip_version"] = opts.IPVersion
Jamie Hannaford63631432014-09-18 11:40:09 +0200156 }
Jamie Hannaford63631432014-09-18 11:40:09 +0200157 if len(opts.AllocationPools) != 0 {
Jon Perritt04851d32014-10-14 02:07:13 -0500158 s["allocation_pools"] = opts.AllocationPools
Jamie Hannaford63631432014-09-18 11:40:09 +0200159 }
Jamie Hannaford965ae702014-09-22 14:58:19 +0200160 if len(opts.DNSNameservers) != 0 {
Jon Perritt04851d32014-10-14 02:07:13 -0500161 s["dns_nameservers"] = opts.DNSNameservers
Jamie Hannaford965ae702014-09-22 14:58:19 +0200162 }
163 if len(opts.HostRoutes) != 0 {
Jon Perritt04851d32014-10-14 02:07:13 -0500164 s["host_routes"] = opts.HostRoutes
165 }
166
167 return map[string]interface{}{"subnet": s}, nil
168}
169
170// Create accepts a CreateOpts struct and creates a new subnet using the values
171// provided. You must remember to provide a valid NetworkID, CIDR and IP version.
172func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
173 var res CreateResult
174
175 reqBody, err := opts.ToSubnetCreateMap()
176 if err != nil {
177 res.Err = err
178 return res
Jamie Hannaford965ae702014-09-22 14:58:19 +0200179 }
Jamie Hannaford63631432014-09-18 11:40:09 +0200180
Jamie Hannaford059e1502015-03-24 16:20:32 +0100181 _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
Jamie Hannafordd9036422014-09-23 17:50:24 +0200182 return res
Jamie Hannaford63631432014-09-18 11:40:09 +0200183}
Jamie Hannafordd11e20c2014-09-18 12:03:01 +0200184
Jon Perritt04851d32014-10-14 02:07:13 -0500185// UpdateOptsBuilder allows extensions to add additional parameters to the
186// Update request.
187type UpdateOptsBuilder interface {
188 ToSubnetUpdateMap() (map[string]interface{}, error)
189}
190
Jamie Hannaford686c4962014-09-23 10:46:20 +0200191// UpdateOpts represents the attributes used when updating an existing subnet.
Jamie Hannaford965ae702014-09-22 14:58:19 +0200192type UpdateOpts struct {
193 Name string
194 GatewayIP string
Joe Topjianf92ae6c2016-04-06 21:24:43 -0600195 NoGateway bool
Jamie Hannaford965ae702014-09-22 14:58:19 +0200196 DNSNameservers []string
Jamie Hannaford5d93f562014-10-09 10:53:32 +0200197 HostRoutes []HostRoute
Jamie Hannaford965ae702014-09-22 14:58:19 +0200198 EnableDHCP *bool
199}
Jamie Hannafordd11e20c2014-09-18 12:03:01 +0200200
Jon Perritt04851d32014-10-14 02:07:13 -0500201// ToSubnetUpdateMap casts an UpdateOpts struct to a map.
202func (opts UpdateOpts) ToSubnetUpdateMap() (map[string]interface{}, error) {
203 s := make(map[string]interface{})
204
Joe Topjian2524d112016-04-07 15:41:39 +0000205 // Both GatewayIP and NoGateway should not be set
206 if opts.GatewayIP != "" && opts.NoGateway {
207 return nil, errInvalidGatewayConfig
208 }
209
Jon Perritt04851d32014-10-14 02:07:13 -0500210 if opts.EnableDHCP != nil {
211 s["enable_dhcp"] = &opts.EnableDHCP
212 }
213 if opts.Name != "" {
214 s["name"] = opts.Name
215 }
216 if opts.GatewayIP != "" {
217 s["gateway_ip"] = opts.GatewayIP
Joe Topjianf92ae6c2016-04-06 21:24:43 -0600218 } else if opts.NoGateway {
219 s["gateway_ip"] = nil
Jon Perritt04851d32014-10-14 02:07:13 -0500220 }
Keith Byrnefa1b3082015-09-10 17:08:44 +0100221 if opts.DNSNameservers != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500222 s["dns_nameservers"] = opts.DNSNameservers
223 }
Keith Byrnefa1b3082015-09-10 17:08:44 +0100224 if opts.HostRoutes != nil {
Jon Perritt04851d32014-10-14 02:07:13 -0500225 s["host_routes"] = opts.HostRoutes
226 }
227
228 return map[string]interface{}{"subnet": s}, nil
229}
230
Jamie Hannaford686c4962014-09-23 10:46:20 +0200231// Update accepts a UpdateOpts struct and updates an existing subnet using the
232// values provided.
Jon Perritt04851d32014-10-14 02:07:13 -0500233func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
Jamie Hannafordd9036422014-09-23 17:50:24 +0200234 var res UpdateResult
Jon Perritt04851d32014-10-14 02:07:13 -0500235
236 reqBody, err := opts.ToSubnetUpdateMap()
237 if err != nil {
238 res.Err = err
239 return res
240 }
241
Jamie Hannaford059e1502015-03-24 16:20:32 +0100242 _, res.Err = c.Put(updateURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
243 OkCodes: []int{200, 201},
Jamie Hannafordd11e20c2014-09-18 12:03:01 +0200244 })
Jamie Hannafordd11e20c2014-09-18 12:03:01 +0200245
Jamie Hannafordd9036422014-09-23 17:50:24 +0200246 return res
Jamie Hannafordd11e20c2014-09-18 12:03:01 +0200247}
248
Jamie Hannaford686c4962014-09-23 10:46:20 +0200249// Delete accepts a unique ID and deletes the subnet associated with it.
Jamie Hannafordd9036422014-09-23 17:50:24 +0200250func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
251 var res DeleteResult
Jamie Hannaford059e1502015-03-24 16:20:32 +0100252 _, res.Err = c.Delete(deleteURL(c, id), nil)
Jamie Hannafordd9036422014-09-23 17:50:24 +0200253 return res
Jamie Hannafordd11e20c2014-09-18 12:03:01 +0200254}
Jon Perritt7ab13282015-06-28 18:47:19 -0600255
jrperritt5d1d8352015-06-28 19:08:09 -0600256// IDFromName is a convenience function that returns a subnet's ID given its name.
Jon Perritt7ab13282015-06-28 18:47:19 -0600257func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
258 subnetCount := 0
259 subnetID := ""
260 if name == "" {
jrperrittdbec8c02015-06-28 18:59:43 -0600261 return "", fmt.Errorf("A subnet name must be provided.")
Jon Perritt7ab13282015-06-28 18:47:19 -0600262 }
263 pager := List(client, nil)
264 pager.EachPage(func(page pagination.Page) (bool, error) {
265 subnetList, err := ExtractSubnets(page)
266 if err != nil {
267 return false, err
268 }
269
270 for _, s := range subnetList {
271 if s.Name == name {
272 subnetCount++
273 subnetID = s.ID
274 }
275 }
276 return true, nil
277 })
278
279 switch subnetCount {
280 case 0:
jrperrittdbec8c02015-06-28 18:59:43 -0600281 return "", fmt.Errorf("Unable to find subnet: %s", name)
Jon Perritt7ab13282015-06-28 18:47:19 -0600282 case 1:
283 return subnetID, nil
284 default:
jrperrittdbec8c02015-06-28 18:59:43 -0600285 return "", fmt.Errorf("Found %d subnets matching %s", subnetCount, name)
Jon Perritt7ab13282015-06-28 18:47:19 -0600286 }
287}