From d407b5f482a464bb3e6fb6d11a2d7e87e6aae25a Mon Sep 17 00:00:00 2001 From: Pratik Shah Date: Tue, 3 Oct 2017 15:19:56 +0530 Subject: [PATCH] [AZURE] Added a fix to create resource group in Azure if not present Change-Id: I8ad06bd32d381573f794c37a577bb6ff2e056efb Closes-Bug: #1720982 --- glance/glance_store/_drivers/azure/store.py | 13 +++++++++ glance/glance_store/_drivers/azure/utils.py | 27 +++++++++++++++++++ .../tests/unit/azure/test_azure.py | 22 +++++++++------ neutron/neutron/common/azure/utils.py | 27 +++++++++++++++++++ .../plugins/ml2/drivers/azure/mech_azure.py | 17 ++++++++---- .../services/l3_router/azure_router_plugin.py | 11 ++++++++ nova/virt/azure/driver.py | 6 +++++ nova/virt/azure/utils.py | 25 +++++++++++++++++ 8 files changed, 135 insertions(+), 13 deletions(-) diff --git a/glance/glance_store/_drivers/azure/store.py b/glance/glance_store/_drivers/azure/store.py index cb681d6..6569df1 100644 --- a/glance/glance_store/_drivers/azure/store.py +++ b/glance/glance_store/_drivers/azure/store.py @@ -99,7 +99,9 @@ class Store(driver.Store): self.client_secret = conf.azure.client_secret self.subscription_id = conf.azure.subscription_id self.resource_group = conf.azure.resource_group + self.region = conf.azure.region self._azure_client = None + LOG.info('Initialized Azure Glance Store driver') def get_schemes(self): @@ -111,8 +113,19 @@ class Store(driver.Store): self._azure_client = utils.get_compute_client( self.tenant_id, self.client_id, self.client_secret, self.subscription_id) + self._create_resource_group_if_not_created() return self._azure_client + def _create_resource_group_if_not_created(self): + resource_client = utils.get_resource_client( + self.tenant_id, self.client_id, self.client_secret, + self.subscription_id) + is_resource_created = utils.check_resource_existence( + resource_client, self.resource_group) + if not is_resource_created: + utils.create_resource_group( + resource_client, self.resource_group, self.region) + @capabilities.check def get(self, location, offset=0, chunk_size=None, context=None): """Takes a `glance_store.location.Location` object that indicates diff --git a/glance/glance_store/_drivers/azure/utils.py b/glance/glance_store/_drivers/azure/utils.py index 44a5a20..0128d9a 100644 --- a/glance/glance_store/_drivers/azure/utils.py +++ b/glance/glance_store/_drivers/azure/utils.py @@ -13,6 +13,7 @@ under the License. from azure.common.credentials import ServicePrincipalCredentials from azure.mgmt.compute import ComputeManagementClient +from azure.mgmt.resource import ResourceManagementClient from functools import partial from oslo_log import log as logging @@ -41,9 +42,35 @@ def _get_client(tenant_id, client_id, client_secret, subscription_id, get_compute_client = partial(_get_client, cls=ComputeManagementClient) +get_resource_client = partial(_get_client, cls=ResourceManagementClient) def get_image(compute, resource_group, name): """Return image info from Azure """ return compute.images.get(resource_group, name) + + +def check_resource_existence(client, resource_group): + """Create if resource group exists in Azure or not + + :param client: Azure object using ResourceManagementClient + :param resource_group: string, name of Azure resource group + :return: True if exists, otherwise False + :rtype: boolean + """ + response = client.resource_groups.check_existence(resource_group) + return response + + +def create_resource_group(client, resource_group, region): + """Create resource group in Azure + + :param client: Azure object using ResourceManagementClient + :param resource_group: string, name of Azure resource group + :param region: string, name of Azure region + """ + response = client.resource_groups.create_or_update( + resource_group, {'location': region}) + LOG.debug("resource_group response: {0}".format(response)) + LOG.debug("Created Resource Group '{0}' in Azure".format(resource_group)) diff --git a/glance/glance_store/tests/unit/azure/test_azure.py b/glance/glance_store/tests/unit/azure/test_azure.py index daf6ea2..9cf369c 100644 --- a/glance/glance_store/tests/unit/azure/test_azure.py +++ b/glance/glance_store/tests/unit/azure/test_azure.py @@ -12,9 +12,9 @@ under the License. """ import mock -import os -from azure.mgmt.compute import models +from azure.mgmt.compute import models as compute_models +from azure.mgmt.resource.resources import models as resource_models from devtools_testutils.mgmt_testcase import fake_settings from glance_store._drivers.azure.store import Store from glance_store._drivers.azure.store import StoreLocation @@ -24,20 +24,23 @@ from glance_store.location import Location from glance_store.tests import base from oslo_config import cfg -DATA_DIR = os.path.dirname(os.path.abspath(__file__)) + '/data' - RESOURCE_GROUP = 'omni_test_group' CLIENT_SECRET = 'fake_key' +def get_fake_resource_group(client, resource_group): + resource_group = resource_models.Resource(location='eastus') + return resource_group + + def fake_get_credentials(tenant_id, client_id, client_secret): return fake_settings.get_credentials() def fake_get_image(compute, resource_group, name): - storage_profile = models.ImageStorageProfile( - models.ImageOSDisk('Linux', 'Generalized')) - _image = models.Image(location='eastus') + storage_profile = compute_models.ImageStorageProfile( + compute_models.ImageOSDisk('Linux', 'Generalized')) + _image = compute_models.Image(location='eastus') _image.storage_profile = storage_profile return _image @@ -59,7 +62,10 @@ class AzureGlanceTestCase(base.StoreBaseTest): self.scheme = "azure" @mock.patch('glance_store._drivers.azure.utils.get_image') - def test_get_size(self, mock_get): + @mock.patch( + "glance_store._drivers.azure.utils.check_resource_existence") + def test_get_size(self, mock_check, mock_get): + mock_check.side_effect = get_fake_resource_group mock_get.side_effect = fake_get_image store_specs = {} attrs_values = [ diff --git a/neutron/neutron/common/azure/utils.py b/neutron/neutron/common/azure/utils.py index 89234a5..2f28f52 100644 --- a/neutron/neutron/common/azure/utils.py +++ b/neutron/neutron/common/azure/utils.py @@ -16,6 +16,7 @@ import uuid from azure.common.credentials import ServicePrincipalCredentials from azure.mgmt.compute import ComputeManagementClient from azure.mgmt.network import NetworkManagementClient +from azure.mgmt.resource import ResourceManagementClient from msrestazure.azure_exceptions import CloudError from oslo_log import log as logging @@ -29,6 +30,31 @@ class FloatingIPNotFound(n_exceptions.NotFound): message = "Floating IP %(ip)s could not be found." +def check_resource_existence(client, resource_group): + """Create if resource group exists in Azure or not + + :param client: Azure object using ResourceManagementClient + :param resource_group: string, name of Azure resource group + :return: True if exists, otherwise False + :rtype: boolean + """ + response = client.resource_groups.check_existence(resource_group) + return response + + +def create_resource_group(client, resource_group, region): + """Create resource group in Azure + + :param client: Azure object using ResourceManagementClient + :param resource_group: string, name of Azure resource group + :param region: string, name of Azure region + """ + response = client.resource_groups.create_or_update( + resource_group, {'location': region}) + LOG.debug("resource_group response: {0}".format(response)) + LOG.debug("Created Resource Group '{0}' in Azure".format(resource_group)) + + def azure_handle_exception(fn): def wrapper(*args, **kwargs): try: @@ -63,6 +89,7 @@ def _get_client(tenant_id, client_id, client_secret, subscription_id, get_compute_client = partial(_get_client, cls=ComputeManagementClient) get_network_client = partial(_get_client, cls=NetworkManagementClient) +get_resource_client = partial(_get_client, cls=ResourceManagementClient) def _perform_and_wait(operation, args=(), kwargs={}, timeout=300): diff --git a/neutron/neutron/plugins/ml2/drivers/azure/mech_azure.py b/neutron/neutron/plugins/ml2/drivers/azure/mech_azure.py index dae0b58..8944da0 100644 --- a/neutron/neutron/plugins/ml2/drivers/azure/mech_azure.py +++ b/neutron/neutron/plugins/ml2/drivers/azure/mech_azure.py @@ -88,8 +88,16 @@ class AzureMechanismDriver(api.MechanismDriver): args = (conf.tenant_id, conf.client_id, conf.client_secret, conf.subscription_id) self._network_client = utils.get_network_client(*args) + self._create_resource_group_if_not_created(conf) return self._network_client + def _create_resource_group_if_not_created(self, conf): + is_resource_created = utils.check_resource_existence( + self.resource_client, conf.resource_group) + if not is_resource_created: + utils.create_resource_group( + self.resource_client, conf.resource_group, conf.region) + def _azure_network_name(self, context): return 'net-' + context.current[api.ID] @@ -283,11 +291,10 @@ class AzureMechanismDriver(api.MechanismDriver): sg_name = self._azure_secgrp_id(rule['security_group_id']) name = self._azure_secrule_id(rule['id']) sg = utils.get_sg(net_svc, resource_group, sg_name) - """Each Azure security rule has a priority. - The value can be between 100 and 4096. The priority number must be - unique for each rule in the collection. The lower the priority number, - the higher the priority of the rule. - """ + # Each Azure security rule has a priority. + # The value can be between 100 and 4096. The priority number must be + # unique for each rule in the collection. The lower the priority + # number, the higher the priority of the rule. previous_priorities = sorted([i.priority for i in sg.security_rules]) if previous_priorities: priority = previous_priorities[-1] + 1 diff --git a/neutron/neutron/services/l3_router/azure_router_plugin.py b/neutron/neutron/services/l3_router/azure_router_plugin.py index b45a35a..1e41d39 100644 --- a/neutron/neutron/services/l3_router/azure_router_plugin.py +++ b/neutron/neutron/services/l3_router/azure_router_plugin.py @@ -85,6 +85,7 @@ class AzureRouterPlugin( args = (self.tenant_id, self.client_id, self.client_secret, self.subscription_id) self._compute_client = utils.get_compute_client(*args) + self._create_resource_group_if_not_created() return self._compute_client @property @@ -95,6 +96,16 @@ class AzureRouterPlugin( self._network_client = utils.get_network_client(*args) return self._network_client + def _create_resource_group_if_not_created(self): + resource_client = utils.get_resource_client( + self.tenant_id, self.client_id, self.client_secret, + self.subscription_id) + is_resource_created = utils.check_resource_existence( + resource_client, self.resource_group) + if not is_resource_created: + utils.create_resource_group( + resource_client, self.resource_group, self.region) + def get_plugin_type(self): return plugin_type diff --git a/nova/virt/azure/driver.py b/nova/virt/azure/driver.py index f54400d..8c6baa3 100644 --- a/nova/virt/azure/driver.py +++ b/nova/virt/azure/driver.py @@ -67,6 +67,12 @@ class AzureDriver(driver.ComputeDriver): self.compute_client = utils.get_compute_client(*args) self.resource_client = utils.get_resource_client(*args) self.network_client = utils.get_network_client(*args) + is_resource_created = utils.check_resource_existence( + self.resource_client, drv_conf.resource_group) + if not is_resource_created: + utils.create_resource_group( + self.resource_client, drv_conf.resource_group, drv_conf.region) + self.flavor_info.update( utils.get_vm_sizes(self.compute_client, drv_conf.region)) LOG.info("%s driver init with %s project, %s region" % diff --git a/nova/virt/azure/utils.py b/nova/virt/azure/utils.py index cfdc1f2..4f7ade9 100644 --- a/nova/virt/azure/utils.py +++ b/nova/virt/azure/utils.py @@ -51,6 +51,31 @@ get_resource_client = partial(_get_client, cls=ResourceManagementClient) get_network_client = partial(_get_client, cls=NetworkManagementClient) +def check_resource_existence(client, resource_group): + """Create if resource group exists in Azure or not + + :param client: Azure object using ResourceManagementClient + :param resource_group: string, name of Azure resource group + :return: True if exists, otherwise False + :rtype: boolean + """ + response = client.resource_groups.check_existence(resource_group) + return response + + +def create_resource_group(client, resource_group, region): + """Create resource group in Azure + + :param client: Azure object using ResourceManagementClient + :param resource_group: string, name of Azure resource group + :param region: string, name of Azure region + """ + response = client.resource_groups.create_or_update( + resource_group, {'location': region}) + LOG.debug("resource_group response: {0}".format(response)) + LOG.debug("Created Resource Group '{0}' in Azure".format(resource_group)) + + def azure_handle_exception(fn): def wrapper(*args, **kwargs): try: