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