Implemented https://trello.com/c/LLwK80P5 - Added eu-central-1 region and updated boto to 2.34.0.

This commit is contained in:
Chris Church
2014-10-23 13:35:53 -04:00
parent 253a6cffd4
commit 7834bfab70
117 changed files with 8035 additions and 7062 deletions

View File

@@ -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
)

View File

@@ -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:

View File

@@ -71,4 +71,3 @@ class Activity(object):
self.status_code = value
else:
setattr(self, name, value)

View File

@@ -57,4 +57,3 @@ class Instance(object):
self.group_name = value
else:
setattr(self, name, value)

View File

@@ -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

View File

@@ -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)

View File

@@ -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'

View File

@@ -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)

View File

@@ -75,4 +75,3 @@ class ScheduledUpdateGroupAction(object):
self.end_time = datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ')
else:
setattr(self, name, value)

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -21,6 +21,7 @@
#
from datetime import datetime
class Datapoint(dict):
def __init__(self, connection=None):

View File

@@ -20,6 +20,7 @@
# IN THE SOFTWARE.
#
class Dimension(dict):
def startElement(self, name, attrs, connection):

View File

@@ -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):

View File

@@ -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):
"""

View File

@@ -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]

View File

@@ -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):

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -106,4 +106,3 @@ class Policies(object):
def endElement(self, name, value, connection):
return

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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':

View File

@@ -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

View File

@@ -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(

View File

@@ -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
)

View File

@@ -23,6 +23,7 @@
from boto.regioninfo import RegionInfo
class EC2RegionInfo(RegionInfo):
"""
Represents an EC2 Region

View File

@@ -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

View File

@@ -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':

View File

@@ -185,6 +185,3 @@ class SnapshotAttribute(object):
self.snapshot_id = value
else:
setattr(self, name, value)

View File

@@ -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
)

View File

@@ -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)

View File

@@ -1,59 +0,0 @@
# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
from boto.ec2.ec2object import EC2Object
class VmType(EC2Object):
"""
Represents an EC2 VM Type
:ivar name: The name of the vm type
:ivar cores: The number of cpu cores for this vm type
:ivar memory: The amount of memory in megabytes for this vm type
:ivar disk: The amount of disk space in gigabytes for this vm type
"""
def __init__(self, connection=None, name=None, cores=None,
memory=None, disk=None):
super(VmType, self).__init__(connection)
self.connection = connection
self.name = name
self.cores = cores
self.memory = memory
self.disk = disk
def __repr__(self):
return 'VmType:%s-%s,%s,%s' % (self.name, self.cores,
self.memory, self.disk)
def endElement(self, name, value, connection):
if name == 'euca:name':
self.name = value
elif name == 'euca:cpu':
self.cores = value
elif name == 'euca:disk':
self.disk = value
elif name == 'euca:memory':
self.memory = value
else:
setattr(self, name, value)

View File

@@ -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)