diff --git a/cloud_governance/cloud_resource_orchestration/clouds/azure/azure_run_cro.py b/cloud_governance/cloud_resource_orchestration/clouds/azure/azure_run_cro.py index c08cdad7..743ac19a 100644 --- a/cloud_governance/cloud_resource_orchestration/clouds/azure/azure_run_cro.py +++ b/cloud_governance/cloud_resource_orchestration/clouds/azure/azure_run_cro.py @@ -1,4 +1,6 @@ -from cloud_governance.cloud_resource_orchestration.clouds.azure.resource_groups.tag_cro_resources import TagCROInstances +from cloud_governance.cloud_resource_orchestration.clouds.azure.resource_groups.monitor_cro_resources import \ + MonitorCROResources +from cloud_governance.cloud_resource_orchestration.clouds.azure.resource_groups.tag_cro_resources import TagCROResources class AzureRunCro: @@ -11,7 +13,8 @@ def __run_cloud_resources(self): This method run the azure resources in specified region or all regions :return: """ - TagCROInstances().run() + TagCROResources().run() + monitored_resources = MonitorCROResources().run() def __start_cro(self): """ diff --git a/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/abstract_resource.py b/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/abstract_resource.py new file mode 100644 index 00000000..9a307c04 --- /dev/null +++ b/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/abstract_resource.py @@ -0,0 +1,15 @@ +from abc import ABC, abstractmethod + +from cloud_governance.common.clouds.azure.compute.compute_operations import ComputeOperations +from cloud_governance.common.clouds.azure.compute.resource_group_operations import ResourceGroupOperations + + +class AbstractResource(ABC): + + def __init__(self): + self._resource_group_operations = ResourceGroupOperations() + self._compute_client = ComputeOperations() + + @abstractmethod + def run(self): + pass diff --git a/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/monitor_cro_resources.py b/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/monitor_cro_resources.py new file mode 100644 index 00000000..e29a01ac --- /dev/null +++ b/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/monitor_cro_resources.py @@ -0,0 +1,57 @@ +from azure.mgmt.compute.v2023_03_01.models import VirtualMachine + +from cloud_governance.cloud_resource_orchestration.clouds.azure.resource_groups.abstract_resource import \ + AbstractResource +from cloud_governance.cloud_resource_orchestration.utils.constant_variables import DURATION, TICKET_ID + + +class MonitorCROResources(AbstractResource): + """ + This class monitor CRO Resources + """ + + def __init__(self): + super().__init__() + + def __monitor_instances(self): + """ + This method monitors resources and returns the data + :return: + :rtype: + """ + monitored_ticket_ids = {} + virtual_machines: [VirtualMachine] = self._compute_client.get_all_instances() + for virtual_machine in virtual_machines: + name, tags = virtual_machine.name, virtual_machine.tags + found_duration = self._compute_client.check_tag_name(tags=tags, tag_name=DURATION) + print(virtual_machine.priority) + if found_duration: + ticket_id = self._compute_client.check_tag_name(tags=tags, tag_name=TICKET_ID) + monitored_ticket_ids.setdefault(ticket_id, []).append({ + 'region_name': virtual_machine.location, + 'ticket_id': ticket_id, + 'instance_id': virtual_machine.vm_id, + 'instance_create_time': virtual_machine.time_created, + 'instance_state': 'NA', # virtual_machine.instance_view - not available + 'instance_type': virtual_machine.hardware_profile.vm_size, + 'instance_running_days': 0, + 'instance_plan': virtual_machine.priority, + 'user_cro': self._compute_client.check_tag_name(tags=tags, tag_name='UserCRO'), + 'user': self._compute_client.check_tag_name(tags=tags, tag_name='User'), + 'manager': self._compute_client.check_tag_name(tags=tags, tag_name='Manager'), + 'approved_manager': self._compute_client.check_tag_name(tags=tags, tag_name='ApprovedManager'), + 'owner': self._compute_client.check_tag_name(tags=tags, tag_name='Owner'), + 'project': self._compute_client.check_tag_name(tags=tags, tag_name='Project'), + 'instance_name': virtual_machine.name, + 'email': self._compute_client.check_tag_name(tags=tags, tag_name='Email'), + 'duration': found_duration, + 'estimated_cost': self._compute_client.check_tag_name(tags=tags, tag_name='EstimatedCost') + }) + return monitored_ticket_ids + + def run(self): + """ + This method starts Azure CRO monitor + :return: + """ + return self.__monitor_instances() diff --git a/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/tag_cro_resources.py b/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/tag_cro_resources.py index 29fc6af5..19cafb6b 100644 --- a/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/tag_cro_resources.py +++ b/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/tag_cro_resources.py @@ -1,17 +1,22 @@ +from cloud_governance.cloud_resource_orchestration.clouds.azure.resource_groups.abstract_resource import \ + AbstractResource from cloud_governance.cloud_resource_orchestration.utils.common_operations import get_ldap_user_data -from cloud_governance.common.clouds.azure.compute.resource_group_operations import ResourceGroupOperations from cloud_governance.common.jira.jira_operations import JiraOperations from cloud_governance.common.logger.init_logger import logger -class TagCROInstances: +class TagCROResources(AbstractResource): + """ + This class manages the tagging resources which have the tag TicketId + """ TICKET_ID = 'TicketId' DURATION = 'Duration' IN_PROGRESS = 'INPROGRESS' def __init__(self): - self.__resource_group_operations = ResourceGroupOperations() + super().__init__() + self._resource_groups = self._resource_group_operations.get_all_resource_groups() def __tag_ticket_id_found_resources(self, resource_ids: list, ticket_id: str): """ @@ -45,7 +50,7 @@ def __tag_ticket_id_found_resources(self, resource_ids: list, ticket_id: str): } tagged_resource_ids = [] for resource_id in resource_ids: - success = self.__resource_group_operations.creates_or_updates_tags(resource_id=resource_id, tags=adding_extra_tags) + success = self._resource_group_operations.creates_or_updates_tags(resource_id=resource_id, tags=adding_extra_tags) if success: tagged_resource_ids.append(resource_id) logger.info(f"Tagged the resources: {tagged_resource_ids}") @@ -55,23 +60,22 @@ def __tag_instances(self): This method list the instances and tag the instances which have the tag TicketId :return: """ - resource_groups = self.__resource_group_operations.get_all_resource_groups() - for resource_group in resource_groups: + for resource_group in self._resource_groups: name = resource_group.name resource_group_tags = resource_group.tags - found_tag_value = self.__resource_group_operations.check_tag_name(tags=resource_group_tags, tag_name=self.TICKET_ID) - found_duration = self.__resource_group_operations.check_tag_name(tags=resource_group_tags, tag_name=self.DURATION) - resources_list = self.__resource_group_operations.get_all_resources(resource_group_name=name) + found_tag_value = self._resource_group_operations.check_tag_name(tags=resource_group_tags, tag_name=self.TICKET_ID) + found_duration = self._resource_group_operations.check_tag_name(tags=resource_group_tags, tag_name=self.DURATION) + resources_list = self._resource_group_operations.get_all_resources(resource_group_name=name) apply_tags = False if found_tag_value and not found_duration: apply_tags = True if not found_tag_value: for resource in resources_list: resource_tags = resource.tags - found_tag_value = self.__resource_group_operations.check_tag_name(tags=resource_tags, tag_name=self.TICKET_ID) + found_tag_value = self._resource_group_operations.check_tag_name(tags=resource_tags, tag_name=self.TICKET_ID) if found_tag_value: if not found_duration: - found_duration = self.__resource_group_operations.check_tag_name(tags=resource_tags, tag_name=self.DURATION) + found_duration = self._resource_group_operations.check_tag_name(tags=resource_tags, tag_name=self.DURATION) if not found_duration: apply_tags = True break diff --git a/cloud_governance/cloud_resource_orchestration/utils/constant_variables.py b/cloud_governance/cloud_resource_orchestration/utils/constant_variables.py index 4e80b199..be22e910 100644 --- a/cloud_governance/cloud_resource_orchestration/utils/constant_variables.py +++ b/cloud_governance/cloud_resource_orchestration/utils/constant_variables.py @@ -12,3 +12,5 @@ CLOSE_JIRA_TICKET: int = 0 DEFAULT_ROUND_DIGITS: int = 3 DATE_FORMAT: str = '%Y-%m-%d' +DURATION = 'Duration' +TICKET_ID = 'TicketId' diff --git a/cloud_governance/common/clouds/azure/compute/common_operations.py b/cloud_governance/common/clouds/azure/compute/common_operations.py index a8b7d796..c3c26049 100644 --- a/cloud_governance/common/clouds/azure/compute/common_operations.py +++ b/cloud_governance/common/clouds/azure/compute/common_operations.py @@ -42,3 +42,15 @@ def check_tag_name(self, tags: Optional[dict], tag_name: str): if string_equal_ignore_case(key, tag_name): return value return '' + + def _get_resource_group_name_from_resource_id(self, resource_id: str): + """ + This method returns the resource_group from resource_id + :param resource_id: + :type resource_id: + :return: + :rtype: + """ + id_list = resource_id.split('/') + key_values = {id_list[i].lower(): id_list[i+1] for i in range(0, len(id_list) - 1)} + return key_values.get('resourcegroups').lower() diff --git a/cloud_governance/common/clouds/azure/compute/compute_operations.py b/cloud_governance/common/clouds/azure/compute/compute_operations.py index ef13e333..3ca52a26 100644 --- a/cloud_governance/common/clouds/azure/compute/compute_operations.py +++ b/cloud_governance/common/clouds/azure/compute/compute_operations.py @@ -1,4 +1,5 @@ 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.logger.logger_time_stamp import logger_time_stamp @@ -11,12 +12,36 @@ def __init__(self): self.__compute_client = ComputeManagementClient(self._default_creds, subscription_id=self._subscription_id) @logger_time_stamp - def get_instances_by_resource_group(self, resource_group_name: str): + def get_instances_by_resource_group(self, resource_group_name: str) -> [VirtualMachine]: """ This method returns all the compute resources by resource group :return: """ instances_paged_object = self.__compute_client.virtual_machines.list(resource_group_name=resource_group_name) - instances_list = self._item_paged_iterator(item_paged_object=instances_paged_object) + instances_list: [VirtualMachine] = self._item_paged_iterator(item_paged_object=instances_paged_object) return instances_list + def get_all_instances(self) -> [VirtualMachine]: + """ + This method returns all the virtual machines + :return: + :rtype: + """ + instances_paged_object = self.__compute_client.virtual_machines.list_all() + instances_list: [VirtualMachine] = self._item_paged_iterator(item_paged_object=instances_paged_object) + return instances_list + + def get_instance_data(self, resource_id: str, vm_name: str) -> VirtualMachine: + """ + This method returns the virtual machine data by taking the id + :param vm_name: + :type vm_name: + :param resource_id: + :type resource_id: + :return: + :rtype: + """ + resource_group_name = self._get_resource_group_name_from_resource_id(resource_id=resource_id) + virtual_machine = self.__compute_client.virtual_machines.get(resource_group_name=resource_group_name, + vm_name=vm_name) + return virtual_machine