Skip to content

Commit

Permalink
add azure monitor log profile module (ansible#54702)
Browse files Browse the repository at this point in the history
* add azure monitor log profile module

* fix version

* fix lint

* mark test as unsupported

* fix lint

* fix lint

* Fix the error prompted in the comments
  • Loading branch information
yungezz authored and adharshsrivatsr committed Sep 3, 2019
1 parent ad56d87 commit 9a72597
Show file tree
Hide file tree
Showing 4 changed files with 501 additions and 0 deletions.
392 changes: 392 additions & 0 deletions lib/ansible/modules/cloud/azure/azure_rm_monitorlogprofile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,392 @@
#!/usr/bin/python
#
# Copyright (c) 2019 Yunge Zhu, <yungez@microsoft.com>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type


ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}


DOCUMENTATION = '''
---
module: azure_rm_monitorlogprofile
version_added: "2.9"
short_description: Manage Azure Monitor log profile
description:
- Create, update and delete instance of Azure Monitor log profile.
options:
name:
description:
- Unique name of the log profile to create or update.
required: True
type: str
location:
description:
- Resource location.
type: str
locations:
description:
- List of regions for which Activity Log events should be stored.
type: list
categories:
description:
- List of categories of logs. These categories are created as is convenient to user. Some Values are C(Write), C(Delete) and/or C(Action).
type: list
retention_policy:
description:
- Retention policy for events in the log.
type: dict
suboptions:
enabled:
description:
- Whether the retention policy is enabled.
type: bool
days:
description:
- The number of days for the retention. A value of 0 will retain the events indefinitely.
type: int
service_bus_rule_id:
description:
- The service bus rule ID of the service bus namespace in which you would like to have Event Hubs created for streaming in the Activity Log.
- Format like {service_bus_resource_id}/authorizationrules{key_name}.
type: str
storage_account:
description:
- The storage account to which send the Activity Log.
- It could be a resource ID.
- It could be a dict containing I(resource_grorup) and I(name).
type: raw
state:
description:
- Assert the state of the log profile.
- Use C(present) to create or update a log profile and C(absent) to delete it.
default: present
type: str
choices:
- absent
- present
extends_documentation_fragment:
- azure
- azure_tags
author:
- Yunge Zhu(@yungezz)
'''

EXAMPLES = '''
- name: Create a log profile
azure_rm_monitorlogprofile:
name: myProfile
location: eastus
locations:
- eastus
- westus
categories:
- Write
- Action
retention_policy:
enabled: False
days: 1
storage_account:
resource_group: myResourceGroup
name: myStorageAccount
register: output
- name: Delete a log profile
azure_rm_monitorlogprofile:
name: myProfile
state: absent
'''

RETURN = '''
id:
description:
- ID of the log profile.
returned: always
type: str
sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/microsoft.insights/logprofiles/myProfile
'''

import time
from ansible.module_utils.azure_rm_common import AzureRMModuleBase, format_resource_id

try:
from msrestazure.azure_exceptions import CloudError
from msrestazure.azure_operation import AzureOperationPoller
from msrestazure.tools import is_valid_resource_id
from msrest.serialization import Model
from azure.mgmt.monitor.models import (RetentionPolicy, LogProfileResource, ErrorResponseException)
except ImportError:
# This is handled in azure_rm_common
pass


retention_policy_spec = dict(
enabled=dict(type='bool'),
days=dict(type='int')
)


def logprofile_to_dict(profile):
return dict(
id=profile.id,
name=profile.name,
location=profile.location,
locations=profile.locations,
categories=profile.categories,
storage_account=profile.storage_account_id,
service_bus_rule_id=profile.service_bus_rule_id,
retention_policy=dict(
enabled=profile.retention_policy.enabled,
days=profile.retention_policy.days
),
tags=profile.tags if profile.tags else None
)


class Actions:
NoAction, CreateOrUpdate, Delete = range(3)


class AzureRMMonitorLogprofile(AzureRMModuleBase):
"""Configuration class for an Azure RM Monitor log profile"""

def __init__(self):
self.module_arg_spec = dict(
name=dict(
type='str',
required=True
),
location=dict(
type='str'
),
locations=dict(
type='list',
elements='str'
),
categories=dict(
type='list',
elements='str'
),
retention_policy=dict(
type='dict',
options=retention_policy_spec
),
service_bus_rule_id=dict(
type='str'
),
storage_account=dict(
type='raw'
),
state=dict(
type='str',
default='present',
choices=['present', 'absent']
)
)

self._client = None

self.name = None
self.location = None

self.locations = None
self.categories = None
self.retention_policy = False
self.service_bus_rule_id = None
self.storage_account = None

self.tags = None

self.results = dict(
changed=False,
id=None
)
self.state = None

super(AzureRMMonitorLogprofile, self).__init__(derived_arg_spec=self.module_arg_spec,
supports_check_mode=True,
supports_tags=True)

def exec_module(self, **kwargs):
"""Main module execution method"""

for key in list(self.module_arg_spec.keys()) + ['tags']:
setattr(self, key, kwargs[key])

old_response = None
response = None
to_be_updated = False

# get storage account id
if self.storage_account:
if isinstance(self.storage_account, dict):
self.storage_account = format_resource_id(val=self.storage_account['name'],
subscription_id=self.storage_account.get('subscription') or self.subscription_id,
namespace='Microsoft.Storage',
types='storageAccounts',
resource_group=self.storage_account.get('resource_group'))
elif not is_valid_resource_id(self.storage_account):
self.fail("storage_account either be a resource id or a dict containing resource_group and name")

# get existing log profile
old_response = self.get_logprofile()

if old_response:
self.results['id'] = old_response['id']

if self.state == 'present':
# if profile not exists, create new
if not old_response:
self.log("Log profile instance doesn't exist")

to_be_updated = True
self.to_do = Actions.CreateOrUpdate

else:
# log profile exists already, do update
self.log("Log profile instance already exists")

update_tags, self.tags = self.update_tags(old_response.get('tags', None))

if update_tags:
to_be_updated = True
self.to_do = Actions.CreateOrUpdate

# check if update
if self.check_update(old_response):
to_be_updated = True
self.to_do = Actions.CreateOrUpdate

elif self.state == 'absent':
if old_response:
self.log("Delete log profile instance")
self.results['id'] = old_response['id']
to_be_updated = True
self.to_do = Actions.Delete
else:
self.results['changed'] = False
self.log("Log profile {0} not exists.".format(self.name))

if to_be_updated:
self.log('Need to Create/Update log profile')
self.results['changed'] = True

if self.check_mode:
return self.results

if self.to_do == Actions.CreateOrUpdate:
response = self.create_or_update_logprofile()
self.results['id'] = response['id']

if self.to_do == Actions.Delete:
self.delete_logprofile()
self.log('Log profile instance deleted')

return self.results

def check_update(self, existing):
if self.locations is not None and existing['locations'] != self.locations:
self.log("locations diff: origin {0} / update {1}".format(existing['locations'], self.locations))
return True
if self.retention_policy is not None:
if existing['retention_policy']['enabled'] != self.retention_policy['enabled']:
self.log("retention_policy diff: origin {0} / update {1}".format(str(existing['sku']['name']), str(self.retention_policy['enabled'])))
return True
if existing['retention_policy']['days'] != self.retention_policy['days']:
self.log("retention_policy diff: origin {0} / update {1}".format(existing['retention_policy']['days'], str(self.retention_policy['days'])))
return True
if self.storage_account is not None and existing['storage_account'] != self.storage_account:
self.log("storage_account diff: origin {0} / update {1}".format(existing['storage_account'], self.storage_account))
return True
if self.service_bus_rule_id is not None and existing['service_bus_rule_id'] != self.service_bus_rule_id:
self.log("service_bus_rule_id diff: origin {0} / update {1}".format(existing['service_bus_rule_id'], self.service_bus_rule_id))
return True
return False

def create_or_update_logprofile(self):
'''
Creates or Update log profile.
:return: deserialized log profile state dictionary
'''
self.log(
"Creating log profile instance {0}".format(self.name))

try:
params = LogProfileResource(
location=self.location,
locations=self.locations,
categories=self.categories,
retention_policy=RetentionPolicy(days=self.retention_policy['days'],
enabled=self.retention_policy['enabled']) if self.retention_policy else None,
storage_account_id=self.storage_account if self.storage_account else None,
service_bus_rule_id=self.service_bus_rule_id if self.service_bus_rule_id else None,
tags=self.tags
)

response = self.monitor_client.log_profiles.create_or_update(log_profile_name=self.name,
parameters=params)
if isinstance(response, AzureOperationPoller):
response = self.get_poller_result(response)

except CloudError as exc:
self.log('Error attempting to create/update log profile.')
self.fail("Error creating/updating log profile: {0}".format(str(exc)))
return logprofile_to_dict(response)

def delete_logprofile(self):
'''
Deletes specified log profile.
:return: True
'''
self.log("Deleting the log profile instance {0}".format(self.name))
try:
response = self.monitor_client.log_profiles.delete(log_profile_name=self.name)
except CloudError as e:
self.log('Error attempting to delete the log profile.')
self.fail(
"Error deleting the log profile: {0}".format(str(e)))
return True

def get_logprofile(self):
'''
Gets the properties of the specified log profile.
:return: log profile state dictionary
'''
self.log("Checking if the log profile {0} is present".format(self.name))

response = None

try:
response = self.monitor_client.log_profiles.get(log_profile_name=self.name)

self.log("Response : {0}".format(response))
self.log("log profile : {0} found".format(response.name))
return logprofile_to_dict(response)

except ErrorResponseException as ex:
self.log("Didn't find log profile {0}".format(self.name))

return False


def main():
"""Main execution"""
AzureRMMonitorLogprofile()


if __name__ == '__main__':
main()
3 changes: 3 additions & 0 deletions test/integration/targets/azure_rm_monitorlogprofile/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cloud/azure
destructive
unsupported

0 comments on commit 9a72597

Please sign in to comment.