| Index: boto/ec2/connection.py
|
| diff --git a/boto/ec2/connection.py b/boto/ec2/connection.py
|
| index 89d1d4ee99b29cebc06fc74a496cd35612957f25..1e492594d6dd61118c83c27e25d3298a2d22089c 100644
|
| --- a/boto/ec2/connection.py
|
| +++ b/boto/ec2/connection.py
|
| @@ -32,7 +32,8 @@ import boto
|
| from boto.connection import AWSQueryConnection
|
| from boto.resultset import ResultSet
|
| from boto.ec2.image import Image, ImageAttribute
|
| -from boto.ec2.instance import Reservation, Instance, ConsoleOutput, InstanceAttribute
|
| +from boto.ec2.instance import Reservation, Instance
|
| +from boto.ec2.instance import ConsoleOutput, InstanceAttribute
|
| from boto.ec2.keypair import KeyPair
|
| from boto.ec2.address import Address
|
| from boto.ec2.volume import Volume
|
| @@ -42,7 +43,8 @@ from boto.ec2.zone import Zone
|
| from boto.ec2.securitygroup import SecurityGroup
|
| from boto.ec2.regioninfo import RegionInfo
|
| from boto.ec2.instanceinfo import InstanceInfo
|
| -from boto.ec2.reservedinstance import ReservedInstancesOffering, ReservedInstance
|
| +from boto.ec2.reservedinstance import ReservedInstancesOffering
|
| +from boto.ec2.reservedinstance import ReservedInstance
|
| from boto.ec2.spotinstancerequest import SpotInstanceRequest
|
| from boto.ec2.spotpricehistory import SpotPriceHistory
|
| from boto.ec2.spotdatafeedsubscription import SpotDatafeedSubscription
|
| @@ -55,16 +57,18 @@ from boto.exception import EC2ResponseError
|
|
|
| class EC2Connection(AWSQueryConnection):
|
|
|
| - APIVersion = boto.config.get('Boto', 'ec2_version', '2010-08-31')
|
| + APIVersion = boto.config.get('Boto', 'ec2_version', '2011-01-01')
|
| DefaultRegionName = boto.config.get('Boto', 'ec2_region_name', 'us-east-1')
|
| DefaultRegionEndpoint = boto.config.get('Boto', 'ec2_region_endpoint',
|
| 'ec2.amazonaws.com')
|
| ResponseError = EC2ResponseError
|
|
|
| def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
|
| - is_secure=True, host=None, port=None, proxy=None, proxy_port=None,
|
| + is_secure=True, host=None, port=None,
|
| + proxy=None, proxy_port=None,
|
| proxy_user=None, proxy_pass=None, debug=0,
|
| - https_connection_factory=None, region=None, path='/'):
|
| + https_connection_factory=None, region=None, path='/',
|
| + api_version=None, security_token=None):
|
| """
|
| Init method to create a new connection to EC2.
|
|
|
| @@ -80,7 +84,10 @@ class EC2Connection(AWSQueryConnection):
|
| is_secure, port, proxy, proxy_port,
|
| proxy_user, proxy_pass,
|
| self.region.endpoint, debug,
|
| - https_connection_factory, path)
|
| + https_connection_factory, path,
|
| + security_token)
|
| + if api_version:
|
| + self.APIVersion = api_version
|
|
|
| def _required_auth_capability(self):
|
| return ['ec2']
|
| @@ -90,8 +97,9 @@ class EC2Connection(AWSQueryConnection):
|
| 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',
|
| + 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:
|
| @@ -101,7 +109,9 @@ class EC2Connection(AWSQueryConnection):
|
| def build_filter_params(self, params, filters):
|
| i = 1
|
| for name in filters:
|
| - aws_name = name.replace('_', '-')
|
| + aws_name = name
|
| + if not aws_name.startswith('tag:'):
|
| + aws_name = name.replace('_', '-')
|
| params['Filter.%d.Name' % i] = aws_name
|
| value = filters[name]
|
| if not isinstance(value, list):
|
| @@ -151,7 +161,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, executable_by, 'ExecutableBy')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - return self.get_list('DescribeImages', params, [('item', Image)], verb='POST')
|
| + return self.get_list('DescribeImages', params,
|
| + [('item', Image)], verb='POST')
|
|
|
| def get_all_kernels(self, kernel_ids=None, owners=None):
|
| """
|
| @@ -174,7 +185,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, owners, 'Owner')
|
| filter = {'image-type' : 'kernel'}
|
| self.build_filter_params(params, filter)
|
| - return self.get_list('DescribeImages', params, [('item', Image)], verb='POST')
|
| + return self.get_list('DescribeImages', params,
|
| + [('item', Image)], verb='POST')
|
|
|
| def get_all_ramdisks(self, ramdisk_ids=None, owners=None):
|
| """
|
| @@ -197,7 +209,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, owners, 'Owner')
|
| filter = {'image-type' : 'ramdisk'}
|
| self.build_filter_params(params, filter)
|
| - return self.get_list('DescribeImages', params, [('item', Image)], verb='POST')
|
| + return self.get_list('DescribeImages', params,
|
| + [('item', Image)], verb='POST')
|
|
|
| def get_image(self, image_id):
|
| """
|
| @@ -227,7 +240,8 @@ class EC2Connection(AWSQueryConnection):
|
| :param description: The description of the AMI.
|
|
|
| :type image_location: string
|
| - :param image_location: Full path to your AMI manifest in Amazon S3 storage.
|
| + :param image_location: Full path to your AMI manifest in
|
| + Amazon S3 storage.
|
| Only used for S3-based AMI's.
|
|
|
| :type architecture: string
|
| @@ -235,7 +249,8 @@ class EC2Connection(AWSQueryConnection):
|
| i386 | x86_64
|
|
|
| :type kernel_id: string
|
| - :param kernel_id: The ID of the kernel with which to launch the instances
|
| + :param kernel_id: The ID of the kernel with which to launch
|
| + the instances
|
|
|
| :type root_device_name: string
|
| :param root_device_name: The root device name (e.g. /dev/sdh)
|
| @@ -269,23 +284,41 @@ class EC2Connection(AWSQueryConnection):
|
| image_id = getattr(rs, 'imageId', None)
|
| return image_id
|
|
|
| - def deregister_image(self, image_id):
|
| + def deregister_image(self, image_id, delete_snapshot=False):
|
| """
|
| Unregister an AMI.
|
|
|
| :type image_id: string
|
| :param image_id: the ID of the Image to unregister
|
|
|
| + :type delete_snapshot: bool
|
| + :param delete_snapshot: Set to True if we should delete the
|
| + snapshot associated with an EBS volume
|
| + mounted at /dev/sda1
|
| +
|
| :rtype: bool
|
| :return: True if successful
|
| """
|
| - return self.get_status('DeregisterImage', {'ImageId':image_id}, verb='POST')
|
| + snapshot_id = None
|
| + if delete_snapshot:
|
| + image = self.get_image(image_id)
|
| + for key in image.block_device_mapping:
|
| + if key == "/dev/sda1":
|
| + snapshot_id = image.block_device_mapping[key].snapshot_id
|
| + break
|
| +
|
| + result = self.get_status('DeregisterImage',
|
| + {'ImageId':image_id}, verb='POST')
|
| + if result and snapshot_id:
|
| + return result and self.delete_snapshot(snapshot_id)
|
| + return result
|
|
|
| - def create_image(self, instance_id, name, description=None, no_reboot=False):
|
| + def create_image(self, instance_id, name,
|
| + description=None, no_reboot=False):
|
| """
|
| Will create an AMI from the instance in the running or stopped
|
| state.
|
| -
|
| +
|
| :type instance_id: string
|
| :param instance_id: the ID of the instance to image.
|
|
|
| @@ -302,7 +335,7 @@ class EC2Connection(AWSQueryConnection):
|
| bundling. If this flag is True, the responsibility
|
| of maintaining file system integrity is left to the
|
| owner of the instance.
|
| -
|
| +
|
| :rtype: string
|
| :return: The new image id
|
| """
|
| @@ -314,7 +347,7 @@ class EC2Connection(AWSQueryConnection):
|
| params['NoReboot'] = 'true'
|
| img = self.get_object('CreateImage', params, Image, verb='POST')
|
| return img.id
|
| -
|
| +
|
| # ImageAttribute methods
|
|
|
| def get_image_attribute(self, image_id, attribute='launchPermission'):
|
| @@ -337,7 +370,8 @@ class EC2Connection(AWSQueryConnection):
|
| """
|
| params = {'ImageId' : image_id,
|
| 'Attribute' : attribute}
|
| - return self.get_object('DescribeImageAttribute', params, ImageAttribute, verb='POST')
|
| + return self.get_object('DescribeImageAttribute', params,
|
| + ImageAttribute, verb='POST')
|
|
|
| def modify_image_attribute(self, image_id, attribute='launchPermission',
|
| operation='add', user_ids=None, groups=None,
|
| @@ -420,6 +454,11 @@ class EC2Connection(AWSQueryConnection):
|
| if instance_ids:
|
| self.build_list_params(params, instance_ids, 'InstanceId')
|
| if filters:
|
| + if 'group-id' in filters:
|
| + warnings.warn("The group-id filter now requires a security "
|
| + "group identifier (sg-*) instead of a group "
|
| + "name. To filter by group name use the "
|
| + "'group-name' filter instead.", UserWarning)
|
| self.build_filter_params(params, filters)
|
| return self.get_list('DescribeInstances', params,
|
| [('item', Reservation)], verb='POST')
|
| @@ -434,7 +473,8 @@ class EC2Connection(AWSQueryConnection):
|
| disable_api_termination=False,
|
| instance_initiated_shutdown_behavior=None,
|
| private_ip_address=None,
|
| - placement_group=None, client_token=None):
|
| + placement_group=None, client_token=None,
|
| + security_group_ids=None):
|
| """
|
| Runs an image on EC2.
|
|
|
| @@ -459,7 +499,7 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type instance_type: string
|
| :param instance_type: The type of instance to run:
|
| -
|
| +
|
| * m1.small
|
| * m1.large
|
| * m1.xlarge
|
| @@ -507,13 +547,12 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type instance_initiated_shutdown_behavior: string
|
| :param instance_initiated_shutdown_behavior: Specifies whether the
|
| - instance's EBS volumes are
|
| - stopped (i.e. detached) or
|
| - terminated (i.e. deleted)
|
| - when the instance is
|
| - shutdown by the
|
| - owner. Valid values are:
|
| -
|
| + instance stops or
|
| + terminates on
|
| + instance-initiated
|
| + shutdown.
|
| + Valid values are:
|
| +
|
| * stop
|
| * terminate
|
|
|
| @@ -529,12 +568,24 @@ class EC2Connection(AWSQueryConnection):
|
| :rtype: Reservation
|
| :return: The :class:`boto.ec2.instance.Reservation` associated with
|
| the request for machines
|
| +
|
| + :type security_group_ids: list of strings
|
| + :param security_group_ids: The ID of the VPC security groups with
|
| + which to associate instances
|
| """
|
| params = {'ImageId':image_id,
|
| 'MinCount':min_count,
|
| 'MaxCount': max_count}
|
| if key_name:
|
| params['KeyName'] = key_name
|
| + if security_group_ids:
|
| + l = []
|
| + for group in security_group_ids:
|
| + if isinstance(group, SecurityGroup):
|
| + l.append(group.name)
|
| + else:
|
| + l.append(group)
|
| + self.build_list_params(params, l, 'SecurityGroupId')
|
| if security_groups:
|
| l = []
|
| for group in security_groups:
|
| @@ -587,18 +638,19 @@ class EC2Connection(AWSQueryConnection):
|
| params = {}
|
| if instance_ids:
|
| self.build_list_params(params, instance_ids, 'InstanceId')
|
| - return self.get_list('TerminateInstances', params, [('item', Instance)], verb='POST')
|
| + return self.get_list('TerminateInstances', params,
|
| + [('item', Instance)], verb='POST')
|
|
|
| def stop_instances(self, instance_ids=None, force=False):
|
| """
|
| Stop the instances specified
|
| -
|
| +
|
| :type instance_ids: list
|
| :param instance_ids: A list of strings of the Instance IDs to stop
|
|
|
| :type force: bool
|
| :param force: Forces the instance to stop
|
| -
|
| +
|
| :rtype: list
|
| :return: A list of the instances stopped
|
| """
|
| @@ -607,22 +659,24 @@ class EC2Connection(AWSQueryConnection):
|
| params['Force'] = 'true'
|
| if instance_ids:
|
| self.build_list_params(params, instance_ids, 'InstanceId')
|
| - return self.get_list('StopInstances', params, [('item', Instance)], verb='POST')
|
| + return self.get_list('StopInstances', params,
|
| + [('item', Instance)], verb='POST')
|
|
|
| def start_instances(self, instance_ids=None):
|
| """
|
| Start the instances specified
|
| -
|
| +
|
| :type instance_ids: list
|
| :param instance_ids: A list of strings of the Instance IDs to start
|
| -
|
| +
|
| :rtype: list
|
| :return: A list of the instances started
|
| """
|
| params = {}
|
| if instance_ids:
|
| self.build_list_params(params, instance_ids, 'InstanceId')
|
| - return self.get_list('StartInstances', params, [('item', Instance)], verb='POST')
|
| + return self.get_list('StartInstances', params,
|
| + [('item', Instance)], verb='POST')
|
|
|
| def get_console_output(self, instance_id):
|
| """
|
| @@ -636,7 +690,8 @@ class EC2Connection(AWSQueryConnection):
|
| """
|
| params = {}
|
| self.build_list_params(params, [instance_id], 'InstanceId')
|
| - return self.get_object('GetConsoleOutput', params, ConsoleOutput, verb='POST')
|
| + return self.get_object('GetConsoleOutput', params,
|
| + ConsoleOutput, verb='POST')
|
|
|
| def reboot_instances(self, instance_ids=None):
|
| """
|
| @@ -653,7 +708,8 @@ class EC2Connection(AWSQueryConnection):
|
| def confirm_product_instance(self, product_code, instance_id):
|
| params = {'ProductCode' : product_code,
|
| 'InstanceId' : instance_id}
|
| - rs = self.get_object('ConfirmProductInstance', params, ResultSet, verb='POST')
|
| + rs = self.get_object('ConfirmProductInstance', params,
|
| + ResultSet, verb='POST')
|
| return (rs.status, rs.ownerId)
|
|
|
| # InstanceAttribute methods
|
| @@ -668,7 +724,7 @@ class EC2Connection(AWSQueryConnection):
|
| :type attribute: string
|
| :param attribute: The attribute you need information about
|
| Valid choices are:
|
| -
|
| +
|
| * instanceType|kernel|ramdisk|userData|
|
| * disableApiTermination|
|
| * instanceInitiatedShutdownBehavior|
|
| @@ -693,7 +749,7 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type attribute: string
|
| :param attribute: The attribute you wish to change.
|
| -
|
| +
|
| * AttributeName - Expected value (default)
|
| * instanceType - A valid instance type (m1.small)
|
| * kernel - Kernel ID (None)
|
| @@ -745,10 +801,10 @@ class EC2Connection(AWSQueryConnection):
|
| filters=None):
|
| """
|
| Retrieve all the spot instances requests associated with your account.
|
| -
|
| +
|
| :type request_ids: list
|
| :param request_ids: A list of strings of spot instance request IDs
|
| -
|
| +
|
| :type filters: dict
|
| :param filters: Optional filters that can be used to limit
|
| the results returned. Filters are provided
|
| @@ -767,30 +823,41 @@ class EC2Connection(AWSQueryConnection):
|
| if request_ids:
|
| self.build_list_params(params, request_ids, 'SpotInstanceRequestId')
|
| if filters:
|
| + if 'launch.group-id' in filters:
|
| + warnings.warn("The 'launch.group-id' filter now requires a "
|
| + "security group id (sg-*) and no longer supports "
|
| + "filtering by group name. Please update your "
|
| + "filters accordingly.", UserWarning)
|
| self.build_filter_params(params, filters)
|
| return self.get_list('DescribeSpotInstanceRequests', params,
|
| [('item', SpotInstanceRequest)], verb='POST')
|
|
|
| def get_spot_price_history(self, start_time=None, end_time=None,
|
| - instance_type=None, product_description=None):
|
| + instance_type=None, product_description=None,
|
| + availability_zone=None):
|
| """
|
| Retrieve the recent history of spot instances pricing.
|
| -
|
| +
|
| :type start_time: str
|
| :param start_time: An indication of how far back to provide price
|
| changes for. An ISO8601 DateTime string.
|
| -
|
| +
|
| :type end_time: str
|
| :param end_time: An indication of how far forward to provide price
|
| changes for. An ISO8601 DateTime string.
|
| -
|
| +
|
| :type instance_type: str
|
| :param instance_type: Filter responses to a particular instance type.
|
| -
|
| +
|
| :type product_description: str
|
| - :param product_descripton: Filter responses to a particular platform.
|
| - Valid values are currently: Linux
|
| -
|
| + :param product_description: Filter responses to a particular platform.
|
| + Valid values are currently: "Linux/UNIX",
|
| + "SUSE Linux", and "Windows"
|
| +
|
| + :type availability_zone: str
|
| + :param availability_zone: The availability zone for which prices
|
| + should be returned
|
| +
|
| :rtype: list
|
| :return: A list tuples containing price and timestamp.
|
| """
|
| @@ -803,6 +870,8 @@ class EC2Connection(AWSQueryConnection):
|
| params['InstanceType'] = instance_type
|
| if product_description:
|
| params['ProductDescription'] = product_description
|
| + if availability_zone:
|
| + params['AvailabilityZone'] = availability_zone
|
| return self.get_list('DescribeSpotPriceHistory', params,
|
| [('item', SpotPriceHistory)], verb='POST')
|
|
|
| @@ -820,13 +889,13 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type price: str
|
| :param price: The maximum price of your bid
|
| -
|
| +
|
| :type image_id: string
|
| :param image_id: The ID of the image to run
|
|
|
| :type count: int
|
| :param count: The of instances to requested
|
| -
|
| +
|
| :type type: str
|
| :param type: Type of request. Can be 'one-time' or 'persistent'.
|
| Default is one-time.
|
| @@ -840,12 +909,12 @@ class EC2Connection(AWSQueryConnection):
|
| :type launch_group: str
|
| :param launch_group: If supplied, all requests will be fulfilled
|
| as a group.
|
| -
|
| +
|
| :type availability_zone_group: str
|
| :param availability_zone_group: If supplied, all requests will be
|
| fulfilled within a single
|
| availability zone.
|
| -
|
| +
|
| :type key_name: string
|
| :param key_name: The name of the key pair with which to launch instances
|
|
|
| @@ -858,7 +927,7 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type instance_type: string
|
| :param instance_type: The type of instance to run:
|
| -
|
| +
|
| * m1.small
|
| * m1.large
|
| * m1.xlarge
|
| @@ -943,14 +1012,14 @@ class EC2Connection(AWSQueryConnection):
|
| [('item', SpotInstanceRequest)],
|
| verb='POST')
|
|
|
| -
|
| +
|
| def cancel_spot_instance_requests(self, request_ids):
|
| """
|
| Cancel the specified Spot Instance Requests.
|
| -
|
| +
|
| :type request_ids: list
|
| :param request_ids: A list of strings of the Request IDs to terminate
|
| -
|
| +
|
| :rtype: list
|
| :return: A list of the instances terminated
|
| """
|
| @@ -964,7 +1033,7 @@ class EC2Connection(AWSQueryConnection):
|
| """
|
| Return the current spot instance data feed subscription
|
| associated with this account, if any.
|
| -
|
| +
|
| :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription`
|
| :return: The datafeed subscription object or None
|
| """
|
| @@ -984,7 +1053,7 @@ class EC2Connection(AWSQueryConnection):
|
| :type prefix: str or unicode
|
| :param prefix: An optional prefix that will be pre-pended to all
|
| data files written to the bucket.
|
| -
|
| +
|
| :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription`
|
| :return: The datafeed subscription object or None
|
| """
|
| @@ -998,11 +1067,12 @@ class EC2Connection(AWSQueryConnection):
|
| """
|
| Delete the current spot instance data feed subscription
|
| associated with this account
|
| -
|
| +
|
| :rtype: bool
|
| :return: True if successful
|
| """
|
| - return self.get_status('DeleteSpotDatafeedSubscription', None, verb='POST')
|
| + return self.get_status('DeleteSpotDatafeedSubscription',
|
| + None, verb='POST')
|
|
|
| # Zone methods
|
|
|
| @@ -1033,11 +1103,12 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, zones, 'ZoneName')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - return self.get_list('DescribeAvailabilityZones', params, [('item', Zone)], verb='POST')
|
| + return self.get_list('DescribeAvailabilityZones', params,
|
| + [('item', Zone)], verb='POST')
|
|
|
| # Address methods
|
|
|
| - def get_all_addresses(self, addresses=None, filters=None):
|
| + def get_all_addresses(self, addresses=None, filters=None, allocation_ids=None):
|
| """
|
| Get all EIP's associated with the current credentials.
|
|
|
| @@ -1056,65 +1127,106 @@ class EC2Connection(AWSQueryConnection):
|
| being performed. Check the EC2 API guide
|
| for details.
|
|
|
| + :type allocation_ids: list
|
| + :param allocation_ids: Optional list of allocation IDs. If this list is
|
| + present, only the Addresses associated with the given
|
| + allocation IDs will be returned.
|
| +
|
| :rtype: list of :class:`boto.ec2.address.Address`
|
| :return: The requested Address objects
|
| """
|
| params = {}
|
| if addresses:
|
| self.build_list_params(params, addresses, 'PublicIp')
|
| + if allocation_ids:
|
| + self.build_list_params(params, allocation_ids, 'AllocationId')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| return self.get_list('DescribeAddresses', params, [('item', Address)], verb='POST')
|
|
|
| - def allocate_address(self):
|
| + def allocate_address(self, domain=None):
|
| """
|
| Allocate a new Elastic IP address and associate it with your account.
|
|
|
| :rtype: :class:`boto.ec2.address.Address`
|
| :return: The newly allocated Address
|
| """
|
| - return self.get_object('AllocateAddress', {}, Address, verb='POST')
|
| + params = {}
|
|
|
| - def associate_address(self, instance_id, public_ip):
|
| + if domain is not None:
|
| + params['Domain'] = domain
|
| +
|
| + return self.get_object('AllocateAddress', params, Address, verb='POST')
|
| +
|
| + def associate_address(self, instance_id, public_ip=None, allocation_id=None):
|
| """
|
| Associate an Elastic IP address with a currently running instance.
|
| + This requires one of ``public_ip`` or ``allocation_id`` depending
|
| + on if you're associating a VPC address or a plain EC2 address.
|
|
|
| :type instance_id: string
|
| :param instance_id: The ID of the instance
|
|
|
| :type public_ip: string
|
| - :param public_ip: The public IP address
|
| + :param public_ip: The public IP address for EC2 based allocations.
|
| +
|
| + :type allocation_id: string
|
| + :param allocation_id: The allocation ID for a VPC-based elastic IP.
|
|
|
| :rtype: bool
|
| :return: True if successful
|
| """
|
| - params = {'InstanceId' : instance_id, 'PublicIp' : public_ip}
|
| + params = { 'InstanceId' : instance_id }
|
| +
|
| + if public_ip is not None:
|
| + params['PublicIp'] = public_ip
|
| + elif allocation_id is not None:
|
| + params['AllocationId'] = allocation_id
|
| +
|
| return self.get_status('AssociateAddress', params, verb='POST')
|
|
|
| - def disassociate_address(self, public_ip):
|
| + def disassociate_address(self, public_ip=None, association_id=None):
|
| """
|
| Disassociate an Elastic IP address from a currently running instance.
|
|
|
| :type public_ip: string
|
| - :param public_ip: The public IP address
|
| + :param public_ip: The public IP address for EC2 elastic IPs.
|
| +
|
| + :type association_id: string
|
| + :param association_id: The association ID for a VPC based elastic ip.
|
|
|
| :rtype: bool
|
| :return: True if successful
|
| """
|
| - params = {'PublicIp' : public_ip}
|
| + params = {}
|
| +
|
| + if public_ip is not None:
|
| + params['PublicIp'] = public_ip
|
| + elif association_id is not None:
|
| + params['AssociationId'] = association_id
|
| +
|
| return self.get_status('DisassociateAddress', params, verb='POST')
|
|
|
| - def release_address(self, public_ip):
|
| + def release_address(self, public_ip=None, allocation_id=None):
|
| """
|
| - Free up an Elastic IP address
|
| + Free up an Elastic IP address.
|
|
|
| :type public_ip: string
|
| - :param public_ip: The public IP address
|
| + :param public_ip: The public IP address for EC2 elastic IPs.
|
| +
|
| + :type allocation_id: string
|
| + :param allocation_id: The ID for VPC elastic IPs.
|
|
|
| :rtype: bool
|
| :return: True if successful
|
| """
|
| - params = {'PublicIp' : public_ip}
|
| + params = {}
|
| +
|
| + if public_ip is not None:
|
| + params['PublicIp'] = public_ip
|
| + elif allocation_id is not None:
|
| + params['AllocationId'] = allocation_id
|
| +
|
| return self.get_status('ReleaseAddress', params, verb='POST')
|
|
|
| # Volume methods
|
| @@ -1124,9 +1236,9 @@ class EC2Connection(AWSQueryConnection):
|
| Get all Volumes associated with the current credentials.
|
|
|
| :type volume_ids: list
|
| - :param volume_ids: Optional list of volume ids. If this list is present,
|
| - only the volumes associated with these volume ids
|
| - will be returned.
|
| + :param volume_ids: Optional list of volume ids. If this list
|
| + is present, only the volumes associated with
|
| + these volume ids will be returned.
|
|
|
| :type filters: dict
|
| :param filters: Optional filters that can be used to limit
|
| @@ -1146,7 +1258,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, volume_ids, 'VolumeId')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - return self.get_list('DescribeVolumes', params, [('item', Volume)], verb='POST')
|
| + return self.get_list('DescribeVolumes', params,
|
| + [('item', Volume)], verb='POST')
|
|
|
| def create_volume(self, size, zone, snapshot=None):
|
| """
|
| @@ -1261,7 +1374,7 @@ class EC2Connection(AWSQueryConnection):
|
| :type owner: str
|
| :param owner: If present, only the snapshots owned by the specified user
|
| will be returned. Valid values are:
|
| -
|
| +
|
| * self
|
| * amazon
|
| * AWS Account ID
|
| @@ -1292,7 +1405,8 @@ class EC2Connection(AWSQueryConnection):
|
| params['RestorableBy'] = restorable_by
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - return self.get_list('DescribeSnapshots', params, [('item', Snapshot)], verb='POST')
|
| + return self.get_list('DescribeSnapshots', params,
|
| + [('item', Snapshot)], verb='POST')
|
|
|
| def create_snapshot(self, volume_id, description=None):
|
| """
|
| @@ -1311,7 +1425,8 @@ class EC2Connection(AWSQueryConnection):
|
| params = {'VolumeId' : volume_id}
|
| if description:
|
| params['Description'] = description[0:255]
|
| - snapshot = self.get_object('CreateSnapshot', params, Snapshot, verb='POST')
|
| + snapshot = self.get_object('CreateSnapshot', params,
|
| + Snapshot, verb='POST')
|
| volume = self.get_all_volumes([volume_id])[0]
|
| volume_name = volume.tags.get('Name')
|
| if volume_name:
|
| @@ -1322,21 +1437,26 @@ class EC2Connection(AWSQueryConnection):
|
| params = {'SnapshotId': snapshot_id}
|
| return self.get_status('DeleteSnapshot', params, verb='POST')
|
|
|
| - def trim_snapshots(self, hourly_backups = 8, daily_backups = 7, weekly_backups = 4):
|
| + def trim_snapshots(self, hourly_backups = 8, daily_backups = 7,
|
| + weekly_backups = 4):
|
| """
|
| - Trim excess snapshots, based on when they were taken. More current snapshots are
|
| - retained, with the number retained decreasing as you move back in time.
|
| + Trim excess snapshots, based on when they were taken. More current
|
| + snapshots are retained, with the number retained decreasing as you
|
| + move back in time.
|
|
|
| - If ebs volumes have a 'Name' tag with a value, their snapshots will be assigned the same
|
| - tag when they are created. The values of the 'Name' tags for snapshots are used by this
|
| - function to group snapshots taken from the same volume (or from a series of like-named
|
| - volumes over time) for trimming.
|
| + If ebs volumes have a 'Name' tag with a value, their snapshots
|
| + will be assigned the same tag when they are created. The values
|
| + of the 'Name' tags for snapshots are used by this function to
|
| + group snapshots taken from the same volume (or from a series
|
| + of like-named volumes over time) for trimming.
|
|
|
| - For every group of like-named snapshots, this function retains the newest and oldest
|
| - snapshots, as well as, by default, the first snapshots taken in each of the last eight
|
| - hours, the first snapshots taken in each of the last seven days, the first snapshots
|
| - taken in the last 4 weeks (counting Midnight Sunday morning as the start of the week),
|
| - and the first snapshot from the first Sunday of each month forever.
|
| + For every group of like-named snapshots, this function retains
|
| + the newest and oldest snapshots, as well as, by default, the
|
| + first snapshots taken in each of the last eight hours, the first
|
| + snapshots taken in each of the last seven days, the first snapshots
|
| + taken in the last 4 weeks (counting Midnight Sunday morning as
|
| + the start of the week), and the first snapshot from the first
|
| + Sunday of each month forever.
|
|
|
| :type hourly_backups: int
|
| :param hourly_backups: How many recent hourly backups should be saved.
|
| @@ -1348,15 +1468,18 @@ class EC2Connection(AWSQueryConnection):
|
| :param weekly_backups: How many recent weekly backups should be saved.
|
| """
|
|
|
| - # This function first builds up an ordered list of target times that snapshots should be saved for
|
| - # (last 8 hours, last 7 days, etc.). Then a map of snapshots is constructed, with the keys being
|
| - # the snapshot / volume names and the values being arrays of chornologically sorted snapshots.
|
| - # Finally, for each array in the map, we go through the snapshot array and the target time array
|
| - # in an interleaved fashion, deleting snapshots whose start_times don't immediately follow a
|
| - # target time (we delete a snapshot if there's another snapshot that was made closer to the
|
| - # preceding target time).
|
| + # This function first builds up an ordered list of target times
|
| + # that snapshots should be saved for (last 8 hours, last 7 days, etc.).
|
| + # Then a map of snapshots is constructed, with the keys being
|
| + # the snapshot / volume names and the values being arrays of
|
| + # chronologically sorted snapshots.
|
| + # Finally, for each array in the map, we go through the snapshot
|
| + # array and the target time array in an interleaved fashion,
|
| + # deleting snapshots whose start_times don't immediately follow a
|
| + # target time (we delete a snapshot if there's another snapshot
|
| + # that was made closer to the preceding target time).
|
|
|
| - now = datetime.utcnow() # work with UTC time, which is what the snapshot start time is reported in
|
| + now = datetime.utcnow()
|
| last_hour = datetime(now.year, now.month, now.day, now.hour)
|
| last_midnight = datetime(now.year, now.month, now.day)
|
| last_sunday = datetime(now.year, now.month, now.day) - timedelta(days = (now.weekday() + 1) % 7)
|
| @@ -1364,7 +1487,8 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| target_backup_times = []
|
|
|
| - oldest_snapshot_date = datetime(2007, 1, 1) # there are no snapshots older than 1/1/2007
|
| + # there are no snapshots older than 1/1/2007
|
| + oldest_snapshot_date = datetime(2007, 1, 1)
|
|
|
| for hour in range(0, hourly_backups):
|
| target_backup_times.append(last_hour - timedelta(hours = hour))
|
| @@ -1377,13 +1501,16 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| one_day = timedelta(days = 1)
|
| while start_of_month > oldest_snapshot_date:
|
| - # append the start of the month to the list of snapshot dates to save:
|
| + # append the start of the month to the list of
|
| + # snapshot dates to save:
|
| target_backup_times.append(start_of_month)
|
| # there's no timedelta setting for one month, so instead:
|
| - # decrement the day by one, so we go to the final day of the previous month...
|
| + # decrement the day by one, so we go to the final day of
|
| + # the previous month...
|
| start_of_month -= one_day
|
| # ... and then go to the first day of that previous month:
|
| - start_of_month = datetime(start_of_month.year, start_of_month.month, 1)
|
| + start_of_month = datetime(start_of_month.year,
|
| + start_of_month.month, 1)
|
|
|
| temp = []
|
|
|
| @@ -1392,14 +1519,18 @@ class EC2Connection(AWSQueryConnection):
|
| temp.append(t)
|
|
|
| target_backup_times = temp
|
| - target_backup_times.reverse() # make the oldest date first
|
| + # make the oldeest dates first, and make sure the month start
|
| + # and last four week's start are in the proper order
|
| + target_backup_times.sort()
|
|
|
| - # get all the snapshots, sort them by date and time, and organize them into one array for each volume:
|
| + # get all the snapshots, sort them by date and time, and
|
| + # organize them into one array for each volume:
|
| all_snapshots = self.get_all_snapshots(owner = 'self')
|
| - all_snapshots.sort(cmp = lambda x, y: cmp(x.start_time, y.start_time)) # oldest first
|
| + all_snapshots.sort(cmp = lambda x, y: cmp(x.start_time, y.start_time))
|
| snaps_for_each_volume = {}
|
| for snap in all_snapshots:
|
| - # the snapshot name and the volume name are the same. The snapshot name is set from the volume
|
| + # the snapshot name and the volume name are the same.
|
| + # The snapshot name is set from the volume
|
| # name at the time the snapshot is taken
|
| volume_name = snap.tags.get('Name')
|
| if volume_name:
|
| @@ -1410,34 +1541,46 @@ class EC2Connection(AWSQueryConnection):
|
| snaps_for_each_volume[volume_name] = snaps_for_volume
|
| snaps_for_volume.append(snap)
|
|
|
| - # Do a running comparison of snapshot dates to desired time periods, keeping the oldest snapshot in each
|
| + # Do a running comparison of snapshot dates to desired time
|
| + #periods, keeping the oldest snapshot in each
|
| # time period and deleting the rest:
|
| for volume_name in snaps_for_each_volume:
|
| snaps = snaps_for_each_volume[volume_name]
|
| - snaps = snaps[:-1] # never delete the newest snapshot, so remove it from consideration
|
| + snaps = snaps[:-1] # never delete the newest snapshot
|
| time_period_number = 0
|
| snap_found_for_this_time_period = False
|
| for snap in snaps:
|
| check_this_snap = True
|
| while check_this_snap and time_period_number < target_backup_times.__len__():
|
| - snap_date = datetime.strptime(snap.start_time, '%Y-%m-%dT%H:%M:%S.000Z')
|
| + snap_date = datetime.strptime(snap.start_time,
|
| + '%Y-%m-%dT%H:%M:%S.000Z')
|
| if snap_date < target_backup_times[time_period_number]:
|
| - # the snap date is before the cutoff date. Figure out if it's the first snap in this
|
| - # date range and act accordingly (since both date the date ranges and the snapshots
|
| - # are sorted chronologically, we know this snapshot isn't in an earlier date range):
|
| + # the snap date is before the cutoff date.
|
| + # Figure out if it's the first snap in this
|
| + # date range and act accordingly (since both
|
| + #date the date ranges and the snapshots
|
| + # are sorted chronologically, we know this
|
| + #snapshot isn't in an earlier date range):
|
| if snap_found_for_this_time_period == True:
|
| if not snap.tags.get('preserve_snapshot'):
|
| - # as long as the snapshot wasn't marked with the 'preserve_snapshot' tag, delete it:
|
| - self.delete_snapshot(snap.id)
|
| - boto.log.info('Trimmed snapshot %s (%s)' % (snap.tags['Name'], snap.start_time))
|
| - # go on and look at the next snapshot, leaving the time period alone
|
| + # as long as the snapshot wasn't marked
|
| + # with the 'preserve_snapshot' tag, delete it:
|
| + try:
|
| + self.delete_snapshot(snap.id)
|
| + boto.log.info('Trimmed snapshot %s (%s)' % (snap.tags['Name'], snap.start_time))
|
| + except EC2ResponseError:
|
| + boto.log.error('Attempt to trim snapshot %s (%s) failed. Possible result of a race condition with trimming on another server?' % (snap.tags['Name'], snap.start_time))
|
| + # go on and look at the next snapshot,
|
| + #leaving the time period alone
|
| else:
|
| - # this was the first snapshot found for this time period. Leave it alone and look at the
|
| + # this was the first snapshot found for this
|
| + #time period. Leave it alone and look at the
|
| # next snapshot:
|
| snap_found_for_this_time_period = True
|
| check_this_snap = False
|
| else:
|
| - # the snap is after the cutoff date. Check it against the next cutoff date
|
| + # the snap is after the cutoff date. Check it
|
| + # against the next cutoff date
|
| time_period_number += 1
|
| snap_found_for_this_time_period = False
|
|
|
| @@ -1453,7 +1596,7 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type attribute: str
|
| :param attribute: The requested attribute. Valid values are:
|
| -
|
| +
|
| * createVolumePermission
|
|
|
| :rtype: list of :class:`boto.ec2.snapshotattribute.SnapshotAttribute`
|
| @@ -1545,7 +1688,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, keynames, 'KeyName')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - return self.get_list('DescribeKeyPairs', params, [('item', KeyPair)], verb='POST')
|
| + return self.get_list('DescribeKeyPairs', params,
|
| + [('item', KeyPair)], verb='POST')
|
|
|
| def get_key_pair(self, keyname):
|
| """
|
| @@ -1621,13 +1765,14 @@ class EC2Connection(AWSQueryConnection):
|
| The material attribute of the new KeyPair object
|
| will contain the the unencrypted PEM encoded RSA private key.
|
| """
|
| + public_key_material = base64.b64encode(public_key_material)
|
| params = {'KeyName' : key_name,
|
| 'PublicKeyMaterial' : public_key_material}
|
| return self.get_object('ImportKeyPair', params, KeyPair, verb='POST')
|
|
|
| # SecurityGroup methods
|
|
|
| - def get_all_security_groups(self, groupnames=None, filters=None):
|
| + def get_all_security_groups(self, groupnames=None, group_ids=None, filters=None):
|
| """
|
| Get all security groups associated with your account in a region.
|
|
|
| @@ -1636,6 +1781,10 @@ class EC2Connection(AWSQueryConnection):
|
| If not provided, all security groups will be
|
| returned.
|
|
|
| + :type group_ids: list
|
| + :param group_ids: A list of IDs of security groups to retrieve for
|
| + security groups within a VPC.
|
| +
|
| :type filters: dict
|
| :param filters: Optional filters that can be used to limit
|
| the results returned. Filters are provided
|
| @@ -1650,14 +1799,17 @@ class EC2Connection(AWSQueryConnection):
|
| :return: A list of :class:`boto.ec2.securitygroup.SecurityGroup`
|
| """
|
| params = {}
|
| - if groupnames:
|
| + if groupnames is not None:
|
| self.build_list_params(params, groupnames, 'GroupName')
|
| - if filters:
|
| + if group_ids is not None:
|
| + self.build_list_params(params, group_ids, 'GroupId')
|
| + if filters is not None:
|
| self.build_filter_params(params, filters)
|
| +
|
| return self.get_list('DescribeSecurityGroups', params,
|
| [('item', SecurityGroup)], verb='POST')
|
|
|
| - def create_security_group(self, name, description):
|
| + def create_security_group(self, name, description, vpc_id=None):
|
| """
|
| Create a new security group for your account.
|
| This will create the security group within the region you
|
| @@ -1669,35 +1821,60 @@ class EC2Connection(AWSQueryConnection):
|
| :type description: string
|
| :param description: The description of the new security group
|
|
|
| + :type vpc_id: string
|
| + :param vpc_id: The ID of the VPC to create the security group in,
|
| + if any.
|
| +
|
| :rtype: :class:`boto.ec2.securitygroup.SecurityGroup`
|
| :return: The newly created :class:`boto.ec2.keypair.KeyPair`.
|
| """
|
| - params = {'GroupName':name, 'GroupDescription':description}
|
| - group = self.get_object('CreateSecurityGroup', params, SecurityGroup, verb='POST')
|
| + params = {
|
| + 'GroupName': name,
|
| + 'GroupDescription': description
|
| + }
|
| +
|
| + if vpc_id is not None:
|
| + params['VpcId'] = vpc_id
|
| +
|
| + group = self.get_object('CreateSecurityGroup', params,
|
| + SecurityGroup, verb='POST')
|
| group.name = name
|
| group.description = description
|
| return group
|
|
|
| - def delete_security_group(self, name):
|
| + def delete_security_group(self, name=None, group_id=None):
|
| """
|
| Delete a security group from your account.
|
|
|
| - :type key_name: string
|
| - :param key_name: The name of the keypair to delete
|
| + :type name: string
|
| + :param name: The name of the security group to delete.
|
| +
|
| + :type group_id: string
|
| + :param group_id: The ID of the security group to delete within
|
| + a VPC.
|
| +
|
| + :rtype: bool
|
| + :return: True if successful.
|
| """
|
| - params = {'GroupName':name}
|
| + params = {}
|
| +
|
| + if name is not None:
|
| + params['GroupName'] = name
|
| + elif group_id is not None:
|
| + params['GroupId'] = group_id
|
| +
|
| return self.get_status('DeleteSecurityGroup', params, verb='POST')
|
|
|
| - def _authorize_deprecated(self, group_name, src_security_group_name=None,
|
| - src_security_group_owner_id=None):
|
| + def authorize_security_group_deprecated(self, group_name,
|
| + src_security_group_name=None,
|
| + src_security_group_owner_id=None,
|
| + ip_protocol=None,
|
| + from_port=None, to_port=None,
|
| + cidr_ip=None):
|
| """
|
| - This method is called only when someone tries to authorize a group
|
| - without specifying a from_port or to_port. Until recently, that was
|
| - the only way to do group authorization but the EC2 API has been
|
| - changed to now require a from_port and to_port when specifying a
|
| - group. This is a much better approach but I don't want to break
|
| - existing boto applications that depend on the old behavior, hence
|
| - this kludge.
|
| + NOTE: This method uses the old-style request parameters
|
| + that did not allow a port to be specified when
|
| + authorizing a group.
|
|
|
| :type group_name: string
|
| :param group_name: The name of the security group you are adding
|
| @@ -1711,22 +1888,43 @@ class EC2Connection(AWSQueryConnection):
|
| :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://goo.gl/Yj5QC
|
| +
|
| :rtype: bool
|
| :return: True if successful.
|
| """
|
| - warnings.warn('FromPort and ToPort now required for group authorization',
|
| - DeprecationWarning)
|
| params = {'GroupName':group_name}
|
| if src_security_group_name:
|
| params['SourceSecurityGroupName'] = src_security_group_name
|
| if src_security_group_owner_id:
|
| params['SourceSecurityGroupOwnerId'] = src_security_group_owner_id
|
| - return self.get_status('AuthorizeSecurityGroupIngress', params, verb='POST')
|
| + if ip_protocol:
|
| + params['IpProtocol'] = ip_protocol
|
| + if from_port:
|
| + params['FromPort'] = from_port
|
| + if to_port:
|
| + params['ToPort'] = to_port
|
| + if cidr_ip:
|
| + params['CidrIp'] = cidr_ip
|
| + return self.get_status('AuthorizeSecurityGroupIngress', params)
|
|
|
| - def authorize_security_group(self, group_name, src_security_group_name=None,
|
| + def authorize_security_group(self, group_name=None,
|
| + src_security_group_name=None,
|
| src_security_group_owner_id=None,
|
| ip_protocol=None, from_port=None, to_port=None,
|
| - cidr_ip=None):
|
| + cidr_ip=None, group_id=None,
|
| + src_security_group_group_id=None):
|
| """
|
| Add a new rule to an existing security group.
|
| You need to pass in either src_security_group_name and
|
| @@ -1757,70 +1955,163 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type cidr_ip: string
|
| :param cidr_ip: The CIDR block you are providing access to.
|
| - See http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
|
| + See http://goo.gl/Yj5QC
|
| +
|
| + :type group_id: string
|
| + :param group_id: ID of the EC2 or VPC security group to modify.
|
| + This is required for VPC security groups and
|
| + can be used instead of group_name for EC2
|
| + security groups.
|
| +
|
| + :type group_id: string
|
| + :param group_id: ID of the EC2 or VPC source security group.
|
| + This is required for VPC security groups and
|
| + can be used instead of group_name for EC2
|
| + security groups.
|
|
|
| :rtype: bool
|
| :return: True if successful.
|
| """
|
| if src_security_group_name:
|
| if from_port is None and to_port is None and ip_protocol is None:
|
| - return self._authorize_deprecated(group_name,
|
| - src_security_group_name,
|
| - src_security_group_owner_id)
|
| - params = {'GroupName':group_name}
|
| + return self.authorize_security_group_deprecated(
|
| + group_name, src_security_group_name,
|
| + src_security_group_owner_id)
|
| +
|
| + params = {}
|
| +
|
| + if group_name:
|
| + params['GroupName'] = group_name
|
| + if group_id:
|
| + params['GroupId'] = group_id
|
| if src_security_group_name:
|
| - params['IpPermissions.1.Groups.1.GroupName'] = src_security_group_name
|
| + param_name = 'IpPermissions.1.Groups.1.GroupName'
|
| + params[param_name] = src_security_group_name
|
| if src_security_group_owner_id:
|
| - params['IpPermissions.1.Groups.1.UserId'] = src_security_group_owner_id
|
| + param_name = 'IpPermissions.1.Groups.1.UserId'
|
| + params[param_name] = src_security_group_owner_id
|
| + if src_security_group_group_id:
|
| + param_name = 'IpPermissions.1.Groups.1.GroupId'
|
| + params[param_name] = src_security_group_group_id
|
| if ip_protocol:
|
| params['IpPermissions.1.IpProtocol'] = ip_protocol
|
| - if from_port:
|
| + if from_port is not None:
|
| params['IpPermissions.1.FromPort'] = from_port
|
| - if to_port:
|
| + if to_port is not None:
|
| params['IpPermissions.1.ToPort'] = to_port
|
| if cidr_ip:
|
| params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip
|
| - return self.get_status('AuthorizeSecurityGroupIngress', params, verb='POST')
|
|
|
| - def _revoke_deprecated(self, group_name, src_security_group_name=None,
|
| - src_security_group_owner_id=None):
|
| + return self.get_status('AuthorizeSecurityGroupIngress',
|
| + params, verb='POST')
|
| +
|
| + def authorize_security_group_egress(group_id,
|
| + ip_protocol,
|
| + from_port=None,
|
| + to_port=None,
|
| + src_group_id=None,
|
| + cidr_ip=None):
|
| + """
|
| + The action adds one or more egress rules to a VPC security
|
| + group. Specifically, this action permits instances in a
|
| + security group to send traffic to one or more destination
|
| + CIDR IP address ranges, or to one or more destination
|
| + security groups in the same VPC.
|
| """
|
| - This method is called only when someone tries to revoke a group
|
| - without specifying a from_port or to_port. Until recently, that was
|
| - the only way to do group revocation but the EC2 API has been
|
| - changed to now require a from_port and to_port when specifying a
|
| - group. This is a much better approach but I don't want to break
|
| - existing boto applications that depend on the old behavior, hence
|
| - this kludge.
|
| + params = {
|
| + 'GroupId': group_id,
|
| + 'IpPermissions.1.IpProtocol': ip_protocol
|
| + }
|
| +
|
| + if from_port is not None:
|
| + params['IpPermissions.1.FromPort'] = from_port
|
| + if to_port is not None:
|
| + params['IpPermissions.1.ToPort'] = to_port
|
| + if src_group_id is not None:
|
| + params['IpPermissions.1.Groups.1.GroupId'] = src_group_id
|
| + if cidr_ip is not None:
|
| + params['IpPermissions.1.Groups.1.CidrIp'] = cidr_ip
|
| +
|
| + return self.get_status('AuthorizeSecurityGroupEgress',
|
| + params, verb='POST')
|
| +
|
| + def revoke_security_group_deprecated(self, group_name,
|
| + src_security_group_name=None,
|
| + src_security_group_owner_id=None,
|
| + ip_protocol=None,
|
| + from_port=None, to_port=None,
|
| + cidr_ip=None):
|
| + """
|
| + NOTE: This method uses the old-style request parameters
|
| + that did not allow a port to be specified when
|
| + authorizing a group.
|
| +
|
| + 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 adding
|
| - the rule to.
|
| + :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
|
| - granting access to.
|
| + 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 granting access to.
|
| + 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.
|
| + http://goo.gl/Yj5QC
|
| +
|
| + :type group_id: string
|
| + :param group_id: ID of the EC2 or VPC security group to modify.
|
| + This is required for VPC security groups and
|
| + can be used instead of group_name for EC2
|
| + security groups.
|
| +
|
| + :type group_id: string
|
| + :param group_id: ID of the EC2 or VPC source security group.
|
| + This is required for VPC security groups and
|
| + can be used instead of group_name for EC2
|
| + security groups.
|
|
|
| :rtype: bool
|
| :return: True if successful.
|
| """
|
| - warnings.warn('FromPort and ToPort now required for group authorization',
|
| - DeprecationWarning)
|
| params = {'GroupName':group_name}
|
| if src_security_group_name:
|
| params['SourceSecurityGroupName'] = src_security_group_name
|
| if src_security_group_owner_id:
|
| params['SourceSecurityGroupOwnerId'] = src_security_group_owner_id
|
| - return self.get_status('RevokeSecurityGroupIngress', params, verb='POST')
|
| + if ip_protocol:
|
| + params['IpProtocol'] = ip_protocol
|
| + if from_port:
|
| + params['FromPort'] = from_port
|
| + if to_port:
|
| + params['ToPort'] = to_port
|
| + if cidr_ip:
|
| + params['CidrIp'] = cidr_ip
|
| + return self.get_status('RevokeSecurityGroupIngress', params)
|
|
|
| def revoke_security_group(self, group_name, src_security_group_name=None,
|
| src_security_group_owner_id=None,
|
| ip_protocol=None, from_port=None, to_port=None,
|
| - cidr_ip=None):
|
| + cidr_ip=None, group_id=None,
|
| + src_security_group_group_id=None):
|
| """
|
| Remove an existing rule from an existing security group.
|
| You need to pass in either src_security_group_name and
|
| @@ -1851,30 +2142,35 @@ class EC2Connection(AWSQueryConnection):
|
|
|
| :type cidr_ip: string
|
| :param cidr_ip: The CIDR block you are revoking access to.
|
| - See http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
|
| + See http://goo.gl/Yj5QC
|
|
|
| :rtype: bool
|
| :return: True if successful.
|
| """
|
| if src_security_group_name:
|
| if from_port is None and to_port is None and ip_protocol is None:
|
| - return self._revoke_deprecated(group_name,
|
| - src_security_group_name,
|
| - src_security_group_owner_id)
|
| - params = {'GroupName':group_name}
|
| + return self.revoke_security_group_deprecated(
|
| + group_name, src_security_group_name,
|
| + src_security_group_owner_id)
|
| + params = {}
|
| + if group_name:
|
| + params['GroupName'] = group_name
|
| if src_security_group_name:
|
| - params['IpPermissions.1.Groups.1.GroupName'] = src_security_group_name
|
| + param_name = 'IpPermissions.1.Groups.1.GroupName'
|
| + params[param_name] = src_security_group_name
|
| if src_security_group_owner_id:
|
| - params['IpPermissions.1.Groups.1.UserId'] = src_security_group_owner_id
|
| + param_name = 'IpPermissions.1.Groups.1.UserId'
|
| + params[param_name] = src_security_group_owner_id
|
| if ip_protocol:
|
| params['IpPermissions.1.IpProtocol'] = ip_protocol
|
| - if from_port:
|
| + if from_port is not None:
|
| params['IpPermissions.1.FromPort'] = from_port
|
| - if to_port:
|
| + if to_port is not None:
|
| params['IpPermissions.1.ToPort'] = to_port
|
| if cidr_ip:
|
| params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip
|
| - return self.get_status('RevokeSecurityGroupIngress', params, verb='POST')
|
| + return self.get_status('RevokeSecurityGroupIngress',
|
| + params, verb='POST')
|
|
|
| #
|
| # Regions
|
| @@ -1905,7 +2201,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_list_params(params, region_names, 'RegionName')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - regions = self.get_list('DescribeRegions', params, [('item', RegionInfo)], verb='POST')
|
| + regions = self.get_list('DescribeRegions', params,
|
| + [('item', RegionInfo)], verb='POST')
|
| for region in regions:
|
| region.connection_cls = EC2Connection
|
| return regions
|
| @@ -1964,7 +2261,8 @@ class EC2Connection(AWSQueryConnection):
|
| self.build_filter_params(params, filters)
|
|
|
| return self.get_list('DescribeReservedInstancesOfferings',
|
| - params, [('item', ReservedInstancesOffering)], verb='POST')
|
| + params, [('item', ReservedInstancesOffering)],
|
| + verb='POST')
|
|
|
| def get_all_reserved_instances(self, reserved_instances_id=None,
|
| filters=None):
|
| @@ -1998,7 +2296,8 @@ class EC2Connection(AWSQueryConnection):
|
| return self.get_list('DescribeReservedInstances',
|
| params, [('item', ReservedInstance)], verb='POST')
|
|
|
| - def purchase_reserved_instance_offering(self, reserved_instances_offering_id,
|
| + def purchase_reserved_instance_offering(self,
|
| + reserved_instances_offering_id,
|
| instance_count=1):
|
| """
|
| Purchase a Reserved Instance for use with your account.
|
| @@ -2017,8 +2316,9 @@ class EC2Connection(AWSQueryConnection):
|
| :rtype: :class:`boto.ec2.reservedinstance.ReservedInstance`
|
| :return: The newly created Reserved Instance
|
| """
|
| - params = {'ReservedInstancesOfferingId' : reserved_instances_offering_id,
|
| - 'InstanceCount' : instance_count}
|
| + params = {
|
| + 'ReservedInstancesOfferingId' : reserved_instances_offering_id,
|
| + 'InstanceCount' : instance_count}
|
| return self.get_object('PurchaseReservedInstancesOffering', params,
|
| ReservedInstance, verb='POST')
|
|
|
| @@ -2026,8 +2326,24 @@ class EC2Connection(AWSQueryConnection):
|
| # Monitoring
|
| #
|
|
|
| + def monitor_instances(self, instance_ids):
|
| + """
|
| + Enable CloudWatch monitoring for the supplied instances.
|
| +
|
| + :type instance_id: list of strings
|
| + :param instance_id: The instance ids
|
| +
|
| + :rtype: list
|
| + :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
|
| + """
|
| + params = {}
|
| + self.build_list_params(params, instance_ids, 'InstanceId')
|
| + return self.get_list('MonitorInstances', params,
|
| + [('item', InstanceInfo)], verb='POST')
|
| +
|
| def monitor_instance(self, instance_id):
|
| """
|
| + Deprecated Version, maintained for backward compatibility.
|
| Enable CloudWatch monitoring for the supplied instance.
|
|
|
| :type instance_id: string
|
| @@ -2036,12 +2352,26 @@ class EC2Connection(AWSQueryConnection):
|
| :rtype: list
|
| :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
|
| """
|
| - params = {'InstanceId' : instance_id}
|
| - return self.get_list('MonitorInstances', params,
|
| + return self.monitor_instances([instance_id])
|
| +
|
| + def unmonitor_instances(self, instance_ids):
|
| + """
|
| + Disable CloudWatch monitoring for the supplied instance.
|
| +
|
| + :type instance_id: list of string
|
| + :param instance_id: The instance id
|
| +
|
| + :rtype: list
|
| + :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
|
| + """
|
| + params = {}
|
| + self.build_list_params(params, instance_ids, 'InstanceId')
|
| + return self.get_list('UnmonitorInstances', params,
|
| [('item', InstanceInfo)], verb='POST')
|
|
|
| def unmonitor_instance(self, instance_id):
|
| """
|
| + Deprecated Version, maintained for backward compatibility.
|
| Disable CloudWatch monitoring for the supplied instance.
|
|
|
| :type instance_id: string
|
| @@ -2050,16 +2380,14 @@ class EC2Connection(AWSQueryConnection):
|
| :rtype: list
|
| :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
|
| """
|
| - params = {'InstanceId' : instance_id}
|
| - return self.get_list('UnmonitorInstances', params,
|
| - [('item', InstanceInfo)], verb='POST')
|
| + return self.unmonitor_instances([instance_id])
|
|
|
| - #
|
| + #
|
| # Bundle Windows Instances
|
| #
|
|
|
| def bundle_instance(self, instance_id,
|
| - s3_bucket,
|
| + s3_bucket,
|
| s3_prefix,
|
| s3_upload_policy):
|
| """
|
| @@ -2084,11 +2412,13 @@ class EC2Connection(AWSQueryConnection):
|
| 'Storage.S3.Bucket' : s3_bucket,
|
| 'Storage.S3.Prefix' : s3_prefix,
|
| 'Storage.S3.UploadPolicy' : s3_upload_policy}
|
| - s3auth = boto.auth.get_auth_handler(None, boto.config, self.provider, ['s3'])
|
| + s3auth = boto.auth.get_auth_handler(None, boto.config,
|
| + self.provider, ['s3'])
|
| params['Storage.S3.AWSAccessKeyId'] = self.aws_access_key_id
|
| signature = s3auth.sign_string(s3_upload_policy)
|
| params['Storage.S3.UploadPolicySignature'] = signature
|
| - return self.get_object('BundleInstance', params, BundleInstanceTask, verb='POST')
|
| + return self.get_object('BundleInstance', params,
|
| + BundleInstanceTask, verb='POST')
|
|
|
| def get_all_bundle_tasks(self, bundle_ids=None, filters=None):
|
| """
|
| @@ -2096,9 +2426,9 @@ class EC2Connection(AWSQueryConnection):
|
| tasks are retrieved.
|
|
|
| :type bundle_ids: list
|
| - :param bundle_ids: A list of strings containing identifiers for
|
| + :param bundle_ids: A list of strings containing identifiers for
|
| previously created bundling tasks.
|
| -
|
| +
|
| :type filters: dict
|
| :param filters: Optional filters that can be used to limit
|
| the results returned. Filters are provided
|
| @@ -2110,7 +2440,7 @@ class EC2Connection(AWSQueryConnection):
|
| for details.
|
|
|
| """
|
| -
|
| +
|
| params = {}
|
| if bundle_ids:
|
| self.build_list_params(params, bundle_ids, 'BundleId')
|
| @@ -2122,13 +2452,14 @@ class EC2Connection(AWSQueryConnection):
|
| def cancel_bundle_task(self, bundle_id):
|
| """
|
| Cancel a previously submitted bundle task
|
| -
|
| +
|
| :type bundle_id: string
|
| :param bundle_id: The identifier of the bundle task to cancel.
|
| - """
|
| + """
|
|
|
| params = {'BundleId' : bundle_id}
|
| - return self.get_object('CancelBundleTask', params, BundleInstanceTask, verb='POST')
|
| + return self.get_object('CancelBundleTask', params,
|
| + BundleInstanceTask, verb='POST')
|
|
|
| def get_password_data(self, instance_id):
|
| """
|
| @@ -2143,7 +2474,7 @@ class EC2Connection(AWSQueryConnection):
|
| rs = self.get_object('GetPasswordData', params, ResultSet, verb='POST')
|
| return rs.passwordData
|
|
|
| - #
|
| + #
|
| # Cluster Placement Groups
|
| #
|
|
|
| @@ -2190,8 +2521,8 @@ class EC2Connection(AWSQueryConnection):
|
| :param strategy: The placement strategy of the new placement group.
|
| Currently, the only acceptable value is "cluster".
|
|
|
| - :rtype: :class:`boto.ec2.placementgroup.PlacementGroup`
|
| - :return: The newly created :class:`boto.ec2.keypair.KeyPair`.
|
| + :rtype: bool
|
| + :return: True if successful
|
| """
|
| params = {'GroupName':name, 'Strategy':strategy}
|
| group = self.get_status('CreatePlacementGroup', params, verb='POST')
|
| @@ -2219,14 +2550,11 @@ class EC2Connection(AWSQueryConnection):
|
| if value is not None:
|
| params['Tag.%d.Value'%i] = value
|
| i += 1
|
| -
|
| - def get_all_tags(self, tags=None, filters=None):
|
| +
|
| + def get_all_tags(self, filters=None):
|
| """
|
| Retrieve all the metadata tags associated with your account.
|
|
|
| - :type tags: list
|
| - :param tags: A list of mumble
|
| -
|
| :type filters: dict
|
| :param filters: Optional filters that can be used to limit
|
| the results returned. Filters are provided
|
| @@ -2241,11 +2569,10 @@ class EC2Connection(AWSQueryConnection):
|
| :return: A dictionary containing metadata tags
|
| """
|
| params = {}
|
| - if tags:
|
| - self.build_list_params(params, instance_ids, 'InstanceId')
|
| if filters:
|
| self.build_filter_params(params, filters)
|
| - return self.get_list('DescribeTags', params, [('item', Tag)], verb='POST')
|
| + return self.get_list('DescribeTags', params,
|
| + [('item', Tag)], verb='POST')
|
|
|
| def create_tags(self, resource_ids, tags):
|
| """
|
| @@ -2255,7 +2582,10 @@ class EC2Connection(AWSQueryConnection):
|
| :param resource_ids: List of strings
|
|
|
| :type tags: dict
|
| - :param tags: A dictionary containing the name/value pairs
|
| + :param tags: A dictionary containing the name/value pairs.
|
| + If you want to create only a tag name, the
|
| + value for that tag should be the empty string
|
| + (e.g. '').
|
|
|
| """
|
| params = {}
|
| @@ -2275,7 +2605,9 @@ class EC2Connection(AWSQueryConnection):
|
| or a list containing just tag names.
|
| If you pass in a dictionary, the values must
|
| match the actual tag values or the tag will
|
| - not be deleted.
|
| + not be deleted. If you pass in a value of None
|
| + for the tag value, all tags with that name will
|
| + be deleted.
|
|
|
| """
|
| if isinstance(tags, list):
|
|
|