|
|
@@ -7,17 +7,27 @@ from cloudbridge.interfaces.exceptions import (DuplicateResourceException,
|
|
|
ProviderConnectionException,
|
|
|
WaitStateException)
|
|
|
|
|
|
+from azure.core.credentials import AzureNamedKeyCredential
|
|
|
from azure.core.exceptions import (ClientAuthenticationError,
|
|
|
HttpResponseError, ResourceExistsError,
|
|
|
ResourceNotFoundError)
|
|
|
-from azure.cosmosdb.table.tableservice import TableService
|
|
|
+from azure.data.tables import TableServiceClient
|
|
|
from azure.identity import ClientSecretCredential
|
|
|
from azure.mgmt.compute import ComputeManagementClient
|
|
|
+from azure.mgmt.compute.models import (CreationData, Disk, DiskUpdate, Image,
|
|
|
+ ImageUpdate, Snapshot, SnapshotUpdate,
|
|
|
+ VirtualMachine, VirtualMachineUpdate)
|
|
|
from azure.mgmt.devtestlabs.models import GalleryImageReference
|
|
|
from azure.mgmt.network import NetworkManagementClient
|
|
|
+from azure.mgmt.network.models import (NetworkInterface,
|
|
|
+ NetworkSecurityGroup, PublicIPAddress,
|
|
|
+ RouteTable, SecurityRule, SubResource,
|
|
|
+ Subnet, TagsObject, VirtualNetwork)
|
|
|
from azure.mgmt.resource import ResourceManagementClient
|
|
|
-from azure.mgmt.resource.subscriptions import SubscriptionClient
|
|
|
+from azure.mgmt.resource.resources.models import ResourceGroup
|
|
|
from azure.mgmt.storage import StorageManagementClient
|
|
|
+from azure.mgmt.storage.models import Sku, StorageAccountCreateParameters
|
|
|
+from azure.mgmt.subscription import SubscriptionClient
|
|
|
from azure.storage.blob import (BlobSasPermissions, BlobServiceClient,
|
|
|
generate_blob_sas)
|
|
|
|
|
|
@@ -172,7 +182,8 @@ class AzureClient(object):
|
|
|
self._compute_client = None
|
|
|
self._access_key_result = None
|
|
|
self._block_blob_service = None
|
|
|
- self._table_service = None
|
|
|
+ self._table_service_client = None
|
|
|
+ self._public_key_table_client = None
|
|
|
self._storage_account = None
|
|
|
|
|
|
log.debug("azure subscription : %s", self.subscription_id)
|
|
|
@@ -273,15 +284,18 @@ class AzureClient(object):
|
|
|
@property
|
|
|
def table_service(self):
|
|
|
self._get_or_create_storage_account()
|
|
|
- if not self._table_service:
|
|
|
- self._table_service = TableService(
|
|
|
+ if not self._table_service_client:
|
|
|
+ credential = AzureNamedKeyCredential(
|
|
|
self.storage_account,
|
|
|
self.access_key_result.keys[0].value)
|
|
|
- if not self._table_service. \
|
|
|
- exists(table_name=self.public_key_storage_table_name):
|
|
|
- self._table_service.create_table(
|
|
|
- self.public_key_storage_table_name)
|
|
|
- return self._table_service
|
|
|
+ self._table_service_client = TableServiceClient(
|
|
|
+ endpoint=f"https://{self.storage_account}.table.core.windows.net/",
|
|
|
+ credential=credential)
|
|
|
+ if not self._public_key_table_client:
|
|
|
+ self._public_key_table_client = \
|
|
|
+ self._table_service_client.create_table_if_not_exists(
|
|
|
+ table_name=self.public_key_storage_table_name)
|
|
|
+ return self._public_key_table_client
|
|
|
|
|
|
def blob_client(self, container_name, blob_name):
|
|
|
return self.blob_service.get_blob_client(container=container_name, blob=blob_name)
|
|
|
@@ -291,7 +305,7 @@ class AzureClient(object):
|
|
|
|
|
|
def create_resource_group(self, name, parameters):
|
|
|
return self.resource_client.resource_groups. \
|
|
|
- create_or_update(name, parameters)
|
|
|
+ create_or_update(name, ResourceGroup(**parameters))
|
|
|
|
|
|
def get_storage_account(self, storage_account):
|
|
|
return self.storage_client.storage_accounts. \
|
|
|
@@ -299,7 +313,8 @@ class AzureClient(object):
|
|
|
|
|
|
def create_storage_account(self, name, params):
|
|
|
return self.storage_client.storage_accounts. \
|
|
|
- begin_create(self.resource_group, name.lower(), params).result()
|
|
|
+ begin_create(self.resource_group, name.lower(),
|
|
|
+ StorageAccountCreateParameters(**params)).result()
|
|
|
|
|
|
# Create a storage account. To prevent a race condition, try
|
|
|
# to get or create at least twice
|
|
|
@@ -315,9 +330,7 @@ class AzureClient(object):
|
|
|
self.get_storage_account(self.storage_account)
|
|
|
except ResourceNotFoundError:
|
|
|
storage_account_params = {
|
|
|
- 'sku': {
|
|
|
- 'name': 'Standard_LRS'
|
|
|
- },
|
|
|
+ 'sku': Sku(name='Standard_LRS'),
|
|
|
'kind': 'storage',
|
|
|
'location': self.region_name,
|
|
|
}
|
|
|
@@ -362,17 +375,16 @@ class AzureClient(object):
|
|
|
|
|
|
def create_vm_firewall(self, name, parameters):
|
|
|
return self.network_management_client.network_security_groups. \
|
|
|
- begin_create_or_update(self.resource_group, name,
|
|
|
- parameters).result()
|
|
|
+ begin_create_or_update(
|
|
|
+ self.resource_group, name,
|
|
|
+ NetworkSecurityGroup(**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, "")
|
|
|
return self.network_management_client.network_security_groups. \
|
|
|
- begin_create_or_update(self.resource_group, name,
|
|
|
- {'tags': tags,
|
|
|
- 'location': self.region_name}).result()
|
|
|
+ update_tags(self.resource_group, name, TagsObject(tags=tags))
|
|
|
|
|
|
def get_vm_firewall(self, fw_id):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RESOURCE_ID,
|
|
|
@@ -393,9 +405,14 @@ class AzureClient(object):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RESOURCE_ID,
|
|
|
fw_id)
|
|
|
vm_firewall_name = url_params.get(VM_FIREWALL_NAME, "")
|
|
|
+ # parameters may be either a raw dict (from VMFirewallRuleService) or
|
|
|
+ # an existing SecurityRule model (when overriding default rules from
|
|
|
+ # the firewall.default_security_rules list).
|
|
|
+ rule = (parameters if isinstance(parameters, SecurityRule)
|
|
|
+ else SecurityRule(**parameters))
|
|
|
return self.network_management_client.security_rules. \
|
|
|
begin_create_or_update(self.resource_group, vm_firewall_name,
|
|
|
- rule_name, parameters).result()
|
|
|
+ rule_name, rule).result()
|
|
|
|
|
|
def delete_vm_firewall_rule(self, fw_rule_id, vm_firewall):
|
|
|
url_params = azure_helpers.parse_url(VM_FIREWALL_RULE_RESOURCE_ID,
|
|
|
@@ -476,14 +493,14 @@ class AzureClient(object):
|
|
|
return self.compute_client.disks.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
disk_name,
|
|
|
- params
|
|
|
+ Disk(**params)
|
|
|
).result()
|
|
|
|
|
|
def create_snapshot_disk(self, disk_name, params):
|
|
|
return self.compute_client.disks.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
disk_name,
|
|
|
- params
|
|
|
+ Disk(**params)
|
|
|
).result()
|
|
|
|
|
|
def get_disk(self, disk_id):
|
|
|
@@ -509,7 +526,7 @@ class AzureClient(object):
|
|
|
return self.compute_client.disks.begin_update(
|
|
|
self.resource_group,
|
|
|
disk_name,
|
|
|
- {'tags': tags} # type: ignore
|
|
|
+ DiskUpdate(tags=tags)
|
|
|
).wait()
|
|
|
|
|
|
def list_snapshots(self):
|
|
|
@@ -527,14 +544,14 @@ class AzureClient(object):
|
|
|
snapshot = self.compute_client.snapshots.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
snapshot_name,
|
|
|
- {
|
|
|
- 'location': volume.location,
|
|
|
- 'creation_data': {
|
|
|
- 'create_option': 'Copy',
|
|
|
- 'source_uri': volume.id
|
|
|
- },
|
|
|
- 'tags': tags
|
|
|
- }
|
|
|
+ Snapshot(
|
|
|
+ location=volume.location,
|
|
|
+ creation_data=CreationData(
|
|
|
+ create_option='Copy',
|
|
|
+ source_uri=volume.id
|
|
|
+ ),
|
|
|
+ tags=tags
|
|
|
+ )
|
|
|
).result()
|
|
|
|
|
|
self.update_snapshot_tags(snapshot.id, tags)
|
|
|
@@ -554,7 +571,7 @@ class AzureClient(object):
|
|
|
return self.compute_client.snapshots.begin_update(
|
|
|
self.resource_group,
|
|
|
snapshot_name,
|
|
|
- {'tags': tags} # type: ignore
|
|
|
+ SnapshotUpdate(tags=tags)
|
|
|
).wait()
|
|
|
|
|
|
def is_gallery_image(self, image_id):
|
|
|
@@ -565,7 +582,8 @@ class AzureClient(object):
|
|
|
|
|
|
def create_image(self, name, params):
|
|
|
return self.compute_client.images. \
|
|
|
- begin_create_or_update(self.resource_group, name, params).result()
|
|
|
+ begin_create_or_update(
|
|
|
+ self.resource_group, name, Image(**params)).result()
|
|
|
|
|
|
def delete_image(self, image_id):
|
|
|
url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
|
|
|
@@ -601,12 +619,9 @@ class AzureClient(object):
|
|
|
return True
|
|
|
else:
|
|
|
name = url_params.get(IMAGE_NAME, "")
|
|
|
- return self.compute_client.images. \
|
|
|
- begin_create_or_update(self.resource_group, name,
|
|
|
- {
|
|
|
- 'tags': tags,
|
|
|
- 'location': self.region_name
|
|
|
- }).result()
|
|
|
+ return self.compute_client.images.begin_update(
|
|
|
+ self.resource_group, name,
|
|
|
+ ImageUpdate(tags=tags)).result()
|
|
|
|
|
|
def list_vm_types(self):
|
|
|
return self.compute_client.virtual_machine_sizes. \
|
|
|
@@ -625,7 +640,9 @@ class AzureClient(object):
|
|
|
|
|
|
def create_network(self, name, params):
|
|
|
return self.network_management_client.virtual_networks. \
|
|
|
- begin_create_or_update(self.networking_resource_group, name, parameters=params).result()
|
|
|
+ begin_create_or_update(
|
|
|
+ self.networking_resource_group, name,
|
|
|
+ parameters=VirtualNetwork(**params)).result()
|
|
|
|
|
|
def delete_network(self, network_id):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
|
|
|
@@ -637,7 +654,8 @@ class AzureClient(object):
|
|
|
url_params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
|
|
|
network_name = url_params.get(NETWORK_NAME, "")
|
|
|
return self.network_management_client.virtual_networks. \
|
|
|
- begin_create_or_update(self.networking_resource_group, network_name, tags).result()
|
|
|
+ update_tags(self.networking_resource_group, network_name,
|
|
|
+ TagsObject(tags=tags))
|
|
|
|
|
|
def get_network_id_for_subnet(self, subnet_id):
|
|
|
url_params = azure_helpers.parse_url(SUBNET_RESOURCE_ID, subnet_id)
|
|
|
@@ -668,7 +686,7 @@ class AzureClient(object):
|
|
|
self.networking_resource_group,
|
|
|
network_name,
|
|
|
subnet_name,
|
|
|
- params
|
|
|
+ Subnet(**params)
|
|
|
)
|
|
|
subnet_info = result_create.result()
|
|
|
|
|
|
@@ -705,8 +723,10 @@ class AzureClient(object):
|
|
|
|
|
|
def create_floating_ip(self, public_ip_name, public_ip_parameters):
|
|
|
return self.network_management_client.public_ip_addresses. \
|
|
|
- begin_create_or_update(self.networking_resource_group,
|
|
|
- public_ip_name, public_ip_parameters).result()
|
|
|
+ begin_create_or_update(
|
|
|
+ self.networking_resource_group,
|
|
|
+ public_ip_name,
|
|
|
+ PublicIPAddress(**public_ip_parameters)).result()
|
|
|
|
|
|
def get_floating_ip(self, public_ip_id):
|
|
|
url_params = azure_helpers.parse_url(PUBLIC_IP_RESOURCE_ID,
|
|
|
@@ -728,7 +748,8 @@ class AzureClient(object):
|
|
|
fip_id)
|
|
|
fip_name = url_params.get(PUBLIC_IP_NAME, "")
|
|
|
self.network_management_client.public_ip_addresses. \
|
|
|
- begin_create_or_update(self.networking_resource_group, fip_name, tags).result()
|
|
|
+ update_tags(self.networking_resource_group, fip_name,
|
|
|
+ TagsObject(tags=tags))
|
|
|
|
|
|
def list_floating_ips(self):
|
|
|
return self.network_management_client.public_ip_addresses.list(
|
|
|
@@ -772,14 +793,18 @@ class AzureClient(object):
|
|
|
|
|
|
def create_vm(self, vm_name, params):
|
|
|
return self.compute_client.virtual_machines. \
|
|
|
- begin_create_or_update(self.resource_group, vm_name, params).result()
|
|
|
+ begin_create_or_update(
|
|
|
+ self.resource_group, vm_name,
|
|
|
+ VirtualMachine(**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, "")
|
|
|
return self.compute_client.virtual_machines. \
|
|
|
- begin_create_or_update(self.resource_group, vm_name, params).wait()
|
|
|
+ begin_create_or_update(
|
|
|
+ self.resource_group, vm_name,
|
|
|
+ VirtualMachine(**params)).wait()
|
|
|
|
|
|
def deallocate_vm(self, vm_id):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
@@ -806,8 +831,9 @@ class AzureClient(object):
|
|
|
url_params = azure_helpers.parse_url(VM_RESOURCE_ID,
|
|
|
vm_id)
|
|
|
vm_name = url_params.get(VM_NAME, "")
|
|
|
- self.compute_client.virtual_machines. \
|
|
|
- begin_create_or_update(self.resource_group, vm_name, tags).result()
|
|
|
+ self.compute_client.virtual_machines.begin_update(
|
|
|
+ self.resource_group, vm_name,
|
|
|
+ VirtualMachineUpdate(tags=tags)).result()
|
|
|
|
|
|
def delete_nic(self, nic_id):
|
|
|
nic_params = azure_helpers.\
|
|
|
@@ -827,11 +853,15 @@ class AzureClient(object):
|
|
|
nic_params = azure_helpers.\
|
|
|
parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
|
|
|
nic_name = nic_params.get(NETWORK_INTERFACE_NAME, "")
|
|
|
+ # update_nic is called with the existing NIC model (from get_nic());
|
|
|
+ # create_nic is called with a raw dict from services.py. Accept both.
|
|
|
+ nic = (params if isinstance(params, NetworkInterface)
|
|
|
+ else NetworkInterface(**params))
|
|
|
async_nic_creation = self.network_management_client. \
|
|
|
network_interfaces.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
nic_name,
|
|
|
- params
|
|
|
+ nic
|
|
|
)
|
|
|
nic_info = async_nic_creation.result()
|
|
|
return nic_info
|
|
|
@@ -841,31 +871,33 @@ class AzureClient(object):
|
|
|
network_interfaces.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
nic_name,
|
|
|
- params
|
|
|
+ NetworkInterface(**params)
|
|
|
).result()
|
|
|
|
|
|
def create_public_key(self, entity):
|
|
|
- return self.table_service. \
|
|
|
- insert_or_replace_entity(self.public_key_storage_table_name,
|
|
|
- entity)
|
|
|
+ return self.table_service.upsert_entity(entity)
|
|
|
|
|
|
def get_public_key(self, name):
|
|
|
- entities = self.table_service. \
|
|
|
- query_entities(self.public_key_storage_table_name,
|
|
|
- "Name eq '{0}'".format(name), num_results=1)
|
|
|
-
|
|
|
- return entities.items[0] if len(entities.items) > 0 else None
|
|
|
+ entities = list(self.table_service.query_entities(
|
|
|
+ query_filter="Name eq '{0}'".format(name),
|
|
|
+ results_per_page=1))
|
|
|
+ return entities[0] if entities else None
|
|
|
|
|
|
def delete_public_key(self, entity):
|
|
|
- self.table_service.delete_entity(self.public_key_storage_table_name,
|
|
|
- entity.PartitionKey, entity.RowKey)
|
|
|
+ self.table_service.delete_entity(
|
|
|
+ partition_key=entity['PartitionKey'],
|
|
|
+ row_key=entity['RowKey'])
|
|
|
|
|
|
def list_public_keys(self, partition_key, limit=None, marker=None):
|
|
|
- entities = self.table_service. \
|
|
|
- query_entities(self.public_key_storage_table_name,
|
|
|
- "PartitionKey eq '{0}'".format(partition_key),
|
|
|
- marker=marker, num_results=limit)
|
|
|
- return (entities.items, entities.next_marker)
|
|
|
+ pager = self.table_service.query_entities(
|
|
|
+ query_filter="PartitionKey eq '{0}'".format(partition_key),
|
|
|
+ results_per_page=limit).by_page(continuation_token=marker)
|
|
|
+ try:
|
|
|
+ page = next(pager)
|
|
|
+ except StopIteration:
|
|
|
+ return ([], None)
|
|
|
+ items = list(page)
|
|
|
+ return (items, pager.continuation_token)
|
|
|
|
|
|
def delete_route_table(self, route_table_name):
|
|
|
self.network_management_client. \
|
|
|
@@ -884,9 +916,7 @@ class AzureClient(object):
|
|
|
subnet_name
|
|
|
)
|
|
|
if subnet_info:
|
|
|
- subnet_info.route_table = {
|
|
|
- 'id': route_table_id
|
|
|
- }
|
|
|
+ subnet_info.route_table = SubResource(id=route_table_id)
|
|
|
|
|
|
result_create = self.network_management_client. \
|
|
|
subnets.begin_create_or_update(
|
|
|
@@ -938,8 +968,9 @@ class AzureClient(object):
|
|
|
return self.network_management_client. \
|
|
|
route_tables.begin_create_or_update(
|
|
|
self.resource_group,
|
|
|
- route_table_name, params).result()
|
|
|
+ route_table_name, RouteTable(**params)).result()
|
|
|
|
|
|
def update_route_table_tags(self, route_table_name, tags):
|
|
|
- self.network_management_client.route_tables. \
|
|
|
- begin_create_or_update(self.resource_group, route_table_name, tags).result()
|
|
|
+ self.network_management_client.route_tables.update_tags(
|
|
|
+ self.resource_group, route_table_name,
|
|
|
+ TagsObject(tags=tags))
|