Compare commits

...

108 Commits
0.4.0 ... 0.8.0

Author SHA1 Message Date
Jenkins
dbc71552f2 Merge "Implement client support for NSD" 2017-01-04 09:18:00 +00:00
Bharath Thiruveedula
1cf8ceb72e Implement client support for NSD
Change-Id: I5653f3bb627b81dfe356e2192c71b13c6cfe6924
Partially-implements: blueprint nsd-support
Co-Authored-By: Dharmendra Kushwaha<dharmendra.kushwaha@nectechnologies.in>
2017-01-04 13:30:18 +05:30
Jenkins
a6a2fa0975 Merge "Support parameter input for vnffg template" 2017-01-03 21:42:24 +00:00
Jenkins
b40c5930d5 Merge "Add Constraints support" 2016-12-23 23:13:06 +00:00
Jenkins
69009d6dad Merge "Remove passing infra and mgmt driver from client" 2016-12-23 01:23:25 +00:00
Jenkins
3b99b49852 Merge "Replaced e.message with str(e)" 2016-12-23 01:22:51 +00:00
gecong1973
3f7cc06aff Replaced e.message with str(e)
For logging the exception message: e.message has been
deprecated. The preferred way is to call str(e).
more details:
https://www.python.org/dev/peps/pep-0352/

Change-Id: Ic22fbd37376843f714d2c1669d2cdc25a3569225
2016-12-23 00:58:02 +00:00
venkatamahesh
d90dac82ca Support parameter input for vnffg template
Change-Id: I93819ff19ae91ca5e24778e220d3d09b63532ddf
Implements: blueprint vnffgd-param-support
2016-12-21 17:19:37 +05:30
Tony Breeds
64e41e103d Add Constraints support
Adding constraints support to libraries is slightly more complex than
services as the libraries themselves are listed in upper-constraints.txt
which leads to errors that you can't install a specific version and a
constrained version.

This change adds constraints support by also adding a helper script to
edit the constraints to remove python-tackerclient.

Change-Id: Ibf4801a72637840cc5f908c4938c5d95077ef9d7
2016-12-21 13:29:52 +11:00
Jenkins
6944ea0405 Merge "Add stevedore to requirements" 2016-12-21 01:57:52 +00:00
Jenkins
592f7d22b3 Merge "Fix oslo.i18n problems in python-tackerclient" 2016-12-21 01:57:51 +00:00
Jenkins
0373528ff3 Merge "Add __ne__ built-in function" 2016-12-21 01:54:07 +00:00
Janki
1e613792fd Remove passing infra and mgmt driver from client
This patch removes passing infra and mgmt driver as part of VNFD body from
client and API.

Change-Id: I4684e69b8993e6c35503317503dd73e2c13f44dd
Partial-Bug: #1630936
2016-12-20 13:25:24 +05:30
Lu lei
ef1585a024 Fix oslo.i18n problems in python-tackerclient
Help msg in tacker project should support oslo.i18n. But
tests directory faces developer, So it needn't support oslo.i18n.

Co-Authored-By: ShuYingya<yingya.shu@easystack.cn>
Change-Id: I60106b106cfd77b46663ff35a2735cfa5ea158f0
2016-12-16 18:46:50 +08:00
venkatamahesh
f673cea49c Changed the help message of --config-file parameter
In this patch the description for --config-file parameter
is modified to be more informative

Change-Id: I61213a675cbb48a89ddb0b2f66fa1bd5bfab6efa
2016-12-06 05:46:37 +00:00
Jenkins
fb1c3cd273 Merge "Usability improvements of vim-update options" 2016-12-05 20:00:10 +00:00
OpenStack Proposal Bot
10711d5b47 Updated from global requirements
Change-Id: I682279972d619c4f1a2615ed023c4b6a5507e4fd
2016-12-02 17:18:29 +00:00
Jenkins
0d941634ae Merge "Show team and repo badges on README" 2016-11-28 04:52:31 +00:00
Flavio Percoco
7617b71841 Show team and repo badges on README
This patch adds the team's and repository's badges to the README file.
The motivation behind this is to communicate the project status and
features at first glance.

For more information about this effort, please read this email thread:

http://lists.openstack.org/pipermail/openstack-dev/2016-October/105562.html

To see an example of how this would look like check:

b'https://gist.github.com/8ad887687a27a845ca0c9e13e2462d27\n'

Change-Id: I59225608c5b19443e20f9877c33de49ecf738a14
2016-11-25 13:07:03 +01:00
OpenStack Proposal Bot
33b1d3f20b Updated from global requirements
Change-Id: I9af4a8bd556aa4356d602a39462e6c83a7c0fcfc
2016-11-16 22:16:57 +00:00
howardlee
2b3b1792d5 Add __ne__ built-in function
In Python 3 __ne__ by default delegates to __eq__ and inverts the
result, but in Python 2 they urge you to define __ne__ when you define
__eq__ for it to work properly [1]. There are no implied relationships
among the comparison operators. The truth of x==y does not imply that
x!=y is false. Accordingly, when defining __eq__(), one should also
define __ne__() so that the operators will behave as expected.

[1]https://docs.python.org/2/reference/datamodel.html#object.__ne__

Change-Id: I6adceadb6e3749e34cf847654f28a3b6eea832fd
2016-11-16 16:20:29 +08:00
Naoya Harada
b45904f7a1 Usability improvements of vim-update options
Tacker CLI does not support updating name and description of VIM.
This patch introduces --name and --description options to vim-update.

Also, existing --is-default option's behavior can be improved.
Currently is_default attribute will be set to False when --is-default
is ommited, and will be set to True when --is-default is specified.
So even a user, who wants to update attributes other than is_default,
needs to be aware of current is_default setting. This patch will make
the behavior of --is-default option clearer like below:

 1.When --is-default True is specified, it'll be set to True.
 2.When --is-default False is specified, it'll be set to False.
 3.When --is-default is ommited, it will stay as-is.

In addition, --config-file should be a required option because both
server and client expect it to be given when updating VIM.

Change-Id: Ic19fb6b0efb48bc3486f94836be4f2ff35f8c84b
Partial-Bug: 1637360
2016-11-11 17:35:52 +09:00
OpenStack Proposal Bot
d26d358145 Updated from global requirements
Change-Id: Ic88221fb4f5da1db7034eac0670b852ac51c3df9
2016-11-06 02:07:31 +00:00
OpenStack Proposal Bot
8a5679c4b0 Updated from global requirements
Change-Id: Iee2abbd51fc118411d4becdb62647d7c4703416e
2016-11-02 15:40:56 +00:00
Tony Xu
bdba1b1384 Add stevedore to requirements
This module is be used in:
tackerclient/common/extension.py

Change-Id: I31e8f8de4572b3868b2ea5264c3276e15c1d62f8
Closes-Bug: #1636374
2016-10-25 13:13:28 +08:00
OpenStack Proposal Bot
ca132cbb3b Updated from global requirements
Change-Id: I50150edf94fadfc54c1421f6941b8831eca9fffd
2016-10-22 01:27:44 +00:00
Jenkins
10f286989d Merge "Using assertIsInstance() instead of assertEqual(True, isinstance())" 2016-10-18 04:08:29 +00:00
Jenkins
71312260d1 Merge "Enable release notes translation" 2016-10-17 05:38:42 +00:00
Jenkins
2a62ba447b Merge "Revert "Remove unused import library"" 2016-10-17 05:05:54 +00:00
Luka Krajger
edf203acb8 Revert "Remove unused import library"
Directive "from __future__ import print_function" is not an actual
import, but it enables print statement in py2 to behave like a real
function in py3.

This allows us to use print() function in py2/py3 compatible way.

This reverts commit 9910cbc746.

Change-Id: Ibdef82f0da42e815fd6c9ec632d0fd36c272b094
2016-10-14 09:53:53 +02:00
gong yong sheng
e3f0d522ba make python34 CI job to pass
remove _get_attr_metadata monkey_patch since it is for XML test.
remove iterkeys() call which is not py3.x compatible.

Change-Id: I46df0a3748f470521553793111a21eea72bd7663
Closes-bug: 1632714
2016-10-14 06:39:50 +00:00
Trevor McCasland
65a5198d73 mox to mock refactor
Refactoring unit tests to use mock instead of mox

other mox usages by not run test cases will be dealt with
later.

Co-Authored-By: gong yong sheng <gong.yongsheng@99cloud.net>
Co-Authored-By: Trevor McCasland <TM2086@att.com>

Change-Id: I7e42494b96f1e54f5f04534d3b453422ea1bf4ef
Partial-Bug: #1572706
2016-10-14 14:38:29 +08:00
Jenkins
f499e93fcf Merge "Remove unused cliff tablib from test requirements" 2016-10-14 06:31:30 +00:00
Jenkins
19d7cadd8e Merge "rename vm into vnfm" 2016-10-14 06:31:20 +00:00
gong yong sheng
62832b010c Remove unused cliff tablib from test requirements
Change-Id: Ief8c6c2988cccdd9442fa6c38630a126218b3fa4
Closes-bug: 1603561
2016-10-12 11:59:19 +08:00
gong yong sheng
7cbdfabc75 rename vm into vnfm
Change-Id: Ia232eeb94adb190a212e9ec766eeee6dcb63bffd
closes-bug: 1632551
2016-10-12 11:30:04 +08:00
Andreas Jaeger
6cf2973c49 Enable release notes translation
Releasenote translation publishing is being prepared. 'locale_dirs'
needs to be defined in conf.py to generate translated version of the
release notes.

Note that this repository might not get translated release notes - or
no translations at all - but we add the entry here nevertheless to
prepare for it.

Change-Id: Iec2b37e4cb673485b8d6c399ddb51d33b828f069
2016-10-06 20:52:15 +02:00
Sharat Sharma
98a6ea328a Updated home-page info with the developer documentation
Change-Id: I0b44b3a45a6461fd05d7f470a984705c7ad63577
2016-10-05 06:09:28 +00:00
OpenStack Proposal Bot
f160afac6a Updated from global requirements
Change-Id: I43f1a07ca568298f8d11ef0e842f1d7ec1658e43
2016-10-02 20:35:16 +00:00
Anh Tran
66c9b13212 Using assertIsInstance() instead of assertEqual(True, isinstance())
Change-Id: I567519f19d415a17a5253d3864031583619586b4
2016-09-30 02:49:34 +00:00
Jenkins
6c78395976 Merge "Fix cString ImportError for py34" 2016-09-30 01:49:58 +00:00
Jenkins
c2e86d3145 Merge "Remove commented out code in test_shell.py" 2016-09-30 01:48:44 +00:00
Tony Xu
c3d69c8e22 Remove commented out code in test_shell.py
TrivialFix

This is patch remove pdb in
tackerclient/tests/unit/test_shell.py

Change-Id: Ie13f931b6e914eb511cdc4a073b0577b4bab2767
2016-09-29 09:18:36 +08:00
OpenStack Proposal Bot
d763fedc3c Updated from global requirements
Change-Id: I8fb66c01de26acc7490615dc49943b14e8b32909
2016-09-28 17:01:10 +00:00
OpenStack Proposal Bot
f01c05a268 Updated from global requirements
Change-Id: Ide9f72cd4c70f393f8a31b725734b49c27068ed4
2016-09-27 10:07:53 +00:00
Lu lei
45ebce43cb Fix cString ImportError for py34
Here cString dose not exist in py3.x. This patch is used to
fix py34 gate errors.

Partial-Bug: #1612071

Change-Id: I0a36777cba8c4602c16be771956d4cd26f7e979f
2016-09-26 12:41:27 +08:00
OpenStack Proposal Bot
36b52a14a2 Updated from global requirements
Change-Id: I04c37b0b3c0bdb9fb9b2a5847a1ae1bb9b26222c
2016-09-21 06:48:57 +00:00
Jenkins
d810074cda Merge "Body can not be None while creating vnfd" 2016-09-19 04:27:42 +00:00
OpenStack Proposal Bot
e6e54b7f33 Updated from global requirements
Change-Id: Ia3268acaba6ba1985eeb95bb3d0ef73fb41a9568
2016-09-15 20:26:19 +00:00
dharmendra
cb66556390 Body can not be None while creating vnfd
Trivial Fix

Change-Id: I8b2cd1171a530c8cdd0b2a09d87a76ed1a10bd37
2016-09-12 09:17:58 +09:00
Jenkins
1612e2227c Merge "Removing test cases for already removed methods" 2016-09-09 17:47:58 +00:00
dharmendra
495ccbd2aa Add support for multi delete
Currently Tacker client support single resource(i.e VNFD, VNF or
VIM) deletion per call. With this fix, multiple VNFs, VNFDs or
VIMs can be deleted in a single client call.

Change-Id: I0819d94e14637d8e9d8a7b2afb5f948587e00ce0
2016-09-09 14:27:09 +09:00
Jenkins
d8a6fa279a Merge "Allow auth url without port for vim registration" 2016-09-08 19:05:26 +00:00
Jenkins
a624948cc8 Merge "Update reno for stable/newton" 2016-09-07 23:26:52 +00:00
Doug Hellmann
f8e1d00eb8 Update reno for stable/newton
Change-Id: I0358a6c7d753c9b2c7c2e94bc9a7036adbe05901
2016-09-07 16:55:12 -04:00
dharmendra
95733d9eb4 Remove "else" branch in "create_vnfd" function
There is not necessary for "else" branch, so it remove.
Co-Authored-By: dharmendra kushwaha <dharmendra.kushwaha@nectechnologies.in>

Change-Id: Ic4313175518513e583795b84c2725b770eb2888f
2016-09-07 15:20:44 +00:00
gong yong sheng
3b60ab1aaa Allow auth url without port for vim registration
This patch allows vim-register command to register keystone
URL without port.

Change-Id: Ie04a0253aa3f42ef532ccf8a7bddbbd1f88e3e34
Closes-bug: 1618756
2016-08-31 17:14:27 +08:00
Jenkins
48d458d290 Merge "Modify MyURLComparator to handle deep match on URL" 2016-08-27 14:29:16 +00:00
Jenkins
32ad7f33b6 Merge "Moving test files to vm directory" 2016-08-27 14:18:08 +00:00
vish
f1eef18974 Moving test files to vm directory
This commit moves the test files from events and nfvo directory
to the vm directory. Currently tests are executed if they are in
the vm directory.

Change-Id: I7ac08fb5686597926ec3b3c62d8221abf2b0f066
Implements: blueprint: audit-support
2016-08-27 03:40:54 +00:00
OpenStack Proposal Bot
23f34cdf1a Updated from global requirements
Change-Id: I9de7f7fdc86598cfbc23a760769e4dcc806d52d7
2016-08-27 00:41:11 +00:00
Jenkins
78b0876baf Merge "cli: modify vnfd, param & config attr. to dict obj" 2016-08-26 23:33:49 +00:00
Sripriya
f6848f0f31 Modify MyURLComparator to handle deep match on URL
MyURLComparator equals method is enhanced to perfom url comparison
based on url parts such as scheme, netloc, path and query instead
of raw string comparison.

pagination methods are modified to wrap the url requests with pagination
params within MyURLComparator objects.

Change-Id: I69b835dce64d662d1af6a14556fb8281e3b04d63
Closes-Bug: #1617480
2016-08-26 16:03:27 -07:00
Jenkins
542a2bb083 Merge "Deprecate infra_driver and mgmt_driver" 2016-08-26 22:34:28 +00:00
digambar
ced23fe6ab Deprecate infra_driver and mgmt_driver
infra_driver will be automatically figured out
in the VNF instantiation based on target VIM type
mgmt_driver is specified in the TOSCA template
per-VDU and the value the client API is ignored

Both these attributes will be removed in Ocata.

Change-Id: Ic59d7f8af6e4b1a27f4125f57d8165dc1011ce9e
Closes-bug: #1524243
2016-08-26 20:26:40 +00:00
Sripriya
aa499bb5f3 Remove list_vnf_resource_pagination unit test
This patch removes the list_vnf_resource_pagination unit test
which tested the pagination support of list_vnf_resources.
Pagination support is not enabled for vnf resources and hence
removed the test case.

Change-Id: I98843a63f6566595ceeb4758926a441fff2ee0ff
2016-08-26 12:54:41 -07:00
Jenkins
c047bf9db2 Merge "Add client support for VNFFG in NFVO" 2016-08-26 17:25:42 +00:00
dharmendra
7951ebb39e Removing test cases for already removed methods
tackerclient/common/utils.py doeas not contains these methods:
  to_primitive
  loads
  dumps.
Removing related test cases

Change-Id: I73035fcd120efc09cd19c94a8fa41671c2b3a7c3
Partial-Bug: 1617157
2016-08-27 01:09:24 +09:00
xu-haiwei
882f6b6c93 Add client support for VNFFG in NFVO
Co-Authored-By: Tim Rozet <trozet@redhat.com>

implements blueprint: tacker-vnffg
Change-Id: Ic5273319a01b8003e9497fbf7f984972602c7698
2016-08-26 09:23:35 -04:00
Sripriya
ed102cac10 cli: modify vnfd, param & config attr. to dict obj
vnfd templates, parameter and config files are sent as yaml
strings in requests body to tacker server.

Change the attributes to dictionary objects. New behavior
is applicable to tosca templates only. Also, this change may mangle
the order of nodes in tosca templates. In order to address this
concern and preserve the network interfaces order in these nodes,
there will be follow on patch (on server) to addres this.

Change-Id: I05a1d60dc643dca864aff559f37491914b1fcfc3
Partial-Bug: #1591361
2016-08-26 00:57:13 -07:00
Tim Rozet
144408331e Adds client commands for listing a VNF resources
Support now for being able list sub resources of a vnf. REST path is
/vnf/<vnf_id>/resources/.  Resources will contain 'name', 'id', and
'type'.

APIImpact
Partial-Bug: 1602112

Change-Id: Ib9f0163c0c86df2a4d17630a5e6f7ca2d2fb22de
Signed-off-by: Tim Rozet <trozet@redhat.com>
2016-08-25 22:34:03 +00:00
Jenkins
7f829587b0 Merge "Revert "Creates details API to fetch VNF detials"" 2016-08-25 21:55:25 +00:00
Janki Chhatbar
cc0a66884b Revert "Creates details API to fetch VNF detials"
This reverts commit 5a1f2f5717.

Reverting in account of a new patch [1].

[1]. https://review.openstack.org/#/c/360197/

Change-Id: Iaf5f65bd20bb098120378f9b63c86b97a86df35d
2016-08-25 14:22:29 +00:00
Jenkins
7a0f627e2e Merge "Add "Description" parameter while creating VNF with CLI." 2016-08-24 21:03:57 +00:00
Janki
5a1f2f5717 Creates details API to fetch VNF detials
Created details API to fetch VNF details. This is optional
based on the --show-details flag enabled.

APIImpact
Partial-Bug: #1602112

Change-Id: I63bcf3f9ad23fbbcfdec6f72e45540ce55e6bd7c
2016-08-20 05:35:42 +05:30
Jenkins
6b677a8f38 Merge "Remove '--config' option when create/update a vim" 2016-08-18 02:59:51 +00:00
vish
647baba801 Adds audit support in client
This commit enables support in the client for the resource event
logging

Implements: blueprint: audit-support

Co-Authored-By: Kanagaraj Manickam <mkr1481@gmail.com>

Change-Id: Ia54aed6720043840b00dd2eb00ca03a2ed92da5e
Depends-On: Change-Id: Ib82be521c5aa8b627e3f34a3696b10508371d3a0
2016-08-16 22:35:03 +00:00
Jenkins
977038a0b3 Merge "VNF scaling: CLI and python client" 2016-08-16 21:28:03 +00:00
xu-haiwei
e5457e5062 Remove '--config' option when create/update a vim
When create/update a vim, only enable '--config-file' option, will
remove '--config' option.

Change-Id: I8a728134ce0229db98de10bff5f4f46e7f2a9f2c
Closes-bug: #1587216
2016-08-15 13:14:39 +00:00
OpenStack Proposal Bot
00520f74d0 Updated from global requirements
Change-Id: I99264b7f6e6211ef486b77e9dcd198d7eaa218ff
2016-08-11 18:18:28 +00:00
Manikantha Srinivas Tadi
6fecf2adf7 Add "Description" parameter while creating VNF with CLI.
Partial-Bug: #1586300

Change-Id: Ifaea2344b7f00414de743be1c035bd750e0af87b
2016-08-11 04:17:44 -04:00
Jenkins
166368b8b0 Merge "Make VNFD/VNF/VIM Name Mandatory in Tacker CLI" 2016-08-11 02:23:41 +00:00
Kanagaraj Manickam
94ccf2ded8 VNF scaling: CLI and python client
vnf-scale --vnf-name <vnf-name> --vnf-id <vnf-id>
          --scaling-policy-name <policy-name>
          --scaling-type <type>

implements:  blueprint #vnf-scaling
depends-on: Ib8cdd1295460e617806eec173e4d4ed8f35e6642

Change-Id: If88273efad41eaff466895ad7dbba6a8de31d119
2016-08-05 06:22:21 +05:30
Jenkins
eebea81587 Merge "VNFD legacy template deprecation warning" 2016-08-04 22:28:43 +00:00
Jenkins
4b7fce5642 Merge "Unified formats of log_xxx function" 2016-08-04 18:40:45 +00:00
Jenkins
1cbf0ba295 Merge "Remove discover from test-requirements" 2016-08-03 20:04:13 +00:00
Janki Chhatbar
5a9490e567 VNFD legacy template deprecation warning
Throws VNFD legacy template deprecation warning in favor of using
TOSCA templates. This is client-side patch.

Partial-Bug: #1582928
Change-Id: Ia8bed682c1724a7d0e4e6330fc99c6ff49f71388
2016-08-03 11:54:13 +05:30
OpenStack Proposal Bot
fc4772603d Updated from global requirements
Change-Id: Iaa1f5337866a6ab3390c6c0de2896e67cc901849
2016-07-29 02:35:14 +00:00
gong yong sheng
0aa7efd292 Add domain information into auth cred.
If we use v3 keystone, these information should be passed
into tacker server.

Change-Id: Ieb5612c966b2110930faac0401f5dabde064ffc1
Partial-Bug: #1603851
2016-07-28 14:06:48 +08:00
Lu lei
31626a41c4 Unified formats of log_xxx function
This patch is used to unified formats of
log_xxx function.I have founded all log_xxx
funtions of project files.Only this one is still
not the same as others. I think change this formats
may make codes more readable and uniform.

OpenStack supports translating some log levels
using separate message catalogs, when we add
Variables to Log Messages, We do not do this:
    LOG.info(_LI('some message: variable=%s') % variable)
actually, we use this style insteaded:
    LOG.info(_LI('some message: variable=%s'), variable)

Change-Id: I3fd924516969853b2b9dced7659d33cdadd8d4ad
2016-07-28 13:35:32 +08:00
Manikantha Srinivas Tadi
f4daaa09ba Make VNFD/VNF/VIM Name Mandatory in Tacker CLI
Change-Id: I7e94cc43a61fbeb2b406d1e973ca422359e761a0
Partial-Bug: #1474966
2016-07-26 00:09:58 -04:00
Jenkins
e88619e985 Merge "Transition default VIM to API and DB operation" 2016-07-25 18:05:44 +00:00
Jenkins
602c06373d Merge "Remove the mask password logic in vim list and vim show" 2016-07-23 02:31:44 +00:00
Kawaguchi Kentaro
c9ac53a722 Remove the mask password logic in vim list and vim show
In vim list and vim show command,
since hashed password masking on server-side,
the "mask_dict_password" modules are removed on client-side.

Change-Id: I463cb04696dc09157fbbc4b0bd64e66850feac84
Depends-On: Ice5c51b6a66cd27f21c144d3a672cf790e4cec41
Closes-bug: #1594495
2016-07-22 14:03:33 +09:00
Swapnil Kulkarni (coolsvap)
4197bd5356 Remove discover from test-requirements
It's only needed for python < 2.7 which is not supported

Change-Id: I5c4982787b561a988eb837fdb8caad50cf0697a3
2016-07-22 04:14:59 +00:00
Saju Madhavan
00d87bde7e Transition default VIM to API and DB operation
Set the default-vim in the tacker-db and provide
API to manage it.

Change-Id: Ie447f13c1d30e3cf5c1756c424fe60882082c211
Partial-Bug: 1592957
2016-07-20 18:27:39 +05:30
xu-haiwei
9910cbc746 Remove unused import library
TrivialFix

Change-Id: I3f75282a0b9b0493f8d0ead8092cee76824290a8
2016-07-20 01:11:11 +00:00
Jenkins
431a79ba3d Merge "remove unused LOG" 2016-07-15 13:14:13 +00:00
Jenkins
3c6f82dfaf Merge "Display Health status of VIM" 2016-07-11 19:30:22 +00:00
Jenkins
af6db3f107 Merge "Updated from global requirements" 2016-07-11 04:15:41 +00:00
Jenkins
6fd6b66466 Merge "Add .idea/ to python-tackerclient .gitignore" 2016-07-11 04:06:18 +00:00
ji-xuepeng
654ad24e3b remove unused LOG
This is to remove unused LOG to keep code clean

Change-Id: Iba4e29892f3011356ce927f73ce9f418365df609
2016-07-10 14:59:47 +08:00
OpenStack Proposal Bot
b35672be34 Updated from global requirements
Change-Id: Icfa8e264b51ffdf10e6891f40b025c5d61933002
2016-07-09 19:27:25 +00:00
Neeldhwaj Pathak
04298efa2d Add .idea/ to python-tackerclient .gitignore
Change-Id: I03c4403d6256825f6d82e81256b60d03b42c52de
2016-07-08 21:23:13 +05:30
xu-haiwei
a5ad0bc3d3 Fix ext-show command error
Currently ext-show command can not be ran correctly, because
there are duplicated arguments added to command options.

Change-Id: I36fdb3608f9976c633902bba04d61c3cd63b1b39
Closes-bug: #1595036
2016-07-08 01:14:20 +00:00
OpenStack Proposal Bot
f42187050f Updated from global requirements
Change-Id: I155f111afd011f42146b24a7591ad0452cd8ed76
2016-06-30 18:50:03 +00:00
OpenStack Proposal Bot
a4dcd7634a Updated from global requirements
Change-Id: Id797401c8b23fba00ac9c20737b5f51a51c2309f
2016-06-24 08:45:56 +00:00
Bharath Thiruveedula
c32028201f Display Health status of VIM
Change-Id: I59993e2b2187588cc216cba3d05e3da1b4f1cc2c
Closes-Bug: #1554280
Depends-On: I25beaa5e1fd2fca87503c45d720f89d6f8156622
2016-05-12 16:39:52 +05:30
47 changed files with 2230 additions and 676 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@ run_tests.log
.autogenerated
.coverage
.testrepository/
.idea/
.tox/
.venv/

View File

@@ -1 +1,10 @@
========================
Team and repository tags
========================
.. image:: http://governance.openstack.org/badges/python-tackerclient.svg
:target: http://governance.openstack.org/reference/tags/index.html
.. Change things from this point on
This is the client API library for Tacker.

View File

@@ -0,0 +1,4 @@
---
deprecations:
- infra_driver and mgmt_driver attributes in VNFD client
attribute is deprecated and will be removed in Ocata.

View File

@@ -0,0 +1,3 @@
---
features:
- Add support for multi delete feature for resources.

View File

@@ -0,0 +1,4 @@
---
features:
- Adds new CLI command 'vnf-resource-list' to view VNF
resources, such as VDU, CP, etc.

View File

@@ -0,0 +1,3 @@
---
fixes:
- Remove passing mgmt and infra driver from client.

View File

@@ -0,0 +1,3 @@
---
features:
- Made VNFD/VNF/VIM names mandatory in tacker CLI.

View File

@@ -0,0 +1,3 @@
---
features:
- Add client support for VNFFG.

View File

@@ -259,3 +259,6 @@ texinfo_documents = [
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# -- Options for Internationalization output ------------------------------
locale_dirs = ['locale/']

View File

@@ -7,3 +7,4 @@ Contents:
:maxdepth: 2
unreleased
newton

View File

@@ -0,0 +1,6 @@
===================================
Newton Series Release Notes
===================================
.. release-notes::
:branch: origin/stable/newton

View File

@@ -1,16 +1,19 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=1.6 # Apache-2.0
cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
pbr>=1.8 # Apache-2.0
cliff>=2.3.0 # Apache-2.0
iso8601>=0.1.11 # MIT
netaddr!=0.7.16,>=0.7.12 # BSD
requests>=2.10.0 # Apache-2.0
python-keystoneclient!=1.8.0,!=2.1.0,>=1.7.0 # Apache-2.0
netaddr!=0.7.16,>=0.7.13 # BSD
requests!=2.12.2,>=2.10.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
simplejson>=2.2.0 # MIT
six>=1.9.0 # MIT
stevedore>=1.17.1 # Apache-2.0
Babel>=2.3.4 # BSD
oslo.i18n>=2.1.0 # Apache-2.0
oslo.utils>=3.11.0 # Apache-2.0
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
oslo.log>=3.11.0 # Apache-2.0
oslo.utils>=3.18.0 # Apache-2.0
oslosphinx>=4.7.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0

View File

@@ -5,7 +5,7 @@ description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
home-page = http://docs.openstack.org/developer/tacker/
classifier =
Environment :: OpenStack
Intended Audience :: Developers

View File

@@ -17,15 +17,10 @@
"""Manage access to the clients, including authenticating when needed.
"""
import logging
from tackerclient import client
from tackerclient.tacker import client as tacker_client
LOG = logging.getLogger(__name__)
class ClientCache(object):
"""Descriptor class for caching created client handles."""

View File

@@ -21,10 +21,10 @@ import argparse
import logging
import os
from oslo_log import versionutils
from oslo_utils import encodeutils
from oslo_utils import importutils
import six
import six.moves.urllib.parse as urlparse
from tackerclient.common import exceptions
from tackerclient.i18n import _
@@ -174,8 +174,13 @@ def add_boolean_argument(parser, name, **kwargs):
**kwargs)
def validate_url(url):
url_parts = urlparse.urlparse(url)
if not url_parts.scheme or not url_parts.netloc or not url_parts.port:
raise exceptions.TackerClientException(message='Invalid URL')
return url_parts
def get_file_path(filename):
file_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'../%s' % filename))
return file_path
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)

View File

@@ -45,10 +45,15 @@ from tackerclient.common import exceptions as exc
from tackerclient.common import extension as client_extension
from tackerclient.common import utils
from tackerclient.i18n import _
from tackerclient.tacker.v1_0.events import events
from tackerclient.tacker.v1_0 import extension
from tackerclient.tacker.v1_0.nfvo import ns
from tackerclient.tacker.v1_0.nfvo import nsd
from tackerclient.tacker.v1_0.nfvo import vim
from tackerclient.tacker.v1_0.vm import vnf
from tackerclient.tacker.v1_0.vm import vnfd
from tackerclient.tacker.v1_0.nfvo import vnffg
from tackerclient.tacker.v1_0.nfvo import vnffgd
from tackerclient.tacker.v1_0.vnfm import vnf
from tackerclient.tacker.v1_0.vnfm import vnfd
from tackerclient.version import __version__
@@ -115,6 +120,8 @@ COMMAND_V1 = {
'vnf-delete': vnf.DeleteVNF,
'vnf-list': vnf.ListVNF,
'vnf-show': vnf.ShowVNF,
'vnf-scale': vnf.ScaleVNF,
'vnf-resource-list': vnf.ListVNFResources,
# 'vnf-config-create'
# 'vnf-config-push'
@@ -123,6 +130,44 @@ COMMAND_V1 = {
'vim-delete': vim.DeleteVIM,
'vim-list': vim.ListVIM,
'vim-show': vim.ShowVIM,
'events-list': events.ListResourceEvents,
'event-show': events.ShowEvent,
'vnf-events-list': events.ListVNFEvents,
'vim-events-list': events.ListVIMEvents,
'vnfd-events-list': events.ListVNFDEvents,
'vnffgd-create': vnffgd.CreateVNFFGD,
'vnffgd-delete': vnffgd.DeleteVNFFGD,
'vnffgd-list': vnffgd.ListVNFFGD,
'vnffgd-show': vnffgd.ShowVNFFGD,
'vnffgd-template-show': vnffgd.ShowTemplateVNFFGD,
'vnffg-create': vnffg.CreateVNFFG,
'vnffg-delete': vnffg.DeleteVNFFG,
'vnffg-list': vnffg.ListVNFFG,
'vnffg-show': vnffg.ShowVNFFG,
'vnffg-update': vnffg.UpdateVNFFG,
'nfp-list': vnffg.ListNFP,
'nfp-show': vnffg.ShowNFP,
'chain-list': vnffg.ListSFC,
'chain-show': vnffg.ShowSFC,
'classifier-list': vnffg.ListFC,
'classifier-show': vnffg.ShowFC,
'nsd-create': nsd.CreateNSD,
'nsd-list': nsd.ListNSD,
'nsd-delete': nsd.DeleteNSD,
'nsd-show': nsd.ShowNSD,
'nsd-template-show': nsd.ShowTemplateNSD,
'ns-create': ns.CreateNS,
'ns-list': ns.ListNS,
'ns-delete': ns.DeleteNS,
'ns-show': ns.ShowNS,
}
COMMANDS = {'1.0': COMMAND_V1}
@@ -296,10 +341,10 @@ class TackerShell(app.App):
'--os-project-name',
metavar='<auth-project-name>',
default=utils.env('OS_PROJECT_NAME'),
help='Another way to specify tenant name. '
'This option is mutually exclusive with '
' --os-tenant-name. '
'Defaults to env[OS_PROJECT_NAME].')
help=_('Another way to specify tenant name. '
'This option is mutually exclusive with '
' --os-tenant-name. '
'Defaults to env[OS_PROJECT_NAME].'))
parser.add_argument(
'--os_tenant_name',
@@ -315,10 +360,10 @@ class TackerShell(app.App):
'--os-project-id',
metavar='<auth-project-id>',
default=utils.env('OS_PROJECT_ID'),
help='Another way to specify tenant ID. '
'This option is mutually exclusive with '
' --os-tenant-id. '
'Defaults to env[OS_PROJECT_ID].')
help=_('Another way to specify tenant ID. '
'This option is mutually exclusive with '
' --os-tenant-id. '
'Defaults to env[OS_PROJECT_ID].'))
parser.add_argument(
'--os-username', metavar='<auth-username>',
@@ -341,8 +386,8 @@ class TackerShell(app.App):
'--os-user-domain-id',
metavar='<auth-user-domain-id>',
default=utils.env('OS_USER_DOMAIN_ID'),
help='OpenStack user domain ID. '
'Defaults to env[OS_USER_DOMAIN_ID].')
help=_('OpenStack user domain ID. '
'Defaults to env[OS_USER_DOMAIN_ID].'))
parser.add_argument(
'--os_user_domain_id',
@@ -352,8 +397,8 @@ class TackerShell(app.App):
'--os-user-domain-name',
metavar='<auth-user-domain-name>',
default=utils.env('OS_USER_DOMAIN_NAME'),
help='OpenStack user domain name. '
'Defaults to env[OS_USER_DOMAIN_NAME].')
help=_('OpenStack user domain name. '
'Defaults to env[OS_USER_DOMAIN_NAME].'))
parser.add_argument(
'--os_user_domain_name',
@@ -371,13 +416,13 @@ class TackerShell(app.App):
'--os-project-domain-id',
metavar='<auth-project-domain-id>',
default=utils.env('OS_PROJECT_DOMAIN_ID'),
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
help=_('Defaults to env[OS_PROJECT_DOMAIN_ID].'))
parser.add_argument(
'--os-project-domain-name',
metavar='<auth-project-domain-name>',
default=utils.env('OS_PROJECT_DOMAIN_NAME'),
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
help=_('Defaults to env[OS_PROJECT_DOMAIN_NAME].'))
parser.add_argument(
'--os-cert',

View File

@@ -25,7 +25,6 @@ from cliff.formatters import table
from cliff import lister
from cliff import show
from oslo_serialization import jsonutils
from oslo_utils import strutils
import six
from tackerclient.common._i18n import _
@@ -50,8 +49,10 @@ def _get_resource_plural(resource, client):
def find_resourceid_by_id(client, resource, resource_id):
resource_plural = _get_resource_plural(resource, client)
obj_lister = getattr(client, "list_%s" % resource_plural)
# perform search by id only if we are passing a valid UUID
match = re.match(UUID_PATTERN, resource_id)
if resource == 'event':
match = resource_id.isdigit() and resource_id != 0
else:
match = re.match(UUID_PATTERN, resource_id)
collection = resource_plural
if match:
data = obj_lister(id=resource_id, fields='id')
@@ -283,7 +284,7 @@ def parse_args_to_dict(values_specs):
_args = _parser.parse_args(_values_specs)
result_dict = {}
for opt in _options.iterkeys():
for opt in _options.keys():
_opt = opt.split('--', 2)[1]
_opt = _opt.replace('-', '_')
_value = getattr(_args, _opt)
@@ -386,8 +387,6 @@ class TackerCommand(command.OpenStackCommand):
def format_output_data(self, data):
# Modify data to make it more readable
if self.resource in data:
data[self.resource] = strutils.mask_dict_password(
data[self.resource])
for k, v in six.iteritems(data[self.resource]):
if isinstance(v, list):
value = '\n'.join(jsonutils.dumps(
@@ -429,7 +428,7 @@ class CreateCommand(TackerCommand, show.ShowOne):
return parser
def get_data(self, parsed_args):
self.log.debug('get_data(%s)' % parsed_args)
self.log.debug('get_data(%s)', parsed_args)
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
_extra_values = parse_args_to_dict(self.values_specs)
@@ -501,7 +500,7 @@ class UpdateCommand(TackerCommand):
class DeleteCommand(TackerCommand):
"""Delete a given resource
"""Delete given resource(s)
"""
@@ -509,34 +508,61 @@ class DeleteCommand(TackerCommand):
resource = None
log = None
allow_names = True
deleted_msg = {}
def get_parser(self, prog_name):
parser = super(DeleteCommand, self).get_parser(prog_name)
if self.allow_names:
help_str = _('ID or name of %s to delete')
help_str = _('IDs or names of %s to delete')
else:
help_str = _('ID of %s to delete')
help_str = _('IDs of %s to delete')
parser.add_argument(
'id', metavar=self.resource.upper(),
'ids', nargs='+',
metavar=self.resource.upper(),
help=help_str % self.resource)
return parser
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
failure = False
deleted_ids = []
failed_items = {}
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
obj_deleter = getattr(tacker_client,
"delete_%s" % self.resource)
if self.allow_names:
_id = find_resourceid_by_name_or_id(tacker_client, self.resource,
parsed_args.id)
for resource_id in parsed_args.ids:
try:
if self.allow_names:
_id = find_resourceid_by_name_or_id(
tacker_client, self.resource, resource_id)
else:
_id = resource_id
obj_deleter(_id)
deleted_ids.append(resource_id)
except Exception as e:
failure = True
failed_items[resource_id] = e
if failure:
msg = ''
if deleted_ids:
status_msg = self.deleted_msg.get(self.resource, 'deleted')
msg = (_('Successfully %(status_msg)s %(resource)s(s):'
' %(deleted_list)s') % {'status_msg': status_msg,
'deleted_list':
', '.join(deleted_ids),
'resource': self.resource})
err_msg = _("\n\nUnable to delete the below"
" %s(s):") % self.resource
for failed_id, error in failed_items.iteritems():
err_msg += (_('\n Cannot delete %(failed_id)s: %(error)s')
% {'failed_id': failed_id,
'error': error})
msg += err_msg
raise exceptions.CommandError(msg)
else:
_id = parsed_args.id
obj_deleter(_id)
print((_('Deleted %(resource)s: %(id)s')
% {'id': parsed_args.id,
'resource': self.resource}),
file=self.app.stdout)
print((_('All %(resource)s(s) %(msg)s successfully')
% {'msg': self.deleted_msg.get(self.resource, 'deleted'),
'resource': self.resource}))
return
@@ -649,6 +675,10 @@ class ShowCommand(TackerCommand, show.ShowOne):
log = None
allow_names = True
def get_id(self):
if self.resource:
return self.resource.upper()
def get_parser(self, prog_name):
parser = super(ShowCommand, self).get_parser(prog_name)
add_show_list_common_argument(parser)
@@ -657,7 +687,7 @@ class ShowCommand(TackerCommand, show.ShowOne):
else:
help_str = _('ID of %s to look up')
parser.add_argument(
'id', metavar=self.resource.upper(),
'id', metavar=self.get_id(),
help=help_str % self.resource)
return parser

View File

@@ -0,0 +1,65 @@
# Copyright 2016 Brocade Communications Systems Inc
# 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.tacker import v1_0 as tackerV10
_EVENT = "event"
class ListResourceEvents(tackerV10.ListCommand):
"""List events that belong to a given resource.
The supported args are --id, --resource_id, --resource_state,
--resource_type, --event_type
"""
resource = _EVENT
list_columns = ['id', 'resource_type', 'resource_id',
'resource_state', 'event_type',
'timestamp', 'event_details']
class ListVNFEvents(ListResourceEvents):
"""List events that belong to a given VNF.
The supported args are --id, --resource_id, --resource_state, --event_type
"""
resource = "vnf_event"
class ListVNFDEvents(ListResourceEvents):
"""List events that belong to a given VNFD.
The supported args are --id, --resource_id, --resource_state, --event_type
"""
resource = "vnfd_event"
class ListVIMEvents(ListResourceEvents):
"""List events that belong to a given VIM.
The supported args are --id, --resource_id, --resource_state, --event_type
"""
resource = "vim_event"
class ShowEvent(tackerV10.ShowCommand):
"""Show event given the event id."""
resource = _EVENT

View File

@@ -14,7 +14,6 @@
# under the License.
#
from tackerclient.common._i18n import _
from tackerclient.tacker import v1_0 as cmd_base
@@ -31,10 +30,5 @@ class ShowExt(cmd_base.ShowCommand):
resource = "extension"
allow_names = False
def get_parser(self, prog_name):
parser = super(ShowExt, self).get_parser(prog_name)
cmd_base.add_show_list_common_argument(parser)
parser.add_argument(
'id', metavar='EXT-ALIAS',
help=_('The extension alias'))
return parser
def get_id(self):
return 'EXT-ALIAS'

View File

@@ -0,0 +1,106 @@
# 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 yaml
from tackerclient.i18n import _
from tackerclient.tacker import v1_0 as tackerV10
_NS = 'ns'
_RESOURCE = 'resource'
class ListNS(tackerV10.ListCommand):
"""List NS that belong to a given tenant."""
resource = _NS
list_columns = ['id', 'name', 'nsd_id', 'mgmt_urls', 'status']
class ShowNS(tackerV10.ShowCommand):
"""Show information of a given NS."""
resource = _NS
class CreateNS(tackerV10.CreateCommand):
"""Create a NS."""
resource = _NS
remove_output_fields = ["attributes"]
def add_known_arguments(self, parser):
parser.add_argument(
'name', metavar='NAME', required=True,
help=_('Set a name for the NS'))
parser.add_argument(
'--description',
help=_('Set description for the NS'))
nsd_group = parser.add_mutually_exclusive_group(required=True)
nsd_group.add_argument(
'--nsd-id',
help=_('NSD ID to use as template to create NS'))
nsd_group.add_argument(
'--nsd-name',
help=_('NSD name to use as template to create NS'))
vim_group = parser.add_mutually_exclusive_group()
vim_group.add_argument(
'--vim-id',
help=_('VIM ID to use to create NS on the specified VIM'))
vim_group.add_argument(
'--vim-name',
help=_('VIM name to use to create NS on the specified VIM'))
parser.add_argument(
'--vim-region-name',
help=_('VIM Region to use to create NS on the specified VIM'))
parser.add_argument(
'--param-file',
help=_('Specify parameter yaml file'))
def args2body(self, parsed_args):
args = {'attributes': {}}
body = {self.resource: args}
if parsed_args.vim_region_name:
args.setdefault('placement_attr', {})['region_name'] = \
parsed_args.vim_region_name
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
if parsed_args.vim_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vim',
parsed_args.
vim_name)
parsed_args.vim_id = _id
if parsed_args.nsd_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'nsd',
parsed_args.
nsd_name)
parsed_args.nsd_id = _id
if parsed_args.param_file:
with open(parsed_args.param_file) as f:
param_yaml = f.read()
args['attributes']['param_values'] = yaml.load(
param_yaml, Loader=yaml.SafeLoader)
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description',
'nsd_id', 'vim_id'])
return body
class DeleteNS(tackerV10.DeleteCommand):
"""Delete given NS(s)."""
resource = _NS
deleted_msg = {'ns': 'delete initiated'}

View File

@@ -0,0 +1,85 @@
# 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 __future__ import print_function
import yaml
from oslo_serialization import jsonutils
from tackerclient.i18n import _
from tackerclient.tacker import v1_0 as tackerV10
_NSD = "nsd"
class ListNSD(tackerV10.ListCommand):
"""List NSDs that belong to a given tenant."""
resource = _NSD
list_columns = ['id', 'name', 'description']
class ShowNSD(tackerV10.ShowCommand):
"""Show information of a given NSD."""
resource = _NSD
class CreateNSD(tackerV10.CreateCommand):
"""Create a NSD."""
resource = _NSD
remove_output_fields = ["attributes"]
def add_known_arguments(self, parser):
parser.add_argument('--nsd-file', help='Specify NSD file',
required=True)
parser.add_argument(
'name', metavar='NAME',
help='Set a name for the NSD', required=True)
parser.add_argument(
'--description',
help='Set a description for the NSD')
def args2body(self, parsed_args):
body = {self.resource: {}}
nsd = None
with open(parsed_args.nsd_file) as f:
nsd = yaml.safe_load(f.read())
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description'])
if nsd:
body[self.resource]['attributes'] = {'nsd': nsd}
return body
class DeleteNSD(tackerV10.DeleteCommand):
"""Delete a given NSD."""
resource = _NSD
class ShowTemplateNSD(tackerV10.ShowCommand):
"""Show template of a given NSD."""
resource = _NSD
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
template = None
data = self.get_data(parsed_args)
try:
attributes_index = data[0].index('attributes')
attributes_json = data[1][attributes_index]
template = jsonutils.loads(attributes_json).get('nsd', None)
except (IndexError, TypeError, ValueError) as e:
self.log.debug('Data handling error: %s', str(e))
print(template or _('Unable to display NSD template!'))

View File

@@ -14,11 +14,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_utils import strutils
import yaml
from oslo_utils import strutils
from tackerclient.common import exceptions
from tackerclient.common import utils
from tackerclient.i18n import _
from tackerclient.tacker import v1_0 as tackerV10
from tackerclient.tacker.v1_0.nfvo import vim_utils
@@ -30,11 +31,7 @@ class ListVIM(tackerV10.ListCommand):
resource = _VIM
list_columns = ['id', 'tenant_id', 'name', 'type', 'description',
'auth_url', 'placement_attr', 'auth_cred']
def extend_list(self, data, parsed_args):
for index, value in enumerate(data):
data[index] = strutils.mask_dict_password(value)
'auth_url', 'placement_attr', 'auth_cred', 'status']
class ShowVIM(tackerV10.ShowCommand):
@@ -49,27 +46,28 @@ class CreateVIM(tackerV10.CreateCommand):
resource = _VIM
def add_known_arguments(self, parser):
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--config-file', help='Specify VIM specific '
'config parameters in a file')
group.add_argument('--config', help='Specify VIM config parameters '
'as a direct input')
parser.add_argument(
'--name',
help='Set a name for the VIM')
'--config-file',
required=True,
help=_('YAML file with VIM configuration parameters'))
parser.add_argument(
'name', metavar='NAME',
help=_('Set a name for the VIM'))
parser.add_argument(
'--description',
help='Set a description for the VIM')
help=_('Set a description for the VIM'))
parser.add_argument(
'--is-default',
action='store_true',
default=False,
help=_('Set as default VIM'))
def args2body(self, parsed_args):
body = {self.resource: {}}
if parsed_args.config_file:
with open(parsed_args.config_file) as f:
vim_config = f.read()
config_param = yaml.load(vim_config)
if parsed_args.config:
parsed_args.config = parsed_args.config.decode('unicode_escape')
config_param = yaml.load(parsed_args.config)
config_param = yaml.load(vim_config, Loader=yaml.SafeLoader)
vim_obj = body[self.resource]
try:
auth_url = config_param.pop('auth_url')
@@ -77,11 +75,12 @@ class CreateVIM(tackerV10.CreateCommand):
raise exceptions.TackerClientException(message='Auth URL must be '
'specified',
status_code=404)
vim_obj['auth_url'] = utils.validate_url(auth_url).geturl()
vim_obj['auth_url'] = vim_utils.validate_auth_url(auth_url).geturl()
vim_obj['type'] = config_param.pop('type', 'openstack')
vim_utils.args2body_vim(config_param, vim_obj)
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description'])
['tenant_id', 'name', 'description',
'is_default'])
return body
@@ -91,13 +90,21 @@ class UpdateVIM(tackerV10.UpdateCommand):
resource = _VIM
def add_known_arguments(self, parser):
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
parser.add_argument(
'--config-file',
help='Specify VIM specific config parameters in a file')
group.add_argument(
'--config',
help='Specify VIM config parameters as a direct input')
required=True,
help=_('YAML file with VIM configuration parameters'))
parser.add_argument(
'--name',
help=_('New name for the VIM'))
parser.add_argument(
'--description',
help=_('New description for the VIM'))
parser.add_argument(
'--is-default',
type=strutils.bool_from_string,
metavar='{True,False}',
help=_('Indicate whether the VIM is used as default'))
def args2body(self, parsed_args):
body = {self.resource: {}}
@@ -106,19 +113,18 @@ class UpdateVIM(tackerV10.UpdateCommand):
with open(parsed_args.config_file) as f:
config_yaml = f.read()
config_param = yaml.load(config_yaml)
if parsed_args.config:
parsed_args.config = parsed_args.config.decode('unicode_escape')
config_param = yaml.load(parsed_args.config)
if 'auth_url' in config_param:
raise exceptions.TackerClientException(message='Auth URL cannot '
'be updated',
status_code=404)
vim_obj = body[self.resource]
vim_utils.args2body_vim(config_param, vim_obj)
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description',
'is_default'])
return body
class DeleteVIM(tackerV10.DeleteCommand):
"""Delete a given VIM."""
"""Delete given VIM(s)."""
resource = _VIM

View File

@@ -13,7 +13,7 @@
# 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 six.moves.urllib.parse as urlparse
from tackerclient.common import exceptions
@@ -25,11 +25,22 @@ def args2body_vim(config_param, vim):
:return: vim body with args populated
"""
vim['vim_project'] = {'id': config_param.pop('project_id', ''),
'name': config_param.pop('project_name', '')}
'name': config_param.pop('project_name', ''),
'project_domain_name':
config_param.pop('project_domain_name', '')}
if not vim['vim_project']['id'] and not vim['vim_project']['name']:
raise exceptions.TackerClientException(message='Project Id or name '
'must be specified',
status_code=404)
vim['auth_cred'] = {'username': config_param.pop('username', ''),
'password': config_param.pop('password', ''),
'user_id': config_param.pop('user_id', '')}
'user_id': config_param.pop('user_id', ''),
'user_domain_name':
config_param.pop('user_domain_name', '')}
def validate_auth_url(url):
url_parts = urlparse.urlparse(url)
if not url_parts.scheme or not url_parts.netloc:
raise exceptions.TackerClientException(message='Invalid auth URL')
return url_parts

View File

@@ -0,0 +1,182 @@
# 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.i18n import _
import yaml
from tackerclient.tacker import v1_0 as tackerV10
_VNFFG = 'vnffg'
_NFP = 'nfp'
_SFC = 'sfc'
_FC = 'classifier'
class ListFC(tackerV10.ListCommand):
"""List FCs that belong to a given tenant."""
resource = _FC
list_columns = ['id', 'status', 'nfp_id', 'chain_id']
class ShowFC(tackerV10.ShowCommand):
"""Show information of a given FC."""
resource = _FC
class ListSFC(tackerV10.ListCommand):
"""List SFCs that belong to a given tenant."""
resource = _SFC
list_columns = ['id', 'status', 'nfp_id']
class ShowSFC(tackerV10.ShowCommand):
"""Show information of a given SFC."""
resource = _SFC
class ListNFP(tackerV10.ListCommand):
"""List NFPs that belong to a given tenant."""
resource = _NFP
list_columns = ['id', 'name', 'status', 'vnffg_id', 'path_id']
class ShowNFP(tackerV10.ShowCommand):
"""Show information of a given NFP."""
resource = _NFP
class ListVNFFG(tackerV10.ListCommand):
"""List VNFFGs that belong to a given tenant."""
resource = _VNFFG
list_columns = ['id', 'name', 'description', 'status', 'vnffgd_id']
class ShowVNFFG(tackerV10.ShowCommand):
"""Show information of a given VNFFG."""
resource = _VNFFG
class CreateVNFFG(tackerV10.CreateCommand):
"""Create a VNFFG."""
resource = _VNFFG
remove_output_fields = ["attributes"]
def add_known_arguments(self, parser):
parser.add_argument(
'name', metavar='NAME',
help=_('Set a name for the VNFFG'))
vnffgd_group = parser.add_mutually_exclusive_group(required=True)
vnffgd_group.add_argument(
'--vnffgd-id',
help=_('VNFFGD ID to use as template to create VNFFG'))
vnffgd_group.add_argument(
'--vnffgd-name',
help=_('VNFFGD Name to use as template to create VNFFG'))
parser.add_argument(
'--vnf-mapping',
help=_('List of logical VNFD name to VNF instance name mapping. '
'Example: VNF1:my_vnf1,VNF2:my_vnf2'))
parser.add_argument(
'--symmetrical', metavar='{True,False}',
help=_('Should a reverse path be created for the NFP'))
parser.add_argument(
'--param-file',
help='Specify parameter yaml file'
)
def args2body(self, parsed_args):
args = {'attributes': {}}
body = {self.resource: args}
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
if parsed_args.vnf_mapping:
_vnf_mapping = dict()
_vnf_mappings = parsed_args.vnf_mapping.split(",")
for mapping in _vnf_mappings:
vnfd_name, vnf = mapping.split(":", 1)
_vnf_mapping[vnfd_name] = \
tackerV10.find_resourceid_by_name_or_id(
tacker_client, 'vnf', vnf)
parsed_args.vnf_mapping = _vnf_mapping
if parsed_args.vnffgd_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vnffgd',
parsed_args.
vnffgd_name)
parsed_args.vnffgd_id = _id
if parsed_args.param_file:
with open(parsed_args.param_file) as f:
param_yaml = f.read()
args['attributes']['param_values'] = yaml.load(
param_yaml, Loader=yaml.SafeLoader)
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'vnffgd_id',
'symmetrical', 'vnf_mapping'])
return body
class UpdateVNFFG(tackerV10.UpdateCommand):
"""Update a given VNFFG."""
resource = _VNFFG
def add_known_arguments(self, parser):
parser.add_argument(
'--vnf-mapping',
help=_('List of logical VNFD name to VNF instance name mapping. '
'Example: VNF1:my_vnf1,VNF2:my_vnf2'))
parser.add_argument(
'--symmetrical', metavar='{True,False}',
help=_('Should a reverse path be created for the NFP'))
def args2body(self, parsed_args):
body = {self.resource: {}}
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
if parsed_args.vnf_mapping:
_vnf_mapping = dict()
_vnf_mappings = parsed_args.vnf_mapping.split(",")
for mapping in _vnf_mappings:
vnfd_name, vnf = mapping.split(":", 1)
_vnf_mapping[vnfd_name] = \
tackerV10.find_resourceid_by_name_or_id(
tacker_client, 'vnf', vnf)
parsed_args.vnf_mapping = _vnf_mapping
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'vnf_mapping', 'symmetrical'])
return body
class DeleteVNFFG(tackerV10.DeleteCommand):
"""Delete a given VNFFG."""
resource = _VNFFG

View File

@@ -0,0 +1,87 @@
# 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 __future__ import print_function
import yaml
from oslo_serialization import jsonutils
from tackerclient.i18n import _
from tackerclient.tacker import v1_0 as tackerV10
_VNFFGD = "vnffgd"
class ListVNFFGD(tackerV10.ListCommand):
"""List VNFFGDs that belong to a given tenant."""
resource = _VNFFGD
list_columns = ['id', 'name', 'description']
class ShowVNFFGD(tackerV10.ShowCommand):
"""Show information of a given VNFFGD."""
resource = _VNFFGD
class CreateVNFFGD(tackerV10.CreateCommand):
"""Create a VNFFGD."""
resource = _VNFFGD
remove_output_fields = ["attributes"]
def add_known_arguments(self, parser):
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--vnffgd-file', help=_('Specify VNFFGD file'))
group.add_argument('--vnffgd', help=_('Specify VNFFGD'))
parser.add_argument(
'name', metavar='NAME',
help=_('Set a name for the VNFFGD'))
parser.add_argument(
'--description',
help=_('Set a description for the VNFFGD'))
def args2body(self, parsed_args):
body = {self.resource: {}}
if parsed_args.vnffgd_file:
with open(parsed_args.vnffgd_file) as f:
vnffgd = yaml.safe_load(f.read())
body[self.resource]['template'] = {'vnffgd': vnffgd}
if parsed_args.vnffgd:
body[self.resource]['template'] = {
'vnffgd': yaml.safe_load(parsed_args.vnffgd)}
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description'])
return body
class DeleteVNFFGD(tackerV10.DeleteCommand):
"""Delete a given VNFFGD."""
resource = _VNFFGD
class ShowTemplateVNFFGD(tackerV10.ShowCommand):
"""Show template of a given VNFFGD."""
resource = _VNFFGD
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
template = None
data = self.get_data(parsed_args)
try:
attributes_index = data[0].index('attributes')
attributes_json = data[1][attributes_index]
template = jsonutils.loads(attributes_json).get('vnffgd', None)
except (IndexError, TypeError, ValueError) as e:
self.log.debug('Data handling error: %s', str(e))
print(template or _('Unable to display VNFFGD template!'))

View File

@@ -1,145 +0,0 @@
#
# Copyright 2013 Intel 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 tackerclient.tacker import v1_0 as tackerV10
_VNF = 'vnf'
class ListVNF(tackerV10.ListCommand):
"""List VNF that belong to a given tenant."""
resource = _VNF
list_columns = ['id', 'name', 'description', 'mgmt_url', 'status',
'vim_id', 'placement_attr', 'error_reason']
class ShowVNF(tackerV10.ShowCommand):
"""Show information of a given VNF."""
resource = _VNF
class CreateVNF(tackerV10.CreateCommand):
"""Create a VNF."""
resource = _VNF
remove_output_fields = ["attributes"]
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help='Set a name for the VNF')
vnfd_group = parser.add_mutually_exclusive_group(required=True)
vnfd_group.add_argument(
'--vnfd-id',
help='VNFD ID to use as template to create VNF')
vnfd_group.add_argument(
'--vnfd-name',
help='VNFD Name to use as template to create VNF')
vim_group = parser.add_mutually_exclusive_group()
vim_group.add_argument(
'--vim-id',
help='VIM ID to use to create VNF on the specified VIM')
vim_group.add_argument(
'--vim-name',
help='VIM name to use to create VNF on the specified VIM')
parser.add_argument(
'--vim-region-name',
help='VIM Region to use to create VNF on the specified VIM')
parser.add_argument(
'--config-file',
help='Specify config yaml file')
parser.add_argument(
'--config',
help='Specify config yaml data')
parser.add_argument(
'--param-file',
help='Specify parameter yaml file'
)
def args2body(self, parsed_args):
args = {'attributes': {}}
body = {self.resource: args}
# config arg passed as data overrides config yaml when both args passed
if parsed_args.config_file:
with open(parsed_args.config_file) as f:
config_yaml = f.read()
args['attributes']['config'] = config_yaml
if parsed_args.config:
parsed_args.config = parsed_args.config.decode('unicode_escape')
args['attributes']['config'] = parsed_args.config
if parsed_args.vim_region_name:
args.setdefault('placement_attr', {})['region_name'] = \
parsed_args.vim_region_name
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
if parsed_args.vim_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vim',
parsed_args.
vim_name)
parsed_args.vim_id = _id
if parsed_args.vnfd_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vnfd',
parsed_args.
vnfd_name)
parsed_args.vnfd_id = _id
if parsed_args.param_file:
with open(parsed_args.param_file) as f:
param_yaml = f.read()
args['attributes']['param_values'] = param_yaml
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'vnfd_id', 'vim_id'])
return body
class UpdateVNF(tackerV10.UpdateCommand):
"""Update a given VNF."""
resource = _VNF
def add_known_arguments(self, parser):
parser.add_argument(
'--config-file',
help='Specify config yaml file')
parser.add_argument(
'--config',
help='Specify config yaml data')
def args2body(self, parsed_args):
body = {self.resource: {}}
# config arg passed as data overrides config yaml when both args passed
if parsed_args.config_file:
with open(parsed_args.config_file) as f:
config_yaml = f.read()
body[self.resource]['attributes'] = {'config': config_yaml}
if parsed_args.config:
parsed_args.config = parsed_args.config.decode('unicode_escape')
body[self.resource]['attributes'] = {'config': parsed_args.config}
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
return body
class DeleteVNF(tackerV10.DeleteCommand):
"""Delete a given VNF."""
resource = _VNF

View File

@@ -0,0 +1,292 @@
#
# Copyright 2013 Intel 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 yaml
from tackerclient.common import utils
from tackerclient.i18n import _
from tackerclient.tacker import v1_0 as tackerV10
_VNF = 'vnf'
_RESOURCE = 'resource'
class ListVNF(tackerV10.ListCommand):
"""List VNF that belong to a given tenant."""
resource = _VNF
list_columns = ['id', 'name', 'description', 'mgmt_url', 'status',
'vim_id', 'placement_attr', 'error_reason']
class ShowVNF(tackerV10.ShowCommand):
"""Show information of a given VNF."""
resource = _VNF
class CreateVNF(tackerV10.CreateCommand):
"""Create a VNF."""
resource = _VNF
remove_output_fields = ["attributes"]
def add_known_arguments(self, parser):
parser.add_argument(
'name', metavar='NAME',
help=_('Set a name for the VNF'))
parser.add_argument(
'--description',
help=_('Set description for the VNF'))
vnfd_group = parser.add_mutually_exclusive_group(required=True)
vnfd_group.add_argument(
'--vnfd-id',
help=_('VNFD ID to use as template to create VNF'))
vnfd_group.add_argument(
'--vnfd-name',
help=_('VNFD Name to use as template to create VNF'))
vim_group = parser.add_mutually_exclusive_group()
vim_group.add_argument(
'--vim-id',
help=_('VIM ID to use to create VNF on the specified VIM'))
vim_group.add_argument(
'--vim-name',
help=_('VIM name to use to create VNF on the specified VIM'))
parser.add_argument(
'--vim-region-name',
help=_('VIM Region to use to create VNF on the specified VIM'))
parser.add_argument(
'--config-file',
help=_('YAML file with VNF configuration'))
parser.add_argument(
'--config',
help=_('Specify config yaml data'))
parser.add_argument(
'--param-file',
help=_('Specify parameter yaml file'))
def args2body(self, parsed_args):
args = {'attributes': {}}
body = {self.resource: args}
# config arg passed as data overrides config yaml when both args passed
config = None
if parsed_args.config_file:
with open(parsed_args.config_file) as f:
config_yaml = f.read()
config = yaml.load(
config_yaml, Loader=yaml.SafeLoader)
if parsed_args.config:
config = parsed_args.config
if isinstance(config, str):
config_str = parsed_args.config.decode('unicode_escape')
config = yaml.load(config_str, Loader=yaml.SafeLoader)
utils.deprecate_warning(what='yaml as string', as_of='N',
in_favor_of='yaml as dictionary')
if config:
args['attributes']['config'] = config
if parsed_args.vim_region_name:
args.setdefault('placement_attr', {})['region_name'] = \
parsed_args.vim_region_name
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
if parsed_args.vim_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vim',
parsed_args.
vim_name)
parsed_args.vim_id = _id
if parsed_args.vnfd_name:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vnfd',
parsed_args.
vnfd_name)
parsed_args.vnfd_id = _id
if parsed_args.param_file:
with open(parsed_args.param_file) as f:
param_yaml = f.read()
args['attributes']['param_values'] = yaml.load(
param_yaml, Loader=yaml.SafeLoader)
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description',
'vnfd_id', 'vim_id'])
return body
class UpdateVNF(tackerV10.UpdateCommand):
"""Update a given VNF."""
resource = _VNF
def add_known_arguments(self, parser):
parser.add_argument(
'--config-file',
help=_('YAML file with VNF configuration'))
parser.add_argument(
'--config',
help=_('Specify config yaml data'))
def args2body(self, parsed_args):
body = {self.resource: {}}
# config arg passed as data overrides config yaml when both args passed
config = None
if parsed_args.config_file:
with open(parsed_args.config_file) as f:
config_yaml = f.read()
config = yaml.load(config_yaml, Loader=yaml.SafeLoader)
if parsed_args.config:
config = parsed_args.config
if isinstance(parsed_args.config, str):
config_str = parsed_args.config.decode('unicode_escape')
config = yaml.load(config_str, Loader=yaml.SafeLoader)
utils.deprecate_warning(what='yaml as string', as_of='N',
in_favor_of='yaml as dictionary')
if config:
body[self.resource]['attributes'] = {'config': config}
tackerV10.update_dict(parsed_args, body[self.resource], ['tenant_id'])
return body
class DeleteVNF(tackerV10.DeleteCommand):
"""Delete given VNF(s)."""
resource = _VNF
deleted_msg = {'vnf': 'delete initiated'}
class ListVNFResources(tackerV10.ListCommand):
"""List resources of a VNF like VDU, CP, etc."""
list_columns = ['name', 'id', 'type']
allow_names = True
resource = _VNF
def get_id(self):
if self.resource:
return self.resource.upper()
def get_parser(self, prog_name):
parser = super(ListVNFResources, self).get_parser(prog_name)
if self.allow_names:
help_str = _('ID or name of %s to look up')
else:
help_str = _('ID of %s to look up')
parser.add_argument(
'id', metavar=self.get_id(),
help=help_str % self.resource)
return parser
def get_data(self, parsed_args):
self.log.debug('get_data(%s)', parsed_args)
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
if self.allow_names:
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
self.resource,
parsed_args.id)
else:
_id = parsed_args.id
data = self.retrieve_list_by_id(_id, parsed_args)
self.extend_list(data, parsed_args)
return self.setup_columns(data, parsed_args)
def retrieve_list_by_id(self, id, parsed_args):
"""Retrieve a list of sub resources from Tacker server"""
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
_extra_values = tackerV10.parse_args_to_dict(self.values_specs)
tackerV10._merge_args(self, parsed_args, _extra_values,
self.values_specs)
search_opts = self.args2search_opts(parsed_args)
search_opts.update(_extra_values)
if self.pagination_support:
page_size = parsed_args.page_size
if page_size:
search_opts.update({'limit': page_size})
if self.sorting_support:
keys = parsed_args.sort_key
if keys:
search_opts.update({'sort_key': keys})
dirs = parsed_args.sort_dir
len_diff = len(keys) - len(dirs)
if len_diff > 0:
dirs += ['asc'] * len_diff
elif len_diff < 0:
dirs = dirs[:len(keys)]
if dirs:
search_opts.update({'sort_dir': dirs})
obj_lister = getattr(tacker_client, "list_vnf_resources")
data = obj_lister(id, **search_opts)
return data.get('resources', [])
class ScaleVNF(tackerV10.TackerCommand):
"""Scale a VNF."""
api = 'nfv-orchestration'
resource = None
log = None
def get_parser(self, prog_name):
parser = super(ScaleVNF, self).get_parser(prog_name)
self.add_known_arguments(parser)
return parser
def run(self, parsed_args):
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
body = self.args2body(parsed_args)
obj_creator = getattr(tacker_client,
"scale_vnf")
obj_creator(body["scale"].pop('vnf_id'), body)
def add_known_arguments(self, parser):
vnf_group = parser.add_mutually_exclusive_group(required=True)
vnf_group.add_argument(
'--vnf-id',
help=_('VNF ID'))
vnf_group.add_argument(
'--vnf-name',
help=_('VNF name'))
parser.add_argument(
'--scaling-policy-name',
help=_('VNF policy name used to scale'))
parser.add_argument(
'--scaling-type',
help=_('VNF scaling type, it could be either "out" or "in"'))
def args2body(self, parsed_args):
args = {}
body = {"scale": args}
if parsed_args.vnf_name:
tacker_client = self.get_client()
tacker_client.format = parsed_args.request_format
_id = tackerV10.find_resourceid_by_name_or_id(tacker_client,
'vnf',
parsed_args.
vnf_name)
parsed_args.vnf_id = _id
args['vnf_id'] = parsed_args.vnf_id
args['type'] = parsed_args.scaling_type
args['policy'] = parsed_args.scaling_policy_name
return body

View File

@@ -18,7 +18,9 @@
from __future__ import print_function
from oslo_serialization import jsonutils
import yaml
from tackerclient.common import utils
from tackerclient.i18n import _
from tackerclient.tacker import v1_0 as tackerV10
@@ -30,7 +32,7 @@ class ListVNFD(tackerV10.ListCommand):
"""List VNFD that belong to a given tenant."""
resource = _VNFD
list_columns = ['id', 'name', 'description', 'infra_driver', 'mgmt_driver']
list_columns = ['id', 'name', 'description']
class ShowVNFD(tackerV10.ShowCommand):
@@ -47,23 +49,32 @@ class CreateVNFD(tackerV10.CreateCommand):
def add_known_arguments(self, parser):
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--vnfd-file', help='Specify VNFD file')
group.add_argument('--vnfd', help='Specify VNFD')
group.add_argument('--vnfd-file', help=_('Specify VNFD file'))
group.add_argument('--vnfd', help=_('Specify VNFD'))
parser.add_argument(
'--name',
help='Set a name for the VNFD')
'name', metavar='NAME',
help=_('Set a name for the VNFD'))
parser.add_argument(
'--description',
help='Set a description for the VNFD')
help=_('Set a description for the VNFD'))
def args2body(self, parsed_args):
body = {self.resource: {}}
vnfd = None
if parsed_args.vnfd_file:
with open(parsed_args.vnfd_file) as f:
vnfd = f.read()
body[self.resource]['attributes'] = {'vnfd': vnfd}
if "tosca_definitions_version" in vnfd:
vnfd = yaml.load(vnfd, Loader=yaml.SafeLoader)
if parsed_args.vnfd:
body[self.resource]['attributes'] = {'vnfd': parsed_args.vnfd}
vnfd = parsed_args.vnfd
if isinstance(vnfd, str):
vnfd = yaml.load(vnfd, Loader=yaml.SafeLoader)
utils.deprecate_warning(what='yaml as string',
as_of='N',
in_favor_of='yaml as dictionary')
if vnfd:
body[self.resource]['attributes'] = {'vnfd': vnfd}
tackerV10.update_dict(parsed_args, body[self.resource],
['tenant_id', 'name', 'description'])
@@ -71,7 +82,7 @@ class CreateVNFD(tackerV10.CreateCommand):
class DeleteVNFD(tackerV10.DeleteCommand):
"""Delete a given VNFD."""
"""Delete given VNFD(s)."""
resource = _VNFD

View File

@@ -17,10 +17,10 @@
import urllib
import contextlib
import cStringIO
import fixtures
import mox
import mock
import six
import six.moves.urllib.parse as urlparse
import sys
import testtools
@@ -28,6 +28,7 @@ from tackerclient.common import constants
from tackerclient.common import exceptions
from tackerclient import shell
from tackerclient.tacker import v1_0 as tackerV1_0
from tackerclient.tacker.v1_0 import TackerCommand
from tackerclient.v1_0 import client
API_VERSION = "1.0"
@@ -38,7 +39,7 @@ ENDURL = 'localurl'
@contextlib.contextmanager
def capture_std_streams():
fake_stdout, fake_stderr = cStringIO.StringIO(), cStringIO.StringIO()
fake_stdout, fake_stderr = six.StringIO(), six.StringIO()
stdout, stderr = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = fake_stdout, fake_stderr
@@ -79,13 +80,23 @@ def end_url(path, query=None, format=FORMAT):
return query and _url_str + "?" + query or _url_str
class MyUrlComparator(mox.Comparator):
class MyUrlComparator(object):
def __init__(self, lhs, client):
self.lhs = lhs
self.client = client
def equals(self, rhs):
return str(self) == rhs
lhsp = urlparse.urlparse(self.lhs)
rhsp = urlparse.urlparse(rhs)
lhs_qs = urlparse.parse_qsl(lhsp.query)
rhs_qs = urlparse.parse_qsl(rhsp.query)
return (lhsp.scheme == rhsp.scheme and
lhsp.netloc == rhsp.netloc and
lhsp.path == rhsp.path and
len(lhs_qs) == len(rhs_qs) and
set(lhs_qs) == set(rhs_qs))
def __str__(self):
if self.client and self.client.format != FORMAT:
@@ -104,7 +115,7 @@ class MyUrlComparator(mox.Comparator):
return str(self)
class MyComparator(mox.Comparator):
class MyComparator(object):
def __init__(self, lhs, client):
self.lhs = lhs
self.client = client
@@ -155,6 +166,12 @@ class MyComparator(mox.Comparator):
return self.client.serialize(self.lhs)
return str(self.lhs)
def __eq__(self, rhs):
return self.equals(rhs)
def __ne__(self, rhs):
return not self.__eq__(rhs)
class CLITestV10Base(testtools.TestCase):
@@ -165,14 +182,6 @@ class CLITestV10Base(testtools.TestCase):
def _find_resourceid(self, client, resource, name_or_id):
return name_or_id
def _get_attr_metadata(self):
return self.metadata
client.Client.EXTED_PLURALS.update(constants.PLURALS)
client.Client.EXTED_PLURALS.update({'tags': 'tag'})
return {'plurals': client.Client.EXTED_PLURALS,
'xmlns': constants.XML_NS_V10,
constants.EXT_NS: {'prefix': 'http://xxxx.yy.com'}}
def setUp(self, plurals={}):
"""Prepare the test environment."""
super(CLITestV10Base, self).setUp()
@@ -182,7 +191,6 @@ class CLITestV10Base(testtools.TestCase):
'xmlns': constants.XML_NS_V10,
constants.EXT_NS: {'prefix':
'http://xxxx.yy.com'}}
self.mox = mox.Mox()
self.endurl = ENDURL
self.fake_stdout = FakeStdout()
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.fake_stdout))
@@ -192,20 +200,17 @@ class CLITestV10Base(testtools.TestCase):
self.useFixture(fixtures.MonkeyPatch(
'tackerclient.tacker.v1_0.find_resourceid_by_id',
self._find_resourceid))
self.useFixture(fixtures.MonkeyPatch(
'tackerclient.v1_0.client.Client.get_attr_metadata',
self._get_attr_metadata))
self.client = client.Client(token=TOKEN, endpoint_url=self.endurl)
@mock.patch.object(TackerCommand, 'get_client')
def _test_create_resource(self, resource, cmd,
name, myid, args,
position_names, position_values, tenant_id=None,
position_names, position_values, mock_get,
tenant_id=None, get_client_called_count=1,
tags=None, admin_state_up=True, extra_body=None,
**kwargs):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
non_admin_status_resources = ['vnfd', 'vnf', 'vim']
mock_get.return_value = self.client
non_admin_status_resources = ['vnfd', 'vnf', 'vim', 'vnffgd', 'vnffg']
if (resource in non_admin_status_resources):
body = {resource: {}, }
else:
@@ -233,53 +238,56 @@ class CLITestV10Base(testtools.TestCase):
# Work around for LP #1217791. XML deserializer called from
# MyComparator does not decodes XML string correctly.
if self.format == 'json':
mox_body = MyComparator(body, self.client)
_body = MyComparator(body, self.client)
else:
mox_body = self.client.serialize(body)
self.client.httpclient.request(
end_url(path, format=self.format), 'POST',
body=mox_body,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr))
args.extend(['--request-format', self.format])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser('create_' + resource)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
_body = self.client.serialize(body)
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(200), resstr)
self.client.httpclient.request(
end_url(path, format=self.format), 'POST',
body=_body,
headers={'X-Auth-Token', TOKEN})
mock_req.assert_called_once_with(
end_url(path, format=self.format), 'POST',
body=_body,
headers={'X-Auth-Token', TOKEN})
args.extend(['--request-format', self.format])
cmd_parser = cmd.get_parser('create_' + resource)
shell.run_command(cmd, cmd_parser, args)
self.assertEqual(get_client_called_count, mock_get.call_count)
_str = self.fake_stdout.make_string()
self.assertIn(myid, _str)
if name:
self.assertIn(name, _str)
@mock.patch.object(TackerCommand, 'get_client')
def _test_list_columns(self, cmd, resources_collection,
resources_out, args=['-f', 'json']):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
resources_out, mock_get,
args=['-f', 'json']):
mock_get.return_value = self.client
self.client.format = self.format
resstr = self.client.serialize(resources_out)
path = getattr(self.client, resources_collection + "_path")
self.client.httpclient.request(
end_url(path, format=self.format), 'GET',
body=None,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr))
args.extend(['--request-format', self.format])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("list_" + resources_collection)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(200), resstr)
self.client.httpclient.request(
end_url(path, format=self.format), 'GET',
body=None,
headers={'X-Auth-Token': TOKEN})
mock_req.assert_called_once_with(
end_url(path, format=self.format), 'GET',
body=None,
headers={'X-Auth-Token': TOKEN})
args.extend(['--request-format', self.format])
cmd_parser = cmd.get_parser("list_" + resources_collection)
shell.run_command(cmd, cmd_parser, args)
mock_get.assert_called_once_with()
def _test_list_resources(self, resources, cmd, detail=False, tags=[],
fields_1=[], fields_2=[], page_size=None,
sort_key=[], sort_dir=[], response_contents=None,
base_args=None, path=None):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
if response_contents is None:
contents = [{self.id_field: 'myid1', },
{self.id_field: 'myid2', }, ]
@@ -352,147 +360,289 @@ class CLITestV10Base(testtools.TestCase):
query += 'sort_dir=%s' % dir
if path is None:
path = getattr(self.client, resources + "_path")
self.client.httpclient.request(
MyUrlComparator(end_url(path, query, format=self.format),
self.client),
'GET',
body=None,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr))
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("list_" + resources)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(200), resstr)
self.client.httpclient.request(
MyUrlComparator(end_url(path, query, format=self.format),
self.client),
'GET',
body=None,
headers={'X-Auth-Token': TOKEN})
with mock.patch.object(TackerCommand, 'get_client') as mock_get:
mock_get.return_value = self.client
cmd_parser = cmd.get_parser("list_" + resources)
shell.run_command(cmd, cmd_parser, args)
_str = self.fake_stdout.make_string()
if response_contents is None:
self.assertIn('myid1', _str)
return _str
def _test_list_resources_with_pagination(self, resources, cmd):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
path = getattr(self.client, resources + "_path")
fake_query = "marker=myid2&limit=2"
reses1 = {resources: [{'id': 'myid1', },
{'id': 'myid2', }],
'%s_links' % resources: [{'href': end_url(path, fake_query),
'rel': 'next'}]}
reses2 = {resources: [{'id': 'myid3', },
{'id': 'myid4', }]}
@mock.patch.object(TackerCommand, 'get_client')
def _test_list_sub_resources(self, resources, api_resource, cmd, myid,
mock_get, detail=False,
tags=[], fields_1=[], fields_2=[],
page_size=None, sort_key=[], sort_dir=[],
response_contents=None, base_args=None,
path=None):
mock_get.return_value = self.client
if response_contents is None:
contents = [{self.id_field: 'myid1', },
{self.id_field: 'myid2', }, ]
else:
contents = response_contents
reses = {api_resource: contents}
self.client.format = self.format
resstr1 = self.client.serialize(reses1)
resstr2 = self.client.serialize(reses2)
self.client.httpclient.request(
end_url(path, "", format=self.format), 'GET',
body=None,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr1))
self.client.httpclient.request(
end_url(path, fake_query, format=self.format), 'GET',
body=None,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr2))
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("list_" + resources)
args = ['--request-format', self.format]
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
resstr = self.client.serialize(reses)
# url method body
query = ""
args = base_args if base_args is not None else []
if detail:
args.append('-D')
args.extend(['--request-format', self.format])
if fields_1:
for field in fields_1:
args.append('--fields')
args.append(field)
def _test_update_resource(self, resource, cmd, myid, args, extrafields):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
if tags:
args.append('--')
args.append("--tag")
for tag in tags:
args.append(tag)
if isinstance(tag, six.string_types):
tag = urllib.quote(tag.encode('utf-8'))
if query:
query += "&tag=" + tag
else:
query = "tag=" + tag
if (not tags) and fields_2:
args.append('--')
if fields_2:
args.append("--fields")
for field in fields_2:
args.append(field)
if detail:
query = query and query + '&verbose=True' or 'verbose=True'
fields_1.extend(fields_2)
for field in fields_1:
if query:
query += "&fields=" + field
else:
query = "fields=" + field
if page_size:
args.append("--page-size")
args.append(str(page_size))
if query:
query += "&limit=%s" % page_size
else:
query = "limit=%s" % page_size
if sort_key:
for key in sort_key:
args.append('--sort-key')
args.append(key)
if query:
query += '&'
query += 'sort_key=%s' % key
if sort_dir:
len_diff = len(sort_key) - len(sort_dir)
if len_diff > 0:
sort_dir += ['asc'] * len_diff
elif len_diff < 0:
sort_dir = sort_dir[:len(sort_key)]
for dir in sort_dir:
args.append('--sort-dir')
args.append(dir)
if query:
query += '&'
query += 'sort_dir=%s' % dir
if path is None:
path = getattr(self.client, resources + "_path")
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(200), resstr)
self.client.httpclient.request(
end_url(path, format=self.format), 'GET',
body=None,
headers={'X-Auth-Token': TOKEN})
mock_req.assert_called_once_with(
end_url(path, format=self.format), 'GET',
body=None,
headers={'X-Auth-Token': TOKEN})
args.extend(['--request-format', self.format])
cmd_parser = cmd.get_parser("list_" + resources)
shell.run_command(cmd, cmd_parser, args)
_str = self.fake_stdout.make_string()
if response_contents is None:
self.assertIn('myid1', _str)
return _str
# TODO(gongysh) add pagination unit test BUG 1633255
# def _test_list_sub_resources_with_pagination(
# self, resources, api_resource, cmd, myid):
# self.mox.StubOutWithMock(cmd, "get_client")
# self.mox.StubOutWithMock(self.client.httpclient, "request")
# cmd.get_client().MultipleTimes().AndReturn(self.client)
# path = getattr(self.client, resources + "_path")
# fake_query = "marker=myid2&limit=2"
# reses1 = {api_resource: [{'id': 'myid1', },
# {'id': 'myid2', }],
# '%s_links' % api_resource: [
# {'href': end_url(path % myid, fake_query),
# 'rel': 'next'}]
# }
# reses2 = {api_resource: [{'id': 'myid3', },
# {'id': 'myid4', }]}
# self.client.format = self.format
# resstr1 = self.client.serialize(reses1)
# resstr2 = self.client.serialize(reses2)
# self.client.httpclient.request(
# end_url(path % myid, "", format=self.format), 'GET',
# body=None,
# headers=mox.ContainsKeyValue(
# 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr1))
# self.client.httpclient.request(
# MyUrlComparator(end_url(path % myid, fake_query,
# format=self.format), self.client), 'GET',
# body=None, headers=mox.ContainsKeyValue(
# 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr2))
# self.mox.ReplayAll()
# cmd_parser = cmd.get_parser("list_" + resources)
# args = [myid, '--request-format', self.format]
# shell.run_command(cmd, cmd_parser, args)
# self.mox.VerifyAll()
# self.mox.UnsetStubs()
# def _test_list_resources_with_pagination(self, resources, cmd):
# self.mox.StubOutWithMock(cmd, "get_client")
# self.mox.StubOutWithMock(self.client.httpclient, "request")
# cmd.get_client().MultipleTimes().AndReturn(self.client)
# path = getattr(self.client, resources + "_path")
# fake_query = "marker=myid2&limit=2"
# reses1 = {resources: [{'id': 'myid1', },
# {'id': 'myid2', }],
# '%s_links' % resources: [
# {'href': end_url(path, fake_query),
# 'rel': 'next'}]}
# reses2 = {resources: [{'id': 'myid3', },
# {'id': 'myid4', }]}
# self.client.format = self.format
# resstr1 = self.client.serialize(reses1)
# resstr2 = self.client.serialize(reses2)
# self.client.httpclient.request(
# end_url(path, "", format=self.format), 'GET',
# body=None,
# headers=mox.ContainsKeyValue(
# 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr1))
# self.client.httpclient.request(
# MyUrlComparator(end_url(path, fake_query, format=self.format),
# self.client), 'GET', body=None,
# headers=mox.ContainsKeyValue(
# 'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr2))
# self.mox.ReplayAll()
# cmd_parser = cmd.get_parser("list_" + resources)
# args = ['--request-format', self.format]
# shell.run_command(cmd, cmd_parser, args)
# self.mox.VerifyAll()
# self.mox.UnsetStubs()
@mock.patch.object(TackerCommand, 'get_client')
def _test_update_resource(self, resource, cmd, myid, args, extrafields,
mock_get, get_client_called_count=1):
mock_get.return_value = self.client
body = {resource: extrafields}
path = getattr(self.client, resource + "_path")
self.client.format = self.format
# Work around for LP #1217791. XML deserializer called from
# MyComparator does not decodes XML string correctly.
if self.format == 'json':
mox_body = MyComparator(body, self.client)
_body = MyComparator(body, self.client)
else:
mox_body = self.client.serialize(body)
self.client.httpclient.request(
MyUrlComparator(end_url(path % myid, format=self.format),
self.client),
'PUT',
body=mox_body,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(204), None))
args.extend(['--request-format', self.format])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("update_" + resource)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
_body = self.client.serialize(body)
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
comparator = MyUrlComparator(
end_url(path % myid, format=self.format), self.client)
mock_req.return_value = (MyResp(204), None)
self.client.httpclient.request(
comparator, 'PUT', body=_body,
headers={'X-Auth-Token', TOKEN})
mock_req.assert_called_once_with(
comparator,
'PUT',
body=_body,
headers={'X-Auth-Token', TOKEN})
args.extend(['--request-format', self.format])
cmd_parser = cmd.get_parser("update_" + resource)
shell.run_command(cmd, cmd_parser, args)
self.assertEqual(get_client_called_count, mock_get.call_count)
_str = self.fake_stdout.make_string()
self.assertIn(myid, _str)
def _test_show_resource(self, resource, cmd, myid, args, fields=[]):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
query = "&".join(["fields=%s" % field for field in fields])
expected_res = {resource:
{self.id_field: myid,
'name': 'myname', }, }
self.client.format = self.format
resstr = self.client.serialize(expected_res)
path = getattr(self.client, resource + "_path")
self.client.httpclient.request(
end_url(path % myid, query, format=self.format), 'GET',
body=None,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(200), resstr))
args.extend(['--request-format', self.format])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("show_" + resource)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
_str = self.fake_stdout.make_string()
self.assertIn(myid, _str)
self.assertIn('myname', _str)
with mock.patch.object(cmd, 'get_client') as mock_get:
mock_get.return_value = self.client
query = "&".join(["fields=%s" % field for field in fields])
expected_res = {resource:
{self.id_field: myid,
'name': 'myname', }, }
self.client.format = self.format
resstr = self.client.serialize(expected_res)
path = getattr(self.client, resource + "_path")
with mock.patch.object(self.client.httpclient, 'request') as\
mock_req:
mock_req.return_value = (MyResp(200), resstr)
self.client.httpclient.request(
end_url(path % myid, query, format=self.format), 'GET',
body=None, headers={'X-Auth-Token': TOKEN})
mock_req.assert_called_once_with(
end_url(path % myid, query, format=self.format), 'GET',
body=None, headers={'X-Auth-Token': TOKEN})
args.extend(['--request-format', self.format])
cmd_parser = cmd.get_parser("show_" + resource)
shell.run_command(cmd, cmd_parser, args)
_str = self.fake_stdout.make_string()
mock_get.assert_called_once_with()
self.assertIn(myid, _str)
self.assertIn('myname', _str)
def _test_delete_resource(self, resource, cmd, myid, args):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
@mock.patch.object(TackerCommand, 'get_client')
def _test_delete_resource(self, resource, cmd, myid, args, mock_get):
deleted_msg = {'vnf': 'delete initiated'}
mock_get.return_value = self.client
path = getattr(self.client, resource + "_path")
self.client.httpclient.request(
end_url(path % myid, format=self.format), 'DELETE',
body=None,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(204), None))
args.extend(['--request-format', self.format])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("delete_" + resource)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(204), None)
self.client.httpclient.request(
end_url(path % myid, format=self.format), 'DELETE',
body=None,
headers={'X-Auth-Token', TOKEN})
args.extend(['--request-format', self.format])
mock_req.assert_called_once_with(
end_url(path % myid, format=self.format), 'DELETE',
body=None, headers={'X-Auth-Token', TOKEN})
cmd_parser = cmd.get_parser("delete_" + resource)
shell.run_command(cmd, cmd_parser, args)
mock_get.assert_called_once_with()
_str = self.fake_stdout.make_string()
self.assertIn(myid, _str)
msg = 'All %(resource)s(s) %(msg)s successfully\n' % {
'msg': deleted_msg.get(resource, 'deleted'),
'resource': resource}
self.assertEqual(msg, _str)
@mock.patch.object(TackerCommand, 'get_client')
def _test_update_resource_action(self, resource, cmd, myid, action, args,
body, retval=None):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
body, mock_get, retval=None):
mock_get.return_value = self.client
path = getattr(self.client, resource + "_path")
path_action = '%s/%s' % (myid, action)
self.client.httpclient.request(
end_url(path % path_action, format=self.format), 'PUT',
body=MyComparator(body, self.client),
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((MyResp(204), retval))
args.extend(['--request-format', self.format])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("delete_" + resource)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
self.mox.UnsetStubs()
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(204), retval)
self.client.httpclient.request(
end_url(path % path_action, format=self.format), 'PUT',
body=MyComparator(body, self.client),
headers={'X-Auth-Token': TOKEN})
args.extend(['--request-format', self.format])
cmd_parser = cmd.get_parser("delete_" + resource)
shell.run_command(cmd, cmd_parser, args)
_str = self.fake_stdout.make_string()
self.assertIn(myid, _str)
@@ -500,7 +650,6 @@ class CLITestV10Base(testtools.TestCase):
class ClientV1TestJson(CLITestV10Base):
def test_do_request_unicode(self):
self.client.format = self.format
self.mox.StubOutWithMock(self.client.httpclient, "request")
unicode_text = u'\u7f51\u7edc'
# url with unicode
action = u'/test'
@@ -515,47 +664,33 @@ class ClientV1TestJson(CLITestV10Base):
# headers with unicode
self.client.httpclient.auth_token = unicode_text
expected_auth_token = unicode_text.encode('utf-8')
self.client.httpclient.request(
end_url(expected_action, query=expect_query, format=self.format),
'PUT', body=expect_body,
headers=mox.ContainsKeyValue(
'X-Auth-Token',
expected_auth_token)).AndReturn((MyResp(200), expect_body))
self.mox.ReplayAll()
res_body = self.client.do_request('PUT', action, body=body,
params=params)
self.mox.VerifyAll()
self.mox.UnsetStubs()
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(200), expect_body)
self.client.httpclient.request(
end_url(expected_action, query=expect_query,
format=self.format), 'PUT', body=expect_body,
headers={'X-Auth-Token': expected_auth_token})
res_body = self.client.do_request('PUT', action, body=body,
params=params)
# test response with unicode
self.assertEqual(res_body, body)
def test_do_request_error_without_response_body(self):
self.client.format = self.format
self.mox.StubOutWithMock(self.client.httpclient, "request")
params = {'test': 'value'}
expect_query = urllib.urlencode(params)
self.client.httpclient.auth_token = 'token'
self.client.httpclient.request(
end_url('/test', query=expect_query, format=self.format),
'PUT', body='',
headers=mox.ContainsKeyValue('X-Auth-Token', 'token')
).AndReturn((MyResp(400, reason='An error'), ''))
self.mox.ReplayAll()
error = self.assertRaises(exceptions.TackerClientException,
self.client.do_request, 'PUT', '/test',
body='', params=params)
self.assertEqual("An error", str(error))
self.mox.VerifyAll()
self.mox.UnsetStubs()
class ClientV1UnicodeTestXML(ClientV1TestJson):
format = 'xml'
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (MyResp(400, reason='An error'), '')
self.client.httpclient.request(
end_url('/test', query=expect_query, format=self.format),
'PUT', body='',
headers={'X-Auth-Token': 'token'}
)
error = self.assertRaises(exceptions.TackerClientException,
self.client.do_request, 'PUT', '/test',
body='', params=params)
self.assertEqual("An error", str(error))
class CLITestV10ExceptionHandler(CLITestV10Base):
@@ -579,7 +714,7 @@ class CLITestV10ExceptionHandler(CLITestV10Base):
expected_msg = '\n'.join([error_msg, error_detail])
else:
expected_msg = error_msg
self.assertEqual(expected_msg, e.message)
self.assertEqual(expected_msg, str(e))
def test_exception_handler_v10_ip_address_in_use(self):
err_msg = ('Unable to complete operation for network '

View File

@@ -70,7 +70,7 @@ class TestHTTPClient(testtools.TestCase):
e = self.assertRaises(exceptions.Unauthorized,
self.http._cs_request, URL, METHOD)
self.assertEqual('unauthorized message', e.message)
self.assertEqual('unauthorized message', str(e))
self.mox.VerifyAll()
def test_request_forbidden_is_returned_to_caller(self):

View File

@@ -14,10 +14,10 @@
# under the License.
import argparse
import cStringIO
import logging
import os
import re
import six
import sys
import fixtures
@@ -61,8 +61,8 @@ class ShellTest(testtools.TestCase):
clean_env = {}
_old_env, os.environ = os.environ, clean_env.copy()
try:
sys.stdout = cStringIO.StringIO()
sys.stderr = cStringIO.StringIO()
sys.stdout = six.StringIO()
sys.stderr = six.StringIO()
_shell = openstack_shell.TackerShell('1.0')
_shell.run(argstr.split())
except SystemExit:
@@ -118,7 +118,6 @@ class ShellTest(testtools.TestCase):
'either --os-url or env[OS_URL]', stderr.strip())
def test_auth(self):
# import pdb; pdb.set_trace()
tacker_shell = openstack_shell.TackerShell('1.0')
self.addCleanup(self.mox.UnsetStubs)
self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__')
@@ -146,7 +145,7 @@ class ShellTest(testtools.TestCase):
def test_build_option_parser(self):
tacker_shell = openstack_shell.TackerShell('1.0')
result = tacker_shell.build_option_parser('descr', '1.0')
self.assertEqual(True, isinstance(result, argparse.ArgumentParser))
self.assertIsInstance(result, argparse.ArgumentParser)
def test_main_with_unicode(self):
self.mox.StubOutClassWithMocks(openstack_shell, 'TackerShell')

View File

@@ -13,9 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import sys
import testtools
from tackerclient.common import exceptions
@@ -106,90 +103,7 @@ class TestUtils(testtools.TestCase):
self.assertEqual(('test_name', 'test_id', 'test', 'pass'), act)
class JSONUtilsTestCase(testtools.TestCase):
def test_dumps(self):
self.assertEqual(utils.dumps({'a': 'b'}), '{"a": "b"}')
def test_dumps_dict_with_date_value(self):
x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7)
res = utils.dumps({1: 'a', 2: x})
expected = '{"1": "a", "2": "1920-02-03 04:05:06.000007"}'
self.assertEqual(expected, res)
def test_dumps_dict_with_spaces(self):
x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7)
res = utils.dumps({1: 'a ', 2: x})
expected = '{"1": "a ", "2": "1920-02-03 04:05:06.000007"}'
self.assertEqual(expected, res)
def test_loads(self):
self.assertEqual(utils.loads('{"a": "b"}'), {'a': 'b'})
class ToPrimitiveTestCase(testtools.TestCase):
def test_list(self):
self.assertEqual(utils.to_primitive([1, 2, 3]), [1, 2, 3])
def test_empty_list(self):
self.assertEqual(utils.to_primitive([]), [])
def test_tuple(self):
self.assertEqual(utils.to_primitive((1, 2, 3)), [1, 2, 3])
def test_empty_tuple(self):
self.assertEqual(utils.to_primitive(()), [])
def test_dict(self):
self.assertEqual(
utils.to_primitive(dict(a=1, b=2, c=3)),
dict(a=1, b=2, c=3))
def test_empty_dict(self):
self.assertEqual(utils.to_primitive({}), {})
def test_datetime(self):
x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7)
self.assertEqual(
utils.to_primitive(x),
'1920-02-03 04:05:06.000007')
def test_iter(self):
x = range(1, 6)
self.assertEqual(utils.to_primitive(x), [1, 2, 3, 4, 5])
def test_iteritems(self):
d = {'a': 1, 'b': 2, 'c': 3}
class IterItemsClass(object):
def iteritems(self):
return d.iteritems()
x = IterItemsClass()
p = utils.to_primitive(x)
self.assertEqual(p, {'a': 1, 'b': 2, 'c': 3})
def test_nasties(self):
def foo():
pass
x = [datetime, foo, dir]
ret = utils.to_primitive(x)
self.assertEqual(len(ret), 3)
def test_to_primitive_dict_with_date_value(self):
x = datetime.datetime(1920, 2, 3, 4, 5, 6, 7)
res = utils.to_primitive({'a': x})
self.assertEqual({'a': '1920-02-03 04:05:06.000007'}, res)
class ImportClassTestCase(testtools.TestCase):
def test_import_class(self):
dt = utils.import_class('datetime.datetime')
self.assertTrue(sys.modules['datetime'].datetime is dt)
def test_import_bad_class(self):
self.assertRaises(
ImportError, utils.import_class,
'lol.u_mad.brah')
def test_get_client_class_invalid_version(self):
self.assertRaises(

View File

@@ -0,0 +1,6 @@
auth_url: 'http://1.2.3.4:5000'
username: 'xyz'
password: '12345'
project_name: 'abc'
project_domain_name: 'prj_domain_name'
user_domain_name: 'user_domain_name'

View File

@@ -0,0 +1,5 @@
username: 'xyz'
password: '12345'
project_name: 'abc'
project_domain_name: 'prj_domain_name'
user_domain_name: 'user_domain_name'

View File

@@ -0,0 +1,69 @@
# Copyright 2014 Intel 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 sys
from tackerclient.tacker.v1_0.events import events
from tackerclient.tests.unit import test_cli10
API_VERSION = "1.0"
FORMAT = 'json'
TOKEN = 'testtoken'
ENDURL = 'localurl'
class CLITestV10EventJSON(test_cli10.CLITestV10Base):
_EVT_RESOURCE = 'event'
_EVT_RESOURCES = _EVT_RESOURCE + 's'
_VNF_EVT_RESOURCE = "vnf_event"
_VNF_EVT_RESOURCES = _VNF_EVT_RESOURCE + 's'
_VNFD_EVT_RESOURCE = "vnfd_event"
_VNFD_EVT_RESOURCES = _VNFD_EVT_RESOURCE + 's'
_VIM_EVT_RESOURCE = "vim_event"
_VIM_EVT_RESOURCES = _VIM_EVT_RESOURCE + 's'
def setUp(self):
plurals = {'events': 'event', 'vnf_events': 'vnf_event',
'vnfd_events': 'vnfd_event', 'vim_events': 'vim_event'}
super(CLITestV10EventJSON, self).setUp(plurals=plurals)
def test_list_events(self):
cmd = events.ListResourceEvents(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._EVT_RESOURCES, cmd, True)
def test_show_event_id(self):
cmd = events.ShowEvent(test_cli10.MyApp(sys.stdout), None)
args = ['--fields', 'id', self.test_id]
self._test_show_resource(self._EVT_RESOURCE, cmd, self.test_id, args,
['id'])
def notest_list_vnf_events(self):
# TODO(vishwanathj): Need to enhance _test_list_resources()
# for supporting filters to get this test working
cmd = events.ListVNFEvents(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._VNF_EVT_RESOURCES, cmd, True)
def notest_list_vnfd_events(self):
# TODO(vishwanathj): Need to enhance _test_list_resources()
# for supporting filters to get this test working
cmd = events.ListVNFDEvents(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._VNFD_EVT_RESOURCES, cmd, True)
def notest_list_vim_events(self):
# TODO(vishwanathj): Need to enhance _test_list_resources()
# for supporting filters to get this test working
cmd = events.ListVIMEvents(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._VIM_EVT_RESOURCES, cmd, True)

View File

@@ -16,8 +16,8 @@
import sys
import mox
from tackerclient.common import exceptions
from tackerclient.common import utils
from tackerclient.tacker.v1_0.nfvo import vim
from tackerclient.tests.unit import test_cli10
@@ -34,43 +34,77 @@ class CLITestV10VIMJSON(test_cli10.CLITestV10Base):
def setUp(self):
plurals = {'vims': 'vim'}
super(CLITestV10VIMJSON, self).setUp(plurals=plurals)
self.vim_project = {'name': 'abc', 'id': ''}
self.vim_project = {
'name': 'abc', 'id': '',
'project_domain_name': 'prj_domain_name'}
self.auth_cred = {'username': 'xyz', 'password': '12345', 'user_id':
''}
'', 'user_domain_name': 'user_domain_name'}
self.auth_url = 'http://1.2.3.4:5000'
def test_register_vim_all_params(self):
cmd = vim.CreateVIM(test_cli10.MyApp(sys.stdout), None)
name = 'my-name'
my_id = 'my-id'
name = 'test_vim'
description = 'Vim Description'
vim_config = {'auth_url': 'http://1.2.3.4:5000', 'username': 'xyz',
'password': '12345', 'project_name': 'abc'}
vim_config = utils.get_file_path(
'tests/unit/vm/samples/vim_config.yaml')
args = [
'--config', str(vim_config),
'--name', name,
name,
'--config-file', vim_config,
'--description', description]
position_names = ['auth_cred', 'vim_project', 'auth_url']
position_values = [self.auth_cred, self.vim_project, self.auth_url]
extra_body = {'type': 'openstack', 'name': name, 'description':
description}
position_values = [self.auth_cred, self.vim_project,
self.auth_url]
extra_body = {'type': 'openstack', 'name': name,
'description': description, 'is_default': False}
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
args, position_names, position_values,
extra_body=extra_body)
def test_register_vim_with_mandatory_params(self):
def test_register_vim_with_no_auth_url(self):
cmd = vim.CreateVIM(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
vim_config = {'auth_url': 'http://1.2.3.4:5000', 'username': 'xyz',
'password': '12345', 'project_name': 'abc'}
name = 'test_vim'
description = 'Vim Description'
vim_config = utils.get_file_path(
'tests/unit/vm/samples/vim_config_without_auth_url.yaml')
args = [
'--config', str(vim_config),
name,
'--config-file', vim_config,
'--description', description]
position_names = ['auth_cred', 'vim_project', 'auth_url']
position_values = [self.auth_cred, self.vim_project,
self.auth_url]
extra_body = {'type': 'openstack', 'name': name,
'description': description, 'is_default': False}
message = 'Auth URL must be specified'
ex = self.assertRaises(exceptions.TackerClientException,
self._test_create_resource,
self._RESOURCE, cmd, None, my_id, args,
position_names, position_values,
extra_body=extra_body)
self.assertEqual(message, ex.message)
self.assertEqual(404, ex.status_code)
def test_register_vim_with_mandatory_params(self):
cmd = vim.CreateVIM(test_cli10.MyApp(sys.stdout), None)
name = 'my-name'
my_id = 'my-id'
vim_config = utils.get_file_path(
'tests/unit/vm/samples/vim_config.yaml')
args = [
name,
'--config-file', vim_config,
]
position_names = ['auth_cred', 'vim_project', 'auth_url']
position_values = [self.auth_cred, self.vim_project, self.auth_url]
extra_body = {'type': 'openstack'}
self._test_create_resource(self._RESOURCE, cmd, None, my_id, args,
position_values = [
self.auth_cred,
self.vim_project,
self.auth_url
]
extra_body = {'type': 'openstack', 'name': name, 'is_default': False}
self._test_create_resource(self._RESOURCE, cmd, name, my_id, args,
position_names, position_values,
extra_body=extra_body)
@@ -78,39 +112,6 @@ class CLITestV10VIMJSON(test_cli10.CLITestV10Base):
cmd = vim.ListVIM(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._RESOURCES, cmd, True)
def _test_list_vims_extend(self, data, expected_data, args=['-f', 'json']):
resp_str = self.client.serialize({self._RESOURCES: data})
resp = (test_cli10.MyResp(200), resp_str)
cmd = vim.ListVIM(
test_cli10.MyApp(sys.stdout), None)
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
path = getattr(self.client, self._RESOURCES + '_path')
self.client.httpclient.request(test_cli10.MyUrlComparator(
test_cli10.end_url(path, format=self.format), self.client),
'GET', body=None, headers=mox.ContainsKeyValue(
'X-Auth-Token', test_cli10.TOKEN)).AndReturn(resp)
self.mox.ReplayAll()
cmd_parser = cmd.get_parser("list_" + self._RESOURCES)
parsed_args = cmd_parser.parse_args(args)
result = cmd.take_action(parsed_args)
res_data = [res for res in result[1]]
self.mox.VerifyAll()
self.mox.UnsetStubs()
for res, exp in zip(res_data, expected_data):
self.assertEqual(len(exp), len(res))
self.assertEqual(exp, res)
def test_list_vims_extend(self):
vim_data = [{'id': 'my_id1', 'auth_cred': {'password':
'encrypted_pw'}}, {'id': 'my_id2', 'auth_cred': {
'password': 'another_encrypted_pw'}}]
expected_data = [('my_id1', {'password': '***'}),
('my_id2', {'password': '***'})]
self._test_list_vims_extend(vim_data, expected_data)
def test_show_vim_id(self):
cmd = vim.ShowVIM(test_cli10.MyApp(sys.stdout), None)
args = ['--fields', 'id', self.test_id]
@@ -123,18 +124,37 @@ class CLITestV10VIMJSON(test_cli10.CLITestV10Base):
self._test_show_resource(self._RESOURCE, cmd, self.test_id,
args, ['id', 'name'])
def test_update_vim(self):
def test_update_vim_all_params(self):
cmd = vim.UpdateVIM(test_cli10.MyApp(sys.stdout), None)
update_config = {'username': 'xyz', 'password': '12345',
'project_name': 'abc'}
update_config = utils.get_file_path(
'tests/unit/vm/samples/vim_config_without_auth_url.yaml')
my_id = 'my-id'
key = 'config'
value = str(update_config)
name = 'new_name'
description = 'new_description'
is_default = 'True'
args = [
my_id,
'--config-file', str(update_config),
'--name', name,
'--description', description,
'--is_default', is_default]
extra_fields = {'vim_project': self.vim_project, 'auth_cred':
self.auth_cred}
self._test_update_resource(self._RESOURCE, cmd, my_id, [my_id,
'--%s' %
key, value],
self.auth_cred, 'is_default': 'True',
'name': name, 'description': description}
self._test_update_resource(self._RESOURCE, cmd, my_id, args,
extra_fields)
def test_update_vim_with_mandatory_params(self):
cmd = vim.UpdateVIM(test_cli10.MyApp(sys.stdout), None)
update_config = utils.get_file_path(
'tests/unit/vm/samples/vim_config_without_auth_url.yaml')
my_id = 'my-id'
args = [
my_id,
'--config-file', str(update_config)]
extra_fields = {'vim_project': self.vim_project,
'auth_cred': self.auth_cred}
self._test_update_resource(self._RESOURCE, cmd, my_id, args,
extra_fields)
def test_delete_vim(self):
@@ -142,3 +162,9 @@ class CLITestV10VIMJSON(test_cli10.CLITestV10Base):
my_id = 'my-id'
args = [my_id]
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)
def test_multi_delete_vim(self):
cmd = vim.DeleteVIM(test_cli10.MyApp(sys.stdout), None)
vim_ids = 'my-id1 my-id2 my-id3'
args = [vim_ids]
self._test_delete_resource(self._RESOURCE, cmd, vim_ids, args)

View File

@@ -13,14 +13,14 @@
# 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 mox
import sys
import mock
from tackerclient import shell
from tackerclient.tacker import v1_0 as tackerV1_0
from tackerclient.tacker.v1_0.vm import vnf
from tackerclient.tacker.v1_0 import TackerCommand
from tackerclient.tacker.v1_0.vnfm import vnf
from tackerclient.tests.unit import test_cli10
API_VERSION = "1.0"
@@ -32,19 +32,19 @@ ENDURL = 'localurl'
class CLITestV10VmVNFJSON(test_cli10.CLITestV10Base):
_RESOURCE = 'vnf'
_RESOURCES = 'vnfs'
_VNF_RESOURCES = 'vnf_resources'
def setUp(self):
plurals = {'vnfs': 'vnf'}
plurals = {'vnfs': 'vnf',
'resources': 'resource'}
super(CLITestV10VmVNFJSON, self).setUp(plurals=plurals)
def _test_create_resource(self, resource, cmd,
name, myid, args,
position_names, position_values, tenant_id=None,
tags=None, admin_state_up=True, extra_body=None,
**kwargs):
self.mox.StubOutWithMock(cmd, "get_client")
self.mox.StubOutWithMock(self.client.httpclient, "request")
cmd.get_client().MultipleTimes().AndReturn(self.client)
@mock.patch.object(TackerCommand, 'get_client')
def _test_create_resource(self, resource, cmd, name, myid, args,
position_names, position_values, mock_get,
tenant_id=None, tags=None, admin_state_up=True,
extra_body=None, **kwargs):
mock_get.return_value = self.client
non_admin_status_resources = ['vnfd', 'vnf']
if (resource in non_admin_status_resources):
body = {resource: {}, }
@@ -73,53 +73,91 @@ class CLITestV10VmVNFJSON(test_cli10.CLITestV10Base):
# Work around for LP #1217791. XML deserializer called from
# MyComparator does not decodes XML string correctly.
if self.format == 'json':
mox_body = test_cli10.MyComparator(body, self.client)
_body = test_cli10.MyComparator(body, self.client)
else:
mox_body = self.client.serialize(body)
self.client.httpclient.request(
test_cli10.end_url(path, format=self.format), 'POST',
body=mox_body,
headers=mox.ContainsKeyValue(
'X-Auth-Token', TOKEN)).AndReturn((
test_cli10.MyResp(200), resstr))
args.extend(['--request-format', self.format])
args.extend(['--vnfd-id', 'vnfd'])
self.mox.ReplayAll()
cmd_parser = cmd.get_parser('create_' + resource)
shell.run_command(cmd, cmd_parser, args)
self.mox.VerifyAll()
_body = self.client.serialize(body)
with mock.patch.object(self.client.httpclient, 'request') as mock_req:
mock_req.return_value = (test_cli10.MyResp(200), resstr)
self.client.httpclient.request(
test_cli10.end_url(path, format=self.format), 'POST',
body=_body,
headers={'X-Auth-Token', TOKEN})
mock_req.assert_called_once_with(
test_cli10.end_url(path, format=self.format), 'POST',
body=_body,
headers={'X-Auth-Token', TOKEN})
args.extend(['--request-format', self.format])
args.extend(['--vnfd-id', 'vnfd'])
cmd_parser = cmd.get_parser('create_' + resource)
shell.run_command(cmd, cmd_parser, args)
mock_get.assert_any_call()
def test_create_vnf_all_params(self):
cmd = vnf.CreateVNF(test_cli10.MyApp(sys.stdout), None)
name = 'my_name'
my_id = 'my-id'
vnfd_id = 'vnfd'
vim_id = 'vim_id'
description = 'my-description'
region_name = 'region'
key = 'key'
value = 'value'
args = [
name,
'--vnfd-id', vnfd_id,
'--vim-id', vim_id,
'--description', description,
'--vim-region-name', region_name,
'--%s' % key, value]
position_names = ['vnfd_id', 'vim_id', 'attributes']
position_values = [vnfd_id, vim_id, {}]
position_names = [
'name',
'vnfd_id',
'vim_id',
'description',
'attributes'
]
position_values = [
name,
vnfd_id,
vim_id,
description,
{}
]
extra_body = {key: value, 'placement_attr': {'region_name':
region_name}}
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
self._test_create_resource(self._RESOURCE, cmd, name, my_id,
args, position_names, position_values,
extra_body=extra_body)
def test_create_vnf_with_mandatory_params(self):
cmd = vnf.CreateVNF(test_cli10.MyApp(sys.stdout), None)
name = 'my_name'
my_id = 'my-id'
vnfd_id = 'vnfd'
args = [
name,
'--vnfd-id', vnfd_id,
]
position_names = ['vnfd_id', 'attributes']
position_values = [vnfd_id, {}]
position_names = ['name', 'vnfd_id', 'attributes']
position_values = [name, vnfd_id, {}]
self._test_create_resource(self._RESOURCE, cmd, name, my_id,
args, position_names, position_values)
def test_create_vnf_with_description_param(self):
cmd = vnf.CreateVNF(test_cli10.MyApp(sys.stdout), None)
name = 'my_name'
my_id = 'my-id'
vnfd_id = 'vnfd'
description = 'my-description'
args = [
name,
'--vnfd-id', vnfd_id,
'--description', description,
]
position_names = ['name', 'vnfd_id', 'description',
'attributes']
position_values = [name, vnfd_id, description, {}]
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
args, position_names, position_values)
@@ -157,3 +195,22 @@ class CLITestV10VmVNFJSON(test_cli10.CLITestV10Base):
my_id = 'my-id'
args = [my_id]
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)
def test_list_vnf_resources(self):
cmd = vnf.ListVNFResources(test_cli10.MyApp(sys.stdout), None)
base_args = [self.test_id]
response = [{'name': 'CP11', 'id': 'id1', 'type': 'NeutronPort'},
{'name': 'CP12', 'id': 'id2', 'type': 'NeutronPort'}]
val = self._test_list_sub_resources(self._VNF_RESOURCES, 'resources',
cmd, self.test_id,
response_contents=response,
detail=True, base_args=base_args)
self.assertIn('id1', val)
self.assertIn('NeutronPort', val)
self.assertIn('CP11', val)
def test_multi_delete_vnf(self):
cmd = vnf.DeleteVNF(test_cli10.MyApp(sys.stdout), None)
vnf_ids = 'vnf1 vnf2 vnf3'
args = [vnf_ids]
self._test_delete_resource(self._RESOURCE, cmd, vnf_ids, args)

View File

@@ -16,7 +16,7 @@
import sys
from tackerclient.tacker.v1_0.vm import vnfd
from tackerclient.tacker.v1_0.vnfm import vnfd
from tackerclient.tests.unit import test_cli10
@@ -33,16 +33,14 @@ class CLITestV10VmVNFDJSON(test_cli10.CLITestV10Base):
test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
name = 'my-name'
mgmt_driver = 'noop'
infra_driver = 'heat'
attr_key = 'vnfd'
attr_val = 'vnfd'
args = [
'--name', name,
name,
'--vnfd', 'vnfd'
]
position_names = ['name', 'mgmt_driver', 'infra_driver']
position_values = [name, mgmt_driver, infra_driver]
position_names = ['name']
position_values = [name]
extra_body = {
'service_types': [{'service_type': 'vnfd'}],
'attributes': {attr_key: attr_val},
@@ -54,17 +52,16 @@ class CLITestV10VmVNFDJSON(test_cli10.CLITestV10Base):
def test_create_vnfd_with_mandatory_params(self):
cmd = vnfd.CreateVNFD(
test_cli10.MyApp(sys.stdout), None)
name = 'my_name'
my_id = 'my-id'
mgmt_driver = 'noop'
infra_driver = 'heat'
args = ['--vnfd', 'vnfd', ]
position_names = ['mgmt_driver', 'infra_driver']
position_values = [mgmt_driver, infra_driver]
args = [name, '--vnfd', 'vnfd', ]
position_names = ['name']
position_values = [name]
extra_body = {
'service_types': [{'service_type': 'vnfd'}],
'attributes': {'vnfd': 'vnfd'}
}
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
self._test_create_resource(self._RESOURCE, cmd, name, my_id,
args, position_names, position_values,
extra_body=extra_body)
@@ -94,3 +91,10 @@ class CLITestV10VmVNFDJSON(test_cli10.CLITestV10Base):
my_id = 'my-id'
args = [my_id]
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)
def test_multi_delete_vnfd(self):
cmd = vnfd.DeleteVNFD(
test_cli10.MyApp(sys.stdout), None)
vnfd_ids = 'my-id1 my-id2 my-id3'
args = [vnfd_ids]
self._test_delete_resource(self._RESOURCE, cmd, vnfd_ids, args)

View File

@@ -0,0 +1,106 @@
# Copyright 2014 Intel 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 sys
from tackerclient.tacker.v1_0.nfvo import vnffg
from tackerclient.tests.unit import test_cli10
API_VERSION = "1.0"
FORMAT = 'json'
TOKEN = 'testtoken'
ENDURL = 'localurl'
class CLITestV10VmVNFFGJSON(test_cli10.CLITestV10Base):
_RESOURCE = 'vnffg'
_RESOURCES = 'vnffgs'
def setUp(self):
plurals = {'vnffgs': 'vnffg'}
super(CLITestV10VmVNFFGJSON, self).setUp(plurals=plurals)
def test_create_vnffg_all_params(self):
cmd = vnffg.CreateVNFFG(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
vnffgd_id = 'vnffgd'
vnffg_name = 'fake-vnffg'
vnf_mapping = 'VNFD1:VNF1'
args = [
vnffg_name,
'--vnffgd-id', vnffgd_id,
'--vnf-mapping', vnf_mapping,
'--symmetrical', 'True']
position_names = ['vnffgd_id', 'vnf_mapping', 'symmetrical']
position_values = [vnffgd_id, {"VNFD1": "VNF1"}, 'True']
extra_body = {'name': vnffg_name}
self._test_create_resource(self._RESOURCE, cmd, None, my_id,
args, position_names, position_values,
extra_body=extra_body,
get_client_called_count=2)
def test_create_vnffg_with_mandatory_params(self):
cmd = vnffg.CreateVNFFG(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
vnffg_name = 'fake-vnffg'
vnffgd_id = 'vnffgd'
args = [
vnffg_name,
'--vnffgd-id', vnffgd_id,
]
position_names = ['vnffgd_id']
position_values = [vnffgd_id]
extra_body = {'name': vnffg_name}
self._test_create_resource(self._RESOURCE, cmd, vnffg_name, my_id,
args, position_names, position_values,
extra_body=extra_body,
get_client_called_count=2)
def test_list_vnffgs(self):
cmd = vnffg.ListVNFFG(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._RESOURCES, cmd, True)
def test_list_vnffgs_pagenation(self):
cmd = vnffg.ListVNFFG(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._RESOURCES, cmd, True)
def test_show_vnffg_id(self):
cmd = vnffg.ShowVNFFG(test_cli10.MyApp(sys.stdout), None)
args = ['--fields', 'id', self.test_id]
self._test_show_resource(self._RESOURCE, cmd, self.test_id, args,
['id'])
def test_show_vnffg_id_name(self):
cmd = vnffg.ShowVNFFG(test_cli10.MyApp(sys.stdout), None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(self._RESOURCE, cmd, self.test_id,
args, ['id', 'name'])
def test_update_vnffg(self):
cmd = vnffg.UpdateVNFFG(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
key = 'new_key'
value = 'new-value'
self._test_update_resource(self._RESOURCE, cmd, my_id,
[my_id, '--%s' % key, value],
{key: value}, get_client_called_count=2)
def test_delete_vnffg(self):
cmd = vnffg.DeleteVNFFG(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
args = [my_id]
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)

View File

@@ -0,0 +1,93 @@
# 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 sys
from tackerclient.tacker.v1_0.nfvo import vnffgd
from tackerclient.tests.unit import test_cli10
class CLITestV10VmVNFFGDJSON(test_cli10.CLITestV10Base):
_RESOURCE = 'vnffgd'
_RESOURCES = 'vnffgds'
def setUp(self):
plurals = {'vnffgds': 'vnffgd'}
super(CLITestV10VmVNFFGDJSON, self).setUp(plurals=plurals)
def test_create_vnffgd_all_params(self):
cmd = vnffgd.CreateVNFFGD(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
name = 'my-name'
attr_key = 'vnffgd'
attr_val = 'vnffgd'
description = 'vnffgd description'
args = [
name,
'--vnffgd', 'vnffgd',
'--description', description,
]
position_names = ['name', 'description']
position_values = [name, description]
extra_body = {
'template': {attr_key: attr_val},
}
self._test_create_resource(self._RESOURCE, cmd, name, my_id,
args, position_names, position_values,
extra_body=extra_body)
def test_create_vnffgd_with_mandatory_params(self):
cmd = vnffgd.CreateVNFFGD(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
name = 'my-name'
attr_key = 'vnffgd'
attr_val = 'vnffgd'
args = [
name,
'--vnffgd', 'vnffgd',
]
position_names = ['name']
position_values = [name]
extra_body = {
'template': {attr_key: attr_val},
}
self._test_create_resource(self._RESOURCE, cmd, name, my_id,
args, position_names, position_values,
extra_body=extra_body)
def test_list_vnffgds(self):
cmd = vnffgd.ListVNFFGD(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._RESOURCES, cmd, True)
def test_list_vnffgds_pagenation(self):
cmd = vnffgd.ListVNFFGD(test_cli10.MyApp(sys.stdout), None)
self._test_list_resources(self._RESOURCES, cmd, True)
def test_show_vnffgd_id(self):
cmd = vnffgd.ShowVNFFGD(test_cli10.MyApp(sys.stdout), None)
args = ['--fields', 'id', self.test_id]
self._test_show_resource(self._RESOURCE, cmd, self.test_id, args,
['id'])
def test_show_vnffgd_id_name(self):
cmd = vnffgd.ShowVNFFGD(test_cli10.MyApp(sys.stdout), None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(self._RESOURCE, cmd, self.test_id,
args, ['id', 'name'])
def test_delete_vnffgd(self):
cmd = vnffgd.DeleteVNFFGD(test_cli10.MyApp(sys.stdout), None)
my_id = 'my-id'
args = [my_id]
self._test_delete_resource(self._RESOURCE, cmd, my_id, args)

View File

@@ -0,0 +1,71 @@
# Copyright 2016 OpenStack Foundation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from mock import sentinel
import testtools
from tackerclient.common import exceptions
from tackerclient.tacker.v1_0.nfvo import vim_utils
class TestVIMUtils(testtools.TestCase):
def test_args2body_vim(self):
config_param = {'project_id': sentinel.prj_id1,
'username': sentinel.usrname1,
'password': sentinel.password1,
'project_domain_name': sentinel.prj_domain_name1,
'user_domain_name': sentinel.user_domain.name, }
vim = {}
auth_cred = config_param.copy()
auth_cred.pop('project_id')
auth_cred.pop('project_domain_name')
auth_cred.update({'user_id': ''})
expected_vim = {'auth_cred': auth_cred,
'vim_project':
{'id': sentinel.prj_id1,
'name': '',
'project_domain_name': sentinel.prj_domain_name1}}
vim_utils.args2body_vim(config_param.copy(), vim)
self.assertEqual(expected_vim, vim)
def test_args2body_vim_no_project(self):
config_param = {'username': sentinel.usrname1,
'password': sentinel.password1,
'user_domain_name': sentinel.user_domain.name, }
vim = {}
self.assertRaises(exceptions.TackerClientException,
vim_utils.args2body_vim,
config_param, vim)
def test_validate_auth_url_with_port(self):
auth_url = "http://localhost:8000/test"
url_parts = vim_utils.validate_auth_url(auth_url)
self.assertEqual('http', url_parts.scheme)
self.assertEqual('localhost:8000', url_parts.netloc)
self.assertEqual(8000, url_parts.port)
def test_validate_auth_url_without_port(self):
auth_url = "http://localhost/test"
url_parts = vim_utils.validate_auth_url(auth_url)
self.assertEqual('http', url_parts.scheme)
self.assertEqual('localhost', url_parts.netloc)
def test_validate_auth_url_exception(self):
auth_url = "localhost/test"
self.assertRaises(exceptions.TackerClientException,
vim_utils.validate_auth_url,
auth_url)

View File

@@ -338,10 +338,36 @@ class Client(ClientBase):
vnfd_path = '/vnfds/%s'
vnfs_path = '/vnfs'
vnf_path = '/vnfs/%s'
vnf_scale_path = '/vnfs/%s/actions'
vnf_resources_path = '/vnfs/%s/resources'
vims_path = '/vims'
vim_path = '/vims/%s'
events_path = '/events'
event_path = '/events/%s'
vnffgds_path = '/vnffgds'
vnffgd_path = '/vnffgds/%s'
vnffgs_path = '/vnffgs'
vnffg_path = '/vnffgs/%s'
nfps_path = '/nfps'
nfp_path = '/nfps/%s'
sfcs_path = '/sfcs'
sfc_path = '/sfcs/%s'
fcs_path = '/classifiers'
fc_path = '/classifiers/%s'
nsds_path = '/nsds'
nsd_path = '/nsds/%s'
nss_path = '/nss'
ns_path = '/nss/%s'
# API has no way to report plurals, so we have to hard code them
# EXTED_PLURALS = {}
@@ -356,6 +382,7 @@ class Client(ClientBase):
return self.get(self.extension_path % ext_alias, params=_params)
_VNFD = "vnfd"
_NSD = "nsd"
@APIParamsCall
def list_vnfds(self, retrieve_all=True, **_params):
@@ -376,13 +403,12 @@ class Client(ClientBase):
params=_params)
@APIParamsCall
def create_vnfd(self, body=None):
if body is not None:
body[self._VNFD]['service_types'] = [{'service_type': 'vnfd'}]
body[self._VNFD]['infra_driver'] = 'heat'
body[self._VNFD]['mgmt_driver'] = 'noop'
else:
body = None
def create_vnfd(self, body):
if ("tosca_definitions_version" not in
body[self._VNFD]['attributes']['vnfd']):
_logger.warning("VNFD legacy templates are deprecated. Please "
"use NFV TOSCA templates.")
body[self._VNFD]['service_types'] = [{'service_type': 'vnfd'}]
return self.post(self.vnfds_path, body)
@APIParamsCall
@@ -406,7 +432,7 @@ class Client(ClientBase):
return self.get(self.vnf_path % vnf, params=_params)
@APIParamsCall
def create_vnf(self, body=None):
def create_vnf(self, body):
return self.post(self.vnfs_path, body=body)
@APIParamsCall
@@ -414,9 +440,18 @@ class Client(ClientBase):
return self.delete(self.vnf_path % vnf)
@APIParamsCall
def update_vnf(self, vnf, body=None):
def update_vnf(self, vnf, body):
return self.put(self.vnf_path % vnf, body=body)
@APIParamsCall
def list_vnf_resources(self, vnf, retrieve_all=True, **_params):
return self.list('resources', self.vnf_resources_path % vnf,
retrieve_all, **_params)
@APIParamsCall
def scale_vnf(self, vnf, body=None):
return self.post(self.vnf_scale_path % vnf, body=body)
@APIParamsCall
def show_vim(self, vim, **_params):
return self.get(self.vim_path % vim, params=_params)
@@ -424,7 +459,7 @@ class Client(ClientBase):
_VIM = "vim"
@APIParamsCall
def create_vim(self, body=None):
def create_vim(self, body):
return self.post(self.vims_path, body=body)
@APIParamsCall
@@ -432,9 +467,201 @@ class Client(ClientBase):
return self.delete(self.vim_path % vim)
@APIParamsCall
def update_vim(self, vim, body=None):
def update_vim(self, vim, body):
return self.put(self.vim_path % vim, body=body)
@APIParamsCall
def list_vims(self, retrieve_all=True, **_params):
return self.list('vims', self.vims_path, retrieve_all, **_params)
@APIParamsCall
def list_events(self, retrieve_all=True, **_params):
events = self.list('events', self.events_path, retrieve_all,
**_params)
return events
@APIParamsCall
def list_vnf_events(self, retrieve_all=True, **_params):
_params['resource_type'] = 'vnf'
events = self.list('events', self.events_path, retrieve_all,
**_params)
vnf_events = {}
vnf_events['vnf_events'] = events['events']
return vnf_events
@APIParamsCall
def list_vnfd_events(self, retrieve_all=True, **_params):
_params['resource_type'] = 'vnfd'
events = self.list('events', self.events_path, retrieve_all,
**_params)
vnfd_events = {}
vnfd_events['vnfd_events'] = events['events']
return vnfd_events
@APIParamsCall
def list_vim_events(self, retrieve_all=True, **_params):
_params['resource_type'] = 'vim'
events = self.list('events', self.events_path, retrieve_all,
**_params)
vim_events = {}
vim_events['vim_events'] = events['events']
return vim_events
@APIParamsCall
def show_event(self, event_id, **_params):
return self.get(self.event_path % event_id, params=_params)
_VNFFGD = "vnffgd"
@APIParamsCall
def create_vnffgd(self, body):
return self.post(self.vnffgds_path, body)
@APIParamsCall
def list_vnffgds(self, retrieve_all=True, **_params):
vnffgds_dict = self.list(self._VNFFGD + 's',
self.vnffgds_path,
retrieve_all,
**_params)
for vnffgd in vnffgds_dict['vnffgds']:
if 'description' in vnffgd.keys() and \
len(vnffgd['description']) > DEFAULT_DESC_LENGTH:
vnffgd['description'] = vnffgd['description'][
:DEFAULT_DESC_LENGTH]
vnffgd['description'] += '...'
return vnffgds_dict
@APIParamsCall
def show_vnffgd(self, vnffgd, **_params):
return self.get(self.vnffgd_path % vnffgd, params=_params)
@APIParamsCall
def delete_vnffgd(self, vnffgd):
return self.delete(self.vnffgd_path % vnffgd)
@APIParamsCall
def list_vnffgs(self, retrieve_all=True, **_params):
vnffgs = self.list('vnffgs', self.vnffgs_path, retrieve_all, **_params)
for vnffg in vnffgs['vnffgs']:
error_reason = vnffg.get('error_reason', None)
if error_reason and \
len(error_reason) > DEFAULT_ERROR_REASON_LENGTH:
vnffg['error_reason'] = error_reason[
:DEFAULT_ERROR_REASON_LENGTH]
vnffg['error_reason'] += '...'
return vnffgs
@APIParamsCall
def show_vnffg(self, vnffg, **_params):
return self.get(self.vnffg_path % vnffg, params=_params)
@APIParamsCall
def create_vnffg(self, body):
return self.post(self.vnffgs_path, body=body)
@APIParamsCall
def delete_vnffg(self, vnffg):
return self.delete(self.vnffg_path % vnffg)
@APIParamsCall
def update_vnffg(self, vnffg, body):
return self.put(self.vnffg_path % vnffg, body=body)
@APIParamsCall
def list_sfcs(self, retrieve_all=True, **_params):
sfcs = self.list('sfcs', self.sfcs_path, retrieve_all, **_params)
for chain in sfcs['sfcs']:
error_reason = chain.get('error_reason', None)
if error_reason and \
len(error_reason) > DEFAULT_ERROR_REASON_LENGTH:
chain['error_reason'] = error_reason[
:DEFAULT_ERROR_REASON_LENGTH]
chain['error_reason'] += '...'
return sfcs
@APIParamsCall
def show_sfc(self, chain, **_params):
return self.get(self.sfc_path % chain, params=_params)
@APIParamsCall
def list_nfps(self, retrieve_all=True, **_params):
nfps = self.list('nfps', self.nfps_path, retrieve_all, **_params)
for nfp in nfps['nfps']:
error_reason = nfp.get('error_reason', None)
if error_reason and \
len(error_reason) > DEFAULT_ERROR_REASON_LENGTH:
nfp['error_reason'] = error_reason[
:DEFAULT_ERROR_REASON_LENGTH]
nfp['error_reason'] += '...'
return nfps
@APIParamsCall
def show_nfp(self, nfp, **_params):
return self.get(self.nfp_path % nfp, params=_params)
@APIParamsCall
def list_classifiers(self, retrieve_all=True, **_params):
classifiers = self.list('classifiers', self.fcs_path, retrieve_all,
**_params)
for classifier in classifiers['classifiers']:
error_reason = classifier.get('error_reason', None)
if error_reason and \
len(error_reason) > DEFAULT_ERROR_REASON_LENGTH:
classifier['error_reason'] = error_reason[
:DEFAULT_ERROR_REASON_LENGTH]
classifier['error_reason'] += '...'
return classifiers
@APIParamsCall
def show_classifier(self, classifier, **_params):
return self.get(self.fc_path % classifier, params=_params)
@APIParamsCall
def list_nsds(self, retrieve_all=True, **_params):
nsds_dict = self.list(self._NSD + 's',
self.nsds_path,
retrieve_all,
**_params)
for nsd in nsds_dict['nsds']:
if 'description' in nsd.keys() and \
len(nsd['description']) > DEFAULT_DESC_LENGTH:
nsd['description'] = nsd['description'][:DEFAULT_DESC_LENGTH]
nsd['description'] += '...'
return nsds_dict
@APIParamsCall
def show_nsd(self, nsd, **_params):
return self.get(self.nsd_path % nsd,
params=_params)
@APIParamsCall
def create_nsd(self, body):
return self.post(self.nsds_path, body)
@APIParamsCall
def delete_nsd(self, nsd):
return self.delete(self.nsd_path % nsd)
@APIParamsCall
def list_nss(self, retrieve_all=True, **_params):
nss = self.list('nss', self.nss_path, retrieve_all, **_params)
for ns in nss['nss']:
error_reason = ns.get('error_reason', None)
if error_reason and \
len(error_reason) > DEFAULT_ERROR_REASON_LENGTH:
ns['error_reason'] = error_reason[
:DEFAULT_ERROR_REASON_LENGTH]
ns['error_reason'] += '...'
return nss
@APIParamsCall
def show_ns(self, ns, **_params):
return self.get(self.ns_path % ns, params=_params)
@APIParamsCall
def create_ns(self, body):
return self.post(self.nss_path, body=body)
@APIParamsCall
def delete_ns(self, ns):
return self.delete(self.ns_path % ns)

View File

@@ -2,18 +2,16 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking<0.11,>=0.10.2
cliff-tablib>=1.0 # Apache-2.0
coverage>=3.6 # Apache-2.0
discover # BSD
coverage>=4.0 # Apache-2.0
fixtures>=3.0.0 # Apache-2.0/BSD
mox>=0.5.3 # Apache-2.0
flake8<2.6.0,>=2.5.4 # MIT
pep8==1.5.7 # MIT
pyflakes==0.8.1 # MIT
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
# releasenotes
reno>=1.6.2 # Apache2
reno>=1.8.0 # Apache-2.0
mock>=2.0 # BSD

30
tools/tox_install.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Client constraint file contains this client version pin that is in conflict
# with installing the client from source. We should remove the version pin in
# the constraints file before applying it for from-source installation.
CONSTRAINTS_FILE="$1"
shift 1
set -e
# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
# published to logs.openstack.org for easy debugging.
localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
if [[ "$CONSTRAINTS_FILE" != http* ]]; then
CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
fi
# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
pip install -c"$localfile" openstack-requirements
# This is the main purpose of the script: Allow local installation of
# the current repo. It is listed in constraints file and thus any
# install will be constrained and we need to unconstrain it.
edit-constraints "$localfile" -- "$CLIENT_NAME"
pip install -c"$localfile" -U "$@"
exit $?

View File

@@ -1,15 +1,17 @@
[tox]
envlist = py34,py27,pypy,pep8
minversion = 1.6
minversion = 2.0
skipsdist = True
[testenv]
setenv = VIRTUAL_ENV={envdir}
BRANCH_NAME=master
CLIENT_NAME=python-tackerclient
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_ALL=C
usedevelop = True
install_command = pip install -U {opts} {packages}
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = python setup.py testr --testr-args='{posargs}'