blob: a0bb0255b5ba229c53e08461c88e22e190b80de7 [file] [log] [blame]
Jamie Hannaford924c09d2014-11-19 12:05:38 +01001package secgroups
2
3import (
Jon Perritt27249f42016-02-18 10:35:59 -06004 "github.com/gophercloud/gophercloud"
5 "github.com/gophercloud/gophercloud/pagination"
Jamie Hannaford924c09d2014-11-19 12:05:38 +01006)
7
Jamie Hannaford19151792014-11-19 12:46:47 +01008func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
Jamie Hannaford924c09d2014-11-19 12:05:38 +01009 createPage := func(r pagination.PageResult) pagination.Page {
10 return SecurityGroupPage{pagination.SinglePageBase(r)}
11 }
12
Jamie Hannaford19151792014-11-19 12:46:47 +010013 return pagination.NewPager(client, url, createPage)
14}
15
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010016// List will return a collection of all the security groups for a particular
17// tenant.
Jamie Hannaford19151792014-11-19 12:46:47 +010018func List(client *gophercloud.ServiceClient) pagination.Pager {
19 return commonList(client, rootURL(client))
20}
21
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010022// ListByServer will return a collection of all the security groups which are
23// associated with a particular server.
Jamie Hannaford19151792014-11-19 12:46:47 +010024func ListByServer(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
25 return commonList(client, listByServerURL(client, serverID))
Jamie Hannaford924c09d2014-11-19 12:05:38 +010026}
Jamie Hannaforda493e642014-11-19 12:40:30 +010027
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010028// GroupOpts is the underlying struct responsible for creating or updating
29// security groups. It therefore represents the mutable attributes of a
30// security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010031type GroupOpts struct {
Jamie Hannaford415ff942014-11-25 15:25:57 +010032 // Required - the name of your security group.
Jamie Hannaford0e750962014-11-24 16:04:38 +010033 Name string `json:"name"`
Jamie Hannaforda493e642014-11-19 12:40:30 +010034
Jamie Hannaford415ff942014-11-25 15:25:57 +010035 // Required - the description of your security group.
Jamie Hannaford0e750962014-11-24 16:04:38 +010036 Description string `json:"description"`
Jamie Hannaforda493e642014-11-19 12:40:30 +010037}
38
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010039// CreateOpts is the struct responsible for creating a security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010040type CreateOpts GroupOpts
41
Jamie Hannaford04abbc72014-11-21 11:27:57 +010042// CreateOptsBuilder builds the create options into a serializable format.
43type CreateOptsBuilder interface {
44 ToSecGroupCreateMap() (map[string]interface{}, error)
45}
46
47// ToSecGroupCreateMap builds the create options into a serializable format.
48func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
49 sg := make(map[string]interface{})
50
Jamie Hannaford0e750962014-11-24 16:04:38 +010051 if opts.Name == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -060052 err := gophercloud.ErrMissingInput{}
53 err.Function = "secgroups.ToSecGroupCreateMap"
54 err.Argument = "secgroups.CreateOpts.Name"
55 return nil, err
Jamie Hannaford04abbc72014-11-21 11:27:57 +010056 }
Jamie Hannaford0e750962014-11-24 16:04:38 +010057 if opts.Description == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -060058 err := gophercloud.ErrMissingInput{}
59 err.Function = "secgroups.ToSecGroupCreateMap"
60 err.Argument = "secgroups.CreateOpts.Description"
61 return nil, err
Jamie Hannaford04abbc72014-11-21 11:27:57 +010062 }
63
Jamie Hannaford0e750962014-11-24 16:04:38 +010064 sg["name"] = opts.Name
65 sg["description"] = opts.Description
66
Jamie Hannaford04abbc72014-11-21 11:27:57 +010067 return map[string]interface{}{"security_group": sg}, nil
68}
69
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010070// Create will create a new security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +010071func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
Jamie Hannaforda493e642014-11-19 12:40:30 +010072 var result CreateResult
73
Jamie Hannaford04abbc72014-11-21 11:27:57 +010074 reqBody, err := opts.ToSecGroupCreateMap()
75 if err != nil {
76 result.Err = err
77 return result
78 }
Jamie Hannaforda493e642014-11-19 12:40:30 +010079
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +010080 _, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
81 OkCodes: []int{200},
Jamie Hannaforda493e642014-11-19 12:40:30 +010082 })
83
84 return result
85}
Jamie Hannafordb38dd312014-11-19 13:02:11 +010086
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010087// UpdateOpts is the struct responsible for updating an existing security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010088type UpdateOpts GroupOpts
89
Jamie Hannaford04abbc72014-11-21 11:27:57 +010090// UpdateOptsBuilder builds the update options into a serializable format.
91type UpdateOptsBuilder interface {
92 ToSecGroupUpdateMap() (map[string]interface{}, error)
93}
94
95// ToSecGroupUpdateMap builds the update options into a serializable format.
96func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
97 sg := make(map[string]interface{})
98
Jamie Hannaford0e750962014-11-24 16:04:38 +010099 if opts.Name == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -0600100 err := gophercloud.ErrMissingInput{}
101 err.Function = "secgroups.ToSecGroupUpdateMap"
102 err.Argument = "secgroups.UpdateOpts.Name"
103 return nil, err
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100104 }
Jamie Hannaford0e750962014-11-24 16:04:38 +0100105 if opts.Description == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -0600106 err := gophercloud.ErrMissingInput{}
107 err.Function = "secgroups.ToSecGroupUpdateMap"
108 err.Argument = "secgroups.UpdateOpts.Description"
109 return nil, err
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100110 }
111
Jamie Hannaford0e750962014-11-24 16:04:38 +0100112 sg["name"] = opts.Name
113 sg["description"] = opts.Description
114
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100115 return map[string]interface{}{"security_group": sg}, nil
116}
117
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100118// Update will modify the mutable properties of a security group, notably its
119// name and description.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100120func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
Jamie Hannaford30c74662014-11-19 15:37:34 +0100121 var result UpdateResult
122
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100123 reqBody, err := opts.ToSecGroupUpdateMap()
124 if err != nil {
125 result.Err = err
126 return result
127 }
Jamie Hannaford30c74662014-11-19 15:37:34 +0100128
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100129 _, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
130 OkCodes: []int{200},
Jamie Hannaford30c74662014-11-19 15:37:34 +0100131 })
132
133 return result
134}
135
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100136// Get will return details for a particular security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100137func Get(client *gophercloud.ServiceClient, id string) GetResult {
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100138 var result GetResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100139 _, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100140 return result
141}
Jamie Hannafordd276e612014-11-19 13:56:28 +0100142
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100143// Delete will permanently delete a security group from the project.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100144func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannafordd276e612014-11-19 13:56:28 +0100145 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100146 _, result.Err = client.Delete(resourceURL(client, id), nil)
Jamie Hannafordd276e612014-11-19 13:56:28 +0100147 return result
148}
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100149
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100150// CreateRuleOpts represents the configuration for adding a new rule to an
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100151// existing security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100152type CreateRuleOpts struct {
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100153 // Required - the ID of the group that this rule will be added to.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100154 ParentGroupID string `json:"parent_group_id"`
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100155
156 // Required - the lower bound of the port range that will be opened.
157 FromPort int `json:"from_port"`
158
159 // Required - the upper bound of the port range that will be opened.
160 ToPort int `json:"to_port"`
161
162 // Required - the protocol type that will be allowed, e.g. TCP.
163 IPProtocol string `json:"ip_protocol"`
164
165 // ONLY required if FromGroupID is blank. This represents the IP range that
166 // will be the source of network traffic to your security group. Use
167 // 0.0.0.0/0 to allow all IP addresses.
168 CIDR string `json:"cidr,omitempty"`
169
170 // ONLY required if CIDR is blank. This value represents the ID of a group
171 // that forwards traffic to the parent group. So, instead of accepting
172 // network traffic from an entire IP range, you can instead refine the
173 // inbound source by an existing security group.
174 FromGroupID string `json:"group_id,omitempty"`
175}
176
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100177// CreateRuleOptsBuilder builds the create rule options into a serializable format.
178type CreateRuleOptsBuilder interface {
179 ToRuleCreateMap() (map[string]interface{}, error)
180}
181
182// ToRuleCreateMap builds the create rule options into a serializable format.
183func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
Jamie Hannaford2f226172014-11-25 11:52:25 +0100184 if opts.ParentGroupID == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -0600185 err := gophercloud.ErrMissingInput{}
186 err.Function = "secgroups.ToRuleCreateMap"
187 err.Argument = "secgroups.CreateRuleOpts.ParentGroupID"
188 return nil, err
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100189 }
190 if opts.FromPort == 0 {
Jon Perrittf094fef2016-03-07 01:41:59 -0600191 err := gophercloud.ErrMissingInput{}
192 err.Function = "secgroups.ToRuleCreateMap"
193 err.Argument = "secgroups.CreateRuleOpts.FromPort"
194 return nil, err
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100195 }
196 if opts.ToPort == 0 {
Jon Perrittf094fef2016-03-07 01:41:59 -0600197 err := gophercloud.ErrMissingInput{}
198 err.Function = "secgroups.ToRuleCreateMap"
199 err.Argument = "secgroups.CreateRuleOpts.ToPort"
200 return nil, err
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100201 }
202 if opts.IPProtocol == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -0600203 err := gophercloud.ErrMissingInput{}
204 err.Function = "secgroups.ToRuleCreateMap"
205 err.Argument = "secgroups.CreateRuleOpts.IPProtocol"
206 return nil, err
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100207 }
208 if opts.CIDR == "" && opts.FromGroupID == "" {
Jon Perrittf094fef2016-03-07 01:41:59 -0600209 err := gophercloud.ErrMissingInput{}
210 err.Function = "secgroups.ToRuleCreateMap"
211 err.Argument = "secgroups.CreateRuleOpts.CIDR/secgroups.CreateRuleOpts.FromGroupID"
212 return nil, err
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100213 }
214
Jon Perrittf094fef2016-03-07 01:41:59 -0600215 rule := make(map[string]interface{})
216
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100217 rule["parent_group_id"] = opts.ParentGroupID
218 rule["from_port"] = opts.FromPort
219 rule["to_port"] = opts.ToPort
220 rule["ip_protocol"] = opts.IPProtocol
221
222 if opts.CIDR != "" {
223 rule["cidr"] = opts.CIDR
224 }
225 if opts.FromGroupID != "" {
Long Nguyenca51f012015-02-16 15:52:22 -0500226 rule["group_id"] = opts.FromGroupID
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100227 }
228
229 return map[string]interface{}{"security_group_rule": rule}, nil
230}
231
232// CreateRule will add a new rule to an existing security group (whose ID is
233// specified in CreateRuleOpts). You have the option of controlling inbound
234// traffic from either an IP range (CIDR) or from another security group.
235func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
236 var result CreateRuleResult
237
238 reqBody, err := opts.ToRuleCreateMap()
239 if err != nil {
240 result.Err = err
241 return result
242 }
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100243
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100244 _, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
245 OkCodes: []int{200},
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100246 })
247
248 return result
249}
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100250
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100251// DeleteRule will permanently delete a rule from a security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100252func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100253 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100254 _, result.Err = client.Delete(resourceRuleURL(client, id), nil)
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100255 return result
256}
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100257
258func actionMap(prefix, groupName string) map[string]map[string]string {
259 return map[string]map[string]string{
260 prefix + "SecurityGroup": map[string]string{"name": groupName},
261 }
262}
263
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100264// AddServerToGroup will associate a server and a security group, enforcing the
265// rules of the group on the server.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100266func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
267 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100268 _, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100269 return result
270}
271
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100272// RemoveServerFromGroup will disassociate a server from a security group.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100273func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
274 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100275 _, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100276 return result
277}