Permalink
Browse files

Merge branch 'release-2.9.8'

* release-2.9.8: (23 commits)
  Bumping version to 2.9.8
  Added release notes for v2.9.8.
  Supports getting and setting lifecycle configuration for buckets.
  Added ``CancelUpdateStack`` to CloudFormation.
  Added some simple tests for Route53's ``ResourceRecordSets``.
  Added support for the STS's ``DecodeAuthorizationMessage``.
  Change mock storage service to do case-insensitive header lookups.
  Updated RDS to current.
  PARTIAL: Started updating RDS to current.
  Update url explaining base64 SQS messages.
  Added some simple tests for Route53's ``ResourceRecordSets``.
  Added support for the STS's ``DecodeAuthorizationMessage``.
  Added tests for the ELB listeners change.
  Corrected the ELB integration tests to actually work.
  Fixed typo
  Switch variable to correct name for complex_listeners
  Fixed typo in function definition
  Updated ELB conenction functions related to listeners to handle InstanceProtcol specifications without breaking current syntax. Ties to boto/boto pull request #562
  Updated ELB listener object to handle InstanceProtocol
  Updated ELB listeners to handle the InstanceProtocol without breaking current syntax
  ...
  • Loading branch information...
2 parents f3fc2c5 + 12f3c1b commit 3c56d13f56d4db34ea59eb526e221c1e07728c98 @toastdriven toastdriven committed Jul 18, 2013
View
@@ -1,9 +1,9 @@
####
boto
####
-boto 2.9.7
+boto 2.9.8
-Released: 08-July-2013
+Released: 18-July-2013
.. image:: https://travis-ci.org/boto/boto.png?branch=develop
:target: https://travis-ci.org/boto/boto
View
@@ -108,7 +108,11 @@ def get(elb, name):
print
# Make map of all instance Id's to Name tags
- ec2 = boto.connect_ec2()
+ if not options.region:
+ ec2 = boto.connect_ec2()
+ else:
+ import boto.ec2.elb
+ ec2 = boto.ec2.connect_to_region(options.region)
instance_health = b.get_instance_health()
instances = [state.instance_id for state in instance_health]
@@ -236,14 +240,21 @@ if __name__ == "__main__":
parser.add_option("-l", "--listener",
help="Specify Listener in,out,proto",
action="append", default=[], dest="listeners")
+ parser.add_option("-r", "--region",
+ help="Region to connect to",
+ action="store", dest="region")
(options, args) = parser.parse_args()
if len(args) < 1:
parser.print_help()
sys.exit(1)
- elb = boto.connect_elb()
+ if not options.region:
+ elb = boto.connect_elb()
+ else:
+ import boto.ec2.elb
+ elb = boto.ec2.elb.connect_to_region(options.region)
print "%s" % (elb.region.endpoint)
View
@@ -36,7 +36,7 @@
import urlparse
from boto.exception import InvalidUriError
-__version__ = '2.9.7'
+__version__ = '2.9.8'
Version = __version__ # for backware compatibility
UserAgent = 'Boto/%s (%s)' % (__version__, sys.platform)
@@ -362,3 +362,9 @@ def validate_template(self, template_body=None, template_url=None):
" specified, only TemplateBody will be honored by the API")
return self.get_object('ValidateTemplate', params, Template,
verb="POST")
+
+ def cancel_update_stack(self, stack_name_or_id=None):
+ params = {}
+ if stack_name_or_id:
+ params['StackName'] = stack_name_or_id
+ return self.get_status('CancelUpdateStack', params)
@@ -137,8 +137,8 @@ def get_all_load_balancers(self, load_balancer_names=None):
return self.get_list('DescribeLoadBalancers', params,
[('member', LoadBalancer)])
- def create_load_balancer(self, name, zones, listeners, subnets=None,
- security_groups=None, scheme='internet-facing'):
+ def create_load_balancer(self, name, zones, listeners=None, subnets=None,
+ security_groups=None, scheme='internet-facing', complex_listeners=None):
"""
Create a new load balancer for your account. By default the load
balancer will be created in EC2. To create a load balancer inside a
@@ -157,7 +157,7 @@ def create_load_balancer(self, name, zones, listeners, subnets=None,
(LoadBalancerPortNumber, InstancePortNumber, Protocol,
[SSLCertificateId]) where LoadBalancerPortNumber and
InstancePortNumber are integer values between 1 and 65535,
- Protocol is a string containing either 'TCP', 'HTTP' or
+ Protocol is a string containing either 'TCP', 'SSL', HTTP', or
'HTTPS'; SSLCertificateID is the ARN of a AWS AIM
certificate, and must be specified when doing HTTPS.
@@ -182,20 +182,54 @@ def create_load_balancer(self, name, zones, listeners, subnets=None,
This option is only available for LoadBalancers attached
to an Amazon VPC.
+ :type complex_listeners: List of tuples
+ :param complex_listeners: Each tuple contains four or five values,
+ (LoadBalancerPortNumber, InstancePortNumber, Protocol, InstanceProtocol,
+ SSLCertificateId).
+
+ Where;
+ - LoadBalancerPortNumber and InstancePortNumber are integer
+ values between 1 and 65535.
+ - Protocol and InstanceProtocol is a string containing either 'TCP',
+ 'SSL', 'HTTP', or 'HTTPS'
+ - SSLCertificateId is the ARN of an SSL certificate loaded into
+ AWS IAM
+
:rtype: :class:`boto.ec2.elb.loadbalancer.LoadBalancer`
:return: The newly created
:class:`boto.ec2.elb.loadbalancer.LoadBalancer`
"""
+ if not listeners and not complex_listeners:
+ # Must specify one of the two options
+ return None
+
params = {'LoadBalancerName': name,
'Scheme': scheme}
- for index, listener in enumerate(listeners):
- i = index + 1
- protocol = listener[2].upper()
- params['Listeners.member.%d.LoadBalancerPort' % i] = listener[0]
- params['Listeners.member.%d.InstancePort' % i] = listener[1]
- params['Listeners.member.%d.Protocol' % i] = listener[2]
- if protocol == 'HTTPS' or protocol == 'SSL':
- params['Listeners.member.%d.SSLCertificateId' % i] = listener[3]
+
+ # Handle legacy listeners
+ if listeners:
+ for index, listener in enumerate(listeners):
+ i = index + 1
+ protocol = listener[2].upper()
+ params['Listeners.member.%d.LoadBalancerPort' % i] = listener[0]
+ params['Listeners.member.%d.InstancePort' % i] = listener[1]
+ params['Listeners.member.%d.Protocol' % i] = listener[2]
+ if protocol == 'HTTPS' or protocol == 'SSL':
+ params['Listeners.member.%d.SSLCertificateId' % i] = listener[3]
+
+ # Handle the full listeners
+ if complex_listeners:
+ for index, listener in enumerate(complex_listeners):
+ i = index + 1
+ protocol = listener[2].upper()
+ InstanceProtocol = listener[3].upper()
+ params['Listeners.member.%d.LoadBalancerPort' % i] = listener[0]
+ params['Listeners.member.%d.InstancePort' % i] = listener[1]
+ params['Listeners.member.%d.Protocol' % i] = listener[2]
+ params['Listeners.member.%d.InstanceProtocol' % i] = listener[3]
+ if protocol == 'HTTPS' or protocol == 'SSL':
+ params['Listeners.member.%d.SSLCertificateId' % i] = listener[4]
+
if zones:
self.build_list_params(params, zones, 'AvailabilityZones.member.%d')
@@ -215,7 +249,7 @@ def create_load_balancer(self, name, zones, listeners, subnets=None,
load_balancer.security_groups = security_groups
return load_balancer
- def create_load_balancer_listeners(self, name, listeners):
+ def create_load_balancer_listeners(self, name, listeners=None, complex_listeners=None):
"""
Creates a Listener (or group of listeners) for an existing
Load Balancer
@@ -224,26 +258,59 @@ def create_load_balancer_listeners(self, name, listeners):
:param name: The name of the load balancer to create the listeners for
:type listeners: List of tuples
- :param listeners: Each tuple contains three values,
+ :param listeners: Each tuple contains three or four values,
(LoadBalancerPortNumber, InstancePortNumber, Protocol,
[SSLCertificateId]) where LoadBalancerPortNumber and
InstancePortNumber are integer values between 1 and 65535,
- Protocol is a string containing either 'TCP', 'HTTP',
- 'HTTPS', or 'SSL'; SSLCertificateID is the ARN of a AWS
- AIM certificate, and must be specified when doing HTTPS or
- SSL.
+ Protocol is a string containing either 'TCP', 'SSL', HTTP', or
+ 'HTTPS'; SSLCertificateID is the ARN of a AWS AIM
+ certificate, and must be specified when doing HTTPS.
+
+ :type complex_listeners: List of tuples
+ :param complex_listeners: Each tuple contains four or five values,
+ (LoadBalancerPortNumber, InstancePortNumber, Protocol, InstanceProtocol,
+ SSLCertificateId).
+
+ Where;
+ - LoadBalancerPortNumber and InstancePortNumber are integer
+ values between 1 and 65535.
+ - Protocol and InstanceProtocol is a string containing either 'TCP',
+ 'SSL', 'HTTP', or 'HTTPS'
+ - SSLCertificateId is the ARN of an SSL certificate loaded into
+ AWS IAM
:return: The status of the request
"""
+ if not listeners and not complex_listeners:
+ # Must specify one of the two options
+ return None
+
params = {'LoadBalancerName': name}
- for index, listener in enumerate(listeners):
- i = index + 1
- protocol = listener[2].upper()
- params['Listeners.member.%d.LoadBalancerPort' % i] = listener[0]
- params['Listeners.member.%d.InstancePort' % i] = listener[1]
- params['Listeners.member.%d.Protocol' % i] = listener[2]
- if protocol == 'HTTPS' or protocol == 'SSL':
- params['Listeners.member.%d.SSLCertificateId' % i] = listener[3]
+
+ # Handle the simple listeners
+ if listeners:
+ for index, listener in enumerate(listeners):
+ i = index + 1
+ protocol = listener[2].upper()
+ params['Listeners.member.%d.LoadBalancerPort' % i] = listener[0]
+ params['Listeners.member.%d.InstancePort' % i] = listener[1]
+ params['Listeners.member.%d.Protocol' % i] = listener[2]
+ if protocol == 'HTTPS' or protocol == 'SSL':
+ params['Listeners.member.%d.SSLCertificateId' % i] = listener[3]
+
+ # Handle the full listeners
+ if complex_listeners:
+ for index, listener in enumerate(complex_listeners):
+ i = index + 1
+ protocol = listener[2].upper()
+ InstanceProtocol = listener[3].upper()
+ params['Listeners.member.%d.LoadBalancerPort' % i] = listener[0]
+ params['Listeners.member.%d.InstancePort' % i] = listener[1]
+ params['Listeners.member.%d.Protocol' % i] = listener[2]
+ params['Listeners.member.%d.InstanceProtocol' % i] = listener[3]
+ if protocol == 'HTTPS' or protocol == 'SSL':
+ params['Listeners.member.%d.SSLCertificateId' % i] = listener[4]
+
return self.get_status('CreateLoadBalancerListeners', params)
def delete_load_balancer(self, name):
@@ -30,16 +30,19 @@ class Listener(object):
"""
def __init__(self, load_balancer=None, load_balancer_port=0,
- instance_port=0, protocol='', ssl_certificate_id=None):
+ instance_port=0, protocol='', ssl_certificate_id=None, instance_protocol=None):
self.load_balancer = load_balancer
self.load_balancer_port = load_balancer_port
self.instance_port = instance_port
self.protocol = protocol
+ self.instance_protocol = instance_protocol
self.ssl_certificate_id = ssl_certificate_id
self.policy_names = ListElement()
def __repr__(self):
r = "(%d, %d, '%s'" % (self.load_balancer_port, self.instance_port, self.protocol)
+ if self.instance_protocol:
+ r += ", '%s'" % self.instance_protocol
if self.ssl_certificate_id:
r += ', %s' % (self.ssl_certificate_id)
r += ')'
@@ -55,6 +58,8 @@ def endElement(self, name, value, connection):
self.load_balancer_port = int(value)
elif name == 'InstancePort':
self.instance_port = int(value)
+ elif name == 'InstanceProtocol':
+ self.instance_protocol = value
elif name == 'Protocol':
self.protocol = value
elif name == 'SSLCertificateId':
@@ -65,11 +70,16 @@ def endElement(self, name, value, connection):
def get_tuple(self):
return self.load_balancer_port, self.instance_port, self.protocol
+ def get_complex_tuple(self):
+ return self.load_balancer_port, self.instance_port, self.protocol, self.instance_protocol
+
def __getitem__(self, key):
if key == 0:
return self.load_balancer_port
if key == 1:
return self.instance_port
if key == 2:
return self.protocol
+ if key == 4:
+ return self.instance_protocol
raise KeyError
View
@@ -409,6 +409,13 @@ class NoAuthHandlerFound(Exception):
"""Is raised when no auth handlers were found ready to authenticate."""
pass
+class InvalidLifecycleConfigError(Exception):
+ """Exception raised when GCS lifecycle configuration XML is invalid."""
+
+ def __init__(self, message):
+ Exception.__init__(self, message)
+ self.message = message
+
# Enum class for resumable upload failure disposition.
class ResumableTransferDisposition(object):
# START_OVER means an attempt to resume an existing transfer failed,
View
@@ -30,6 +30,7 @@
from boto.gs.acl import SupportedPermissions as GSPermissions
from boto.gs.bucketlistresultset import VersionedBucketListResultSet
from boto.gs.cors import Cors
+from boto.gs.lifecycle import LifecycleConfig
from boto.gs.key import Key as GSKey
from boto.s3.acl import Policy
from boto.s3.bucket import Bucket as S3Bucket
@@ -39,6 +40,7 @@
DEF_OBJ_ACL = 'defaultObjectAcl'
STANDARD_ACL = 'acl'
CORS_ARG = 'cors'
+LIFECYCLE_ARG = 'lifecycle'
class Bucket(S3Bucket):
"""Represents a Google Cloud Storage bucket."""
@@ -918,3 +920,43 @@ def configure_versioning(self, enabled, headers=None):
else:
req_body = self.VersioningBody % ('Suspended')
self.set_subresource('versioning', req_body, headers=headers)
+
+ def get_lifecycle_config(self, headers=None):
+ """
+ Returns the current lifecycle configuration on the bucket.
+
+ :rtype: :class:`boto.gs.lifecycle.LifecycleConfig`
+ :returns: A LifecycleConfig object that describes all current
+ lifecycle rules in effect for the bucket.
+ """
+ response = self.connection.make_request('GET', self.name,
+ query_args=LIFECYCLE_ARG, headers=headers)
+ body = response.read()
+ boto.log.debug(body)
+ if response.status == 200:
+ lifecycle_config = LifecycleConfig()
+ h = handler.XmlHandler(lifecycle_config, self)
+ xml.sax.parseString(body, h)
+ return lifecycle_config
+ else:
+ raise self.connection.provider.storage_response_error(
+ response.status, response.reason, body)
+
+ def configure_lifecycle(self, lifecycle_config, headers=None):
+ """
+ Configure lifecycle for this bucket.
+
+ :type lifecycle_config: :class:`boto.gs.lifecycle.LifecycleConfig`
+ :param lifecycle_config: The lifecycle configuration you want
+ to configure for this bucket.
+ """
+ xml = lifecycle_config.to_xml()
+ response = self.connection.make_request(
+ 'PUT', get_utf8_value(self.name), data=get_utf8_value(xml),
+ query_args=LIFECYCLE_ARG, headers=headers)
+ body = response.read()
+ if response.status == 200:
+ return True
+ else:
+ raise self.connection.provider.storage_response_error(
+ response.status, response.reason, body)
Oops, something went wrong.

0 comments on commit 3c56d13

Please sign in to comment.