blob: 8f0a7a032fd3cfe7421a353f43424a0deece22ba [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,
141 OkCodes: []int{200},
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100142 })
143
144 return result
145}
Jamie Hannafordd276e612014-11-19 13:56:28 +0100146
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100147// Delete will permanently delete a security group from the project.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100148func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannafordd276e612014-11-19 13:56:28 +0100149 var result gophercloud.ErrResult
150
Ash Wilson59fb6c42015-02-12 16:21:13 -0500151 _, result.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{
152 OkCodes: []int{202},
Jamie Hannafordd276e612014-11-19 13:56:28 +0100153 })
154
155 return result
156}
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100157
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100158// CreateRuleOpts represents the configuration for adding a new rule to an
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100159// existing security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100160type CreateRuleOpts struct {
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100161 // Required - the ID of the group that this rule will be added to.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100162 ParentGroupID string `json:"parent_group_id"`
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100163
164 // Required - the lower bound of the port range that will be opened.
165 FromPort int `json:"from_port"`
166
167 // Required - the upper bound of the port range that will be opened.
168 ToPort int `json:"to_port"`
169
170 // Required - the protocol type that will be allowed, e.g. TCP.
171 IPProtocol string `json:"ip_protocol"`
172
173 // ONLY required if FromGroupID is blank. This represents the IP range that
174 // will be the source of network traffic to your security group. Use
175 // 0.0.0.0/0 to allow all IP addresses.
176 CIDR string `json:"cidr,omitempty"`
177
178 // ONLY required if CIDR is blank. This value represents the ID of a group
179 // that forwards traffic to the parent group. So, instead of accepting
180 // network traffic from an entire IP range, you can instead refine the
181 // inbound source by an existing security group.
182 FromGroupID string `json:"group_id,omitempty"`
183}
184
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100185// CreateRuleOptsBuilder builds the create rule options into a serializable format.
186type CreateRuleOptsBuilder interface {
187 ToRuleCreateMap() (map[string]interface{}, error)
188}
189
190// ToRuleCreateMap builds the create rule options into a serializable format.
191func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
192 rule := make(map[string]interface{})
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100193
Jamie Hannaford2f226172014-11-25 11:52:25 +0100194 if opts.ParentGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100195 return rule, errors.New("A ParentGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100196 }
197 if opts.FromPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100198 return rule, errors.New("A FromPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100199 }
200 if opts.ToPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100201 return rule, errors.New("A ToPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100202 }
203 if opts.IPProtocol == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100204 return rule, errors.New("A IPProtocol must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100205 }
206 if opts.CIDR == "" && opts.FromGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100207 return rule, errors.New("A CIDR or FromGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100208 }
209
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100210 rule["parent_group_id"] = opts.ParentGroupID
211 rule["from_port"] = opts.FromPort
212 rule["to_port"] = opts.ToPort
213 rule["ip_protocol"] = opts.IPProtocol
214
215 if opts.CIDR != "" {
216 rule["cidr"] = opts.CIDR
217 }
218 if opts.FromGroupID != "" {
Long Nguyenca51f012015-02-16 15:52:22 -0500219 rule["group_id"] = opts.FromGroupID
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100220 }
221
222 return map[string]interface{}{"security_group_rule": rule}, nil
223}
224
225// CreateRule will add a new rule to an existing security group (whose ID is
226// specified in CreateRuleOpts). You have the option of controlling inbound
227// traffic from either an IP range (CIDR) or from another security group.
228func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
229 var result CreateRuleResult
230
231 reqBody, err := opts.ToRuleCreateMap()
232 if err != nil {
233 result.Err = err
234 return result
235 }
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100236
Ash Wilson4bf41a32015-02-12 15:52:44 -0500237 _, result.Err = client.Request("POST", rootRuleURL(client), gophercloud.RequestOpts{
238 JSONResponse: &result.Body,
239 JSONBody: &reqBody,
240 OkCodes: []int{200},
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100241 })
242
243 return result
244}
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100245
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100246// DeleteRule will permanently delete a rule from a security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100247func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100248 var result gophercloud.ErrResult
249
Ash Wilson59fb6c42015-02-12 16:21:13 -0500250 _, result.Err = client.Request("DELETE", resourceRuleURL(client, id), gophercloud.RequestOpts{
251 OkCodes: []int{202},
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100252 })
253
254 return result
255}
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100256
257func actionMap(prefix, groupName string) map[string]map[string]string {
258 return map[string]map[string]string{
259 prefix + "SecurityGroup": map[string]string{"name": groupName},
260 }
261}
262
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100263// AddServerToGroup will associate a server and a security group, enforcing the
264// rules of the group on the server.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100265func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
266 var result gophercloud.ErrResult
267
Ash Wilson59fb6c42015-02-12 16:21:13 -0500268 _, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
269 JSONResponse: &result.Body,
270 JSONBody: actionMap("add", groupName),
271 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
Ash Wilson59fb6c42015-02-12 16:21:13 -0500281 _, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
282 JSONResponse: &result.Body,
283 JSONBody: actionMap("remove", groupName),
284 OkCodes: []int{202},
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100285 })
286
287 return result
288}