diff options
Diffstat (limited to 'boto/ec2')
39 files changed, 219 insertions, 164 deletions
diff --git a/boto/ec2/address.py b/boto/ec2/address.py index ce1189ed..807406f7 100644 --- a/boto/ec2/address.py +++ b/boto/ec2/address.py @@ -22,6 +22,7 @@ from boto.ec2.ec2object import EC2Object + class Address(EC2Object): """ Represents an EC2 Elastic IP Address @@ -78,33 +79,36 @@ class Address(EC2Object): """ if self.allocation_id: return self.connection.release_address( - None, - self.allocation_id, + allocation_id=self.allocation_id, dry_run=dry_run) else: return self.connection.release_address( - self.public_ip, + public_ip=self.public_ip, dry_run=dry_run ) delete = release - def associate(self, instance_id, allow_reassociation=False, dry_run=False): + def associate(self, instance_id=None, network_interface_id=None, private_ip_address=None, allow_reassociation=False, dry_run=False): """ Associate this Elastic IP address with a currently running instance. :see: :meth:`boto.ec2.connection.EC2Connection.associate_address` """ if self.allocation_id: return self.connection.associate_address( - instance_id, - self.public_ip, + instance_id=instance_id, + public_ip=self.public_ip, allocation_id=self.allocation_id, + network_interface_id=network_interface_id, + private_ip_address=private_ip_address, allow_reassociation=allow_reassociation, dry_run=dry_run ) return self.connection.associate_address( - instance_id, - self.public_ip, + instance_id=instance_id, + public_ip=self.public_ip, + network_interface_id=network_interface_id, + private_ip_address=private_ip_address, allow_reassociation=allow_reassociation, dry_run=dry_run ) @@ -116,14 +120,11 @@ class Address(EC2Object): """ if self.association_id: return self.connection.disassociate_address( - None, - self.association_id, + association_id=self.association_id, dry_run=dry_run ) else: return self.connection.disassociate_address( - self.public_ip, + public_ip=self.public_ip, dry_run=dry_run ) - - diff --git a/boto/ec2/autoscale/__init__.py b/boto/ec2/autoscale/__init__.py index fc0534b4..5a58748d 100644 --- a/boto/ec2/autoscale/__init__.py +++ b/boto/ec2/autoscale/__init__.py @@ -105,14 +105,14 @@ class AutoScaleConnection(AWSQueryConnection): self.region = region self.use_block_device_types = use_block_device_types super(AutoScaleConnection, self).__init__(aws_access_key_id, - aws_secret_access_key, - is_secure, port, proxy, proxy_port, - proxy_user, proxy_pass, - self.region.endpoint, debug, - https_connection_factory, path=path, - security_token=security_token, - validate_certs=validate_certs, - profile_name=profile_name) + aws_secret_access_key, + is_secure, port, proxy, proxy_port, + proxy_user, proxy_pass, + self.region.endpoint, debug, + https_connection_factory, path=path, + security_token=security_token, + validate_certs=validate_certs, + profile_name=profile_name) def _required_auth_capability(self): return ['hmac-v4'] @@ -222,7 +222,10 @@ class AutoScaleConnection(AWSQueryConnection): if launch_config.key_name: params['KeyName'] = launch_config.key_name if launch_config.user_data: - params['UserData'] = base64.b64encode(launch_config.user_data).decode('utf-8') + user_data = launch_config.user_data + if isinstance(user_data, six.text_type): + user_data = user_data.encode('utf-8') + params['UserData'] = base64.b64encode(user_data).decode('utf-8') if launch_config.kernel_id: params['KernelId'] = launch_config.kernel_id if launch_config.ramdisk_id: diff --git a/boto/ec2/autoscale/activity.py b/boto/ec2/autoscale/activity.py index 3f23d05d..bfe32f43 100644 --- a/boto/ec2/autoscale/activity.py +++ b/boto/ec2/autoscale/activity.py @@ -71,4 +71,3 @@ class Activity(object): self.status_code = value else: setattr(self, name, value) - diff --git a/boto/ec2/autoscale/instance.py b/boto/ec2/autoscale/instance.py index 6eb89c2c..6095c17b 100644 --- a/boto/ec2/autoscale/instance.py +++ b/boto/ec2/autoscale/instance.py @@ -57,4 +57,3 @@ class Instance(object): self.group_name = value else: setattr(self, name, value) - diff --git a/boto/ec2/autoscale/launchconfig.py b/boto/ec2/autoscale/launchconfig.py index a4e6ce9a..889cee21 100644 --- a/boto/ec2/autoscale/launchconfig.py +++ b/boto/ec2/autoscale/launchconfig.py @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -from datetime import datetime from boto.ec2.elb.listelement import ListElement # Namespacing issue with deprecated local class from boto.ec2.blockdevicemapping import BlockDeviceMapping as BDM @@ -129,8 +128,8 @@ class LaunchConfiguration(object): :type instance_type: str :param instance_type: The instance type - :type kern_id: str - :param kern_id: Kernel id for instance + :type kernel_id: str + :param kernel_id: Kernel id for instance :type ramdisk_id: str :param ramdisk_id: RAM disk id for instance diff --git a/boto/ec2/autoscale/limits.py b/boto/ec2/autoscale/limits.py index 8472a201..89ece672 100644 --- a/boto/ec2/autoscale/limits.py +++ b/boto/ec2/autoscale/limits.py @@ -19,6 +19,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. + class AccountLimits(object): def __init__(self, connection=None): self.connection = connection @@ -27,7 +28,7 @@ class AccountLimits(object): def __repr__(self): return 'AccountLimits: [%s, %s]' % (self.max_autoscaling_groups, - self.max_launch_configurations) + self.max_launch_configurations) def startElement(self, name, attrs, connection): return None @@ -41,4 +42,3 @@ class AccountLimits(object): self.max_launch_configurations = int(value) else: setattr(self, name, value) - diff --git a/boto/ec2/autoscale/policy.py b/boto/ec2/autoscale/policy.py index fbe7dc5f..191ac496 100644 --- a/boto/ec2/autoscale/policy.py +++ b/boto/ec2/autoscale/policy.py @@ -23,6 +23,7 @@ from boto.resultset import ResultSet from boto.ec2.elb.listelement import ListElement + class Alarm(object): def __init__(self, connection=None): self.connection = connection @@ -64,18 +65,24 @@ class AdjustmentType(object): class MetricCollectionTypes(object): class BaseType(object): arg = '' + def __init__(self, connection): self.connection = connection self.val = None + def __repr__(self): return '%s:%s' % (self.arg, self.val) + def startElement(self, name, attrs, connection): return + def endElement(self, name, value, connection): if name == self.arg: self.val = value + class Metric(BaseType): arg = 'Metric' + class Granularity(BaseType): arg = 'Granularity' diff --git a/boto/ec2/autoscale/request.py b/boto/ec2/autoscale/request.py index c066dff5..b17b534f 100644 --- a/boto/ec2/autoscale/request.py +++ b/boto/ec2/autoscale/request.py @@ -19,6 +19,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. + class Request(object): def __init__(self, connection=None): self.connection = connection @@ -35,4 +36,3 @@ class Request(object): self.request_id = value else: setattr(self, name, value) - diff --git a/boto/ec2/autoscale/scheduled.py b/boto/ec2/autoscale/scheduled.py index 8e307c20..8d2eda40 100644 --- a/boto/ec2/autoscale/scheduled.py +++ b/boto/ec2/autoscale/scheduled.py @@ -75,4 +75,3 @@ class ScheduledUpdateGroupAction(object): self.end_time = datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ') else: setattr(self, name, value) - diff --git a/boto/ec2/blockdevicemapping.py b/boto/ec2/blockdevicemapping.py index 65ffbb1d..2f4e1faf 100644 --- a/boto/ec2/blockdevicemapping.py +++ b/boto/ec2/blockdevicemapping.py @@ -38,7 +38,8 @@ class BlockDeviceType(object): delete_on_termination=False, size=None, volume_type=None, - iops=None): + iops=None, + encrypted=None): self.connection = connection self.ephemeral_name = ephemeral_name self.no_device = no_device @@ -50,6 +51,7 @@ class BlockDeviceType(object): self.size = size self.volume_type = volume_type self.iops = iops + self.encrypted = encrypted def startElement(self, name, attrs, connection): pass @@ -76,6 +78,8 @@ class BlockDeviceType(object): self.volume_type = value elif lname == 'iops': self.iops = int(value) + elif lname == 'encrypted': + self.encrypted = (value == 'true') else: setattr(self, name, value) @@ -150,4 +154,12 @@ class BlockDeviceMapping(dict): params['%s.Ebs.VolumeType' % pre] = block_dev.volume_type if block_dev.iops is not None: params['%s.Ebs.Iops' % pre] = block_dev.iops + # The encrypted flag (even if False) cannot be specified for the root EBS + # volume. + if block_dev.encrypted is not None: + if block_dev.encrypted: + params['%s.Ebs.Encrypted' % pre] = 'true' + else: + params['%s.Ebs.Encrypted' % pre] = 'false' + i += 1 diff --git a/boto/ec2/bundleinstance.py b/boto/ec2/bundleinstance.py index 1bb4dd16..e241da9a 100644 --- a/boto/ec2/bundleinstance.py +++ b/boto/ec2/bundleinstance.py @@ -25,6 +25,7 @@ Represents an EC2 Bundle Task from boto.ec2.ec2object import EC2Object + class BundleInstanceTask(EC2Object): def __init__(self, connection=None): @@ -75,4 +76,3 @@ class BundleInstanceTask(EC2Object): self.message = value else: setattr(self, name, value) - diff --git a/boto/ec2/buyreservation.py b/boto/ec2/buyreservation.py index 7a0e6751..786d0fed 100644 --- a/boto/ec2/buyreservation.py +++ b/boto/ec2/buyreservation.py @@ -14,19 +14,21 @@ # 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, +# 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. import boto.ec2 from boto.sdb.db.property import StringProperty, IntegerProperty from boto.manage import propget +from boto.compat import six InstanceTypes = ['m1.small', 'm1.large', 'm1.xlarge', 'c1.medium', 'c1.xlarge', 'm2.xlarge', 'm2.2xlarge', 'm2.4xlarge', 'cc1.4xlarge', 't1.micro'] + class BuyReservation(object): def get_region(self, params): @@ -51,7 +53,7 @@ class BuyReservation(object): prop = StringProperty(name='zone', verbose_name='EC2 Availability Zone', choices=self.ec2.get_all_zones) params['zone'] = propget.get(prop) - + def get(self, params): self.get_region(params) self.ec2 = params['region'].connect() @@ -76,7 +78,7 @@ if __name__ == "__main__": unit_price = float(offering.fixed_price) total_price = unit_price * params['quantity'] print('!!! You are about to purchase %d of these offerings for a total of $%.2f !!!' % (params['quantity'], total_price)) - answer = raw_input('Are you sure you want to do this? If so, enter YES: ') + answer = six.moves.input('Are you sure you want to do this? If so, enter YES: ') if answer.strip().lower() == 'yes': offering.purchase(params['quantity']) else: diff --git a/boto/ec2/cloudwatch/__init__.py b/boto/ec2/cloudwatch/__init__.py index 0c9115e8..9b150b4e 100644 --- a/boto/ec2/cloudwatch/__init__.py +++ b/boto/ec2/cloudwatch/__init__.py @@ -92,14 +92,14 @@ class CloudWatchConnection(AWSQueryConnection): validate_certs = False super(CloudWatchConnection, self).__init__(aws_access_key_id, - aws_secret_access_key, - is_secure, port, proxy, proxy_port, - proxy_user, proxy_pass, - self.region.endpoint, debug, - https_connection_factory, path, - security_token, - validate_certs=validate_certs, - profile_name=profile_name) + aws_secret_access_key, + is_secure, port, proxy, proxy_port, + proxy_user, proxy_pass, + self.region.endpoint, debug, + https_connection_factory, path, + security_token, + validate_certs=validate_certs, + profile_name=profile_name) def _required_auth_capability(self): return ['hmac-v4'] @@ -113,11 +113,11 @@ class CloudWatchConnection(AWSQueryConnection): if isinstance(dim_value, six.string_types): dim_value = [dim_value] for value in dim_value: - params['%s.%d.Name' % (prefix, i+1)] = dim_name - params['%s.%d.Value' % (prefix, i+1)] = value + params['%s.%d.Name' % (prefix, i + 1)] = dim_name + params['%s.%d.Value' % (prefix, i + 1)] = value i += 1 else: - params['%s.%d.Name' % (prefix, i+1)] = dim_name + params['%s.%d.Name' % (prefix, i + 1)] = dim_name i += 1 def build_list_params(self, params, items, label): @@ -134,7 +134,7 @@ class CloudWatchConnection(AWSQueryConnection): params[label % i] = item def build_put_params(self, params, name, value=None, timestamp=None, - unit=None, dimensions=None, statistics=None): + unit=None, dimensions=None, statistics=None): args = (name, value, unit, dimensions, statistics, timestamp) length = max(map(lambda a: len(a) if isinstance(a, list) else 1, args)) @@ -329,7 +329,7 @@ class CloudWatchConnection(AWSQueryConnection): """ params = {'Namespace': namespace} self.build_put_params(params, name, value=value, timestamp=timestamp, - unit=unit, dimensions=dimensions, statistics=statistics) + unit=unit, dimensions=dimensions, statistics=statistics) return self.get_status('PutMetricData', params, verb="POST") @@ -498,15 +498,15 @@ class CloudWatchConnection(AWSQueryConnection): :param alarm: MetricAlarm object. """ params = { - 'AlarmName': alarm.name, - 'MetricName': alarm.metric, - 'Namespace': alarm.namespace, - 'Statistic': alarm.statistic, - 'ComparisonOperator': alarm.comparison, - 'Threshold': alarm.threshold, - 'EvaluationPeriods': alarm.evaluation_periods, - 'Period': alarm.period, - } + 'AlarmName': alarm.name, + 'MetricName': alarm.metric, + 'Namespace': alarm.namespace, + 'Statistic': alarm.statistic, + 'ComparisonOperator': alarm.comparison, + 'Threshold': alarm.threshold, + 'EvaluationPeriods': alarm.evaluation_periods, + 'Period': alarm.period, + } if alarm.actions_enabled is not None: params['ActionsEnabled'] = alarm.actions_enabled if alarm.alarm_actions: diff --git a/boto/ec2/cloudwatch/alarm.py b/boto/ec2/cloudwatch/alarm.py index 787c08cf..c267ab03 100644 --- a/boto/ec2/cloudwatch/alarm.py +++ b/boto/ec2/cloudwatch/alarm.py @@ -52,11 +52,11 @@ class MetricAlarm(object): INSUFFICIENT_DATA = 'INSUFFICIENT_DATA' _cmp_map = { - '>=': 'GreaterThanOrEqualToThreshold', - '>': 'GreaterThanThreshold', - '<': 'LessThanThreshold', - '<=': 'LessThanOrEqualToThreshold', - } + '>=': 'GreaterThanOrEqualToThreshold', + '>': 'GreaterThanThreshold', + '<': 'LessThanThreshold', + '<=': 'LessThanOrEqualToThreshold', + } _rev_cmp_map = dict((v, k) for (k, v) in six.iteritems(_cmp_map)) def __init__(self, connection=None, name=None, metric=None, @@ -122,15 +122,15 @@ class MetricAlarm(object): 'InstanceId': ['i-0123456', 'i-0123457'], 'LoadBalancerName': 'test-lb' } - + :type alarm_actions: list of strs :param alarm_actions: A list of the ARNs of the actions to take in ALARM state - + :type insufficient_data_actions: list of strs :param insufficient_data_actions: A list of the ARNs of the actions to take in INSUFFICIENT_DATA state - + :type ok_actions: list of strs :param ok_actions: A list of the ARNs of the actions to take in OK state """ @@ -295,6 +295,7 @@ class MetricAlarm(object): def delete(self): self.connection.delete_alarms([self.name]) + class AlarmHistoryItem(object): def __init__(self, connection=None): self.connection = connection diff --git a/boto/ec2/cloudwatch/datapoint.py b/boto/ec2/cloudwatch/datapoint.py index a33771a1..94955acd 100644 --- a/boto/ec2/cloudwatch/datapoint.py +++ b/boto/ec2/cloudwatch/datapoint.py @@ -21,6 +21,7 @@ # from datetime import datetime + class Datapoint(dict): def __init__(self, connection=None): diff --git a/boto/ec2/cloudwatch/dimension.py b/boto/ec2/cloudwatch/dimension.py index 86ebb9c3..9ff4fb11 100644 --- a/boto/ec2/cloudwatch/dimension.py +++ b/boto/ec2/cloudwatch/dimension.py @@ -20,6 +20,7 @@ # IN THE SOFTWARE. # + class Dimension(dict): def startElement(self, name, attrs, connection): diff --git a/boto/ec2/cloudwatch/listelement.py b/boto/ec2/cloudwatch/listelement.py index 2dd9cef0..6a290418 100644 --- a/boto/ec2/cloudwatch/listelement.py +++ b/boto/ec2/cloudwatch/listelement.py @@ -14,11 +14,12 @@ # 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, +# 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 ListElement(list): def startElement(self, name, attrs, connection): diff --git a/boto/ec2/connection.py b/boto/ec2/connection.py index 4fa205b6..f301ae5d 100644 --- a/boto/ec2/connection.py +++ b/boto/ec2/connection.py @@ -93,14 +93,14 @@ class EC2Connection(AWSQueryConnection): self.DefaultRegionEndpoint) self.region = region super(EC2Connection, self).__init__(aws_access_key_id, - aws_secret_access_key, - is_secure, port, proxy, proxy_port, - proxy_user, proxy_pass, - self.region.endpoint, debug, - https_connection_factory, path, - security_token, - validate_certs=validate_certs, - profile_name=profile_name) + aws_secret_access_key, + is_secure, port, proxy, proxy_port, + proxy_user, proxy_pass, + self.region.endpoint, debug, + https_connection_factory, path, + security_token, + validate_certs=validate_certs, + profile_name=profile_name) if api_version: self.APIVersion = api_version @@ -270,7 +270,7 @@ class EC2Connection(AWSQueryConnection): root_device_name=None, block_device_map=None, dry_run=False, virtualization_type=None, sriov_net_support=None, - snapshot_id=None, + snapshot_id=None, delete_root_volume_on_termination=False): """ Register an image. @@ -323,7 +323,7 @@ class EC2Connection(AWSQueryConnection): :type delete_root_volume_on_termination: bool :param delete_root_volume_on_termination: Whether to delete the root volume of the image after instance termination. Only applies when - creating image from snapshot_id. Defaults to False. Note that + creating image from snapshot_id. Defaults to False. Note that leaving volumes behind after instance termination is not free. :rtype: string @@ -345,8 +345,8 @@ class EC2Connection(AWSQueryConnection): if root_device_name: params['RootDeviceName'] = root_device_name if snapshot_id: - root_vol = BlockDeviceType(snapshot_id=snapshot_id, - delete_on_termination=delete_root_volume_on_termination) + root_vol = BlockDeviceType(snapshot_id=snapshot_id, + delete_on_termination=delete_root_volume_on_termination) block_device_map = BlockDeviceMapping() block_device_map[root_device_name] = root_vol if block_device_map: @@ -358,7 +358,6 @@ class EC2Connection(AWSQueryConnection): if sriov_net_support: params['SriovNetSupport'] = sriov_net_support - rs = self.get_object('RegisterImage', params, ResultSet, verb='POST') image_id = getattr(rs, 'imageId', None) return image_id @@ -1881,9 +1880,9 @@ class EC2Connection(AWSQueryConnection): return self.get_status('AssignPrivateIpAddresses', params, verb='POST') def _associate_address(self, status, instance_id=None, public_ip=None, - allocation_id=None, network_interface_id=None, - private_ip_address=None, allow_reassociation=False, - dry_run=False): + allocation_id=None, network_interface_id=None, + private_ip_address=None, allow_reassociation=False, + dry_run=False): params = {} if instance_id is not None: params['InstanceId'] = instance_id @@ -1960,9 +1959,9 @@ class EC2Connection(AWSQueryConnection): allow_reassociation=allow_reassociation, dry_run=dry_run) def associate_address_object(self, instance_id=None, public_ip=None, - allocation_id=None, network_interface_id=None, - private_ip_address=None, allow_reassociation=False, - dry_run=False): + allocation_id=None, network_interface_id=None, + private_ip_address=None, allow_reassociation=False, + dry_run=False): """ Associate an Elastic IP address with a currently running instance. This requires one of ``public_ip`` or ``allocation_id`` depending @@ -2589,7 +2588,7 @@ class EC2Connection(AWSQueryConnection): 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) + last_sunday = datetime(now.year, now.month, now.day) - timedelta(days=(now.weekday() + 1) % 7) start_of_month = datetime(now.year, now.month, 1) target_backup_times = [] @@ -2598,15 +2597,15 @@ class EC2Connection(AWSQueryConnection): oldest_snapshot_date = datetime(2007, 1, 1) for hour in range(0, hourly_backups): - target_backup_times.append(last_hour - timedelta(hours = hour)) + target_backup_times.append(last_hour - timedelta(hours=hour)) for day in range(0, daily_backups): - target_backup_times.append(last_midnight - timedelta(days = day)) + target_backup_times.append(last_midnight - timedelta(days=day)) for week in range(0, weekly_backups): - target_backup_times.append(last_sunday - timedelta(weeks = week)) + target_backup_times.append(last_sunday - timedelta(weeks=week)) - one_day = timedelta(days = 1) + one_day = timedelta(days=1) monthly_snapshots_added = 0 while (start_of_month > oldest_snapshot_date and (monthly_backups is True or @@ -3080,7 +3079,7 @@ class EC2Connection(AWSQueryConnection): :rtype: bool :return: True if successful. """ - params = {'GroupName':group_name} + params = {'GroupName': group_name} if src_security_group_name: params['SourceSecurityGroupName'] = src_security_group_name if src_security_group_owner_id: @@ -3184,7 +3183,7 @@ class EC2Connection(AWSQueryConnection): if not isinstance(cidr_ip, list): cidr_ip = [cidr_ip] for i, single_cidr_ip in enumerate(cidr_ip): - params['IpPermissions.1.IpRanges.%d.CidrIp' % (i+1)] = \ + params['IpPermissions.1.IpRanges.%d.CidrIp' % (i + 1)] = \ single_cidr_ip if dry_run: params['DryRun'] = 'true' @@ -3278,7 +3277,7 @@ class EC2Connection(AWSQueryConnection): :rtype: bool :return: True if successful. """ - params = {'GroupName':group_name} + params = {'GroupName': group_name} if src_security_group_name: params['SourceSecurityGroupName'] = src_security_group_name if src_security_group_owner_id: @@ -3476,7 +3475,7 @@ class EC2Connection(AWSQueryConnection): if dry_run: params['DryRun'] = 'true' regions = self.get_list('DescribeRegions', params, - [('item', RegionInfo)], verb='POST') + [('item', RegionInfo)], verb='POST') for region in regions: region.connection_cls = EC2Connection return regions @@ -4110,7 +4109,7 @@ class EC2Connection(AWSQueryConnection): :rtype: bool :return: True if successful """ - params = {'GroupName':name, 'Strategy':strategy} + params = {'GroupName': name, 'Strategy': strategy} if dry_run: params['DryRun'] = 'true' group = self.get_status('CreatePlacementGroup', params, verb='POST') @@ -4127,7 +4126,7 @@ class EC2Connection(AWSQueryConnection): :param dry_run: Set to True if the operation should not actually run. """ - params = {'GroupName':name} + params = {'GroupName': name} if dry_run: params['DryRun'] = 'true' return self.get_status('DeletePlacementGroup', params, verb='POST') @@ -4139,9 +4138,9 @@ class EC2Connection(AWSQueryConnection): i = 1 for key in keys: value = tags[key] - params['Tag.%d.Key'%i] = key + params['Tag.%d.Key' % i] = key if value is not None: - params['Tag.%d.Value'%i] = value + params['Tag.%d.Value' % i] = value i += 1 def get_all_tags(self, filters=None, dry_run=False, max_results=None): @@ -4240,7 +4239,7 @@ class EC2Connection(AWSQueryConnection): :type network_interface_ids: list :param network_interface_ids: a list of strings representing ENI IDs - + :type filters: dict :param filters: Optional filters that can be used to limit the results returned. Filters are provided @@ -4409,7 +4408,7 @@ class EC2Connection(AWSQueryConnection): if dry_run: params['DryRun'] = 'true' return self.get_object('CopyImage', params, CopyImage, - verb='POST') + verb='POST') def describe_account_attributes(self, attribute_names=None, dry_run=False): """ diff --git a/boto/ec2/ec2object.py b/boto/ec2/ec2object.py index 383602e5..fa50a9fc 100644 --- a/boto/ec2/ec2object.py +++ b/boto/ec2/ec2object.py @@ -25,6 +25,7 @@ Represents an EC2 Object """ from boto.ec2.tag import TagSet + class EC2Object(object): def __init__(self, connection=None): @@ -64,7 +65,7 @@ class TaggedEC2Object(EC2Object): def add_tag(self, key, value='', dry_run=False): """ - Add a tag to this object. Tag's are stored by AWS and can be used + Add a tag to this object. Tags are stored by AWS and can be used to organize and filter resources. Adding a tag involves a round-trip to the EC2 service. @@ -76,14 +77,7 @@ class TaggedEC2Object(EC2Object): If you want only the tag name and no value, the value should be the empty string. """ - status = self.connection.create_tags( - [self.id], - {key : value}, - dry_run=dry_run - ) - if self.tags is None: - self.tags = TagSet() - self.tags[key] = value + self.add_tags({key: value}, dry_run) def add_tags(self, tags, dry_run=False): """ @@ -116,21 +110,35 @@ class TaggedEC2Object(EC2Object): :type value: str :param value: An optional value that can be stored with the tag. - If a value is provided, it must match the value - currently stored in EC2. If not, the tag will not - be removed. If a value of None is provided, all - tags with the specified name will be deleted. - NOTE: There is an important distinction between - a value of '' and a value of None. + If a value is provided, it must match the value currently + stored in EC2. If not, the tag will not be removed. If + a value of None is provided, the tag will be + unconditionally deleted. + NOTE: There is an important distinction between a value + of '' and a value of None. + """ + self.remove_tags({key: value}, dry_run) + + def remove_tags(self, tags, dry_run=False): + """ + Removes tags from this object. Removing tags involves a round-trip + to the EC2 service. + + :type tags: dict + :param tags: A dictionary of key-value pairs for the tags being removed. + For each key, the provided value must match the value + currently stored in EC2. If not, that particular tag will + not be removed. However, if a value of None is provided, + the tag will be unconditionally deleted. + NOTE: There is an important distinction between a value of + '' and a value of None. """ - if value is not None: - tags = {key : value} - else: - tags = [key] status = self.connection.delete_tags( [self.id], tags, dry_run=dry_run ) - if key in self.tags: - del self.tags[key] + for key, value in tags.items(): + if key in self.tags: + if value is None or value == self.tags[key]: + del self.tags[key] diff --git a/boto/ec2/elb/__init__.py b/boto/ec2/elb/__init__.py index 9971e060..6123909c 100644 --- a/boto/ec2/elb/__init__.py +++ b/boto/ec2/elb/__init__.py @@ -400,6 +400,7 @@ class ELBConnection(AWSQueryConnection): :param attribute: The attribute you wish to change. * crossZoneLoadBalancing - Boolean (true) + * connectingSettings - :py:class:`ConnectionSettingAttribute` instance * accessLog - :py:class:`AccessLogAttribute` instance * connectionDraining - :py:class:`ConnectionDrainingAttribute` instance @@ -436,6 +437,9 @@ class ELBConnection(AWSQueryConnection): value.enabled and 'true' or 'false' params['LoadBalancerAttributes.ConnectionDraining.Timeout'] = \ value.timeout + elif attribute.lower() == 'connectingsettings': + params['LoadBalancerAttributes.ConnectionSettings.IdleTimeout'] = \ + value.idle_timeout else: raise ValueError('InvalidAttribute', attribute) return self.get_status('ModifyLoadBalancerAttributes', params, @@ -468,6 +472,7 @@ class ELBConnection(AWSQueryConnection): * accessLog - :py:class:`AccessLogAttribute` instance * crossZoneLoadBalancing - Boolean + * connectingSettings - :py:class:`ConnectionSettingAttribute` instance * connectionDraining - :py:class:`ConnectionDrainingAttribute` instance @@ -481,6 +486,8 @@ class ELBConnection(AWSQueryConnection): return attributes.cross_zone_load_balancing.enabled if attribute.lower() == 'connectiondraining': return attributes.connection_draining + if attribute.lower() == 'connectingsettings': + return attributes.connecting_settings return None def register_instances(self, load_balancer_name, instances): diff --git a/boto/ec2/elb/attributes.py b/boto/ec2/elb/attributes.py index 05ca8f82..605e5d54 100644 --- a/boto/ec2/elb/attributes.py +++ b/boto/ec2/elb/attributes.py @@ -19,6 +19,24 @@ # # Created by Chris Huegle for TellApart, Inc. +class ConnectionSettingAttribute(object): + """ + Represents the ConnectionSetting segment of ELB Attributes. + """ + def __init__(self, connection=None): + self.idle_timeout = None + + def __repr__(self): + return 'ConnectionSettingAttribute(%s)' % ( + self.idle_timeout) + + def startElement(self, name, attrs, connection): + pass + + def endElement(self, name, value, connection): + if name == 'IdleTimeout': + self.idle_timeout = int(value) + class CrossZoneLoadBalancingAttribute(object): """ Represents the CrossZoneLoadBalancing segement of ELB Attributes. @@ -40,6 +58,7 @@ class CrossZoneLoadBalancingAttribute(object): else: self.enabled = False + class AccessLogAttribute(object): """ Represents the AccessLog segment of ELB attributes. @@ -74,6 +93,7 @@ class AccessLogAttribute(object): elif name == 'EmitInterval': self.emit_interval = int(value) + class ConnectionDrainingAttribute(object): """ Represents the ConnectionDraining segment of ELB attributes. @@ -100,6 +120,7 @@ class ConnectionDrainingAttribute(object): elif name == 'Timeout': self.timeout = int(value) + class LbAttributes(object): """ Represents the Attributes of an Elastic Load Balancer. @@ -107,15 +128,17 @@ class LbAttributes(object): def __init__(self, connection=None): self.connection = connection self.cross_zone_load_balancing = CrossZoneLoadBalancingAttribute( - self.connection) + self.connection) self.access_log = AccessLogAttribute(self.connection) self.connection_draining = ConnectionDrainingAttribute(self.connection) + self.connecting_settings = ConnectionSettingAttribute(self.connection) def __repr__(self): - return 'LbAttributes(%s, %s, %s)' % ( + return 'LbAttributes(%s, %s, %s, %s)' % ( repr(self.cross_zone_load_balancing), repr(self.access_log), - repr(self.connection_draining)) + repr(self.connection_draining), + repr(self.connecting_settings)) def startElement(self, name, attrs, connection): if name == 'CrossZoneLoadBalancing': @@ -124,6 +147,8 @@ class LbAttributes(object): return self.access_log if name == 'ConnectionDraining': return self.connection_draining + if name == 'ConnectionSettings': + return self.connecting_settings def endElement(self, name, value, connection): pass diff --git a/boto/ec2/elb/instancestate.py b/boto/ec2/elb/instancestate.py index 40f4cbe6..dd61c123 100644 --- a/boto/ec2/elb/instancestate.py +++ b/boto/ec2/elb/instancestate.py @@ -19,6 +19,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. + class InstanceState(object): """ Represents the state of an EC2 Load Balancer Instance diff --git a/boto/ec2/elb/listener.py b/boto/ec2/elb/listener.py index cf26c41c..ed33b131 100644 --- a/boto/ec2/elb/listener.py +++ b/boto/ec2/elb/listener.py @@ -80,6 +80,8 @@ class Listener(object): return self.instance_port if key == 2: return self.protocol - if key == 4: + if key == 3: return self.instance_protocol + if key == 4: + return self.ssl_certificate_id raise KeyError diff --git a/boto/ec2/elb/policies.py b/boto/ec2/elb/policies.py index faea1c78..50fac0af 100644 --- a/boto/ec2/elb/policies.py +++ b/boto/ec2/elb/policies.py @@ -106,4 +106,3 @@ class Policies(object): def endElement(self, name, value, connection): return - diff --git a/boto/ec2/elb/securitygroup.py b/boto/ec2/elb/securitygroup.py index 4f377907..65f981f8 100644 --- a/boto/ec2/elb/securitygroup.py +++ b/boto/ec2/elb/securitygroup.py @@ -19,6 +19,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. + class SecurityGroup(object): def __init__(self, connection=None): self.name = None @@ -35,4 +36,3 @@ class SecurityGroup(object): self.name = value elif name == 'OwnerAlias': self.owner_alias = value - diff --git a/boto/ec2/group.py b/boto/ec2/group.py index fef54977..99d78734 100644 --- a/boto/ec2/group.py +++ b/boto/ec2/group.py @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. + class Group(object): def __init__(self, parent=None): self.id = None @@ -35,4 +36,3 @@ class Group(object): self.name = value else: setattr(self, name, value) - diff --git a/boto/ec2/image.py b/boto/ec2/image.py index f94f77e8..612404f0 100644 --- a/boto/ec2/image.py +++ b/boto/ec2/image.py @@ -41,6 +41,7 @@ class BillingProducts(list): if name == 'billingProduct': self.append(value) + class Image(TaggedEC2Object): """ Represents an EC2 Image @@ -106,7 +107,7 @@ class Image(TaggedEC2Object): self.is_public = True else: raise Exception( - 'Unexpected value of isPublic %s for image %s'%( + 'Unexpected value of isPublic %s for image %s' % ( value, self.id ) @@ -368,7 +369,7 @@ class Image(TaggedEC2Object): ) def get_kernel(self, dry_run=False): - img_attrs =self.connection.get_image_attribute( + img_attrs = self.connection.get_image_attribute( self.id, 'kernel', dry_run=dry_run diff --git a/boto/ec2/instanceinfo.py b/boto/ec2/instanceinfo.py index 623ba17a..afa8b9cb 100644 --- a/boto/ec2/instanceinfo.py +++ b/boto/ec2/instanceinfo.py @@ -14,16 +14,17 @@ # 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, +# 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 InstanceInfo(object): """ Represents an EC2 Instance status response from CloudWatch """ - + def __init__(self, connection=None, id=None, state=None): """ :ivar str id: The instance's EC2 ID. @@ -46,6 +47,3 @@ class InstanceInfo(object): self.state = value else: setattr(self, name, value) - - - diff --git a/boto/ec2/instancetype.py b/boto/ec2/instancetype.py index 2de4b853..6197a336 100644 --- a/boto/ec2/instancetype.py +++ b/boto/ec2/instancetype.py @@ -44,7 +44,7 @@ class InstanceType(EC2Object): def __repr__(self): return 'InstanceType:%s-%s,%s,%s' % (self.name, self.cores, - self.memory, self.disk) + self.memory, self.disk) def endElement(self, name, value, connection): if name == 'name': diff --git a/boto/ec2/keypair.py b/boto/ec2/keypair.py index b399a97e..623fb409 100644 --- a/boto/ec2/keypair.py +++ b/boto/ec2/keypair.py @@ -27,6 +27,7 @@ import os from boto.ec2.ec2object import EC2Object from boto.exception import BotoClientError + class KeyPair(EC2Object): def __init__(self, connection=None): @@ -108,6 +109,3 @@ class KeyPair(EC2Object): rconn = region.connect(**conn_params) kp = rconn.create_key_pair(self.name, dry_run=dry_run) return kp - - - diff --git a/boto/ec2/networkinterface.py b/boto/ec2/networkinterface.py index 6596439e..9bbeb771 100644 --- a/boto/ec2/networkinterface.py +++ b/boto/ec2/networkinterface.py @@ -119,8 +119,7 @@ class NetworkInterface(TaggedEC2Object): return 'NetworkInterface:%s' % self.id def startElement(self, name, attrs, connection): - retval = super(NetworkInterface, self).startElement(name, attrs, - connection) + retval = super(NetworkInterface, self).startElement(name, attrs, connection) if retval is not None: return retval if name == 'groupSet': @@ -313,10 +312,10 @@ class NetworkInterfaceCollection(list): if spec.associate_public_ip_address is not None: if not params[full_prefix + 'DeviceIndex'] in (0, '0'): raise BotoClientError( - "Only the interface with device index of 0 can " + \ - "be provided when using " + \ - "'associate_public_ip_address'." - ) + "Only the interface with device index of 0 can " + \ + "be provided when using " + \ + "'associate_public_ip_address'." + ) if len(self) > 1: raise BotoClientError( diff --git a/boto/ec2/placementgroup.py b/boto/ec2/placementgroup.py index 65e32844..0c259661 100644 --- a/boto/ec2/placementgroup.py +++ b/boto/ec2/placementgroup.py @@ -24,6 +24,7 @@ Represents an EC2 Placement Group from boto.ec2.ec2object import EC2Object from boto.exception import BotoClientError + class PlacementGroup(EC2Object): def __init__(self, connection=None, name=None, strategy=None, state=None): @@ -50,5 +51,3 @@ class PlacementGroup(EC2Object): self.name, dry_run=dry_run ) - - diff --git a/boto/ec2/regioninfo.py b/boto/ec2/regioninfo.py index 78cd757c..21a56fb9 100644 --- a/boto/ec2/regioninfo.py +++ b/boto/ec2/regioninfo.py @@ -23,6 +23,7 @@ from boto.regioninfo import RegionInfo + class EC2RegionInfo(RegionInfo): """ Represents an EC2 Region diff --git a/boto/ec2/reservedinstance.py b/boto/ec2/reservedinstance.py index 72d2bf30..02d15276 100644 --- a/boto/ec2/reservedinstance.py +++ b/boto/ec2/reservedinstance.py @@ -128,9 +128,9 @@ class ReservedInstance(ReservedInstancesOffering): usage_price=None, description=None, instance_count=None, state=None): super(ReservedInstance, self).__init__(connection, id, instance_type, - availability_zone, duration, - fixed_price, usage_price, - description) + availability_zone, duration, + fixed_price, usage_price, + description) self.instance_count = instance_count self.state = state self.start = None diff --git a/boto/ec2/securitygroup.py b/boto/ec2/securitygroup.py index 5674f4e9..dec49cb2 100644 --- a/boto/ec2/securitygroup.py +++ b/boto/ec2/securitygroup.py @@ -44,8 +44,7 @@ class SecurityGroup(TaggedEC2Object): return 'SecurityGroup:%s' % self.name def startElement(self, name, attrs, connection): - retval = super(SecurityGroup, self).startElement(name, attrs, - connection) + retval = super(SecurityGroup, self).startElement(name, attrs, connection) if retval is not None: return retval if name == 'ipPermissions': diff --git a/boto/ec2/snapshot.py b/boto/ec2/snapshot.py index 22f69ab2..8a84cdee 100644 --- a/boto/ec2/snapshot.py +++ b/boto/ec2/snapshot.py @@ -185,6 +185,3 @@ class SnapshotAttribute(object): self.snapshot_id = value else: setattr(self, name, value) - - - diff --git a/boto/ec2/spotdatafeedsubscription.py b/boto/ec2/spotdatafeedsubscription.py index 26ef7adc..d0e0be8d 100644 --- a/boto/ec2/spotdatafeedsubscription.py +++ b/boto/ec2/spotdatafeedsubscription.py @@ -25,10 +25,11 @@ Represents an EC2 Spot Instance Datafeed Subscription from boto.ec2.ec2object import EC2Object from boto.ec2.spotinstancerequest import SpotInstanceStateFault + class SpotDatafeedSubscription(EC2Object): def __init__(self, connection=None, owner_id=None, - bucket=None, prefix=None, state=None,fault=None): + bucket=None, prefix=None, state=None, fault=None): super(SpotDatafeedSubscription, self).__init__(connection) self.owner_id = owner_id self.bucket = bucket @@ -62,4 +63,3 @@ class SpotDatafeedSubscription(EC2Object): return self.connection.delete_spot_datafeed_subscription( dry_run=dry_run ) - diff --git a/boto/ec2/spotpricehistory.py b/boto/ec2/spotpricehistory.py index 7bd0ce89..ac125de6 100644 --- a/boto/ec2/spotpricehistory.py +++ b/boto/ec2/spotpricehistory.py @@ -25,6 +25,7 @@ Represents an EC2 Spot Instance Request from boto.ec2.ec2object import EC2Object + class SpotPriceHistory(EC2Object): def __init__(self, connection=None): @@ -51,5 +52,3 @@ class SpotPriceHistory(EC2Object): self.availability_zone = value else: setattr(self, name, value) - - diff --git a/boto/ec2/zone.py b/boto/ec2/zone.py index 725d1769..85ed1022 100644 --- a/boto/ec2/zone.py +++ b/boto/ec2/zone.py @@ -24,6 +24,7 @@ Represents an EC2 Availability Zone """ from boto.ec2.ec2object import EC2Object + class MessageSet(list): """ A list object that contains messages associated with @@ -39,6 +40,7 @@ class MessageSet(list): else: setattr(self, name, value) + class Zone(EC2Object): """ Represents an Availability Zone. @@ -74,7 +76,3 @@ class Zone(EC2Object): self.region_name = value else: setattr(self, name, value) - - - - |