diff --git a/resalloc_ibm_cloud/helpers.py b/resalloc_ibm_cloud/helpers.py index ebfeee5..95bf303 100644 --- a/resalloc_ibm_cloud/helpers.py +++ b/resalloc_ibm_cloud/helpers.py @@ -78,3 +78,13 @@ def setup_logging(log_level="info"): logging.basicConfig(level=log_level.upper(), datefmt="[%H:%M:%S]") root_logger.debug(f"Log level set to {log_level}") + + +def powervs_name(name: str) -> str: + """ + PowerVS has restriction to name, that it must contain maximum of 47 + characters. + + Returns last 46 characters of the name. + """ + return name[-46:] diff --git a/resalloc_ibm_cloud/powervs/client.py b/resalloc_ibm_cloud/powervs/client.py index 45939c2..7210aea 100644 --- a/resalloc_ibm_cloud/powervs/client.py +++ b/resalloc_ibm_cloud/powervs/client.py @@ -110,7 +110,7 @@ def request( try: response.raise_for_status() - except requests.HTTPError as e: + except requests.HTTPError: logger.error("API request failed: %s %s - %s", method, url, response.text) raise diff --git a/resalloc_ibm_cloud/powervs/credentials.py b/resalloc_ibm_cloud/powervs/credentials.py index 6aeec2b..4a1d535 100644 --- a/resalloc_ibm_cloud/powervs/credentials.py +++ b/resalloc_ibm_cloud/powervs/credentials.py @@ -5,8 +5,6 @@ import subprocess from dataclasses import dataclass -from functools import cached_property - from ibm_cloud_sdk_core.authenticators import IAMAuthenticator diff --git a/resalloc_ibm_cloud/powervs/powervs_vm.py b/resalloc_ibm_cloud/powervs/powervs_vm.py index 1812d27..7ef1fa5 100644 --- a/resalloc_ibm_cloud/powervs/powervs_vm.py +++ b/resalloc_ibm_cloud/powervs/powervs_vm.py @@ -15,7 +15,7 @@ from resalloc_ibm_cloud.argparsers import powervs_arg_parser from resalloc_ibm_cloud.exceptions import PowerVSNotFoundException -from resalloc_ibm_cloud.helpers import run_playbook, setup_logging, wait_for_ssh +from resalloc_ibm_cloud.helpers import powervs_name, run_playbook, setup_logging, wait_for_ssh from resalloc_ibm_cloud.powervs.credentials import get_powervs_credentials from resalloc_ibm_cloud.powervs.client import PowerVSClient @@ -57,7 +57,7 @@ def _build_instance_base_body(name: str, options: Any) -> dict: return instance_body def _create_volumes_with_tags( - self, vm_id: str, volumes: list[dict], tags: Optional[list[str]] + self, volumes: list[dict], tags: Optional[list[str]] ) -> list[str]: if not volumes: return [] @@ -113,13 +113,22 @@ def create_vm(self, name: str, options: Any) -> str: instance_body = self._build_instance_base_body(name, options) volumes = self._parse_volumes(getattr(options, "volumes", [])) - volume_ids = self._create_volumes_with_tags( - instance["pvmInstanceID"], volumes, getattr(options, "tags", None) - ) + volume_ids = self._create_volumes_with_tags(volumes, getattr(options, "tags", None)) instance_body["volumeIDs"] = volume_ids - instance = self._create_instance(instance_body, options.no_rmc) + try: + instance = self._create_instance(instance_body, options.no_rmc) + except Exception: + logger.error("Instance creation failed, cleaning up allocated volumes...") + sleep(20) # give IBM Cloud a while to process the volumes + for volume_id in volume_ids: + try: + self._delete_volume_with_backoff(volume_id) + logger.info("Cleaned up orphaned volume with ID %s", volume_id) + except Exception as e: + logger.error("Failed to clean up volume %s: %s", volume_id, str(e)) + raise ip_address = self._extract_ip_address(instance) wait_for_ssh(ip_address) @@ -161,7 +170,7 @@ def delete_vm(self, name: str) -> None: if not instance_id: logger.warning("No instance found with name %s", name) return - + instance_information = self.client.get_instance(instance_id) volume_ids = instance_information.get("volumeIDs", []) @@ -265,6 +274,7 @@ def main() -> int: Exit code """ opts = powervs_arg_parser().parse_args() + opts.name = powervs_name(opts.name) setup_logging(opts.log_level) @@ -278,10 +288,12 @@ def main() -> int: ip_address = vm_manager.create_vm(opts.name, opts) print(ip_address) except Exception as e: + # this mainly handles the post VM creation cleanup logger.error( "Failed to create VM: %s; trying to remove allocated resources...", str(e) ) + sleep(20) # give IBM Cloud a while vm_manager.delete_vm(opts.name) raise elif opts.subparser == "delete":