blob: f8d88d3d48708dd617bdd038ccc1204e9a324e74 [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 Hannaford924c09d2014-11-19 12:05:38 +01006 "github.com/rackspace/gophercloud"
7 "github.com/rackspace/gophercloud/pagination"
8)
9
Jamie Hannaford19151792014-11-19 12:46:47 +010010func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
Jamie Hannaford924c09d2014-11-19 12:05:38 +010011 createPage := func(r pagination.PageResult) pagination.Page {
12 return SecurityGroupPage{pagination.SinglePageBase(r)}
13 }
14
Jamie Hannaford19151792014-11-19 12:46:47 +010015 return pagination.NewPager(client, url, createPage)
16}
17
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010018// List will return a collection of all the security groups for a particular
19// tenant.
Jamie Hannaford19151792014-11-19 12:46:47 +010020func List(client *gophercloud.ServiceClient) pagination.Pager {
21 return commonList(client, rootURL(client))
22}
23
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010024// ListByServer will return a collection of all the security groups which are
25// associated with a particular server.
Jamie Hannaford19151792014-11-19 12:46:47 +010026func ListByServer(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
27 return commonList(client, listByServerURL(client, serverID))
Jamie Hannaford924c09d2014-11-19 12:05:38 +010028}
Jamie Hannaforda493e642014-11-19 12:40:30 +010029
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010030// GroupOpts is the underlying struct responsible for creating or updating
31// security groups. It therefore represents the mutable attributes of a
32// security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010033type GroupOpts struct {
Jamie Hannaford415ff942014-11-25 15:25:57 +010034 // Required - the name of your security group.
Jamie Hannaford0e750962014-11-24 16:04:38 +010035 Name string `json:"name"`
Jamie Hannaforda493e642014-11-19 12:40:30 +010036
Jamie Hannaford415ff942014-11-25 15:25:57 +010037 // Required - the description of your security group.
Jamie Hannaford0e750962014-11-24 16:04:38 +010038 Description string `json:"description"`
Jamie Hannaforda493e642014-11-19 12:40:30 +010039}
40
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010041// CreateOpts is the struct responsible for creating a security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010042type CreateOpts GroupOpts
43
Jamie Hannaford04abbc72014-11-21 11:27:57 +010044// CreateOptsBuilder builds the create options into a serializable format.
45type CreateOptsBuilder interface {
46 ToSecGroupCreateMap() (map[string]interface{}, error)
47}
48
Jamie Hannaford0e750962014-11-24 16:04:38 +010049var (
50 errName = errors.New("Name is a required field")
51 errDesc = errors.New("Description is a required field")
52)
53
Jamie Hannaford04abbc72014-11-21 11:27:57 +010054// ToSecGroupCreateMap builds the create options into a serializable format.
55func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
56 sg := make(map[string]interface{})
57
Jamie Hannaford0e750962014-11-24 16:04:38 +010058 if opts.Name == "" {
59 return sg, errName
Jamie Hannaford04abbc72014-11-21 11:27:57 +010060 }
Jamie Hannaford0e750962014-11-24 16:04:38 +010061 if opts.Description == "" {
62 return sg, errDesc
Jamie Hannaford04abbc72014-11-21 11:27:57 +010063 }
64
Jamie Hannaford0e750962014-11-24 16:04:38 +010065 sg["name"] = opts.Name
66 sg["description"] = opts.Description
67
Jamie Hannaford04abbc72014-11-21 11:27:57 +010068 return map[string]interface{}{"security_group": sg}, nil
69}
70
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010071// Create will create a new security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +010072func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
Jamie Hannaforda493e642014-11-19 12:40:30 +010073 var result CreateResult
74
Jamie Hannaford04abbc72014-11-21 11:27:57 +010075 reqBody, err := opts.ToSecGroupCreateMap()
76 if err != nil {
77 result.Err = err
78 return result
79 }
Jamie Hannaforda493e642014-11-19 12:40:30 +010080
Ash Wilson4bf41a32015-02-12 15:52:44 -050081 _, result.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{
82 JSONResponse: &result.Body,
83 JSONBody: &reqBody,
84 OkCodes: []int{200},
Jamie Hannaforda493e642014-11-19 12:40:30 +010085 })
86
87 return result
88}
Jamie Hannafordb38dd312014-11-19 13:02:11 +010089
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010090// UpdateOpts is the struct responsible for updating an existing security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010091type UpdateOpts GroupOpts
92
Jamie Hannaford04abbc72014-11-21 11:27:57 +010093// UpdateOptsBuilder builds the update options into a serializable format.
94type UpdateOptsBuilder interface {
95 ToSecGroupUpdateMap() (map[string]interface{}, error)
96}
97
98// ToSecGroupUpdateMap builds the update options into a serializable format.
99func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
100 sg := make(map[string]interface{})
101
Jamie Hannaford0e750962014-11-24 16:04:38 +0100102 if opts.Name == "" {
103 return sg, errName
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100104 }
Jamie Hannaford0e750962014-11-24 16:04:38 +0100105 if opts.Description == "" {
106 return sg, errDesc
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100107 }
108
Jamie Hannaford0e750962014-11-24 16:04:38 +0100109 sg["name"] = opts.Name
110 sg["description"] = opts.Description
111
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100112 return map[string]interface{}{"security_group": sg}, nil
113}
114
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100115// Update will modify the mutable properties of a security group, notably its
116// name and description.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100117func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
Jamie Hannaford30c74662014-11-19 15:37:34 +0100118 var result UpdateResult
119
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100120 reqBody, err := opts.ToSecGroupUpdateMap()
121 if err != nil {
122 result.Err = err
123 return result
124 }
Jamie Hannaford30c74662014-11-19 15:37:34 +0100125
Ash Wilson59fb6c42015-02-12 16:21:13 -0500126 _, result.Err = client.Request("PUT", resourceURL(client, id), gophercloud.RequestOpts{
127 JSONResponse: &result.Body,
128 JSONBody: &reqBody,
129 OkCodes: []int{200},
Jamie Hannaford30c74662014-11-19 15:37:34 +0100130 })
131
132 return result
133}
134
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100135// Get will return details for a particular security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100136func Get(client *gophercloud.ServiceClient, id string) GetResult {
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100137 var result GetResult
138
Ash Wilson59fb6c42015-02-12 16:21:13 -0500139 _, result.Err = client.Request("GET", resourceURL(client, id), gophercloud.RequestOpts{
140 JSONResponse: &result.Body,
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100141 })
142
143 return result
144}
Jamie Hannafordd276e612014-11-19 13:56:28 +0100145
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100146// Delete will permanently delete a security group from the project.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100147func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannafordd276e612014-11-19 13:56:28 +0100148 var result gophercloud.ErrResult
149
Jamie Hannafordc530ba12015-03-23 17:50:46 +0100150 _, result.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{})
Jamie Hannafordd276e612014-11-19 13:56:28 +0100151
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.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100159 ParentGroupID string `json:"parent_group_id"`
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100160
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
Jamie Hannaford2f226172014-11-25 11:52:25 +0100191 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 != "" {
Long Nguyenca51f012015-02-16 15:52:22 -0500216 rule["group_id"] = opts.FromGroupID
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100217 }
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
Ash Wilson4bf41a32015-02-12 15:52:44 -0500234 _, result.Err = client.Request("POST", rootRuleURL(client), gophercloud.RequestOpts{
235 JSONResponse: &result.Body,
236 JSONBody: &reqBody,
237 OkCodes: []int{200},
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100238 })
239
240 return result
241}
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100242
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100243// DeleteRule will permanently delete a rule from a security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100244func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100245 var result gophercloud.ErrResult
246
Jamie Hannafordc530ba12015-03-23 17:50:46 +0100247 _, result.Err = client.Request("DELETE", resourceRuleURL(client, id), gophercloud.RequestOpts{})
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100248
249 return result
250}
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100251
252func actionMap(prefix, groupName string) map[string]map[string]string {
253 return map[string]map[string]string{
254 prefix + "SecurityGroup": map[string]string{"name": groupName},
255 }
256}
257
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100258// AddServerToGroup will associate a server and a security group, enforcing the
259// rules of the group on the server.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100260func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
261 var result gophercloud.ErrResult
262
Ash Wilson59fb6c42015-02-12 16:21:13 -0500263 _, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
264 JSONResponse: &result.Body,
265 JSONBody: actionMap("add", groupName),
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100266 })
267
268 return result
269}
270
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100271// RemoveServerFromGroup will disassociate a server from a security group.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100272func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
273 var result gophercloud.ErrResult
274
Ash Wilson59fb6c42015-02-12 16:21:13 -0500275 _, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
276 JSONResponse: &result.Body,
277 JSONBody: actionMap("remove", groupName),
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100278 })
279
280 return result
281}