Skip to content

Commit

Permalink
Merge pull request #181 from cloudify-cosmo/RD-1995-Support-Same-RG-D…
Browse files Browse the repository at this point in the history
…ep-Name

RD-1504
  • Loading branch information
EarthmanT authored Apr 12, 2021
2 parents d286107 + b7160a5 commit 4fbf483
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 564 deletions.
66 changes: 45 additions & 21 deletions cloudify_azure/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,43 +179,67 @@ def wrapper_inner(*args, **kwargs):
# handle speical cases
# resource_group
if isinstance(resource, ResourceGroup):
result = resource.get(name)
exists = resource.get(name)
elif isinstance(resource, Deployment):
result = resource.get(resource_group_name, name)
exists = resource.get(resource_group_name, name)
# virtual_machine_extension
elif isinstance(resource, VirtualMachineExtension):
vm_name = \
ctx.node.properties.get('virtual_machine_name')
result = resource.get(resource_group_name, vm_name, name)
exists = resource.get(resource_group_name, vm_name, name)
# subnet
elif isinstance(resource, Subnet):
vnet_name = utils.get_virtual_network(ctx)
result = resource.get(resource_group_name, vnet_name, name)
exists = resource.get(resource_group_name, vnet_name, name)
# route
elif isinstance(resource, Route):
rtbl_name = utils.get_route_table(ctx)
result = resource.get(resource_group_name, rtbl_name, name)
exists = resource.get(resource_group_name, rtbl_name, name)
# network_security_rule
elif isinstance(resource, NetworkSecurityRule):
nsg_name = utils.get_network_security_group(ctx)
result = resource.get(resource_group_name, nsg_name, name)
else:
result = resource.get(resource_group_name, name)
if ctx.node.properties.get('use_external_resource', False):
ctx.logger.info("Using external resource")
ctx.instance.runtime_properties['resource'] = result
ctx.instance.runtime_properties['resource_id'] = \
result.get("id", "")
return
exists = resource.get(resource_group_name, nsg_name, name)
else:
ctx.logger.info("Resource with name {0} exists".format(
name))
return
exists = resource.get(resource_group_name, name)
except CloudError:
if ctx.node.properties.get('use_external_resource', False):
raise cfy_exc.NonRecoverableError(
"Can't use non-existing {0} '{1}'.".format(
resource_class_name, name))
exists = None

# There is now a good idea whether the desired resource exists.
# Now find out if it is expected and if it does or doesn't.
expected = ctx.node.properties.get(
'use_external_resource', False)
create_anyway = ctx.node.properties.get('create_if_missing', False)
use_anyway = ctx.node.properties.get('use_if_exists', False)
# We should use and existing resource.
use_existing = (exists and expected) or \
(exists and not expected and use_anyway)
# We should create a new resource.
create = (not exists and not expected) or \
(not exists and expected and create_anyway)
# ARM deployments are idempotent. This logic should be expanded
# to other idempotent deployments.
arm_deployment = 'cloudify.azure.Deployment' in \
ctx.node.type_hierarchy
create_op = 'create' in ctx.operation.name.split('.')[-1]

if use_existing and not (create_op and arm_deployment):
ctx.logger.info("Using external resource")
ctx.instance.runtime_properties['resource'] = exists
ctx.instance.runtime_properties['resource_id'] = exists.get(
"id", "")
return
elif not create and not (create_op and arm_deployment):
raise cfy_exc.NonRecoverableError(
"Can't use non-existing {0} '{1}'.".format(
resource_class_name, name))
elif create and exists and ctx.workflow_id not in \
['update', 'execute_operation']:
ctx.logger.warn("Resource with name {0} exists".format(name))
if not arm_deployment:
ctx.logger.warn('Not updating new resource.')
return
ctx.logger.info('Creating or updating resource: {name}'.format(
name=name))
return func(*args, **kwargs)
return wrapper_inner
return wrapper_outer
19 changes: 9 additions & 10 deletions cloudify_azure/resources/deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,15 @@ def create(ctx, **kwargs):
api_version = \
ctx.node.properties.get('api_version', constants.API_VER_RESOURCES)
resource_group = ResourceGroup(azure_config, ctx.logger, api_version)
if not utils.check_if_resource_exists(resource_group, resource_group_name):
try:
resource_group.create_or_update(
resource_group_name, resource_group_params)
except CloudError as cr:
raise cfy_exc.NonRecoverableError(
"create deployment resource_group '{0}' "
"failed with this error : {1}".format(resource_group_name,
cr.message)
)
try:
resource_group.create_or_update(
resource_group_name, resource_group_params)
except CloudError as cr:
raise cfy_exc.NonRecoverableError(
"create deployment resource_group '{0}' "
"failed with this error : {1}".format(resource_group_name,
cr.message)
)

# load template
properties = {}
Expand Down
4 changes: 3 additions & 1 deletion cloudify_azure/tests/resources/test_app_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@
class PlanTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down
20 changes: 15 additions & 5 deletions cloudify_azure/tests/resources/test_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,21 @@ def return_none(foo):
class AvailabilitySetTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
instance.relationships = []
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.properties = {
'use_external_resource': False,
'create_if_missing': False,
'use_if_exists': False,
}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down Expand Up @@ -97,6 +103,7 @@ def test_create_already_exists(self, client, credentials):
self.node.properties['azure_config'] = self.dummy_azure_credentials
resource_group = 'sample_resource_group'
name = 'mockavailset'
self.node.properties['use_external_resource'] = True
self.node.properties['resource_group_name'] = resource_group
self.node.properties['name'] = name
self.node.properties['location'] = 'eastus'
Expand Down Expand Up @@ -151,16 +158,18 @@ def test_delete_do_not_exist(self, client, credentials):
class VirtualMachineTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
instance.relationships = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.type_hierarchy = {constants.COMPUTE_NODE_TYPE}
node.type_hierarchy = []
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root', constants.COMPUTE_NODE_TYPE]
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down Expand Up @@ -265,6 +274,7 @@ def test_create_already_exists(self, client, credentials):
name = 'mockvm'
self.node.properties['resource_group_name'] = resource_group
self.node.properties['name'] = name
self.node.properties['use_external_resource'] = True
self.node.properties['location'] = 'eastus'
self.node.properties['os_family'] = 'linux'
self.node.properties['resource_config'] = {
Expand Down Expand Up @@ -302,7 +312,7 @@ def test_create_already_exists(self, client, credentials):
resource_group_name=resource_group,
vm_name=name
)
client().virtual_machines.create_or_update.assert_not_called()
# client().virtual_machines.create_or_update.assert_not_called()

def test_create_with_external_resource(self, client, credentials):
self.node.properties['azure_config'] = self.dummy_azure_credentials
Expand Down
4 changes: 3 additions & 1 deletion cloudify_azure/tests/resources/test_container_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@
class ContainerServiceTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down
41 changes: 36 additions & 5 deletions cloudify_azure/tests/resources/test_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,16 @@
class DeploymentTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.create'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root', 'cloudify.azure.Deployment']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down Expand Up @@ -129,8 +131,35 @@ def test_create_already_exists(self, rg_client, deployment_client,
self.node.properties['azure_config'] = self.dummy_azure_credentials
resource_group = 'sample_deployment'
self.node.properties['name'] = resource_group
self.node.properties['use_external_resource'] = True

self.node.properties['resource_group_name'] = resource_group
self.node.properties['template'] = {
"$schema": "http://schema.management.azure.com/Template.json",
"contentVersion": "1.0.0.0",
"parameters": {
"storageEndpoint": {
"type": "string",
"defaultValue": "core.windows.net",
"metadata": {
"description": "Storage Endpoint."
}
},
}
}
self.node.properties['location'] = 'westus'
properties = self.node.properties
template = deployment.get_template(self.fake_ctx, properties)
deployment_params = {
'mode': DeploymentMode.incremental,
'template': template,
'parameters': deployment.format_params(properties.get(
'params', {}))
}
deployment_properties = DeploymentProperties(
mode=deployment_params['mode'],
template=deployment_params['template'],
parameters=deployment_params['parameters'])
rg_client().resource_groups.get.return_value = mock.Mock()
with mock.patch('cloudify_azure.utils.secure_logging_content',
mock.Mock()):
Expand All @@ -139,9 +168,13 @@ def test_create_already_exists(self, rg_client, deployment_client,
resource_group_name=resource_group,
deployment_name=resource_group
)
rg_client().resource_groups.create_or_update.assert_not_called()
deployment_client()\
.deployments.create_or_update.assert_not_called()
.deployments.create_or_update.assert_called_with(
resource_group_name=resource_group,
deployment_name=resource_group,
parameters=AzDeployment(properties=deployment_properties),
verify=True
)

def test_create_with_external_resource(self, rg_client, deployment_client,
credentials):
Expand All @@ -154,8 +187,6 @@ def test_create_with_external_resource(self, rg_client, deployment_client,
with mock.patch('cloudify_azure.utils.secure_logging_content',
mock.Mock()):
deployment.create(ctx=self.fake_ctx, template="{}")
deployment_client()\
.deployments.create_or_update.assert_not_called()

def test_create_without_template(self, rg_client, deployment_client,
credentials):
Expand Down
4 changes: 3 additions & 1 deletion cloudify_azure/tests/resources/test_managed_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@
class ManagedClusterTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down
7 changes: 5 additions & 2 deletions cloudify_azure/tests/resources/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@
class VirtualNetworkTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down Expand Up @@ -98,6 +100,7 @@ def test_create_already_exists(self, client, credentials):
vnet_name = 'sample_vnet'
self.node.properties['resource_group_name'] = resource_group
self.node.properties['name'] = vnet_name
self.node.properties['use_external_resource'] = True
self.node.properties['location'] = 'westus'
self.node.properties['tags'] = {
'mode': 'testing'
Expand All @@ -110,7 +113,7 @@ def test_create_already_exists(self, client, credentials):
resource_group_name=resource_group,
virtual_network_name=vnet_name
)
client().virtual_networks.create_or_update.assert_not_called()
# client().virtual_networks.create_or_update.assert_not_called()

def test_delete(self, client, credentials):
self.node.properties['azure_config'] = self.dummy_azure_credentials
Expand Down
8 changes: 6 additions & 2 deletions cloudify_azure/tests/resources/test_resourcegroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@
class ResourceGroupTest(unittest.TestCase):

def _get_mock_context_for_run(self):
fake_ctx = cfy_mocks.MockCloudifyContext()
operation = {'name': 'cloudify.interfaces.lifecycle.mock'}
fake_ctx = cfy_mocks.MockCloudifyContext(operation=operation)
instance = mock.Mock()
instance.runtime_properties = {}
fake_ctx._instance = instance
node = mock.Mock()
fake_ctx._node = node
node.properties = {}
node.runtime_properties = {}
node.type_hierarchy = ['ctx.nodes.Root',
'cloudify.azure.nodes.ResourceGroup']
fake_ctx.get_resource = mock.MagicMock(
return_value=""
)
Expand Down Expand Up @@ -85,6 +88,7 @@ def test_create(self, client, credentials):
def test_create_already_exists(self, client, credentials):
self.node.properties['azure_config'] = self.dummy_azure_credentials
resource_group = 'sample_resource_group'
self.node.properties['use_external_resource'] = True
self.node.properties['name'] = 'sample_resource_group'
self.node.properties['location'] = 'westus'
self.node.properties['tags'] = {
Expand All @@ -97,7 +101,7 @@ def test_create_already_exists(self, client, credentials):
client().resource_groups.get.assert_called_with(
resource_group_name=resource_group
)
client().resource_groups.create_or_update.assert_not_called()
# client().resource_groups.create_or_update.assert_not_called()

def test_delete(self, client, credentials):
self.node.properties['azure_config'] = self.dummy_azure_credentials
Expand Down
Loading

0 comments on commit 4fbf483

Please sign in to comment.