Permalink
Browse files

Merge branch 'release-2.9.9'

* release-2.9.9: (39 commits)
  Bumping version to 2.9.9
  Added release notes for v2.9.9.
  Revert "Added "lookup" and "new_item" to dynamodb2.table, which makes it more"
  Updated Opsworks for support AMI ID & configuration managers.
  Add unit tests for #1555 to ensure behavior works as expected
  Added a try block around json.loads call, and code to look for 403 errors
  Fix compatibility issues with python 2.5
  Set secure connection to elb api as default, as for any other connection
  Reformat SES unit tests for PEP8
  using from clause to import TestCase
  Changing to unittest2 Changing call  to super for setUp
  pep8 standards
  Adding unit test for detach_internet_gateway
  Fix for Issue#1417
  add unit tests for InstanceGroup instantation
  don't require the price to be a string, and then report 'must be specified' if I pass a float.
  Updated erroneous test.
  Updated a test to match current autoscale output.
  Fixed up BotoServerException's use of message
  Fixed the ability to specify ``logging`` on ``DistributionConfig``.
  ...
  • Loading branch information...
toastdriven committed Jul 24, 2013
2 parents 3c56d13 + 35617d8 commit 15c650e3af28c7a6b36ad736b0911bcf0ad7fb86
View
@@ -1,9 +1,9 @@
####
boto
####
-boto 2.9.8
+boto 2.9.9
-Released: 18-July-2013
+Released: 24-July-2013
.. image:: https://travis-ci.org/boto/boto.png?branch=develop
:target: https://travis-ci.org/boto/boto
View
@@ -36,7 +36,7 @@
import urlparse
from boto.exception import InvalidUriError
-__version__ = '2.9.8'
+__version__ = '2.9.9'
Version = __version__ # for backware compatibility
UserAgent = 'Boto/%s (%s)' % (__version__, sys.platform)
View
@@ -385,8 +385,9 @@ def signed_headers(self, headers_to_sign):
def canonical_uri(self, http_request):
path = http_request.auth_path
- # Normalize the path.
- normalized = posixpath.normpath(path)
+ # Normalize the path
+ # in windows normpath('/') will be '\\' so we chane it back to '/'
+ normalized = posixpath.normpath(path).replace('\\','/')
# Then urlencode whatever's left.
encoded = urllib.quote(normalized)
if len(path) > 1 and path.endswith('/'):
@@ -48,7 +48,10 @@ def endElement(self, name, value, connection):
elif name == "Description":
self.description = value
elif name == "DisableRollback":
- self.disable_rollback = bool(value)
+ if str(value).lower() == 'true':
+ self.disable_rollback = True
+ else:
+ self.disable_rollback = False
elif name == 'StackId':
self.stack_id = value
elif name == 'StackName':
@@ -30,7 +30,7 @@
from boto.cloudfront.origin import S3Origin, CustomOrigin
from boto.s3.acl import ACL
-class DistributionConfig:
+class DistributionConfig(object):
def __init__(self, connection=None, origin=None, enabled=False,
caller_reference='', cnames=None, comment='',
@@ -100,7 +100,7 @@ def __init__(self, connection=None, origin=None, enabled=False,
self.cnames = cnames
self.comment = comment
self.trusted_signers = trusted_signers
- self.logging = None
+ self.logging = logging
self.default_root_object = default_root_object
def to_xml(self):
@@ -214,7 +214,7 @@ def to_xml(self):
s += '</StreamingDistributionConfig>\n'
return s
-class DistributionSummary:
+class DistributionSummary(object):
def __init__(self, connection=None, domain_name='', id='',
last_modified_time=None, status='', origin=None,
@@ -279,7 +279,7 @@ class StreamingDistributionSummary(DistributionSummary):
def get_distribution(self):
return self.connection.get_streaming_distribution_info(self.id)
-class Distribution:
+class Distribution(object):
def __init__(self, connection=None, config=None, domain_name='',
id='', last_modified_time=None, status=''):
@@ -654,12 +654,14 @@ def _sign_string(message, private_key_file=None, private_key_string=None):
raise ValueError("Only specify the private_key_file or the private_key_string not both")
if not private_key_file and not private_key_string:
raise ValueError("You must specify one of private_key_file or private_key_string")
- # If private_key_file is a file, read its contents. Otherwise, open it and then read it
- if isinstance(private_key_file, file):
- private_key_string = private_key_file.read()
- elif private_key_file:
- with open(private_key_file, 'r') as file_handle:
- private_key_string = file_handle.read()
+ # If private_key_file is a file name, open it and read it
+ if private_key_string is None:
+ if isinstance(private_key_file, basestring):
+ with open(private_key_file, 'r') as file_handle:
+ private_key_string = file_handle.read()
+ # Otherwise, treat it like a file
+ else:
+ private_key_string = private_key_file.read()
# Sign it!
private_key = rsa.PrivateKey.load_pkcs1(private_key_string)
View
@@ -289,7 +289,19 @@ def __call__(self, query):
params = query.to_params()
r = requests.get(url, params=params)
- data = json.loads(r.content)
+ try:
+ data = json.loads(r.content)
+ except json.JSONDecodeError,e:
+ if r.status_code == 403:
+ msg = ''
+ import re
+ g = re.search('<html><body><h1>403 Forbidden</h1>([^<]+)<', r.content)
+ try:
+ msg = ': %s' % (g.groups()[0].strip())
+ except AttributeError:
+ pass
+ raise SearchServiceException('Authentication error from Amazon%s' % msg)
+ raise SearchServiceException("Got non-json response from Amazon")
data['query'] = query
data['search_service'] = self
View
@@ -673,6 +673,8 @@ def handle_proxy(self, proxy, proxy_port, proxy_user, proxy_pass):
print "http_proxy environment variable does not specify " \
"a port, using default"
self.proxy_port = self.port
+
+ self.no_proxy = os.environ.get('no_proxy', '') or os.environ.get('NO_PROXY', '')
self.use_proxy = (self.proxy != None)
def get_http_connection(self, host, is_secure):
@@ -682,16 +684,33 @@ def get_http_connection(self, host, is_secure):
else:
return self.new_http_connection(host, is_secure)
+ def skip_proxy(self, host):
+ if not self.no_proxy:
+ return False
+
+ if self.no_proxy == "*":
+ return True
+
+ hostonly = host
+ hostonly = host.split(':')[0]
+
+ for name in self.no_proxy.split(','):
+ if name and (hostonly.endswith(name) or host.endswith(name)):
+ return True
+
+ return False
+
def new_http_connection(self, host, is_secure):
- if self.use_proxy and not is_secure:
+ if self.use_proxy and not is_secure and \
+ not self.skip_proxy(host):
host = '%s:%d' % (self.proxy, int(self.proxy_port))
if host is None:
host = self.server_name()
if is_secure:
boto.log.debug(
'establishing HTTPS connection: host=%s, kwargs=%s',
host, self.http_connection_kwargs)
- if self.use_proxy:
+ if self.use_proxy and not self.skip_proxy(host):
connection = self.proxy_ssl(host, is_secure and 443 or 80)
elif self.https_connection_factory:
connection = self.https_connection_factory(host)
@@ -224,8 +224,7 @@ def create_launch_configuration(self, launch_config):
if launch_config.ramdisk_id:
params['RamdiskId'] = launch_config.ramdisk_id
if launch_config.block_device_mappings:
- self.build_list_params(params, launch_config.block_device_mappings,
- 'BlockDeviceMappings')
+ [x.build_list_params(params) for x in launch_config.block_device_mappings]
if launch_config.security_groups:
self.build_list_params(params, launch_config.security_groups,
'SecurityGroups')
View
@@ -87,7 +87,7 @@ class ELBConnection(AWSQueryConnection):
'elasticloadbalancing.us-east-1.amazonaws.com')
def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
- is_secure=False, port=None, proxy=None, proxy_port=None,
+ is_secure=True, port=None, proxy=None, proxy_port=None,
proxy_user=None, proxy_pass=None, debug=0,
https_connection_factory=None, region=None, path='/',
security_token=None, validate_certs=True):
@@ -616,5 +616,5 @@ def detach_lb_from_subnets(self, name, subnets):
params = {'LoadBalancerName': name}
self.build_list_params(params, subnets,
'Subnets.member.%d')
- return self.get_list('DettachLoadBalancerFromSubnets',
+ return self.get_list('DetachLoadBalancerFromSubnets',
params, None)
@@ -49,6 +49,9 @@ def regions():
RegionInfo(name='ap-southeast-1',
endpoint='elasticache.ap-southeast-1.amazonaws.com',
connection_cls=ElastiCacheConnection),
+ RegionInfo(name='ap-southeast-2',
+ endpoint='elasticache.ap-southeast-2.amazonaws.com',
+ connection_cls=ElastiCacheConnection),
RegionInfo(name='sa-east-1',
endpoint='elasticache.sa-east-1.amazonaws.com',
connection_cls=ElastiCacheConnection),
@@ -27,9 +27,9 @@ def __init__(self, num_instances, role, type, market, name, bidprice=None):
self.market = market
self.name = name
if market == 'SPOT':
- if not isinstance(bidprice, basestring):
+ if not bidprice:
raise ValueError('bidprice must be specified if market == SPOT')
- self.bidprice = bidprice
+ self.bidprice = str(bidprice)
def __repr__(self):
if self.market == 'SPOT':
View
@@ -76,7 +76,7 @@ def __init__(self, status, reason, body=None, *args):
self.body = body or ''
self.request_id = None
self.error_code = None
- self.error_message = None
+ self._error_message = None
self.box_usage = None
# Attempt to parse the error response. If body isn't present,
@@ -90,16 +90,22 @@ def __init__(self, status, reason, body=None, *args):
# in exception. But first, save self.body in self.error_message
# because occasionally we get error messages from Eucalyptus
# that are just text strings that we want to preserve.
- self.error_message = self.body
+ self.message = self.body
self.body = None
def __getattr__(self, name):
- if name == 'message':
- return self.error_message
+ if name == 'error_message':
+ return self.message
if name == 'code':
return self.error_code
raise AttributeError
+ def __setattr__(self, name, value):
+ if name == 'error_message':
+ self.message = value
+ else:
+ super(BotoServerError, self).__setattr__(name, value)
+
def __repr__(self):
return '%s: %s %s\n%s' % (self.__class__.__name__,
self.status, self.reason, self.body)
@@ -117,15 +123,15 @@ def endElement(self, name, value, connection):
elif name == 'Code':
self.error_code = value
elif name == 'Message':
- self.error_message = value
+ self.message = value
elif name == 'BoxUsage':
self.box_usage = value
return None
def _cleanupParsedProperties(self):
self.request_id = None
self.error_code = None
- self.error_message = None
+ self.message = None
self.box_usage = None
class ConsoleOutput:
Oops, something went wrong.

0 comments on commit 15c650e

Please sign in to comment.