| # Copyright (c) 2006-2010 Mitch Garnaat http://garnaat.org/ |
| # Copyright (c) 2010, Eucalyptus Systems, Inc. |
| # |
| # 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. |
| |
| """ |
| Represents a connection to the EC2 service. |
| """ |
| |
| import base64 |
| import warnings |
| from datetime import datetime |
| from datetime import timedelta |
| import boto |
| from boto.connection import AWSQueryConnection |
| from boto.resultset import ResultSet |
| from boto.ec2.image import Image, ImageAttribute |
| from boto.ec2.instance import Reservation, Instance |
| from boto.ec2.instance import ConsoleOutput, InstanceAttribute |
| from boto.ec2.keypair import KeyPair |
| from boto.ec2.address import Address |
| from boto.ec2.volume import Volume |
| from boto.ec2.snapshot import Snapshot |
| from boto.ec2.snapshot import SnapshotAttribute |
| from boto.ec2.zone import Zone |
| from boto.ec2.securitygroup import SecurityGroup |
| from boto.ec2.regioninfo import RegionInfo |
| from boto.ec2.instanceinfo import InstanceInfo |
| from boto.ec2.reservedinstance import ReservedInstancesOffering |
| from boto.ec2.reservedinstance import ReservedInstance |
| from boto.ec2.spotinstancerequest import SpotInstanceRequest |
| from boto.ec2.spotpricehistory import SpotPriceHistory |
| from boto.ec2.spotdatafeedsubscription import SpotDatafeedSubscription |
| from boto.ec2.bundleinstance import BundleInstanceTask |
| from boto.ec2.placementgroup import PlacementGroup |
| from boto.ec2.tag import Tag |
| from boto.exception import EC2ResponseError |
| |
| #boto.set_stream_logger('ec2') |
| |
| class EC2Connection(AWSQueryConnection): |
| |
| APIVersion = boto.config.get('Boto', 'ec2_version', '2011-01-01') |
| DefaultRegionName = boto.config.get('Boto', 'ec2_region_name', 'us-east-1') |
| DefaultRegionEndpoint = boto.config.get('Boto', 'ec2_region_endpoint', |
| 'ec2.amazonaws.com') |
| ResponseError = EC2ResponseError |
| |
| def __init__(self, aws_access_key_id=None, aws_secret_access_key=None, |
| is_secure=True, host=None, port=None, |
| proxy=None, proxy_port=None, |
| proxy_user=None, proxy_pass=None, debug=0, |
| https_connection_factory=None, region=None, path='/', |
| api_version=None, security_token=None): |
| """ |
| Init method to create a new connection to EC2. |
| |
| B{Note:} The host argument is overridden by the host specified in the |
| boto configuration file. |
| """ |
| if not region: |
| region = RegionInfo(self, self.DefaultRegionName, |
| self.DefaultRegionEndpoint) |
| self.region = region |
| AWSQueryConnection.__init__(self, 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) |
| if api_version: |
| self.APIVersion = api_version |
| |
| def _required_auth_capability(self): |
| return ['ec2'] |
| |
| def get_params(self): |
| """ |
| Returns a dictionary containing the value of of all of the keyword |
| arguments passed when constructing this connection. |
| """ |
| param_names = ['aws_access_key_id', 'aws_secret_access_key', |
| 'is_secure', 'port', 'proxy', 'proxy_port', |
| 'proxy_user', 'proxy_pass', |
| 'debug', 'https_connection_factory'] |
| params = {} |
| for name in param_names: |
| params[name] = getattr(self, name) |
| return params |
| |
| def build_filter_params(self, params, filters): |
| i = 1 |
| for name in filters: |
| aws_name = name |
| if not aws_name.startswith('tag:'): |
| aws_name = name.replace('_', '-') |
| params['Filter.%d.Name' % i] = aws_name |
| value = filters[name] |
| if not isinstance(value, list): |
| value = [value] |
| j = 1 |
| for v in value: |
| params['Filter.%d.Value.%d' % (i,j)] = v |
| j += 1 |
| i += 1 |
| |
| # Image methods |
| |
| def get_all_images(self, image_ids=None, owners=None, |
| executable_by=None, filters=None): |
| """ |
| Retrieve all the EC2 images available on your account. |
| |
| :type image_ids: list |
| :param image_ids: A list of strings with the image IDs wanted |
| |
| :type owners: list |
| :param owners: A list of owner IDs |
| |
| :type executable_by: list |
| :param executable_by: Returns AMIs for which the specified |
| user ID has explicit launch permissions |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.image.Image` |
| """ |
| params = {} |
| if image_ids: |
| self.build_list_params(params, image_ids, 'ImageId') |
| if owners: |
| self.build_list_params(params, owners, 'Owner') |
| if executable_by: |
| self.build_list_params(params, executable_by, 'ExecutableBy') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeImages', params, |
| [('item', Image)], verb='POST') |
| |
| def get_all_kernels(self, kernel_ids=None, owners=None): |
| """ |
| Retrieve all the EC2 kernels available on your account. |
| Constructs a filter to allow the processing to happen server side. |
| |
| :type kernel_ids: list |
| :param kernel_ids: A list of strings with the image IDs wanted |
| |
| :type owners: list |
| :param owners: A list of owner IDs |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.image.Image` |
| """ |
| params = {} |
| if kernel_ids: |
| self.build_list_params(params, kernel_ids, 'ImageId') |
| if owners: |
| self.build_list_params(params, owners, 'Owner') |
| filter = {'image-type' : 'kernel'} |
| self.build_filter_params(params, filter) |
| return self.get_list('DescribeImages', params, |
| [('item', Image)], verb='POST') |
| |
| def get_all_ramdisks(self, ramdisk_ids=None, owners=None): |
| """ |
| Retrieve all the EC2 ramdisks available on your account. |
| Constructs a filter to allow the processing to happen server side. |
| |
| :type ramdisk_ids: list |
| :param ramdisk_ids: A list of strings with the image IDs wanted |
| |
| :type owners: list |
| :param owners: A list of owner IDs |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.image.Image` |
| """ |
| params = {} |
| if ramdisk_ids: |
| self.build_list_params(params, ramdisk_ids, 'ImageId') |
| if owners: |
| self.build_list_params(params, owners, 'Owner') |
| filter = {'image-type' : 'ramdisk'} |
| self.build_filter_params(params, filter) |
| return self.get_list('DescribeImages', params, |
| [('item', Image)], verb='POST') |
| |
| def get_image(self, image_id): |
| """ |
| Shortcut method to retrieve a specific image (AMI). |
| |
| :type image_id: string |
| :param image_id: the ID of the Image to retrieve |
| |
| :rtype: :class:`boto.ec2.image.Image` |
| :return: The EC2 Image specified or None if the image is not found |
| """ |
| try: |
| return self.get_all_images(image_ids=[image_id])[0] |
| except IndexError: # None of those images available |
| return None |
| |
| def register_image(self, name=None, description=None, image_location=None, |
| architecture=None, kernel_id=None, ramdisk_id=None, |
| root_device_name=None, block_device_map=None): |
| """ |
| Register an image. |
| |
| :type name: string |
| :param name: The name of the AMI. Valid only for EBS-based images. |
| |
| :type description: string |
| :param description: The description of the AMI. |
| |
| :type image_location: string |
| :param image_location: Full path to your AMI manifest in |
| Amazon S3 storage. |
| Only used for S3-based AMI's. |
| |
| :type architecture: string |
| :param architecture: The architecture of the AMI. Valid choices are: |
| i386 | x86_64 |
| |
| :type kernel_id: string |
| :param kernel_id: The ID of the kernel with which to launch |
| the instances |
| |
| :type root_device_name: string |
| :param root_device_name: The root device name (e.g. /dev/sdh) |
| |
| :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` |
| :param block_device_map: A BlockDeviceMapping data structure |
| describing the EBS volumes associated |
| with the Image. |
| |
| :rtype: string |
| :return: The new image id |
| """ |
| params = {} |
| if name: |
| params['Name'] = name |
| if description: |
| params['Description'] = description |
| if architecture: |
| params['Architecture'] = architecture |
| if kernel_id: |
| params['KernelId'] = kernel_id |
| if ramdisk_id: |
| params['RamdiskId'] = ramdisk_id |
| if image_location: |
| params['ImageLocation'] = image_location |
| if root_device_name: |
| params['RootDeviceName'] = root_device_name |
| if block_device_map: |
| block_device_map.build_list_params(params) |
| rs = self.get_object('RegisterImage', params, ResultSet, verb='POST') |
| image_id = getattr(rs, 'imageId', None) |
| return image_id |
| |
| def deregister_image(self, image_id, delete_snapshot=False): |
| """ |
| Unregister an AMI. |
| |
| :type image_id: string |
| :param image_id: the ID of the Image to unregister |
| |
| :type delete_snapshot: bool |
| :param delete_snapshot: Set to True if we should delete the |
| snapshot associated with an EBS volume |
| mounted at /dev/sda1 |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| snapshot_id = None |
| if delete_snapshot: |
| image = self.get_image(image_id) |
| for key in image.block_device_mapping: |
| if key == "/dev/sda1": |
| snapshot_id = image.block_device_mapping[key].snapshot_id |
| break |
| |
| result = self.get_status('DeregisterImage', |
| {'ImageId':image_id}, verb='POST') |
| if result and snapshot_id: |
| return result and self.delete_snapshot(snapshot_id) |
| return result |
| |
| def create_image(self, instance_id, name, |
| description=None, no_reboot=False): |
| """ |
| Will create an AMI from the instance in the running or stopped |
| state. |
| |
| :type instance_id: string |
| :param instance_id: the ID of the instance to image. |
| |
| :type name: string |
| :param name: The name of the new image |
| |
| :type description: string |
| :param description: An optional human-readable string describing |
| the contents and purpose of the AMI. |
| |
| :type no_reboot: bool |
| :param no_reboot: An optional flag indicating that the bundling process |
| should not attempt to shutdown the instance before |
| bundling. If this flag is True, the responsibility |
| of maintaining file system integrity is left to the |
| owner of the instance. |
| |
| :rtype: string |
| :return: The new image id |
| """ |
| params = {'InstanceId' : instance_id, |
| 'Name' : name} |
| if description: |
| params['Description'] = description |
| if no_reboot: |
| params['NoReboot'] = 'true' |
| img = self.get_object('CreateImage', params, Image, verb='POST') |
| return img.id |
| |
| # ImageAttribute methods |
| |
| def get_image_attribute(self, image_id, attribute='launchPermission'): |
| """ |
| Gets an attribute from an image. |
| |
| :type image_id: string |
| :param image_id: The Amazon image id for which you want info about |
| |
| :type attribute: string |
| :param attribute: The attribute you need information about. |
| Valid choices are: |
| * launchPermission |
| * productCodes |
| * blockDeviceMapping |
| |
| :rtype: :class:`boto.ec2.image.ImageAttribute` |
| :return: An ImageAttribute object representing the value of the |
| attribute requested |
| """ |
| params = {'ImageId' : image_id, |
| 'Attribute' : attribute} |
| return self.get_object('DescribeImageAttribute', params, |
| ImageAttribute, verb='POST') |
| |
| def modify_image_attribute(self, image_id, attribute='launchPermission', |
| operation='add', user_ids=None, groups=None, |
| product_codes=None): |
| """ |
| Changes an attribute of an image. |
| |
| :type image_id: string |
| :param image_id: The image id you wish to change |
| |
| :type attribute: string |
| :param attribute: The attribute you wish to change |
| |
| :type operation: string |
| :param operation: Either add or remove (this is required for changing |
| launchPermissions) |
| |
| :type user_ids: list |
| :param user_ids: The Amazon IDs of users to add/remove attributes |
| |
| :type groups: list |
| :param groups: The groups to add/remove attributes |
| |
| :type product_codes: list |
| :param product_codes: Amazon DevPay product code. Currently only one |
| product code can be associated with an AMI. Once |
| set, the product code cannot be changed or reset. |
| """ |
| params = {'ImageId' : image_id, |
| 'Attribute' : attribute, |
| 'OperationType' : operation} |
| if user_ids: |
| self.build_list_params(params, user_ids, 'UserId') |
| if groups: |
| self.build_list_params(params, groups, 'UserGroup') |
| if product_codes: |
| self.build_list_params(params, product_codes, 'ProductCode') |
| return self.get_status('ModifyImageAttribute', params, verb='POST') |
| |
| def reset_image_attribute(self, image_id, attribute='launchPermission'): |
| """ |
| Resets an attribute of an AMI to its default value. |
| |
| :type image_id: string |
| :param image_id: ID of the AMI for which an attribute will be described |
| |
| :type attribute: string |
| :param attribute: The attribute to reset |
| |
| :rtype: bool |
| :return: Whether the operation succeeded or not |
| """ |
| params = {'ImageId' : image_id, |
| 'Attribute' : attribute} |
| return self.get_status('ResetImageAttribute', params, verb='POST') |
| |
| # Instance methods |
| |
| def get_all_instances(self, instance_ids=None, filters=None): |
| """ |
| Retrieve all the instances associated with your account. |
| |
| :type instance_ids: list |
| :param instance_ids: A list of strings of instance IDs |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.instance.Reservation` |
| """ |
| params = {} |
| if instance_ids: |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| if filters: |
| if 'group-id' in filters: |
| warnings.warn("The group-id filter now requires a security " |
| "group identifier (sg-*) instead of a group " |
| "name. To filter by group name use the " |
| "'group-name' filter instead.", UserWarning) |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeInstances', params, |
| [('item', Reservation)], verb='POST') |
| |
| def run_instances(self, image_id, min_count=1, max_count=1, |
| key_name=None, security_groups=None, |
| user_data=None, addressing_type=None, |
| instance_type='m1.small', placement=None, |
| kernel_id=None, ramdisk_id=None, |
| monitoring_enabled=False, subnet_id=None, |
| block_device_map=None, |
| disable_api_termination=False, |
| instance_initiated_shutdown_behavior=None, |
| private_ip_address=None, |
| placement_group=None, client_token=None, |
| security_group_ids=None): |
| """ |
| Runs an image on EC2. |
| |
| :type image_id: string |
| :param image_id: The ID of the image to run |
| |
| :type min_count: int |
| :param min_count: The minimum number of instances to launch |
| |
| :type max_count: int |
| :param max_count: The maximum number of instances to launch |
| |
| :type key_name: string |
| :param key_name: The name of the key pair with which to launch instances |
| |
| :type security_groups: list of strings |
| :param security_groups: The names of the security groups with which to |
| associate instances |
| |
| :type user_data: string |
| :param user_data: The user data passed to the launched instances |
| |
| :type instance_type: string |
| :param instance_type: The type of instance to run: |
| |
| * m1.small |
| * m1.large |
| * m1.xlarge |
| * c1.medium |
| * c1.xlarge |
| * m2.xlarge |
| * m2.2xlarge |
| * m2.4xlarge |
| * cc1.4xlarge |
| * t1.micro |
| |
| :type placement: string |
| :param placement: The availability zone in which to launch the instances |
| |
| :type kernel_id: string |
| :param kernel_id: The ID of the kernel with which to launch the |
| instances |
| |
| :type ramdisk_id: string |
| :param ramdisk_id: The ID of the RAM disk with which to launch the |
| instances |
| |
| :type monitoring_enabled: bool |
| :param monitoring_enabled: Enable CloudWatch monitoring on the instance. |
| |
| :type subnet_id: string |
| :param subnet_id: The subnet ID within which to launch the instances |
| for VPC. |
| |
| :type private_ip_address: string |
| :param private_ip_address: If you're using VPC, you can optionally use |
| this parameter to assign the instance a |
| specific available IP address from the |
| subnet (e.g., 10.0.0.25). |
| |
| :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` |
| :param block_device_map: A BlockDeviceMapping data structure |
| describing the EBS volumes associated |
| with the Image. |
| |
| :type disable_api_termination: bool |
| :param disable_api_termination: If True, the instances will be locked |
| and will not be able to be terminated |
| via the API. |
| |
| :type instance_initiated_shutdown_behavior: string |
| :param instance_initiated_shutdown_behavior: Specifies whether the |
| instance stops or |
| terminates on |
| instance-initiated |
| shutdown. |
| Valid values are: |
| |
| * stop |
| * terminate |
| |
| :type placement_group: string |
| :param placement_group: If specified, this is the name of the placement |
| group in which the instance(s) will be launched. |
| |
| :type client_token: string |
| :param client_token: Unique, case-sensitive identifier you provide |
| to ensure idempotency of the request. |
| Maximum 64 ASCII characters |
| |
| :rtype: Reservation |
| :return: The :class:`boto.ec2.instance.Reservation` associated with |
| the request for machines |
| |
| :type security_group_ids: list of strings |
| :param security_group_ids: The ID of the VPC security groups with |
| which to associate instances |
| """ |
| params = {'ImageId':image_id, |
| 'MinCount':min_count, |
| 'MaxCount': max_count} |
| if key_name: |
| params['KeyName'] = key_name |
| if security_group_ids: |
| l = [] |
| for group in security_group_ids: |
| if isinstance(group, SecurityGroup): |
| l.append(group.name) |
| else: |
| l.append(group) |
| self.build_list_params(params, l, 'SecurityGroupId') |
| if security_groups: |
| l = [] |
| for group in security_groups: |
| if isinstance(group, SecurityGroup): |
| l.append(group.name) |
| else: |
| l.append(group) |
| self.build_list_params(params, l, 'SecurityGroup') |
| if user_data: |
| params['UserData'] = base64.b64encode(user_data) |
| if addressing_type: |
| params['AddressingType'] = addressing_type |
| if instance_type: |
| params['InstanceType'] = instance_type |
| if placement: |
| params['Placement.AvailabilityZone'] = placement |
| if placement_group: |
| params['Placement.GroupName'] = placement_group |
| if kernel_id: |
| params['KernelId'] = kernel_id |
| if ramdisk_id: |
| params['RamdiskId'] = ramdisk_id |
| if monitoring_enabled: |
| params['Monitoring.Enabled'] = 'true' |
| if subnet_id: |
| params['SubnetId'] = subnet_id |
| if private_ip_address: |
| params['PrivateIpAddress'] = private_ip_address |
| if block_device_map: |
| block_device_map.build_list_params(params) |
| if disable_api_termination: |
| params['DisableApiTermination'] = 'true' |
| if instance_initiated_shutdown_behavior: |
| val = instance_initiated_shutdown_behavior |
| params['InstanceInitiatedShutdownBehavior'] = val |
| if client_token: |
| params['ClientToken'] = client_token |
| return self.get_object('RunInstances', params, Reservation, verb='POST') |
| |
| def terminate_instances(self, instance_ids=None): |
| """ |
| Terminate the instances specified |
| |
| :type instance_ids: list |
| :param instance_ids: A list of strings of the Instance IDs to terminate |
| |
| :rtype: list |
| :return: A list of the instances terminated |
| """ |
| params = {} |
| if instance_ids: |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| return self.get_list('TerminateInstances', params, |
| [('item', Instance)], verb='POST') |
| |
| def stop_instances(self, instance_ids=None, force=False): |
| """ |
| Stop the instances specified |
| |
| :type instance_ids: list |
| :param instance_ids: A list of strings of the Instance IDs to stop |
| |
| :type force: bool |
| :param force: Forces the instance to stop |
| |
| :rtype: list |
| :return: A list of the instances stopped |
| """ |
| params = {} |
| if force: |
| params['Force'] = 'true' |
| if instance_ids: |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| return self.get_list('StopInstances', params, |
| [('item', Instance)], verb='POST') |
| |
| def start_instances(self, instance_ids=None): |
| """ |
| Start the instances specified |
| |
| :type instance_ids: list |
| :param instance_ids: A list of strings of the Instance IDs to start |
| |
| :rtype: list |
| :return: A list of the instances started |
| """ |
| params = {} |
| if instance_ids: |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| return self.get_list('StartInstances', params, |
| [('item', Instance)], verb='POST') |
| |
| def get_console_output(self, instance_id): |
| """ |
| Retrieves the console output for the specified instance. |
| |
| :type instance_id: string |
| :param instance_id: The instance ID of a running instance on the cloud. |
| |
| :rtype: :class:`boto.ec2.instance.ConsoleOutput` |
| :return: The console output as a ConsoleOutput object |
| """ |
| params = {} |
| self.build_list_params(params, [instance_id], 'InstanceId') |
| return self.get_object('GetConsoleOutput', params, |
| ConsoleOutput, verb='POST') |
| |
| def reboot_instances(self, instance_ids=None): |
| """ |
| Reboot the specified instances. |
| |
| :type instance_ids: list |
| :param instance_ids: The instances to terminate and reboot |
| """ |
| params = {} |
| if instance_ids: |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| return self.get_status('RebootInstances', params) |
| |
| def confirm_product_instance(self, product_code, instance_id): |
| params = {'ProductCode' : product_code, |
| 'InstanceId' : instance_id} |
| rs = self.get_object('ConfirmProductInstance', params, |
| ResultSet, verb='POST') |
| return (rs.status, rs.ownerId) |
| |
| # InstanceAttribute methods |
| |
| def get_instance_attribute(self, instance_id, attribute): |
| """ |
| Gets an attribute from an instance. |
| |
| :type instance_id: string |
| :param instance_id: The Amazon id of the instance |
| |
| :type attribute: string |
| :param attribute: The attribute you need information about |
| Valid choices are: |
| |
| * instanceType|kernel|ramdisk|userData| |
| * disableApiTermination| |
| * instanceInitiatedShutdownBehavior| |
| * rootDeviceName|blockDeviceMapping |
| |
| :rtype: :class:`boto.ec2.image.InstanceAttribute` |
| :return: An InstanceAttribute object representing the value of the |
| attribute requested |
| """ |
| params = {'InstanceId' : instance_id} |
| if attribute: |
| params['Attribute'] = attribute |
| return self.get_object('DescribeInstanceAttribute', params, |
| InstanceAttribute, verb='POST') |
| |
| def modify_instance_attribute(self, instance_id, attribute, value): |
| """ |
| Changes an attribute of an instance |
| |
| :type instance_id: string |
| :param instance_id: The instance id you wish to change |
| |
| :type attribute: string |
| :param attribute: The attribute you wish to change. |
| |
| * AttributeName - Expected value (default) |
| * instanceType - A valid instance type (m1.small) |
| * kernel - Kernel ID (None) |
| * ramdisk - Ramdisk ID (None) |
| * userData - Base64 encoded String (None) |
| * disableApiTermination - Boolean (true) |
| * instanceInitiatedShutdownBehavior - stop|terminate |
| * rootDeviceName - device name (None) |
| |
| :type value: string |
| :param value: The new value for the attribute |
| |
| :rtype: bool |
| :return: Whether the operation succeeded or not |
| """ |
| # Allow a bool to be passed in for value of disableApiTermination |
| if attribute == 'disableApiTermination': |
| if isinstance(value, bool): |
| if value: |
| value = 'true' |
| else: |
| value = 'false' |
| params = {'InstanceId' : instance_id, |
| 'Attribute' : attribute, |
| 'Value' : value} |
| return self.get_status('ModifyInstanceAttribute', params, verb='POST') |
| |
| def reset_instance_attribute(self, instance_id, attribute): |
| """ |
| Resets an attribute of an instance to its default value. |
| |
| :type instance_id: string |
| :param instance_id: ID of the instance |
| |
| :type attribute: string |
| :param attribute: The attribute to reset. Valid values are: |
| kernel|ramdisk |
| |
| :rtype: bool |
| :return: Whether the operation succeeded or not |
| """ |
| params = {'InstanceId' : instance_id, |
| 'Attribute' : attribute} |
| return self.get_status('ResetInstanceAttribute', params, verb='POST') |
| |
| # Spot Instances |
| |
| def get_all_spot_instance_requests(self, request_ids=None, |
| filters=None): |
| """ |
| Retrieve all the spot instances requests associated with your account. |
| |
| :type request_ids: list |
| :param request_ids: A list of strings of spot instance request IDs |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of |
| :class:`boto.ec2.spotinstancerequest.SpotInstanceRequest` |
| """ |
| params = {} |
| if request_ids: |
| self.build_list_params(params, request_ids, 'SpotInstanceRequestId') |
| if filters: |
| if 'launch.group-id' in filters: |
| warnings.warn("The 'launch.group-id' filter now requires a " |
| "security group id (sg-*) and no longer supports " |
| "filtering by group name. Please update your " |
| "filters accordingly.", UserWarning) |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeSpotInstanceRequests', params, |
| [('item', SpotInstanceRequest)], verb='POST') |
| |
| def get_spot_price_history(self, start_time=None, end_time=None, |
| instance_type=None, product_description=None, |
| availability_zone=None): |
| """ |
| Retrieve the recent history of spot instances pricing. |
| |
| :type start_time: str |
| :param start_time: An indication of how far back to provide price |
| changes for. An ISO8601 DateTime string. |
| |
| :type end_time: str |
| :param end_time: An indication of how far forward to provide price |
| changes for. An ISO8601 DateTime string. |
| |
| :type instance_type: str |
| :param instance_type: Filter responses to a particular instance type. |
| |
| :type product_description: str |
| :param product_description: Filter responses to a particular platform. |
| Valid values are currently: "Linux/UNIX", |
| "SUSE Linux", and "Windows" |
| |
| :type availability_zone: str |
| :param availability_zone: The availability zone for which prices |
| should be returned |
| |
| :rtype: list |
| :return: A list tuples containing price and timestamp. |
| """ |
| params = {} |
| if start_time: |
| params['StartTime'] = start_time |
| if end_time: |
| params['EndTime'] = end_time |
| if instance_type: |
| params['InstanceType'] = instance_type |
| if product_description: |
| params['ProductDescription'] = product_description |
| if availability_zone: |
| params['AvailabilityZone'] = availability_zone |
| return self.get_list('DescribeSpotPriceHistory', params, |
| [('item', SpotPriceHistory)], verb='POST') |
| |
| def request_spot_instances(self, price, image_id, count=1, type='one-time', |
| valid_from=None, valid_until=None, |
| launch_group=None, availability_zone_group=None, |
| key_name=None, security_groups=None, |
| user_data=None, addressing_type=None, |
| instance_type='m1.small', placement=None, |
| kernel_id=None, ramdisk_id=None, |
| monitoring_enabled=False, subnet_id=None, |
| block_device_map=None): |
| """ |
| Request instances on the spot market at a particular price. |
| |
| :type price: str |
| :param price: The maximum price of your bid |
| |
| :type image_id: string |
| :param image_id: The ID of the image to run |
| |
| :type count: int |
| :param count: The of instances to requested |
| |
| :type type: str |
| :param type: Type of request. Can be 'one-time' or 'persistent'. |
| Default is one-time. |
| |
| :type valid_from: str |
| :param valid_from: Start date of the request. An ISO8601 time string. |
| |
| :type valid_until: str |
| :param valid_until: End date of the request. An ISO8601 time string. |
| |
| :type launch_group: str |
| :param launch_group: If supplied, all requests will be fulfilled |
| as a group. |
| |
| :type availability_zone_group: str |
| :param availability_zone_group: If supplied, all requests will be |
| fulfilled within a single |
| availability zone. |
| |
| :type key_name: string |
| :param key_name: The name of the key pair with which to launch instances |
| |
| :type security_groups: list of strings |
| :param security_groups: The names of the security groups with which to |
| associate instances |
| |
| :type user_data: string |
| :param user_data: The user data passed to the launched instances |
| |
| :type instance_type: string |
| :param instance_type: The type of instance to run: |
| |
| * m1.small |
| * m1.large |
| * m1.xlarge |
| * c1.medium |
| * c1.xlarge |
| * m2.xlarge |
| * m2.2xlarge |
| * m2.4xlarge |
| * cc1.4xlarge |
| * t1.micro |
| |
| :type placement: string |
| :param placement: The availability zone in which to launch the instances |
| |
| :type kernel_id: string |
| :param kernel_id: The ID of the kernel with which to launch the |
| instances |
| |
| :type ramdisk_id: string |
| :param ramdisk_id: The ID of the RAM disk with which to launch the |
| instances |
| |
| :type monitoring_enabled: bool |
| :param monitoring_enabled: Enable CloudWatch monitoring on the instance. |
| |
| :type subnet_id: string |
| :param subnet_id: The subnet ID within which to launch the instances |
| for VPC. |
| |
| :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping` |
| :param block_device_map: A BlockDeviceMapping data structure |
| describing the EBS volumes associated |
| with the Image. |
| |
| :rtype: Reservation |
| :return: The :class:`boto.ec2.spotinstancerequest.SpotInstanceRequest` |
| associated with the request for machines |
| """ |
| params = {'LaunchSpecification.ImageId':image_id, |
| 'Type' : type, |
| 'SpotPrice' : price} |
| if count: |
| params['InstanceCount'] = count |
| if valid_from: |
| params['ValidFrom'] = valid_from |
| if valid_until: |
| params['ValidUntil'] = valid_until |
| if launch_group: |
| params['LaunchGroup'] = launch_group |
| if availability_zone_group: |
| params['AvailabilityZoneGroup'] = availability_zone_group |
| if key_name: |
| params['LaunchSpecification.KeyName'] = key_name |
| if security_groups: |
| l = [] |
| for group in security_groups: |
| if isinstance(group, SecurityGroup): |
| l.append(group.name) |
| else: |
| l.append(group) |
| self.build_list_params(params, l, |
| 'LaunchSpecification.SecurityGroup') |
| if user_data: |
| params['LaunchSpecification.UserData'] = base64.b64encode(user_data) |
| if addressing_type: |
| params['LaunchSpecification.AddressingType'] = addressing_type |
| if instance_type: |
| params['LaunchSpecification.InstanceType'] = instance_type |
| if placement: |
| params['LaunchSpecification.Placement.AvailabilityZone'] = placement |
| if kernel_id: |
| params['LaunchSpecification.KernelId'] = kernel_id |
| if ramdisk_id: |
| params['LaunchSpecification.RamdiskId'] = ramdisk_id |
| if monitoring_enabled: |
| params['LaunchSpecification.Monitoring.Enabled'] = 'true' |
| if subnet_id: |
| params['LaunchSpecification.SubnetId'] = subnet_id |
| if block_device_map: |
| block_device_map.build_list_params(params, 'LaunchSpecification.') |
| return self.get_list('RequestSpotInstances', params, |
| [('item', SpotInstanceRequest)], |
| verb='POST') |
| |
| |
| def cancel_spot_instance_requests(self, request_ids): |
| """ |
| Cancel the specified Spot Instance Requests. |
| |
| :type request_ids: list |
| :param request_ids: A list of strings of the Request IDs to terminate |
| |
| :rtype: list |
| :return: A list of the instances terminated |
| """ |
| params = {} |
| if request_ids: |
| self.build_list_params(params, request_ids, 'SpotInstanceRequestId') |
| return self.get_list('CancelSpotInstanceRequests', params, |
| [('item', Instance)], verb='POST') |
| |
| def get_spot_datafeed_subscription(self): |
| """ |
| Return the current spot instance data feed subscription |
| associated with this account, if any. |
| |
| :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription` |
| :return: The datafeed subscription object or None |
| """ |
| return self.get_object('DescribeSpotDatafeedSubscription', |
| None, SpotDatafeedSubscription, verb='POST') |
| |
| def create_spot_datafeed_subscription(self, bucket, prefix): |
| """ |
| Create a spot instance datafeed subscription for this account. |
| |
| :type bucket: str or unicode |
| :param bucket: The name of the bucket where spot instance data |
| will be written. The account issuing this request |
| must have FULL_CONTROL access to the bucket |
| specified in the request. |
| |
| :type prefix: str or unicode |
| :param prefix: An optional prefix that will be pre-pended to all |
| data files written to the bucket. |
| |
| :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription` |
| :return: The datafeed subscription object or None |
| """ |
| params = {'Bucket' : bucket} |
| if prefix: |
| params['Prefix'] = prefix |
| return self.get_object('CreateSpotDatafeedSubscription', |
| params, SpotDatafeedSubscription, verb='POST') |
| |
| def delete_spot_datafeed_subscription(self): |
| """ |
| Delete the current spot instance data feed subscription |
| associated with this account |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| return self.get_status('DeleteSpotDatafeedSubscription', |
| None, verb='POST') |
| |
| # Zone methods |
| |
| def get_all_zones(self, zones=None, filters=None): |
| """ |
| Get all Availability Zones associated with the current region. |
| |
| :type zones: list |
| :param zones: Optional list of zones. If this list is present, |
| only the Zones associated with these zone names |
| will be returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list of :class:`boto.ec2.zone.Zone` |
| :return: The requested Zone objects |
| """ |
| params = {} |
| if zones: |
| self.build_list_params(params, zones, 'ZoneName') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeAvailabilityZones', params, |
| [('item', Zone)], verb='POST') |
| |
| # Address methods |
| |
| def get_all_addresses(self, addresses=None, filters=None, allocation_ids=None): |
| """ |
| Get all EIP's associated with the current credentials. |
| |
| :type addresses: list |
| :param addresses: Optional list of addresses. If this list is present, |
| only the Addresses associated with these addresses |
| will be returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :type allocation_ids: list |
| :param allocation_ids: Optional list of allocation IDs. If this list is |
| present, only the Addresses associated with the given |
| allocation IDs will be returned. |
| |
| :rtype: list of :class:`boto.ec2.address.Address` |
| :return: The requested Address objects |
| """ |
| params = {} |
| if addresses: |
| self.build_list_params(params, addresses, 'PublicIp') |
| if allocation_ids: |
| self.build_list_params(params, allocation_ids, 'AllocationId') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeAddresses', params, [('item', Address)], verb='POST') |
| |
| def allocate_address(self, domain=None): |
| """ |
| Allocate a new Elastic IP address and associate it with your account. |
| |
| :rtype: :class:`boto.ec2.address.Address` |
| :return: The newly allocated Address |
| """ |
| params = {} |
| |
| if domain is not None: |
| params['Domain'] = domain |
| |
| return self.get_object('AllocateAddress', params, Address, verb='POST') |
| |
| def associate_address(self, instance_id, public_ip=None, allocation_id=None): |
| """ |
| Associate an Elastic IP address with a currently running instance. |
| This requires one of ``public_ip`` or ``allocation_id`` depending |
| on if you're associating a VPC address or a plain EC2 address. |
| |
| :type instance_id: string |
| :param instance_id: The ID of the instance |
| |
| :type public_ip: string |
| :param public_ip: The public IP address for EC2 based allocations. |
| |
| :type allocation_id: string |
| :param allocation_id: The allocation ID for a VPC-based elastic IP. |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = { 'InstanceId' : instance_id } |
| |
| if public_ip is not None: |
| params['PublicIp'] = public_ip |
| elif allocation_id is not None: |
| params['AllocationId'] = allocation_id |
| |
| return self.get_status('AssociateAddress', params, verb='POST') |
| |
| def disassociate_address(self, public_ip=None, association_id=None): |
| """ |
| Disassociate an Elastic IP address from a currently running instance. |
| |
| :type public_ip: string |
| :param public_ip: The public IP address for EC2 elastic IPs. |
| |
| :type association_id: string |
| :param association_id: The association ID for a VPC based elastic ip. |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {} |
| |
| if public_ip is not None: |
| params['PublicIp'] = public_ip |
| elif association_id is not None: |
| params['AssociationId'] = association_id |
| |
| return self.get_status('DisassociateAddress', params, verb='POST') |
| |
| def release_address(self, public_ip=None, allocation_id=None): |
| """ |
| Free up an Elastic IP address. |
| |
| :type public_ip: string |
| :param public_ip: The public IP address for EC2 elastic IPs. |
| |
| :type allocation_id: string |
| :param allocation_id: The ID for VPC elastic IPs. |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {} |
| |
| if public_ip is not None: |
| params['PublicIp'] = public_ip |
| elif allocation_id is not None: |
| params['AllocationId'] = allocation_id |
| |
| return self.get_status('ReleaseAddress', params, verb='POST') |
| |
| # Volume methods |
| |
| def get_all_volumes(self, volume_ids=None, filters=None): |
| """ |
| Get all Volumes associated with the current credentials. |
| |
| :type volume_ids: list |
| :param volume_ids: Optional list of volume ids. If this list |
| is present, only the volumes associated with |
| these volume ids will be returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list of :class:`boto.ec2.volume.Volume` |
| :return: The requested Volume objects |
| """ |
| params = {} |
| if volume_ids: |
| self.build_list_params(params, volume_ids, 'VolumeId') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeVolumes', params, |
| [('item', Volume)], verb='POST') |
| |
| def create_volume(self, size, zone, snapshot=None): |
| """ |
| Create a new EBS Volume. |
| |
| :type size: int |
| :param size: The size of the new volume, in GiB |
| |
| :type zone: string or :class:`boto.ec2.zone.Zone` |
| :param zone: The availability zone in which the Volume will be created. |
| |
| :type snapshot: string or :class:`boto.ec2.snapshot.Snapshot` |
| :param snapshot: The snapshot from which the new Volume will be created. |
| """ |
| if isinstance(zone, Zone): |
| zone = zone.name |
| params = {'AvailabilityZone' : zone} |
| if size: |
| params['Size'] = size |
| if snapshot: |
| if isinstance(snapshot, Snapshot): |
| snapshot = snapshot.id |
| params['SnapshotId'] = snapshot |
| return self.get_object('CreateVolume', params, Volume, verb='POST') |
| |
| def delete_volume(self, volume_id): |
| """ |
| Delete an EBS volume. |
| |
| :type volume_id: str |
| :param volume_id: The ID of the volume to be delete. |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {'VolumeId': volume_id} |
| return self.get_status('DeleteVolume', params, verb='POST') |
| |
| def attach_volume(self, volume_id, instance_id, device): |
| """ |
| Attach an EBS volume to an EC2 instance. |
| |
| :type volume_id: str |
| :param volume_id: The ID of the EBS volume to be attached. |
| |
| :type instance_id: str |
| :param instance_id: The ID of the EC2 instance to which it will |
| be attached. |
| |
| :type device: str |
| :param device: The device on the instance through which the |
| volume will be exposted (e.g. /dev/sdh) |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {'InstanceId' : instance_id, |
| 'VolumeId' : volume_id, |
| 'Device' : device} |
| return self.get_status('AttachVolume', params, verb='POST') |
| |
| def detach_volume(self, volume_id, instance_id=None, |
| device=None, force=False): |
| """ |
| Detach an EBS volume from an EC2 instance. |
| |
| :type volume_id: str |
| :param volume_id: The ID of the EBS volume to be attached. |
| |
| :type instance_id: str |
| :param instance_id: The ID of the EC2 instance from which it will |
| be detached. |
| |
| :type device: str |
| :param device: The device on the instance through which the |
| volume is exposted (e.g. /dev/sdh) |
| |
| :type force: bool |
| :param force: Forces detachment if the previous detachment attempt did |
| not occur cleanly. This option can lead to data loss or |
| a corrupted file system. Use this option only as a last |
| resort to detach a volume from a failed instance. The |
| instance will not have an opportunity to flush file system |
| caches nor file system meta data. If you use this option, |
| you must perform file system check and repair procedures. |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {'VolumeId' : volume_id} |
| if instance_id: |
| params['InstanceId'] = instance_id |
| if device: |
| params['Device'] = device |
| if force: |
| params['Force'] = 'true' |
| return self.get_status('DetachVolume', params, verb='POST') |
| |
| # Snapshot methods |
| |
| def get_all_snapshots(self, snapshot_ids=None, |
| owner=None, restorable_by=None, |
| filters=None): |
| """ |
| Get all EBS Snapshots associated with the current credentials. |
| |
| :type snapshot_ids: list |
| :param snapshot_ids: Optional list of snapshot ids. If this list is |
| present, only the Snapshots associated with |
| these snapshot ids will be returned. |
| |
| :type owner: str |
| :param owner: If present, only the snapshots owned by the specified user |
| will be returned. Valid values are: |
| |
| * self |
| * amazon |
| * AWS Account ID |
| |
| :type restorable_by: str |
| :param restorable_by: If present, only the snapshots that are restorable |
| by the specified account id will be returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list of :class:`boto.ec2.snapshot.Snapshot` |
| :return: The requested Snapshot objects |
| """ |
| params = {} |
| if snapshot_ids: |
| self.build_list_params(params, snapshot_ids, 'SnapshotId') |
| if owner: |
| params['Owner'] = owner |
| if restorable_by: |
| params['RestorableBy'] = restorable_by |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeSnapshots', params, |
| [('item', Snapshot)], verb='POST') |
| |
| def create_snapshot(self, volume_id, description=None): |
| """ |
| Create a snapshot of an existing EBS Volume. |
| |
| :type volume_id: str |
| :param volume_id: The ID of the volume to be snapshot'ed |
| |
| :type description: str |
| :param description: A description of the snapshot. |
| Limited to 255 characters. |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {'VolumeId' : volume_id} |
| if description: |
| params['Description'] = description[0:255] |
| snapshot = self.get_object('CreateSnapshot', params, |
| Snapshot, verb='POST') |
| volume = self.get_all_volumes([volume_id])[0] |
| volume_name = volume.tags.get('Name') |
| if volume_name: |
| snapshot.add_tag('Name', volume_name) |
| return snapshot |
| |
| def delete_snapshot(self, snapshot_id): |
| params = {'SnapshotId': snapshot_id} |
| return self.get_status('DeleteSnapshot', params, verb='POST') |
| |
| def trim_snapshots(self, hourly_backups = 8, daily_backups = 7, |
| weekly_backups = 4): |
| """ |
| Trim excess snapshots, based on when they were taken. More current |
| snapshots are retained, with the number retained decreasing as you |
| move back in time. |
| |
| If ebs volumes have a 'Name' tag with a value, their snapshots |
| will be assigned the same tag when they are created. The values |
| of the 'Name' tags for snapshots are used by this function to |
| group snapshots taken from the same volume (or from a series |
| of like-named volumes over time) for trimming. |
| |
| For every group of like-named snapshots, this function retains |
| the newest and oldest snapshots, as well as, by default, the |
| first snapshots taken in each of the last eight hours, the first |
| snapshots taken in each of the last seven days, the first snapshots |
| taken in the last 4 weeks (counting Midnight Sunday morning as |
| the start of the week), and the first snapshot from the first |
| Sunday of each month forever. |
| |
| :type hourly_backups: int |
| :param hourly_backups: How many recent hourly backups should be saved. |
| |
| :type daily_backups: int |
| :param daily_backups: How many recent daily backups should be saved. |
| |
| :type weekly_backups: int |
| :param weekly_backups: How many recent weekly backups should be saved. |
| """ |
| |
| # This function first builds up an ordered list of target times |
| # that snapshots should be saved for (last 8 hours, last 7 days, etc.). |
| # Then a map of snapshots is constructed, with the keys being |
| # the snapshot / volume names and the values being arrays of |
| # chronologically sorted snapshots. |
| # Finally, for each array in the map, we go through the snapshot |
| # array and the target time array in an interleaved fashion, |
| # deleting snapshots whose start_times don't immediately follow a |
| # target time (we delete a snapshot if there's another snapshot |
| # that was made closer to the preceding target time). |
| |
| 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) |
| start_of_month = datetime(now.year, now.month, 1) |
| |
| target_backup_times = [] |
| |
| # there are no snapshots older than 1/1/2007 |
| oldest_snapshot_date = datetime(2007, 1, 1) |
| |
| for hour in range(0, hourly_backups): |
| 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)) |
| |
| for week in range(0, weekly_backups): |
| target_backup_times.append(last_sunday - timedelta(weeks = week)) |
| |
| one_day = timedelta(days = 1) |
| while start_of_month > oldest_snapshot_date: |
| # append the start of the month to the list of |
| # snapshot dates to save: |
| target_backup_times.append(start_of_month) |
| # there's no timedelta setting for one month, so instead: |
| # decrement the day by one, so we go to the final day of |
| # the previous month... |
| start_of_month -= one_day |
| # ... and then go to the first day of that previous month: |
| start_of_month = datetime(start_of_month.year, |
| start_of_month.month, 1) |
| |
| temp = [] |
| |
| for t in target_backup_times: |
| if temp.__contains__(t) == False: |
| temp.append(t) |
| |
| target_backup_times = temp |
| # make the oldeest dates first, and make sure the month start |
| # and last four week's start are in the proper order |
| target_backup_times.sort() |
| |
| # get all the snapshots, sort them by date and time, and |
| # organize them into one array for each volume: |
| all_snapshots = self.get_all_snapshots(owner = 'self') |
| all_snapshots.sort(cmp = lambda x, y: cmp(x.start_time, y.start_time)) |
| snaps_for_each_volume = {} |
| for snap in all_snapshots: |
| # the snapshot name and the volume name are the same. |
| # The snapshot name is set from the volume |
| # name at the time the snapshot is taken |
| volume_name = snap.tags.get('Name') |
| if volume_name: |
| # only examine snapshots that have a volume name |
| snaps_for_volume = snaps_for_each_volume.get(volume_name) |
| if not snaps_for_volume: |
| snaps_for_volume = [] |
| snaps_for_each_volume[volume_name] = snaps_for_volume |
| snaps_for_volume.append(snap) |
| |
| # Do a running comparison of snapshot dates to desired time |
| #periods, keeping the oldest snapshot in each |
| # time period and deleting the rest: |
| for volume_name in snaps_for_each_volume: |
| snaps = snaps_for_each_volume[volume_name] |
| snaps = snaps[:-1] # never delete the newest snapshot |
| time_period_number = 0 |
| snap_found_for_this_time_period = False |
| for snap in snaps: |
| check_this_snap = True |
| while check_this_snap and time_period_number < target_backup_times.__len__(): |
| snap_date = datetime.strptime(snap.start_time, |
| '%Y-%m-%dT%H:%M:%S.000Z') |
| if snap_date < target_backup_times[time_period_number]: |
| # the snap date is before the cutoff date. |
| # Figure out if it's the first snap in this |
| # date range and act accordingly (since both |
| #date the date ranges and the snapshots |
| # are sorted chronologically, we know this |
| #snapshot isn't in an earlier date range): |
| if snap_found_for_this_time_period == True: |
| if not snap.tags.get('preserve_snapshot'): |
| # as long as the snapshot wasn't marked |
| # with the 'preserve_snapshot' tag, delete it: |
| try: |
| self.delete_snapshot(snap.id) |
| boto.log.info('Trimmed snapshot %s (%s)' % (snap.tags['Name'], snap.start_time)) |
| except EC2ResponseError: |
| boto.log.error('Attempt to trim snapshot %s (%s) failed. Possible result of a race condition with trimming on another server?' % (snap.tags['Name'], snap.start_time)) |
| # go on and look at the next snapshot, |
| #leaving the time period alone |
| else: |
| # this was the first snapshot found for this |
| #time period. Leave it alone and look at the |
| # next snapshot: |
| snap_found_for_this_time_period = True |
| check_this_snap = False |
| else: |
| # the snap is after the cutoff date. Check it |
| # against the next cutoff date |
| time_period_number += 1 |
| snap_found_for_this_time_period = False |
| |
| |
| def get_snapshot_attribute(self, snapshot_id, |
| attribute='createVolumePermission'): |
| """ |
| Get information about an attribute of a snapshot. Only one attribute |
| can be specified per call. |
| |
| :type snapshot_id: str |
| :param snapshot_id: The ID of the snapshot. |
| |
| :type attribute: str |
| :param attribute: The requested attribute. Valid values are: |
| |
| * createVolumePermission |
| |
| :rtype: list of :class:`boto.ec2.snapshotattribute.SnapshotAttribute` |
| :return: The requested Snapshot attribute |
| """ |
| params = {'Attribute' : attribute} |
| if snapshot_id: |
| params['SnapshotId'] = snapshot_id |
| return self.get_object('DescribeSnapshotAttribute', params, |
| SnapshotAttribute, verb='POST') |
| |
| def modify_snapshot_attribute(self, snapshot_id, |
| attribute='createVolumePermission', |
| operation='add', user_ids=None, groups=None): |
| """ |
| Changes an attribute of an image. |
| |
| :type snapshot_id: string |
| :param snapshot_id: The snapshot id you wish to change |
| |
| :type attribute: string |
| :param attribute: The attribute you wish to change. Valid values are: |
| createVolumePermission |
| |
| :type operation: string |
| :param operation: Either add or remove (this is required for changing |
| snapshot ermissions) |
| |
| :type user_ids: list |
| :param user_ids: The Amazon IDs of users to add/remove attributes |
| |
| :type groups: list |
| :param groups: The groups to add/remove attributes. The only valid |
| value at this time is 'all'. |
| |
| """ |
| params = {'SnapshotId' : snapshot_id, |
| 'Attribute' : attribute, |
| 'OperationType' : operation} |
| if user_ids: |
| self.build_list_params(params, user_ids, 'UserId') |
| if groups: |
| self.build_list_params(params, groups, 'UserGroup') |
| return self.get_status('ModifySnapshotAttribute', params, verb='POST') |
| |
| def reset_snapshot_attribute(self, snapshot_id, |
| attribute='createVolumePermission'): |
| """ |
| Resets an attribute of a snapshot to its default value. |
| |
| :type snapshot_id: string |
| :param snapshot_id: ID of the snapshot |
| |
| :type attribute: string |
| :param attribute: The attribute to reset |
| |
| :rtype: bool |
| :return: Whether the operation succeeded or not |
| """ |
| params = {'SnapshotId' : snapshot_id, |
| 'Attribute' : attribute} |
| return self.get_status('ResetSnapshotAttribute', params, verb='POST') |
| |
| # Keypair methods |
| |
| def get_all_key_pairs(self, keynames=None, filters=None): |
| """ |
| Get all key pairs associated with your account. |
| |
| :type keynames: list |
| :param keynames: A list of the names of keypairs to retrieve. |
| If not provided, all key pairs will be returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.keypair.KeyPair` |
| """ |
| params = {} |
| if keynames: |
| self.build_list_params(params, keynames, 'KeyName') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeKeyPairs', params, |
| [('item', KeyPair)], verb='POST') |
| |
| def get_key_pair(self, keyname): |
| """ |
| Convenience method to retrieve a specific keypair (KeyPair). |
| |
| :type image_id: string |
| :param image_id: the ID of the Image to retrieve |
| |
| :rtype: :class:`boto.ec2.keypair.KeyPair` |
| :return: The KeyPair specified or None if it is not found |
| """ |
| try: |
| return self.get_all_key_pairs(keynames=[keyname])[0] |
| except IndexError: # None of those key pairs available |
| return None |
| |
| def create_key_pair(self, key_name): |
| """ |
| Create a new key pair for your account. |
| This will create the key pair within the region you |
| are currently connected to. |
| |
| :type key_name: string |
| :param key_name: The name of the new keypair |
| |
| :rtype: :class:`boto.ec2.keypair.KeyPair` |
| :return: The newly created :class:`boto.ec2.keypair.KeyPair`. |
| The material attribute of the new KeyPair object |
| will contain the the unencrypted PEM encoded RSA private key. |
| """ |
| params = {'KeyName':key_name} |
| return self.get_object('CreateKeyPair', params, KeyPair, verb='POST') |
| |
| def delete_key_pair(self, key_name): |
| """ |
| Delete a key pair from your account. |
| |
| :type key_name: string |
| :param key_name: The name of the keypair to delete |
| """ |
| params = {'KeyName':key_name} |
| return self.get_status('DeleteKeyPair', params, verb='POST') |
| |
| def import_key_pair(self, key_name, public_key_material): |
| """ |
| mports the public key from an RSA key pair that you created |
| with a third-party tool. |
| |
| Supported formats: |
| |
| * OpenSSH public key format (e.g., the format |
| in ~/.ssh/authorized_keys) |
| |
| * Base64 encoded DER format |
| |
| * SSH public key file format as specified in RFC4716 |
| |
| DSA keys are not supported. Make sure your key generator is |
| set up to create RSA keys. |
| |
| Supported lengths: 1024, 2048, and 4096. |
| |
| :type key_name: string |
| :param key_name: The name of the new keypair |
| |
| :type public_key_material: string |
| :param public_key_material: The public key. You must base64 encode |
| the public key material before sending |
| it to AWS. |
| |
| :rtype: :class:`boto.ec2.keypair.KeyPair` |
| :return: The newly created :class:`boto.ec2.keypair.KeyPair`. |
| The material attribute of the new KeyPair object |
| will contain the the unencrypted PEM encoded RSA private key. |
| """ |
| public_key_material = base64.b64encode(public_key_material) |
| params = {'KeyName' : key_name, |
| 'PublicKeyMaterial' : public_key_material} |
| return self.get_object('ImportKeyPair', params, KeyPair, verb='POST') |
| |
| # SecurityGroup methods |
| |
| def get_all_security_groups(self, groupnames=None, group_ids=None, filters=None): |
| """ |
| Get all security groups associated with your account in a region. |
| |
| :type groupnames: list |
| :param groupnames: A list of the names of security groups to retrieve. |
| If not provided, all security groups will be |
| returned. |
| |
| :type group_ids: list |
| :param group_ids: A list of IDs of security groups to retrieve for |
| security groups within a VPC. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.securitygroup.SecurityGroup` |
| """ |
| params = {} |
| if groupnames is not None: |
| self.build_list_params(params, groupnames, 'GroupName') |
| if group_ids is not None: |
| self.build_list_params(params, group_ids, 'GroupId') |
| if filters is not None: |
| self.build_filter_params(params, filters) |
| |
| return self.get_list('DescribeSecurityGroups', params, |
| [('item', SecurityGroup)], verb='POST') |
| |
| def create_security_group(self, name, description, vpc_id=None): |
| """ |
| Create a new security group for your account. |
| This will create the security group within the region you |
| are currently connected to. |
| |
| :type name: string |
| :param name: The name of the new security group |
| |
| :type description: string |
| :param description: The description of the new security group |
| |
| :type vpc_id: string |
| :param vpc_id: The ID of the VPC to create the security group in, |
| if any. |
| |
| :rtype: :class:`boto.ec2.securitygroup.SecurityGroup` |
| :return: The newly created :class:`boto.ec2.keypair.KeyPair`. |
| """ |
| params = { |
| 'GroupName': name, |
| 'GroupDescription': description |
| } |
| |
| if vpc_id is not None: |
| params['VpcId'] = vpc_id |
| |
| group = self.get_object('CreateSecurityGroup', params, |
| SecurityGroup, verb='POST') |
| group.name = name |
| group.description = description |
| return group |
| |
| def delete_security_group(self, name=None, group_id=None): |
| """ |
| Delete a security group from your account. |
| |
| :type name: string |
| :param name: The name of the security group to delete. |
| |
| :type group_id: string |
| :param group_id: The ID of the security group to delete within |
| a VPC. |
| |
| :rtype: bool |
| :return: True if successful. |
| """ |
| params = {} |
| |
| if name is not None: |
| params['GroupName'] = name |
| elif group_id is not None: |
| params['GroupId'] = group_id |
| |
| return self.get_status('DeleteSecurityGroup', params, verb='POST') |
| |
| def authorize_security_group_deprecated(self, group_name, |
| src_security_group_name=None, |
| src_security_group_owner_id=None, |
| ip_protocol=None, |
| from_port=None, to_port=None, |
| cidr_ip=None): |
| """ |
| NOTE: This method uses the old-style request parameters |
| that did not allow a port to be specified when |
| authorizing a group. |
| |
| :type group_name: string |
| :param group_name: The name of the security group you are adding |
| the rule to. |
| |
| :type src_security_group_name: string |
| :param src_security_group_name: The name of the security group you are |
| granting access to. |
| |
| :type src_security_group_owner_id: string |
| :param src_security_group_owner_id: The ID of the owner of the security |
| group you are granting access to. |
| |
| :type ip_protocol: string |
| :param ip_protocol: Either tcp | udp | icmp |
| |
| :type from_port: int |
| :param from_port: The beginning port number you are enabling |
| |
| :type to_port: int |
| :param to_port: The ending port number you are enabling |
| |
| :type to_port: string |
| :param to_port: The CIDR block you are providing access to. |
| See http://goo.gl/Yj5QC |
| |
| :rtype: bool |
| :return: True if successful. |
| """ |
| params = {'GroupName':group_name} |
| if src_security_group_name: |
| params['SourceSecurityGroupName'] = src_security_group_name |
| if src_security_group_owner_id: |
| params['SourceSecurityGroupOwnerId'] = src_security_group_owner_id |
| if ip_protocol: |
| params['IpProtocol'] = ip_protocol |
| if from_port: |
| params['FromPort'] = from_port |
| if to_port: |
| params['ToPort'] = to_port |
| if cidr_ip: |
| params['CidrIp'] = cidr_ip |
| return self.get_status('AuthorizeSecurityGroupIngress', params) |
| |
| def authorize_security_group(self, group_name=None, |
| src_security_group_name=None, |
| src_security_group_owner_id=None, |
| ip_protocol=None, from_port=None, to_port=None, |
| cidr_ip=None, group_id=None, |
| src_security_group_group_id=None): |
| """ |
| Add a new rule to an existing security group. |
| You need to pass in either src_security_group_name and |
| src_security_group_owner_id OR ip_protocol, from_port, to_port, |
| and cidr_ip. In other words, either you are authorizing another |
| group or you are authorizing some ip-based rule. |
| |
| :type group_name: string |
| :param group_name: The name of the security group you are adding |
| the rule to. |
| |
| :type src_security_group_name: string |
| :param src_security_group_name: The name of the security group you are |
| granting access to. |
| |
| :type src_security_group_owner_id: string |
| :param src_security_group_owner_id: The ID of the owner of the security |
| group you are granting access to. |
| |
| :type ip_protocol: string |
| :param ip_protocol: Either tcp | udp | icmp |
| |
| :type from_port: int |
| :param from_port: The beginning port number you are enabling |
| |
| :type to_port: int |
| :param to_port: The ending port number you are enabling |
| |
| :type cidr_ip: string |
| :param cidr_ip: The CIDR block you are providing access to. |
| See http://goo.gl/Yj5QC |
| |
| :type group_id: string |
| :param group_id: ID of the EC2 or VPC security group to modify. |
| This is required for VPC security groups and |
| can be used instead of group_name for EC2 |
| security groups. |
| |
| :type group_id: string |
| :param group_id: ID of the EC2 or VPC source security group. |
| This is required for VPC security groups and |
| can be used instead of group_name for EC2 |
| security groups. |
| |
| :rtype: bool |
| :return: True if successful. |
| """ |
| if src_security_group_name: |
| if from_port is None and to_port is None and ip_protocol is None: |
| return self.authorize_security_group_deprecated( |
| group_name, src_security_group_name, |
| src_security_group_owner_id) |
| |
| params = {} |
| |
| if group_name: |
| params['GroupName'] = group_name |
| if group_id: |
| params['GroupId'] = group_id |
| if src_security_group_name: |
| param_name = 'IpPermissions.1.Groups.1.GroupName' |
| params[param_name] = src_security_group_name |
| if src_security_group_owner_id: |
| param_name = 'IpPermissions.1.Groups.1.UserId' |
| params[param_name] = src_security_group_owner_id |
| if src_security_group_group_id: |
| param_name = 'IpPermissions.1.Groups.1.GroupId' |
| params[param_name] = src_security_group_group_id |
| if ip_protocol: |
| params['IpPermissions.1.IpProtocol'] = ip_protocol |
| if from_port is not None: |
| params['IpPermissions.1.FromPort'] = from_port |
| if to_port is not None: |
| params['IpPermissions.1.ToPort'] = to_port |
| if cidr_ip: |
| params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip |
| |
| return self.get_status('AuthorizeSecurityGroupIngress', |
| params, verb='POST') |
| |
| def authorize_security_group_egress(group_id, |
| ip_protocol, |
| from_port=None, |
| to_port=None, |
| src_group_id=None, |
| cidr_ip=None): |
| """ |
| The action adds one or more egress rules to a VPC security |
| group. Specifically, this action permits instances in a |
| security group to send traffic to one or more destination |
| CIDR IP address ranges, or to one or more destination |
| security groups in the same VPC. |
| """ |
| params = { |
| 'GroupId': group_id, |
| 'IpPermissions.1.IpProtocol': ip_protocol |
| } |
| |
| if from_port is not None: |
| params['IpPermissions.1.FromPort'] = from_port |
| if to_port is not None: |
| params['IpPermissions.1.ToPort'] = to_port |
| if src_group_id is not None: |
| params['IpPermissions.1.Groups.1.GroupId'] = src_group_id |
| if cidr_ip is not None: |
| params['IpPermissions.1.Groups.1.CidrIp'] = cidr_ip |
| |
| return self.get_status('AuthorizeSecurityGroupEgress', |
| params, verb='POST') |
| |
| def revoke_security_group_deprecated(self, group_name, |
| src_security_group_name=None, |
| src_security_group_owner_id=None, |
| ip_protocol=None, |
| from_port=None, to_port=None, |
| cidr_ip=None): |
| """ |
| NOTE: This method uses the old-style request parameters |
| that did not allow a port to be specified when |
| authorizing a group. |
| |
| Remove an existing rule from an existing security group. |
| You need to pass in either src_security_group_name and |
| src_security_group_owner_id OR ip_protocol, from_port, to_port, |
| and cidr_ip. In other words, either you are revoking another |
| group or you are revoking some ip-based rule. |
| |
| :type group_name: string |
| :param group_name: The name of the security group you are removing |
| the rule from. |
| |
| :type src_security_group_name: string |
| :param src_security_group_name: The name of the security group you are |
| revoking access to. |
| |
| :type src_security_group_owner_id: string |
| :param src_security_group_owner_id: The ID of the owner of the security |
| group you are revoking access to. |
| |
| :type ip_protocol: string |
| :param ip_protocol: Either tcp | udp | icmp |
| |
| :type from_port: int |
| :param from_port: The beginning port number you are disabling |
| |
| :type to_port: int |
| :param to_port: The ending port number you are disabling |
| |
| :type to_port: string |
| :param to_port: The CIDR block you are revoking access to. |
| http://goo.gl/Yj5QC |
| |
| :type group_id: string |
| :param group_id: ID of the EC2 or VPC security group to modify. |
| This is required for VPC security groups and |
| can be used instead of group_name for EC2 |
| security groups. |
| |
| :type group_id: string |
| :param group_id: ID of the EC2 or VPC source security group. |
| This is required for VPC security groups and |
| can be used instead of group_name for EC2 |
| security groups. |
| |
| :rtype: bool |
| :return: True if successful. |
| """ |
| params = {'GroupName':group_name} |
| if src_security_group_name: |
| params['SourceSecurityGroupName'] = src_security_group_name |
| if src_security_group_owner_id: |
| params['SourceSecurityGroupOwnerId'] = src_security_group_owner_id |
| if ip_protocol: |
| params['IpProtocol'] = ip_protocol |
| if from_port: |
| params['FromPort'] = from_port |
| if to_port: |
| params['ToPort'] = to_port |
| if cidr_ip: |
| params['CidrIp'] = cidr_ip |
| return self.get_status('RevokeSecurityGroupIngress', params) |
| |
| def revoke_security_group(self, group_name, src_security_group_name=None, |
| src_security_group_owner_id=None, |
| ip_protocol=None, from_port=None, to_port=None, |
| cidr_ip=None, group_id=None, |
| src_security_group_group_id=None): |
| """ |
| Remove an existing rule from an existing security group. |
| You need to pass in either src_security_group_name and |
| src_security_group_owner_id OR ip_protocol, from_port, to_port, |
| and cidr_ip. In other words, either you are revoking another |
| group or you are revoking some ip-based rule. |
| |
| :type group_name: string |
| :param group_name: The name of the security group you are removing |
| the rule from. |
| |
| :type src_security_group_name: string |
| :param src_security_group_name: The name of the security group you are |
| revoking access to. |
| |
| :type src_security_group_owner_id: string |
| :param src_security_group_owner_id: The ID of the owner of the security |
| group you are revoking access to. |
| |
| :type ip_protocol: string |
| :param ip_protocol: Either tcp | udp | icmp |
| |
| :type from_port: int |
| :param from_port: The beginning port number you are disabling |
| |
| :type to_port: int |
| :param to_port: The ending port number you are disabling |
| |
| :type cidr_ip: string |
| :param cidr_ip: The CIDR block you are revoking access to. |
| See http://goo.gl/Yj5QC |
| |
| :rtype: bool |
| :return: True if successful. |
| """ |
| if src_security_group_name: |
| if from_port is None and to_port is None and ip_protocol is None: |
| return self.revoke_security_group_deprecated( |
| group_name, src_security_group_name, |
| src_security_group_owner_id) |
| params = {} |
| if group_name: |
| params['GroupName'] = group_name |
| if src_security_group_name: |
| param_name = 'IpPermissions.1.Groups.1.GroupName' |
| params[param_name] = src_security_group_name |
| if src_security_group_owner_id: |
| param_name = 'IpPermissions.1.Groups.1.UserId' |
| params[param_name] = src_security_group_owner_id |
| if ip_protocol: |
| params['IpPermissions.1.IpProtocol'] = ip_protocol |
| if from_port is not None: |
| params['IpPermissions.1.FromPort'] = from_port |
| if to_port is not None: |
| params['IpPermissions.1.ToPort'] = to_port |
| if cidr_ip: |
| params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip |
| return self.get_status('RevokeSecurityGroupIngress', |
| params, verb='POST') |
| |
| # |
| # Regions |
| # |
| |
| def get_all_regions(self, region_names=None, filters=None): |
| """ |
| Get all available regions for the EC2 service. |
| |
| :type region_names: list of str |
| :param region_names: Names of regions to limit output |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.regioninfo.RegionInfo` |
| """ |
| params = {} |
| if region_names: |
| self.build_list_params(params, region_names, 'RegionName') |
| if filters: |
| self.build_filter_params(params, filters) |
| regions = self.get_list('DescribeRegions', params, |
| [('item', RegionInfo)], verb='POST') |
| for region in regions: |
| region.connection_cls = EC2Connection |
| return regions |
| |
| # |
| # Reservation methods |
| # |
| |
| def get_all_reserved_instances_offerings(self, reserved_instances_id=None, |
| instance_type=None, |
| availability_zone=None, |
| product_description=None, |
| filters=None): |
| """ |
| Describes Reserved Instance offerings that are available for purchase. |
| |
| :type reserved_instances_id: str |
| :param reserved_instances_id: Displays Reserved Instances with the |
| specified offering IDs. |
| |
| :type instance_type: str |
| :param instance_type: Displays Reserved Instances of the specified |
| instance type. |
| |
| :type availability_zone: str |
| :param availability_zone: Displays Reserved Instances within the |
| specified Availability Zone. |
| |
| :type product_description: str |
| :param product_description: Displays Reserved Instances with the |
| specified product description. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.reservedinstance.ReservedInstancesOffering` |
| """ |
| params = {} |
| if reserved_instances_id: |
| params['ReservedInstancesId'] = reserved_instances_id |
| if instance_type: |
| params['InstanceType'] = instance_type |
| if availability_zone: |
| params['AvailabilityZone'] = availability_zone |
| if product_description: |
| params['ProductDescription'] = product_description |
| if filters: |
| self.build_filter_params(params, filters) |
| |
| return self.get_list('DescribeReservedInstancesOfferings', |
| params, [('item', ReservedInstancesOffering)], |
| verb='POST') |
| |
| def get_all_reserved_instances(self, reserved_instances_id=None, |
| filters=None): |
| """ |
| Describes Reserved Instance offerings that are available for purchase. |
| |
| :type reserved_instance_ids: list |
| :param reserved_instance_ids: A list of the reserved instance ids that |
| will be returned. If not provided, all |
| reserved instances will be returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.reservedinstance.ReservedInstance` |
| """ |
| params = {} |
| if reserved_instances_id: |
| self.build_list_params(params, reserved_instances_id, |
| 'ReservedInstancesId') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeReservedInstances', |
| params, [('item', ReservedInstance)], verb='POST') |
| |
| def purchase_reserved_instance_offering(self, |
| reserved_instances_offering_id, |
| instance_count=1): |
| """ |
| Purchase a Reserved Instance for use with your account. |
| ** CAUTION ** |
| This request can result in large amounts of money being charged to your |
| AWS account. Use with caution! |
| |
| :type reserved_instances_offering_id: string |
| :param reserved_instances_offering_id: The offering ID of the Reserved |
| Instance to purchase |
| |
| :type instance_count: int |
| :param instance_count: The number of Reserved Instances to purchase. |
| Default value is 1. |
| |
| :rtype: :class:`boto.ec2.reservedinstance.ReservedInstance` |
| :return: The newly created Reserved Instance |
| """ |
| params = { |
| 'ReservedInstancesOfferingId' : reserved_instances_offering_id, |
| 'InstanceCount' : instance_count} |
| return self.get_object('PurchaseReservedInstancesOffering', params, |
| ReservedInstance, verb='POST') |
| |
| # |
| # Monitoring |
| # |
| |
| def monitor_instances(self, instance_ids): |
| """ |
| Enable CloudWatch monitoring for the supplied instances. |
| |
| :type instance_id: list of strings |
| :param instance_id: The instance ids |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo` |
| """ |
| params = {} |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| return self.get_list('MonitorInstances', params, |
| [('item', InstanceInfo)], verb='POST') |
| |
| def monitor_instance(self, instance_id): |
| """ |
| Deprecated Version, maintained for backward compatibility. |
| Enable CloudWatch monitoring for the supplied instance. |
| |
| :type instance_id: string |
| :param instance_id: The instance id |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo` |
| """ |
| return self.monitor_instances([instance_id]) |
| |
| def unmonitor_instances(self, instance_ids): |
| """ |
| Disable CloudWatch monitoring for the supplied instance. |
| |
| :type instance_id: list of string |
| :param instance_id: The instance id |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo` |
| """ |
| params = {} |
| self.build_list_params(params, instance_ids, 'InstanceId') |
| return self.get_list('UnmonitorInstances', params, |
| [('item', InstanceInfo)], verb='POST') |
| |
| def unmonitor_instance(self, instance_id): |
| """ |
| Deprecated Version, maintained for backward compatibility. |
| Disable CloudWatch monitoring for the supplied instance. |
| |
| :type instance_id: string |
| :param instance_id: The instance id |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo` |
| """ |
| return self.unmonitor_instances([instance_id]) |
| |
| # |
| # Bundle Windows Instances |
| # |
| |
| def bundle_instance(self, instance_id, |
| s3_bucket, |
| s3_prefix, |
| s3_upload_policy): |
| """ |
| Bundle Windows instance. |
| |
| :type instance_id: string |
| :param instance_id: The instance id |
| |
| :type s3_bucket: string |
| :param s3_bucket: The bucket in which the AMI should be stored. |
| |
| :type s3_prefix: string |
| :param s3_prefix: The beginning of the file name for the AMI. |
| |
| :type s3_upload_policy: string |
| :param s3_upload_policy: Base64 encoded policy that specifies condition |
| and permissions for Amazon EC2 to upload the |
| user's image into Amazon S3. |
| """ |
| |
| params = {'InstanceId' : instance_id, |
| 'Storage.S3.Bucket' : s3_bucket, |
| 'Storage.S3.Prefix' : s3_prefix, |
| 'Storage.S3.UploadPolicy' : s3_upload_policy} |
| s3auth = boto.auth.get_auth_handler(None, boto.config, |
| self.provider, ['s3']) |
| params['Storage.S3.AWSAccessKeyId'] = self.aws_access_key_id |
| signature = s3auth.sign_string(s3_upload_policy) |
| params['Storage.S3.UploadPolicySignature'] = signature |
| return self.get_object('BundleInstance', params, |
| BundleInstanceTask, verb='POST') |
| |
| def get_all_bundle_tasks(self, bundle_ids=None, filters=None): |
| """ |
| Retrieve current bundling tasks. If no bundle id is specified, all |
| tasks are retrieved. |
| |
| :type bundle_ids: list |
| :param bundle_ids: A list of strings containing identifiers for |
| previously created bundling tasks. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| """ |
| |
| params = {} |
| if bundle_ids: |
| self.build_list_params(params, bundle_ids, 'BundleId') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeBundleTasks', params, |
| [('item', BundleInstanceTask)], verb='POST') |
| |
| def cancel_bundle_task(self, bundle_id): |
| """ |
| Cancel a previously submitted bundle task |
| |
| :type bundle_id: string |
| :param bundle_id: The identifier of the bundle task to cancel. |
| """ |
| |
| params = {'BundleId' : bundle_id} |
| return self.get_object('CancelBundleTask', params, |
| BundleInstanceTask, verb='POST') |
| |
| def get_password_data(self, instance_id): |
| """ |
| Get encrypted administrator password for a Windows instance. |
| |
| :type instance_id: string |
| :param instance_id: The identifier of the instance to retrieve the |
| password for. |
| """ |
| |
| params = {'InstanceId' : instance_id} |
| rs = self.get_object('GetPasswordData', params, ResultSet, verb='POST') |
| return rs.passwordData |
| |
| # |
| # Cluster Placement Groups |
| # |
| |
| def get_all_placement_groups(self, groupnames=None, filters=None): |
| """ |
| Get all placement groups associated with your account in a region. |
| |
| :type groupnames: list |
| :param groupnames: A list of the names of placement groups to retrieve. |
| If not provided, all placement groups will be |
| returned. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: list |
| :return: A list of :class:`boto.ec2.placementgroup.PlacementGroup` |
| """ |
| params = {} |
| if groupnames: |
| self.build_list_params(params, groupnames, 'GroupName') |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribePlacementGroups', params, |
| [('item', PlacementGroup)], verb='POST') |
| |
| def create_placement_group(self, name, strategy='cluster'): |
| """ |
| Create a new placement group for your account. |
| This will create the placement group within the region you |
| are currently connected to. |
| |
| :type name: string |
| :param name: The name of the new placement group |
| |
| :type strategy: string |
| :param strategy: The placement strategy of the new placement group. |
| Currently, the only acceptable value is "cluster". |
| |
| :rtype: bool |
| :return: True if successful |
| """ |
| params = {'GroupName':name, 'Strategy':strategy} |
| group = self.get_status('CreatePlacementGroup', params, verb='POST') |
| return group |
| |
| def delete_placement_group(self, name): |
| """ |
| Delete a placement group from your account. |
| |
| :type key_name: string |
| :param key_name: The name of the keypair to delete |
| """ |
| params = {'GroupName':name} |
| return self.get_status('DeletePlacementGroup', params, verb='POST') |
| |
| # Tag methods |
| |
| def build_tag_param_list(self, params, tags): |
| keys = tags.keys() |
| keys.sort() |
| i = 1 |
| for key in keys: |
| value = tags[key] |
| params['Tag.%d.Key'%i] = key |
| if value is not None: |
| params['Tag.%d.Value'%i] = value |
| i += 1 |
| |
| def get_all_tags(self, filters=None): |
| """ |
| Retrieve all the metadata tags associated with your account. |
| |
| :type filters: dict |
| :param filters: Optional filters that can be used to limit |
| the results returned. Filters are provided |
| in the form of a dictionary consisting of |
| filter names as the key and filter values |
| as the value. The set of allowable filter |
| names/values is dependent on the request |
| being performed. Check the EC2 API guide |
| for details. |
| |
| :rtype: dict |
| :return: A dictionary containing metadata tags |
| """ |
| params = {} |
| if filters: |
| self.build_filter_params(params, filters) |
| return self.get_list('DescribeTags', params, |
| [('item', Tag)], verb='POST') |
| |
| def create_tags(self, resource_ids, tags): |
| """ |
| Create new metadata tags for the specified resource ids. |
| |
| :type resource_ids: list |
| :param resource_ids: List of strings |
| |
| :type tags: dict |
| :param tags: A dictionary containing the name/value pairs. |
| If you want to create only a tag name, the |
| value for that tag should be the empty string |
| (e.g. ''). |
| |
| """ |
| params = {} |
| self.build_list_params(params, resource_ids, 'ResourceId') |
| self.build_tag_param_list(params, tags) |
| return self.get_status('CreateTags', params, verb='POST') |
| |
| def delete_tags(self, resource_ids, tags): |
| """ |
| Delete metadata tags for the specified resource ids. |
| |
| :type resource_ids: list |
| :param resource_ids: List of strings |
| |
| :type tags: dict or list |
| :param tags: Either a dictionary containing name/value pairs |
| or a list containing just tag names. |
| If you pass in a dictionary, the values must |
| match the actual tag values or the tag will |
| not be deleted. If you pass in a value of None |
| for the tag value, all tags with that name will |
| be deleted. |
| |
| """ |
| if isinstance(tags, list): |
| tags = {}.fromkeys(tags, None) |
| params = {} |
| self.build_list_params(params, resource_ids, 'ResourceId') |
| self.build_tag_param_list(params, tags) |
| return self.get_status('DeleteTags', params, verb='POST') |
| |