| OLD | NEW |
| (Empty) | |
| 1 # Copyright (c) 2006-2011 Mitch Garnaat http://garnaat.org/ |
| 2 # Copyright (c) 2011, Eucalyptus Systems, Inc. |
| 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining a |
| 5 # copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 8 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 9 # persons to whom the Software is furnished to do so, subject to the fol- |
| 10 # lowing conditions: |
| 11 # |
| 12 # The above copyright notice and this permission notice shall be included |
| 13 # in all copies or substantial portions of the Software. |
| 14 # |
| 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 21 # IN THE SOFTWARE. |
| 22 |
| 23 """ |
| 24 Represents an EC2 Security Group |
| 25 """ |
| 26 from boto.ec2.ec2object import TaggedEC2Object |
| 27 from boto.exception import BotoClientError |
| 28 |
| 29 class SecurityGroup(TaggedEC2Object): |
| 30 |
| 31 def __init__(self, connection=None, owner_id=None, |
| 32 name=None, description=None, id=None): |
| 33 TaggedEC2Object.__init__(self, connection) |
| 34 self.id = id |
| 35 self.owner_id = owner_id |
| 36 self.name = name |
| 37 self.description = description |
| 38 self.vpc_id = None |
| 39 self.rules = IPPermissionsList() |
| 40 self.rules_egress = IPPermissionsList() |
| 41 |
| 42 def __repr__(self): |
| 43 return 'SecurityGroup:%s' % self.name |
| 44 |
| 45 def startElement(self, name, attrs, connection): |
| 46 retval = TaggedEC2Object.startElement(self, name, attrs, connection) |
| 47 if retval is not None: |
| 48 return retval |
| 49 if name == 'ipPermissions': |
| 50 return self.rules |
| 51 elif name == 'ipPermissionsEgress': |
| 52 return self.rules_egress |
| 53 else: |
| 54 return None |
| 55 |
| 56 def endElement(self, name, value, connection): |
| 57 if name == 'ownerId': |
| 58 self.owner_id = value |
| 59 elif name == 'groupId': |
| 60 self.id = value |
| 61 elif name == 'groupName': |
| 62 self.name = value |
| 63 elif name == 'vpcId': |
| 64 self.vpc_id = value |
| 65 elif name == 'groupDescription': |
| 66 self.description = value |
| 67 elif name == 'ipRanges': |
| 68 pass |
| 69 elif name == 'return': |
| 70 if value == 'false': |
| 71 self.status = False |
| 72 elif value == 'true': |
| 73 self.status = True |
| 74 else: |
| 75 raise Exception( |
| 76 'Unexpected value of status %s for group %s'%( |
| 77 value, |
| 78 self.name |
| 79 ) |
| 80 ) |
| 81 else: |
| 82 setattr(self, name, value) |
| 83 |
| 84 def delete(self): |
| 85 if self.vpc_id: |
| 86 return self.connection.delete_security_group(group_id=self.id) |
| 87 else: |
| 88 return self.connection.delete_security_group(self.name) |
| 89 |
| 90 def add_rule(self, ip_protocol, from_port, to_port, |
| 91 src_group_name, src_group_owner_id, cidr_ip, src_group_group_id
): |
| 92 """ |
| 93 Add a rule to the SecurityGroup object. Note that this method |
| 94 only changes the local version of the object. No information |
| 95 is sent to EC2. |
| 96 """ |
| 97 rule = IPPermissions(self) |
| 98 rule.ip_protocol = ip_protocol |
| 99 rule.from_port = from_port |
| 100 rule.to_port = to_port |
| 101 self.rules.append(rule) |
| 102 rule.add_grant(src_group_name, src_group_owner_id, cidr_ip, src_group_gr
oup_id) |
| 103 |
| 104 def remove_rule(self, ip_protocol, from_port, to_port, |
| 105 src_group_name, src_group_owner_id, cidr_ip, src_group_group
_id): |
| 106 """ |
| 107 Remove a rule to the SecurityGroup object. Note that this method |
| 108 only changes the local version of the object. No information |
| 109 is sent to EC2. |
| 110 """ |
| 111 target_rule = None |
| 112 for rule in self.rules: |
| 113 if rule.ip_protocol == ip_protocol: |
| 114 if rule.from_port == from_port: |
| 115 if rule.to_port == to_port: |
| 116 target_rule = rule |
| 117 target_grant = None |
| 118 for grant in rule.grants: |
| 119 if grant.name == src_group_name or grant.group_id ==
src_group_group_id: |
| 120 if grant.owner_id == src_group_owner_id: |
| 121 if grant.cidr_ip == cidr_ip: |
| 122 target_grant = grant |
| 123 if target_grant: |
| 124 rule.grants.remove(target_grant) |
| 125 if len(rule.grants) == 0: |
| 126 self.rules.remove(target_rule) |
| 127 |
| 128 def authorize(self, ip_protocol=None, from_port=None, to_port=None, |
| 129 cidr_ip=None, src_group=None): |
| 130 """ |
| 131 Add a new rule to this security group. |
| 132 You need to pass in either src_group_name |
| 133 OR ip_protocol, from_port, to_port, |
| 134 and cidr_ip. In other words, either you are authorizing another |
| 135 group or you are authorizing some ip-based rule. |
| 136 |
| 137 :type ip_protocol: string |
| 138 :param ip_protocol: Either tcp | udp | icmp |
| 139 |
| 140 :type from_port: int |
| 141 :param from_port: The beginning port number you are enabling |
| 142 |
| 143 :type to_port: int |
| 144 :param to_port: The ending port number you are enabling |
| 145 |
| 146 :type cidr_ip: string or list of strings |
| 147 :param cidr_ip: The CIDR block you are providing access to. |
| 148 See http://en.wikipedia.org/wiki/Classless_Inter-Domain_
Routing |
| 149 |
| 150 :type src_group: :class:`boto.ec2.securitygroup.SecurityGroup` or |
| 151 :class:`boto.ec2.securitygroup.GroupOrCIDR` |
| 152 :param src_group: The Security Group you are granting access to. |
| 153 |
| 154 :rtype: bool |
| 155 :return: True if successful. |
| 156 """ |
| 157 group_name = None |
| 158 if not self.vpc_id: |
| 159 group_name = self.name |
| 160 group_id = None |
| 161 if self.vpc_id: |
| 162 group_id = self.id |
| 163 src_group_name = None |
| 164 src_group_owner_id = None |
| 165 src_group_group_id = None |
| 166 if src_group: |
| 167 cidr_ip = None |
| 168 src_group_owner_id = src_group.owner_id |
| 169 if not self.vpc_id: |
| 170 src_group_name = src_group.name |
| 171 else: |
| 172 if hasattr(src_group, 'group_id'): |
| 173 src_group_group_id = src_group.group_id |
| 174 else: |
| 175 src_group_group_id = src_group.id |
| 176 status = self.connection.authorize_security_group(group_name, |
| 177 src_group_name, |
| 178 src_group_owner_id, |
| 179 ip_protocol, |
| 180 from_port, |
| 181 to_port, |
| 182 cidr_ip, |
| 183 group_id, |
| 184 src_group_group_id) |
| 185 if status: |
| 186 if not isinstance(cidr_ip, list): |
| 187 cidr_ip = [cidr_ip] |
| 188 for single_cidr_ip in cidr_ip: |
| 189 self.add_rule(ip_protocol, from_port, to_port, src_group_name, |
| 190 src_group_owner_id, single_cidr_ip, src_group_grou
p_id) |
| 191 return status |
| 192 |
| 193 def revoke(self, ip_protocol=None, from_port=None, to_port=None, |
| 194 cidr_ip=None, src_group=None): |
| 195 group_name = None |
| 196 if not self.vpc_id: |
| 197 group_name = self.name |
| 198 group_id = None |
| 199 if self.vpc_id: |
| 200 group_id = self.id |
| 201 src_group_name = None |
| 202 src_group_owner_id = None |
| 203 src_group_group_id = None |
| 204 if src_group: |
| 205 cidr_ip = None |
| 206 src_group_owner_id = src_group.owner_id |
| 207 if not self.vpc_id: |
| 208 src_group_name = src_group.name |
| 209 else: |
| 210 if hasattr(src_group, 'group_id'): |
| 211 src_group_group_id = src_group.group_id |
| 212 else: |
| 213 src_group_group_id = src_group.id |
| 214 status = self.connection.revoke_security_group(group_name, |
| 215 src_group_name, |
| 216 src_group_owner_id, |
| 217 ip_protocol, |
| 218 from_port, |
| 219 to_port, |
| 220 cidr_ip, |
| 221 group_id, |
| 222 src_group_group_id) |
| 223 if status: |
| 224 self.remove_rule(ip_protocol, from_port, to_port, src_group_name, |
| 225 src_group_owner_id, cidr_ip, src_group_group_id) |
| 226 return status |
| 227 |
| 228 def copy_to_region(self, region, name=None): |
| 229 """ |
| 230 Create a copy of this security group in another region. |
| 231 Note that the new security group will be a separate entity |
| 232 and will not stay in sync automatically after the copy |
| 233 operation. |
| 234 |
| 235 :type region: :class:`boto.ec2.regioninfo.RegionInfo` |
| 236 :param region: The region to which this security group will be copied. |
| 237 |
| 238 :type name: string |
| 239 :param name: The name of the copy. If not supplied, the copy |
| 240 will have the same name as this security group. |
| 241 |
| 242 :rtype: :class:`boto.ec2.securitygroup.SecurityGroup` |
| 243 :return: The new security group. |
| 244 """ |
| 245 if region.name == self.region: |
| 246 raise BotoClientError('Unable to copy to the same Region') |
| 247 conn_params = self.connection.get_params() |
| 248 rconn = region.connect(**conn_params) |
| 249 sg = rconn.create_security_group(name or self.name, self.description) |
| 250 source_groups = [] |
| 251 for rule in self.rules: |
| 252 for grant in rule.grants: |
| 253 grant_nom = grant.name or grant.group_id |
| 254 if grant_nom: |
| 255 if grant_nom not in source_groups: |
| 256 source_groups.append(grant_nom) |
| 257 sg.authorize(None, None, None, None, grant) |
| 258 else: |
| 259 sg.authorize(rule.ip_protocol, rule.from_port, rule.to_port, |
| 260 grant.cidr_ip) |
| 261 return sg |
| 262 |
| 263 def instances(self): |
| 264 """ |
| 265 Find all of the current instances that are running within this |
| 266 security group. |
| 267 |
| 268 :rtype: list of :class:`boto.ec2.instance.Instance` |
| 269 :return: A list of Instance objects |
| 270 """ |
| 271 # It would be more efficient to do this with filters now |
| 272 # but not all services that implement EC2 API support filters. |
| 273 instances = [] |
| 274 rs = self.connection.get_all_instances() |
| 275 for reservation in rs: |
| 276 uses_group = [g.name for g in reservation.groups if g.name == self.n
ame] |
| 277 if uses_group: |
| 278 instances.extend(reservation.instances) |
| 279 return instances |
| 280 |
| 281 class IPPermissionsList(list): |
| 282 |
| 283 def startElement(self, name, attrs, connection): |
| 284 if name == 'item': |
| 285 self.append(IPPermissions(self)) |
| 286 return self[-1] |
| 287 return None |
| 288 |
| 289 def endElement(self, name, value, connection): |
| 290 pass |
| 291 |
| 292 class IPPermissions(object): |
| 293 |
| 294 def __init__(self, parent=None): |
| 295 self.parent = parent |
| 296 self.ip_protocol = None |
| 297 self.from_port = None |
| 298 self.to_port = None |
| 299 self.grants = [] |
| 300 |
| 301 def __repr__(self): |
| 302 return 'IPPermissions:%s(%s-%s)' % (self.ip_protocol, |
| 303 self.from_port, self.to_port) |
| 304 |
| 305 def startElement(self, name, attrs, connection): |
| 306 if name == 'item': |
| 307 self.grants.append(GroupOrCIDR(self)) |
| 308 return self.grants[-1] |
| 309 return None |
| 310 |
| 311 def endElement(self, name, value, connection): |
| 312 if name == 'ipProtocol': |
| 313 self.ip_protocol = value |
| 314 elif name == 'fromPort': |
| 315 self.from_port = value |
| 316 elif name == 'toPort': |
| 317 self.to_port = value |
| 318 else: |
| 319 setattr(self, name, value) |
| 320 |
| 321 def add_grant(self, name=None, owner_id=None, cidr_ip=None, group_id=None): |
| 322 grant = GroupOrCIDR(self) |
| 323 grant.owner_id = owner_id |
| 324 grant.group_id = group_id |
| 325 grant.name = name |
| 326 grant.cidr_ip = cidr_ip |
| 327 self.grants.append(grant) |
| 328 return grant |
| 329 |
| 330 class GroupOrCIDR(object): |
| 331 |
| 332 def __init__(self, parent=None): |
| 333 self.owner_id = None |
| 334 self.group_id = None |
| 335 self.name = None |
| 336 self.cidr_ip = None |
| 337 |
| 338 def __repr__(self): |
| 339 if self.cidr_ip: |
| 340 return '%s' % self.cidr_ip |
| 341 else: |
| 342 return '%s-%s' % (self.name or self.group_id, self.owner_id) |
| 343 |
| 344 def startElement(self, name, attrs, connection): |
| 345 return None |
| 346 |
| 347 def endElement(self, name, value, connection): |
| 348 if name == 'userId': |
| 349 self.owner_id = value |
| 350 elif name == 'groupId': |
| 351 self.group_id = value |
| 352 elif name == 'groupName': |
| 353 self.name = value |
| 354 if name == 'cidrIp': |
| 355 self.cidr_ip = value |
| 356 else: |
| 357 setattr(self, name, value) |
| OLD | NEW |