+
+ created_items = created_items or {}
+ try:
+ # Check vm exists, we can call delete_vm to clean created_items
+ if vm_id:
+ res_name = self._get_resource_name_from_resource_id(vm_id)
+ vm = self.conn_compute.virtual_machines.get(
+ self.resource_group, res_name
+ )
+
+ # Shuts down the virtual machine and releases the compute resources
+ # vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
+ # vm_stop.wait()
+
+ vm_delete = self.conn_compute.virtual_machines.begin_delete(
+ self.resource_group, res_name
+ )
+ vm_delete.wait()
+ self.logger.debug("deleted VM name: %s", res_name)
+
+ # Delete OS Disk, check if exists, in case of error creating
+ # it may not be fully created
+ if vm.storage_profile.os_disk:
+ os_disk_name = vm.storage_profile.os_disk.name
+ self.logger.debug("delete OS DISK: %s", os_disk_name)
+ async_disk_delete = self.conn_compute.disks.begin_delete(
+ self.resource_group, os_disk_name
+ )
+ async_disk_delete.wait()
+ # os disks are created always with the machine
+ self.logger.debug("deleted OS DISK name: %s", os_disk_name)
+
+ for data_disk in vm.storage_profile.data_disks:
+ self.logger.debug("delete data_disk: %s", data_disk.name)
+ async_disk_delete = self.conn_compute.disks.begin_delete(
+ self.resource_group, data_disk.name
+ )
+ async_disk_delete.wait()
+ self._markdel_created_item(data_disk.managed_disk.id, created_items)
+ self.logger.debug("deleted OS DISK name: %s", data_disk.name)
+
+ # After deleting VM, it is necessary to delete NIC, because if is not deleted delete_network
+ # does not work because Azure says that is in use the subnet
+ network_interfaces = vm.network_profile.network_interfaces
+
+ for network_interface in network_interfaces:
+ nic_name = self._get_resource_name_from_resource_id(
+ network_interface.id
+ )
+ nic_data = self.conn_vnet.network_interfaces.get(
+ self.resource_group, nic_name
+ )
+
+ public_ip_name = None
+ exist_public_ip = nic_data.ip_configurations[0].public_ip_address
+ if exist_public_ip:
+ public_ip_id = nic_data.ip_configurations[
+ 0
+ ].public_ip_address.id
+
+ # Delete public_ip
+ public_ip_name = self._get_resource_name_from_resource_id(
+ public_ip_id
+ )
+
+ # Public ip must be deleted afterwards of nic that is attached
+
+ self.logger.debug("delete NIC name: %s", nic_name)
+ nic_delete = self.conn_vnet.network_interfaces.begin_delete(
+ self.resource_group, nic_name
+ )
+ nic_delete.wait()
+ self._markdel_created_item(network_interface.id, created_items)
+ self.logger.debug("deleted NIC name: %s", nic_name)
+
+ # Delete list of public ips
+ if public_ip_name:
+ self.logger.debug("delete PUBLIC IP - " + public_ip_name)
+ ip_delete = self.conn_vnet.public_ip_addresses.begin_delete(
+ self.resource_group, public_ip_name
+ )
+ ip_delete.wait()
+ self._markdel_created_item(public_ip_id, created_items)
+
+ # Delete created items
+ self._delete_created_items(created_items)
+
+ except ResourceNotFoundError:
+ raise vimconn.VimConnNotFoundException(
+ "No vm instance found '{}'".format(vm_id)
+ )
+ except CloudError as e:
+ if e.error.error and "notfound" in e.error.error.lower():
+ raise vimconn.VimConnNotFoundException(
+ "No vm instance found '{}'".format(vm_id)
+ )
+ else:
+ self._format_vimconn_exception(e)
+ except Exception as e:
+ self._format_vimconn_exception(e)
+
+ def _markdel_created_item(self, item_id, created_items):
+ if item_id in created_items:
+ created_items[item_id] = False
+
+ def _delete_created_items(self, created_items):
+ """Delete created_items elements that have not been deleted with the virtual machine
+ Created_items may not be deleted correctly with the created machine if the
+ virtual machine fails creating or in other cases of error
+ """
+ self.logger.debug("Created items: %s", created_items)
+ # TODO - optimize - should not wait until it is deleted
+ # Must delete in order first nics, then public_ips
+ # As dictionaries don't preserve order, first get items to be deleted then delete them
+ nics_to_delete = []
+ publics_ip_to_delete = []
+ disks_to_delete = []
+ for item_id, v in created_items.items():
+ if not v: # skip already deleted
+ continue
+
+ # self.logger.debug("Must delete item id: %s", item_id)
+ # Obtain type, supported nic, disk or public ip
+ parsed_id = azure_tools.parse_resource_id(item_id)
+ resource_type = parsed_id.get("resource_type")
+ name = parsed_id.get("name")
+
+ if resource_type == "networkInterfaces":
+ nics_to_delete.append(name)
+ elif resource_type == "publicIPAddresses":
+ publics_ip_to_delete.append(name)
+ elif resource_type == "disks":
+ disks_to_delete.append(name)
+
+ # Now delete
+ for item_name in nics_to_delete:
+ try:
+ self.logger.debug("deleting nic name %s:", item_name)
+ nic_delete = self.conn_vnet.network_interfaces.begin_delete(
+ self.resource_group, item_name
+ )
+ nic_delete.wait()
+ self.logger.debug("deleted nic name %s:", item_name)
+ except Exception as e:
+ self.logger.error(
+ "Error deleting item: {}: {}".format(type(e).__name__, e)
+ )
+
+ for item_name in publics_ip_to_delete:
+ try:
+ self.logger.debug("deleting public ip name %s:", item_name)
+ ip_delete = self.conn_vnet.public_ip_addresses.begin_delete(
+ self.resource_group, name
+ )
+ ip_delete.wait()
+ self.logger.debug("deleted public ip name %s:", item_name)
+ except Exception as e:
+ self.logger.error(
+ "Error deleting item: {}: {}".format(type(e).__name__, e)
+ )
+
+ for item_name in disks_to_delete:
+ try:
+ self.logger.debug("deleting data disk name %s:", name)
+ async_disk_delete = self.conn_compute.disks.begin_delete(
+ self.resource_group, item_name
+ )
+ async_disk_delete.wait()
+ self.logger.debug("deleted data disk name %s:", name)
+ except Exception as e:
+ self.logger.error(
+ "Error deleting item: {}: {}".format(type(e).__name__, e)
+ )
+
+ def action_vminstance(self, vm_id, action_dict, created_items={}):
+ """Send and action over a VM instance from VIM
+ Returns the vm_id if the action was successfully sent to the VIM
+ """
+ self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
+
+ try:
+ self._reload_connection()
+ resName = self._get_resource_name_from_resource_id(vm_id)
+
+ if "start" in action_dict:
+ self.conn_compute.virtual_machines.begin_start(
+ self.resource_group, resName
+ )
+ elif (
+ "stop" in action_dict
+ or "shutdown" in action_dict
+ or "shutoff" in action_dict
+ ):
+ self.conn_compute.virtual_machines.begin_power_off(
+ self.resource_group, resName
+ )
+ elif "terminate" in action_dict:
+ self.conn_compute.virtual_machines.begin_delete(
+ self.resource_group, resName
+ )
+ elif "reboot" in action_dict:
+ self.conn_compute.virtual_machines.begin_restart(
+ self.resource_group, resName
+ )
+
+ return None
+ except ResourceNotFoundError:
+ raise vimconn.VimConnNotFoundException("No vm found '{}'".format(vm_id))
+ except CloudError as e:
+ if e.error.error and "notfound" in e.error.error.lower():
+ raise vimconn.VimConnNotFoundException("No vm found '{}'".format(vm_id))
+ else:
+ self._format_vimconn_exception(e)
+ except Exception as e:
+ self._format_vimconn_exception(e)
+
+ def delete_flavor(self, flavor_id):
+ raise vimconn.VimConnAuthException(
+ "It is not possible to delete a FLAVOR in AZURE"
+ )
+
+ def delete_tenant(self, tenant_id):
+ raise vimconn.VimConnAuthException(
+ "It is not possible to delete a TENANT in AZURE"
+ )
+
+ def delete_image(self, image_id):
+ raise vimconn.VimConnAuthException(
+ "It is not possible to delete a IMAGE in AZURE"
+ )