blob: 61fa59301e6fea35015aa7fe5c42e20e902ad459 [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 Hannaford79742542014-11-25 15:19:24 +010036 // Required - the name of your security group. If no value provided, null
Jamie Hannaforda493e642014-11-19 12:40:30 +010037 // will be set.
Jamie Hannaford0e750962014-11-24 16:04:38 +010038 Name string `json:"name"`
Jamie Hannaforda493e642014-11-19 12:40:30 +010039
Jamie Hannaford79742542014-11-25 15:19:24 +010040 // Required - the description of your security group. If no value provided,
Jamie Hannaforda493e642014-11-19 12:40:30 +010041 // null will be set.
Jamie Hannaford0e750962014-11-24 16:04:38 +010042 Description string `json:"description"`
Jamie Hannaforda493e642014-11-19 12:40:30 +010043}
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
Jamie Hannaford0e750962014-11-24 16:04:38 +010053var (
54 errName = errors.New("Name is a required field")
55 errDesc = errors.New("Description is a required field")
56)
57
Jamie Hannaford04abbc72014-11-21 11:27:57 +010058// ToSecGroupCreateMap builds the create options into a serializable format.
59func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
60 sg := make(map[string]interface{})
61
Jamie Hannaford0e750962014-11-24 16:04:38 +010062 if opts.Name == "" {
63 return sg, errName
Jamie Hannaford04abbc72014-11-21 11:27:57 +010064 }
Jamie Hannaford0e750962014-11-24 16:04:38 +010065 if opts.Description == "" {
66 return sg, errDesc
Jamie Hannaford04abbc72014-11-21 11:27:57 +010067 }
68
Jamie Hannaford0e750962014-11-24 16:04:38 +010069 sg["name"] = opts.Name
70 sg["description"] = opts.Description
71
Jamie Hannaford04abbc72014-11-21 11:27:57 +010072 return map[string]interface{}{"security_group": sg}, nil
73}
74
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010075// Create will create a new security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +010076func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
Jamie Hannaforda493e642014-11-19 12:40:30 +010077 var result CreateResult
78
Jamie Hannaford04abbc72014-11-21 11:27:57 +010079 reqBody, err := opts.ToSecGroupCreateMap()
80 if err != nil {
81 result.Err = err
82 return result
83 }
Jamie Hannaforda493e642014-11-19 12:40:30 +010084
85 _, result.Err = perigee.Request("POST", rootURL(client), perigee.Options{
86 Results: &result.Body,
87 ReqBody: &reqBody,
88 MoreHeaders: client.AuthenticatedHeaders(),
89 OkCodes: []int{200},
90 })
91
92 return result
93}
Jamie Hannafordb38dd312014-11-19 13:02:11 +010094
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010095// UpdateOpts is the struct responsible for updating an existing security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010096type UpdateOpts GroupOpts
97
Jamie Hannaford04abbc72014-11-21 11:27:57 +010098// UpdateOptsBuilder builds the update options into a serializable format.
99type UpdateOptsBuilder interface {
100 ToSecGroupUpdateMap() (map[string]interface{}, error)
101}
102
103// ToSecGroupUpdateMap builds the update options into a serializable format.
104func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
105 sg := make(map[string]interface{})
106
Jamie Hannaford0e750962014-11-24 16:04:38 +0100107 if opts.Name == "" {
108 return sg, errName
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100109 }
Jamie Hannaford0e750962014-11-24 16:04:38 +0100110 if opts.Description == "" {
111 return sg, errDesc
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100112 }
113
Jamie Hannaford0e750962014-11-24 16:04:38 +0100114 sg["name"] = opts.Name
115 sg["description"] = opts.Description
116
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100117 return map[string]interface{}{"security_group": sg}, nil
118}
119
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100120// Update will modify the mutable properties of a security group, notably its
121// name and description.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100122func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
Jamie Hannaford30c74662014-11-19 15:37:34 +0100123 var result UpdateResult
124
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100125 reqBody, err := opts.ToSecGroupUpdateMap()
126 if err != nil {
127 result.Err = err
128 return result
129 }
Jamie Hannaford30c74662014-11-19 15:37:34 +0100130
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100131 _, result.Err = perigee.Request("PUT", resourceURL(client, id), perigee.Options{
Jamie Hannaford30c74662014-11-19 15:37:34 +0100132 Results: &result.Body,
133 ReqBody: &reqBody,
134 MoreHeaders: client.AuthenticatedHeaders(),
135 OkCodes: []int{200},
136 })
137
138 return result
139}
140
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100141// Get will return details for a particular security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100142func Get(client *gophercloud.ServiceClient, id string) GetResult {
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100143 var result GetResult
144
145 _, result.Err = perigee.Request("GET", resourceURL(client, id), perigee.Options{
146 Results: &result.Body,
147 MoreHeaders: client.AuthenticatedHeaders(),
148 OkCodes: []int{200},
149 })
150
151 return result
152}
Jamie Hannafordd276e612014-11-19 13:56:28 +0100153
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100154// Delete will permanently delete a security group from the project.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100155func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannafordd276e612014-11-19 13:56:28 +0100156 var result gophercloud.ErrResult
157
158 _, result.Err = perigee.Request("DELETE", resourceURL(client, id), perigee.Options{
159 MoreHeaders: client.AuthenticatedHeaders(),
160 OkCodes: []int{202},
161 })
162
163 return result
164}
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100165
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100166// CreateRuleOpts represents the configuration for adding a new rule to an
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100167// existing security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100168type CreateRuleOpts struct {
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100169 // Required - the ID of the group that this rule will be added to.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100170 ParentGroupID string `json:"parent_group_id"`
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100171
172 // Required - the lower bound of the port range that will be opened.
173 FromPort int `json:"from_port"`
174
175 // Required - the upper bound of the port range that will be opened.
176 ToPort int `json:"to_port"`
177
178 // Required - the protocol type that will be allowed, e.g. TCP.
179 IPProtocol string `json:"ip_protocol"`
180
181 // ONLY required if FromGroupID is blank. This represents the IP range that
182 // will be the source of network traffic to your security group. Use
183 // 0.0.0.0/0 to allow all IP addresses.
184 CIDR string `json:"cidr,omitempty"`
185
186 // ONLY required if CIDR is blank. This value represents the ID of a group
187 // that forwards traffic to the parent group. So, instead of accepting
188 // network traffic from an entire IP range, you can instead refine the
189 // inbound source by an existing security group.
190 FromGroupID string `json:"group_id,omitempty"`
191}
192
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100193// CreateRuleOptsBuilder builds the create rule options into a serializable format.
194type CreateRuleOptsBuilder interface {
195 ToRuleCreateMap() (map[string]interface{}, error)
196}
197
198// ToRuleCreateMap builds the create rule options into a serializable format.
199func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
200 rule := make(map[string]interface{})
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100201
Jamie Hannaford2f226172014-11-25 11:52:25 +0100202 if opts.ParentGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100203 return rule, errors.New("A ParentGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100204 }
205 if opts.FromPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100206 return rule, errors.New("A FromPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100207 }
208 if opts.ToPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100209 return rule, errors.New("A ToPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100210 }
211 if opts.IPProtocol == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100212 return rule, errors.New("A IPProtocol must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100213 }
214 if opts.CIDR == "" && opts.FromGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100215 return rule, errors.New("A CIDR or FromGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100216 }
217
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100218 rule["parent_group_id"] = opts.ParentGroupID
219 rule["from_port"] = opts.FromPort
220 rule["to_port"] = opts.ToPort
221 rule["ip_protocol"] = opts.IPProtocol
222
223 if opts.CIDR != "" {
224 rule["cidr"] = opts.CIDR
225 }
226 if opts.FromGroupID != "" {
227 rule["from_group_id"] = opts.FromGroupID
228 }
229
230 return map[string]interface{}{"security_group_rule": rule}, nil
231}
232
233// CreateRule will add a new rule to an existing security group (whose ID is
234// specified in CreateRuleOpts). You have the option of controlling inbound
235// traffic from either an IP range (CIDR) or from another security group.
236func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
237 var result CreateRuleResult
238
239 reqBody, err := opts.ToRuleCreateMap()
240 if err != nil {
241 result.Err = err
242 return result
243 }
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100244
245 _, result.Err = perigee.Request("POST", rootRuleURL(client), perigee.Options{
246 Results: &result.Body,
247 ReqBody: &reqBody,
248 MoreHeaders: client.AuthenticatedHeaders(),
249 OkCodes: []int{200},
250 })
251
252 return result
253}
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100254
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100255// DeleteRule will permanently delete a rule from a security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100256func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100257 var result gophercloud.ErrResult
258
259 _, result.Err = perigee.Request("DELETE", resourceRuleURL(client, id), perigee.Options{
260 MoreHeaders: client.AuthenticatedHeaders(),
261 OkCodes: []int{202},
262 })
263
264 return result
265}
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100266
267func actionMap(prefix, groupName string) map[string]map[string]string {
268 return map[string]map[string]string{
269 prefix + "SecurityGroup": map[string]string{"name": groupName},
270 }
271}
272
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100273// AddServerToGroup will associate a server and a security group, enforcing the
274// rules of the group on the server.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100275func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
276 var result gophercloud.ErrResult
277
278 _, result.Err = perigee.Request("POST", serverActionURL(client, serverID), perigee.Options{
279 Results: &result.Body,
280 ReqBody: actionMap("add", groupName),
281 MoreHeaders: client.AuthenticatedHeaders(),
Jamie Hannafordd8ac5bb2014-11-20 12:01:37 +0100282 OkCodes: []int{202},
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100283 })
284
285 return result
286}
287
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100288// RemoveServerFromGroup will disassociate a server from a security group.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100289func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
290 var result gophercloud.ErrResult
291
292 _, result.Err = perigee.Request("POST", serverActionURL(client, serverID), perigee.Options{
293 Results: &result.Body,
294 ReqBody: actionMap("remove", groupName),
295 MoreHeaders: client.AuthenticatedHeaders(),
Jamie Hannafordd8ac5bb2014-11-20 12:01:37 +0100296 OkCodes: []int{202},
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100297 })
298
299 return result
300}