summaryrefslogtreecommitdiff
path: root/boto/ec2
diff options
context:
space:
mode:
authorMitch.Garnaat <Mitch.Garnaat@604d75c7-a419-0410-a38f-bde1a0bd1dbf>2008-12-10 11:43:15 +0000
committerMitch.Garnaat <Mitch.Garnaat@604d75c7-a419-0410-a38f-bde1a0bd1dbf>2008-12-10 11:43:15 +0000
commitc829df67b9b852a52956347aaaceab2e21538646 (patch)
tree1b91e63bc748f9b951e2f36c136b5c89aa2b8f67 /boto/ec2
parentf091147c248b2c250e6ac002ea622cad3affdd44 (diff)
downloadboto-c829df67b9b852a52956347aaaceab2e21538646.tar.gz
Checking in changes to support regions in EC2.
Diffstat (limited to 'boto/ec2')
-rw-r--r--boto/ec2/__init__.py21
-rw-r--r--boto/ec2/address.py16
-rw-r--r--boto/ec2/connection.py256
-rw-r--r--boto/ec2/ec2object.py41
-rw-r--r--boto/ec2/image.py14
-rw-r--r--boto/ec2/instance.py14
-rw-r--r--boto/ec2/keypair.py67
-rw-r--r--boto/ec2/regioninfo.py60
-rw-r--r--boto/ec2/securitygroup.py97
-rw-r--r--boto/ec2/snapshot.py8
-rw-r--r--boto/ec2/volume.py8
-rw-r--r--boto/ec2/zone.py8
12 files changed, 536 insertions, 74 deletions
diff --git a/boto/ec2/__init__.py b/boto/ec2/__init__.py
index 449bd162..0cc3277c 100644
--- a/boto/ec2/__init__.py
+++ b/boto/ec2/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
+# Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
@@ -19,5 +19,22 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
+"""
+This module provides an interface to the Elastic Compute Cloud (EC2)
+service from AWS.
+"""
+from boto.ec2.connection import EC2Connection
-
+def regions(**kw_params):
+ """
+ Get all available regions for the EC2 service.
+ You may pass any of the arguments accepted by the EC2Connection
+ object's constructor as keyword arguments and they will be
+ passed along to the EC2Connection object.
+
+ @rtype: list
+ @return: A list of L{RegionInfo<boto.ec2.regioninfo.RegionInfo>}
+ """
+ c = EC2Connection(**kw_params)
+ return c.get_all_regions()
+
diff --git a/boto/ec2/address.py b/boto/ec2/address.py
index eec06e71..b2af1075 100644
--- a/boto/ec2/address.py
+++ b/boto/ec2/address.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
+# Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
@@ -23,19 +23,19 @@
Represents an EC2 Elastic IP Address
"""
-class Address:
+from boto.ec2.ec2object import EC2Object
+
+class Address(EC2Object):
- def __init__(self, connection=None):
+ def __init__(self, connection=None, public_ip=None, instance_id=None):
+ EC2Object.__init__(self, connection)
self.connection = connection
- self.public_ip = None
- self.instance_id = None
+ self.public_ip = public_ip
+ self.instance_id = instance_id
def __repr__(self):
return 'Address:%s' % self.public_ip
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'publicIp':
self.public_ip = value
diff --git a/boto/ec2/connection.py b/boto/ec2/connection.py
index 397e4154..7d7a8b17 100644
--- a/boto/ec2/connection.py
+++ b/boto/ec2/connection.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
+# Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
@@ -38,28 +38,46 @@ from boto.ec2.volume import Volume
from boto.ec2.snapshot import Snapshot
from boto.ec2.zone import Zone
from boto.ec2.securitygroup import SecurityGroup
+from boto.ec2.regioninfo import RegionInfo
from boto.exception import EC2ResponseError
class EC2Connection(AWSQueryConnection):
- APIVersion = boto.config.get('Boto', 'ec2_version', '2008-05-05')
+ APIVersion = boto.config.get('Boto', 'ec2_version', '2008-12-01')
+ DefaultRegionName = boto.config.get('Boto', 'ec2_region_name', 'us-east-1')
+ DefaultRegionEndpoint = boto.config.get('Boto', 'ec2_region_endpoint',
+ 'us-east-1.ec2.amazonaws.com')
SignatureVersion = '1'
ResponseError = EC2ResponseError
def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
is_secure=True, port=None, proxy=None, proxy_port=None,
- proxy_user=None, proxy_pass=None, host='ec2.amazonaws.com', debug=0,
- https_connection_factory=None):
+ proxy_user=None, proxy_pass=None, debug=0,
+ https_connection_factory=None, region=None):
"""
Init method to create a new connection to EC2.
B{Note:} The host argument is overridden by the host specified in the boto configuration file.
"""
- if config.has_option('Boto', 'ec2_host'):
- host = config.get('Boto', 'ec2_host')
+ if not region:
+ region = RegionInfo(self, self.DefaultRegionName, self.DefaultRegionEndpoint)
+ self.region = region
AWSQueryConnection.__init__(self, aws_access_key_id, aws_secret_access_key,
is_secure, port, proxy, proxy_port, proxy_user, proxy_pass,
- host, debug, https_connection_factory)
+ self.region.endpoint, debug, https_connection_factory)
+
+ def get_params(self):
+ """
+ Returns a dictionary containing the value of of all of the keyword
+ arguments passed when constructing this connection.
+ """
+ param_names = ['aws_access_key_id', 'aws_secret_access_key', 'is_secure',
+ 'port', 'proxy', 'proxy_port', 'proxy_user', 'proxy_pass',
+ 'debug', 'https_connection_factory']
+ params = {}
+ for name in param_names:
+ params[name] = getattr(self, name)
+ return params
# Image methods
@@ -146,11 +164,29 @@ class EC2Connection(AWSQueryConnection):
return None
def register_image(self, image_location):
+ """
+ Register an image.
+
+ @type image_location: string
+ @param image_location: Full path to your AMI manifest in Amazon S3 storage.
+
+ @rtype: string
+ @return: The new image id
+ """
params = {'ImageLocation':image_location}
rs = self.get_object('RegisterImage', params, ResultSet)
return rs.imageId
def deregister_image(self, image_id):
+ """
+ Unregister an AMI.
+
+ @type image_id: string
+ @param image_id: the ID of the Image to unregister
+
+ @rtype: bool
+ @return: True if successful
+ """
return self.get_status('DeregisterImage', {'ImageId':image_id})
# ImageAttribute methods
@@ -205,7 +241,7 @@ class EC2Connection(AWSQueryConnection):
def reset_image_attribute(self, image_id, attribute='launchPermission'):
"""
- Rresets an attribute of an AMI to its default value.
+ Resets an attribute of an AMI to its default value.
See http://docs.amazonwebservices.com/AWSEC2/2008-02-01/DeveloperGuide/ApiReference-Query-ResetImageAttribute.html
@type image_id: string
@@ -357,6 +393,17 @@ class EC2Connection(AWSQueryConnection):
# Zone methods
def get_all_zones(self, zones=None):
+ """
+ Get all Availability Zones associated with the current region.
+
+ @type zones: list
+ @param zones: Optional list of zones. If this list is present,
+ only the Zones associated with these zone names
+ will be returned.
+
+ @rtype: list of L{boto.ec2.zone.Zone}
+ @return: The requested Zone objects
+ """
params = {}
if zones:
self.build_list_params(params, zones, 'ZoneName')
@@ -365,26 +412,73 @@ class EC2Connection(AWSQueryConnection):
# Address methods
def get_all_addresses(self, addresses=None):
+ """
+ Get all EIP's associated with the current credentials.
+
+ @type addresses: list
+ @param addresses: Optional list of addresses. If this list is present,
+ only the Addresses associated with these addresses
+ will be returned.
+
+ @rtype: list of L{boto.ec2.address.Address}
+ @return: The requested Address objects
+ """
params = {}
if addresses:
self.build_list_params(params, addresses, 'PublicIp')
return self.get_list('DescribeAddresses', params, [('item', Address)])
def allocate_address(self):
- return self.get_object('AllocateAddress', None, Address)
+ """
+ Allocate a new Elastic IP address and associate it with your account.
- def release_address(self, public_ip):
- params = {'PublicIp' : public_ip}
- return self.get_status('ReleaseAddress', params)
+ @rtype: L{boto.ec2.address.Address}
+ @return: The newly allocated Address
+ """
+ return self.get_object('AllocateAddress', None, Address)
def associate_address(self, instance_id, public_ip):
+ """
+ Associate an Elastic IP address with a currently running instance.
+
+ @type instance_id: string
+ @param instance_id: The ID of the instance
+
+ @type public_ip: string
+ @param public_ip: The public IP address
+
+ @rtype: bool
+ @return: True if successful
+ """
params = {'InstanceId' : instance_id, 'PublicIp' : public_ip}
return self.get_status('AssociateAddress', params)
def disassociate_address(self, public_ip):
+ """
+ Disassociate an Elastic IP address from a currently running instance.
+
+ @type public_ip: string
+ @param public_ip: The public IP address
+
+ @rtype: bool
+ @return: True if successful
+ """
params = {'PublicIp' : public_ip}
return self.get_status('DisassociateAddress', params)
+ def release_address(self, public_ip):
+ """
+ Free up an Elastic IP address
+
+ @type public_ip: string
+ @param public_ip: The public IP address
+
+ @rtype: bool
+ @return: True if successful
+ """
+ params = {'PublicIp' : public_ip}
+ return self.get_status('ReleaseAddress', params)
+
# Volume methods
def get_all_volumes(self, volume_ids=None):
@@ -447,6 +541,17 @@ class EC2Connection(AWSQueryConnection):
# Snapshot methods
def get_all_snapshots(self, snapshot_ids=None):
+ """
+ Get all EBS Snapshots associated with the current credentials.
+
+ @type snapshot_ids: list
+ @param snapshot_ids: Optional list of snapshot ids. If this list is present,
+ only the Snapshots associated with these snapshot ids
+ will be returned.
+
+ @rtype: list of L{boto.ec2.snapshot.Snapshot}
+ @return: The requested Snapshot objects
+ """
params = {}
if snapshot_ids:
self.build_list_params(params, snapshot_ids, 'SnapshotId')
@@ -467,7 +572,8 @@ class EC2Connection(AWSQueryConnection):
Get all key pairs associated with your account.
@type keynames: list
- @param keynames: A list of the names of keypairs to retrieve
+ @param keynames: A list of the names of keypairs to retrieve.
+ If not provided, all key pairs will be returned.
@rtype: list
@return: A list of L{KeyPairs<boto.ec2.keypair.KeyPair>}
@@ -489,18 +595,22 @@ class EC2Connection(AWSQueryConnection):
"""
try:
return self.get_all_key_pairs(keynames=[keyname])[0]
- except IndexError: # None of those images available
+ except IndexError: # None of those key pairs available
return None
def create_key_pair(self, key_name):
"""
Create a new key pair for your account.
+ This will create the key pair within the region you
+ are currently connected to.
@type key_name: string
@param key_name: The name of the new keypair
- @rtype: KeyPair
- @return: The newly created L{KeyPair<boto.ec2.keypair.KeyPair>}
+ @rtype: L{KeyPair<boto.ec2.keypair.KeyPair>}
+ @return: The newly created L{KeyPair<boto.ec2.keypair.KeyPair>}.
+ The material attribute of the new KeyPair object
+ will contain the the unencrypted PEM encoded RSA private key.
"""
params = {'KeyName':key_name}
return self.get_object('CreateKeyPair', params, KeyPair)
@@ -518,12 +628,36 @@ class EC2Connection(AWSQueryConnection):
# SecurityGroup methods
def get_all_security_groups(self, groupnames=None):
+ """
+ Get all security groups associated with your account in a region.
+
+ @type groupnames: list
+ @param groupnames: A list of the names of security groups to retrieve.
+ If not provided, all security groups will be returned.
+
+ @rtype: list
+ @return: A list of L{SecurityGroups<boto.ec2.securitygroup.SecurityGroup>}
+ """
params = {}
if groupnames:
self.build_list_params(params, groupnames, 'GroupName')
return self.get_list('DescribeSecurityGroups', params, [('item', SecurityGroup)])
def create_security_group(self, name, description):
+ """
+ Create a new security group for your account.
+ This will create the security group within the region you
+ are currently connected to.
+
+ @type name: string
+ @param name: The name of the new security group
+
+ @type description: string
+ @param description: The description of the new security group
+
+ @rtype: L{SecurityGroup<boto.ec2.securitygroup.SecurityGroup>}
+ @return: The newly created L{KeyPair<boto.ec2.keypair.KeyPair>}.
+ """
params = {'GroupName':name, 'GroupDescription':description}
group = self.get_object('CreateSecurityGroup', params, SecurityGroup)
group.name = name
@@ -531,6 +665,12 @@ class EC2Connection(AWSQueryConnection):
return group
def delete_security_group(self, name):
+ """
+ Delete a security group from your account.
+
+ @type key_name: string
+ @param key_name: The name of the keypair to delete
+ """
params = {'GroupName':name}
return self.get_status('DeleteSecurityGroup', params)
@@ -538,6 +678,41 @@ class EC2Connection(AWSQueryConnection):
src_security_group_owner_id=None,
ip_protocol=None, from_port=None, to_port=None,
cidr_ip=None):
+ """
+ Add a new rule to an existing security group.
+ You need to pass in either src_security_group_name and
+ src_security_group_owner_id OR ip_protocol, from_port, to_port,
+ and cidr_ip. In other words, either you are authorizing another
+ group or you are authorizing some ip-based rule.
+
+ @type group_name: string
+ @param group_name: The name of the security group you are adding
+ the rule to.
+
+ @type src_security_group_name: string
+ @param src_security_group_name: The name of the security group you are
+ granting access to.
+
+ @type src_security_group_owner_id: string
+ @param src_security_group_owner_id: The ID of the owner of the security group you are
+ granting access to.
+
+ @type ip_protocol: string
+ @param ip_protocol: Either tcp | udp | icmp
+
+ @type from_port: int
+ @param from_port: The beginning port number you are enabling
+
+ @type to_port: int
+ @param to_port: The ending port number you are enabling
+
+ @type to_port: string
+ @param to_port: The CIDR block you are providing access to.
+ See http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
+
+ @rtype: bool
+ @return: True if successful.
+ """
params = {'GroupName':group_name}
if src_security_group_name:
params['SourceSecurityGroupName'] = src_security_group_name
@@ -557,6 +732,41 @@ class EC2Connection(AWSQueryConnection):
src_security_group_owner_id=None,
ip_protocol=None, from_port=None, to_port=None,
cidr_ip=None):
+ """
+ Remove an existing rule from an existing security group.
+ You need to pass in either src_security_group_name and
+ src_security_group_owner_id OR ip_protocol, from_port, to_port,
+ and cidr_ip. In other words, either you are revoking another
+ group or you are revoking some ip-based rule.
+
+ @type group_name: string
+ @param group_name: The name of the security group you are removing
+ the rule from.
+
+ @type src_security_group_name: string
+ @param src_security_group_name: The name of the security group you are
+ revoking access to.
+
+ @type src_security_group_owner_id: string
+ @param src_security_group_owner_id: The ID of the owner of the security group you are
+ revoking access to.
+
+ @type ip_protocol: string
+ @param ip_protocol: Either tcp | udp | icmp
+
+ @type from_port: int
+ @param from_port: The beginning port number you are disabling
+
+ @type to_port: int
+ @param to_port: The ending port number you are disabling
+
+ @type to_port: string
+ @param to_port: The CIDR block you are revoking access to.
+ See http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
+
+ @rtype: bool
+ @return: True if successful.
+ """
params = {'GroupName':group_name}
if src_security_group_name:
params['SourceSecurityGroupName'] = src_security_group_name
@@ -572,3 +782,17 @@ class EC2Connection(AWSQueryConnection):
params['CidrIp'] = cidr_ip
return self.get_status('RevokeSecurityGroupIngress', params)
+ #
+ # Regions
+ #
+
+ def get_all_regions(self):
+ """
+ Get all available regions for the EC2 service.
+
+ @rtype: list
+ @return: A list of L{RegionInfo<boto.ec2.regioninfo.RegionInfo>}
+ """
+ return self.get_list('DescribeRegions', None, [('item', RegionInfo)])
+
+
diff --git a/boto/ec2/ec2object.py b/boto/ec2/ec2object.py
new file mode 100644
index 00000000..3a50760a
--- /dev/null
+++ b/boto/ec2/ec2object.py
@@ -0,0 +1,41 @@
+# Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish, dis-
+# tribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the fol-
+# lowing conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+"""
+Represents an EC2 Object
+"""
+
+class EC2Object(object):
+
+ def __init__(self, connection=None):
+ self.connection = connection
+ if self.connection:
+ self.region = connection.region
+ else:
+ self.region = None
+
+ def startElement(self, name, attrs, connection):
+ return None
+
+ def endElement(self, name, value, connection):
+ setattr(self, name, value)
+
+
diff --git a/boto/ec2/image.py b/boto/ec2/image.py
index 81ce5c2c..1eedc18e 100644
--- a/boto/ec2/image.py
+++ b/boto/ec2/image.py
@@ -19,14 +19,15 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-"""
-Represents an EC2 Image
-"""
+from boto.ec2.ec2object import EC2Object
-class Image:
+class Image(EC2Object):
+ """
+ Represents an EC2 Image
+ """
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.id = None
self.location = None
self.state = None
@@ -41,9 +42,6 @@ class Image:
def __repr__(self):
return 'Image:%s' % self.id
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'imageId':
self.id = value
diff --git a/boto/ec2/instance.py b/boto/ec2/instance.py
index 50a2a7a4..4a74e866 100644
--- a/boto/ec2/instance.py
+++ b/boto/ec2/instance.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2007 Mitch Garnaat http://garnaat.org/
+# Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
@@ -23,14 +23,15 @@
Represents an EC2 Instance
"""
+from boto.ec2.ec2object import EC2Object
from boto.resultset import ResultSet
from boto.ec2.address import Address
import base64
-class Reservation:
+class Reservation(EC2Object):
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.id = None
self.owner_id = None
self.groups = []
@@ -61,10 +62,10 @@ class Reservation:
for instance in self.instances:
instance.stop()
-class Instance:
+class Instance(EC2Object):
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.id = None
self.dns_name = None
self.public_dns_name = None
@@ -85,9 +86,6 @@ class Instance:
def __repr__(self):
return 'Instance:%s' % self.id
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'instanceId':
self.id = value
diff --git a/boto/ec2/keypair.py b/boto/ec2/keypair.py
index 172a80c9..64ab1422 100644
--- a/boto/ec2/keypair.py
+++ b/boto/ec2/keypair.py
@@ -23,10 +23,14 @@
Represents an EC2 Keypair
"""
-class KeyPair:
+import os
+from boto.ec2.ec2object import EC2Object
+from boto.exception import BotoClientError
+
+class KeyPair(EC2Object):
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.name = None
self.fingerprint = None
self.material = None
@@ -34,9 +38,6 @@ class KeyPair:
def __repr__(self):
return 'KeyPair:%s' % self.name
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'keyName':
self.name = value
@@ -48,7 +49,63 @@ class KeyPair:
setattr(self, name, value)
def delete(self):
+ """
+ Delete the KeyPair.
+
+ @rtype: bool
+ @return: True if successful, otherwise False.
+ """
return self.connection.delete_key_pair(self.name)
+ def save(self, directory_path):
+ """
+ Save the material (the unencrypted PEM encoded RSA private key)
+ of a newly created KeyPair to a local file.
+
+ @type directory_path: string
+ @param directory_path: The fully qualified path to the directory
+ in which the keypair will be saved. The
+ keypair file will be named using the name
+ of the keypair as the base name and .pem
+ for the file extension. If a file of that
+ name already exists in the directory, an
+ exception will be raised and the old file
+ will not be overwritten.
+
+ @rtype: bool
+ @return: True if successful.
+ """
+ if self.material:
+ file_path = os.path.join(directory_path, '%s.pem' % self.name)
+ if os.exists(file_path):
+ raise BotoClientError('%s already exists, it will not be overwritten' % file_path)
+ fp = open(file_path, 'wb')
+ fp.write(self.material)
+ fp.close()
+ return True
+ else:
+ raise BotoClientError('KeyPair contains no material')
+
+ def copy_to_region(self, region):
+ """
+ Create a new key pair of the same new in another region.
+ Note that the new key pair will use a different ssh
+ cert than the this key pair. After doing the copy,
+ you will need to save the material associated with the
+ new key pair (use the save method) to a local file.
+
+ @type region: L{RegionInfo<boto.ec2.regioninfo.RegionInfo>}
+ @param region: The region to which this security group will be copied.
+
+ @rtype: L{KeyPair<boto.ec2.keypair.KeyPair>}
+ @return: The new key pair
+ """
+ if region.name == self.region:
+ raise BotoClientError('Unable to copy to the same Region')
+ conn_params = self.connection.get_params()
+ rconn = region.connect(**conn_params)
+ kp = rconn.create_key_pair(self.name)
+ return kp
+
diff --git a/boto/ec2/regioninfo.py b/boto/ec2/regioninfo.py
new file mode 100644
index 00000000..1a8e5866
--- /dev/null
+++ b/boto/ec2/regioninfo.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2006-2008 Mitch Garnaat http://garnaat.org/
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish, dis-
+# tribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the fol-
+# lowing conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+class RegionInfo(object):
+ """
+ Represents an EC2 Region
+ """
+
+ def __init__(self, connection=None, name=None, endpoint=None):
+ self.connection = connection
+ self.name = name
+ self.endpoint = endpoint
+
+ def __repr__(self):
+ return 'RegionInfo:%s' % self.name
+
+ def startElement(self, name, attrs, connection):
+ return None
+
+ def endElement(self, name, value, connection):
+ if name == 'regionName':
+ self.name = value
+ elif name == 'regionEndpoint':
+ self.endpoint = value
+ else:
+ setattr(self, name, value)
+
+ def connect(self, **kw_params):
+ """
+ Connect to this Region's endpoint. Returns an EC2Connection
+ object pointing to the endpoint associated with this region.
+ You may pass any of the arguments accepted by the EC2Connection
+ object's constructor as keyword arguments and they will be
+ passed along to the EC2Connection object.
+
+ @rtype: L{EC2Connection<boto.ec2.connection.EC2Connection}
+ @return: The connection to this regions endpoint
+ """
+ from boto.ec2.connection import EC2Connection
+ return EC2Connection(region=self, **kw_params)
+
+
diff --git a/boto/ec2/securitygroup.py b/boto/ec2/securitygroup.py
index ba951c07..6797d53f 100644
--- a/boto/ec2/securitygroup.py
+++ b/boto/ec2/securitygroup.py
@@ -22,12 +22,13 @@
"""
Represents an EC2 Security Group
"""
+from boto.ec2.ec2object import EC2Object
-class SecurityGroup:
+class SecurityGroup(EC2Object):
def __init__(self, connection=None, owner_id=None,
name=None, description=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.owner_id = owner_id
self.name = name
self.description = description
@@ -89,8 +90,8 @@ class SecurityGroup:
target_rule = rule
target_grant = None
for grant in rule.grants:
- if grant.group_name == src_group_name:
- if grant.user_id == src_group_owner_id:
+ if grant.name == src_group_name:
+ if grant.owner_id == src_group_owner_id:
if grant.cidr_ip == cidr_ip:
target_grant = grant
if target_grant:
@@ -100,7 +101,41 @@ class SecurityGroup:
def authorize(self, ip_protocol=None, from_port=None, to_port=None,
cidr_ip=None, src_group=None):
+ """
+ Add a new rule to this security group.
+ You need to pass in either src_group_name
+ OR ip_protocol, from_port, to_port,
+ and cidr_ip. In other words, either you are authorizing another
+ group or you are authorizing some ip-based rule.
+
+ @type src_security_group_owner_id: string
+ @param src_security_group_owner_id: The ID of the owner of the security group you are
+ granting access to.
+
+ @type ip_protocol: string
+ @param ip_protocol: Either tcp | udp | icmp
+
+ @type from_port: int
+ @param from_port: The beginning port number you are enabling
+
+ @type to_port: int
+ @param to_port: The ending port number you are enabling
+
+ @type to_port: string
+ @param to_port: The CIDR block you are providing access to.
+ See http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
+
+ @type src_group: L{SecurityGroup<boto.ec2.securitygroup.SecurityGroup>} or
+ L{GroupOrCIDR<boto.ec2.securitygroup.GroupOrCIDR}
+
+ @rtype: bool
+ @return: True if successful.
+ """
if src_group:
+ from_port = None
+ to_port = None
+ cidr_ip = None
+ ip_protocol = None
src_group_name = src_group.name
src_group_owner_id = src_group.owner_id
else:
@@ -121,6 +156,10 @@ class SecurityGroup:
def revoke(self, ip_protocol=None, from_port=None, to_port=None,
cidr_ip=None, src_group=None):
if src_group:
+ from_port=None
+ to_port=None
+ cidr_ip=None
+ ip_protocol = None
src_group_name = src_group.name
src_group_owner_id = src_group.owner_id
else:
@@ -138,6 +177,40 @@ class SecurityGroup:
src_group_owner_id, cidr_ip)
return status
+ def copy_to_region(self, region, name=None):
+ """
+ Create a copy of this security group in another region.
+ Note that the new security group will be a separate entity
+ and will not stay in sync automatically after the copy
+ operation.
+
+ @type region: L{RegionInfo<boto.ec2.regioninfo.RegionInfo>}
+ @param region: The region to which this security group will be copied.
+
+ @type name: string
+ @param name: The name of the copy. If not supplied, the copy
+ will have the same name as this security group.
+
+ @rtype: L{SecurityGroup<boto.ec2.securitygroup.SecurityGroup>}
+ @return: The new security group.
+ """
+ if region.name == self.region:
+ raise BotoClientError('Unable to copy to the same Region')
+ conn_params = self.connection.get_params()
+ rconn = region.connect(**conn_params)
+ sg = rconn.create_security_group(name or self.name, self.description)
+ source_groups = []
+ for rule in self.rules:
+ grant = rule.grants[0]
+ if grant.name:
+ if grant.name not in source_groups:
+ source_groups.append(grant.name)
+ sg.authorize(None, None, None, None, grant)
+ else:
+ sg.authorize(rule.ip_protocol, rule.from_port, rule.to_port,
+ grant.cidr_ip)
+ return sg
+
class IPPermissions:
def __init__(self, parent=None):
@@ -167,10 +240,10 @@ class IPPermissions:
else:
setattr(self, name, value)
- def add_grant(self, user_id=None, group_name=None, cidr_ip=None):
+ def add_grant(self, owner_id=None, name=None, cidr_ip=None):
grant = GroupOrCIDR(self)
- grant.user_id = user_id
- grant.group_name = group_name
+ grant.owner_id = owner_id
+ grant.name = name
grant.cidr_ip = cidr_ip
self.grants.append(grant)
return grant
@@ -178,24 +251,24 @@ class IPPermissions:
class GroupOrCIDR:
def __init__(self, parent=None):
- self.user_id = None
- self.group_name = None
+ self.owner_id = None
+ self.name = None
self.cidr_ip = None
def __repr__(self):
if self.cidr_ip:
return '%s' % self.cidr_ip
else:
- return '%s-%s' % (self.group_name, self.user_id)
+ return '%s-%s' % (self.name, self.owner_id)
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'userId':
- self.user_id = value
+ self.owner_id = value
elif name == 'groupName':
- self.group_name = value
+ self.name = value
if name == 'cidrIp':
self.cidr_ip = value
else:
diff --git a/boto/ec2/snapshot.py b/boto/ec2/snapshot.py
index e64fdeff..beefbb97 100644
--- a/boto/ec2/snapshot.py
+++ b/boto/ec2/snapshot.py
@@ -22,11 +22,12 @@
"""
Represents an EC2 Elastic IP Snapshot
"""
+from boto.ec2.ec2object import EC2Object
-class Snapshot:
+class Snapshot(EC2Object):
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.id = None
self.progress = None
self.start_time = None
@@ -35,9 +36,6 @@ class Snapshot:
def __repr__(self):
return 'Snapshot:%s' % self.id
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'snapshotId':
self.id = value
diff --git a/boto/ec2/volume.py b/boto/ec2/volume.py
index 0d85202b..052b3cd4 100644
--- a/boto/ec2/volume.py
+++ b/boto/ec2/volume.py
@@ -22,11 +22,12 @@
"""
Represents an EC2 Elastic IP Volume
"""
+from boto.ec2.ec2object import EC2Object
-class Volume:
+class Volume(EC2Object):
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.id = None
self.instance_id = None
self.snapshot_id = None
@@ -37,9 +38,6 @@ class Volume:
def __repr__(self):
return 'Volume:%s' % self.id
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'volumeId':
self.id = value
diff --git a/boto/ec2/zone.py b/boto/ec2/zone.py
index f8bf3ad7..aec79b2c 100644
--- a/boto/ec2/zone.py
+++ b/boto/ec2/zone.py
@@ -22,20 +22,18 @@
"""
Represents an EC2 Availability Zone
"""
+from boto.ec2.ec2object import EC2Object
-class Zone:
+class Zone(EC2Object):
def __init__(self, connection=None):
- self.connection = connection
+ EC2Object.__init__(self, connection)
self.name = None
self.state = None
def __repr__(self):
return 'Zone:%s' % self.name
- def startElement(self, name, attrs, connection):
- return None
-
def endElement(self, name, value, connection):
if name == 'zoneName':
self.name = value