From 4737cb631f94c3395314821df7dab4fd34c22cc6 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 21 Oct 2021 17:53:24 -0400 Subject: [PATCH 01/58] before writing unit tests --- cloudify_vcd/legacy/__init__.py | 0 cloudify_vcd/legacy/compute/__init__.py | 0 cloudify_vcd/legacy/compute/tasks.py | 101 +++++++++++ cloudify_vcd/legacy/decorators.py | 98 +++++++++++ cloudify_vcd/legacy/network/__init__.py | 0 cloudify_vcd/legacy/network/tasks.py | 63 +++++++ cloudify_vcd/legacy/utils.py | 103 +++++++++++ cloudify_vcd/network_tasks.py | 41 +++-- cloudify_vcd/vapp_tasks.py | 223 ++++++++++++++---------- plugin.yaml | 86 ++++++++- tox.ini | 4 +- vcd_plugin_sdk/resources/base.py | 1 + vcloud_network_plugin/README.md | 3 + vcloud_network_plugin/__init__.py | 0 vcloud_network_plugin/server.py | 51 ++++++ vcloud_network_plugin/tests/__init__.py | 0 vcloud_server_plugin/README.md | 4 + vcloud_server_plugin/__init__.py | 0 vcloud_server_plugin/network.py | 32 ++++ vcloud_server_plugin/port.py | 25 +++ vcloud_server_plugin/tests/__init__.py | 0 21 files changed, 723 insertions(+), 112 deletions(-) create mode 100644 cloudify_vcd/legacy/__init__.py create mode 100644 cloudify_vcd/legacy/compute/__init__.py create mode 100644 cloudify_vcd/legacy/compute/tasks.py create mode 100644 cloudify_vcd/legacy/decorators.py create mode 100644 cloudify_vcd/legacy/network/__init__.py create mode 100644 cloudify_vcd/legacy/network/tasks.py create mode 100644 cloudify_vcd/legacy/utils.py create mode 100644 vcloud_network_plugin/README.md create mode 100644 vcloud_network_plugin/__init__.py create mode 100644 vcloud_network_plugin/server.py create mode 100644 vcloud_network_plugin/tests/__init__.py create mode 100644 vcloud_server_plugin/README.md create mode 100644 vcloud_server_plugin/__init__.py create mode 100644 vcloud_server_plugin/network.py create mode 100644 vcloud_server_plugin/port.py create mode 100644 vcloud_server_plugin/tests/__init__.py diff --git a/cloudify_vcd/legacy/__init__.py b/cloudify_vcd/legacy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cloudify_vcd/legacy/compute/__init__.py b/cloudify_vcd/legacy/compute/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py new file mode 100644 index 0000000..68745bb --- /dev/null +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -0,0 +1,101 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from vcd_plugin_sdk.resources.vapp import VCloudVM +from cloudify_common_sdk.utils import \ + skip_creative_or_destructive_operation as skip + +from .. import decorators +from ... import vapp_tasks + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def create_server(vm_client, ctx, **_): + exists = vm_client.get() + if not skip(type(vm_client), vm_client.name, exists): + return vapp_tasks._create_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc_name, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def configure_server(vm_client, ctx, **_): + exists = vm_client.get() + if not skip(type(vm_client), vm_client.name, exists): + return vapp_tasks._configure_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc_name, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def start_server(vm_client, ctx, **_): + exists = vm_client.get() + if not skip(type(vm_client), vm_client.name, exists): + return vapp_tasks._start_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def delete_server(vm_client, ctx, **_): + exists = vm_client.get() + if not skip(type(vm_client), vm_client.name, exists): + return vapp_tasks._delete_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def stop_server(vm_client, ctx, **_): + exists = vm_client.get() + if not skip(type(vm_client), vm_client.name, exists): + return vapp_tasks._stop_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +def configure_nic(ctx, **_): + ctx.logger.info('Storing') + return vapp_tasks._configure_nic( + nic_config=ctx.node.properties['port'], nic_ctx=ctx) diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py new file mode 100644 index 0000000..eac4686 --- /dev/null +++ b/cloudify_vcd/legacy/decorators.py @@ -0,0 +1,98 @@ +# Copyright (c) 2020 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from functools import wraps + +from cloudify.exceptions import OperationRetry +from cloudify_common_sdk.utils import get_ctx_instance + +from . import utils +from ..utils import (get_last_task, check_if_task_successful) + + +def with_vcd_client(): + def wrapper_outer(func): + @wraps(func) + def wrapper_inner(*args, **kwargs): + """ + Initializes the connection object from vcloud_config. + :param args: + :param kwargs: From vcloud_config property. + :return: + """ + ctx = kwargs.get('ctx') + kwargs['vcloud_cx'] = utils.get_vcloud_cx( + kwargs['vcloud_config'], ctx.logger) + resource, result = utils.get_function_return(func(*args, **kwargs)) + last_task = get_last_task(result) + ctx_instance = get_ctx_instance(ctx) + if not check_if_task_successful(resource, last_task): + ctx_instance.runtime_properties['__RETRY_BAD_REQUEST'] = True + raise OperationRetry('Pending for operation completion.') + return wrapper_inner + return wrapper_outer + + +def with_network_resource(): + def wrapper_outer(func): + @wraps(func) + def wrapper_inner(*args, **kwargs): + """ + Initializes the network object with connection and the translated + configuration from network property. + :param args: + :param kwargs: + :return: + """ + client = utils.get_network_client(**kwargs) + kwargs['network_client'] = client + return func(*args, **kwargs) + return wrapper_inner + return wrapper_outer + + +def with_gateway_resource(): + def wrapper_outer(func): + @wraps(func) + def wrapper_inner(*args, **kwargs): + """ + Initializes the gateway object with connection and the translated + configuration from network property. + :param args: + :param kwargs: + :return: + """ + client = utils.get_gateway_client(**kwargs) + kwargs['gateway_client'] = client + return func(*args, **kwargs) + return wrapper_inner + return wrapper_outer + + +def with_vm_resource(): + def wrapper_outer(func): + @wraps(func) + def wrapper_inner(*args, **kwargs): + """ + Initializes the gateway object with connection and the translated + configuration from network property. + :param args: + :param kwargs: + :return: + """ + client = utils.get_vm_client(**kwargs) + kwargs['vm_client'] = client + return func(*args, **kwargs) + return wrapper_inner + return wrapper_outer diff --git a/cloudify_vcd/legacy/network/__init__.py b/cloudify_vcd/legacy/network/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cloudify_vcd/legacy/network/tasks.py b/cloudify_vcd/legacy/network/tasks.py new file mode 100644 index 0000000..4df16f8 --- /dev/null +++ b/cloudify_vcd/legacy/network/tasks.py @@ -0,0 +1,63 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from cloudify.exceptions import NonRecoverableError +from vcd_plugin_sdk.resources.network import VCloudNetwork +from cloudify_common_sdk.utils import \ + skip_creative_or_destructive_operation as skip + +from .. import decorators +from ... import network_tasks + + +class MissingGateway(NonRecoverableError): + pass + + +@decorators.with_vcd_client() +@decorators.with_network_resource() +@decorators.with_gateway_resource() +def create_network(network_client, gateway_client, ctx, **_): + gateway_exists = gateway_client.get() + if network_client.network_type == 'routed_vdc_network' and gateway_exists: + raise MissingGateway( + 'The provided gateway {} does not exist.'.format( + gateway_client.name)) + exists = network_client.get() + if not skip(network_client.network_type, network_client.name, exists): + return network_tasks._delete_network( + external_network=False, + network_id=network_client.name, + network_client=network_client.connection, + network_vdc=network_client.vdc_name, + network_config=network_client.kwargs, + network_class=VCloudNetwork, + ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_network_resource() +@decorators.with_gateway_resource() +def delete_network(network_client, ctx, **_): + exists = network_client.get() + if not skip( + network_client.network_type, network_client.name, exists=exists): + return network_tasks._delete_network( + external_network=False, + network_id=network_client.name, + network_client=network_client.connection, + network_vdc=network_client.vdc_name, + network_config=network_client.kwargs, + network_class=VCloudNetwork, + ctx=ctx) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py new file mode 100644 index 0000000..17687a3 --- /dev/null +++ b/cloudify_vcd/legacy/utils.py @@ -0,0 +1,103 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from vcd_plugin_sdk.resources.vapp import VCloudVM +from vcd_plugin_sdk.connection import VCloudConnect +from vcd_plugin_sdk.resources.network import VCloudNetwork, VCloudGateway + +from cloudify_common_sdk.utils import ( + get_ctx_node, + get_ctx_instance) + + +def get_function_return(func_ret): + if not isinstance(func_ret, tuple) and len(func_ret) == 2: + return func_ret + return None, None + + +def get_vcloud_cx(client_config, logger): + credentials = { + 'org': client_config.pop('org'), + 'user': client_config.pop('user'), + 'password': client_config.pop('password') + } + new_client_config = { + 'uri': client_config.pop('url'), + 'api_version': client_config.pop('api_version'), + 'verify_ssl_certs': client_config.pop('verify_ssl_certs'), + } + # TODO: Figure out what to do with the rest of the stuff in client_config. + return VCloudConnect(logger, new_client_config, credentials) + + +def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): + """ + Take the network configuration from legacy node type and convert it to + something that the vcd_plugin_sdk objects can understand. + + :param network: from ctx.node.properties['network'] or + operation inputs['network'] + :param vcloud_cx: VCloudConnect from with_vcloud_client decorator. + :param vcloud_config: from ctx.node.properties['vcloud_config'] or + operation inputs['vcloud_config'] + :param ctx: + :param kwargs: + :return: + """ + + _ctx_node = get_ctx_node(ctx) + _ctx_instance = get_ctx_instance(ctx) + + if 'edge_gateway' in vcloud_config: + network_type = 'routed_vdc_network' + network['gateway_name'] = vcloud_config['edge_gateway'] + else: + network_type = 'isolated_vdc_network' + + new_network_config = { + 'resource_name': _ctx_node.properties.get( + 'resource_id', _ctx_instance.id), + 'resource_type': network_type, + 'connection': vcloud_cx, + 'vdc_name': vcloud_config.get('vdc'), + 'vapp_name': None, + 'kwargs': network, + 'tasks': _ctx_instance.runtime_properties['__TASKS'] + } + + return VCloudNetwork(**new_network_config) + + +def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): + _ctx_instance = get_ctx_instance(ctx) + + if 'edge_gateway' in vcloud_config: + return VCloudGateway( + vcloud_config['edge_gateway'], + connection=vcloud_cx, + vdc_name=vcloud_config.get('vdc'), + tasks=_ctx_instance.runtime_properties['__TASKS'] + ) + + +def get_vm_client(vcloud_cx, vcloud_config, ctx): + _ctx_node = get_ctx_node(ctx) + _ctx_instance = get_ctx_instance(ctx) + name = _ctx_node.properties.get('resource_id', _ctx_instance.id) + return VCloudVM(name, + name, + connection=vcloud_cx, + vdc_name=vcloud_config.get('vdc'), + tasks=_ctx_instance.runtime_properties['__TASKS']) diff --git a/cloudify_vcd/network_tasks.py b/cloudify_vcd/network_tasks.py index a7da8a6..7f52ec5 100644 --- a/cloudify_vcd/network_tasks.py +++ b/cloudify_vcd/network_tasks.py @@ -20,14 +20,18 @@ def get_network_type(types): @resource_operation -def create_network(external_network, - network_id, - network_client, - network_vdc, - network_config, - network_class, - ctx, - **__): +def create_network(*args, **kwargs): + return _create_network(*args, **kwargs) + + +def _create_network(external_network, + network_id, + network_client, + network_vdc, + network_config, + network_class, + ctx, + **__): network = find_resource_id_from_relationship_by_type( ctx.instance, REL_NETWORK_GW) @@ -47,14 +51,19 @@ def create_network(external_network, @resource_operation -def delete_network(external_network, - network_id, - network_client, - network_vdc, - network_config, - network_class, - ctx, - **___): +def delete_network(*args, **kwargs): + return _delete_network(*args, **kwargs) + + +def _delete_network(external_network, + network_id, + network_client, + network_vdc, + network_config, + network_class, + ctx, + **___): + network = network_class( network_id, get_network_type(ctx.node.type_hierarchy), diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 69c8153..485faf0 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -186,14 +186,19 @@ def delete_vapp(vapp_ext, @resource_operation -def create_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **_): +def create_vm(*args, **kwargs): + return _create_vm(*args, **kwargs) + + +def _create_vm(vm_external, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **_): + """ Instiatiate a vApp and create a virtual machine. @@ -268,14 +273,18 @@ def create_vm(vm_external, @resource_operation -def configure_vm(_, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **__): +def configure_vm(*args, **kwargs): + return _configure_vm(*args, **kwargs) + + +def _configure_vm(_, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **__): vapp_name = find_resource_id_from_relationship_by_type( vm_ctx.instance, REL_VM_VAPP) @@ -290,14 +299,18 @@ def configure_vm(_, @resource_operation -def start_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **__): +def start_vm(*args, **kwargs): + return _start_vm(*args, **kwargs) + + +def _start_vm(vm_external, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **__): """ Power on both existing and new VMs. :param vm_external: @@ -344,14 +357,18 @@ def start_vm(vm_external, @resource_operation -def stop_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **__): +def stop_vm(*args, **kwargs): + return _stop_vm(*args, **kwargs) + + +def _stop_vm(vm_external, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **__): """ :param vm_external: @@ -393,14 +410,18 @@ def stop_vm(vm_external, @resource_operation -def delete_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **__): +def delete_vm(*args, **kwargs): + return _delete_vm(*args, **kwargs) + + +def _delete_vm(vm_external, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **__): """ :param vm_external: @@ -444,14 +465,18 @@ def delete_vm(vm_external, @resource_operation -def configure_nic(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - **______): +def configure_nic(*args, **kwargs): + return _configure_vm(*args, **kwargs) + + +def _configure_nic(_=None, + __=None, + ___=None, + ____=None, + nic_config=None, + _____=None, + nic_ctx=None, + **______): """ :param _: Unused external @@ -477,21 +502,25 @@ def configure_nic(_, @resource_operation -def add_network(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - ______, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **_______): +def add_network(*args, **kwargs): + return _add_network(*args, **kwargs) + + +def _add_network(_, + __, + ___, + ____, + nic_config, + _____, + nic_ctx, + ______, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **_______): """Add a network to a VM. @@ -548,21 +577,25 @@ def add_network(_, @resource_operation -def add_nic(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - ______, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **_______): +def add_nic(*args, **kwargs): + return _add_nic(*args, **kwargs) + + +def _add_nic(_, + __, + ___, + ____, + nic_config, + _____, + nic_ctx, + ______, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **_______): """ Add Nic to VM. :param _: Unused external nic @@ -616,21 +649,25 @@ def add_nic(_, @resource_operation -def delete_nic(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - ______, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, - **_______): +def delete_nic(*args, **kwargs): + return _delete_nic(*args, **kwargs) + + +def _delete_nic(_, + __, + ___, + ____, + nic_config, + _____, + nic_ctx, + ______, + vm_id, + vm_client, + vm_vdc, + vm_config, + vm_class, + vm_ctx, + **_______): """ Delete NIC and remove network from vapp. :param _: Unused external nic diff --git a/plugin.yaml b/plugin.yaml index c969370..a35414d 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -84,6 +84,18 @@ data_types: description: Configuration options for pyvcloud.vcd.client.Client and pyvcloud.vcd.client.BasicLoginCredentials required: false + cloudify.datatypes.vcloud.LegacyBaseProperties: + properties: &LegacyBaseProperties + use_external_resource: + type: boolean + default: false + resource_id: + type: string + default: '' + vcloud_config: + type: dict + default: {} + node_types: cloudify.nodes.vcloud.Media: @@ -115,7 +127,7 @@ node_types: implementation: vcd.cloudify_vcd.disk_tasks.delete_disk cloudify.nodes.vcloud.NIC: - derived_from: cloudify.nodes.Volume + derived_from: cloudify.nodes.Port properties: <<: *BaseProperties resource_config: @@ -223,6 +235,64 @@ node_types: delete: implementation: vcd.cloudify_vcd.gateway_tasks.delete_gateway +## legacy types + + cloudify.vcloud.nodes.Server: + derived_from: cloudify.nodes.Compute + properties: + <<: *LegacyBaseProperties + server: + default: {} + management_network_name: + type: string + interfaces: + cloudify.interfaces.lifecycle: + create: + implementation: vcd.cloudify_vcd.legacy.compute.tasks.create_server + inputs: + server: + default: { get_property: [SELF, server ] } + vcloud_config: + default: { get_property: [SELF, vcloud_config] } + delete: + implementation: vcd.cloudify_vcd.legacy.compute.tasks.delete_server + inputs: + vcloud_config: + default: { get_property: [SELF, vcloud_config] } + + cloudify.vcloud.nodes.Port: + derived_from: cloudify.nodes.Port + properties: + vcloud_config: + default: {} + port: + default: {} + interfaces: + cloudify.interfaces.lifecycle: + configure: + implementation: vcd.cloudify_vcd.legacy.compute.tasks.configure_nic + + cloudify.vcloud.nodes.Network: + derived_from: cloudify.nodes.Network + properties: + <<: *LegacyBaseProperties + network: + default: {} + interfaces: + cloudify.interfaces.lifecycle: + create: + implementation: vcd.cloudify_vcd.legacy.network.tasks.create_network + inputs: + network: + default: { get_property: [SELF, network ] } + vcloud_config: + default: { get_property: [SELF, vcloud_config] } + delete: + implementation: vcd.cloudify_vcd.legacy.network.tasks.delete_network + inputs: + vcloud_config: + default: { get_property: [SELF, vcloud_config] } + relationships: cloudify.relationships.vcloud.network_connected_to_gateway: @@ -304,3 +374,17 @@ relationships: cloudify.relationships.vcloud.nic_connected_to_network: derived_from: cloudify.relationships.connected_to + +### Legacy Relationships + + cloudify.vcloud.port_connected_to_network: + derived_from: cloudify.relationships.vcloud.nic_connected_to_network + + cloudify.vcloud.server_connected_to_port: + derived_from: cloudify.relationships.vcloud.vm_connected_to_nic + preconfigure: + implementation: vcd.cloudify_vcd.vapp_tasks.add_network + postconfigure: + implementation: vcd.cloudify_vcd.vapp_tasks.add_nic + unlink: + implementation: vcd.cloudify_vcd.vapp_tasks.delete_nic diff --git a/tox.ini b/tox.ini index a6bbdea..220d156 100644 --- a/tox.ini +++ b/tox.ini @@ -17,8 +17,8 @@ whitelist_externals = bash [testenv:code_quality] commands = - flake8 vcd_plugin_sdk cloudify_vcd + flake8 vcd_plugin_sdk cloudify_vcd vcloud_server_plugin vcloud_network_plugin [testenv:unit_tests] commands = - pytest vcd_plugin_sdk cloudify_vcd + pytest vcd_plugin_sdk cloudify_vcd vcloud_server_plugin vcloud_network_plugin diff --git a/vcd_plugin_sdk/resources/base.py b/vcd_plugin_sdk/resources/base.py index cdb172c..e912a41 100644 --- a/vcd_plugin_sdk/resources/base.py +++ b/vcd_plugin_sdk/resources/base.py @@ -30,6 +30,7 @@ def __init__(self, connection, vdc_name, vapp_name=None, tasks=None): self._connection = connection or VCloudConnect() self.logger = self.connection.logger + self.vdc_name = vdc_name try: vdc_resource = self._connection.org.get_vdc(vdc_name) diff --git a/vcloud_network_plugin/README.md b/vcloud_network_plugin/README.md new file mode 100644 index 0000000..8e0c690 --- /dev/null +++ b/vcloud_network_plugin/README.md @@ -0,0 +1,3 @@ +# Tosca VCloud Plugin Compatibility Project + +The Cloudify VCloud Plugin is a replacement for the Tosca VCloud Plugin. However, it is not backward compatible. The new plugin uses modern Cloudify topology and design. In order for users olf the old Tosca VCloud Plugin to continue to use their old blueprints on Python 3 managers, we have limited compatibility modules. diff --git a/vcloud_network_plugin/__init__.py b/vcloud_network_plugin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vcloud_network_plugin/server.py b/vcloud_network_plugin/server.py new file mode 100644 index 0000000..4f1ce12 --- /dev/null +++ b/vcloud_network_plugin/server.py @@ -0,0 +1,51 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from cloudify.decorators import operation +from cloudify_vcd.legacy.compute.tasks import ( + create_server, + configure_server, + start_server, + stop_sterver, + delete_server) + + +@operation(resumable=True) +def create(*args, **kwargs): + create_server(*args, **kwargs) + + +@operation(resumable=True) +def configure(*args, **kwargs): + configure_server(*args, **kwargs) + + +@operation(resumable=True) +def start(*args, **kwargs): + start_server(*args, **kwargs) + + +@operation(resumable=True) +def stop(*args, **kwargs): + stop_sterver(*args, **kwargs) + + +@operation(resumable=True) +def delete(*args, **kwargs): + delete_server(*args, **kwargs) + + +@operation(resumable=True) +def creation_validation(*args, **kwargs): + pass diff --git a/vcloud_network_plugin/tests/__init__.py b/vcloud_network_plugin/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vcloud_server_plugin/README.md b/vcloud_server_plugin/README.md new file mode 100644 index 0000000..37f4a7e --- /dev/null +++ b/vcloud_server_plugin/README.md @@ -0,0 +1,4 @@ +# Tosca VCloud Plugin Compatibility Project + +The Cloudify VCloud Plugin is a replacement for the Tosca VCloud Plugin. However, it is not backward compatible. The new plugin uses modern Cloudify topology and design. In order for users olf the old Tosca VCloud Plugin to continue to use their old blueprints on Python 3 managers, we have limited compatibility modules. + diff --git a/vcloud_server_plugin/__init__.py b/vcloud_server_plugin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vcloud_server_plugin/network.py b/vcloud_server_plugin/network.py new file mode 100644 index 0000000..6eded98 --- /dev/null +++ b/vcloud_server_plugin/network.py @@ -0,0 +1,32 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from cloudify.decorators import operation + +from cloudify_vcd.legacy.network.tasks import create_network, delete_network + + +@operation(resumable=True) +def create(*args, **kwargs): + create_network(*args, **kwargs) + + +@operation(resumable=True) +def delete(*args, **kwargs): + delete_network(*args, **kwargs) + + +@operation(resumable=True) +def creation_validation(*args, **kwargs): + pass diff --git a/vcloud_server_plugin/port.py b/vcloud_server_plugin/port.py new file mode 100644 index 0000000..e58238d --- /dev/null +++ b/vcloud_server_plugin/port.py @@ -0,0 +1,25 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from cloudify.decorators import operation + + +@operation(resumable=True) +def creation_validation(port, *args, **kwargs): + pass + + +@operation(resumable=True) +def delete(*args, **kwargs): + pass diff --git a/vcloud_server_plugin/tests/__init__.py b/vcloud_server_plugin/tests/__init__.py new file mode 100644 index 0000000..e69de29 From d2def33e1e68af8b3749a11c35ac7f14b004d0d8 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Fri, 22 Oct 2021 10:35:34 -0400 Subject: [PATCH 02/58] update tests. fix style issues --- cloudify_vcd/disk_tasks.py | 2 +- cloudify_vcd/tests/test_decorator.py | 37 ++++--- cloudify_vcd/tests/test_tasks.py | 149 ++++++++++++++++----------- cloudify_vcd/vapp_tasks.py | 14 +-- tox.ini | 22 +++- 5 files changed, 140 insertions(+), 84 deletions(-) diff --git a/cloudify_vcd/disk_tasks.py b/cloudify_vcd/disk_tasks.py index 2ecbc4e..3681425 100644 --- a/cloudify_vcd/disk_tasks.py +++ b/cloudify_vcd/disk_tasks.py @@ -108,7 +108,7 @@ def detach_disk(_, disk_config, disk_ctx.instance.runtime_properties.get('tasks')) if not vapp_name: - ctx.logger.warn('No vapp was found to detach disk {n}.'.format( + ctx.logger.debug('No vapp was found to detach disk {n}.'.format( n=disk_id)) last_task = None else: diff --git a/cloudify_vcd/tests/test_decorator.py b/cloudify_vcd/tests/test_decorator.py index c5e0e74..bf1c932 100644 --- a/cloudify_vcd/tests/test_decorator.py +++ b/cloudify_vcd/tests/test_decorator.py @@ -24,12 +24,13 @@ def test_external_resource_exists(*_, **__): :return: """ operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': True, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _task = E.Task( status='foo', serviceNamespace='bar', @@ -55,7 +56,8 @@ def test_external_resource_not_exists(*_, **__): :return: """ operation = {'name': 'foo', 'retry_number': 1} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': True, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, @@ -82,7 +84,8 @@ def test_external_resource_not_exists_create_op(*_, **__): :return: """ operation = {'name': 'create', 'retry_number': 1} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': True, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, @@ -111,7 +114,8 @@ def test_implicit_external_resource_bad_request(*_, **__): :return: """ operation = {'name': 'foo', 'retry_number': 1} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, @@ -148,12 +152,13 @@ def test_new_resource(*_, **__): :return: """ operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _task = E.Task( status='foo', serviceNamespace='bar', @@ -180,11 +185,13 @@ def test_new_resource_access_forbidden(*_, **__): :return: """ operation = {'name': 'foo', 'retry_number': 1} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, - 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, + 'client_config': {'foo': 'bar', 'vdc': 'vdc'} + }, operation=operation ) @@ -207,11 +214,13 @@ def test_new_resource_bad_request_handled(*_, **__): :param __: :return: """ - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, - 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, + 'client_config': {'foo': 'bar', 'vdc': 'vdc'} + }, ) @resource_operation @@ -241,11 +250,13 @@ def test_new_resource_not_found(*_, **__): :param __: :return: """ - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, - 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, + 'client_config': {'foo': 'bar', 'vdc': 'vdc'} + }, ) @resource_operation diff --git a/cloudify_vcd/tests/test_tasks.py b/cloudify_vcd/tests/test_tasks.py index 03490d0..2dc5b12 100644 --- a/cloudify_vcd/tests/test_tasks.py +++ b/cloudify_vcd/tests/test_tasks.py @@ -67,12 +67,13 @@ return_value=True) def test_configure_gateway(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.Gateway'] configure_gateway(ctx=_ctx) @@ -86,12 +87,13 @@ def test_configure_gateway(*_, **__): return_value=True) def test_delete_gateway(*_, **__): operation = {'name': 'delete', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.Gateway'] delete_gateway(ctx=_ctx) @@ -516,12 +518,13 @@ def test_delete_nat_rules(*_, **__): return_value=True) def test_create_disk(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'size': 1, 'description': 'foo'}, 'client_config': {'size': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.Disk'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -538,12 +541,13 @@ def test_create_disk(*_, **__): return_value=True) def test_delete_disk(*_, **__): operation = {'name': 'delete', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'size': 1, 'description': 'foo'}, 'client_config': {'size': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.Disk'] delete_disk(ctx=_ctx) @@ -669,14 +673,15 @@ def test_detach_disk(*_, **__): return_value=True) def test_create_media(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog_name': 'foo'}, 'iso': {'vol_ident': 'foo', 'sys_ident': '', 'files': {'ISO/FOLDER/content.json': 'baz'}}, 'client_config': {'size': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.Media'] create_media(ctx=_ctx) @@ -692,14 +697,15 @@ def test_create_media(*_, **__): return_value=True) def test_delete_media(*_, **__): operation = {'name': 'delete', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog_name': 'foo'}, 'iso': {'vol_ident': 'foo', 'sys_ident': '', 'files': {'ISO/FOLDER/content.json': 'baz'}}, 'client_config': {'size': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.Media'] delete_media(ctx=_ctx) @@ -833,14 +839,15 @@ def test_detach_media(*_, **__): 'by_type', return_value='foo') def test_create_network(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': { 'gateway_name': 'bar', 'network_cidr': '1.1.1.1/1'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.RoutedVDCNetwork'] create_network(ctx=_ctx) @@ -854,12 +861,13 @@ def test_create_network(*_, **__): return_value=True) def test_delete_network(*_, **__): operation = {'name': 'delete', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'foo': 'bar'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.RoutedVDCNetwork'] delete_network(ctx=_ctx) @@ -875,13 +883,14 @@ def test_delete_network(*_, **__): 'by_type', return_value='foo') def test_create_vapp(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'description': 'bar', 'fence_mode': 'isolated'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VApp'] create_vapp(ctx=_ctx) @@ -896,12 +905,13 @@ def test_create_vapp(*_, **__): return_value=True) def test_stop_vapp(*_, **__): operation = {'name': 'stop', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'description': 'bar', 'fence_mode': 'baz'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VApp'] stop_vapp(ctx=_ctx) @@ -916,12 +926,13 @@ def test_stop_vapp(*_, **__): return_value=True) def test_delete_vapp(*_, **__): operation = {'name': 'delete', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'description': 'bar', 'fence_mode': 'baz'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VApp'] delete_vapp(ctx=_ctx) @@ -938,14 +949,17 @@ def test_delete_vapp(*_, **__): 'by_type', return_value='foo') def test_create_vm(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', - 'resource_config': {'catalog': 'bar', - 'template': 'baz', - 'fence_mode': 'isolated'}, + 'resource_config': { + 'catalog': 'bar', + 'template': 'baz', + 'fence_mode': 'isolated' + }, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -964,14 +978,16 @@ def test_create_vm(*_, **__): 'by_type', return_value='foo') def test_create_vm_external(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': True, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz', 'fence_mode': 'isolated'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation + ) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -991,24 +1007,30 @@ def test_create_vm_external(*_, **__): 'by_type', return_value='foo') def test_create_vm_handles_bad_request(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', - 'resource_config': {'catalog': 'bar', - 'template': 'baz', - 'fence_mode': 'isolated'}, - 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + 'resource_config': { + 'catalog': 'bar', + 'template': 'baz', + 'fence_mode': 'isolated'}, + 'client_config': {'foo': 'bar', 'vdc': 'vdc'} + }, + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] - with mock.patch('cloudify_vcd.constants.VCloudVM.instantiate_vapp', - side_effect=BadRequestException( - 400, - 'foo', - { - 'message': 'DUPLICATE_NAME', - 'minorCode': 400 - })): + with mock.patch( + 'cloudify_vcd.constants.VCloudVM.instantiate_vapp', + side_effect=BadRequestException( + 400, + 'foo', + { + 'message': 'DUPLICATE_NAME', + 'minorCode': 400 + } + ) + ): create_vm(ctx=_ctx) assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert '__created' in _ctx.instance.runtime_properties @@ -1024,14 +1046,15 @@ def test_create_vm_handles_bad_request(*_, **__): 'by_type', return_value='foo') def test_create_vm_raises_bad_request(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz', 'fence_mode': 'isolated'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('cloudify_vcd.constants.VCloudVM.instantiate_vapp', @@ -1050,14 +1073,15 @@ def test_create_vm_raises_bad_request(*_, **__): 'by_type', return_value='foo') def test_create_vm_raises_retry(*_, **__): operation = {'name': 'create', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz', 'fence_mode': 'isolated'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('cloudify_vcd.constants.VCloudVM.instantiate_vapp', @@ -1082,12 +1106,13 @@ def test_create_vm_raises_retry(*_, **__): 'by_type', return_value='foo') def test_configure_vm(*_, **__): operation = {'name': 'configure', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -1106,12 +1131,14 @@ def test_configure_vm(*_, **__): 'by_type', return_value='foo') def test_start_vm(*_, **__): operation = {'name': 'start', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation + ) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -1130,12 +1157,14 @@ def test_start_vm(*_, **__): 'by_type', return_value='foo') def test_stop_vm(*_, **__): operation = {'name': 'stop', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation + ) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -1154,12 +1183,14 @@ def test_stop_vm(*_, **__): 'by_type', return_value='foo') def test_delete_vm(*_, **__): operation = {'name': 'delete', 'retry_number': 0} - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': {'catalog': 'bar', 'template': 'baz'}, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation) + operation=operation + ) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.VM'] with mock.patch('vcd_plugin_sdk.resources.base.VDC') as vdc: @@ -1178,7 +1209,8 @@ def test_configure_nic(*_, **__): ) ) )] - _ctx = get_mock_node_instance_context(properties={ + _ctx = get_mock_node_instance_context( + properties={ 'use_external_resource': False, 'resource_id': 'foo', 'resource_config': { @@ -1189,8 +1221,9 @@ def test_configure_nic(*_, **__): 'ip_address': '192.169.2.2' }, 'client_config': {'foo': 'bar', 'vdc': 'vdc'}}, - operation=operation, - relationships=relationships) + operation=operation, + relationships=relationships + ) _ctx.node.type_hierarchy = ['cloudify.nodes.Root', 'cloudify.nodes.vcloud.NIC'] configure_nic(ctx=_ctx) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 485faf0..f109e1a 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -225,7 +225,7 @@ def _create_vm(vm_external, vm_name = vm_config.get('vm_name') if vm_name != vm_id: - ctx.logger.warn( + ctx.logger.debug( 'The parameter vm_name {v} in resource_config does not match ' 'the resource ID provided {i}. ' 'Using resource_id instead.'.format(v=vm_name, i=vm_id)) @@ -265,7 +265,7 @@ def _create_vm(vm_external, if not (vcd_already_exists(e) and not vm_external) or bad_vm_name(e): raise else: - vm.logger.warn('The vm {name} unexpectedly exists.'.format( + vm.logger.debug('The vm {name} unexpectedly exists.'.format( name=vm.name)) last_task = None vm_ctx.instance.runtime_properties['__VM_CREATE_VAPP'] = True @@ -344,9 +344,9 @@ def _start_vm(vm_external, last_task = \ vm_ctx.instance.runtime_properties['tasks']['update'][-1] except (KeyError, IndexError): - vm.logger.warn('The vm {name} is powered on, ' - 'but has no previous start task ' - 'and is not external.'.format(name=vm.name)) + vm.logger.debug('The vm {name} is powered on, ' + 'but has no previous start task ' + 'and is not external.'.format(name=vm.name)) return vm, None else: return vm, last_task @@ -466,7 +466,7 @@ def _delete_vm(vm_external, @resource_operation def configure_nic(*args, **kwargs): - return _configure_vm(*args, **kwargs) + return _configure_nic(*args, **kwargs) def _configure_nic(_=None, @@ -718,7 +718,7 @@ def _delete_nic(_, last_task = vm.remove_vapp_network(nic_config['network_name']) return vm, last_task - ctx.logger.warn( + ctx.logger.debug( 'The NIC {config} was not found, ' 'so we cannot remove it from the VM.'.format(config=nic_config)) diff --git a/tox.ini b/tox.ini index 220d156..18e9a67 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = nosetest,pep8 +envlist = nosetest,flake8 minversion = 1.6 skipsdist = True @@ -13,12 +13,24 @@ usedevelop = True install_command = pip install -U {opts} {packages} deps = -r{toxinidir}/dev-requirements.txt -r{toxinidir}/test-requirements.txt + -e . whitelist_externals = bash -[testenv:code_quality] +[testenv:flake8] commands = - flake8 vcd_plugin_sdk cloudify_vcd vcloud_server_plugin vcloud_network_plugin + flake8 cloudify_vcd vcd_plugin_sdk -[testenv:unit_tests] +[testenv:nosetest] commands = - pytest vcd_plugin_sdk cloudify_vcd vcloud_server_plugin vcloud_network_plugin + pytest cloudify_vcd + pytest vcd_plugin_sdk + +[testenv:venv] +commands = {posargs} + +[flake8] +show-source = True +ignore = +exclude=.venv,.tox,dist,*egg,etc,build,bin,lib,local,share +filename=*.py + From c2af4c6c1fc88e349a6fc2e1997794dec7079bb5 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Fri, 22 Oct 2021 12:51:26 -0400 Subject: [PATCH 03/58] first working test --- .circleci/config.yml | 4 +- CHANGELOG.txt | 2 + cloudify_vcd/legacy/__init__.py | 13 +++ cloudify_vcd/legacy/decorators.py | 8 +- cloudify_vcd/legacy/network/tasks.py | 13 +-- cloudify_vcd/legacy/tests/__init__.py | 72 +++++++++++++++++ cloudify_vcd/legacy/utils.py | 48 ++++++++--- plugin.yaml | 4 +- tox.ini | 6 +- .../network.py | 5 ++ .../port.py | 0 vcloud_network_plugin/tests/test_network.py | 79 +++++++++++++++++++ .../server.py | 0 13 files changed, 231 insertions(+), 23 deletions(-) create mode 100644 cloudify_vcd/legacy/tests/__init__.py rename {vcloud_server_plugin => vcloud_network_plugin}/network.py (80%) rename {vcloud_server_plugin => vcloud_network_plugin}/port.py (100%) create mode 100644 vcloud_network_plugin/tests/test_network.py rename {vcloud_network_plugin => vcloud_server_plugin}/server.py (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 72a4d5d..cae4d15 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,10 +38,10 @@ commands: command: pip install --user tox - run: name: Run Flake8 - command: /home/circleci/.local/bin/tox -e code_quality + command: /home/circleci/.local/bin/tox -e flake8 - run: name: Run nosetest - command: /home/circleci/.local/bin/tox -e unit_tests + command: /home/circleci/.local/bin/tox -e pytest check_py3_compat: steps: diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 00d5f15..5efeab9 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -2,3 +2,5 @@ - New version. 2.0.1: - Attempt to decrease amount of superfluous API requests, however these calls are almost all inside of the client library. +2.0.2: + - Support some legacy types. diff --git a/cloudify_vcd/legacy/__init__.py b/cloudify_vcd/legacy/__init__.py index e69de29..95c6c3e 100644 --- a/cloudify_vcd/legacy/__init__.py +++ b/cloudify_vcd/legacy/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2020 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py index eac4686..8ecb642 100644 --- a/cloudify_vcd/legacy/decorators.py +++ b/cloudify_vcd/legacy/decorators.py @@ -15,7 +15,7 @@ from functools import wraps from cloudify.exceptions import OperationRetry -from cloudify_common_sdk.utils import get_ctx_instance +from cloudify_common_sdk.utils import get_ctx_node, get_ctx_instance from . import utils from ..utils import (get_last_task, check_if_task_successful) @@ -32,6 +32,9 @@ def wrapper_inner(*args, **kwargs): :return: """ ctx = kwargs.get('ctx') + _ctx_node = get_ctx_node() + if 'vcloud_config' not in kwargs: + kwargs['vcloud_config'] = _ctx_node.properties['vcloud_config'] kwargs['vcloud_cx'] = utils.get_vcloud_cx( kwargs['vcloud_config'], ctx.logger) resource, result = utils.get_function_return(func(*args, **kwargs)) @@ -55,6 +58,9 @@ def wrapper_inner(*args, **kwargs): :param kwargs: :return: """ + _ctx_node = get_ctx_node() + if 'network' not in kwargs: + kwargs['network'] = _ctx_node.properties['network'] client = utils.get_network_client(**kwargs) kwargs['network_client'] = client return func(*args, **kwargs) diff --git a/cloudify_vcd/legacy/network/tasks.py b/cloudify_vcd/legacy/network/tasks.py index 4df16f8..5a04562 100644 --- a/cloudify_vcd/legacy/network/tasks.py +++ b/cloudify_vcd/legacy/network/tasks.py @@ -29,13 +29,16 @@ class MissingGateway(NonRecoverableError): @decorators.with_network_resource() @decorators.with_gateway_resource() def create_network(network_client, gateway_client, ctx, **_): - gateway_exists = gateway_client.get() - if network_client.network_type == 'routed_vdc_network' and gateway_exists: + gateway_exists = gateway_client.gateway + if network_client.network_type == 'routed_vdc_network' and \ + not gateway_exists: raise MissingGateway( 'The provided gateway {} does not exist.'.format( gateway_client.name)) - exists = network_client.get() - if not skip(network_client.network_type, network_client.name, exists): + exists = network_client.network + if not skip(network_client.network_type, + network_client.name, + exists=exists): return network_tasks._delete_network( external_network=False, network_id=network_client.name, @@ -50,7 +53,7 @@ def create_network(network_client, gateway_client, ctx, **_): @decorators.with_network_resource() @decorators.with_gateway_resource() def delete_network(network_client, ctx, **_): - exists = network_client.get() + exists = network_client.network if not skip( network_client.network_type, network_client.name, exists=exists): return network_tasks._delete_network( diff --git a/cloudify_vcd/legacy/tests/__init__.py b/cloudify_vcd/legacy/tests/__init__.py new file mode 100644 index 0000000..165ced3 --- /dev/null +++ b/cloudify_vcd/legacy/tests/__init__.py @@ -0,0 +1,72 @@ +# Copyright (c) 2014-21 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from cloudify.mocks import MockCloudifyContext + + +DEFAULT_NODE_PROPS = { + 'use_external_resource': False, + 'resource_id': '', + 'vcloud_config': { + 'username': 'taco', + 'password': 'secret', + 'token': None, + 'url': 'protocol://subdomain.domain.com/endpoint/version/resource', + 'instance': None, + 'vdc': 'vdc', + 'org': 'org', + 'service_type': None, + 'service': None, + 'api_version': '1.0', + 'org_url': None, + 'edge_gateway': None, + 'ssl_verify': True, + } +} + + +def create_ctx(node_id, + node_type, + node_properties, + runtime_props=None, + operation_name=None, + relationships=None): + """ + Create a Mock Context. + + :param node_id: + :param node_type: + :param node_properties: + :param runtime_props: + :param operation_name: + :param relationships: + :return: + """ + + type_hierarchy = ['cloudify.nodes.Root'] + type_hierarchy.extend(node_type) + operation_name = operation_name or 'cloudify.interfaces.lifecycle.create' + operation = { + 'name': operation_name, + 'retry': 0, + } + return MockCloudifyContext( + node_id=node_id, + node_name=node_id, + node_type=node_type, + properties=node_properties, + runtime_properties=runtime_props, + relationships=relationships, + operation=operation + ) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 17687a3..5f4355c 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -16,28 +16,52 @@ from vcd_plugin_sdk.connection import VCloudConnect from vcd_plugin_sdk.resources.network import VCloudNetwork, VCloudGateway +from cloudify.exceptions import NonRecoverableError from cloudify_common_sdk.utils import ( get_ctx_node, get_ctx_instance) +class RequiredClientKeyMissing(NonRecoverableError): + def __init__(self, key, *args, **kwargs): + msg = 'Required vcloud config key "{}" not provided.'.format(key) + super().__init__(msg, *args, **kwargs) + + def get_function_return(func_ret): - if not isinstance(func_ret, tuple) and len(func_ret) == 2: + if isinstance(func_ret, tuple) and len(func_ret) == 2: return func_ret return None, None def get_vcloud_cx(client_config, logger): + for bad, good in [('username', 'user'), + ('ssl_verify', 'verify_ssl_certs')]: + if bad in client_config: + logger.warning( + 'The vcloud_config contains the key "{}". ' + 'This is an invalid key. The correct key is "{}".'.format( + good, bad)) + client_config[good] = client_config.pop(bad) + + for key in ['user', 'password', 'org']: + if key not in client_config: + raise RequiredClientKeyMissing(key) + credentials = { 'org': client_config.pop('org'), 'user': client_config.pop('user'), 'password': client_config.pop('password') } - new_client_config = { - 'uri': client_config.pop('url'), - 'api_version': client_config.pop('api_version'), - 'verify_ssl_certs': client_config.pop('verify_ssl_certs'), - } + new_client_config = {'uri': client_config.pop('url')} + + if 'api_version' in client_config: + new_client_config['api_version'] = client_config.pop('api_version') + + if 'verify_ssl_certs' in client_config: + new_client_config['verify_ssl_certs'] = client_config.pop( + 'verify_ssl_certs') + # TODO: Figure out what to do with the rest of the stuff in client_config. return VCloudConnect(logger, new_client_config, credentials) @@ -66,15 +90,16 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): else: network_type = 'isolated_vdc_network' + tasks = _ctx_instance.runtime_properties.get('__TASKS', []) + new_network_config = { - 'resource_name': _ctx_node.properties.get( + 'network_name': _ctx_node.properties.get( 'resource_id', _ctx_instance.id), - 'resource_type': network_type, + 'network_type': network_type, 'connection': vcloud_cx, 'vdc_name': vcloud_config.get('vdc'), - 'vapp_name': None, 'kwargs': network, - 'tasks': _ctx_instance.runtime_properties['__TASKS'] + 'tasks': tasks } return VCloudNetwork(**new_network_config) @@ -82,13 +107,14 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): _ctx_instance = get_ctx_instance(ctx) + tasks = _ctx_instance.runtime_properties.get('__TASKS', []) if 'edge_gateway' in vcloud_config: return VCloudGateway( vcloud_config['edge_gateway'], connection=vcloud_cx, vdc_name=vcloud_config.get('vdc'), - tasks=_ctx_instance.runtime_properties['__TASKS'] + tasks=tasks ) diff --git a/plugin.yaml b/plugin.yaml index a35414d..27d97a0 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -3,7 +3,7 @@ plugins: vcd: executor: central_deployment_agent package_name: cloudify-vcloud-plugin - package_version: '2.0.1' + package_version: '2.0.2' data_types: @@ -382,6 +382,8 @@ relationships: cloudify.vcloud.server_connected_to_port: derived_from: cloudify.relationships.vcloud.vm_connected_to_nic + target_interfaces: + cloudify.interfaces.relationship_lifecycle: preconfigure: implementation: vcd.cloudify_vcd.vapp_tasks.add_network postconfigure: diff --git a/tox.ini b/tox.ini index 18e9a67..71e80a4 100644 --- a/tox.ini +++ b/tox.ini @@ -18,12 +18,13 @@ whitelist_externals = bash [testenv:flake8] commands = - flake8 cloudify_vcd vcd_plugin_sdk + flake8 cloudify_vcd vcd_plugin_sdk vcloud_network_plugin -[testenv:nosetest] +[testenv:pytest] commands = pytest cloudify_vcd pytest vcd_plugin_sdk + pytest vcloud_network_plugin [testenv:venv] commands = {posargs} @@ -33,4 +34,3 @@ show-source = True ignore = exclude=.venv,.tox,dist,*egg,etc,build,bin,lib,local,share filename=*.py - diff --git a/vcloud_server_plugin/network.py b/vcloud_network_plugin/network.py similarity index 80% rename from vcloud_server_plugin/network.py rename to vcloud_network_plugin/network.py index 6eded98..38f92c0 100644 --- a/vcloud_server_plugin/network.py +++ b/vcloud_network_plugin/network.py @@ -19,6 +19,11 @@ @operation(resumable=True) def create(*args, **kwargs): + _ctx = kwargs.get('ctx') + _ctx.logger.info( + 'Using translation of legacy tosca-cloudify-plugin ' + 'cloudify.vcloud.nodes.Network node type. Please upgrade to ' + 'cloudify.vcloud.plugin cloudify.nodes.vcloud.Network.') create_network(*args, **kwargs) diff --git a/vcloud_server_plugin/port.py b/vcloud_network_plugin/port.py similarity index 100% rename from vcloud_server_plugin/port.py rename to vcloud_network_plugin/port.py diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py new file mode 100644 index 0000000..e6edcf4 --- /dev/null +++ b/vcloud_network_plugin/tests/test_network.py @@ -0,0 +1,79 @@ +# Copyright (c) 2020 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from mock import patch +from copy import deepcopy +from cloudify.state import current_ctx + +from .. network import create as legacy_network_create +from .. network import delete as legacy_network_delete +from cloudify_vcd.legacy.tests import create_ctx, DEFAULT_NODE_PROPS + + +def get_network_ctx(existing=False, + resource_id=None, + network=None, + gateway=None): + """ + Generate the node props for use in the test. + :param existing: whether to create or not + :param resource_id: name of the resource + :param network: the network resource config + :param gateway: name of the edge gateway + :return: + """ + + network = network or {} + network_node_props = {'network': network} + network_node_props.update( + deepcopy(DEFAULT_NODE_PROPS)) + network_node_props['use_external_resource'] = existing + network_node_props['resource_id'] = resource_id + if gateway: + network_node_props['vcloud_config']['edge_gateway'] = gateway + return network_node_props + + +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) +def test_create_external_network_with_gateway(*_, **__): + network_node_props = get_network_ctx(True, 'foo', gateway='baz') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Network', + 'cloudify.vcloud.nodes.Network' + ], + node_properties=network_node_props) + current_ctx.set(_ctx) + legacy_network_create(ctx=_ctx) + + +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) +def test_delete_external_network_with_gateway(*_, **__): + network_node_props = get_network_ctx(True, 'foo', gateway='baz') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Network', + 'cloudify.vcloud.nodes.Network' + ], + node_properties=network_node_props) + current_ctx.set(_ctx) + legacy_network_delete(ctx=_ctx) diff --git a/vcloud_network_plugin/server.py b/vcloud_server_plugin/server.py similarity index 100% rename from vcloud_network_plugin/server.py rename to vcloud_server_plugin/server.py From b688af04050880ad1b617fa8f82b816b30e29c90 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 26 Oct 2021 13:17:32 -0400 Subject: [PATCH 04/58] have tests --- cloudify_vcd/legacy/compute/tasks.py | 41 ++-- cloudify_vcd/legacy/decorators.py | 5 +- cloudify_vcd/legacy/network/tasks.py | 19 +- cloudify_vcd/legacy/tests/__init__.py | 4 +- cloudify_vcd/legacy/utils.py | 253 +++++++++++++++++++- cloudify_vcd/network_tasks.py | 12 +- cloudify_vcd/utils.py | 3 +- cloudify_vcd/vapp_tasks.py | 20 +- plugin.yaml | 8 +- test-requirements.txt | 1 + tox.ini | 8 +- vcd_plugin_sdk/resources/network.py | 7 + vcd_plugin_sdk/resources/vapp.py | 8 + vcloud_network_plugin/port.py | 2 + vcloud_network_plugin/tests/test_network.py | 55 ++++- vcloud_server_plugin/server.py | 7 +- vcloud_server_plugin/tests/test_server.py | 251 +++++++++++++++++++ 17 files changed, 644 insertions(+), 60 deletions(-) create mode 100644 vcloud_server_plugin/tests/test_server.py diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 68745bb..61cc965 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -23,14 +23,17 @@ @decorators.with_vcd_client() @decorators.with_vm_resource() def create_server(vm_client, ctx, **_): - exists = vm_client.get() - if not skip(type(vm_client), vm_client.name, exists): + if not skip(type(vm_client), + vm_client.name, + ctx, + exists=vm_client.exists, + create_operation=True): return vapp_tasks._create_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc_name, - vm_config=vm_client.kwargs, + vm_config=vm_client.vapp_object.kwargs, vm_class=VCloudVM, vm_ctx=ctx) @@ -38,8 +41,10 @@ def create_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() def configure_server(vm_client, ctx, **_): - exists = vm_client.get() - if not skip(type(vm_client), vm_client.name, exists): + if not skip(type(vm_client), + vm_client.name, + ctx, + exists=vm_client.exists): return vapp_tasks._configure_vm( vm_external=False, vm_id=vm_client.name, @@ -53,8 +58,10 @@ def configure_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() def start_server(vm_client, ctx, **_): - exists = vm_client.get() - if not skip(type(vm_client), vm_client.name, exists): + if not skip(type(vm_client), + vm_client.name, + ctx, + exists=vm_client.exists): return vapp_tasks._start_vm( vm_external=False, vm_id=vm_client.name, @@ -67,10 +74,12 @@ def start_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() -def delete_server(vm_client, ctx, **_): - exists = vm_client.get() - if not skip(type(vm_client), vm_client.name, exists): - return vapp_tasks._delete_vm( +def stop_server(vm_client, ctx, **_): + if not skip(type(vm_client), + vm_client.name, + ctx, + exists=vm_client.exists): + return vapp_tasks._stop_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, @@ -82,10 +91,12 @@ def delete_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() -def stop_server(vm_client, ctx, **_): - exists = vm_client.get() - if not skip(type(vm_client), vm_client.name, exists): - return vapp_tasks._stop_vm( +def delete_server(vm_client, ctx, **_): + if not skip(type(vm_client), + vm_client.name, + vm_client.exists, + delete_operation=True): + return vapp_tasks._delete_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py index 8ecb642..effd485 100644 --- a/cloudify_vcd/legacy/decorators.py +++ b/cloudify_vcd/legacy/decorators.py @@ -92,11 +92,14 @@ def wrapper_outer(func): def wrapper_inner(*args, **kwargs): """ Initializes the gateway object with connection and the translated - configuration from network property. + configuration from vm property. :param args: :param kwargs: :return: """ + _ctx_node = get_ctx_node() + if 'server' not in kwargs: + kwargs['server'] = _ctx_node.properties['server'] client = utils.get_vm_client(**kwargs) kwargs['vm_client'] = client return func(*args, **kwargs) diff --git a/cloudify_vcd/legacy/network/tasks.py b/cloudify_vcd/legacy/network/tasks.py index 5a04562..989e456 100644 --- a/cloudify_vcd/legacy/network/tasks.py +++ b/cloudify_vcd/legacy/network/tasks.py @@ -29,17 +29,17 @@ class MissingGateway(NonRecoverableError): @decorators.with_network_resource() @decorators.with_gateway_resource() def create_network(network_client, gateway_client, ctx, **_): - gateway_exists = gateway_client.gateway if network_client.network_type == 'routed_vdc_network' and \ - not gateway_exists: + not gateway_client.gateway: raise MissingGateway( 'The provided gateway {} does not exist.'.format( gateway_client.name)) - exists = network_client.network if not skip(network_client.network_type, network_client.name, - exists=exists): - return network_tasks._delete_network( + ctx, + exists=network_client.exists, + create_operation=True): + return network_tasks._create_network( external_network=False, network_id=network_client.name, network_client=network_client.connection, @@ -51,11 +51,12 @@ def create_network(network_client, gateway_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_network_resource() -@decorators.with_gateway_resource() def delete_network(network_client, ctx, **_): - exists = network_client.network - if not skip( - network_client.network_type, network_client.name, exists=exists): + if not skip(network_client.network_type, + network_client.name, + ctx, + exists=network_client.exists, + delete_operation=True): return network_tasks._delete_network( external_network=False, network_id=network_client.name, diff --git a/cloudify_vcd/legacy/tests/__init__.py b/cloudify_vcd/legacy/tests/__init__.py index 165ced3..63d98e4 100644 --- a/cloudify_vcd/legacy/tests/__init__.py +++ b/cloudify_vcd/legacy/tests/__init__.py @@ -61,7 +61,7 @@ def create_ctx(node_id, 'name': operation_name, 'retry': 0, } - return MockCloudifyContext( + mock_ctx = MockCloudifyContext( node_id=node_id, node_name=node_id, node_type=node_type, @@ -70,3 +70,5 @@ def create_ctx(node_id, relationships=relationships, operation=operation ) + mock_ctx.node.type_hierarchy = type_hierarchy + return mock_ctx diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 5f4355c..0070126 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -12,6 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import ipaddress +from copy import deepcopy + +from ..utils import ( + find_rels_by_type, + find_resource_id_from_relationship_by_type) + from vcd_plugin_sdk.resources.vapp import VCloudVM from vcd_plugin_sdk.connection import VCloudConnect from vcd_plugin_sdk.resources.network import VCloudNetwork, VCloudGateway @@ -22,6 +29,31 @@ get_ctx_instance) +OLD_NETWORK_KEYS = [ + 'dns', + 'name', + 'dhcp', + 'netmask', + 'gateway_ip', + 'dns_suffix', + 'static_range', + 'edge_gateway' +] +OLD_PORT_KEYS = [ + 'network', + 'mac_address', + 'primary_interface', + 'ip_allocation_mode' +] +OLD_VM_KEYS = [ + 'name', + 'hardware', + 'guest_customization', +] +PORT_NET_REL = 'cloudify.vcloud.port_connected_to_network' +VM_NIC_REL = 'cloudify.vcloud.server_connected_to_port' + + class RequiredClientKeyMissing(NonRecoverableError): def __init__(self, key, *args, **kwargs): msg = 'Required vcloud config key "{}" not provided.'.format(key) @@ -35,6 +67,7 @@ def get_function_return(func_ret): def get_vcloud_cx(client_config, logger): + client_config = deepcopy(client_config) for bad, good in [('username', 'user'), ('ssl_verify', 'verify_ssl_certs')]: if bad in client_config: @@ -85,26 +118,57 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): _ctx_instance = get_ctx_instance(ctx) if 'edge_gateway' in vcloud_config: - network_type = 'routed_vdc_network' network['gateway_name'] = vcloud_config['edge_gateway'] + network_type = 'routed_vdc_network' else: network_type = 'isolated_vdc_network' tasks = _ctx_instance.runtime_properties.get('__TASKS', []) + if 'name' in network: + network_name = network.pop('name') + else: + network_name = _ctx_node.properties.get( + 'resource_id', _ctx_instance.id) + + network = convert_network_config(network) new_network_config = { - 'network_name': _ctx_node.properties.get( - 'resource_id', _ctx_instance.id), + 'network_name': network_name, 'network_type': network_type, 'connection': vcloud_cx, 'vdc_name': vcloud_config.get('vdc'), 'kwargs': network, 'tasks': tasks } - return VCloudNetwork(**new_network_config) +def get_port_client(port, vcloud_cx, vcloud_config, ctx, **kwargs): + """ + :param port: + :param vcloud_cx: + :param vcloud_config: + :param ctx: + :param kwargs: + :return: + """ + + _node_instance = get_ctx_instance(ctx) + + if 'network' in port: + network = port.pop('network') + else: + network = find_resource_id_from_relationship_by_type( + _node_instance, PORT_NET_REL) + + port = convert_port_config(port) + if 'is_connected' not in port: + # TODO: Decide what to do here. + pass + _node_instance.runtime_properties['network'] = network + _node_instance.runtime_properties['port'] = port + + def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): _ctx_instance = get_ctx_instance(ctx) tasks = _ctx_instance.runtime_properties.get('__TASKS', []) @@ -118,12 +182,187 @@ def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): ) -def get_vm_client(vcloud_cx, vcloud_config, ctx): +def get_vm_client(server, vcloud_cx, vcloud_config, ctx): _ctx_node = get_ctx_node(ctx) _ctx_instance = get_ctx_instance(ctx) - name = _ctx_node.properties.get('resource_id', _ctx_instance.id) + name = server.pop( + 'name', _ctx_node.properties.get('resource_id', _ctx_instance.id)) + tasks = _ctx_instance.runtime_properties.get('__TASKS', []) + convert_vm_config(server) + get_server_network(server, _ctx_node, _ctx_instance) return VCloudVM(name, name, connection=vcloud_cx, vdc_name=vcloud_config.get('vdc'), - tasks=_ctx_instance.runtime_properties['__TASKS']) + kwargs={}, + vapp_kwargs=server, + tasks=tasks) + + +def get_server_network(server, _ctx_node, _ctx_instance): + rel = None + server_network_adapter = 'VMXNET3' + + if 'network' not in server and \ + 'management_network_name' in _ctx_node.properties: + server['network'] = _ctx_node.properties['management_network_name'] + elif 'netwokr' not in server: + for rel in find_rels_by_type(_ctx_instance, VM_NIC_REL): + if rel.node.properties['port']['primary_interface']: + break + if rel: + server['network'] = rel.instance.runtime_properties.get( + 'network_name') + + if 'network_adapter_type' not in server and rel: + server['network_adapter_type'] = \ + rel.instance.runtime_properties['__future_config'].get( + 'adapter_type', server_network_adapter) + elif 'network_adapter_type' not in server: + server['network_adapter_type'] = server_network_adapter + + if 'ip_address' not in server and rel: + ip_address = rel.instance.runtime_properties['__future_config'].get( + 'ip_address') + if ip_address: + server['ip_address'] = ip_address + + +def convert_network_config(config): + + if 'network_cidr' not in config: + cidr = get_network_cidr(config) + if cidr: + config['network_cidr'] = cidr + + if 'ip_range_start' not in config or 'ip_range_end' not in config: + ip_range_start, ip_range_end = get_ip_range(config) + config['ip_range_start'] = ip_range_start.compressed + config['ip_range_end'] = ip_range_end.compressed + + if 'dns' in config: + primary_ip, secondary_ip = get_dns_ips(config['dns']) + config['primary_dns_ip'] = primary_ip + config['secondary_dns_ip'] = secondary_ip + + for key in OLD_NETWORK_KEYS: + config.pop(key, None) + + return config + + +def get_start_end_ip_config(config=None): + start = None + end = None + if config: + start, end = config.split('-') + start = ipaddress.IPv4Address(start) + end = ipaddress.IPv4Address(end) + return start, end + + +def get_gateway_ip(config): + gateway_ip = config.get('gateway_ip') + if gateway_ip: + return ipaddress.IPv4Address(gateway_ip) + + +def get_ip_range(config): + start_static, end_static = get_start_end_ip_config( + config.get('static_range')) + start_dhcp, end_dhcp = get_start_end_ip_config(config.get('dhcp_range')) + start_list = sorted( + [n for n in [start_static, start_dhcp] if n]) + if start_list: + start = start_list[-1] + else: + return None, None + end_list = sorted([n for n in [end_static, end_dhcp] if n]) + if end_list: + end = end_list[-1] + else: + return None, None + return start, end + + +def get_network_cidr(config): + """ + A naive way to generate a CIDR from old style network configuration. + :param config: + :return: + """ + start, end = get_ip_range(config) + gateway_ip = get_gateway_ip(config) + netmask = config.get('netmask') + if netmask: + netmask = ipaddress.IPv4Address('0.0.0.0/{}'.format(netmask)) + if gateway_ip: + start = gateway_ip + ip_range = [addr for addr in ipaddress.summarize_address_range(start, end)] + if len(ip_range) >= 1: + if netmask: + return '{}/{}'.format( + ip_range[0].network_address, netmask.prefixlen) + return ip_range[0].compressed + + +def get_dns_ips(ips): + if len(ips) > 1: + return ips[0], ips[1] + return ips[0], None + + +def convert_port_config(config): + """Convert something like this: + port: + network: { get_input: RSP_VRS2_APP_EXT_PROXY_network_name } + ip_allocation_mode: manual + ip_address: { get_input: RSP_VRS2_APP_EXT_PROXY } + primary_interface: false + To this: + adapter_type: 'VMXNET3' + is_primary: false + is_connected: false + ip_address_mode: 'MANUAL' + ip_address: '192.179.2.2' + :param config: + :return: + """ + + if 'ip_allocation_mode' in config: + config['ip_address_mode'] = config.pop('ip_allocation_mode').upper() + + if 'primary_interface' in config: + config['is_primary'] = config.pop('primary_interface') + + for key in OLD_PORT_KEYS: + config.pop(key, None) + + return config + + +def convert_vapp_config(config): + return { + 'fence_mode': config.get('fence_mode', 'bridged'), + 'accept_all_eulas': config.get('accept_all_eulas', True) + } + + +def convert_vm_config(config): + if 'hardware' in config: + if 'memory' in config['hardware']: + config['memory'] = config['hardware']['memory'] + if 'cpus' in config['hardware']: + config['cpus'] = config['hardware']['cpu'] + if 'guest_customization' in config: + if 'admin_password' in config['guest_customization']: + config['password'] = \ + config['guest_customization']['admin_password'] + if 'computer_name' in config: + config['hostname'] = \ + config['guest_customization']['computer_name'] + + config.update(convert_vapp_config(config)) + + for key in OLD_VM_KEYS: + config.pop(key, None) diff --git a/cloudify_vcd/network_tasks.py b/cloudify_vcd/network_tasks.py index 7f52ec5..66f089f 100644 --- a/cloudify_vcd/network_tasks.py +++ b/cloudify_vcd/network_tasks.py @@ -12,11 +12,14 @@ } -def get_network_type(types): +def get_network_type(types, config=None): for node_type in types: network_type = NETWORK_TYPES.get(node_type) if network_type: return network_type + config = config or {} + if 'gateway_name' in config: + return 'routed_vdc_network' @resource_operation @@ -38,9 +41,10 @@ def _create_network(external_network, if network and 'network_name' not in network_config: network_config['network_name'] = network + network_type = get_network_type(ctx.node.type_hierarchy, network_config) network = network_class( network_id, - get_network_type(ctx.node.type_hierarchy), + network_type, network_client, network_vdc, kwargs=network_config) @@ -64,9 +68,11 @@ def _delete_network(external_network, ctx, **___): + network_type = get_network_type(ctx.node.type_hierarchy, network_config) + network = network_class( network_id, - get_network_type(ctx.node.type_hierarchy), + network_type, network_client, network_vdc, kwargs=network_config) diff --git a/cloudify_vcd/utils.py b/cloudify_vcd/utils.py index 84a9f2e..c83a85b 100644 --- a/cloudify_vcd/utils.py +++ b/cloudify_vcd/utils.py @@ -389,7 +389,8 @@ def find_rel_by_type(node_instance, rel_type): def find_resource_id_from_relationship_by_type(node_instance, rel_type): rel = find_rel_by_type(node_instance, rel_type) - return rel.target.instance.runtime_properties.get('resource_id') + if rel: + return rel.target.instance.runtime_properties.get('resource_id') def use_external_resource(external, diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index f109e1a..d7cd601 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -29,14 +29,18 @@ @resource_operation -def create_vapp(_, - vapp_id, - vapp_client, - vapp_vdc, - vapp_config, - vapp_class, - vapp_ctx, - **___): +def create_vapp(*args, **kwargs): + return _create_vapp(*args, **kwargs) + + +def _create_vapp(_, + vapp_id, + vapp_client, + vapp_vdc, + vapp_config, + vapp_class, + vapp_ctx, + **___): """ At the moment this function does nothing substantial. Creating vApps happens during VM create. diff --git a/plugin.yaml b/plugin.yaml index 27d97a0..bd398be 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -269,8 +269,12 @@ node_types: default: {} interfaces: cloudify.interfaces.lifecycle: - configure: - implementation: vcd.cloudify_vcd.legacy.compute.tasks.configure_nic + create: + implementation: vcloud.vcloud_network_plugin.port.creation_validation + inputs: {} + delete: + implementation: vcloud.vcloud_network_plugin.port.delete + inputs: {} cloudify.vcloud.nodes.Network: derived_from: cloudify.nodes.Network diff --git a/test-requirements.txt b/test-requirements.txt index a594f94..99df67e 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,3 +1,4 @@ mock pytest flake8 +https://github.com/cloudify-incubator/cloudify-utilities-plugins-sdk/archive/refs/heads/add-explicit-delete-logic.zip diff --git a/tox.ini b/tox.ini index 71e80a4..62f0e39 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = nosetest,flake8 +envlist = pytest,flake8 minversion = 1.6 skipsdist = True @@ -18,13 +18,11 @@ whitelist_externals = bash [testenv:flake8] commands = - flake8 cloudify_vcd vcd_plugin_sdk vcloud_network_plugin + flake8 cloudify_vcd vcd_plugin_sdk vcloud_network_plugin vcloud_server_plugin [testenv:pytest] commands = - pytest cloudify_vcd - pytest vcd_plugin_sdk - pytest vcloud_network_plugin + pytest -s -v cloudify_vcd vcd_plugin_sdk vcloud_network_plugin vcloud_server_plugin [testenv:venv] commands = {posargs} diff --git a/vcd_plugin_sdk/resources/network.py b/vcd_plugin_sdk/resources/network.py index 9c394c2..7606c36 100644 --- a/vcd_plugin_sdk/resources/network.py +++ b/vcd_plugin_sdk/resources/network.py @@ -76,6 +76,13 @@ def network(self): sleep(5) return self._network + @property + def exists(self): + try: + return self.network + except VCloudSDKException: + return False + @property def allocated_addresses(self): # In busy environments, this can be pretty testy. diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index d50a503..809582a 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -204,6 +204,14 @@ def vm(self): self._vm.reload() return self._vm + @property + def exists(self): + try: + return self.vm + except EntityNotFoundException: + pass + return False + @property def nics(self): return self.vm.list_nics() diff --git a/vcloud_network_plugin/port.py b/vcloud_network_plugin/port.py index e58238d..89eaf52 100644 --- a/vcloud_network_plugin/port.py +++ b/vcloud_network_plugin/port.py @@ -14,6 +14,8 @@ from cloudify.decorators import operation +# TODO: We need to add add_network, add_nic, and remove_nic, after we do VM. + @operation(resumable=True) def creation_validation(port, *args, **kwargs): diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py index e6edcf4..95c6655 100644 --- a/vcloud_network_plugin/tests/test_network.py +++ b/vcloud_network_plugin/tests/test_network.py @@ -16,8 +16,7 @@ from copy import deepcopy from cloudify.state import current_ctx -from .. network import create as legacy_network_create -from .. network import delete as legacy_network_delete +from .. network import create, delete from cloudify_vcd.legacy.tests import create_ctx, DEFAULT_NODE_PROPS @@ -34,7 +33,11 @@ def get_network_ctx(existing=False, :return: """ - network = network or {} + network = network or { + 'static_range': '10.10.0.2-10.10.0.128', + 'gateway_ip': '10.10.0.1' + } + network_node_props = {'network': network} network_node_props.update( deepcopy(DEFAULT_NODE_PROPS)) @@ -59,7 +62,7 @@ def test_create_external_network_with_gateway(*_, **__): ], node_properties=network_node_props) current_ctx.set(_ctx) - legacy_network_create(ctx=_ctx) + create(ctx=_ctx) @patch('vcd_plugin_sdk.connection.Org', autospec=True) @@ -76,4 +79,46 @@ def test_delete_external_network_with_gateway(*_, **__): ], node_properties=network_node_props) current_ctx.set(_ctx) - legacy_network_delete(ctx=_ctx) + delete(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +@patch('vcd_plugin_sdk.resources.network.VCloudNetwork.get_network', + return_value=False) +def test_create_network_with_gateway(*_, **__): + network_node_props = get_network_ctx(resource_id='foo', gateway='baz') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Network', + 'cloudify.vcloud.nodes.Network' + ], + node_properties=network_node_props) + current_ctx.set(_ctx) + create(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_delete_network_with_gateway(*_, **__): + network_node_props = get_network_ctx(resource_id='foo', gateway='baz') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Network', + 'cloudify.vcloud.nodes.Network' + ], + node_properties=network_node_props, + operation_name='cloudify.interfaces.lifecycle.delete') + current_ctx.set(_ctx) + delete(ctx=_ctx) diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index 4f1ce12..7411df7 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -17,8 +17,9 @@ create_server, configure_server, start_server, - stop_sterver, - delete_server) + stop_server, + delete_server, +) @operation(resumable=True) @@ -38,7 +39,7 @@ def start(*args, **kwargs): @operation(resumable=True) def stop(*args, **kwargs): - stop_sterver(*args, **kwargs) + stop_server(*args, **kwargs) @operation(resumable=True) diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py new file mode 100644 index 0000000..e04f339 --- /dev/null +++ b/vcloud_server_plugin/tests/test_server.py @@ -0,0 +1,251 @@ +# Copyright (c) 2020 Cloudify Platform Ltd. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from mock import patch +from copy import deepcopy +from cloudify.state import current_ctx + +from .. server import create, delete, configure, start, stop +from cloudify_vcd.legacy.tests import create_ctx, DEFAULT_NODE_PROPS + + +def get_vm_ctx(existing=False, + resource_id=None, + server=None): + """ + Generate the node props for use in the test. + :param existing: whether to create or not + :param resource_id: name of the resource + :param server: the server resource config + :param gateway: name of the edge gateway + :return: + """ + server = server or { + 'name': 'foo', + 'catalog': 'acme', + 'template': 'taco', + 'hardware': { + 'memory': 1024, + 'cpu': 1, + }, + 'guest_customization': { + 'computer_name': 'bar' + } + + } + server_node_props = {'server': server} + server_node_props.update( + deepcopy(DEFAULT_NODE_PROPS)) + server_node_props['use_external_resource'] = existing + server_node_props['resource_id'] = resource_id + return server_node_props + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_create_external_vm(*_, **__): + server_node_props = get_vm_ctx(True, 'foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + create(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.get_vm') +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_delete_external_vm(*_, **__): + server_node_props = get_vm_ctx(True, 'foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + delete(ctx=_ctx) + + +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) +def test_configure_external_vm(*_, **__): + server_node_props = get_vm_ctx(True, 'foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + configure(ctx=_ctx) + + +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) +def test_start_external_vm(*_, **__): + server_node_props = get_vm_ctx(True, 'foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + start(ctx=_ctx) + + +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) +def test_stop_external_vm(*_, **__): + server_node_props = get_vm_ctx(True, 'foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + stop(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_create_vm(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + create(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_configure_vm(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + configure(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_start_vm(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + start(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_stop_vm(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + stop(ctx=_ctx) + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.get_vm') +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_delete_vm(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + delete(ctx=_ctx) From 6684660251ca91026f30b0fff27e1d1625b9761e Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 26 Oct 2021 18:06:06 -0400 Subject: [PATCH 05/58] more stuff that has working tests --- cloudify_vcd/legacy/compute/tasks.py | 130 ++++-- cloudify_vcd/legacy/decorators.py | 20 + cloudify_vcd/legacy/network/tasks.py | 2 + cloudify_vcd/legacy/tests/__init__.py | 23 +- cloudify_vcd/legacy/utils.py | 27 +- cloudify_vcd/vapp_tasks.py | 220 ++++----- vcloud_network_plugin/port.py | 11 +- vcloud_network_plugin/tests/test_network.py | 4 + vcloud_network_plugin/tests/test_port.py | 62 +++ vcloud_server_plugin/server.py | 6 + vcloud_server_plugin/tests/test_server.py | 468 +++++++++++++++++++- 11 files changed, 809 insertions(+), 164 deletions(-) create mode 100644 vcloud_network_plugin/tests/test_port.py diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 61cc965..b1dee9b 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -12,12 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +from cloudify.exceptions import OperationRetry + from vcd_plugin_sdk.resources.vapp import VCloudVM -from cloudify_common_sdk.utils import \ - skip_creative_or_destructive_operation as skip +from cloudify_common_sdk.utils import ( + get_ctx_instance, + skip_creative_or_destructive_operation as skip) from .. import decorators from ... import vapp_tasks +from ..utils import VM_NIC_REL +from ...utils import ( + get_last_task, + find_rels_by_type, + check_if_task_successful) @decorators.with_vcd_client() @@ -41,72 +49,122 @@ def create_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() def configure_server(vm_client, ctx, **_): + return vapp_tasks._configure_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc_name, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def start_server(vm_client, ctx, **_): + return vapp_tasks._start_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def stop_server(vm_client, ctx, **_): + return vapp_tasks._stop_vm( + vm_external=False, + vm_id=vm_client.name, + vm_client=vm_client.connection, + vm_vdc=vm_client.vdc, + vm_config=vm_client.kwargs, + vm_class=VCloudVM, + vm_ctx=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def delete_server(vm_client, ctx, **_): if not skip(type(vm_client), vm_client.name, - ctx, - exists=vm_client.exists): - return vapp_tasks._configure_vm( + exists=vm_client.exists, + delete_operation=True): + return vapp_tasks._delete_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc_name, + vm_vdc=vm_client.vdc, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) +@decorators.with_port_resource() +def port_creation_validation(*_, **__): + pass + + @decorators.with_vcd_client() @decorators.with_vm_resource() -def start_server(vm_client, ctx, **_): - if not skip(type(vm_client), - vm_client.name, - ctx, - exists=vm_client.exists): - return vapp_tasks._start_vm( - vm_external=False, +def preconfigure_nic(vm_client, ctx, **kwargs): + for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): + resource, result = vapp_tasks._add_network( + nic_config=port_ctx.instance.runtime_properties['port'], + nic_ctx=port_ctx, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc, vm_config=vm_client.kwargs, vm_class=VCloudVM, - vm_ctx=ctx) + vm_ctx=ctx, + **kwargs) + last_task = get_last_task(result) + if not check_if_task_successful(resource, last_task): + port_ctx.instance.runtime_properties['__RETRY_BAD_REQUEST'] = \ + True + raise OperationRetry('Pending for operation completion.') @decorators.with_vcd_client() @decorators.with_vm_resource() -def stop_server(vm_client, ctx, **_): - if not skip(type(vm_client), - vm_client.name, - ctx, - exists=vm_client.exists): - return vapp_tasks._stop_vm( - vm_external=False, +def postconfigure_nic(vm_client, ctx, **kwargs): + for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): + resource, result = vapp_tasks._add_nic( + nic_config=port_ctx.instance.runtime_properties['port'], + nic_ctx=port_ctx, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc, vm_config=vm_client.kwargs, vm_class=VCloudVM, - vm_ctx=ctx) + vm_ctx=ctx, + **kwargs) + last_task = get_last_task(result) + if not check_if_task_successful(resource, last_task): + port_ctx.instance.runtime_properties['__RETRY_BAD_REQUEST'] = \ + True + raise OperationRetry('Pending for operation completion.') @decorators.with_vcd_client() @decorators.with_vm_resource() -def delete_server(vm_client, ctx, **_): - if not skip(type(vm_client), - vm_client.name, - vm_client.exists, - delete_operation=True): - return vapp_tasks._delete_vm( - vm_external=False, +def unlink_nic(vm_client, ctx, **kwargs): + for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): + resource, result = vapp_tasks._delete_nic( + nic_config=port_ctx.instance.runtime_properties['port'], + nic_ctx=port_ctx, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc, vm_config=vm_client.kwargs, vm_class=VCloudVM, - vm_ctx=ctx) - - -def configure_nic(ctx, **_): - ctx.logger.info('Storing') - return vapp_tasks._configure_nic( - nic_config=ctx.node.properties['port'], nic_ctx=ctx) + vm_ctx=ctx, + **kwargs) + last_task = get_last_task(result) + if not check_if_task_successful(resource, last_task): + port_ctx.instance.runtime_properties['__RETRY_BAD_REQUEST'] = \ + True + raise OperationRetry('Pending for operation completion.') diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py index effd485..ce8f4d4 100644 --- a/cloudify_vcd/legacy/decorators.py +++ b/cloudify_vcd/legacy/decorators.py @@ -105,3 +105,23 @@ def wrapper_inner(*args, **kwargs): return func(*args, **kwargs) return wrapper_inner return wrapper_outer + + +def with_port_resource(): + def wrapper_outer(func): + @wraps(func) + def wrapper_inner(*args, **kwargs): + """ + Initializes the gateway object with connection and the translated + configuration from vm property. + :param args: + :param kwargs: + :return: + """ + _ctx_node = get_ctx_node() + if 'port' not in kwargs: + kwargs['port'] = _ctx_node.properties['port'] + utils.get_port_config(**kwargs) + return func(*args, **kwargs) + return wrapper_inner + return wrapper_outer diff --git a/cloudify_vcd/legacy/network/tasks.py b/cloudify_vcd/legacy/network/tasks.py index 989e456..d0be8cd 100644 --- a/cloudify_vcd/legacy/network/tasks.py +++ b/cloudify_vcd/legacy/network/tasks.py @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. + from cloudify.exceptions import NonRecoverableError + from vcd_plugin_sdk.resources.network import VCloudNetwork from cloudify_common_sdk.utils import \ skip_creative_or_destructive_operation as skip diff --git a/cloudify_vcd/legacy/tests/__init__.py b/cloudify_vcd/legacy/tests/__init__.py index 63d98e4..53ed7e5 100644 --- a/cloudify_vcd/legacy/tests/__init__.py +++ b/cloudify_vcd/legacy/tests/__init__.py @@ -12,7 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cloudify.mocks import MockCloudifyContext +from cloudify.mocks import MockNodeContext, MockCloudifyContext + + +class CorrectedMockNodeContext(MockNodeContext): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.type_hierarchy = self.type + + +class CorrectedMockCloudifyContext(MockCloudifyContext): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + node_name = kwargs.get('node_name') + properties = kwargs.get('properties') + node_type = kwargs.get('node_type') + self._node = CorrectedMockNodeContext( + node_name, properties, node_type) + self.type_hierarchy = self.type DEFAULT_NODE_PROPS = { @@ -61,7 +79,7 @@ def create_ctx(node_id, 'name': operation_name, 'retry': 0, } - mock_ctx = MockCloudifyContext( + mock_ctx = CorrectedMockCloudifyContext( node_id=node_id, node_name=node_id, node_type=node_type, @@ -70,5 +88,4 @@ def create_ctx(node_id, relationships=relationships, operation=operation ) - mock_ctx.node.type_hierarchy = type_hierarchy return mock_ctx diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 0070126..3232db6 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -126,12 +126,17 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): tasks = _ctx_instance.runtime_properties.get('__TASKS', []) if 'name' in network: network_name = network.pop('name') + elif 'resource_id' in _ctx_instance.runtime_properties: + network_name = _ctx_instance.runtime_properties['resource_id'] else: network_name = _ctx_node.properties.get( 'resource_id', _ctx_instance.id) network = convert_network_config(network) + _ctx_instance.runtime_properties['resource_id'] = network_name + _ctx_instance.runtime_properties['network'] = network + new_network_config = { 'network_name': network_name, 'network_type': network_type, @@ -143,7 +148,7 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): return VCloudNetwork(**new_network_config) -def get_port_client(port, vcloud_cx, vcloud_config, ctx, **kwargs): +def get_port_config(port, ctx, **kwargs): """ :param port: :param vcloud_cx: @@ -185,11 +190,17 @@ def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): def get_vm_client(server, vcloud_cx, vcloud_config, ctx): _ctx_node = get_ctx_node(ctx) _ctx_instance = get_ctx_instance(ctx) - name = server.pop( - 'name', _ctx_node.properties.get('resource_id', _ctx_instance.id)) + if 'name' in server: + name = server.pop('name') + elif 'name' in _ctx_instance.runtime_properties: + name = _ctx_instance.runtime_properties['name'] + else: + name = _ctx_node.properties.get('resource_id', _ctx_instance.id) tasks = _ctx_instance.runtime_properties.get('__TASKS', []) convert_vm_config(server) get_server_network(server, _ctx_node, _ctx_instance) + _ctx_instance.runtime_properties['resource_id'] = name + _ctx_instance.runtime_properties['server'] = server return VCloudVM(name, name, connection=vcloud_cx, @@ -206,23 +217,23 @@ def get_server_network(server, _ctx_node, _ctx_instance): if 'network' not in server and \ 'management_network_name' in _ctx_node.properties: server['network'] = _ctx_node.properties['management_network_name'] - elif 'netwokr' not in server: + elif 'network' not in server: for rel in find_rels_by_type(_ctx_instance, VM_NIC_REL): - if rel.node.properties['port']['primary_interface']: + if rel.target.node.properties['port'].get('primary_interface'): break if rel: - server['network'] = rel.instance.runtime_properties.get( + server['network'] = rel.target.instance.runtime_properties.get( 'network_name') if 'network_adapter_type' not in server and rel: server['network_adapter_type'] = \ - rel.instance.runtime_properties['__future_config'].get( + rel.target.instance.runtime_properties['port'].get( 'adapter_type', server_network_adapter) elif 'network_adapter_type' not in server: server['network_adapter_type'] = server_network_adapter if 'ip_address' not in server and rel: - ip_address = rel.instance.runtime_properties['__future_config'].get( + ip_address = rel.target.instance.runtime_properties['port'].get( 'ip_address') if ip_address: server['ip_address'] = ip_address diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index d7cd601..61cfe9c 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -33,13 +33,13 @@ def create_vapp(*args, **kwargs): return _create_vapp(*args, **kwargs) -def _create_vapp(_, - vapp_id, - vapp_client, - vapp_vdc, - vapp_config, - vapp_class, - vapp_ctx, +def _create_vapp(_=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + vapp_ctx=None, **___): """ At the moment this function does nothing substantial. @@ -77,13 +77,13 @@ def _create_vapp(_, @resource_operation -def stop_vapp(vapp_ext, - vapp_id, - vapp_client, - vapp_vdc, - vapp_config, - vapp_class, - __, +def stop_vapp(vapp_ext=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + __=None, **___): """ Perform undeploy operation on a vApp. @@ -111,13 +111,13 @@ def stop_vapp(vapp_ext, @resource_operation -def power_off_vapp(vapp_ext, - vapp_id, - vapp_client, - vapp_vdc, - vapp_config, - vapp_class, - __, +def power_off_vapp(vapp_ext=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + __=None, **___): """ Execute power off on the vApp before deletion. @@ -151,13 +151,13 @@ def power_off_vapp(vapp_ext, @resource_operation -def delete_vapp(vapp_ext, - vapp_id, - vapp_client, - vapp_vdc, - vapp_config, - vapp_class, - __, +def delete_vapp(vapp_ext=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + __=None, **___): """ Delete a vApp. @@ -194,13 +194,13 @@ def create_vm(*args, **kwargs): return _create_vm(*args, **kwargs) -def _create_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _create_vm(vm_external=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **_): """ @@ -244,7 +244,7 @@ def _create_vm(vm_external, vm = vm_class( vm_id, - vapp_name, + vapp_name or vm_id, vm_client, vdc_name=vm_vdc, kwargs={}, @@ -281,13 +281,13 @@ def configure_vm(*args, **kwargs): return _configure_vm(*args, **kwargs) -def _configure_vm(_, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _configure_vm(_=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **__): vapp_name = find_resource_id_from_relationship_by_type( @@ -307,13 +307,13 @@ def start_vm(*args, **kwargs): return _start_vm(*args, **kwargs) -def _start_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _start_vm(vm_external=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **__): """ Power on both existing and new VMs. @@ -365,13 +365,13 @@ def stop_vm(*args, **kwargs): return _stop_vm(*args, **kwargs) -def _stop_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _stop_vm(vm_external=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **__): """ @@ -418,13 +418,13 @@ def delete_vm(*args, **kwargs): return _delete_vm(*args, **kwargs) -def _delete_vm(vm_external, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _delete_vm(vm_external=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **__): """ @@ -510,20 +510,20 @@ def add_network(*args, **kwargs): return _add_network(*args, **kwargs) -def _add_network(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - ______, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _add_network(_=None, + __=None, + ___=None, + ____=None, + nic_config=None, + _____=None, + nic_ctx=None, + ______=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **_______): """Add a network to a VM. @@ -551,8 +551,12 @@ def _add_network(_, nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) vapp_node = find_rel_by_type(vm_ctx.instance, REL_VM_VAPP) - fence_mode = vapp_node.target.node.properties['resource_config'].get( - 'fence_mode') + if vapp_node: + fence_mode = vapp_node.target.node.properties['resource_config'].get( + 'fence_mode') + elif 'server' in vm_ctx.instance.runtime_properties: + fence_mode = vm_ctx.instance.runtime_properties['server'].get( + 'fence_mode', 'bridged') if nic_network: nic_config['network_name'] = nic_network @@ -585,20 +589,20 @@ def add_nic(*args, **kwargs): return _add_nic(*args, **kwargs) -def _add_nic(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - ______, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _add_nic(_=None, + __=None, + ___=None, + ____=None, + nic_config=None, + _____=None, + nic_ctx=None, + ______=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **_______): """ Add Nic to VM. @@ -657,20 +661,20 @@ def delete_nic(*args, **kwargs): return _delete_nic(*args, **kwargs) -def _delete_nic(_, - __, - ___, - ____, - nic_config, - _____, - nic_ctx, - ______, - vm_id, - vm_client, - vm_vdc, - vm_config, - vm_class, - vm_ctx, +def _delete_nic(_=None, + __=None, + ___=None, + ____=None, + nic_config=None, + _____=None, + nic_ctx=None, + ______=None, + vm_id=None, + vm_client=None, + vm_vdc=None, + vm_config=None, + vm_class=None, + vm_ctx=None, **_______): """ Delete NIC and remove network from vapp. diff --git a/vcloud_network_plugin/port.py b/vcloud_network_plugin/port.py index 89eaf52..a0da08d 100644 --- a/vcloud_network_plugin/port.py +++ b/vcloud_network_plugin/port.py @@ -13,15 +13,18 @@ # limitations under the License. from cloudify.decorators import operation +from cloudify_vcd.legacy.compute.tasks import port_creation_validation # TODO: We need to add add_network, add_nic, and remove_nic, after we do VM. @operation(resumable=True) -def creation_validation(port, *args, **kwargs): - pass +def creation_validation(*args, **kwargs): + port_creation_validation(*args, **kwargs) @operation(resumable=True) -def delete(*args, **kwargs): - pass +def delete(*_, **kwargs): + _ctx = kwargs.get('ctx') + for key in _ctx.instance.runtime_properties.keys(): + del _ctx.instance.runtime_properties[key] diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py index 95c6655..7cffc6a 100644 --- a/vcloud_network_plugin/tests/test_network.py +++ b/vcloud_network_plugin/tests/test_network.py @@ -63,6 +63,7 @@ def test_create_external_network_with_gateway(*_, **__): node_properties=network_node_props) current_ctx.set(_ctx) create(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' @patch('vcd_plugin_sdk.connection.Org', autospec=True) @@ -80,6 +81,7 @@ def test_delete_external_network_with_gateway(*_, **__): node_properties=network_node_props) current_ctx.set(_ctx) delete(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -101,6 +103,7 @@ def test_create_network_with_gateway(*_, **__): node_properties=network_node_props) current_ctx.set(_ctx) create(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -122,3 +125,4 @@ def test_delete_network_with_gateway(*_, **__): operation_name='cloudify.interfaces.lifecycle.delete') current_ctx.set(_ctx) delete(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' diff --git a/vcloud_network_plugin/tests/test_port.py b/vcloud_network_plugin/tests/test_port.py new file mode 100644 index 0000000..ee284a6 --- /dev/null +++ b/vcloud_network_plugin/tests/test_port.py @@ -0,0 +1,62 @@ +from copy import deepcopy + +from mock import MagicMock +from cloudify.state import current_ctx + +from .. port import creation_validation +from .test_network import get_network_ctx +from cloudify_vcd.legacy.tests import create_ctx, DEFAULT_NODE_PROPS + + +def get_port_ctx(num=None, primary=True): + num = num or '1' + port = { + 'ip_allocation_mode': 'manual', + 'ip_address': '10.10.10.{}'.format(num), + 'primary_interface': primary, + } + port_props = {'port': port} + port_props.update( + deepcopy(DEFAULT_NODE_PROPS)) + return port_props + + +def test_create_external_network_with_gateway(*_, **__): + port_props = get_port_ctx() + net_props = get_network_ctx(resource_id='foo-bar') + _net_ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Network', + 'cloudify.vcloud.nodes.Network' + ], + node_properties=net_props, + runtime_props={ + 'resource_id': net_props['resource_id'], + 'network': net_props['network'] + } + ) + rels = [ + MagicMock( + name='network1', + target=_net_ctx, + type_hierarchy=[ + 'cloudify.vcloud.port_connected_to_network', + 'cloudify.relationships.connected_to' + ] + ), + ] + _ctx = create_ctx( + node_id='external_proxy', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=port_props, + relationships=rels + ) + current_ctx.set(_ctx) + creation_validation(ctx=_ctx) + assert _ctx.instance.runtime_properties['network'] == 'foo-bar' + assert _ctx.instance.runtime_properties['port']['ip_address'] == \ + '10.10.10.1' diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index 7411df7..494fdbf 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -19,6 +19,9 @@ start_server, stop_server, delete_server, + preconfigure_nic, + postconfigure_nic, + unlink_nic ) @@ -29,7 +32,9 @@ def create(*args, **kwargs): @operation(resumable=True) def configure(*args, **kwargs): + preconfigure_nic(*args, **kwargs) configure_server(*args, **kwargs) + postconfigure_nic(*args, **kwargs) @operation(resumable=True) @@ -44,6 +49,7 @@ def stop(*args, **kwargs): @operation(resumable=True) def delete(*args, **kwargs): + unlink_nic(*args, **kwargs) delete_server(*args, **kwargs) diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index e04f339..e3bbbda 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -12,11 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from mock import patch from copy import deepcopy +from mock import patch, MagicMock from cloudify.state import current_ctx from .. server import create, delete, configure, start, stop +from vcloud_network_plugin.tests.test_port import get_port_ctx from cloudify_vcd.legacy.tests import create_ctx, DEFAULT_NODE_PROPS @@ -61,16 +62,18 @@ def get_vm_ctx(existing=False, def test_create_external_vm(*_, **__): server_node_props = get_vm_ctx(True, 'foo') _ctx = create_ctx( - node_id='external_proxy', + node_id='server', node_type=[ 'cloudify.nodes.Compute', 'cloudify.vcloud.nodes.Server' ], - node_properties=server_node_props) + node_properties=server_node_props, + ) current_ctx.set(_ctx) with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') create(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -93,8 +96,10 @@ def test_delete_external_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') delete(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) @@ -111,10 +116,15 @@ def test_configure_external_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') configure(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) def test_start_external_vm(*_, **__): server_node_props = get_vm_ctx(True, 'foo') @@ -129,10 +139,15 @@ def test_start_external_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') start(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) def test_stop_external_vm(*_, **__): server_node_props = get_vm_ctx(True, 'foo') @@ -147,6 +162,7 @@ def test_stop_external_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') stop(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -156,19 +172,222 @@ def test_stop_external_vm(*_, **__): return_value=True) def test_create_vm(*_, **__): server_node_props = get_vm_ctx(resource_id='foo') + _port1_ctx = create_ctx( + node_id='port1', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx(), + runtime_props={ + 'network_name': 'port1_network', + 'port': { + 'ip_address': '10.10.10.1' + } + } + ) + _port2_ctx = create_ctx( + node_id='port2', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx('2', False), + runtime_props={ + 'network_name': 'port2_network', + 'port': { + 'ip_address': '10.10.10.2' + } + } + ) + rels = [ + MagicMock( + name='port1', + target=_port1_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + MagicMock( + name='port2', + target=_port2_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + ] _ctx = create_ctx( - node_id='external_proxy', + node_id='server', node_type=[ 'cloudify.nodes.Compute', 'cloudify.vcloud.nodes.Server' ], - node_properties=server_node_props) + node_properties=server_node_props, + relationships=rels + ) current_ctx.set(_ctx) with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') create(ctx=_ctx) + assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert _ctx.instance.runtime_properties['server']['network'] == \ + 'port1_network' + assert _ctx.instance.runtime_properties['server']['ip_address'] == \ + '10.10.10.1' +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_create_vm_no_primary_port(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _port1_ctx = create_ctx( + node_id='port1', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx(primary=False), + runtime_props={ + 'network_name': 'port1_network', + 'port': { + 'ip_address': '10.10.10.1' + } + } + ) + _port2_ctx = create_ctx( + node_id='port2', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx('2', False), + runtime_props={ + 'network_name': 'port2_network', + 'port': { + 'ip_address': '10.10.10.2' + } + } + ) + rels = [ + MagicMock( + name='port1', + target=_port1_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + MagicMock( + name='port2', + target=_port2_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + ] + _ctx = create_ctx( + node_id='server', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props, + relationships=rels + ) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + create(ctx=_ctx) + assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert _ctx.instance.runtime_properties['server']['network'] == \ + 'port2_network' + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_create_vm_port_network(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _port1_props = get_port_ctx() + _port1_props['port']['network'] = 'port1_port_network' + _port1_ctx = create_ctx( + node_id='port1', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=_port1_props, + runtime_props={ + 'network_name': 'port1_network', + 'port': { + 'ip_address': '10.10.10.5' + } + } + ) + _port2_ctx = create_ctx( + node_id='port2', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx('2', False), + runtime_props={ + 'network_name': 'port2_network', + 'port': { + 'ip_address': '10.10.10.2' + } + } + ) + rels = [ + MagicMock( + name='port1', + target=_port1_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + MagicMock( + name='port2', + target=_port2_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + ] + _ctx = create_ctx( + node_id='server', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props, + relationships=rels + ) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + create(ctx=_ctx) + assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert _ctx.instance.runtime_properties['server']['network'] == \ + 'port1_network' + assert _ctx.instance.runtime_properties['server']['ip_address'] == \ + '10.10.10.5' + + +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -187,8 +406,243 @@ def test_configure_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') configure(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + + +@patch('pyvcloud.vcd.vapp.VApp') +@patch('cloudify_vcd.legacy.compute.tasks.VCloudVM') +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.compute.tasks.get_last_task') +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +@patch('cloudify_vcd.legacy.compute.tasks.check_if_task_successful', + return_value=True) +def test_configure_vm_with_two_ports(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _port1_ctx = create_ctx( + node_id='port1', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx(), + runtime_props={ + 'network_name': 'port1_network', + 'port': { + 'ip_address': '10.10.10.1' + } + } + ) + _port2_ctx = create_ctx( + node_id='port2', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx('2', False), + runtime_props={ + 'network_name': 'port2_network', + 'port': { + 'ip_address': '10.10.10.2' + } + } + ) + rels = [ + MagicMock( + name='port1', + target=_port1_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + MagicMock( + name='port2', + target=_port2_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + ] + _ctx = create_ctx( + node_id='server', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props, + relationships=rels, + operation_name='cloudify.interfaces.lifecycle.configure' + ) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + configure(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert _ctx.instance.runtime_properties['server']['network'] == \ + 'port1_network' + assert _ctx.instance.runtime_properties['server']['ip_address'] == \ + '10.10.10.1' + + +@patch('pyvcloud.vcd.vapp.VApp') +@patch('cloudify_vcd.legacy.compute.tasks.VCloudVM') +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.compute.tasks.get_last_task') +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +@patch('cloudify_vcd.legacy.compute.tasks.check_if_task_successful', + return_value=True) +def test_configure_vm_with_two_ports_and_network_name(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _port1_props = get_port_ctx() + _port1_props['port']['network'] = 'port1_port_network' + _port1_ctx = create_ctx( + node_id='port1', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=_port1_props, + runtime_props={ + 'network_name': 'port1_network', + 'port': { + 'ip_address': '10.10.10.5' + } + } + ) + _port2_ctx = create_ctx( + node_id='port2', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx('2', False), + runtime_props={ + 'network_name': 'port2_network', + 'port': { + 'ip_address': '10.10.10.2' + } + } + ) + rels = [ + MagicMock( + name='port1', + target=_port1_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + MagicMock( + name='port2', + target=_port2_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + ] + _ctx = create_ctx( + node_id='server', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props, + relationships=rels + ) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + configure(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert _ctx.instance.runtime_properties['server']['network'] == \ + 'port1_network' + assert _ctx.instance.runtime_properties['server']['ip_address'] == \ + '10.10.10.5' + + +@patch('cloudify_vcd.legacy.decorators.get_last_task') +@patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.connection.Client', autospec=True) +@patch('cloudify_vcd.legacy.decorators.check_if_task_successful', + return_value=True) +def test_configure_vm_port_no_primary_port(*_, **__): + server_node_props = get_vm_ctx(resource_id='foo') + _port1_ctx = create_ctx( + node_id='port1', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx(primary=False), + runtime_props={ + 'network_name': 'port1_network', + 'port': { + 'ip_address': '10.10.10.1' + } + } + ) + _port2_ctx = create_ctx( + node_id='port2', + node_type=[ + 'cloudify.nodes.Port', + 'cloudify.vcloud.nodes.Port' + ], + node_properties=get_port_ctx('2', False), + runtime_props={ + 'network_name': 'port2_network', + 'port': { + 'ip_address': '10.10.10.2' + } + } + ) + rels = [ + MagicMock( + name='port1', + target=_port1_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + MagicMock( + name='port2', + target=_port2_ctx, + type_hierarchy=[ + 'cloudify.vcloud.server_connected_to_port', + 'cloudify.relationships.connected_to' + ] + ), + ] + _ctx = create_ctx( + node_id='server', + node_type=[ + 'cloudify.nodes.Compute', + 'cloudify.vcloud.nodes.Server' + ], + node_properties=server_node_props, + relationships=rels + ) + current_ctx.set(_ctx) + with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: + vdc.client.get_api_version = (lambda: '33') + create(ctx=_ctx) + assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert _ctx.instance.runtime_properties['server']['network'] == \ + 'port2_network' + assert _ctx.instance.runtime_properties['server']['ip_address'] == \ + '10.10.10.2' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -207,8 +661,10 @@ def test_start_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') start(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -227,6 +683,7 @@ def test_stop_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') stop(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -249,3 +706,4 @@ def test_delete_vm(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') delete(ctx=_ctx) + assert _ctx.instance.runtime_properties['resource_id'] == 'foo' From b9b2a97ab503e19372377f6fd1d6622c5c07550b Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Wed, 27 Oct 2021 09:46:39 -0400 Subject: [PATCH 06/58] test --- .circleci/config.yml | 9 +- examples/SPARX_SERVICE.yaml | 213 +++++++++++++++++++++++++++++++ plugin.yaml | 3 + setup.py | 2 + test-requirements.txt | 1 - vcloud_network_plugin/network.py | 5 - 6 files changed, 223 insertions(+), 10 deletions(-) create mode 100644 examples/SPARX_SERVICE.yaml diff --git a/.circleci/config.yml b/.circleci/config.yml index cae4d15..e55c2f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -402,10 +402,11 @@ workflows: - unittests_py36 - validate_version - validate_documentation - - rhel_wagon: - filters: - branches: - only: /([0-9\.]*\-build|main|dev)/ + - rhel_wagon +# - rhel_wagon: +# filters: +# branches: +# only: /([0-9\.]*\-build|main|dev)/ # - wagon: # filters: # branches: diff --git a/examples/SPARX_SERVICE.yaml b/examples/SPARX_SERVICE.yaml new file mode 100644 index 0000000..98eba59 --- /dev/null +++ b/examples/SPARX_SERVICE.yaml @@ -0,0 +1,213 @@ +tosca_definitions_version: cloudify_dsl_1_3 + +description: + This vcd test1 VRS project. + +imports: + - http://www.getcloudify.org/spec/cloudify/4.6/types.yaml + - plugin:cloudify-vcloud-plugin + +inputs: + + RSP_VRS1_APP_EXT_PROXY: + type: string + default: x + + RSP_VRS1_APP_OAM: + type: string + default: x + + +#server_name is the vm name + server_name: + type: string +# vCloud section + default: x + + host_name: + type: string + default: x + + vcloud_username: + type: string + default: { get_secret: vcd_username } + + vcloud_password: + type: string + default: { get_secret: vcd_password } + + vcloud_token: + type: string + default: '' + + vcloud_url: + type: string + default: { get_secret: vcd_fqdn } + + vcloud_service: + type: string + default: 'RSP' + + vcloud_service_type: + type: string + default: 'vcd' + + vcloud_instance: + type: string + default: 'RSP' + + vcloud_api_version: + type: string + default: '5.5' + + vcloud_org_url: + type: string + default: { get_secret: vcd_url } + + vcloud_org: + type: string + default: 'RSP' + + vcloud_vdc: + type: string + default: 'RSP' + + catalog: + type: string + default: 'TOMIA_Catalog' + + ssl_verify: + type: boolean + default: false + description: > + ssl check for connections to private services + (disable self-signed certificates) + + edge_gateway: + type: string + default: ESMAD0VEGRSP + +# Server section + + template: + type: string + description: rhel7 + default: { get_secret: rhel7_template } + + server_cpu: + type: string + default: 6 + + server_memory: + type: string + default: 32768 + +# Agent section: + user: + type: string + default: shuser + + login_pass: + type: string + default: "Sxx-Pxx00" + +# Network section + + RSP_VRS1_APP_EXT_PROXY_network_name: + type: string + default: "RSP_VRS1_APP_EXT_PROXY" + + RSP_VRS1_APP_OAM_network_name: + type: string + default: "RSP_VRS1_APP_OAM" + + + +dsl_definitions: + +######################################################## +# CREDENTIALS +######################################################## + + vcloud_config: &vcloud_config + username: { get_input: vcloud_username } + password: { get_input: vcloud_password } + # token: { get_input: vcloud_token } + url: { get_input: vcloud_url } + # instance: { get_input: vcloud_instance } + vdc: { get_input: vcloud_vdc } + org: { get_input: vcloud_org } + service_type: { get_input: vcloud_service_type } + #service: { get_input: vcloud_service } + #api_version: { get_input: vcloud_api_version } + #org_url: { get_input: vcloud_org_url } + #edge_gateway: { get_input: edge_gateway } + ssl_verify: { get_input: ssl_verify } + +node_templates: +#network + RSP_VRS1_APP_EXT_PROXY_network: + type: cloudify.vcloud.nodes.Network + properties: + use_external_resource: true + resource_id: { get_input: RSP_VRS1_APP_EXT_PROXY_network_name } + vcloud_config: *vcloud_config + + RSP_VRS1_APP_OAM_network: + type: cloudify.vcloud.nodes.Network + properties: + use_external_resource: true + resource_id: { get_input: RSP_VRS1_APP_OAM_network_name } + vcloud_config: *vcloud_config + + +#ports + RSP_VRS1_APP_EXT_PROXY_port: + type: cloudify.vcloud.nodes.Port + properties: + port: + network: { get_input: RSP_VRS1_APP_EXT_PROXY_network_name } + ip_allocation_mode: manual + ip_address: { get_input: RSP_VRS1_APP_EXT_PROXY } + primary_interface: false + vcloud_config: *vcloud_config + relationships: + - target: RSP_VRS1_APP_EXT_PROXY_network + type: cloudify.vcloud.port_connected_to_network + + RSP_VRS1_APP_OAM_port: + type: cloudify.vcloud.nodes.Port + properties: + port: + network: { get_input: RSP_VRS1_APP_OAM_network_name } + ip_allocation_mode: manual + ip_address: { get_input: RSP_VRS1_APP_OAM } + primary_interface: true + vcloud_config: *vcloud_config + relationships: + - target: RSP_VRS1_APP_OAM_network + type: cloudify.vcloud.port_connected_to_network + + sparx_service_server: + type: cloudify.vcloud.nodes.Server + properties: + agent_config: + user: shuser + install_method: remote + password: { get_secret: login_pass } + server: + name: { get_input: server_name } + catalog: { get_input: catalog } + template: { get_input: template } + hardware: + cpu: { get_input: server_cpu } + memory: { get_input: server_memory } + #guest_customization: + # computer_name: { get_input: host_name } + management_network: { get_input: RSP_VRS1_APP_OAM_network_name } + vcloud_config: *vcloud_config + relationships: + - target: RSP_VRS1_APP_EXT_PROXY_port + type: cloudify.vcloud.server_connected_to_port + - target: RSP_VRS1_APP_OAM_port + type: cloudify.vcloud.server_connected_to_port diff --git a/plugin.yaml b/plugin.yaml index bd398be..54644d4 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -243,8 +243,11 @@ node_types: <<: *LegacyBaseProperties server: default: {} + management_network: + type: string management_network_name: type: string + default: { get_property: [SELF, management_network]} interfaces: cloudify.interfaces.lifecycle: create: diff --git a/setup.py b/setup.py index c9476bf..9cb1422 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,8 @@ def get_version(rel_file='plugin.yaml'): name='cloudify-vcloud-plugin', version=get_version(), packages=[ + 'vcloud_network_plugin', + 'vcloud_server_plugin', 'cloudify_vcd', 'vcd_plugin_sdk', 'vcd_plugin_sdk.resources', diff --git a/test-requirements.txt b/test-requirements.txt index 99df67e..a594f94 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,3 @@ mock pytest flake8 -https://github.com/cloudify-incubator/cloudify-utilities-plugins-sdk/archive/refs/heads/add-explicit-delete-logic.zip diff --git a/vcloud_network_plugin/network.py b/vcloud_network_plugin/network.py index 38f92c0..6eded98 100644 --- a/vcloud_network_plugin/network.py +++ b/vcloud_network_plugin/network.py @@ -19,11 +19,6 @@ @operation(resumable=True) def create(*args, **kwargs): - _ctx = kwargs.get('ctx') - _ctx.logger.info( - 'Using translation of legacy tosca-cloudify-plugin ' - 'cloudify.vcloud.nodes.Network node type. Please upgrade to ' - 'cloudify.vcloud.plugin cloudify.nodes.vcloud.Network.') create_network(*args, **kwargs) From c2d5abc4fc12e71ffcd9ca6a5815e0d757a0ca9f Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Wed, 27 Oct 2021 10:30:44 -0400 Subject: [PATCH 07/58] build rhel step 1 --- cloudify_vcd/legacy/utils.py | 21 ++++++++++++++++++--- plugin.yaml | 4 +++- setup.py | 3 +++ vcd_plugin_sdk/connection.py | 6 +++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 3232db6..8322aca 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -14,6 +14,7 @@ import ipaddress from copy import deepcopy +from tempfile import NamedTemporaryFile from ..utils import ( find_rels_by_type, @@ -23,10 +24,13 @@ from vcd_plugin_sdk.connection import VCloudConnect from vcd_plugin_sdk.resources.network import VCloudNetwork, VCloudGateway +from cloudify import ctx as ctx_from_import from cloudify.exceptions import NonRecoverableError from cloudify_common_sdk.utils import ( get_ctx_node, - get_ctx_instance) + get_ctx_instance, + get_deployment_dir +) OLD_NETWORK_KEYS = [ @@ -95,6 +99,11 @@ def get_vcloud_cx(client_config, logger): new_client_config['verify_ssl_certs'] = client_config.pop( 'verify_ssl_certs') + if 'log_file' not in new_client_config: + new_temp = NamedTemporaryFile( + dir=get_deployment_dir(ctx_from_import.deployment.id)) + new_client_config['log_file'] = new_temp.name + # TODO: Figure out what to do with the rest of the stuff in client_config. return VCloudConnect(logger, new_client_config, credentials) @@ -248,8 +257,10 @@ def convert_network_config(config): if 'ip_range_start' not in config or 'ip_range_end' not in config: ip_range_start, ip_range_end = get_ip_range(config) - config['ip_range_start'] = ip_range_start.compressed - config['ip_range_end'] = ip_range_end.compressed + if ip_range_start: + config['ip_range_start'] = ip_range_start.compressed + if ip_range_end: + config['ip_range_end'] = ip_range_end.compressed if 'dns' in config: primary_ip, secondary_ip = get_dns_ips(config['dns']) @@ -309,6 +320,10 @@ def get_network_cidr(config): netmask = ipaddress.IPv4Address('0.0.0.0/{}'.format(netmask)) if gateway_ip: start = gateway_ip + ctx_from_import.logger.info( + 'Using these IPs for CIDR: {} {}'.format(start, end)) + if not start or not end: + return None ip_range = [addr for addr in ipaddress.summarize_address_range(start, end)] if len(ip_range) >= 1: if netmask: diff --git a/plugin.yaml b/plugin.yaml index 54644d4..6c067a9 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,9 +1,11 @@ plugins: - vcd: + vcd: &plugin_mapping executor: central_deployment_agent package_name: cloudify-vcloud-plugin package_version: '2.0.2' + # legacy + vcloud: *plugin_mapping data_types: diff --git a/setup.py b/setup.py index 9cb1422..d8cdb83 100644 --- a/setup.py +++ b/setup.py @@ -43,6 +43,9 @@ def get_version(rel_file='plugin.yaml'): 'vcloud_network_plugin', 'vcloud_server_plugin', 'cloudify_vcd', + 'cloudify_vcd.legacy', + 'cloudify_vcd.legacy.compute', + 'cloudify_vcd.legacy.network', 'vcd_plugin_sdk', 'vcd_plugin_sdk.resources', ], diff --git a/vcd_plugin_sdk/connection.py b/vcd_plugin_sdk/connection.py index a43c0c7..bea2547 100644 --- a/vcd_plugin_sdk/connection.py +++ b/vcd_plugin_sdk/connection.py @@ -26,9 +26,9 @@ def default_logger(stream=sys.stdout): logging.basicConfig( # stream=stream, - filename=os.path.join( - os.path.expanduser('~'), - 'Desktop', 'vcloudclient.log'), + # filename=os.path.join( + # os.path.expanduser('~'), + # 'Desktop', 'vcloudclient.log'), level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%y.%m.%d-%H:%M:%S') From ae902f74e6c0c7a0f4a75dc9ef4c8b678323209f Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Wed, 27 Oct 2021 10:37:07 -0400 Subject: [PATCH 08/58] fix that --- cloudify_vcd/legacy/tests/__init__.py | 8 +++++- constraints.txt | 1 + vcloud_network_plugin/tests/test_network.py | 8 ++++++ vcloud_server_plugin/tests/test_server.py | 30 +++++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 constraints.txt diff --git a/cloudify_vcd/legacy/tests/__init__.py b/cloudify_vcd/legacy/tests/__init__.py index 53ed7e5..2daae8c 100644 --- a/cloudify_vcd/legacy/tests/__init__.py +++ b/cloudify_vcd/legacy/tests/__init__.py @@ -79,13 +79,19 @@ def create_ctx(node_id, 'name': operation_name, 'retry': 0, } + tenant = { + 'name': 'footen', + } mock_ctx = CorrectedMockCloudifyContext( node_id=node_id, node_name=node_id, node_type=node_type, + blueprint_id='fooblu', + deployment_id='foodep', properties=node_properties, runtime_properties=runtime_props, relationships=relationships, - operation=operation + operation=operation, + tenant=tenant, ) return mock_ctx diff --git a/constraints.txt b/constraints.txt new file mode 100644 index 0000000..a5911a1 --- /dev/null +++ b/constraints.txt @@ -0,0 +1 @@ +https://github.com/cloudify-incubator/pyvcloud/archive/refs/heads/23.0.0-build.zip diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py index 7cffc6a..c4122e8 100644 --- a/vcloud_network_plugin/tests/test_network.py +++ b/vcloud_network_plugin/tests/test_network.py @@ -48,6 +48,8 @@ def get_network_ctx(existing=False, return network_node_props +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -66,6 +68,8 @@ def test_create_external_network_with_gateway(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -84,6 +88,8 @@ def test_delete_external_network_with_gateway(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -106,6 +112,8 @@ def test_create_network_with_gateway(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index e3bbbda..b24bcaa 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -53,6 +53,8 @@ def get_vm_ctx(existing=False, return server_node_props +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -76,6 +78,8 @@ def test_create_external_vm(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.get_vm') @@ -100,6 +104,8 @@ def test_delete_external_vm(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) @@ -120,6 +126,8 @@ def test_configure_external_vm(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -143,6 +151,8 @@ def test_start_external_vm(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -165,6 +175,8 @@ def test_stop_external_vm(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -239,6 +251,8 @@ def test_create_vm(*_, **__): '10.10.10.1' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -311,6 +325,8 @@ def test_create_vm_no_primary_port(*_, **__): 'port2_network' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -388,6 +404,8 @@ def test_create_vm_port_network(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -411,6 +429,8 @@ def test_configure_vm(*_, **__): @patch('pyvcloud.vcd.vapp.VApp') @patch('cloudify_vcd.legacy.compute.tasks.VCloudVM') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -490,6 +510,8 @@ def test_configure_vm_with_two_ports(*_, **__): @patch('pyvcloud.vcd.vapp.VApp') @patch('cloudify_vcd.legacy.compute.tasks.VCloudVM') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -568,6 +590,8 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): '10.10.10.5' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -643,6 +667,8 @@ def test_configure_vm_port_no_primary_port(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -665,6 +691,8 @@ def test_start_vm(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.connection.Client', autospec=True) @@ -686,6 +714,8 @@ def test_stop_vm(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') +@patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.get_vm') From 1feb794d6602b424cbddde7dd7cdf47d18de0b26 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 28 Oct 2021 08:07:49 -0400 Subject: [PATCH 09/58] update plugin yaml --- .DS_Store | Bin 0 -> 6148 bytes plugin.yaml | 8 ++++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f93ad8857d0e223bfc5694936234d2e28cdd8166 GIT binary patch literal 6148 zcmeH~O^O0R4256(0bw>SUDn0}c!NTm6U+rf8$l3Ui2FLaFR5&7XFW8-3#48pRq3B^ z(bWN9`{%F&)&N#?S8RP4nK54CgeR`JVYm#B^XY!Sc^b3a>j9nDcwf(Di3o^*2#A0P zh`@vh#39b}|7$|eq(>0}5ts%6|2`DDYfWukw^_-6!carimx`BHhde!QONkD2v(qf=u$hqs>q27VN8=wVzhKB3ms)|DBWegp!8 J1`+sE0xx3T6K((i literal 0 HcmV?d00001 diff --git a/plugin.yaml b/plugin.yaml index 6c067a9..41c662a 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -290,17 +290,21 @@ node_types: interfaces: cloudify.interfaces.lifecycle: create: - implementation: vcd.cloudify_vcd.legacy.network.tasks.create_network + implementation: vcloud.vcloud_network_plugin.network.create inputs: network: default: { get_property: [SELF, network ] } vcloud_config: default: { get_property: [SELF, vcloud_config] } delete: - implementation: vcd.cloudify_vcd.legacy.network.tasks.delete_network + implementation: vcloud.vcloud_network_plugin.network.delete inputs: vcloud_config: default: { get_property: [SELF, vcloud_config] } + cloudify.interfaces.validation: + creation: + implementation: vcloud.vcloud_network_plugin.network.creation_validation + inputs: {} relationships: From 8c0b0412f58da05a4c1de8d0e0e0b684f600418b Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 28 Oct 2021 08:26:30 -0400 Subject: [PATCH 10/58] fix server path --- plugin.yaml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugin.yaml b/plugin.yaml index 41c662a..a7c737d 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -253,17 +253,20 @@ node_types: interfaces: cloudify.interfaces.lifecycle: create: - implementation: vcd.cloudify_vcd.legacy.compute.tasks.create_server - inputs: - server: - default: { get_property: [SELF, server ] } - vcloud_config: - default: { get_property: [SELF, vcloud_config] } + implementation: vcloud.vcloud_server_plugin.server.create + inputs: {} + configure: + implementation: vcloud.vcloud_server_plugin.server.create + inputs: {} + start: + implementation: vcloud.vcloud_server_plugin.server.create + inputs: {} + stop: + implementation: vcloud.vcloud_server_plugin.server.create + inputs: {} delete: implementation: vcd.cloudify_vcd.legacy.compute.tasks.delete_server - inputs: - vcloud_config: - default: { get_property: [SELF, vcloud_config] } + inputs: {} cloudify.vcloud.nodes.Port: derived_from: cloudify.nodes.Port From 814a03615cc3bda13e3bff6f0efcfa558998220e Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 1 Nov 2021 10:40:43 -0400 Subject: [PATCH 11/58] try without paramiko --- constraints.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/constraints.txt b/constraints.txt index a5911a1..b4bc115 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1 +1,2 @@ https://github.com/cloudify-incubator/pyvcloud/archive/refs/heads/23.0.0-build.zip +https://github.com/cloudify-incubator/cloudify-utilities-plugins-sdk/archive/refs/heads/0.0.45-without-paramiko.zip \ No newline at end of file From 193dea814774a7cf131797d39d7f9a88954a9d0d Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 1 Nov 2021 10:54:48 -0400 Subject: [PATCH 12/58] remove from setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d8cdb83..ba63e7c 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def get_version(rel_file='plugin.yaml'): install_requires=[ 'cloudify-common>=5.1.0', 'pyvcloud==23.0.0', - 'cloudify-utilities-plugins-sdk', + # 'cloudify-utilities-plugins-sdk', 'lxml' ] ) From 384ab700c09e6cd176714c1c4cc4a024b1b5c742 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 1 Nov 2021 11:55:45 -0400 Subject: [PATCH 13/58] update --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ba63e7c..0f37e69 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def get_version(rel_file='plugin.yaml'): install_requires=[ 'cloudify-common>=5.1.0', 'pyvcloud==23.0.0', - # 'cloudify-utilities-plugins-sdk', + 'cloudify-utilities-plugins-sdk==0.0.45b', 'lxml' ] ) From 80272b4b93c9f33e7ef0f61ce07b9ac32579aeb3 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 1 Nov 2021 12:53:10 -0400 Subject: [PATCH 14/58] setup py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0f37e69..7b953f2 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def get_version(rel_file='plugin.yaml'): install_requires=[ 'cloudify-common>=5.1.0', 'pyvcloud==23.0.0', - 'cloudify-utilities-plugins-sdk==0.0.45b', + 'cloudify-utilities-plugins-sdk-without-paramiko==0.0.45b', 'lxml' ] ) From a761ec7cded697e73f75a0bf2cd26770b8f53430 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 1 Nov 2021 12:56:13 -0400 Subject: [PATCH 15/58] remove constraints --- constraints.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/constraints.txt b/constraints.txt index b4bc115..a5911a1 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,2 +1 @@ https://github.com/cloudify-incubator/pyvcloud/archive/refs/heads/23.0.0-build.zip -https://github.com/cloudify-incubator/cloudify-utilities-plugins-sdk/archive/refs/heads/0.0.45-without-paramiko.zip \ No newline at end of file From ff5874b7d50a771e471812d3ac1f1487220b3dce Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Wed, 3 Nov 2021 11:16:27 -0400 Subject: [PATCH 16/58] testing updates --- cloudify_vcd/legacy/utils.py | 14 ++++++++------ cloudify_vcd/network_tasks.py | 1 + cloudify_vcd/vapp_tasks.py | 5 +++++ plugin.yaml | 9 +++------ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 8322aca..bf24800 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -126,11 +126,13 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): _ctx_node = get_ctx_node(ctx) _ctx_instance = get_ctx_instance(ctx) - if 'edge_gateway' in vcloud_config: - network['gateway_name'] = vcloud_config['edge_gateway'] - network_type = 'routed_vdc_network' - else: - network_type = 'isolated_vdc_network' + network_type = 'directly_connected_vdc_network' + + # if 'edge_gateway' in vcloud_config: + # network['gateway_name'] = vcloud_config['edge_gateway'] + # network_type = 'routed_vdc_network' + # else: + # network_type = 'isolated_vdc_network' tasks = _ctx_instance.runtime_properties.get('__TASKS', []) if 'name' in network: @@ -369,7 +371,7 @@ def convert_port_config(config): def convert_vapp_config(config): return { - 'fence_mode': config.get('fence_mode', 'bridged'), + 'fence_mode': config.get('fence_mode', 'direct'), 'accept_all_eulas': config.get('accept_all_eulas', True) } diff --git a/cloudify_vcd/network_tasks.py b/cloudify_vcd/network_tasks.py index 66f089f..2f71229 100644 --- a/cloudify_vcd/network_tasks.py +++ b/cloudify_vcd/network_tasks.py @@ -5,6 +5,7 @@ REL_NETWORK_GW = 'cloudify.relationships.vcloud.network_connected_to_gateway' NETWORK_TYPES = { + 'cloudify.vcloud.nodes.Network': 'directly_connected_vdc_network', 'cloudify.nodes.vcloud.RoutedVDCNetwork': 'routed_vdc_network', 'cloudify.nodes.vcloud.DirectlyConnectedVDCNetwork': 'directly_connected_vdc_network', diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 61cfe9c..28a2206 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -242,6 +242,8 @@ def _create_vm(vm_external=None, 'is invalid. Valid values are {v}.'.format( fm=fence_mode, v=FENCE_MODE)) + ctx.logger.info(vm_config) + vm = vm_class( vm_id, vapp_name or vm_id, @@ -560,6 +562,9 @@ def _add_network(_=None, if nic_network: nic_config['network_name'] = nic_network + ctx.logger.info('nic_config {}'.format(nic_config)) + + ctx.logger.info('vm_config {}'.format(vm_config)) vm = vm_class( vm_id, diff --git a/plugin.yaml b/plugin.yaml index a7c737d..c819924 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -400,9 +400,6 @@ relationships: derived_from: cloudify.relationships.vcloud.vm_connected_to_nic target_interfaces: cloudify.interfaces.relationship_lifecycle: - preconfigure: - implementation: vcd.cloudify_vcd.vapp_tasks.add_network - postconfigure: - implementation: vcd.cloudify_vcd.vapp_tasks.add_nic - unlink: - implementation: vcd.cloudify_vcd.vapp_tasks.delete_nic + preconfigure: {} + postconfigure: {} + unlink: {} From 423cebe3072c7c89601c6e3746e6dc6fe7b24ea3 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Wed, 3 Nov 2021 16:27:45 -0400 Subject: [PATCH 17/58] trust --- cloudify_vcd/legacy/compute/tasks.py | 8 +++++++- cloudify_vcd/legacy/utils.py | 9 ++++++--- cloudify_vcd/vapp_tasks.py | 5 +++-- vcloud_network_plugin/tests/test_network.py | 8 +++++--- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index b1dee9b..b6579d0 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from copy import deepcopy + from cloudify.exceptions import OperationRetry from vcd_plugin_sdk.resources.vapp import VCloudVM @@ -36,12 +38,16 @@ def create_server(vm_client, ctx, **_): ctx, exists=vm_client.exists, create_operation=True): + vm_kwargs = deepcopy(vm_client.vapp_object.kwargs) + if 'network' in vm_kwargs: + del vm_kwargs['network'] + del vm_kwargs['network_adapter_type'] return vapp_tasks._create_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc_name, - vm_config=vm_client.vapp_object.kwargs, + vm_config=vm_kwargs, vm_class=VCloudVM, vm_ctx=ctx) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index bf24800..7463c83 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -142,8 +142,11 @@ def get_network_client(network, vcloud_cx, vcloud_config, ctx, **_): else: network_name = _ctx_node.properties.get( 'resource_id', _ctx_instance.id) - - network = convert_network_config(network) + if network_type == 'directly_connected_vdc_network': + network = { + 'parent_network_name': network.get('parent_network_name', None) + } + network = convert_routed_network_config(network) _ctx_instance.runtime_properties['resource_id'] = network_name _ctx_instance.runtime_properties['network'] = network @@ -250,7 +253,7 @@ def get_server_network(server, _ctx_node, _ctx_instance): server['ip_address'] = ip_address -def convert_network_config(config): +def convert_routed_network_config(config): if 'network_cidr' not in config: cidr = get_network_cidr(config) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 28a2206..11ed18d 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -553,12 +553,13 @@ def _add_network(_=None, nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) vapp_node = find_rel_by_type(vm_ctx.instance, REL_VM_VAPP) + fence_mode = 'bridged' if vapp_node: fence_mode = vapp_node.target.node.properties['resource_config'].get( 'fence_mode') - elif 'server' in vm_ctx.instance.runtime_properties: + elif 'fence_mode' in vm_ctx.instance.runtime_properties.get('server', {}): fence_mode = vm_ctx.instance.runtime_properties['server'].get( - 'fence_mode', 'bridged') + 'fence_mode') if nic_network: nic_config['network_name'] = nic_network diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py index c4122e8..81d088e 100644 --- a/vcloud_network_plugin/tests/test_network.py +++ b/vcloud_network_plugin/tests/test_network.py @@ -51,7 +51,7 @@ def get_network_ctx(existing=False, @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('vcd_plugin_sdk.connection.Org', autospec=True) -@patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') +@patch('pyvcloud.vcd.vdc.VDC.get_direct_orgvdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) def test_create_external_network_with_gateway(*_, **__): @@ -71,7 +71,7 @@ def test_create_external_network_with_gateway(*_, **__): @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('vcd_plugin_sdk.connection.Org', autospec=True) -@patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') +@patch('pyvcloud.vcd.vdc.VDC.get_direct_orgvdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) def test_delete_external_network_with_gateway(*_, **__): @@ -98,6 +98,8 @@ def test_delete_external_network_with_gateway(*_, **__): return_value=True) @patch('vcd_plugin_sdk.resources.network.VCloudNetwork.get_network', return_value=False) +@patch('pyvcloud.vcd.vdc.Platform.get_external_network', + return_value={'href': 'foo'}) def test_create_network_with_gateway(*_, **__): network_node_props = get_network_ctx(resource_id='foo', gateway='baz') _ctx = create_ctx( @@ -116,7 +118,7 @@ def test_create_network_with_gateway(*_, **__): @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) -@patch('pyvcloud.vcd.vdc.VDC.get_routed_orgvdc_network') +@patch('pyvcloud.vcd.vdc.VDC.get_direct_orgvdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) @patch('cloudify_vcd.legacy.decorators.check_if_task_successful', From 00630860fccd546ebe577f019aa2c8ccd2f066ce Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Wed, 3 Nov 2021 16:49:16 -0400 Subject: [PATCH 18/58] fix test? --- vcloud_network_plugin/tests/test_network.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py index 81d088e..2569340 100644 --- a/vcloud_network_plugin/tests/test_network.py +++ b/vcloud_network_plugin/tests/test_network.py @@ -70,6 +70,7 @@ def test_create_external_network_with_gateway(*_, **__): @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') +@patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('pyvcloud.vcd.vdc.VDC.get_direct_orgvdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) From e08e07342255e07cb17db36ecd6bcb0fd1c23392 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 09:34:31 -0400 Subject: [PATCH 19/58] fix plugin yaml --- plugin.yaml | 8 ++++---- vcloud_network_plugin/port.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugin.yaml b/plugin.yaml index c819924..d5f6e60 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -256,16 +256,16 @@ node_types: implementation: vcloud.vcloud_server_plugin.server.create inputs: {} configure: - implementation: vcloud.vcloud_server_plugin.server.create + implementation: vcloud.vcloud_server_plugin.server.configure inputs: {} start: - implementation: vcloud.vcloud_server_plugin.server.create + implementation: vcloud.vcloud_server_plugin.server.start inputs: {} stop: - implementation: vcloud.vcloud_server_plugin.server.create + implementation: vcloud.vcloud_server_plugin.server.stop inputs: {} delete: - implementation: vcd.cloudify_vcd.legacy.compute.tasks.delete_server + implementation: vcloud.vcloud_server_plugin.server.delete inputs: {} cloudify.vcloud.nodes.Port: diff --git a/vcloud_network_plugin/port.py b/vcloud_network_plugin/port.py index a0da08d..ac8e12b 100644 --- a/vcloud_network_plugin/port.py +++ b/vcloud_network_plugin/port.py @@ -26,5 +26,5 @@ def creation_validation(*args, **kwargs): @operation(resumable=True) def delete(*_, **kwargs): _ctx = kwargs.get('ctx') - for key in _ctx.instance.runtime_properties.keys(): + for key in list(_ctx.instance.runtime_properties.keys()): del _ctx.instance.runtime_properties[key] From f602503ed21c189fad6c16b25c42a1ae25da7e0c Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 09:50:21 -0400 Subject: [PATCH 20/58] port_ctx.target --- cloudify_vcd/legacy/compute/tasks.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index b6579d0..60d32b6 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -118,8 +118,8 @@ def port_creation_validation(*_, **__): def preconfigure_nic(vm_client, ctx, **kwargs): for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): resource, result = vapp_tasks._add_network( - nic_config=port_ctx.instance.runtime_properties['port'], - nic_ctx=port_ctx, + nic_config=port_ctx.target.instance.runtime_properties['port'], + nic_ctx=port_ctx.target, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc, @@ -129,7 +129,8 @@ def preconfigure_nic(vm_client, ctx, **kwargs): **kwargs) last_task = get_last_task(result) if not check_if_task_successful(resource, last_task): - port_ctx.instance.runtime_properties['__RETRY_BAD_REQUEST'] = \ + port_ctx.target.instance.runtime_properties['__RETRY_BAD_' + 'REQUEST'] = \ True raise OperationRetry('Pending for operation completion.') @@ -139,8 +140,8 @@ def preconfigure_nic(vm_client, ctx, **kwargs): def postconfigure_nic(vm_client, ctx, **kwargs): for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): resource, result = vapp_tasks._add_nic( - nic_config=port_ctx.instance.runtime_properties['port'], - nic_ctx=port_ctx, + nic_config=port_ctx.target.instance.runtime_properties['port'], + nic_ctx=port_ctx.target, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc, @@ -150,7 +151,8 @@ def postconfigure_nic(vm_client, ctx, **kwargs): **kwargs) last_task = get_last_task(result) if not check_if_task_successful(resource, last_task): - port_ctx.instance.runtime_properties['__RETRY_BAD_REQUEST'] = \ + port_ctx.target.instance.runtime_properties['__RETRY_BAD_' + 'REQUEST'] = \ True raise OperationRetry('Pending for operation completion.') @@ -160,8 +162,8 @@ def postconfigure_nic(vm_client, ctx, **kwargs): def unlink_nic(vm_client, ctx, **kwargs): for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): resource, result = vapp_tasks._delete_nic( - nic_config=port_ctx.instance.runtime_properties['port'], - nic_ctx=port_ctx, + nic_config=port_ctx.target.instance.runtime_properties['port'], + nic_ctx=port_ctx.target, vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc, @@ -171,6 +173,7 @@ def unlink_nic(vm_client, ctx, **kwargs): **kwargs) last_task = get_last_task(result) if not check_if_task_successful(resource, last_task): - port_ctx.instance.runtime_properties['__RETRY_BAD_REQUEST'] = \ + port_ctx.target.instance.runtime_properties['__RETRY_BAD_' + 'REQUEST'] = \ True raise OperationRetry('Pending for operation completion.') From b2a88061eaedb46a0148ccdc61c5981c3554e4fc Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 09:54:56 -0400 Subject: [PATCH 21/58] fix port network prop --- cloudify_vcd/legacy/utils.py | 2 ++ vcloud_server_plugin/tests/test_server.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 7463c83..139a945 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -181,6 +181,8 @@ def get_port_config(port, ctx, **kwargs): _node_instance, PORT_NET_REL) port = convert_port_config(port) + if 'network_name' not in port: + port['network_name'] = network if 'is_connected' not in port: # TODO: Decide what to do here. pass diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index b24bcaa..4a34075 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -534,6 +534,7 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): runtime_props={ 'network_name': 'port1_network', 'port': { + 'network_name': 'port1_network', 'ip_address': '10.10.10.5' } } @@ -548,6 +549,7 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): runtime_props={ 'network_name': 'port2_network', 'port': { + 'network_name': 'port1_network', 'ip_address': '10.10.10.2' } } From eedf024d505a6c23b734aee475c27b8c0702182f Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 09:56:35 -0400 Subject: [PATCH 22/58] fix test --- vcloud_server_plugin/tests/test_server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index 4a34075..ed9b485 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -451,6 +451,7 @@ def test_configure_vm_with_two_ports(*_, **__): runtime_props={ 'network_name': 'port1_network', 'port': { + 'network_name': 'port1_network', 'ip_address': '10.10.10.1' } } @@ -465,6 +466,7 @@ def test_configure_vm_with_two_ports(*_, **__): runtime_props={ 'network_name': 'port2_network', 'port': { + 'network_name': 'port2_network', 'ip_address': '10.10.10.2' } } From ed5e8782bc17deff731efb68197aebcb994da99e Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 10:21:30 -0400 Subject: [PATCH 23/58] update expose props --- cloudify_vcd/legacy/compute/tasks.py | 55 +++++++++++++++++++++------ cloudify_vcd/legacy/network/tasks.py | 13 ++++++- cloudify_vcd/legacy/tests/__init__.py | 4 +- cloudify_vcd/utils.py | 2 +- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 60d32b6..83ca4e8 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -25,6 +25,7 @@ from ... import vapp_tasks from ..utils import VM_NIC_REL from ...utils import ( + expose_props, get_last_task, find_rels_by_type, check_if_task_successful) @@ -42,7 +43,7 @@ def create_server(vm_client, ctx, **_): if 'network' in vm_kwargs: del vm_kwargs['network'] del vm_kwargs['network_adapter_type'] - return vapp_tasks._create_vm( + resource, result = vapp_tasks._create_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, @@ -50,12 +51,16 @@ def create_server(vm_client, ctx, **_): vm_config=vm_kwargs, vm_class=VCloudVM, vm_ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_vcd_client() @decorators.with_vm_resource() def configure_server(vm_client, ctx, **_): - return vapp_tasks._configure_vm( + resource, result = vapp_tasks._configure_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, @@ -63,32 +68,44 @@ def configure_server(vm_client, ctx, **_): vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_vcd_client() @decorators.with_vm_resource() def start_server(vm_client, ctx, **_): - return vapp_tasks._start_vm( + resource, result = vapp_tasks._start_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc, + vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_vcd_client() @decorators.with_vm_resource() def stop_server(vm_client, ctx, **_): - return vapp_tasks._stop_vm( + resource, result = vapp_tasks._stop_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc, + vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_vcd_client() @@ -98,14 +115,18 @@ def delete_server(vm_client, ctx, **_): vm_client.name, exists=vm_client.exists, delete_operation=True): - return vapp_tasks._delete_vm( + resource, result = vapp_tasks._delete_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc, + vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_port_resource() @@ -122,7 +143,7 @@ def preconfigure_nic(vm_client, ctx, **kwargs): nic_ctx=port_ctx.target, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc, + vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx, @@ -133,6 +154,10 @@ def preconfigure_nic(vm_client, ctx, **kwargs): 'REQUEST'] = \ True raise OperationRetry('Pending for operation completion.') + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=port_ctx.target) @decorators.with_vcd_client() @@ -144,7 +169,7 @@ def postconfigure_nic(vm_client, ctx, **kwargs): nic_ctx=port_ctx.target, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc, + vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx, @@ -155,6 +180,10 @@ def postconfigure_nic(vm_client, ctx, **kwargs): 'REQUEST'] = \ True raise OperationRetry('Pending for operation completion.') + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=port_ctx.target) @decorators.with_vcd_client() @@ -166,7 +195,7 @@ def unlink_nic(vm_client, ctx, **kwargs): nic_ctx=port_ctx.target, vm_id=vm_client.name, vm_client=vm_client.connection, - vm_vdc=vm_client.vdc, + vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx, @@ -177,3 +206,7 @@ def unlink_nic(vm_client, ctx, **kwargs): 'REQUEST'] = \ True raise OperationRetry('Pending for operation completion.') + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=port_ctx.target) diff --git a/cloudify_vcd/legacy/network/tasks.py b/cloudify_vcd/legacy/network/tasks.py index d0be8cd..c45b2d7 100644 --- a/cloudify_vcd/legacy/network/tasks.py +++ b/cloudify_vcd/legacy/network/tasks.py @@ -21,6 +21,7 @@ from .. import decorators from ... import network_tasks +from ...utils import expose_props class MissingGateway(NonRecoverableError): @@ -41,7 +42,7 @@ def create_network(network_client, gateway_client, ctx, **_): ctx, exists=network_client.exists, create_operation=True): - return network_tasks._create_network( + resource, result = network_tasks._create_network( external_network=False, network_id=network_client.name, network_client=network_client.connection, @@ -49,6 +50,10 @@ def create_network(network_client, gateway_client, ctx, **_): network_config=network_client.kwargs, network_class=VCloudNetwork, ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_vcd_client() @@ -59,7 +64,7 @@ def delete_network(network_client, ctx, **_): ctx, exists=network_client.exists, delete_operation=True): - return network_tasks._delete_network( + resource, result = network_tasks._delete_network( external_network=False, network_id=network_client.name, network_client=network_client.connection, @@ -67,3 +72,7 @@ def delete_network(network_client, ctx, **_): network_config=network_client.kwargs, network_class=VCloudNetwork, ctx=ctx) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) diff --git a/cloudify_vcd/legacy/tests/__init__.py b/cloudify_vcd/legacy/tests/__init__.py index 2daae8c..30b4f24 100644 --- a/cloudify_vcd/legacy/tests/__init__.py +++ b/cloudify_vcd/legacy/tests/__init__.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from cloudify.manager import DirtyTrackingDict from cloudify.mocks import MockNodeContext, MockCloudifyContext @@ -72,6 +73,7 @@ def create_ctx(node_id, :return: """ + runtime_props = runtime_props or {} type_hierarchy = ['cloudify.nodes.Root'] type_hierarchy.extend(node_type) operation_name = operation_name or 'cloudify.interfaces.lifecycle.create' @@ -89,7 +91,7 @@ def create_ctx(node_id, blueprint_id='fooblu', deployment_id='foodep', properties=node_properties, - runtime_properties=runtime_props, + runtime_properties=DirtyTrackingDict(runtime_props), relationships=relationships, operation=operation, tenant=tenant, diff --git a/cloudify_vcd/utils.py b/cloudify_vcd/utils.py index c83a85b..9b8adfd 100644 --- a/cloudify_vcd/utils.py +++ b/cloudify_vcd/utils.py @@ -266,7 +266,7 @@ def update_runtime_properties(current_ctx, props): ctx.logger.debug('Updating instance with properties {props}.'.format( props=props)) - if is_relationship(): + if is_relationship(current_ctx): if current_ctx.instance.id == ctx.source.instance.id: ctx.source.instance.runtime_properties.update(props) ctx.source.instance.runtime_properties.dirty = True From ad6775883524076f3fd2c360ff4489a457649028 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 10:53:11 -0400 Subject: [PATCH 24/58] update add network --- cloudify_vcd/vapp_tasks.py | 2 ++ vcd_plugin_sdk/resources/vapp.py | 4 ++++ vcloud_server_plugin/tests/test_server.py | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 11ed18d..8566419 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -550,6 +550,8 @@ def _add_network(_=None, vapp_name = find_resource_id_from_relationship_by_type( vm_ctx.instance, REL_VM_VAPP) + if not vapp_name: + vapp_name = vm_id nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) vapp_node = find_rel_by_type(vm_ctx.instance, REL_VM_VAPP) diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 809582a..8e80cec 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -146,6 +146,10 @@ def undeploy(self, vapp_name=None, action='default'): # return self.vapp.delete_vms(vm_names) # def add_network(self, **kwargs): + if kwargs.get('fence_mode') not in ['bridged', + 'isolated', + 'natRouted']: + kwargs.pop('fence_mode', None) task = self.vapp.connect_org_vdc_network(**kwargs) if 'add_network' in self.tasks: self.tasks['add_network'].append(task) diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index ed9b485..37b1ece 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -594,10 +594,13 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): '10.10.10.5' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') +@patch('cloudify_vcd.legacy.compute.tasks.get_last_task') @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('pyvcloud.vcd.vapp.VApp.connect_org_vdc_network') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('cloudify_vcd.legacy.decorators.check_if_task_successful', return_value=True) @@ -613,6 +616,7 @@ def test_configure_vm_port_no_primary_port(*_, **__): runtime_props={ 'network_name': 'port1_network', 'port': { + 'network_name': 'port1_network', 'ip_address': '10.10.10.1' } } @@ -661,7 +665,7 @@ def test_configure_vm_port_no_primary_port(*_, **__): current_ctx.set(_ctx) with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') - create(ctx=_ctx) + configure(ctx=_ctx) assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ From 1b078e609f21f16863491c51d1d962dafc5d5de3 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 11:42:59 -0400 Subject: [PATCH 25/58] use is deployed --- cloudify_vcd/legacy/utils.py | 3 +- vcd_plugin_sdk/resources/vapp.py | 1 + vcloud_server_plugin/tests/test_server.py | 35 ++++++++++++++++++++--- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 139a945..9b566ad 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -184,8 +184,7 @@ def get_port_config(port, ctx, **kwargs): if 'network_name' not in port: port['network_name'] = network if 'is_connected' not in port: - # TODO: Decide what to do here. - pass + port['is_connected'] = True _node_instance.runtime_properties['network'] = network _node_instance.runtime_properties['port'] = port diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 8e80cec..69f9550 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -150,6 +150,7 @@ def add_network(self, **kwargs): 'isolated', 'natRouted']: kwargs.pop('fence_mode', None) + kwargs['is_deployed'] = True task = self.vapp.connect_org_vdc_network(**kwargs) if 'add_network' in self.tasks: self.tasks['add_network'].append(task) diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index 37b1ece..6a42d87 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -175,6 +175,7 @@ def test_stop_external_vm(*_, **__): assert _ctx.instance.runtime_properties['resource_id'] == 'foo' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -251,6 +252,7 @@ def test_create_vm(*_, **__): '10.10.10.1' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -325,6 +327,7 @@ def test_create_vm_no_primary_port(*_, **__): 'port2_network' +@patch('pyvcloud.vcd.vapp.VApp.get_vm') @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @@ -451,6 +454,10 @@ def test_configure_vm_with_two_ports(*_, **__): runtime_props={ 'network_name': 'port1_network', 'port': { + 'is_primary': False, + 'is_connected': True, + 'ip_address_mode': 'manual', + 'adapter_type': 'VXNET3', 'network_name': 'port1_network', 'ip_address': '10.10.10.1' } @@ -466,6 +473,10 @@ def test_configure_vm_with_two_ports(*_, **__): runtime_props={ 'network_name': 'port2_network', 'port': { + 'is_primary': False, + 'is_connected': True, + 'ip_address_mode': 'manual', + 'adapter_type': 'VXNET3', 'network_name': 'port2_network', 'ip_address': '10.10.10.2' } @@ -503,7 +514,7 @@ def test_configure_vm_with_two_ports(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') configure(ctx=_ctx) - assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + # assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ 'port1_network' assert _ctx.instance.runtime_properties['server']['ip_address'] == \ @@ -536,6 +547,10 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): runtime_props={ 'network_name': 'port1_network', 'port': { + 'is_primary': False, + 'is_connected': True, + 'ip_address_mode': 'manual', + 'adapter_type': 'VXNET3', 'network_name': 'port1_network', 'ip_address': '10.10.10.5' } @@ -551,6 +566,10 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): runtime_props={ 'network_name': 'port2_network', 'port': { + 'is_primary': False, + 'is_connected': True, + 'ip_address_mode': 'manual', + 'adapter_type': 'VXNET3', 'network_name': 'port1_network', 'ip_address': '10.10.10.2' } @@ -587,7 +606,7 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') configure(ctx=_ctx) - assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + # assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ 'port1_network' assert _ctx.instance.runtime_properties['server']['ip_address'] == \ @@ -595,12 +614,12 @@ def test_configure_vm_with_two_ports_and_network_name(*_, **__): @patch('pyvcloud.vcd.vapp.VApp.get_vm') -@patch('cloudify_vcd.legacy.compute.tasks.get_last_task') @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) @patch('pyvcloud.vcd.vapp.VApp.connect_org_vdc_network') +@patch('cloudify_vcd.legacy.compute.tasks.get_last_task') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('cloudify_vcd.legacy.decorators.check_if_task_successful', return_value=True) @@ -616,6 +635,10 @@ def test_configure_vm_port_no_primary_port(*_, **__): runtime_props={ 'network_name': 'port1_network', 'port': { + 'is_primary': False, + 'is_connected': True, + 'ip_address_mode': 'manual', + 'adapter_type': 'VXNET3', 'network_name': 'port1_network', 'ip_address': '10.10.10.1' } @@ -631,6 +654,11 @@ def test_configure_vm_port_no_primary_port(*_, **__): runtime_props={ 'network_name': 'port2_network', 'port': { + 'is_primary': False, + 'is_connected': True, + 'ip_address_mode': 'manual', + 'adapter_type': 'VXNET3', + 'network_name': 'port2_network', 'ip_address': '10.10.10.2' } } @@ -666,7 +694,6 @@ def test_configure_vm_port_no_primary_port(*_, **__): with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') configure(ctx=_ctx) - assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ 'port2_network' From 493d348ffe95098cdceab02061de77c8524e1c82 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 11:48:43 -0400 Subject: [PATCH 26/58] log info about network --- cloudify_vcd/vapp_tasks.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 8566419..218cf4d 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -584,6 +584,9 @@ def _add_network(_=None, orgvdc_network_name=nic_config['network_name'], fence_mode=fence_mode) return vm, last_task + except OperationNotSupportedException: + ctx.logger.info('We have these networks: {}'.format( + vm.vapp_networks)) except InvalidStateException as e: raise OperationRetry( 'Failed to add network {n} to vm {vm} for {e}.'.format( From 1914c3f95dfa45d2538176784c54482de91ee77a Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 11:55:21 -0400 Subject: [PATCH 27/58] making expose props work with legacy stuff --- cloudify_vcd/legacy/compute/tasks.py | 24 ++++++++++++++++-------- cloudify_vcd/utils.py | 16 ++++++++++++---- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 83ca4e8..847a02f 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -54,7 +54,8 @@ def create_server(vm_client, ctx, **_): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=ctx) + _ctx=ctx, + legacy=True) @decorators.with_vcd_client() @@ -71,7 +72,8 @@ def configure_server(vm_client, ctx, **_): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=ctx) + _ctx=ctx, + legacy=True) @decorators.with_vcd_client() @@ -88,7 +90,8 @@ def start_server(vm_client, ctx, **_): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=ctx) + _ctx=ctx, + legacy=True) @decorators.with_vcd_client() @@ -105,7 +108,8 @@ def stop_server(vm_client, ctx, **_): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=ctx) + _ctx=ctx, + legacy=True) @decorators.with_vcd_client() @@ -126,7 +130,8 @@ def delete_server(vm_client, ctx, **_): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=ctx) + _ctx=ctx, + legacy=True) @decorators.with_port_resource() @@ -157,7 +162,8 @@ def preconfigure_nic(vm_client, ctx, **kwargs): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=port_ctx.target) + _ctx=port_ctx.target, + legacy=True) @decorators.with_vcd_client() @@ -183,7 +189,8 @@ def postconfigure_nic(vm_client, ctx, **kwargs): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=port_ctx.target) + _ctx=port_ctx.target, + legacy=True) @decorators.with_vcd_client() @@ -209,4 +216,5 @@ def unlink_nic(vm_client, ctx, **kwargs): operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, - _ctx=port_ctx.target) + _ctx=port_ctx.target, + legacy=True) diff --git a/cloudify_vcd/utils.py b/cloudify_vcd/utils.py index 9b8adfd..7714723 100644 --- a/cloudify_vcd/utils.py +++ b/cloudify_vcd/utils.py @@ -261,12 +261,16 @@ def get_resource_data(__ctx): return base_properties -def update_runtime_properties(current_ctx, props): +def update_runtime_properties(current_ctx, props, legacy=False): props = cleanup_objectify(props) ctx.logger.debug('Updating instance with properties {props}.'.format( props=props)) - if is_relationship(current_ctx): + if legacy: + is_rel = is_relationship(current_ctx) + else: + is_rel = is_relationship() + if is_rel: if current_ctx.instance.id == ctx.source.instance.id: ctx.source.instance.runtime_properties.update(props) ctx.source.instance.runtime_properties.dirty = True @@ -427,7 +431,11 @@ def use_external_resource(external, t=resource_type, r=resource_name)) -def expose_props(operation_name, resource=None, new_props=None, _ctx=None): +def expose_props(operation_name, + resource=None, + new_props=None, + _ctx=None, + legacy=False): _ctx = _ctx or ctx new_props = new_props or {} @@ -451,7 +459,7 @@ def expose_props(operation_name, resource=None, new_props=None, _ctx=None): # expose props is called after a successful operation, # so we should override this if we reach this point. new_props.update({'__RETRY_BAD_REQUEST': False}) - update_runtime_properties(_ctx, new_props) + update_runtime_properties(_ctx, new_props, legacy) def get_last_task(task): From c65fce6a1c097fb239bca7d015e27293afaa980e Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 11:56:22 -0400 Subject: [PATCH 28/58] fix flake8 --- cloudify_vcd/legacy/compute/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 847a02f..5003b78 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -73,7 +73,7 @@ def configure_server(vm_client, ctx, **_): expose_props(operation_name, resource, _ctx=ctx, - legacy=True) + legacy=True) @decorators.with_vcd_client() From f5dfe6c321cb2d0f81a17f32a62f68f0d71a4f62 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 12:18:58 -0400 Subject: [PATCH 29/58] cycle fence mode --- cloudify_vcd/vapp_tasks.py | 1 + vcd_plugin_sdk/resources/vapp.py | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 218cf4d..9ef9e64 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -587,6 +587,7 @@ def _add_network(_=None, except OperationNotSupportedException: ctx.logger.info('We have these networks: {}'.format( vm.vapp_networks)) + raise except InvalidStateException as e: raise OperationRetry( 'Failed to add network {n} to vm {vm} for {e}.'.format( diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 69f9550..30802c3 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -19,7 +19,8 @@ from pyvcloud.vcd.client import TaskStatus from pyvcloud.vcd.exceptions import ( VcdTaskException, - EntityNotFoundException) + EntityNotFoundException, + OperationNotSupportedException) from .base import VCloudResource from .network import VCloudNetwork @@ -146,12 +147,28 @@ def undeploy(self, vapp_name=None, action='default'): # return self.vapp.delete_vms(vm_names) # def add_network(self, **kwargs): - if kwargs.get('fence_mode') not in ['bridged', - 'isolated', - 'natRouted']: - kwargs.pop('fence_mode', None) - kwargs['is_deployed'] = True - task = self.vapp.connect_org_vdc_network(**kwargs) + # if kwargs.get('fence_mode') not in ['bridged', + # 'isolated', + # 'natRouted']: + # kwargs.pop('fence_mode', None) + # kwargs['is_deployed'] = True + fence_mode = [kwargs.get('fence_mode')] + fence_mode.extend(['bridged', 'isolated', 'natRouted']) + e = None + from time import sleep + for mode in fence_mode: + e = None + kwargs['fence_mode'] = mode + try: + task = self.vapp.connect_org_vdc_network(**kwargs) + except OperationNotSupportedException as e: + self.logger.info('Using fence mode {} did not work.'.format(mode)) + sleep(5) + continue + + if e: + raise e + if 'add_network' in self.tasks: self.tasks['add_network'].append(task) else: From e80cd6376bd57878a656d2af54d7c06ed2594e04 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 12:36:55 -0400 Subject: [PATCH 30/58] add more logs and more tries --- vcd_plugin_sdk/resources/vapp.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 30802c3..61c80e1 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -147,6 +147,12 @@ def undeploy(self, vapp_name=None, action='default'): # return self.vapp.delete_vms(vm_names) # def add_network(self, **kwargs): + self.logger.info('We have these direct networks: {}'.format( + self.vdc.list_orgvdc_direct_networks())) + self.logger.info('We have these routed networks: {}'.format( + self.vdc.list_orgvdc_routed_networks())) + self.logger.info('We have these isolated networks: {}'.format( + self.vdc.list_orgvdc_isolated_networks())) # if kwargs.get('fence_mode') not in ['bridged', # 'isolated', # 'natRouted']: @@ -155,19 +161,34 @@ def add_network(self, **kwargs): fence_mode = [kwargs.get('fence_mode')] fence_mode.extend(['bridged', 'isolated', 'natRouted']) e = None - from time import sleep for mode in fence_mode: e = None kwargs['fence_mode'] = mode try: task = self.vapp.connect_org_vdc_network(**kwargs) except OperationNotSupportedException as e: - self.logger.info('Using fence mode {} did not work.'.format(mode)) + self.logger.error(e) + self.logger.info('Using fence mode {} did not work.' + .format(mode)) sleep(5) continue if e: - raise e + kwargs['is_deployed'] = True + for mode in fence_mode: + e = None + kwargs['fence_mode'] = mode + try: + task = self.vapp.connect_org_vdc_network(**kwargs) + except OperationNotSupportedException as e: + self.logger.error(e) + self.logger.info( + 'Using fence mode {} did not work with is_deployed.' + .format(mode)) + sleep(5) + continue + if e: + raise e if 'add_network' in self.tasks: self.tasks['add_network'].append(task) From b7e9fb27161fd875fce54099186d8f4c6d9be5c1 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 12:39:45 -0400 Subject: [PATCH 31/58] you can pull --- vcd_plugin_sdk/resources/vapp.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 61c80e1..de25bf4 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -190,6 +190,8 @@ def add_network(self, **kwargs): if e: raise e + self.logger.info('These worked {}'.format(kwargs)) + if 'add_network' in self.tasks: self.tasks['add_network'].append(task) else: From 368f57de751d7e48090cb96ceb59ab326e684521 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 13:02:06 -0400 Subject: [PATCH 32/58] fix bad request --- vcd_plugin_sdk/resources/vapp.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index de25bf4..9672dfe 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -19,6 +19,7 @@ from pyvcloud.vcd.client import TaskStatus from pyvcloud.vcd.exceptions import ( VcdTaskException, + BadRequestException, EntityNotFoundException, OperationNotSupportedException) @@ -153,6 +154,11 @@ def add_network(self, **kwargs): self.vdc.list_orgvdc_routed_networks())) self.logger.info('We have these isolated networks: {}'.format( self.vdc.list_orgvdc_isolated_networks())) + bad_networks_exc = (BadRequestException, OperationNotSupportedException) + try: + task = self.vapp.connect_org_vdc_network(kwargs['network_name']) + except bad_networks_exc as e: + self.logger.info('Using just name did not work. {}'.format(e)) # if kwargs.get('fence_mode') not in ['bridged', # 'isolated', # 'natRouted']: @@ -160,35 +166,39 @@ def add_network(self, **kwargs): # kwargs['is_deployed'] = True fence_mode = [kwargs.get('fence_mode')] fence_mode.extend(['bridged', 'isolated', 'natRouted']) - e = None + ee = None for mode in fence_mode: - e = None + ee = None kwargs['fence_mode'] = mode + self.logger.info('kwargs {}'.format(kwargs)) try: task = self.vapp.connect_org_vdc_network(**kwargs) - except OperationNotSupportedException as e: + except bad_networks_exc as e: + ee = e self.logger.error(e) self.logger.info('Using fence mode {} did not work.' .format(mode)) sleep(5) continue - if e: + if ee: kwargs['is_deployed'] = True for mode in fence_mode: - e = None + ee = None kwargs['fence_mode'] = mode + self.logger.info('kwargs {}'.format(kwargs)) try: task = self.vapp.connect_org_vdc_network(**kwargs) - except OperationNotSupportedException as e: + except bad_networks_exc as e: + ee = e self.logger.error(e) self.logger.info( 'Using fence mode {} did not work with is_deployed.' .format(mode)) sleep(5) continue - if e: - raise e + if ee: + raise ee self.logger.info('These worked {}'.format(kwargs)) From 9b15a37f674b35f7334545c6e1e0c8327fc37067 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 13:07:30 -0400 Subject: [PATCH 33/58] update --- vcd_plugin_sdk/resources/vapp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 9672dfe..d22aa47 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -156,7 +156,8 @@ def add_network(self, **kwargs): self.vdc.list_orgvdc_isolated_networks())) bad_networks_exc = (BadRequestException, OperationNotSupportedException) try: - task = self.vapp.connect_org_vdc_network(kwargs['network_name']) + task = self.vapp.connect_org_vdc_network( + kwargs['orgvdc_network_name']) except bad_networks_exc as e: self.logger.info('Using just name did not work. {}'.format(e)) # if kwargs.get('fence_mode') not in ['bridged', From 74101e676b1186d972540e76a9c50ddbc2373a9b Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 13:32:02 -0400 Subject: [PATCH 34/58] handle exception bettter --- cloudify_vcd/utils.py | 5 ++++- cloudify_vcd/vapp_tasks.py | 7 ++++--- vcd_plugin_sdk/resources/vapp.py | 12 ++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cloudify_vcd/utils.py b/cloudify_vcd/utils.py index 7714723..bb3ce3b 100644 --- a/cloudify_vcd/utils.py +++ b/cloudify_vcd/utils.py @@ -118,7 +118,10 @@ def _return_resource_args(self, index): def is_relationship(_ctx=None): _ctx = _ctx or ctx - return _ctx.type == RELATIONSHIP_INSTANCE + try: + return _ctx.type == RELATIONSHIP_INSTANCE + except AttributeError: + return False def is_node_instance(_ctx=None): diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 9ef9e64..392fcec 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -589,9 +589,10 @@ def _add_network(_=None, vm.vapp_networks)) raise except InvalidStateException as e: - raise OperationRetry( - 'Failed to add network {n} to vm {vm} for {e}.'.format( - n=nic_config['network_name'], vm=vm.name, e=e)) + if 'is already connected to vApp' not in str(e): + raise OperationRetry( + 'Failed to add network {n} to vm {vm} for {e}.'.format( + n=nic_config['network_name'], vm=vm.name, e=e)) return vm, None diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index d22aa47..88baeb2 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -155,11 +155,13 @@ def add_network(self, **kwargs): self.logger.info('We have these isolated networks: {}'.format( self.vdc.list_orgvdc_isolated_networks())) bad_networks_exc = (BadRequestException, OperationNotSupportedException) + self.logger.info('1We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) try: task = self.vapp.connect_org_vdc_network( kwargs['orgvdc_network_name']) except bad_networks_exc as e: self.logger.info('Using just name did not work. {}'.format(e)) + self.logger.info('1We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) # if kwargs.get('fence_mode') not in ['bridged', # 'isolated', # 'natRouted']: @@ -174,6 +176,8 @@ def add_network(self, **kwargs): self.logger.info('kwargs {}'.format(kwargs)) try: task = self.vapp.connect_org_vdc_network(**kwargs) + self.logger.info('2We have these networks in vapp: {}'.format( + self.vapp.get_all_networks())) except bad_networks_exc as e: ee = e self.logger.error(e) @@ -181,6 +185,7 @@ def add_network(self, **kwargs): .format(mode)) sleep(5) continue + self.logger.info('3We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) if ee: kwargs['is_deployed'] = True @@ -191,6 +196,9 @@ def add_network(self, **kwargs): try: task = self.vapp.connect_org_vdc_network(**kwargs) except bad_networks_exc as e: + self.logger.info( + '4We have these networks in vapp: {}'.format( + self.vapp.get_all_networks())) ee = e self.logger.error(e) self.logger.info( @@ -198,6 +206,10 @@ def add_network(self, **kwargs): .format(mode)) sleep(5) continue + self.logger.info('5We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) + if kwargs['ororgvdc_network_name'] in self.vapp.get_all_networks(): + return task + if ee: raise ee From 3208c4d3481a9b195ece94541ae678bb0a973a73 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Thu, 4 Nov 2021 19:26:55 -0400 Subject: [PATCH 35/58] all tests should now be OK at least until we revert some testing thingzzz --- cloudify_vcd/decorators.py | 1 - cloudify_vcd/legacy/compute/tasks.py | 4 +- cloudify_vcd/legacy/decorators.py | 7 +- cloudify_vcd/vapp_tasks.py | 20 ++--- .../resources/tests/test_resources.py | 2 +- vcd_plugin_sdk/resources/vapp.py | 81 +++++++++---------- vcloud_network_plugin/tests/test_network.py | 11 ++- vcloud_server_plugin/tests/test_server.py | 17 +++- 8 files changed, 75 insertions(+), 68 deletions(-) diff --git a/cloudify_vcd/decorators.py b/cloudify_vcd/decorators.py index 1c67c20..69e8980 100644 --- a/cloudify_vcd/decorators.py +++ b/cloudify_vcd/decorators.py @@ -1,6 +1,5 @@ from pyvcloud.vcd.exceptions import ( - AccessForbiddenException, InternalServerException, EntityNotFoundException, diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 5003b78..24fe0ec 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -141,7 +141,7 @@ def port_creation_validation(*_, **__): @decorators.with_vcd_client() @decorators.with_vm_resource() -def preconfigure_nic(vm_client, ctx, **kwargs): +def preconfigure_nic(vm_client, ctx, server, **kwargs): for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): resource, result = vapp_tasks._add_network( nic_config=port_ctx.target.instance.runtime_properties['port'], @@ -149,7 +149,7 @@ def preconfigure_nic(vm_client, ctx, **kwargs): vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc_name, - vm_config=vm_client.kwargs, + vm_config=server, vm_class=VCloudVM, vm_ctx=ctx, **kwargs) diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py index ce8f4d4..ea7ce3b 100644 --- a/cloudify_vcd/legacy/decorators.py +++ b/cloudify_vcd/legacy/decorators.py @@ -18,7 +18,7 @@ from cloudify_common_sdk.utils import get_ctx_node, get_ctx_instance from . import utils -from ..utils import (get_last_task, check_if_task_successful) +from ..utils import (expose_props, get_last_task, check_if_task_successful) def with_vcd_client(): @@ -43,6 +43,11 @@ def wrapper_inner(*args, **kwargs): if not check_if_task_successful(resource, last_task): ctx_instance.runtime_properties['__RETRY_BAD_REQUEST'] = True raise OperationRetry('Pending for operation completion.') + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx, + legacy=True) return wrapper_inner return wrapper_outer diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 392fcec..01b8b73 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -565,9 +565,8 @@ def _add_network(_=None, if nic_network: nic_config['network_name'] = nic_network - ctx.logger.info('nic_config {}'.format(nic_config)) - ctx.logger.info('vm_config {}'.format(vm_config)) + ctx.logger.info('Initializing vm with vm config {}'.format(vm_config)) vm = vm_class( vm_id, @@ -579,20 +578,21 @@ def _add_network(_=None, ) if nic_network not in vm.vapp_networks: + vapp_network_config = { + 'orgvdc_network_name': nic_network, + 'fence_mode': fence_mode + } + ctx.logger.info( + 'Initializing vapp network with vapp network config {}'.format( + vapp_network_config)) try: - last_task = vm.add_vapp_network( - orgvdc_network_name=nic_config['network_name'], - fence_mode=fence_mode) + last_task = vm.add_vapp_network(**vapp_network_config) return vm, last_task - except OperationNotSupportedException: - ctx.logger.info('We have these networks: {}'.format( - vm.vapp_networks)) - raise except InvalidStateException as e: if 'is already connected to vApp' not in str(e): raise OperationRetry( 'Failed to add network {n} to vm {vm} for {e}.'.format( - n=nic_config['network_name'], vm=vm.name, e=e)) + n=nic_network, vm=vm.name, e=e)) return vm, None diff --git a/vcd_plugin_sdk/resources/tests/test_resources.py b/vcd_plugin_sdk/resources/tests/test_resources.py index 4e71c14..b54368f 100644 --- a/vcd_plugin_sdk/resources/tests/test_resources.py +++ b/vcd_plugin_sdk/resources/tests/test_resources.py @@ -506,7 +506,7 @@ def test_vcloud_vm(*_, **__): vcloud_vm.add_vapp_network(**{ 'orgvdc_network_name': 'bar', }) - assert vcloud_vm.vapp_object.vapp.connect_org_vdc_network.call_count == 1 + assert vcloud_vm.vapp_object.vapp.connect_org_vdc_network.call_count == 2 vcloud_vm.remove_vapp_network('bar') assert \ vcloud_vm.vapp_object.vapp.disconnect_org_vdc_network.call_count == 1 diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 88baeb2..bff4cb0 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -147,6 +147,7 @@ def undeploy(self, vapp_name=None, action='default'): # def delete_vms(self, vm_names): # return self.vapp.delete_vms(vm_names) # + def add_network(self, **kwargs): self.logger.info('We have these direct networks: {}'.format( self.vdc.list_orgvdc_direct_networks())) @@ -154,66 +155,60 @@ def add_network(self, **kwargs): self.vdc.list_orgvdc_routed_networks())) self.logger.info('We have these isolated networks: {}'.format( self.vdc.list_orgvdc_isolated_networks())) - bad_networks_exc = (BadRequestException, OperationNotSupportedException) - self.logger.info('1We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) + bad_networks_exc = (BadRequestException, + OperationNotSupportedException) + if 'network_name' in kwargs: + kwargs['orgvdc_network_name'] = kwargs['network_name'] try: task = self.vapp.connect_org_vdc_network( kwargs['orgvdc_network_name']) except bad_networks_exc as e: self.logger.info('Using just name did not work. {}'.format(e)) - self.logger.info('1We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) - # if kwargs.get('fence_mode') not in ['bridged', - # 'isolated', - # 'natRouted']: - # kwargs.pop('fence_mode', None) - # kwargs['is_deployed'] = True + self.logger.info('1We have these networks in vapp: {}'.format( + self.vapp.get_all_networks())) + fence_mode = [kwargs.get('fence_mode')] fence_mode.extend(['bridged', 'isolated', 'natRouted']) - ee = None for mode in fence_mode: - ee = None kwargs['fence_mode'] = mode - self.logger.info('kwargs {}'.format(kwargs)) try: + self.logger.info('Trying these parameters {}'.format(kwargs)) task = self.vapp.connect_org_vdc_network(**kwargs) - self.logger.info('2We have these networks in vapp: {}'.format( - self.vapp.get_all_networks())) except bad_networks_exc as e: - ee = e self.logger.error(e) - self.logger.info('Using fence mode {} did not work.' - .format(mode)) - sleep(5) - continue - self.logger.info('3We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) - - if ee: - kwargs['is_deployed'] = True - for mode in fence_mode: - ee = None - kwargs['fence_mode'] = mode - self.logger.info('kwargs {}'.format(kwargs)) + self.logger.info('These parameters failed: {}'.format( + kwargs)) + sleep(2) try: - task = self.vapp.connect_org_vdc_network(**kwargs) - except bad_networks_exc as e: self.logger.info( - '4We have these networks in vapp: {}'.format( - self.vapp.get_all_networks())) - ee = e + 'Trying these parameters {}'.format(kwargs)) + task = self.vapp.connect_org_vdc_network( + is_deployed=True, **kwargs) + except bad_networks_exc as e: self.logger.error(e) self.logger.info( - 'Using fence mode {} did not work with is_deployed.' - .format(mode)) - sleep(5) - continue - self.logger.info('5We have these networks in vapp: {}'.format(self.vapp.get_all_networks())) - if kwargs['ororgvdc_network_name'] in self.vapp.get_all_networks(): - return task - - if ee: - raise ee - - self.logger.info('These worked {}'.format(kwargs)) + 'These parameters failed: {}'.format(kwargs)) + # sleep(2) + else: + self.logger.info( + 'These parameters did not fail: {}'.format( + kwargs)) + break + continue + else: + self.logger.info('These parameters did not fail: {}'.format( + kwargs)) + break + self.logger.info( + '3We have these networks in vapp: {}'.format( + self.vapp.get_all_networks())) + + self.logger.info('Pausing to let vcloud think....') + # sleep(10) + + if 'orgvdc_network_name' in kwargs: + if kwargs['orgvdc_network_name'] in self.vapp.get_all_networks(): + return task if 'add_network' in self.tasks: self.tasks['add_network'].append(task) diff --git a/vcloud_network_plugin/tests/test_network.py b/vcloud_network_plugin/tests/test_network.py index 2569340..85bcd6a 100644 --- a/vcloud_network_plugin/tests/test_network.py +++ b/vcloud_network_plugin/tests/test_network.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from mock import patch from copy import deepcopy from cloudify.state import current_ctx +from mock import patch, PropertyMock from .. network import create, delete from cloudify_vcd.legacy.tests import create_ctx, DEFAULT_NODE_PROPS @@ -97,8 +97,6 @@ def test_delete_external_network_with_gateway(*_, **__): @patch('pyvcloud.vcd.vdc.VDC.get_gateway', return_value={'href': 'foo'}) @patch('cloudify_vcd.legacy.decorators.check_if_task_successful', return_value=True) -@patch('vcd_plugin_sdk.resources.network.VCloudNetwork.get_network', - return_value=False) @patch('pyvcloud.vcd.vdc.Platform.get_external_network', return_value={'href': 'foo'}) def test_create_network_with_gateway(*_, **__): @@ -111,8 +109,9 @@ def test_create_network_with_gateway(*_, **__): ], node_properties=network_node_props) current_ctx.set(_ctx) - create(ctx=_ctx) - assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + with patch('cloudify_vcd.legacy.utils.VCloudNetwork.exists', + new_callable=PropertyMock) as net_exists: + net_exists.return_value = False @patch('cloudify_vcd.legacy.utils.NamedTemporaryFile') @@ -136,4 +135,4 @@ def test_delete_network_with_gateway(*_, **__): operation_name='cloudify.interfaces.lifecycle.delete') current_ctx.set(_ctx) delete(ctx=_ctx) - assert _ctx.instance.runtime_properties['resource_id'] == 'foo' + assert '__deleted' in _ctx.instance.runtime_properties diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index 6a42d87..cc74788 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -13,7 +13,7 @@ # limitations under the License. from copy import deepcopy -from mock import patch, MagicMock +from mock import patch, MagicMock, PropertyMock from cloudify.state import current_ctx from .. server import create, delete, configure, start, stop @@ -243,7 +243,10 @@ def test_create_vm(*_, **__): current_ctx.set(_ctx) with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') - create(ctx=_ctx) + with patch('cloudify_vcd.legacy.utils.VCloudVM.exists', + new_callable=PropertyMock) as vm_exists: + vm_exists.return_value = False + create(ctx=_ctx) assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ @@ -320,7 +323,10 @@ def test_create_vm_no_primary_port(*_, **__): current_ctx.set(_ctx) with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') - create(ctx=_ctx) + with patch('cloudify_vcd.legacy.utils.VCloudVM.exists', + new_callable=PropertyMock) as vm_exists: + vm_exists.return_value = False + create(ctx=_ctx) assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ @@ -397,7 +403,10 @@ def test_create_vm_port_network(*_, **__): current_ctx.set(_ctx) with patch('vcd_plugin_sdk.resources.base.VDC') as vdc: vdc.client.get_api_version = (lambda: '33') - create(ctx=_ctx) + with patch('cloudify_vcd.legacy.utils.VCloudVM.exists', + new_callable=PropertyMock) as vm_exists: + vm_exists.return_value = False + create(ctx=_ctx) assert '__VM_CREATE_VAPP' in _ctx.instance.runtime_properties assert _ctx.instance.runtime_properties['resource_id'] == 'foo' assert _ctx.instance.runtime_properties['server']['network'] == \ From 28910518ce651a8ae81c06233170c8d83f447e41 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 08:31:12 -0500 Subject: [PATCH 36/58] try to set name --- cloudify_vcd/legacy/compute/tasks.py | 25 +++++++++++++++---------- cloudify_vcd/legacy/network/tasks.py | 20 ++++++++++++-------- cloudify_vcd/legacy/utils.py | 4 ++-- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 24fe0ec..347d089 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -51,11 +51,14 @@ def create_server(vm_client, ctx, **_): vm_config=vm_kwargs, vm_class=VCloudVM, vm_ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) + else: + resource = vm_client.vm + ctx.logger.info('Logging resource object: {}'.format(resource)) + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + vm_client, + _ctx=ctx, + legacy=True) @decorators.with_vcd_client() @@ -127,11 +130,13 @@ def delete_server(vm_client, ctx, **_): vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) + else: + resource = vm_client + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx, + legacy=True) @decorators.with_port_resource() diff --git a/cloudify_vcd/legacy/network/tasks.py b/cloudify_vcd/legacy/network/tasks.py index c45b2d7..a207a11 100644 --- a/cloudify_vcd/legacy/network/tasks.py +++ b/cloudify_vcd/legacy/network/tasks.py @@ -50,10 +50,12 @@ def create_network(network_client, gateway_client, ctx, **_): network_config=network_client.kwargs, network_class=VCloudNetwork, ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx) + else: + resource = network_client + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) @decorators.with_vcd_client() @@ -72,7 +74,9 @@ def delete_network(network_client, ctx, **_): network_config=network_client.kwargs, network_class=VCloudNetwork, ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx) + else: + resource = network_client + operation_name = ctx.operation.name.split('.')[-1] + expose_props(operation_name, + resource, + _ctx=ctx) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 9b566ad..30486fd 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -207,9 +207,9 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): _ctx_instance = get_ctx_instance(ctx) if 'name' in server: name = server.pop('name') - elif 'name' in _ctx_instance.runtime_properties: + if not name and 'name' in _ctx_instance.runtime_properties: name = _ctx_instance.runtime_properties['name'] - else: + if not name: name = _ctx_node.properties.get('resource_id', _ctx_instance.id) tasks = _ctx_instance.runtime_properties.get('__TASKS', []) convert_vm_config(server) From 87c17b2c49a45c179d940736474e963277d8fa72 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 08:56:04 -0500 Subject: [PATCH 37/58] rebuild --- cloudify_vcd/legacy/utils.py | 1 + cloudify_vcd/vapp_tasks.py | 5 +++++ vcd_plugin_sdk/resources/vapp.py | 9 ++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 30486fd..041a091 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -205,6 +205,7 @@ def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): def get_vm_client(server, vcloud_cx, vcloud_config, ctx): _ctx_node = get_ctx_node(ctx) _ctx_instance = get_ctx_instance(ctx) + name = None if 'name' in server: name = server.pop('name') if not name and 'name' in _ctx_instance.runtime_properties: diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 01b8b73..c82a98b 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -594,6 +594,11 @@ def _add_network(_=None, 'Failed to add network {n} to vm {vm} for {e}.'.format( n=nic_network, vm=vm.name, e=e)) + if nic_network not in vm.vapp_networks: + raise OperationRetry( + 'Waiting to add network {} to vapp {}.'.format( + nic_network, vapp_name)) + return vm, None diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index bff4cb0..d21906f 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -163,7 +163,7 @@ def add_network(self, **kwargs): task = self.vapp.connect_org_vdc_network( kwargs['orgvdc_network_name']) except bad_networks_exc as e: - self.logger.info('Using just name did not work. {}'.format(e)) + self.logger.info('Using just name did not work. {}'.format(str(e))) self.logger.info('1We have these networks in vapp: {}'.format( self.vapp.get_all_networks())) @@ -175,7 +175,7 @@ def add_network(self, **kwargs): self.logger.info('Trying these parameters {}'.format(kwargs)) task = self.vapp.connect_org_vdc_network(**kwargs) except bad_networks_exc as e: - self.logger.error(e) + self.logger.error(str(e)) self.logger.info('These parameters failed: {}'.format( kwargs)) sleep(2) @@ -185,7 +185,7 @@ def add_network(self, **kwargs): task = self.vapp.connect_org_vdc_network( is_deployed=True, **kwargs) except bad_networks_exc as e: - self.logger.error(e) + self.logger.error(str(e)) self.logger.info( 'These parameters failed: {}'.format(kwargs)) # sleep(2) @@ -210,6 +210,9 @@ def add_network(self, **kwargs): if kwargs['orgvdc_network_name'] in self.vapp.get_all_networks(): return task + if not task: + return + if 'add_network' in self.tasks: self.tasks['add_network'].append(task) else: From 8a63874dfde73ace2d99ff5c4b3eec36bf681571 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 09:56:17 -0500 Subject: [PATCH 38/58] fix that annoying bug --- cloudify_vcd/legacy/compute/tasks.py | 10 ++++---- cloudify_vcd/legacy/decorators.py | 5 ---- cloudify_vcd/vapp_tasks.py | 34 +++++++++++++--------------- vcd_plugin_sdk/resources/vapp.py | 5 +++- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 347d089..764c483 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -72,11 +72,11 @@ def configure_server(vm_client, ctx, **_): vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) + # operation_name = ctx.operation.name.split('.')[-1] + # expose_props(operation_name, + # resource, + # _ctx=ctx, + # legacy=True) @decorators.with_vcd_client() diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py index ea7ce3b..b7b4f64 100644 --- a/cloudify_vcd/legacy/decorators.py +++ b/cloudify_vcd/legacy/decorators.py @@ -43,11 +43,6 @@ def wrapper_inner(*args, **kwargs): if not check_if_task_successful(resource, last_task): ctx_instance.runtime_properties['__RETRY_BAD_REQUEST'] = True raise OperationRetry('Pending for operation completion.') - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) return wrapper_inner return wrapper_outer diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index c82a98b..cfa6494 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -217,8 +217,7 @@ def _create_vm(vm_external=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) # or vapp_id + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) network = find_rel_by_type( vm_ctx.instance, REL_VM_NETWORK) @@ -283,6 +282,14 @@ def configure_vm(*args, **kwargs): return _configure_vm(*args, **kwargs) +def get_vapp_name_from_vm_ctx(vm_ctx): + vapp_name = find_resource_id_from_relationship_by_type( + vm_ctx.instance, REL_VM_VAPP) + if not vapp_name: + vapp_name = vm_ctx.instance.runtime_properties['resource_id'] + return vapp_name + + def _configure_vm(_=None, vm_id=None, vm_client=None, @@ -292,8 +299,7 @@ def _configure_vm(_=None, vm_ctx=None, **__): - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) return vm_class( vm_id, vapp_name, @@ -330,8 +336,7 @@ def _start_vm(vm_external=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) vm = vm_class( vm_id, vapp_name, @@ -388,8 +393,7 @@ def _stop_vm(vm_external=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) vm = vm_class( vm_id, vapp_name, @@ -441,8 +445,7 @@ def _delete_vm(vm_external=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) vm = vm_class( vm_id, vapp_name, @@ -548,10 +551,7 @@ def _add_network(_=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) - if not vapp_name: - vapp_name = vm_id + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) vapp_node = find_rel_by_type(vm_ctx.instance, REL_VM_VAPP) @@ -642,8 +642,7 @@ def _add_nic(_=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) @@ -714,8 +713,7 @@ def _delete_nic(_=None, :return: """ - vapp_name = find_resource_id_from_relationship_by_type( - vm_ctx.instance, REL_VM_VAPP) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) if nic_network: diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index d21906f..31349af 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -149,6 +149,7 @@ def undeploy(self, vapp_name=None, action='default'): # def add_network(self, **kwargs): + task = None self.logger.info('We have these direct networks: {}'.format( self.vdc.list_orgvdc_direct_networks())) self.logger.info('We have these routed networks: {}'.format( @@ -305,7 +306,9 @@ def exposed_data(self): sleep(1) return data - def get_vm(self, vm_name): + def get_vm(self, vm_name=None): + if not vm_name: + vm_name = self._vm_name vm_resource = self.vapp_object.vapp.get_vm(vm_name) vm = VM(self.client, resource=vm_resource) return vm From a7a6faf65272b87bdc0d080aa7b13973470845bd Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 09:57:48 -0500 Subject: [PATCH 39/58] a little nitpicky --- cloudify_vcd/legacy/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudify_vcd/legacy/decorators.py b/cloudify_vcd/legacy/decorators.py index b7b4f64..ce8f4d4 100644 --- a/cloudify_vcd/legacy/decorators.py +++ b/cloudify_vcd/legacy/decorators.py @@ -18,7 +18,7 @@ from cloudify_common_sdk.utils import get_ctx_node, get_ctx_instance from . import utils -from ..utils import (expose_props, get_last_task, check_if_task_successful) +from ..utils import (get_last_task, check_if_task_successful) def with_vcd_client(): From 4371b476b185fe2e8c1ddbe58f7a5269f9d3331c Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 10:50:11 -0500 Subject: [PATCH 40/58] pushed --- cloudify_vcd/legacy/compute/tasks.py | 6 ++++-- cloudify_vcd/vapp_tasks.py | 10 +++++----- vcd_plugin_sdk/resources/vapp.py | 5 ++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 764c483..0a1d2d0 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -173,7 +173,9 @@ def preconfigure_nic(vm_client, ctx, server, **kwargs): @decorators.with_vcd_client() @decorators.with_vm_resource() -def postconfigure_nic(vm_client, ctx, **kwargs): +def postconfigure_nic(vm_client, server, ctx, **kwargs): + ctx.logger.info('Preconfigure vm client name {}'.format(vm_client.name)) + ctx.logger.info('Preconfigure server {}'.format(server)) for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): resource, result = vapp_tasks._add_nic( nic_config=port_ctx.target.instance.runtime_properties['port'], @@ -181,7 +183,7 @@ def postconfigure_nic(vm_client, ctx, **kwargs): vm_id=vm_client.name, vm_client=vm_client.connection, vm_vdc=vm_client.vdc_name, - vm_config=vm_client.kwargs, + vm_config=server, vm_class=VCloudVM, vm_ctx=ctx, **kwargs) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index cfa6494..478bd52 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -282,12 +282,12 @@ def configure_vm(*args, **kwargs): return _configure_vm(*args, **kwargs) -def get_vapp_name_from_vm_ctx(vm_ctx): +def get_vapp_name_from_vm_ctx(vm_ctx, vm_id): vapp_name = find_resource_id_from_relationship_by_type( vm_ctx.instance, REL_VM_VAPP) if not vapp_name: - vapp_name = vm_ctx.instance.runtime_properties['resource_id'] - return vapp_name + return vm_id + return vm_id def _configure_vm(_=None, @@ -573,7 +573,7 @@ def _add_network(_=None, vapp_name, vm_client, vdc_name=vm_vdc, - kwargs={}, + kwargs=vm_config, vapp_kwargs=vm_config ) @@ -654,7 +654,7 @@ def _add_nic(_=None, vapp_name, vm_client, vdc_name=vm_vdc, - kwargs={}, + kwargs=vm_config, vapp_kwargs=vm_config ) last_task = None diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 31349af..50fb5b0 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -95,6 +95,8 @@ def get_catalog_items(self): return items def get_vapp(self, vapp_name=None): + vapp_name = vapp_name or self.name + self.logger.info('Looking for vapp {}'.format(vapp_name)) vapp_resource = self.vdc.get_vapp(vapp_name) return VApp(self.client, resource=vapp_resource) @@ -308,7 +310,8 @@ def exposed_data(self): def get_vm(self, vm_name=None): if not vm_name: - vm_name = self._vm_name + vm_name = self.name + self.logger.info('Looking for vm_name {}'.format(vm_name)) vm_resource = self.vapp_object.vapp.get_vm(vm_name) vm = VM(self.client, resource=vm_resource) return vm From 85d5a1a6c0768c84a92f51fa968bd8445e6e206b Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 10:52:53 -0500 Subject: [PATCH 41/58] fix that --- cloudify_vcd/vapp_tasks.py | 16 ++++++++-------- vcloud_server_plugin/tests/test_server.py | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 478bd52..3cc5469 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -217,7 +217,7 @@ def _create_vm(vm_external=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) network = find_rel_by_type( vm_ctx.instance, REL_VM_NETWORK) @@ -299,7 +299,7 @@ def _configure_vm(_=None, vm_ctx=None, **__): - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) return vm_class( vm_id, vapp_name, @@ -336,7 +336,7 @@ def _start_vm(vm_external=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) vm = vm_class( vm_id, vapp_name, @@ -393,7 +393,7 @@ def _stop_vm(vm_external=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) vm = vm_class( vm_id, vapp_name, @@ -445,7 +445,7 @@ def _delete_vm(vm_external=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) vm = vm_class( vm_id, vapp_name, @@ -551,7 +551,7 @@ def _add_network(_=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) vapp_node = find_rel_by_type(vm_ctx.instance, REL_VM_VAPP) @@ -642,7 +642,7 @@ def _add_nic(_=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) @@ -713,7 +713,7 @@ def _delete_nic(_=None, :return: """ - vapp_name = get_vapp_name_from_vm_ctx(vm_ctx) + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) if nic_network: diff --git a/vcloud_server_plugin/tests/test_server.py b/vcloud_server_plugin/tests/test_server.py index cc74788..78d8317 100644 --- a/vcloud_server_plugin/tests/test_server.py +++ b/vcloud_server_plugin/tests/test_server.py @@ -57,6 +57,7 @@ def get_vm_ctx(existing=False, @patch('cloudify_vcd.legacy.utils.get_deployment_dir') @patch('cloudify_vcd.legacy.decorators.get_last_task') @patch('vcd_plugin_sdk.connection.Org', autospec=True) +@patch('vcd_plugin_sdk.resources.vapp.VCloudVM.get_vm') @patch('vcd_plugin_sdk.connection.Client', autospec=True) @patch('vcd_plugin_sdk.resources.vapp.VCloudVM.exists', return_value=True) @patch('cloudify_vcd.legacy.decorators.check_if_task_successful', From 2283ab03ca37b36891affd09b7fa5de824f2dceb Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 11:19:39 -0500 Subject: [PATCH 42/58] using this --- cloudify_vcd/legacy/compute/tasks.py | 7 +++++-- cloudify_vcd/legacy/utils.py | 4 ++++ cloudify_vcd/vapp_tasks.py | 3 +++ vcloud_server_plugin/server.py | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 0a1d2d0..289f2b6 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -174,13 +174,16 @@ def preconfigure_nic(vm_client, ctx, server, **kwargs): @decorators.with_vcd_client() @decorators.with_vm_resource() def postconfigure_nic(vm_client, server, ctx, **kwargs): - ctx.logger.info('Preconfigure vm client name {}'.format(vm_client.name)) + vm_id = vm_client.name + if not vm_id: + vm_id = ctx.node.properties.get('server', {}).get('name') + ctx.logger.info('Preconfigure vm client name {}'.format(vm_id)) ctx.logger.info('Preconfigure server {}'.format(server)) for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): resource, result = vapp_tasks._add_nic( nic_config=port_ctx.target.instance.runtime_properties['port'], nic_ctx=port_ctx.target, - vm_id=vm_client.name, + vm_id=vm_id, vm_client=vm_client.connection, vm_vdc=vm_client.vdc_name, vm_config=server, diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 041a091..84596ac 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -210,6 +210,9 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): name = server.pop('name') if not name and 'name' in _ctx_instance.runtime_properties: name = _ctx_instance.runtime_properties['name'] + if not name: + server_from_props = _ctx_node.properties.get('server') + name = server_from_props.get('name') if not name: name = _ctx_node.properties.get('resource_id', _ctx_instance.id) tasks = _ctx_instance.runtime_properties.get('__TASKS', []) @@ -217,6 +220,7 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): get_server_network(server, _ctx_node, _ctx_instance) _ctx_instance.runtime_properties['resource_id'] = name _ctx_instance.runtime_properties['server'] = server + # TODO: Change vcloud VM name to host name guest customization pizazz. return VCloudVM(name, name, connection=vcloud_cx, diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 3cc5469..898d61e 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -649,6 +649,9 @@ def _add_nic(_=None, if nic_network: nic_config['network_name'] = nic_network + ctx.logger.info('We are using this VM ID : {}'.format(vm_id)) + ctx.logger.info('We are using this VM App : {}'.format(vapp_name)) + vm = vm_class( vm_id, vapp_name, diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index 494fdbf..14ac1ed 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -33,7 +33,7 @@ def create(*args, **kwargs): @operation(resumable=True) def configure(*args, **kwargs): preconfigure_nic(*args, **kwargs) - configure_server(*args, **kwargs) + # configure_server(*args, **kwargs) postconfigure_nic(*args, **kwargs) From 1d95c18387892572372e24e516f2e011cc677208 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 11:33:49 -0500 Subject: [PATCH 43/58] more fools games --- cloudify_vcd/legacy/utils.py | 3 +++ cloudify_vcd/vapp_tasks.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 84596ac..3578bac 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -215,11 +215,14 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): name = server_from_props.get('name') if not name: name = _ctx_node.properties.get('resource_id', _ctx_instance.id) + if not name and 'resource_id' in _ctx_instance.runtime_properties: + name = _ctx_instance.runtime_properties['resource_id'] tasks = _ctx_instance.runtime_properties.get('__TASKS', []) convert_vm_config(server) get_server_network(server, _ctx_node, _ctx_instance) _ctx_instance.runtime_properties['resource_id'] = name _ctx_instance.runtime_properties['server'] = server + ctx.logger.info('We are getting this name: {}'.format(name)) # TODO: Change vcloud VM name to host name guest customization pizazz. return VCloudVM(name, name, diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 898d61e..f24d006 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -642,6 +642,9 @@ def _add_nic(_=None, :return: """ + if not vm_id: + vm_id = vm_ctx.node.properties.get('server', {}).get('name') + vapp_name = get_vapp_name_from_vm_ctx(vm_ctx, vm_id) nic_network = find_resource_id_from_relationship_by_type( nic_ctx.instance, REL_NIC_NETWORK) From d7d429b982242ef19842597a4888d19aef5df991 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 11:57:06 -0500 Subject: [PATCH 44/58] push --- cloudify_vcd/legacy/compute/tasks.py | 2 ++ cloudify_vcd/legacy/utils.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 289f2b6..4ed2990 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -180,6 +180,8 @@ def postconfigure_nic(vm_client, server, ctx, **kwargs): ctx.logger.info('Preconfigure vm client name {}'.format(vm_id)) ctx.logger.info('Preconfigure server {}'.format(server)) for port_ctx in find_rels_by_type(get_ctx_instance(), VM_NIC_REL): + # port = convert_nic_config( + # port_ctx.target.instance.runtime_properties['port']) resource, result = vapp_tasks._add_nic( nic_config=port_ctx.target.instance.runtime_properties['port'], nic_ctx=port_ctx.target, diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 3578bac..c63642a 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -375,6 +375,9 @@ def convert_port_config(config): if 'primary_interface' in config: config['is_primary'] = config.pop('primary_interface') + if 'adapter_type' not in config: + config['adapter_type'] = 'VMXNET3' + for key in OLD_PORT_KEYS: config.pop(key, None) From 9019e474a90ae1a252b54ed70d311205f22f4a8f Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Sun, 7 Nov 2021 12:22:14 -0500 Subject: [PATCH 45/58] testing --- cloudify_vcd/legacy/compute/tasks.py | 16 +++++++++++++- cloudify_vcd/vapp_tasks.py | 31 +++++++++++++++++++--------- vcloud_server_plugin/server.py | 2 +- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 4ed2990..5e36457 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -14,7 +14,7 @@ from copy import deepcopy -from cloudify.exceptions import OperationRetry +from cloudify.exceptions import OperationRetry, NonRecoverableError from vcd_plugin_sdk.resources.vapp import VCloudVM from cloudify_common_sdk.utils import ( @@ -193,6 +193,20 @@ def postconfigure_nic(vm_client, server, ctx, **kwargs): vm_ctx=ctx, **kwargs) last_task = get_last_task(result) + temp_storage = ctx.instance.runtime_properties.get( + '__TEMP_STORAGE', + { + 'ip_address': None, + 'mac_address': None + } + ) + try: + port_ctx.target.instance.runtime_properties['ip_address'] = \ + temp_storage['ip_address'] + port_ctx.target.instance.runtime_properties['mac_address'] = \ + temp_storage['mac_address'] + except NonRecoverableError: + ctx.logger.info('TODO: FIX THIS') if not check_if_task_successful(resource, last_task): port_ctx.target.instance.runtime_properties['__RETRY_BAD_' 'REQUEST'] = \ diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index f24d006..376d613 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -666,16 +666,27 @@ def _add_nic(_=None, last_task = None if not vm.get_nic_from_config(nic_config): last_task = vm.add_nic(**nic_config) - nic_ctx.instance.runtime_properties['ip_address'] = None - nic_ctx.instance.runtime_properties['mac_address'] = None - for nic in vm.nics: - _nic_network = nic.get('network') - if _nic_network == nic_network: - nic_ctx.instance.runtime_properties['ip_address'] = \ - nic.get('ip_address') - nic_ctx.instance.runtime_properties['mac_address'] = \ - nic.get('mac_address') - break + try: + nic_ctx.instance.runtime_properties['ip_address'] = None + nic_ctx.instance.runtime_properties['mac_address'] = None + except NonRecoverableError: + vm_ctx.instance.runtime_properties['__TEMP_STORAGE'] = {} + for nic in vm.nics: + _nic_network = nic.get('network') + if _nic_network == nic_network: + vm_ctx.instance.runtime_properties['__TEMP_STORAGE']['ip_address'] = nic.get('ip_address') # noqa + vm_ctx.instance.runtime_properties['__TEMP_STORAGE']['mac_address'] = nic.get('mac_address') # noqa + break + + else: + for nic in vm.nics: + _nic_network = nic.get('network') + if _nic_network == nic_network: + nic_ctx.instance.runtime_properties['ip_address'] = \ + nic.get('ip_address') + nic_ctx.instance.runtime_properties['mac_address'] = \ + nic.get('mac_address') + break return vm, last_task diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index 14ac1ed..36a6ed1 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -15,7 +15,7 @@ from cloudify.decorators import operation from cloudify_vcd.legacy.compute.tasks import ( create_server, - configure_server, + # configure_server, start_server, stop_server, delete_server, From 91ab512fb36d302ba5779534f7a5282a43b8cec9 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 8 Nov 2021 08:45:12 -0500 Subject: [PATCH 46/58] properly assign ip --- cloudify_vcd/legacy/compute/tasks.py | 18 +++--------------- cloudify_vcd/vapp_tasks.py | 9 ++------- plugin.yaml | 3 ++- vcloud_server_plugin/server.py | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 5e36457..92bc5b5 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -14,7 +14,7 @@ from copy import deepcopy -from cloudify.exceptions import OperationRetry, NonRecoverableError +from cloudify.exceptions import OperationRetry from vcd_plugin_sdk.resources.vapp import VCloudVM from cloudify_common_sdk.utils import ( @@ -95,6 +95,8 @@ def start_server(vm_client, ctx, **_): resource, _ctx=ctx, legacy=True) + ctx.instance.runtime_properties['vcloud_vapp_name'] = \ + ctx.instance.runtime_properties.get('name') @decorators.with_vcd_client() @@ -193,20 +195,6 @@ def postconfigure_nic(vm_client, server, ctx, **kwargs): vm_ctx=ctx, **kwargs) last_task = get_last_task(result) - temp_storage = ctx.instance.runtime_properties.get( - '__TEMP_STORAGE', - { - 'ip_address': None, - 'mac_address': None - } - ) - try: - port_ctx.target.instance.runtime_properties['ip_address'] = \ - temp_storage['ip_address'] - port_ctx.target.instance.runtime_properties['mac_address'] = \ - temp_storage['mac_address'] - except NonRecoverableError: - ctx.logger.info('TODO: FIX THIS') if not check_if_task_successful(resource, last_task): port_ctx.target.instance.runtime_properties['__RETRY_BAD_' 'REQUEST'] = \ diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 376d613..5721184 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -670,13 +670,8 @@ def _add_nic(_=None, nic_ctx.instance.runtime_properties['ip_address'] = None nic_ctx.instance.runtime_properties['mac_address'] = None except NonRecoverableError: - vm_ctx.instance.runtime_properties['__TEMP_STORAGE'] = {} - for nic in vm.nics: - _nic_network = nic.get('network') - if _nic_network == nic_network: - vm_ctx.instance.runtime_properties['__TEMP_STORAGE']['ip_address'] = nic.get('ip_address') # noqa - vm_ctx.instance.runtime_properties['__TEMP_STORAGE']['mac_address'] = nic.get('mac_address') # noqa - break + ctx.logger.debug( + 'Skipping IP assignment in legacy plugin will do it later.') else: for nic in vm.nics: diff --git a/plugin.yaml b/plugin.yaml index d5f6e60..155ee63 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -401,5 +401,6 @@ relationships: target_interfaces: cloudify.interfaces.relationship_lifecycle: preconfigure: {} - postconfigure: {} + postconfigure: + implementation: vcloud.vcloud_server_plugin.server.postconfigure unlink: {} diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index 36a6ed1..fd8a565 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -37,6 +37,20 @@ def configure(*args, **kwargs): postconfigure_nic(*args, **kwargs) +@operation +def postconfigure(ctx, *args, **kwargs): + ctx.logger.info('Assigning IP properties...') + nic = None + for nic in ctx.target.instance.runtime_properties.get('nics', []): + if nic['primary'] == 'true': + break + + if nic: + ctx.logger.info('Found primary IP address.') + ctx.target.instance.runtime_properties['ip'] = \ + nic['primary']['ip_address'] + + @operation(resumable=True) def start(*args, **kwargs): start_server(*args, **kwargs) From 67e6a2fb3cdc0353fc13ee36193db6f8a9cbd4dc Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 8 Nov 2021 09:27:10 -0500 Subject: [PATCH 47/58] fix fumb mistake --- cloudify_vcd/legacy/utils.py | 1 + cloudify_vcd/vapp_tasks.py | 6 +++++- vcloud_server_plugin/server.py | 15 +++++++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index c63642a..b04d12b 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -217,6 +217,7 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): name = _ctx_node.properties.get('resource_id', _ctx_instance.id) if not name and 'resource_id' in _ctx_instance.runtime_properties: name = _ctx_instance.runtime_properties['resource_id'] + _ctx_instance.runtime_properties['name'] = name tasks = _ctx_instance.runtime_properties.get('__TASKS', []) convert_vm_config(server) get_server_network(server, _ctx_node, _ctx_instance) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 5721184..b6d8da8 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -664,7 +664,11 @@ def _add_nic(_=None, vapp_kwargs=vm_config ) last_task = None - if not vm.get_nic_from_config(nic_config): + try: + has_nic_in_config = vm.get_nic_from_config(nic_config) + except AttributeError: + raise OperationRetry('Waiting for nics to be assigned...') + if not has_nic_in_config: last_task = vm.add_nic(**nic_config) try: nic_ctx.instance.runtime_properties['ip_address'] = None diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index fd8a565..e3aa103 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -35,19 +35,18 @@ def configure(*args, **kwargs): preconfigure_nic(*args, **kwargs) # configure_server(*args, **kwargs) postconfigure_nic(*args, **kwargs) - - -@operation -def postconfigure(ctx, *args, **kwargs): - ctx.logger.info('Assigning IP properties...') + ctx = kwargs['ctx'] nic = None - for nic in ctx.target.instance.runtime_properties.get('nics', []): + data = ctx.instance.runtime_properties.get('data', {}) + for nic in data.get('nics', []): if nic['primary'] == 'true': break - if nic: ctx.logger.info('Found primary IP address.') - ctx.target.instance.runtime_properties['ip'] = \ + ctx.instance.runtime_properties['ip'] = nic['primary']['ip_address'] + ctx.instance.runtime_properties['ip_address'] = \ + nic['primary']['ip_address'] + ctx.instance.runtime_properties['private_ip_address'] = \ nic['primary']['ip_address'] From d8250b8dcb36ef82b9fcb02ddcec82f4ad2c69f1 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Mon, 8 Nov 2021 09:45:46 -0500 Subject: [PATCH 48/58] push stuff --- cloudify_vcd/legacy/compute/tasks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 92bc5b5..4ed2990 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -95,8 +95,6 @@ def start_server(vm_client, ctx, **_): resource, _ctx=ctx, legacy=True) - ctx.instance.runtime_properties['vcloud_vapp_name'] = \ - ctx.instance.runtime_properties.get('name') @decorators.with_vcd_client() From 7b4fd70e17550d560274d76c69a4db328a6c9705 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 09:04:31 -0500 Subject: [PATCH 49/58] update --- cloudify_vcd/legacy/compute/tasks.py | 10 ++-------- cloudify_vcd/legacy/utils.py | 2 +- plugin.yaml | 3 +-- vcloud_server_plugin/server.py | 14 ++++++++++---- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 4ed2990..3a29898 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -194,10 +194,7 @@ def postconfigure_nic(vm_client, server, ctx, **kwargs): **kwargs) last_task = get_last_task(result) if not check_if_task_successful(resource, last_task): - port_ctx.target.instance.runtime_properties['__RETRY_BAD_' - 'REQUEST'] = \ - True - raise OperationRetry('Pending for operation completion.') + raise OperationRetry('Pending for add nic operation completion...') operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, @@ -221,10 +218,7 @@ def unlink_nic(vm_client, ctx, **kwargs): **kwargs) last_task = get_last_task(result) if not check_if_task_successful(resource, last_task): - port_ctx.target.instance.runtime_properties['__RETRY_BAD_' - 'REQUEST'] = \ - True - raise OperationRetry('Pending for operation completion.') + raise OperationRetry('Pending for unlink operation completion...') operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, resource, diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index b04d12b..740bf1a 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -184,7 +184,7 @@ def get_port_config(port, ctx, **kwargs): if 'network_name' not in port: port['network_name'] = network if 'is_connected' not in port: - port['is_connected'] = True + port['is_connected'] = False _node_instance.runtime_properties['network'] = network _node_instance.runtime_properties['port'] = port diff --git a/plugin.yaml b/plugin.yaml index 155ee63..d5f6e60 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -401,6 +401,5 @@ relationships: target_interfaces: cloudify.interfaces.relationship_lifecycle: preconfigure: {} - postconfigure: - implementation: vcloud.vcloud_server_plugin.server.postconfigure + postconfigure: {} unlink: {} diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index e3aa103..4dcad48 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -43,11 +43,17 @@ def configure(*args, **kwargs): break if nic: ctx.logger.info('Found primary IP address.') - ctx.instance.runtime_properties['ip'] = nic['primary']['ip_address'] - ctx.instance.runtime_properties['ip_address'] = \ - nic['primary']['ip_address'] + ctx.instance.runtime_properties['ip'] = nic['ip_address'] + ctx.instance.runtime_properties['ip_address'] = nic['ip_address'] ctx.instance.runtime_properties['private_ip_address'] = \ - nic['primary']['ip_address'] + nic['ip_address'] + ctx.logger.info('Assigned ip properties to ip address {}'.format( + nic['ip_address'])) + + +@operation(resumable=True) +def postconfigure(*args, **kwargs): + pass @operation(resumable=True) From 23d286d4d995d98a85dc0c3b9f2421f98ee5dc07 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 09:51:19 -0500 Subject: [PATCH 50/58] fix vm --- cloudify_vcd/legacy/compute/tasks.py | 42 ++++++++-------------------- cloudify_vcd/legacy/utils.py | 11 ++++++-- 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 3a29898..d0b4ae5 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -43,7 +43,7 @@ def create_server(vm_client, ctx, **_): if 'network' in vm_kwargs: del vm_kwargs['network'] del vm_kwargs['network_adapter_type'] - resource, result = vapp_tasks._create_vm( + return vapp_tasks._create_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, @@ -51,14 +51,7 @@ def create_server(vm_client, ctx, **_): vm_config=vm_kwargs, vm_class=VCloudVM, vm_ctx=ctx) - else: - resource = vm_client.vm - ctx.logger.info('Logging resource object: {}'.format(resource)) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - vm_client, - _ctx=ctx, - legacy=True) + return vm_client.vm, None @decorators.with_vcd_client() @@ -82,7 +75,7 @@ def configure_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() def start_server(vm_client, ctx, **_): - resource, result = vapp_tasks._start_vm( + return vapp_tasks._start_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, @@ -90,17 +83,12 @@ def start_server(vm_client, ctx, **_): vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) @decorators.with_vcd_client() @decorators.with_vm_resource() def stop_server(vm_client, ctx, **_): - resource, result = vapp_tasks._stop_vm( + return vapp_tasks._stop_vm( vm_external=False, vm_id=vm_client.name, vm_client=vm_client.connection, @@ -108,35 +96,27 @@ def stop_server(vm_client, ctx, **_): vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) @decorators.with_vcd_client() @decorators.with_vm_resource() def delete_server(vm_client, ctx, **_): + vm_id = vm_client.name + if not vm_id: + vm_id = ctx.node.properties.get('server', {}).get('name') if not skip(type(vm_client), - vm_client.name, + vm_id, exists=vm_client.exists, delete_operation=True): - resource, result = vapp_tasks._delete_vm( + return vapp_tasks._delete_vm( vm_external=False, - vm_id=vm_client.name, + vm_id=vm_id, vm_client=vm_client.connection, vm_vdc=vm_client.vdc_name, vm_config=vm_client.kwargs, vm_class=VCloudVM, vm_ctx=ctx) - else: - resource = vm_client - operation_name = ctx.operation.name.split('.')[-1] - expose_props(operation_name, - resource, - _ctx=ctx, - legacy=True) + return vm_client.vm, None @decorators.with_port_resource() diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index 740bf1a..a4d95f6 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -184,7 +184,7 @@ def get_port_config(port, ctx, **kwargs): if 'network_name' not in port: port['network_name'] = network if 'is_connected' not in port: - port['is_connected'] = False + port['is_connected'] = True _node_instance.runtime_properties['network'] = network _node_instance.runtime_properties['port'] = port @@ -207,7 +207,7 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): _ctx_instance = get_ctx_instance(ctx) name = None if 'name' in server: - name = server.pop('name') + name = server.get('name') if not name and 'name' in _ctx_instance.runtime_properties: name = _ctx_instance.runtime_properties['name'] if not name: @@ -221,7 +221,8 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): tasks = _ctx_instance.runtime_properties.get('__TASKS', []) convert_vm_config(server) get_server_network(server, _ctx_node, _ctx_instance) - _ctx_instance.runtime_properties['resource_id'] = name + if name: + _ctx_instance.runtime_properties['resource_id'] = name _ctx_instance.runtime_properties['server'] = server ctx.logger.info('We are getting this name: {}'.format(name)) # TODO: Change vcloud VM name to host name guest customization pizazz. @@ -393,6 +394,10 @@ def convert_vapp_config(config): def convert_vm_config(config): + if 'name' in config: + del config['name'] + if 'power_on' not in config: + config['power_on'] = False if 'hardware' in config: if 'memory' in config['hardware']: config['memory'] = config['hardware']['memory'] From 051cc296f0a8f559ff5edd8d3a173ef5e3d351c4 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 09:52:44 -0500 Subject: [PATCH 51/58] ... --- cloudify_vcd/legacy/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index a4d95f6..f6fad56 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -203,6 +203,7 @@ def get_gateway_client(vcloud_cx, vcloud_config, ctx, **_): def get_vm_client(server, vcloud_cx, vcloud_config, ctx): + ctx.logger.info('We are getting this server: {}'.format(server)) _ctx_node = get_ctx_node(ctx) _ctx_instance = get_ctx_instance(ctx) name = None @@ -225,6 +226,7 @@ def get_vm_client(server, vcloud_cx, vcloud_config, ctx): _ctx_instance.runtime_properties['resource_id'] = name _ctx_instance.runtime_properties['server'] = server ctx.logger.info('We are getting this name: {}'.format(name)) + ctx.logger.info('We are getting this server: {}'.format(server)) # TODO: Change vcloud VM name to host name guest customization pizazz. return VCloudVM(name, name, From 2b3ad79838716ab2f33258a5be547394d4f98a5a Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 10:39:10 -0500 Subject: [PATCH 52/58] add deploy false and delete vm improvements --- cloudify_vcd/legacy/compute/tasks.py | 41 ++++++++++++++++++- cloudify_vcd/legacy/utils.py | 2 + cloudify_vcd/vapp_tasks.py | 60 +++++++++++++++++----------- vcloud_server_plugin/server.py | 18 ++++++--- 4 files changed, 90 insertions(+), 31 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index d0b4ae5..a93947e 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -16,7 +16,7 @@ from cloudify.exceptions import OperationRetry -from vcd_plugin_sdk.resources.vapp import VCloudVM +from vcd_plugin_sdk.resources.vapp import VCloudVM, VCloudvApp from cloudify_common_sdk.utils import ( get_ctx_instance, skip_creative_or_destructive_operation as skip) @@ -72,6 +72,45 @@ def configure_server(vm_client, ctx, **_): # legacy=True) +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def power_off_vapp(vm_client, ctx, **_): + return vapp_tasks._power_off_vapp( + vapp_ext=False, + vapp_id=vm_client.name, + vapp_client=vm_client.vapp_object.connection, + vm_vdc=vm_client.vdc_name, + vapp_config=vm_client.kwargs, + vapp_class=VCloudvApp, + __=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def stop_vapp(vm_client, ctx, **_): + return vapp_tasks._stop_vapp( + vapp_ext=False, + vapp_id=vm_client.name, + vapp_client=vm_client.vapp_object.connection, + vm_vdc=vm_client.vdc_name, + vapp_config=vm_client.kwargs, + vapp_class=VCloudvApp, + __=ctx) + + +@decorators.with_vcd_client() +@decorators.with_vm_resource() +def delete_vapp(vm_client, ctx, **_): + return vapp_tasks._delete_vapp( + vapp_ext=False, + vapp_id=vm_client.name, + vapp_client=vm_client.vapp_object.connection, + vm_vdc=vm_client.vdc_name, + vapp_config=vm_client.kwargs, + vapp_class=VCloudvApp, + __=ctx) + + @decorators.with_vcd_client() @decorators.with_vm_resource() def start_server(vm_client, ctx, **_): diff --git a/cloudify_vcd/legacy/utils.py b/cloudify_vcd/legacy/utils.py index f6fad56..0d22969 100644 --- a/cloudify_vcd/legacy/utils.py +++ b/cloudify_vcd/legacy/utils.py @@ -400,6 +400,8 @@ def convert_vm_config(config): del config['name'] if 'power_on' not in config: config['power_on'] = False + if 'deploy' not in config: + config['deploy'] = False if 'hardware' in config: if 'memory' in config['hardware']: config['memory'] = config['hardware']['memory'] diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index b6d8da8..c5c5372 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -77,14 +77,18 @@ def _create_vapp(_=None, @resource_operation -def stop_vapp(vapp_ext=None, - vapp_id=None, - vapp_client=None, - vapp_vdc=None, - vapp_config=None, - vapp_class=None, - __=None, - **___): +def stop_vapp(*args, **kwargs): + return _stop_vapp(*args, *kwargs) + + +def _stop_vapp(vapp_ext=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + __=None, + **___): """ Perform undeploy operation on a vApp. @@ -111,14 +115,18 @@ def stop_vapp(vapp_ext=None, @resource_operation -def power_off_vapp(vapp_ext=None, - vapp_id=None, - vapp_client=None, - vapp_vdc=None, - vapp_config=None, - vapp_class=None, - __=None, - **___): +def power_off_vapp(*args, **kwargs): + return _power_off_vapp(*args, **kwargs) + + +def _power_off_vapp(vapp_ext=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + __=None, + **___): """ Execute power off on the vApp before deletion. :param vapp_ext: @@ -151,14 +159,18 @@ def power_off_vapp(vapp_ext=None, @resource_operation -def delete_vapp(vapp_ext=None, - vapp_id=None, - vapp_client=None, - vapp_vdc=None, - vapp_config=None, - vapp_class=None, - __=None, - **___): +def delete_vapp(*args, **kwargs): + return _delete_vapp(*args, **kwargs) + + +def _delete_vapp(vapp_ext=None, + vapp_id=None, + vapp_client=None, + vapp_vdc=None, + vapp_config=None, + vapp_class=None, + __=None, + **___): """ Delete a vApp. diff --git a/vcloud_server_plugin/server.py b/vcloud_server_plugin/server.py index 4dcad48..43477f0 100644 --- a/vcloud_server_plugin/server.py +++ b/vcloud_server_plugin/server.py @@ -14,14 +14,17 @@ from cloudify.decorators import operation from cloudify_vcd.legacy.compute.tasks import ( - create_server, # configure_server, + postconfigure_nic, + preconfigure_nic, + power_off_vapp, + delete_server, + create_server, start_server, stop_server, - delete_server, - preconfigure_nic, - postconfigure_nic, - unlink_nic + delete_vapp, + unlink_nic, + stop_vapp, ) @@ -64,12 +67,15 @@ def start(*args, **kwargs): @operation(resumable=True) def stop(*args, **kwargs): stop_server(*args, **kwargs) + unlink_nic(*args, **kwargs) + stop_vapp(*args, **kwargs) + power_off_vapp(*args, **kwargs) @operation(resumable=True) def delete(*args, **kwargs): - unlink_nic(*args, **kwargs) delete_server(*args, **kwargs) + delete_vapp(*args, **kwargs) @operation(resumable=True) From ec0e516ff5d48b4ded8b86a234df98e35cc16cea Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 12:00:06 -0500 Subject: [PATCH 53/58] delete work --- cloudify_vcd/legacy/compute/tasks.py | 63 +++++++++++++++++----------- cloudify_vcd/vapp_tasks.py | 9 ++-- vcd_plugin_sdk/resources/vapp.py | 8 ++++ 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index a93947e..07c1778 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -75,40 +75,55 @@ def configure_server(vm_client, ctx, **_): @decorators.with_vcd_client() @decorators.with_vm_resource() def power_off_vapp(vm_client, ctx, **_): - return vapp_tasks._power_off_vapp( - vapp_ext=False, - vapp_id=vm_client.name, - vapp_client=vm_client.vapp_object.connection, - vm_vdc=vm_client.vdc_name, - vapp_config=vm_client.kwargs, - vapp_class=VCloudvApp, - __=ctx) + if not skip(type(vm_client.vapp_object), + vm_client.vapp_object.name, + ctx, + exists=vm_client.vapp_object.exists, + delete_operation=True): + return vapp_tasks._power_off_vapp( + vapp_ext=False, + vapp_id=vm_client.name, + vapp_client=vm_client.vapp_object.connection, + vapp_vdc=vm_client.vdc_name, + vapp_config=vm_client.kwargs, + vapp_class=VCloudvApp, + __=ctx) @decorators.with_vcd_client() @decorators.with_vm_resource() def stop_vapp(vm_client, ctx, **_): - return vapp_tasks._stop_vapp( - vapp_ext=False, - vapp_id=vm_client.name, - vapp_client=vm_client.vapp_object.connection, - vm_vdc=vm_client.vdc_name, - vapp_config=vm_client.kwargs, - vapp_class=VCloudvApp, - __=ctx) + if not skip(type(vm_client.vapp_object), + vm_client.vapp_object.name, + ctx, + exists=vm_client.vapp_object.exists, + delete_operation=True): + return vapp_tasks._stop_vapp( + vapp_ext=False, + vapp_id=vm_client.name, + vapp_client=vm_client.vapp_object.connection, + vapp_vdc=vm_client.vdc_name, + vapp_config=vm_client.kwargs, + vapp_class=VCloudvApp, + __=ctx) @decorators.with_vcd_client() @decorators.with_vm_resource() def delete_vapp(vm_client, ctx, **_): - return vapp_tasks._delete_vapp( - vapp_ext=False, - vapp_id=vm_client.name, - vapp_client=vm_client.vapp_object.connection, - vm_vdc=vm_client.vdc_name, - vapp_config=vm_client.kwargs, - vapp_class=VCloudvApp, - __=ctx) + if not skip(type(vm_client.vapp_object), + vm_client.vapp_object.name, + ctx, + exists=vm_client.vapp_object.exists, + delete_operation=True): + return vapp_tasks._delete_vapp( + vapp_ext=False, + vapp_id=vm_client.name, + vapp_client=vm_client.vapp_object.connection, + vapp_vdc=vm_client.vdc_name, + vapp_config=vm_client.kwargs, + vapp_class=VCloudvApp, + __=ctx) @decorators.with_vcd_client() diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index c5c5372..710e4ac 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -479,9 +479,12 @@ def _delete_vm(vm_external=None, last_task = None if vm_ctx.instance.runtime_properties.get('__VM_CREATE_VAPP'): - vm.delete() - last_task = vm.vapp_object.delete() - + try: + vm.delete() + # except OperationNotSupportedException: + # raise + finally: + last_task = vm.vapp_object.delete() return vm, last_task diff --git a/vcd_plugin_sdk/resources/vapp.py b/vcd_plugin_sdk/resources/vapp.py index 50fb5b0..0a59b02 100644 --- a/vcd_plugin_sdk/resources/vapp.py +++ b/vcd_plugin_sdk/resources/vapp.py @@ -62,6 +62,14 @@ def vapp(self): self._vapp = self.get_vapp(self.vapp_name) return self._vapp + @property + def exists(self): + try: + return self.vapp + except EntityNotFoundException: + pass + return False + @property def networks(self): try: From a7ac4bcae9bda0f9f85473ff41cb5d02a27dcae4 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 12:23:38 -0500 Subject: [PATCH 54/58] try to delete some more --- cloudify_vcd/vapp_tasks.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 710e4ac..003310f 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -467,7 +467,7 @@ def _delete_vm(vm_external=None, vapp_kwargs=vm_config ) - if vm_external: + if vm_external or not vm.vapp_object.exists: return vm, None try: last_task = vm.undeploy() @@ -481,10 +481,16 @@ def _delete_vm(vm_external=None, if vm_ctx.instance.runtime_properties.get('__VM_CREATE_VAPP'): try: vm.delete() - # except OperationNotSupportedException: - # raise + except Exception as e: + if vm.exists: + raise + elif not isinstance(e, OperationNotSupportedException): + raise e finally: - last_task = vm.vapp_object.delete() + try: + last_task = vm.vapp_object.delete() + except BadRequestException: + raise OperationRetry('Waiting for vapp to be deleted.') return vm, last_task From 834bf40acec66c9acff16dbc347c75a2764ded8f Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 12:42:02 -0500 Subject: [PATCH 55/58] pushed --- cloudify_vcd/vapp_tasks.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 003310f..298f75c 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -3,6 +3,7 @@ BadRequestException, MissingLinkException, InvalidStateException, + EntityNotFoundException, OperationNotSupportedException) from cloudify import ctx @@ -477,6 +478,8 @@ def _delete_vm(vm_external=None, (not vcd_unresolved_vm(e) and not cannot_power_off(e)): raise last_task = None + except EntityNotFoundException: + ctx.logger.info('VM is deleted. Now to delete Vapp.') if vm_ctx.instance.runtime_properties.get('__VM_CREATE_VAPP'): try: From a345d761756b9bc8c7d07f93caa9c19f1f506df4 Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 13:01:34 -0500 Subject: [PATCH 56/58] push vm --- cloudify_vcd/vapp_tasks.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index 298f75c..b8c1f66 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -482,14 +482,12 @@ def _delete_vm(vm_external=None, ctx.logger.info('VM is deleted. Now to delete Vapp.') if vm_ctx.instance.runtime_properties.get('__VM_CREATE_VAPP'): - try: - vm.delete() - except Exception as e: - if vm.exists: - raise - elif not isinstance(e, OperationNotSupportedException): - raise e - finally: + if vm.exists: + try: + vm.delete() + except: + raise OperationRetry('Waiting for VM to be deleted.') + if vm.vapp_object.exists: try: last_task = vm.vapp_object.delete() except BadRequestException: From 5266e4bec30c5246a3f22845cebdb040b6c00b2f Mon Sep 17 00:00:00 2001 From: EarthmanT Date: Tue, 9 Nov 2021 13:02:35 -0500 Subject: [PATCH 57/58] delete vm vapp --- cloudify_vcd/vapp_tasks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cloudify_vcd/vapp_tasks.py b/cloudify_vcd/vapp_tasks.py index b8c1f66..9af5194 100644 --- a/cloudify_vcd/vapp_tasks.py +++ b/cloudify_vcd/vapp_tasks.py @@ -485,8 +485,9 @@ def _delete_vm(vm_external=None, if vm.exists: try: vm.delete() - except: - raise OperationRetry('Waiting for VM to be deleted.') + except Exception as e: + raise OperationRetry( + 'Waiting for VM to be deleted. {}'.format(str(e))) if vm.vapp_object.exists: try: last_task = vm.vapp_object.delete() From 90af7780fd552ce73381df09fac1840ae5dc50a6 Mon Sep 17 00:00:00 2001 From: jrzeszutek Date: Wed, 15 Dec 2021 13:19:19 +0100 Subject: [PATCH 58/58] added fix for failing preconfigure_nic & bumped the version to 2.0.3 --- CHANGELOG.txt | 2 ++ cloudify_vcd/legacy/compute/tasks.py | 3 --- plugin.yaml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5efeab9..951d89d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,3 +4,5 @@ - Attempt to decrease amount of superfluous API requests, however these calls are almost all inside of the client library. 2.0.2: - Support some legacy types. +2.0.3: + - Fixed issue with RETRY BAD REQUEST in preconfigure_nic diff --git a/cloudify_vcd/legacy/compute/tasks.py b/cloudify_vcd/legacy/compute/tasks.py index 07c1778..8e78e1d 100644 --- a/cloudify_vcd/legacy/compute/tasks.py +++ b/cloudify_vcd/legacy/compute/tasks.py @@ -194,9 +194,6 @@ def preconfigure_nic(vm_client, ctx, server, **kwargs): **kwargs) last_task = get_last_task(result) if not check_if_task_successful(resource, last_task): - port_ctx.target.instance.runtime_properties['__RETRY_BAD_' - 'REQUEST'] = \ - True raise OperationRetry('Pending for operation completion.') operation_name = ctx.operation.name.split('.')[-1] expose_props(operation_name, diff --git a/plugin.yaml b/plugin.yaml index d5f6e60..7e89bc0 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -3,7 +3,7 @@ plugins: vcd: &plugin_mapping executor: central_deployment_agent package_name: cloudify-vcloud-plugin - package_version: '2.0.2' + package_version: '2.0.3' # legacy vcloud: *plugin_mapping