1#!/usr/local/bin/python3.8
2# Copyright (c) 2017 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
9DOCUMENTATION = '''
10module: elasticache_info
11short_description: Retrieve information for AWS ElastiCache clusters
12version_added: 1.0.0
13description:
14  - Retrieve information from AWS ElastiCache clusters
15  - This module was called C(elasticache_facts) before Ansible 2.9. The usage did not change.
16options:
17  name:
18    description:
19      - The name of an ElastiCache cluster.
20    type: str
21
22author:
23  - Will Thames (@willthames)
24extends_documentation_fragment:
25- amazon.aws.aws
26- amazon.aws.ec2
27
28'''
29
30EXAMPLES = '''
31- name: obtain all ElastiCache information
32  community.aws.elasticache_info:
33
34- name: obtain all information for a single ElastiCache cluster
35  community.aws.elasticache_info:
36    name: test_elasticache
37'''
38
39RETURN = '''
40elasticache_clusters:
41  description: List of ElastiCache clusters
42  returned: always
43  type: complex
44  contains:
45    auto_minor_version_upgrade:
46      description: Whether to automatically upgrade to minor versions
47      returned: always
48      type: bool
49      sample: true
50    cache_cluster_create_time:
51      description: Date and time cluster was created
52      returned: always
53      type: str
54      sample: '2017-09-15T05:43:46.038000+00:00'
55    cache_cluster_id:
56      description: ID of the cache cluster
57      returned: always
58      type: str
59      sample: abcd-1234-001
60    cache_cluster_status:
61      description: Status of ElastiCache cluster
62      returned: always
63      type: str
64      sample: available
65    cache_node_type:
66      description: Instance type of ElastiCache nodes
67      returned: always
68      type: str
69      sample: cache.t2.micro
70    cache_nodes:
71      description: List of ElastiCache nodes in the cluster
72      returned: always
73      type: complex
74      contains:
75        cache_node_create_time:
76          description: Date and time node was created
77          returned: always
78          type: str
79          sample: '2017-09-15T05:43:46.038000+00:00'
80        cache_node_id:
81          description: ID of the cache node
82          returned: always
83          type: str
84          sample: '0001'
85        cache_node_status:
86          description: Status of the cache node
87          returned: always
88          type: str
89          sample: available
90        customer_availability_zone:
91          description: Availability Zone in which the cache node was created
92          returned: always
93          type: str
94          sample: ap-southeast-2b
95        endpoint:
96          description: Connection details for the cache node
97          returned: always
98          type: complex
99          contains:
100            address:
101              description: URL of the cache node endpoint
102              returned: always
103              type: str
104              sample: abcd-1234-001.bgiz2p.0001.apse2.cache.amazonaws.com
105            port:
106              description: Port of the cache node endpoint
107              returned: always
108              type: int
109              sample: 6379
110        parameter_group_status:
111          description: Status of the Cache Parameter Group
112          returned: always
113          type: str
114          sample: in-sync
115    cache_parameter_group:
116      description: Contents of the Cache Parameter Group
117      returned: always
118      type: complex
119      contains:
120        cache_node_ids_to_reboot:
121          description: Cache nodes which need to be rebooted for parameter changes to be applied
122          returned: always
123          type: list
124          sample: []
125        cache_parameter_group_name:
126          description: Name of the cache parameter group
127          returned: always
128          type: str
129          sample: default.redis3.2
130        parameter_apply_status:
131          description: Status of parameter updates
132          returned: always
133          type: str
134          sample: in-sync
135    cache_security_groups:
136      description: Security Groups used by the cache
137      returned: always
138      type: list
139      sample:
140        - 'sg-abcd1234'
141    cache_subnet_group_name:
142      description: ElastiCache Subnet Group used by the cache
143      returned: always
144      type: str
145      sample: abcd-subnet-group
146    client_download_landing_page:
147      description: URL of client download web page
148      returned: always
149      type: str
150      sample: 'https://console.aws.amazon.com/elasticache/home#client-download:'
151    engine:
152      description: Engine used by ElastiCache
153      returned: always
154      type: str
155      sample: redis
156    engine_version:
157      description: Version of ElastiCache engine
158      returned: always
159      type: str
160      sample: 3.2.4
161    notification_configuration:
162      description: Configuration of notifications
163      returned: if notifications are enabled
164      type: complex
165      contains:
166        topic_arn:
167          description: ARN of notification destination topic
168          returned: if notifications are enabled
169          type: str
170          sample: arn:aws:sns:*:123456789012:my_topic
171        topic_name:
172          description: Name of notification destination topic
173          returned: if notifications are enabled
174          type: str
175          sample: MyTopic
176    num_cache_nodes:
177      description: Number of Cache Nodes
178      returned: always
179      type: int
180      sample: 1
181    pending_modified_values:
182      description: Values that are pending modification
183      returned: always
184      type: complex
185      contains: {}
186    preferred_availability_zone:
187      description: Preferred Availability Zone
188      returned: always
189      type: str
190      sample: ap-southeast-2b
191    preferred_maintenance_window:
192      description: Time slot for preferred maintenance window
193      returned: always
194      type: str
195      sample: sat:12:00-sat:13:00
196    replication_group_id:
197      description: Replication Group Id
198      returned: always
199      type: str
200      sample: replication-001
201    security_groups:
202      description: List of Security Groups associated with ElastiCache
203      returned: always
204      type: complex
205      contains:
206        security_group_id:
207          description: Security Group ID
208          returned: always
209          type: str
210          sample: sg-abcd1234
211        status:
212          description: Status of Security Group
213          returned: always
214          type: str
215          sample: active
216    tags:
217      description: Tags applied to the ElastiCache cluster
218      returned: always
219      type: complex
220      contains: {}
221      sample:
222        Application: web
223        Environment: test
224'''
225
226from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
227from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
228from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
229from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
230from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
231
232
233try:
234    import botocore
235except ImportError:
236    pass  # caught by AnsibleAWSModule
237
238
239@AWSRetry.exponential_backoff()
240def describe_cache_clusters_with_backoff(client, cluster_id=None):
241    paginator = client.get_paginator('describe_cache_clusters')
242    params = dict(ShowCacheNodeInfo=True)
243    if cluster_id:
244        params['CacheClusterId'] = cluster_id
245    try:
246        response = paginator.paginate(**params).build_full_result()
247    except is_boto3_error_code('CacheClusterNotFound'):
248        return []
249    return response['CacheClusters']
250
251
252@AWSRetry.exponential_backoff()
253def get_elasticache_tags_with_backoff(client, cluster_id):
254    return client.list_tags_for_resource(ResourceName=cluster_id)['TagList']
255
256
257def get_aws_account_id(module):
258    try:
259        client = module.client('sts')
260    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
261        module.fail_json_aws(e, msg="Can't authorize connection")
262
263    try:
264        return client.get_caller_identity()['Account']
265    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
266        module.fail_json_aws(e, msg="Couldn't obtain AWS account id")
267
268
269def get_elasticache_clusters(client, module):
270    region = module.region
271    try:
272        clusters = describe_cache_clusters_with_backoff(client, cluster_id=module.params.get('name'))
273    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
274        module.fail_json_aws(e, msg="Couldn't obtain cache cluster info")
275
276    account_id = get_aws_account_id(module)
277    results = []
278    for cluster in clusters:
279
280        cluster = camel_dict_to_snake_dict(cluster)
281        arn = "arn:aws:elasticache:%s:%s:cluster:%s" % (region, account_id, cluster['cache_cluster_id'])
282        try:
283            tags = get_elasticache_tags_with_backoff(client, arn)
284        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
285            module.fail_json_aws(e, msg="Couldn't get tags for cluster %s")
286
287        cluster['tags'] = boto3_tag_list_to_ansible_dict(tags)
288        results.append(cluster)
289    return results
290
291
292def main():
293    argument_spec = dict(
294        name=dict(required=False),
295    )
296    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
297    if module._name == 'elasticache_facts':
298        module.deprecate("The 'elasticache_facts' module has been renamed to 'elasticache_info'", date='2021-12-01', collection_name='community.aws')
299
300    client = module.client('elasticache')
301
302    module.exit_json(elasticache_clusters=get_elasticache_clusters(client, module))
303
304
305if __name__ == '__main__':
306    main()
307