1#!/usr/local/bin/python3.8 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 7__metaclass__ = type 8 9 10DOCUMENTATION = ''' 11--- 12module: cloudwatchlogs_log_group 13version_added: 1.0.0 14short_description: create or delete log_group in CloudWatchLogs 15notes: 16 - For details of the parameters and returns see U(http://boto3.readthedocs.io/en/latest/reference/services/logs.html). 17description: 18 - Create or delete log_group in CloudWatchLogs. 19author: 20 - Willian Ricardo (@willricardo) <willricardo@gmail.com> 21requirements: [ json, botocore, boto3 ] 22options: 23 state: 24 description: 25 - Whether the rule is present or absent. 26 choices: ["present", "absent"] 27 default: present 28 required: false 29 type: str 30 log_group_name: 31 description: 32 - The name of the log group. 33 required: true 34 type: str 35 kms_key_id: 36 description: 37 - The Amazon Resource Name (ARN) of the CMK to use when encrypting log data. 38 required: false 39 type: str 40 tags: 41 description: 42 - The key-value pairs to use for the tags. 43 required: false 44 type: dict 45 retention: 46 description: 47 - The number of days to retain the log events in the specified log group. 48 - "Valid values are: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653]" 49 - Mutually exclusive with I(purge_retention_policy). 50 required: false 51 type: int 52 purge_retention_policy: 53 description: 54 - "Whether to purge the retention policy or not." 55 - "Mutually exclusive with I(retention) and I(overwrite)." 56 default: false 57 required: false 58 type: bool 59 overwrite: 60 description: 61 - Whether an existing log group should be overwritten on create. 62 - Mutually exclusive with I(purge_retention_policy). 63 default: false 64 required: false 65 type: bool 66extends_documentation_fragment: 67- amazon.aws.aws 68- amazon.aws.ec2 69 70''' 71 72EXAMPLES = ''' 73# Note: These examples do not set authentication details, see the AWS Guide for details. 74 75- community.aws.cloudwatchlogs_log_group: 76 log_group_name: test-log-group 77 78- community.aws.cloudwatchlogs_log_group: 79 state: present 80 log_group_name: test-log-group 81 tags: { "Name": "test-log-group", "Env" : "QA" } 82 83- community.aws.cloudwatchlogs_log_group: 84 state: present 85 log_group_name: test-log-group 86 tags: { "Name": "test-log-group", "Env" : "QA" } 87 kms_key_id: arn:aws:kms:region:account-id:key/key-id 88 89- community.aws.cloudwatchlogs_log_group: 90 state: absent 91 log_group_name: test-log-group 92 93''' 94 95RETURN = ''' 96log_groups: 97 description: Return the list of complex objects representing log groups 98 returned: success 99 type: complex 100 contains: 101 log_group_name: 102 description: The name of the log group. 103 returned: always 104 type: str 105 creation_time: 106 description: The creation time of the log group. 107 returned: always 108 type: int 109 retention_in_days: 110 description: The number of days to retain the log events in the specified log group. 111 returned: always 112 type: int 113 metric_filter_count: 114 description: The number of metric filters. 115 returned: always 116 type: int 117 arn: 118 description: The Amazon Resource Name (ARN) of the log group. 119 returned: always 120 type: str 121 stored_bytes: 122 description: The number of bytes stored. 123 returned: always 124 type: str 125 kms_key_id: 126 description: The Amazon Resource Name (ARN) of the CMK to use when encrypting log data. 127 returned: always 128 type: str 129''' 130 131try: 132 import botocore 133except ImportError: 134 pass # Handled by AnsibleAWSModule 135 136from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict 137 138from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule 139 140 141def create_log_group(client, log_group_name, kms_key_id, tags, retention, module): 142 request = {'logGroupName': log_group_name} 143 if kms_key_id: 144 request['kmsKeyId'] = kms_key_id 145 if tags: 146 request['tags'] = tags 147 148 try: 149 client.create_log_group(**request) 150 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 151 module.fail_json_aws(e, msg="Unable to create log group") 152 153 if retention: 154 input_retention_policy(client=client, 155 log_group_name=log_group_name, 156 retention=retention, module=module) 157 158 desc_log_group = describe_log_group(client=client, 159 log_group_name=log_group_name, 160 module=module) 161 162 if 'logGroups' in desc_log_group: 163 for i in desc_log_group['logGroups']: 164 if log_group_name == i['logGroupName']: 165 return i 166 module.fail_json(msg="The aws CloudWatchLogs log group was not created. \n please try again!") 167 168 169def input_retention_policy(client, log_group_name, retention, module): 170 try: 171 permited_values = [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] 172 173 if retention in permited_values: 174 response = client.put_retention_policy(logGroupName=log_group_name, 175 retentionInDays=retention) 176 else: 177 delete_log_group(client=client, log_group_name=log_group_name, module=module) 178 module.fail_json(msg="Invalid retention value. Valid values are: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653]") 179 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 180 module.fail_json_aws(e, msg="Unable to put retention policy for log group {0}".format(log_group_name)) 181 182 183def delete_retention_policy(client, log_group_name, module): 184 try: 185 client.delete_retention_policy(logGroupName=log_group_name) 186 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 187 module.fail_json_aws(e, msg="Unable to delete retention policy for log group {0}".format(log_group_name)) 188 189 190def delete_log_group(client, log_group_name, module): 191 desc_log_group = describe_log_group(client=client, 192 log_group_name=log_group_name, 193 module=module) 194 195 try: 196 if 'logGroups' in desc_log_group: 197 for i in desc_log_group['logGroups']: 198 if log_group_name == i['logGroupName']: 199 client.delete_log_group(logGroupName=log_group_name) 200 201 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 202 module.fail_json_aws(e, msg="Unable to delete log group {0}".format(log_group_name)) 203 204 205def describe_log_group(client, log_group_name, module): 206 try: 207 desc_log_group = client.describe_log_groups(logGroupNamePrefix=log_group_name) 208 return desc_log_group 209 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 210 module.fail_json_aws(e, msg="Unable to describe log group {0}".format(log_group_name)) 211 212 213def main(): 214 argument_spec = dict( 215 log_group_name=dict(required=True, type='str'), 216 state=dict(choices=['present', 'absent'], 217 default='present'), 218 kms_key_id=dict(required=False, type='str'), 219 tags=dict(required=False, type='dict'), 220 retention=dict(required=False, type='int'), 221 purge_retention_policy=dict(required=False, type='bool', default=False), 222 overwrite=dict(required=False, type='bool', default=False), 223 ) 224 225 mutually_exclusive = [['retention', 'purge_retention_policy'], ['purge_retention_policy', 'overwrite']] 226 module = AnsibleAWSModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive) 227 228 try: 229 logs = module.client('logs') 230 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 231 module.fail_json_aws(e, msg='Failed to connect to AWS') 232 233 state = module.params.get('state') 234 changed = False 235 236 # Determine if the log group exists 237 desc_log_group = describe_log_group(client=logs, log_group_name=module.params['log_group_name'], module=module) 238 found_log_group = {} 239 for i in desc_log_group.get('logGroups', []): 240 if module.params['log_group_name'] == i['logGroupName']: 241 found_log_group = i 242 break 243 244 if state == 'present': 245 if found_log_group: 246 if module.params['overwrite'] is True: 247 changed = True 248 delete_log_group(client=logs, log_group_name=module.params['log_group_name'], module=module) 249 found_log_group = create_log_group(client=logs, 250 log_group_name=module.params['log_group_name'], 251 kms_key_id=module.params['kms_key_id'], 252 tags=module.params['tags'], 253 retention=module.params['retention'], 254 module=module) 255 elif module.params['purge_retention_policy']: 256 if found_log_group.get('retentionInDays'): 257 changed = True 258 delete_retention_policy(client=logs, 259 log_group_name=module.params['log_group_name'], 260 module=module) 261 elif module.params['retention'] != found_log_group.get('retentionInDays'): 262 if module.params['retention'] is not None: 263 changed = True 264 input_retention_policy(client=logs, 265 log_group_name=module.params['log_group_name'], 266 retention=module.params['retention'], 267 module=module) 268 found_log_group['retentionInDays'] = module.params['retention'] 269 270 elif not found_log_group: 271 changed = True 272 found_log_group = create_log_group(client=logs, 273 log_group_name=module.params['log_group_name'], 274 kms_key_id=module.params['kms_key_id'], 275 tags=module.params['tags'], 276 retention=module.params['retention'], 277 module=module) 278 279 module.exit_json(changed=changed, **camel_dict_to_snake_dict(found_log_group)) 280 281 elif state == 'absent': 282 if found_log_group: 283 changed = True 284 delete_log_group(client=logs, 285 log_group_name=module.params['log_group_name'], 286 module=module) 287 288 module.exit_json(changed=changed) 289 290 291if __name__ == '__main__': 292 main() 293