Permalink
Browse files

Merge branch 'release-2.25.0'

  • Loading branch information...
toastdriven committed Feb 7, 2014
2 parents 4d4746e + d4fc260 commit 522d67f9ff32af03df4be73ac7b9541c3ab6e3c0
View
@@ -1,9 +1,9 @@
####
boto
####
-boto 2.24.0
+boto 2.25.0
-Released: 29-January-2014
+Released: 07-February-2014
.. image:: https://travis-ci.org/boto/boto.png?branch=develop
:target: https://travis-ci.org/boto/boto
View
@@ -37,7 +37,7 @@
import urlparse
from boto.exception import InvalidUriError
-__version__ = '2.24.0'
+__version__ = '2.25.0'
Version = __version__ # for backware compatibility
# http://bugs.python.org/issue7980
View
@@ -499,7 +499,10 @@ def add_auth(self, req, **kwargs):
# Safe to modify req.path here since
# the signature will use req.auth_path.
req.path = req.path.split('?')[0]
- req.path = req.path + '?' + qs
+
+ if qs:
+ # Don't insert the '?' unless there's actually a query string
+ req.path = req.path + '?' + qs
canonical_request = self.canonical_request(req)
boto.log.debug('CanonicalRequest:\n%s' % canonical_request)
string_to_sign = self.string_to_sign(req, canonical_request)
@@ -893,6 +896,12 @@ def get_auth_handler(host, config, provider, requested_capability=None):
def detect_potential_sigv4(func):
def _wrapper(self):
+ if os.environ.get('EC2_USE_SIGV4', False):
+ return ['hmac-v4']
+
+ if boto.config.get('ec2', 'use-sigv4', False):
+ return ['hmac-v4']
+
if hasattr(self, 'region'):
if getattr(self.region, 'endpoint', ''):
if '.cn-' in self.region.endpoint:
@@ -103,6 +103,9 @@ def __init__(self, connection=None, origin=None, enabled=False,
self.logging = logging
self.default_root_object = default_root_object
+ def __repr__(self):
+ return "DistributionConfig:%s" % self.origin
+
def to_xml(self):
s = '<?xml version="1.0" encoding="UTF-8"?>\n'
s += '<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-07-15/">\n'
@@ -234,6 +237,9 @@ def __init__(self, connection=None, domain_name='', id='',
self.etag = None
self.streaming = False
+ def __repr__(self):
+ return "DistributionSummary:%s" % self.domain_name
+
def startElement(self, name, attrs, connection):
if name == 'TrustedSigners':
self.trusted_signers = TrustedSigners()
@@ -295,6 +301,9 @@ def __init__(self, connection=None, config=None, domain_name='',
self._bucket = None
self._object_class = Object
+ def __repr__(self):
+ return "Distribution:%s" % self.domain_name
+
def startElement(self, name, attrs, connection):
if name == 'DistributionConfig':
self.config = DistributionConfig()
@@ -146,9 +146,9 @@ def __init__(self, connection=None, name=None,
:param placement_group: Physical location of your cluster placement
group created in Amazon EC2.
- :type vpc_zone_identifier: str
- :param vpc_zone_identifier: The subnet identifier of the Virtual
- Private Cloud.
+ :type vpc_zone_identifier: str or list
+ :param vpc_zone_identifier: A comma-separated string or python list of
+ the subnet identifiers of the Virtual Private Cloud.
:type tags: list
:param tags: List of :class:`boto.ec2.autoscale.tag.Tag`s
@@ -188,6 +188,8 @@ def __init__(self, connection=None, name=None,
self.health_check_type = health_check_type
self.placement_group = placement_group
self.autoscaling_group_arn = None
+ if type(vpc_zone_identifier) is list:
+ vpc_zone_identifier = ','.join(vpc_zone_identifier)
self.vpc_zone_identifier = vpc_zone_identifier
self.instances = None
self.tags = tags or None
@@ -223,6 +223,8 @@ def endElement(self, name, value, connection):
self.instance_profile_name = value
elif name == 'EbsOptimized':
self.ebs_optimized = True if value.lower() == 'true' else False
+ elif name == 'AssociatePublicIpAddress':
+ self.associate_public_ip_address = True if value.lower() == 'true' else False
elif name == 'VolumeType':
self.volume_type = value
elif name == 'DeleteOnTermination':
@@ -47,16 +47,17 @@ def endElement(self, name, value, connection):
class AdjustmentType(object):
def __init__(self, connection=None):
self.connection = connection
- self.adjustment_types = ListElement([])
+ self.adjustment_type = None
def __repr__(self):
- return 'AdjustmentType:%s' % self.adjustment_types
+ return 'AdjustmentType:%s' % self.adjustment_type
def startElement(self, name, attrs, connection):
- if name == 'AdjustmentType':
- return self.adjustment_types
+ return
def endElement(self, name, value, connection):
+ if name == 'AdjustmentType':
+ self.adjustment_type = value
return
View
@@ -262,11 +262,12 @@ def startElement(self, name, attrs, connection):
if name == 'Status':
self.status = ClusterStatus()
return self.status
- elif name == 'EC2InstanceAttributes':
+ elif name == 'Ec2InstanceAttributes':
self.ec2instanceattributes = Ec2InstanceAttributes()
return self.ec2instanceattributes
elif name == 'Applications':
self.applications = ResultSet([('member', Application)])
+ return self.applications
elif name == 'Tags':
self.tags = ResultSet([('member', KeyValue)])
return self.tags
View
@@ -126,16 +126,16 @@
"us-west-2": "elasticloadbalancing.us-west-2.amazonaws.com"
},
"elasticmapreduce": {
- "ap-northeast-1": "elasticmapreduce.ap-northeast-1.amazonaws.com",
- "ap-southeast-1": "elasticmapreduce.ap-southeast-1.amazonaws.com",
- "ap-southeast-2": "elasticmapreduce.ap-southeast-2.amazonaws.com",
+ "ap-northeast-1": "ap-northeast-1.elasticmapreduce.amazonaws.com",
+ "ap-southeast-1": "ap-southeast-1.elasticmapreduce.amazonaws.com",
+ "ap-southeast-2": "ap-southeast-2.elasticmapreduce.amazonaws.com",
"cn-north-1": "elasticmapreduce.cn-north-1.amazonaws.com.cn",
"eu-west-1": "elasticmapreduce.eu-west-1.amazonaws.com",
- "sa-east-1": "elasticmapreduce.sa-east-1.amazonaws.com",
+ "sa-east-1": "sa-east-1.elasticmapreduce.amazonaws.com",
"us-east-1": "elasticmapreduce.us-east-1.amazonaws.com",
- "us-gov-west-1": "elasticmapreduce.us-gov-west-1.amazonaws.com",
- "us-west-1": "elasticmapreduce.us-west-1.amazonaws.com",
- "us-west-2": "elasticmapreduce.us-west-2.amazonaws.com"
+ "us-gov-west-1": "us-gov-west-1.elasticmapreduce.amazonaws.com",
+ "us-west-1": "us-west-1.elasticmapreduce.amazonaws.com",
+ "us-west-2": "us-west-2.elasticmapreduce.amazonaws.com"
},
"elastictranscoder": {
"ap-northeast-1": "elastictranscoder.ap-northeast-1.amazonaws.com",
@@ -186,7 +186,7 @@
"cn-north-1": "rds.cn-north-1.amazonaws.com.cn",
"eu-west-1": "rds.eu-west-1.amazonaws.com",
"sa-east-1": "rds.sa-east-1.amazonaws.com",
- "us-east-1": "rds.us-east-1.amazonaws.com",
+ "us-east-1": "rds.amazonaws.com",
"us-gov-west-1": "rds.us-gov-west-1.amazonaws.com",
"us-west-1": "rds.us-west-1.amazonaws.com",
"us-west-2": "rds.us-west-2.amazonaws.com"
@@ -249,16 +249,16 @@
"us-west-2": "sns.us-west-2.amazonaws.com"
},
"sqs": {
- "ap-northeast-1": "sqs.ap-northeast-1.amazonaws.com",
- "ap-southeast-1": "sqs.ap-southeast-1.amazonaws.com",
- "ap-southeast-2": "sqs.ap-southeast-2.amazonaws.com",
+ "ap-northeast-1": "ap-northeast-1.queue.amazonaws.com",
+ "ap-southeast-1": "ap-southeast-1.queue.amazonaws.com",
+ "ap-southeast-2": "ap-southeast-2.queue.amazonaws.com",
"cn-north-1": "sqs.cn-north-1.amazonaws.com.cn",
- "eu-west-1": "sqs.eu-west-1.amazonaws.com",
- "sa-east-1": "sqs.sa-east-1.amazonaws.com",
- "us-east-1": "sqs.us-east-1.amazonaws.com",
- "us-gov-west-1": "sqs.us-gov-west-1.amazonaws.com",
- "us-west-1": "sqs.us-west-1.amazonaws.com",
- "us-west-2": "sqs.us-west-2.amazonaws.com"
+ "eu-west-1": "eu-west-1.queue.amazonaws.com",
+ "sa-east-1": "sa-east-1.queue.amazonaws.com",
+ "us-east-1": "queue.amazonaws.com",
+ "us-gov-west-1": "us-gov-west-1.queue.amazonaws.com",
+ "us-west-1": "us-west-1.queue.amazonaws.com",
+ "us-west-2": "us-west-2.queue.amazonaws.com"
},
"storagegateway": {
"ap-northeast-1": "storagegateway.ap-northeast-1.amazonaws.com",
View
@@ -103,3 +103,27 @@ def create_bucket(self, bucket_name, headers=None,
raise self.provider.storage_response_error(
response.status, response.reason, body)
+ def get_bucket(self, bucket_name, validate=True, headers=None):
+ """
+ Retrieves a bucket by name.
+
+ If the bucket does not exist, an ``S3ResponseError`` will be raised. If
+ you are unsure if the bucket exists or not, you can use the
+ ``S3Connection.lookup`` method, which will either return a valid bucket
+ or ``None``.
+
+ :type bucket_name: string
+ :param bucket_name: The name of the bucket
+
+ :type headers: dict
+ :param headers: Additional headers to pass along with the request to
+ AWS.
+
+ :type validate: boolean
+ :param validate: If ``True``, it will try to fetch all keys within the
+ given bucket. (Default: ``True``)
+ """
+ bucket = self.bucket_class(self, bucket_name)
+ if validate:
+ bucket.get_all_keys(headers, maxkeys=0)
+ return bucket
View
@@ -609,7 +609,7 @@ def __init__(self, *args, **kw):
class GetProductCategoriesResult(ResponseElement):
- Self = Element(ProductCategory)
+ Self = ElementList(ProductCategory)
class GetProductCategoriesForSKUResult(GetProductCategoriesResult):
View
@@ -32,6 +32,8 @@
from boto.rds.dbsubnetgroup import DBSubnetGroup
from boto.rds.vpcsecuritygroupmembership import VPCSecurityGroupMembership
from boto.regioninfo import get_regions
+from boto.rds.logfile import LogFile
+
def regions():
"""
@@ -1074,6 +1076,27 @@ def get_all_dbsnapshots(self, snapshot_id=None, instance_id=None,
return self.get_list('DescribeDBSnapshots', params,
[('DBSnapshot', DBSnapshot)])
+ def get_all_logs(self, dbinstance_id=None):
+ """
+ Get all log files
+
+ :type instance_id: str
+ :param instance_id: The identifier of a DBInstance. If provided,
+ only the :class:`boto.rds.logfile.LogFile` related
+ to that instance will be returned. If not
+ provided, all logfiles will be returned.
+
+ :rtype: list
+ :return: A list of :class:`boto.rds.logfile.LogFile`
+ """
+ params = {}
+ if dbinstance_id:
+ params['DBInstanceIdentifier'] = dbinstance_id
+ params['MaxRecords'] = 26
+
+ return self.get_list('DescribeDBLogFiles', params,
+ [('DescribeDBLogFilesDetails',LogFile)])
+
def create_dbsnapshot(self, snapshot_id, dbinstance_id):
"""
Create a new DB snapshot.
View
@@ -0,0 +1,46 @@
+# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
+# Copyright (c) 2014 Jumping Qu http://newrice.blogspot.com/
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish, dis-
+# tribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the fol-
+# lowing conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+class LogFile(object):
+
+ def __init__(self, connection=None):
+ self.connection = connection
+ self.size = None
+ self.log_filename = None
+ self.last_written = None
+
+ def __repr__(self):
+ #return '(%s, %s, %s)' % (self.logfilename, self.size, self.lastwritten)
+ return '%s' % (self.log_filename)
+
+ def startElement(self, name, attrs, connection):
+ pass
+
+ def endElement(self, name, value, connection):
+ if name == 'LastWritten':
+ self.last_written = value
+ elif name == 'LogFileName':
+ self.log_filename = value
+ elif name == 'Size':
+ self.size = value
+ else:
+ setattr(self, name, value)
@@ -54,10 +54,10 @@ class Route53Connection(AWSAuthConnection):
DefaultHost = 'route53.amazonaws.com'
"""The default Route53 API endpoint to connect to."""
- Version = '2012-02-29'
+ Version = '2013-04-01'
"""Route53 API version."""
- XMLNameSpace = 'https://route53.amazonaws.com/doc/2012-02-29/'
+ XMLNameSpace = 'https://route53.amazonaws.com/doc/2013-04-01/'
"""XML schema for this Route53 API version."""
def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
View
@@ -35,7 +35,7 @@ class ResourceRecordSets(ResultSet):
"""
ChangeResourceRecordSetsBody = """<?xml version="1.0" encoding="UTF-8"?>
- <ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2012-02-29/">
+ <ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
<ChangeBatch>
<Comment>%(comment)s</Comment>
<Changes>%(changes)s</Changes>
@@ -71,7 +71,7 @@ def add_change(self, action, name, type, ttl=600,
Add a change request to the set.
:type action: str
- :param action: The action to perform ('CREATE'|'DELETE')
+ :param action: The action to perform ('CREATE'|'DELETE'|'UPSERT')
:type name: str
:param name: The name of the domain you want to perform the action on.
View
@@ -34,8 +34,8 @@ class Zone(object):
"""
A Route53 Zone.
- :ivar Route53Connection route53connection
- :ivar str Id: The ID of the hosted zone.
+ :ivar route53connection: A :class:`boto.route53.connection.Route53Connection` connection
+ :ivar id: The ID of the hosted zone
"""
def __init__(self, route53connection, zone_dict):
self.route53connection = route53connection
Oops, something went wrong.

0 comments on commit 522d67f

Please sign in to comment.