Compare commits
26 Commits
victoria-e
...
wallaby-eo
| Author | SHA1 | Date | |
|---|---|---|---|
| 8636b3dbb5 | |||
|
|
900a1aa78e | ||
| 21abb7ffd0 | |||
| ecdf16a9b7 | |||
|
|
1a457e074a | ||
|
|
4e6dc4c031 | ||
|
|
6b29bb78b1 | ||
|
|
1299e15f35 | ||
|
|
cfe14110d1 | ||
|
|
58167535c7 | ||
|
|
b7968d815e | ||
|
|
e7a0c96920 | ||
|
|
68df82918a | ||
|
|
76da3dbd9d | ||
|
|
17f4bcac1a | ||
|
|
69d9668282 | ||
|
|
bbe6d2c7e0 | ||
|
|
c6df687c94 | ||
|
|
754f6df5a7 | ||
|
|
727493c7bf | ||
|
|
6bdb64f464 | ||
|
|
cfbc810bdc | ||
|
|
8e2f5f854e | ||
|
|
97f0903242 | ||
| b69220634f | |||
| e628157a7d |
@@ -2,3 +2,4 @@
|
||||
host=review.opendev.org
|
||||
port=29418
|
||||
project=openstack/python-tackerclient.git
|
||||
defaultbranch=stable/wallaby
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
- project:
|
||||
templates:
|
||||
- check-requirements
|
||||
- openstack-lower-constraints-jobs
|
||||
- openstack-python3-victoria-jobs
|
||||
- openstack-python3-wallaby-jobs
|
||||
- publish-openstack-docs-pti
|
||||
- release-notes-jobs-python3
|
||||
|
||||
@@ -71,8 +71,8 @@ htmlhelp_basename = 'tackerclientdoc'
|
||||
# -- Options for manual page output -------------------------------------------
|
||||
|
||||
man_pages = [
|
||||
('cli/index', 'tacker', u'Client for Tacker API',
|
||||
[u'OpenStack Contributors'], 1),
|
||||
('cli/index', 'tacker', 'Client for Tacker API',
|
||||
['OpenStack Contributors'], 1),
|
||||
]
|
||||
|
||||
# -- Options for openstackdocstheme -------------------------------------------
|
||||
|
||||
@@ -11,59 +11,53 @@
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Convention for heading levels in Neutron devref:
|
||||
======= Heading 0 (reserved for the title in a document)
|
||||
------- Heading 1
|
||||
~~~~~~~ Heading 2
|
||||
+++++++ Heading 3
|
||||
''''''' Heading 4
|
||||
(Avoid deeper levels because they do not render well.)
|
||||
|
||||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
**Note:** The paths we are using for configuration files in these steps
|
||||
are with reference to Ubuntu Operating System. The paths may vary for
|
||||
other Operating Systems.
|
||||
This document describes how to install python-tackerclient.
|
||||
|
||||
The branch_name which is used in commands, specify the branch_name
|
||||
as stable/<branch> for any stable branch installation. For eg:
|
||||
stable/queens, stable/pike. If unspecified the default will be
|
||||
master branch.
|
||||
.. note::
|
||||
|
||||
This installation guide contents are specific to Ubuntu distro.
|
||||
|
||||
Using python install
|
||||
====================
|
||||
1. Clone python-tackerclient repository.
|
||||
|
||||
::
|
||||
#. Clone python-tackerclient repository.
|
||||
|
||||
$ cd ~/
|
||||
$ git clone https://github.com/openstack/python-tackerclient -b <branch_name>
|
||||
You can use -b for specific release, optionally.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
2. Install python-tackerclient.
|
||||
$ cd ~/
|
||||
$ git clone https://opendev.org/openstack/python-tackerclient -b <branch_name>
|
||||
|
||||
::
|
||||
.. note::
|
||||
|
||||
$ cd python-tackerclient
|
||||
$ sudo python setup.py install
|
||||
Make sure to replace the ``<branch_name>`` in command example with
|
||||
specific branch name, such as ``stable/victoria``.
|
||||
|
||||
#. Install python-tackerclient.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ cd python-tackerclient
|
||||
$ sudo python3 setup.py install
|
||||
|
||||
Using pip
|
||||
=========
|
||||
|
||||
You can also install the latest version by using ``pip`` command:
|
||||
|
||||
::
|
||||
|
||||
$ pip install python-tackerclient
|
||||
.. code-block:: console
|
||||
|
||||
$ pip3 install python-tackerclient
|
||||
|
||||
Or, if it is needed to install ``python-tackerclient`` from master branch,
|
||||
type
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install git+https://github.com/openstack/python-tackerclient.git
|
||||
$ pip3 install git+https://opendev.org/openstack/python-tackerclient
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
appdirs==1.3.0
|
||||
Babel==2.3.4
|
||||
cliff==2.8.0
|
||||
cmd2==0.8.0
|
||||
coverage==4.0
|
||||
ddt==1.0.1
|
||||
debtcollector==1.2.0
|
||||
decorator==3.4.0
|
||||
deprecation==1.0
|
||||
dogpile.cache==0.6.2
|
||||
extras==1.0.0
|
||||
fixtures==3.0.0
|
||||
flake8==2.5.5
|
||||
hacking==0.12.0
|
||||
iso8601==0.1.11
|
||||
jmespath==0.9.0
|
||||
jsonpatch==1.16
|
||||
jsonpointer==1.13
|
||||
keystoneauth1==3.4.0
|
||||
linecache2==1.0.0
|
||||
mccabe==0.2.1
|
||||
monotonic==0.6
|
||||
msgpack-python==0.4.0
|
||||
munch==2.1.0
|
||||
netaddr==0.7.18
|
||||
netifaces==0.10.4
|
||||
openstacksdk==0.11.2
|
||||
os-client-config==1.28.0
|
||||
os-service-types==1.2.0
|
||||
osc-lib==1.8.0
|
||||
oslo.config==5.2.0
|
||||
oslo.context==2.19.2
|
||||
oslo.i18n==3.15.3
|
||||
oslo.log==3.36.0
|
||||
oslo.serialization==2.18.0
|
||||
oslo.utils==3.40.0
|
||||
pbr==2.0.0
|
||||
pep8==1.5.7
|
||||
positional==1.2.1
|
||||
prettytable==0.7.2
|
||||
pyflakes==0.8.1
|
||||
pyinotify==0.9.6
|
||||
pyparsing==2.1.0
|
||||
pyperclip==1.5.27
|
||||
python-dateutil==2.5.3
|
||||
python-keystoneclient==3.8.0
|
||||
python-mimeparse==1.6.0
|
||||
python-subunit==1.0.0
|
||||
pytz==2013.6
|
||||
PyYAML==3.12
|
||||
requests==2.14.2
|
||||
requests-mock==1.2.0
|
||||
requestsexceptions==1.2.0
|
||||
rfc3986==0.3.1
|
||||
simplejson==3.5.1
|
||||
six==1.10.0
|
||||
stestr==2.0.0
|
||||
stevedore==1.20.0
|
||||
testtools==2.2.0
|
||||
traceback2==1.4.0
|
||||
unittest2==1.1.0
|
||||
wrapt==1.7.0
|
||||
@@ -53,8 +53,8 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Tacker Client Release Notes'
|
||||
copyright = u'2016, Tacker Developers'
|
||||
project = 'Tacker Client Release Notes'
|
||||
copyright = '2016, Tacker Developers'
|
||||
|
||||
# Release notes are version independent.
|
||||
release = ''
|
||||
@@ -190,8 +190,8 @@ latex_elements = {
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'TackerClientReleaseNotes.tex',
|
||||
u'Tacker Client Release Notes Documentation',
|
||||
u'Tacker Developers', 'manual'),
|
||||
'Tacker Client Release Notes Documentation',
|
||||
'Tacker Developers', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@@ -221,8 +221,8 @@ latex_documents = [
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'tackerreleasenotes',
|
||||
u'Tacker Client Release Notes Documentation',
|
||||
[u'Tacker Developers'], 1)
|
||||
'Tacker Client Release Notes Documentation',
|
||||
['Tacker Developers'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
@@ -236,8 +236,8 @@ man_pages = [
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'TackerClientReleaseNotes',
|
||||
u'Tacker Client Release Notes Documentation',
|
||||
u'Tacker Developers', 'TackerClientReleaseNotes',
|
||||
'Tacker Client Release Notes Documentation',
|
||||
'Tacker Developers', 'TackerClientReleaseNotes',
|
||||
'Tacker Client Project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,7 @@ Contents:
|
||||
:maxdepth: 2
|
||||
|
||||
unreleased
|
||||
victoria
|
||||
ussuri
|
||||
train
|
||||
stein
|
||||
|
||||
6
releasenotes/source/victoria.rst
Normal file
6
releasenotes/source/victoria.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
=============================
|
||||
Victoria Series Release Notes
|
||||
=============================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/victoria
|
||||
@@ -8,7 +8,6 @@ netaddr>=0.7.18 # BSD
|
||||
requests>=2.14.2 # Apache-2.0
|
||||
python-keystoneclient>=3.8.0 # Apache-2.0
|
||||
simplejson>=3.5.1 # MIT
|
||||
six>=1.10.0 # MIT
|
||||
stevedore>=1.20.0 # Apache-2.0
|
||||
Babel!=2.4.0,>=2.3.4 # BSD
|
||||
oslo.i18n>=3.15.3 # Apache-2.0
|
||||
|
||||
@@ -94,4 +94,9 @@ openstack.tackerclient.v1 =
|
||||
vnflcm_heal = tackerclient.osc.v1.vnflcm.vnflcm:HealVnfLcm
|
||||
vnflcm_update = tackerclient.osc.v1.vnflcm.vnflcm:UpdateVnfLcm
|
||||
vnflcm_scale = tackerclient.osc.v1.vnflcm.vnflcm:ScaleVnfLcm
|
||||
vnflcm_change-ext-conn = tackerclient.osc.v1.vnflcm.vnflcm:ChangeExtConnVnfLcm
|
||||
vnflcm_op_rollback = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RollbackVnfLcmOp
|
||||
vnflcm_op_fail = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:FailVnfLcmOp
|
||||
vnflcm_op_retry = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:RetryVnfLcmOp
|
||||
vnflcm_op_list = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ListVnfLcmOp
|
||||
vnflcm_op_show = tackerclient.osc.v1.vnflcm.vnflcm_op_occs:ShowVnfLcmOp
|
||||
|
||||
@@ -28,7 +28,6 @@ ATOM_LINK_NOTATION = "{%s}link" % ATOM_NAMESPACE
|
||||
|
||||
TYPE_BOOL = "bool"
|
||||
TYPE_INT = "int"
|
||||
TYPE_LONG = "long"
|
||||
TYPE_FLOAT = "float"
|
||||
TYPE_LIST = "list"
|
||||
TYPE_DICT = "dict"
|
||||
|
||||
@@ -18,7 +18,6 @@ from xml.etree import ElementTree as etree
|
||||
from xml.parsers import expat
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
|
||||
from tackerclient.common import constants
|
||||
from tackerclient.common import exceptions as exception
|
||||
@@ -26,9 +25,6 @@ from tackerclient.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
if six.PY3:
|
||||
long = int
|
||||
|
||||
|
||||
class ActionDispatcher(object):
|
||||
"""Maps method name to local methods through action name."""
|
||||
@@ -58,7 +54,7 @@ class JSONDictSerializer(DictSerializer):
|
||||
|
||||
def default(self, data):
|
||||
def sanitizer(obj):
|
||||
return six.text_type(obj)
|
||||
return str(obj)
|
||||
return jsonutils.dumps(data, default=sanitizer)
|
||||
|
||||
|
||||
@@ -93,7 +89,7 @@ class XMLDictSerializer(DictSerializer):
|
||||
root_key = constants.VIRTUAL_ROOT_KEY
|
||||
root_value = None
|
||||
else:
|
||||
link_keys = [k for k in six.iterkeys(data) or []
|
||||
link_keys = [k for k in data.keys() or []
|
||||
if k.endswith('_links')]
|
||||
if link_keys:
|
||||
links = data.pop(link_keys[0], None)
|
||||
@@ -183,10 +179,6 @@ class XMLDictSerializer(DictSerializer):
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_INT)
|
||||
elif isinstance(data, long):
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_LONG)
|
||||
elif isinstance(data, float):
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
@@ -194,7 +186,7 @@ class XMLDictSerializer(DictSerializer):
|
||||
LOG.debug("Data %(data)s type is %(type)s",
|
||||
{'data': data,
|
||||
'type': type(data)})
|
||||
result.text = six.text_type(data)
|
||||
result.text = str(data)
|
||||
return result
|
||||
|
||||
def _create_link_nodes(self, xml_doc, links):
|
||||
@@ -323,8 +315,6 @@ class XMLDeserializer(TextDeserializer):
|
||||
lambda x: x.lower() == 'true',
|
||||
constants.TYPE_INT:
|
||||
lambda x: int(x),
|
||||
constants.TYPE_LONG:
|
||||
lambda x: long(x),
|
||||
constants.TYPE_FLOAT:
|
||||
lambda x: float(x)}
|
||||
if attrType and attrType in converters:
|
||||
|
||||
@@ -24,7 +24,6 @@ import os
|
||||
from oslo_log import versionutils
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
from tackerclient.i18n import _
|
||||
@@ -141,7 +140,7 @@ def http_log_resp(_logger, resp, body):
|
||||
|
||||
|
||||
def _safe_encode_without_obj(data):
|
||||
if isinstance(data, six.string_types):
|
||||
if isinstance(data, str):
|
||||
return encodeutils.safe_encode(data)
|
||||
return data
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ class ShowTemplateNSD(command.ShowOne):
|
||||
obj[_NSD]['attributes']['nsd'])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_NSD]),
|
||||
(u'attributes',),
|
||||
('attributes',),
|
||||
formatters=_formatters)
|
||||
data = (data or _('Unable to display NSD template!'))
|
||||
return ((u'attributes',), data)
|
||||
return (('attributes',), data)
|
||||
|
||||
@@ -211,7 +211,7 @@ class ShowTemplateVNFFGD(command.ShowOne):
|
||||
obj = client.show_vnffgd(obj_id)
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_VNFFGD]),
|
||||
(u'template',),
|
||||
('template',),
|
||||
formatters=_formatters)
|
||||
data = (data or _('Unable to display VNFFGD template!'))
|
||||
return ((u'template',), data)
|
||||
return (('template',), data)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"extVirtualLinks": [
|
||||
{
|
||||
"id": "ext-vl-uuid-VL1",
|
||||
"resourceId": "neutron-network-uuid_VL1",
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "CP1",
|
||||
"cpConfig": [
|
||||
{
|
||||
"cpProtocolData": [
|
||||
{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [
|
||||
{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": 1,
|
||||
"subnetId": "subnet-uuid"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cpdId": "CP2",
|
||||
"cpConfig": [
|
||||
{
|
||||
"cpProtocolData": [
|
||||
{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [
|
||||
{
|
||||
"type": "IPV4",
|
||||
"fixedAddresses": [
|
||||
"10.0.0.1"
|
||||
],
|
||||
"subnetId": "subnet-uuid"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"vimConnectionInfo": [
|
||||
{
|
||||
"id": "vim-uuid",
|
||||
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
|
||||
"vimConnectionId": "dummy-vimid",
|
||||
"interfaceInfo": {
|
||||
"key1":"value1",
|
||||
"key2":"value2"
|
||||
},
|
||||
"accessInfo": {
|
||||
"key1":"value1",
|
||||
"key2":"value2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -476,46 +476,51 @@ class ScaleVnfLcm(command.Command):
|
||||
_VNF_INSTANCE,
|
||||
metavar="<vnf-instance>",
|
||||
help=_('VNF instance ID to scale'))
|
||||
parser.add_argument(
|
||||
'--I',
|
||||
metavar="<param-file>",
|
||||
help=_("Specify scale request parameters in a json file."))
|
||||
parser.add_argument(
|
||||
'--type',
|
||||
metavar="<type>",
|
||||
choices=['SCALE_OUT', 'SCALE_IN'],
|
||||
help=_("Indicates the type of the scale operation requested"))
|
||||
parser.add_argument(
|
||||
'--aspect-id',
|
||||
metavar="<aspect-id>",
|
||||
help=_("Identifier of the scaling aspect."))
|
||||
parser.add_argument(
|
||||
'--number-of-steps',
|
||||
metavar="<number-of-steps>",
|
||||
type=int,
|
||||
help=_("Number of scaling steps to be executed as part of"
|
||||
help=_("Number of scaling steps to be executed as part of "
|
||||
"this Scale VNF operation."))
|
||||
parser.add_argument(
|
||||
'--additional-param-file',
|
||||
metavar="<additional-param-file>",
|
||||
help=_("Additional parameters passed by the NFVO as input"
|
||||
help=_("Additional parameters passed by the NFVO as input "
|
||||
"to the scaling process."))
|
||||
|
||||
scale_require_parameters = parser.add_argument_group(
|
||||
"require arguments"
|
||||
)
|
||||
scale_require_parameters.add_argument(
|
||||
'--type',
|
||||
metavar="<type>",
|
||||
required=True,
|
||||
choices=['SCALE_OUT', 'SCALE_IN'],
|
||||
help=_("SCALE_OUT or SCALE_IN for type of scale operation."))
|
||||
scale_require_parameters.add_argument(
|
||||
'--aspect-id',
|
||||
required=True,
|
||||
metavar="<aspect-id>",
|
||||
help=_("Identifier of the scaling aspect."))
|
||||
|
||||
return parser
|
||||
|
||||
def args2body(self, file_path=None):
|
||||
def args2body(self, parsed_args):
|
||||
"""To store request body, call jsonfile2body.
|
||||
|
||||
Args:
|
||||
file_path ([string], optional): file path of param file(json).
|
||||
Defaults to None.
|
||||
parsed_args ([Namespace]): arguments of CLI.
|
||||
|
||||
Returns:
|
||||
body[dict]: [description]
|
||||
body ([dict]): Request body is stored
|
||||
"""
|
||||
body = {}
|
||||
body = {'type': parsed_args.type, 'aspectId': parsed_args.aspect_id}
|
||||
|
||||
if file_path:
|
||||
return jsonfile2body(file_path)
|
||||
if parsed_args.number_of_steps:
|
||||
body['numberOfSteps'] = parsed_args.number_of_steps
|
||||
|
||||
if parsed_args.additional_param_file:
|
||||
body.update(jsonfile2body(parsed_args.additional_param_file))
|
||||
|
||||
return body
|
||||
|
||||
@@ -523,13 +528,39 @@ class ScaleVnfLcm(command.Command):
|
||||
"""Execute scale_vnf_instance and output result comment.
|
||||
|
||||
Args:
|
||||
parsed_args ([Namespace]): [description]
|
||||
parsed_args ([Namespace]): arguments of CLI.
|
||||
"""
|
||||
client = self.app.client_manager.tackerclient
|
||||
if parsed_args.additional_param_file:
|
||||
result = client.scale_vnf_instance(
|
||||
parsed_args.vnf_instance,
|
||||
self.args2body(file_path=parsed_args.additional_param_file))
|
||||
if not result:
|
||||
print((_('Scale request for VNF Instance %(id)s has been'
|
||||
' accepted.') % {'id': parsed_args.vnf_instance}))
|
||||
result = client.scale_vnf_instance(
|
||||
parsed_args.vnf_instance,
|
||||
self.args2body(parsed_args))
|
||||
if not result:
|
||||
print((_('Scale request for VNF Instance %s has been accepted.')
|
||||
% parsed_args.vnf_instance))
|
||||
|
||||
|
||||
class ChangeExtConnVnfLcm(command.Command):
|
||||
_description = _("Change External VNF Connectivity")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ChangeExtConnVnfLcm, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_VNF_INSTANCE,
|
||||
metavar="<vnf-instance>",
|
||||
help=_("VNF instance ID to Change External VNF Connectivity"))
|
||||
parser.add_argument(
|
||||
'request_file',
|
||||
metavar="<param-file>",
|
||||
help=_("Specify change-ext-conn request parameters "
|
||||
"in a json file."))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.tackerclient
|
||||
result = client.change_ext_conn_vnf_instance(
|
||||
parsed_args.vnf_instance, jsonfile2body(
|
||||
parsed_args.request_file))
|
||||
if not result:
|
||||
print((_('Change External VNF Connectivity for VNF Instance %s '
|
||||
'has been accepted.') % parsed_args.vnf_instance))
|
||||
|
||||
@@ -11,7 +11,63 @@
|
||||
# under the License.
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
from tackerclient.i18n import _
|
||||
from tackerclient.osc import sdk_utils
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
|
||||
_VNF_LCM_OP_OCC_ID = 'vnf_lcm_op_occ_id'
|
||||
|
||||
_MIXED_CASE_FIELDS = ['operationState', 'stateEnteredTime', 'startTime',
|
||||
'vnfInstanceId', 'grantId', 'isAutomaticInvocation',
|
||||
'isCancelPending', 'cancelMode', 'operationParams',
|
||||
'resourceChanges', 'changedInfo',
|
||||
'changedExtConnectivity']
|
||||
|
||||
_FORMATTERS = {
|
||||
'operationParams': tacker_osc_utils.FormatComplexDataColumn,
|
||||
'error': tacker_osc_utils.FormatComplexDataColumn,
|
||||
'resourceChanges': tacker_osc_utils.FormatComplexDataColumn,
|
||||
'changedInfo': tacker_osc_utils.FormatComplexDataColumn,
|
||||
'changedExtConnectivity': tacker_osc_utils.FormatComplexDataColumn,
|
||||
'_links': tacker_osc_utils.FormatComplexDataColumn
|
||||
}
|
||||
|
||||
_ATTR_MAP = (
|
||||
('id', 'id', tacker_osc_utils.LIST_BOTH),
|
||||
('operationState', 'operationState', tacker_osc_utils.LIST_BOTH),
|
||||
('vnfInstanceId', 'vnfInstanceId', tacker_osc_utils.LIST_BOTH),
|
||||
('operation', 'operation', tacker_osc_utils.LIST_BOTH)
|
||||
)
|
||||
|
||||
|
||||
def _get_columns(vnflcm_op_occ_obj, action=None):
|
||||
|
||||
column_map = {
|
||||
'id': 'ID',
|
||||
'operationState': 'Operation State',
|
||||
'stateEnteredTime': 'State Entered Time',
|
||||
'startTime': 'Start Time',
|
||||
'vnfInstanceId': 'VNF Instance ID',
|
||||
'operation': 'Operation',
|
||||
'isAutomaticInvocation': 'Is Automatic Invocation',
|
||||
'isCancelPending': 'Is Cancel Pending',
|
||||
'error': 'Error',
|
||||
'_links': 'Links'
|
||||
}
|
||||
|
||||
if action == 'show':
|
||||
column_map.update(
|
||||
{'operationParams': 'Operation Parameters',
|
||||
'grantId': 'Grant ID',
|
||||
'resourceChanges': 'Resource Changes',
|
||||
'changedInfo': 'Changed Info',
|
||||
'cancelMode': 'Cancel Mode',
|
||||
'changedExtConnectivity': 'Changed External Connectivity'}
|
||||
)
|
||||
|
||||
return sdk_utils.get_osc_show_columns_for_sdk_resource(vnflcm_op_occ_obj,
|
||||
column_map)
|
||||
|
||||
|
||||
class RollbackVnfLcmOp(command.Command):
|
||||
@@ -26,7 +82,7 @@ class RollbackVnfLcmOp(command.Command):
|
||||
"""
|
||||
parser = super(RollbackVnfLcmOp, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'vnf_lcm_op_occ_id',
|
||||
_VNF_LCM_OP_OCC_ID,
|
||||
metavar="<vnf-lcm-op-occ-id>",
|
||||
help=_('VNF lifecycle management operation occurrence ID.'))
|
||||
|
||||
@@ -43,3 +99,208 @@ class RollbackVnfLcmOp(command.Command):
|
||||
if not result:
|
||||
print((_('Rollback request for LCM operation %(id)s has been'
|
||||
' accepted') % {'id': parsed_args.vnf_lcm_op_occ_id}))
|
||||
|
||||
|
||||
class FailVnfLcmOp(command.ShowOne):
|
||||
_description = _("Fail VNF Instance")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
"""Add arguments to parser.
|
||||
|
||||
Args:
|
||||
prog_name ([type]): program name
|
||||
|
||||
Returns:
|
||||
parser([ArgumentParser]):
|
||||
"""
|
||||
parser = super(FailVnfLcmOp, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_VNF_LCM_OP_OCC_ID,
|
||||
metavar="<vnf-lcm-op-occ-id>",
|
||||
help=_('VNF lifecycle management operation occurrence ID.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Execute fail_vnf_instance and output response.
|
||||
|
||||
Args:
|
||||
parsed_args ([Namespace]): arguments of CLI.
|
||||
"""
|
||||
client = self.app.client_manager.tackerclient
|
||||
obj = client.fail_vnf_instance(parsed_args.vnf_lcm_op_occ_id)
|
||||
display_columns, columns = _get_columns(obj)
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj),
|
||||
columns, formatters=_FORMATTERS,
|
||||
mixed_case_fields=_MIXED_CASE_FIELDS)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class RetryVnfLcmOp(command.Command):
|
||||
_description = _("Retry VNF Instance")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
"""Add arguments to parser.
|
||||
|
||||
Args:
|
||||
prog_name ([type]): program name
|
||||
|
||||
Returns:
|
||||
parser([ArgumentParser]):
|
||||
"""
|
||||
|
||||
parser = super(RetryVnfLcmOp, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_VNF_LCM_OP_OCC_ID,
|
||||
metavar="<vnf-lcm-op-occ-id>",
|
||||
help=_('VNF lifecycle management operation occurrence ID.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Execute retry_vnf_instance and output comment.
|
||||
|
||||
Args:
|
||||
parsed_args ([Namespace]): arguments of CLI.
|
||||
"""
|
||||
client = self.app.client_manager.tackerclient
|
||||
result = client.retry_vnf_instance(parsed_args.vnf_lcm_op_occ_id)
|
||||
if not result:
|
||||
print((_('Retry request for LCM operation %(id)s has been'
|
||||
' accepted') % {'id': parsed_args.vnf_lcm_op_occ_id}))
|
||||
|
||||
|
||||
class ListVnfLcmOp(command.Lister):
|
||||
_description = _("List LCM Operation Occurrences")
|
||||
|
||||
def get_parser(self, program_name):
|
||||
"""Add arguments to parser.
|
||||
|
||||
Args:
|
||||
program_name ([type]): program name
|
||||
|
||||
Returns:
|
||||
parser([ArgumentParser]):
|
||||
"""
|
||||
parser = super(ListVnfLcmOp, self).get_parser(program_name)
|
||||
parser.add_argument(
|
||||
"--filter",
|
||||
metavar="<filter>",
|
||||
help=_("Attribute-based-filtering parameters"),
|
||||
)
|
||||
fields_exclusive_group = parser.add_mutually_exclusive_group(
|
||||
required=False)
|
||||
fields_exclusive_group.add_argument(
|
||||
"--fields",
|
||||
metavar="<fields>",
|
||||
help=_("Complex attributes to be included into the response"),
|
||||
)
|
||||
fields_exclusive_group.add_argument(
|
||||
"--exclude-fields",
|
||||
metavar="<exclude-fields>",
|
||||
help=_("Complex attributes to be excluded from the response"),
|
||||
)
|
||||
return parser
|
||||
|
||||
def get_attributes(self):
|
||||
"""Get attributes.
|
||||
|
||||
Returns:
|
||||
attributes([attributes]): a list of table entry definitions.
|
||||
Each entry should be a tuple consisting of
|
||||
(API attribute name, header name, listing mode).
|
||||
"""
|
||||
fields = [
|
||||
{
|
||||
"key": "id",
|
||||
"value": "ID"
|
||||
},
|
||||
{
|
||||
"key": "operationState",
|
||||
"value": "Operation State"
|
||||
},
|
||||
{
|
||||
"key": "vnfInstanceId",
|
||||
"value": "VNF Instance ID"
|
||||
},
|
||||
{
|
||||
"key": "operation",
|
||||
"value": "Operation"
|
||||
}
|
||||
]
|
||||
|
||||
attributes = []
|
||||
for field in fields:
|
||||
attributes.extend([(field['key'], field['value'],
|
||||
tacker_osc_utils.LIST_BOTH)])
|
||||
|
||||
return tuple(attributes)
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Execute list_vnflcm_op_occs and output response.
|
||||
|
||||
Args:
|
||||
parsed_args ([Namespace]): arguments of CLI.
|
||||
"""
|
||||
params = {}
|
||||
exclude_fields = []
|
||||
extra_fields = []
|
||||
|
||||
if parsed_args.filter:
|
||||
params['filter'] = parsed_args.filter
|
||||
if parsed_args.fields:
|
||||
params['fields'] = parsed_args.fields
|
||||
fields = parsed_args.fields.split(',')
|
||||
for field in fields:
|
||||
extra_fields.append(field.split('/')[0])
|
||||
if parsed_args.exclude_fields:
|
||||
params['exclude-fields'] = parsed_args.exclude_fields
|
||||
fields = parsed_args.exclude_fields.split(',')
|
||||
exclude_fields.extend(fields)
|
||||
|
||||
client = self.app.client_manager.tackerclient
|
||||
vnflcm_op_occs = client.list_vnf_lcm_op_occs(**params)
|
||||
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||
self.get_attributes(),
|
||||
long_listing=True)
|
||||
|
||||
dictionary_properties = (utils.get_dict_properties(
|
||||
s, columns, mixed_case_fields=_MIXED_CASE_FIELDS)
|
||||
for s in vnflcm_op_occs
|
||||
)
|
||||
|
||||
return (headers, dictionary_properties)
|
||||
|
||||
|
||||
class ShowVnfLcmOp(command.ShowOne):
|
||||
_description = _("Display Operation Occurrence details")
|
||||
|
||||
def get_parser(self, program_name):
|
||||
"""Add arguments to parser.
|
||||
|
||||
Args:
|
||||
program_name ([type]): program name
|
||||
|
||||
Returns:
|
||||
parser([ArgumentParser]):
|
||||
"""
|
||||
parser = super(ShowVnfLcmOp, self).get_parser(program_name)
|
||||
parser.add_argument(
|
||||
_VNF_LCM_OP_OCC_ID,
|
||||
metavar="<vnf-lcm-op-occ-id>",
|
||||
help=_('VNF lifecycle management operation occurrence ID.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Execute show_vnf_lcm_op_occs and output response.
|
||||
|
||||
Args:
|
||||
parsed_args ([Namespace]): arguments of CLI.
|
||||
"""
|
||||
client = self.app.client_manager.tackerclient
|
||||
obj = client.show_vnf_lcm_op_occs(parsed_args.vnf_lcm_op_occ_id)
|
||||
display_columns, columns = _get_columns(obj, action='show')
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj),
|
||||
columns, formatters=_FORMATTERS,
|
||||
mixed_case_fields=_MIXED_CASE_FIELDS)
|
||||
return (display_columns, data)
|
||||
|
||||
@@ -218,7 +218,7 @@ class ShowTemplateVNFD(command.ShowOne):
|
||||
obj[_VNFD]['attributes']['vnfd'])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_VNFD]),
|
||||
(u'attributes',),
|
||||
('attributes',),
|
||||
formatters=_formatters)
|
||||
data = (data or _('Unable to display VNFD template!'))
|
||||
return ((u'attributes',), data)
|
||||
return (('attributes',), data)
|
||||
|
||||
@@ -434,9 +434,9 @@ class DownloadVnfPackageArtifact(command.Command):
|
||||
parser.add_argument(
|
||||
"--file",
|
||||
metavar="<FILE>",
|
||||
help=_("Local file to save downloaded VNF Package or VNFD data. "
|
||||
"If this is not specified and there is no redirection "
|
||||
"then data will not be saved.")
|
||||
help=_("Local file to save downloaded VNF Package artifact "
|
||||
"file data. If this is not specified and "
|
||||
"there is no redirection then data will not be saved.")
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ import itertools
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from urllib import parse as urlparse
|
||||
|
||||
from cliff import app
|
||||
from cliff import commandmanager
|
||||
|
||||
from keystoneclient.auth.identity import v2 as v2_auth
|
||||
from keystoneclient.auth.identity import v3 as v3_auth
|
||||
@@ -32,10 +36,6 @@ from keystoneclient import discover
|
||||
from keystoneclient import exceptions as ks_exc
|
||||
from keystoneclient import session
|
||||
from oslo_utils import encodeutils
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
from cliff import app
|
||||
from cliff import commandmanager
|
||||
|
||||
from tackerclient.common import clientmanager
|
||||
from tackerclient.common import command as openstack_command
|
||||
|
||||
@@ -23,7 +23,6 @@ from cliff.formatters import table
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
|
||||
from tackerclient.common._i18n import _
|
||||
from tackerclient.common import command
|
||||
@@ -354,8 +353,7 @@ class TackerCommandMeta(abc.ABCMeta):
|
||||
name, bases, cls_dict)
|
||||
|
||||
|
||||
@six.add_metaclass(TackerCommandMeta)
|
||||
class TackerCommand(command.OpenStackCommand):
|
||||
class TackerCommand(command.OpenStackCommand, metaclass=TackerCommandMeta):
|
||||
|
||||
api = 'nfv-orchestration'
|
||||
values_specs = []
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
# 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 urllib import parse as urlparse
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ from unittest import mock
|
||||
|
||||
import ddt
|
||||
from oslo_utils.fixture import uuidsentinel
|
||||
import six
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
@@ -448,7 +447,7 @@ class TestTerminateVnfLcm(TestVnfLcm):
|
||||
"delete vnf instance %(id)s"
|
||||
% {'timeout': 15, 'id': vnf_instance['id']})
|
||||
|
||||
self.assertIn(expected_message, six.text_type(result))
|
||||
self.assertIn(expected_message, str(result))
|
||||
self.assertNotCalled(mock_delete)
|
||||
|
||||
def test_terminate_no_options(self):
|
||||
@@ -652,6 +651,38 @@ class TestScaleVnfLcm(TestVnfLcm):
|
||||
|
||||
self.assertEqual(expected_message, actual_message)
|
||||
|
||||
@ddt.data('SCALE_IN', 'SCALE_OUT')
|
||||
def test_take_action_no_param_file(self, scale_type):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
|
||||
arglist = [vnf_instance['id'],
|
||||
'--aspect-id', uuidsentinel.aspect_id,
|
||||
'--number-of-steps', '1',
|
||||
'--type', scale_type]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('aspect_id', uuidsentinel.aspect_id),
|
||||
('number_of_steps', 1),
|
||||
('type', scale_type)]
|
||||
|
||||
parsed_args = self.check_parser(self.scale_vnf_lcm, arglist,
|
||||
verifylist)
|
||||
|
||||
url = os.path.join(self.url, 'vnflcm/v1/vnf_instances',
|
||||
vnf_instance['id'], 'scale')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, json={})
|
||||
|
||||
sys.stdout = buffer = StringIO()
|
||||
self.scale_vnf_lcm.take_action(parsed_args)
|
||||
|
||||
actual_message = buffer.getvalue().strip()
|
||||
|
||||
expected_message = ("Scale request for VNF Instance %s has been "
|
||||
"accepted.") % vnf_instance['id']
|
||||
|
||||
self.assertEqual(expected_message, actual_message)
|
||||
|
||||
@ddt.data('SCALE_IN', 'SCALE_OUT')
|
||||
def test_take_action_param_file_not_exists(self, scale_type):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
@@ -708,3 +739,110 @@ class TestScaleVnfLcm(TestVnfLcm):
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.scale_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
|
||||
class TestChangeExtConnVnfLcm(TestVnfLcm):
|
||||
|
||||
def setUp(self):
|
||||
super(TestChangeExtConnVnfLcm, self).setUp()
|
||||
self.change_ext_conn_vnf_lcm = vnflcm.ChangeExtConnVnfLcm(
|
||||
self.app, self.app_args,
|
||||
cmd_name='vnflcm change-ext-conn')
|
||||
|
||||
def test_take_action(self):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
|
||||
"change_ext_conn_vnf_instance_param_sample.json")
|
||||
|
||||
arglist = [vnf_instance['id'], sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('request_file', sample_param_file)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(self.change_ext_conn_vnf_lcm,
|
||||
arglist,
|
||||
verifylist)
|
||||
|
||||
url = os.path.join(self.url, 'vnflcm/v1/vnf_instances',
|
||||
vnf_instance['id'], 'change_ext_conn')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, json={})
|
||||
|
||||
sys.stdout = buffer = StringIO()
|
||||
with mock.patch.object(proxy_client.ClientBase,
|
||||
'_handle_fault_response') as m:
|
||||
self.change_ext_conn_vnf_lcm.take_action(parsed_args)
|
||||
# check no fault response is received
|
||||
self.assertNotCalled(m)
|
||||
self.assertEqual(
|
||||
('Change External VNF Connectivity for VNF Instance {0} '
|
||||
'has been accepted.'.format(vnf_instance['id'])),
|
||||
buffer.getvalue().strip())
|
||||
|
||||
def test_take_action_vnf_instance_not_found(self):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
|
||||
"change_ext_conn_vnf_instance_param_sample.json")
|
||||
arglist = [vnf_instance['id'], sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('request_file', sample_param_file)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(self.change_ext_conn_vnf_lcm,
|
||||
arglist,
|
||||
verifylist)
|
||||
|
||||
url = os.path.join(self.url, 'vnflcm/v1/vnf_instances',
|
||||
vnf_instance['id'], 'change_ext_conn')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=404, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.change_ext_conn_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_param_file_not_exists(self):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = "./not_exists.json"
|
||||
arglist = [vnf_instance['id'], sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('request_file', sample_param_file)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.change_ext_conn_vnf_lcm,
|
||||
arglist,
|
||||
verifylist)
|
||||
|
||||
ex = self.assertRaises(
|
||||
exceptions.InvalidInput,
|
||||
self.change_ext_conn_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
expected_msg = ("Invalid input: File %s does not exist "
|
||||
"or user does not have read privileges to it")
|
||||
self.assertEqual(expected_msg % sample_param_file, str(ex))
|
||||
|
||||
@mock.patch("os.open")
|
||||
@mock.patch("os.access")
|
||||
def test_take_action_invalid_format_param_file(self, mock_open,
|
||||
mock_access):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = "./invalid_param_file.json"
|
||||
arglist = [vnf_instance['id'], sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('request_file', sample_param_file)]
|
||||
|
||||
mock_open.return_value = "invalid_json_data"
|
||||
# command param
|
||||
parsed_args = self.check_parser(self.change_ext_conn_vnf_lcm,
|
||||
arglist,
|
||||
verifylist)
|
||||
|
||||
ex = self.assertRaises(
|
||||
exceptions.InvalidInput,
|
||||
self.change_ext_conn_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
expected_msg = "Failed to load parameter file."
|
||||
self.assertIn(expected_msg, str(ex))
|
||||
|
||||
@@ -18,9 +18,30 @@ from oslo_utils.fixture import uuidsentinel
|
||||
from unittest import mock
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
from tackerclient.osc.v1.vnflcm import vnflcm_op_occs
|
||||
from tackerclient.tests.unit.osc import base
|
||||
from tackerclient.tests.unit.osc.v1.fixture_data import client
|
||||
from tackerclient.tests.unit.osc.v1 import vnflcm_op_occs_fakes
|
||||
|
||||
|
||||
def _get_columns_vnflcm_op_occs(action='show'):
|
||||
|
||||
if action == 'fail':
|
||||
return ['ID', 'Operation State', 'State Entered Time',
|
||||
'Start Time', 'VNF Instance ID', 'Operation',
|
||||
'Is Automatic Invocation', 'Is Cancel Pending',
|
||||
'Error', 'Links']
|
||||
elif action == 'list':
|
||||
return ['ID', 'Operation State', 'VNF Instance ID',
|
||||
'Operation']
|
||||
else:
|
||||
return ['ID', 'Operation State', 'State Entered Time',
|
||||
'Start Time', 'VNF Instance ID', 'Grant ID',
|
||||
'Operation', 'Is Automatic Invocation',
|
||||
'Operation Parameters', 'Is Cancel Pending',
|
||||
'Cancel Mode', 'Error', 'Resource Changes',
|
||||
'Changed Info', 'Changed External Connectivity', 'Links']
|
||||
|
||||
|
||||
class TestVnfLcm(base.FixturedTestCase):
|
||||
@@ -92,3 +113,391 @@ class TestRollbackVnfLcmOp(TestVnfLcm):
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.rollback_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
|
||||
class TestFailVnfLcmOp(TestVnfLcm):
|
||||
|
||||
def setUp(self):
|
||||
super(TestFailVnfLcmOp, self).setUp()
|
||||
self.fail_vnf_lcm = vnflcm_op_occs.FailVnfLcmOp(
|
||||
self.app, self.app_args, cmd_name='vnflcm op fail')
|
||||
|
||||
def test_take_action(self):
|
||||
"""Test of take_action()"""
|
||||
|
||||
vnflcm_op_occ = vnflcm_op_occs_fakes.vnflcm_op_occ_response(
|
||||
action='fail')
|
||||
|
||||
arg_list = [vnflcm_op_occ['id']]
|
||||
verify_list = [('vnf_lcm_op_occ_id', vnflcm_op_occ['id'])]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.fail_vnf_lcm, arg_list, verify_list)
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
vnflcm_op_occ['id'],
|
||||
'fail')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, json=vnflcm_op_occ)
|
||||
|
||||
columns, data = (self.fail_vnf_lcm.take_action(parsed_args))
|
||||
expected_columns = _get_columns_vnflcm_op_occs(action='fail')
|
||||
|
||||
self.assertCountEqual(expected_columns, columns)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_id_not_found(self):
|
||||
"""Test if vnf-lcm-op-occ-id does not find"""
|
||||
|
||||
arg_list = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verify_list = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.fail_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'fail')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=404, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.fail_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_state_is_conflict(self):
|
||||
"""Test if vnf-lcm-op-occ state is conflict"""
|
||||
|
||||
arg_list = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verify_list = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.fail_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'fail')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=409, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.fail_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_internal_server_error(self):
|
||||
"""Test if request is internal server error"""
|
||||
|
||||
arg_list = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verify_list = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.fail_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'fail')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=500, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.fail_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_missing_vnf_lcm_op_occ_id_argument(
|
||||
self):
|
||||
"""Test if vnflcm_op_occ_id is not provided"""
|
||||
|
||||
arg_list = []
|
||||
verify_list = [('vnf_lcm_op_occ_id', arg_list)]
|
||||
self.assertRaises(base.ParserException, self.check_parser,
|
||||
self.fail_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
|
||||
class TestRetryVnfLcmOp(TestVnfLcm):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRetryVnfLcmOp, self).setUp()
|
||||
self.retry_vnf_lcm = vnflcm_op_occs.RetryVnfLcmOp(
|
||||
self.app, self.app_args, cmd_name='vnflcm op retry')
|
||||
|
||||
def test_take_action(self):
|
||||
"""Test of take_action()"""
|
||||
arg_list = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verify_list = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.retry_vnf_lcm, arg_list, verify_list)
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'retry')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, json={})
|
||||
|
||||
sys.stdout = buffer = StringIO()
|
||||
self.retry_vnf_lcm.take_action(parsed_args)
|
||||
|
||||
actual_message = buffer.getvalue().strip()
|
||||
|
||||
expected_message = (
|
||||
'Retry request for LCM operation ' +
|
||||
uuidsentinel.vnf_lcm_op_occ_id +
|
||||
' has been accepted')
|
||||
|
||||
self.assertEqual(expected_message, actual_message)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_id_not_found(self):
|
||||
"""Test if vnf-lcm-op-occ-id is not found."""
|
||||
arglist = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verifylist = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.retry_vnf_lcm, arglist, verifylist)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'retry')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=404, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.retry_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_state_is_conflict(self):
|
||||
"""Test if vnf-lcm-op-occ state is conflict"""
|
||||
|
||||
arg_list = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verify_list = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.retry_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'retry')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=409, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.retry_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_internal_server_error(self):
|
||||
"""Test if request is internal server error"""
|
||||
|
||||
arg_list = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verify_list = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.retry_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id,
|
||||
'retry')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=500, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.retry_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_missing_vnf_lcm_op_occ_id_argument(
|
||||
self):
|
||||
"""Test if vnflcm_op_occ_id is not provided"""
|
||||
|
||||
arg_list = []
|
||||
verify_list = [('vnf_lcm_op_occ_id', arg_list)]
|
||||
self.assertRaises(base.ParserException, self.check_parser,
|
||||
self.retry_vnf_lcm, arg_list, verify_list)
|
||||
|
||||
|
||||
class TestListVnfLcmOp(TestVnfLcm):
|
||||
|
||||
def setUp(self):
|
||||
super(TestListVnfLcmOp, self).setUp()
|
||||
self.list_vnflcm_op_occ = vnflcm_op_occs.ListVnfLcmOp(
|
||||
self.app, self.app_args, cmd_name='vnflcm op list')
|
||||
|
||||
def test_take_action(self):
|
||||
vnflcm_op_occs_obj = vnflcm_op_occs_fakes.create_vnflcm_op_occs(
|
||||
count=3)
|
||||
parsed_args = self.check_parser(self.list_vnflcm_op_occ, [], [])
|
||||
self.requests_mock.register_uri(
|
||||
'GET', os.path.join(self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs'),
|
||||
json=vnflcm_op_occs_obj, headers=self.header)
|
||||
|
||||
actual_columns, data = self.list_vnflcm_op_occ.take_action(parsed_args)
|
||||
|
||||
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||
self.list_vnflcm_op_occ.get_attributes(), long_listing=True)
|
||||
|
||||
expected_data = []
|
||||
for vnflcm_op_occ_obj_idx in vnflcm_op_occs_obj:
|
||||
expected_data.append(vnflcm_op_occs_fakes.get_vnflcm_op_occ_data(
|
||||
vnflcm_op_occ_obj_idx, columns=columns))
|
||||
|
||||
self.assertCountEqual(_get_columns_vnflcm_op_occs(action='list'),
|
||||
actual_columns)
|
||||
self.assertCountEqual(expected_data, list(data))
|
||||
|
||||
def test_take_action_with_filter(self):
|
||||
vnflcm_op_occs_obj = vnflcm_op_occs_fakes.create_vnflcm_op_occs(
|
||||
count=3)
|
||||
parsed_args = self.check_parser(
|
||||
self.list_vnflcm_op_occ,
|
||||
["--filter", '(eq,operationState,STARTING)'],
|
||||
[('filter', '(eq,operationState,STARTING)')])
|
||||
self.requests_mock.register_uri(
|
||||
'GET', os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs?'
|
||||
'filter=(eq,operationState,STARTING)'),
|
||||
json=vnflcm_op_occs_obj, headers=self.header)
|
||||
|
||||
actual_columns, data = self.list_vnflcm_op_occ.take_action(parsed_args)
|
||||
|
||||
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||
self.list_vnflcm_op_occ.get_attributes(), long_listing=True)
|
||||
|
||||
expected_data = []
|
||||
for vnflcm_op_occ_obj_idx in vnflcm_op_occs_obj:
|
||||
expected_data.append(vnflcm_op_occs_fakes.get_vnflcm_op_occ_data(
|
||||
vnflcm_op_occ_obj_idx, columns=columns))
|
||||
|
||||
self.assertCountEqual(_get_columns_vnflcm_op_occs(action='list'),
|
||||
actual_columns)
|
||||
self.assertListItemsEqual(expected_data, list(data))
|
||||
|
||||
def test_take_action_with_incorrect_filter(self):
|
||||
|
||||
parsed_args = self.check_parser(
|
||||
self.list_vnflcm_op_occ,
|
||||
["--filter", '(operationState)'],
|
||||
[('filter', '(operationState)')])
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs?filter=(operationState)')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=400, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.list_vnflcm_op_occ.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_internal_server_error(self):
|
||||
|
||||
parsed_args = self.check_parser(
|
||||
self.list_vnflcm_op_occ,
|
||||
["--filter", '(eq,operationState,STARTING)'],
|
||||
[('filter', '(eq,operationState,STARTING)')])
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs?'
|
||||
'filter=(eq,operationState,STARTING)')
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, status_code=500, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.list_vnflcm_op_occ.take_action,
|
||||
parsed_args)
|
||||
|
||||
|
||||
class TestShowVnfLcmOp(TestVnfLcm):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShowVnfLcmOp, self).setUp()
|
||||
self.show_vnf_lcm_op_occs = vnflcm_op_occs.ShowVnfLcmOp(
|
||||
self.app, self.app_args, cmd_name='vnflcm op show')
|
||||
|
||||
def test_take_action(self):
|
||||
"""Test of take_action()"""
|
||||
vnflcm_op_occ = vnflcm_op_occs_fakes.vnflcm_op_occ_response()
|
||||
|
||||
arglist = [vnflcm_op_occ['id']]
|
||||
verifylist = [('vnf_lcm_op_occ_id', vnflcm_op_occ['id'])]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.show_vnf_lcm_op_occs, arglist, verifylist)
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
vnflcm_op_occ['id'])
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'GET', url, headers=self.header, json=vnflcm_op_occ)
|
||||
|
||||
columns, data = (self.show_vnf_lcm_op_occs.take_action(parsed_args))
|
||||
|
||||
self.assertCountEqual(_get_columns_vnflcm_op_occs(),
|
||||
columns)
|
||||
|
||||
def test_take_action_vnf_lcm_op_occ_id_not_found(self):
|
||||
"""Test if vnf-lcm-op-occ-id does not find."""
|
||||
arglist = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verifylist = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.show_vnf_lcm_op_occs, arglist, verifylist)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id)
|
||||
self.requests_mock.register_uri(
|
||||
'GET', url, headers=self.header, status_code=404, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.show_vnf_lcm_op_occs.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_take_action_internal_server_error(self):
|
||||
"""Test for internal server error."""
|
||||
arglist = [uuidsentinel.vnf_lcm_op_occ_id]
|
||||
verifylist = [('vnf_lcm_op_occ_id', uuidsentinel.vnf_lcm_op_occ_id)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.show_vnf_lcm_op_occs, arglist, verifylist)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_lcm_op_occs',
|
||||
uuidsentinel.vnf_lcm_op_occ_id)
|
||||
self.requests_mock.register_uri(
|
||||
'GET', url, headers=self.header, status_code=500, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.show_vnf_lcm_op_occs.take_action,
|
||||
parsed_args)
|
||||
|
||||
107
tackerclient/tests/unit/osc/v1/vnflcm_op_occs_fakes.py
Normal file
107
tackerclient/tests/unit/osc/v1/vnflcm_op_occs_fakes.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_utils.fixture import uuidsentinel
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
|
||||
|
||||
def vnflcm_op_occ_response(attrs=None, action=''):
|
||||
"""Create a fake vnflcm op occurrence.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
A vnf lcm op occs dict
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attributes.
|
||||
dummy_vnf_lcm_op_occ = {
|
||||
"id": uuidsentinel.vnflcm_op_occ_id,
|
||||
"operationState": "STARTING",
|
||||
"stateEnteredTime": "2018-12-22T16:59:45.187Z",
|
||||
"startTime": "2018-12-22T16:59:45.187Z",
|
||||
"vnfInstanceId": "376f37f3-d4e9-4d41-8e6a-9b0ec98695cc",
|
||||
"grantId": "",
|
||||
"operation": "INSTANTIATE",
|
||||
"isAutomaticInvocation": "true",
|
||||
"operationParams": {
|
||||
"flavourId": "default",
|
||||
"instantiationLevelId": "n-mme-min"
|
||||
},
|
||||
"isCancelPending": "true",
|
||||
"cancelMode": "",
|
||||
"error": {
|
||||
"status": "500",
|
||||
"detail": "internal server error"
|
||||
},
|
||||
"resourceChanges": [],
|
||||
"changedInfo": [],
|
||||
"changedExtConnectivity": [],
|
||||
"_links": {
|
||||
"self": ""
|
||||
}
|
||||
}
|
||||
|
||||
if action == 'fail':
|
||||
fail_not_needed_columns = [
|
||||
'grantId', 'operationParams',
|
||||
'cancelMode', 'resourceChanges', 'changedInfo',
|
||||
'changedExtConnectivity']
|
||||
|
||||
for key in fail_not_needed_columns:
|
||||
del dummy_vnf_lcm_op_occ[key]
|
||||
|
||||
# Overwrite default attributes.
|
||||
dummy_vnf_lcm_op_occ.update(attrs)
|
||||
|
||||
return dummy_vnf_lcm_op_occ
|
||||
|
||||
|
||||
def get_vnflcm_op_occ_data(vnf_lcm_op_occ, columns=None):
|
||||
"""Get the vnflcm op occurrence.
|
||||
|
||||
:return:
|
||||
A tuple object sorted based on the name of the columns.
|
||||
"""
|
||||
complex_attributes = [
|
||||
'operationParams', 'error', 'resourceChanges',
|
||||
'changedInfo', 'changedExtConnectivity', 'links']
|
||||
|
||||
for attribute in complex_attributes:
|
||||
if vnf_lcm_op_occ.get(attribute):
|
||||
vnf_lcm_op_occ.update(
|
||||
{attribute: tacker_osc_utils.FormatComplexDataColumn(
|
||||
vnf_lcm_op_occ[attribute])})
|
||||
|
||||
# return the list of data as per column order
|
||||
if columns:
|
||||
return tuple([vnf_lcm_op_occ[key] for key in columns])
|
||||
|
||||
return tuple([vnf_lcm_op_occ[key] for key in sorted(
|
||||
vnf_lcm_op_occ.keys())])
|
||||
|
||||
|
||||
def create_vnflcm_op_occs(count=2):
|
||||
"""Create multiple fake vnflcm op occs.
|
||||
|
||||
:param count: The number of vnflcm op occs to fake
|
||||
:return:
|
||||
A list of fake vnflcm op occs dictionary
|
||||
"""
|
||||
vnflcm_op_occs = []
|
||||
for i in range(0, count):
|
||||
unique_id = uuidutils.generate_uuid()
|
||||
vnflcm_op_occs.append(vnflcm_op_occ_response(attrs={'id': unique_id}))
|
||||
return vnflcm_op_occs
|
||||
@@ -14,15 +14,14 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
from unittest import mock
|
||||
import urllib
|
||||
|
||||
import contextlib
|
||||
import fixtures
|
||||
import six
|
||||
import six.moves.urllib.parse as urlparse
|
||||
import io
|
||||
import sys
|
||||
import testtools
|
||||
from unittest import mock
|
||||
import urllib
|
||||
from urllib import parse as urlparse
|
||||
|
||||
from tackerclient.common import constants
|
||||
from tackerclient.common import exceptions
|
||||
@@ -40,7 +39,7 @@ ENDURL = 'localurl'
|
||||
|
||||
@contextlib.contextmanager
|
||||
def capture_std_streams():
|
||||
fake_stdout, fake_stderr = six.StringIO(), six.StringIO()
|
||||
fake_stdout, fake_stderr = io.StringIO(), io.StringIO()
|
||||
stdout, stderr = sys.stdout, sys.stderr
|
||||
try:
|
||||
sys.stdout, sys.stderr = fake_stdout, fake_stderr
|
||||
@@ -317,7 +316,7 @@ class CLITestV10Base(testtools.TestCase):
|
||||
args.append("--tag")
|
||||
for tag in tags:
|
||||
args.append(tag)
|
||||
if isinstance(tag, six.string_types):
|
||||
if isinstance(tag, str):
|
||||
tag = urllib.quote(tag.encode('utf-8'))
|
||||
if query:
|
||||
query += "&tag=" + tag
|
||||
@@ -414,7 +413,7 @@ class CLITestV10Base(testtools.TestCase):
|
||||
args.append("--tag")
|
||||
for tag in tags:
|
||||
args.append(tag)
|
||||
if isinstance(tag, six.string_types):
|
||||
if isinstance(tag, str):
|
||||
tag = urllib.quote(tag.encode('utf-8'))
|
||||
if query:
|
||||
query += "&tag=" + tag
|
||||
@@ -654,8 +653,8 @@ class CLITestV10Base(testtools.TestCase):
|
||||
class ClientV1TestJson(CLITestV10Base):
|
||||
def test_do_request_unicode(self):
|
||||
self.client.format = self.format
|
||||
unicode_text = u'\u7f51\u7edc'
|
||||
action = u'/test'
|
||||
unicode_text = '\u7f51\u7edc'
|
||||
action = '/test'
|
||||
params = {'test': unicode_text}
|
||||
body = params
|
||||
expect_body = self.client.serialize(body)
|
||||
@@ -664,7 +663,7 @@ class ClientV1TestJson(CLITestV10Base):
|
||||
mock_req.return_value = (MyResp(200), expect_body)
|
||||
res_body = self.client.do_request('PUT', action, body=body,
|
||||
params=params)
|
||||
expected_uri = u'localurl/v1.0/test.json?test=%E7%BD%91%E7%BB%9C'
|
||||
expected_uri = 'localurl/v1.0/test.json?test=%E7%BD%91%E7%BB%9C'
|
||||
mock_req.assert_called_with(
|
||||
expected_uri, 'PUT', body=expect_body,
|
||||
headers={'X-Auth-Token': unicode_text,
|
||||
@@ -799,3 +798,27 @@ class CLITestV10ExceptionHandler(CLITestV10Base):
|
||||
exceptions.TackerClientException, 500,
|
||||
expected_msg=expected_msg,
|
||||
error_content=error_content)
|
||||
|
||||
def test_exception_handler_v10_tacker_etsi_error(self):
|
||||
"""Test ETSI error response"""
|
||||
|
||||
known_error_map = [
|
||||
({
|
||||
"status": "status 1",
|
||||
"detail": "sample 1"
|
||||
}, 400),
|
||||
({
|
||||
"status": "status 2",
|
||||
"detail": "sample 2"
|
||||
}, 404),
|
||||
({
|
||||
"status": "status 3",
|
||||
"detail": "sample 3"
|
||||
}, 409)
|
||||
]
|
||||
|
||||
for error_content, status_code in known_error_map:
|
||||
self._test_exception_handler_v10(
|
||||
exceptions.TackerClientException, status_code,
|
||||
expected_msg=error_content['detail'],
|
||||
error_content=error_content)
|
||||
|
||||
@@ -14,18 +14,17 @@
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import fixtures
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from unittest import mock
|
||||
|
||||
import six
|
||||
import sys
|
||||
|
||||
import fixtures
|
||||
from keystoneclient import session
|
||||
import testtools
|
||||
from testtools import matchers
|
||||
from unittest import mock
|
||||
|
||||
from keystoneclient import session
|
||||
|
||||
from tackerclient.common import clientmanager
|
||||
from tackerclient import shell as openstack_shell
|
||||
@@ -63,8 +62,8 @@ class ShellTest(testtools.TestCase):
|
||||
clean_env = {}
|
||||
_old_env, os.environ = os.environ, clean_env.copy()
|
||||
try:
|
||||
sys.stdout = six.StringIO()
|
||||
sys.stderr = six.StringIO()
|
||||
sys.stdout = io.StringIO()
|
||||
sys.stderr = io.StringIO()
|
||||
_shell = openstack_shell.TackerShell(DEFAULT_API_VERSION)
|
||||
_shell.run(argstr.split())
|
||||
except SystemExit:
|
||||
@@ -155,10 +154,10 @@ class ShellTest(testtools.TestCase):
|
||||
@mock.patch.object(openstack_shell.TackerShell, 'run')
|
||||
def test_main_with_unicode(self, mock_run):
|
||||
mock_run.return_value = 0
|
||||
unicode_text = u'\u7f51\u7edc'
|
||||
unicode_text = '\u7f51\u7edc'
|
||||
argv = ['net-list', unicode_text, unicode_text.encode('utf-8')]
|
||||
ret = openstack_shell.main(argv=argv)
|
||||
mock_run.assert_called_once_with([u'net-list', unicode_text,
|
||||
mock_run.assert_called_once_with(['net-list', unicode_text,
|
||||
unicode_text])
|
||||
self.assertEqual(0, ret)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import logging
|
||||
import time
|
||||
|
||||
import requests
|
||||
import six.moves.urllib.parse as urlparse
|
||||
from urllib import parse as urlparse
|
||||
|
||||
from tackerclient import client
|
||||
from tackerclient.common import constants
|
||||
@@ -54,6 +54,7 @@ def exception_handler_v10(status_code, error_content):
|
||||
:param status_code: HTTP error status code
|
||||
:param error_content: deserialized body of error response
|
||||
"""
|
||||
etsi_error_content = error_content
|
||||
error_dict = None
|
||||
if isinstance(error_content, dict):
|
||||
error_dict = error_content.get('TackerError')
|
||||
@@ -94,6 +95,13 @@ def exception_handler_v10(status_code, error_content):
|
||||
if message:
|
||||
raise exceptions.TackerClientException(status_code=status_code,
|
||||
message=message)
|
||||
# ETSI error response
|
||||
if isinstance(etsi_error_content, dict):
|
||||
if etsi_error_content.get('status') and \
|
||||
etsi_error_content.get('detail'):
|
||||
message = etsi_error_content.get('detail')
|
||||
raise exceptions.TackerClientException(status_code=status_code,
|
||||
message=message)
|
||||
|
||||
# If we end up here the exception was not a tacker error
|
||||
msg = "%s-%s" % (status_code, error_content)
|
||||
@@ -868,6 +876,7 @@ class VnfLCMClient(ClientBase):
|
||||
|
||||
vnf_instances_path = '/vnflcm/v1/vnf_instances'
|
||||
vnf_instance_path = '/vnflcm/v1/vnf_instances/%s'
|
||||
vnf_lcm_op_occurrences_path = '/vnflcm/v1/vnf_lcm_op_occs'
|
||||
vnf_lcm_op_occs_path = '/vnflcm/v1/vnf_lcm_op_occs/%s'
|
||||
|
||||
def build_action(self, action):
|
||||
@@ -919,6 +928,29 @@ class VnfLCMClient(ClientBase):
|
||||
def rollback_vnf_instance(self, occ_id):
|
||||
return self.post((self.vnf_lcm_op_occs_path + "/rollback") % occ_id)
|
||||
|
||||
@APIParamsCall
|
||||
def fail_vnf_instance(self, occ_id):
|
||||
return self.post((self.vnf_lcm_op_occs_path + "/fail") % occ_id)
|
||||
|
||||
@APIParamsCall
|
||||
def change_ext_conn_vnf_instance(self, vnf_id, body):
|
||||
return self.post((self.vnf_instance_path + "/change_ext_conn") %
|
||||
vnf_id, body=body)
|
||||
|
||||
@APIParamsCall
|
||||
def retry_vnf_instance(self, occ_id):
|
||||
return self.post((self.vnf_lcm_op_occs_path + "/retry") % occ_id)
|
||||
|
||||
@APIParamsCall
|
||||
def list_vnf_lcm_op_occs(self, retrieve_all=True, **_params):
|
||||
vnf_lcm_op_occs = self.list(None, self.vnf_lcm_op_occurrences_path,
|
||||
retrieve_all, **_params)
|
||||
return vnf_lcm_op_occs
|
||||
|
||||
@APIParamsCall
|
||||
def show_vnf_lcm_op_occs(self, occ_id):
|
||||
return self.get(self.vnf_lcm_op_occs_path % occ_id)
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Unified interface to interact with multiple applications of tacker service.
|
||||
@@ -1192,6 +1224,9 @@ class Client(object):
|
||||
def scale_vnf_instance(self, vnf_id, body):
|
||||
return self.vnf_lcm_client.scale_vnf_instance(vnf_id, body)
|
||||
|
||||
def change_ext_conn_vnf_instance(self, vnf_id, body):
|
||||
return self.vnf_lcm_client.change_ext_conn_vnf_instance(vnf_id, body)
|
||||
|
||||
def delete_vnf_instance(self, vnf_id):
|
||||
return self.vnf_lcm_client.delete_vnf_instance(vnf_id)
|
||||
|
||||
@@ -1201,6 +1236,12 @@ class Client(object):
|
||||
def rollback_vnf_instance(self, occ_id):
|
||||
return self.vnf_lcm_client.rollback_vnf_instance(occ_id)
|
||||
|
||||
def fail_vnf_instance(self, occ_id):
|
||||
return self.vnf_lcm_client.fail_vnf_instance(occ_id)
|
||||
|
||||
def retry_vnf_instance(self, occ_id):
|
||||
return self.vnf_lcm_client.retry_vnf_instance(occ_id)
|
||||
|
||||
def update_vnf_package(self, vnf_package, body):
|
||||
return self.vnf_package_client.update_vnf_package(vnf_package, body)
|
||||
|
||||
@@ -1215,3 +1256,10 @@ class Client(object):
|
||||
|
||||
def download_vnf_package(self, vnf_package):
|
||||
return self.vnf_package_client.download_vnf_package(vnf_package)
|
||||
|
||||
def list_vnf_lcm_op_occs(self, retrieve_all=True, **_params):
|
||||
return self.vnf_lcm_client.list_vnf_lcm_op_occs(
|
||||
retrieve_all=retrieve_all, **_params)
|
||||
|
||||
def show_vnf_lcm_op_occs(self, occ_id):
|
||||
return self.vnf_lcm_client.show_vnf_lcm_op_occs(occ_id)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking>=3.0.1,<3.1.0 # Apache-2.0
|
||||
hacking>=4.0.0,<4.1.0 # Apache-2.0
|
||||
coverage!=4.4,>=4.0 # Apache-2.0
|
||||
ddt>=1.0.1 # MIT
|
||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||
|
||||
12
tox.ini
12
tox.ini
@@ -1,5 +1,5 @@
|
||||
[tox]
|
||||
envlist = py37,py36,pep8,docs
|
||||
envlist = py38,py36,pep8,docs
|
||||
minversion = 3.1.1
|
||||
skipsdist = True
|
||||
ignore_basepython_conflict = True
|
||||
@@ -13,7 +13,7 @@ setenv = VIRTUAL_ENV={envdir}
|
||||
usedevelop = True
|
||||
install_command = pip install {opts} {packages}
|
||||
deps =
|
||||
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/wallaby}
|
||||
-r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = stestr run --slowest {posargs}
|
||||
@@ -31,7 +31,7 @@ commands = sphinx-build -W -b html doc/source doc/build/html
|
||||
|
||||
[testenv:releasenotes]
|
||||
deps =
|
||||
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/wallaby}
|
||||
-r{toxinidir}/doc/requirements.txt
|
||||
commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
|
||||
|
||||
@@ -53,9 +53,3 @@ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools
|
||||
# F821 undefined name 'unicode'
|
||||
# if isinstance(config, str) or isinstance(config, unicode):
|
||||
builtins = unicode
|
||||
|
||||
[testenv:lower-constraints]
|
||||
deps =
|
||||
-c{toxinidir}/lower-constraints.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
-r{toxinidir}/requirements.txt
|
||||
|
||||
Reference in New Issue
Block a user