OLD | NEW |
1 # Copyright (c) 2009 Reza Lotun http://reza.lotun.name/ | 1 # Copyright (c) 2009-2011 Reza Lotun http://reza.lotun.name/ |
2 # | 2 # |
3 # Permission is hereby granted, free of charge, to any person obtaining a | 3 # Permission is hereby granted, free of charge, to any person obtaining a |
4 # copy of this software and associated documentation files (the | 4 # copy of this software and associated documentation files (the |
5 # "Software"), to deal in the Software without restriction, including | 5 # "Software"), to deal in the Software without restriction, including |
6 # without limitation the rights to use, copy, modify, merge, publish, dis- | 6 # without limitation the rights to use, copy, modify, merge, publish, dis- |
7 # tribute, sublicense, and/or sell copies of the Software, and to permit | 7 # tribute, sublicense, and/or sell copies of the Software, and to permit |
8 # persons to whom the Software is furnished to do so, subject to the fol- | 8 # persons to whom the Software is furnished to do so, subject to the fol- |
9 # lowing conditions: | 9 # lowing conditions: |
10 # | 10 # |
11 # The above copyright notice and this permission notice shall be included | 11 # The above copyright notice and this permission notice shall be included |
12 # in all copies or substantial portions of the Software. | 12 # in all copies or substantial portions of the Software. |
13 # | 13 # |
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- | 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | 17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 # IN THE SOFTWARE. | 20 # IN THE SOFTWARE. |
21 | 21 |
22 import weakref | |
23 | 22 |
24 from boto.ec2.elb.listelement import ListElement | 23 from boto.ec2.elb.listelement import ListElement |
25 from boto.resultset import ResultSet | 24 from boto.resultset import ResultSet |
26 from boto.ec2.autoscale.trigger import Trigger | 25 from boto.ec2.autoscale.launchconfig import LaunchConfiguration |
27 from boto.ec2.autoscale.request import Request | 26 from boto.ec2.autoscale.request import Request |
| 27 from boto.ec2.autoscale.instance import Instance |
28 | 28 |
29 class Instance(object): | 29 |
| 30 class ProcessType(object): |
30 def __init__(self, connection=None): | 31 def __init__(self, connection=None): |
31 self.connection = connection | 32 self.connection = connection |
32 self.instance_id = '' | 33 self.process_name = None |
33 | 34 |
34 def __repr__(self): | 35 def __repr__(self): |
35 return 'Instance:%s' % self.instance_id | 36 return 'ProcessType(%s)' % self.process_name |
36 | 37 |
37 def startElement(self, name, attrs, connection): | 38 def startElement(self, name, attrs, connection): |
38 return None | 39 pass |
39 | 40 |
40 def endElement(self, name, value, connection): | 41 def endElement(self, name, value, connection): |
41 if name == 'InstanceId': | 42 if name == 'ProcessName': |
42 self.instance_id = value | 43 self.process_name = value |
43 else: | 44 |
44 setattr(self, name, value) | 45 |
| 46 class SuspendedProcess(object): |
| 47 def __init__(self, connection=None): |
| 48 self.connection = connection |
| 49 self.process_name = None |
| 50 self.reason = None |
| 51 |
| 52 def __repr__(self): |
| 53 return 'SuspendedProcess(%s, %s)' % (self.process_name, self.reason) |
| 54 |
| 55 def startElement(self, name, attrs, connection): |
| 56 pass |
| 57 |
| 58 def endElement(self, name, value, connection): |
| 59 if name == 'ProcessName': |
| 60 self.process_name = value |
| 61 elif name == 'SuspensionReason': |
| 62 self.reason = value |
| 63 |
| 64 |
| 65 class EnabledMetric(object): |
| 66 def __init__(self, connection=None, metric=None, granularity=None): |
| 67 self.connection = connection |
| 68 self.metric = metric |
| 69 self.granularity = granularity |
| 70 |
| 71 def __repr__(self): |
| 72 return 'EnabledMetric(%s, %s)' % (self.metric, self.granularity) |
| 73 |
| 74 def startElement(self, name, attrs, connection): |
| 75 pass |
| 76 |
| 77 def endElement(self, name, value, connection): |
| 78 if name == 'Granularity': |
| 79 self.granularity = value |
| 80 elif name == 'Metric': |
| 81 self.metric = value |
45 | 82 |
46 | 83 |
47 class AutoScalingGroup(object): | 84 class AutoScalingGroup(object): |
48 def __init__(self, connection=None, group_name=None, | 85 def __init__(self, connection=None, name=None, |
49 availability_zone=None, launch_config=None, | 86 launch_config=None, availability_zones=None, |
50 availability_zones=None, | 87 load_balancers=None, default_cooldown=None, |
51 load_balancers=None, cooldown=0, | 88 health_check_type=None, health_check_period=None, |
52 min_size=None, max_size=None): | 89 placement_group=None, vpc_zone_identifier=None, desired_capacit
y=None, |
| 90 min_size=None, max_size=None, **kwargs): |
53 """ | 91 """ |
54 Creates a new AutoScalingGroup with the specified name. | 92 Creates a new AutoScalingGroup with the specified name. |
55 | 93 |
56 You must not have already used up your entire quota of | 94 You must not have already used up your entire quota of |
57 AutoScalingGroups in order for this call to be successful. Once the | 95 AutoScalingGroups in order for this call to be successful. Once the |
58 creation request is completed, the AutoScalingGroup is ready to be | 96 creation request is completed, the AutoScalingGroup is ready to be |
59 used in other calls. | 97 used in other calls. |
60 | 98 |
61 :type name: str | 99 :type name: str |
62 :param name: Name of autoscaling group. | 100 :param name: Name of autoscaling group (required). |
63 | 101 |
64 :type availability_zone: str | 102 :type availability_zones: list |
65 :param availability_zone: An availability zone. DEPRECATED - use the | 103 :param availability_zones: List of availability zones (required). |
66 availability_zones parameter, which expects | |
67 a list of availability zone | |
68 strings | |
69 | 104 |
70 :type availability_zone: list | 105 :type default_cooldown: int |
71 :param availability_zone: List of availability zones. | 106 :param default_cooldown: Number of seconds after a Scaling Activity comp
letes |
| 107 before any further scaling activities can start
. |
72 | 108 |
73 :type launch_config: str | 109 :type desired_capacity: int |
74 :param launch_config: Name of launch configuration name. | 110 :param desired_capacity: The desired capacity for the group. |
| 111 |
| 112 :type health_check_period: str |
| 113 :param health_check_period: Length of time in seconds after a new EC2 in
stance |
| 114 comes into service that Auto Scaling starts
checking its |
| 115 health. |
| 116 |
| 117 :type health_check_type: str |
| 118 :param health_check_type: The service you want the health status from, |
| 119 Amazon EC2 or Elastic Load Balancer. |
| 120 |
| 121 :type launch_config: str or LaunchConfiguration |
| 122 :param launch_config: Name of launch configuration (required). |
| 123 |
75 | 124 |
76 :type load_balancers: list | 125 :type load_balancers: list |
77 :param load_balancers: List of load balancers. | 126 :param load_balancers: List of load balancers. |
78 | 127 |
79 :type minsize: int | 128 :type max_size: int |
80 :param minsize: Minimum size of group | 129 :param maxsize: Maximum size of group (required). |
81 | 130 |
82 :type maxsize: int | 131 :type min_size: int |
83 :param maxsize: Maximum size of group | 132 :param minsize: Minimum size of group (required). |
84 | 133 |
85 :type cooldown: int | 134 :type placement_group: str |
86 :param cooldown: Amount of time after a Scaling Activity completes | 135 :param placement_group: Physical location of your cluster placement |
87 before any further scaling activities can start. | 136 group created in Amazon EC2. |
88 | 137 |
89 :rtype: tuple | 138 :type vpc_zone_identifier: str |
90 :return: Updated healthcheck for the instances. | 139 :param vpc_zone_identifier: The subnet identifier of the Virtual Private
Cloud. |
| 140 |
| 141 :rtype: :class:`boto.ec2.autoscale.group.AutoScalingGroup` |
| 142 :return: An autoscale group. |
91 """ | 143 """ |
92 self.name = group_name | 144 self.name = name or kwargs.get('group_name') # backwards compatibility |
93 self.connection = connection | 145 self.connection = connection |
94 self.min_size = min_size | 146 self.min_size = int(min_size) if min_size is not None else None |
95 self.max_size = max_size | 147 self.max_size = int(max_size) if max_size is not None else None |
96 self.created_time = None | 148 self.created_time = None |
97 self.cooldown = cooldown | 149 default_cooldown = default_cooldown or kwargs.get('cooldown') # backwar
ds compatibility |
98 self.launch_config = launch_config | 150 self.default_cooldown = int(default_cooldown) if default_cooldown is not
None else None |
99 if self.launch_config: | 151 self.launch_config_name = launch_config |
100 self.launch_config_name = self.launch_config.name | 152 if launch_config and isinstance(launch_config, LaunchConfiguration): |
101 else: | 153 self.launch_config_name = launch_config.name |
102 self.launch_config_name = None | 154 self.desired_capacity = desired_capacity |
103 self.desired_capacity = None | |
104 lbs = load_balancers or [] | 155 lbs = load_balancers or [] |
105 self.load_balancers = ListElement(lbs) | 156 self.load_balancers = ListElement(lbs) |
106 zones = availability_zones or [] | 157 zones = availability_zones or [] |
107 self.availability_zone = availability_zone | |
108 self.availability_zones = ListElement(zones) | 158 self.availability_zones = ListElement(zones) |
| 159 self.health_check_period = health_check_period |
| 160 self.health_check_type = health_check_type |
| 161 self.placement_group = placement_group |
| 162 self.autoscaling_group_arn = None |
| 163 self.vpc_zone_identifier = vpc_zone_identifier |
109 self.instances = None | 164 self.instances = None |
110 | 165 |
| 166 # backwards compatible access to 'cooldown' param |
| 167 def _get_cooldown(self): |
| 168 return self.default_cooldown |
| 169 def _set_cooldown(self, val): |
| 170 self.default_cooldown = val |
| 171 cooldown = property(_get_cooldown, _set_cooldown) |
| 172 |
111 def __repr__(self): | 173 def __repr__(self): |
112 return 'AutoScalingGroup:%s' % self.name | 174 return 'AutoScalingGroup<%s>: created:%s, minsize:%s, maxsize:%s, capaci
ty:%s' % (self.name, |
| 175
self.created_time, |
| 176
self.min_size, |
| 177
self.max_size, |
| 178
self.desired_capacity) |
113 | 179 |
114 def startElement(self, name, attrs, connection): | 180 def startElement(self, name, attrs, connection): |
115 if name == 'Instances': | 181 if name == 'Instances': |
116 self.instances = ResultSet([('member', Instance)]) | 182 self.instances = ResultSet([('member', Instance)]) |
117 return self.instances | 183 return self.instances |
118 elif name == 'LoadBalancerNames': | 184 elif name == 'LoadBalancerNames': |
119 return self.load_balancers | 185 return self.load_balancers |
120 elif name == 'AvailabilityZones': | 186 elif name == 'AvailabilityZones': |
121 return self.availability_zones | 187 return self.availability_zones |
| 188 elif name == 'EnabledMetrics': |
| 189 self.enabled_metrics = ResultSet([('member', EnabledMetric)]) |
| 190 return self.enabled_metrics |
| 191 elif name == 'SuspendedProcesses': |
| 192 self.suspended_processes = ResultSet([('member', SuspendedProcess)]) |
| 193 return self.suspended_processes |
122 else: | 194 else: |
123 return | 195 return |
124 | 196 |
125 def endElement(self, name, value, connection): | 197 def endElement(self, name, value, connection): |
126 if name == 'MinSize': | 198 if name == 'MinSize': |
127 self.min_size = value | 199 self.min_size = int(value) |
| 200 elif name == 'AutoScalingGroupARN': |
| 201 self.autoscaling_group_arn = value |
128 elif name == 'CreatedTime': | 202 elif name == 'CreatedTime': |
129 self.created_time = value | 203 self.created_time = value |
130 elif name == 'Cooldown': | 204 elif name == 'DefaultCooldown': |
131 self.cooldown = value | 205 self.default_cooldown = int(value) |
132 elif name == 'LaunchConfigurationName': | 206 elif name == 'LaunchConfigurationName': |
133 self.launch_config_name = value | 207 self.launch_config_name = value |
134 elif name == 'DesiredCapacity': | 208 elif name == 'DesiredCapacity': |
135 self.desired_capacity = value | 209 self.desired_capacity = int(value) |
136 elif name == 'MaxSize': | 210 elif name == 'MaxSize': |
137 self.max_size = value | 211 self.max_size = int(value) |
138 elif name == 'AutoScalingGroupName': | 212 elif name == 'AutoScalingGroupName': |
139 self.name = value | 213 self.name = value |
| 214 elif name == 'PlacementGroup': |
| 215 self.placement_group = value |
| 216 elif name == 'HealthCheckGracePeriod': |
| 217 self.health_check_period = int(value) |
| 218 elif name == 'HealthCheckType': |
| 219 self.health_check_type = value |
| 220 elif name == 'VPCZoneIdentifier': |
| 221 self.vpc_zone_identifier = value |
140 else: | 222 else: |
141 setattr(self, name, value) | 223 setattr(self, name, value) |
142 | 224 |
143 def set_capacity(self, capacity): | 225 def set_capacity(self, capacity): |
144 """ Set the desired capacity for the group. """ | 226 """ Set the desired capacity for the group. """ |
145 params = { | 227 params = { |
146 'AutoScalingGroupName' : self.name, | 228 'AutoScalingGroupName' : self.name, |
147 'DesiredCapacity' : capacity, | 229 'DesiredCapacity' : capacity, |
148 } | 230 } |
149 req = self.connection.get_object('SetDesiredCapacity', params, | 231 req = self.connection.get_object('SetDesiredCapacity', params, |
150 Request) | 232 Request) |
151 self.connection.last_request = req | 233 self.connection.last_request = req |
152 return req | 234 return req |
153 | 235 |
154 def update(self): | 236 def update(self): |
155 """ Sync local changes with AutoScaling group. """ | 237 """ Sync local changes with AutoScaling group. """ |
156 return self.connection._update_group('UpdateAutoScalingGroup', self) | 238 return self.connection._update_group('UpdateAutoScalingGroup', self) |
157 | 239 |
158 def shutdown_instances(self): | 240 def shutdown_instances(self): |
159 """ Convenience method which shuts down all instances associated with | 241 """ Convenience method which shuts down all instances associated with |
160 this group. | 242 this group. |
161 """ | 243 """ |
162 self.min_size = 0 | 244 self.min_size = 0 |
163 self.max_size = 0 | 245 self.max_size = 0 |
| 246 self.desired_capacity = 0 |
164 self.update() | 247 self.update() |
165 | 248 |
166 def get_all_triggers(self): | 249 def delete(self, force_delete=False): |
167 """ Get all triggers for this auto scaling group. """ | 250 """ Delete this auto-scaling group if no instances attached or no |
168 params = {'AutoScalingGroupName' : self.name} | 251 scaling activities in progress. |
169 triggers = self.connection.get_list('DescribeTriggers', params, | 252 """ |
170 [('member', Trigger)]) | 253 return self.connection.delete_auto_scaling_group(self.name, force_delete
) |
171 | 254 |
172 # allow triggers to be able to access the autoscale group | 255 def get_activities(self, activity_ids=None, max_records=50): |
173 for tr in triggers: | |
174 tr.autoscale_group = weakref.proxy(self) | |
175 | |
176 return triggers | |
177 | |
178 def delete(self): | |
179 """ Delete this auto-scaling group. """ | |
180 params = {'AutoScalingGroupName' : self.name} | |
181 return self.connection.get_object('DeleteAutoScalingGroup', params, | |
182 Request) | |
183 | |
184 def get_activities(self, activity_ids=None, max_records=100): | |
185 """ | 256 """ |
186 Get all activies for this group. | 257 Get all activies for this group. |
187 """ | 258 """ |
188 return self.connection.get_all_activities(self, activity_ids, max_record
s) | 259 return self.connection.get_all_activities(self, activity_ids, max_record
s) |
189 | 260 |
| 261 def suspend_processes(self, scaling_processes=None): |
| 262 """ Suspends Auto Scaling processes for an Auto Scaling group. """ |
| 263 return self.connection.suspend_processes(self.name, scaling_processes) |
| 264 |
| 265 def resume_processes(self, scaling_processes=None): |
| 266 """ Resumes Auto Scaling processes for an Auto Scaling group. """ |
| 267 return self.connection.resume_processes(self.name, scaling_processes) |
| 268 |
| 269 |
| 270 class AutoScalingGroupMetric(object): |
| 271 def __init__(self, connection=None): |
| 272 |
| 273 self.connection = connection |
| 274 self.metric = None |
| 275 self.granularity = None |
| 276 |
| 277 def __repr__(self): |
| 278 return 'AutoScalingGroupMetric:%s' % self.metric |
| 279 |
| 280 def startElement(self, name, attrs, connection): |
| 281 return |
| 282 |
| 283 def endElement(self, name, value, connection): |
| 284 if name == 'Metric': |
| 285 self.metric = value |
| 286 elif name == 'Granularity': |
| 287 self.granularity = value |
| 288 else: |
| 289 setattr(self, name, value) |
| 290 |
OLD | NEW |