1#!/usr/bin/python 2# Copyright: Ansible Project 3# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 4 5from __future__ import absolute_import, division, print_function 6__metaclass__ = type 7 8 9ANSIBLE_METADATA = {'metadata_version': '1.1', 10 'status': ['preview'], 11 'supported_by': 'community'} 12 13 14DOCUMENTATION = ''' 15--- 16module: ec2_asg_info 17short_description: Gather information about ec2 Auto Scaling Groups (ASGs) in AWS 18description: 19 - Gather information about ec2 Auto Scaling Groups (ASGs) in AWS 20 - This module was called C(ec2_asg_facts) before Ansible 2.9. The usage did not change. 21version_added: "2.2" 22requirements: [ boto3 ] 23author: "Rob White (@wimnat)" 24options: 25 name: 26 description: 27 - The prefix or name of the auto scaling group(s) you are searching for. 28 - "Note: This is a regular expression match with implicit '^' (beginning of string). Append '$' for a complete name match." 29 required: false 30 tags: 31 description: 32 - > 33 A dictionary/hash of tags in the format { tag1_name: 'tag1_value', tag2_name: 'tag2_value' } to match against the auto scaling 34 group(s) you are searching for. 35 required: false 36extends_documentation_fragment: 37 - aws 38 - ec2 39''' 40 41EXAMPLES = ''' 42# Note: These examples do not set authentication details, see the AWS Guide for details. 43 44# Find all groups 45- ec2_asg_info: 46 register: asgs 47 48# Find a group with matching name/prefix 49- ec2_asg_info: 50 name: public-webserver-asg 51 register: asgs 52 53# Find a group with matching tags 54- ec2_asg_info: 55 tags: 56 project: webapp 57 env: production 58 register: asgs 59 60# Find a group with matching name/prefix and tags 61- ec2_asg_info: 62 name: myproject 63 tags: 64 env: production 65 register: asgs 66 67# Fail if no groups are found 68- ec2_asg_info: 69 name: public-webserver-asg 70 register: asgs 71 failed_when: "{{ asgs.results | length == 0 }}" 72 73# Fail if more than 1 group is found 74- ec2_asg_info: 75 name: public-webserver-asg 76 register: asgs 77 failed_when: "{{ asgs.results | length > 1 }}" 78''' 79 80RETURN = ''' 81--- 82auto_scaling_group_arn: 83 description: The Amazon Resource Name of the ASG 84 returned: success 85 type: str 86 sample: "arn:aws:autoscaling:us-west-2:1234567890:autoScalingGroup:10787c52-0bcb-427d-82ba-c8e4b008ed2e:autoScalingGroupName/public-webapp-production-1" 87auto_scaling_group_name: 88 description: Name of autoscaling group 89 returned: success 90 type: str 91 sample: "public-webapp-production-1" 92availability_zones: 93 description: List of Availability Zones that are enabled for this ASG. 94 returned: success 95 type: list 96 sample: ["us-west-2a", "us-west-2b", "us-west-2a"] 97created_time: 98 description: The date and time this ASG was created, in ISO 8601 format. 99 returned: success 100 type: str 101 sample: "2015-11-25T00:05:36.309Z" 102default_cooldown: 103 description: The default cooldown time in seconds. 104 returned: success 105 type: int 106 sample: 300 107desired_capacity: 108 description: The number of EC2 instances that should be running in this group. 109 returned: success 110 type: int 111 sample: 3 112health_check_period: 113 description: Length of time in seconds after a new EC2 instance comes into service that Auto Scaling starts checking its health. 114 returned: success 115 type: int 116 sample: 30 117health_check_type: 118 description: The service you want the health status from, one of "EC2" or "ELB". 119 returned: success 120 type: str 121 sample: "ELB" 122instances: 123 description: List of EC2 instances and their status as it relates to the ASG. 124 returned: success 125 type: list 126 sample: [ 127 { 128 "availability_zone": "us-west-2a", 129 "health_status": "Healthy", 130 "instance_id": "i-es22ad25", 131 "launch_configuration_name": "public-webapp-production-1", 132 "lifecycle_state": "InService", 133 "protected_from_scale_in": "false" 134 } 135 ] 136launch_config_name: 137 description: > 138 Name of launch configuration associated with the ASG. Same as launch_configuration_name, 139 provided for compatibility with ec2_asg module. 140 returned: success 141 type: str 142 sample: "public-webapp-production-1" 143launch_configuration_name: 144 description: Name of launch configuration associated with the ASG. 145 returned: success 146 type: str 147 sample: "public-webapp-production-1" 148load_balancer_names: 149 description: List of load balancers names attached to the ASG. 150 returned: success 151 type: list 152 sample: ["elb-webapp-prod"] 153max_size: 154 description: Maximum size of group 155 returned: success 156 type: int 157 sample: 3 158min_size: 159 description: Minimum size of group 160 returned: success 161 type: int 162 sample: 1 163new_instances_protected_from_scale_in: 164 description: Whether or not new instances a protected from automatic scaling in. 165 returned: success 166 type: bool 167 sample: "false" 168placement_group: 169 description: Placement group into which instances are launched, if any. 170 returned: success 171 type: str 172 sample: None 173status: 174 description: The current state of the group when DeleteAutoScalingGroup is in progress. 175 returned: success 176 type: str 177 sample: None 178tags: 179 description: List of tags for the ASG, and whether or not each tag propagates to instances at launch. 180 returned: success 181 type: list 182 sample: [ 183 { 184 "key": "Name", 185 "value": "public-webapp-production-1", 186 "resource_id": "public-webapp-production-1", 187 "resource_type": "auto-scaling-group", 188 "propagate_at_launch": "true" 189 }, 190 { 191 "key": "env", 192 "value": "production", 193 "resource_id": "public-webapp-production-1", 194 "resource_type": "auto-scaling-group", 195 "propagate_at_launch": "true" 196 } 197 ] 198target_group_arns: 199 description: List of ARNs of the target groups that the ASG populates 200 returned: success 201 type: list 202 sample: [ 203 "arn:aws:elasticloadbalancing:ap-southeast-2:123456789012:targetgroup/target-group-host-hello/1a2b3c4d5e6f1a2b", 204 "arn:aws:elasticloadbalancing:ap-southeast-2:123456789012:targetgroup/target-group-path-world/abcd1234abcd1234" 205 ] 206target_group_names: 207 description: List of names of the target groups that the ASG populates 208 returned: success 209 type: list 210 sample: [ 211 "target-group-host-hello", 212 "target-group-path-world" 213 ] 214termination_policies: 215 description: A list of termination policies for the group. 216 returned: success 217 type: str 218 sample: ["Default"] 219''' 220 221import re 222 223try: 224 from botocore.exceptions import ClientError 225except ImportError: 226 pass # caught by imported HAS_BOTO3 227 228from ansible.module_utils.basic import AnsibleModule 229from ansible.module_utils.ec2 import (get_aws_connection_info, boto3_conn, ec2_argument_spec, 230 camel_dict_to_snake_dict, HAS_BOTO3) 231 232 233def match_asg_tags(tags_to_match, asg): 234 for key, value in tags_to_match.items(): 235 for tag in asg['Tags']: 236 if key == tag['Key'] and value == tag['Value']: 237 break 238 else: 239 return False 240 return True 241 242 243def find_asgs(conn, module, name=None, tags=None): 244 """ 245 Args: 246 conn (boto3.AutoScaling.Client): Valid Boto3 ASG client. 247 name (str): Optional name of the ASG you are looking for. 248 tags (dict): Optional dictionary of tags and values to search for. 249 250 Basic Usage: 251 >>> name = 'public-webapp-production' 252 >>> tags = { 'env': 'production' } 253 >>> conn = boto3.client('autoscaling', region_name='us-west-2') 254 >>> results = find_asgs(name, conn) 255 256 Returns: 257 List 258 [ 259 { 260 "auto_scaling_group_arn": ( 261 "arn:aws:autoscaling:us-west-2:275977225706:autoScalingGroup:58abc686-9783-4528-b338-3ad6f1cbbbaf:" 262 "autoScalingGroupName/public-webapp-production" 263 ), 264 "auto_scaling_group_name": "public-webapp-production", 265 "availability_zones": ["us-west-2c", "us-west-2b", "us-west-2a"], 266 "created_time": "2016-02-02T23:28:42.481000+00:00", 267 "default_cooldown": 300, 268 "desired_capacity": 2, 269 "enabled_metrics": [], 270 "health_check_grace_period": 300, 271 "health_check_type": "ELB", 272 "instances": 273 [ 274 { 275 "availability_zone": "us-west-2c", 276 "health_status": "Healthy", 277 "instance_id": "i-047a12cb", 278 "launch_configuration_name": "public-webapp-production-1", 279 "lifecycle_state": "InService", 280 "protected_from_scale_in": false 281 }, 282 { 283 "availability_zone": "us-west-2a", 284 "health_status": "Healthy", 285 "instance_id": "i-7a29df2c", 286 "launch_configuration_name": "public-webapp-production-1", 287 "lifecycle_state": "InService", 288 "protected_from_scale_in": false 289 } 290 ], 291 "launch_config_name": "public-webapp-production-1", 292 "launch_configuration_name": "public-webapp-production-1", 293 "load_balancer_names": ["public-webapp-production-lb"], 294 "max_size": 4, 295 "min_size": 2, 296 "new_instances_protected_from_scale_in": false, 297 "placement_group": None, 298 "status": None, 299 "suspended_processes": [], 300 "tags": 301 [ 302 { 303 "key": "Name", 304 "propagate_at_launch": true, 305 "resource_id": "public-webapp-production", 306 "resource_type": "auto-scaling-group", 307 "value": "public-webapp-production" 308 }, 309 { 310 "key": "env", 311 "propagate_at_launch": true, 312 "resource_id": "public-webapp-production", 313 "resource_type": "auto-scaling-group", 314 "value": "production" 315 } 316 ], 317 "target_group_names": [], 318 "target_group_arns": [], 319 "termination_policies": 320 [ 321 "Default" 322 ], 323 "vpc_zone_identifier": 324 [ 325 "subnet-a1b1c1d1", 326 "subnet-a2b2c2d2", 327 "subnet-a3b3c3d3" 328 ] 329 } 330 ] 331 """ 332 333 try: 334 asgs_paginator = conn.get_paginator('describe_auto_scaling_groups') 335 asgs = asgs_paginator.paginate().build_full_result() 336 except ClientError as e: 337 module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response)) 338 339 if not asgs: 340 return asgs 341 try: 342 region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) 343 elbv2 = boto3_conn(module, conn_type='client', resource='elbv2', region=region, endpoint=ec2_url, **aws_connect_kwargs) 344 except ClientError as e: 345 # This is nice to have, not essential 346 elbv2 = None 347 matched_asgs = [] 348 349 if name is not None: 350 # if the user didn't specify a name 351 name_prog = re.compile(r'^' + name) 352 353 for asg in asgs['AutoScalingGroups']: 354 if name: 355 matched_name = name_prog.search(asg['AutoScalingGroupName']) 356 else: 357 matched_name = True 358 359 if tags: 360 matched_tags = match_asg_tags(tags, asg) 361 else: 362 matched_tags = True 363 364 if matched_name and matched_tags: 365 asg = camel_dict_to_snake_dict(asg) 366 # compatibility with ec2_asg module 367 if 'launch_configuration_name' in asg: 368 asg['launch_config_name'] = asg['launch_configuration_name'] 369 # workaround for https://github.com/ansible/ansible/pull/25015 370 if 'target_group_ar_ns' in asg: 371 asg['target_group_arns'] = asg['target_group_ar_ns'] 372 del(asg['target_group_ar_ns']) 373 if asg.get('target_group_arns'): 374 if elbv2: 375 try: 376 tg_paginator = elbv2.get_paginator('describe_target_groups') 377 tg_result = tg_paginator.paginate(TargetGroupArns=asg['target_group_arns']).build_full_result() 378 asg['target_group_names'] = [tg['TargetGroupName'] for tg in tg_result['TargetGroups']] 379 except ClientError as e: 380 if e.response['Error']['Code'] == 'TargetGroupNotFound': 381 asg['target_group_names'] = [] 382 else: 383 asg['target_group_names'] = [] 384 matched_asgs.append(asg) 385 386 return matched_asgs 387 388 389def main(): 390 391 argument_spec = ec2_argument_spec() 392 argument_spec.update( 393 dict( 394 name=dict(type='str'), 395 tags=dict(type='dict'), 396 ) 397 ) 398 module = AnsibleModule(argument_spec=argument_spec) 399 if module._name == 'ec2_asg_facts': 400 module.deprecate("The 'ec2_asg_facts' module has been renamed to 'ec2_asg_info'", version='2.13') 401 402 if not HAS_BOTO3: 403 module.fail_json(msg='boto3 required for this module') 404 405 asg_name = module.params.get('name') 406 asg_tags = module.params.get('tags') 407 408 try: 409 region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) 410 autoscaling = boto3_conn(module, conn_type='client', resource='autoscaling', region=region, endpoint=ec2_url, **aws_connect_kwargs) 411 except ClientError as e: 412 module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response)) 413 414 results = find_asgs(autoscaling, module, name=asg_name, tags=asg_tags) 415 module.exit_json(results=results) 416 417 418if __name__ == '__main__': 419 main() 420