diff --git a/ocw/lib/azure.py b/ocw/lib/azure.py index 6ce836d0..db2311f8 100644 --- a/ocw/lib/azure.py +++ b/ocw/lib/azure.py @@ -7,6 +7,7 @@ from azure.storage.blob import BlobServiceClient from azure.core.exceptions import ResourceNotFoundError from msrest.exceptions import AuthenticationError +from dateutil.parser import parse from webui.PCWConfig import PCWConfig from .provider import Provider from ..models import Instance @@ -96,6 +97,9 @@ def get_vm_types_in_resource_group(self, resource_group: str) -> str: return ', '.join(type_set) return "N/A" + def get_resource_properties(self, resource_id): + return self.resource_mgmt_client().resources.get_by_id(resource_id, api_version="2023-07-03").properties + def list_resource_groups(self) -> list: return list(self.resource_mgmt_client().resource_groups.list()) @@ -114,6 +118,10 @@ def list_disks_by_resource_group(self, resource_group): return self.list_by_resource_group(resource_group, filters="resourceType eq 'Microsoft.Compute/disks'") + def list_galleries_by_resource_group(self, resource_group): + return self.list_by_resource_group(resource_group, + filters="resourceType eq 'Microsoft.Compute/galleries'") + def list_by_resource_group(self, resource_group, filters=None) -> list: return list(self.resource_mgmt_client().resources.list_by_resource_group( resource_group, filter=filters, expand="changedTime")) @@ -121,6 +129,7 @@ def list_by_resource_group(self, resource_group, filters=None) -> list: def cleanup_all(self) -> None: self.log_info("Call cleanup_all") self.cleanup_images_from_rg() + self.cleanup_versions_from_rg() self.cleanup_disks_from_rg() self.cleanup_blob_containers() @@ -172,10 +181,27 @@ def cleanup_disks_from_rg(self) -> None: for item in self.list_disks_by_resource_group(self.__resource_group): if self.is_outdated(item.changed_time): if self.compute_mgmt_client().disks.get(self.__resource_group, item.name).managed_by: - self.log_warn(f"Disk is in use - unable delete {item.name}") + self.log_warn(f"Disk is in use - skipping {item.name}") else: if self.dry_run: self.log_info(f"Deletion of disk {item.name} skipped due to dry run mode") else: self.log_info(f"Delete disk '{item.name}'") self.compute_mgmt_client().disks.begin_delete(self.__resource_group, item.name) + + def cleanup_versions_from_rg(self) -> None: + self.log_dbg("Call cleanup_versions_from_rg") + # for gallery in self.compute_mgmt_client().galleries.list_by_resource_group(self.__resource_group): + for gallery in self.list_galleries_by_resource_group(self.__resource_group): + for image in self.compute_mgmt_client().gallery_images.list_by_gallery(self.__resource_group, gallery.name): + for version in self.compute_mgmt_client().gallery_image_versions.list_by_gallery_image( + self.__resource_group, gallery.name, image.name): + properties = self.get_resource_properties(version.id) + if self.is_outdated(parse(properties['publishingProfile']['publishedDate'])): + if self.dry_run: + self.log_info(f"Deletion of version {gallery.name}/{image.name}/{version.name} skipped due to dry run mode") + else: + self.log_info(f"Delete version '{gallery.name}/{image.name}/{version.name}'") + self.compute_mgmt_client().gallery_image_versions.begin_delete( + self.__resource_group, gallery.name, image.name, version.name + ) # .wait() diff --git a/tests/test_azure.py b/tests/test_azure.py index 3b73716c..fc872290 100644 --- a/tests/test_azure.py +++ b/tests/test_azure.py @@ -271,11 +271,12 @@ def count_call(*args, **kwargs): monkeypatch.setattr(Azure, 'cleanup_blob_containers', count_call) monkeypatch.setattr(Azure, 'cleanup_disks_from_rg', count_call) monkeypatch.setattr(Azure, 'cleanup_images_from_rg', count_call) + monkeypatch.setattr(Azure, 'cleanup_versions_from_rg', count_call) monkeypatch.setattr(Provider, 'read_auth_json', lambda *args, **kwargs: '{}') az = Azure('fake') az.cleanup_all() - assert called == 3 + assert called == 4 def test_check_credentials(monkeypatch):