| 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 |