summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitch Garnaat <mitch@garnaat.com>2012-02-07 17:33:36 -0800
committerMitch Garnaat <mitch@garnaat.com>2012-02-07 17:33:36 -0800
commite3920747c251893b95a3dd9fb5c8f2741f4e29ea (patch)
tree505c8ee32db7eda17c72b09aa9321b2629530206
parent236c0164538743e957d13a98e4301403f20cedcd (diff)
parentb7cb53b24d3f57349b5e0d05fc2f9eb246540b6d (diff)
downloadboto-e3920747c251893b95a3dd9fb5c8f2741f4e29ea.tar.gz
Merging conflict in bucket.py
-rw-r--r--boto/dynamodb/layer1.py4
-rw-r--r--boto/ec2/autoscale/group.py9
-rw-r--r--boto/ec2/autoscale/tag.py7
-rw-r--r--boto/ec2/zone.py33
-rw-r--r--boto/manage/volume.py4
-rw-r--r--boto/s3/bucket.py10
-rw-r--r--docs/source/boto_config_tut.rst110
-rw-r--r--docs/source/ec2_tut.rst10
-rw-r--r--docs/source/index.rst2
-rw-r--r--tests/autoscale/test_connection.py71
10 files changed, 245 insertions, 15 deletions
diff --git a/boto/dynamodb/layer1.py b/boto/dynamodb/layer1.py
index 8da03c76..4443f7fa 100644
--- a/boto/dynamodb/layer1.py
+++ b/boto/dynamodb/layer1.py
@@ -344,11 +344,11 @@ class Layer1(AWSAuthConnection):
attribute values).
:type table_name: str
- :param table_name: The name of the table to delete.
+ :param table_name: The name of the table.
:type key: dict
:param key: A Python version of the Key data structure
- defined by DynamoDB.
+ defined by DynamoDB which identifies the item to be updated.
:type attribute_updates: dict
:param attribute_updates: A Python version of the AttributeUpdates
diff --git a/boto/ec2/autoscale/group.py b/boto/ec2/autoscale/group.py
index fb42b65c..ab303d33 100644
--- a/boto/ec2/autoscale/group.py
+++ b/boto/ec2/autoscale/group.py
@@ -24,6 +24,7 @@ from boto.resultset import ResultSet
from boto.ec2.autoscale.launchconfig import LaunchConfiguration
from boto.ec2.autoscale.request import Request
from boto.ec2.autoscale.instance import Instance
+from boto.ec2.autoscale.tag import Tag
class ProcessType(object):
def __init__(self, connection=None):
@@ -163,6 +164,7 @@ class AutoScalingGroup(object):
self.autoscaling_group_arn = None
self.vpc_zone_identifier = vpc_zone_identifier
self.instances = None
+ self.tags = None
# backwards compatible access to 'cooldown' param
def _get_cooldown(self):
@@ -174,9 +176,7 @@ class AutoScalingGroup(object):
cooldown = property(_get_cooldown, _set_cooldown)
def __repr__(self):
- return 'AutoScaleGroup<%s>: min:%s, max:%s' % (self.name,
- self.min_size,
- self.max_size)
+ return 'AutoScaleGroup<%s>' % self.name
def startElement(self, name, attrs, connection):
if name == 'Instances':
@@ -192,6 +192,9 @@ class AutoScalingGroup(object):
elif name == 'SuspendedProcesses':
self.suspended_processes = ResultSet([('member', SuspendedProcess)])
return self.suspended_processes
+ elif name == 'Tags':
+ self.tags = ResultSet([('member', Tag)])
+ return self.tags
else:
return
diff --git a/boto/ec2/autoscale/tag.py b/boto/ec2/autoscale/tag.py
index 4b2f9380..70deddae 100644
--- a/boto/ec2/autoscale/tag.py
+++ b/boto/ec2/autoscale/tag.py
@@ -34,12 +34,12 @@ class Tag(object):
"""
def __init__(self, connection=None, key=None, value=None,
- propogate_at_launch=False, resource_id=None,
+ propagate_at_launch=False, resource_id=None,
resource_type='auto-scaling-group'):
self.connection = connection
self.key = key
self.value = value
- self.propagate_at_launch = propogate_at_launch
+ self.propagate_at_launch = propagate_at_launch
self.resource_id = resource_id
self.resource_type = resource_type
@@ -78,4 +78,7 @@ class Tag(object):
params[prefix+'PropagateAtLaunch'] = 'true'
else:
params[prefix+'PropagateAtLaunch'] = 'false'
+
+ def delete(self):
+ return self.connection.delete_tags([self])
diff --git a/boto/ec2/zone.py b/boto/ec2/zone.py
index aec79b2c..44068d4d 100644
--- a/boto/ec2/zone.py
+++ b/boto/ec2/zone.py
@@ -24,21 +24,54 @@ Represents an EC2 Availability Zone
"""
from boto.ec2.ec2object import EC2Object
+class MessageSet(list):
+ """
+ A list object that contains messages associated with
+ an availability zone.
+ """
+
+ def startElement(self, name, attrs, connection):
+ return None
+
+ def endElement(self, name, value, connection):
+ if name == 'message':
+ self.append(value)
+ else:
+ setattr(self, name, value)
+
class Zone(EC2Object):
+ """
+ Represents an Availability Zone.
+
+ :ivar name: The name of the zone.
+ :ivar state: The current state of the zone.
+ :ivar region_name: The name of the region the zone is associated with.
+ :ivar messages: A list of messages related to the zone.
+ """
def __init__(self, connection=None):
EC2Object.__init__(self, connection)
self.name = None
self.state = None
+ self.region_name = None
+ self.messages = None
def __repr__(self):
return 'Zone:%s' % self.name
+ def startElement(self, name, attrs, connection):
+ if name == 'messageSet':
+ self.messages = MessageSet()
+ return self.messages
+ return None
+
def endElement(self, name, value, connection):
if name == 'zoneName':
self.name = value
elif name == 'zoneState':
self.state = value
+ elif name == 'regionName':
+ self.region_name = value
else:
setattr(self, name, value)
diff --git a/boto/manage/volume.py b/boto/manage/volume.py
index 66a458f6..52c344fe 100644
--- a/boto/manage/volume.py
+++ b/boto/manage/volume.py
@@ -24,11 +24,11 @@ from boto.sdb.db.model import Model
from boto.sdb.db.property import StringProperty, IntegerProperty, ListProperty, ReferenceProperty, CalculatedProperty
from boto.manage.server import Server
from boto.manage import propget
+import boto.utils
import boto.ec2
import time
import traceback
from contextlib import closing
-import dateutil.parser
import datetime
@@ -191,7 +191,7 @@ class Volume(Model):
for snapshot in rs:
if snapshot.volume_id in all_vols:
if snapshot.progress == '100%':
- snapshot.date = dateutil.parser.parse(snapshot.start_time)
+ snapshot.date = boto.utils.parse_ts(snapshot.start_time)
snapshot.keep = True
snaps.append(snapshot)
snaps.sort(cmp=lambda x,y: cmp(x.date, y.date))
diff --git a/boto/s3/bucket.py b/boto/s3/bucket.py
index 6c39a3e5..25325a07 100644
--- a/boto/s3/bucket.py
+++ b/boto/s3/bucket.py
@@ -1259,6 +1259,10 @@ class Bucket(object):
return '.'.join(l)
def get_policy(self, headers=None):
+ """
+ Returns the JSON policy associated with the bucket. The policy
+ is returned as an uninterpreted JSON string.
+ """
response = self.connection.make_request('GET', self.name,
query_args='policy', headers=headers)
body = response.content
@@ -1269,6 +1273,12 @@ class Bucket(object):
response.status_code, response.reason, body)
def set_policy(self, policy, headers=None):
+ """
+ Add or replace the JSON policy associated with the bucket.
+
+ :type policy: str
+ :param policy: The JSON policy as a string.
+ """
headers = headers or {}
headers['Content-Type'] = 'text/json'
response = self.connection.make_request('PUT', self.name,
diff --git a/docs/source/boto_config_tut.rst b/docs/source/boto_config_tut.rst
new file mode 100644
index 00000000..76b27b6b
--- /dev/null
+++ b/docs/source/boto_config_tut.rst
@@ -0,0 +1,110 @@
+.. _ref-boto_config:
+
+===========
+Boto Config
+===========
+
+Introduction
+------------
+
+There is a growing list of configuration options for the boto library. Many of
+these options can be passed into the constructors for top-level objects such as
+connections. Some options, such as credentials, can also be read from
+environment variables (e.g. ``AWS_ACCESS_KEY_ID`` and ``AWS_SECRET_ACCESS_KEY``).
+But there is no central place to manage these options. So, the development
+version of boto has now introduced the notion of boto config files.
+
+Details
+-------
+
+A boto config file is simply a .ini format configuration file that specifies
+values for options that control the behavior of the boto library. Upon startup,
+the boto library looks for configuration files in the following locations
+and in the following order:
+
+* /etc/boto.cfg - for site-wide settings that all users on this machine will use
+* ~/.boto - for user-specific settings
+
+The options are merged into a single, in-memory configuration that is
+available as :py:mod:`boto.config`. The :py:class:`boto.pyami.config.Config`
+class is a subclass of the standard Python
+:py:class:`ConfigParser.SafeConfigParser` object and inherits all of the
+methods of that object. In addition, the boto
+:py:class:`Config <boto.pyami.config.Config>` class defines additional
+methods that are described on the PyamiConfigMethods page.
+
+Sections
+--------
+
+The following sections and options are currently recognized within the
+boto config file.
+
+Credentials
+^^^^^^^^^^^
+
+The Credentials section is used to specify the AWS credentials used for all
+boto requests. The order of precedence for authentication credentials is:
+
+* Credentials passed into Connection class constructor.
+* Credentials specified by environment variables
+* Credentials specified as options in the config file.
+
+This section defines the following options: ``aws_access_key_id`` and
+``aws_secret_access_key``. The former being your aws key id and the latter
+being the secret key.
+
+For example::
+
+ [Credentials]
+ aws_access_key_id = <your access key>
+ aws_secret_access_key = <your secret key>
+
+Please notice that quote characters are not used to either side of the '='
+operator even when both your aws access key id and secret key are strings.
+
+Boto
+^^^^
+
+The Boto section is used to specify options that control the operaton of
+boto itself. This section defines the following options:
+
+:debug: Controls the level of debug messages that will be printed by the boto library.
+ The following values are defined::
+
+ 0 - no debug messages are printed
+ 1 - basic debug messages from boto are printed
+ 2 - all boto debugging messages plus request/response messages from httplib
+
+:proxy: The name of the proxy host to use for connecting to AWS.
+:proxy_port: The port number to use to connect to the proxy host.
+:proxy_user: The user name to use when authenticating with proxy host.
+:proxy_pass: The password to use when authenticating with proxy host.
+:num_retries: The number of times to retry failed requests to an AWS server.
+ If boto receives an error from AWS, it will attempt to recover and retry the
+ request. The default number of retries is 5 but you can change the default
+ with this option.
+
+As an example::
+
+ [Boto]
+ debug = 0
+ num_retries = 10
+
+ proxy = myproxy.com
+ proxy_port = 8080
+ proxy_user = foo
+ proxy_pass = bar
+
+Precedence
+----------
+
+Even if you have your boto config setup, you can also have credentials and
+options stored in environmental variables or you can explicitly pass them to
+method calls i.e.::
+
+ >>> boto.connect_ec2('<KEY_ID>','<SECRET_KEY>')
+
+In these cases where these options can be found in more than one place boto
+will first use the explicitly supplied arguments, if none found it will then
+look for them amidst environment variables and if that fails it will use the
+ones in boto config.
diff --git a/docs/source/ec2_tut.rst b/docs/source/ec2_tut.rst
index 7eeb622a..f8614dbe 100644
--- a/docs/source/ec2_tut.rst
+++ b/docs/source/ec2_tut.rst
@@ -19,8 +19,8 @@ There are two ways to do this in boto. The first is::
At this point the variable conn will point to an EC2Connection object. In
this example, the AWS access key and AWS secret key are passed in to the
-method explicitely. Alternatively, you can set the boto config environment
-variables and then call the constructor without any arguments, like this::
+method explicitely. Alternatively, you can set the boto config environment variables
+and then call the constructor without any arguments, like this::
>>> conn = EC2Connection()
@@ -64,7 +64,6 @@ check out boto's :doc:`EC2 API reference <ref/ec2>`.
Stopping Instances
------------------
-
Once you have your instances up and running, you might wish to shut them down
if they're not in use. Please note that this will only de-allocate virtual
hardware resources (as well as instance store drives), but won't destroy your
@@ -74,13 +73,12 @@ even if your instance is stopped. To do this, you can do so as follows::
>>> conn.stop_instances(instance_ids=['instance-id-1','instance-id-2', ...])
This will request a 'graceful' stop of each of the specified instances. If you
-wish to request the equivalent of unplugging your instance(s),
-simply add force=True keyword argument to the call above. Please note that stop
+wish to request the equivalent of unplugging your instance(s), simply add
+``force=True`` keyword argument to the call above. Please note that stop
instance is not allowed with Spot instances.
Terminating Instances
---------------------
-
Once you are completely done with your instance and wish to surrender both
virtual hardware, root EBS volume and all other underlying components
you can request instance termination. To do so you can use the call bellow::
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 457aa4ff..264d3d49 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -67,6 +67,7 @@ Currently Supported Services
Additional Resources
--------------------
+* :doc:`Boto Config Tutorial <boto_config_tut>`
* `Boto Source Repository`_
* `Boto Issue Tracker`_
* `Boto Twitter`_
@@ -114,6 +115,7 @@ Additional Resources
s3_tut
ref/s3
ref/mturk
+ boto_config_tut
ref/index
documentation
diff --git a/tests/autoscale/test_connection.py b/tests/autoscale/test_connection.py
index 921fe435..a650dcef 100644
--- a/tests/autoscale/test_connection.py
+++ b/tests/autoscale/test_connection.py
@@ -33,6 +33,7 @@ from boto.ec2.autoscale.launchconfig import LaunchConfiguration
from boto.ec2.autoscale.policy import AdjustmentType, MetricCollectionTypes, ScalingPolicy
from boto.ec2.autoscale.scheduled import ScheduledUpdateGroupAction
from boto.ec2.autoscale.instance import Instance
+from boto.ec2.autoscale.tag import Tag
class AutoscaleConnectionTest(unittest.TestCase):
@@ -91,5 +92,75 @@ class AutoscaleConnectionTest(unittest.TestCase):
types = c.get_all_metric_collection_types()
self.assertTrue(type(types), MetricCollectionTypes)
+ # create the simplest possible AutoScale group
+ # first create the launch configuration
+ time_string = '%d' % int(time.time())
+ lc_name = 'lc-%s' % time_string
+ lc = LaunchConfiguration(name=lc_name, image_id='ami-2272864b',
+ instance_type='t1.micro')
+ c.create_launch_configuration(lc)
+ found = False
+ lcs = c.get_all_launch_configurations()
+ for lc in lcs:
+ if lc.name == lc_name:
+ found = True
+ break
+ assert found
+
+ # now create autoscaling group
+ group_name = 'group-%s' % time_string
+ group = AutoScalingGroup(name=group_name, launch_config=lc,
+ availability_zones=['us-east-1a'],
+ min_size=1, max_size=1)
+ c.create_auto_scaling_group(group)
+ found = False
+ groups = c.get_all_groups()
+ for group in groups:
+ if group.name == group_name:
+ found = True
+ break
+ assert found
+
+ # now create a tag
+ tag = Tag(key='foo', value='bar', resource_id=group_name,
+ propagate_at_launch=True)
+ c.create_or_update_tags([tag])
+
+ found = False
+ tags = c.get_all_tags()
+ for tag in tags:
+ if tag.resource_id == group_name and tag.key == 'foo':
+ found = True
+ break
+ assert found
+
+ c.delete_tags([tag])
+
+ # shutdown instances and wait for them to disappear
+ group.shutdown_instances()
+ instances = True
+ while instances:
+ time.sleep(5)
+ groups = c.get_all_groups()
+ for group in groups:
+ if group.name == group_name:
+ if not group.instances:
+ instances = False
+
+ group.delete()
+ lc.delete()
+
+ found = True
+ while found:
+ found = False
+ time.sleep(5)
+ tags = c.get_all_tags()
+ for tag in tags:
+ if tag.resource_id == group_name and tag.key == 'foo':
+ found = True
+
+ assert not found
+
print '--- tests completed ---'
+