From 3233644b138c9ebd39b938367164e5390f58a402 Mon Sep 17 00:00:00 2001 From: Thirumalesh Aaraveti Date: Mon, 26 Feb 2024 17:12:11 +0530 Subject: [PATCH] Azure: add the monitor log operations --- .../common/clouds/azure/common/__init__.py | 0 .../{compute => common}/common_operations.py | 0 .../azure/compute/compute_operations.py | 2 +- .../compute/resource_group_operations.py | 2 +- .../common/clouds/azure/monitor/__init__.py | 0 .../monitor/monitor_management_operations.py | 60 +++++++++++++++++++ cloud_governance/common/utils/configs.py | 3 + requirements.txt | 1 + setup.py | 3 +- .../common/clouds/azure/__init__.py | 0 .../common/clouds/azure/monitor/__init__.py | 0 .../test_monitor_management_operations.py | 24 ++++++++ tests/unittest/configs.py | 1 + .../mocks/azure/mock_monitor/__init__.py | 0 .../mock_activity_logs_operations.py | 40 +++++++++++++ .../mocks/azure/mock_monitor/mock_monitor.py | 28 +++++++++ tests_requirements.txt | 1 + 17 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 cloud_governance/common/clouds/azure/common/__init__.py rename cloud_governance/common/clouds/azure/{compute => common}/common_operations.py (100%) create mode 100644 cloud_governance/common/clouds/azure/monitor/__init__.py create mode 100644 cloud_governance/common/clouds/azure/monitor/monitor_management_operations.py create mode 100644 cloud_governance/common/utils/configs.py create mode 100644 tests/unittest/cloud_governance/common/clouds/azure/__init__.py create mode 100644 tests/unittest/cloud_governance/common/clouds/azure/monitor/__init__.py create mode 100644 tests/unittest/cloud_governance/common/clouds/azure/monitor/test_monitor_management_operations.py create mode 100644 tests/unittest/mocks/azure/mock_monitor/__init__.py create mode 100644 tests/unittest/mocks/azure/mock_monitor/mock_activity_logs_operations.py create mode 100644 tests/unittest/mocks/azure/mock_monitor/mock_monitor.py diff --git a/cloud_governance/common/clouds/azure/common/__init__.py b/cloud_governance/common/clouds/azure/common/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cloud_governance/common/clouds/azure/compute/common_operations.py b/cloud_governance/common/clouds/azure/common/common_operations.py similarity index 100% rename from cloud_governance/common/clouds/azure/compute/common_operations.py rename to cloud_governance/common/clouds/azure/common/common_operations.py diff --git a/cloud_governance/common/clouds/azure/compute/compute_operations.py b/cloud_governance/common/clouds/azure/compute/compute_operations.py index e77d8a23e..dc7c27631 100644 --- a/cloud_governance/common/clouds/azure/compute/compute_operations.py +++ b/cloud_governance/common/clouds/azure/compute/compute_operations.py @@ -1,7 +1,7 @@ from azure.mgmt.compute import ComputeManagementClient from azure.mgmt.compute.v2023_03_01.models import VirtualMachine -from cloud_governance.common.clouds.azure.compute.common_operations import CommonOperations +from cloud_governance.common.clouds.azure.common.common_operations import CommonOperations from cloud_governance.common.logger.logger_time_stamp import logger_time_stamp diff --git a/cloud_governance/common/clouds/azure/compute/resource_group_operations.py b/cloud_governance/common/clouds/azure/compute/resource_group_operations.py index f86a77b5d..331e57e60 100644 --- a/cloud_governance/common/clouds/azure/compute/resource_group_operations.py +++ b/cloud_governance/common/clouds/azure/compute/resource_group_operations.py @@ -4,7 +4,7 @@ from azure.mgmt.resource import ResourceManagementClient from azure.mgmt.resource.resources.v2022_09_01.models import ResourceGroup, GenericResourceExpanded, TagsResource, Tags -from cloud_governance.common.clouds.azure.compute.common_operations import CommonOperations +from cloud_governance.common.clouds.azure.common.common_operations import CommonOperations from cloud_governance.common.logger.logger_time_stamp import logger_time_stamp diff --git a/cloud_governance/common/clouds/azure/monitor/__init__.py b/cloud_governance/common/clouds/azure/monitor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cloud_governance/common/clouds/azure/monitor/monitor_management_operations.py b/cloud_governance/common/clouds/azure/monitor/monitor_management_operations.py new file mode 100644 index 000000000..3a59390a8 --- /dev/null +++ b/cloud_governance/common/clouds/azure/monitor/monitor_management_operations.py @@ -0,0 +1,60 @@ +import json +from datetime import datetime, timedelta + +from azure.core.exceptions import HttpResponseError +from azure.mgmt.monitor import MonitorManagementClient + +from cloud_governance.common.clouds.azure.common.common_operations import CommonOperations +from cloud_governance.common.logger.init_logger import logger +from cloud_governance.common.utils.configs import LOOK_BACK_DAYS + + +class MonitorManagementOperations(CommonOperations): + + def __init__(self): + super().__init__() + self.__monitor_client = MonitorManagementClient(credential=self._default_creds, + subscription_id=self._subscription_id) + + def __get_end_date(self): + """ + This method returns the end date + :return: + :rtype: + """ + return datetime.utcnow() + + def __get_start_date(self): + """ + This method returns the start date + :return: + :rtype: + """ + return self.__get_end_date() - timedelta(LOOK_BACK_DAYS) + + def get_audit_records(self, resource_id: str, start_date: datetime = None, end_date: datetime = None): + """ + This method returns the audit record for the resource_id + :param start_date: + :type start_date: + :param end_date: + :type end_date: + :param resource_id: + :type resource_id: + :return: + :rtype: + """ + if not start_date: + start_date = self.__get_start_date() + if not end_date: + end_date = self.__get_end_date() + try: + filter_query = f"eventTimestamp ge '{start_date}'" \ + f" and eventTimestamp le '{end_date}' " \ + f"and resourceUri eq '{resource_id}'.:code:" + records = self.__monitor_client.activity_logs.list(filter=filter_query) + return self._item_paged_iterator(item_paged_object=records, as_dict=True) + except HttpResponseError as http_error: + logger.error(http_error) + except Exception as err: + logger.error(err) diff --git a/cloud_governance/common/utils/configs.py b/cloud_governance/common/utils/configs.py new file mode 100644 index 000000000..f46e6d883 --- /dev/null +++ b/cloud_governance/common/utils/configs.py @@ -0,0 +1,3 @@ + + +LOOK_BACK_DAYS = 30 diff --git a/requirements.txt b/requirements.txt index 49e4cf828..7639d3d27 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ azure-identity==1.12.0 azure-mgmt-billing==6.0.0 azure-mgmt-resource==23.0.1 azure-mgmt-compute==30.1.0 +azure-mgmt-monitor==6.0.2 azure-mgmt-network==25.0.0 azure-mgmt-costmanagement==3.0.0 azure-mgmt-subscription==3.1.1 diff --git a/setup.py b/setup.py index 23fc14b8b..36d7c7e58 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,8 @@ 'urllib3==1.26.7', # required by jira 'azure-mgmt-resource==23.0.1', 'azure-mgmt-compute==30.1.0', - 'azure-mgmt-network==25.0.0' + 'azure-mgmt-network==25.0.0', + 'azure-mgmt-monitor==6.0.2' ], setup_requires=['pytest', 'pytest-runner', 'wheel', 'coverage'], diff --git a/tests/unittest/cloud_governance/common/clouds/azure/__init__.py b/tests/unittest/cloud_governance/common/clouds/azure/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unittest/cloud_governance/common/clouds/azure/monitor/__init__.py b/tests/unittest/cloud_governance/common/clouds/azure/monitor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unittest/cloud_governance/common/clouds/azure/monitor/test_monitor_management_operations.py b/tests/unittest/cloud_governance/common/clouds/azure/monitor/test_monitor_management_operations.py new file mode 100644 index 000000000..d3e08e28e --- /dev/null +++ b/tests/unittest/cloud_governance/common/clouds/azure/monitor/test_monitor_management_operations.py @@ -0,0 +1,24 @@ +from azure.mgmt.monitor import MonitorManagementClient + +from cloud_governance.common.clouds.azure.monitor.monitor_management_operations import MonitorManagementOperations +from tests.unittest.configs import AZURE_RESOURCE_ID +from tests.unittest.mocks.azure.mock_monitor.mock_monitor import mock_monitor + + +@mock_monitor +def test_monitor_management_operations__get_audit_records(): + """ + This method tests the get_start date + :return: + :rtype: + """ + monitor_client = MonitorManagementClient(credential='', subscription_id='') + monitor_client.activity_logs.create_log( + caller='unittest@cloudgovernance.com', + resource_id=AZURE_RESOURCE_ID + ) + monitor_operations = MonitorManagementOperations() + + assert len(monitor_operations.get_audit_records(resource_id=AZURE_RESOURCE_ID)) == 1 + + diff --git a/tests/unittest/configs.py b/tests/unittest/configs.py index 1e13b99ef..7e48d9215 100644 --- a/tests/unittest/configs.py +++ b/tests/unittest/configs.py @@ -20,3 +20,4 @@ SUB_ID = f'/subscription/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP}' NETWORK_PROVIDER = f'providers/Microsoft.Network' COMPUTE_PROVIDER = 'providers/Microsoft.Compute' +AZURE_RESOURCE_ID = f'{SUB_ID}/{COMPUTE_PROVIDER}/cloud-governance-unittest' diff --git a/tests/unittest/mocks/azure/mock_monitor/__init__.py b/tests/unittest/mocks/azure/mock_monitor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unittest/mocks/azure/mock_monitor/mock_activity_logs_operations.py b/tests/unittest/mocks/azure/mock_monitor/mock_activity_logs_operations.py new file mode 100644 index 000000000..a96ce982a --- /dev/null +++ b/tests/unittest/mocks/azure/mock_monitor/mock_activity_logs_operations.py @@ -0,0 +1,40 @@ +from azure.mgmt.monitor.models import EventData + +from tests.unittest.mocks.azure.common_operations import CustomItemPaged + + +class MockEventData(EventData): + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + +class MockActivityLogsOperations: + + def __init__(self): + super().__init__() + self.__audit_logs = [] + + def list(self, filter: str, **kwargs): + """ + This method returns the list of EventData + :param filter: + :type filter: + :param kwargs: + :type kwargs: + :return: + :rtype: + """ + return CustomItemPaged(resource_list=self.__audit_logs) + + def create_log(self, **kwargs): + """ + This method creates audit log entry + :param kwargs: + :type kwargs: + :return: + :rtype: + """ + record = MockEventData(**kwargs) + self.__audit_logs.append(record) + return record diff --git a/tests/unittest/mocks/azure/mock_monitor/mock_monitor.py b/tests/unittest/mocks/azure/mock_monitor/mock_monitor.py new file mode 100644 index 000000000..f5d52db20 --- /dev/null +++ b/tests/unittest/mocks/azure/mock_monitor/mock_monitor.py @@ -0,0 +1,28 @@ + +from functools import wraps +from unittest.mock import patch + +from azure.mgmt.monitor import MonitorManagementClient + +from tests.unittest.mocks.azure.mock_monitor.mock_activity_logs_operations import MockActivityLogsOperations + + +def mock_monitor(method): + """ + This method is mocking for Jira class methods which are used in Jira Operations @param method: + @return: + """ + + @wraps(method) + def method_wrapper(*args, **kwargs): + """ + This is the wrapper method to wraps the method inside the function + @param args: + @param kwargs: + @return: + """ + with patch.object(MonitorManagementClient, 'activity_logs', MockActivityLogsOperations()): + result = method(*args, **kwargs) + return result + + return method_wrapper diff --git a/tests_requirements.txt b/tests_requirements.txt index ecc467955..62d5432b5 100644 --- a/tests_requirements.txt +++ b/tests_requirements.txt @@ -2,6 +2,7 @@ aiohttp==3.8.5 azure-identity==1.12.0 azure-mgmt-costmanagement==3.0.0 azure-mgmt-billing==6.0.0 +azure-mgmt-monitor==6.0.2 azure-mgmt-subscription==3.1.1 boto3==1.26.4 elasticsearch==7.11.0