blob: 4cef480222362944c5c01edaf1a6821b9efab9de [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
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +010081 _, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
82 OkCodes: []int{200},
Jamie Hannaforda493e642014-11-19 12:40:30 +010083 })
84
85 return result
86}
Jamie Hannafordb38dd312014-11-19 13:02:11 +010087
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +010088// UpdateOpts is the struct responsible for updating an existing security group.
Jamie Hannaford30c74662014-11-19 15:37:34 +010089type UpdateOpts GroupOpts
90
Jamie Hannaford04abbc72014-11-21 11:27:57 +010091// UpdateOptsBuilder builds the update options into a serializable format.
92type UpdateOptsBuilder interface {
93 ToSecGroupUpdateMap() (map[string]interface{}, error)
94}
95
96// ToSecGroupUpdateMap builds the update options into a serializable format.
97func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
98 sg := make(map[string]interface{})
99
Jamie Hannaford0e750962014-11-24 16:04:38 +0100100 if opts.Name == "" {
101 return sg, errName
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100102 }
Jamie Hannaford0e750962014-11-24 16:04:38 +0100103 if opts.Description == "" {
104 return sg, errDesc
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100105 }
106
Jamie Hannaford0e750962014-11-24 16:04:38 +0100107 sg["name"] = opts.Name
108 sg["description"] = opts.Description
109
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100110 return map[string]interface{}{"security_group": sg}, nil
111}
112
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100113// Update will modify the mutable properties of a security group, notably its
114// name and description.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100115func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
Jamie Hannaford30c74662014-11-19 15:37:34 +0100116 var result UpdateResult
117
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100118 reqBody, err := opts.ToSecGroupUpdateMap()
119 if err != nil {
120 result.Err = err
121 return result
122 }
Jamie Hannaford30c74662014-11-19 15:37:34 +0100123
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100124 _, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
125 OkCodes: []int{200},
Jamie Hannaford30c74662014-11-19 15:37:34 +0100126 })
127
128 return result
129}
130
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100131// Get will return details for a particular security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100132func Get(client *gophercloud.ServiceClient, id string) GetResult {
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100133 var result GetResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100134 _, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
Jamie Hannafordb38dd312014-11-19 13:02:11 +0100135 return result
136}
Jamie Hannafordd276e612014-11-19 13:56:28 +0100137
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100138// Delete will permanently delete a security group from the project.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100139func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannafordd276e612014-11-19 13:56:28 +0100140 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100141 _, result.Err = client.Delete(resourceURL(client, id), nil)
Jamie Hannafordd276e612014-11-19 13:56:28 +0100142 return result
143}
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100144
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100145// CreateRuleOpts represents the configuration for adding a new rule to an
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100146// existing security group.
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100147type CreateRuleOpts struct {
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100148 // Required - the ID of the group that this rule will be added to.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100149 ParentGroupID string `json:"parent_group_id"`
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100150
151 // Required - the lower bound of the port range that will be opened.
152 FromPort int `json:"from_port"`
153
154 // Required - the upper bound of the port range that will be opened.
155 ToPort int `json:"to_port"`
156
157 // Required - the protocol type that will be allowed, e.g. TCP.
158 IPProtocol string `json:"ip_protocol"`
159
160 // ONLY required if FromGroupID is blank. This represents the IP range that
161 // will be the source of network traffic to your security group. Use
162 // 0.0.0.0/0 to allow all IP addresses.
163 CIDR string `json:"cidr,omitempty"`
164
165 // ONLY required if CIDR is blank. This value represents the ID of a group
166 // that forwards traffic to the parent group. So, instead of accepting
167 // network traffic from an entire IP range, you can instead refine the
168 // inbound source by an existing security group.
169 FromGroupID string `json:"group_id,omitempty"`
170}
171
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100172// CreateRuleOptsBuilder builds the create rule options into a serializable format.
173type CreateRuleOptsBuilder interface {
174 ToRuleCreateMap() (map[string]interface{}, error)
175}
176
177// ToRuleCreateMap builds the create rule options into a serializable format.
178func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
179 rule := make(map[string]interface{})
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100180
Jamie Hannaford2f226172014-11-25 11:52:25 +0100181 if opts.ParentGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100182 return rule, errors.New("A ParentGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100183 }
184 if opts.FromPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100185 return rule, errors.New("A FromPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100186 }
187 if opts.ToPort == 0 {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100188 return rule, errors.New("A ToPort must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100189 }
190 if opts.IPProtocol == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100191 return rule, errors.New("A IPProtocol must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100192 }
193 if opts.CIDR == "" && opts.FromGroupID == "" {
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100194 return rule, errors.New("A CIDR or FromGroupID must be set")
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100195 }
196
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100197 rule["parent_group_id"] = opts.ParentGroupID
198 rule["from_port"] = opts.FromPort
199 rule["to_port"] = opts.ToPort
200 rule["ip_protocol"] = opts.IPProtocol
201
202 if opts.CIDR != "" {
203 rule["cidr"] = opts.CIDR
204 }
205 if opts.FromGroupID != "" {
Long Nguyenca51f012015-02-16 15:52:22 -0500206 rule["group_id"] = opts.FromGroupID
Jamie Hannaford04abbc72014-11-21 11:27:57 +0100207 }
208
209 return map[string]interface{}{"security_group_rule": rule}, nil
210}
211
212// CreateRule will add a new rule to an existing security group (whose ID is
213// specified in CreateRuleOpts). You have the option of controlling inbound
214// traffic from either an IP range (CIDR) or from another security group.
215func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
216 var result CreateRuleResult
217
218 reqBody, err := opts.ToRuleCreateMap()
219 if err != nil {
220 result.Err = err
221 return result
222 }
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100223
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100224 _, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
225 OkCodes: []int{200},
Jamie Hannaford8badf1e2014-11-19 14:39:26 +0100226 })
227
228 return result
229}
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100230
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100231// DeleteRule will permanently delete a rule from a security group.
Jamie Hannaford2f226172014-11-25 11:52:25 +0100232func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100233 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100234 _, result.Err = client.Delete(resourceRuleURL(client, id), nil)
Jamie Hannaford61f81ca2014-11-19 14:44:33 +0100235 return result
236}
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100237
238func actionMap(prefix, groupName string) map[string]map[string]string {
239 return map[string]map[string]string{
240 prefix + "SecurityGroup": map[string]string{"name": groupName},
241 }
242}
243
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100244// AddServerToGroup will associate a server and a security group, enforcing the
245// rules of the group on the server.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100246func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
247 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100248 _, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100249 return result
250}
251
Jamie Hannaford7f34d8e2014-11-20 12:24:55 +0100252// RemoveServerFromGroup will disassociate a server from a security group.
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100253func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
254 var result gophercloud.ErrResult
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100255 _, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
Jamie Hannaford740e4a32014-11-19 16:13:30 +0100256 return result
257}