1# Copyright (c) 2006-2012 Mitch Garnaat http://garnaat.org/
2# Copyright (c) 2010, Eucalyptus Systems, Inc.
3# Copyright (c) 2013 Amazon.com, Inc. or its affiliates.  All Rights Reserved
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the
7# "Software"), to deal in the Software without restriction, including
8# without limitation the rights to use, copy, modify, merge, publish, dis-
9# tribute, sublicense, and/or sell copies of the Software, and to permit
10# persons to whom the Software is furnished to do so, subject to the fol-
11# lowing conditions:
12#
13# The above copyright notice and this permission notice shall be included
14# in all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
18# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23
24"""
25Represents a connection to the EC2 service.
26"""
27
28import base64
29import warnings
30from datetime import datetime
31from datetime import timedelta
32
33import boto
34from boto.auth import detect_potential_sigv4
35from boto.connection import AWSQueryConnection
36from boto.resultset import ResultSet
37from boto.ec2.image import Image, ImageAttribute, CopyImage
38from boto.ec2.instance import Reservation, Instance
39from boto.ec2.instance import ConsoleOutput, InstanceAttribute
40from boto.ec2.keypair import KeyPair
41from boto.ec2.address import Address
42from boto.ec2.volume import Volume, VolumeAttribute
43from boto.ec2.snapshot import Snapshot
44from boto.ec2.snapshot import SnapshotAttribute
45from boto.ec2.zone import Zone
46from boto.ec2.securitygroup import SecurityGroup
47from boto.ec2.regioninfo import RegionInfo
48from boto.ec2.instanceinfo import InstanceInfo
49from boto.ec2.reservedinstance import ReservedInstancesOffering
50from boto.ec2.reservedinstance import ReservedInstance
51from boto.ec2.reservedinstance import ReservedInstanceListing
52from boto.ec2.reservedinstance import ReservedInstancesConfiguration
53from boto.ec2.reservedinstance import ModifyReservedInstancesResult
54from boto.ec2.reservedinstance import ReservedInstancesModification
55from boto.ec2.spotinstancerequest import SpotInstanceRequest
56from boto.ec2.spotpricehistory import SpotPriceHistory
57from boto.ec2.spotdatafeedsubscription import SpotDatafeedSubscription
58from boto.ec2.bundleinstance import BundleInstanceTask
59from boto.ec2.placementgroup import PlacementGroup
60from boto.ec2.tag import Tag
61from boto.ec2.instancetype import InstanceType
62from boto.ec2.instancestatus import InstanceStatusSet
63from boto.ec2.volumestatus import VolumeStatusSet
64from boto.ec2.networkinterface import NetworkInterface
65from boto.ec2.attributes import AccountAttribute, VPCAttribute
66from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
67from boto.exception import EC2ResponseError
68from boto.compat import six
69
70#boto.set_stream_logger('ec2')
71
72
73class EC2Connection(AWSQueryConnection):
74
75    APIVersion = boto.config.get('Boto', 'ec2_version', '2014-10-01')
76    DefaultRegionName = boto.config.get('Boto', 'ec2_region_name', 'us-east-1')
77    DefaultRegionEndpoint = boto.config.get('Boto', 'ec2_region_endpoint',
78                                            'ec2.us-east-1.amazonaws.com')
79    ResponseError = EC2ResponseError
80
81    def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
82                 is_secure=True, host=None, port=None,
83                 proxy=None, proxy_port=None,
84                 proxy_user=None, proxy_pass=None, debug=0,
85                 https_connection_factory=None, region=None, path='/',
86                 api_version=None, security_token=None,
87                 validate_certs=True, profile_name=None):
88        """
89        Init method to create a new connection to EC2.
90        """
91        if not region:
92            region = RegionInfo(self, self.DefaultRegionName,
93                                self.DefaultRegionEndpoint)
94        self.region = region
95        super(EC2Connection, self).__init__(aws_access_key_id,
96                                            aws_secret_access_key,
97                                            is_secure, port, proxy, proxy_port,
98                                            proxy_user, proxy_pass,
99                                            self.region.endpoint, debug,
100                                            https_connection_factory, path,
101                                            security_token,
102                                            validate_certs=validate_certs,
103                                            profile_name=profile_name)
104        if api_version:
105            self.APIVersion = api_version
106
107    def _required_auth_capability(self):
108        return ['hmac-v4']
109
110    def get_params(self):
111        """
112        Returns a dictionary containing the value of all of the keyword
113        arguments passed when constructing this connection.
114        """
115        param_names = ['aws_access_key_id', 'aws_secret_access_key',
116                       'is_secure', 'port', 'proxy', 'proxy_port',
117                       'proxy_user', 'proxy_pass',
118                       'debug', 'https_connection_factory']
119        params = {}
120        for name in param_names:
121            params[name] = getattr(self, name)
122        return params
123
124    def build_filter_params(self, params, filters):
125        if not isinstance(filters, dict):
126            filters = dict(filters)
127
128        i = 1
129        for name in filters:
130            aws_name = name
131            if not aws_name.startswith('tag:'):
132                aws_name = name.replace('_', '-')
133            params['Filter.%d.Name' % i] = aws_name
134            value = filters[name]
135            if not isinstance(value, list):
136                value = [value]
137            j = 1
138            for v in value:
139                params['Filter.%d.Value.%d' % (i, j)] = v
140                j += 1
141            i += 1
142
143    # Image methods
144
145    def get_all_images(self, image_ids=None, owners=None,
146                       executable_by=None, filters=None, dry_run=False):
147        """
148        Retrieve all the EC2 images available on your account.
149
150        :type image_ids: list
151        :param image_ids: A list of strings with the image IDs wanted
152
153        :type owners: list
154        :param owners: A list of owner IDs, the special strings 'self',
155            'amazon', and 'aws-marketplace', may be used to describe
156            images owned by you, Amazon or AWS Marketplace
157            respectively
158
159        :type executable_by: list
160        :param executable_by: Returns AMIs for which the specified
161                              user ID has explicit launch permissions
162
163        :type filters: dict
164        :param filters: Optional filters that can be used to limit the
165            results returned.  Filters are provided in the form of a
166            dictionary consisting of filter names as the key and
167            filter values as the value.  The set of allowable filter
168            names/values is dependent on the request being performed.
169            Check the EC2 API guide for details.
170
171        :type dry_run: bool
172        :param dry_run: Set to True if the operation should not actually run.
173
174        :rtype: list
175        :return: A list of :class:`boto.ec2.image.Image`
176        """
177        params = {}
178        if image_ids:
179            self.build_list_params(params, image_ids, 'ImageId')
180        if owners:
181            self.build_list_params(params, owners, 'Owner')
182        if executable_by:
183            self.build_list_params(params, executable_by, 'ExecutableBy')
184        if filters:
185            self.build_filter_params(params, filters)
186        if dry_run:
187            params['DryRun'] = 'true'
188        return self.get_list('DescribeImages', params,
189                             [('item', Image)], verb='POST')
190
191    def get_all_kernels(self, kernel_ids=None, owners=None, dry_run=False):
192        """
193        Retrieve all the EC2 kernels available on your account.
194        Constructs a filter to allow the processing to happen server side.
195
196        :type kernel_ids: list
197        :param kernel_ids: A list of strings with the image IDs wanted
198
199        :type owners: list
200        :param owners: A list of owner IDs
201
202        :type dry_run: bool
203        :param dry_run: Set to True if the operation should not actually run.
204
205        :rtype: list
206        :return: A list of :class:`boto.ec2.image.Image`
207        """
208        params = {}
209        if kernel_ids:
210            self.build_list_params(params, kernel_ids, 'ImageId')
211        if owners:
212            self.build_list_params(params, owners, 'Owner')
213        filter = {'image-type': 'kernel'}
214        self.build_filter_params(params, filter)
215        if dry_run:
216            params['DryRun'] = 'true'
217        return self.get_list('DescribeImages', params,
218                             [('item', Image)], verb='POST')
219
220    def get_all_ramdisks(self, ramdisk_ids=None, owners=None, dry_run=False):
221        """
222        Retrieve all the EC2 ramdisks available on your account.
223        Constructs a filter to allow the processing to happen server side.
224
225        :type ramdisk_ids: list
226        :param ramdisk_ids: A list of strings with the image IDs wanted
227
228        :type owners: list
229        :param owners: A list of owner IDs
230
231        :type dry_run: bool
232        :param dry_run: Set to True if the operation should not actually run.
233
234        :rtype: list
235        :return: A list of :class:`boto.ec2.image.Image`
236        """
237        params = {}
238        if ramdisk_ids:
239            self.build_list_params(params, ramdisk_ids, 'ImageId')
240        if owners:
241            self.build_list_params(params, owners, 'Owner')
242        filter = {'image-type': 'ramdisk'}
243        self.build_filter_params(params, filter)
244        if dry_run:
245            params['DryRun'] = 'true'
246        return self.get_list('DescribeImages', params,
247                             [('item', Image)], verb='POST')
248
249    def get_image(self, image_id, dry_run=False):
250        """
251        Shortcut method to retrieve a specific image (AMI).
252
253        :type image_id: string
254        :param image_id: the ID of the Image to retrieve
255
256        :type dry_run: bool
257        :param dry_run: Set to True if the operation should not actually run.
258
259        :rtype: :class:`boto.ec2.image.Image`
260        :return: The EC2 Image specified or None if the image is not found
261        """
262        try:
263            return self.get_all_images(image_ids=[image_id], dry_run=dry_run)[0]
264        except IndexError:  # None of those images available
265            return None
266
267    def register_image(self, name=None, description=None, image_location=None,
268                       architecture=None, kernel_id=None, ramdisk_id=None,
269                       root_device_name=None, block_device_map=None,
270                       dry_run=False, virtualization_type=None,
271                       sriov_net_support=None,
272                       snapshot_id=None,
273                       delete_root_volume_on_termination=False):
274        """
275        Register an image.
276
277        :type name: string
278        :param name: The name of the AMI.  Valid only for EBS-based images.
279
280        :type description: string
281        :param description: The description of the AMI.
282
283        :type image_location: string
284        :param image_location: Full path to your AMI manifest in
285            Amazon S3 storage.  Only used for S3-based AMI's.
286
287        :type architecture: string
288        :param architecture: The architecture of the AMI.  Valid choices are:
289            * i386
290            * x86_64
291
292        :type kernel_id: string
293        :param kernel_id: The ID of the kernel with which to launch
294            the instances
295
296        :type root_device_name: string
297        :param root_device_name: The root device name (e.g. /dev/sdh)
298
299        :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
300        :param block_device_map: A BlockDeviceMapping data structure
301            describing the EBS volumes associated with the Image.
302
303        :type dry_run: bool
304        :param dry_run: Set to True if the operation should not actually run.
305
306        :type virtualization_type: string
307        :param virtualization_type: The virutalization_type of the image.
308            Valid choices are:
309            * paravirtual
310            * hvm
311
312        :type sriov_net_support: string
313        :param sriov_net_support: Advanced networking support.
314            Valid choices are:
315            * simple
316
317        :type snapshot_id: string
318        :param snapshot_id: A snapshot ID for the snapshot to be used
319            as root device for the image. Mutually exclusive with
320            block_device_map, requires root_device_name
321
322        :type delete_root_volume_on_termination: bool
323        :param delete_root_volume_on_termination: Whether to delete the root
324            volume of the image after instance termination. Only applies when
325            creating image from snapshot_id. Defaults to False.  Note that
326            leaving volumes behind after instance termination is not free.
327
328        :rtype: string
329        :return: The new image id
330        """
331        params = {}
332        if name:
333            params['Name'] = name
334        if description:
335            params['Description'] = description
336        if architecture:
337            params['Architecture'] = architecture
338        if kernel_id:
339            params['KernelId'] = kernel_id
340        if ramdisk_id:
341            params['RamdiskId'] = ramdisk_id
342        if image_location:
343            params['ImageLocation'] = image_location
344        if root_device_name:
345            params['RootDeviceName'] = root_device_name
346        if snapshot_id:
347            root_vol = BlockDeviceType(snapshot_id=snapshot_id,
348                delete_on_termination=delete_root_volume_on_termination)
349            block_device_map = BlockDeviceMapping()
350            block_device_map[root_device_name] = root_vol
351        if block_device_map:
352            block_device_map.ec2_build_list_params(params)
353        if dry_run:
354            params['DryRun'] = 'true'
355        if virtualization_type:
356            params['VirtualizationType'] = virtualization_type
357        if sriov_net_support:
358            params['SriovNetSupport'] = sriov_net_support
359
360        rs = self.get_object('RegisterImage', params, ResultSet, verb='POST')
361        image_id = getattr(rs, 'imageId', None)
362        return image_id
363
364    def deregister_image(self, image_id, delete_snapshot=False, dry_run=False):
365        """
366        Unregister an AMI.
367
368        :type image_id: string
369        :param image_id: the ID of the Image to unregister
370
371        :type delete_snapshot: bool
372        :param delete_snapshot: Set to True if we should delete the
373            snapshot associated with an EBS volume mounted at /dev/sda1
374
375        :type dry_run: bool
376        :param dry_run: Set to True if the operation should not actually run.
377
378        :rtype: bool
379        :return: True if successful
380        """
381        snapshot_id = None
382        if delete_snapshot:
383            image = self.get_image(image_id)
384            for key in image.block_device_mapping:
385                if key == "/dev/sda1":
386                    snapshot_id = image.block_device_mapping[key].snapshot_id
387                    break
388        params = {
389            'ImageId': image_id,
390        }
391        if dry_run:
392            params['DryRun'] = 'true'
393        result = self.get_status('DeregisterImage',
394                                 params, verb='POST')
395        if result and snapshot_id:
396            return result and self.delete_snapshot(snapshot_id)
397        return result
398
399    def create_image(self, instance_id, name,
400                     description=None, no_reboot=False,
401                     block_device_mapping=None, dry_run=False):
402        """
403        Will create an AMI from the instance in the running or stopped
404        state.
405
406        :type instance_id: string
407        :param instance_id: the ID of the instance to image.
408
409        :type name: string
410        :param name: The name of the new image
411
412        :type description: string
413        :param description: An optional human-readable string describing
414            the contents and purpose of the AMI.
415
416        :type no_reboot: bool
417        :param no_reboot: An optional flag indicating that the
418            bundling process should not attempt to shutdown the
419            instance before bundling.  If this flag is True, the
420            responsibility of maintaining file system integrity is
421            left to the owner of the instance.
422
423        :type block_device_mapping: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
424        :param block_device_mapping: A BlockDeviceMapping data structure
425            describing the EBS volumes associated with the Image.
426
427        :type dry_run: bool
428        :param dry_run: Set to True if the operation should not actually run.
429
430        :rtype: string
431        :return: The new image id
432        """
433        params = {'InstanceId': instance_id,
434                  'Name': name}
435        if description:
436            params['Description'] = description
437        if no_reboot:
438            params['NoReboot'] = 'true'
439        if block_device_mapping:
440            block_device_mapping.ec2_build_list_params(params)
441        if dry_run:
442            params['DryRun'] = 'true'
443        img = self.get_object('CreateImage', params, Image, verb='POST')
444        return img.id
445
446    # ImageAttribute methods
447
448    def get_image_attribute(self, image_id, attribute='launchPermission',
449                            dry_run=False):
450        """
451        Gets an attribute from an image.
452
453        :type image_id: string
454        :param image_id: The Amazon image id for which you want info about
455
456        :type attribute: string
457        :param attribute: The attribute you need information about.
458            Valid choices are:
459            * launchPermission
460            * productCodes
461            * blockDeviceMapping
462
463        :type dry_run: bool
464        :param dry_run: Set to True if the operation should not actually run.
465
466        :rtype: :class:`boto.ec2.image.ImageAttribute`
467        :return: An ImageAttribute object representing the value of the
468                 attribute requested
469        """
470        params = {'ImageId': image_id,
471                  'Attribute': attribute}
472        if dry_run:
473            params['DryRun'] = 'true'
474        return self.get_object('DescribeImageAttribute', params,
475                               ImageAttribute, verb='POST')
476
477    def modify_image_attribute(self, image_id, attribute='launchPermission',
478                               operation='add', user_ids=None, groups=None,
479                               product_codes=None, dry_run=False):
480        """
481        Changes an attribute of an image.
482
483        :type image_id: string
484        :param image_id: The image id you wish to change
485
486        :type attribute: string
487        :param attribute: The attribute you wish to change
488
489        :type operation: string
490        :param operation: Either add or remove (this is required for changing
491            launchPermissions)
492
493        :type user_ids: list
494        :param user_ids: The Amazon IDs of users to add/remove attributes
495
496        :type groups: list
497        :param groups: The groups to add/remove attributes
498
499        :type product_codes: list
500        :param product_codes: Amazon DevPay product code. Currently only one
501            product code can be associated with an AMI. Once
502            set, the product code cannot be changed or reset.
503
504        :type dry_run: bool
505        :param dry_run: Set to True if the operation should not actually run.
506
507        """
508        params = {'ImageId': image_id,
509                  'Attribute': attribute,
510                  'OperationType': operation}
511        if user_ids:
512            self.build_list_params(params, user_ids, 'UserId')
513        if groups:
514            self.build_list_params(params, groups, 'UserGroup')
515        if product_codes:
516            self.build_list_params(params, product_codes, 'ProductCode')
517        if dry_run:
518            params['DryRun'] = 'true'
519        return self.get_status('ModifyImageAttribute', params, verb='POST')
520
521    def reset_image_attribute(self, image_id, attribute='launchPermission',
522                              dry_run=False):
523        """
524        Resets an attribute of an AMI to its default value.
525
526        :type image_id: string
527        :param image_id: ID of the AMI for which an attribute will be described
528
529        :type attribute: string
530        :param attribute: The attribute to reset
531
532        :type dry_run: bool
533        :param dry_run: Set to True if the operation should not actually run.
534
535        :rtype: bool
536        :return: Whether the operation succeeded or not
537        """
538        params = {'ImageId': image_id,
539                  'Attribute': attribute}
540        if dry_run:
541            params['DryRun'] = 'true'
542        return self.get_status('ResetImageAttribute', params, verb='POST')
543
544    # Instance methods
545
546    def get_all_instances(self, instance_ids=None, filters=None, dry_run=False,
547                          max_results=None):
548        """
549        Retrieve all the instance reservations associated with your account.
550
551        .. note::
552        This method's current behavior is deprecated in favor of
553        :meth:`get_all_reservations`.  A future major release will change
554        :meth:`get_all_instances` to return a list of
555        :class:`boto.ec2.instance.Instance` objects as its name suggests.
556        To obtain that behavior today, use :meth:`get_only_instances`.
557
558        :type instance_ids: list
559        :param instance_ids: A list of strings of instance IDs
560
561        :type filters: dict
562        :param filters: Optional filters that can be used to limit the
563            results returned.  Filters are provided in the form of a
564            dictionary consisting of filter names as the key and
565            filter values as the value.  The set of allowable filter
566            names/values is dependent on the request being performed.
567            Check the EC2 API guide for details.
568
569        :type dry_run: bool
570        :param dry_run: Set to True if the operation should not actually run.
571
572        :type max_results: int
573        :param max_results: The maximum number of paginated instance
574            items per response.
575
576        :rtype: list
577        :return: A list of  :class:`boto.ec2.instance.Reservation`
578
579        """
580        warnings.warn(('The current get_all_instances implementation will be '
581                       'replaced with get_all_reservations.'),
582                      PendingDeprecationWarning)
583        return self.get_all_reservations(instance_ids=instance_ids,
584                                         filters=filters, dry_run=dry_run,
585                                         max_results=max_results)
586
587    def get_only_instances(self, instance_ids=None, filters=None,
588                           dry_run=False, max_results=None):
589        # A future release should rename this method to get_all_instances
590        # and make get_only_instances an alias for that.
591        """
592        Retrieve all the instances associated with your account.
593
594        :type instance_ids: list
595        :param instance_ids: A list of strings of instance IDs
596
597        :type filters: dict
598        :param filters: Optional filters that can be used to limit the
599            results returned.  Filters are provided in the form of a
600            dictionary consisting of filter names as the key and
601            filter values as the value.  The set of allowable filter
602            names/values is dependent on the request being performed.
603            Check the EC2 API guide for details.
604
605        :type dry_run: bool
606        :param dry_run: Set to True if the operation should not actually run.
607
608        :type max_results: int
609        :param max_results: The maximum number of paginated instance
610            items per response.
611
612        :rtype: list
613        :return: A list of  :class:`boto.ec2.instance.Instance`
614        """
615        next_token = None
616        retval = []
617        while True:
618            reservations = self.get_all_reservations(instance_ids=instance_ids,
619                                                     filters=filters,
620                                                     dry_run=dry_run,
621                                                     max_results=max_results,
622                                                     next_token=next_token)
623            retval.extend([instance for reservation in reservations for
624                           instance in reservation.instances])
625            next_token = reservations.next_token
626            if not next_token:
627                break
628
629        return retval
630
631    def get_all_reservations(self, instance_ids=None, filters=None,
632                             dry_run=False, max_results=None, next_token=None):
633        """
634        Retrieve all the instance reservations associated with your account.
635
636        :type instance_ids: list
637        :param instance_ids: A list of strings of instance IDs
638
639        :type filters: dict
640        :param filters: Optional filters that can be used to limit the
641            results returned.  Filters are provided in the form of a
642            dictionary consisting of filter names as the key and
643            filter values as the value.  The set of allowable filter
644            names/values is dependent on the request being performed.
645            Check the EC2 API guide for details.
646
647        :type dry_run: bool
648        :param dry_run: Set to True if the operation should not actually run.
649
650        :type max_results: int
651        :param max_results: The maximum number of paginated instance
652            items per response.
653
654        :type next_token: str
655        :param next_token: A string specifying the next paginated set
656            of results to return.
657
658        :rtype: list
659        :return: A list of  :class:`boto.ec2.instance.Reservation`
660        """
661        params = {}
662        if instance_ids:
663            self.build_list_params(params, instance_ids, 'InstanceId')
664        if filters:
665            if 'group-id' in filters:
666                gid = filters.get('group-id')
667                if not gid.startswith('sg-') or len(gid) != 11:
668                    warnings.warn(
669                        "The group-id filter now requires a security group "
670                        "identifier (sg-*) instead of a group name. To filter "
671                        "by group name use the 'group-name' filter instead.",
672                        UserWarning)
673            self.build_filter_params(params, filters)
674        if dry_run:
675            params['DryRun'] = 'true'
676        if max_results is not None:
677            params['MaxResults'] = max_results
678        if next_token:
679            params['NextToken'] = next_token
680        return self.get_list('DescribeInstances', params,
681                             [('item', Reservation)], verb='POST')
682
683    def get_all_instance_status(self, instance_ids=None,
684                                max_results=None, next_token=None,
685                                filters=None, dry_run=False,
686                                include_all_instances=False):
687        """
688        Retrieve all the instances in your account scheduled for maintenance.
689
690        :type instance_ids: list
691        :param instance_ids: A list of strings of instance IDs
692
693        :type max_results: int
694        :param max_results: The maximum number of paginated instance
695            items per response.
696
697        :type next_token: str
698        :param next_token: A string specifying the next paginated set
699            of results to return.
700
701        :type filters: dict
702        :param filters: Optional filters that can be used to limit
703            the results returned.  Filters are provided
704            in the form of a dictionary consisting of
705            filter names as the key and filter values
706            as the value.  The set of allowable filter
707            names/values is dependent on the request
708            being performed.  Check the EC2 API guide
709            for details.
710
711        :type dry_run: bool
712        :param dry_run: Set to True if the operation should not actually run.
713
714        :type include_all_instances: bool
715        :param include_all_instances: Set to True if all
716            instances should be returned. (Only running
717            instances are included by default.)
718
719        :rtype: list
720        :return: A list of instances that have maintenance scheduled.
721        """
722        params = {}
723        if instance_ids:
724            self.build_list_params(params, instance_ids, 'InstanceId')
725        if max_results:
726            params['MaxResults'] = max_results
727        if next_token:
728            params['NextToken'] = next_token
729        if filters:
730            self.build_filter_params(params, filters)
731        if dry_run:
732            params['DryRun'] = 'true'
733        if include_all_instances:
734            params['IncludeAllInstances'] = 'true'
735        return self.get_object('DescribeInstanceStatus', params,
736                               InstanceStatusSet, verb='POST')
737
738    def run_instances(self, image_id, min_count=1, max_count=1,
739                      key_name=None, security_groups=None,
740                      user_data=None, addressing_type=None,
741                      instance_type='m1.small', placement=None,
742                      kernel_id=None, ramdisk_id=None,
743                      monitoring_enabled=False, subnet_id=None,
744                      block_device_map=None,
745                      disable_api_termination=False,
746                      instance_initiated_shutdown_behavior=None,
747                      private_ip_address=None,
748                      placement_group=None, client_token=None,
749                      security_group_ids=None,
750                      additional_info=None, instance_profile_name=None,
751                      instance_profile_arn=None, tenancy=None,
752                      ebs_optimized=False, network_interfaces=None,
753                      dry_run=False):
754        """
755        Runs an image on EC2.
756
757        :type image_id: string
758        :param image_id: The ID of the image to run.
759
760        :type min_count: int
761        :param min_count: The minimum number of instances to launch.
762
763        :type max_count: int
764        :param max_count: The maximum number of instances to launch.
765
766        :type key_name: string
767        :param key_name: The name of the key pair with which to
768            launch instances.
769
770        :type security_groups: list of strings
771        :param security_groups: The names of the EC2 classic security groups
772            with which to associate instances
773
774        :type user_data: string
775        :param user_data: The Base64-encoded MIME user data to be made
776            available to the instance(s) in this reservation.
777
778        :type instance_type: string
779        :param instance_type: The type of instance to run:
780
781            * t1.micro
782            * m1.small
783            * m1.medium
784            * m1.large
785            * m1.xlarge
786            * m3.medium
787            * m3.large
788            * m3.xlarge
789            * m3.2xlarge
790            * c1.medium
791            * c1.xlarge
792            * m2.xlarge
793            * m2.2xlarge
794            * m2.4xlarge
795            * cr1.8xlarge
796            * hi1.4xlarge
797            * hs1.8xlarge
798            * cc1.4xlarge
799            * cg1.4xlarge
800            * cc2.8xlarge
801            * g2.2xlarge
802            * c3.large
803            * c3.xlarge
804            * c3.2xlarge
805            * c3.4xlarge
806            * c3.8xlarge
807            * i2.xlarge
808            * i2.2xlarge
809            * i2.4xlarge
810            * i2.8xlarge
811            * t2.micro
812            * t2.small
813            * t2.medium
814
815        :type placement: string
816        :param placement: The Availability Zone to launch the instance into.
817
818        :type kernel_id: string
819        :param kernel_id: The ID of the kernel with which to launch the
820            instances.
821
822        :type ramdisk_id: string
823        :param ramdisk_id: The ID of the RAM disk with which to launch the
824            instances.
825
826        :type monitoring_enabled: bool
827        :param monitoring_enabled: Enable detailed CloudWatch monitoring on
828            the instance.
829
830        :type subnet_id: string
831        :param subnet_id: The subnet ID within which to launch the instances
832            for VPC.
833
834        :type private_ip_address: string
835        :param private_ip_address: If you're using VPC, you can
836            optionally use this parameter to assign the instance a
837            specific available IP address from the subnet (e.g.,
838            10.0.0.25).
839
840        :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
841        :param block_device_map: A BlockDeviceMapping data structure
842            describing the EBS volumes associated with the Image.
843
844        :type disable_api_termination: bool
845        :param disable_api_termination: If True, the instances will be locked
846            and will not be able to be terminated via the API.
847
848        :type instance_initiated_shutdown_behavior: string
849        :param instance_initiated_shutdown_behavior: Specifies whether the
850            instance stops or terminates on instance-initiated shutdown.
851            Valid values are:
852
853            * stop
854            * terminate
855
856        :type placement_group: string
857        :param placement_group: If specified, this is the name of the placement
858            group in which the instance(s) will be launched.
859
860        :type client_token: string
861        :param client_token: Unique, case-sensitive identifier you provide
862            to ensure idempotency of the request. Maximum 64 ASCII characters.
863
864        :type security_group_ids: list of strings
865        :param security_group_ids: The ID of the VPC security groups with
866            which to associate instances.
867
868        :type additional_info: string
869        :param additional_info: Specifies additional information to make
870            available to the instance(s).
871
872        :type tenancy: string
873        :param tenancy: The tenancy of the instance you want to
874            launch. An instance with a tenancy of 'dedicated' runs on
875            single-tenant hardware and can only be launched into a
876            VPC. Valid values are:"default" or "dedicated".
877            NOTE: To use dedicated tenancy you MUST specify a VPC
878            subnet-ID as well.
879
880        :type instance_profile_arn: string
881        :param instance_profile_arn: The Amazon resource name (ARN) of
882            the IAM Instance Profile (IIP) to associate with the instances.
883
884        :type instance_profile_name: string
885        :param instance_profile_name: The name of
886            the IAM Instance Profile (IIP) to associate with the instances.
887
888        :type ebs_optimized: bool
889        :param ebs_optimized: Whether the instance is optimized for
890            EBS I/O.  This optimization provides dedicated throughput
891            to Amazon EBS and an optimized configuration stack to
892            provide optimal EBS I/O performance.  This optimization
893            isn't available with all instance types.
894
895        :type network_interfaces: :class:`boto.ec2.networkinterface.NetworkInterfaceCollection`
896        :param network_interfaces: A NetworkInterfaceCollection data
897            structure containing the ENI specifications for the instance.
898
899        :type dry_run: bool
900        :param dry_run: Set to True if the operation should not actually run.
901
902        :rtype: Reservation
903        :return: The :class:`boto.ec2.instance.Reservation` associated with
904                 the request for machines
905        """
906        params = {'ImageId': image_id,
907                  'MinCount': min_count,
908                  'MaxCount': max_count}
909        if key_name:
910            params['KeyName'] = key_name
911        if security_group_ids:
912            l = []
913            for group in security_group_ids:
914                if isinstance(group, SecurityGroup):
915                    l.append(group.id)
916                else:
917                    l.append(group)
918            self.build_list_params(params, l, 'SecurityGroupId')
919        if security_groups:
920            l = []
921            for group in security_groups:
922                if isinstance(group, SecurityGroup):
923                    l.append(group.name)
924                else:
925                    l.append(group)
926            self.build_list_params(params, l, 'SecurityGroup')
927        if user_data:
928            if isinstance(user_data, six.text_type):
929                user_data = user_data.encode('utf-8')
930            params['UserData'] = base64.b64encode(user_data).decode('utf-8')
931        if addressing_type:
932            params['AddressingType'] = addressing_type
933        if instance_type:
934            params['InstanceType'] = instance_type
935        if placement:
936            params['Placement.AvailabilityZone'] = placement
937        if placement_group:
938            params['Placement.GroupName'] = placement_group
939        if tenancy:
940            params['Placement.Tenancy'] = tenancy
941        if kernel_id:
942            params['KernelId'] = kernel_id
943        if ramdisk_id:
944            params['RamdiskId'] = ramdisk_id
945        if monitoring_enabled:
946            params['Monitoring.Enabled'] = 'true'
947        if subnet_id:
948            params['SubnetId'] = subnet_id
949        if private_ip_address:
950            params['PrivateIpAddress'] = private_ip_address
951        if block_device_map:
952            block_device_map.ec2_build_list_params(params)
953        if disable_api_termination:
954            params['DisableApiTermination'] = 'true'
955        if instance_initiated_shutdown_behavior:
956            val = instance_initiated_shutdown_behavior
957            params['InstanceInitiatedShutdownBehavior'] = val
958        if client_token:
959            params['ClientToken'] = client_token
960        if additional_info:
961            params['AdditionalInfo'] = additional_info
962        if instance_profile_name:
963            params['IamInstanceProfile.Name'] = instance_profile_name
964        if instance_profile_arn:
965            params['IamInstanceProfile.Arn'] = instance_profile_arn
966        if ebs_optimized:
967            params['EbsOptimized'] = 'true'
968        if network_interfaces:
969            network_interfaces.build_list_params(params)
970        if dry_run:
971            params['DryRun'] = 'true'
972        return self.get_object('RunInstances', params, Reservation,
973                               verb='POST')
974
975    def terminate_instances(self, instance_ids=None, dry_run=False):
976        """
977        Terminate the instances specified
978
979        :type instance_ids: list
980        :param instance_ids: A list of strings of the Instance IDs to terminate
981
982        :type dry_run: bool
983        :param dry_run: Set to True if the operation should not actually run.
984
985        :rtype: list
986        :return: A list of the instances terminated
987        """
988        params = {}
989        if instance_ids:
990            self.build_list_params(params, instance_ids, 'InstanceId')
991        if dry_run:
992            params['DryRun'] = 'true'
993        return self.get_list('TerminateInstances', params,
994                             [('item', Instance)], verb='POST')
995
996    def stop_instances(self, instance_ids=None, force=False, dry_run=False):
997        """
998        Stop the instances specified
999
1000        :type instance_ids: list
1001        :param instance_ids: A list of strings of the Instance IDs to stop
1002
1003        :type force: bool
1004        :param force: Forces the instance to stop
1005
1006        :type dry_run: bool
1007        :param dry_run: Set to True if the operation should not actually run.
1008
1009        :rtype: list
1010        :return: A list of the instances stopped
1011        """
1012        params = {}
1013        if force:
1014            params['Force'] = 'true'
1015        if instance_ids:
1016            self.build_list_params(params, instance_ids, 'InstanceId')
1017        if dry_run:
1018            params['DryRun'] = 'true'
1019        return self.get_list('StopInstances', params,
1020                             [('item', Instance)], verb='POST')
1021
1022    def start_instances(self, instance_ids=None, dry_run=False):
1023        """
1024        Start the instances specified
1025
1026        :type instance_ids: list
1027        :param instance_ids: A list of strings of the Instance IDs to start
1028
1029        :type dry_run: bool
1030        :param dry_run: Set to True if the operation should not actually run.
1031
1032        :rtype: list
1033        :return: A list of the instances started
1034        """
1035        params = {}
1036        if instance_ids:
1037            self.build_list_params(params, instance_ids, 'InstanceId')
1038        if dry_run:
1039            params['DryRun'] = 'true'
1040        return self.get_list('StartInstances', params,
1041                             [('item', Instance)], verb='POST')
1042
1043    def get_console_output(self, instance_id, dry_run=False):
1044        """
1045        Retrieves the console output for the specified instance.
1046
1047        :type instance_id: string
1048        :param instance_id: The instance ID of a running instance on the cloud.
1049
1050        :type dry_run: bool
1051        :param dry_run: Set to True if the operation should not actually run.
1052
1053        :rtype: :class:`boto.ec2.instance.ConsoleOutput`
1054        :return: The console output as a ConsoleOutput object
1055        """
1056        params = {}
1057        self.build_list_params(params, [instance_id], 'InstanceId')
1058        if dry_run:
1059            params['DryRun'] = 'true'
1060        return self.get_object('GetConsoleOutput', params,
1061                               ConsoleOutput, verb='POST')
1062
1063    def reboot_instances(self, instance_ids=None, dry_run=False):
1064        """
1065        Reboot the specified instances.
1066
1067        :type instance_ids: list
1068        :param instance_ids: The instances to terminate and reboot
1069
1070        :type dry_run: bool
1071        :param dry_run: Set to True if the operation should not actually run.
1072
1073        """
1074        params = {}
1075        if instance_ids:
1076            self.build_list_params(params, instance_ids, 'InstanceId')
1077        if dry_run:
1078            params['DryRun'] = 'true'
1079        return self.get_status('RebootInstances', params)
1080
1081    def confirm_product_instance(self, product_code, instance_id,
1082                                 dry_run=False):
1083        """
1084        :type dry_run: bool
1085        :param dry_run: Set to True if the operation should not actually run.
1086
1087        """
1088        params = {'ProductCode': product_code,
1089                  'InstanceId': instance_id}
1090        if dry_run:
1091            params['DryRun'] = 'true'
1092        rs = self.get_object('ConfirmProductInstance', params,
1093                             ResultSet, verb='POST')
1094        return (rs.status, rs.ownerId)
1095
1096    # InstanceAttribute methods
1097
1098    def get_instance_attribute(self, instance_id, attribute, dry_run=False):
1099        """
1100        Gets an attribute from an instance.
1101
1102        :type instance_id: string
1103        :param instance_id: The Amazon id of the instance
1104
1105        :type attribute: string
1106        :param attribute: The attribute you need information about
1107            Valid choices are:
1108
1109            * instanceType
1110            * kernel
1111            * ramdisk
1112            * userData
1113            * disableApiTermination
1114            * instanceInitiatedShutdownBehavior
1115            * rootDeviceName
1116            * blockDeviceMapping
1117            * productCodes
1118            * sourceDestCheck
1119            * groupSet
1120            * ebsOptimized
1121            * sriovNetSupport
1122
1123        :type dry_run: bool
1124        :param dry_run: Set to True if the operation should not actually run.
1125
1126        :rtype: :class:`boto.ec2.image.InstanceAttribute`
1127        :return: An InstanceAttribute object representing the value of the
1128                 attribute requested
1129        """
1130        params = {'InstanceId': instance_id}
1131        if attribute:
1132            params['Attribute'] = attribute
1133        if dry_run:
1134            params['DryRun'] = 'true'
1135        return self.get_object('DescribeInstanceAttribute', params,
1136                               InstanceAttribute, verb='POST')
1137
1138    def modify_network_interface_attribute(self, interface_id, attr, value,
1139                                           attachment_id=None, dry_run=False):
1140        """
1141        Changes an attribute of a network interface.
1142
1143        :type interface_id: string
1144        :param interface_id: The interface id. Looks like 'eni-xxxxxxxx'
1145
1146        :type attr: string
1147        :param attr: The attribute you wish to change.
1148
1149            Learn more at http://docs.aws.amazon.com/AWSEC2/latest/API\
1150            Reference/ApiReference-query-ModifyNetworkInterfaceAttribute.html
1151
1152            * description - Textual description of interface
1153            * groupSet - List of security group ids or group objects
1154            * sourceDestCheck - Boolean
1155            * deleteOnTermination - Boolean. Must also specify attachment_id
1156
1157        :type value: string
1158        :param value: The new value for the attribute
1159
1160        :rtype: bool
1161        :return: Whether the operation succeeded or not
1162
1163        :type attachment_id: string
1164        :param attachment_id: If you're modifying DeleteOnTermination you must
1165            specify the attachment_id.
1166
1167        :type dry_run: bool
1168        :param dry_run: Set to True if the operation should not actually run.
1169
1170        """
1171        bool_reqs = (
1172            'deleteontermination',
1173            'sourcedestcheck',
1174        )
1175        if attr.lower() in bool_reqs:
1176            if isinstance(value, bool):
1177                if value:
1178                    value = 'true'
1179                else:
1180                    value = 'false'
1181            elif value not in ['true', 'false']:
1182                raise ValueError('%s must be a boolean, "true", or "false"!'
1183                                 % attr)
1184
1185        params = {'NetworkInterfaceId': interface_id}
1186
1187        # groupSet is handled differently from other arguments
1188        if attr.lower() == 'groupset':
1189            for idx, sg in enumerate(value):
1190                if isinstance(sg, SecurityGroup):
1191                    sg = sg.id
1192                params['SecurityGroupId.%s' % (idx + 1)] = sg
1193        elif attr.lower() == 'description':
1194            params['Description.Value'] = value
1195        elif attr.lower() == 'sourcedestcheck':
1196            params['SourceDestCheck.Value'] = value
1197        elif attr.lower() == 'deleteontermination':
1198            params['Attachment.DeleteOnTermination'] = value
1199            if not attachment_id:
1200                raise ValueError('You must also specify an attachment_id')
1201            params['Attachment.AttachmentId'] = attachment_id
1202        else:
1203            raise ValueError('Unknown attribute "%s"' % (attr,))
1204
1205        if dry_run:
1206            params['DryRun'] = 'true'
1207        return self.get_status(
1208            'ModifyNetworkInterfaceAttribute', params, verb='POST')
1209
1210    def modify_instance_attribute(self, instance_id, attribute, value,
1211                                  dry_run=False):
1212        """
1213        Changes an attribute of an instance
1214
1215        :type instance_id: string
1216        :param instance_id: The instance id you wish to change
1217
1218        :type attribute: string
1219        :param attribute: The attribute you wish to change.
1220
1221            * instanceType - A valid instance type (m1.small)
1222            * kernel - Kernel ID (None)
1223            * ramdisk - Ramdisk ID (None)
1224            * userData - Base64 encoded String (None)
1225            * disableApiTermination - Boolean (true)
1226            * instanceInitiatedShutdownBehavior - stop|terminate
1227            * blockDeviceMapping - List of strings - ie: ['/dev/sda=false']
1228            * sourceDestCheck - Boolean (true)
1229            * groupSet - Set of Security Groups or IDs
1230            * ebsOptimized - Boolean (false)
1231            * sriovNetSupport - String - ie: 'simple'
1232
1233        :type value: string
1234        :param value: The new value for the attribute
1235
1236        :type dry_run: bool
1237        :param dry_run: Set to True if the operation should not actually run.
1238
1239        :rtype: bool
1240        :return: Whether the operation succeeded or not
1241        """
1242        # Allow a bool to be passed in for value of disableApiTermination
1243        bool_reqs = ('disableapitermination',
1244                     'sourcedestcheck',
1245                     'ebsoptimized')
1246        if attribute.lower() in bool_reqs:
1247            if isinstance(value, bool):
1248                if value:
1249                    value = 'true'
1250                else:
1251                    value = 'false'
1252
1253        params = {'InstanceId': instance_id}
1254
1255        # groupSet is handled differently from other arguments
1256        if attribute.lower() == 'groupset':
1257            for idx, sg in enumerate(value):
1258                if isinstance(sg, SecurityGroup):
1259                    sg = sg.id
1260                params['GroupId.%s' % (idx + 1)] = sg
1261        elif attribute.lower() == 'blockdevicemapping':
1262            for idx, kv in enumerate(value):
1263                dev_name, _, flag = kv.partition('=')
1264                pre = 'BlockDeviceMapping.%d' % (idx + 1)
1265                params['%s.DeviceName' % pre] = dev_name
1266                params['%s.Ebs.DeleteOnTermination' % pre] = flag or 'true'
1267        else:
1268            # for backwards compatibility handle lowercase first letter
1269            attribute = attribute[0].upper() + attribute[1:]
1270            params['%s.Value' % attribute] = value
1271
1272        if dry_run:
1273            params['DryRun'] = 'true'
1274        return self.get_status('ModifyInstanceAttribute', params, verb='POST')
1275
1276    def reset_instance_attribute(self, instance_id, attribute, dry_run=False):
1277        """
1278        Resets an attribute of an instance to its default value.
1279
1280        :type instance_id: string
1281        :param instance_id: ID of the instance
1282
1283        :type attribute: string
1284        :param attribute: The attribute to reset. Valid values are:
1285                          kernel|ramdisk
1286
1287        :type dry_run: bool
1288        :param dry_run: Set to True if the operation should not actually run.
1289
1290        :rtype: bool
1291        :return: Whether the operation succeeded or not
1292        """
1293        params = {'InstanceId': instance_id,
1294                  'Attribute': attribute}
1295        if dry_run:
1296            params['DryRun'] = 'true'
1297        return self.get_status('ResetInstanceAttribute', params, verb='POST')
1298
1299    # Spot Instances
1300
1301    def get_all_spot_instance_requests(self, request_ids=None,
1302                                       filters=None, dry_run=False):
1303        """
1304        Retrieve all the spot instances requests associated with your account.
1305
1306        :type request_ids: list
1307        :param request_ids: A list of strings of spot instance request IDs
1308
1309        :type filters: dict
1310        :param filters: Optional filters that can be used to limit the
1311            results returned.  Filters are provided in the form of a
1312            dictionary consisting of filter names as the key and
1313            filter values as the value.  The set of allowable filter
1314            names/values is dependent on the request being performed.
1315            Check the EC2 API guide for details.
1316
1317        :type dry_run: bool
1318        :param dry_run: Set to True if the operation should not actually run.
1319
1320        :rtype: list
1321        :return: A list of
1322                 :class:`boto.ec2.spotinstancerequest.SpotInstanceRequest`
1323        """
1324        params = {}
1325        if request_ids:
1326            self.build_list_params(params, request_ids, 'SpotInstanceRequestId')
1327        if filters:
1328            if 'launch.group-id' in filters:
1329                lgid = filters.get('launch.group-id')
1330                if not lgid.startswith('sg-') or len(lgid) != 11:
1331                    warnings.warn(
1332                        "The 'launch.group-id' filter now requires a security "
1333                        "group id (sg-*) and no longer supports filtering by "
1334                        "group name. Please update your filters accordingly.",
1335                        UserWarning)
1336            self.build_filter_params(params, filters)
1337        if dry_run:
1338            params['DryRun'] = 'true'
1339        return self.get_list('DescribeSpotInstanceRequests', params,
1340                             [('item', SpotInstanceRequest)], verb='POST')
1341
1342    def get_spot_price_history(self, start_time=None, end_time=None,
1343                               instance_type=None, product_description=None,
1344                               availability_zone=None, dry_run=False,
1345                               max_results=None, next_token=None,
1346                               filters=None):
1347        """
1348        Retrieve the recent history of spot instances pricing.
1349
1350        :type start_time: str
1351        :param start_time: An indication of how far back to provide price
1352            changes for. An ISO8601 DateTime string.
1353
1354        :type end_time: str
1355        :param end_time: An indication of how far forward to provide price
1356            changes for.  An ISO8601 DateTime string.
1357
1358        :type instance_type: str
1359        :param instance_type: Filter responses to a particular instance type.
1360
1361        :type product_description: str
1362        :param product_description: Filter responses to a particular platform.
1363            Valid values are currently:
1364
1365            * Linux/UNIX
1366            * SUSE Linux
1367            * Windows
1368            * Linux/UNIX (Amazon VPC)
1369            * SUSE Linux (Amazon VPC)
1370            * Windows (Amazon VPC)
1371
1372        :type availability_zone: str
1373        :param availability_zone: The availability zone for which prices
1374            should be returned.  If not specified, data for all
1375            availability zones will be returned.
1376
1377        :type dry_run: bool
1378        :param dry_run: Set to True if the operation should not actually run.
1379
1380        :type max_results: int
1381        :param max_results: The maximum number of paginated items
1382            per response.
1383
1384        :type next_token: str
1385        :param next_token: The next set of rows to return.  This should
1386            be the value of the ``next_token`` attribute from a previous
1387            call to ``get_spot_price_history``.
1388
1389        :type filters: dict
1390        :param filters: Optional filters that can be used to limit the
1391            results returned.  Filters are provided in the form of a
1392            dictionary consisting of filter names as the key and
1393            filter values as the value.  The set of allowable filter
1394            names/values is dependent on the request being performed.
1395            Check the EC2 API guide for details.
1396
1397        :rtype: list
1398        :return: A list tuples containing price and timestamp.
1399        """
1400        params = {}
1401        if start_time:
1402            params['StartTime'] = start_time
1403        if end_time:
1404            params['EndTime'] = end_time
1405        if instance_type:
1406            params['InstanceType'] = instance_type
1407        if product_description:
1408            params['ProductDescription'] = product_description
1409        if availability_zone:
1410            params['AvailabilityZone'] = availability_zone
1411        if dry_run:
1412            params['DryRun'] = 'true'
1413        if max_results is not None:
1414            params['MaxResults'] = max_results
1415        if next_token:
1416            params['NextToken'] = next_token
1417        if filters:
1418            self.build_filter_params(params, filters)
1419        return self.get_list('DescribeSpotPriceHistory', params,
1420                             [('item', SpotPriceHistory)], verb='POST')
1421
1422    def request_spot_instances(self, price, image_id, count=1, type='one-time',
1423                               valid_from=None, valid_until=None,
1424                               launch_group=None, availability_zone_group=None,
1425                               key_name=None, security_groups=None,
1426                               user_data=None, addressing_type=None,
1427                               instance_type='m1.small', placement=None,
1428                               kernel_id=None, ramdisk_id=None,
1429                               monitoring_enabled=False, subnet_id=None,
1430                               placement_group=None,
1431                               block_device_map=None,
1432                               instance_profile_arn=None,
1433                               instance_profile_name=None,
1434                               security_group_ids=None,
1435                               ebs_optimized=False,
1436                               network_interfaces=None, dry_run=False):
1437        """
1438        Request instances on the spot market at a particular price.
1439
1440        :type price: str
1441        :param price: The maximum price of your bid
1442
1443        :type image_id: string
1444        :param image_id: The ID of the image to run
1445
1446        :type count: int
1447        :param count: The of instances to requested
1448
1449        :type type: str
1450        :param type: Type of request. Can be 'one-time' or 'persistent'.
1451                     Default is one-time.
1452
1453        :type valid_from: str
1454        :param valid_from: Start date of the request. An ISO8601 time string.
1455
1456        :type valid_until: str
1457        :param valid_until: End date of the request.  An ISO8601 time string.
1458
1459        :type launch_group: str
1460        :param launch_group: If supplied, all requests will be fulfilled
1461            as a group.
1462
1463        :type availability_zone_group: str
1464        :param availability_zone_group: If supplied, all requests will be
1465            fulfilled within a single availability zone.
1466
1467        :type key_name: string
1468        :param key_name: The name of the key pair with which to
1469            launch instances
1470
1471        :type security_groups: list of strings
1472        :param security_groups: The names of the security groups with which to
1473            associate instances
1474
1475        :type user_data: string
1476        :param user_data: The user data passed to the launched instances
1477
1478        :type instance_type: string
1479        :param instance_type: The type of instance to run:
1480
1481            * t1.micro
1482            * m1.small
1483            * m1.medium
1484            * m1.large
1485            * m1.xlarge
1486            * m3.medium
1487            * m3.large
1488            * m3.xlarge
1489            * m3.2xlarge
1490            * c1.medium
1491            * c1.xlarge
1492            * m2.xlarge
1493            * m2.2xlarge
1494            * m2.4xlarge
1495            * cr1.8xlarge
1496            * hi1.4xlarge
1497            * hs1.8xlarge
1498            * cc1.4xlarge
1499            * cg1.4xlarge
1500            * cc2.8xlarge
1501            * g2.2xlarge
1502            * c3.large
1503            * c3.xlarge
1504            * c3.2xlarge
1505            * c3.4xlarge
1506            * c3.8xlarge
1507            * i2.xlarge
1508            * i2.2xlarge
1509            * i2.4xlarge
1510            * i2.8xlarge
1511            * t2.micro
1512            * t2.small
1513            * t2.medium
1514
1515        :type placement: string
1516        :param placement: The availability zone in which to launch
1517            the instances
1518
1519        :type kernel_id: string
1520        :param kernel_id: The ID of the kernel with which to launch the
1521            instances
1522
1523        :type ramdisk_id: string
1524        :param ramdisk_id: The ID of the RAM disk with which to launch the
1525            instances
1526
1527        :type monitoring_enabled: bool
1528        :param monitoring_enabled: Enable detailed CloudWatch monitoring on
1529            the instance.
1530
1531        :type subnet_id: string
1532        :param subnet_id: The subnet ID within which to launch the instances
1533            for VPC.
1534
1535        :type placement_group: string
1536        :param placement_group: If specified, this is the name of the placement
1537            group in which the instance(s) will be launched.
1538
1539        :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
1540        :param block_device_map: A BlockDeviceMapping data structure
1541            describing the EBS volumes associated with the Image.
1542
1543        :type security_group_ids: list of strings
1544        :param security_group_ids: The ID of the VPC security groups with
1545            which to associate instances.
1546
1547        :type instance_profile_arn: string
1548        :param instance_profile_arn: The Amazon resource name (ARN) of
1549            the IAM Instance Profile (IIP) to associate with the instances.
1550
1551        :type instance_profile_name: string
1552        :param instance_profile_name: The name of
1553            the IAM Instance Profile (IIP) to associate with the instances.
1554
1555        :type ebs_optimized: bool
1556        :param ebs_optimized: Whether the instance is optimized for
1557            EBS I/O.  This optimization provides dedicated throughput
1558            to Amazon EBS and an optimized configuration stack to
1559            provide optimal EBS I/O performance.  This optimization
1560            isn't available with all instance types.
1561
1562        :type network_interfaces: list
1563        :param network_interfaces: A list of
1564            :class:`boto.ec2.networkinterface.NetworkInterfaceSpecification`
1565
1566        :type dry_run: bool
1567        :param dry_run: Set to True if the operation should not actually run.
1568
1569        :rtype: Reservation
1570        :return: The :class:`boto.ec2.spotinstancerequest.SpotInstanceRequest`
1571                 associated with the request for machines
1572        """
1573        ls = 'LaunchSpecification'
1574        params = {'%s.ImageId' % ls: image_id,
1575                  'Type': type,
1576                  'SpotPrice': price}
1577        if count:
1578            params['InstanceCount'] = count
1579        if valid_from:
1580            params['ValidFrom'] = valid_from
1581        if valid_until:
1582            params['ValidUntil'] = valid_until
1583        if launch_group:
1584            params['LaunchGroup'] = launch_group
1585        if availability_zone_group:
1586            params['AvailabilityZoneGroup'] = availability_zone_group
1587        if key_name:
1588            params['%s.KeyName' % ls] = key_name
1589        if security_group_ids:
1590            l = []
1591            for group in security_group_ids:
1592                if isinstance(group, SecurityGroup):
1593                    l.append(group.id)
1594                else:
1595                    l.append(group)
1596            self.build_list_params(params, l,
1597                                   '%s.SecurityGroupId' % ls)
1598        if security_groups:
1599            l = []
1600            for group in security_groups:
1601                if isinstance(group, SecurityGroup):
1602                    l.append(group.name)
1603                else:
1604                    l.append(group)
1605            self.build_list_params(params, l, '%s.SecurityGroup' % ls)
1606        if user_data:
1607            params['%s.UserData' % ls] = base64.b64encode(user_data)
1608        if addressing_type:
1609            params['%s.AddressingType' % ls] = addressing_type
1610        if instance_type:
1611            params['%s.InstanceType' % ls] = instance_type
1612        if placement:
1613            params['%s.Placement.AvailabilityZone' % ls] = placement
1614        if kernel_id:
1615            params['%s.KernelId' % ls] = kernel_id
1616        if ramdisk_id:
1617            params['%s.RamdiskId' % ls] = ramdisk_id
1618        if monitoring_enabled:
1619            params['%s.Monitoring.Enabled' % ls] = 'true'
1620        if subnet_id:
1621            params['%s.SubnetId' % ls] = subnet_id
1622        if placement_group:
1623            params['%s.Placement.GroupName' % ls] = placement_group
1624        if block_device_map:
1625            block_device_map.ec2_build_list_params(params, '%s.' % ls)
1626        if instance_profile_name:
1627            params['%s.IamInstanceProfile.Name' % ls] = instance_profile_name
1628        if instance_profile_arn:
1629            params['%s.IamInstanceProfile.Arn' % ls] = instance_profile_arn
1630        if ebs_optimized:
1631            params['%s.EbsOptimized' % ls] = 'true'
1632        if network_interfaces:
1633            network_interfaces.build_list_params(params, prefix=ls + '.')
1634        if dry_run:
1635            params['DryRun'] = 'true'
1636        return self.get_list('RequestSpotInstances', params,
1637                             [('item', SpotInstanceRequest)],
1638                             verb='POST')
1639
1640    def cancel_spot_instance_requests(self, request_ids, dry_run=False):
1641        """
1642        Cancel the specified Spot Instance Requests.
1643
1644        :type request_ids: list
1645        :param request_ids: A list of strings of the Request IDs to terminate
1646
1647        :type dry_run: bool
1648        :param dry_run: Set to True if the operation should not actually run.
1649
1650        :rtype: list
1651        :return: A list of the instances terminated
1652        """
1653        params = {}
1654        if request_ids:
1655            self.build_list_params(params, request_ids, 'SpotInstanceRequestId')
1656        if dry_run:
1657            params['DryRun'] = 'true'
1658        return self.get_list('CancelSpotInstanceRequests', params,
1659                             [('item', SpotInstanceRequest)], verb='POST')
1660
1661    def get_spot_datafeed_subscription(self, dry_run=False):
1662        """
1663        Return the current spot instance data feed subscription
1664        associated with this account, if any.
1665
1666        :type dry_run: bool
1667        :param dry_run: Set to True if the operation should not actually run.
1668
1669        :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription`
1670        :return: The datafeed subscription object or None
1671        """
1672        params = {}
1673        if dry_run:
1674            params['DryRun'] = 'true'
1675        return self.get_object('DescribeSpotDatafeedSubscription',
1676                               params, SpotDatafeedSubscription, verb='POST')
1677
1678    def create_spot_datafeed_subscription(self, bucket, prefix, dry_run=False):
1679        """
1680        Create a spot instance datafeed subscription for this account.
1681
1682        :type bucket: str or unicode
1683        :param bucket: The name of the bucket where spot instance data
1684                       will be written.  The account issuing this request
1685                       must have FULL_CONTROL access to the bucket
1686                       specified in the request.
1687
1688        :type prefix: str or unicode
1689        :param prefix: An optional prefix that will be pre-pended to all
1690                       data files written to the bucket.
1691
1692        :type dry_run: bool
1693        :param dry_run: Set to True if the operation should not actually run.
1694
1695        :rtype: :class:`boto.ec2.spotdatafeedsubscription.SpotDatafeedSubscription`
1696        :return: The datafeed subscription object or None
1697        """
1698        params = {'Bucket': bucket}
1699        if prefix:
1700            params['Prefix'] = prefix
1701        if dry_run:
1702            params['DryRun'] = 'true'
1703        return self.get_object('CreateSpotDatafeedSubscription',
1704                               params, SpotDatafeedSubscription, verb='POST')
1705
1706    def delete_spot_datafeed_subscription(self, dry_run=False):
1707        """
1708        Delete the current spot instance data feed subscription
1709        associated with this account
1710
1711        :type dry_run: bool
1712        :param dry_run: Set to True if the operation should not actually run.
1713
1714        :rtype: bool
1715        :return: True if successful
1716        """
1717        params = {}
1718        if dry_run:
1719            params['DryRun'] = 'true'
1720        return self.get_status('DeleteSpotDatafeedSubscription',
1721                               params, verb='POST')
1722
1723    # Zone methods
1724
1725    def get_all_zones(self, zones=None, filters=None, dry_run=False):
1726        """
1727        Get all Availability Zones associated with the current region.
1728
1729        :type zones: list
1730        :param zones: Optional list of zones.  If this list is present,
1731                      only the Zones associated with these zone names
1732                      will be returned.
1733
1734        :type filters: dict
1735        :param filters: Optional filters that can be used to limit
1736                        the results returned.  Filters are provided
1737                        in the form of a dictionary consisting of
1738                        filter names as the key and filter values
1739                        as the value.  The set of allowable filter
1740                        names/values is dependent on the request
1741                        being performed.  Check the EC2 API guide
1742                        for details.
1743
1744        :type dry_run: bool
1745        :param dry_run: Set to True if the operation should not actually run.
1746
1747        :rtype: list of :class:`boto.ec2.zone.Zone`
1748        :return: The requested Zone objects
1749        """
1750        params = {}
1751        if zones:
1752            self.build_list_params(params, zones, 'ZoneName')
1753        if filters:
1754            self.build_filter_params(params, filters)
1755        if dry_run:
1756            params['DryRun'] = 'true'
1757        return self.get_list('DescribeAvailabilityZones', params,
1758                             [('item', Zone)], verb='POST')
1759
1760    # Address methods
1761
1762    def get_all_addresses(self, addresses=None, filters=None,
1763                          allocation_ids=None, dry_run=False):
1764        """
1765        Get all EIP's associated with the current credentials.
1766
1767        :type addresses: list
1768        :param addresses: Optional list of addresses.  If this list is present,
1769                           only the Addresses associated with these addresses
1770                           will be returned.
1771
1772        :type filters: dict
1773        :param filters: Optional filters that can be used to limit
1774                        the results returned.  Filters are provided
1775                        in the form of a dictionary consisting of
1776                        filter names as the key and filter values
1777                        as the value.  The set of allowable filter
1778                        names/values is dependent on the request
1779                        being performed.  Check the EC2 API guide
1780                        for details.
1781
1782        :type allocation_ids: list
1783        :param allocation_ids: Optional list of allocation IDs.  If this list is
1784                           present, only the Addresses associated with the given
1785                           allocation IDs will be returned.
1786
1787        :type dry_run: bool
1788        :param dry_run: Set to True if the operation should not actually run.
1789
1790        :rtype: list of :class:`boto.ec2.address.Address`
1791        :return: The requested Address objects
1792        """
1793        params = {}
1794        if addresses:
1795            self.build_list_params(params, addresses, 'PublicIp')
1796        if allocation_ids:
1797            self.build_list_params(params, allocation_ids, 'AllocationId')
1798        if filters:
1799            self.build_filter_params(params, filters)
1800        if dry_run:
1801            params['DryRun'] = 'true'
1802        return self.get_list('DescribeAddresses', params, [('item', Address)], verb='POST')
1803
1804    def allocate_address(self, domain=None, dry_run=False):
1805        """
1806        Allocate a new Elastic IP address and associate it with your account.
1807
1808        :type domain: string
1809        :param domain: Optional string. If domain is set to "vpc" the address
1810            will be allocated to VPC . Will return address object with
1811            allocation_id.
1812
1813        :type dry_run: bool
1814        :param dry_run: Set to True if the operation should not actually run.
1815
1816        :rtype: :class:`boto.ec2.address.Address`
1817        :return: The newly allocated Address
1818        """
1819        params = {}
1820
1821        if domain is not None:
1822            params['Domain'] = domain
1823
1824        if dry_run:
1825            params['DryRun'] = 'true'
1826
1827        return self.get_object('AllocateAddress', params, Address, verb='POST')
1828
1829    def assign_private_ip_addresses(self, network_interface_id=None,
1830                                    private_ip_addresses=None,
1831                                    secondary_private_ip_address_count=None,
1832                                    allow_reassignment=False, dry_run=False):
1833        """
1834        Assigns one or more secondary private IP addresses to a network
1835        interface in Amazon VPC.
1836
1837        :type network_interface_id: string
1838        :param network_interface_id: The network interface to which the IP
1839            address will be assigned.
1840
1841        :type private_ip_addresses: list
1842        :param private_ip_addresses: Assigns the specified IP addresses as
1843            secondary IP addresses to the network interface.
1844
1845        :type secondary_private_ip_address_count: int
1846        :param secondary_private_ip_address_count: The number of secondary IP
1847            addresses to assign to the network interface. You cannot specify
1848            this parameter when also specifying private_ip_addresses.
1849
1850        :type allow_reassignment: bool
1851        :param allow_reassignment: Specifies whether to allow an IP address
1852            that is already assigned to another network interface or instance
1853            to be reassigned to the specified network interface.
1854
1855        :type dry_run: bool
1856        :param dry_run: Set to True if the operation should not actually run.
1857
1858        :rtype: bool
1859        :return: True if successful
1860        """
1861        params = {}
1862
1863        if network_interface_id is not None:
1864            params['NetworkInterfaceId'] = network_interface_id
1865
1866        if private_ip_addresses is not None:
1867            self.build_list_params(params, private_ip_addresses,
1868                                   'PrivateIpAddress')
1869        elif secondary_private_ip_address_count is not None:
1870            params['SecondaryPrivateIpAddressCount'] = \
1871                secondary_private_ip_address_count
1872
1873        if allow_reassignment:
1874            params['AllowReassignment'] = 'true'
1875
1876        if dry_run:
1877            params['DryRun'] = 'true'
1878
1879        return self.get_status('AssignPrivateIpAddresses', params, verb='POST')
1880
1881    def _associate_address(self, status, instance_id=None, public_ip=None,
1882                           allocation_id=None, network_interface_id=None,
1883                           private_ip_address=None, allow_reassociation=False,
1884                           dry_run=False):
1885        params = {}
1886        if instance_id is not None:
1887                params['InstanceId'] = instance_id
1888        elif network_interface_id is not None:
1889                params['NetworkInterfaceId'] = network_interface_id
1890
1891        # Allocation id trumps public ip in order to associate with VPCs
1892        if allocation_id is not None:
1893            params['AllocationId'] = allocation_id
1894        elif public_ip is not None:
1895            params['PublicIp'] = public_ip
1896
1897        if private_ip_address is not None:
1898            params['PrivateIpAddress'] = private_ip_address
1899
1900        if allow_reassociation:
1901            params['AllowReassociation'] = 'true'
1902
1903        if dry_run:
1904            params['DryRun'] = 'true'
1905
1906        if status:
1907            return self.get_status('AssociateAddress', params, verb='POST')
1908        else:
1909            return self.get_object('AssociateAddress', params, Address,
1910                                   verb='POST')
1911
1912    def associate_address(self, instance_id=None, public_ip=None,
1913                          allocation_id=None, network_interface_id=None,
1914                          private_ip_address=None, allow_reassociation=False,
1915                          dry_run=False):
1916        """
1917        Associate an Elastic IP address with a currently running instance.
1918        This requires one of ``public_ip`` or ``allocation_id`` depending
1919        on if you're associating a VPC address or a plain EC2 address.
1920
1921        When using an Allocation ID, make sure to pass ``None`` for ``public_ip``
1922        as EC2 expects a single parameter and if ``public_ip`` is passed boto
1923        will preference that instead of ``allocation_id``.
1924
1925        :type instance_id: string
1926        :param instance_id: The ID of the instance
1927
1928        :type public_ip: string
1929        :param public_ip: The public IP address for EC2 based allocations.
1930
1931        :type allocation_id: string
1932        :param allocation_id: The allocation ID for a VPC-based elastic IP.
1933
1934        :type network_interface_id: string
1935        :param network_interface_id: The network interface ID to which
1936            elastic IP is to be assigned to
1937
1938        :type private_ip_address: string
1939        :param private_ip_address: The primary or secondary private IP address
1940            to associate with the Elastic IP address.
1941
1942        :type allow_reassociation: bool
1943        :param allow_reassociation: Specify this option to allow an Elastic IP
1944            address that is already associated with another network interface
1945            or instance to be re-associated with the specified instance or
1946            interface.
1947
1948        :type dry_run: bool
1949        :param dry_run: Set to True if the operation should not actually run.
1950
1951        :rtype: bool
1952        :return: True if successful
1953        """
1954        return self._associate_address(True, instance_id=instance_id,
1955            public_ip=public_ip, allocation_id=allocation_id,
1956            network_interface_id=network_interface_id,
1957            private_ip_address=private_ip_address,
1958            allow_reassociation=allow_reassociation, dry_run=dry_run)
1959
1960    def associate_address_object(self, instance_id=None, public_ip=None,
1961                                 allocation_id=None, network_interface_id=None,
1962                                 private_ip_address=None, allow_reassociation=False,
1963                                 dry_run=False):
1964        """
1965        Associate an Elastic IP address with a currently running instance.
1966        This requires one of ``public_ip`` or ``allocation_id`` depending
1967        on if you're associating a VPC address or a plain EC2 address.
1968
1969        When using an Allocation ID, make sure to pass ``None`` for ``public_ip``
1970        as EC2 expects a single parameter and if ``public_ip`` is passed boto
1971        will preference that instead of ``allocation_id``.
1972
1973        :type instance_id: string
1974        :param instance_id: The ID of the instance
1975
1976        :type public_ip: string
1977        :param public_ip: The public IP address for EC2 based allocations.
1978
1979        :type allocation_id: string
1980        :param allocation_id: The allocation ID for a VPC-based elastic IP.
1981
1982        :type network_interface_id: string
1983        :param network_interface_id: The network interface ID to which
1984            elastic IP is to be assigned to
1985
1986        :type private_ip_address: string
1987        :param private_ip_address: The primary or secondary private IP address
1988            to associate with the Elastic IP address.
1989
1990        :type allow_reassociation: bool
1991        :param allow_reassociation: Specify this option to allow an Elastic IP
1992            address that is already associated with another network interface
1993            or instance to be re-associated with the specified instance or
1994            interface.
1995
1996        :type dry_run: bool
1997        :param dry_run: Set to True if the operation should not actually run.
1998
1999        :rtype: class:`boto.ec2.address.Address`
2000        :return: The associated address instance
2001        """
2002        return self._associate_address(False, instance_id=instance_id,
2003            public_ip=public_ip, allocation_id=allocation_id,
2004            network_interface_id=network_interface_id,
2005            private_ip_address=private_ip_address,
2006            allow_reassociation=allow_reassociation, dry_run=dry_run)
2007
2008    def disassociate_address(self, public_ip=None, association_id=None,
2009                             dry_run=False):
2010        """
2011        Disassociate an Elastic IP address from a currently running instance.
2012
2013        :type public_ip: string
2014        :param public_ip: The public IP address for EC2 elastic IPs.
2015
2016        :type association_id: string
2017        :param association_id: The association ID for a VPC based elastic ip.
2018
2019        :type dry_run: bool
2020        :param dry_run: Set to True if the operation should not actually run.
2021
2022        :rtype: bool
2023        :return: True if successful
2024        """
2025        params = {}
2026
2027        # If there is an association id it trumps public ip
2028        # in order to successfully dissassociate with a VPC elastic ip
2029        if association_id is not None:
2030            params['AssociationId'] = association_id
2031        elif public_ip is not None:
2032            params['PublicIp'] = public_ip
2033
2034        if dry_run:
2035            params['DryRun'] = 'true'
2036
2037        return self.get_status('DisassociateAddress', params, verb='POST')
2038
2039    def release_address(self, public_ip=None, allocation_id=None,
2040                        dry_run=False):
2041        """
2042        Free up an Elastic IP address.  Pass a public IP address to
2043        release an EC2 Elastic IP address and an AllocationId to
2044        release a VPC Elastic IP address.  You should only pass
2045        one value.
2046
2047        This requires one of ``public_ip`` or ``allocation_id`` depending
2048        on if you're associating a VPC address or a plain EC2 address.
2049
2050        When using an Allocation ID, make sure to pass ``None`` for ``public_ip``
2051        as EC2 expects a single parameter and if ``public_ip`` is passed boto
2052        will preference that instead of ``allocation_id``.
2053
2054        :type public_ip: string
2055        :param public_ip: The public IP address for EC2 elastic IPs.
2056
2057        :type allocation_id: string
2058        :param allocation_id: The Allocation ID for VPC elastic IPs.
2059
2060        :type dry_run: bool
2061        :param dry_run: Set to True if the operation should not actually run.
2062
2063        :rtype: bool
2064        :return: True if successful
2065        """
2066        params = {}
2067
2068        if public_ip is not None:
2069            params['PublicIp'] = public_ip
2070        elif allocation_id is not None:
2071            params['AllocationId'] = allocation_id
2072
2073        if dry_run:
2074            params['DryRun'] = 'true'
2075
2076        return self.get_status('ReleaseAddress', params, verb='POST')
2077
2078    def unassign_private_ip_addresses(self, network_interface_id=None,
2079                                      private_ip_addresses=None, dry_run=False):
2080        """
2081        Unassigns one or more secondary private IP addresses from a network
2082        interface in Amazon VPC.
2083
2084        :type network_interface_id: string
2085        :param network_interface_id: The network interface from which the
2086            secondary private IP address will be unassigned.
2087
2088        :type private_ip_addresses: list
2089        :param private_ip_addresses: Specifies the secondary private IP
2090            addresses that you want to unassign from the network interface.
2091
2092        :type dry_run: bool
2093        :param dry_run: Set to True if the operation should not actually run.
2094
2095        :rtype: bool
2096        :return: True if successful
2097        """
2098        params = {}
2099
2100        if network_interface_id is not None:
2101            params['NetworkInterfaceId'] = network_interface_id
2102
2103        if private_ip_addresses is not None:
2104            self.build_list_params(params, private_ip_addresses,
2105                                   'PrivateIpAddress')
2106
2107        if dry_run:
2108            params['DryRun'] = 'true'
2109
2110        return self.get_status('UnassignPrivateIpAddresses', params,
2111                               verb='POST')
2112
2113    # Volume methods
2114
2115    def get_all_volumes(self, volume_ids=None, filters=None, dry_run=False):
2116        """
2117        Get all Volumes associated with the current credentials.
2118
2119        :type volume_ids: list
2120        :param volume_ids: Optional list of volume ids.  If this list
2121                           is present, only the volumes associated with
2122                           these volume ids will be returned.
2123
2124        :type filters: dict
2125        :param filters: Optional filters that can be used to limit
2126                        the results returned.  Filters are provided
2127                        in the form of a dictionary consisting of
2128                        filter names as the key and filter values
2129                        as the value.  The set of allowable filter
2130                        names/values is dependent on the request
2131                        being performed.  Check the EC2 API guide
2132                        for details.
2133
2134        :type dry_run: bool
2135        :param dry_run: Set to True if the operation should not actually run.
2136
2137        :rtype: list of :class:`boto.ec2.volume.Volume`
2138        :return: The requested Volume objects
2139        """
2140        params = {}
2141        if volume_ids:
2142            self.build_list_params(params, volume_ids, 'VolumeId')
2143        if filters:
2144            self.build_filter_params(params, filters)
2145        if dry_run:
2146            params['DryRun'] = 'true'
2147        return self.get_list('DescribeVolumes', params,
2148                             [('item', Volume)], verb='POST')
2149
2150    def get_all_volume_status(self, volume_ids=None,
2151                              max_results=None, next_token=None,
2152                              filters=None, dry_run=False):
2153        """
2154        Retrieve the status of one or more volumes.
2155
2156        :type volume_ids: list
2157        :param volume_ids: A list of strings of volume IDs
2158
2159        :type max_results: int
2160        :param max_results: The maximum number of paginated instance
2161            items per response.
2162
2163        :type next_token: str
2164        :param next_token: A string specifying the next paginated set
2165            of results to return.
2166
2167        :type filters: dict
2168        :param filters: Optional filters that can be used to limit
2169            the results returned.  Filters are provided
2170            in the form of a dictionary consisting of
2171            filter names as the key and filter values
2172            as the value.  The set of allowable filter
2173            names/values is dependent on the request
2174            being performed.  Check the EC2 API guide
2175            for details.
2176
2177        :type dry_run: bool
2178        :param dry_run: Set to True if the operation should not actually run.
2179
2180        :rtype: list
2181        :return: A list of volume status.
2182        """
2183        params = {}
2184        if volume_ids:
2185            self.build_list_params(params, volume_ids, 'VolumeId')
2186        if max_results:
2187            params['MaxResults'] = max_results
2188        if next_token:
2189            params['NextToken'] = next_token
2190        if filters:
2191            self.build_filter_params(params, filters)
2192        if dry_run:
2193            params['DryRun'] = 'true'
2194        return self.get_object('DescribeVolumeStatus', params,
2195                               VolumeStatusSet, verb='POST')
2196
2197    def enable_volume_io(self, volume_id, dry_run=False):
2198        """
2199        Enables I/O operations for a volume that had I/O operations
2200        disabled because the data on the volume was potentially inconsistent.
2201
2202        :type volume_id: str
2203        :param volume_id: The ID of the volume.
2204
2205        :type dry_run: bool
2206        :param dry_run: Set to True if the operation should not actually run.
2207
2208        :rtype: bool
2209        :return: True if successful
2210        """
2211        params = {'VolumeId': volume_id}
2212        if dry_run:
2213            params['DryRun'] = 'true'
2214        return self.get_status('EnableVolumeIO', params, verb='POST')
2215
2216    def get_volume_attribute(self, volume_id,
2217                             attribute='autoEnableIO', dry_run=False):
2218        """
2219        Describes attribute of the volume.
2220
2221        :type volume_id: str
2222        :param volume_id: The ID of the volume.
2223
2224        :type attribute: str
2225        :param attribute: The requested attribute.  Valid values are:
2226
2227            * autoEnableIO
2228
2229        :type dry_run: bool
2230        :param dry_run: Set to True if the operation should not actually run.
2231
2232        :rtype: list of :class:`boto.ec2.volume.VolumeAttribute`
2233        :return: The requested Volume attribute
2234        """
2235        params = {'VolumeId': volume_id, 'Attribute': attribute}
2236        if dry_run:
2237            params['DryRun'] = 'true'
2238        return self.get_object('DescribeVolumeAttribute', params,
2239                               VolumeAttribute, verb='POST')
2240
2241    def modify_volume_attribute(self, volume_id, attribute, new_value,
2242                                dry_run=False):
2243        """
2244        Changes an attribute of an Volume.
2245
2246        :type volume_id: string
2247        :param volume_id: The volume id you wish to change
2248
2249        :type attribute: string
2250        :param attribute: The attribute you wish to change.  Valid values are:
2251            AutoEnableIO.
2252
2253        :type new_value: string
2254        :param new_value: The new value of the attribute.
2255
2256        :type dry_run: bool
2257        :param dry_run: Set to True if the operation should not actually run.
2258
2259        """
2260        params = {'VolumeId': volume_id}
2261        if attribute == 'AutoEnableIO':
2262            params['AutoEnableIO.Value'] = new_value
2263        if dry_run:
2264            params['DryRun'] = 'true'
2265        return self.get_status('ModifyVolumeAttribute', params, verb='POST')
2266
2267    def create_volume(self, size, zone, snapshot=None, volume_type=None,
2268                      iops=None, encrypted=False, dry_run=False):
2269        """
2270        Create a new EBS Volume.
2271
2272        :type size: int
2273        :param size: The size of the new volume, in GiB
2274
2275        :type zone: string or :class:`boto.ec2.zone.Zone`
2276        :param zone: The availability zone in which the Volume will be created.
2277
2278        :type snapshot: string or :class:`boto.ec2.snapshot.Snapshot`
2279        :param snapshot: The snapshot from which the new Volume will be
2280            created.
2281
2282        :type volume_type: string
2283        :param volume_type: The type of the volume. (optional).  Valid
2284            values are: standard | io1 | gp2.
2285
2286        :type iops: int
2287        :param iops: The provisioned IOPS you want to associate with
2288            this volume. (optional)
2289
2290        :type encrypted: bool
2291        :param encrypted: Specifies whether the volume should be encrypted.
2292            (optional)
2293
2294        :type dry_run: bool
2295        :param dry_run: Set to True if the operation should not actually run.
2296
2297        """
2298        if isinstance(zone, Zone):
2299            zone = zone.name
2300        params = {'AvailabilityZone': zone}
2301        if size:
2302            params['Size'] = size
2303        if snapshot:
2304            if isinstance(snapshot, Snapshot):
2305                snapshot = snapshot.id
2306            params['SnapshotId'] = snapshot
2307        if volume_type:
2308            params['VolumeType'] = volume_type
2309        if iops:
2310            params['Iops'] = str(iops)
2311        if encrypted:
2312            params['Encrypted'] = 'true'
2313        if dry_run:
2314            params['DryRun'] = 'true'
2315        return self.get_object('CreateVolume', params, Volume, verb='POST')
2316
2317    def delete_volume(self, volume_id, dry_run=False):
2318        """
2319        Delete an EBS volume.
2320
2321        :type volume_id: str
2322        :param volume_id: The ID of the volume to be delete.
2323
2324        :type dry_run: bool
2325        :param dry_run: Set to True if the operation should not actually run.
2326
2327        :rtype: bool
2328        :return: True if successful
2329        """
2330        params = {'VolumeId': volume_id}
2331        if dry_run:
2332            params['DryRun'] = 'true'
2333        return self.get_status('DeleteVolume', params, verb='POST')
2334
2335    def attach_volume(self, volume_id, instance_id, device, dry_run=False):
2336        """
2337        Attach an EBS volume to an EC2 instance.
2338
2339        :type volume_id: str
2340        :param volume_id: The ID of the EBS volume to be attached.
2341
2342        :type instance_id: str
2343        :param instance_id: The ID of the EC2 instance to which it will
2344                            be attached.
2345
2346        :type device: str
2347        :param device: The device on the instance through which the
2348                       volume will be exposted (e.g. /dev/sdh)
2349
2350        :type dry_run: bool
2351        :param dry_run: Set to True if the operation should not actually run.
2352
2353        :rtype: bool
2354        :return: True if successful
2355        """
2356        params = {'InstanceId': instance_id,
2357                  'VolumeId': volume_id,
2358                  'Device': device}
2359        if dry_run:
2360            params['DryRun'] = 'true'
2361        return self.get_status('AttachVolume', params, verb='POST')
2362
2363    def detach_volume(self, volume_id, instance_id=None,
2364                      device=None, force=False, dry_run=False):
2365        """
2366        Detach an EBS volume from an EC2 instance.
2367
2368        :type volume_id: str
2369        :param volume_id: The ID of the EBS volume to be attached.
2370
2371        :type instance_id: str
2372        :param instance_id: The ID of the EC2 instance from which it will
2373            be detached.
2374
2375        :type device: str
2376        :param device: The device on the instance through which the
2377            volume is exposted (e.g. /dev/sdh)
2378
2379        :type force: bool
2380        :param force: Forces detachment if the previous detachment
2381            attempt did not occur cleanly.  This option can lead to
2382            data loss or a corrupted file system. Use this option only
2383            as a last resort to detach a volume from a failed
2384            instance. The instance will not have an opportunity to
2385            flush file system caches nor file system meta data. If you
2386            use this option, you must perform file system check and
2387            repair procedures.
2388
2389        :type dry_run: bool
2390        :param dry_run: Set to True if the operation should not actually run.
2391
2392        :rtype: bool
2393        :return: True if successful
2394        """
2395        params = {'VolumeId': volume_id}
2396        if instance_id:
2397            params['InstanceId'] = instance_id
2398        if device:
2399            params['Device'] = device
2400        if force:
2401            params['Force'] = 'true'
2402        if dry_run:
2403            params['DryRun'] = 'true'
2404        return self.get_status('DetachVolume', params, verb='POST')
2405
2406    # Snapshot methods
2407
2408    def get_all_snapshots(self, snapshot_ids=None,
2409                          owner=None, restorable_by=None,
2410                          filters=None, dry_run=False):
2411        """
2412        Get all EBS Snapshots associated with the current credentials.
2413
2414        :type snapshot_ids: list
2415        :param snapshot_ids: Optional list of snapshot ids.  If this list is
2416                             present, only the Snapshots associated with
2417                             these snapshot ids will be returned.
2418
2419        :type owner: str or list
2420        :param owner: If present, only the snapshots owned by the specified user(s)
2421                      will be returned.  Valid values are:
2422
2423                      * self
2424                      * amazon
2425                      * AWS Account ID
2426
2427        :type restorable_by: str or list
2428        :param restorable_by: If present, only the snapshots that are restorable
2429                              by the specified account id(s) will be returned.
2430
2431        :type filters: dict
2432        :param filters: Optional filters that can be used to limit
2433                        the results returned.  Filters are provided
2434                        in the form of a dictionary consisting of
2435                        filter names as the key and filter values
2436                        as the value.  The set of allowable filter
2437                        names/values is dependent on the request
2438                        being performed.  Check the EC2 API guide
2439                        for details.
2440
2441        :type dry_run: bool
2442        :param dry_run: Set to True if the operation should not actually run.
2443
2444        :rtype: list of :class:`boto.ec2.snapshot.Snapshot`
2445        :return: The requested Snapshot objects
2446        """
2447        params = {}
2448        if snapshot_ids:
2449            self.build_list_params(params, snapshot_ids, 'SnapshotId')
2450
2451        if owner:
2452            self.build_list_params(params, owner, 'Owner')
2453        if restorable_by:
2454            self.build_list_params(params, restorable_by, 'RestorableBy')
2455        if filters:
2456            self.build_filter_params(params, filters)
2457        if dry_run:
2458            params['DryRun'] = 'true'
2459        return self.get_list('DescribeSnapshots', params,
2460                             [('item', Snapshot)], verb='POST')
2461
2462    def create_snapshot(self, volume_id, description=None, dry_run=False):
2463        """
2464        Create a snapshot of an existing EBS Volume.
2465
2466        :type volume_id: str
2467        :param volume_id: The ID of the volume to be snapshot'ed
2468
2469        :type description: str
2470        :param description: A description of the snapshot.
2471                            Limited to 255 characters.
2472
2473        :type dry_run: bool
2474        :param dry_run: Set to True if the operation should not actually run.
2475
2476        :rtype: :class:`boto.ec2.snapshot.Snapshot`
2477        :return: The created Snapshot object
2478        """
2479        params = {'VolumeId': volume_id}
2480        if description:
2481            params['Description'] = description[0:255]
2482        if dry_run:
2483            params['DryRun'] = 'true'
2484        snapshot = self.get_object('CreateSnapshot', params,
2485                                   Snapshot, verb='POST')
2486        volume = self.get_all_volumes([volume_id], dry_run=dry_run)[0]
2487        volume_name = volume.tags.get('Name')
2488        if volume_name:
2489            snapshot.add_tag('Name', volume_name)
2490        return snapshot
2491
2492    def delete_snapshot(self, snapshot_id, dry_run=False):
2493        """
2494        :type dry_run: bool
2495        :param dry_run: Set to True if the operation should not actually run.
2496
2497        """
2498        params = {'SnapshotId': snapshot_id}
2499        if dry_run:
2500            params['DryRun'] = 'true'
2501        return self.get_status('DeleteSnapshot', params, verb='POST')
2502
2503    def copy_snapshot(self, source_region, source_snapshot_id,
2504                      description=None, dry_run=False):
2505        """
2506        Copies a point-in-time snapshot of an Amazon Elastic Block Store
2507        (Amazon EBS) volume and stores it in Amazon Simple Storage Service
2508        (Amazon S3). You can copy the snapshot within the same region or from
2509        one region to another. You can use the snapshot to create new Amazon
2510        EBS volumes or Amazon Machine Images (AMIs).
2511
2512
2513        :type source_region: str
2514        :param source_region: The ID of the AWS region that contains the
2515            snapshot to be copied (e.g 'us-east-1', 'us-west-2', etc.).
2516
2517        :type source_snapshot_id: str
2518        :param source_snapshot_id: The ID of the Amazon EBS snapshot to copy
2519
2520        :type description: str
2521        :param description: A description of the new Amazon EBS snapshot.
2522
2523        :type dry_run: bool
2524        :param dry_run: Set to True if the operation should not actually run.
2525
2526        :rtype: str
2527        :return: The snapshot ID
2528
2529        """
2530        params = {
2531            'SourceRegion': source_region,
2532            'SourceSnapshotId': source_snapshot_id,
2533        }
2534        if description is not None:
2535            params['Description'] = description
2536        if dry_run:
2537            params['DryRun'] = 'true'
2538        snapshot = self.get_object('CopySnapshot', params, Snapshot,
2539                                   verb='POST')
2540        return snapshot.id
2541
2542    def trim_snapshots(self, hourly_backups=8, daily_backups=7,
2543                       weekly_backups=4, monthly_backups=True):
2544        """
2545        Trim excess snapshots, based on when they were taken. More current
2546        snapshots are retained, with the number retained decreasing as you
2547        move back in time.
2548
2549        If ebs volumes have a 'Name' tag with a value, their snapshots
2550        will be assigned the same tag when they are created. The values
2551        of the 'Name' tags for snapshots are used by this function to
2552        group snapshots taken from the same volume (or from a series
2553        of like-named volumes over time) for trimming.
2554
2555        For every group of like-named snapshots, this function retains
2556        the newest and oldest snapshots, as well as, by default,  the
2557        first snapshots taken in each of the last eight hours, the first
2558        snapshots taken in each of the last seven days, the first snapshots
2559        taken in the last 4 weeks (counting Midnight Sunday morning as
2560        the start of the week), and the first snapshot from the first
2561        day of each month forever.
2562
2563        :type hourly_backups: int
2564        :param hourly_backups: How many recent hourly backups should be saved.
2565
2566        :type daily_backups: int
2567        :param daily_backups: How many recent daily backups should be saved.
2568
2569        :type weekly_backups: int
2570        :param weekly_backups: How many recent weekly backups should be saved.
2571
2572        :type monthly_backups: int
2573        :param monthly_backups: How many monthly backups should be saved. Use True for no limit.
2574        """
2575
2576        # This function first builds up an ordered list of target times
2577        # that snapshots should be saved for (last 8 hours, last 7 days, etc.).
2578        # Then a map of snapshots is constructed, with the keys being
2579        # the snapshot / volume names and the values being arrays of
2580        # chronologically sorted snapshots.
2581        # Finally, for each array in the map, we go through the snapshot
2582        # array and the target time array in an interleaved fashion,
2583        # deleting snapshots whose start_times don't immediately follow a
2584        # target time (we delete a snapshot if there's another snapshot
2585        # that was made closer to the preceding target time).
2586
2587        now = datetime.utcnow()
2588        last_hour = datetime(now.year, now.month, now.day, now.hour)
2589        last_midnight = datetime(now.year, now.month, now.day)
2590        last_sunday = datetime(now.year, now.month, now.day) - timedelta(days=(now.weekday() + 1) % 7)
2591        start_of_month = datetime(now.year, now.month, 1)
2592
2593        target_backup_times = []
2594
2595        # there are no snapshots older than 1/1/2007
2596        oldest_snapshot_date = datetime(2007, 1, 1)
2597
2598        for hour in range(0, hourly_backups):
2599            target_backup_times.append(last_hour - timedelta(hours=hour))
2600
2601        for day in range(0, daily_backups):
2602            target_backup_times.append(last_midnight - timedelta(days=day))
2603
2604        for week in range(0, weekly_backups):
2605            target_backup_times.append(last_sunday - timedelta(weeks=week))
2606
2607        one_day = timedelta(days=1)
2608        monthly_snapshots_added = 0
2609        while (start_of_month > oldest_snapshot_date and
2610               (monthly_backups is True or
2611                monthly_snapshots_added < monthly_backups)):
2612            # append the start of the month to the list of
2613            # snapshot dates to save:
2614            target_backup_times.append(start_of_month)
2615            monthly_snapshots_added += 1
2616            # there's no timedelta setting for one month, so instead:
2617            # decrement the day by one, so we go to the final day of
2618            # the previous month...
2619            start_of_month -= one_day
2620            # ... and then go to the first day of that previous month:
2621            start_of_month = datetime(start_of_month.year,
2622                                      start_of_month.month, 1)
2623
2624        temp = []
2625
2626        for t in target_backup_times:
2627            if temp.__contains__(t) == False:
2628                temp.append(t)
2629
2630        # sort to make the oldest dates first, and make sure the month start
2631        # and last four week's start are in the proper order
2632        target_backup_times = sorted(temp)
2633
2634        # get all the snapshots, sort them by date and time, and
2635        # organize them into one array for each volume:
2636        all_snapshots = self.get_all_snapshots(owner = 'self')
2637        all_snapshots.sort(cmp = lambda x, y: cmp(x.start_time, y.start_time))
2638        snaps_for_each_volume = {}
2639        for snap in all_snapshots:
2640            # the snapshot name and the volume name are the same.
2641            # The snapshot name is set from the volume
2642            # name at the time the snapshot is taken
2643            volume_name = snap.tags.get('Name')
2644            if volume_name:
2645                # only examine snapshots that have a volume name
2646                snaps_for_volume = snaps_for_each_volume.get(volume_name)
2647                if not snaps_for_volume:
2648                    snaps_for_volume = []
2649                    snaps_for_each_volume[volume_name] = snaps_for_volume
2650                snaps_for_volume.append(snap)
2651
2652        # Do a running comparison of snapshot dates to desired time
2653        #periods, keeping the oldest snapshot in each
2654        # time period and deleting the rest:
2655        for volume_name in snaps_for_each_volume:
2656            snaps = snaps_for_each_volume[volume_name]
2657            snaps = snaps[:-1] # never delete the newest snapshot
2658            time_period_number = 0
2659            snap_found_for_this_time_period = False
2660            for snap in snaps:
2661                check_this_snap = True
2662                while check_this_snap and time_period_number < target_backup_times.__len__():
2663                    snap_date = datetime.strptime(snap.start_time,
2664                                                  '%Y-%m-%dT%H:%M:%S.000Z')
2665                    if snap_date < target_backup_times[time_period_number]:
2666                        # the snap date is before the cutoff date.
2667                        # Figure out if it's the first snap in this
2668                        # date range and act accordingly (since both
2669                        #date the date ranges and the snapshots
2670                        # are sorted chronologically, we know this
2671                        #snapshot isn't in an earlier date range):
2672                        if snap_found_for_this_time_period == True:
2673                            if not snap.tags.get('preserve_snapshot'):
2674                                # as long as the snapshot wasn't marked
2675                                # with the 'preserve_snapshot' tag, delete it:
2676                                try:
2677                                    self.delete_snapshot(snap.id)
2678                                    boto.log.info('Trimmed snapshot %s (%s)' % (snap.tags['Name'], snap.start_time))
2679                                except EC2ResponseError:
2680                                    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))
2681                            # go on and look at the next snapshot,
2682                            #leaving the time period alone
2683                        else:
2684                            # this was the first snapshot found for this
2685                            #time period. Leave it alone and look at the
2686                            # next snapshot:
2687                            snap_found_for_this_time_period = True
2688                        check_this_snap = False
2689                    else:
2690                        # the snap is after the cutoff date. Check it
2691                        # against the next cutoff date
2692                        time_period_number += 1
2693                        snap_found_for_this_time_period = False
2694
2695    def get_snapshot_attribute(self, snapshot_id,
2696                               attribute='createVolumePermission',
2697                               dry_run=False):
2698        """
2699        Get information about an attribute of a snapshot.  Only one attribute
2700        can be specified per call.
2701
2702        :type snapshot_id: str
2703        :param snapshot_id: The ID of the snapshot.
2704
2705        :type attribute: str
2706        :param attribute: The requested attribute.  Valid values are:
2707
2708                          * createVolumePermission
2709
2710        :type dry_run: bool
2711        :param dry_run: Set to True if the operation should not actually run.
2712
2713        :rtype: list of :class:`boto.ec2.snapshotattribute.SnapshotAttribute`
2714        :return: The requested Snapshot attribute
2715        """
2716        params = {'Attribute': attribute}
2717        if snapshot_id:
2718            params['SnapshotId'] = snapshot_id
2719        if dry_run:
2720            params['DryRun'] = 'true'
2721        return self.get_object('DescribeSnapshotAttribute', params,
2722                               SnapshotAttribute, verb='POST')
2723
2724    def modify_snapshot_attribute(self, snapshot_id,
2725                                  attribute='createVolumePermission',
2726                                  operation='add', user_ids=None, groups=None,
2727                                  dry_run=False):
2728        """
2729        Changes an attribute of an image.
2730
2731        :type snapshot_id: string
2732        :param snapshot_id: The snapshot id you wish to change
2733
2734        :type attribute: string
2735        :param attribute: The attribute you wish to change.  Valid values are:
2736            createVolumePermission
2737
2738        :type operation: string
2739        :param operation: Either add or remove (this is required for changing
2740            snapshot ermissions)
2741
2742        :type user_ids: list
2743        :param user_ids: The Amazon IDs of users to add/remove attributes
2744
2745        :type groups: list
2746        :param groups: The groups to add/remove attributes.  The only valid
2747            value at this time is 'all'.
2748
2749        :type dry_run: bool
2750        :param dry_run: Set to True if the operation should not actually run.
2751
2752        """
2753        params = {'SnapshotId': snapshot_id,
2754                  'Attribute': attribute,
2755                  'OperationType': operation}
2756        if user_ids:
2757            self.build_list_params(params, user_ids, 'UserId')
2758        if groups:
2759            self.build_list_params(params, groups, 'UserGroup')
2760        if dry_run:
2761            params['DryRun'] = 'true'
2762        return self.get_status('ModifySnapshotAttribute', params, verb='POST')
2763
2764    def reset_snapshot_attribute(self, snapshot_id,
2765                                 attribute='createVolumePermission',
2766                                 dry_run=False):
2767        """
2768        Resets an attribute of a snapshot to its default value.
2769
2770        :type snapshot_id: string
2771        :param snapshot_id: ID of the snapshot
2772
2773        :type attribute: string
2774        :param attribute: The attribute to reset
2775
2776        :type dry_run: bool
2777        :param dry_run: Set to True if the operation should not actually run.
2778
2779        :rtype: bool
2780        :return: Whether the operation succeeded or not
2781        """
2782        params = {'SnapshotId': snapshot_id,
2783                  'Attribute': attribute}
2784        if dry_run:
2785            params['DryRun'] = 'true'
2786        return self.get_status('ResetSnapshotAttribute', params, verb='POST')
2787
2788    # Keypair methods
2789
2790    def get_all_key_pairs(self, keynames=None, filters=None, dry_run=False):
2791        """
2792        Get all key pairs associated with your account.
2793
2794        :type keynames: list
2795        :param keynames: A list of the names of keypairs to retrieve.
2796            If not provided, all key pairs will be returned.
2797
2798        :type filters: dict
2799        :param filters: Optional filters that can be used to limit the
2800            results returned.  Filters are provided in the form of a
2801            dictionary consisting of filter names as the key and
2802            filter values as the value.  The set of allowable filter
2803            names/values is dependent on the request being performed.
2804            Check the EC2 API guide for details.
2805
2806        :type dry_run: bool
2807        :param dry_run: Set to True if the operation should not actually run.
2808
2809        :rtype: list
2810        :return: A list of :class:`boto.ec2.keypair.KeyPair`
2811        """
2812        params = {}
2813        if keynames:
2814            self.build_list_params(params, keynames, 'KeyName')
2815        if filters:
2816            self.build_filter_params(params, filters)
2817        if dry_run:
2818            params['DryRun'] = 'true'
2819        return self.get_list('DescribeKeyPairs', params,
2820                             [('item', KeyPair)], verb='POST')
2821
2822    def get_key_pair(self, keyname, dry_run=False):
2823        """
2824        Convenience method to retrieve a specific keypair (KeyPair).
2825
2826        :type keyname: string
2827        :param keyname: The name of the keypair to retrieve
2828
2829        :type dry_run: bool
2830        :param dry_run: Set to True if the operation should not actually run.
2831
2832        :rtype: :class:`boto.ec2.keypair.KeyPair`
2833        :return: The KeyPair specified or None if it is not found
2834        """
2835        try:
2836            return self.get_all_key_pairs(
2837                keynames=[keyname],
2838                dry_run=dry_run
2839            )[0]
2840        except self.ResponseError as e:
2841            if e.code == 'InvalidKeyPair.NotFound':
2842                return None
2843            else:
2844                raise
2845
2846    def create_key_pair(self, key_name, dry_run=False):
2847        """
2848        Create a new key pair for your account.
2849        This will create the key pair within the region you
2850        are currently connected to.
2851
2852        :type key_name: string
2853        :param key_name: The name of the new keypair
2854
2855        :type dry_run: bool
2856        :param dry_run: Set to True if the operation should not actually run.
2857
2858        :rtype: :class:`boto.ec2.keypair.KeyPair`
2859        :return: The newly created :class:`boto.ec2.keypair.KeyPair`.
2860                 The material attribute of the new KeyPair object
2861                 will contain the the unencrypted PEM encoded RSA private key.
2862        """
2863        params = {'KeyName': key_name}
2864        if dry_run:
2865            params['DryRun'] = 'true'
2866        return self.get_object('CreateKeyPair', params, KeyPair, verb='POST')
2867
2868    def delete_key_pair(self, key_name, dry_run=False):
2869        """
2870        Delete a key pair from your account.
2871
2872        :type key_name: string
2873        :param key_name: The name of the keypair to delete
2874
2875        :type dry_run: bool
2876        :param dry_run: Set to True if the operation should not actually run.
2877
2878        """
2879        params = {'KeyName': key_name}
2880        if dry_run:
2881            params['DryRun'] = 'true'
2882        return self.get_status('DeleteKeyPair', params, verb='POST')
2883
2884    def import_key_pair(self, key_name, public_key_material, dry_run=False):
2885        """
2886        imports the public key from an RSA key pair that you created
2887        with a third-party tool.
2888
2889        Supported formats:
2890
2891        * OpenSSH public key format (e.g., the format
2892          in ~/.ssh/authorized_keys)
2893
2894        * Base64 encoded DER format
2895
2896        * SSH public key file format as specified in RFC4716
2897
2898        DSA keys are not supported. Make sure your key generator is
2899        set up to create RSA keys.
2900
2901        Supported lengths: 1024, 2048, and 4096.
2902
2903        :type key_name: string
2904        :param key_name: The name of the new keypair
2905
2906        :type public_key_material: string
2907        :param public_key_material: The public key. You must base64 encode
2908                                    the public key material before sending
2909                                    it to AWS.
2910
2911        :type dry_run: bool
2912        :param dry_run: Set to True if the operation should not actually run.
2913
2914        :rtype: :class:`boto.ec2.keypair.KeyPair`
2915        :return: A :class:`boto.ec2.keypair.KeyPair` object representing
2916            the newly imported key pair.  This object will contain only
2917            the key name and the fingerprint.
2918        """
2919        public_key_material = base64.b64encode(public_key_material)
2920        params = {'KeyName': key_name,
2921                  'PublicKeyMaterial': public_key_material}
2922        if dry_run:
2923            params['DryRun'] = 'true'
2924        return self.get_object('ImportKeyPair', params, KeyPair, verb='POST')
2925
2926    # SecurityGroup methods
2927
2928    def get_all_security_groups(self, groupnames=None, group_ids=None,
2929                                filters=None, dry_run=False):
2930        """
2931        Get all security groups associated with your account in a region.
2932
2933        :type groupnames: list
2934        :param groupnames: A list of the names of security groups to retrieve.
2935                           If not provided, all security groups will be
2936                           returned.
2937
2938        :type group_ids: list
2939        :param group_ids: A list of IDs of security groups to retrieve for
2940                          security groups within a VPC.
2941
2942        :type filters: dict
2943        :param filters: Optional filters that can be used to limit
2944                        the results returned.  Filters are provided
2945                        in the form of a dictionary consisting of
2946                        filter names as the key and filter values
2947                        as the value.  The set of allowable filter
2948                        names/values is dependent on the request
2949                        being performed.  Check the EC2 API guide
2950                        for details.
2951
2952        :type dry_run: bool
2953        :param dry_run: Set to True if the operation should not actually run.
2954
2955        :rtype: list
2956        :return: A list of :class:`boto.ec2.securitygroup.SecurityGroup`
2957        """
2958        params = {}
2959        if groupnames is not None:
2960            self.build_list_params(params, groupnames, 'GroupName')
2961        if group_ids is not None:
2962            self.build_list_params(params, group_ids, 'GroupId')
2963        if filters is not None:
2964            self.build_filter_params(params, filters)
2965        if dry_run:
2966            params['DryRun'] = 'true'
2967        return self.get_list('DescribeSecurityGroups', params,
2968                             [('item', SecurityGroup)], verb='POST')
2969
2970    def create_security_group(self, name, description, vpc_id=None,
2971                              dry_run=False):
2972        """
2973        Create a new security group for your account.
2974        This will create the security group within the region you
2975        are currently connected to.
2976
2977        :type name: string
2978        :param name: The name of the new security group
2979
2980        :type description: string
2981        :param description: The description of the new security group
2982
2983        :type vpc_id: string
2984        :param vpc_id: The ID of the VPC to create the security group in,
2985                       if any.
2986
2987        :type dry_run: bool
2988        :param dry_run: Set to True if the operation should not actually run.
2989
2990        :rtype: :class:`boto.ec2.securitygroup.SecurityGroup`
2991        :return: The newly created :class:`boto.ec2.securitygroup.SecurityGroup`.
2992        """
2993        params = {'GroupName': name,
2994                  'GroupDescription': description}
2995
2996        if vpc_id is not None:
2997            params['VpcId'] = vpc_id
2998
2999        if dry_run:
3000            params['DryRun'] = 'true'
3001
3002        group = self.get_object('CreateSecurityGroup', params,
3003                                SecurityGroup, verb='POST')
3004        group.name = name
3005        group.description = description
3006        if vpc_id is not None:
3007            group.vpc_id = vpc_id
3008        return group
3009
3010    def delete_security_group(self, name=None, group_id=None, dry_run=False):
3011        """
3012        Delete a security group from your account.
3013
3014        :type name: string
3015        :param name: The name of the security group to delete.
3016
3017        :type group_id: string
3018        :param group_id: The ID of the security group to delete within
3019          a VPC.
3020
3021        :type dry_run: bool
3022        :param dry_run: Set to True if the operation should not actually run.
3023
3024        :rtype: bool
3025        :return: True if successful.
3026        """
3027        params = {}
3028
3029        if name is not None:
3030            params['GroupName'] = name
3031        elif group_id is not None:
3032            params['GroupId'] = group_id
3033
3034        if dry_run:
3035            params['DryRun'] = 'true'
3036
3037        return self.get_status('DeleteSecurityGroup', params, verb='POST')
3038
3039    def authorize_security_group_deprecated(self, group_name,
3040                                            src_security_group_name=None,
3041                                            src_security_group_owner_id=None,
3042                                            ip_protocol=None,
3043                                            from_port=None, to_port=None,
3044                                            cidr_ip=None, dry_run=False):
3045        """
3046        NOTE: This method uses the old-style request parameters
3047              that did not allow a port to be specified when
3048              authorizing a group.
3049
3050        :type group_name: string
3051        :param group_name: The name of the security group you are adding
3052            the rule to.
3053
3054        :type src_security_group_name: string
3055        :param src_security_group_name: The name of the security group you are
3056            granting access to.
3057
3058        :type src_security_group_owner_id: string
3059        :param src_security_group_owner_id: The ID of the owner of the security
3060            group you are granting access to.
3061
3062        :type ip_protocol: string
3063        :param ip_protocol: Either tcp | udp | icmp
3064
3065        :type from_port: int
3066        :param from_port: The beginning port number you are enabling
3067
3068        :type to_port: int
3069        :param to_port: The ending port number you are enabling
3070
3071        :type to_port: string
3072        :param to_port: The CIDR block you are providing access to.
3073            See http://goo.gl/Yj5QC
3074
3075        :type dry_run: bool
3076        :param dry_run: Set to True if the operation should not actually run.
3077
3078        :rtype: bool
3079        :return: True if successful.
3080        """
3081        params = {'GroupName': group_name}
3082        if src_security_group_name:
3083            params['SourceSecurityGroupName'] = src_security_group_name
3084        if src_security_group_owner_id:
3085            params['SourceSecurityGroupOwnerId'] = src_security_group_owner_id
3086        if ip_protocol:
3087            params['IpProtocol'] = ip_protocol
3088        if from_port:
3089            params['FromPort'] = from_port
3090        if to_port:
3091            params['ToPort'] = to_port
3092        if cidr_ip:
3093            params['CidrIp'] = cidr_ip
3094        if dry_run:
3095            params['DryRun'] = 'true'
3096        return self.get_status('AuthorizeSecurityGroupIngress', params)
3097
3098    def authorize_security_group(self, group_name=None,
3099                                 src_security_group_name=None,
3100                                 src_security_group_owner_id=None,
3101                                 ip_protocol=None,
3102                                 from_port=None, to_port=None,
3103                                 cidr_ip=None, group_id=None,
3104                                 src_security_group_group_id=None,
3105                                 dry_run=False):
3106        """
3107        Add a new rule to an existing security group.
3108        You need to pass in either src_security_group_name and
3109        src_security_group_owner_id OR ip_protocol, from_port, to_port,
3110        and cidr_ip.  In other words, either you are authorizing another
3111        group or you are authorizing some ip-based rule.
3112
3113        :type group_name: string
3114        :param group_name: The name of the security group you are adding
3115            the rule to.
3116
3117        :type src_security_group_name: string
3118        :param src_security_group_name: The name of the security group you are
3119            granting access to.
3120
3121        :type src_security_group_owner_id: string
3122        :param src_security_group_owner_id: The ID of the owner of the security
3123            group you are granting access to.
3124
3125        :type ip_protocol: string
3126        :param ip_protocol: Either tcp | udp | icmp
3127
3128        :type from_port: int
3129        :param from_port: The beginning port number you are enabling
3130
3131        :type to_port: int
3132        :param to_port: The ending port number you are enabling
3133
3134        :type cidr_ip: string or list of strings
3135        :param cidr_ip: The CIDR block you are providing access to.
3136            See http://goo.gl/Yj5QC
3137
3138        :type group_id: string
3139        :param group_id: ID of the EC2 or VPC security group to
3140            modify.  This is required for VPC security groups and can
3141            be used instead of group_name for EC2 security groups.
3142
3143        :type src_security_group_group_id: string
3144        :param src_security_group_group_id: The ID of the security
3145            group you are granting access to.  Can be used instead of
3146            src_security_group_name
3147
3148        :type dry_run: bool
3149        :param dry_run: Set to True if the operation should not actually run.
3150
3151        :rtype: bool
3152        :return: True if successful.
3153        """
3154        if src_security_group_name:
3155            if from_port is None and to_port is None and ip_protocol is None:
3156                return self.authorize_security_group_deprecated(
3157                    group_name, src_security_group_name,
3158                    src_security_group_owner_id)
3159
3160        params = {}
3161
3162        if group_name:
3163            params['GroupName'] = group_name
3164        if group_id:
3165            params['GroupId'] = group_id
3166        if src_security_group_name:
3167            param_name = 'IpPermissions.1.Groups.1.GroupName'
3168            params[param_name] = src_security_group_name
3169        if src_security_group_owner_id:
3170            param_name = 'IpPermissions.1.Groups.1.UserId'
3171            params[param_name] = src_security_group_owner_id
3172        if src_security_group_group_id:
3173            param_name = 'IpPermissions.1.Groups.1.GroupId'
3174            params[param_name] = src_security_group_group_id
3175        if ip_protocol:
3176            params['IpPermissions.1.IpProtocol'] = ip_protocol
3177        if from_port is not None:
3178            params['IpPermissions.1.FromPort'] = from_port
3179        if to_port is not None:
3180            params['IpPermissions.1.ToPort'] = to_port
3181        if cidr_ip:
3182            if not isinstance(cidr_ip, list):
3183                cidr_ip = [cidr_ip]
3184            for i, single_cidr_ip in enumerate(cidr_ip):
3185                params['IpPermissions.1.IpRanges.%d.CidrIp' % (i + 1)] = \
3186                    single_cidr_ip
3187        if dry_run:
3188            params['DryRun'] = 'true'
3189
3190        return self.get_status('AuthorizeSecurityGroupIngress',
3191                               params, verb='POST')
3192
3193    def authorize_security_group_egress(self,
3194                                        group_id,
3195                                        ip_protocol,
3196                                        from_port=None,
3197                                        to_port=None,
3198                                        src_group_id=None,
3199                                        cidr_ip=None,
3200                                        dry_run=False):
3201        """
3202        The action adds one or more egress rules to a VPC security
3203        group. Specifically, this action permits instances in a
3204        security group to send traffic to one or more destination
3205        CIDR IP address ranges, or to one or more destination
3206        security groups in the same VPC.
3207
3208        :type dry_run: bool
3209        :param dry_run: Set to True if the operation should not actually run.
3210
3211        """
3212        params = {
3213            'GroupId': group_id,
3214            'IpPermissions.1.IpProtocol': ip_protocol
3215        }
3216
3217        if from_port is not None:
3218            params['IpPermissions.1.FromPort'] = from_port
3219        if to_port is not None:
3220            params['IpPermissions.1.ToPort'] = to_port
3221        if src_group_id is not None:
3222            params['IpPermissions.1.Groups.1.GroupId'] = src_group_id
3223        if cidr_ip is not None:
3224            params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip
3225        if dry_run:
3226            params['DryRun'] = 'true'
3227
3228        return self.get_status('AuthorizeSecurityGroupEgress',
3229                               params, verb='POST')
3230
3231    def revoke_security_group_deprecated(self, group_name,
3232                                         src_security_group_name=None,
3233                                         src_security_group_owner_id=None,
3234                                         ip_protocol=None,
3235                                         from_port=None, to_port=None,
3236                                         cidr_ip=None, dry_run=False):
3237        """
3238        NOTE: This method uses the old-style request parameters
3239              that did not allow a port to be specified when
3240              authorizing a group.
3241
3242        Remove an existing rule from an existing security group.
3243        You need to pass in either src_security_group_name and
3244        src_security_group_owner_id OR ip_protocol, from_port, to_port,
3245        and cidr_ip.  In other words, either you are revoking another
3246        group or you are revoking some ip-based rule.
3247
3248        :type group_name: string
3249        :param group_name: The name of the security group you are removing
3250                           the rule from.
3251
3252        :type src_security_group_name: string
3253        :param src_security_group_name: The name of the security group you are
3254                                        revoking access to.
3255
3256        :type src_security_group_owner_id: string
3257        :param src_security_group_owner_id: The ID of the owner of the security
3258                                            group you are revoking access to.
3259
3260        :type ip_protocol: string
3261        :param ip_protocol: Either tcp | udp | icmp
3262
3263        :type from_port: int
3264        :param from_port: The beginning port number you are disabling
3265
3266        :type to_port: int
3267        :param to_port: The ending port number you are disabling
3268
3269        :type to_port: string
3270        :param to_port: The CIDR block you are revoking access to.
3271                        http://goo.gl/Yj5QC
3272
3273        :type dry_run: bool
3274        :param dry_run: Set to True if the operation should not actually run.
3275
3276        :rtype: bool
3277        :return: True if successful.
3278        """
3279        params = {'GroupName': group_name}
3280        if src_security_group_name:
3281            params['SourceSecurityGroupName'] = src_security_group_name
3282        if src_security_group_owner_id:
3283            params['SourceSecurityGroupOwnerId'] = src_security_group_owner_id
3284        if ip_protocol:
3285            params['IpProtocol'] = ip_protocol
3286        if from_port:
3287            params['FromPort'] = from_port
3288        if to_port:
3289            params['ToPort'] = to_port
3290        if cidr_ip:
3291            params['CidrIp'] = cidr_ip
3292        if dry_run:
3293            params['DryRun'] = 'true'
3294        return self.get_status('RevokeSecurityGroupIngress', params)
3295
3296    def revoke_security_group(self, group_name=None,
3297                              src_security_group_name=None,
3298                              src_security_group_owner_id=None,
3299                              ip_protocol=None, from_port=None, to_port=None,
3300                              cidr_ip=None, group_id=None,
3301                              src_security_group_group_id=None, dry_run=False):
3302        """
3303        Remove an existing rule from an existing security group.
3304        You need to pass in either src_security_group_name and
3305        src_security_group_owner_id OR ip_protocol, from_port, to_port,
3306        and cidr_ip.  In other words, either you are revoking another
3307        group or you are revoking some ip-based rule.
3308
3309        :type group_name: string
3310        :param group_name: The name of the security group you are removing
3311            the rule from.
3312
3313        :type src_security_group_name: string
3314        :param src_security_group_name: The name of the security group you are
3315            revoking access to.
3316
3317        :type src_security_group_owner_id: string
3318        :param src_security_group_owner_id: The ID of the owner of the security
3319            group you are revoking access to.
3320
3321        :type ip_protocol: string
3322        :param ip_protocol: Either tcp | udp | icmp
3323
3324        :type from_port: int
3325        :param from_port: The beginning port number you are disabling
3326
3327        :type to_port: int
3328        :param to_port: The ending port number you are disabling
3329
3330        :type cidr_ip: string
3331        :param cidr_ip: The CIDR block you are revoking access to.
3332            See http://goo.gl/Yj5QC
3333
3334        :type group_id: string
3335        :param group_id: ID of the EC2 or VPC security group to
3336            modify.  This is required for VPC security groups and can
3337            be used instead of group_name for EC2 security groups.
3338
3339        :type src_security_group_group_id: string
3340        :param src_security_group_group_id: The ID of the security group
3341            for which you are revoking access.  Can be used instead
3342            of src_security_group_name
3343
3344        :type dry_run: bool
3345        :param dry_run: Set to True if the operation should not actually run.
3346
3347        :rtype: bool
3348        :return: True if successful.
3349        """
3350        if src_security_group_name:
3351            if from_port is None and to_port is None and ip_protocol is None:
3352                return self.revoke_security_group_deprecated(
3353                    group_name, src_security_group_name,
3354                    src_security_group_owner_id)
3355        params = {}
3356        if group_name is not None:
3357            params['GroupName'] = group_name
3358        if group_id is not None:
3359            params['GroupId'] = group_id
3360        if src_security_group_name:
3361            param_name = 'IpPermissions.1.Groups.1.GroupName'
3362            params[param_name] = src_security_group_name
3363        if src_security_group_group_id:
3364            param_name = 'IpPermissions.1.Groups.1.GroupId'
3365            params[param_name] = src_security_group_group_id
3366        if src_security_group_owner_id:
3367            param_name = 'IpPermissions.1.Groups.1.UserId'
3368            params[param_name] = src_security_group_owner_id
3369        if ip_protocol:
3370            params['IpPermissions.1.IpProtocol'] = ip_protocol
3371        if from_port is not None:
3372            params['IpPermissions.1.FromPort'] = from_port
3373        if to_port is not None:
3374            params['IpPermissions.1.ToPort'] = to_port
3375        if cidr_ip:
3376            params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip
3377        if dry_run:
3378            params['DryRun'] = 'true'
3379        return self.get_status('RevokeSecurityGroupIngress',
3380                               params, verb='POST')
3381
3382    def revoke_security_group_egress(self,
3383                                     group_id,
3384                                     ip_protocol,
3385                                     from_port=None,
3386                                     to_port=None,
3387                                     src_group_id=None,
3388                                     cidr_ip=None, dry_run=False):
3389        """
3390        Remove an existing egress rule from an existing VPC security
3391        group.  You need to pass in an ip_protocol, from_port and
3392        to_port range only if the protocol you are using is
3393        port-based. You also need to pass in either a src_group_id or
3394        cidr_ip.
3395
3396        :type group_name: string
3397        :param group_id:  The name of the security group you are removing
3398            the rule from.
3399
3400        :type ip_protocol: string
3401        :param ip_protocol: Either tcp | udp | icmp | -1
3402
3403        :type from_port: int
3404        :param from_port: The beginning port number you are disabling
3405
3406        :type to_port: int
3407        :param to_port: The ending port number you are disabling
3408
3409        :type src_group_id: src_group_id
3410        :param src_group_id: The source security group you are
3411            revoking access to.
3412
3413        :type cidr_ip: string
3414        :param cidr_ip: The CIDR block you are revoking access to.
3415            See http://goo.gl/Yj5QC
3416
3417        :type dry_run: bool
3418        :param dry_run: Set to True if the operation should not actually run.
3419
3420        :rtype: bool
3421        :return: True if successful.
3422        """
3423
3424        params = {}
3425        if group_id:
3426            params['GroupId'] = group_id
3427        if ip_protocol:
3428            params['IpPermissions.1.IpProtocol'] = ip_protocol
3429        if from_port is not None:
3430            params['IpPermissions.1.FromPort'] = from_port
3431        if to_port is not None:
3432            params['IpPermissions.1.ToPort'] = to_port
3433        if src_group_id is not None:
3434            params['IpPermissions.1.Groups.1.GroupId'] = src_group_id
3435        if cidr_ip:
3436            params['IpPermissions.1.IpRanges.1.CidrIp'] = cidr_ip
3437        if dry_run:
3438            params['DryRun'] = 'true'
3439        return self.get_status('RevokeSecurityGroupEgress',
3440                               params, verb='POST')
3441
3442    #
3443    # Regions
3444    #
3445
3446    def get_all_regions(self, region_names=None, filters=None, dry_run=False):
3447        """
3448        Get all available regions for the EC2 service.
3449
3450        :type region_names: list of str
3451        :param region_names: Names of regions to limit output
3452
3453        :type filters: dict
3454        :param filters: Optional filters that can be used to limit
3455                        the results returned.  Filters are provided
3456                        in the form of a dictionary consisting of
3457                        filter names as the key and filter values
3458                        as the value.  The set of allowable filter
3459                        names/values is dependent on the request
3460                        being performed.  Check the EC2 API guide
3461                        for details.
3462
3463        :type dry_run: bool
3464        :param dry_run: Set to True if the operation should not actually run.
3465
3466        :rtype: list
3467        :return: A list of :class:`boto.ec2.regioninfo.RegionInfo`
3468        """
3469        params = {}
3470        if region_names:
3471            self.build_list_params(params, region_names, 'RegionName')
3472        if filters:
3473            self.build_filter_params(params, filters)
3474        if dry_run:
3475            params['DryRun'] = 'true'
3476        regions = self.get_list('DescribeRegions', params,
3477                                [('item', RegionInfo)], verb='POST')
3478        for region in regions:
3479            region.connection_cls = EC2Connection
3480        return regions
3481
3482    #
3483    # Reservation methods
3484    #
3485
3486    def get_all_reserved_instances_offerings(self,
3487                                             reserved_instances_offering_ids=None,
3488                                             instance_type=None,
3489                                             availability_zone=None,
3490                                             product_description=None,
3491                                             filters=None,
3492                                             instance_tenancy=None,
3493                                             offering_type=None,
3494                                             include_marketplace=None,
3495                                             min_duration=None,
3496                                             max_duration=None,
3497                                             max_instance_count=None,
3498                                             next_token=None,
3499                                             max_results=None,
3500                                             dry_run=False):
3501        """
3502        Describes Reserved Instance offerings that are available for purchase.
3503
3504        :type reserved_instances_offering_ids: list
3505        :param reserved_instances_id: One or more Reserved Instances
3506            offering IDs.
3507
3508        :type instance_type: str
3509        :param instance_type: Displays Reserved Instances of the specified
3510                              instance type.
3511
3512        :type availability_zone: str
3513        :param availability_zone: Displays Reserved Instances within the
3514                                  specified Availability Zone.
3515
3516        :type product_description: str
3517        :param product_description: Displays Reserved Instances with the
3518                                    specified product description.
3519
3520        :type filters: dict
3521        :param filters: Optional filters that can be used to limit
3522                        the results returned.  Filters are provided
3523                        in the form of a dictionary consisting of
3524                        filter names as the key and filter values
3525                        as the value.  The set of allowable filter
3526                        names/values is dependent on the request
3527                        being performed.  Check the EC2 API guide
3528                        for details.
3529
3530        :type instance_tenancy: string
3531        :param instance_tenancy: The tenancy of the Reserved Instance offering.
3532            A Reserved Instance with tenancy of dedicated will run on
3533            single-tenant hardware and can only be launched within a VPC.
3534
3535        :type offering_type: string
3536        :param offering_type: The Reserved Instance offering type.  Valid
3537            Values: `"Heavy Utilization" | "Medium Utilization" | "Light
3538            Utilization"`
3539
3540        :type include_marketplace: bool
3541        :param include_marketplace: Include Marketplace offerings in the
3542            response.
3543
3544        :type min_duration: int :param min_duration: Minimum duration (in
3545            seconds) to filter when searching for offerings.
3546
3547        :type max_duration: int
3548        :param max_duration: Maximum duration (in seconds) to filter when
3549            searching for offerings.
3550
3551        :type max_instance_count: int
3552        :param max_instance_count: Maximum number of instances to filter when
3553            searching for offerings.
3554
3555        :type next_token: string
3556        :param next_token: Token to use when requesting the next paginated set
3557            of offerings.
3558
3559        :type max_results: int
3560        :param max_results: Maximum number of offerings to return per call.
3561
3562        :type dry_run: bool
3563        :param dry_run: Set to True if the operation should not actually run.
3564
3565        :rtype: list
3566        :return: A list of
3567            :class:`boto.ec2.reservedinstance.ReservedInstancesOffering`.
3568
3569        """
3570        params = {}
3571        if reserved_instances_offering_ids is not None:
3572            self.build_list_params(params, reserved_instances_offering_ids,
3573                                   'ReservedInstancesOfferingId')
3574        if instance_type:
3575            params['InstanceType'] = instance_type
3576        if availability_zone:
3577            params['AvailabilityZone'] = availability_zone
3578        if product_description:
3579            params['ProductDescription'] = product_description
3580        if filters:
3581            self.build_filter_params(params, filters)
3582        if instance_tenancy is not None:
3583            params['InstanceTenancy'] = instance_tenancy
3584        if offering_type is not None:
3585            params['OfferingType'] = offering_type
3586        if include_marketplace is not None:
3587            if include_marketplace:
3588                params['IncludeMarketplace'] = 'true'
3589            else:
3590                params['IncludeMarketplace'] = 'false'
3591        if min_duration is not None:
3592            params['MinDuration'] = str(min_duration)
3593        if max_duration is not None:
3594            params['MaxDuration'] = str(max_duration)
3595        if max_instance_count is not None:
3596            params['MaxInstanceCount'] = str(max_instance_count)
3597        if next_token is not None:
3598            params['NextToken'] = next_token
3599        if max_results is not None:
3600            params['MaxResults'] = str(max_results)
3601        if dry_run:
3602            params['DryRun'] = 'true'
3603
3604        return self.get_list('DescribeReservedInstancesOfferings',
3605                             params, [('item', ReservedInstancesOffering)],
3606                             verb='POST')
3607
3608    def get_all_reserved_instances(self, reserved_instances_id=None,
3609                                   filters=None, dry_run=False):
3610        """
3611        Describes one or more of the Reserved Instances that you purchased.
3612
3613        :type reserved_instance_ids: list
3614        :param reserved_instance_ids: A list of the reserved instance ids that
3615            will be returned. If not provided, all reserved instances
3616            will be returned.
3617
3618        :type filters: dict
3619        :param filters: Optional filters that can be used to limit the
3620            results returned.  Filters are provided in the form of a
3621            dictionary consisting of filter names as the key and
3622            filter values as the value.  The set of allowable filter
3623            names/values is dependent on the request being performed.
3624            Check the EC2 API guide for details.
3625
3626        :type dry_run: bool
3627        :param dry_run: Set to True if the operation should not actually run.
3628
3629        :rtype: list
3630        :return: A list of :class:`boto.ec2.reservedinstance.ReservedInstance`
3631        """
3632        params = {}
3633        if reserved_instances_id:
3634            self.build_list_params(params, reserved_instances_id,
3635                                   'ReservedInstancesId')
3636        if filters:
3637            self.build_filter_params(params, filters)
3638        if dry_run:
3639            params['DryRun'] = 'true'
3640        return self.get_list('DescribeReservedInstances',
3641                             params, [('item', ReservedInstance)], verb='POST')
3642
3643    def purchase_reserved_instance_offering(self,
3644                                            reserved_instances_offering_id,
3645                                            instance_count=1, limit_price=None,
3646                                            dry_run=False):
3647        """
3648        Purchase a Reserved Instance for use with your account.
3649        ** CAUTION **
3650        This request can result in large amounts of money being charged to your
3651        AWS account.  Use with caution!
3652
3653        :type reserved_instances_offering_id: string
3654        :param reserved_instances_offering_id: The offering ID of the Reserved
3655            Instance to purchase
3656
3657        :type instance_count: int
3658        :param instance_count: The number of Reserved Instances to purchase.
3659            Default value is 1.
3660
3661        :type limit_price: tuple
3662        :param instance_count: Limit the price on the total order.
3663            Must be a tuple of (amount, currency_code), for example:
3664            (100.0, 'USD').
3665
3666        :type dry_run: bool
3667        :param dry_run: Set to True if the operation should not actually run.
3668
3669        :rtype: :class:`boto.ec2.reservedinstance.ReservedInstance`
3670        :return: The newly created Reserved Instance
3671        """
3672        params = {
3673            'ReservedInstancesOfferingId': reserved_instances_offering_id,
3674            'InstanceCount': instance_count}
3675        if limit_price is not None:
3676            params['LimitPrice.Amount'] = str(limit_price[0])
3677            params['LimitPrice.CurrencyCode'] = str(limit_price[1])
3678        if dry_run:
3679            params['DryRun'] = 'true'
3680        return self.get_object('PurchaseReservedInstancesOffering', params,
3681                               ReservedInstance, verb='POST')
3682
3683    def create_reserved_instances_listing(self, reserved_instances_id,
3684                                          instance_count, price_schedules,
3685                                          client_token, dry_run=False):
3686        """Creates a new listing for Reserved Instances.
3687
3688        Creates a new listing for Amazon EC2 Reserved Instances that will be
3689        sold in the Reserved Instance Marketplace. You can submit one Reserved
3690        Instance listing at a time.
3691
3692        The Reserved Instance Marketplace matches sellers who want to resell
3693        Reserved Instance capacity that they no longer need with buyers who
3694        want to purchase additional capacity. Reserved Instances bought and
3695        sold through the Reserved Instance Marketplace work like any other
3696        Reserved Instances.
3697
3698        If you want to sell your Reserved Instances, you must first register as
3699        a Seller in the Reserved Instance Marketplace. After completing the
3700        registration process, you can create a Reserved Instance Marketplace
3701        listing of some or all of your Reserved Instances, and specify the
3702        upfront price you want to receive for them. Your Reserved Instance
3703        listings then become available for purchase.
3704
3705        :type reserved_instances_id: string
3706        :param reserved_instances_id: The ID of the Reserved Instance that
3707            will be listed.
3708
3709        :type instance_count: int
3710        :param instance_count: The number of instances that are a part of a
3711            Reserved Instance account that will be listed in the Reserved
3712            Instance Marketplace. This number should be less than or equal to
3713            the instance count associated with the Reserved Instance ID
3714            specified in this call.
3715
3716        :type price_schedules: List of tuples
3717        :param price_schedules: A list specifying the price of the Reserved
3718            Instance for each month remaining in the Reserved Instance term.
3719            Each tuple contains two elements, the price and the term.  For
3720            example, for an instance that 11 months remaining in its term,
3721            we can have a price schedule with an upfront price of $2.50.
3722            At 8 months remaining we can drop the price down to $2.00.
3723            This would be expressed as::
3724
3725                price_schedules=[('2.50', 11), ('2.00', 8)]
3726
3727        :type client_token: string
3728        :param client_token: Unique, case-sensitive identifier you provide
3729            to ensure idempotency of the request.  Maximum 64 ASCII characters.
3730
3731        :type dry_run: bool
3732        :param dry_run: Set to True if the operation should not actually run.
3733
3734        :rtype: list
3735        :return: A list of
3736            :class:`boto.ec2.reservedinstance.ReservedInstanceListing`
3737
3738        """
3739        params = {
3740            'ReservedInstancesId': reserved_instances_id,
3741            'InstanceCount': str(instance_count),
3742            'ClientToken': client_token,
3743        }
3744        for i, schedule in enumerate(price_schedules):
3745            price, term = schedule
3746            params['PriceSchedules.%s.Price' % i] = str(price)
3747            params['PriceSchedules.%s.Term' % i] = str(term)
3748        if dry_run:
3749            params['DryRun'] = 'true'
3750        return self.get_list('CreateReservedInstancesListing',
3751                             params, [('item', ReservedInstanceListing)], verb='POST')
3752
3753    def cancel_reserved_instances_listing(self,
3754                                          reserved_instances_listing_ids=None,
3755                                          dry_run=False):
3756        """Cancels the specified Reserved Instance listing.
3757
3758        :type reserved_instances_listing_ids: List of strings
3759        :param reserved_instances_listing_ids: The ID of the
3760            Reserved Instance listing to be cancelled.
3761
3762        :type dry_run: bool
3763        :param dry_run: Set to True if the operation should not actually run.
3764
3765        :rtype: list
3766        :return: A list of
3767            :class:`boto.ec2.reservedinstance.ReservedInstanceListing`
3768
3769        """
3770        params = {}
3771        if reserved_instances_listing_ids is not None:
3772            self.build_list_params(params, reserved_instances_listing_ids,
3773                                   'ReservedInstancesListingId')
3774        if dry_run:
3775            params['DryRun'] = 'true'
3776        return self.get_list('CancelReservedInstancesListing',
3777                             params, [('item', ReservedInstanceListing)], verb='POST')
3778
3779    def build_configurations_param_list(self, params, target_configurations):
3780        for offset, tc in enumerate(target_configurations):
3781            prefix = 'ReservedInstancesConfigurationSetItemType.%d.' % offset
3782            if tc.availability_zone is not None:
3783                params[prefix + 'AvailabilityZone'] = tc.availability_zone
3784            if tc.platform is not None:
3785                params[prefix + 'Platform'] = tc.platform
3786            if tc.instance_count is not None:
3787                params[prefix + 'InstanceCount'] = tc.instance_count
3788            if tc.instance_type is not None:
3789                params[prefix + 'InstanceType'] = tc.instance_type
3790
3791    def modify_reserved_instances(self, client_token, reserved_instance_ids,
3792                                  target_configurations):
3793        """
3794        Modifies the specified Reserved Instances.
3795
3796        :type client_token: string
3797        :param client_token: A unique, case-sensitive, token you provide to
3798                             ensure idempotency of your modification request.
3799
3800        :type reserved_instance_ids: List of strings
3801        :param reserved_instance_ids: The IDs of the Reserved Instances to
3802                                      modify.
3803
3804        :type target_configurations: List of :class:`boto.ec2.reservedinstance.ReservedInstancesConfiguration`
3805        :param target_configurations: The configuration settings for the
3806                                      modified Reserved Instances.
3807
3808        :rtype: string
3809        :return: The unique ID for the submitted modification request.
3810        """
3811        params = {
3812            'ClientToken': client_token,
3813        }
3814        if reserved_instance_ids is not None:
3815            self.build_list_params(params, reserved_instance_ids,
3816                                   'ReservedInstancesId')
3817        if target_configurations is not None:
3818            self.build_configurations_param_list(params, target_configurations)
3819        mrir = self.get_object(
3820            'ModifyReservedInstances',
3821            params,
3822            ModifyReservedInstancesResult,
3823            verb='POST'
3824        )
3825        return mrir.modification_id
3826
3827    def describe_reserved_instances_modifications(self,
3828            reserved_instances_modification_ids=None, next_token=None,
3829            filters=None):
3830        """
3831        A request to describe the modifications made to Reserved Instances in
3832        your account.
3833
3834        :type reserved_instances_modification_ids: list
3835        :param reserved_instances_modification_ids: An optional list of
3836            Reserved Instances modification IDs to describe.
3837
3838        :type next_token: str
3839        :param next_token: A string specifying the next paginated set
3840            of results to return.
3841
3842        :type filters: dict
3843        :param filters: Optional filters that can be used to limit the
3844            results returned.  Filters are provided in the form of a
3845            dictionary consisting of filter names as the key and
3846            filter values as the value.  The set of allowable filter
3847            names/values is dependent on the request being performed.
3848            Check the EC2 API guide for details.
3849
3850        :rtype: list
3851        :return: A list of :class:`boto.ec2.reservedinstance.ReservedInstance`
3852        """
3853        params = {}
3854        if reserved_instances_modification_ids:
3855            self.build_list_params(params, reserved_instances_modification_ids,
3856                                   'ReservedInstancesModificationId')
3857        if next_token:
3858            params['NextToken'] = next_token
3859        if filters:
3860            self.build_filter_params(params, filters)
3861        return self.get_list('DescribeReservedInstancesModifications',
3862                             params, [('item', ReservedInstancesModification)],
3863                             verb='POST')
3864
3865    #
3866    # Monitoring
3867    #
3868
3869    def monitor_instances(self, instance_ids, dry_run=False):
3870        """
3871        Enable detailed CloudWatch monitoring for the supplied instances.
3872
3873        :type instance_id: list of strings
3874        :param instance_id: The instance ids
3875
3876        :type dry_run: bool
3877        :param dry_run: Set to True if the operation should not actually run.
3878
3879        :rtype: list
3880        :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
3881        """
3882        params = {}
3883        self.build_list_params(params, instance_ids, 'InstanceId')
3884        if dry_run:
3885            params['DryRun'] = 'true'
3886        return self.get_list('MonitorInstances', params,
3887                             [('item', InstanceInfo)], verb='POST')
3888
3889    def monitor_instance(self, instance_id, dry_run=False):
3890        """
3891        Deprecated Version, maintained for backward compatibility.
3892        Enable detailed CloudWatch monitoring for the supplied instance.
3893
3894        :type instance_id: string
3895        :param instance_id: The instance id
3896
3897        :type dry_run: bool
3898        :param dry_run: Set to True if the operation should not actually run.
3899
3900        :rtype: list
3901        :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
3902        """
3903        return self.monitor_instances([instance_id], dry_run=dry_run)
3904
3905    def unmonitor_instances(self, instance_ids, dry_run=False):
3906        """
3907        Disable CloudWatch monitoring for the supplied instance.
3908
3909        :type instance_id: list of string
3910        :param instance_id: The instance id
3911
3912        :type dry_run: bool
3913        :param dry_run: Set to True if the operation should not actually run.
3914
3915        :rtype: list
3916        :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
3917        """
3918        params = {}
3919        self.build_list_params(params, instance_ids, 'InstanceId')
3920        if dry_run:
3921            params['DryRun'] = 'true'
3922        return self.get_list('UnmonitorInstances', params,
3923                             [('item', InstanceInfo)], verb='POST')
3924
3925    def unmonitor_instance(self, instance_id, dry_run=False):
3926        """
3927        Deprecated Version, maintained for backward compatibility.
3928        Disable detailed CloudWatch monitoring for the supplied instance.
3929
3930        :type instance_id: string
3931        :param instance_id: The instance id
3932
3933        :type dry_run: bool
3934        :param dry_run: Set to True if the operation should not actually run.
3935
3936        :rtype: list
3937        :return: A list of :class:`boto.ec2.instanceinfo.InstanceInfo`
3938        """
3939        return self.unmonitor_instances([instance_id], dry_run=dry_run)
3940
3941    #
3942    # Bundle Windows Instances
3943    #
3944
3945    def bundle_instance(self, instance_id,
3946                        s3_bucket,
3947                        s3_prefix,
3948                        s3_upload_policy, dry_run=False):
3949        """
3950        Bundle Windows instance.
3951
3952        :type instance_id: string
3953        :param instance_id: The instance id
3954
3955        :type s3_bucket: string
3956        :param s3_bucket: The bucket in which the AMI should be stored.
3957
3958        :type s3_prefix: string
3959        :param s3_prefix: The beginning of the file name for the AMI.
3960
3961        :type s3_upload_policy: string
3962        :param s3_upload_policy: Base64 encoded policy that specifies condition
3963                                 and permissions for Amazon EC2 to upload the
3964                                 user's image into Amazon S3.
3965
3966        :type dry_run: bool
3967        :param dry_run: Set to True if the operation should not actually run.
3968
3969        """
3970
3971        params = {'InstanceId': instance_id,
3972                  'Storage.S3.Bucket': s3_bucket,
3973                  'Storage.S3.Prefix': s3_prefix,
3974                  'Storage.S3.UploadPolicy': s3_upload_policy}
3975        s3auth = boto.auth.get_auth_handler(None, boto.config,
3976                                            self.provider, ['s3'])
3977        params['Storage.S3.AWSAccessKeyId'] = self.aws_access_key_id
3978        signature = s3auth.sign_string(s3_upload_policy)
3979        params['Storage.S3.UploadPolicySignature'] = signature
3980        if dry_run:
3981            params['DryRun'] = 'true'
3982        return self.get_object('BundleInstance', params,
3983                               BundleInstanceTask, verb='POST')
3984
3985    def get_all_bundle_tasks(self, bundle_ids=None, filters=None,
3986                             dry_run=False):
3987        """
3988        Retrieve current bundling tasks. If no bundle id is specified, all
3989        tasks are retrieved.
3990
3991        :type bundle_ids: list
3992        :param bundle_ids: A list of strings containing identifiers for
3993                           previously created bundling tasks.
3994
3995        :type filters: dict
3996        :param filters: Optional filters that can be used to limit
3997                        the results returned.  Filters are provided
3998                        in the form of a dictionary consisting of
3999                        filter names as the key and filter values
4000                        as the value.  The set of allowable filter
4001                        names/values is dependent on the request
4002                        being performed.  Check the EC2 API guide
4003                        for details.
4004
4005        :type dry_run: bool
4006        :param dry_run: Set to True if the operation should not actually run.
4007
4008        """
4009        params = {}
4010        if bundle_ids:
4011            self.build_list_params(params, bundle_ids, 'BundleId')
4012        if filters:
4013            self.build_filter_params(params, filters)
4014        if dry_run:
4015            params['DryRun'] = 'true'
4016        return self.get_list('DescribeBundleTasks', params,
4017                             [('item', BundleInstanceTask)], verb='POST')
4018
4019    def cancel_bundle_task(self, bundle_id, dry_run=False):
4020        """
4021        Cancel a previously submitted bundle task
4022
4023        :type bundle_id: string
4024        :param bundle_id: The identifier of the bundle task to cancel.
4025
4026        :type dry_run: bool
4027        :param dry_run: Set to True if the operation should not actually run.
4028
4029        """
4030        params = {'BundleId': bundle_id}
4031        if dry_run:
4032            params['DryRun'] = 'true'
4033        return self.get_object('CancelBundleTask', params,
4034                               BundleInstanceTask, verb='POST')
4035
4036    def get_password_data(self, instance_id, dry_run=False):
4037        """
4038        Get encrypted administrator password for a Windows instance.
4039
4040        :type instance_id: string
4041        :param instance_id: The identifier of the instance to retrieve the
4042                            password for.
4043
4044        :type dry_run: bool
4045        :param dry_run: Set to True if the operation should not actually run.
4046
4047        """
4048        params = {'InstanceId': instance_id}
4049        if dry_run:
4050            params['DryRun'] = 'true'
4051        rs = self.get_object('GetPasswordData', params, ResultSet, verb='POST')
4052        return rs.passwordData
4053
4054    #
4055    # Cluster Placement Groups
4056    #
4057
4058    def get_all_placement_groups(self, groupnames=None, filters=None,
4059                                 dry_run=False):
4060        """
4061        Get all placement groups associated with your account in a region.
4062
4063        :type groupnames: list
4064        :param groupnames: A list of the names of placement groups to retrieve.
4065                           If not provided, all placement groups will be
4066                           returned.
4067
4068        :type filters: dict
4069        :param filters: Optional filters that can be used to limit
4070                        the results returned.  Filters are provided
4071                        in the form of a dictionary consisting of
4072                        filter names as the key and filter values
4073                        as the value.  The set of allowable filter
4074                        names/values is dependent on the request
4075                        being performed.  Check the EC2 API guide
4076                        for details.
4077
4078        :type dry_run: bool
4079        :param dry_run: Set to True if the operation should not actually run.
4080
4081        :rtype: list
4082        :return: A list of :class:`boto.ec2.placementgroup.PlacementGroup`
4083        """
4084        params = {}
4085        if groupnames:
4086            self.build_list_params(params, groupnames, 'GroupName')
4087        if filters:
4088            self.build_filter_params(params, filters)
4089        if dry_run:
4090            params['DryRun'] = 'true'
4091        return self.get_list('DescribePlacementGroups', params,
4092                             [('item', PlacementGroup)], verb='POST')
4093
4094    def create_placement_group(self, name, strategy='cluster', dry_run=False):
4095        """
4096        Create a new placement group for your account.
4097        This will create the placement group within the region you
4098        are currently connected to.
4099
4100        :type name: string
4101        :param name: The name of the new placement group
4102
4103        :type strategy: string
4104        :param strategy: The placement strategy of the new placement group.
4105                         Currently, the only acceptable value is "cluster".
4106
4107        :type dry_run: bool
4108        :param dry_run: Set to True if the operation should not actually run.
4109
4110        :rtype: bool
4111        :return: True if successful
4112        """
4113        params = {'GroupName': name, 'Strategy': strategy}
4114        if dry_run:
4115            params['DryRun'] = 'true'
4116        group = self.get_status('CreatePlacementGroup', params, verb='POST')
4117        return group
4118
4119    def delete_placement_group(self, name, dry_run=False):
4120        """
4121        Delete a placement group from your account.
4122
4123        :type key_name: string
4124        :param key_name: The name of the keypair to delete
4125
4126        :type dry_run: bool
4127        :param dry_run: Set to True if the operation should not actually run.
4128
4129        """
4130        params = {'GroupName': name}
4131        if dry_run:
4132            params['DryRun'] = 'true'
4133        return self.get_status('DeletePlacementGroup', params, verb='POST')
4134
4135    # Tag methods
4136
4137    def build_tag_param_list(self, params, tags):
4138        keys = sorted(tags.keys())
4139        i = 1
4140        for key in keys:
4141            value = tags[key]
4142            params['Tag.%d.Key' % i] = key
4143            if value is not None:
4144                params['Tag.%d.Value' % i] = value
4145            i += 1
4146
4147    def get_all_tags(self, filters=None, dry_run=False, max_results=None):
4148        """
4149        Retrieve all the metadata tags associated with your account.
4150
4151        :type filters: dict
4152        :param filters: Optional filters that can be used to limit
4153                        the results returned.  Filters are provided
4154                        in the form of a dictionary consisting of
4155                        filter names as the key and filter values
4156                        as the value.  The set of allowable filter
4157                        names/values is dependent on the request
4158                        being performed.  Check the EC2 API guide
4159                        for details.
4160
4161        :type dry_run: bool
4162        :param dry_run: Set to True if the operation should not actually run.
4163
4164        :type max_results: int
4165        :param max_results: The maximum number of paginated instance
4166            items per response.
4167
4168        :rtype: list
4169        :return: A list of :class:`boto.ec2.tag.Tag` objects
4170        """
4171        params = {}
4172        if filters:
4173            self.build_filter_params(params, filters)
4174        if dry_run:
4175            params['DryRun'] = 'true'
4176        if max_results is not None:
4177            params['MaxResults'] = max_results
4178        return self.get_list('DescribeTags', params,
4179                             [('item', Tag)], verb='POST')
4180
4181    def create_tags(self, resource_ids, tags, dry_run=False):
4182        """
4183        Create new metadata tags for the specified resource ids.
4184
4185        :type resource_ids: list
4186        :param resource_ids: List of strings
4187
4188        :type tags: dict
4189        :param tags: A dictionary containing the name/value pairs.
4190                     If you want to create only a tag name, the
4191                     value for that tag should be the empty string
4192                     (e.g. '').
4193
4194        :type dry_run: bool
4195        :param dry_run: Set to True if the operation should not actually run.
4196
4197        """
4198        params = {}
4199        self.build_list_params(params, resource_ids, 'ResourceId')
4200        self.build_tag_param_list(params, tags)
4201        if dry_run:
4202            params['DryRun'] = 'true'
4203        return self.get_status('CreateTags', params, verb='POST')
4204
4205    def delete_tags(self, resource_ids, tags, dry_run=False):
4206        """
4207        Delete metadata tags for the specified resource ids.
4208
4209        :type resource_ids: list
4210        :param resource_ids: List of strings
4211
4212        :type tags: dict or list
4213        :param tags: Either a dictionary containing name/value pairs
4214                     or a list containing just tag names.
4215                     If you pass in a dictionary, the values must
4216                     match the actual tag values or the tag will
4217                     not be deleted.  If you pass in a value of None
4218                     for the tag value, all tags with that name will
4219                     be deleted.
4220
4221        :type dry_run: bool
4222        :param dry_run: Set to True if the operation should not actually run.
4223
4224        """
4225        if isinstance(tags, list):
4226            tags = {}.fromkeys(tags, None)
4227        params = {}
4228        self.build_list_params(params, resource_ids, 'ResourceId')
4229        self.build_tag_param_list(params, tags)
4230        if dry_run:
4231            params['DryRun'] = 'true'
4232        return self.get_status('DeleteTags', params, verb='POST')
4233
4234    # Network Interface methods
4235
4236    def get_all_network_interfaces(self, network_interface_ids=None, filters=None, dry_run=False):
4237        """
4238        Retrieve all of the Elastic Network Interfaces (ENI's)
4239        associated with your account.
4240
4241        :type network_interface_ids: list
4242        :param network_interface_ids: a list of strings representing ENI IDs
4243
4244        :type filters: dict
4245        :param filters: Optional filters that can be used to limit
4246                        the results returned.  Filters are provided
4247                        in the form of a dictionary consisting of
4248                        filter names as the key and filter values
4249                        as the value.  The set of allowable filter
4250                        names/values is dependent on the request
4251                        being performed.  Check the EC2 API guide
4252                        for details.
4253
4254        :type dry_run: bool
4255        :param dry_run: Set to True if the operation should not actually run.
4256
4257        :rtype: list
4258        :return: A list of :class:`boto.ec2.networkinterface.NetworkInterface`
4259        """
4260        params = {}
4261        if network_interface_ids:
4262            self.build_list_params(params, network_interface_ids, 'NetworkInterfaceId')
4263        if filters:
4264            self.build_filter_params(params, filters)
4265        if dry_run:
4266            params['DryRun'] = 'true'
4267        return self.get_list('DescribeNetworkInterfaces', params,
4268                             [('item', NetworkInterface)], verb='POST')
4269
4270    def create_network_interface(self, subnet_id, private_ip_address=None,
4271                                 description=None, groups=None, dry_run=False):
4272        """
4273        Creates a network interface in the specified subnet.
4274
4275        :type subnet_id: str
4276        :param subnet_id: The ID of the subnet to associate with the
4277            network interface.
4278
4279        :type private_ip_address: str
4280        :param private_ip_address: The private IP address of the
4281            network interface.  If not supplied, one will be chosen
4282            for you.
4283
4284        :type description: str
4285        :param description: The description of the network interface.
4286
4287        :type groups: list
4288        :param groups: Lists the groups for use by the network interface.
4289            This can be either a list of group ID's or a list of
4290            :class:`boto.ec2.securitygroup.SecurityGroup` objects.
4291
4292        :type dry_run: bool
4293        :param dry_run: Set to True if the operation should not actually run.
4294
4295        :rtype: :class:`boto.ec2.networkinterface.NetworkInterface`
4296        :return: The newly created network interface.
4297        """
4298        params = {'SubnetId': subnet_id}
4299        if private_ip_address:
4300            params['PrivateIpAddress'] = private_ip_address
4301        if description:
4302            params['Description'] = description
4303        if groups:
4304            ids = []
4305            for group in groups:
4306                if isinstance(group, SecurityGroup):
4307                    ids.append(group.id)
4308                else:
4309                    ids.append(group)
4310            self.build_list_params(params, ids, 'SecurityGroupId')
4311        if dry_run:
4312            params['DryRun'] = 'true'
4313        return self.get_object('CreateNetworkInterface', params,
4314                               NetworkInterface, verb='POST')
4315
4316    def attach_network_interface(self, network_interface_id,
4317                                 instance_id, device_index, dry_run=False):
4318        """
4319        Attaches a network interface to an instance.
4320
4321        :type network_interface_id: str
4322        :param network_interface_id: The ID of the network interface to attach.
4323
4324        :type instance_id: str
4325        :param instance_id: The ID of the instance that will be attached
4326            to the network interface.
4327
4328        :type device_index: int
4329        :param device_index: The index of the device for the network
4330            interface attachment on the instance.
4331
4332        :type dry_run: bool
4333        :param dry_run: Set to True if the operation should not actually run.
4334
4335        """
4336        params = {'NetworkInterfaceId': network_interface_id,
4337                  'InstanceId': instance_id,
4338                  'DeviceIndex': device_index}
4339        if dry_run:
4340            params['DryRun'] = 'true'
4341        return self.get_status('AttachNetworkInterface', params, verb='POST')
4342
4343    def detach_network_interface(self, attachment_id, force=False,
4344                                 dry_run=False):
4345        """
4346        Detaches a network interface from an instance.
4347
4348        :type attachment_id: str
4349        :param attachment_id: The ID of the attachment.
4350
4351        :type force: bool
4352        :param force: Set to true to force a detachment.
4353
4354        :type dry_run: bool
4355        :param dry_run: Set to True if the operation should not actually run.
4356
4357        """
4358        params = {'AttachmentId': attachment_id}
4359        if force:
4360            params['Force'] = 'true'
4361        if dry_run:
4362            params['DryRun'] = 'true'
4363        return self.get_status('DetachNetworkInterface', params, verb='POST')
4364
4365    def delete_network_interface(self, network_interface_id, dry_run=False):
4366        """
4367        Delete the specified network interface.
4368
4369        :type network_interface_id: str
4370        :param network_interface_id: The ID of the network interface to delete.
4371
4372        :type dry_run: bool
4373        :param dry_run: Set to True if the operation should not actually run.
4374
4375        """
4376        params = {'NetworkInterfaceId': network_interface_id}
4377        if dry_run:
4378            params['DryRun'] = 'true'
4379        return self.get_status('DeleteNetworkInterface', params, verb='POST')
4380
4381    def get_all_instance_types(self):
4382        """
4383        Get all instance_types available on this cloud (eucalyptus specific)
4384
4385        :rtype: list of :class:`boto.ec2.instancetype.InstanceType`
4386        :return: The requested InstanceType objects
4387        """
4388        params = {}
4389        return self.get_list('DescribeInstanceTypes', params, [('item', InstanceType)], verb='POST')
4390
4391    def copy_image(self, source_region, source_image_id, name=None,
4392                   description=None, client_token=None, dry_run=False):
4393        """
4394        :type dry_run: bool
4395        :param dry_run: Set to True if the operation should not actually run.
4396        :rtype: :class:`boto.ec2.image.CopyImage`
4397        :return: Object containing the image_id of the copied image.
4398        """
4399        params = {
4400            'SourceRegion': source_region,
4401            'SourceImageId': source_image_id,
4402        }
4403        if name is not None:
4404            params['Name'] = name
4405        if description is not None:
4406            params['Description'] = description
4407        if client_token is not None:
4408            params['ClientToken'] = client_token
4409        if dry_run:
4410            params['DryRun'] = 'true'
4411        return self.get_object('CopyImage', params, CopyImage,
4412                               verb='POST')
4413
4414    def describe_account_attributes(self, attribute_names=None, dry_run=False):
4415        """
4416        :type dry_run: bool
4417        :param dry_run: Set to True if the operation should not actually run.
4418
4419        """
4420        params = {}
4421        if attribute_names is not None:
4422            self.build_list_params(params, attribute_names, 'AttributeName')
4423        if dry_run:
4424            params['DryRun'] = 'true'
4425        return self.get_list('DescribeAccountAttributes', params,
4426                             [('item', AccountAttribute)], verb='POST')
4427
4428    def describe_vpc_attribute(self, vpc_id, attribute=None, dry_run=False):
4429        """
4430        :type dry_run: bool
4431        :param dry_run: Set to True if the operation should not actually run.
4432
4433        """
4434        params = {
4435            'VpcId': vpc_id
4436        }
4437        if attribute is not None:
4438            params['Attribute'] = attribute
4439        if dry_run:
4440            params['DryRun'] = 'true'
4441        return self.get_object('DescribeVpcAttribute', params,
4442                               VPCAttribute, verb='POST')
4443
4444    def modify_vpc_attribute(self, vpc_id, enable_dns_support=None,
4445                             enable_dns_hostnames=None, dry_run=False):
4446        """
4447        :type dry_run: bool
4448        :param dry_run: Set to True if the operation should not actually run.
4449
4450        """
4451        params = {
4452            'VpcId': vpc_id
4453        }
4454        if enable_dns_support is not None:
4455            params['EnableDnsSupport.Value'] = (
4456                'true' if enable_dns_support else 'false')
4457        if enable_dns_hostnames is not None:
4458            params['EnableDnsHostnames.Value'] = (
4459                'true' if enable_dns_hostnames else 'false')
4460        if dry_run:
4461            params['DryRun'] = 'true'
4462        return self.get_status('ModifyVpcAttribute', params, verb='POST')
4463
4464    def get_all_classic_link_instances(self, instance_ids=None, filters=None,
4465                                       dry_run=False, max_results=None,
4466                                       next_token=None):
4467        """
4468        Get all of your linked EC2-Classic instances. This request only
4469        returns information about EC2-Classic instances linked  to
4470        a VPC through ClassicLink
4471
4472        :type instance_ids: list
4473        :param instance_ids: A list of strings of instance IDs. Must be
4474            instances linked to a VPC through ClassicLink.
4475
4476        :type filters: dict
4477        :param filters: Optional filters that can be used to limit the
4478            results returned.  Filters are provided in the form of a
4479            dictionary consisting of filter names as the key and
4480            filter values as the value.  The set of allowable filter
4481            names/values is dependent on the request being performed.
4482            Check the EC2 API guide for details.
4483
4484        :type dry_run: bool
4485        :param dry_run: Set to True if the operation should not actually run.
4486
4487        :type max_results: int
4488        :param max_results: The maximum number of paginated instance
4489            items per response.
4490
4491        :rtype: list
4492        :return: A list of  :class:`boto.ec2.instance.Instance`
4493        """
4494        params = {}
4495        if instance_ids:
4496            self.build_list_params(params, instance_ids, 'InstanceId')
4497        if filters:
4498            self.build_filter_params(params, filters)
4499        if dry_run:
4500            params['DryRun'] = 'true'
4501        if max_results is not None:
4502            params['MaxResults'] = max_results
4503        if next_token:
4504            params['NextToken'] = next_token
4505        return self.get_list('DescribeClassicLinkInstances', params,
4506                             [('item', Instance)], verb='POST')
4507