Compare commits

...

46 Commits

Author SHA1 Message Date
7dbb27989c Update .gitreview for unmaintained/2023.1
Change-Id: I95ba0980f4bfe503efe62fa120c144cba94a43bc
2024-11-14 10:17:48 +00:00
a091ced648 Update TOX_CONSTRAINTS_FILE for stable/2023.1
Update the URL to the upper-constraints file to point to the redirect
rule on releases.openstack.org so that anyone working on this branch
will switch to the correct upper-constraints list automatically when
the requirements repository branches.

Until the requirements repository has as stable/2023.1 branch, tests will
continue to use the upper-constraints list on master.

Change-Id: Ifc62b7b4239c70d601de5bc238baaac3d15de17d
2023-02-24 15:18:53 +00:00
3f04d0a220 Update .gitreview for stable/2023.1
Change-Id: I9dd52f32e59f4879329f13a1ff2c8b1c0c974627
2023-02-24 15:18:52 +00:00
Zuul
e5bd58ffe1 Merge "Extends unit test code support for merged patch" 2023-02-17 05:07:40 +00:00
Zuul
2add9e0f85 Merge "Fix list VNF/Subscription UT error" 2023-02-17 04:39:07 +00:00
Ai Hamano
a41323dc1d Fix list VNF/Subscription UT error
This patch resolves the following error caused by using one data in
multiple tests.
-----
ft1.2: tackerclient.tests.unit.osc.v1.test_vnflcm_subsc.
TestListLccnSubscription.test_take_action_with_
paginationtesttools.testresult.real._StringException:
 Traceback (most recent call last):
  File "/home/zuul/src/opendev.org/openstack/
python-tackerclient/tackerclient/tests/unit/osc/v1
/test_vnflcm_subsc.py", line 139, in test_take_action_with_
pagination
    expected_data.append(vnflcm_subsc_fakes.get_subscription_
data(
  File "/home/zuul/src/opendev.org/openstack
/python-tackerclient/tackerclient/tests/unit/osc/v1
/vnflcm_subsc_fakes.py", line 166, in get_subscription_data
    subscription.pop(item)
KeyError: 'filter'
-----

Add test data for each test.
(Three data are set for each test data so that the first, last, and
other values can be checked.)
And change not to modify test data directly in get method.

Closes-Bug: #2007524
Change-Id: Id3919fc638f6b858c115a3a7d7e4ca60036217d4
2023-02-17 02:25:25 +00:00
Zuul
a4e0790e75 Merge "Extra param for OpenStack type when register vim" 2023-02-16 12:07:03 +00:00
Zuul
0f9b6f5c52 Merge "Add support cnf auto scale via threshold interface" 2023-02-16 10:32:17 +00:00
kexuesheng
e398f422a8 Extra param for OpenStack type when register vim
This patch changes to allow setting the `extra` parameter in the VIM
configuration for openstack vim type.

Implements: blueprint enhance-api-policy
Change-Id: I37a3e21afced0aae6e0fd3c0cbb28ab16f2b7df8
2023-02-16 11:07:39 +09:00
Yi Feng
8b45c8082b Add support cnf auto scale via threshold interface
Add the Performance Management Threshold CLI to support AutoScale.
The Performance Management Threshold API is based on ETSI NFV-SOL
002 v3.3.1 and ETSI NFV-SOL 003 v3.3.1, which is Version "2.0.0"
API of Tacker.

Implements: blueprint support-auto-lcm
Change-Id: Idd313d6abe47dfa41fc86ddc614d00f99f3fc3b2
2023-02-16 10:36:47 +09:00
psingla
6b168365d6 Extends unit test code support for merged patch
This patch extends unit test code for the
feature which is implemented in this patch
https://review.opendev.org/c/openstack/python-tackerclient/+/847746

Implements: blueprint paging-query-result
Change-Id: Ic1c23ee51ab838168577c60a3ac44b600bca2563
2023-02-15 05:49:53 +00:00
Ayumu Ueha
156deea66c Add deprecation notice for Legacy APIs
This patch deprecates CLI for Legacy APIs excluding VIM feature.

Implements: blueprint deprecate-legacy-apis
Change-Id: Ib74db43b4a3de4676e61f4f9ce6d3d2095a11ddf
2023-01-27 00:38:21 +00:00
Ayumu Ueha
82bf387f77 Fix tox4 error
Remove skipsdist that it was never supported and causes breakage
when used with usedevelop.

Change-Id: Ia0c03eaa5474f13600880dd6eca79d284bba5ca8
2023-01-12 05:08:29 +00:00
Manpreet Kaur
326d02671e Update python classifier for python 3.10
In 2023.1 cycle, we are testing the python 3.10
as voting job so updating the python classifier.

Currently we have python 3.8 unit test job running on
Ubuntu Focal and python 3.10 job on Ubuntu Jammy.

Change-Id: Ie5ef1e398f6709e2164db57c3f5bbfbc69053a02
2022-12-15 12:21:12 +05:30
Zuul
6a13f2ecbd Merge "Switch to 2023.1 Python3 unit tests and generic template name" 2022-10-24 01:30:11 +00:00
0849569507 Switch to 2023.1 Python3 unit tests and generic template name
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for antelope. Also,
updating the template name to generic one.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Change-Id: I92990bd9aa48941e092fafc6246317e152ad4602
2022-09-14 09:28:28 +00:00
Zuul
190dc6d581 Merge "Update master for stable/zed" 2022-09-12 17:28:18 +00:00
b4e49b3653 Update master for stable/zed
Add file to the reno documentation build to show release notes for
stable/zed.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/zed.

Sem-Ver: feature
Change-Id: I2bf82a833e8adfb5606ccbd336872b4973f93440
2022-09-08 15:52:48 +00:00
Koji Shimizu
80ee721263 Add docs for cnf auto heal and scale
This patch makes the following updates to the API and CLI docs.

* Add support cnf auto heal and scale

Implements: blueprint support-auto-lcm
Change-Id: Ide4d8c8652cdf8ac611e65376a21806488667ace
2022-09-08 19:49:24 +09:00
Koji Shimizu
64d7a87670 Add support cnf auto heal and scale
Support container based VNF AutoHeal and AutoScale operation with
External Monitoring Tools.

Add the Fault Management interfaces and CLI to support AutoHeal.
Add the Performance Management interfaces and CLI to support
AutoScale. The Fault Management and Performance Management
interfaces are based on ETSI NFV-SOL 002 v3.3.1 and ETSI NFV-SOL
003 v3.3.1, which are Version "2.0.0" API of Tacker. Add the
Prometheus Plugin that has a interface between tacker and the
External Monitoring Tool.

Implements: blueprint support-auto-lcm
Change-Id: I7023a72b73f17f3746c74d311919497c7c4e8b3f
2022-09-01 12:16:57 +00:00
Zuul
3da27cc89a Merge "Support listing all records at once with paging" 2022-09-01 01:03:51 +00:00
Koichi Edagawa
06750997e6 Support listing all records at once with paging
This patch enables you to receive all records for target list
commands at once even if Tacker's server paginates them.

Target commands are below.

 - openstack vnflcm list
 - openstack vnflcm op list
 - openstack vnflcm subsc list

* As for the following command, it will be supported after
  implementing pagination feature in Tacker's server.

 - openstack vnf package list

Implements: blueprint paging-query-result
Change-Id: I8e5c9bdd99b9c1e45aef8aa1e74bdbbfdd7c5c89
2022-08-31 17:18:24 +09:00
Zuul
52ebdc0aec Merge "Update Python-TackerClient Documentation" 2022-08-30 16:49:10 +00:00
Hirofumi Noguchi
075a327f63 Update Python-TackerClient Documentation
Current Python-TackerClient Documentation does not reflect
the latest implementation.
This patch adds the vnflcm commands to the CLI usage,
revises the contributor guide, and makes some minor modifications.

Implements: blueprint update-tackerclient-documentation
Change-Id: Iacd871c52baa0e20c254b7c75d588b52c6086851
2022-08-30 21:15:56 +09:00
Hideki Matsuda
fa4a66858e Support for 'extra' parameters for vim register
If the `extra` parameter is present in the config-file specified
when the 'openstack vim register' command is executed,
the data is sent to the tacker.

Implements: blueprint remove-cnf-restriction
Change-Id: I13420945f7d4f81f48a5be7f8f92a0635fbef18a
2022-08-30 10:56:39 +00:00
Zuul
bfc0c8fdeb Merge "Add OpenID Connect Token Auth for k8s" 2022-08-25 09:36:16 +00:00
Yi Feng
0fcb9a59a1 Add OpenID Connect Token Auth for k8s
This patch adds openid auth info settings support when calling
vim register/update.

Implements: blueprint support-openid-k8s-vim
Change-Id: Id267050ac7adb349f562477dfc7aa6a53188b4cc
2022-08-18 12:26:30 +09:00
Ai Hamano
21f60be225 Add vnflcm subscriptions APIs
This patch supports CLI of vnflcm subscriptions APIs.

They are as follows.
* vnflcm subsc create
* vnflcm subsc delete
* vnflcm subsc list
* vnflcm subsc show

The output message of "vnflcm delete" was also modified
to match "vnflcm subsc delete".

Implements: blueprint support-nfv-solv3-subscriptions
Implements: blueprint support-etsi-nfv-specs
Change-Id: I9a839a3d131afc80fec0c2bbaa30443798117e0d
2022-07-21 14:56:56 +09:00
Yasufumi Ogawa
5c643d007e Add Python3 zed unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for zed.

See also the PTI in governance [1].

[1]:https://governance.openstack.org/tc/reference/project-testing-interface.html

Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
Change-Id: I4ea4b74fed206aa79078796106c4cee990ad067c
2022-07-13 23:21:46 +00:00
50c6570c51 Update master for stable/yoga
Add file to the reno documentation build to show release notes for
stable/yoga.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/yoga.

Sem-Ver: feature
Change-Id: I4f89c2cfa951117c832498a17daeb92b4ce8c70f
2022-03-03 10:51:00 +00:00
Zuul
417f27b9b8 Merge "Support ChangeVNFPackage command in tackerclient" 2022-02-25 02:32:22 +00:00
Yi Feng
ab901b6466 Support ChangeVNFPackage command in tackerclient
Add ``openstack vnflcm change_vnfpkg`` to python-tackerclient. This
command can execute change current vnf package operation [1].

[1]
https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.03.01_60/gs_NFV-SOL003v030301p.pdf

Implements: blueprint upgrade-vnf-package
Change-Id: I0d9c88147dee3a273cb27224db6be6c91cf7fe55
2022-02-25 09:51:40 +09:00
Itsuro Oda
3724240344 Add vnflcm v2 APIs
This patch supports CLI of vnflcm v2 APIs which are added in Yoga
release.

They are as follows.
* vnflcm update
* vnflcm scale
* vnflcm heal
* vnflcm change-ext-conn
* vnflcm op fail
* vnflcm op retry
* vnflcm op rollback

They are common with v1 except heal. An optional parameter
'--additional-param-file' is added to heal CLI.

Implements: blueprint support-nfv-solv3-heal-vnf
Implements: blueprint support-nfv-solv3-change-external-connectivity
Implements: blueprint support-nfv-solv3-modify-vnf
Implements: blueprint support-nfv-solv3-scale-vnf
Implements: blueprint support-nfv-solv3-error-handling
Change-Id: If4acd9c4d35ce7a5bf6c23db1a8238654d536c87
2022-02-22 03:01:25 +00:00
Zuul
45412f63f0 Merge "Help message of heal cli modified" 2022-02-22 00:09:08 +00:00
Pooja Singla
cc73d9d099 Help message of heal cli modified
Usage message of all cli commands of tacker is constructed by
argument parser by default. It includes optional parameter
first and insert mandatory parameter at end.

All cli commands are implemented with this design only
except heal cli.

Heal cli is a special case in which optional parameter is
coming at end and mandatory parameter is coming before optional.
To fix this issue usage parameter of argument parser is set
in heal cli.

Closes-Bug: #1954744

Change-Id: I3b1d04df210ad07d4b9a99f300017d49e2b56f0b
2022-02-18 16:37:12 +05:30
Renu
1c73f54664 Fix in "vnflcm op list" CLI with exclude-fields
"vnflcm op list" with "--exclude-fields" is not
excluding parameters from CLI result.

Closes-Bug: 1953377
Change-Id: If47beccfbab4b85173bbe159905d0605e721cedd
2022-01-27 04:53:39 +00:00
Manpreet Kaur
b7f27c3dc6 Update python testing classifier
Yoga testing runtime[1] has been updated to add py39
testing as voting. Unit tests update are handled by the
job template change in openstack-zuul-job

- https://review.opendev.org/c/openstack/openstack-zuul-jobs/+/820286

this commit updates the classifier in setup.cfg file and envlist in
tox.ini.

[1] https://governance.openstack.org/tc/reference/runtimes/yoga.html

Change-Id: Ic732cbd41691b11ae500eb9465423bb1d57c9a1e
2021-12-14 21:18:41 +05:30
Zuul
ccda0487d7 Merge "Support of Cancel VNF command in openstackclient" 2021-12-13 18:35:34 +00:00
Hiromu Asahina
6834454309 Support of Cancel VNF command in openstackclient
Add ``openstack vnflcm op cancel`` to python-tackerclient. This
command can execute Cancel operation [1]. This API makes a transition a
LCM that is stopped in the PROCESSING state to the FAILED_TEMP state.

[1]
https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.03.01_60/gs_NFV-SOL003v030301p.pdf

Implements: blueprint support-cancel
Change-Id: Id957f6a7992f9fd5b04806aff3d76680d8d63a8d
Signed-off-by: Hiromu Asahina <hiromu.asahina.az@hco.ntt.co.jp>
2021-12-10 18:09:33 +09:00
Zuul
7ee70f5236 Merge "setup.cfg: Replace dashes with underscores" 2021-09-29 02:24:05 +00:00
a3d485cfc5 Add Python3 yoga unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for yoga.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
Change-Id: I92cd2f1bfbc16bdd1e36e5e9c3500b488d17bd47
2021-09-24 09:32:35 +09:00
Yasufumi Ogawa
861a57594b Drop test for lower constraints
As we agreed on IRC meeting[1], remain lower constraints test only
master branch of tacker and tacker-horizon to difficulty of maintaining
package depencencies for the recent pip dependency resolver. This patch
is to drop lower constraints test from python-tackerclient.

[1] https://meetings.opendev.org/meetings/tacker/2021/tacker.2021-09-14-08.02.log.txt

Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
Change-Id: I4e10e76fb2ab06fb3269f115b0bd9b893265e2e6
2021-09-22 23:19:36 +09:00
015e6e21df Update master for stable/xena
Add file to the reno documentation build to show release notes for
stable/xena.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/xena.

Sem-Ver: feature
Change-Id: I874fe47b95881f35cc9599087feb69810cd9c803
2021-09-22 06:39:15 +00:00
Zuul
aed2714275 Merge "Update master for stable/wallaby" 2021-09-22 05:40:28 +00:00
maaoyu
b6aec209fd setup.cfg: Replace dashes with underscores
Setuptools v54.1.0 introduces a warning that the use of dash-separated
options in 'setup.cfg' will not be supported in a future version [1].
Get ahead of the issue by replacing the dashes with underscores. Without
this, we see 'UserWarning' messages like the following on new enough
versions of setuptools:

  UserWarning: Usage of dash-separated 'description-file' will not be
  supported in future versions. Please use the underscore name
  'description_file' instead

[1] https://github.com/pypa/setuptools/commit/a2e9ae4cb

Change-Id: Iab9666e111d6a5c68fe0526e40189d330be0086f
2021-05-04 10:36:37 +08:00
4299140444 Update master for stable/wallaby
Add file to the reno documentation build to show release notes for
stable/wallaby.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/wallaby.

Sem-Ver: feature
Change-Id: I600ba860fd192d8262ade921b9edbb4da8c2a538
2021-03-18 10:45:24 +00:00
82 changed files with 5665 additions and 354 deletions

View File

@@ -2,3 +2,4 @@
host=review.opendev.org
port=29418
project=openstack/python-tackerclient.git
defaultbranch=unmaintained/2023.1

View File

@@ -1,7 +1,6 @@
- project:
templates:
- check-requirements
- openstack-lower-constraints-jobs
- openstack-python3-xena-jobs
- openstack-python3-jobs
- publish-openstack-docs-pti
- release-notes-jobs-python3

View File

@@ -11,14 +11,6 @@
License for the specific language governing permissions and limitations
under the License.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
=============
Command List
=============
@@ -76,10 +68,50 @@ of individual command can be referred by **openstack help <command-name>**.
openstack nfv event show Show event given the event id.
openstack nfv event list List events of resources.
openstack vnf package create Create a new individual VNF package resource.
openstack vnf package delete Delete given VNF package(s).
openstack vnf package list List all VNF packages.
openstack vnf package show Show package details.
openstack vnf package upload Upload a VNF package by providing the address information
of the VNF package.
openstack vnf package delete Delete given VNF package(s).
openstack vnf package upload Upload a VNF package.
openstack vnf package download Download a VNF package.
openstack vnf package artifact download Download a VNF package artifact.
openstack vnf package update Update a state of a VNF package.
openstack vnflcm create Create a new VNF instance resource.
openstack vnflcm instantiate Instantiate a VNF instance.
openstack vnflcm list List VNF instance.
openstack vnflcm show Show VNF instance.
openstack vnflcm terminate Terminate a VNF instance.
openstack vnflcm delete Delete a VNF instance resource.
openstack vnflcm heal Heal a VNF instance.
openstack vnflcm update Update information of a VNF instance.
openstack vnflcm scale Scale a VNF instance.
openstack vnflcm change-ext-conn Change external VNF connectivity.
openstack vnflcm change-vnfpkg Change current VNF package.
openstack vnflcm op rollback Rollback a VNF LCM operation occurrence.
openstack vnflcm op retry Retry a VNF LCM operation occurrence.
openstack vnflcm op fail Fail a VNF LCM operation occurrence.
openstack vnflcm op list List VNF LCM operation occurrence.
openstack vnflcm op show Show VNF LCM operation occurrence.
openstack vnflcm op cancel Cancel a VNF LCM operation occurrence.
openstack vnflcm versions Show VNF LCM API versions.
openstack vnflcm subsc create Create new subscription.
openstack vnflcm subsc delete Delete subscription.
openstack vnflcm subsc list List subscription.
openstack vnflcm subsc show Show subscription.
openstack vnffm alarm list List alarm.
openstack vnffm alarm show Show alarm.
openstack vnffm alarm update Update alarm.
openstack vnffm sub create Create FM subscription.
openstack vnffm sub list List FM subscription.
openstack vnffm sub show Show FM subscription.
openstack vnffm sub delete Delete FM subscription.
openstack vnfpm job create Create PM job.
openstack vnfpm job list List PM job.
openstack vnfpm job show Show PM job.
openstack vnfpm job update Update PM job.
openstack vnfpm job delete Delete PM job.
openstack vnfpm report show Show PM report.
openstack vnfpm threshold create Create PM threshold.
openstack vnfpm threshold list List PM threshold.
openstack vnfpm threshold show Show PM threshold.
openstack vnfpm threshold update Update PM threshold.
openstack vnfpm threshold delete Delete PM threshold.

View File

@@ -1,9 +1,50 @@
============
..
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.
=========
CLI Usage
============
=========
Command List
------------
.. toctree::
:glob:
:maxdepth: 3
*
commands
Operations for ETSI NFV-SOL implementation
------------------------------------------
.. toctree::
vnf_package_commands
vnflcm_commands
vnffm_commands
vnfpm_commands
Operations for Legacy implementation
------------------------------------
.. toctree::
vnf_commands
vnf_descriptor_commands
vim_commands
ns_commands
ns_descriptor_commands
vnf_graph_commands
vnf_graph_descriptor_commands
vnf_chain_commands
vnf_classifier_commands
vnf_network_forwarding_path_commands
nfv_event_commands

View File

@@ -0,0 +1,24 @@
..
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.
=========================
Event Management commands
=========================
.. warning::
Event Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: nfv event *

View File

@@ -0,0 +1,24 @@
..
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.
===================================
Network Service Management commands
===================================
.. warning::
Network Service Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: ns *

View File

@@ -0,0 +1,24 @@
..
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.
==============================================
Network Service Descriptor Management commands
==============================================
.. warning::
Network Service Descriptor Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: ns descriptor *

View File

@@ -0,0 +1,19 @@
..
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.
=======================
VIM Management commands
=======================
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vim *

View File

@@ -0,0 +1,24 @@
..
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.
================================================
Service Function Chain (SFC) Management commands
================================================
.. warning::
Service Function Chain (SFC) Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf chain *

View File

@@ -0,0 +1,24 @@
..
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.
===================================
Flow Classifier Management commands
===================================
.. warning::
Flow Classifier Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf classifier *

View File

@@ -0,0 +1,24 @@
..
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.
=======================
VNF Management commands
=======================
.. warning::
VNF Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf *

View File

@@ -0,0 +1,24 @@
..
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.
=========================================
VNF Descriptor (VNFD) Management commands
=========================================
.. warning::
VNF Descriptor (VNFD) Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf descriptor *

View File

@@ -0,0 +1,24 @@
..
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.
================================================
VNF Forwarding Graph (VNFFG) Management commands
================================================
.. warning::
VNF Forwarding Graph (VNFFG) Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf graph *

View File

@@ -0,0 +1,24 @@
..
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.
============================================================
VNF Forwarding Graph Descriptor (VNFFGD) Management commands
============================================================
.. warning::
VNF Forwarding Graph Descriptor (VNFFGD) Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf graph descriptor *

View File

@@ -0,0 +1,24 @@
..
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.
===========================================
Network Forwarding Path Management commands
===========================================
.. warning::
Network Forwarding Path Management commands are deprecated
and will be removed in the first major release after the Tacker server
version 9.0.0 (2023.1 Antelope release).
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnf network forwarding path *

View File

@@ -1,3 +1,16 @@
..
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.
====================
VNF Package commands
====================

View File

@@ -0,0 +1,28 @@
..
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.
===============
VNF FM commands
===============
VNF FM commands are CLI interface of VNF Fault Management interface in
`ETSI NFV-SOL 002 <https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/002/03.03.01_60/gs_NFV-SOL002v030301p.pdf>`_
and `ETSI NFV-SOL 003 <https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.03.01_60/gs_nfv-sol003v030301p.pdf>`_.
.. note::
Commands only support calling version 2 vnffm APIs.
You can use the commands with **\-\-os-tacker-api-version 2** to
call version 2 vnffm APIs.
.. autoprogram-cliff:: openstack.tackerclient.v2
:command: vnffm *

View File

@@ -0,0 +1,34 @@
..
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.
================
VNF Lcm commands
================
VNF LCM commands are CLI interface of VNF Lifecycle Management Interface in
`ETSI NFV-SOL 002 <https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/002/03.03.01_60/gs_NFV-SOL002v030301p.pdf>`_
and `ETSI NFV-SOL 003 <https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.03.01_60/gs_nfv-sol003v030301p.pdf>`_.
.. note::
Commands call version 1 vnflcm APIs by default.
You can call the specific version of vnflcm APIs
by using the option **\-\-os-tacker-api-version**.
Commands with **\-\-os-tacker-api-version 2** call version 2 vnflcm APIs.
**vnflcm op cancel** is included in only version 1 vnflcm APIs
and **change-vnfpkg** is included in only version 2 vnflcm APIs.
.. autoprogram-cliff:: openstack.tackerclient.v1
:command: vnflcm *
.. autoprogram-cliff:: openstack.tackerclient.v2
:command: vnflcm change-vnfpkg

View File

@@ -0,0 +1,28 @@
..
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.
===============
VNF PM commands
===============
VNF PM commands are CLI interface of VNF Performance Management interface in
`ETSI NFV-SOL 002 <https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/002/03.03.01_60/gs_NFV-SOL002v030301p.pdf>`_
and `ETSI NFV-SOL 003 <https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.03.01_60/gs_nfv-sol003v030301p.pdf>`_.
.. note::
Commands only support calling version 2 vnfpm APIs.
You can use the commands with **\-\-os-tacker-api-version 2** to
call version 2 vnfpm APIs.
.. autoprogram-cliff:: openstack.tackerclient.v2
:command: vnfpm *

View File

@@ -11,14 +11,6 @@
License for the specific language governing permissions and limitations
under the License.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
============
Contributing
============

View File

@@ -11,14 +11,6 @@
License for the specific language governing permissions and limitations
under the License.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
===================================
Developing with Python-TackerClient
===================================
@@ -42,154 +34,6 @@ For details please refer to the `OpenStack IRC meetings`_ page.
Testing
=======
Install the prerequisites for Tox:
* On Ubuntu or Debian:
.. code-block:: bash
$ apt-get install gcc gettext python-dev libxml2-dev libxslt1-dev \
zlib1g-dev
You may need to use pip install for some packages.
* On RHEL or CentOS including Fedora:
.. code-block:: bash
$ yum install gcc python-devel libxml2-devel libxslt-devel
* On openSUSE or SUSE linux Enterprise:
.. code-block:: bash
$ zypper install gcc python-devel libxml2-devel libxslt-devel
Install python-tox:
.. code-block:: bash
$ pip install tox
To run the full suite of tests maintained within TackerClient.
.. code-block:: bash
$ tox
.. NOTE::
The first time you run ``tox``, it will take additional time to build
virtualenvs. You can later use the ``-r`` option with ``tox`` to rebuild
your virtualenv in a similar manner.
To run tests for one or more specific test environments(for example, the
most common configuration of Python 2.7, Python 3.5 and PEP-8), list the
environments with the ``-e`` option, separated by spaces:
.. code-block:: bash
$ tox -e py27,py35,pep8
See ``tox.ini`` for the full list of available test environments.
Building the Documentation
==========================
The documentation is generated with Sphinx using the ``tox`` command. To
create HTML docs, run the commands:
.. code-block:: bash
$ tox -e docs
The resultant HTML will be in the ``doc/build/html`` directory.
Release Notes
=============
The release notes for a patch should be included in the patch. See the
`Project Team Guide`_ for more information on using reno in OpenStack.
.. _`Project Team Guide`: http://docs.openstack.org/project-team-guide/release-management.html#managing-release-notes
If any of the following applies to the patch, a release note is required:
* The deployer needs to take an action when upgrading
* The plugin interface changes
* A new feature is implemented
* A command or option is removed
* Current behavior is changed
* A security bug is fixed
Reno is used to generate release notes. Use the commands:
.. code-block:: bash
$ tox -e venv -- reno new <bug-,bp-,whatever>
Then edit the sample file that was created and push it with your change.
To run the commands and see results:
.. code-block:: bash
$ git commit # Commit the change because reno scans git log.
$ tox -e releasenotes
At last, look at the generated release notes
files in ``releasenotes/build/html`` in your browser.
Testing new code
================
If a developer wants to test new code (feature, command or option) that
they have written, Python-TackerClient may be installed from source by running
the following commands in the base directory of the project:
.. code-block:: bash
$ python setup.py install
or
.. code-block:: bash
$ pip install -e .
Standardize Import Format
=========================
.. _`Import Order Guide`: https://docs.openstack.org/hacking/latest/user/hacking.html#imports
The import order shows below:
* {{stdlib imports in human alphabetical order}}
* \n
* {{third-party lib imports in human alphabetical order}}
* \n
* {{project imports in human alphabetical order}}
* \n
* \n
* {{begin your code}}
Example
~~~~~~~
.. code-block:: python
import copy
import fixtures
import mock
import os
from osc_lib.api import auth
from osc_lib import utils
import six
from openstackclient import shell
from openstackclient.tests import utils
For details please refer to the `Developing with OpenStackClient`_ page.
.. _`Developing with OpenStackClient`: https://docs.openstack.org/python-openstackclient/latest/contributor/developing.html

View File

@@ -11,14 +11,6 @@
License for the specific language governing permissions and limitations
under the License.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
=================
Contributor Guide
=================

View File

@@ -11,19 +11,12 @@
License for the specific language governing permissions and limitations
under the License.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
=================================
Python-TackerClient Documentation
=================================
This is a client for OpenStack NFV MANO (Tacker) API. It provides
Python-TackerClient is a client for OpenStack NFV MANO (Tacker) API.
It provides
:doc:`Python API bindings <reference/index>` (the tackerclient module) and
:doc:`command-line interface (CLI) <cli/index>`.

View File

@@ -11,16 +11,9 @@
License for the specific language governing permissions and limitations
under the License.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
=========
Reference
=========
(To be updated)
- `Tacker API reference <https://docs.openstack.org/api-ref/nfv-orchestration/>`_
- `Tacker CLI reference <https://docs.openstack.org/tacker/latest/cli/>`_

View File

@@ -1,56 +0,0 @@
appdirs==1.3.0
Babel==2.3.4
cliff==2.8.0
cmd2==0.8.0
coverage==4.0
ddt==1.0.1
debtcollector==1.2.0
decorator==3.4.0
deprecation==1.0
dogpile.cache==0.6.2
extras==1.0.0
fixtures==3.0.0
iso8601==0.1.11
jmespath==0.9.0
jsonpatch==1.16
jsonpointer==1.13
keystoneauth1==3.4.0
linecache2==1.0.0
monotonic==0.6
msgpack-python==0.4.0
munch==2.1.0
netaddr==0.7.18
netifaces==0.10.4
openstacksdk==0.11.2
os-client-config==1.28.0
os-service-types==1.2.0
osc-lib==1.8.0
oslo.config==5.2.0
oslo.context==2.19.2
oslo.i18n==3.15.3
oslo.log==3.36.0
oslo.serialization==2.18.0
oslo.utils==3.40.0
pbr==2.0.0
positional==1.2.1
prettytable==0.7.2
pyinotify==0.9.6
pyparsing==2.1.0
pyperclip==1.5.27
python-dateutil==2.5.3
python-keystoneclient==3.8.0
python-mimeparse==1.6.0
python-subunit==1.0.0
pytz==2013.6
PyYAML==3.12
requests==2.14.2
requests-mock==1.2.0
requestsexceptions==1.2.0
rfc3986==0.3.1
simplejson==3.5.1
stestr==2.0.0
stevedore==1.20.0
testtools==2.2.0
traceback2==1.4.0
unittest2==1.1.0
wrapt==1.7.0

View File

@@ -0,0 +1,6 @@
---
deprecations:
- |
Legacy APIs 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).

View File

@@ -7,6 +7,10 @@ Contents:
:maxdepth: 2
unreleased
zed
yoga
xena
wallaby
victoria
ussuri
train

View File

@@ -0,0 +1,6 @@
============================
Wallaby Series Release Notes
============================
.. release-notes::
:branch: stable/wallaby

View File

@@ -0,0 +1,6 @@
=========================
Xena Series Release Notes
=========================
.. release-notes::
:branch: stable/xena

View File

@@ -0,0 +1,6 @@
=========================
Yoga Series Release Notes
=========================
.. release-notes::
:branch: stable/yoga

View File

@@ -0,0 +1,6 @@
========================
Zed Series Release Notes
========================
.. release-notes::
:branch: stable/zed

View File

@@ -1,12 +1,12 @@
[metadata]
name = python-tackerclient
summary = CLI and Client Library for OpenStack Tacker
description-file =
description_file =
README.rst
author = OpenStack
author-email = openstack-discuss@lists.openstack.org
home-page = https://docs.openstack.org/python-tackerclient/
python-requires = >=3.6
author_email = openstack-discuss@lists.openstack.org
home_page = https://docs.openstack.org/python-tackerclient/
python_requires = >=3.6
classifier =
Environment :: OpenStack
Intended Audience :: Developers
@@ -20,6 +20,9 @@ classifier =
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
[files]
packages =
@@ -96,10 +99,15 @@ openstack.tackerclient.v1 =
vnflcm_scale = tackerclient.osc.v1.vnflcm.vnflcm:ScaleVnfLcm
vnflcm_change-ext-conn = tackerclient.osc.v1.vnflcm.vnflcm:ChangeExtConnVnfLcm
vnflcm_op_rollback = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RollbackVnfLcmOp
vnflcm_op_cancel = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:CancelVnfLcmOp
vnflcm_op_fail = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:FailVnfLcmOp
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
vnflcm_subsc_create = tackerclient.osc.v1.vnflcm.vnflcm_subsc:CreateLccnSubscription
vnflcm_subsc_delete = tackerclient.osc.v1.vnflcm.vnflcm_subsc:DeleteLccnSubscription
vnflcm_subsc_list = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ListLccnSubscription
vnflcm_subsc_show = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ShowLccnSubscription
vnflcm_versions = tackerclient.osc.common.vnflcm.vnflcm_versions:VnfLcmVersions
openstack.tackerclient.v2 =
vnflcm_create = tackerclient.osc.v1.vnflcm.vnflcm:CreateVnfLcm
@@ -107,7 +115,37 @@ openstack.tackerclient.v2 =
vnflcm_list = tackerclient.osc.v1.vnflcm.vnflcm:ListVnfLcm
vnflcm_instantiate = tackerclient.osc.v1.vnflcm.vnflcm:InstantiateVnfLcm
vnflcm_terminate = tackerclient.osc.v1.vnflcm.vnflcm:TerminateVnfLcm
vnflcm_change-vnfpkg = tackerclient.osc.v1.vnflcm.vnflcm:ChangeVnfPkgVnfLcm
vnflcm_delete = tackerclient.osc.v1.vnflcm.vnflcm:DeleteVnfLcm
vnflcm_heal = tackerclient.osc.v1.vnflcm.vnflcm:HealVnfLcm
vnflcm_update = tackerclient.osc.v1.vnflcm.vnflcm:UpdateVnfLcm
vnflcm_scale = tackerclient.osc.v1.vnflcm.vnflcm:ScaleVnfLcm
vnflcm_change-ext-conn = tackerclient.osc.v1.vnflcm.vnflcm:ChangeExtConnVnfLcm
vnflcm_op_rollback = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RollbackVnfLcmOp
vnflcm_op_fail = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:FailVnfLcmOp
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
vnflcm_subsc_create = tackerclient.osc.v1.vnflcm.vnflcm_subsc:CreateLccnSubscription
vnflcm_subsc_delete = tackerclient.osc.v1.vnflcm.vnflcm_subsc:DeleteLccnSubscription
vnflcm_subsc_list = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ListLccnSubscription
vnflcm_subsc_show = tackerclient.osc.v1.vnflcm.vnflcm_subsc:ShowLccnSubscription
vnflcm_versions = tackerclient.osc.common.vnflcm.vnflcm_versions:VnfLcmVersions
vnfpm_job_create = tackerclient.osc.v2.vnfpm.vnfpm_job:CreateVnfPmJob
vnfpm_job_list = tackerclient.osc.v2.vnfpm.vnfpm_job:ListVnfPmJob
vnfpm_job_show = tackerclient.osc.v2.vnfpm.vnfpm_job:ShowVnfPmJob
vnfpm_job_update = tackerclient.osc.v2.vnfpm.vnfpm_job:UpdateVnfPmJob
vnfpm_job_delete = tackerclient.osc.v2.vnfpm.vnfpm_job:DeleteVnfPmJob
vnfpm_report_show = tackerclient.osc.v2.vnfpm.vnfpm_report:ShowVnfPmReport
vnfpm_threshold_create = tackerclient.osc.v2.vnfpm.vnfpm_threshold:CreateVnfPmThreshold
vnfpm_threshold_list = tackerclient.osc.v2.vnfpm.vnfpm_threshold:ListVnfPmThreshold
vnfpm_threshold_show = tackerclient.osc.v2.vnfpm.vnfpm_threshold:ShowVnfPmThreshold
vnfpm_threshold_update = tackerclient.osc.v2.vnfpm.vnfpm_threshold:UpdateVnfPmThreshold
vnfpm_threshold_delete = tackerclient.osc.v2.vnfpm.vnfpm_threshold:DeleteVnfPmThreshold
vnffm_alarm_list = tackerclient.osc.v2.vnffm.vnffm_alarm:ListVnfFmAlarm
vnffm_alarm_show = tackerclient.osc.v2.vnffm.vnffm_alarm:ShowVnfFmAlarm
vnffm_alarm_update = tackerclient.osc.v2.vnffm.vnffm_alarm:UpdateVnfFmAlarm
vnffm_sub_create = tackerclient.osc.v2.vnffm.vnffm_sub:CreateVnfFmSub
vnffm_sub_list = tackerclient.osc.v2.vnffm.vnffm_sub:ListVnfFmSub
vnffm_sub_show = tackerclient.osc.v2.vnffm.vnffm_sub:ShowVnfFmSub
vnffm_sub_delete = tackerclient.osc.v2.vnffm.vnffm_sub:DeleteVnfFmSub

View File

@@ -207,6 +207,14 @@ class InvalidInput(TackerClientException):
message = _("Invalid input: %(reason)s")
class EmptyInput(TackerClientException):
message = _("Empty input: %(reason)s")
class UnsupportedCommandVersion(TackerClientException):
message = _("This command is not supported in version %(version)s")
# Command line exceptions
class TackerCLIError(TackerException):

View File

@@ -20,6 +20,7 @@
import argparse
import logging
import os
import sys
from oslo_log import versionutils
from oslo_utils import encodeutils
@@ -183,3 +184,15 @@ def deprecate_warning(what, as_of, in_favor_of=None, remove_in=1):
versionutils.deprecation_warning(as_of=as_of, what=what,
in_favor_of=in_favor_of,
remove_in=remove_in)
# TODO(ueha): Remove this along with the deprecated commands in the first major
# python-tackerclient release after the Tacker server version 9.0.0 (2023.1
# Antelope release).
def deprecate_legacy_warning():
# NOTE(ueha): versionutils has not support Antelope version yet.
msg = _(
'The Legacy API interface has been deprecated. This command will be '
'removed in the first major release after the Tacker server version '
'9.0.0 (2023.1 Antelope release).')
print(msg, file=sys.stderr)

View File

@@ -20,7 +20,9 @@ Stuffs specific to tackerclient OSC plugin should not be added
to this module. They should go to tackerclient.osc.v1.utils.
"""
import json
import operator
import os
from cliff import columns as cliff_columns
from keystoneclient import exceptions as identity_exc
@@ -29,6 +31,7 @@ from keystoneclient.v3 import projects
from osc_lib import utils
from oslo_serialization import jsonutils
from tackerclient.common import exceptions
from tackerclient.i18n import _
@@ -212,3 +215,29 @@ class FormatComplexDataColumn(cliff_columns.FormattableColumn):
def human_readable(self):
return format_dict_with_indention(self._value)
def jsonfile2body(file_path):
if file_path is None:
msg = _("File %s does not exist")
reason = msg % file_path
raise exceptions.InvalidInput(reason=reason)
if os.access(file_path, os.R_OK) is False:
msg = _("User does not have read privileges to it")
raise exceptions.InvalidInput(reason=msg)
try:
with open(file_path) as f:
body = json.load(f)
except (IOError, ValueError) as ex:
msg = _("Failed to load parameter file. Error: %s")
reason = msg % ex
raise exceptions.InvalidInput(reason=reason)
if not body:
reason = _('The parameter file is empty')
raise exceptions.EmptyInput(reason=reason)
return body

View File

@@ -17,6 +17,7 @@
from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -55,6 +56,7 @@ class ShowEvent(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _EVENT, parsed_args.event)
@@ -93,6 +95,7 @@ class ListEvent(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
_params = {}
if parsed_args.id:

View File

@@ -20,6 +20,7 @@ from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -133,6 +134,7 @@ class CreateNS(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
ns = client.create_ns(self.args2body(parsed_args))
display_columns, columns = _get_columns(ns[_NS])
@@ -174,6 +176,7 @@ class DeleteNS(command.Command):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
failure = False
deleted_ids = []
@@ -217,6 +220,7 @@ class ListNS(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
data = client.list_nss()
headers, columns = tacker_osc_utils.get_column_definitions(
@@ -240,6 +244,7 @@ class ShowNS(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _NS, parsed_args.ns)

View File

@@ -20,6 +20,7 @@ from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -86,6 +87,7 @@ class CreateNSD(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
nsd = client.create_nsd(self.args2body(parsed_args))
display_columns, columns = _get_columns(nsd[_NSD])
@@ -111,6 +113,7 @@ class DeleteNSD(command.Command):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
failure = False
deleted_ids = []
@@ -159,6 +162,7 @@ class ListNSD(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
data = client.list_nsds()
headers, columns = tacker_osc_utils.get_column_definitions(
@@ -182,6 +186,7 @@ class ShowNSD(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _NSD, parsed_args.nsd)
@@ -209,6 +214,7 @@ class ShowTemplateNSD(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _NSD, parsed_args.nsd)

View File

@@ -20,6 +20,7 @@ from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -169,6 +170,7 @@ class CreateVNFFG(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
vnffg = client.create_vnffg(self.args2body(parsed_args))
display_columns, columns = _get_columns(vnffg[_VNFFG])
@@ -206,6 +208,7 @@ class DeleteVNFFG(command.Command):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
failure = False
deleted_ids = []
@@ -316,6 +319,7 @@ class UpdateVNFFG(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNFFG, parsed_args.vnffg)
@@ -341,6 +345,7 @@ class ListVNFFG(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
data = client.list_vnffgs()
headers, columns = tacker_osc_utils.get_column_definitions(
@@ -364,6 +369,7 @@ class ShowVNFFG(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNFFG, parsed_args.vnffg)
@@ -387,6 +393,7 @@ class ListNFP(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
_params = {}
if parsed_args.vnffg_id:
@@ -423,6 +430,7 @@ class ShowNFP(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _NFP, parsed_args.nfp)
@@ -448,6 +456,7 @@ class ListFC(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
_params = {}
if parsed_args.nfp_id:
@@ -487,6 +496,7 @@ class ShowFC(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _FC, parsed_args.classifier)
@@ -513,6 +523,7 @@ class ListSFC(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
_params = {}
if parsed_args.nfp_id:
@@ -550,6 +561,7 @@ class ShowSFC(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _SFC, parsed_args.sfc)

View File

@@ -20,6 +20,7 @@ from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -87,6 +88,7 @@ class CreateVNFFGD(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
vnffgd = client.create_vnffgd(self.args2body(parsed_args))
display_columns, columns = _get_columns(vnffgd[_VNFFGD])
@@ -110,6 +112,7 @@ class DeleteVNFFGD(command.Command):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
failure = False
deleted_ids = []
@@ -158,6 +161,7 @@ class ListVNFFGD(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
data = client.list_vnffgds()
headers, columns = tacker_osc_utils.get_column_definitions(
@@ -181,6 +185,7 @@ class ShowVNFFGD(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNFFGD, parsed_args.vnffgd)
@@ -205,6 +210,7 @@ class ShowTemplateVNFFGD(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNFFGD, parsed_args.vnffgd)

View File

@@ -0,0 +1,114 @@
{
"filter": {
"vnfInstanceSubscriptionFilter": {
"vnfdIds": [
"dummy-vnfdId-1",
"dummy-vnfdId-2"
],
"vnfProductsFromProviders": [
{
"vnfProvider": "dummy-vnfProvider-1",
"vnfProducts": [
{
"vnfProductName": "dummy-vnfProductName-1-1",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
},
{
"vnfProductName": "dummy-vnfProductName-1-2",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
}
]
},
{
"vnfProvider": "dummy-vnfProvider-2",
"vnfProducts": [
{
"vnfProductName": "dummy-vnfProductName-2-1",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
},
{
"vnfProductName": "dummy-vnfProductName-2-2",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
}
]
}
],
"vnfInstanceIds": [
"dummy-vnfInstanceId-1",
"dummy-vnfInstanceId-2"
],
"vnfInstanceNames": [
"dummy-vnfInstanceName-1",
"dummy-vnfInstanceName-2"
]
},
"notificationTypes": [
"VnfLcmOperationOccurrenceNotification",
"VnfIdentifierCreationNotification",
"VnfIdentifierDeletionNotification"
],
"operationTypes": [
"INSTANTIATE",
"SCALE",
"TERMINATE",
"HEAL",
"MODIFY_INFO",
"CHANGE_EXT_CONN"
],
"operationStates": [
"COMPLETED",
"FAILED",
"FAILED_TEMP",
"PROCESSING",
"ROLLING_BACK",
"ROLLED_BACK",
"STARTING"
]
},
"callbackUri": "http://localhost:9990/notification/callback/test",
"authentication": {
"authType": [
"BASIC"
],
"paramsBasic": {
"password": "test_pass",
"userName": "test_user"
}
}
}

View File

@@ -0,0 +1,3 @@
{
"additionalParams": {"all": true}
}

View File

@@ -13,9 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import json
import logging
import os
import time
from osc_lib.command import command
@@ -113,7 +111,7 @@ class CreateVnfLcm(command.ShowOne):
body = {}
if file_path:
return jsonfile2body(file_path)
return tacker_osc_utils.jsonfile2body(file_path)
body['vnfdId'] = parsed_args.vnfd_id
@@ -184,29 +182,6 @@ class ListVnfLcm(command.Lister):
) for s in vnf_instances))
def jsonfile2body(file_path):
if file_path is not None and os.access(file_path, os.R_OK) is False:
msg = _("File %s does not exist or user does not have read "
"privileges to it")
reason = msg % file_path
raise exceptions.InvalidInput(reason=reason)
try:
with open(file_path) as f:
body = json.load(f)
except (IOError, ValueError) as ex:
msg = _("Failed to load parameter file. Error: %s")
reason = msg % ex
raise exceptions.InvalidInput(reason=reason)
if not body:
reason = _('The parameter file is empty')
raise exceptions.InvalidInput(reason=reason)
return body
class InstantiateVnfLcm(command.Command):
_description = _("Instantiate a VNF Instance")
@@ -226,7 +201,7 @@ class InstantiateVnfLcm(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
result = client.instantiate_vnf_instance(
parsed_args.vnf_instance, jsonfile2body(
parsed_args.vnf_instance, tacker_osc_utils.jsonfile2body(
parsed_args.instantiation_request_file))
if not result:
print((_('Instantiate request for VNF Instance %(id)s has been'
@@ -238,6 +213,12 @@ class HealVnfLcm(command.Command):
def get_parser(self, prog_name):
parser = super(HealVnfLcm, self).get_parser(prog_name)
usage_message = ('''%(prog)s [-h] [--cause CAUSE]
[--vnfc-instance <vnfc-instance-id> '''
'''[<vnfc-instance-id> ...]]
[--additional-param-file <additional-param-file>]
-- <vnf-instance>''')
parser.usage = usage_message
parser.add_argument(
_VNF_INSTANCE,
metavar="<vnf-instance>",
@@ -251,6 +232,11 @@ class HealVnfLcm(command.Command):
nargs="+",
help=_("List of VNFC instances requiring a healing action.")
)
parser.add_argument(
'--additional-param-file',
metavar="<additional-param-file>",
help=_("Additional parameters passed by the NFVO as input "
"to the healing process."))
return parser
def args2body(self, parsed_args):
@@ -259,6 +245,9 @@ class HealVnfLcm(command.Command):
body['cause'] = parsed_args.cause
if parsed_args.vnfc_instance:
body['vnfcInstanceId'] = parsed_args.vnfc_instance
if parsed_args.additional_param_file:
body.update(tacker_osc_utils.jsonfile2body(
parsed_args.additional_param_file))
return body
@@ -334,7 +323,7 @@ class TerminateVnfLcm(command.Command):
result = client.delete_vnf_instance(parsed_args.vnf_instance)
if not result:
print(_("VNF Instance '%(id)s' deleted successfully") %
print(_("VNF Instance '%(id)s' is deleted successfully") %
{'id': parsed_args.vnf_instance})
def _wait_until_vnf_is_terminated(self, client, vnf_instance_id,
@@ -407,7 +396,7 @@ class DeleteVnfLcm(command.Command):
print(_('All specified vnf instances are deleted '
'successfully'))
else:
print(_("Vnf instance '%s' deleted "
print(_("Vnf instance '%s' is deleted "
"successfully") % vnf_instances[0])
@@ -448,7 +437,7 @@ class UpdateVnfLcm(command.Command):
body = {}
if file_path:
return jsonfile2body(file_path)
return tacker_osc_utils.jsonfile2body(file_path)
return body
@@ -522,7 +511,8 @@ class ScaleVnfLcm(command.Command):
body['numberOfSteps'] = parsed_args.number_of_steps
if parsed_args.additional_param_file:
body.update(jsonfile2body(parsed_args.additional_param_file))
body.update(tacker_osc_utils.jsonfile2body(
parsed_args.additional_param_file))
return body
@@ -561,8 +551,35 @@ class ChangeExtConnVnfLcm(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
result = client.change_ext_conn_vnf_instance(
parsed_args.vnf_instance, jsonfile2body(
parsed_args.vnf_instance, tacker_osc_utils.jsonfile2body(
parsed_args.request_file))
if not result:
print((_('Change External VNF Connectivity for VNF Instance %s '
'has been accepted.') % parsed_args.vnf_instance))
class ChangeVnfPkgVnfLcm(command.Command):
_description = _("Change Current VNF Package")
def get_parser(self, prog_name):
parser = super(ChangeVnfPkgVnfLcm, self).get_parser(prog_name)
parser.add_argument(
_VNF_INSTANCE,
metavar="<vnf-instance>",
help=_("VNF instance ID to Change Current VNF Package"))
parser.add_argument(
'request_file',
metavar="<param-file>",
help=_("Specify change-vnfpkg request parameters "
"in a json file."))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
result = client.change_vnfpkg_vnf_instance(
parsed_args.vnf_instance, tacker_osc_utils.jsonfile2body(
parsed_args.request_file))
if not result:
print((_('Change Current VNF Package for VNF Instance %s '
'has been accepted.') % parsed_args.vnf_instance))

View File

@@ -101,6 +101,47 @@ class RollbackVnfLcmOp(command.Command):
' accepted') % {'id': parsed_args.vnf_lcm_op_occ_id}))
class CancelVnfLcmOp(command.ShowOne):
_description = _("Cancel VNF Instance")
def get_parser(self, prog_name):
"""Add arguments to parser.
Args:
prog_name ([type]): program name
Returns:
parser([ArgumentParser]):
"""
parser = super(CancelVnfLcmOp, self).get_parser(prog_name)
parser.add_argument(
_VNF_LCM_OP_OCC_ID,
metavar="<vnf-lcm-op-occ-id>",
help=_('VNF lifecycle management operation occurrence ID.'))
parser.add_argument(
"--cancel-mode",
default='GRACEFUL',
metavar="<cancel-mode>",
choices=['GRACEFUL', 'FORCEFUL'],
help=_("Cancel mode can be 'GRACEFUL' or 'FORCEFUL'. "
"Default is 'GRACEFUL'"))
return parser
def take_action(self, parsed_args):
"""Execute cancel_vnf_instance and output comment.
Args:
parsed_args ([Namespace]): arguments of CLI.
"""
client = self.app.client_manager.tackerclient
result = client.cancel_vnf_instance(
parsed_args.vnf_lcm_op_occ_id,
{'cancelMode': parsed_args.cancel_mode})
if not result:
print((_('Cancel request for LCM operation %(id)s has been'
' accepted') % {'id': parsed_args.vnf_lcm_op_occ_id}))
class FailVnfLcmOp(command.ShowOne):
_description = _("Fail VNF Instance")
@@ -201,9 +242,12 @@ class ListVnfLcmOp(command.Lister):
)
return parser
def get_attributes(self):
def get_attributes(self, exclude=None):
"""Get attributes.
Args:
exclude([exclude]): a list of fields which needs to exclude.
Returns:
attributes([attributes]): a list of table entry definitions.
Each entry should be a tuple consisting of
@@ -229,10 +273,13 @@ class ListVnfLcmOp(command.Lister):
]
attributes = []
for field in fields:
attributes.extend([(field['key'], field['value'],
tacker_osc_utils.LIST_BOTH)])
if exclude is None:
exclude = []
for field in fields:
if field['value'] not in exclude:
attributes.extend([(field['key'], field['value'],
tacker_osc_utils.LIST_BOTH)])
return tuple(attributes)
def take_action(self, parsed_args):
@@ -260,7 +307,7 @@ class ListVnfLcmOp(command.Lister):
client = self.app.client_manager.tackerclient
vnflcm_op_occs = client.list_vnf_lcm_op_occs(**params)
headers, columns = tacker_osc_utils.get_column_definitions(
self.get_attributes(),
self.get_attributes(exclude=exclude_fields),
long_listing=True)
dictionary_properties = (utils.get_dict_properties(

View File

@@ -0,0 +1,181 @@
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
# 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.
import logging
from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
LOG = logging.getLogger(__name__)
_LCCN_SUBSCRIPTION_ID = 'subscription_id'
_MIXED_CASE_FIELDS = ['filter', 'callbackUri']
_FORMATTERS = {
'filter': tacker_osc_utils.FormatComplexDataColumn,
'_links': tacker_osc_utils.FormatComplexDataColumn
}
def _get_columns(lccn_subsc_obj):
column_map = {
'id': 'ID',
'filter': 'Filter',
'callbackUri': 'Callback URI',
'_links': 'Links'
}
return sdk_utils.get_osc_show_columns_for_sdk_resource(lccn_subsc_obj,
column_map)
class CreateLccnSubscription(command.ShowOne):
_description = _("Create a new Lccn Subscription")
def get_parser(self, prog_name):
parser = super(CreateLccnSubscription, self).get_parser(prog_name)
parser.add_argument(
'create_request_file',
metavar="<param-file>",
help=_('Specify create request parameters in a json file.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
subsc = client.create_lccn_subscription(
tacker_osc_utils.jsonfile2body(parsed_args.create_request_file))
display_columns, columns = _get_columns(subsc)
data = utils.get_item_properties(sdk_utils.DictModel(subsc),
columns, formatters=_FORMATTERS,
mixed_case_fields=_MIXED_CASE_FIELDS)
return (display_columns, data)
class DeleteLccnSubscription(command.Command):
_description = _("Delete Lccn Subscription(s)")
def get_parser(self, prog_name):
parser = super(DeleteLccnSubscription, self).get_parser(prog_name)
parser.add_argument(
_LCCN_SUBSCRIPTION_ID,
metavar="<subscription-id>",
nargs="+",
help=_("Lccn Subscription ID(s) to delete"))
return parser
def take_action(self, parsed_args):
error_count = 0
client = self.app.client_manager.tackerclient
lccn_subscriptions = parsed_args.subscription_id
for lccn_subscription in lccn_subscriptions:
try:
client.delete_lccn_subscription(lccn_subscription)
except Exception as e:
error_count += 1
LOG.error(_("Failed to delete Lccn Subscription with "
"ID '%(subsc)s': %(e)s"),
{'subsc': lccn_subscription, 'e': e})
total = len(lccn_subscriptions)
if (error_count > 0):
msg = (_("Failed to delete %(error_count)s of %(total)s "
"Lccn Subscriptions.") % {'error_count': error_count,
'total': total})
raise exceptions.CommandError(message=msg)
else:
if total > 1:
print(_('All specified Lccn Subscriptions are deleted '
'successfully'))
else:
print(_("Lccn Subscription '%s' is deleted "
"successfully") % lccn_subscriptions[0])
class ListLccnSubscription(command.Lister):
_description = _("List Lccn Subscriptions")
def get_parser(self, program_name):
parser = super(ListLccnSubscription, self).get_parser(program_name)
parser.add_argument(
"--filter",
metavar="<filter>",
help=_("Attribute-based-filtering parameters"),
)
return parser
def get_attributes(self, exclude=None):
fields = [
{
"key": "id",
"value": "ID"
},
{
"key": "callbackUri",
"value": "Callback URI"
}
]
attributes = []
for field in fields:
attributes.extend([(field['key'], field['value'],
tacker_osc_utils.LIST_BOTH)])
return tuple(attributes)
def take_action(self, parsed_args):
params = {}
if parsed_args.filter:
params['filter'] = parsed_args.filter
client = self.app.client_manager.tackerclient
subscriptions = client.list_lccn_subscriptions(**params)
headers, columns = tacker_osc_utils.get_column_definitions(
self.get_attributes(), long_listing=True)
dictionary_properties = (utils.get_dict_properties(
s, columns, mixed_case_fields=_MIXED_CASE_FIELDS)
for s in subscriptions
)
return (headers, dictionary_properties)
class ShowLccnSubscription(command.ShowOne):
_description = _("Display Lccn Subscription details")
def get_parser(self, program_name):
parser = super(ShowLccnSubscription, self).get_parser(program_name)
parser.add_argument(
_LCCN_SUBSCRIPTION_ID,
metavar="<subscription-id>",
help=_('Lccn Subscription ID to display'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
obj = client.show_lccn_subscription(parsed_args.subscription_id)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(
sdk_utils.DictModel(obj),
columns, formatters=_FORMATTERS,
mixed_case_fields=_MIXED_CASE_FIELDS)
return (display_columns, data)

View File

@@ -21,6 +21,7 @@ from osc_lib import utils
from oslo_utils import encodeutils
from tackerclient.common import exceptions
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -170,6 +171,7 @@ class CreateVNF(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
vnf = client.create_vnf(self.args2body(parsed_args))
display_columns, columns = _get_columns(vnf[_VNF])
@@ -208,6 +210,7 @@ class DeleteVNF(command.Command):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
failure = False
deleted_ids = []
@@ -278,6 +281,7 @@ class ListVNF(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
_params = {}
if parsed_args.vim_id:
@@ -317,6 +321,7 @@ class ShowVNF(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNF, parsed_args.vnf)
@@ -343,6 +348,7 @@ class ListVNFResources(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNF, parsed_args.vnf)
@@ -418,6 +424,7 @@ class UpdateVNF(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNF, parsed_args.vnf)
@@ -457,6 +464,7 @@ class ScaleVNF(command.Command):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNF, parsed_args.vnf)

View File

@@ -20,6 +20,7 @@ from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.common import utils as tacker_common_utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
@@ -87,6 +88,7 @@ class CreateVNFD(command.ShowOne):
return body
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
vnfd = client.create_vnfd(self.args2body(parsed_args))
display_columns, columns = _get_columns(vnfd[_VNFD])
@@ -112,6 +114,7 @@ class DeleteVNFD(command.Command):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
failure = False
deleted_ids = []
@@ -160,6 +163,7 @@ class ListVNFD(command.Lister):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
data = client.list_vnfds()
headers, columns = tacker_osc_utils.get_column_definitions(
@@ -183,6 +187,7 @@ class ShowVNFD(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNFD, parsed_args.vnfd)
@@ -210,6 +215,7 @@ class ShowTemplateVNFD(command.ShowOne):
return parser
def take_action(self, parsed_args):
tacker_common_utils.deprecate_legacy_warning()
client = self.app.client_manager.tackerclient
obj_id = tackerV10.find_resourceid_by_name_or_id(
client, _VNFD, parsed_args.vnfd)

View File

View File

View File

@@ -0,0 +1,62 @@
{
"filter": {
"vnfInstanceSubscriptionFilter": {
"vnfdIds": [
"dummy-vnfdId-1"
],
"vnfProductsFromProviders": [
{
"vnfProvider": "dummy-vnfProvider-1",
"vnfProducts": [
{
"vnfProductName": "dummy-vnfProductName-1-1",
"versions": [
{
"vnfSoftwareVersion": 1.0,
"vnfdVersions": [1.0, 2.0]
}
]
}
]
}
],
"vnfInstanceIds": [
"dummy-vnfInstanceId-1"
],
"vnfInstanceNames": [
"dummy-vnfInstanceName-1"
]
},
"notificationTypes": [
"AlarmNotification"
],
"faultyResourceTypes": [
"COMPUTE"
],
"perceivedSeverities": [
"WARNING"
],
"eventTypes": [
"EQUIPMENT_ALARM"
],
"probableCauses": [
"The server cannot be connected."
]
},
"callbackUri": "/nfvo/notify/alarm",
"authentication": {
"authType": [
"BASIC",
"OAUTH2_CLIENT_CREDENTIALS"
],
"paramsBasic": {
"userName": "nfvo",
"password": "nfvopwd"
},
"paramsOauth2ClientCredentials": {
"clientId": "auth_user_name",
"clientPassword": "auth_password",
"tokenEndpoint": "token_endpoint"
}
}
}

View File

@@ -0,0 +1,177 @@
# Copyright (C) 2022 Fujitsu
# 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.
import logging
from osc_lib.command import command
from osc_lib import utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
LOG = logging.getLogger(__name__)
_ATTR_MAP = (
('id', 'ID', tacker_osc_utils.LIST_BOTH),
('managedObjectId', 'Managed Object Id', tacker_osc_utils.LIST_BOTH),
('ackState', 'Ack State', tacker_osc_utils.LIST_BOTH),
('eventType', 'Event Type', tacker_osc_utils.LIST_BOTH),
('perceivedSeverity', 'Perceived Severity', tacker_osc_utils.LIST_BOTH),
('probableCause', 'Probable Cause', tacker_osc_utils.LIST_BOTH)
)
_FORMATTERS = {
'vnfcInstanceIds': tacker_osc_utils.FormatComplexDataColumn,
'rootCauseFaultyResource': tacker_osc_utils.FormatComplexDataColumn,
'correlatedAlarmIds': tacker_osc_utils.FormatComplexDataColumn,
'faultDetails': tacker_osc_utils.FormatComplexDataColumn,
'_links': tacker_osc_utils.FormatComplexDataColumn
}
_MIXED_CASE_FIELDS = (
'managedObjectId', 'rootCauseFaultyResource', 'vnfcInstanceIds',
'alarmRaisedTime', 'alarmChangedTime', 'alarmClearedTime',
'alarmAcknowledgedTime', 'ackState', 'perceivedSeverity', 'eventTime',
'eventType', 'faultType', 'probableCause', 'isRootCause',
'correlatedAlarmIds', 'faultDetails'
)
_VNF_FM_ALARM_ID = 'vnf_fm_alarm_id'
def _get_columns(vnffm_alarm_obj, action=None):
if action == 'update':
column_map = {
'ackState': 'Ack State'
}
else:
column_map = {
'id': 'ID',
'managedObjectId': 'Managed Object Id',
'ackState': 'Ack State',
'perceivedSeverity': 'Perceived Severity',
'eventType': 'Event Type',
'probableCause': 'Probable Cause'
}
if action == 'show':
column_map.update({
'vnfcInstanceIds': 'Vnfc Instance Ids',
'rootCauseFaultyResource': 'Root Cause Faulty Resource',
'alarmRaisedTime': 'Alarm Raised Time',
'alarmChangedTime': 'Alarm Changed Time',
'alarmClearedTime': 'Alarm Cleared Time',
'alarmAcknowledgedTime': 'Alarm Acknowledged Time',
'eventTime': 'Event Time',
'faultType': 'Fault Type',
'isRootCause': 'Is Root Cause',
'correlatedAlarmIds': 'Correlated Alarm Ids',
'faultDetails': 'Fault Details',
'_links': 'Links'
})
return sdk_utils.get_osc_show_columns_for_sdk_resource(
vnffm_alarm_obj, column_map)
class ListVnfFmAlarm(command.Lister):
_description = _("List VNF FM alarms")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(ListVnfFmAlarm, self).get_parser(prog_name)
parser.add_argument(
"--filter",
metavar="<filter>",
help=_("Attribute-based-filtering parameters"),
)
return parser
def take_action(self, parsed_args):
_params = {}
if parsed_args.filter:
_params['filter'] = parsed_args.filter
client = self.app.client_manager.tackerclient
data = client.list_vnf_fm_alarms(**_params)
headers, columns = tacker_osc_utils.get_column_definitions(
_ATTR_MAP, long_listing=True)
return (headers,
(utils.get_dict_properties(
s, columns, formatters=_FORMATTERS,
mixed_case_fields=_MIXED_CASE_FIELDS,
) for s in data['vnf_fm_alarms']))
class ShowVnfFmAlarm(command.ShowOne):
_description = _("Display VNF FM alarm details")
def get_parser(self, prog_name):
parser = super(ShowVnfFmAlarm, self).get_parser(prog_name)
parser.add_argument(
_VNF_FM_ALARM_ID,
metavar="<vnf-fm-alarm-id>",
help=_("VNF FM alarm ID to display"))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
obj = client.show_vnf_fm_alarm(parsed_args.vnf_fm_alarm_id)
display_columns, columns = _get_columns(obj, action='show')
data = utils.get_item_properties(
sdk_utils.DictModel(obj), columns,
mixed_case_fields=_MIXED_CASE_FIELDS,
formatters=_FORMATTERS)
return (display_columns, data)
class UpdateVnfFmAlarm(command.ShowOne):
_description = _("Update information about an individual VNF FM alarm")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(UpdateVnfFmAlarm, self).get_parser(prog_name)
parser.add_argument(
_VNF_FM_ALARM_ID,
metavar="<vnf-fm-alarm-id>",
help=_("VNF FM alarm ID to update.")
)
update_require_parameters = parser.add_argument_group(
"require arguments"
)
update_require_parameters.add_argument(
"--ack-state",
metavar="<ack-state>",
choices=['ACKNOWLEDGED', 'UNACKNOWLEDGED'],
help=_("Ask state can be 'ACKNOWLEDGED' or 'UNACKNOWLEDGED'."))
return parser
def args2body(self, parsed_args):
body = {'ackState': parsed_args.ack_state}
return body
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
updated_values = client.update_vnf_fm_alarm(
parsed_args.vnf_fm_alarm_id, self.args2body(parsed_args))
display_columns, columns = _get_columns(
updated_values, action='update')
data = utils.get_item_properties(
sdk_utils.DictModel(updated_values), columns,
mixed_case_fields=_MIXED_CASE_FIELDS,
formatters=_FORMATTERS)
return (display_columns, data)

View File

@@ -0,0 +1,169 @@
# Copyright (C) 2022 Fujitsu
# 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.
import logging
from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
LOG = logging.getLogger(__name__)
_ATTR_MAP = (
('id', 'ID', tacker_osc_utils.LIST_BOTH),
('callbackUri', 'Callback Uri', tacker_osc_utils.LIST_BOTH)
)
_FORMATTERS = {
'filter': tacker_osc_utils.FormatComplexDataColumn,
'_links': tacker_osc_utils.FormatComplexDataColumn
}
_MIXED_CASE_FIELDS = (
'callbackUri'
)
_VNF_FM_SUB_ID = 'vnf_fm_sub_id'
def _get_columns(vnffm_sub_obj):
column_map = {
'id': 'ID',
'filter': 'Filter',
'callbackUri': 'Callback Uri',
'_links': 'Links'
}
return sdk_utils.get_osc_show_columns_for_sdk_resource(
vnffm_sub_obj, column_map)
class CreateVnfFmSub(command.ShowOne):
_description = _("Create a new VNF FM subscription")
def get_parser(self, prog_name):
parser = super(CreateVnfFmSub, self).get_parser(prog_name)
parser.add_argument(
'request_file',
metavar="<param-file>",
help=_('Specify create VNF FM subscription request '
'parameters in a json file.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
vnf_fm_sub = client.create_vnf_fm_sub(
tacker_osc_utils.jsonfile2body(parsed_args.request_file))
display_columns, columns = _get_columns(vnf_fm_sub)
data = utils.get_item_properties(
sdk_utils.DictModel(vnf_fm_sub), columns,
formatters=_FORMATTERS, mixed_case_fields=_MIXED_CASE_FIELDS)
return (display_columns, data)
class ListVnfFmSub(command.Lister):
_description = _("List VNF FM subs")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(ListVnfFmSub, self).get_parser(prog_name)
parser.add_argument(
"--filter",
metavar="<filter>",
help=_("Attribute-based-filtering parameters"),
)
return parser
def take_action(self, parsed_args):
_params = {}
if parsed_args.filter:
_params['filter'] = parsed_args.filter
client = self.app.client_manager.tackerclient
data = client.list_vnf_fm_subs(**_params)
headers, columns = tacker_osc_utils.get_column_definitions(
_ATTR_MAP, long_listing=True)
return (headers,
(utils.get_dict_properties(
s, columns, formatters=_FORMATTERS,
mixed_case_fields=_MIXED_CASE_FIELDS,
) for s in data['vnf_fm_subs']))
class ShowVnfFmSub(command.ShowOne):
_description = _("Display VNF FM subscription details")
def get_parser(self, prog_name):
parser = super(ShowVnfFmSub, self).get_parser(prog_name)
parser.add_argument(
_VNF_FM_SUB_ID,
metavar="<vnf-fm-sub-id>",
help=_("VNF FM subscription ID to display"))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
obj = client.show_vnf_fm_sub(parsed_args.vnf_fm_sub_id)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(
sdk_utils.DictModel(obj), columns,
mixed_case_fields=_MIXED_CASE_FIELDS,
formatters=_FORMATTERS)
return (display_columns, data)
class DeleteVnfFmSub(command.Command):
_description = _("Delete VNF FM subscription(s)")
def get_parser(self, prog_name):
parser = super(DeleteVnfFmSub, self).get_parser(prog_name)
parser.add_argument(
_VNF_FM_SUB_ID,
metavar="<vnf-fm-sub-id>",
nargs="+",
help=_("VNF FM subscription ID(s) to delete"))
return parser
def take_action(self, parsed_args):
error_count = 0
client = self.app.client_manager.tackerclient
vnf_fm_sub_ids = parsed_args.vnf_fm_sub_id
for sub_id in vnf_fm_sub_ids:
try:
client.delete_vnf_fm_sub(sub_id)
except Exception as e:
error_count += 1
LOG.error(_("Failed to delete VNF FM subscription with "
"ID '%(sub_id)s': %(e)s"),
{'sub_id': sub_id, 'e': e})
total = len(vnf_fm_sub_ids)
if error_count > 0:
msg = (_("Failed to delete %(error_count)s of %(total)s "
"VNF FM subscriptions.") % {'error_count': error_count,
'total': total})
raise exceptions.CommandError(message=msg)
if total > 1:
print(_('All specified VNF FM subscriptions are deleted '
'successfully'))
else:
print(_("VNF FM subscription '%s' deleted "
"successfully") % vnf_fm_sub_ids[0])

View File

@@ -0,0 +1,36 @@
{
"vnfdId": "c6595341-a5bb-8246-53c4-7aeb843d60c5",
"additionalParams": {
"upgrade_type": "RollingUpdate",
"lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_old_vnf.py",
"lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf",
"lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_new_vnf.py",
"lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf",
"vdu_params": [{
"vduId": "VDU1",
"old_vnfc_param": {
"cp_name": "VDU1_CP1",
"username": "ubuntu",
"password": "ubuntu"
},
"new_vnfc_param": {
"cp_name": "VDU1_CP1",
"username": "ubuntu",
"password": "ubuntu"
}
}, {
"vduId": "VDU2",
"old_vnfc_param": {
"cp_name": "VDU2_CP1",
"username": "ubuntu",
"password": "ubuntu"
},
"new_vnfc_param": {
"cp_name": "VDU2_CP1",
"username": "ubuntu",
"password": "ubuntu"
}
}]
}
}

View File

View File

@@ -0,0 +1,36 @@
{
"objectType": "VNFC",
"objectInstanceIds": [
"object-instance-id-1"
],
"subObjectInstanceIds": [
"sub-object-instance-id-2"
],
"criteria": {
"performanceMetric": [
"VCpuUsageMeanVnf.object-instance-id-1"
],
"performanceMetricGroup": [
"VirtualisedComputeResource"
],
"collectionPeriod": "500",
"reportingPeriod": "1000",
"reportingBoundary": "2022/07/25 10:43:55"
},
"callbackUri": "/nfvo/notify/job",
"authentication": {
"authType": [
"BASIC",
"OAUTH2_CLIENT_CREDENTIALS"
],
"paramsBasic": {
"userName": "nfvo",
"password": "nfvopwd"
},
"paramsOauth2ClientCredentials": {
"clientId": "auth_user_name",
"clientPassword": "auth_password",
"tokenEndpoint": "token_endpoint"
}
}
}

View File

@@ -0,0 +1,40 @@
{
"objectType": "Vnfc",
"objectInstanceId": "object-instance-id-1",
"subObjectInstanceIds": [
"sub-object-instance-id-2"
],
"criteria": {
"performanceMetric": "VCpuUsageMeanVnf.object-instance-id-1",
"thresholdType": "SIMPLE",
"simpleThresholdDetails": {
"thresholdValue": 400.5,
"hysteresis": 10.3
}
},
"callbackUri": "/nfvo/notify/threshold",
"authentication": {
"authType": [
"BASIC",
"OAUTH2_CLIENT_CREDENTIALS",
"OAUTH2_CLIENT_CERT"
],
"paramsBasic": {
"userName": "nfvo",
"password": "nfvopwd"
},
"paramsOauth2ClientCredentials": {
"clientId": "auth_user_name",
"clientPassword": "auth_password",
"tokenEndpoint": "token_endpoint"
},
"paramsOauth2ClientCert": {
"clientId": "test",
"certificateRef": {
"type": "x5t#256",
"value": "03c6e188d1fe5d3da8c9bc9a8dc531a2b3e"
},
"tokenEndpoint": "http://127.0.0.1/token"
}
}
}

View File

@@ -0,0 +1,18 @@
{
"callbackUri": "/nfvo/notify/job",
"authentication": {
"authType": [
"BASIC",
"OAUTH2_CLIENT_CREDENTIALS"
],
"paramsBasic": {
"userName": "nfvo",
"password": "nfvopwd"
},
"paramsOauth2ClientCredentials": {
"clientId": "auth_user_name",
"clientPassword": "auth_password",
"tokenEndpoint": "token_endpoint"
}
}
}

View File

@@ -0,0 +1,27 @@
{
"callbackUri": "/nfvo/notify/threshold",
"authentication": {
"authType": [
"BASIC",
"OAUTH2_CLIENT_CREDENTIALS",
"OAUTH2_CLIENT_CERT"
],
"paramsBasic": {
"userName": "nfvo",
"password": "nfvopwd"
},
"paramsOauth2ClientCredentials": {
"clientId": "auth_user_name",
"clientPassword": "auth_password",
"tokenEndpoint": "token_endpoint"
},
"paramsOauth2ClientCert": {
"clientId": "test",
"certificateRef": {
"type": "x5t#256",
"value": "03c6e188d1fe5d3da8c9bc9a8dc531a2b3e"
},
"tokenEndpoint": "http://127.0.0.1/token"
}
}
}

View File

@@ -0,0 +1,306 @@
# Copyright (C) 2022 Fujitsu
# 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.
import logging
from functools import reduce
from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
LOG = logging.getLogger(__name__)
_FORMATTERS = {
'objectInstanceIds': tacker_osc_utils.FormatComplexDataColumn,
'subObjectInstanceIds': tacker_osc_utils.FormatComplexDataColumn,
'criteria': tacker_osc_utils.FormatComplexDataColumn,
'reports': tacker_osc_utils.FormatComplexDataColumn,
'_links': tacker_osc_utils.FormatComplexDataColumn
}
_FORMATTERS_UPDATE = {
'authentication': tacker_osc_utils.FormatComplexDataColumn
}
_MIXED_CASE_FIELDS = (
'objectType', 'objectInstanceIds', 'subObjectInstanceIds', 'callbackUri'
)
_MIXED_CASE_FIELDS_UPDATE = (
'callbackUri'
)
_VNF_PM_JOB_ID = 'vnf_pm_job_id'
def _get_columns(vnfpm_job_obj, action=None):
if action == 'update':
column_map = {
'callbackUri': 'Callback Uri',
'authentication': 'Authentication'
}
else:
column_map = {
'id': 'ID',
'objectType': 'Object Type',
'objectInstanceIds': 'Object Instance Ids',
'subObjectInstanceIds': 'Sub Object Instance Ids',
'criteria': 'Criteria',
'callbackUri': 'Callback Uri',
'reports': 'Reports',
'_links': 'Links'
}
if action == 'show':
column_map.update(
{'reports': 'Reports'}
)
return sdk_utils.get_osc_show_columns_for_sdk_resource(
vnfpm_job_obj, column_map)
class CreateVnfPmJob(command.ShowOne):
_description = _("Create a new VNF PM job")
def get_parser(self, prog_name):
parser = super(CreateVnfPmJob, self).get_parser(prog_name)
parser.add_argument(
'request_file',
metavar="<param-file>",
help=_('Specify create VNF PM job request '
'parameters in a json file.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
vnf_pm_job = client.create_vnf_pm_job(
tacker_osc_utils.jsonfile2body(parsed_args.request_file))
display_columns, columns = _get_columns(vnf_pm_job)
data = utils.get_item_properties(
sdk_utils.DictModel(vnf_pm_job), columns,
formatters=_FORMATTERS, mixed_case_fields=_MIXED_CASE_FIELDS)
return (display_columns, data)
class ListVnfPmJob(command.Lister):
_description = _("List VNF PM jobs")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(ListVnfPmJob, self).get_parser(prog_name)
parser.add_argument(
"--filter",
metavar="<filter>",
help=_("Attribute-based-filtering parameters"),
)
fields_exclusive_group = parser.add_mutually_exclusive_group(
required=False)
fields_exclusive_group.add_argument(
"--all_fields",
action="store_true",
default=False,
help=_("Include all complex attributes in the response"),
)
fields_exclusive_group.add_argument(
"--fields",
metavar="fields",
help=_("Complex attributes to be included into the response"),
)
fields_exclusive_group.add_argument(
"--exclude_fields",
metavar="exclude-fields",
help=_("Complex attributes to be excluded from the response"),
)
parser.add_argument(
"--exclude_default",
action="store_true",
default=False,
help=_("Indicates to exclude all complex attributes"
" from the response. This argument can be used alone or"
" with --fields and --filter. For all other combinations"
" tacker server will throw bad request error"),
)
return parser
def case_modify(self, field):
return reduce(
lambda x, y: x + (' ' if y.isupper() else '') + y, field).title()
def get_attributes(self, extra_fields=None, all_fields=False,
exclude_fields=None, exclude_default=False):
fields = ['id', 'objectType', '_links']
complex_fields = [
'objectInstanceIds',
'subObjectInstanceIds',
'criteria',
'reports']
simple_fields = ['callbackUri']
if extra_fields:
fields.extend(extra_fields)
if exclude_fields:
fields.extend([field for field in complex_fields
if field not in exclude_fields])
if all_fields:
fields.extend(complex_fields)
fields.extend(simple_fields)
if exclude_default:
fields.extend(simple_fields)
attrs = []
for field in fields:
if field == '_links':
attrs.extend([(field, 'Links', tacker_osc_utils.LIST_BOTH)])
else:
attrs.extend([(field, self.case_modify(field),
tacker_osc_utils.LIST_BOTH)])
return tuple(attrs)
def take_action(self, parsed_args):
_params = {}
extra_fields = []
exclude_fields = []
all_fields = False
exclude_default = False
if parsed_args.filter:
_params['filter'] = parsed_args.filter
if parsed_args.fields:
_params['fields'] = parsed_args.fields
fields = parsed_args.fields.split(',')
for field in fields:
extra_fields.append(field.split('/')[0])
if parsed_args.exclude_fields:
_params['exclude_fields'] = parsed_args.exclude_fields
fields = parsed_args.exclude_fields.split(',')
exclude_fields.extend(fields)
if parsed_args.exclude_default:
_params['exclude_default'] = None
exclude_default = True
if parsed_args.all_fields:
_params['all_fields'] = None
all_fields = True
client = self.app.client_manager.tackerclient
data = client.list_vnf_pm_jobs(**_params)
headers, columns = tacker_osc_utils.get_column_definitions(
self.get_attributes(extra_fields, all_fields, exclude_fields,
exclude_default), long_listing=True)
return (headers,
(utils.get_dict_properties(
s, columns, formatters=_FORMATTERS,
mixed_case_fields=_MIXED_CASE_FIELDS,
) for s in data['vnf_pm_jobs']))
class ShowVnfPmJob(command.ShowOne):
_description = _("Display VNF PM job details")
def get_parser(self, prog_name):
parser = super(ShowVnfPmJob, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_JOB_ID,
metavar="<vnf-pm-job-id>",
help=_("VNF PM job ID to display"))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
obj = client.show_vnf_pm_job(parsed_args.vnf_pm_job_id)
display_columns, columns = _get_columns(obj, action='show')
data = utils.get_item_properties(
sdk_utils.DictModel(obj), columns,
mixed_case_fields=_MIXED_CASE_FIELDS,
formatters=_FORMATTERS)
return (display_columns, data)
class UpdateVnfPmJob(command.ShowOne):
_description = _("Update information about an individual VNF PM job")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(UpdateVnfPmJob, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_JOB_ID,
metavar="<vnf-pm-job-id>",
help=_("VNF PM job ID to update.")
)
parser.add_argument(
'request_file',
metavar="<param-file>",
help=_('Specify update PM job request '
'parameters in a json file.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
updated_values = client.update_vnf_pm_job(
parsed_args.vnf_pm_job_id,
tacker_osc_utils.jsonfile2body(parsed_args.request_file))
display_columns, columns = _get_columns(updated_values, 'update')
data = utils.get_item_properties(
sdk_utils.DictModel(updated_values),
columns, formatters=_FORMATTERS_UPDATE,
mixed_case_fields=_MIXED_CASE_FIELDS_UPDATE)
return (display_columns, data)
class DeleteVnfPmJob(command.Command):
_description = _("Delete VNF PM job")
def get_parser(self, prog_name):
parser = super(DeleteVnfPmJob, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_JOB_ID,
metavar="<vnf-pm-job-id>",
nargs="+",
help=_("VNF PM job ID(s) to delete"))
return parser
def take_action(self, parsed_args):
error_count = 0
client = self.app.client_manager.tackerclient
vnf_pm_job_ids = parsed_args.vnf_pm_job_id
for job_id in vnf_pm_job_ids:
try:
client.delete_vnf_pm_job(job_id)
except Exception as e:
error_count += 1
LOG.error(_("Failed to delete VNF PM job with "
"ID '%(job_id)s': %(e)s"),
{'job_id': job_id, 'e': e})
total = len(vnf_pm_job_ids)
if error_count > 0:
msg = (_("Failed to delete %(error_count)s of %(total)s "
"VNF PM jobs.") % {'error_count': error_count,
'total': total})
raise exceptions.CommandError(message=msg)
if total > 1:
print(_('All specified VNF PM jobs are deleted '
'successfully'))
else:
print(_("VNF PM job '%s' deleted "
"successfully") % vnf_pm_job_ids[0])

View File

@@ -0,0 +1,67 @@
# Copyright (C) 2022 Fujitsu
# 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.
import logging
from osc_lib.command import command
from osc_lib import utils
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
LOG = logging.getLogger(__name__)
_FORMATTERS = {
'entries': tacker_osc_utils.FormatComplexDataColumn
}
_VNF_PM_JOB_ID = 'vnf_pm_job_id'
_VNF_PM_REPORT_ID = 'vnf_pm_report_id'
def _get_columns(vnfpm_report_obj):
column_map = {
'entries': 'Entries'
}
return sdk_utils.get_osc_show_columns_for_sdk_resource(
vnfpm_report_obj, column_map)
class ShowVnfPmReport(command.ShowOne):
_description = _("Display VNF PM report details")
def get_parser(self, prog_name):
parser = super(ShowVnfPmReport, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_JOB_ID,
metavar="<vnf-pm-job-id>",
help=_("VNF PM job id where the VNF PM report is located"))
parser.add_argument(
_VNF_PM_REPORT_ID,
metavar="<vnf-pm-report-id>",
help=_("VNF PM report ID to display"))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
obj = client.show_vnf_pm_report(
parsed_args.vnf_pm_job_id, parsed_args.vnf_pm_report_id)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(
sdk_utils.DictModel(obj),
columns, formatters=_FORMATTERS,
mixed_case_fields=None)
return (display_columns, data)

View File

@@ -0,0 +1,216 @@
# Copyright (C) 2023 Fujitsu
# 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.
import logging
from osc_lib.command import command
from osc_lib import utils
from tackerclient.common import exceptions
from tackerclient.i18n import _
from tackerclient.osc import sdk_utils
from tackerclient.osc import utils as tacker_osc_utils
LOG = logging.getLogger(__name__)
_ATTR_MAP = (
('id', 'ID', tacker_osc_utils.LIST_BOTH),
('objectType', 'Object Type', tacker_osc_utils.LIST_BOTH),
('_links', 'Links', tacker_osc_utils.LIST_BOTH)
)
_FORMATTERS = {
'subObjectInstanceIds': tacker_osc_utils.FormatComplexDataColumn,
'criteria': tacker_osc_utils.FormatComplexDataColumn,
'_links': tacker_osc_utils.FormatComplexDataColumn
}
_MIXED_CASE_FIELDS = (
'objectType', 'objectInstanceId', 'subObjectInstanceIds', 'callbackUri'
)
_MIXED_CASE_FIELDS_UPDATE = (
'callbackUri'
)
_VNF_PM_THRESHOLD_ID = 'vnf_pm_threshold_id'
def _get_columns(vnf_pm_threshold, action=None):
if action == 'update':
column_map = {
'callbackUri': 'Callback Uri'
}
else:
column_map = {
'id': 'ID',
'objectType': 'Object Type',
'objectInstanceId': 'Object Instance Id',
'subObjectInstanceIds': 'Sub Object Instance Ids',
'criteria': 'Criteria',
'callbackUri': 'Callback Uri',
'_links': 'Links'
}
return sdk_utils.get_osc_show_columns_for_sdk_resource(
vnf_pm_threshold, column_map)
class CreateVnfPmThreshold(command.ShowOne):
_description = _("Create a new VNF PM threshold")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(CreateVnfPmThreshold, self).get_parser(prog_name)
parser.add_argument(
'request_file',
metavar="<param-file>",
help=_('Specify create VNF PM threshold request '
'parameters in a json file.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
vnf_pm_threshold = client.create_vnf_pm_threshold(
tacker_osc_utils.jsonfile2body(parsed_args.request_file))
display_columns, columns = _get_columns(vnf_pm_threshold)
data = utils.get_item_properties(
sdk_utils.DictModel(vnf_pm_threshold), columns,
formatters=_FORMATTERS, mixed_case_fields=_MIXED_CASE_FIELDS)
return (display_columns, data)
class ListVnfPmThreshold(command.Lister):
_description = _("List VNF PM thresholds")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(ListVnfPmThreshold, self).get_parser(prog_name)
parser.add_argument(
"--filter",
metavar="<filter>",
help=_("Attribute-based-filtering parameters"),
)
return parser
def take_action(self, parsed_args):
_params = {}
if parsed_args.filter:
_params['filter'] = parsed_args.filter
client = self.app.client_manager.tackerclient
data = client.list_vnf_pm_thresholds(**_params)
headers, columns = tacker_osc_utils.get_column_definitions(
_ATTR_MAP, long_listing=True)
return (headers,
(utils.get_dict_properties(
s, columns, formatters=_FORMATTERS,
mixed_case_fields=_MIXED_CASE_FIELDS,
) for s in data['vnf_pm_thresholds']))
class ShowVnfPmThreshold(command.ShowOne):
_description = _("Display VNF PM threshold details")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(ShowVnfPmThreshold, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_THRESHOLD_ID,
metavar="<vnf-pm-threshold-id>",
help=_("VNF PM threshold ID to display"))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
obj = client.show_vnf_pm_threshold(parsed_args.vnf_pm_threshold_id)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(
sdk_utils.DictModel(obj), columns,
mixed_case_fields=_MIXED_CASE_FIELDS,
formatters=_FORMATTERS)
return (display_columns, data)
class UpdateVnfPmThreshold(command.ShowOne):
_description = _("Update information about an individual VNF PM threshold")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(UpdateVnfPmThreshold, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_THRESHOLD_ID,
metavar="<vnf-pm-threshold-id>",
help=_("VNF PM threshold ID to update.")
)
parser.add_argument(
'request_file',
metavar="<param-file>",
help=_('Specify update PM threshold request '
'parameters in a json file.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.tackerclient
updated_values = client.update_vnf_pm_threshold(
parsed_args.vnf_pm_threshold_id,
tacker_osc_utils.jsonfile2body(parsed_args.request_file))
display_columns, columns = _get_columns(updated_values, 'update')
data = utils.get_item_properties(
sdk_utils.DictModel(updated_values), columns,
mixed_case_fields=_MIXED_CASE_FIELDS_UPDATE)
return (display_columns, data)
class DeleteVnfPmThreshold(command.Command):
_description = _("Delete VNF PM threshold")
def get_parser(self, prog_name):
LOG.debug('get_parser(%s)', prog_name)
parser = super(DeleteVnfPmThreshold, self).get_parser(prog_name)
parser.add_argument(
_VNF_PM_THRESHOLD_ID,
metavar="<vnf-pm-threshold-id>",
nargs="+",
help=_("VNF PM threshold ID(s) to delete"))
return parser
def take_action(self, parsed_args):
error_count = 0
client = self.app.client_manager.tackerclient
vnf_pm_threshold_ids = parsed_args.vnf_pm_threshold_id
for threshold_id in vnf_pm_threshold_ids:
try:
client.delete_vnf_pm_threshold(threshold_id)
except Exception as e:
error_count += 1
LOG.error(_("Failed to delete VNF PM threshold with "
"ID '%(threshold_id)s': %(e)s"),
{'threshold_id': threshold_id, 'e': e})
total = len(vnf_pm_threshold_ids)
if error_count > 0:
msg = (_("Failed to delete %(error_count)s of %(total)s "
"VNF PM thresholds.") %
{'error_count': error_count, 'total': total})
raise exceptions.CommandError(message=msg)
if total > 1:
print(_('All specified VNF PM thresholds are deleted '
'successfully'))
return
print(_("VNF PM threshold '%s' deleted "
"successfully") % vnf_pm_threshold_ids[0])

View File

@@ -63,7 +63,25 @@ def args2body_vim(config_param, vim):
message='Project name must be specified in Kubernetes VIM,'
'it is namespace in Kubernetes environment',
status_code=404)
if ('username' in config_param) and ('password' in config_param):
if 'oidc_token_url' in config_param:
if ('username' not in config_param or
'password' not in config_param or
'client_id' not in config_param):
# the username, password, client_id are required.
# client_secret is not required when client type is public.
raise exceptions.TackerClientException(
message='oidc_token_url must be specified with username,'
' password, client_id, client_secret(optional).',
status_code=404)
vim['auth_cred'] = {
'oidc_token_url': config_param.pop('oidc_token_url'),
'username': config_param.pop('username'),
'password': config_param.pop('password'),
'client_id': config_param.pop('client_id')}
if 'client_secret' in config_param:
vim['auth_cred']['client_secret'] = config_param.pop(
'client_secret')
elif ('username' in config_param) and ('password' in config_param):
vim['auth_cred'] = {
'username': config_param.pop('username', ''),
'password': config_param.pop('password', '')}
@@ -78,6 +96,8 @@ def args2body_vim(config_param, vim):
ssl_ca_cert = config_param.pop('ssl_ca_cert', '')
if ssl_ca_cert:
vim['auth_cred']['ssl_ca_cert'] = ssl_ca_cert
if 'extra' in config_param:
vim['extra'] = config_param.pop('extra')
def validate_auth_url(url):

View File

@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import filecmp
import os
import shutil
@@ -201,6 +202,51 @@ class TestListVnfPackage(TestVnfPackage):
self.assertCountEqual(self.get_list_columns(**kwargs), actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_pagination(self):
next_links_num = 3
parsed_args = self.check_parser(self.list_vnf_package, [], [])
path = os.path.join(self.url, '/vnfpkgm/v1/vnf_packages?')
links = [0] * next_links_num
link_headers = [0] * next_links_num
for i in range(next_links_num):
links[i] = (
'{base_url}?nextpage_opaque_marker={vnf_package_id}'.format(
base_url=path,
vnf_package_id=self._vnf_packages
['vnf_packages'][i]['id']))
link_headers[i] = copy.deepcopy(self.header)
link_headers[i]['Link'] = '<{link_url}>; rel="next"'.format(
link_url=links[i])
self.requests_mock.register_uri(
'GET', path, json=[self._vnf_packages['vnf_packages'][0]],
headers=link_headers[0])
self.requests_mock.register_uri(
'GET', links[0], json=[self._vnf_packages['vnf_packages'][1]],
headers=link_headers[1])
self.requests_mock.register_uri(
'GET', links[1], json=[self._vnf_packages['vnf_packages'][2]],
headers=link_headers[2])
self.requests_mock.register_uri(
'GET', links[2], json=[], headers=self.header)
actual_columns, data = self.list_vnf_package.take_action(parsed_args)
kwargs = {}
headers, columns = tacker_osc_utils.get_column_definitions(
self.list_vnf_package.get_attributes(**kwargs), long_listing=True)
expected_data = []
for vnf_package_obj in self._vnf_packages['vnf_packages']:
expected_data.append(vnf_package_fakes.get_vnf_package_data(
vnf_package_obj, columns=columns, list_action=True, **kwargs))
self.assertCountEqual(self.get_list_columns(**kwargs), actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_exclude_fields(self):
parsed_args = self.check_parser(
self.list_vnf_package,

View File

@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
from io import StringIO
import os
import sys
@@ -156,25 +157,67 @@ class TestShowVnfLcm(TestVnfLcm):
class TestListVnfLcm(TestVnfLcm):
vnf_instances = vnflcm_fakes.create_vnf_instances(count=3)
def setUp(self):
super(TestListVnfLcm, self).setUp()
self.list_vnf_instance = vnflcm.ListVnfLcm(
self.app, self.app_args, cmd_name='vnflcm list')
def test_take_action(self):
vnf_instances = vnflcm_fakes.create_vnf_instances(count=3)
parsed_args = self.check_parser(self.list_vnf_instance, [], [])
self.requests_mock.register_uri(
'GET', os.path.join(self.url, 'vnflcm/v1/vnf_instances'),
json=self.vnf_instances, headers=self.header)
json=vnf_instances, headers=self.header)
actual_columns, data = self.list_vnf_instance.take_action(parsed_args)
headers, columns = tacker_osc_utils.get_column_definitions(
vnflcm._attr_map, long_listing=True)
expected_data = []
for vnf_instance_obj in self.vnf_instances:
for vnf_instance_obj in vnf_instances:
expected_data.append(vnflcm_fakes.get_vnflcm_data(
vnf_instance_obj, columns=columns, list_action=True))
self.assertCountEqual(_get_columns_vnflcm(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
def test_take_action_with_pagination(self):
vnf_instances = vnflcm_fakes.create_vnf_instances(count=3)
next_links_num = 3
parsed_args = self.check_parser(self.list_vnf_instance, [], [])
path = os.path.join(self.url, 'vnflcm/v1/vnf_instances')
links = [0] * next_links_num
link_headers = [0] * next_links_num
for i in range(next_links_num):
links[i] = (
'{base_url}?nextpage_opaque_marker={vnf_instance_id}'.format(
base_url=path,
vnf_instance_id=vnf_instances[i]['id']))
link_headers[i] = copy.deepcopy(self.header)
link_headers[i]['Link'] = '<{link_url}>; rel="next"'.format(
link_url=links[i])
self.requests_mock.register_uri(
'GET', path, json=[vnf_instances[0]], headers=link_headers[0])
self.requests_mock.register_uri(
'GET', links[0], json=[vnf_instances[1]],
headers=link_headers[1])
self.requests_mock.register_uri(
'GET', links[1], json=[vnf_instances[2]],
headers=link_headers[2])
self.requests_mock.register_uri(
'GET', links[2], json=[], headers=self.header)
actual_columns, data = self.list_vnf_instance.take_action(parsed_args)
headers, columns = tacker_osc_utils.get_column_definitions(
vnflcm._attr_map, long_listing=True)
expected_data = []
for vnf_instance_obj in vnf_instances:
expected_data.append(vnflcm_fakes.get_vnflcm_data(
vnf_instance_obj, columns=columns, list_action=True))
@@ -254,9 +297,9 @@ class TestInstantiateVnfLcm(TestVnfLcm):
self.instantiate_vnf_lcm.take_action,
parsed_args)
expected_msg = ("Invalid input: File %s does not exist "
"or user does not have read privileges to it")
self.assertEqual(expected_msg % sample_param_file, str(ex))
expected_msg = ("Invalid input: "
"User does not have read privileges to it")
self.assertEqual(expected_msg, str(ex))
@mock.patch("os.open")
@mock.patch("os.access")
@@ -288,6 +331,9 @@ class TestHealVnfLcm(TestVnfLcm):
self.heal_vnf_lcm = vnflcm.HealVnfLcm(
self.app, self.app_args, cmd_name='vnflcm heal')
_heal_sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
"heal_vnf_instance_param_sample.json")
@ddt.data((['--cause', 'test-cause', "--vnfc-instance",
'vnfc-id-1', 'vnfc-id-2'],
[('cause', 'test-cause'),
@@ -296,6 +342,8 @@ class TestHealVnfLcm(TestVnfLcm):
[('cause', 'test-cause')]),
(["--vnfc-instance", 'vnfc-id-1', 'vnfc-id-2'],
[('vnfc_instance', ['vnfc-id-1', 'vnfc-id-2'])]),
(["--additional-param-file", _heal_sample_param_file],
[('additional_param_file', _heal_sample_param_file)]),
([], []))
@ddt.unpack
def test_take_action(self, arglist, verifylist):
@@ -340,6 +388,25 @@ class TestHealVnfLcm(TestVnfLcm):
self.heal_vnf_lcm.take_action,
parsed_args)
def test_take_action_param_file_not_exists(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = "./not_exists.json"
arglist = [vnf_instance['id'],
'--additional-param-file', sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('additional_param_file', sample_param_file)]
# command param
parsed_args = self.check_parser(self.heal_vnf_lcm, arglist,
verifylist)
ex = self.assertRaises(exceptions.InvalidInput,
self.heal_vnf_lcm.take_action, parsed_args)
expected_msg = ("Invalid input: "
"User does not have read privileges to it")
self.assertEqual(expected_msg, str(ex))
@ddt.ddt
class TestTerminateVnfLcm(TestVnfLcm):
@@ -396,7 +463,7 @@ class TestTerminateVnfLcm(TestVnfLcm):
self.assertIn(expected_message, actual_message)
if delete_vnf:
expected_message = ("VNF Instance '%s' deleted successfully"
expected_message = ("VNF Instance '%s' is deleted successfully"
% vnf_instance['id'])
self.assertIn(expected_message, actual_message)
@@ -512,7 +579,7 @@ class TestDeleteVnfLcm(TestVnfLcm):
sys.stdout = buffer = StringIO()
result = self.delete_vnf_instance.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual(("Vnf instance '%s' deleted successfully")
self.assertEqual(("Vnf instance '%s' is deleted successfully")
% self.vnf_instances[0]['id'],
buffer.getvalue().strip())
@@ -707,9 +774,9 @@ class TestScaleVnfLcm(TestVnfLcm):
ex = self.assertRaises(exceptions.InvalidInput,
self.scale_vnf_lcm.take_action, parsed_args)
expected_msg = ("Invalid input: File %s does not exist "
"or user does not have read privileges to it")
self.assertEqual(expected_msg % sample_param_file, str(ex))
expected_msg = ("Invalid input: "
"User does not have read privileges to it")
self.assertEqual(expected_msg, str(ex))
@ddt.data('SCALE_IN', 'SCALE_OUT')
def test_take_action_vnf_instance_not_found(self, scale_type):
@@ -821,9 +888,9 @@ class TestChangeExtConnVnfLcm(TestVnfLcm):
self.change_ext_conn_vnf_lcm.take_action,
parsed_args)
expected_msg = ("Invalid input: File %s does not exist "
"or user does not have read privileges to it")
self.assertEqual(expected_msg % sample_param_file, str(ex))
expected_msg = ("Invalid input: "
"User does not have read privileges to it")
self.assertEqual(expected_msg, str(ex))
@mock.patch("os.open")
@mock.patch("os.access")
@@ -850,6 +917,40 @@ class TestChangeExtConnVnfLcm(TestVnfLcm):
self.assertIn(expected_msg, str(ex))
class TestChangeVnfPkgVnfLcm(TestVnfLcm):
def setUp(self):
super(TestChangeVnfPkgVnfLcm, self).setUp()
self.change_vnfpkg_vnf_lcm = vnflcm.ChangeVnfPkgVnfLcm(
self.app, self.app_args,
cmd_name='vnflcm change-vnfpkg')
def test_take_action_with_v1_version(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = ("./tackerclient/osc/v2/vnflcm/samples/"
"change_vnfpkg_vnf_instance_param_sample.json")
arglist = [vnf_instance['id'], sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('request_file', sample_param_file)]
# command param
parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm,
arglist,
verifylist)
url = os.path.join(self.url, 'vnflcm/v1/vnf_instances',
vnf_instance['id'], 'change_vnfpkg')
self.requests_mock.register_uri(
'POST', url, headers=self.header, status_code=400, json={})
ex = self.assertRaises(exceptions.UnsupportedCommandVersion,
self.change_vnfpkg_vnf_lcm.take_action,
parsed_args)
expected_msg = "This command is not supported in version 1"
self.assertEqual(expected_msg, str(ex))
class TestVnfLcmV1(base.FixturedTestCase):
client_fixture_class = client.ClientFixture
api_version = '1'

View File

@@ -10,10 +10,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
from io import StringIO
import os
import sys
import ddt
from oslo_utils.fixture import uuidsentinel
from unittest import mock
@@ -25,7 +27,7 @@ from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v1 import vnflcm_op_occs_fakes
def _get_columns_vnflcm_op_occs(action='show'):
def _get_columns_vnflcm_op_occs(action='show', parameter=None):
if action == 'fail':
return ['ID', 'Operation State', 'State Entered Time',
@@ -33,8 +35,11 @@ def _get_columns_vnflcm_op_occs(action="/?originalUrl=https%3A%2F%2Fgit.openstack.org%2F%26%2339%3Bshow%26%2339%3B)%3A%253C%2Fcode">
'Is Automatic Invocation', 'Is Cancel Pending',
'Error', 'Links']
elif action == 'list':
return ['ID', 'Operation State', 'VNF Instance ID',
'Operation']
if parameter is not None:
return ['ID', 'Operation']
else:
return ['ID', 'Operation State', 'VNF Instance ID',
'Operation']
else:
return ['ID', 'Operation State', 'State Entered Time',
'Start Time', 'VNF Instance ID', 'Grant ID',
@@ -57,6 +62,70 @@ class TestVnfLcm(base.FixturedTestCase):
self.app.client_manager.tackerclient = self.client_manager
@ddt.ddt
class TestCancelVnfLcmOp(TestVnfLcm):
def setUp(self):
super(TestCancelVnfLcmOp, self).setUp()
self.cancel_vnf_lcm = vnflcm_op_occs.CancelVnfLcmOp(
self.app, self.app_args, cmd_name='vnflcm op cancel')
@ddt.data('GRACEFUL', 'FORCEFUL')
def test_take_action(self, cancel_mode):
"""take_action normal system test"""
arglist = ['--cancel-mode', cancel_mode,
uuidsentinel.vnf_lcm_op_occ_id]
verifylist = [('cancel_mode', cancel_mode),
('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
parsed_args = self.check_parser(
self.cancel_vnf_lcm, arglist, verifylist)
url = os.path.join(
self.url,
'vnflcm/v1/vnf_lcm_op_occs',
uuidsentinel.vnf_lcm_op_occ_id,
'cancel')
self.requests_mock.register_uri(
'POST', url, headers=self.header, json={})
sys.stdout = buffer = StringIO()
self.cancel_vnf_lcm.take_action(parsed_args)
actual_message = buffer.getvalue().strip()
expected_message = (
'Cancel request for LCM operation ' +
uuidsentinel.vnf_lcm_op_occ_id +
' has been accepted')
self.assertEqual(expected_message, actual_message)
def test_terminate_no_options(self):
self.assertRaises(base.ParserException, self.check_parser,
self.cancel_vnf_lcm, [], [])
def test_take_action_vnf_lcm_op_occ_id_not_found(self):
"""take_action abnomaly system test"""
arglist = [uuidsentinel.vnf_lcm_op_occ_id]
verifylist = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
parsed_args = self.check_parser(
self.cancel_vnf_lcm, arglist, verifylist)
url = os.path.join(
self.url,
'vnflcm/v1/vnf_lcm_op_occs',
uuidsentinel.vnf_lcm_op_occ_id,
'cancel')
self.requests_mock.register_uri(
'POST', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.cancel_vnf_lcm.take_action,
parsed_args)
class TestRollbackVnfLcmOp(TestVnfLcm):
def setUp(self):
@@ -431,6 +500,80 @@ class TestListVnfLcmOp(TestVnfLcm):
self.list_vnflcm_op_occ.take_action,
parsed_args)
def test_take_action_with_exclude_fields(self):
vnflcm_op_occs_obj = vnflcm_op_occs_fakes.create_vnflcm_op_occs(
count=3)
parsed_args = self.check_parser(
self.list_vnflcm_op_occ,
["--exclude-fields", 'VNF Instance ID,Operation State'],
[('exclude_fields', 'VNF Instance ID,Operation State')])
self.requests_mock.register_uri(
'GET', os.path.join(
self.url,
'vnflcm/v1/vnf_lcm_op_occs?'
'exclude-fields=VNF Instance ID,Operation State'),
json=vnflcm_op_occs_obj, headers=self.header)
actual_columns, data = self.list_vnflcm_op_occ.take_action(parsed_args)
headers, columns = tacker_osc_utils.get_column_definitions(
self.list_vnflcm_op_occ.get_attributes(
exclude=['VNF Instance ID', 'Operation State']),
long_listing=True)
expected_data = []
for vnflcm_op_occ_obj_idx in vnflcm_op_occs_obj:
expected_data.append(
vnflcm_op_occs_fakes.get_vnflcm_op_occ_data(
vnflcm_op_occ_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnflcm_op_occs(
action='list', parameter="exclude_fields"),
actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_pagination(self):
next_links_num = 3
vnflcm_op_occs_obj = vnflcm_op_occs_fakes.create_vnflcm_op_occs(
count=next_links_num)
parsed_args = self.check_parser(self.list_vnflcm_op_occ, [], [])
path = os.path.join(self.url, 'vnflcm/v1/vnf_lcm_op_occs')
links = [0] * next_links_num
link_headers = [0] * next_links_num
for i in range(next_links_num):
links[i] = (
'{base_url}?nextpage_opaque_marker={vnflcm_op_occ_id}'.format(
base_url=path,
vnflcm_op_occ_id=vnflcm_op_occs_obj[i]['id']))
link_headers[i] = copy.deepcopy(self.header)
link_headers[i]['Link'] = '<{link_url}>; rel="next"'.format(
link_url=links[i])
self.requests_mock.register_uri(
'GET', path, json=[vnflcm_op_occs_obj[0]], headers=link_headers[0])
self.requests_mock.register_uri(
'GET', links[0], json=[vnflcm_op_occs_obj[1]],
headers=link_headers[1])
self.requests_mock.register_uri(
'GET', links[1], json=[vnflcm_op_occs_obj[2]],
headers=link_headers[2])
self.requests_mock.register_uri(
'GET', links[2], json=[], headers=self.header)
actual_columns, data = self.list_vnflcm_op_occ.take_action(parsed_args)
headers, columns = tacker_osc_utils.get_column_definitions(
self.list_vnflcm_op_occ.get_attributes(), long_listing=True)
expected_data = []
for vnflcm_op_occ_obj_idx in vnflcm_op_occs_obj:
expected_data.append(vnflcm_op_occs_fakes.get_vnflcm_op_occ_data(
vnflcm_op_occ_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnflcm_op_occs(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
class TestShowVnfLcmOp(TestVnfLcm):

View File

@@ -0,0 +1,254 @@
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
# 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.
import copy
import os
import sys
from io import StringIO
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v1.vnflcm import vnflcm_subsc
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1 import test_vnflcm
from tackerclient.tests.unit.osc.v1 import vnflcm_subsc_fakes
def _get_columns_vnflcm_subsc(action=None):
columns = ['ID', 'Filter', 'Callback URI', 'Links']
if action == 'list':
columns = [ele for ele in columns if ele not in
['Filter', 'Links']]
return columns
class TestCreateLccnSubscription(test_vnflcm.TestVnfLcm):
def setUp(self):
super(TestCreateLccnSubscription, self).setUp()
self.create_subscription = vnflcm_subsc.CreateLccnSubscription(
self.app, self.app_args, cmd_name='vnflcm subsc create')
def test_create_no_args(self):
self.assertRaises(base.ParserException, self.check_parser,
self.create_subscription, [], [])
def test_take_action(self):
subscription = vnflcm_subsc_fakes.lccn_subsc_response()
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
"create_lccn_subscription_param_sample.json")
arglist = [sample_param_file]
verifylist = [('create_request_file', sample_param_file)]
# command param
parsed_args = self.check_parser(self.create_subscription,
arglist, verifylist)
self.requests_mock.register_uri(
'POST', os.path.join(self.url, 'vnflcm/v1/subscriptions'),
json=subscription, headers=self.header)
actual_columns, data = (self.create_subscription.take_action(
parsed_args))
headers, attributes = vnflcm_subsc._get_columns(subscription)
self.assertCountEqual(_get_columns_vnflcm_subsc(),
actual_columns)
self.assertListItemsEqual(vnflcm_subsc_fakes.get_subscription_data(
subscription, columns=attributes), data)
class TestListLccnSubscription(test_vnflcm.TestVnfLcm):
def setUp(self):
super(TestListLccnSubscription, self).setUp()
self.list_subscription = vnflcm_subsc.ListLccnSubscription(
self.app, self.app_args, cmd_name='vnflcm subsc list')
def test_take_action(self):
subscriptions = vnflcm_subsc_fakes.create_subscriptions(count=3)
parsed_args = self.check_parser(self.list_subscription, [], [])
self.requests_mock.register_uri(
'GET', os.path.join(self.url, 'vnflcm/v1/subscriptions'),
json=subscriptions, headers=self.header)
actual_columns, data = self.list_subscription.take_action(parsed_args)
headers, columns = tacker_osc_utils.get_column_definitions(
self.list_subscription.get_attributes(), long_listing=True)
expected_data = []
for subscription_obj in subscriptions:
expected_data.append(vnflcm_subsc_fakes.get_subscription_data(
subscription_obj, columns=columns, list_action=True))
self.assertCountEqual(_get_columns_vnflcm_subsc(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
def test_take_action_with_pagination(self):
subscriptions = vnflcm_subsc_fakes.create_subscriptions(count=3)
next_links_num = 3
path = os.path.join(self.url, 'vnflcm/v1/subscriptions')
parsed_args = self.check_parser(self.list_subscription, [], [])
links = [0] * next_links_num
link_headers = [0] * next_links_num
for i in range(next_links_num):
links[i] = (
'{base_url}?nextpage_opaque_marker={subscription_id}'.format(
base_url=path,
subscription_id=subscriptions[i]['id']))
link_headers[i] = copy.deepcopy(self.header)
link_headers[i]['Link'] = '<{link_url}>; rel="next"'.format(
link_url=links[i])
self.requests_mock.register_uri(
'GET', path, json=[subscriptions[0]], headers=link_headers[0])
self.requests_mock.register_uri(
'GET', links[0], json=[subscriptions[1]],
headers=link_headers[1])
self.requests_mock.register_uri(
'GET', links[1], json=[subscriptions[2]],
headers=link_headers[2])
self.requests_mock.register_uri(
'GET', links[2], json=[], headers=self.header)
actual_columns, data = self.list_subscription.take_action(parsed_args)
headers, columns = tacker_osc_utils.get_column_definitions(
self.list_subscription.get_attributes(), long_listing=True)
expected_data = []
for subscription_obj in subscriptions:
expected_data.append(vnflcm_subsc_fakes.get_subscription_data(
subscription_obj, columns=columns, list_action=True))
self.assertCountEqual(_get_columns_vnflcm_subsc(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
class TestShowLccnSubscription(test_vnflcm.TestVnfLcm):
def setUp(self):
super(TestShowLccnSubscription, self).setUp()
self.show_subscription = vnflcm_subsc.ShowLccnSubscription(
self.app, self.app_args, cmd_name='vnflcm subsc show')
def test_take_action(self):
subscription = vnflcm_subsc_fakes.lccn_subsc_response()
arglist = [subscription['id']]
verifylist = [('subscription_id', subscription['id'])]
# command param
parsed_args = self.check_parser(self.show_subscription, arglist,
verifylist)
self.requests_mock.register_uri(
'GET', os.path.join(self.url, 'vnflcm/v1/subscriptions',
subscription['id']),
json=subscription, headers=self.header)
columns, data = (self.show_subscription.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnflcm_subsc(),
columns)
headers, attributes = vnflcm_subsc._get_columns(subscription)
self.assertListItemsEqual(
vnflcm_subsc_fakes.get_subscription_data(subscription,
columns=attributes),
data)
class TestDeleteLccnSubscription(test_vnflcm.TestVnfLcm):
subscriptions = vnflcm_subsc_fakes.create_subscriptions(count=3)
def setUp(self):
super(TestDeleteLccnSubscription, self).setUp()
self.delete_subscription = vnflcm_subsc.DeleteLccnSubscription(
self.app, self.app_args, cmd_name='vnflcm subsc delete')
def _mock_request_url_for_delete(self, subsc_index):
url = os.path.join(self.url, 'vnflcm/v1/subscriptions',
self.subscriptions[subsc_index]['id'])
json = self.subscriptions[subsc_index]
self.requests_mock.register_uri('GET', url, json=json,
headers=self.header)
self.requests_mock.register_uri('DELETE', url,
headers=self.header, json={})
def test_delete_one_subscription(self):
arglist = [self.subscriptions[0]['id']]
verifylist = [('subscription_id',
[self.subscriptions[0]['id']])]
parsed_args = self.check_parser(self.delete_subscription,
arglist, verifylist)
self._mock_request_url_for_delete(0)
sys.stdout = buffer = StringIO()
result = self.delete_subscription.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual(("Lccn Subscription '%s' is deleted successfully")
% self.subscriptions[0]['id'],
buffer.getvalue().strip())
def test_delete_multiple_subscription(self):
arglist = []
for subscription in self.subscriptions:
arglist.append(subscription['id'])
verifylist = [('subscription_id', arglist)]
parsed_args = self.check_parser(self.delete_subscription,
arglist, verifylist)
for i in range(0, 3):
self._mock_request_url_for_delete(i)
sys.stdout = buffer = StringIO()
result = self.delete_subscription.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual('All specified Lccn Subscriptions are deleted '
'successfully', buffer.getvalue().strip())
def test_delete_multiple_subscription_exception(self):
arglist = [
self.subscriptions[0]['id'],
'xxxx-yyyy-zzzz',
self.subscriptions[1]['id'],
]
verifylist = [('subscription_id', arglist)]
parsed_args = self.check_parser(self.delete_subscription,
arglist, verifylist)
self._mock_request_url_for_delete(0)
url = os.path.join(self.url, 'vnflcm/v1/subscriptions',
'xxxx-yyyy-zzzz')
self.requests_mock.register_uri(
'GET', url, exc=exceptions.ConnectionFailed)
self._mock_request_url_for_delete(1)
exception = self.assertRaises(exceptions.CommandError,
self.delete_subscription.take_action,
parsed_args)
self.assertEqual('Failed to delete 1 of 3 Lccn Subscriptions.',
exception.message)

View File

@@ -121,23 +121,24 @@ def get_vnflcm_data(vnf_instance, list_action="/?originalUrl=https%3A%2F%2Fgit.openstack.org%2FFalse%2C%2520columns%3DNone)%3A%253C%2Fcode">
:return:
A tuple object sorted based on the name of the columns.
"""
vnf = vnf_instance.copy()
complex_attributes = ['vimConnectionInfo', 'instantiatedVnfInfo', '_links']
for attribute in complex_attributes:
if vnf_instance.get(attribute):
vnf_instance.update(
if vnf.get(attribute):
vnf.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
vnf_instance[attribute])})
vnf[attribute])})
if list_action:
for item in ['vnfInstanceDescription', 'vnfdVersion']:
vnf_instance.pop(item)
vnf.pop(item)
# return the list of data as per column order
if columns:
return tuple([vnf_instance[key] for key in columns])
return tuple([vnf[key] for key in columns])
return tuple([vnf_instance[key] for key in sorted(
vnf_instance.keys())])
return tuple([vnf[key] for key in sorted(
vnf.keys())])
def create_vnf_instances(count=2):

View File

@@ -0,0 +1,191 @@
# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation
# 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 oslo_utils.fixture import uuidsentinel
from oslo_utils import uuidutils
from tackerclient.osc import utils as tacker_osc_utils
def lccn_subsc_response(attrs=None):
"""Create a fake subscription.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A subscription dict
"""
attrs = attrs or {}
id = uuidsentinel.lccn_subsc_id
# Set default attributes.
dummy_subscription = {
"id": id,
"filter": {
"vnfInstanceSubscriptionFilter": {
"vnfdIds": [
"dummy-vnfdId-1",
"dummy-vnfdId-2"
],
"vnfProductsFromProviders": [
{
"vnfProvider": "dummy-vnfProvider-1",
"vnfProducts": [
{
"vnfProductName": "dummy-vnfProductName-1-1",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
},
{
"vnfProductName": "dummy-vnfProductName-1-2",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
}
]
},
{
"vnfProvider": "dummy-vnfProvider-2",
"vnfProducts": [
{
"vnfProductName": "dummy-vnfProductName-2-1",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
},
{
"vnfProductName": "dummy-vnfProductName-2-2",
"versions": [
{
"vnfSoftwareVersion": "1.0",
"vnfdVersions": ["1.0", "2.0"]
},
{
"vnfSoftwareVersion": "1.1",
"vnfdVersions": ["1.1", "2.1"]
}
]
}
]
}
],
"vnfInstanceIds": [
"dummy-vnfInstanceId-1",
"dummy-vnfInstanceId-2"
],
"vnfInstanceNames": [
"dummy-vnfInstanceName-1",
"dummy-vnfInstanceName-2"
]
},
"notificationTypes": [
"VnfLcmOperationOccurrenceNotification",
"VnfIdentifierCreationNotification",
"VnfIdentifierDeletionNotification"
],
"operationTypes": [
"INSTANTIATE",
"SCALE",
"TERMINATE",
"HEAL",
"MODIFY_INFO",
"CHANGE_EXT_CONN"
],
"operationStates": [
"COMPLETED",
"FAILED",
"FAILED_TEMP",
"PROCESSING",
"ROLLING_BACK",
"ROLLED_BACK",
"STARTING"
]
},
"callbackUri": "http://localhost:9990/notification/callback/test",
"_links": {
"self": {
"href": "http://127.0.0.1:9890/vnflcm/v2/subscriptions/" + id
}
}
}
# Overwrite default attributes.
dummy_subscription.update(attrs)
return dummy_subscription
def get_subscription_data(subscription, list_action=False, columns=None):
"""Get the subscription data.
:return:
A tuple object sorted based on the name of the columns.
"""
subsc = subscription.copy()
complex_attributes = ['filter', '_links']
for attribute in complex_attributes:
if subsc.get(attribute):
subsc.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
subsc[attribute])})
if list_action:
for item in ['filter', '_links']:
subsc.pop(item)
# return the list of data as per column order
if columns:
return tuple([subsc[key] for key in columns])
return tuple([subsc[key] for key in sorted(
subsc.keys())])
def create_subscriptions(count=2):
"""Create multiple fake subscriptions.
:param count: The number of subscriptions to fake
:return:
A list of fake subscriptions dictionary
"""
uri = "http://localhost:9990/notification/callback/"
subscriptions = []
for i in range(0, count):
unique_id = uuidutils.generate_uuid()
subscriptions.append(lccn_subsc_response(
attrs={'id': unique_id,
'callbackUri': uri + str(i)}))
return subscriptions

View File

@@ -0,0 +1,307 @@
# Copyright (C) 2022 Fujitsu
# 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.
import ddt
import os
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnffm import vnffm_alarm
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnffm_alarm_fakes
class TestVnfFmAlarm(base.FixturedTestCase):
client_fixture_class = client.ClientFixture
def setUp(self):
super(TestVnfFmAlarm, self).setUp()
self.url = client.TACKER_URL
self.header = {'content-type': 'application/json'}
self.app = mock.Mock()
self.app_args = mock.Mock()
self.client_manager = self.cs
self.app.client_manager.tackerclient = self.client_manager
def _get_columns_vnffm_alarm(action=None):
if action == 'update':
columns = ['Ack State']
else:
columns = ['ID', 'Managed Object Id', 'Ack State',
'Perceived Severity', 'Event Type', 'Probable Cause']
if action == 'show':
columns.extend([
'Vnfc Instance Ids', 'Root Cause Faulty Resource',
'Alarm Raised Time', 'Alarm Changed Time',
'Alarm Cleared Time', 'Alarm Acknowledged Time',
'Event Time', 'Fault Type', 'Is Root Cause',
'Correlated Alarm Ids', 'Fault Details', 'Links'
])
return columns
class TestListVnfFmAlarm(TestVnfFmAlarm):
def setUp(self):
super(TestListVnfFmAlarm, self).setUp()
self.list_vnf_fm_alarms = vnffm_alarm.ListVnfFmAlarm(
self.app, self.app_args, cmd_name='vnffm alarm list')
def test_take_action(self):
vnffm_alarms_obj = vnffm_alarm_fakes.create_vnf_fm_alarms(
count=3)
parsed_args = self.check_parser(self.list_vnf_fm_alarms, [], [])
self.requests_mock.register_uri(
'GET', os.path.join(self.url, 'vnffm/v1/alarms'),
json=vnffm_alarms_obj, headers=self.header)
actual_columns, data = self.list_vnf_fm_alarms.take_action(parsed_args)
_, columns = tacker_osc_utils.get_column_definitions(
vnffm_alarm._ATTR_MAP, long_listing=True)
expected_data = []
for vnffm_alarm_obj_idx in vnffm_alarms_obj:
expected_data.append(vnffm_alarm_fakes.get_vnffm_alarm_data(
vnffm_alarm_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnffm_alarm(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
def test_take_action_with_filter(self):
vnffm_alarms_obj = vnffm_alarm_fakes.create_vnf_fm_alarms(
count=3)
parsed_args = self.check_parser(
self.list_vnf_fm_alarms,
["--filter", '(eq,perceivedSeverity,WARNING)'],
[('filter', '(eq,perceivedSeverity,WARNING)')])
self.requests_mock.register_uri(
'GET', os.path.join(
self.url,
'vnffm/v1/alarms?filter=(eq,perceivedSeverity,WARNING)'),
json=vnffm_alarms_obj, headers=self.header)
actual_columns, data = self.list_vnf_fm_alarms.take_action(parsed_args)
_, columns = tacker_osc_utils.get_column_definitions(
vnffm_alarm._ATTR_MAP, long_listing=True)
expected_data = []
for vnffm_alarm_obj_idx in vnffm_alarms_obj:
expected_data.append(vnffm_alarm_fakes.get_vnffm_alarm_data(
vnffm_alarm_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnffm_alarm(action='list'),
actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_incorrect_filter(self):
parsed_args = self.check_parser(
self.list_vnf_fm_alarms,
["--filter", '(perceivedSeverity)'],
[('filter', '(perceivedSeverity)')])
url = os.path.join(
self.url, 'vnffm/v1/alarms?filter=(perceivedSeverity)')
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=400, json={})
self.assertRaises(exceptions.TackerClientException,
self.list_vnf_fm_alarms.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
parsed_args = self.check_parser(
self.list_vnf_fm_alarms,
["--filter", '(eq,perceivedSeverity,WARNING)'],
[('filter', '(eq,perceivedSeverity,WARNING)')])
url = os.path.join(
self.url, 'vnffm/v1/alarms?filter=(eq,perceivedSeverity,WARNING)')
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.list_vnf_fm_alarms.take_action,
parsed_args)
class TestShowVnfFmAlarm(TestVnfFmAlarm):
def setUp(self):
super(TestShowVnfFmAlarm, self).setUp()
self.show_vnf_fm_alarm = vnffm_alarm.ShowVnfFmAlarm(
self.app, self.app_args, cmd_name='vnffm alarm show')
def test_take_action(self):
"""Test of take_action()"""
vnffm_alarm_obj = vnffm_alarm_fakes.vnf_fm_alarm_response()
arglist = [vnffm_alarm_obj['id']]
verifylist = [('vnf_fm_alarm_id', vnffm_alarm_obj['id'])]
# command param
parsed_args = self.check_parser(
self.show_vnf_fm_alarm, arglist, verifylist)
url = os.path.join(
self.url, 'vnffm/v1/alarms', vnffm_alarm_obj['id'])
self.requests_mock.register_uri(
'GET', url, headers=self.header, json=vnffm_alarm_obj)
columns, _ = (self.show_vnf_fm_alarm.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnffm_alarm(action='show'),
columns)
def test_take_action_vnf_lcm_op_occ_id_not_found(self):
"""Test if vnf-lcm-op-occ-id does not find."""
arglist = [uuidsentinel.vnf_fm_alarm_id]
verifylist = [('vnf_fm_alarm_id', uuidsentinel.vnf_fm_alarm_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_fm_alarm, arglist, verifylist)
url = os.path.join(
self.url, 'vnffm/v1/alarms', uuidsentinel.vnf_fm_alarm_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_fm_alarm.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
"""Test for internal server error."""
arglist = [uuidsentinel.vnf_fm_alarm_id]
verifylist = [('vnf_fm_alarm_id', uuidsentinel.vnf_fm_alarm_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_fm_alarm, arglist, verifylist)
url = os.path.join(
self.url, 'vnffm/v1/alarms', uuidsentinel.vnf_fm_alarm_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_fm_alarm.take_action,
parsed_args)
@ddt.ddt
class TestUpdateVnfFmAlarm(TestVnfFmAlarm):
def setUp(self):
super(TestUpdateVnfFmAlarm, self).setUp()
self.update_vnf_fm_alarm = vnffm_alarm.UpdateVnfFmAlarm(
self.app, self.app_args, cmd_name='vnffm alarm update')
@ddt.data('ACKNOWLEDGED', 'UNACKNOWLEDGED')
def test_take_action(self, ack_state):
"""Test of take_action()"""
vnffm_alarm_obj = vnffm_alarm_fakes.vnf_fm_alarm_response(
None, 'update')
arg_list = ['--ack-state', ack_state, uuidsentinel.vnf_fm_alarm_id]
verify_list = [('ack_state', ack_state),
('vnf_fm_alarm_id', uuidsentinel.vnf_fm_alarm_id)]
# command param
parsed_args = self.check_parser(
self.update_vnf_fm_alarm, arg_list, verify_list)
url = os.path.join(
self.url, 'vnffm/v1/alarms', uuidsentinel.vnf_fm_alarm_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json=vnffm_alarm_obj)
actual_columns, data = (
self.update_vnf_fm_alarm.take_action(parsed_args))
expected_columns = _get_columns_vnffm_alarm(action='update')
self.assertCountEqual(expected_columns, actual_columns)
_, columns = vnffm_alarm._get_columns(
vnffm_alarm_obj, action='update')
expected_data = vnffm_alarm_fakes.get_vnffm_alarm_data(
vnffm_alarm_obj, columns=columns)
self.assertEqual(expected_data, data)
@ddt.data('ACKNOWLEDGED')
def test_take_action_vnf_lcm_op_occ_id_not_found(self, ack_state):
"""Test if vnf-lcm-op-occ-id does not find"""
arg_list = ['--ack-state', ack_state, uuidsentinel.vnf_fm_alarm_id]
verify_list = [('ack_state', ack_state),
('vnf_fm_alarm_id', uuidsentinel.vnf_fm_alarm_id)]
# command param
parsed_args = self.check_parser(
self.update_vnf_fm_alarm, arg_list, verify_list)
url = os.path.join(
self.url, 'vnffm/v1/alarms', uuidsentinel.vnf_fm_alarm_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.update_vnf_fm_alarm.take_action,
parsed_args)
@ddt.data('UNACKNOWLEDGED')
def test_take_action_vnf_lcm_op_occ_state_is_conflict(self, ack_state):
"""Test if vnf-lcm-op-occ state is conflict"""
arg_list = ['--ack-state', ack_state, uuidsentinel.vnf_fm_alarm_id]
verify_list = [('ack_state', ack_state),
('vnf_fm_alarm_id', uuidsentinel.vnf_fm_alarm_id)]
# command param
parsed_args = self.check_parser(
self.update_vnf_fm_alarm, arg_list, verify_list)
url = os.path.join(
self.url, 'vnffm/v1/alarms', uuidsentinel.vnf_fm_alarm_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, status_code=409, json={})
self.assertRaises(exceptions.TackerClientException,
self.update_vnf_fm_alarm.take_action,
parsed_args)

View File

@@ -0,0 +1,329 @@
# Copyright (C) 2022 Fujitsu
# 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.
import ddt
import os
import sys
from io import StringIO
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnffm import vnffm_sub
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnffm_sub_fakes
class TestVnfFmSub(base.FixturedTestCase):
client_fixture_class = client.ClientFixture
def setUp(self):
super(TestVnfFmSub, self).setUp()
self.url = client.TACKER_URL
self.header = {'content-type': 'application/json'}
self.app = mock.Mock()
self.app_args = mock.Mock()
self.client_manager = self.cs
self.app.client_manager.tackerclient = self.client_manager
def _get_columns_vnffm_sub(action=None):
columns = ['ID', 'Callback Uri']
if action == 'show' or action == 'create':
columns.extend(['Filter', 'Links'])
return columns
@ddt.ddt
class TestCreateVnfFmSub(TestVnfFmSub):
def setUp(self):
super(TestCreateVnfFmSub, self).setUp()
self.create_vnf_fm_sub = vnffm_sub.CreateVnfFmSub(
self.app, self.app_args, cmd_name='vnffm sub create')
def test_create_no_args(self):
self.assertRaises(base.ParserException, self.check_parser,
self.create_vnf_fm_sub, [], [])
@ddt.unpack
def test_take_action(self):
param_file = ("./tackerclient/osc/v2/vnffm/samples/"
"create_vnf_fm_subscription_param_sample.json")
arg_list = [param_file]
verify_list = [('request_file', param_file)]
parsed_args = self.check_parser(self.create_vnf_fm_sub, arg_list,
verify_list)
json = vnffm_sub_fakes.vnf_fm_sub_response()
self.requests_mock.register_uri(
'POST', os.path.join(self.url, 'vnffm/v1/subscriptions'),
json=json, headers=self.header)
actual_columns, data = (
self.create_vnf_fm_sub.take_action(parsed_args))
_, attributes = vnffm_sub._get_columns(json)
self.assertCountEqual(_get_columns_vnffm_sub("create"),
actual_columns)
self.assertListItemsEqual(vnffm_sub_fakes.get_vnffm_sub_data(
json, columns=attributes), data)
class TestListVnfFmSub(TestVnfFmSub):
def setUp(self):
super(TestListVnfFmSub, self).setUp()
self.list_vnffm_sub = vnffm_sub.ListVnfFmSub(
self.app, self.app_args, cmd_name='vnffm sub list')
def test_take_action(self):
vnffm_subs_obj = vnffm_sub_fakes.create_vnf_fm_subs(
count=3)
parsed_args = self.check_parser(self.list_vnffm_sub, [], [])
self.requests_mock.register_uri(
'GET', os.path.join(self.url, 'vnffm/v1/subscriptions'),
json=vnffm_subs_obj, headers=self.header)
actual_columns, data = self.list_vnffm_sub.take_action(parsed_args)
_, columns = tacker_osc_utils.get_column_definitions(
vnffm_sub._ATTR_MAP, long_listing=True)
expected_data = []
for vnffm_sub_obj_idx in vnffm_subs_obj:
expected_data.append(vnffm_sub_fakes.get_vnffm_sub_data(
vnffm_sub_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnffm_sub(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
def test_take_action_with_filter(self):
vnffm_subs_obj = vnffm_sub_fakes.create_vnf_fm_subs(
count=3)
parsed_args = self.check_parser(
self.list_vnffm_sub,
["--filter", '(eq,callbackUri,/nfvo/notify/alarm)'],
[('filter', '(eq,callbackUri,/nfvo/notify/alarm)')])
self.requests_mock.register_uri(
'GET', os.path.join(
self.url,
'vnffm/v1/subscriptions?'
'filter=(eq,callbackUri,/nfvo/notify/alarm)'),
json=vnffm_subs_obj, headers=self.header)
actual_columns, data = self.list_vnffm_sub.take_action(parsed_args)
_, columns = tacker_osc_utils.get_column_definitions(
vnffm_sub._ATTR_MAP, long_listing=True)
expected_data = []
for vnffm_sub_obj_idx in vnffm_subs_obj:
expected_data.append(vnffm_sub_fakes.get_vnffm_sub_data(
vnffm_sub_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnffm_sub(action='list'),
actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_incorrect_filter(self):
parsed_args = self.check_parser(
self.list_vnffm_sub,
["--filter", '(callbackUri)'],
[('filter', '(callbackUri)')])
url = os.path.join(
self.url,
'vnffm/v1/subscriptions?filter=(callbackUri)')
self.requests_mock.register_uri(
'POST', url, headers=self.header, status_code=400, json={})
self.assertRaises(exceptions.TackerClientException,
self.list_vnffm_sub.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
parsed_args = self.check_parser(
self.list_vnffm_sub,
["--filter", '(eq,callbackUri,/nfvo/notify/alarm)'],
[('filter', '(eq,callbackUri,/nfvo/notify/alarm)')])
url = os.path.join(
self.url,
'vnffm/v1/subscriptions?'
'filter=(eq,callbackUri,/nfvo/notify/alarm)')
self.requests_mock.register_uri(
'POST', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.list_vnffm_sub.take_action,
parsed_args)
class TestShowVnfFmSub(TestVnfFmSub):
def setUp(self):
super(TestShowVnfFmSub, self).setUp()
self.show_vnf_fm_subs = vnffm_sub.ShowVnfFmSub(
self.app, self.app_args, cmd_name='vnffm sub show')
def test_take_action(self):
"""Test of take_action()"""
vnffm_sub_obj = vnffm_sub_fakes.vnf_fm_sub_response()
arg_list = [vnffm_sub_obj['id']]
verify_list = [('vnf_fm_sub_id', vnffm_sub_obj['id'])]
# command param
parsed_args = self.check_parser(
self.show_vnf_fm_subs, arg_list, verify_list)
url = os.path.join(
self.url,
'vnffm/v1/subscriptions',
vnffm_sub_obj['id'])
self.requests_mock.register_uri(
'GET', url, headers=self.header, json=vnffm_sub_obj)
columns, _ = (self.show_vnf_fm_subs.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnffm_sub('show'),
columns)
def test_take_action_vnf_fm_sub_id_not_found(self):
"""Test if vnf-lcm-op-occ-id does not find."""
arg_list = [uuidsentinel.vnf_fm_sub_id]
verify_list = [('vnf_fm_sub_id', uuidsentinel.vnf_fm_sub_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_fm_subs, arg_list, verify_list)
url = os.path.join(
self.url,
'vnffm/v1/subscriptions',
uuidsentinel.vnf_fm_sub_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_fm_subs.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
"""Test for internal server error."""
arg_list = [uuidsentinel.vnf_fm_sub_id]
verify_list = [('vnf_fm_sub_id', uuidsentinel.vnf_fm_sub_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_fm_subs, arg_list, verify_list)
url = os.path.join(
self.url,
'vnffm/v1/subscriptions',
uuidsentinel.vnf_fm_sub_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_fm_subs.take_action,
parsed_args)
class TestDeleteVnfFmSub(TestVnfFmSub):
def setUp(self):
super(TestDeleteVnfFmSub, self).setUp()
self.delete_vnf_fm_sub = vnffm_sub.DeleteVnfFmSub(
self.app, self.app_args, cmd_name='vnffm sub delete')
# Vnf Fm subscription to delete
self.vnf_fm_subs = vnffm_sub_fakes.create_vnf_fm_subs(count=3)
def _mock_request_url_for_delete(self, index):
url = os.path.join(self.url, 'vnffm/v1/subscriptions',
self.vnf_fm_subs[index]['id'])
self.requests_mock.register_uri('DELETE', url,
headers=self.header, json={})
def test_delete_one_vnf_fm_sub(self):
arg_list = [self.vnf_fm_subs[0]['id']]
verify_list = [('vnf_fm_sub_id',
[self.vnf_fm_subs[0]['id']])]
parsed_args = self.check_parser(self.delete_vnf_fm_sub, arg_list,
verify_list)
self._mock_request_url_for_delete(0)
sys.stdout = buffer = StringIO()
result = self.delete_vnf_fm_sub.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual(
(f"VNF FM subscription '{self.vnf_fm_subs[0]['id']}' "
f"deleted successfully"), buffer.getvalue().strip())
def test_delete_multiple_vnf_fm_sub(self):
arg_list = []
for obj in self.vnf_fm_subs:
arg_list.append(obj['id'])
verify_list = [('vnf_fm_sub_id', arg_list)]
parsed_args = self.check_parser(self.delete_vnf_fm_sub, arg_list,
verify_list)
for i in range(0, 3):
self._mock_request_url_for_delete(i)
sys.stdout = buffer = StringIO()
result = self.delete_vnf_fm_sub.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual('All specified VNF FM subscriptions are deleted '
'successfully', buffer.getvalue().strip())
def test_delete_multiple_vnf_fm_sub_exception(self):
arg_list = [
self.vnf_fm_subs[0]['id'],
'xxxx-yyyy-zzzz',
self.vnf_fm_subs[1]['id'],
]
verify_list = [('vnf_fm_sub_id', arg_list)]
parsed_args = self.check_parser(self.delete_vnf_fm_sub,
arg_list, verify_list)
self._mock_request_url_for_delete(0)
url = os.path.join(self.url, 'vnffm/v1/subscriptions',
'xxxx-yyyy-zzzz')
self.requests_mock.register_uri(
'GET', url, exc=exceptions.ConnectionFailed)
self._mock_request_url_for_delete(1)
exception = self.assertRaises(exceptions.CommandError,
self.delete_vnf_fm_sub.take_action,
parsed_args)
self.assertEqual('Failed to delete 1 of 3 VNF FM subscriptions.',
exception.message)

View File

@@ -13,8 +13,18 @@
# License for the specific language governing permissions and limitations
# under the License.
from io import StringIO
import os
import sys
from unittest import mock
from tackerclient.common import exceptions
from tackerclient.osc.v1.vnflcm import vnflcm
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v1 import test_vnflcm
from tackerclient.tests.unit.osc.v1 import vnflcm_fakes
from tackerclient.v1_0 import client as proxy_client
class TestVnfLcmV2(base.FixturedTestCase):
@@ -30,3 +40,112 @@ class TestVnfLcmV2(base.FixturedTestCase):
self.assertEqual(self.cs.vnf_lcm_client.vnf_instances_path,
'/vnflcm/v2/vnf_instances')
# check of other paths is omitted.
class TestChangeVnfPkgVnfLcm(test_vnflcm.TestVnfLcm):
api_version = '2'
def setUp(self):
super(TestChangeVnfPkgVnfLcm, self).setUp()
self.change_vnfpkg_vnf_lcm = vnflcm.ChangeVnfPkgVnfLcm(
self.app, self.app_args,
cmd_name='vnflcm change-vnfpkg')
def test_take_action(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = ("./tackerclient/osc/v2/vnflcm/samples/"
"change_vnfpkg_vnf_instance_param_sample.json")
arglist = [vnf_instance['id'], sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('request_file', sample_param_file)]
# command param
parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm,
arglist,
verifylist)
url = os.path.join(self.url, 'vnflcm/v2/vnf_instances',
vnf_instance['id'], 'change_vnfpkg')
self.requests_mock.register_uri(
'POST', url, headers=self.header, json={})
sys.stdout = buffer = StringIO()
with mock.patch.object(proxy_client.ClientBase,
'_handle_fault_response') as m:
self.change_vnfpkg_vnf_lcm.take_action(parsed_args)
# check no fault response is received
self.assertNotCalled(m)
self.assertEqual(
('Change Current VNF Package for VNF Instance {0} '
'has been accepted.'.format(vnf_instance['id'])),
buffer.getvalue().strip())
def test_take_action_vnf_instance_not_found(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
"change_vnfpkg_vnf_instance_param_sample.json")
arglist = [vnf_instance['id'], sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('request_file', sample_param_file)]
# command param
parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm,
arglist,
verifylist)
url = os.path.join(self.url, 'vnflcm/v2/vnf_instances',
vnf_instance['id'], 'change_vnfpkg')
self.requests_mock.register_uri(
'POST', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.change_vnfpkg_vnf_lcm.take_action,
parsed_args)
def test_take_action_param_file_not_exists(self):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = "./not_exists.json"
arglist = [vnf_instance['id'], sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('request_file', sample_param_file)]
# command param
parsed_args = self.check_parser(
self.change_vnfpkg_vnf_lcm,
arglist,
verifylist)
ex = self.assertRaises(
exceptions.InvalidInput,
self.change_vnfpkg_vnf_lcm.take_action,
parsed_args)
expected_msg = ("Invalid input: "
"User does not have read privileges to it")
self.assertEqual(expected_msg, str(ex))
@mock.patch("os.open")
@mock.patch("os.access")
def test_take_action_invalid_format_param_file(self, mock_access,
mock_open):
vnf_instance = vnflcm_fakes.vnf_instance_response()
sample_param_file = "./invalid_param_file.json"
arglist = [vnf_instance['id'], sample_param_file]
verifylist = [('vnf_instance', vnf_instance['id']),
('request_file', sample_param_file)]
mock_open.return_value = "invalid_json_data"
mock_access.return_value = True
# command param
parsed_args = self.check_parser(self.change_vnfpkg_vnf_lcm,
arglist,
verifylist)
ex = self.assertRaises(
exceptions.InvalidInput,
self.change_vnfpkg_vnf_lcm.take_action,
parsed_args)
expected_msg = "Failed to load parameter file."
self.assertIn(expected_msg, str(ex))

View File

@@ -0,0 +1,476 @@
# Copyright (C) 2022 Fujitsu
# 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.
import ddt
import os
import sys
from io import StringIO
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnfpm import vnfpm_job
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnfpm_job_fakes
class TestVnfPmJob(base.FixturedTestCase):
client_fixture_class = client.ClientFixture
def setUp(self):
super(TestVnfPmJob, self).setUp()
self.url = client.TACKER_URL
self.header = {'content-type': 'application/json'}
self.app = mock.Mock()
self.app_args = mock.Mock()
self.client_manager = self.cs
self.app.client_manager.tackerclient = self.client_manager
def _get_columns_vnfpm_job(action=None):
if action == 'update':
columns = ['Callback Uri', 'Authentication']
else:
columns = ['ID', 'Object Type', 'Object Instance Ids',
'Sub Object Instance Ids', 'Criteria', 'Callback Uri',
'Reports', 'Links']
if action == 'list':
columns = [
ele for ele in columns if ele not in [
'Criteria', 'Sub Object Instance Ids', 'Reports', 'Links'
]
]
return columns
@ddt.ddt
class TestCreateVnfPmJob(TestVnfPmJob):
def setUp(self):
super(TestCreateVnfPmJob, self).setUp()
self.create_vnf_pm_job = vnfpm_job.CreateVnfPmJob(
self.app, self.app_args, cmd_name='vnfpm job create')
def test_create_no_args(self):
self.assertRaises(base.ParserException, self.check_parser,
self.create_vnf_pm_job, [], [])
@ddt.unpack
def test_take_action(self):
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"create_vnf_pm_job_param_sample.json")
arg_list = [param_file]
verify_list = [('request_file', param_file)]
parsed_args = self.check_parser(self.create_vnf_pm_job, arg_list,
verify_list)
json = vnfpm_job_fakes.vnf_pm_job_response()
self.requests_mock.register_uri(
'POST', os.path.join(self.url, 'vnfpm/v2/pm_jobs'),
json=json, headers=self.header)
actual_columns, data = (
self.create_vnf_pm_job.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnfpm_job(),
actual_columns)
_, attributes = vnfpm_job._get_columns(json)
expected_data = vnfpm_job_fakes.get_vnfpm_job_data(
json, columns=attributes)
self.assertListItemsEqual(expected_data, data)
@ddt.ddt
class TestListVnfPmJob(TestVnfPmJob):
def setUp(self):
super(TestListVnfPmJob, self).setUp()
self.list_vnf_pm_jobs = vnfpm_job.ListVnfPmJob(
self.app, self.app_args, cmd_name='vnfpm job list')
self._vnf_pm_jobs = self._get_vnf_pm_jobs()
def _get_vnf_pm_jobs(self):
return vnfpm_job_fakes.create_vnf_pm_jobs(count=3)
def get_list_columns(self, all_fields=False, exclude_fields=None,
extra_fields=None, exclude_default=False):
columns = ['Id', 'Object Type', 'Links']
complex_columns = [
'Object Instance Ids',
'Sub Object Instance Ids',
'Criteria',
'Reports'
]
simple_columns = ['Callback Uri']
if extra_fields:
columns.extend(extra_fields)
if exclude_fields:
columns.extend([field for field in complex_columns
if field not in exclude_fields])
if all_fields:
columns.extend(complex_columns)
columns.extend(simple_columns)
if exclude_default:
columns.extend(simple_columns)
return columns
def _get_mock_response_for_list_vnf_pm_jobs(
self, filter_attribute, json=None):
self.requests_mock.register_uri(
'GET', self.url + '/vnfpm/v2/pm_jobs?' + filter_attribute,
json=json if json else self._get_vnf_pm_jobs(),
headers=self.header)
def test_take_action_default_fields(self):
parsed_args = self.check_parser(self.list_vnf_pm_jobs, [], [])
self.requests_mock.register_uri(
'GET', self.url + '/vnfpm/v2/pm_jobs',
json=self._vnf_pm_jobs, headers=self.header)
actual_columns, data = self.list_vnf_pm_jobs.take_action(parsed_args)
expected_data = []
_, columns = tacker_osc_utils.get_column_definitions(
self.list_vnf_pm_jobs.get_attributes(), long_listing=True)
for vnf_pm_job_obj in self._vnf_pm_jobs['vnf_pm_jobs']:
expected_data.append(vnfpm_job_fakes.get_vnfpm_job_data(
vnf_pm_job_obj, columns=columns))
self.assertCountEqual(self.get_list_columns(), actual_columns)
self.assertListItemsEqual(expected_data, list(data))
@ddt.data('all_fields', 'exclude_default')
def test_take_action(self, arg):
parsed_args = self.check_parser(
self.list_vnf_pm_jobs,
["--" + arg, "--filter", '(eq,objectType,VNFC)'],
[(arg, True), ('filter', '(eq,objectType,VNFC)')])
vnf_pm_jobs = self._get_vnf_pm_jobs()
self._get_mock_response_for_list_vnf_pm_jobs(
'filter=(eq,objectType,VNFC)&' + arg, json=vnf_pm_jobs)
actual_columns, data = self.list_vnf_pm_jobs.take_action(parsed_args)
expected_data = []
kwargs = {arg: True}
_, columns = tacker_osc_utils.get_column_definitions(
self.list_vnf_pm_jobs.get_attributes(**kwargs), long_listing=True)
for vnf_pm_job_obj in vnf_pm_jobs['vnf_pm_jobs']:
expected_data.append(vnfpm_job_fakes.get_vnfpm_job_data(
vnf_pm_job_obj, columns=columns))
self.assertCountEqual(self.get_list_columns(**kwargs), actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_exclude_fields(self):
parsed_args = self.check_parser(
self.list_vnf_pm_jobs,
["--exclude_fields", 'objectInstanceIds,criteria',
"--filter", '(eq,objectType,VNFC)'],
[('exclude_fields', 'objectInstanceIds,criteria'),
('filter', '(eq,objectType,VNFC)')])
vnf_pm_jobs = self._get_vnf_pm_jobs()
updated_vnf_pm_jobs = {'vnf_pm_jobs': []}
for vnf_pm_job_obj in vnf_pm_jobs['vnf_pm_jobs']:
vnf_pm_job_obj.pop('objectInstanceIds')
vnf_pm_job_obj.pop('criteria')
updated_vnf_pm_jobs['vnf_pm_jobs'].append(vnf_pm_job_obj)
self._get_mock_response_for_list_vnf_pm_jobs(
'filter=(eq,objectType,VNFC)&'
'exclude_fields=objectInstanceIds,criteria',
json=updated_vnf_pm_jobs)
actual_columns, data = self.list_vnf_pm_jobs.take_action(parsed_args)
expected_data = []
_, columns = tacker_osc_utils.get_column_definitions(
self.list_vnf_pm_jobs.get_attributes(
exclude_fields=['objectInstanceIds', 'criteria']),
long_listing=True)
for updated_vnf_pm_obj in updated_vnf_pm_jobs['vnf_pm_jobs']:
expected_data.append(vnfpm_job_fakes.get_vnfpm_job_data(
updated_vnf_pm_obj, columns=columns))
expected_columns = self.get_list_columns(
exclude_fields=['Object Instance Ids', 'Criteria'])
self.assertCountEqual(expected_columns, actual_columns)
self.assertListItemsEqual(expected_data, list(data))
@ddt.data((['--all_fields', '--fields', 'objectInstanceIds'],
[('all_fields', True), ('fields', 'objectInstanceIds')]),
(['--all_fields', '--exclude_fields', 'criteria'],
[('all_fields', True), ('exclude_fields', 'criteria')]),
(['--fields', 'objectInstanceIds',
'--exclude_fields', 'criteria'],
[('fields', 'objectInstanceIds'),
('exclude_fields', 'criteria')]))
@ddt.unpack
def test_take_action_with_invalid_combination(self, arglist, verifylist):
self.assertRaises(base.ParserException, self.check_parser,
self.list_vnf_pm_jobs, arglist, verifylist)
def test_take_action_with_valid_combination(self):
parsed_args = self.check_parser(
self.list_vnf_pm_jobs,
[
"--fields", 'subObjectInstanceIds,criteria',
"--exclude_default"
],
[
('fields', 'subObjectInstanceIds,criteria'),
('exclude_default', True)
])
vnf_pm_jobs = self._get_vnf_pm_jobs()
updated_vnf_pm_jobs = {'vnf_pm_jobs': []}
for vnf_pm_job_obj in vnf_pm_jobs['vnf_pm_jobs']:
# vnf_pm_job_obj.pop('userDefinedData')
updated_vnf_pm_jobs['vnf_pm_jobs'].append(vnf_pm_job_obj)
self._get_mock_response_for_list_vnf_pm_jobs(
'exclude_default&fields=subObjectInstanceIds,criteria',
json=updated_vnf_pm_jobs)
actual_columns, data = self.list_vnf_pm_jobs.take_action(parsed_args)
expected_data = []
_, columns = tacker_osc_utils.get_column_definitions(
self.list_vnf_pm_jobs.get_attributes(
extra_fields=['subObjectInstanceIds', 'criteria'],
exclude_default=True),
long_listing=True)
for updated_vnf_pm_job_obj in updated_vnf_pm_jobs['vnf_pm_jobs']:
expected_data.append(vnfpm_job_fakes.get_vnfpm_job_data(
updated_vnf_pm_job_obj, columns=columns))
expected_columns = self.get_list_columns(
extra_fields=['Sub Object Instance Ids', 'Criteria'],
exclude_default=True)
self.assertCountEqual(expected_columns, actual_columns)
self.assertListItemsEqual(expected_data, list(data))
class TestShowVnfPmJob(TestVnfPmJob):
def setUp(self):
super(TestShowVnfPmJob, self).setUp()
self.show_vnf_pm_jobs = vnfpm_job.ShowVnfPmJob(
self.app, self.app_args, cmd_name='vnfpm job show')
def test_take_action(self):
"""Test of take_action()"""
vnfpm_job_obj = vnfpm_job_fakes.vnf_pm_job_response()
arg_list = [vnfpm_job_obj['id']]
verify_list = [('vnf_pm_job_id', vnfpm_job_obj['id'])]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_jobs, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', vnfpm_job_obj['id'])
self.requests_mock.register_uri(
'GET', url, headers=self.header, json=vnfpm_job_obj)
columns, data = (self.show_vnf_pm_jobs.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnfpm_job('show'), columns)
_, attributes = vnfpm_job._get_columns(vnfpm_job_obj)
self.assertListItemsEqual(
vnfpm_job_fakes.get_vnfpm_job_data(
vnfpm_job_obj, columns=attributes), data)
def test_take_action_vnf_pm_job_id_not_found(self):
"""Test if vnf-pm-job-id does not find."""
arg_list = [uuidsentinel.vnf_pm_job_id]
verify_list = [('vnf_pm_job_id', uuidsentinel.vnf_pm_job_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_jobs, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', uuidsentinel.vnf_pm_job_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_pm_jobs.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
"""Test for internal server error."""
arg_list = [uuidsentinel.vnf_pm_job_id]
verify_list = [('vnf_pm_job_id', uuidsentinel.vnf_pm_job_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_jobs, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', uuidsentinel.vnf_pm_job_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_pm_jobs.take_action,
parsed_args)
@ddt.ddt
class TestUpdateVnfPmJob(TestVnfPmJob):
def setUp(self):
super(TestUpdateVnfPmJob, self).setUp()
self.update_vnf_pm_job = vnfpm_job.UpdateVnfPmJob(
self.app, self.app_args, cmd_name='vnfpm job update')
def test_take_action(self):
"""Test of take_action()"""
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"update_vnf_pm_job_param_sample.json")
arg_list = [uuidsentinel.vnf_pm_job_id, param_file]
verify_list = [
('vnf_pm_job_id', uuidsentinel.vnf_pm_job_id),
('request_file', param_file)
]
vnfpm_job_obj = vnfpm_job_fakes.vnf_pm_job_response(
None, 'update')
# command param
parsed_args = self.check_parser(
self.update_vnf_pm_job, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', uuidsentinel.vnf_pm_job_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json=vnfpm_job_obj)
actual_columns, data = (
self.update_vnf_pm_job.take_action(parsed_args))
expected_columns = _get_columns_vnfpm_job(action='update')
self.assertCountEqual(expected_columns, actual_columns)
_, columns = vnfpm_job._get_columns(
vnfpm_job_obj, action='update')
expected_data = vnfpm_job_fakes.get_vnfpm_job_data(
vnfpm_job_obj, columns=columns)
self.assertEqual(expected_data, data)
def test_take_action_vnf_pm_job_id_not_found(self):
"""Test if vnf-pm-job-id does not find"""
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"update_vnf_pm_job_param_sample.json")
arg_list = [uuidsentinel.vnf_pm_job_id, param_file]
verify_list = [
('vnf_pm_job_id', uuidsentinel.vnf_pm_job_id),
('request_file', param_file)
]
# command param
parsed_args = self.check_parser(
self.update_vnf_pm_job, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', uuidsentinel.vnf_pm_job_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.update_vnf_pm_job.take_action,
parsed_args)
class TestDeleteVnfPmJob(TestVnfPmJob):
def setUp(self):
super(TestDeleteVnfPmJob, self).setUp()
self.delete_vnf_pm_job = vnfpm_job.DeleteVnfPmJob(
self.app, self.app_args, cmd_name='vnfpm job delete')
# Vnf Fm job to delete
self.vnf_pm_jobs = vnfpm_job_fakes.create_vnf_pm_jobs(
count=3)['vnf_pm_jobs']
def _mock_request_url_for_delete(self, index):
url = os.path.join(self.url, 'vnfpm/v2/pm_jobs',
self.vnf_pm_jobs[index]['id'])
self.requests_mock.register_uri('DELETE', url,
headers=self.header, json={})
def test_delete_one_vnf_pm_job(self):
arg_list = [self.vnf_pm_jobs[0]['id']]
verify_list = [('vnf_pm_job_id',
[self.vnf_pm_jobs[0]['id']])]
parsed_args = self.check_parser(self.delete_vnf_pm_job, arg_list,
verify_list)
self._mock_request_url_for_delete(0)
sys.stdout = buffer = StringIO()
result = self.delete_vnf_pm_job.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual(
(f"VNF PM job '{self.vnf_pm_jobs[0]['id']}' "
f"deleted successfully"), buffer.getvalue().strip())
def test_delete_multiple_vnf_pm_job(self):
arg_list = []
for obj in self.vnf_pm_jobs:
arg_list.append(obj['id'])
verify_list = [('vnf_pm_job_id', arg_list)]
parsed_args = self.check_parser(self.delete_vnf_pm_job, arg_list,
verify_list)
for i in range(0, 3):
self._mock_request_url_for_delete(i)
sys.stdout = buffer = StringIO()
result = self.delete_vnf_pm_job.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual('All specified VNF PM jobs are deleted '
'successfully', buffer.getvalue().strip())
def test_delete_multiple_vnf_pm_job_exception(self):
arg_list = [
self.vnf_pm_jobs[0]['id'],
'xxxx-yyyy-zzzz',
self.vnf_pm_jobs[1]['id'],
]
verify_list = [('vnf_pm_job_id', arg_list)]
parsed_args = self.check_parser(self.delete_vnf_pm_job,
arg_list, verify_list)
self._mock_request_url_for_delete(0)
url = os.path.join(self.url, 'vnfpm/v2/jobs',
'xxxx-yyyy-zzzz')
self.requests_mock.register_uri(
'GET', url, exc=exceptions.ConnectionFailed)
self._mock_request_url_for_delete(1)
exception = self.assertRaises(exceptions.CommandError,
self.delete_vnf_pm_job.take_action,
parsed_args)
self.assertEqual('Failed to delete 1 of 3 VNF PM jobs.',
exception.message)

View File

@@ -0,0 +1,131 @@
# Copyright (C) 2022 Fujitsu
# 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.
import os
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient.common import exceptions
from tackerclient.osc.v2.vnfpm import vnfpm_report
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnfpm_report_fakes
class TestVnfPmReport(base.FixturedTestCase):
client_fixture_class = client.ClientFixture
def setUp(self):
super(TestVnfPmReport, self).setUp()
self.url = client.TACKER_URL
self.header = {'content-type': 'application/json'}
self.app = mock.Mock()
self.app_args = mock.Mock()
self.client_manager = self.cs
self.app.client_manager.tackerclient = self.client_manager
def _get_columns_vnfpm_report():
columns = ['Entries']
return columns
class TestShowVnfPmReport(TestVnfPmReport):
def setUp(self):
super(TestShowVnfPmReport, self).setUp()
self.show_vnf_pm_reports = vnfpm_report.ShowVnfPmReport(
self.app, self.app_args, cmd_name='vnfpm report show')
def test_take_action(self):
"""Test of take_action()"""
vnfpm_report_obj = vnfpm_report_fakes.vnf_pm_report_response()
vnf_pm_job_id = uuidsentinel.vnf_pm_job_id
vnf_pm_report_id = uuidsentinel.vnfpm_report_obj
arg_list = [vnf_pm_job_id, vnf_pm_report_id]
verify_list = [
('vnf_pm_job_id', vnf_pm_job_id),
('vnf_pm_report_id', vnf_pm_report_id)
]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_reports, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', vnf_pm_job_id,
'reports', vnf_pm_report_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, json=vnfpm_report_obj)
columns, data = (self.show_vnf_pm_reports.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnfpm_report(), columns)
_, attributes = vnfpm_report._get_columns(vnfpm_report_obj)
expected_data = vnfpm_report_fakes.get_vnfpm_report_data(
vnfpm_report_obj, columns=attributes)
print(f'123, {expected_data}')
print(f'456, {data}')
self.assertListItemsEqual(expected_data, data)
def test_take_action_vnf_pm_report_id_not_found(self):
"""Test if vnf-pm-report-id does not find."""
vnf_pm_job_id = uuidsentinel.vnf_pm_job_id
vnf_pm_report_id = uuidsentinel.vnf_pm_report_id
arg_list = [vnf_pm_job_id, vnf_pm_report_id]
verify_list = [
('vnf_pm_job_id', vnf_pm_job_id),
('vnf_pm_report_id', vnf_pm_report_id)
]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_reports, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', vnf_pm_job_id,
'reports', vnf_pm_report_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_pm_reports.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
"""Test for internal server error."""
vnf_pm_job_id = uuidsentinel.vnf_pm_job_id
vnf_pm_report_id = uuidsentinel.vnf_pm_report_id
arg_list = [vnf_pm_job_id, vnf_pm_report_id]
verify_list = [
('vnf_pm_job_id', vnf_pm_job_id),
('vnf_pm_report_id', vnf_pm_report_id)
]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_reports, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/pm_jobs', vnf_pm_job_id,
'reports', vnf_pm_report_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_pm_reports.take_action,
parsed_args)

View File

@@ -0,0 +1,398 @@
# Copyright (C) 2023 Fujitsu
# 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.
import ddt
import os
import sys
from io import StringIO
from oslo_utils.fixture import uuidsentinel
from unittest import mock
from tackerclient.common import exceptions
from tackerclient.osc import utils as tacker_osc_utils
from tackerclient.osc.v2.vnfpm import vnfpm_threshold
from tackerclient.tests.unit.osc import base
from tackerclient.tests.unit.osc.v1.fixture_data import client
from tackerclient.tests.unit.osc.v2 import vnfpm_threshold_fakes
class TestVnfPmThreshold(base.FixturedTestCase):
client_fixture_class = client.ClientFixture
def setUp(self):
super(TestVnfPmThreshold, self).setUp()
self.url = client.TACKER_URL
self.header = {'content-type': 'application/json'}
self.app = mock.Mock()
self.app_args = mock.Mock()
self.client_manager = self.cs
self.app.client_manager.tackerclient = self.client_manager
def _get_columns_vnfpm_threshold(action=None):
if action == 'update':
columns = ['Callback Uri']
else:
columns = ['ID', 'Object Type', 'Object Instance Id',
'Sub Object Instance Ids', 'Criteria', 'Callback Uri',
'Links']
if action == 'list':
columns = [
'ID', 'Object Type', 'Links'
]
return columns
@ddt.ddt
class TestCreateVnfPmThreshold(TestVnfPmThreshold):
def setUp(self):
super(TestCreateVnfPmThreshold, self).setUp()
self.create_vnf_pm_threshold = vnfpm_threshold.CreateVnfPmThreshold(
self.app, self.app_args, cmd_name='vnfpm threshold create')
def test_create_no_args(self):
self.assertRaises(base.ParserException, self.check_parser,
self.create_vnf_pm_threshold, [], [])
@ddt.unpack
def test_take_action(self):
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"create_vnf_pm_threshold_param_sample.json")
arg_list = [param_file]
verify_list = [('request_file', param_file)]
parsed_args = self.check_parser(self.create_vnf_pm_threshold, arg_list,
verify_list)
response_json = vnfpm_threshold_fakes.vnf_pm_threshold_response()
self.requests_mock.register_uri(
'POST', os.path.join(self.url, 'vnfpm/v2/thresholds'),
json=response_json, headers=self.header)
actual_columns, data = (
self.create_vnf_pm_threshold.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnfpm_threshold(),
actual_columns)
_, attributes = vnfpm_threshold._get_columns(response_json)
expected_data = vnfpm_threshold_fakes.get_vnfpm_threshold_data(
response_json, columns=attributes)
self.assertListItemsEqual(expected_data, data)
@ddt.ddt
class TestListVnfPmThreshold(TestVnfPmThreshold):
def setUp(self):
super(TestListVnfPmThreshold, self).setUp()
self.list_vnf_pm_thresholds = vnfpm_threshold.ListVnfPmThreshold(
self.app, self.app_args, cmd_name='vnfpm threshold list')
def test_take_action(self):
vnf_pm_threshold_objs = vnfpm_threshold_fakes.create_vnf_pm_thresholds(
count=3)
parsed_args = self.check_parser(self.list_vnf_pm_thresholds, [], [])
self.requests_mock.register_uri(
'GET',
os.path.join(self.url, 'vnfpm/v2/thresholds'),
json=vnf_pm_threshold_objs, headers=self.header)
actual_columns, data = self.list_vnf_pm_thresholds.take_action(
parsed_args)
_, columns = tacker_osc_utils.get_column_definitions(
vnfpm_threshold._ATTR_MAP, long_listing=True)
expected_data = []
for vnf_pm_threshold_obj_idx in vnf_pm_threshold_objs:
expected_data.append(
vnfpm_threshold_fakes.get_vnfpm_threshold_data(
vnf_pm_threshold_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnfpm_threshold(action='list'),
actual_columns)
self.assertCountEqual(expected_data, list(data))
def test_take_action_with_filter(self):
vnf_pm_threshold_objs = vnfpm_threshold_fakes.create_vnf_pm_thresholds(
count=3)
parsed_args = self.check_parser(
self.list_vnf_pm_thresholds,
["--filter", '(eq,perceivedSeverity,WARNING)'],
[('filter', '(eq,perceivedSeverity,WARNING)')])
self.requests_mock.register_uri(
'GET', os.path.join(
self.url,
'vnfpm/v2/thresholds?filter=(eq,perceivedSeverity,WARNING)'),
json=vnf_pm_threshold_objs, headers=self.header)
actual_columns, data = self.list_vnf_pm_thresholds.take_action(
parsed_args)
_, columns = tacker_osc_utils.get_column_definitions(
vnfpm_threshold._ATTR_MAP, long_listing=True)
expected_data = []
for vnf_pm_threshold_obj_idx in vnf_pm_threshold_objs:
expected_data.append(
vnfpm_threshold_fakes.get_vnfpm_threshold_data(
vnf_pm_threshold_obj_idx, columns=columns))
self.assertCountEqual(_get_columns_vnfpm_threshold(action='list'),
actual_columns)
self.assertListItemsEqual(expected_data, list(data))
def test_take_action_with_incorrect_filter(self):
parsed_args = self.check_parser(
self.list_vnf_pm_thresholds,
["--filter", '(perceivedSeverity)'],
[('filter', '(perceivedSeverity)')])
url = os.path.join(
self.url, 'vnfpm/v2/thresholds?filter=(perceivedSeverity)')
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=400, json={})
self.assertRaises(exceptions.TackerClientException,
self.list_vnf_pm_thresholds.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
parsed_args = self.check_parser(
self.list_vnf_pm_thresholds,
["--filter", '(eq,perceivedSeverity,WARNING)'],
[('filter', '(eq,perceivedSeverity,WARNING)')])
url = os.path.join(
self.url,
'vnfpm/v2/thresholds?filter=(eq,perceivedSeverity,WARNING)')
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.list_vnf_pm_thresholds.take_action,
parsed_args)
class TestShowVnfPmThreshold(TestVnfPmThreshold):
def setUp(self):
super(TestShowVnfPmThreshold, self).setUp()
self.show_vnf_pm_thresholds = vnfpm_threshold.ShowVnfPmThreshold(
self.app, self.app_args, cmd_name='vnfpm threshold show')
def test_take_action(self):
vnfpm_threshold_obj = vnfpm_threshold_fakes.vnf_pm_threshold_response()
arg_list = [vnfpm_threshold_obj['id']]
verify_list = [('vnf_pm_threshold_id', vnfpm_threshold_obj['id'])]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_thresholds, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/thresholds', vnfpm_threshold_obj['id'])
self.requests_mock.register_uri(
'GET', url, headers=self.header, json=vnfpm_threshold_obj)
columns, data = (self.show_vnf_pm_thresholds.take_action(parsed_args))
self.assertCountEqual(_get_columns_vnfpm_threshold('show'), columns)
_, attributes = vnfpm_threshold._get_columns(vnfpm_threshold_obj)
self.assertListItemsEqual(
vnfpm_threshold_fakes.get_vnfpm_threshold_data(
vnfpm_threshold_obj, columns=attributes), data)
def test_take_action_vnf_pm_threshold_id_not_found(self):
arg_list = [uuidsentinel.vnf_pm_threshold_id]
verify_list = [('vnf_pm_threshold_id',
uuidsentinel.vnf_pm_threshold_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_thresholds, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/thresholds',
uuidsentinel.vnf_pm_threshold_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_pm_thresholds.take_action,
parsed_args)
def test_take_action_internal_server_error(self):
arg_list = [uuidsentinel.vnf_pm_threshold_id]
verify_list = [('vnf_pm_threshold_id',
uuidsentinel.vnf_pm_threshold_id)]
# command param
parsed_args = self.check_parser(
self.show_vnf_pm_thresholds, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/thresholds',
uuidsentinel.vnf_pm_threshold_id)
self.requests_mock.register_uri(
'GET', url, headers=self.header, status_code=500, json={})
self.assertRaises(exceptions.TackerClientException,
self.show_vnf_pm_thresholds.take_action,
parsed_args)
@ddt.ddt
class TestUpdateVnfPmThreshold(TestVnfPmThreshold):
def setUp(self):
super(TestUpdateVnfPmThreshold, self).setUp()
self.update_vnf_pm_threshold = vnfpm_threshold.UpdateVnfPmThreshold(
self.app, self.app_args, cmd_name='vnfpm threshold update')
def test_take_action(self):
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"update_vnf_pm_threshold_param_sample.json")
arg_list = [uuidsentinel.vnf_pm_threshold_id, param_file]
verify_list = [
('vnf_pm_threshold_id', uuidsentinel.vnf_pm_threshold_id),
('request_file', param_file)
]
vnfpm_threshold_obj = vnfpm_threshold_fakes.vnf_pm_threshold_response(
None, 'update')
# command param
parsed_args = self.check_parser(
self.update_vnf_pm_threshold, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/thresholds',
uuidsentinel.vnf_pm_threshold_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, json=vnfpm_threshold_obj)
actual_columns, data = (
self.update_vnf_pm_threshold.take_action(parsed_args))
expected_columns = _get_columns_vnfpm_threshold(action='update')
self.assertCountEqual(expected_columns, actual_columns)
_, columns = vnfpm_threshold._get_columns(
vnfpm_threshold_obj, action='update')
expected_data = vnfpm_threshold_fakes.get_vnfpm_threshold_data(
vnfpm_threshold_obj, columns=columns)
self.assertEqual(expected_data, data)
def test_take_action_vnf_pm_threshold_id_not_found(self):
param_file = ("./tackerclient/osc/v2/vnfpm/samples/"
"update_vnf_pm_threshold_param_sample.json")
arg_list = [uuidsentinel.vnf_pm_threshold_id, param_file]
verify_list = [
('vnf_pm_threshold_id', uuidsentinel.vnf_pm_threshold_id),
('request_file', param_file)
]
# command param
parsed_args = self.check_parser(
self.update_vnf_pm_threshold, arg_list, verify_list)
url = os.path.join(
self.url, 'vnfpm/v2/thresholds',
uuidsentinel.vnf_pm_threshold_id)
self.requests_mock.register_uri(
'PATCH', url, headers=self.header, status_code=404, json={})
self.assertRaises(exceptions.TackerClientException,
self.update_vnf_pm_threshold.take_action,
parsed_args)
class TestDeleteVnfPmThreshold(TestVnfPmThreshold):
def setUp(self):
super(TestDeleteVnfPmThreshold, self).setUp()
self.delete_vnf_pm_threshold = vnfpm_threshold.DeleteVnfPmThreshold(
self.app, self.app_args, cmd_name='vnfpm threshold delete')
# Vnf Pm threshold to delete
self.vnf_pm_thresholds = (
vnfpm_threshold_fakes.create_vnf_pm_thresholds(count=3))
def _mock_request_url_for_delete(self, index):
url = os.path.join(self.url, 'vnfpm/v2/thresholds',
self.vnf_pm_thresholds[index]['id'])
self.requests_mock.register_uri('DELETE', url,
headers=self.header, json={})
def test_delete_one_vnf_pm_threshold(self):
arg_list = [self.vnf_pm_thresholds[0]['id']]
verify_list = [('vnf_pm_threshold_id',
[self.vnf_pm_thresholds[0]['id']])]
parsed_args = self.check_parser(self.delete_vnf_pm_threshold, arg_list,
verify_list)
self._mock_request_url_for_delete(0)
sys.stdout = buffer = StringIO()
result = self.delete_vnf_pm_threshold.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual(
(f"VNF PM threshold '{self.vnf_pm_thresholds[0]['id']}' "
f"deleted successfully"), buffer.getvalue().strip())
def test_delete_multiple_vnf_pm_threshold(self):
arg_list = []
for obj in self.vnf_pm_thresholds:
arg_list.append(obj['id'])
verify_list = [('vnf_pm_threshold_id', arg_list)]
parsed_args = self.check_parser(self.delete_vnf_pm_threshold, arg_list,
verify_list)
for i in range(0, len(self.vnf_pm_thresholds)):
self._mock_request_url_for_delete(i)
sys.stdout = buffer = StringIO()
result = self.delete_vnf_pm_threshold.take_action(parsed_args)
self.assertIsNone(result)
self.assertEqual('All specified VNF PM thresholds are deleted '
'successfully', buffer.getvalue().strip())
def test_delete_multiple_vnf_pm_threshold_exception(self):
arg_list = [
self.vnf_pm_thresholds[0]['id'],
'xxxx-yyyy-zzzz',
self.vnf_pm_thresholds[1]['id'],
]
verify_list = [('vnf_pm_threshold_id', arg_list)]
parsed_args = self.check_parser(self.delete_vnf_pm_threshold,
arg_list, verify_list)
self._mock_request_url_for_delete(0)
url = os.path.join(self.url, 'vnfpm/v2/thresholds',
'xxxx-yyyy-zzzz')
self.requests_mock.register_uri(
'GET', url, exc=exceptions.ConnectionFailed)
self._mock_request_url_for_delete(1)
exception = self.assertRaises(exceptions.CommandError,
self.delete_vnf_pm_threshold.take_action,
parsed_args)
self.assertEqual(
f'Failed to delete 1 of {len(self.vnf_pm_thresholds)} '
'VNF PM thresholds.', exception.message)

View File

@@ -0,0 +1,127 @@
# Copyright (C) 2022 Fujitsu
# 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 oslo_utils import uuidutils
from tackerclient.osc import utils as tacker_osc_utils
def create_vnf_fm_alarms(count=2):
"""Create multiple fake vnf packages.
:param int count:
The number of vnf_fm_alarms to fake
:return:
A list of fake vnf fm alarms dictionary
"""
vnf_fm_alarms = []
for i in range(0, count):
unique_id = uuidutils.generate_uuid()
vnf_fm_alarms.append(vnf_fm_alarm_response(attrs={'id': unique_id}))
return vnf_fm_alarms
def vnf_fm_alarm_response(attrs=None, action=None):
"""Create a fake vnf fm alarm.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A FakeVnfFmAlarm dict
"""
if action == 'update':
fake_vnf_fm_alarm = {
"ackState": "UNACKNOWLEDGED"
}
return fake_vnf_fm_alarm
attrs = attrs or {}
# Set default attributes.
fake_vnf_fm_alarm = {
"id": "78a39661-60a8-4824-b989-88c1b0c3534a",
"managedObjectId": "c61314d0-f583-4ab3-a457-46426bce02d3",
"vnfcInstanceIds": "0e5f3086-4e79-47ed-a694-54c29155fa26",
"rootCauseFaultyResource": {
"faultyResource": {
"vimConnectionId": "0d57e928-86a4-4445-a4bd-1634edae73f3",
"resourceId": "4e6ccbe1-38ec-4b1b-a278-64de09ba01b3",
"vimLevelResourceType": "OS::Nova::Server"
},
"faultyResourceType": "COMPUTE"
},
"alarmRaisedTime": "2021-09-03 10:21:03",
"alarmChangedTime": "2021-09-04 10:21:03",
"alarmClearedTime": "2021-09-05 10:21:03",
"alarmAcknowledgedTime": "2021-09-06 10:21:03",
"ackState": "UNACKNOWLEDGED",
"perceivedSeverity": "WARNING",
"eventTime": "2021-09-07 10:06:03",
"eventType": "EQUIPMENT_ALARM",
"faultType": "Fault Type",
"probableCause": "The server cannot be connected.",
"isRootCause": False,
"correlatedAlarmIds": [
"c88b624e-e997-4b17-b674-10ca2bab62e0",
"c16d41fd-12e2-49a6-bb17-72faf702353f"
],
"faultDetails": [
"Fault",
"Details"
],
"_links": {
"self": {
"href": "/vnffm/v1/alarms/"
"78a39661-60a8-4824-b989-88c1b0c3534a"
},
"objectInstance": {
"href": "/vnflcm/v1/vnf_instances/"
"0e5f3086-4e79-47ed-a694-54c29155fa26"
}
}
}
# Overwrite default attributes.
fake_vnf_fm_alarm.update(attrs)
return fake_vnf_fm_alarm
def get_vnffm_alarm_data(vnf_fm_alarm, columns=None):
"""Get the vnffm alarm.
:return:
A tuple object sorted based on the name of the columns.
"""
complex_attributes = [
'vnfcInstanceIds',
'rootCauseFaultyResource',
'correlatedAlarmIds',
'faultDetails',
'_links'
]
for attribute in complex_attributes:
if vnf_fm_alarm.get(attribute):
vnf_fm_alarm.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
vnf_fm_alarm[attribute])})
# return the list of data as per column order
if columns:
return tuple([vnf_fm_alarm[key] for key in columns])
return tuple([vnf_fm_alarm[key] for key in sorted(
vnf_fm_alarm.keys())])

View File

@@ -0,0 +1,127 @@
# Copyright (C) 2022 Fujitsu
# 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 oslo_utils import uuidutils
from tackerclient.osc import utils as tacker_osc_utils
def create_vnf_fm_subs(count=2):
"""Create multiple fake vnf packages.
:param int count:
The number of vnf_fm_subs to fake
:return:
A list of fake vnf fm subs dictionary
"""
vnf_fm_subs = []
for i in range(0, count):
unique_id = uuidutils.generate_uuid()
vnf_fm_subs.append(vnf_fm_sub_response(attrs={'id': unique_id}))
return vnf_fm_subs
def vnf_fm_sub_response(attrs=None):
"""Create a fake vnf fm sub.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A FakeVnfFmAlarm dict
"""
attrs = attrs or {}
# Set default attributes.
fake_vnf_fm_sub = {
"id": "78a39661-60a8-4824-b989-88c1b0c3534a",
"filter": {
"vnfInstanceSubscriptionFilter": {
"vnfdIds": [
"dummy-vnfdId-1"
],
"vnfProductsFromProviders": [
{
"vnfProvider": "dummy-vnfProvider-1",
"vnfProducts": [
{
"vnfProductName": "dummy-vnfProductName-1-1",
"versions": [
{
"vnfSoftwareVersion": 1.0,
"vnfdVersions": [1.0, 2.0]
}
]
}
]
}
],
"vnfInstanceIds": [
"dummy-vnfInstanceId-1"
],
"vnfInstanceNames": [
"dummy-vnfInstanceName-1"
]
},
"notificationTypes": [
"AlarmNotification"
],
"faultyResourceTypes": [
"COMPUTE"
],
"perceivedSeverities": [
"WARNING"
],
"eventTypes": [
"EQUIPMENT_ALARM"
],
"probableCauses": [
"The server cannot be connected."
]
},
"callbackUri": "/nfvo/notify/alarm",
"_links": {
"self": {
"href": "/vnffm/v1/subscriptions/"
"78a39661-60a8-4824-b989-88c1b0c3534a"
}
}
}
# Overwrite default attributes.
fake_vnf_fm_sub.update(attrs)
return fake_vnf_fm_sub
def get_vnffm_sub_data(vnf_fm_sub, columns=None):
"""Get the vnffm sub.
:return:
A tuple object sorted based on the name of the columns.
"""
complex_attributes = ['filter', '_links']
for attribute in complex_attributes:
if vnf_fm_sub.get(attribute):
vnf_fm_sub.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
vnf_fm_sub[attribute])})
# return the list of data as per column order
if columns:
return tuple([vnf_fm_sub[key] for key in columns])
return tuple([vnf_fm_sub[key] for key in sorted(
vnf_fm_sub.keys())])

View File

@@ -0,0 +1,134 @@
# Copyright (C) 2022 Fujitsu
# 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 oslo_utils import uuidutils
from tackerclient.osc import utils as tacker_osc_utils
def create_vnf_pm_jobs(count=2):
"""Create multiple fake vnf pm jobs.
:param int count:
The number of vnf_pm_jobs to fake
:return:
A list of fake vnf pm jobs dictionary
"""
vnf_pm_jobs = []
for i in range(0, count):
unique_id = uuidutils.generate_uuid()
vnf_pm_jobs.append(vnf_pm_job_response(attrs={'id': unique_id}))
return {'vnf_pm_jobs': vnf_pm_jobs}
def vnf_pm_job_response(attrs=None, action=None):
"""Create a fake vnf pm job.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A pm job dict
"""
if action == 'update':
fake_vnf_pm_job = {
"callbackUri": "/nfvo/notify/job",
"authentication": {
"authType": [
"BASIC",
"OAUTH2_CLIENT_CREDENTIALS"
],
"paramsBasic": {
"userName": "nfvo",
"password": "nfvopwd"
},
"paramsOauth2ClientCredentials": {
"clientId": "auth_user_name",
"clientPassword": "auth_password",
"tokenEndpoint": "token_endpoint"
}
}
}
return fake_vnf_pm_job
attrs = attrs or {}
# Set default attributes.
fake_vnf_pm_job = {
"id": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d",
"objectType": "VNFC",
"objectInstanceIds": [
"object-instance-id-1"
],
"subObjectInstanceIds": [
"sub-object-instance-id-2"
],
"criteria": {
"performanceMetric": [
"VCpuUsageMeanVnf.object-instance-id-1"
],
"performanceMetricGroup": [
"VirtualisedComputeResource"
],
"collectionPeriod": 500,
"reportingPeriod": 1000,
"reportingBoundary": "2022/07/25 10:43:55"
},
"callbackUri": "/nfvo/notify/job",
"reports": [{
"href": "/vnfpm/v2/pm_jobs/2bb72d78-b1d9-48fe-8c64-332654ffeb5d/"
"reports/09d46aed-3ec2-45d9-bfa2-add431e069b3",
"readyTime": "2022/07/25 10:43:55",
"expiryTime": "2022/07/25 10:43:55",
"fileSize": 9999
}],
"_links": {
"self": {
"href": "/vnfpm/v2/pm_jobs/"
"78a39661-60a8-4824-b989-88c1b0c3534a"
},
"objects": [{
"href": "/vnflcm/v1/vnf_instances/"
"0e5f3086-4e79-47ed-a694-54c29155fa26"
}]
}
}
# Overwrite default attributes.
fake_vnf_pm_job.update(attrs)
return fake_vnf_pm_job
def get_vnfpm_job_data(vnf_pm_job, columns=None):
"""Get the vnfpm job.
:return:
A tuple object sorted based on the name of the columns.
"""
complex_attributes = [
'objectInstanceIds', 'subObjectInstanceIds',
'criteria', 'reports', '_links',
'authentication'
]
for attribute in complex_attributes:
if vnf_pm_job.get(attribute):
vnf_pm_job.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
vnf_pm_job[attribute])})
# return the list of data as per column order
if columns is None:
columns = sorted(vnf_pm_job.keys())
return tuple([vnf_pm_job[key] for key in columns])

View File

@@ -0,0 +1,73 @@
# Copyright (C) 2022 Fujitsu
# 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 tackerclient.osc import utils as tacker_osc_utils
def vnf_pm_report_response(attrs=None):
"""Create a fake vnf pm report.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A pm report dict
"""
attrs = attrs or {}
# Set default attributes.
fake_vnf_pm_report = {
"entries": [
{
"objectType": "VNFC",
"objectInstanceId": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d",
"subObjectInstanceId": "09d46aed-3ec2-45d9-bfa2-add431e069b3",
"performanceMetric":
"VCpuUsagePeakVnf.2bb72d78-b1d9-48fe-8c64-332654ffeb5d,",
"performanceValues": [
{
"timeStamp": "2022/07/27 08:58:58",
"value": "1.88",
"context": {
"key": "value"
}
}
]
}
]
}
# Overwrite default attributes.
fake_vnf_pm_report.update(attrs)
return fake_vnf_pm_report
def get_vnfpm_report_data(vnf_pm_report, columns=None):
"""Get the vnfpm report.
:return:
A tuple object sorted based on the name of the columns.
"""
attribute = 'entries'
if vnf_pm_report.get(attribute):
vnf_pm_report.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
vnf_pm_report[attribute])})
# return the list of data as per column order
if columns is None:
columns = sorted(vnf_pm_report.keys())
return tuple([vnf_pm_report[key] for key in columns])

View File

@@ -0,0 +1,111 @@
# Copyright (C) 2023 Fujitsu
# 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 oslo_utils import uuidutils
from tackerclient.osc import utils as tacker_osc_utils
def create_vnf_pm_thresholds(count=2):
"""Create multiple fake vnf pm thresholds.
:param int count:
The number of vnf_pm_thresholds to fake
:return:
A list of fake vnf pm thresholds dictionary
"""
vnf_pm_thresholds = []
for _ in range(0, count):
unique_id = uuidutils.generate_uuid()
vnf_pm_thresholds.append(vnf_pm_threshold_response(
attrs={'id': unique_id}))
return vnf_pm_thresholds
def vnf_pm_threshold_response(attrs=None, action=None):
"""Create a fake vnf pm threshold.
:param Dictionary attrs:
A dictionary with all attributes
:param String action:
The operation performed on threshold
:return:
A pm threshold dict
"""
if action == 'update':
fake_vnf_pm_threshold = {
"callbackUri": "/nfvo/notify/threshold",
}
return fake_vnf_pm_threshold
attrs = attrs or {}
# Set default attributes.
fake_vnf_pm_threshold = {
"id": "2bb72d78-b1d9-48fe-8c64-332654ffeb5d",
"objectType": "Vnfc",
"objectInstanceId": "object-instance-id-1",
"subObjectInstanceIds": [
"sub-object-instance-id-2"
],
"criteria": {
"performanceMetric": "VCpuUsageMeanVnf.object-instance-id-1",
"thresholdType": "SIMPLE",
"simpleThresholdDetails": {
"thresholdValue": 500.5,
"hysteresis": 10.5
}
},
"callbackUri": "/nfvo/notify/threshold",
"_links": {
"self": {
"href": "/vnfpm/v2/thresholds/"
"78a39661-60a8-4824-b989-88c1b0c3534a"
},
"object": {
"href": "/vnflcm/v1/vnf_instances/"
"0e5f3086-4e79-47ed-a694-54c29155fa26"
}
}
}
# Overwrite default attributes.
fake_vnf_pm_threshold.update(attrs)
return fake_vnf_pm_threshold
def get_vnfpm_threshold_data(vnf_pm_threshold, columns=None):
"""Get the vnfpm threshold.
:param Dictionary vnf_pm_threshold:
A dictionary with vnf_pm_threshold
:param List columns:
A list of column names
:return:
A tuple object sorted based on the name of the columns.
"""
complex_attributes = ['subObjectInstanceIds',
'criteria', '_links', 'authentication']
for attribute in complex_attributes:
if vnf_pm_threshold.get(attribute):
vnf_pm_threshold.update(
{attribute: tacker_osc_utils.FormatComplexDataColumn(
vnf_pm_threshold[attribute])})
# return the list of data as per column order
if columns is None:
columns = sorted(vnf_pm_threshold.keys())
return tuple([vnf_pm_threshold[key] for key in columns])

View File

@@ -43,6 +43,28 @@ class TestVIMUtils(testtools.TestCase):
vim_utils.args2body_vim(config_param.copy(), vim)
self.assertEqual(expected_vim, vim)
def test_args2body_vim_extra(self):
auth_cred = {'username': sentinel.usrname1,
'password': sentinel.password1,
'user_domain_name': sentinel.user_domain.name,
'cert_verify': 'True'}
config_param = {'project_name': sentinel.prj_name,
'project_domain_name': sentinel.prj_domain_name1,
'type': 'openstack',
'extra': {'area': 'area_A@region_A'},
**auth_cred}
vim = {}
expected_vim = {'auth_cred': auth_cred,
'vim_project':
{'name': sentinel.prj_name,
'project_domain_name': sentinel.prj_domain_name1},
'type': 'openstack',
'extra': {'area': 'area_A@region_A'}}
vim_utils.args2body_vim(config_param.copy(), vim)
self.assertEqual(expected_vim, vim)
def test_args2body_kubernetes_vim(self):
config_param = {'username': sentinel.usrname1,
'password': sentinel.password1,
@@ -76,6 +98,68 @@ class TestVIMUtils(testtools.TestCase):
vim_utils.args2body_vim(config_param.copy(), vim)
self.assertEqual(expected_vim, vim)
def test_args2body_kubernetes_vim_oidc(self):
config_param = {'oidc_token_url': sentinel.oidc_token_url,
'username': sentinel.username,
'password': sentinel.password,
'client_id': sentinel.client_id,
'client_secret': sentinel.client_secret,
'ssl_ca_cert': "None",
'project_name': sentinel.prj_name,
'type': 'kubernetes'}
vim = {}
auth_cred = config_param.copy()
auth_cred.pop('project_name')
auth_cred.pop('type')
expected_vim = {'auth_cred': auth_cred,
'vim_project':
{'name': sentinel.prj_name},
'type': 'kubernetes'}
vim_utils.args2body_vim(config_param.copy(), vim)
self.assertEqual(expected_vim, vim)
def test_args2body_kubernetes_vim_extra(self):
extra_param = {
'helm_info': {
'masternode_ip': [
'192.168.10.110'
],
'masternode_username': 'helm_user',
'masternode_password': 'helm_pass'
}}
config_param = {'username': sentinel.usrname1,
'password': sentinel.password1,
'ssl_ca_cert': 'abcxyz',
'project_name': sentinel.prj_name,
'type': 'kubernetes',
'extra': extra_param}
vim = {}
auth_cred = config_param.copy()
auth_cred.pop('project_name')
auth_cred.pop('type')
auth_cred.pop('extra')
expected_vim = {'auth_cred': auth_cred,
'vim_project':
{'name': sentinel.prj_name},
'type': 'kubernetes',
'extra': extra_param}
vim_utils.args2body_vim(config_param.copy(), vim)
self.assertEqual(expected_vim, vim)
def test_args2body_kubernetes_vim_oidc_no_username(self):
config_param = {'oidc_token_url': sentinel.oidc_token_url,
'password': sentinel.password,
'client_id': sentinel.client_id,
'client_secret': sentinel.client_secret,
'ssl_ca_cert': "None",
'project_name': sentinel.prj_name,
'type': 'kubernetes'}
vim = {}
self.assertRaises(exceptions.TackerClientException,
vim_utils.args2body_vim,
config_param, vim)
def test_args2body_vim_no_project(self):
config_param = {'username': sentinel.usrname1,
'password': sentinel.password1,

View File

@@ -16,6 +16,7 @@
#
import logging
import re
import time
import requests
@@ -180,6 +181,8 @@ class ClientBase(object):
self.format = 'json'
self.action_prefix = "/v%s" % (self.version)
self.retry_interval = 1
self.rel = None
self.params = None
def _handle_fault_response(self, status_code, response_body):
# Create exception with HTTP status code and message
@@ -246,6 +249,19 @@ class ClientBase(object):
else:
self.format = 'json'
url = None
rel = None
link = resp.headers.get('Link', None)
if link is not None:
url = re.findall('<(.*)>', link)[0]
rel = re.findall('rel="(.*)"', link)[0]
if rel == 'next':
self.rel = 'next'
query_str = urlparse.urlparse(url).query
self.params = urlparse.parse_qs(query_str)
status_code = resp.status_code
if status_code in (requests.codes.ok,
requests.codes.created,
@@ -379,21 +395,23 @@ class ClientBase(object):
linkrel = 'next'
next = True
while next:
self.rel = None
res = self.get(path, headers=headers, params=params)
yield res
next = False
try:
# TODO(tpatil): Handle pagination for list data type
# once it's supported by tacker.
if type(res) is list:
break
for link in res['%s_links' % collection]:
if link['rel'] == linkrel:
query_str = urlparse.urlparse(link['href']).query
params = urlparse.parse_qs(query_str)
if self.rel == 'next':
params = self.params
next = True
break
else:
for link in res['%s_links' % collection]:
if link['rel'] == linkrel:
query_str = urlparse.urlparse(link['href']).query
params = urlparse.parse_qs(query_str)
next = True
break
except KeyError:
break
@@ -895,6 +913,10 @@ class VnfLCMClient(ClientBase):
'/vnflcm/{}/vnf_lcm_op_occs'.format(sol_api_version))
self.vnf_lcm_op_occs_path = (
'/vnflcm/{}/vnf_lcm_op_occs/%s'.format(sol_api_version))
self.lccn_subscriptions_path = (
'/vnflcm/{}/subscriptions'.format(sol_api_version))
self.lccn_subscription_path = (
'/vnflcm/{}/subscriptions/%s'.format(sol_api_version))
def build_action(self, action):
return action
@@ -951,6 +973,11 @@ class VnfLCMClient(ClientBase):
return self.post((self.vnf_lcm_op_occs_path + "/rollback") % occ_id,
headers=self.headers)
@APIParamsCall
def cancel_vnf_instance(self, occ_id, body):
return self.post((self.vnf_lcm_op_occs_path + "/cancel") % occ_id,
body=body)
@APIParamsCall
def fail_vnf_instance(self, occ_id):
return self.post((self.vnf_lcm_op_occs_path + "/fail") % occ_id,
@@ -961,6 +988,15 @@ class VnfLCMClient(ClientBase):
return self.post((self.vnf_instance_path + "/change_ext_conn") %
vnf_id, body=body, headers=self.headers)
@APIParamsCall
def change_vnfpkg_vnf_instance(self, vnf_id, body):
# NOTE: it is only supported by V2-API.
if self.vnf_instance_path.split('/')[2] == 'v2':
return self.post((self.vnf_instance_path + "/change_vnfpkg") %
vnf_id, body=body, headers=self.headers)
else:
raise exceptions.UnsupportedCommandVersion(version='1')
@APIParamsCall
def retry_vnf_instance(self, occ_id):
return self.post((self.vnf_lcm_op_occs_path + "/retry") % occ_id,
@@ -978,6 +1014,28 @@ class VnfLCMClient(ClientBase):
return self.get(self.vnf_lcm_op_occs_path % occ_id,
headers=self.headers)
@APIParamsCall
def create_lccn_subscription(self, body):
return self.post(self.lccn_subscriptions_path, body=body,
headers=self.headers)
@APIParamsCall
def delete_lccn_subscription(self, subsc_id):
return self.delete(self.lccn_subscription_path % subsc_id,
headers=self.headers)
@APIParamsCall
def list_lccn_subscriptions(self, retrieve_all=True, **_params):
subscriptions = self.list(None, self.lccn_subscriptions_path,
retrieve_all, headers=self.headers,
**_params)
return subscriptions
@APIParamsCall
def show_lccn_subscription(self, subsc_id):
return self.get(self.lccn_subscription_path % subsc_id,
headers=self.headers)
@APIParamsCall
def show_vnf_lcm_versions(self, major_version):
if major_version is None:
@@ -991,6 +1049,132 @@ class VnfLCMClient(ClientBase):
return self.get(path, headers={'Version': '2.0.0'})
class VnfFMClient(ClientBase):
headers = {'Version': '1.3.0'}
vnf_fm_alarms_path = '/vnffm/v1/alarms'
vnf_fm_alarm_path = '/vnffm/v1/alarms/%s'
vnf_fm_subs_path = '/vnffm/v1/subscriptions'
vnf_fm_sub_path = '/vnffm/v1/subscriptions/%s'
def build_action(self, action):
return action
@APIParamsCall
def list_vnf_fm_alarms(self, retrieve_all=True, **_params):
vnf_fm_alarms = self.list(
"vnf_fm_alarms", self.vnf_fm_alarms_path, retrieve_all,
headers=self.headers, **_params)
return vnf_fm_alarms
@APIParamsCall
def show_vnf_fm_alarm(self, vnf_fm_alarm_id):
return self.get(
self.vnf_fm_alarm_path % vnf_fm_alarm_id, headers=self.headers)
@APIParamsCall
def update_vnf_fm_alarm(self, vnf_fm_alarm_id, body):
return self.patch(
self.vnf_fm_alarm_path % vnf_fm_alarm_id, body=body,
headers=self.headers)
@APIParamsCall
def create_vnf_fm_sub(self, body):
return self.post(
self.vnf_fm_subs_path, body=body, headers=self.headers)
@APIParamsCall
def list_vnf_fm_subs(self, retrieve_all=True, **_params):
vnf_fm_subs = self.list("vnf_fm_subs", self.vnf_fm_subs_path,
retrieve_all, headers=self.headers, **_params)
return vnf_fm_subs
@APIParamsCall
def show_vnf_fm_sub(self, vnf_fm_sub_id):
return self.get(
self.vnf_fm_sub_path % vnf_fm_sub_id, headers=self.headers)
@APIParamsCall
def delete_vnf_fm_sub(self, vnf_fm_sub_id):
return self.delete(
self.vnf_fm_sub_path % vnf_fm_sub_id, headers=self.headers)
class VnfPMClient(ClientBase):
headers = {'Version': '2.1.0'}
vnf_pm_jobs_path = '/vnfpm/v2/pm_jobs'
vnf_pm_job_path = '/vnfpm/v2/pm_jobs/%s'
vnf_pm_reports_path = '/vnfpm/v2/pm_jobs/%(job_id)s/reports/%(report_id)s'
vnf_pm_thresholds_path = '/vnfpm/v2/thresholds'
vnf_pm_threshold_path = '/vnfpm/v2/thresholds/%s'
def build_action(self, action):
return action
@APIParamsCall
def create_vnf_pm_job(self, body):
return self.post(
self.vnf_pm_jobs_path, body=body, headers=self.headers)
@APIParamsCall
def list_vnf_pm_jobs(self, retrieve_all=True, **_params):
vnf_pm_jobs = self.list(
"vnf_pm_jobs", self.vnf_pm_jobs_path, retrieve_all,
headers=self.headers, **_params)
return vnf_pm_jobs
@APIParamsCall
def show_vnf_pm_job(self, vnf_pm_job_id):
return self.get(
self.vnf_pm_job_path % vnf_pm_job_id, headers=self.headers)
@APIParamsCall
def update_vnf_pm_job(self, vnf_pm_job_id, body):
return self.patch(
self.vnf_pm_job_path % vnf_pm_job_id, body=body,
headers=self.headers)
@APIParamsCall
def delete_vnf_pm_job(self, vnf_pm_job_id):
return self.delete(
self.vnf_pm_job_path % vnf_pm_job_id, headers=self.headers)
@APIParamsCall
def show_vnf_pm_report(self, vnf_pm_job_id, vnf_pm_report_id):
return self.get(
self.vnf_pm_reports_path % {
'job_id': vnf_pm_job_id, 'report_id': vnf_pm_report_id
}, headers=self.headers)
@APIParamsCall
def create_vnf_pm_threshold(self, body):
return self.post(
self.vnf_pm_thresholds_path, body=body, headers=self.headers)
@APIParamsCall
def list_vnf_pm_thresholds(self, retrieve_all=True, **_params):
return self.list(
"vnf_pm_thresholds", self.vnf_pm_thresholds_path, retrieve_all,
headers=self.headers, **_params)
@APIParamsCall
def show_vnf_pm_threshold(self, vnf_pm_threshold_id):
return self.get(
self.vnf_pm_threshold_path % vnf_pm_threshold_id,
headers=self.headers)
@APIParamsCall
def update_vnf_pm_threshold(self, vnf_pm_threshold_id, body):
return self.patch(
self.vnf_pm_threshold_path % vnf_pm_threshold_id, body=body,
headers=self.headers)
@APIParamsCall
def delete_vnf_pm_threshold(self, vnf_pm_threshold_id):
return self.delete(
self.vnf_pm_threshold_path % vnf_pm_threshold_id,
headers=self.headers)
class Client(object):
"""Unified interface to interact with multiple applications of tacker service.
@@ -1013,6 +1197,8 @@ class Client(object):
def __init__(self, **kwargs):
api_version = kwargs.pop('api_version', '1')
self.vnf_lcm_client = VnfLCMClient(api_version, **kwargs)
self.vnf_fm_client = VnfFMClient(**kwargs)
self.vnf_pm_client = VnfPMClient(**kwargs)
self.vnf_package_client = VnfPackageClient(**kwargs)
self.legacy_client = LegacyClient(**kwargs)
@@ -1267,6 +1453,9 @@ class Client(object):
def change_ext_conn_vnf_instance(self, vnf_id, body):
return self.vnf_lcm_client.change_ext_conn_vnf_instance(vnf_id, body)
def change_vnfpkg_vnf_instance(self, vnf_id, body):
return self.vnf_lcm_client.change_vnfpkg_vnf_instance(vnf_id, body)
def delete_vnf_instance(self, vnf_id):
return self.vnf_lcm_client.delete_vnf_instance(vnf_id)
@@ -1276,6 +1465,9 @@ class Client(object):
def rollback_vnf_instance(self, occ_id):
return self.vnf_lcm_client.rollback_vnf_instance(occ_id)
def cancel_vnf_instance(self, occ_id, body):
return self.vnf_lcm_client.cancel_vnf_instance(occ_id, body)
def fail_vnf_instance(self, occ_id):
return self.vnf_lcm_client.fail_vnf_instance(occ_id)
@@ -1304,5 +1496,82 @@ class Client(object):
def show_vnf_lcm_op_occs(self, occ_id):
return self.vnf_lcm_client.show_vnf_lcm_op_occs(occ_id)
def create_lccn_subscription(self, body):
return self.vnf_lcm_client.create_lccn_subscription(body)
def delete_lccn_subscription(self, subsc_id):
return self.vnf_lcm_client.delete_lccn_subscription(subsc_id)
def list_lccn_subscriptions(self, retrieve_all=True, **_params):
return self.vnf_lcm_client.list_lccn_subscriptions(
retrieve_all=retrieve_all, **_params)
def show_lccn_subscription(self, subsc_id):
return self.vnf_lcm_client.show_lccn_subscription(subsc_id)
def show_vnf_lcm_versions(self, major_version):
return self.vnf_lcm_client.show_vnf_lcm_versions(major_version)
# VnfFMClient methods.
def list_vnf_fm_alarms(self, retrieve_all=True, **_params):
return self.vnf_fm_client.list_vnf_fm_alarms(
retrieve_all=retrieve_all, **_params)
def show_vnf_fm_alarm(self, vnf_fm_alarm_id):
return self.vnf_fm_client.show_vnf_fm_alarm(vnf_fm_alarm_id)
def update_vnf_fm_alarm(self, vnf_fm_alarm_id, body):
return self.vnf_fm_client.update_vnf_fm_alarm(vnf_fm_alarm_id, body)
def create_vnf_fm_sub(self, body):
return self.vnf_fm_client.create_vnf_fm_sub(body)
def list_vnf_fm_subs(self, retrieve_all=True, **_params):
return self.vnf_fm_client.list_vnf_fm_subs(
retrieve_all=retrieve_all, **_params)
def show_vnf_fm_sub(self, vnf_fm_sub_id):
return self.vnf_fm_client.show_vnf_fm_sub(vnf_fm_sub_id)
def delete_vnf_fm_sub(self, vnf_fm_sub_id):
return self.vnf_fm_client.delete_vnf_fm_sub(vnf_fm_sub_id)
# VnfPMClient methods.
def create_vnf_pm_job(self, body):
return self.vnf_pm_client.create_vnf_pm_job(body)
def list_vnf_pm_jobs(self, retrieve_all=True, **_params):
return self.vnf_pm_client.list_vnf_pm_jobs(
retrieve_all=retrieve_all, **_params)
def show_vnf_pm_job(self, vnf_pm_job_id):
return self.vnf_pm_client.show_vnf_pm_job(vnf_pm_job_id)
def update_vnf_pm_job(self, vnf_pm_job_id, body):
return self.vnf_pm_client.update_vnf_pm_job(vnf_pm_job_id, body)
def delete_vnf_pm_job(self, vnf_pm_job_id):
return self.vnf_pm_client.delete_vnf_pm_job(vnf_pm_job_id)
def show_vnf_pm_report(self, vnf_pm_job_id, vnf_pm_report_id):
return self.vnf_pm_client.show_vnf_pm_report(
vnf_pm_job_id, vnf_pm_report_id)
def create_vnf_pm_threshold(self, body):
return self.vnf_pm_client.create_vnf_pm_threshold(body)
def list_vnf_pm_thresholds(self, retrieve_all=True, **_params):
return self.vnf_pm_client.list_vnf_pm_thresholds(
retrieve_all=retrieve_all, **_params)
def show_vnf_pm_threshold(self, vnf_pm_threshold_id):
return self.vnf_pm_client.show_vnf_pm_threshold(vnf_pm_threshold_id)
def update_vnf_pm_threshold(self, vnf_pm_threshold_id, body):
return self.vnf_pm_client.update_vnf_pm_threshold(
vnf_pm_threshold_id, body)
def delete_vnf_pm_threshold(self, vnf_pm_threshold_id):
return self.vnf_pm_client.delete_vnf_pm_threshold(vnf_pm_threshold_id)

13
tox.ini
View File

@@ -1,7 +1,6 @@
[tox]
envlist = py38,py36,pep8,docs
envlist = py39,py38,py36,pep8,docs
minversion = 3.18.0
skipsdist = True
ignore_basepython_conflict = True
[testenv]
@@ -12,7 +11,7 @@ setenv = VIRTUAL_ENV={envdir}
LC_ALL=C
usedevelop = True
deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2023.1}
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = stestr run --slowest {posargs}
@@ -30,7 +29,7 @@ commands = sphinx-build -W -b html doc/source doc/build/html
[testenv:releasenotes]
deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2023.1}
-r{toxinidir}/doc/requirements.txt
commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
@@ -52,9 +51,3 @@ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools
# F821 undefined name 'unicode'
# if isinstance(config, str) or isinstance(config, unicode):
builtins = unicode
[testenv:lower-constraints]
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt