blob: 31473102ca44ae8d5dbd9f9868c5dcd8268f42a7 [file] [log] [blame]
Jamie Hannaford924c09d2014-11-19 12:05:38 +01001package secgroups
2
3import (
Jamie Hannaford8badf1e2014-11-19 14:39:26 +01004 "errors"
5
Jamie Hannaforda493e642014-11-19 12:40:30 +01006 "github.com/racker/perigee"
7
Jamie Hannaford924c09d2014-11-19 12:05:38 +01008 "github.com/rackspace/gophercloud"
9 "github.com/rackspace/gophercloud/pagination"
10)
11
Jamie Hannaford19151792014-11-19 12:46:47 +010012func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
Jamie Hannaford924c09d2014-11-19 12:05:38 +010013 createPage := func(r pagination.PageResult) pagination.Page {
14 return SecurityGroupPage{pagination.SinglePageBase(r)}
15 }
16
Jamie Hannaford19151792014-11-19 12:46:47 +010017 return pagination.NewPager(client, url, createPage)
18}
19
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010020// List will return a collection of all the security groups for a particular
21// tenant.
Jamie Hannaford19151792014-11-19 12:46:47 +010022func List(client *gophercloud.ServiceClient) pagination.Pager {
23 return commonList(client, rootURL(client))
24}
25
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010026// ListByServer will return a collection of all the security groups which are
27// associated with a particular server.
Jamie Hannaford19151792014-11-19 12:46:47 +010028func ListByServer(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
29 return commonList(client, listByServerURL(client, serverID))
Jamie Hannaford924c09d2014-11-19 12:05:38 +010030}
Jamie Hannaforda493e642014-11-19 12:40:30 +010031
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010032// GroupOpts is the underlying struct responsible for creating or updating
33// security groups. It therefore represents the mutable attributes of a
34// security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010035type GroupOpts struct {
Jamie Hannaforda493e642014-11-19 12:40:30 +010036 // Optional - the name of your security group. If no value provided, null
37 // will be set.
38 Name string `json:"name,omitempty"`
39
40 // Optional - the description of your security group. If no value provided,
41 // null will be set.
42 Description string `json:"description,omitempty"`
43}
44
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010045// CreateOpts is the struct responsible for creating a security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010046type CreateOpts GroupOpts
47
Jamie Hannaford04abbc72014-11-21 11:27:57 +010048// CreateOptsBuilder builds the create options into a serializable format.
49type CreateOptsBuilder interface {
50 ToSecGroupCreateMap() (map[string]interface{}, error)
51}
52
53// ToSecGroupCreateMap builds the create options into a serializable format.
54func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
55 sg := make(map[string]interface{})
56
57 if opts.Name != "" {
58 sg["name"] = opts.Name
59 }
60 if opts.Description != "" {
61 sg["description"] = opts.Description
62 }
63
64 return map[string]interface{}{"security_group": sg}, nil
65}
66
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010067// Create will create a new security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +010068func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
Jamie Hannaforda493e642014-11-19 12:40:30 +010069 var result CreateResult
70
Jamie Hannaford04abbc72014-11-21 11:27:57 +010071 reqBody, err := opts.ToSecGroupCreateMap()
72 if err != nil {
73 result.Err = err
74 return result
75 }
Jamie Hannaforda493e642014-11-19 12:40:30 +010076
77 _, result.Err = perigee.Request("POST", rootURL(client), perigee.Options{
78 Results: &result.Body,
79 ReqBody: &reqBody,
80 MoreHeaders: client.AuthenticatedHeaders(),
81 OkCodes: []int{200},
82 })
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
99 if opts.Name != "" {
100 sg["name"] = opts.Name
101 }
102 if opts.Description != "" {
103 sg["description"] = opts.Description
104 }
105
106 return map[string]interface{}{"security_group": sg}, nil
107}
108
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100109// Update will modify the mutable properties of a security group, notably its
110// name and description.
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100111func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
Jamie Hannaford30c74662014-11-19 15:37:34 +0100112 var result UpdateResult
113
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100114 reqBody, err := opts.ToSecGroupUpdateMap()
115 if err != nil {
116 result.Err = err
117 return result
118 }
Jamie Hannaford30c74662014-11-19 15:37:34 +0100119
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100120 _, result.Err = perigee.Request("PUT", resourceURL(client, id), perigee.Options{
Jamie Hannaford30c74662014-11-19 15:37:34 +0100121 Results: &result.Body,
122 ReqBody: &reqBody,
123 MoreHeaders: client.AuthenticatedHeaders(),
124 OkCodes: []int{200},
125 })
126
127 return result
128}
129
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100130// Get will return details for a particular security group.
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100131func Get(client *gophercloud.ServiceClient, id string) GetResult {
132 var result GetResult
133
134 _, result.Err = perigee.Request("GET", resourceURL(client, id), perigee.Options{
135 Results: &result.Body,
136 MoreHeaders: client.AuthenticatedHeaders(),
137 OkCodes: []int{200},
138 })
139
140 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 Hannafordd276e612014-11-19 13:56:28 +0100144func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
145 var result gophercloud.ErrResult
146
147 _, result.Err = perigee.Request("DELETE", resourceURL(client, id), perigee.Options{
148 MoreHeaders: client.AuthenticatedHeaders(),
149 OkCodes: []int{202},
150 })
151
152 return result
153}
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100154
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100155// CreateRuleOpts represents the configuration for adding a new rule to an
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100156// existing security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100157type CreateRuleOpts struct {
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100158 // Required - the ID of the group that this rule will be added to.
159 ParentGroupID string `json:"parent_group_id"`
160
161 // Required - the lower bound of the port range that will be opened.
162 FromPort int `json:"from_port"`
163
164 // Required - the upper bound of the port range that will be opened.
165 ToPort int `json:"to_port"`
166
167 // Required - the protocol type that will be allowed, e.g. TCP.
168 IPProtocol string `json:"ip_protocol"`
169
170 // ONLY required if FromGroupID is blank. This represents the IP range that
171 // will be the source of network traffic to your security group. Use
172 // 0.0.0.0/0 to allow all IP addresses.
173 CIDR string `json:"cidr,omitempty"`
174
175 // ONLY required if CIDR is blank. This value represents the ID of a group
176 // that forwards traffic to the parent group. So, instead of accepting
177 // network traffic from an entire IP range, you can instead refine the
178 // inbound source by an existing security group.
179 FromGroupID string `json:"group_id,omitempty"`
180}
181
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100182// CreateRuleOptsBuilder builds the create rule options into a serializable format.
183type CreateRuleOptsBuilder interface {
184 ToRuleCreateMap() (map[string]interface{}, error)
185}
186
187// ToRuleCreateMap builds the create rule options into a serializable format.
188func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
189 rule := make(map[string]interface{})
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100190
191 if opts.ParentGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100192 return rule, errors.New("A ParentGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100193 }
194 if opts.FromPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100195 return rule, errors.New("A FromPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100196 }
197 if opts.ToPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100198 return rule, errors.New("A ToPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100199 }
200 if opts.IPProtocol == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100201 return rule, errors.New("A IPProtocol must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100202 }
203 if opts.CIDR == "" && opts.FromGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100204 return rule, errors.New("A CIDR or FromGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100205 }
206
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100207 rule["parent_group_id"] = opts.ParentGroupID
208 rule["from_port"] = opts.FromPort
209 rule["to_port"] = opts.ToPort
210 rule["ip_protocol"] = opts.IPProtocol
211
212 if opts.CIDR != "" {
213 rule["cidr"] = opts.CIDR
214 }
215 if opts.FromGroupID != "" {
216 rule["from_group_id"] = opts.FromGroupID
217 }
218
219 return map[string]interface{}{"security_group_rule": rule}, nil
220}
221
222// CreateRule will add a new rule to an existing security group (whose ID is
223// specified in CreateRuleOpts). You have the option of controlling inbound
224// traffic from either an IP range (CIDR) or from another security group.
225func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
226 var result CreateRuleResult
227
228 reqBody, err := opts.ToRuleCreateMap()
229 if err != nil {
230 result.Err = err
231 return result
232 }
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100233
234 _, result.Err = perigee.Request("POST", rootRuleURL(client), perigee.Options{
235 Results: &result.Body,
236 ReqBody: &reqBody,
237 MoreHeaders: client.AuthenticatedHeaders(),
238 OkCodes: []int{200},
239 })
240
241 return result
242}
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100243
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100244// DeleteRule will permanently delete a rule from a security group.
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100245func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
246 var result gophercloud.ErrResult
247
248 _, result.Err = perigee.Request("DELETE", resourceRuleURL(client, id), perigee.Options{
249 MoreHeaders: client.AuthenticatedHeaders(),
250 OkCodes: []int{202},
251 })
252
253 return result
254}
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100255
256func actionMap(prefix, groupName string) map[string]map[string]string {
257 return map[string]map[string]string{
258 prefix + "SecurityGroup": map[string]string{"name": groupName},
259 }
260}
261
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100262// AddServerToGroup will associate a server and a security group, enforcing the
263// rules of the group on the server.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100264func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
265 var result gophercloud.ErrResult
266
267 _, result.Err = perigee.Request("POST", serverActionURL(client, serverID), perigee.Options{
268 Results: &result.Body,
269 ReqBody: actionMap("add", groupName),
270 MoreHeaders: client.AuthenticatedHeaders(),
Jamie Hannafordd8ac5bb2014-11-20 12:01:37 +0100271 OkCodes: []int{202},
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100272 })
273
274 return result
275}
276
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100277// RemoveServerFromGroup will disassociate a server from a security group.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100278func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
279 var result gophercloud.ErrResult
280
281 _, result.Err = perigee.Request("POST", serverActionURL(client, serverID), perigee.Options{
282 Results: &result.Body,
283 ReqBody: actionMap("remove", groupName),
284 MoreHeaders: client.AuthenticatedHeaders(),
Jamie Hannafordd8ac5bb2014-11-20 12:01:37 +0100285 OkCodes: []int{202},
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100286 })
287
288 return result
289}