Skip to content

Commit

Permalink
added 2 handlers: disk, image. Updated instance handler. Completed vm…
Browse files Browse the repository at this point in the history
…_details_actions
  • Loading branch information
Costya-Y committed Sep 10, 2024
1 parent 44a6648 commit 9c41e80
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 117 deletions.
170 changes: 72 additions & 98 deletions cloudshell/cp/gcp/actions/vm_details_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
VmDetailsNetworkInterface,
VmDetailsProperty,
)

from cloudshell.cp.gcp.handlers.disk import DiskHandler
from cloudshell.cp.gcp.handlers.image import ImageHandler
from cloudshell.cp.gcp.helpers.constants import PUBLIC_IMAGE_PROJECTS
from cloudshell.cp.gcp.helpers.interface_helper import InterfaceHelper

if typing.TYPE_CHECKING:
from cloudshell.cp.gcp.resource_conf import GCPResourceConfig
from cloudshell.cp.gcp.handlers.instance import Instance
from cloudshell.cp.gcp.handlers.instance import Instance, InstanceHandler


@define
Expand All @@ -23,79 +27,68 @@ class VMDetailsActions:
logger: Logger

@staticmethod
def _parse_image_name(resource_id):
"""Get image name from the Azure image reference ID.
:param str resource_id: Azure image reference ID
:return: Azure image name
:rtype: str
"""
match_images = re.match(
r".*images/(?P<image_name>[^/]*).*", resource_id, flags=re.IGNORECASE
)
return match_images.group("image_name") if match_images else ""

@staticmethod
def _prepare_common_vm_instance_data(instance, resource_group_name: str):
def _prepare_common_vm_instance_data(instance_handler: InstanceHandler):
"""Prepare common VM instance data."""
disks = instance.disks
os_disk = instance.disks[0]
# os_disk_type = convert_azure_to_cs_disk_type(
# azure_disk_type=os_disk.managed_disk.storage_account_type
# )
if isinstance(instance.storage_profile.os_disk.os_type, str):
os_name = instance.storage_profile.os_disk.os_type
else:
os_name = instance.storage_profile.os_disk.os_type.name

instance = instance_handler.instance
vm_properties = [
VmDetailsProperty(
key="VM Size", value=instance.machine_type
),
VmDetailsProperty(
key="Operating System",
value=os_name,
),
# VmDetailsProperty(
# key="OS Disk Size",
# value=f"{instance.storage_profile.os_disk.disk_size_gb}GB "
# f"({os_disk_type})",
# ),
VmDetailsProperty(
key="Resource Group",
value=resource_group_name,
key="Machine Type", value=instance.machine_type.rsplit('/', 1)[-1],
),
]

disks = list(instance.disks)
os_disk = next((disk for disk in disks if disk.boot), None)
disks.remove(os_disk)
if os_disk:
os_disk_data = DiskHandler.get(
disk_name=os_disk.source.rsplit('/', 1)[-1],
zone=instance.zone.rsplit('/', 1)[-1],
credentials=instance_handler.credentials,
)
image_data = ImageHandler.parse_image_name(
image_url=os_disk_data.source_image,
)

image_name = image_data.get("image_name", "N/A")
image_project = image_data.get("image_project", "N/A")
image_project = next(
(k for k, v in PUBLIC_IMAGE_PROJECTS.items() if v == image_project),
image_project)
disk_type = os_disk_data.disk_type
disk_size = os_disk_data.disk_size
vm_properties.extend(
[
VmDetailsProperty(key="Instance Arch",
value=f"{os_disk_data.architecture.lower()}", ),
VmDetailsProperty(key="OS Disk Size",
value=f"{disk_size}GB ({disk_type})", ),
VmDetailsProperty(key="Image Name", value=image_name),
VmDetailsProperty(key="Image Project", value=image_project),
]
)

for disk_number, data_disk in enumerate(
instance.disks, start=1
disks, start=1
):
if data_disk.boot:
vm_properties.append(VmDetailsProperty(
key="OS Disk Size",
value=f"{instance.storage_profile.os_disk.disk_size_gb}GB "
f"({instance.storage_profile.os_disk.disk_type})",))

# else:
# disk_type = convert_azure_to_cs_disk_type(
# azure_disk_type=data_disk.managed_disk.storage_account_type
# )
# disk_name_prop = VmDetailsProperty(
# key=f"Data Disk {disk_number} Name",
# value=get_display_data_disk_name(
# vm_name=instance.name, full_disk_name=data_disk.name
# ),
# )
# disk_size_prop = VmDetailsProperty(
# key=f"Data Disk {disk_number} Size",
# value=f"{data_disk.disk_size_gb}GB ({disk_type})",
# )
# vm_properties.append(disk_name_prop)
# vm_properties.append(disk_size_prop)
disk_data = DiskHandler.get(
disk_name=data_disk.name,
zone=instance.zone.rsplit('/', 1)[-1],
credentials=instance_handler.credentials,
)
disk_name_prop = VmDetailsProperty(
key=f"Data Disk {disk_number} Name",
value=disk_data.disk.name,
)
disk_size_prop = VmDetailsProperty(
key=f"Data Disk {disk_number} Size",
value=f"{data_disk.disk_size}GB ({disk_data.disk_type})",
)
vm_properties.append(disk_name_prop)
vm_properties.append(disk_size_prop)

return vm_properties

def _prepare_vm_network_data(self, instance: Instance):
def _prepare_vm_network_data(self, instance_handler: InstanceHandler):
"""Prepare VM Network data.
:param instance:
Expand All @@ -105,19 +98,17 @@ def _prepare_vm_network_data(self, instance: Instance):
vm_network_interfaces = []


for network_interface in instance.network_interfaces:
for network_interface in instance_handler.instance.network_interfaces:
is_primary = False
index = instance.network_interfaces.index(network_interface)
index = instance_handler.instance.network_interfaces.index(
network_interface)
if index == 0:
is_primary = True
interface_name = network_interface.name

private_ip = network_interface.network_i_p
# nic_type
public_ip = InterfaceHelper(instance).get_public_ip(index)
network_data = [
# VmDetailsProperty(key="IP", value=private_ip),
]
public_ip = InterfaceHelper(instance_handler.instance).get_public_ip(index)
network_data = []

subnet_name = network_interface.subnetwork

Expand Down Expand Up @@ -147,47 +138,30 @@ def _prepare_vm_network_data(self, instance: Instance):

def _prepare_vm_details(
self,
instance,
instance_handler: InstanceHandler,
prepare_vm_instance_data_function: typing.Callable,
):
"""Prepare VM details."""
try:
return VmDetailsData(
appName=instance.name,
appName=instance_handler.instance.name,
vmInstanceData=prepare_vm_instance_data_function(
instance=instance,
instance_handler=instance_handler,
),
vmNetworkData=self._prepare_vm_network_data(
instance=instance,
instance_handler=instance_handler,
),
)
except Exception as e:
self._logger.exception(
f"Error getting VM details for {instance.name}"
self.logger.exception(
f"Error getting VM details for {instance_handler.instance.name}"
)
return VmDetailsData(appName=instance.name, errorMessage=str(e))
return VmDetailsData(appName=instance_handler.instance.name,
errorMessage=str(e))

def _prepare_vm_instance_data(
self, instance, resource_group_name: str
):
"""Prepare custom VM instance data."""
image_resource_id = instance.storage_profile.image_reference.id
image_name = self._parse_image_name(resource_id=image_resource_id)
image_resource_group = self._parse_resource_group_name(
resource_id=image_resource_id
)

return [
VmDetailsProperty(key="Image", value=image_name),
VmDetailsProperty(key="Image Project", value=image_resource_group),
] + self._prepare_common_vm_instance_data(
instance=instance,
resource_group_name=resource_group_name,
)

def prepare_custom_vm_details(self, instance):
def prepare_vm_details(self, instance_handler: InstanceHandler):
"""Prepare custom VM details."""
return self._prepare_vm_details(
instance=instance,
prepare_vm_instance_data_function=self._prepare_vm_instance_data,
instance_handler=instance_handler,
prepare_vm_instance_data_function=self._prepare_common_vm_instance_data,
)
6 changes: 3 additions & 3 deletions cloudshell/cp/gcp/flows/cleanup_infra_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
from cloudshell.cp.gcp.handlers.ssh_keys import SSHKeysHandler
from cloudshell.cp.gcp.handlers.subnet import SubnetHandler
from cloudshell.cp.gcp.handlers.vpc import VPCHandler
from cloudshell.cp.gcp.helpers.name_generator import generate_vpc_name

from cloudshell.cp.core.request_actions import CleanupSandboxInfraRequestActions

from cloudshell.cp.gcp.helpers.name_generator import GCPNameGenerator

if TYPE_CHECKING:
from logging import Logger
from cloudshell.cp.gcp.resource_conf import GCPResourceConfig
Expand All @@ -37,7 +37,7 @@ def cleanup_sandbox_infra(self, request_actions: CleanupSandboxInfraRequestActio
def _cleanup_network(self, cleanup_network_action: CleanupNetwork):
sandbox_id = self.config.reservation_info.reservation_id
storage_handler = SSHKeysHandler(self.config.credentials)
network_name = generate_vpc_name(sandbox_id)
network_name = GCPNameGenerator().network(sandbox_id)
self._logger.info(f"Cleaning up network: quali{network_name} in region:"
f" {self.config.region}")

Expand Down
11 changes: 7 additions & 4 deletions cloudshell/cp/gcp/flows/prepare_infra_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
from cloudshell.cp.gcp.handlers.ssh_keys import SSHKeysHandler
from cloudshell.cp.gcp.handlers.subnet import SubnetHandler
from cloudshell.cp.gcp.handlers.vpc import VPCHandler
from cloudshell.cp.gcp.helpers.name_generator import generate_name, generate_vpc_name

from cloudshell.cp.gcp.helpers.name_generator import GCPNameGenerator

if TYPE_CHECKING:
from logging import Logger
Expand All @@ -29,6 +28,7 @@ class PrepareGCPInfraFlow(AbstractPrepareSandboxInfraFlow):
logger: Logger
config: GCPResourceConfig
vpc: str = field(init=False, default=None)
name_generator: GCPNameGenerator = field(init=False, default=GCPNameGenerator())

def __attrs_post_init__(self):
super().__init__(self.logger)
Expand All @@ -37,7 +37,8 @@ def prepare_common_objects(self, request_actions: RequestActions) -> None:
""""""
vpc_handler = VPCHandler(self.config.credentials)
self.vpc = vpc_handler.get_or_create_vpc(
generate_vpc_name(self.config.reservation_info.reservation_id)
self.name_generator.network(
self.config.reservation_info.reservation_id)
)
self._create_firewall_rules(request_actions, self.vpc)

Expand All @@ -55,7 +56,9 @@ def prepare_subnets(self, request_actions: RequestActions) -> dict[str, str]:
subnet_request.actionId: subnet_handler.get_or_create_subnet(
network_name=self.vpc,
ip_cidr_range=subnet_request.get_cidr(),
subnet_name=generate_name(subnet_request.get_alias())
subnet_name=self.name_generator.subnet(
subnet_request.get_alias()
),
)
}
)
Expand Down
21 changes: 13 additions & 8 deletions cloudshell/cp/gcp/flows/vm_details_flow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import json
from typing import TYPE_CHECKING

from attr import define
Expand All @@ -19,22 +20,26 @@ class GCPGetVMDetailsFlow(AbstractVMDetailsFlow):
logger: Logger
config: GCPResourceConfig

def __attrs_post_init__(self):
super().__init__(self.logger)

def _get_vm_details(self, deployed_app: BaseGCPDeployApp):
"""Get VM Details.
:param deployed_app:
:return:
"""
# sandbox_id = self.config.reservation_info.reservation_id
name, zone = json.loads(deployed_app.vmdetails.uid).values()

vm_actions = InstanceHandler()
instance_handler = InstanceHandler.get(
instance_name=name,
credentials=self.config.credentials,
zone=zone,
)
vm_details_actions = VMDetailsActions(
config=self.config, logger=self._logger
config=self.config, logger=self.logger
)

# with self._cancellation_manager:
vm = vm_actions.get_vm_by_name(
vm_name=deployed_app.name,
return vm_details_actions.prepare_vm_details(
instance_handler=instance_handler
)

return vm_details_actions.prepare_custom_vm_details(instance=vm)
53 changes: 53 additions & 0 deletions cloudshell/cp/gcp/handlers/disk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from __future__ import annotations

import logging

from attr import define
from google.cloud import compute_v1
from google.cloud.compute_v1.types import compute
from typing_extensions import TYPE_CHECKING


from cloudshell.cp.gcp.handlers.base import BaseGCPHandler

if TYPE_CHECKING:
from google.auth.credentials import Credentials
from typing_extensions import Self

logger = logging.getLogger(__name__)

@define
class DiskHandler(BaseGCPHandler):
disk: compute.Disk

@classmethod
def get(cls, disk_name: str, zone: str, credentials: Credentials) -> Self:
"""Get disk object from GCP and create DiskHandler object."""
logger.info(f"Getting Disk {disk_name}.")
client = compute_v1.DisksClient(credentials=credentials)
disk = client.get(
project=credentials.project_id,
zone=zone,
disk=disk_name
)
return cls(disk=disk, credentials=credentials)

@property
def disk_size(self) -> str:
"""Get image name from disk."""
return self.disk.size_gb

@property
def disk_type(self) -> str:
"""Get image project from disk."""
return self.disk.type_.rsplit("/", 1)[-1]

@property
def architecture(self) -> str:
"""Get image project from disk."""
return self.disk.architecture

@property
def source_image(self) -> str:
"""Get image project from disk."""
return self.disk.source_image
Loading

0 comments on commit 9c41e80

Please sign in to comment.