def __init__(self, region_name: str): super().__init__(region_name=region_name) self.azure_region = AzureRegion(region_name=region_name) self.azure_region_source = AzureRegion( region_name=self.SOURCE_IMAGE_REGION) self.azure_service = self.azure_region.azure_service
class AzureSctRunner(SctRunner): """Provision and configure the SCT runner on Azure.""" CLOUD_PROVIDER = "azure" GALLERY_IMAGE_NAME = "sct-runner" GALLERY_IMAGE_VERSION = f"{SctRunner.VERSION}.0" # Azure requires to have it in `X.Y.Z' format BASE_IMAGE = { "publisher": "canonical", "offer": "0001-com-ubuntu-server-focal", "sku": "20_04-lts-gen2", "version": "latest", } SOURCE_IMAGE_REGION = AzureRegion.SCT_GALLERY_REGION IMAGE_BUILDER_INSTANCE_TYPE = "Standard_D2s_v3" REGULAR_TEST_INSTANCE_TYPE = "Standard_D2s_v3" # 2 vcpus, 8G, recommended by Ubuntu 20.04 LTS image publisher LONGTERM_TEST_INSTANCE_TYPE = "Standard_E2s_v3" # 2 vcpus, 16G, recommended by Ubuntu 20.04 LTS image publisher def __init__(self, region_name: str): super().__init__(region_name=region_name) self.azure_region = AzureRegion(region_name=region_name) self.azure_region_source = AzureRegion( region_name=self.SOURCE_IMAGE_REGION) self.azure_service = self.azure_region.azure_service def region_az(self, region_name: str, availability_zone: str) -> str: return region_name @cached_property def image_name(self) -> str: return f"sct-runner-{self.VERSION}" @cached_property def key_pair(self) -> SSHKey: return KeyStore().get_gce_ssh_key_pair() # scylla-test def _image(self, image_type: ImageType = ImageType.SOURCE) -> Any: with suppress(AzureResourceNotFoundError): gallery_image_version = self.azure_region.get_gallery_image_version( gallery_image_name=self.GALLERY_IMAGE_NAME, gallery_image_version_name=self.GALLERY_IMAGE_VERSION, ) if image_type is ImageType.SOURCE: return gallery_image_version elif image_type is ImageType.GENERAL: for target_region in gallery_image_version.publishing_profile.target_regions: if region_name_to_location( target_region.name) == self.azure_region.location: return gallery_image_version return None def _create_instance( self, # pylint: disable=too-many-arguments instance_type: str, base_image: Any, tags: dict[str, str], instance_name: str, region_az: str = "", test_duration: Optional[int] = None) -> Any: if base_image is self.BASE_IMAGE: azure_region = self.azure_region_source additional_kwargs = { "os_state": AzureOsState.GENERALIZED, "computer_name": self.image_name.replace(".", "-"), "admin_username": self.LOGIN_USER, "admin_public_key": self.key_pair.public_key.decode(), } else: azure_region = self.azure_region additional_kwargs = { "os_state": AzureOsState.SPECIALIZED, } return azure_region.create_virtual_machine( vm_name=instance_name, vm_size=instance_type, image=base_image, disk_size=self.instance_root_disk_size( test_duration=test_duration), tags=tags | {"launch_time": get_current_datetime_formatted()}, **additional_kwargs, ) def _stop_image_builder_instance(self, instance: Any) -> None: self.azure_region_source.deallocate_virtual_machine( vm_name=instance.name) def _terminate_image_builder_instance(self, instance: Any) -> None: self.azure_service.delete_virtual_machine(virtual_machine=instance) def _get_instance_id(self, instance: Any) -> Any: return instance.id def get_instance_public_ip(self, instance: Any) -> str: return self.azure_service.get_virtual_machine_ips( virtual_machine=instance).public_ip def _create_image(self, instance: Any) -> Any: self.azure_region.create_gallery_image( gallery_image_name=self.GALLERY_IMAGE_NAME, os_state=AzureOsState.SPECIALIZED, ) self.azure_region.create_gallery_image_version( gallery_image_name=self.GALLERY_IMAGE_NAME, gallery_image_version_name=self.GALLERY_IMAGE_VERSION, source_id=instance.id, tags=self.image_tags, ) def _get_image_id(self, image: Any) -> Any: return image.id def _copy_source_image_to_region(self) -> None: self.azure_region.append_target_region_to_image_version( gallery_image_name=self.GALLERY_IMAGE_NAME, gallery_image_version_name=self.GALLERY_IMAGE_VERSION, region_name=self.region_name, ) def _get_base_image(self, image: Optional[Any] = None) -> Any: if image is None: image = self.image if isinstance(image, GalleryImageVersion): return {"id": image.id} return image @classmethod def list_sct_runners(cls) -> list[SctRunnerInfo]: azure_service = AzureService() sct_runners = [] for instance in list_instances_azure( tags_dict={"NodeType": cls.NODE_TYPE}, verbose=True): if launch_time := instance.tags.get("launch_time") or None: try: launch_time = datetime_from_formatted( date_string=launch_time) except ValueError as exc: LOGGER.warning("Value of `launch_time' tag is invalid: %s", exc) launch_time = None sct_runners.append( SctRunnerInfo( sct_runner_class=cls, cloud_service_instance=azure_service, region_az=instance.location, instance=instance, instance_name=instance.name, public_ips=[ azure_service.get_virtual_machine_ips( virtual_machine=instance).public_ip ], launch_time=launch_time, keep=instance.tags.get("keep"), keep_action=instance.tags.get("keep_action"), )) return sct_runners