18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2011 Mitch Garnaat http://garnaat.org/
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2012 Amazon.com, Inc. or its affiliates.  All Rights Reserved
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Permission is hereby granted, free of charge, to any person obtaining a
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# copy of this software and associated documentation files (the
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# "Software"), to deal in the Software without restriction, including
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# without limitation the rights to use, copy, modify, merge, publish, dis-
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# tribute, sublicense, and/or sell copies of the Software, and to permit
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# persons to whom the Software is furnished to do so, subject to the fol-
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# lowing conditions:
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# The above copyright notice and this permission notice shall be included
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# in all copies or substantial portions of the Software.
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# IN THE SOFTWARE.
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiRepresents an EC2 Elastic Network Interface
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.exception import BotoClientError
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.ec2.ec2object import TaggedEC2Object
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.resultset import ResultSet
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.ec2.group import Group
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass Attachment(object):
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar id: The ID of the attachment.
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar instance_id: The ID of the instance.
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar device_index: The index of this device.
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar status: The status of the device.
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar attach_time: The time the device was attached.
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar delete_on_termination: Whether the device will be deleted
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        when the instance is terminated.
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self):
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.id = None
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.instance_id = None
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.instance_owner_id = None
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.device_index = 0
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.status = None
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.attach_time = None
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.delete_on_termination = False
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __repr__(self):
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return 'Attachment:%s' % self.id
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def startElement(self, name, attrs, connection):
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return None
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def endElement(self, name, value, connection):
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if name == 'attachmentId':
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.id = value
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'instanceId':
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.instance_id = value
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'deviceIndex':
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.device_index = int(value)
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'instanceOwnerId':
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.instance_owner_id = value
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'status':
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.status = value
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'attachTime':
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.attach_time = value
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'deleteOnTermination':
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if value.lower() == 'true':
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.delete_on_termination = True
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.delete_on_termination = False
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            setattr(self, name, value)
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass NetworkInterface(TaggedEC2Object):
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    An Elastic Network Interface.
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar id: The ID of the ENI.
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar subnet_id: The ID of the VPC subnet.
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar vpc_id: The ID of the VPC.
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar description: The description.
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar owner_id: The ID of the owner of the ENI.
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar requester_managed:
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar status: The interface's status (available|in-use).
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar mac_address: The MAC address of the interface.
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar private_ip_address: The IP address of the interface within
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        the subnet.
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar source_dest_check: Flag to indicate whether to validate
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        network traffic to or from this network interface.
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar groups: List of security groups associated with the interface.
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar attachment: The attachment object.
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    :ivar private_ip_addresses: A list of PrivateIPAddress objects.
998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
1008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, connection=None):
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        super(NetworkInterface, self).__init__(connection)
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.id = None
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.subnet_id = None
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.vpc_id = None
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.availability_zone = None
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.description = None
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.owner_id = None
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.requester_managed = False
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.status = None
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.mac_address = None
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.private_ip_address = None
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.source_dest_check = None
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.groups = []
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.attachment = None
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.private_ip_addresses = []
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __repr__(self):
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return 'NetworkInterface:%s' % self.id
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def startElement(self, name, attrs, connection):
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        retval = super(NetworkInterface, self).startElement(name, attrs, connection)
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if retval is not None:
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return retval
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if name == 'groupSet':
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.groups = ResultSet([('item', Group)])
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self.groups
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'attachment':
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.attachment = Attachment()
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self.attachment
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'privateIpAddressesSet':
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.private_ip_addresses = ResultSet([('item', PrivateIPAddress)])
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self.private_ip_addresses
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return None
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def endElement(self, name, value, connection):
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if name == 'networkInterfaceId':
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.id = value
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'subnetId':
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.subnet_id = value
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'vpcId':
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.vpc_id = value
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'availabilityZone':
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.availability_zone = value
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'description':
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.description = value
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'ownerId':
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.owner_id = value
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'requesterManaged':
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if value.lower() == 'true':
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.requester_managed = True
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.requester_managed = False
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'status':
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.status = value
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'macAddress':
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.mac_address = value
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'privateIpAddress':
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.private_ip_address = value
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'sourceDestCheck':
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if value.lower() == 'true':
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.source_dest_check = True
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.source_dest_check = False
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            setattr(self, name, value)
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _update(self, updated):
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.__dict__.update(updated.__dict__)
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def update(self, validate=False, dry_run=False):
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Update the data associated with this ENI by querying EC2.
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type validate: bool
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param validate: By default, if EC2 returns no data about the
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         ENI the update method returns quietly.  If
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         the validate param is True, however, it will
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         raise a ValueError exception if no data is
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                         returned from EC2.
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        rs = self.connection.get_all_network_interfaces(
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            [self.id],
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            dry_run=dry_run
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        )
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if len(rs) > 0:
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self._update(rs[0])
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif validate:
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise ValueError('%s is not a valid ENI ID' % self.id)
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.status
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def attach(self, instance_id, device_index, dry_run=False):
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Attach this ENI to an EC2 instance.
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type instance_id: str
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param instance_id: The ID of the EC2 instance to which it will
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            be attached.
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type device_index: int
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param device_index: The interface nunber, N, on the instance (eg. ethN)
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :rtype: bool
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :return: True if successful
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.connection.attach_network_interface(
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.id,
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            instance_id,
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            device_index,
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            dry_run=dry_run
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        )
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def detach(self, force=False, dry_run=False):
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Detach this ENI from an EC2 instance.
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type force: bool
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param force: Forces detachment if the previous detachment
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                      attempt did not occur cleanly.
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :rtype: bool
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :return: True if successful
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        attachment_id = getattr(self.attachment, 'id', None)
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.connection.detach_network_interface(
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            attachment_id,
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            force,
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            dry_run=dry_run
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        )
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def delete(self, dry_run=False):
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.connection.delete_network_interface(
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.id,
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            dry_run=dry_run
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        )
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass PrivateIPAddress(object):
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, connection=None, private_ip_address=None,
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 primary=None):
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.connection = connection
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.private_ip_address = private_ip_address
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.primary = primary
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def startElement(self, name, attrs, connection):
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        pass
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def endElement(self, name, value, connection):
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if name == 'privateIpAddress':
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.private_ip_address = value
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif name == 'primary':
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.primary = True if value.lower() == 'true' else False
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __repr__(self):
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return "PrivateIPAddress(%s, primary=%s)" % (self.private_ip_address,
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                     self.primary)
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass NetworkInterfaceCollection(list):
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, *interfaces):
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.extend(interfaces)
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def build_list_params(self, params, prefix=''):
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for i, spec in enumerate(self):
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            full_prefix = '%sNetworkInterface.%s.' % (prefix, i)
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.network_interface_id is not None:
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'NetworkInterfaceId'] = \
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        str(spec.network_interface_id)
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.device_index is not None:
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'DeviceIndex'] = \
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        str(spec.device_index)
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'DeviceIndex'] = 0
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.subnet_id is not None:
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'SubnetId'] = str(spec.subnet_id)
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.description is not None:
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'Description'] = str(spec.description)
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.delete_on_termination is not None:
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'DeleteOnTermination'] = \
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        'true' if spec.delete_on_termination else 'false'
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.secondary_private_ip_address_count is not None:
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'SecondaryPrivateIpAddressCount'] = \
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        str(spec.secondary_private_ip_address_count)
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.private_ip_address is not None:
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_prefix + 'PrivateIpAddress'] = \
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        str(spec.private_ip_address)
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.groups is not None:
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                for j, group_id in enumerate(spec.groups):
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    query_param_key = '%sSecurityGroupId.%s' % (full_prefix, j)
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    params[query_param_key] = str(group_id)
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.private_ip_addresses is not None:
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                for k, ip_addr in enumerate(spec.private_ip_addresses):
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    query_param_key_prefix = (
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        '%sPrivateIpAddresses.%s' % (full_prefix, k))
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    params[query_param_key_prefix + '.PrivateIpAddress'] = \
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            str(ip_addr.private_ip_address)
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if ip_addr.primary is not None:
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        params[query_param_key_prefix + '.Primary'] = \
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                'true' if ip_addr.primary else 'false'
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Associating Public IPs have special logic around them:
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            #
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # * Only assignable on an device_index of ``0``
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # * Only on one interface
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # * Only if there are no other interfaces being created
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # * Only if it's a new interface (which we can't really guard
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            #   against)
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            #
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # More details on http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-RunInstances.html
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if spec.associate_public_ip_address is not None:
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if not params[full_prefix + 'DeviceIndex'] in (0, '0'):
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    raise BotoClientError(
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        "Only the interface with device index of 0 can " + \
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        "be provided when using " + \
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        "'associate_public_ip_address'."
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    )
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if len(self) > 1:
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    raise BotoClientError(
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        "Only one interface can be provided when using " + \
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        "'associate_public_ip_address'."
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    )
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                key = full_prefix + 'AssociatePublicIpAddress'
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if spec.associate_public_ip_address:
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    params[key] = 'true'
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                else:
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    params[key] = 'false'
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass NetworkInterfaceSpecification(object):
3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, network_interface_id=None, device_index=None,
3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 subnet_id=None, description=None, private_ip_address=None,
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 groups=None, delete_on_termination=None,
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 private_ip_addresses=None,
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 secondary_private_ip_address_count=None,
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 associate_public_ip_address=None):
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.network_interface_id = network_interface_id
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.device_index = device_index
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.subnet_id = subnet_id
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.description = description
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.private_ip_address = private_ip_address
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.groups = groups
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.delete_on_termination = delete_on_termination
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.private_ip_addresses = private_ip_addresses
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.secondary_private_ip_address_count = \
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                secondary_private_ip_address_count
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.associate_public_ip_address = associate_public_ip_address
352