Remove Mistral

This patch is a part of Legacy APIs deprecation.

A Mistral workflow is created when NS is created, however, Tacker
doesn't have actual action scripts. Therefore, even though a Mistral
workflow is created, it never runs successfully due to the absence of
specified scripts.

This patch removes the dependency on Mistral for the legacy NS
create/delete APIs and also remove Mistral from Tacker entirely, as
there's no longer any place to use Mistral.

Implements: blueprint deprecate-legacy-apis
Change-Id: Iee5d109e4fdb9546730164aea94985b1c535bbc6
This commit is contained in:
Hiromu Asahina 2023-02-25 01:46:42 +09:00 committed by Yasufumi Ogawa
parent fd41f08914
commit b1bba29dfc
27 changed files with 36 additions and 1791 deletions

View File

@ -121,12 +121,9 @@
- openstack/horizon
- openstack/barbican
- openstack/heat
- openstack/mistral
- openstack/mistral-dashboard
- openstack/networking-sfc
- openstack/python-barbicanclient
- openstack/python-blazarclient
- openstack/python-mistralclient
- openstack/python-tackerclient
- openstack/tacker
- openstack/tacker-horizon
@ -168,7 +165,6 @@
networking-sfc: https://opendev.org/openstack/networking-sfc
aodh: https://opendev.org/openstack/aodh
barbican: https://opendev.org/openstack/barbican
mistral: https://opendev.org/openstack/mistral
blazar: https://opendev.org/openstack/blazar
fenix: https://opendev.org/x/fenix
devstack_services:
@ -390,14 +386,12 @@
- openstack/horizon
- openstack/keystone
- openstack/kuryr-kubernetes
- openstack/mistral
- openstack/neutron
- openstack/nova
- openstack/octavia
- openstack/placement
- openstack/python-barbicanclient
- openstack/python-blazarclient
- openstack/python-mistralclient
- openstack/python-octaviaclient
- openstack/python-tackerclient
- openstack/tacker
@ -407,7 +401,6 @@
devstack_plugins:
barbican: https://opendev.org/openstack/barbican
heat: https://opendev.org/openstack/heat
mistral: https://opendev.org/openstack/mistral
neutron: https://opendev.org/openstack/neutron
octavia: https://opendev.org/openstack/octavia
devstack_services:

View File

@ -34,11 +34,10 @@ Q_AGENT=ovn
# Disable security groups
LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
# Enable heat, networking-sfc, barbican and mistral
# Enable heat, networking-sfc and barbican
enable_plugin heat https://opendev.org/openstack/heat master
enable_plugin networking-sfc https://opendev.org/openstack/networking-sfc master
enable_plugin barbican https://opendev.org/openstack/barbican master
enable_plugin mistral https://opendev.org/openstack/mistral master
# Ceilometer
#CEILOMETER_PIPELINE_INTERVAL=300

View File

@ -34,12 +34,11 @@ Q_AGENT=ovn
# Disable security groups
LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
# Enable neutron, heat, networking-sfc, barbican and mistral
# Enable neutron, heat, networking-sfc and barbican
enable_plugin neutron https://opendev.org/openstack/neutron master
enable_plugin heat https://opendev.org/openstack/heat master
enable_plugin networking-sfc https://opendev.org/openstack/networking-sfc master
enable_plugin barbican https://opendev.org/openstack/barbican master
enable_plugin mistral https://opendev.org/openstack/mistral master
# Ceilometer
#CEILOMETER_PIPELINE_INTERVAL=300

View File

@ -24,5 +24,4 @@ TACKER_MODE=standalone
USE_BARBICAN=True
enable_plugin networking-sfc ${GIT_BASE}/openstack/networking-sfc
enable_plugin barbican ${GIT_BASE}/openstack/barbican
enable_plugin mistral ${GIT_BASE}/openstack/mistral
enable_plugin tacker ${GIT_BASE}/openstack/tacker

View File

@ -16,7 +16,6 @@ redirectmatch 301 ^/tacker/([^/]+)/devref/vnfd_template_parameterization.html$ ^
redirectmatch 301 ^/tacker/([^/]+)/devref/vnffgd_template_description.html$ ^/tacker/$1/contributor/vnffgd_template_description.html
redirectmatch 301 ^/tacker/([^/]+)/devref/vnfm_usage_guide.html$ ^/tacker/$1/user/vnfm_usage_guide.html
redirectmatch 301 ^/tacker/([^/]+)/policies/dev-process.html$ ^/tacker/$1/contributor/dev-process.html
redirectmatch 301 ^/tacker/([^/]+)/devref/mistral_workflows_usage_guide.html$ ^/tacker/$1/reference/mistral_workflows_usage_guide.html
redirectmatch 301 ^/tacker/([^/]+)/devref/alarm_monitoring_usage_guide.html$ ^/tacker/$1/user/alarm_monitoring_usage_guide.html
redirectmatch 301 ^/tacker/([^/]+)/devref/enhanced_placement_awareness_usage_guide.html$ ^/tacker/$1/user/enhanced_placement_awareness_usage_guide.html
redirectmatch 301 ^/tacker/([^/]+)/devref/multisite_vim_usage_guide.html$ ^/tacker/$1/user/multisite_vim_usage_guide.html

View File

@ -1,124 +0,0 @@
..
Copyright 2014-2015 OpenStack Foundation
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.
===============================
Mistral workflow VIM monitoring
===============================
For the purpose to make tacker server scale, the mistral workflow is used to
re-implement the VIM monitoring feature.
The main monitoring process is like this:
- user registers a VIM
- tacker server saves it into database
- tacker server generates a mistral workflow and executes it
- the VIM monitor mistral action is executed and do the monitoring, if there
is status change, it will RPC call conductor
- the conductor changes the VIM status
Feature exploration
===================
Firstly register a VIM:
.. code-block:: console
$ openstack vim register --config-file ~/testvim_config.yaml testvim2 -c id -c name -c status
Created a new vim:
+--------+--------------------------------------+
| Field | Value |
+--------+--------------------------------------+
| id | 4406cf8f-f2af-46cc-bfb9-e00add5805b7 |
| name | testvim2 |
| status | PENDING |
+--------+--------------------------------------+
..
The registered VIM's id is '4406cf8f-f2af-46cc-bfb9-e00add5805b7', after this,
there is a mistral workflow named as
'vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7', is generated in mistral:
.. code-block:: console
$ openstack workflow list --filter name=vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7 -c ID -c Name
+--------------------------------------+---------------------------------------------+
| ID | Name |
+--------------------------------------+---------------------------------------------+
| 0cd0deff-6132-4ee2-a181-1c877cd594cc | vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7 |
+--------------------------------------+---------------------------------------------+
..
and it is executed:
.. code-block:: console
$ openstack workflow execution list --filter workflow_name=vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7 -c ID -c 'Workflow name' -c State
+--------------------------------------+---------------------------------------------+---------+
| ID | Workflow name | State |
+--------------------------------------+---------------------------------------------+---------+
| 99ced0e2-be09-4219-ab94-299df8ee8789 | vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7 | RUNNING |
+--------------------------------------+---------------------------------------------+---------+
..
The monitoring task is running too:
.. code-block:: console
$ openstack task execution list --filter workflow_name=vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7 -c ID -c 'Workflow name' -c Name -c State
+--------------------------------------+-----------------------------+---------------------------------------------+---------+
| ID | Name | Workflow name | State |
+--------------------------------------+-----------------------------+---------------------------------------------+---------+
| f2fe2904-6ff2-4531-9bd0-4c998ef1515f | monitor_ping_vimPingVIMTASK | vim_id_4406cf8f-f2af-46cc-bfb9-e00add5805b7 | RUNNING |
+--------------------------------------+-----------------------------+---------------------------------------------+---------+
..
Of course, the VIM's state is in 'REACHABLE' status:
.. code-block:: console
$ openstack vim list --name testvim2 -c id -c name -c status
+--------------------------------------+----------+-----------+
| id | name | status |
+--------------------------------------+----------+-----------+
| 4406cf8f-f2af-46cc-bfb9-e00add5805b7 | testvim2 | REACHABLE |
+--------------------------------------+----------+-----------+
..
The deletion of VIM will lead to removal of all of these mistral resources.
Rabbitmq queues
===============
Each mistral VIM monitoring action is listening on three queues:
.. code-block:: console
~/tacker$ sudo rabbitmqctl list_queues | grep -i KILL_ACTION
KILL_ACTION 0
KILL_ACTION.4406cf8f-f2af-46cc-bfb9-e00add5805b7 0
KILL_ACTION_fanout_a8118e2e18b9443986a1b37f7b082ab9 0
..
But only KILL_ACTION with VIM id as suffix is used.

View File

@ -114,7 +114,6 @@ Install Tacker
enable_neutron: "no"
enable_nova: "no"
enable_barbican: "yes"
enable_mistral: "yes"
enable_tacker: "yes"
enable_heat: "no"
enable_openvswitch: "no"
@ -181,10 +180,6 @@ Install Tacker
11b5ccf91d86 kolla/centos-source-barbican-worker:ussuri barbican_worker
4a5224d14f36 kolla/centos-source-barbican-keystone-listener:ussuri barbican_keystone_listener
a169e7aed0b6 kolla/centos-source-barbican-api:ussuri barbican_api
2b3b0341b562 kolla/centos-source-mistral-executor:ussuri mistral_executor
6c69bbdf6aea kolla/centos-source-mistral-event-engine:ussuri mistral_event_engine
d035295fe9f0 kolla/centos-source-mistral-engine:ussuri mistral_engine
72f52de2fb77 kolla/centos-source-mistral-api:ussuri mistral_api
07ecaad80542 kolla/centos-source-horizon:ussuri horizon
7e6ac94ea505 kolla/centos-source-keystone:ussuri keystone
2b16b169ed18 kolla/centos-source-keystone-fernet:ussuri keystone_fernet

View File

@ -33,12 +33,11 @@ Pre-requisites
#. Install required components.
Ensure that all required OpenStack components i.e. Keystone, Mistral,
Barbican and Horizon are installed. Refer the list below for installation
of these OpenStack components on different Operating Systems.
Ensure that all required OpenStack components i.e. Keystone, Barbican and
Horizon are installed. Refer the list below for installation of these
OpenStack components on different Operating Systems.
* https://docs.openstack.org/keystone/latest/install/index.html
* https://docs.openstack.org/mistral/latest/admin/install/index.html
* https://docs.openstack.org/barbican/latest/install/install.html
* https://docs.openstack.org/horizon/latest/install/index.html

View File

@ -22,7 +22,6 @@ Reference
:maxdepth: 1
vim_config.rst
mistral_workflows_usage_guide.rst
block_storage_usage_guide.rst
reservation_policy_usage_guide.rst
maintenance_usage_guide.rst

View File

@ -1,509 +0,0 @@
..
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.
.. _ref-mistral:
============================
Mistral workflows for Tacker
============================
.. warning::
Legacy Tacker features excluding VIM feature are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
OpenStack Mistral already integrated with Tacker. The Tenant User or Operator
can make use of tacker actions to create custom Mistral Workflows. This
document describes the usage of OpenStackClient CLI to validate, create
and executing Tacker workflows.
References
~~~~~~~~~~
- `Mistral workflow samples <https://github.com/openstack/tacker/tree/master/samples/mistral/workflows>`_.
- `Mistral Client / CLI Guide <https://docs.openstack.org/mistral/latest/admin/install/mistralclient_guide.html>`_.
Workflow definition file validation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Validate workflow definition files before registering with Mistral.
::
usage: openstack workflow validate <definition>
::
$ openstack workflow validate create_vnf.yaml
+-------+-------+
| Field | Value |
+-------+-------+
| Valid | True |
| Error | None |
+-------+-------+
$ openstack workflow validate create_vnfd.yaml
+-------+-------+
| Field | Value |
+-------+-------+
| Valid | True |
| Error | None |
+-------+-------+
$ openstack workflow validate delete_vnf.yaml
+-------+-------+
| Field | Value |
+-------+-------+
| Valid | True |
| Error | None |
+-------+-------+
$ openstack workflow validate delete_vnfd.yaml
+-------+-------+
| Field | Value |
+-------+-------+
| Valid | True |
| Error | None |
+-------+-------+
Registering Tacker workflows with Mistral
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To create std.create_vnf, std.create_vnfd, std.delete_vnfd and
std.delete_vnf workflows in Mistral.
::
usage: openstack workflow create <definition> --public
::
$ openstack workflow create create_vnf.yaml --public
+--------------------------------------+----------------+----------------------------------+--------+-------+----------------------------+------------+
| ID | Name | Project ID | Tags | Input | Created at | Updated at |
+--------------------------------------+----------------+----------------------------------+--------+-------+----------------------------+------------+
| 445e165a-3654-4996-aad4-c6fea65e95d5 | std.create_vnf | bde60e557de840a8a837733aaa96e42e | <none> | body | 2016-07-29 15:08:45.585192 | None |
+--------------------------------------+----------------+----------------------------------+--------+-------+----------------------------+------------+
$ openstack workflow create create_vnfd.yaml --public
+--------------------------------------+-----------------+----------------------------------+--------+-------+----------------------------+------------+
| ID | Name | Project ID | Tags | Input | Created at | Updated at |
+--------------------------------------+-----------------+----------------------------------+--------+-------+----------------------------+------------+
| 926caa3e-ee59-4ca0-ac1b-cae03538e389 | std.create_vnfd | bde60e557de840a8a837733aaa96e42e | <none> | body | 2016-07-29 15:08:54.933874 | None |
+--------------------------------------+-----------------+----------------------------------+--------+-------+----------------------------+------------+
$ openstack workflow create delete_vnfd.yaml --public
+--------------------------------------+-----------------+----------------------------------+--------+---------+----------------------------+------------+
| ID | Name | Project ID | Tags | Input | Created at | Updated at |
+--------------------------------------+-----------------+----------------------------------+--------+---------+----------------------------+------------+
| f15b7402-ce31-4369-98d4-818125191564 | std.delete_vnfd | bde60e557de840a8a837733aaa96e42e | <none> | vnfd_id | 2016-08-14 20:01:00.135104 | None |
+--------------------------------------+-----------------+----------------------------------+--------+---------+----------------------------+------------+
$ openstack workflow create delete_vnf.yaml --public
+--------------------------------------+----------------+----------------------------------+--------+--------+----------------------------+------------+
| ID | Name | Project ID | Tags | Input | Created at | Updated at |
+--------------------------------------+----------------+----------------------------------+--------+--------+----------------------------+------------+
| d6451b4e-6448-4a26-aa33-ac5e18c7a412 | std.delete_vnf | bde60e557de840a8a837733aaa96e42e | <none> | vnf_id | 2016-08-14 20:01:08.088654 | None |
+--------------------------------------+----------------+----------------------------------+--------+--------+----------------------------+------------+
VNFD resource creation with std.create_vnfd workflow
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To create VNFD tacker resource based on the VNFD workflow input file.
Create new execution for VNFD creation.
::
usage: openstack workflow execution create <workflow_name> [<workflow_input>] [<params>]
::
$ openstack workflow execution create std.create_vnfd create_vnfd.json
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 31f086aa-a3c9-4f44-b8b2-bec560e32653 |
| Workflow ID | 926caa3e-ee59-4ca0-ac1b-cae03538e389 |
| Workflow name | std.create_vnfd |
| Description | |
| Task Execution ID | <none> |
| State | RUNNING |
| State info | None |
| Created at | 2016-07-29 15:11:19.485722 |
| Updated at | 2016-07-29 15:11:19.491694 |
+-------------------+--------------------------------------+
Gather execution details based on execution id.
::
usage: openstack workflow execution show <id>
::
$ openstack workflow execution show 31f086aa-a3c9-4f44-b8b2-bec560e32653
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 31f086aa-a3c9-4f44-b8b2-bec560e32653 |
| Workflow ID | 926caa3e-ee59-4ca0-ac1b-cae03538e389 |
| Workflow name | std.create_vnfd |
| Description | |
| Task Execution ID | <none> |
| State | SUCCESS |
| State info | None |
| Created at | 2016-07-29 15:11:19 |
| Updated at | 2016-07-29 15:11:21 |
+-------------------+--------------------------------------+
.. note:: Wait until execution state become as SUCCESS.
Gather VNFD ID from execution output data.
::
usage: openstack workflow execution output show <id>
::
$ openstack workflow execution output show 31f086aa-a3c9-4f44-b8b2-bec560e32653
Response:
{
"vnfd_id": "fb164b77-5e24-402d-b5f4-c6596352cabe"
}
Verify VNFD details using OpenStackClient CLI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
$ openstack vnf descriptor show "fb164b77-5e24-402d-b5f4-c6596352cabe"
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| attributes | {"vnfd": "tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0\n\ndescription: Demo example\n\nmetadata:\n template_name: sample-tosca- |
| | vnfd\n\ntopology_template:\n node_templates:\n VDU1:\n type: tosca.nodes.nfv.VDU.Tacker\n properties:\n image: cirros-0.5.2-x86_64-disk\n |
| | flavor: m1.tiny\n availability_zone: nova\n mgmt_driver: noop\n config: |\n param0: key1\n param1: key2\n\n CP1:\n type: |
| | tosca.nodes.nfv.CP.Tacker\n properties:\n management: true\n anti_spoofing_protection: false\n requirements:\n - virtualLink:\n |
| | node: VL1\n - virtualBinding:\n node: VDU1\n\n CP2:\n type: tosca.nodes.nfv.CP.Tacker\n properties:\n anti_spoofing_protection: |
| | false\n requirements:\n - virtualLink:\n node: VL2\n - virtualBinding:\n node: VDU1\n\n CP3:\n type: |
| | tosca.nodes.nfv.CP.Tacker\n properties:\n anti_spoofing_protection: false\n requirements:\n - virtualLink:\n node: VL3\n - |
| | virtualBinding:\n node: VDU1\n\n VL1:\n type: tosca.nodes.nfv.VL\n properties:\n network_name: net_mgmt\n vendor: Tacker\n\n |
| | VL2:\n type: tosca.nodes.nfv.VL\n properties:\n network_name: net0\n vendor: Tacker\n\n VL3:\n type: tosca.nodes.nfv.VL\n |
| | properties:\n network_name: net1\n vendor: Tacker\n"} |
| description | Demo example |
| id | fb164b77-5e24-402d-b5f4-c6596352cabe |
| infra_driver | openstack |
| mgmt_driver | noop |
| name | tacker-create-vnfd |
| service_types | {"service_type": "vnfd", "id": "db7c5077-7bbf-4bd3-87d5-e3c52daba255"} |
| tenant_id | bde60e557de840a8a837733aaa96e42e |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
VNF resource creation with std.create_vnf workflow
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Update the vnfd_id from the output of above execution in create_vnf.json
Create new execution for VNF creation.
::
$ openstack workflow execution create std.create_vnf create_vnf.json
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 3bf2051b-ac2e-433b-8f18-23f57f32f184 |
| Workflow ID | 445e165a-3654-4996-aad4-c6fea65e95d5 |
| Workflow name | std.create_vnf |
| Description | |
| Task Execution ID | <none> |
| State | RUNNING |
| State info | None |
| Created at | 2016-07-29 15:16:13.066555 |
| Updated at | 2016-07-29 15:16:13.072436 |
+-------------------+--------------------------------------+
Gather execution details based on execution id.
::
$ openstack workflow execution show 3bf2051b-ac2e-433b-8f18-23f57f32f184
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 3bf2051b-ac2e-433b-8f18-23f57f32f184 |
| Workflow ID | 445e165a-3654-4996-aad4-c6fea65e95d5 |
| Workflow name | std.create_vnf |
| Description | |
| Task Execution ID | <none> |
| State | SUCCESS |
| State info | None |
| Created at | 2016-07-29 15:16:13 |
| Updated at | 2016-07-29 15:16:45 |
+-------------------+--------------------------------------+
Gather VNF ID from execution output data.
::
$ openstack workflow execution output show 3bf2051b-ac2e-433b-8f18-23f57f32f184
Response:
{
"status": "ACTIVE",
"mgmt_ip_address": "{\"VDU1\": \"192.168.120.7\"}",
"vim_id": "22ac5ce6-1415-460c-badf-40ffc5091f94",
"vnf_id": "1c349534-a539-4d5a-b854-033f98036cd5"
}
Verify VNF details using OpenStackClient CLI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
$ openstack vnf show "1c349534-a539-4d5a-b854-033f98036cd5"
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| attributes | {"heat_template": "heat_template_version: 2013-05-23\ndescription: 'Demo example\n\n '\nparameters: {}\nresources:\n VDU1:\n type: OS::Nova::Server\n |
| | properties:\n availability_zone: nova\n config_drive: false\n flavor: m1.tiny\n image: cirros-0.5.2-x86_64-disk\n networks:\n - port:\n |
| | get_resource: CP1\n - port:\n get_resource: CP2\n - port:\n get_resource: CP3\n user_data_format: SOFTWARE_CONFIG\n CP1:\n type: |
| | OS::Neutron::Port\n properties:\n network: net_mgmt\n port_security_enabled: false\n CP2:\n type: OS::Neutron::Port\n properties:\n network: |
| | net0\n port_security_enabled: false\n CP3:\n type: OS::Neutron::Port\n properties:\n network: net1\n port_security_enabled: false\noutputs:\n |
| | mgmt_ip-VDU1:\n value:\n get_attr: [CP1, fixed_ips, 0, ip_address]\n", "monitoring_policy": "{\"vdus\": {}}"} |
| description | Demo example |
| error_reason | |
| id | 1c349534-a539-4d5a-b854-033f98036cd5 |
| instance_id | 771c53df-9f41-454c-a719-7eccd3a4eba9 |
| mgmt_ip_address| {"VDU1": "192.168.120.7"} |
| name | tacker-create-vnf |
| placement_attr | {"vim_name": "VIM0"} |
| status | ACTIVE |
| tenant_id | bde60e557de840a8a837733aaa96e42e |
| vim_id | 22ac5ce6-1415-460c-badf-40ffc5091f94 |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
VNF resource deletion with std.delete_vnf workflow
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Update the vnf_id from the output of above execution in delete_vnf.json
Create new execution for VNF deletion.
::
$ openstack workflow execution create std.delete_vnf delete_vnf.json
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 677c7bab-18ee-4a34-b1e6-a305e98ba887 |
| Workflow ID | d6451b4e-6448-4a26-aa33-ac5e18c7a412 |
| Workflow name | std.delete_vnf |
| Description | |
| Task Execution ID | <none> |
| State | RUNNING |
| State info | None |
| Created at | 2016-08-14 20:48:00.333116 |
| Updated at | 2016-08-14 20:48:00.340124 |
+-------------------+--------------------------------------+
Gather execution details based on execution id.
::
$ openstack workflow execution show 677c7bab-18ee-4a34-b1e6-a305e98ba887
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 677c7bab-18ee-4a34-b1e6-a305e98ba887 |
| Workflow ID | d6451b4e-6448-4a26-aa33-ac5e18c7a412 |
| Workflow name | std.delete_vnf |
| Description | |
| Task Execution ID | <none> |
| State | SUCCESS |
| State info | None |
| Created at | 2016-08-14 20:48:00 |
| Updated at | 2016-08-14 20:48:03 |
+-------------------+--------------------------------------+
Gather execution output data from execution id.
::
$ openstack workflow execution output show 677c7bab-18ee-4a34-b1e6-a305e98ba887
Response:
{
"openstack": {
"project_name": "demo",
"user_id": "f39a28fa574848dfa950b50329c1309b",
"roles": [
"anotherrole",
"Member"
],
"www_authenticate_uri": "http://192.168.122.250:5000/v3",
"auth_cacert": null,
"auth_token": "2871049fae3643ca84f44f7e17f809a0",
"is_trust_scoped": false,
"service_catalog": "[{\"endpoints\": [{\"adminURL\": \"http://192.168.122.250/identity_v2_admin\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250/identity\", \"publicURL\": \"http://192.168.122.250/identity\"}], \"type\": \"identity\", \"name\": \"keystone\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9292\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9292\", \"publicURL\": \"http://192.168.122.250:9292\"}], \"type\": \"image\", \"name\": \"glance\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8774/v2.1\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8774/v2.1\", \"publicURL\": \"http://192.168.122.250:8774/v2.1\"}], \"type\": \"compute\", \"name\": \"nova\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8776/v2/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8776/v2/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8776/v2/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"volumev2\", \"name\": \"cinderv2\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8776/v1/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8776/v1/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8776/v1/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"volume\", \"name\": \"cinder\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9494\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9494\", \"publicURL\": \"http://192.168.122.250:9494\"}], \"type\": \"artifact\", \"name\": \"glare\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8004/v1/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8004/v1/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8004/v1/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"orchestration\", \"name\": \"heat\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8774/v2/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8774/v2/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8774/v2/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"compute_legacy\", \"name\": \"nova_legacy\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9890/\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9890/\", \"publicURL\": \"http://192.168.122.250:9890/\"}], \"type\": \"nfv-orchestration\", \"name\": \"tacker\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8989/v2\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8989/v2\", \"publicURL\": \"http://192.168.122.250:8989/v2\"}], \"type\": \"workflowv2\", \"name\": \"mistral\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9696/\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9696/\", \"publicURL\": \"http://192.168.122.250:9696/\"}], \"type\": \"network\", \"name\": \"neutron\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8776/v3/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8776/v3/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8776/v3/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"volumev3\", \"name\": \"cinderv3\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8082\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8082\", \"publicURL\": \"http://192.168.122.250:8082\"}], \"type\": \"application-catalog\", \"name\": \"murano\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8779/v1.0/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8779/v1.0/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8779/v1.0/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"database\", \"name\": \"trove\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8000/v1\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8000/v1\", \"publicURL\": \"http://192.168.122.250:8000/v1\"}], \"type\": \"cloudformation\", \"name\": \"heat-cfn\"}]",
"project_id": "bde60e557de840a8a837733aaa96e42e",
"user_name": "demo"
},
"vnf_id": "f467e215-43a3-4083-8bbb-ce49d9c70443",
"__env": {},
"__execution": {
"input": {
"vnf_id": "f467e215-43a3-4083-8bbb-ce49d9c70443"
},
"params": {},
"id": "677c7bab-18ee-4a34-b1e6-a305e98ba887",
"spec": {
"tasks": {
"delete_vnf": {
"action": "tacker.delete_vnf vnf=<% $.vnf_id %>",
"version": "2.0",
"type": "direct",
"description": "Request to delete a VNF.",
"name": "delete_vnf"
}
},
"description": "Delete a VNF.\n",
"version": "2.0",
"input": [
"vnf_id"
],
"type": "direct",
"name": "std.delete_vnf"
}
}
}
VNFD resource deletion with std.delete_vnfd workflow
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Update the vnfd_id from the output of above execution in delete_vnfd.json
Create new execution for VNF deletion.
::
$ openstack workflow execution create std.delete_vnfd delete_vnfd.json
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 1e0340c0-bee8-4ca4-8150-ac6e5eb58c99 |
| Workflow ID | f15b7402-ce31-4369-98d4-818125191564 |
| Workflow name | std.delete_vnfd |
| Description | |
| Task Execution ID | <none> |
| State | RUNNING |
| State info | None |
| Created at | 2016-08-14 20:57:06.500941 |
| Updated at | 2016-08-14 20:57:06.505780 |
+-------------------+--------------------------------------+
Gather execution details based on execution id.
::
$ openstack workflow execution show 1e0340c0-bee8-4ca4-8150-ac6e5eb58c99
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| ID | 1e0340c0-bee8-4ca4-8150-ac6e5eb58c99 |
| Workflow ID | f15b7402-ce31-4369-98d4-818125191564 |
| Workflow name | std.delete_vnfd |
| Description | |
| Task Execution ID | <none> |
| State | SUCCESS |
| State info | None |
| Created at | 2016-08-14 20:57:06 |
| Updated at | 2016-08-14 20:57:07 |
+-------------------+--------------------------------------+
Gather execution output data from execution id.
::
$ openstack workflow execution output show 1e0340c0-bee8-4ca4-8150-ac6e5eb58c99
Response:
{
"openstack": {
"project_name": "demo",
"user_id": "f39a28fa574848dfa950b50329c1309b",
"roles": [
"anotherrole",
"Member"
],
"www_authenticate_uri": "http://192.168.122.250:5000/v3",
"auth_cacert": null,
"auth_token": "176c9b5ebd9d40fb9fb0a8db921609eb",
"is_trust_scoped": false,
"service_catalog": "[{\"endpoints\": [{\"adminURL\": \"http://192.168.122.250/identity_v2_admin\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250/identity\", \"publicURL\": \"http://192.168.122.250/identity\"}], \"type\": \"identity\", \"name\": \"keystone\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9292\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9292\", \"publicURL\": \"http://192.168.122.250:9292\"}], \"type\": \"image\", \"name\": \"glance\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8774/v2.1\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8774/v2.1\", \"publicURL\": \"http://192.168.122.250:8774/v2.1\"}], \"type\": \"compute\", \"name\": \"nova\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8776/v2/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8776/v2/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8776/v2/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"volumev2\", \"name\": \"cinderv2\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8776/v1/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8776/v1/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8776/v1/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"volume\", \"name\": \"cinder\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9494\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9494\", \"publicURL\": \"http://192.168.122.250:9494\"}], \"type\": \"artifact\", \"name\": \"glare\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8004/v1/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8004/v1/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8004/v1/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"orchestration\", \"name\": \"heat\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8774/v2/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8774/v2/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8774/v2/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"compute_legacy\", \"name\": \"nova_legacy\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9890/\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9890/\", \"publicURL\": \"http://192.168.122.250:9890/\"}], \"type\": \"nfv-orchestration\", \"name\": \"tacker\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8989/v2\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8989/v2\", \"publicURL\": \"http://192.168.122.250:8989/v2\"}], \"type\": \"workflowv2\", \"name\": \"mistral\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:9696/\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:9696/\", \"publicURL\": \"http://192.168.122.250:9696/\"}], \"type\": \"network\", \"name\": \"neutron\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8776/v3/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8776/v3/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8776/v3/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"volumev3\", \"name\": \"cinderv3\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8082\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8082\", \"publicURL\": \"http://192.168.122.250:8082\"}], \"type\": \"application-catalog\", \"name\": \"murano\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8779/v1.0/bde60e557de840a8a837733aaa96e42e\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8779/v1.0/bde60e557de840a8a837733aaa96e42e\", \"publicURL\": \"http://192.168.122.250:8779/v1.0/bde60e557de840a8a837733aaa96e42e\"}], \"type\": \"database\", \"name\": \"trove\"}, {\"endpoints\": [{\"adminURL\": \"http://192.168.122.250:8000/v1\", \"region\": \"RegionOne\", \"internalURL\": \"http://192.168.122.250:8000/v1\", \"publicURL\": \"http://192.168.122.250:8000/v1\"}], \"type\": \"cloudformation\", \"name\": \"heat-cfn\"}]",
"project_id": "bde60e557de840a8a837733aaa96e42e",
"user_name": "demo"
},
"vnfd_id": "fb164b77-5e24-402d-b5f4-c6596352cabe",
"__env": {},
"__execution": {
"input": {
"vnfd_id": "fb164b77-5e24-402d-b5f4-c6596352cabe"
},
"params": {},
"id": "1e0340c0-bee8-4ca4-8150-ac6e5eb58c99",
"spec": {
"tasks": {
"delete_vnfd": {
"action": "tacker.delete_vnfd vnfd=<% $.vnfd_id %>",
"version": "2.0",
"type": "direct",
"description": "Request to delete a VNFD.",
"name": "delete_vnfd"
}
},
"description": "Delete a VNFD.\n",
"version": "2.0",
"input": [
"vnfd_id"
],
"type": "direct",
"name": "std.delete_vnfd"
}
}
}

View File

@ -10,14 +10,6 @@ Legacy Tacker Use Cases
VIM
---
Register
^^^^^^^^
.. toctree::
:maxdepth: 1
../contributor/tacker_vim_monitoring
Enable Multi Site
^^^^^^^^^^^^^^^^^
@ -144,6 +136,5 @@ Collaboration with Other Projects
../contributor/encrypt_vim_auth_with_barbican
../reference/block_storage_usage_guide
../reference/mistral_workflows_usage_guide
alarm_monitoring_usage_guide
../reference/reservation_policy_usage_guide

View File

@ -0,0 +1,9 @@
---
deprecations:
- |
From 2023.1 release, dependency on Mistral has been removed from Tacker
entirely. This change removed: i) VIM monitoring; and ii) Mistral workflow
in NS API. Due to the deletion of the VIM monitoring, the status field has
been removed from the VIM table and VIM status in the response will be
filled by a dummy value. This field will be completely removed in the next
release

View File

@ -40,7 +40,6 @@ openstacksdk>=0.44.0 # Apache-2.0
python-barbicanclient>=4.5.2 # Apache-2.0
python-heatclient>=1.10.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
python-mistralclient>=4.2.0 # Apache-2.0
python-neutronclient>=6.7.0 # Apache-2.0
python-novaclient>=9.1.0 # Apache-2.0
python-tackerclient>=1.11.0 # Apache-2.0

View File

@ -104,9 +104,6 @@ oslo.config.opts =
tacker.vnfm.plugin = tacker.vnfm.plugin:config_opts
tacker.wsgi = tacker.wsgi:config_opts
mistral.actions =
tacker.vim_ping_action = tacker.nfvo.workflows.vim_monitor.vim_ping_action:PingVimAction
oslo.policy.enforcer =
tacker = tacker.policy:get_enforcer

View File

@ -24,7 +24,6 @@ class OpenstackClients(object):
super(OpenstackClients, self).__init__()
self.keystone_plugin = keystone.Keystone()
self.heat_client = None
self.mistral_client = None
self.keystone_client = None
self.region_name = region_name

View File

@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import ast
from datetime import datetime
from oslo_db.exception import DBDuplicateEntry
@ -292,27 +291,11 @@ class NSPluginDb(network_service.NSPluginBase, db_base.CommonDbMixin):
details=evt_details)
return self._make_ns_dict(ns_db)
def create_ns_post(self, context, ns_id, mistral_obj,
vnfd_dict, vnffgd_templates, error_reason):
def create_ns_post(self, context, ns_id, vnfd_dict, vnffgd_templates):
LOG.debug('ns ID %s', ns_id)
output = ast.literal_eval(mistral_obj.output)
mgmt_ip_addresses = dict()
vnf_ids = dict()
vnffg_ids = dict()
if len(output) > 0:
for vnfd_name, vnfd_val in vnfd_dict.items():
for instance in vnfd_val['instances']:
if 'mgmt_ip_address_' + instance in output:
mgmt_ip_addresses[instance] = ast.literal_eval(
output['mgmt_ip_address_' + instance].strip())
vnf_ids[instance] = output['vnf_id_' + instance]
vnf_ids = str(vnf_ids)
mgmt_ip_addresses = str(mgmt_ip_addresses)
if vnffgd_templates:
for vnffg_name in vnffgd_templates:
vnffg_output = 'vnffg_id_%s' % vnffg_name
vnffg_ids[vnffg_name] = output[vnffg_output]
vnffg_ids = str(vnffg_ids)
if not vnf_ids:
vnf_ids = None
@ -320,8 +303,7 @@ class NSPluginDb(network_service.NSPluginBase, db_base.CommonDbMixin):
mgmt_ip_addresses = None
if not vnffg_ids:
vnffg_ids = None
status = constants.ACTIVE if mistral_obj.state == 'SUCCESS' \
else constants.ERROR
status = constants.ACTIVE
with context.session.begin(subtransactions=True):
ns_db = self._get_resource(context, NS, ns_id)
@ -329,7 +311,6 @@ class NSPluginDb(network_service.NSPluginBase, db_base.CommonDbMixin):
ns_db.update({'vnffg_ids': vnffg_ids})
ns_db.update({'mgmt_ip_addresses': mgmt_ip_addresses})
ns_db.update({'status': status})
ns_db.update({'error_reason': error_reason})
ns_db.update({'updated_at': timeutils.utcnow()})
ns_dict = self._make_ns_dict(ns_db)
@ -362,8 +343,8 @@ class NSPluginDb(network_service.NSPluginBase, db_base.CommonDbMixin):
tstamp=timeutils.utcnow(), details="NS delete initiated")
return deleted_ns_db
def delete_ns_post(self, context, ns_id, mistral_obj,
error_reason, soft_delete=True, force_delete=False):
def delete_ns_post(self, context, ns_id, soft_delete=True,
force_delete=False):
ns = self.get_ns(context, ns_id)
nsd_id = ns.get('nsd_id')
with context.session.begin(subtransactions=True):
@ -376,29 +357,18 @@ class NSPluginDb(network_service.NSPluginBase, db_base.CommonDbMixin):
self._model_query(context, NS).
filter(NS.id == ns_id).
filter(NS.status == constants.PENDING_DELETE))
if not force_delete and (mistral_obj
and mistral_obj.state == 'ERROR'):
query.update({'status': constants.ERROR})
if soft_delete:
deleted_time_stamp = timeutils.utcnow()
query.update({'deleted_at': deleted_time_stamp})
self._cos_db_plg.create_event(
context, res_id=ns_id,
res_type=constants.RES_TYPE_NS,
res_state=constants.ERROR,
res_state=constants.PENDING_DELETE,
evt_type=constants.RES_EVT_DELETE,
tstamp=timeutils.utcnow(),
details="NS Delete ERROR")
tstamp=deleted_time_stamp,
details="ns Delete Complete")
else:
if soft_delete:
deleted_time_stamp = timeutils.utcnow()
query.update({'deleted_at': deleted_time_stamp})
self._cos_db_plg.create_event(
context, res_id=ns_id,
res_type=constants.RES_TYPE_NS,
res_state=constants.PENDING_DELETE,
evt_type=constants.RES_EVT_DELETE,
tstamp=deleted_time_stamp,
details="ns Delete Complete")
else:
query.delete()
query.delete()
try:
template_db = self._get_resource(context, NSD, nsd_id)
if template_db.get('template_source') == 'inline':

View File

@ -1,27 +0,0 @@
# 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 mistralclient.api import client as mistral_client
class MistralClient(object):
"""Mistral Client class for NSD"""
def __init__(self, keystone, auth_token):
endpoint = keystone.get_endpoint(
service_type='workflowv2', region_name=None)
self.client = mistral_client.client(auth_token=auth_token,
mistral_url=endpoint)
def get_client(self):
return self.client

View File

@ -1,36 +0,0 @@
# 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 oslo_utils import uuidutils
class WorkflowGeneratorBase(object):
def __init__(self, resource, action):
self.resource = resource
self.action = action
self.wf_name = self.action + '_' + self.resource
self.wf_identifier = 'std.' + self.wf_name + uuidutils.generate_uuid()
self.task = getattr(self, self.wf_name)
self.input_dict = dict()
self._build_basic_workflow()
def _build_basic_workflow(self):
self.definition = {
'version': '2.0',
self.wf_identifier: {
'type': 'direct',
'input': [self.resource]
}
}
def get_tasks(self):
return self.definition[self.wf_identifier].get('tasks')

View File

@ -15,7 +15,6 @@
# under the License.
import os
import yaml
from keystoneauth1 import exceptions
from keystoneauth1 import identity
@ -32,10 +31,8 @@ from tacker.common import utils
from tacker import context as t_context
from tacker.extensions import nfvo
from tacker.keymgr import API as KEYMGR_API
from tacker.mistral import mistral_client
from tacker.nfvo.drivers.vim import abstract_vim_driver
from tacker.nfvo.drivers.vnffg import abstract_vnffg_driver
from tacker.nfvo.drivers.workflow import workflow_generator
from tacker.nfvo.nfvo_plugin import NfvoPlugin
from tacker.plugins.common import constants
from tacker.vnfm import keystone
@ -707,46 +704,6 @@ class OpenStack_Driver(abstract_vim_driver.VimAbstractDriver,
neutronclient_ = NeutronClient(auth_attr)
neutronclient_.flow_classifier_delete(fc_id)
def get_mistral_client(self, auth_dict):
if not auth_dict:
LOG.warning("auth dict required to instantiate mistral client")
raise EnvironmentError('auth dict required for'
' mistral workflow driver')
return mistral_client.MistralClient(
keystone.Keystone().initialize_client(**auth_dict),
auth_dict['token']).get_client()
def prepare_and_create_workflow(self, resource, action,
kwargs, auth_dict=None):
mistral_client = self.get_mistral_client(auth_dict)
wg = workflow_generator.WorkflowGenerator(resource, action)
wg.task(**kwargs)
if not wg.get_tasks():
raise nfvo.NoTasksException(resource=resource, action=action)
yaml.SafeDumper.ignore_aliases = lambda self, data: True
definition_yaml = yaml.safe_dump(wg.definition)
workflow = mistral_client.workflows.create(definition_yaml)
return {'id': workflow[0].id, 'input': wg.get_input_dict()}
def execute_workflow(self, workflow, auth_dict=None):
return self.get_mistral_client(auth_dict) \
.executions.create(
workflow_identifier=workflow['id'],
workflow_input=workflow['input'],
wf_params={})
def get_execution(self, execution_id, auth_dict=None):
return self.get_mistral_client(auth_dict) \
.executions.get(execution_id)
def delete_execution(self, execution_id, auth_dict=None):
return self.get_mistral_client(auth_dict).executions \
.delete(execution_id, force=True)
def delete_workflow(self, workflow_id, auth_dict=None):
return self.get_mistral_client(auth_dict) \
.workflows.delete(workflow_id)
def _delete_ppgs_and_pps(self, neutronclient, new_ppgs,
past_ppgs_dict, pcs_list, fc_ids):
if new_ppgs:

View File

@ -1,277 +0,0 @@
# 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.
import ast
from tacker.mistral import workflow_generator
OUTPUT = {
'create_vnf': ['vnf_id', 'vim_id', 'mgmt_ip_address', 'status'],
'create_vnffg': ['vnffg_id'],
}
class WorkflowGenerator(workflow_generator.WorkflowGeneratorBase):
def _add_create_vnf_tasks(self, ns):
vnfds = ns['vnfd_details']
task_dict = dict()
for vnfd_name, vnfd_info in (vnfds).items():
nodes = vnfd_info['instances']
for node in nodes:
task = self.wf_name + '_' + node
task_dict[task] = {
'action': 'tacker.create_vnf body=<% $.ns.{0} '
'%>'.format(node),
'input': {'body': '<% $.ns.{0} %>'.format(node)},
'publish': {
'vnf_id_' + node: '<% task({0}).result.vnf.id '
'%>'.format(task),
'vim_id_' + node: '<% task({0}).result.vnf.vim_id'
' %>'.format(task),
'mgmt_ip_address_' + node: '<% task({0}).result.vnf.'
'mgmt_ip_address '
'%>'.format(task),
'status_' + node: '<% task({0}).result.vnf.status'
' %>'.format(task),
},
'on-success': ['wait_vnf_active_%s' % node]
}
return task_dict
def _add_wait_vnf_tasks(self, ns):
vnfds = ns['vnfd_details']
task_dict = dict()
for vnfd_name, vnfd_info in (vnfds).items():
nodes = vnfd_info['instances']
for node in nodes:
task = 'wait_vnf_active_%s' % node
task_dict[task] = {
'action': 'tacker.show_vnf vnf=<% $.vnf_id_{0} '
'%>'.format(node),
'retry': {
'count': 10,
'delay': 10,
'break-on': '<% $.status_{0} = "ERROR"'
' %>'.format(node),
'continue-on': '<% $.status_{0} = "PENDING_CREATE" '
'%>'.format(node),
},
'publish': {
'mgmt_ip_address_' + node: ' <% task({0}).result.'
'vnf.mgmt_ip_address '
'%>'.format(task),
'status_' + node: '<% task({0}).result.vnf.status'
' %>'.format(task),
},
'on-success': [
{'delete_vnf_' + node: '<% $.status_{0}='
'"ERROR" %>'.format(node)}
]
}
vnffgd_templates = ns.get('vnffgd_templates')
if vnffgd_templates:
for vnffg_name in vnffgd_templates:
vnffg_group = vnffgd_templates[vnffg_name][
'topology_template']['groups'][vnffg_name]
constituent_vnfs = vnffg_group[
'properties']['constituent_vnfs']
if vnfd_name in constituent_vnfs:
task_dict[task]['on-success'].append(
'create_vnffg_%s' % vnffg_name)
return task_dict
def _add_delete_vnf_tasks(self, ns, vnffg_ids=None):
vnfds = ns['vnfd_details']
vnf_attr = {'vnf': {'attributes': {
'force': ns.get('force_delete', False)}}}
task_dict = dict()
for vnfd_name, vnfd_info in (vnfds).items():
nodes = vnfd_info['instances']
for node in nodes:
task = 'delete_vnf_%s' % node
task_dict[task] = {
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_{0}'
'%>'.format(node),
'input': {'body': vnf_attr},
}
if vnffg_ids and len(vnffg_ids):
task_dict[task].update({'join': 'all'})
return task_dict
def _add_create_vnffg_task(self, vnffgd_templates):
task_dict = dict()
previous_task = None
for vnffg_name in vnffgd_templates:
task = 'create_vnffg_%s' % vnffg_name
vnffg_output = 'vnffg_id_%s' % vnffg_name
task_dict[task] = {
'join': 'all',
'action': 'tacker.create_vnffg body=<% $.ns.{0} '
'%>'.format(vnffg_name),
'input': {'body': '<% $.ns.{0} %>'.format(vnffg_name)},
'publish': {
vnffg_output: '<% task({0}).result.'
'vnffg.id %>'.format(task)}
}
if previous_task:
task_dict[previous_task].update({'on-success': [task]})
previous_task = task
return task_dict
def _add_delete_vnffg_task(self, ns):
task_dict = dict()
vnfds = ns['vnfd_details']
vnffg_ids = ns['vnffg_details']
delayed_tasks = list()
for vnfd_name, vnfd_info in (vnfds).items():
nodes = vnfd_info['instances']
for node in nodes:
wait_task = 'delete_vnf_%s' % node
delayed_tasks.append(wait_task)
previous_task = None
for vnffg_name in vnffg_ids:
task = 'delete_vnffg_%s' % vnffg_name
if previous_task:
wait_tasks = delayed_tasks + [previous_task]
else:
wait_tasks = delayed_tasks
previous_task = task
task_dict[task] = {
'action': 'tacker.delete_vnffg vnffg=<% $.{0} '
'%>'.format(vnffg_name),
'on-success': wait_tasks
}
return task_dict
def _build_output_dict(self, ns):
vnfds = ns['vnfd_details']
task_dict = dict()
for vnfd_name, vnfd_info in (vnfds).items():
nodes = vnfd_info['instances']
for node in nodes:
for op_name in OUTPUT['create_vnf']:
task_dict[op_name + '_' + node] = \
'<% $.{0}_{1} %>'.format(op_name, node)
vnffgd_templates = ns.get('vnffgd_templates')
if vnffgd_templates:
for vnffg_name in vnffgd_templates:
for op_name in OUTPUT['create_vnffg']:
vnffg_output = '%s_%s' % (op_name, vnffg_name)
task_dict[vnffg_output] = \
'<% $.{0}_{1} %>'.format(op_name, vnffg_name)
return task_dict
def get_input_dict(self):
return self.input_dict
def build_input(self, ns, params):
vnfds = ns['vnfd_details']
ns_id = ns['ns'].get('ns_id')
ns_name = ns['ns'].get('name')
self.input_dict = {'ns': {}}
for vnfd_name, vnfd_info in (vnfds).items():
nodes = vnfd_info['instances']
for node in nodes:
vnf_name = '%s_VNF_%s' % (ns_name, vnfd_info['id'])
self.input_dict['ns'][node] = dict()
self.input_dict['ns'][node]['vnf'] = {
'attributes': {},
'vim_id': ns['ns'].get('vim_id', ''),
'vnfd_id': vnfd_info['id'],
'name': vnf_name
}
if params.get(vnfd_name):
self.input_dict['ns'][node]['vnf']['attributes'] = {
'param_values': params.get(vnfd_name)
}
if ns.get('vnffgd_templates'):
vnffg_input = self.build_vnffg_input(ns, params, ns_id)
self.input_dict['ns'].update(vnffg_input)
def build_vnffg_input(self, ns, params, ns_id):
vnffgd_templates = ns.get('vnffgd_templates')
vnffg_input = dict()
for vnffg_name in vnffgd_templates:
vnffg_group = vnffgd_templates[vnffg_name][
'topology_template']['groups'][vnffg_name]
constituent_vnfs = vnffg_group[
'properties']['constituent_vnfs']
vnf_mapping = self.get_vnf_mapping(ns, constituent_vnfs)
vnffgd_body = dict()
vnffgd_body['vnffg'] = {
'name': '%s_%s_%s' % (ns['ns'].get('name'), vnffg_name, ns_id),
'vnffgd_template': vnffgd_templates[vnffg_name],
'vnf_mapping': vnf_mapping,
'attributes': {
'param_values': params.get('nsd')},
'ns_id': ns_id
}
vnffg_input[vnffg_name] = vnffgd_body
return vnffg_input
def get_vnf_mapping(self, ns, constituent_vnfs):
vnfds = ns['vnfd_details']
vnf_mapping = dict()
for vnfd_name, vnfd_info in (vnfds).items():
if vnfd_name in constituent_vnfs:
vnf_name = '%s_VNF_%s' % (ns['ns'].get('name'),
vnfd_info['id'])
vnf_mapping[vnfd_name] = vnf_name
return vnf_mapping
def create_ns(self, **kwargs):
ns = kwargs.get('ns')
params = kwargs.get('params')
tasks = {}
for func in [self._add_create_vnf_tasks,
self._add_wait_vnf_tasks,
self._add_delete_vnf_tasks]:
tasks.update(func(ns))
self.build_input(ns, params)
vnffgd_templates = ns.get('vnffgd_templates')
if vnffgd_templates:
create_task = self._add_create_vnffg_task(vnffgd_templates)
tasks.update(create_task)
self.definition[self.wf_identifier]['tasks'] = tasks
self.definition[self.wf_identifier]['output'] = \
self._build_output_dict(ns)
def delete_ns(self, ns):
ns_dict = {'vnfd_details': {}}
vnf_ids = ast.literal_eval(ns['vnf_ids'])
self.definition[self.wf_identifier]['input'] = []
for vnf in vnf_ids:
vnf_key = 'vnf_id_' + vnf
self.definition[self.wf_identifier]['input'].append(vnf_key)
self.input_dict[vnf_key] = vnf_ids[vnf]
ns_dict['vnfd_details'][vnf] = {'instances': [vnf]}
self.definition[self.wf_identifier]['tasks'] = dict()
vnffg_ids = ast.literal_eval(ns.get('vnffg_ids'))
if len(vnffg_ids):
for vnffg_name in vnffg_ids:
self.definition[self.wf_identifier]['input'].append(vnffg_name)
self.input_dict[vnffg_name] = vnffg_ids[vnffg_name]
ns_dict['vnffg_details'] = vnffg_ids
self.definition[self.wf_identifier]['tasks'].update(
self._add_delete_vnffg_task(ns_dict))
ns_dict['force_delete'] = ns.get('force_delete', False)
self.definition[self.wf_identifier]['tasks'].update(
self._add_delete_vnf_tasks(ns_dict, vnffg_ids))

View File

@ -16,7 +16,6 @@
import copy
import os
import time
import yaml
from cryptography import fernet
@ -51,8 +50,6 @@ from toscaparser import tosca_template
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
MISTRAL_RETRIES = 30
MISTRAL_RETRY_WAIT = 6
def config_opts():
@ -719,17 +716,12 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
vnffgd_templates[vnffg_name] = vnffgd_template
return vnffgd_templates
# TODO(hiromu): Remove create NS API after the deprecation is accepted.
@log.log
def create_ns(self, context, ns):
"""Create NS, corresponding VNFs, VNFFGs.
:param ns: ns dict which contains nsd_id and attributes
This method has 3 steps:
step-1: substitute all get_input params to its corresponding values
step-2: Build params dict for substitution mappings case through which
VNFs will actually substitute their requirements.
step-3: Create mistral workflow to create VNFs, VNFFG and execute the
workflow
"""
ns_info = ns['ns']
name = ns_info['name']
@ -753,7 +745,6 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
vim_res = self.vim_client.get_vim(context, ns['ns']['vim_id'],
region_name)
driver_type = vim_res['vim_type']
if not ns['ns']['vim_id']:
ns['ns']['vim_id'] = vim_res['vim_id']
@ -810,75 +801,10 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
LOG.debug('vnffgd_templates: %s', vnffgd_templates)
ns['vnffgd_templates'] = vnffgd_templates
# Step-3
kwargs = {'ns': ns, 'params': param_values}
# NOTE NoTasksException is raised if no tasks.
workflow = self._vim_drivers.invoke(
driver_type,
'prepare_and_create_workflow',
resource='ns',
action='create',
auth_dict=self.get_auth_dict(context),
kwargs=kwargs)
try:
mistral_execution = self._vim_drivers.invoke(
driver_type,
'execute_workflow',
workflow=workflow,
auth_dict=self.get_auth_dict(context))
except Exception as ex:
LOG.error('Error while executing workflow: %s', ex)
self._vim_drivers.invoke(driver_type,
'delete_workflow',
workflow_id=workflow['id'],
auth_dict=self.get_auth_dict(context))
raise ex
ns_dict = super(NfvoPlugin, self).create_ns(context, ns)
def _create_ns_wait(self_obj, ns_id, execution_id):
exec_state = "RUNNING"
mistral_retries = MISTRAL_RETRIES
while exec_state == "RUNNING" and mistral_retries > 0:
time.sleep(MISTRAL_RETRY_WAIT)
exec_state = self._vim_drivers.invoke(
driver_type,
'get_execution',
execution_id=execution_id,
auth_dict=self.get_auth_dict(context)).state
LOG.debug('status: %s', exec_state)
if exec_state == 'SUCCESS' or exec_state == 'ERROR':
break
mistral_retries = mistral_retries - 1
# TODO(phuoc): add more information about error reason in case
# of exec_state is 'ERROR'
error_reason = None
if mistral_retries == 0 and exec_state == 'RUNNING':
error_reason = _(
"NS creation is not completed within"
" {wait} seconds as creation of mistral"
" execution {mistral} is not completed").format(
wait=MISTRAL_RETRIES * MISTRAL_RETRY_WAIT,
mistral=execution_id)
exec_obj = self._vim_drivers.invoke(
driver_type,
'get_execution',
execution_id=execution_id,
auth_dict=self.get_auth_dict(context))
self._vim_drivers.invoke(driver_type,
'delete_execution',
execution_id=execution_id,
auth_dict=self.get_auth_dict(context))
self._vim_drivers.invoke(driver_type,
'delete_workflow',
workflow_id=workflow['id'],
auth_dict=self.get_auth_dict(context))
super(NfvoPlugin, self).create_ns_post(
context, ns_id, exec_obj, vnfd_dict,
vnffgd_templates, error_reason)
self.spawn_n(_create_ns_wait, self, ns_dict['id'],
mistral_execution.id)
super(NfvoPlugin, self).create_ns_post(
context, ns_dict['id'], vnfd_dict, vnffgd_templates)
return ns_dict
@log.log
@ -907,6 +833,7 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
else:
raise cs.ParamYAMLInputMissing()
# TODO(hiromu): Remove delete NS API after the deprecation is accepted.
@log.log
def delete_ns(self, context, ns_id, ns=None):
# Extract "force_delete" from request's body
@ -918,83 +845,7 @@ class NfvoPlugin(nfvo_db_plugin.NfvoPluginDb, vnffg_db.VnffgPluginDbMixin,
raise exceptions.AdminRequired(reason="Admin only operation")
ns = super(NfvoPlugin, self).get_ns(context, ns_id)
LOG.debug("Deleting ns: %s", ns)
vim_res = self.vim_client.get_vim(context, ns['vim_id'])
super(NfvoPlugin, self).delete_ns_pre(context, ns_id, force_delete)
driver_type = vim_res['vim_type']
workflow = None
try:
if ns['vnf_ids']:
ns['force_delete'] = force_delete
workflow = self._vim_drivers.invoke(
driver_type,
'prepare_and_create_workflow',
resource='ns',
action='delete',
auth_dict=self.get_auth_dict(context),
kwargs={'ns': ns})
except nfvo.NoTasksException:
LOG.warning("No VNF deletion task(s).")
if workflow:
try:
mistral_execution = self._vim_drivers.invoke(
driver_type,
'execute_workflow',
workflow=workflow,
auth_dict=self.get_auth_dict(context))
except Exception as ex:
LOG.error('Error while executing workflow: %s', ex)
self._vim_drivers.invoke(driver_type,
'delete_workflow',
workflow_id=workflow['id'],
auth_dict=self.get_auth_dict(context))
raise ex
def _delete_ns_wait(ns_id, execution_id):
exec_state = "RUNNING"
mistral_retries = MISTRAL_RETRIES
while exec_state == "RUNNING" and mistral_retries > 0:
time.sleep(MISTRAL_RETRY_WAIT)
exec_state = self._vim_drivers.invoke(
driver_type,
'get_execution',
execution_id=execution_id,
auth_dict=self.get_auth_dict(context)).state
LOG.debug('status: %s', exec_state)
if exec_state == 'SUCCESS' or exec_state == 'ERROR':
break
mistral_retries -= 1
# TODO(phuoc): add more information about error reason in case
# of exec_state is 'ERROR'
error_reason = None
if mistral_retries == 0 and exec_state == 'RUNNING':
error_reason = _(
"NS deletion is not completed within"
" {wait} seconds as deletion of mistral"
" execution {mistral} is not completed").format(
wait=MISTRAL_RETRIES * MISTRAL_RETRY_WAIT,
mistral=execution_id)
exec_obj = self._vim_drivers.invoke(
driver_type,
'get_execution',
execution_id=execution_id,
auth_dict=self.get_auth_dict(context))
self._vim_drivers.invoke(driver_type,
'delete_execution',
execution_id=execution_id,
auth_dict=self.get_auth_dict(context))
self._vim_drivers.invoke(driver_type,
'delete_workflow',
workflow_id=workflow['id'],
auth_dict=self.get_auth_dict(context))
super(NfvoPlugin, self).delete_ns_post(context, ns_id, exec_obj,
error_reason,
force_delete=force_delete)
if workflow:
self.spawn_n(_delete_ns_wait, ns['id'], mistral_execution.id)
else:
super(NfvoPlugin, self).delete_ns_post(
context, ns_id, None, None, force_delete=force_delete)
super(NfvoPlugin, self).delete_ns_post(
context, ns_id, force_delete=force_delete)
return ns['id']

View File

@ -1,403 +0,0 @@
# 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 tacker import context
from tacker.nfvo.drivers.workflow import workflow_generator
from tacker.tests.unit import base
def get_dummy_ns():
return {'ns': {'description': '',
'tenant_id': 'a81900a92bda40588c52699e1873a92f',
'vim_id': '96025dd5-ca16-49f3-9823-958eb04260c4',
'vnf_ids': '', 'attributes': {},
'nsd_id': 'b8587afb-6099-4f56-abce-572c62e3d61d',
'name': 'test_create_ns'},
'vnfd_details': {'vnf1': {'instances': ['VNF1'],
'id': 'dec09ed4-f355-4ec8-a00b-8548f6575a80'},
'vnf2': {'instances': ['VNF2'],
'id': '9f8f2af7-6407-4f79-a6fe-302c56172231'}},
'placement_attr': {}}
def get_dummy_vnffg_ns():
return {
'ns': {
'description': '',
'vim_id': '96025dd5-ca16-49f3-9823-958eb04260c4',
'vnf_ids': '', 'attributes': {},
'nsd_id': 'b8587afb-6099-4f56-abce-572c62e3d61d',
'name': 'test_create_ns'},
'vnfd_details': {
'vnf1': {'instances': ['VNF1'],
'id': 'dec09ed4-f355-4ec8-a00b-8548f6575a80'},
'vnf2': {'instances': ['VNF2'],
'id': '9f8f2af7-6407-4f79-a6fe-302c56172231'}},
'placement_attr': {},
'vnffgd_templates': {
'VNFFG1': {
'tosca_definitions_version':
'tosca_simple_profile_for_nfv_1_0_0',
'description': 'VNFFG1 descriptor',
'topology_template': {
'node_templates': {
'Forwarding_path1': {
'type': 'tosca.nodes.nfv.FP.TackerV2',
'description': 'creates path inside ns - test',
'properties': {
'policy': {
'type': 'ACL',
'criteria': [{
'classifier': {
'ip_proto': 6,
'network_src_port_id': {
'get_input': 'net_src_port_id'
},
'ip_dst_prefix': {
'get_input': 'ip_dest_prefix'
},
'destination_port_range': '80-1024'
},
'name': 'block_tcp'}]},
'path': [
{'capability': 'CP12',
'forwarder': 'vnf1'},
{'capability': 'CP22',
'forwarder': 'vnf2'}],
'id': 51}}},
'groups': {
'VNFFG1': {
'type': 'tosca.groups.nfv.VNFFG',
'description': 'HTTP to Corporate Net',
'members': ['Forwarding_path1'],
'properties': {
'version': 1.0,
'vendor': 'tacker',
'constituent_vnfs': ['vnf1', 'vnf2'],
'connection_point': ['CP12', 'CP22'],
'number_of_endpoints': 2,
'dependent_virtual_link': ['VL1', 'VL2']}
}
}
}
}
}
}
def get_dummy_param():
return {'vnf1': {'substitution_mappings': {'VL1b8587afb-60': {
'type': 'tosca.nodes.nfv.VL', 'properties': {
'network_name': 'net_mgmt',
'vendor': 'tacker'}}, 'requirements': {
'virtualLink2': 'VL2b8587afb-60',
'virtualLink1': 'VL1b8587afb-60'}, 'VL2b8587afb-60': {
'type': 'tosca.nodes.nfv.VL',
'properties': {'network_name': 'net0',
'vendor': 'tacker'}}}},
'nsd': {'vl2_name': 'net0', 'vl1_name': 'net_mgmt'}}
def get_dummy_create_workflow():
return {'std.create_ns_dummy': {'input': ['ns'],
'tasks': {
'wait_vnf_active_VNF2': {
'action': 'tacker.show_vnf vnf=<% $.vnf_id_VNF2 %>',
'retry': {'count': 10, 'delay': 10,
'continue-on': '<% $.status_VNF2 = '
'"PENDING_CREATE" %>',
'break-on': '<% $.status_VNF2 = "ERROR" %>'},
'publish': {
'status_VNF2': '<% task(wait_vnf_active_VNF2).'
'result.vnf.status %>',
'mgmt_ip_address_VNF2': ' <% task('
'wait_vnf_active_VNF2).'
'result.vnf.'
'mgmt_ip_address %>'},
'on-success': [{
'delete_vnf_VNF2': '<% $.status_VNF2='
'"ERROR" %>'}]},
'create_ns_VNF2': {
'action': 'tacker.create_vnf body=<% $.ns.VNF2 %>',
'input': {'body': '<% $.ns.VNF2 %>'},
'publish': {
'status_VNF2': '<% task(create_ns_VNF2).'
'result.vnf.status %>',
'vim_id_VNF2': '<% task(create_ns_VNF2).'
'result.vnf.vim_id %>',
'mgmt_ip_address_VNF2': '<% task('
'create_ns_VNF2).'
'result.vnf.'
'mgmt_ip_address %>',
'vnf_id_VNF2': '<% task(create_ns_VNF2)'
'.result.vnf.id %>'},
'on-success': ['wait_vnf_active_VNF2']},
'create_ns_VNF1': {
'action': 'tacker.create_vnf body=<% $.ns.VNF1 %>',
'input': {'body': '<% $.ns.VNF1 %>'},
'publish': {
'status_VNF1': '<% task(create_ns_VNF1).'
'result.vnf.status %>',
'vnf_id_VNF1': '<% task(create_ns_VNF1).'
'result.vnf.id %>',
'mgmt_ip_address_VNF1': '<% task('
'create_ns_VNF1).'
'result.vnf.'
'mgmt_ip_address %>',
'vim_id_VNF1': '<% task(create_ns_VNF1).'
'result.vnf.vim_id %>'},
'on-success': ['wait_vnf_active_VNF1']},
'wait_vnf_active_VNF1': {
'action': 'tacker.show_vnf vnf=<% $.vnf_id_VNF1 %>',
'retry': {'count': 10, 'delay': 10,
'continue-on': '<% $.status_VNF1 = "PENDING_'
'CREATE" %>',
'break-on': '<% $.status_VNF1 = "ERROR" %>'},
'publish': {
'status_VNF1': '<% task(wait_vnf_active_VNF1).'
'result.vnf.status %>',
'mgmt_ip_address_VNF1': ' <% task('
'wait_vnf_active_VNF1).'
'result.vnf.'
'mgmt_ip_address %>'},
'on-success': [{'delete_vnf_VNF1': '<% $.status_VNF1='
'"ERROR" %>'}]},
'delete_vnf_VNF1': {
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_VNF1%>',
'input': {'body': {'vnf': {'attributes': {
'force': False}}}}},
'delete_vnf_VNF2': {
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_VNF2%>',
'input': {'body': {'vnf': {'attributes': {
'force': False}}}}}},
'type': 'direct', 'output': {
'status_VNF1': '<% $.status_VNF1 %>',
'status_VNF2': '<% $.status_VNF2 %>',
'mgmt_ip_address_VNF2': '<% $.mgmt_ip_address_VNF2 %>',
'mgmt_ip_address_VNF1': '<% $.mgmt_ip_address_VNF1 %>',
'vim_id_VNF2': '<% $.vim_id_VNF2 %>',
'vnf_id_VNF1': '<% $.vnf_id_VNF1 %>',
'vnf_id_VNF2': '<% $.vnf_id_VNF2 %>',
'vim_id_VNF1': '<% $.vim_id_VNF1 %>'}},
'version': '2.0'}
def get_dummy_create_vnffg_ns_workflow():
return {
'std.create_ns_dummy': {
'input': ['ns'],
'tasks': {
'wait_vnf_active_VNF2': {
'action': 'tacker.show_vnf vnf=<% $.vnf_id_VNF2 %>',
'retry': {
'count': 10,
'delay': 10,
'continue-on':
'<% $.status_VNF2 = "PENDING_CREATE" %>',
'break-on':
'<% $.status_VNF2 = "ERROR" %>'},
'publish': {
'status_VNF2':
'<% task(wait_vnf_active_VNF2).result.'
'vnf.status %>',
'mgmt_ip_address_VNF2':
' <% task(wait_vnf_active_VNF2).result.'
'vnf.mgmt_ip_address %>'},
'on-success': [
{'delete_vnf_VNF2': '<% $.status_VNF2="ERROR" %>'},
'create_vnffg_VNFFG1']},
'create_vnffg_VNFFG1': {
'action': 'tacker.create_vnffg body=<% $.ns.VNFFG1 %>',
'input': {'body': '<% $.ns.VNFFG1 %>'},
'join': 'all',
'publish': {
'vnffg_id_VNFFG1': '<% task(create_vnffg_VNFFG1).'
'result.vnffg.id %>'}},
'wait_vnf_active_VNF1': {
'action': 'tacker.show_vnf vnf=<% $.vnf_id_VNF1 %>',
'retry': {
'count': 10,
'delay': 10,
'continue-on':
'<% $.status_VNF1 = "PENDING_CREATE" %>',
'break-on':
'<% $.status_VNF1 = "ERROR" %>'},
'publish': {
'status_VNF1':
'<% task(wait_vnf_active_VNF1).result.'
'vnf.status %>',
'mgmt_ip_address_VNF1':
' <% task(wait_vnf_active_VNF1).result.'
'vnf.mgmt_ip_address %>'},
'on-success': [
{'delete_vnf_VNF1': '<% $.status_VNF1="ERROR" %>'},
'create_vnffg_VNFFG1']},
'create_ns_VNF1': {
'action': 'tacker.create_vnf body=<% $.ns.VNF1 %>',
'input': {'body': '<% $.ns.VNF1 %>'},
'publish': {
'status_VNF1':
'<% task(create_ns_VNF1).result.vnf.status %>',
'vnf_id_VNF1':
'<% task(create_ns_VNF1).result.vnf.id %>',
'mgmt_ip_address_VNF1':
'<% task(create_ns_VNF1).result.'
'vnf.mgmt_ip_address %>',
'vim_id_VNF1':
'<% task(create_ns_VNF1).result.vnf.vim_id %>'},
'on-success': ['wait_vnf_active_VNF1']},
'create_ns_VNF2': {
'action': 'tacker.create_vnf body=<% $.ns.VNF2 %>',
'input': {'body': '<% $.ns.VNF2 %>'},
'publish': {
'status_VNF2':
'<% task(create_ns_VNF2).result.vnf.status %>',
'vim_id_VNF2':
'<% task(create_ns_VNF2).result.vnf.vim_id %>',
'mgmt_ip_address_VNF2':
'<% task(create_ns_VNF2).result.'
'vnf.mgmt_ip_address %>',
'vnf_id_VNF2':
'<% task(create_ns_VNF2).result.vnf.id %>'},
'on-success': ['wait_vnf_active_VNF2']},
'delete_vnf_VNF1': {
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_VNF1%>',
'input': {'body': {'vnf': {'attributes': {
'force': False}}}}},
'delete_vnf_VNF2': {
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_VNF2%>',
'input': {'body': {'vnf': {'attributes': {
'force': False}}}}}},
'type': 'direct',
'output': {
'status_VNF1': '<% $.status_VNF1 %>',
'status_VNF2': '<% $.status_VNF2 %>',
'mgmt_ip_address_VNF2': '<% $.mgmt_ip_address_VNF2 %>',
'mgmt_ip_address_VNF1': '<% $.mgmt_ip_address_VNF1 %>',
'vnffg_id_VNFFG1': '<% $.vnffg_id_VNFFG1 %>',
'vim_id_VNF2': '<% $.vim_id_VNF2 %>',
'vnf_id_VNF1': '<% $.vnf_id_VNF1 %>',
'vnf_id_VNF2': '<% $.vnf_id_VNF2 %>',
'vim_id_VNF1': '<% $.vim_id_VNF1 %>'}},
'version': '2.0'}
def dummy_delete_ns_obj():
return {'vnf_ids': "{'VNF1': '5de5eca6-3e21-4bbd-a9d7-86458de75f0c'}",
'vnffg_ids': "{}"}
def dummy_delete_vnffg_ns_obj():
return {'vnf_ids': "{'VNF1': '5de5eca6-3e21-4bbd-a9d7-86458de75f0c'}",
'vnffg_ids': "{'VNFFG1': '99066f25-3124-44f1-bc5d-bc0bf236b012'}"}
def get_dummy_delete_workflow():
return {'version': '2.0',
'std.delete_ns_dummy': {
'input': ['vnf_id_VNF1'],
'tasks': {
'delete_vnf_VNF1': {
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_VNF1%>',
'input': {'body': {'vnf': {'attributes': {
'force': False}}}}}},
'type': 'direct'}}
def get_dummy_delete_vnffg_ns_workflow():
return {'version': '2.0',
'std.delete_ns_dummy': {
'input': ['vnf_id_VNF1', 'VNFFG1'],
'tasks': {
'delete_vnf_VNF1': {
'join': 'all',
'action': 'tacker.delete_vnf vnf=<% $.vnf_id_VNF1%>',
'input': {'body': {'vnf': {'attributes': {
'force': False}}}}},
'delete_vnffg_VNFFG1': {
'action': 'tacker.delete_vnffg vnffg='
'<% $.VNFFG1 %>',
'on-success': ['delete_vnf_VNF1']}},
'type': 'direct'}}
class FakeMistral(object):
def __init__(self):
pass
class FakeNFVOPlugin(object):
def __init__(self, context, client, resource, action):
self.context = context
self.client = client
self.wg = workflow_generator.WorkflowGenerator(resource, action)
def prepare_workflow(self, **kwargs):
self.wg.task(**kwargs)
class TestWorkflowGenerator(base.TestCase):
def setUp(self):
super(TestWorkflowGenerator, self).setUp()
self.mistral_client = FakeMistral()
def test_prepare_workflow_create(self):
fPlugin = FakeNFVOPlugin(context, self.mistral_client,
resource='ns', action='create')
fPlugin.prepare_workflow(ns=get_dummy_ns(), params=get_dummy_param())
wf_def_values = [fPlugin.wg.definition[k] for
k in fPlugin.wg.definition]
self.assertIn(get_dummy_create_workflow()['std.create_ns_dummy'],
wf_def_values)
self.assertEqual(get_dummy_create_workflow()['version'],
fPlugin.wg.definition['version'])
def test_prepare_vnffg_ns_workflow_create(self):
fPlugin = FakeNFVOPlugin(context, self.mistral_client,
resource='ns', action='create')
fPlugin.prepare_workflow(ns=get_dummy_vnffg_ns(),
params=get_dummy_param())
wf_def_values = [fPlugin.wg.definition[k] for
k in fPlugin.wg.definition]
self.assertIn(
get_dummy_create_vnffg_ns_workflow()['std.create_ns_dummy'],
wf_def_values)
self.assertEqual(
get_dummy_create_vnffg_ns_workflow()['version'],
fPlugin.wg.definition['version'])
def test_prepare_workflow_delete(self):
fPlugin = FakeNFVOPlugin(context, self.mistral_client,
resource='ns', action='delete')
fPlugin.prepare_workflow(ns=dummy_delete_ns_obj())
wf_def_values = [fPlugin.wg.definition[k] for
k in fPlugin.wg.definition]
self.assertIn(get_dummy_delete_workflow()['std.delete_ns_dummy'],
wf_def_values)
self.assertEqual(get_dummy_delete_workflow()['version'],
fPlugin.wg.definition['version'])
def test_prepare_vnffg_ns_workflow_delete(self):
fPlugin = FakeNFVOPlugin(context, self.mistral_client,
resource='ns', action='delete')
fPlugin.prepare_workflow(ns=dummy_delete_vnffg_ns_obj())
wf_def_values = [fPlugin.wg.definition[k] for
k in fPlugin.wg.definition]
self.assertIn(
get_dummy_delete_vnffg_ns_workflow()['std.delete_ns_dummy'],
wf_def_values)
self.assertEqual(
get_dummy_delete_vnffg_ns_workflow()['version'],
fPlugin.wg.definition['version'])

View File

@ -29,7 +29,6 @@ from tacker.db.nfvo import ns_db
from tacker.db.nfvo import vnffg_db
from tacker.extensions import nfvo
from tacker.manager import TackerManager
from tacker.nfvo.drivers.vim import openstack_driver
from tacker.nfvo import nfvo_plugin
from tacker.plugins.common import constants
from tacker.tests import constants as test_constants
@ -62,22 +61,6 @@ class FakeDriverManager(mock.Mock):
return uuidutils.generate_uuid()
elif 'create_chain' in args:
return uuidutils.generate_uuid(), uuidutils.generate_uuid()
elif 'execute_workflow' in args:
mock_execution = mock.Mock()
mock_execution.id.return_value = \
"ba6bf017-f6f7-45f1-a280-57b073bf78ea"
return mock_execution
elif ('prepare_and_create_workflow' in args and
'delete' == kwargs['action'] and
DUMMY_NS_2 == kwargs['kwargs']['ns']['id']):
raise nfvo.NoTasksException(action=kwargs['action'],
resource=kwargs['kwargs']['ns']['id'])
elif ('prepare_and_create_workflow' in args and
'create' == kwargs['action'] and
utils.DUMMY_NS_2_NAME == kwargs['kwargs']['ns']['ns']['name']):
raise nfvo.NoTasksException(
action=kwargs['action'],
resource=kwargs['kwargs']['ns']['ns']['name'])
def get_by_name():
@ -1464,11 +1447,10 @@ class TestNfvoPlugin(db_base.SqlTestCase):
@mock.patch.object(vim_client.VimClient, 'get_vim',
return_value={"vim_type": "openstack"})
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@mock.patch.object(openstack_driver.OpenStack_Driver, 'get_mistral_client')
@mock.patch.object(uuidutils, 'generate_uuid',
return_value=test_constants.UUID)
def test_create_ns(self, mock_uuid, mock_mistral_client,
mock_get_by_name, mock_get_vimi, mock_auth_dict):
def test_create_ns(self, mock_uuid, mock_get_by_name, mock_get_vimi,
mock_auth_dict):
self._insert_dummy_ns_template()
self._insert_dummy_vim()
mock_auth_dict.return_value = {
@ -1478,62 +1460,6 @@ class TestNfvoPlugin(db_base.SqlTestCase):
'project_name': 'dummy_project'
}
sample_yaml = 'std.create_ns' + test_constants.UUID + ':\n '\
'input:\n - ns\n output:\n mgmt_ip_address_VNF1: '\
'<% $.mgmt_ip_address_VNF1 %>\n mgmt_ip_address_VNF2: '\
'<% $.mgmt_ip_address_VNF2 %>\n status_VNF1: '\
'<% $.status_VNF1 %>\n status_VNF2: '\
'<% $.status_VNF2 %>\n vim_id_VNF1: <% $.vim_id_VNF1 %>\n'\
' vim_id_VNF2: <% $.vim_id_VNF2 %>\n vnf_id_VNF1: '\
'<% $.vnf_id_VNF1 %>\n vnf_id_VNF2: <% $.vnf_id_VNF2 %>\n '\
'tasks:\n create_ns_VNF1:\n action: tacker.create_vnf '\
'body=<% $.ns.VNF1 %>\n input:\n body: '\
'<% $.ns.VNF1 %>\n on-success:\n '\
'- wait_vnf_active_VNF1\n publish:\n '\
'mgmt_ip_address_VNF1: <% task(create_ns_VNF1).result.'\
'vnf.mgmt_ip_address %>\n status_VNF1: <% '\
'task(create_ns_VNF1).result.vnf.status %>\n'\
' vim_id_VNF1: <% task(create_ns_VNF1).'\
'result.vnf.vim_id %>\n vnf_id_VNF1: <% '\
'task(create_ns_VNF1).result.vnf.id %>\n'\
' create_ns_VNF2:\n action: tacker.create_vnf '\
'body=<% $.ns.VNF2 %>\n input:\n '\
'body: <% $.ns.VNF2 %>\n on-success:\n'\
' - wait_vnf_active_VNF2\n publish:\n '\
'mgmt_ip_address_VNF2: <% task(create_ns_VNF2).result.vnf.'\
'mgmt_ip_address %>\n status_VNF2: <% task(create_ns_VNF2)'\
'.result.vnf.status %>\n vim_id_VNF2: <% '\
'task(create_ns_VNF2).result.vnf.vim_id %>\n'\
' vnf_id_VNF2: <% task(create_ns_VNF2).result.vnf.id '\
'%>\n delete_vnf_VNF1:\n action: tacker.delete_vnf vnf'\
'=<% $.vnf_id_VNF1%>\n input:\n body:\n '\
'vnf:\n attributes:\n force: false\n'\
' delete_vnf_VNF2:\n action: tacker.delete_vnf'\
' vnf=<% $.vnf_id_VNF2%>\n input:\n body:\n'\
' vnf:\n attributes:\n '\
'force: false\n wait_vnf_active_VNF1:\n action:'\
' tacker.show_vnf vnf=<% $.vnf_id_VNF1 %>\n on-success:\n'\
' - delete_vnf_VNF1: <% $.status_VNF1="ERROR" %>\n '\
'publish:\n mgmt_ip_address_VNF1: \' <% '\
'task(wait_vnf_active_VNF1).result.vnf.mgmt_ip_address\n'\
' %>\'\n status_VNF1: <% '\
'task(wait_vnf_active_VNF1).result.vnf.status %>\n '\
'retry:\n break-on: <% $.status_VNF1 = "ERROR"'\
' %>\n continue-on: <% $.status_VNF1 = "PENDING_CREATE" '\
'%>\n count: 10\n delay: 10\n '\
'wait_vnf_active_VNF2:\n action: tacker.show_vnf vnf=<% '\
'$.vnf_id_VNF2 %>\n on-success:\n '\
'- delete_vnf_VNF2: <% $.status_VNF2="ERROR" %>\n '\
'publish:\n mgmt_ip_address_VNF2: \' <% '\
'task(wait_vnf_active_VNF2).result.vnf.mgmt_ip_address\n'\
' %>\'\n status_VNF2: '\
'<% task(wait_vnf_active_VNF2).result.vnf.status %>\n'\
' retry:\n break-on: <% $.status_VNF2 = '\
'"ERROR" %>\n continue-on: '\
'<% $.status_VNF2 = "PENDING_CREATE" %>\n '\
'count: 10\n '\
'delay: 10\n type: direct\nversion: \'2.0\'\n'
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
@ -1547,17 +1473,13 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertEqual(ns_obj['ns']['name'], result['name'])
self.assertIn('status', result)
self.assertIn('tenant_id', result)
mock_mistral_client().workflows.create.\
assert_called_with(sample_yaml)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim',
return_value={"vim_type": "openstack"})
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@mock.patch.object(openstack_driver.OpenStack_Driver, 'get_mistral_client')
def test_create_ns_empty_description(self, mock_mistral_client,
mock_get_by_name,
mock_get_vimi, mock_auth_dict):
def test_create_ns_empty_description(self, mock_get_by_name, mock_get_vim,
mock_auth_dict):
self._insert_dummy_ns_template()
self._insert_dummy_vim()
mock_auth_dict.return_value = {
@ -1583,8 +1505,7 @@ class TestNfvoPlugin(db_base.SqlTestCase):
@mock.patch.object(vim_client.VimClient, 'get_vim',
return_value={"vim_type": "openstack"})
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@mock.patch.object(openstack_driver.OpenStack_Driver, 'get_mistral_client')
def test_create_ns_inline(self, mock_mistral_client, mock_get_by_name,
def test_create_ns_inline(self, mock_get_by_name,
mock_get_vimi, mock_auth_dict, mock_create_nsd):
self._insert_dummy_ns_template_inline()
self._insert_dummy_vim()
@ -1612,34 +1533,6 @@ class TestNfvoPlugin(db_base.SqlTestCase):
self.assertIn('tenant_id', result)
mock_create_nsd.assert_called_once_with(mock.ANY, mock.ANY)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim',
return_value={"vim_type": "openstack"})
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@mock.patch('tacker.common.driver_manager.DriverManager.invoke',
side_effect=nfvo.NoTasksException(action='create',
resource='ns'))
def test_create_ns_workflow_no_task_exception(
self, mock_mistral_client, mock_get_by_name,
mock_get_vimi, mock_auth_dict):
self._insert_dummy_ns_template()
self._insert_dummy_vim()
mock_auth_dict.return_value = {
'auth_url': 'http://127.0.0.1',
'token': 'DummyToken',
'project_domain_name': 'dummy_domain',
'project_name': 'dummy_project'
}
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock_get_by_name.return_value = get_by_name()
ns_obj = utils.get_dummy_ns_obj_2()
self.assertRaises(nfvo.NoTasksException,
self.nfvo_plugin.create_ns,
self.context, ns_obj)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim')
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@ -1662,33 +1555,6 @@ class TestNfvoPlugin(db_base.SqlTestCase):
'ba6bf017-f6f7-45f1-a280-57b073bf78ea')
self.assertIsNotNone(result)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim')
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')
@mock.patch("tacker.db.nfvo.ns_db.NSPluginDb.delete_ns_post")
def test_delete_ns_no_task_exception(
self, mock_delete_ns_post, mock_get_by_name, mock_get_vim,
mock_auth_dict):
self._insert_dummy_vim()
self._insert_dummy_ns_template()
self._insert_dummy_ns_2()
mock_auth_dict.return_value = {
'auth_url': 'http://127.0.0.1',
'token': 'DummyToken',
'project_domain_name': 'dummy_domain',
'project_name': 'dummy_project'
}
with patch.object(TackerManager, 'get_service_plugins') as \
mock_plugins:
mock_plugins.return_value = {'VNFM': FakeVNFMPlugin()}
mock_get_by_name.return_value = get_by_name()
self.nfvo_plugin.delete_ns(self.context,
DUMMY_NS_2)
mock_delete_ns_post.assert_called_with(
self.context, DUMMY_NS_2, None, None, force_delete=False)
@mock.patch.object(nfvo_plugin.NfvoPlugin, 'get_auth_dict')
@mock.patch.object(vim_client.VimClient, 'get_vim')
@mock.patch.object(nfvo_plugin.NfvoPlugin, '_get_by_name')