1# Copyright (c) 2009 Reza Lotun http://reza.lotun.name/
2# Copyright (c) 2012 Amazon.com, Inc. or its affiliates.  All Rights Reserved
3#
4# Permission is hereby granted, free of charge, to any person obtaining a
5# copy of this software and associated documentation files (the
6# "Software"), to deal in the Software without restriction, including
7# without limitation the rights to use, copy, modify, merge, publish, dis-
8# tribute, sublicense, and/or sell copies of the Software, and to permit
9# persons to whom the Software is furnished to do so, subject to the fol-
10# lowing conditions:
11#
12# The above copyright notice and this permission notice shall be included
13# in all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21# IN THE SOFTWARE.
22
23from boto.ec2.elb.listelement import ListElement
24# Namespacing issue with deprecated local class
25from boto.ec2.blockdevicemapping import BlockDeviceMapping as BDM
26from boto.resultset import ResultSet
27import boto.utils
28import base64
29
30
31# this should use the corresponding object from boto.ec2
32# Currently in use by deprecated local BlockDeviceMapping class
33class Ebs(object):
34    def __init__(self, connection=None, snapshot_id=None, volume_size=None):
35        self.connection = connection
36        self.snapshot_id = snapshot_id
37        self.volume_size = volume_size
38
39    def __repr__(self):
40        return 'Ebs(%s, %s)' % (self.snapshot_id, self.volume_size)
41
42    def startElement(self, name, attrs, connection):
43        pass
44
45    def endElement(self, name, value, connection):
46        if name == 'SnapshotId':
47            self.snapshot_id = value
48        elif name == 'VolumeSize':
49            self.volume_size = value
50
51
52class InstanceMonitoring(object):
53    def __init__(self, connection=None, enabled='false'):
54        self.connection = connection
55        self.enabled = enabled
56
57    def __repr__(self):
58        return 'InstanceMonitoring(%s)' % self.enabled
59
60    def startElement(self, name, attrs, connection):
61        pass
62
63    def endElement(self, name, value, connection):
64        if name == 'Enabled':
65            self.enabled = value
66
67
68# this should use the BlockDeviceMapping from boto.ec2.blockdevicemapping
69# Currently in use by deprecated code for backwards compatability
70# Removing this class can also remove the Ebs class in this same file
71class BlockDeviceMapping(object):
72    def __init__(self, connection=None, device_name=None, virtual_name=None,
73                 ebs=None, no_device=None):
74        self.connection = connection
75        self.device_name = device_name
76        self.virtual_name = virtual_name
77        self.ebs = ebs
78        self.no_device = no_device
79
80    def __repr__(self):
81        return 'BlockDeviceMapping(%s, %s)' % (self.device_name,
82                                               self.virtual_name)
83
84    def startElement(self, name, attrs, connection):
85        if name == 'Ebs':
86            self.ebs = Ebs(self)
87            return self.ebs
88
89    def endElement(self, name, value, connection):
90        if name == 'DeviceName':
91            self.device_name = value
92        elif name == 'VirtualName':
93            self.virtual_name = value
94        elif name == 'NoDevice':
95            self.no_device = bool(value)
96
97
98class LaunchConfiguration(object):
99    def __init__(self, connection=None, name=None, image_id=None,
100                 key_name=None, security_groups=None, user_data=None,
101                 instance_type='m1.small', kernel_id=None,
102                 ramdisk_id=None, block_device_mappings=None,
103                 instance_monitoring=False, spot_price=None,
104                 instance_profile_name=None, ebs_optimized=False,
105                 associate_public_ip_address=None, volume_type=None,
106                 delete_on_termination=True, iops=None,
107                 use_block_device_types=False, classic_link_vpc_id=None,
108                 classic_link_vpc_security_groups=None):
109        """
110        A launch configuration.
111
112        :type name: str
113        :param name: Name of the launch configuration to create.
114
115        :type image_id: str
116        :param image_id: Unique ID of the Amazon Machine Image (AMI) which was
117            assigned during registration.
118
119        :type key_name: str
120        :param key_name: The name of the EC2 key pair.
121
122        :type security_groups: list
123        :param security_groups: Names or security group id's of the security
124            groups with which to associate the EC2 instances or VPC instances,
125            respectively.
126
127        :type user_data: str
128        :param user_data: The user data available to launched EC2 instances.
129
130        :type instance_type: str
131        :param instance_type: The instance type
132
133        :type kernel_id: str
134        :param kernel_id: Kernel id for instance
135
136        :type ramdisk_id: str
137        :param ramdisk_id: RAM disk id for instance
138
139        :type block_device_mappings: list
140        :param block_device_mappings: Specifies how block devices are exposed
141            for instances
142
143        :type instance_monitoring: bool
144        :param instance_monitoring: Whether instances in group are launched
145            with detailed monitoring.
146
147        :type spot_price: float
148        :param spot_price: The spot price you are bidding.  Only applies
149            if you are building an autoscaling group with spot instances.
150
151        :type instance_profile_name: string
152        :param instance_profile_name: The name or the Amazon Resource
153            Name (ARN) of the instance profile associated with the IAM
154            role for the instance.
155
156        :type ebs_optimized: bool
157        :param ebs_optimized: Specifies whether the instance is optimized
158            for EBS I/O (true) or not (false).
159
160
161        :type associate_public_ip_address: bool
162        :param associate_public_ip_address: Used for Auto Scaling groups that launch instances into an Amazon Virtual Private Cloud.
163            Specifies whether to assign a public IP address to each instance launched in a Amazon VPC.
164
165        :type classic_link_vpc_id: str
166        :param classic_link_vpc_id: ID of ClassicLink enabled VPC.
167
168        :type classic_link_vpc_security_groups: list
169        :param classic_link_vpc_security_groups: Security group
170            id's of the security groups with which to associate the
171            ClassicLink VPC instances.
172        """
173        self.connection = connection
174        self.name = name
175        self.instance_type = instance_type
176        self.block_device_mappings = block_device_mappings
177        self.key_name = key_name
178        sec_groups = security_groups or []
179        self.security_groups = ListElement(sec_groups)
180        self.image_id = image_id
181        self.ramdisk_id = ramdisk_id
182        self.created_time = None
183        self.kernel_id = kernel_id
184        self.user_data = user_data
185        self.created_time = None
186        self.instance_monitoring = instance_monitoring
187        self.spot_price = spot_price
188        self.instance_profile_name = instance_profile_name
189        self.launch_configuration_arn = None
190        self.ebs_optimized = ebs_optimized
191        self.associate_public_ip_address = associate_public_ip_address
192        self.volume_type = volume_type
193        self.delete_on_termination = delete_on_termination
194        self.iops = iops
195        self.use_block_device_types = use_block_device_types
196        self.classic_link_vpc_id = classic_link_vpc_id
197        classic_link_vpc_sec_groups = classic_link_vpc_security_groups or []
198        self.classic_link_vpc_security_groups = \
199            ListElement(classic_link_vpc_sec_groups)
200
201        if connection is not None:
202            self.use_block_device_types = connection.use_block_device_types
203
204    def __repr__(self):
205        return 'LaunchConfiguration:%s' % self.name
206
207    def startElement(self, name, attrs, connection):
208        if name == 'SecurityGroups':
209            return self.security_groups
210        elif name == 'ClassicLinkVPCSecurityGroups':
211            return self.classic_link_vpc_security_groups
212        elif name == 'BlockDeviceMappings':
213            if self.use_block_device_types:
214                self.block_device_mappings = BDM()
215            else:
216                self.block_device_mappings = ResultSet([('member', BlockDeviceMapping)])
217            return self.block_device_mappings
218        elif name == 'InstanceMonitoring':
219            self.instance_monitoring = InstanceMonitoring(self)
220            return self.instance_monitoring
221
222    def endElement(self, name, value, connection):
223        if name == 'InstanceType':
224            self.instance_type = value
225        elif name == 'LaunchConfigurationName':
226            self.name = value
227        elif name == 'KeyName':
228            self.key_name = value
229        elif name == 'ImageId':
230            self.image_id = value
231        elif name == 'CreatedTime':
232            self.created_time = boto.utils.parse_ts(value)
233        elif name == 'KernelId':
234            self.kernel_id = value
235        elif name == 'RamdiskId':
236            self.ramdisk_id = value
237        elif name == 'UserData':
238            try:
239                self.user_data = base64.b64decode(value)
240            except TypeError:
241                self.user_data = value
242        elif name == 'LaunchConfigurationARN':
243            self.launch_configuration_arn = value
244        elif name == 'InstanceMonitoring':
245            self.instance_monitoring = value
246        elif name == 'SpotPrice':
247            self.spot_price = float(value)
248        elif name == 'IamInstanceProfile':
249            self.instance_profile_name = value
250        elif name == 'EbsOptimized':
251            self.ebs_optimized = True if value.lower() == 'true' else False
252        elif name == 'AssociatePublicIpAddress':
253            self.associate_public_ip_address = True if value.lower() == 'true' else False
254        elif name == 'VolumeType':
255            self.volume_type = value
256        elif name == 'DeleteOnTermination':
257            if value.lower() == 'true':
258                self.delete_on_termination = True
259            else:
260                self.delete_on_termination = False
261        elif name == 'Iops':
262            self.iops = int(value)
263        elif name == 'ClassicLinkVPCId':
264            self.classic_link_vpc_id = value
265        else:
266            setattr(self, name, value)
267
268    def delete(self):
269        """ Delete this launch configuration. """
270        return self.connection.delete_launch_configuration(self.name)
271