summaryrefslogtreecommitdiff
path: root/tests/cloud_tests/platforms/azurecloud
diff options
context:
space:
mode:
Diffstat (limited to 'tests/cloud_tests/platforms/azurecloud')
-rw-r--r--tests/cloud_tests/platforms/azurecloud/__init__.py0
-rw-r--r--tests/cloud_tests/platforms/azurecloud/image.py116
-rw-r--r--tests/cloud_tests/platforms/azurecloud/instance.py247
-rw-r--r--tests/cloud_tests/platforms/azurecloud/platform.py240
-rw-r--r--tests/cloud_tests/platforms/azurecloud/regions.json42
-rw-r--r--tests/cloud_tests/platforms/azurecloud/snapshot.py58
6 files changed, 0 insertions, 703 deletions
diff --git a/tests/cloud_tests/platforms/azurecloud/__init__.py b/tests/cloud_tests/platforms/azurecloud/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/tests/cloud_tests/platforms/azurecloud/__init__.py
+++ /dev/null
diff --git a/tests/cloud_tests/platforms/azurecloud/image.py b/tests/cloud_tests/platforms/azurecloud/image.py
deleted file mode 100644
index aad2bca1..00000000
--- a/tests/cloud_tests/platforms/azurecloud/image.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Azure Cloud image Base class."""
-
-from tests.cloud_tests import LOG
-
-from ..images import Image
-from .snapshot import AzureCloudSnapshot
-
-
-class AzureCloudImage(Image):
- """Azure Cloud backed image."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, platform, config, image_id):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- @param image_id: image id used to boot instance
- """
- super(AzureCloudImage, self).__init__(platform, config)
- self._img_instance = None
- self.image_id = image_id
-
- @property
- def _instance(self):
- """Internal use only, returns a running instance"""
- if not self._img_instance:
- self._img_instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self.image_id, user_data=None)
- self._img_instance.start(wait=True, wait_for_cloud_init=True)
- return self._img_instance
-
- def destroy(self):
- """Delete the instance used to create a custom image."""
- if self._img_instance:
- LOG.debug('Deleting backing instance %s',
- self._img_instance.vm_name)
- delete_vm = self.platform.compute_client.virtual_machines.delete(
- self.platform.resource_group.name, self._img_instance.vm_name)
- delete_vm.wait()
-
- super(AzureCloudImage, self).destroy()
-
- def _execute(self, *args, **kwargs):
- """Execute command in image, modifying image."""
- LOG.debug('executing commands on image')
- self._instance.start(wait=True)
- return self._instance._execute(*args, **kwargs)
-
- def push_file(self, local_path, remote_path):
- """Copy file at 'local_path' to instance at 'remote_path'."""
- LOG.debug('pushing file to image')
- return self._instance.push_file(local_path, remote_path)
-
- def run_script(self, *args, **kwargs):
- """Run script in image, modifying image.
-
- @return_value: script output
- """
- LOG.debug('running script on image')
- self._instance.start()
- return self._instance.run_script(*args, **kwargs)
-
- def snapshot(self):
- """ Create snapshot (image) of instance, wait until done.
-
- If no instance has been booted, base image is returned.
- Otherwise runs the clean script, deallocates, generalizes
- and creates custom image from instance.
- """
- LOG.debug('creating snapshot of image')
- if not self._img_instance:
- LOG.debug('No existing image, snapshotting base image')
- return AzureCloudSnapshot(self.platform, self.properties,
- self.config, self.features,
- self._instance.vm_name,
- delete_on_destroy=False)
-
- LOG.debug('creating snapshot from instance: %s', self._img_instance)
- if self.config.get('boot_clean_script'):
- self._img_instance.run_script(self.config.get('boot_clean_script'))
-
- LOG.debug('deallocating instance %s', self._instance.vm_name)
- deallocate = self.platform.compute_client.virtual_machines.deallocate(
- self.platform.resource_group.name, self._instance.vm_name)
- deallocate.wait()
-
- LOG.debug('generalizing instance %s', self._instance.vm_name)
- self.platform.compute_client.virtual_machines.generalize(
- self.platform.resource_group.name, self._instance.vm_name)
-
- image_params = {
- "location": self.platform.location,
- "properties": {
- "sourceVirtualMachine": {
- "id": self._img_instance.instance.id
- }
- }
- }
- LOG.debug('updating resource group image %s', self._instance.vm_name)
- self.platform.compute_client.images.create_or_update(
- self.platform.resource_group.name, self._instance.vm_name,
- image_params)
-
- LOG.debug('destroying self')
- self.destroy()
-
- LOG.debug('snapshot complete')
- return AzureCloudSnapshot(self.platform, self.properties, self.config,
- self.features, self._instance.vm_name)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/azurecloud/instance.py b/tests/cloud_tests/platforms/azurecloud/instance.py
deleted file mode 100644
index eedbaae8..00000000
--- a/tests/cloud_tests/platforms/azurecloud/instance.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base Azure Cloud instance."""
-
-from datetime import datetime, timedelta
-from urllib.parse import urlparse
-from time import sleep
-import traceback
-import os
-
-
-# pylint: disable=no-name-in-module
-from azure.storage.blob import BlockBlobService, BlobPermissions
-from msrestazure.azure_exceptions import CloudError
-
-from tests.cloud_tests import LOG
-
-from ..instances import Instance
-
-
-class AzureCloudInstance(Instance):
- """Azure Cloud backed instance."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, platform, properties, config,
- features, image_id, user_data=None):
- """Set up instance.
-
- @param platform: platform object
- @param properties: dictionary of properties
- @param config: dictionary of configuration values
- @param features: dictionary of supported feature flags
- @param image_id: image to find and/or use
- @param user_data: test user-data to pass to instance
- """
- super(AzureCloudInstance, self).__init__(
- platform, image_id, properties, config, features)
-
- self.ssh_port = 22
- self.ssh_ip = None
- self.instance = None
- self.image_id = image_id
- self.vm_name = 'ci-azure-i-%s' % self.platform.tag
- self.user_data = user_data
- self.ssh_key_file = os.path.join(
- platform.config['data_dir'], platform.config['private_key'])
- self.ssh_pubkey_file = os.path.join(
- platform.config['data_dir'], platform.config['public_key'])
- self.blob_client, self.container, self.blob = None, None, None
-
- def start(self, wait=True, wait_for_cloud_init=False):
- """Start instance with the platforms NIC."""
- if self.instance:
- return
- data = self.image_id.split('-')
- release, support = data[2].replace('_', '.'), data[3]
- sku = '%s-%s' % (release, support) if support == 'LTS' else release
- image_resource_id = '/subscriptions/%s' \
- '/resourceGroups/%s' \
- '/providers/Microsoft.Compute/images/%s' % (
- self.platform.subscription_id,
- self.platform.resource_group.name,
- self.image_id)
- storage_uri = "http://%s.blob.core.windows.net" \
- % self.platform.storage.name
- with open(self.ssh_pubkey_file, 'r') as key:
- ssh_pub_keydata = key.read()
-
- image_exists = False
- try:
- LOG.debug('finding image in resource group using image_id')
- self.platform.compute_client.images.get(
- self.platform.resource_group.name,
- self.image_id
- )
- image_exists = True
- LOG.debug('image found, launching instance, image_id=%s',
- self.image_id)
- except CloudError:
- LOG.debug(('image not found, launching instance with base image, '
- 'image_id=%s'), self.image_id)
-
- vm_params = {
- 'name': self.vm_name,
- 'location': self.platform.location,
- 'os_profile': {
- 'computer_name': 'CI-%s' % self.platform.tag,
- 'admin_username': self.ssh_username,
- "customData": self.user_data,
- "linuxConfiguration": {
- "disable_password_authentication": True,
- "ssh": {
- "public_keys": [{
- "path": "/home/%s/.ssh/authorized_keys" %
- self.ssh_username,
- "keyData": ssh_pub_keydata
- }]
- }
- }
- },
- "diagnosticsProfile": {
- "bootDiagnostics": {
- "storageUri": storage_uri,
- "enabled": True
- }
- },
- 'hardware_profile': {
- 'vm_size': self.platform.vm_size
- },
- 'storage_profile': {
- 'image_reference': {
- 'id': image_resource_id
- } if image_exists else {
- 'publisher': 'Canonical',
- 'offer': 'UbuntuServer',
- 'sku': sku,
- 'version': 'latest'
- }
- },
- 'network_profile': {
- 'network_interfaces': [{
- 'id': self.platform.nic.id
- }]
- },
- 'tags': {
- 'Name': self.platform.tag,
- }
- }
-
- try:
- self.instance = self.platform.compute_client.virtual_machines.\
- create_or_update(self.platform.resource_group.name,
- self.vm_name, vm_params)
- LOG.debug('creating instance %s from image_id=%s', self.vm_name,
- self.image_id)
- except CloudError as e:
- raise RuntimeError(
- 'failed creating instance:\n{}'.format(traceback.format_exc())
- ) from e
-
- if wait:
- self.instance.wait()
- self.ssh_ip = self.platform.network_client.\
- public_ip_addresses.get(
- self.platform.resource_group.name,
- self.platform.public_ip.name
- ).ip_address
- self._wait_for_system(wait_for_cloud_init)
-
- self.instance = self.instance.result()
- self.blob_client, self.container, self.blob =\
- self._get_blob_client()
-
- def shutdown(self, wait=True):
- """Finds console log then stopping/deallocates VM"""
- LOG.debug('waiting on console log before stopping')
- attempts, exists = 5, False
- while not exists and attempts:
- try:
- attempts -= 1
- exists = self.blob_client.get_blob_to_bytes(
- self.container, self.blob)
- LOG.debug('found console log')
- except Exception as e:
- if attempts:
- LOG.debug('Unable to find console log, '
- '%s attempts remaining', attempts)
- sleep(15)
- else:
- LOG.warning('Could not find console log: %s', e)
-
- LOG.debug('stopping instance %s', self.image_id)
- vm_deallocate = \
- self.platform.compute_client.virtual_machines.deallocate(
- self.platform.resource_group.name, self.image_id)
- if wait:
- vm_deallocate.wait()
-
- def destroy(self):
- """Delete VM and close all connections"""
- if self.instance:
- LOG.debug('destroying instance: %s', self.image_id)
- vm_delete = self.platform.compute_client.virtual_machines.delete(
- self.platform.resource_group.name, self.image_id)
- vm_delete.wait()
-
- self._ssh_close()
-
- super(AzureCloudInstance, self).destroy()
-
- def _execute(self, command, stdin=None, env=None):
- """Execute command on instance."""
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- return self._ssh(['sudo'] + env_args + list(command), stdin=stdin)
-
- def _get_blob_client(self):
- """
- Use VM details to retrieve container and blob name.
- Then Create blob service client for sas token to
- retrieve console log.
-
- :return: blob service, container name, blob name
- """
- LOG.debug('creating blob service for console log')
- storage = self.platform.storage_client.storage_accounts.get_properties(
- self.platform.resource_group.name, self.platform.storage.name)
-
- keys = self.platform.storage_client.storage_accounts.list_keys(
- self.platform.resource_group.name, self.platform.storage.name
- ).keys[0].value
-
- virtual_machine = self.platform.compute_client.virtual_machines.get(
- self.platform.resource_group.name, self.instance.name,
- expand='instanceView')
-
- blob_uri = virtual_machine.instance_view.boot_diagnostics.\
- serial_console_log_blob_uri
-
- container, blob = urlparse(blob_uri).path.split('/')[-2:]
-
- blob_client = BlockBlobService(
- account_name=storage.name,
- account_key=keys)
-
- sas = blob_client.generate_blob_shared_access_signature(
- container_name=container, blob_name=blob, protocol='https',
- expiry=datetime.utcnow() + timedelta(hours=1),
- permission=BlobPermissions.READ)
-
- blob_client = BlockBlobService(
- account_name=storage.name,
- sas_token=sas)
-
- return blob_client, container, blob
-
- def console_log(self):
- """Instance console.
-
- @return_value: bytes of this instance’s console
- """
- boot_diagnostics = self.blob_client.get_blob_to_bytes(
- self.container, self.blob)
- return boot_diagnostics.content
diff --git a/tests/cloud_tests/platforms/azurecloud/platform.py b/tests/cloud_tests/platforms/azurecloud/platform.py
deleted file mode 100644
index a664f612..00000000
--- a/tests/cloud_tests/platforms/azurecloud/platform.py
+++ /dev/null
@@ -1,240 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base Azure Cloud class."""
-
-import os
-import base64
-import traceback
-from datetime import datetime
-from tests.cloud_tests import LOG
-
-# pylint: disable=no-name-in-module
-from azure.common.credentials import ServicePrincipalCredentials
-# pylint: disable=no-name-in-module
-from azure.mgmt.resource import ResourceManagementClient
-# pylint: disable=no-name-in-module
-from azure.mgmt.network import NetworkManagementClient
-# pylint: disable=no-name-in-module
-from azure.mgmt.compute import ComputeManagementClient
-# pylint: disable=no-name-in-module
-from azure.mgmt.storage import StorageManagementClient
-from msrestazure.azure_exceptions import CloudError
-
-from .image import AzureCloudImage
-from .instance import AzureCloudInstance
-from ..platforms import Platform
-
-from cloudinit import util as c_util
-
-
-class AzureCloudPlatform(Platform):
- """Azure Cloud test platforms."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, config):
- """Set up platform."""
- super(AzureCloudPlatform, self).__init__(config)
- self.tag = '%s-%s' % (
- config['tag'], datetime.now().strftime('%Y%m%d%H%M%S'))
- self.storage_sku = config['storage_sku']
- self.vm_size = config['vm_size']
- self.location = config['region']
-
- try:
- self.credentials, self.subscription_id = self._get_credentials()
-
- self.resource_client = ResourceManagementClient(
- self.credentials, self.subscription_id)
- self.compute_client = ComputeManagementClient(
- self.credentials, self.subscription_id)
- self.network_client = NetworkManagementClient(
- self.credentials, self.subscription_id)
- self.storage_client = StorageManagementClient(
- self.credentials, self.subscription_id)
-
- self.resource_group = self._create_resource_group()
- self.public_ip = self._create_public_ip_address()
- self.storage = self._create_storage_account(config)
- self.vnet = self._create_vnet()
- self.subnet = self._create_subnet()
- self.nic = self._create_nic()
- except CloudError as e:
- raise RuntimeError(
- 'failed creating a resource:\n{}'.format(
- traceback.format_exc()
- )
- ) from e
-
- def create_instance(self, properties, config, features,
- image_id, user_data=None):
- """Create an instance
-
- @param properties: image properties
- @param config: image configuration
- @param features: image features
- @param image_id: string of image id
- @param user_data: test user-data to pass to instance
- @return_value: cloud_tests.instances instance
- """
- if user_data is not None:
- user_data = str(base64.b64encode(
- user_data.encode('utf-8')), 'utf-8')
-
- return AzureCloudInstance(self, properties, config, features,
- image_id, user_data)
-
- def get_image(self, img_conf):
- """Get image using specified image configuration.
-
- @param img_conf: configuration for image
- @return_value: cloud_tests.images instance
- """
- ss_region = self.azure_location_to_simplestreams_region()
-
- filters = [
- 'arch=%s' % 'amd64',
- 'endpoint=https://management.core.windows.net/',
- 'region=%s' % ss_region,
- 'release=%s' % img_conf['release']
- ]
-
- LOG.debug('finding image using streams')
- image = self._query_streams(img_conf, filters)
-
- try:
- image_id = image['id']
- LOG.debug('found image: %s', image_id)
- if image_id.find('__') > 0:
- image_id = image_id.split('__')[1]
- LOG.debug('image_id shortened to %s', image_id)
- except KeyError as e:
- raise RuntimeError(
- 'no images found for %s' % img_conf['release']
- ) from e
-
- return AzureCloudImage(self, img_conf, image_id)
-
- def destroy(self):
- """Delete all resources in resource group."""
- LOG.debug("Deleting resource group: %s", self.resource_group.name)
- delete = self.resource_client.resource_groups.delete(
- self.resource_group.name)
- delete.wait()
-
- def azure_location_to_simplestreams_region(self):
- """Convert location to simplestreams region"""
- location = self.location.lower().replace(' ', '')
- LOG.debug('finding location %s using simple streams', location)
- regions_file = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), 'regions.json')
- region_simplestreams_map = c_util.load_json(
- c_util.load_file(regions_file))
- return region_simplestreams_map.get(location, location)
-
- def _get_credentials(self):
- """Get credentials from environment"""
- LOG.debug('getting credentials from environment')
- cred_file = os.path.expanduser('~/.azure/credentials.json')
- try:
- azure_creds = c_util.load_json(
- c_util.load_file(cred_file))
- subscription_id = azure_creds['subscriptionId']
- credentials = ServicePrincipalCredentials(
- client_id=azure_creds['clientId'],
- secret=azure_creds['clientSecret'],
- tenant=azure_creds['tenantId'])
- return credentials, subscription_id
- except KeyError as e:
- raise RuntimeError(
- 'Please configure Azure service principal'
- ' credentials in %s' % cred_file
- ) from e
-
- def _create_resource_group(self):
- """Create resource group"""
- LOG.debug('creating resource group')
- resource_group_name = self.tag
- resource_group_params = {
- 'location': self.location
- }
- resource_group = self.resource_client.resource_groups.create_or_update(
- resource_group_name, resource_group_params)
- return resource_group
-
- def _create_storage_account(self, config):
- LOG.debug('creating storage account')
- storage_account_name = 'storage%s' % datetime.now().\
- strftime('%Y%m%d%H%M%S')
- storage_params = {
- 'sku': {
- 'name': config['storage_sku']
- },
- 'kind': "Storage",
- 'location': self.location
- }
- storage_account = self.storage_client.storage_accounts.create(
- self.resource_group.name, storage_account_name, storage_params)
- return storage_account.result()
-
- def _create_public_ip_address(self):
- """Create public ip address"""
- LOG.debug('creating public ip address')
- public_ip_name = '%s-ip' % self.resource_group.name
- public_ip_params = {
- 'location': self.location,
- 'public_ip_allocation_method': 'Dynamic'
- }
- ip = self.network_client.public_ip_addresses.create_or_update(
- self.resource_group.name, public_ip_name, public_ip_params)
- return ip.result()
-
- def _create_vnet(self):
- """create virtual network"""
- LOG.debug('creating vnet')
- vnet_name = '%s-vnet' % self.resource_group.name
- vnet_params = {
- 'location': self.location,
- 'address_space': {
- 'address_prefixes': ['10.0.0.0/16']
- }
- }
- vnet = self.network_client.virtual_networks.create_or_update(
- self.resource_group.name, vnet_name, vnet_params)
- return vnet.result()
-
- def _create_subnet(self):
- """create sub-network"""
- LOG.debug('creating subnet')
- subnet_name = '%s-subnet' % self.resource_group.name
- subnet_params = {
- 'address_prefix': '10.0.0.0/24'
- }
- subnet = self.network_client.subnets.create_or_update(
- self.resource_group.name, self.vnet.name,
- subnet_name, subnet_params)
- return subnet.result()
-
- def _create_nic(self):
- """Create network interface controller"""
- LOG.debug('creating nic')
- nic_name = '%s-nic' % self.resource_group.name
- nic_params = {
- 'location': self.location,
- 'ip_configurations': [{
- 'name': 'ipconfig',
- 'subnet': {
- 'id': self.subnet.id
- },
- 'publicIpAddress': {
- 'id': "/subscriptions/%s"
- "/resourceGroups/%s/providers/Microsoft.Network"
- "/publicIPAddresses/%s" % (
- self.subscription_id, self.resource_group.name,
- self.public_ip.name),
- }
- }]
- }
- nic = self.network_client.network_interfaces.create_or_update(
- self.resource_group.name, nic_name, nic_params)
- return nic.result()
diff --git a/tests/cloud_tests/platforms/azurecloud/regions.json b/tests/cloud_tests/platforms/azurecloud/regions.json
deleted file mode 100644
index c1b4da20..00000000
--- a/tests/cloud_tests/platforms/azurecloud/regions.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "eastasia": "East Asia",
- "southeastasia": "Southeast Asia",
- "centralus": "Central US",
- "eastus": "East US",
- "eastus2": "East US 2",
- "westus": "West US",
- "northcentralus": "North Central US",
- "southcentralus": "South Central US",
- "northeurope": "North Europe",
- "westeurope": "West Europe",
- "japanwest": "Japan West",
- "japaneast": "Japan East",
- "brazilsouth": "Brazil South",
- "australiaeast": "Australia East",
- "australiasoutheast": "Australia Southeast",
- "southindia": "South India",
- "centralindia": "Central India",
- "westindia": "West India",
- "canadacentral": "Canada Central",
- "canadaeast": "Canada East",
- "uksouth": "UK South",
- "ukwest": "UK West",
- "westcentralus": "West Central US",
- "westus2": "West US 2",
- "koreacentral": "Korea Central",
- "koreasouth": "Korea South",
- "francecentral": "France Central",
- "francesouth": "France South",
- "australiacentral": "Australia Central",
- "australiacentral2": "Australia Central 2",
- "uaecentral": "UAE Central",
- "uaenorth": "UAE North",
- "southafricanorth": "South Africa North",
- "southafricawest": "South Africa West",
- "switzerlandnorth": "Switzerland North",
- "switzerlandwest": "Switzerland West",
- "germanynorth": "Germany North",
- "germanywestcentral": "Germany West Central",
- "norwaywest": "Norway West",
- "norwayeast": "Norway East"
-}
diff --git a/tests/cloud_tests/platforms/azurecloud/snapshot.py b/tests/cloud_tests/platforms/azurecloud/snapshot.py
deleted file mode 100644
index 580cc596..00000000
--- a/tests/cloud_tests/platforms/azurecloud/snapshot.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base Azure Cloud snapshot."""
-
-from ..snapshots import Snapshot
-
-from tests.cloud_tests import LOG
-
-
-class AzureCloudSnapshot(Snapshot):
- """Azure Cloud image copy backed snapshot."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, platform, properties, config, features, image_id,
- delete_on_destroy=True):
- """Set up snapshot.
-
- @param platform: platform object
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- """
- super(AzureCloudSnapshot, self).__init__(
- platform, properties, config, features)
-
- self.image_id = image_id
- self.delete_on_destroy = delete_on_destroy
-
- def launch(self, user_data, meta_data=None, block=True, start=True,
- use_desc=None):
- """Launch instance.
-
- @param user_data: user-data for the instance
- @param meta_data: meta_data for the instance
- @param block: wait until instance is created
- @param start: start instance and wait until fully started
- @param use_desc: description of snapshot instance use
- @return_value: an Instance
- """
- if meta_data is not None:
- raise ValueError("metadata not supported on Azure Cloud tests")
-
- instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self.image_id, user_data)
-
- return instance
-
- def destroy(self):
- """Clean up snapshot data."""
- LOG.debug('destroying image %s', self.image_id)
- if self.delete_on_destroy:
- self.platform.compute_client.images.delete(
- self.platform.resource_group.name,
- self.image_id)
-
-# vi: ts=4 expandtab