|
|
@@ -1,28 +1,25 @@
|
|
|
import datetime
|
|
|
import logging
|
|
|
-from io import BytesIO
|
|
|
|
|
|
-from azure.common import AzureConflictHttpError
|
|
|
-from azure.common.credentials import ServicePrincipalCredentials
|
|
|
+import tenacity
|
|
|
+from cloudbridge.interfaces.exceptions import (DuplicateResourceException,
|
|
|
+ InvalidLabelException,
|
|
|
+ ProviderConnectionException,
|
|
|
+ WaitStateException)
|
|
|
+
|
|
|
+from azure.core.exceptions import (ClientAuthenticationError,
|
|
|
+ HttpResponseError, ResourceExistsError,
|
|
|
+ ResourceNotFoundError)
|
|
|
from azure.cosmosdb.table.tableservice import TableService
|
|
|
+from azure.identity import ClientSecretCredential
|
|
|
from azure.mgmt.compute import ComputeManagementClient
|
|
|
from azure.mgmt.devtestlabs.models import GalleryImageReference
|
|
|
from azure.mgmt.network import NetworkManagementClient
|
|
|
from azure.mgmt.resource import ResourceManagementClient
|
|
|
from azure.mgmt.resource.subscriptions import SubscriptionClient
|
|
|
from azure.mgmt.storage import StorageManagementClient
|
|
|
-from azure.storage.blob import BlobPermissions
|
|
|
-from azure.storage.blob import BlockBlobService
|
|
|
-from azure.storage.common import TokenCredential
|
|
|
-
|
|
|
-from msrestazure.azure_exceptions import CloudError
|
|
|
-
|
|
|
-import tenacity
|
|
|
-
|
|
|
-from cloudbridge.interfaces.exceptions import DuplicateResourceException
|
|
|
-from cloudbridge.interfaces.exceptions import InvalidLabelException
|
|
|
-from cloudbridge.interfaces.exceptions import ProviderConnectionException
|
|
|
-from cloudbridge.interfaces.exceptions import WaitStateException
|
|
|
+from azure.storage.blob import (BlobSasPermissions, BlobServiceClient,
|
|
|
+ generate_blob_sas)
|
|
|
|
|
|
from . import helpers as azure_helpers
|
|
|
|
|
|
@@ -161,10 +158,10 @@ class AzureClient(object):
|
|
|
def __init__(self, config):
|
|
|
self._config = config
|
|
|
self.subscription_id = str(config.get('azure_subscription_id'))
|
|
|
- self._credentials = ServicePrincipalCredentials(
|
|
|
+ self._credentials = ClientSecretCredential(
|
|
|
+ tenant_id=config.get('azure_tenant'),
|
|
|
client_id=config.get('azure_client_id'),
|
|
|
- secret=config.get('azure_secret'),
|
|
|
- tenant=config.get('azure_tenant')
|
|
|
+ client_secret=config.get('azure_secret')
|
|
|
)
|
|
|
|
|
|
self._access_token = config.get('azure_access_token')
|
|
|
@@ -181,13 +178,13 @@ class AzureClient(object):
|
|
|
log.debug("azure subscription : %s", self.subscription_id)
|
|
|
|
|
|
@property
|
|
|
- @tenacity.retry(stop=tenacity.stop_after_attempt(5), reraise=True)
|
|
|
+ @tenacity.retry(stop=tenacity.stop.stop_after_attempt(5), reraise=True)
|
|
|
def access_key_result(self):
|
|
|
if not self._access_key_result:
|
|
|
storage_account = self.storage_account
|
|
|
|
|
|
if self.get_storage_account(storage_account).\
|
|
|
- provisioning_state.value != 'Succeeded':
|
|
|
+ provisioning_state != 'Succeeded':
|
|
|
log.debug(
|
|
|
"Storage account %s is not in Succeeded state yet. ",
|
|
|
storage_account)
|
|
|
@@ -260,14 +257,13 @@ class AzureClient(object):
|
|
|
self._get_or_create_storage_account()
|
|
|
if not self._block_blob_service:
|
|
|
if self._access_token:
|
|
|
- token_credential = TokenCredential(self._access_token)
|
|
|
- self._block_blob_service = BlockBlobService(
|
|
|
- account_name=self.storage_account,
|
|
|
- token_credential=token_credential)
|
|
|
+ self._block_blob_service = BlobServiceClient(
|
|
|
+ account_url=f"https://{self.storage_account}.blob.core.windows.net/",
|
|
|
+ credential=self._access_token)
|
|
|
else:
|
|
|
- self._block_blob_service = BlockBlobService(
|
|
|
- account_name=self.storage_account,
|
|
|
- account_key=self.access_key_result.keys[0].value)
|
|
|
+ self._block_blob_service = BlobServiceClient(
|
|
|
+ account_url=f"https://{self.storage_account}.blob.core.windows.net/",
|
|
|
+ credential=self._credentials)
|
|
|
return self._block_blob_service
|
|
|
|
|
|
@property
|
|
|
@@ -283,6 +279,9 @@ class AzureClient(object):
|
|
|
self.public_key_storage_table_name)
|
|
|
return self._table_service
|
|
|
|
|
|
+ def blob_client(self, container_name, blob_name):
|
|
|
+ return self.blob_service.get_blob_client(container=container_name, blob=blob_name)
|
|
|
+
|
|
|
def get_resource_group(self, name):
|
|
|
return self.resource_client.resource_groups.get(name)
|
|
|
|
|
|
@@ -296,12 +295,12 @@ class AzureClient(object):
|
|
|
|
|
|
def create_storage_account(self, name, params):
|
|
|
return self.storage_client.storage_accounts. \
|
|
|
- create(self.resource_group, name.lower(), params).result()
|
|
|
+ begin_create(self.resource_group, name.lower(), params).result()
|
|
|
|
|
|
# Create a storage account. To prevent a race condition, try
|
|
|
# to get or create at least twice
|
|
|
- @tenacity.retry(stop=tenacity.stop_after_attempt(2),
|
|
|
- retry=tenacity.retry_if_exception_type(CloudError),
|
|
|
+ @tenacity.retry(stop=tenacity.stop.stop_after_attempt(2),
|
|
|
+ retry=tenacity.retry_if_exception_type(HttpResponseError),
|
|
|
reraise=True)
|
|
|
def _get_or_create_storage_account(self):
|
|
|
if self._storage_account:
|
|
|
@@ -310,52 +309,44 @@ class AzureClient(object):
|
|
|
try:
|
|
|
self._storage_account = \
|
|
|
self.get_storage_account(self.storage_account)
|
|
|
- except CloudError as cloud_error:
|
|
|
- if cloud_error.error.error == "ResourceNotFound":
|
|
|
- storage_account_params = {
|
|
|
- 'sku': {
|
|
|
- 'name': 'Standard_LRS'
|
|
|
- },
|
|
|
- 'kind': 'storage',
|
|
|
- 'location': self.region_name,
|
|
|
- }
|
|
|
- try:
|
|
|
- self._storage_account = \
|
|
|
- self.create_storage_account(self.storage_account,
|
|
|
- storage_account_params)
|
|
|
- except CloudError as cloud_error2: # pragma: no cover
|
|
|
- if cloud_error2.error.error == "AuthorizationFailed":
|
|
|
- mess = 'The following error was returned by ' \
|
|
|
- 'Azure:\n%s\n\nThis is likely because the' \
|
|
|
- ' Role associated with the provided ' \
|
|
|
- 'credentials does not allow for Storage ' \
|
|
|
- 'Account creation.\nA Storage Account is ' \
|
|
|
- 'necessary in order to perform the ' \
|
|
|
- 'desired operation. You must either ' \
|
|
|
- 'provide an existing Storage Account name' \
|
|
|
- ' as part of the configuration, or ' \
|
|
|
- 'elevate the associated Role.\nFor more ' \
|
|
|
- 'information on roles, see: https://docs.' \
|
|
|
- 'microsoft.com/en-us/azure/role-based-' \
|
|
|
- 'access-control/overview\n' % cloud_error2
|
|
|
- raise ProviderConnectionException(mess)
|
|
|
-
|
|
|
- elif cloud_error2.error.error == \
|
|
|
- "StorageAccountAlreadyTaken":
|
|
|
- mess = 'The following error was ' \
|
|
|
- 'returned by Azure:\n%s\n\n' \
|
|
|
- 'Note that Storage Account names must be ' \
|
|
|
- 'unique across Azure (not just in your ' \
|
|
|
- 'subscription).\nFor more information ' \
|
|
|
- 'see https://docs.microsoft.com/en-us/' \
|
|
|
- 'azure/azure-resource-manager/resource-' \
|
|
|
- 'manager-storage-account-name-errors\n' \
|
|
|
- % cloud_error2
|
|
|
- raise InvalidLabelException(mess)
|
|
|
- else:
|
|
|
- raise cloud_error2
|
|
|
- else:
|
|
|
- raise cloud_error
|
|
|
+ except ResourceNotFoundError:
|
|
|
+ storage_account_params = {
|
|
|
+ 'sku': {
|
|
|
+ 'name': 'Standard_LRS'
|
|
|
+ },
|
|
|
+ 'kind': 'storage',
|
|
|
+ 'location': self.region_name,
|
|
|
+ }
|
|
|
+ try:
|
|
|
+ self._storage_account = \
|
|
|
+ self.create_storage_account(self.storage_account,
|
|
|
+ storage_account_params)
|
|
|
+ except ClientAuthenticationError as auth_err:
|
|
|
+ mess = 'The following error was returned by ' \
|
|
|
+ 'Azure:\n%s\n\nThis is likely because the' \
|
|
|
+ ' Role associated with the provided ' \
|
|
|
+ 'credentials does not allow for Storage ' \
|
|
|
+ 'Account creation.\nA Storage Account is ' \
|
|
|
+ 'necessary in order to perform the ' \
|
|
|
+ 'desired operation. You must either ' \
|
|
|
+ 'provide an existing Storage Account name' \
|
|
|
+ ' as part of the configuration, or ' \
|
|
|
+ 'elevate the associated Role.\nFor more ' \
|
|
|
+ 'information on roles, see: https://docs.' \
|
|
|
+ 'microsoft.com/en-us/azure/role-based-' \
|
|
|
+ 'access-control/overview\n' % auth_err
|
|
|
+ raise ProviderConnectionException(mess)
|
|
|
+ except ResourceExistsError as exists_err:
|
|
|
+ mess = 'The following error was ' \
|
|
|
+ 'returned by Azure:\n%s\n\n' \
|
|
|
+ 'Note that Storage Account names must be ' \
|
|
|
+ 'unique across Azure (not just in your ' \
|
|
|
+ 'subscription).\nFor more information ' \
|
|
|
+ 'see https://docs.microsoft.com/en-us/' \
|
|
|
+ 'azure/azure-resource-manager/resource-' \
|
|
|
+ 'manager-storage-account-name-errors\n' \
|
|
|
+ % exists_err
|
|
|
+ raise InvalidLabelException(mess)
|
|
|
|
|
|
def list_locations(self):
|
|
|
return self.subscription_client.subscriptions. \
|
|
|
@@ -367,116 +358,129 @@ class AzureClient(object):
|
|
|
|
|
|
def create_vm_firewall(self, name, parameters):
|
|
|
return self.network_management_client.network_security_groups. \
|
|
|
- create_or_update(self.resource_group, name,
|
|
|
- parameters).result()
|
|
|
+ begin_create_or_update(self.resource_group, name,
|
|
|
+ parameters).result()
|
|
|
|
|
|
def update_vm_firewall_tags(self, fw_id, tags):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RESOURCE_ID,
|
|
|
fw_id)
|
|
|
- name = url_params.get(VM_FIREWALL_NAME)
|
|
|
+ name = url_params.get(VM_FIREWALL_NAME, "")
|
|
|
return self.network_management_client.network_security_groups. \
|
|
|
- create_or_update(self.resource_group, name,
|
|
|
- {'tags': tags,
|
|
|
- 'location': self.region_name}).result()
|
|
|
+ begin_create_or_update(self.resource_group, name,
|
|
|
+ {'tags': tags,
|
|
|
+ 'location': self.region_name}).result()
|
|
|
|
|
|
def get_vm_firewall(self, fw_id):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RESOURCE_ID,
|
|
|
fw_id)
|
|
|
- fw_name = url_params.get(VM_FIREWALL_NAME)
|
|
|
+ fw_name = url_params.get(VM_FIREWALL_NAME, "")
|
|
|
return self.network_management_client.network_security_groups. \
|
|
|
get(self.resource_group, fw_name)
|
|
|
|
|
|
def delete_vm_firewall(self, fw_id):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RESOURCE_ID,
|
|
|
fw_id)
|
|
|
- name = url_params.get(VM_FIREWALL_NAME)
|
|
|
+ name = url_params.get(VM_FIREWALL_NAME, "")
|
|
|
self.network_management_client \
|
|
|
- .network_security_groups.delete(self.resource_group, name).wait()
|
|
|
+ .network_security_groups.begin_delete(self.resource_group, name).wait()
|
|
|
|
|
|
def create_vm_firewall_rule(self, fw_id,
|
|
|
rule_name, parameters):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RESOURCE_ID,
|
|
|
fw_id)
|
|
|
- vm_firewall_name = url_params.get(VM_FIREWALL_NAME)
|
|
|
+ vm_firewall_name = url_params.get(VM_FIREWALL_NAME, "")
|
|
|
return self.network_management_client.security_rules. \
|
|
|
- create_or_update(self.resource_group, vm_firewall_name,
|
|
|
- rule_name, parameters).result()
|
|
|
+ begin_create_or_update(self.resource_group, vm_firewall_name,
|
|
|
+ rule_name, parameters).result()
|
|
|
|
|
|
def delete_vm_firewall_rule(self, fw_rule_id, vm_firewall):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RULE_RESOURCE_ID,
|
|
|
fw_rule_id)
|
|
|
- name = url_params.get(VM_FIREWALL_RULE_NAME)
|
|
|
+ name = url_params.get(VM_FIREWALL_RULE_NAME, "")
|
|
|
return self.network_management_client.security_rules. \
|
|
|
- delete(self.resource_group, vm_firewall, name).result()
|
|
|
+ begin_delete(self.resource_group, vm_firewall, name).result()
|
|
|
|
|
|
def list_containers(self, prefix=None, limit=None, marker=None):
|
|
|
- results = self.blob_service.list_containers(prefix=prefix,
|
|
|
- num_results=limit,
|
|
|
+ results = self.blob_service.list_containers(name_starts_with=prefix,
|
|
|
+ results_per_page=limit,
|
|
|
marker=marker)
|
|
|
- return (results.items, results.next_marker)
|
|
|
+ return results
|
|
|
|
|
|
def create_container(self, container_name):
|
|
|
try:
|
|
|
- self.blob_service.create_container(container_name,
|
|
|
- fail_on_exist=True)
|
|
|
- except AzureConflictHttpError as cloud_error:
|
|
|
- if cloud_error.error_code == "ContainerAlreadyExists":
|
|
|
- msg = "The given Bucket name '%s' already exists. Please " \
|
|
|
- "use the `get` or `find` method to get a reference to " \
|
|
|
- "an existing Bucket, or specify a new Bucket name to " \
|
|
|
- "create.\nNote that in Azure, Buckets are contained " \
|
|
|
- "in Storage Accounts." % container_name
|
|
|
- raise DuplicateResourceException(msg)
|
|
|
-
|
|
|
- return self.blob_service.get_container_properties(container_name)
|
|
|
+ return self.blob_service.create_container(container_name)
|
|
|
+ except ResourceExistsError:
|
|
|
+ msg = "The given Bucket name '%s' already exists. Please " \
|
|
|
+ "use the `get` or `find` method to get a reference to " \
|
|
|
+ "an existing Bucket, or specify a new Bucket name to " \
|
|
|
+ "create.\nNote that in Azure, Buckets are contained " \
|
|
|
+ "in Storage Accounts." % container_name
|
|
|
+ raise DuplicateResourceException(msg)
|
|
|
|
|
|
def get_container(self, container_name):
|
|
|
- return self.blob_service.get_container_properties(container_name)
|
|
|
+ return self.blob_service.get_container_client(container_name)
|
|
|
|
|
|
def delete_container(self, container_name):
|
|
|
self.blob_service.delete_container(container_name)
|
|
|
|
|
|
- def list_blobs(self, container_name, prefix=None):
|
|
|
- return self.blob_service.list_blobs(container_name, prefix=prefix)
|
|
|
+ def list_blobs(self, container_name, prefix=None, include=None):
|
|
|
+ container_client = self.get_container(container_name)
|
|
|
+ return container_client.list_blobs(name_starts_with=prefix, include=include)
|
|
|
+
|
|
|
+ def upload_blob(self, container_name, blob_name, data, length=None):
|
|
|
+ blob_client = self.blob_client(container_name, blob_name)
|
|
|
+ blob_client.upload_blob(data=data, length=length, overwrite=True)
|
|
|
|
|
|
def get_blob(self, container_name, blob_name):
|
|
|
- return self.blob_service.get_blob_properties(container_name, blob_name)
|
|
|
+ blob_client = self.blob_client(container_name, blob_name)
|
|
|
+ return blob_client.get_blob_properties(container_name, blob_name)
|
|
|
|
|
|
def create_blob_from_text(self, container_name, blob_name, text):
|
|
|
- self.blob_service.create_blob_from_text(container_name,
|
|
|
- blob_name, text)
|
|
|
+ if isinstance(text, bytes):
|
|
|
+ length = len(text)
|
|
|
+ else:
|
|
|
+ length = len(text.encode())
|
|
|
+ self.upload_blob(container_name, blob_name, text, length)
|
|
|
|
|
|
- def create_blob_from_file(self, container_name, blob_name, file_path):
|
|
|
- self.blob_service.create_blob_from_path(container_name,
|
|
|
- blob_name, file_path)
|
|
|
+ def create_blob_from_file(self, container_name, blob_name, file_path, length=None):
|
|
|
+ with open(file_path, 'rb') as data:
|
|
|
+ data = data.read()
|
|
|
+ self.upload_blob(container_name, blob_name, data, len(data))
|
|
|
|
|
|
- def delete_blob(self, container_name, blob_name):
|
|
|
- self.blob_service.delete_blob(container_name, blob_name)
|
|
|
+ def delete_blob(self, container_name, blob_name, delete_snapshots="include"):
|
|
|
+ blob_client = self.blob_client(container_name, blob_name)
|
|
|
+ blob_client.delete_blob(delete_snapshots)
|
|
|
|
|
|
def get_blob_url(self, container_name, blob_name, expiry_time):
|
|
|
- expiry_date = datetime.datetime.utcnow() + datetime.timedelta(
|
|
|
+ now = datetime.datetime.utcnow()
|
|
|
+ expiry = now + datetime.timedelta(
|
|
|
seconds=expiry_time)
|
|
|
- sas = self.blob_service.generate_blob_shared_access_signature(
|
|
|
- container_name, blob_name, permission=BlobPermissions.READ,
|
|
|
- expiry=expiry_date)
|
|
|
- return self.blob_service.make_blob_url(container_name, blob_name,
|
|
|
- sas_token=sas)
|
|
|
-
|
|
|
- def get_blob_content(self, container_name, blob_name):
|
|
|
- out_stream = BytesIO()
|
|
|
- self.blob_service.get_blob_to_stream(container_name,
|
|
|
- blob_name, out_stream)
|
|
|
- return out_stream
|
|
|
+ blob_name = blob_name
|
|
|
+ container_name = container_name.name
|
|
|
+ delegation_key = self.blob_service.get_user_delegation_key(
|
|
|
+ key_start_time=now, key_expiry_time=expiry
|
|
|
+ )
|
|
|
+ sas = generate_blob_sas(
|
|
|
+ self.storage_account, container_name, blob_name,
|
|
|
+ permission=BlobSasPermissions(read=True), expiry=expiry,
|
|
|
+ user_delegation_key=delegation_key
|
|
|
+ )
|
|
|
+ url = (
|
|
|
+ f"https://{self.storage_account}.blob.core.windows.net/"
|
|
|
+ f"{container_name}/{blob_name}?{sas}"
|
|
|
+ )
|
|
|
+
|
|
|
+ return url
|
|
|
|
|
|
def create_empty_disk(self, disk_name, params):
|
|
|
- return self.compute_client.disks.create_or_update(
|
|
|
+ return self.compute_client.disks.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
disk_name,
|
|
|
params
|
|
|
).result()
|
|
|
|
|
|
def create_snapshot_disk(self, disk_name, params):
|
|
|
- return self.compute_client.disks.create_or_update(
|
|
|
+ return self.compute_client.disks.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
disk_name,
|
|
|
params
|
|
|
@@ -485,7 +489,7 @@ class AzureClient(object):
|
|
|
def get_disk(self, disk_id):
|
|
|
url_params = azure_helpers.parse_url(VOLUME_RESOURCE_ID,
|
|
|
disk_id)
|
|
|
- disk_name = url_params.get(VOLUME_NAME)
|
|
|
+ disk_name = url_params.get(VOLUME_NAME, "")
|
|
|
return self.compute_client.disks.get(self.resource_group, disk_name)
|
|
|
|
|
|
def list_disks(self):
|
|
|
@@ -495,19 +499,18 @@ class AzureClient(object):
|
|
|
def delete_disk(self, disk_id):
|
|
|
url_params = azure_helpers.parse_url(VOLUME_RESOURCE_ID,
|
|
|
disk_id)
|
|
|
- disk_name = url_params.get(VOLUME_NAME)
|
|
|
- self.compute_client.disks.delete(self.resource_group, disk_name).wait()
|
|
|
+ disk_name = url_params.get(VOLUME_NAME, "")
|
|
|
+ self.compute_client.disks.begin_delete(self.resource_group, disk_name).wait()
|
|
|
|
|
|
def update_disk_tags(self, disk_id, tags):
|
|
|
url_params = azure_helpers.parse_url(VOLUME_RESOURCE_ID,
|
|
|
disk_id)
|
|
|
- disk_name = url_params.get(VOLUME_NAME)
|
|
|
- return self.compute_client.disks.update(
|
|
|
+ disk_name = url_params.get(VOLUME_NAME, "")
|
|
|
+ return self.compute_client.disks.begin_update(
|
|
|
self.resource_group,
|
|
|
disk_name,
|
|
|
- {'tags': tags},
|
|
|
- raw=True
|
|
|
- )
|
|
|
+ {'tags': tags} # type: ignore
|
|
|
+ ).wait()
|
|
|
|
|
|
def list_snapshots(self):
|
|
|
return self.compute_client.snapshots. \
|
|
|
@@ -516,34 +519,43 @@ class AzureClient(object):
|
|
|
def get_snapshot(self, snapshot_id):
|
|
|
url_params = azure_helpers.parse_url(SNAPSHOT_RESOURCE_ID,
|
|
|
snapshot_id)
|
|
|
- snapshot_name = url_params.get(SNAPSHOT_NAME)
|
|
|
+ snapshot_name = url_params.get(SNAPSHOT_NAME, "")
|
|
|
return self.compute_client.snapshots.get(self.resource_group,
|
|
|
snapshot_name)
|
|
|
|
|
|
- def create_snapshot(self, snapshot_name, params):
|
|
|
- return self.compute_client.snapshots.create_or_update(
|
|
|
+ def create_snapshot(self, snapshot_name, volume, tags):
|
|
|
+ snapshot = self.compute_client.snapshots.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
snapshot_name,
|
|
|
- params
|
|
|
+ {
|
|
|
+ 'location': volume.location,
|
|
|
+ 'creation_data': {
|
|
|
+ 'create_option': 'Copy',
|
|
|
+ 'source_uri': volume.id
|
|
|
+ },
|
|
|
+ 'tags': tags
|
|
|
+ }
|
|
|
).result()
|
|
|
|
|
|
+ self.update_snapshot_tags(snapshot.id, tags)
|
|
|
+ return snapshot
|
|
|
+
|
|
|
def delete_snapshot(self, snapshot_id):
|
|
|
url_params = azure_helpers.parse_url(SNAPSHOT_RESOURCE_ID,
|
|
|
snapshot_id)
|
|
|
- snapshot_name = url_params.get(SNAPSHOT_NAME)
|
|
|
- self.compute_client.snapshots.delete(self.resource_group,
|
|
|
- snapshot_name).wait()
|
|
|
+ snapshot_name = url_params.get(SNAPSHOT_NAME, "")
|
|
|
+ self.compute_client.snapshots.begin_delete(self.resource_group,
|
|
|
+ snapshot_name).wait()
|
|
|
|
|
|
def update_snapshot_tags(self, snapshot_id, tags):
|
|
|
url_params = azure_helpers.parse_url(SNAPSHOT_RESOURCE_ID,
|
|
|
snapshot_id)
|
|
|
- snapshot_name = url_params.get(SNAPSHOT_NAME)
|
|
|
- return self.compute_client.snapshots.update(
|
|
|
+ snapshot_name = url_params.get(SNAPSHOT_NAME, "")
|
|
|
+ return self.compute_client.snapshots.begin_update(
|
|
|
self.resource_group,
|
|
|
snapshot_name,
|
|
|
- {'tags': tags},
|
|
|
- raw=True
|
|
|
- )
|
|
|
+ {'tags': tags} # type: ignore
|
|
|
+ ).wait()
|
|
|
|
|
|
def is_gallery_image(self, image_id):
|
|
|
url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
|
|
|
@@ -553,15 +565,14 @@ class AzureClient(object):
|
|
|
|
|
|
def create_image(self, name, params):
|
|
|
return self.compute_client.images. \
|
|
|
- create_or_update(self.resource_group, name,
|
|
|
- params).result()
|
|
|
+ begin_create_or_update(self.resource_group, name, params).result()
|
|
|
|
|
|
def delete_image(self, image_id):
|
|
|
url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
|
|
|
image_id)
|
|
|
if not self.is_gallery_image(image_id):
|
|
|
- name = url_params.get(IMAGE_NAME)
|
|
|
- self.compute_client.images.delete(self.resource_group, name).wait()
|
|
|
+ name = url_params.get(IMAGE_NAME, "")
|
|
|
+ self.compute_client.images.begin_delete(self.resource_group, name).wait()
|
|
|
|
|
|
def list_images(self):
|
|
|
azure_images = list(self.compute_client.images.
|
|
|
@@ -580,7 +591,7 @@ class AzureClient(object):
|
|
|
sku=url_params['sku'],
|
|
|
version=url_params['version'])
|
|
|
else:
|
|
|
- name = url_params.get(IMAGE_NAME)
|
|
|
+ name = url_params.get(IMAGE_NAME, "")
|
|
|
return self.compute_client.images.get(self.resource_group, name)
|
|
|
|
|
|
def update_image_tags(self, image_id, tags):
|
|
|
@@ -589,13 +600,13 @@ class AzureClient(object):
|
|
|
if self.is_gallery_image(image_id):
|
|
|
return True
|
|
|
else:
|
|
|
- name = url_params.get(IMAGE_NAME)
|
|
|
+ name = url_params.get(IMAGE_NAME, "")
|
|
|
return self.compute_client.images. \
|
|
|
- create_or_update(self.resource_group, name,
|
|
|
- {
|
|
|
- 'tags': tags,
|
|
|
- 'location': self.region_name
|
|
|
- }).result()
|
|
|
+ begin_create_or_update(self.resource_group, name,
|
|
|
+ {
|
|
|
+ 'tags': tags,
|
|
|
+ 'location': self.region_name
|
|
|
+ }).result()
|
|
|
|
|
|
def list_vm_types(self):
|
|
|
return self.compute_client.virtual_machine_sizes. \
|
|
|
@@ -608,28 +619,25 @@ class AzureClient(object):
|
|
|
def get_network(self, network_id):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID,
|
|
|
network_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
return self.network_management_client.virtual_networks.get(
|
|
|
self.resource_group, network_name)
|
|
|
|
|
|
def create_network(self, name, params):
|
|
|
return self.network_management_client.virtual_networks. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- name,
|
|
|
- parameters=params).result()
|
|
|
+ begin_create_or_update(self.resource_group, name, parameters=params).result()
|
|
|
|
|
|
def delete_network(self, network_id):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
return self.network_management_client.virtual_networks. \
|
|
|
- delete(self.resource_group, network_name).wait()
|
|
|
+ begin_delete(self.resource_group, network_name).wait()
|
|
|
|
|
|
def update_network_tags(self, network_id, tags):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
return self.network_management_client.virtual_networks. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- network_name, tags).result()
|
|
|
+ begin_create_or_update(self.resource_group, network_name, tags).result()
|
|
|
|
|
|
def get_network_id_for_subnet(self, subnet_id):
|
|
|
url_params = azure_helpers.parse_url(SUBNET_RESOURCE_ID, subnet_id)
|
|
|
@@ -640,23 +648,23 @@ class AzureClient(object):
|
|
|
|
|
|
def list_subnets(self, network_id):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
return self.network_management_client.subnets. \
|
|
|
list(self.resource_group, network_name)
|
|
|
|
|
|
def get_subnet(self, subnet_id):
|
|
|
url_params = azure_helpers.parse_url(SUBNET_RESOURCE_ID,
|
|
|
subnet_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
- subnet_name = url_params.get(SUBNET_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
+ subnet_name = url_params.get(SUBNET_NAME, "")
|
|
|
return self.network_management_client.subnets. \
|
|
|
get(self.resource_group, network_name, subnet_name)
|
|
|
|
|
|
def create_subnet(self, network_id, subnet_name, params):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
result_create = self.network_management_client \
|
|
|
- .subnets.create_or_update(
|
|
|
+ .subnets.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
network_name,
|
|
|
subnet_name,
|
|
|
@@ -668,61 +676,59 @@ class AzureClient(object):
|
|
|
|
|
|
def __if_subnet_in_use(e):
|
|
|
# return True if the CloudError exception is due to subnet being in use
|
|
|
- if isinstance(e, CloudError):
|
|
|
- if e.error.error == "InUseSubnetCannotBeDeleted":
|
|
|
+ if isinstance(e, HttpResponseError):
|
|
|
+ if "InUseSubnetCannotBeDeleted" in e.message:
|
|
|
return True
|
|
|
return False
|
|
|
|
|
|
- @tenacity.retry(stop=tenacity.stop_after_attempt(5),
|
|
|
+ @tenacity.retry(stop=tenacity.stop.stop_after_attempt(5),
|
|
|
retry=tenacity.retry_if_exception(__if_subnet_in_use),
|
|
|
- wait=tenacity.wait_fixed(5),
|
|
|
+ wait=tenacity.wait.wait_fixed(5),
|
|
|
reraise=True)
|
|
|
def delete_subnet(self, subnet_id):
|
|
|
url_params = azure_helpers.parse_url(SUBNET_RESOURCE_ID,
|
|
|
subnet_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
- subnet_name = url_params.get(SUBNET_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
+ subnet_name = url_params.get(SUBNET_NAME, "")
|
|
|
|
|
|
try:
|
|
|
result_delete = self.network_management_client \
|
|
|
- .subnets.delete(
|
|
|
+ .subnets.begin_delete(
|
|
|
self.resource_group,
|
|
|
network_name,
|
|
|
subnet_name
|
|
|
)
|
|
|
result_delete.wait()
|
|
|
- except CloudError as cloud_error:
|
|
|
+ except HttpResponseError as cloud_error:
|
|
|
log.exception(cloud_error.message)
|
|
|
raise cloud_error
|
|
|
|
|
|
def create_floating_ip(self, public_ip_name, public_ip_parameters):
|
|
|
return self.network_management_client.public_ip_addresses. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- public_ip_name,
|
|
|
- public_ip_parameters).result()
|
|
|
+ begin_create_or_update(self.resource_group,
|
|
|
+ public_ip_name, public_ip_parameters).result()
|
|
|
|
|
|
def get_floating_ip(self, public_ip_id):
|
|
|
url_params = azure_helpers.parse_url(PUBLIC_IP_RESOURCE_ID,
|
|
|
public_ip_id)
|
|
|
- public_ip_name = url_params.get(PUBLIC_IP_NAME)
|
|
|
+ public_ip_name = url_params.get(PUBLIC_IP_NAME, "")
|
|
|
return self.network_management_client. \
|
|
|
public_ip_addresses.get(self.resource_group, public_ip_name)
|
|
|
|
|
|
def delete_floating_ip(self, public_ip_id):
|
|
|
url_params = azure_helpers.parse_url(PUBLIC_IP_RESOURCE_ID,
|
|
|
public_ip_id)
|
|
|
- public_ip_name = url_params.get(PUBLIC_IP_NAME)
|
|
|
+ public_ip_name = url_params.get(PUBLIC_IP_NAME, "")
|
|
|
self.network_management_client. \
|
|
|
- public_ip_addresses.delete(self.resource_group,
|
|
|
- public_ip_name).wait()
|
|
|
+ public_ip_addresses.begin_delete(self.resource_group,
|
|
|
+ public_ip_name).wait()
|
|
|
|
|
|
def update_fip_tags(self, fip_id, tags):
|
|
|
url_params = azure_helpers.parse_url(PUBLIC_IP_RESOURCE_ID,
|
|
|
fip_id)
|
|
|
- fip_name = url_params.get(PUBLIC_IP_NAME)
|
|
|
+ fip_name = url_params.get(PUBLIC_IP_NAME, "")
|
|
|
self.network_management_client.public_ip_addresses. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- fip_name, tags).result()
|
|
|
+ begin_create_or_update(self.resource_group, fip_name, tags).result()
|
|
|
|
|
|
def list_floating_ips(self):
|
|
|
return self.network_management_client.public_ip_addresses.list(
|
|
|
@@ -736,21 +742,21 @@ class AzureClient(object):
|
|
|
def restart_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
- return self.compute_client.virtual_machines.restart(
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
+ return self.compute_client.virtual_machines.begin_restart(
|
|
|
self.resource_group, vm_name).wait()
|
|
|
|
|
|
def delete_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
- return self.compute_client.virtual_machines.delete(
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
+ return self.compute_client.virtual_machines.begin_delete(
|
|
|
self.resource_group, vm_name).wait()
|
|
|
|
|
|
def get_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
return self.compute_client.virtual_machines.get(
|
|
|
self.resource_group,
|
|
|
vm_name,
|
|
|
@@ -759,69 +765,63 @@ class AzureClient(object):
|
|
|
|
|
|
def create_vm(self, vm_name, params):
|
|
|
return self.compute_client.virtual_machines. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- vm_name, params).result()
|
|
|
+ begin_create_or_update(self.resource_group, vm_name, params).result()
|
|
|
|
|
|
def update_vm(self, vm_id, params):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
return self.compute_client.virtual_machines. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- vm_name, params, raw=True)
|
|
|
+ begin_create_or_update(self.resource_group, vm_name, params).wait()
|
|
|
|
|
|
def deallocate_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
self.compute_client. \
|
|
|
- virtual_machines.deallocate(self.resource_group,
|
|
|
- vm_name).wait()
|
|
|
+ virtual_machines.begin_deallocate(self.resource_group, vm_name).wait()
|
|
|
|
|
|
def generalize_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
self.compute_client.virtual_machines. \
|
|
|
generalize(self.resource_group, vm_name)
|
|
|
|
|
|
def start_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
self.compute_client.virtual_machines. \
|
|
|
- start(self.resource_group,
|
|
|
- vm_name).wait()
|
|
|
+ begin_start(self.resource_group, vm_name).wait()
|
|
|
|
|
|
def update_vm_tags(self, vm_id, tags):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
- vm_name = url_params.get(VM_NAME)
|
|
|
+ vm_name = url_params.get(VM_NAME, "")
|
|
|
self.compute_client.virtual_machines. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- vm_name, tags).result()
|
|
|
+ begin_create_or_update(self.resource_group, vm_name, tags).result()
|
|
|
|
|
|
def delete_nic(self, nic_id):
|
|
|
nic_params = azure_helpers.\
|
|
|
parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
|
|
|
- nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
|
|
|
+ nic_name = nic_params.get(NETWORK_INTERFACE_NAME, "")
|
|
|
self.network_management_client. \
|
|
|
- network_interfaces.delete(self.resource_group,
|
|
|
- nic_name).wait()
|
|
|
+ network_interfaces.begin_delete(self.resource_group, nic_name).wait()
|
|
|
|
|
|
def get_nic(self, nic_id):
|
|
|
nic_params = azure_helpers.\
|
|
|
parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
|
|
|
- nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
|
|
|
+ nic_name = nic_params.get(NETWORK_INTERFACE_NAME, "")
|
|
|
return self.network_management_client. \
|
|
|
network_interfaces.get(self.resource_group, nic_name)
|
|
|
|
|
|
def update_nic(self, nic_id, params):
|
|
|
nic_params = azure_helpers.\
|
|
|
parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
|
|
|
- nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
|
|
|
+ nic_name = nic_params.get(NETWORK_INTERFACE_NAME, "")
|
|
|
async_nic_creation = self.network_management_client. \
|
|
|
- network_interfaces.create_or_update(
|
|
|
+ network_interfaces.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
nic_name,
|
|
|
params
|
|
|
@@ -831,7 +831,7 @@ class AzureClient(object):
|
|
|
|
|
|
def create_nic(self, nic_name, params):
|
|
|
return self.network_management_client. \
|
|
|
- network_interfaces.create_or_update(
|
|
|
+ network_interfaces.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
nic_name,
|
|
|
params
|
|
|
@@ -862,14 +862,14 @@ class AzureClient(object):
|
|
|
|
|
|
def delete_route_table(self, route_table_name):
|
|
|
self.network_management_client. \
|
|
|
- route_tables.delete(self.resource_group, route_table_name
|
|
|
- ).wait()
|
|
|
+ route_tables.begin_delete(self.resource_group,
|
|
|
+ route_table_name).wait()
|
|
|
|
|
|
def attach_subnet_to_route_table(self, subnet_id, route_table_id):
|
|
|
url_params = azure_helpers.parse_url(SUBNET_RESOURCE_ID,
|
|
|
subnet_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
- subnet_name = url_params.get(SUBNET_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
+ subnet_name = url_params.get(SUBNET_NAME, "")
|
|
|
|
|
|
subnet_info = self.network_management_client.subnets.get(
|
|
|
self.resource_group,
|
|
|
@@ -882,11 +882,11 @@ class AzureClient(object):
|
|
|
}
|
|
|
|
|
|
result_create = self.network_management_client. \
|
|
|
- subnets.create_or_update(
|
|
|
+ subnets.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
network_name,
|
|
|
subnet_name,
|
|
|
- subnet_info)
|
|
|
+ subnet_info) # type: ignore
|
|
|
subnet_info = result_create.result()
|
|
|
|
|
|
return subnet_info
|
|
|
@@ -894,8 +894,8 @@ class AzureClient(object):
|
|
|
def detach_subnet_to_route_table(self, subnet_id, route_table_id):
|
|
|
url_params = azure_helpers.parse_url(SUBNET_RESOURCE_ID,
|
|
|
subnet_id)
|
|
|
- network_name = url_params.get(NETWORK_NAME)
|
|
|
- subnet_name = url_params.get(SUBNET_NAME)
|
|
|
+ network_name = url_params.get(NETWORK_NAME, "")
|
|
|
+ subnet_name = url_params.get(SUBNET_NAME, "")
|
|
|
|
|
|
subnet_info = self.network_management_client.subnets.get(
|
|
|
self.resource_group,
|
|
|
@@ -907,11 +907,11 @@ class AzureClient(object):
|
|
|
subnet_info.route_table = None
|
|
|
|
|
|
result_create = self.network_management_client. \
|
|
|
- subnets.create_or_update(
|
|
|
+ subnets.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
network_name,
|
|
|
subnet_name,
|
|
|
- subnet_info)
|
|
|
+ subnet_info) # type: ignore
|
|
|
subnet_info = result_create.result()
|
|
|
|
|
|
return subnet_info
|
|
|
@@ -923,17 +923,16 @@ class AzureClient(object):
|
|
|
def get_route_table(self, router_id):
|
|
|
url_params = azure_helpers.parse_url(ROUTER_RESOURCE_ID,
|
|
|
router_id)
|
|
|
- router_name = url_params.get(ROUTER_NAME)
|
|
|
+ router_name = url_params.get(ROUTER_NAME, "")
|
|
|
return self.network_management_client. \
|
|
|
route_tables.get(self.resource_group, router_name)
|
|
|
|
|
|
def create_route_table(self, route_table_name, params):
|
|
|
return self.network_management_client. \
|
|
|
- route_tables.create_or_update(
|
|
|
+ route_tables.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
route_table_name, params).result()
|
|
|
|
|
|
def update_route_table_tags(self, route_table_name, tags):
|
|
|
self.network_management_client.route_tables. \
|
|
|
- create_or_update(self.resource_group,
|
|
|
- route_table_name, tags).result()
|
|
|
+ begin_create_or_update(self.resource_group, route_table_name, tags).result()
|