Obsolete Legacy APIs excluding VIM feature
This patch obsoletes CLI for Legacy APIs excluding VIM feature. Implements: blueprint deprecate-legacy-apis Change-Id: I9be376a660c6f7c34c0abe7e327dec7a91d49ee2
This commit is contained in:
parent
1c608378b1
commit
e1cd39fa41
@ -0,0 +1,4 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Legacy APIs excluding VIM feature are obsoleted.
|
39
setup.cfg
39
setup.cfg
@ -40,45 +40,6 @@ openstack.tackerclient.v1 =
|
||||
vim_set = tackerclient.osc.v1.nfvo.vim:UpdateVIM
|
||||
vim_delete = tackerclient.osc.v1.nfvo.vim:DeleteVIM
|
||||
vim_show = tackerclient.osc.v1.nfvo.vim:ShowVIM
|
||||
vnf_descriptor_create = tackerclient.osc.v1.vnfm.vnfd:CreateVNFD
|
||||
vnf_descriptor_delete = tackerclient.osc.v1.vnfm.vnfd:DeleteVNFD
|
||||
vnf_descriptor_list = tackerclient.osc.v1.vnfm.vnfd:ListVNFD
|
||||
vnf_descriptor_show = tackerclient.osc.v1.vnfm.vnfd:ShowVNFD
|
||||
vnf_descriptor_template_show = tackerclient.osc.v1.vnfm.vnfd:ShowTemplateVNFD
|
||||
vnf_create = tackerclient.osc.v1.vnfm.vnf:CreateVNF
|
||||
vnf_delete = tackerclient.osc.v1.vnfm.vnf:DeleteVNF
|
||||
vnf_list = tackerclient.osc.v1.vnfm.vnf:ListVNF
|
||||
vnf_show = tackerclient.osc.v1.vnfm.vnf:ShowVNF
|
||||
vnf_resource_list = tackerclient.osc.v1.vnfm.vnf:ListVNFResources
|
||||
vnf_set = tackerclient.osc.v1.vnfm.vnf:UpdateVNF
|
||||
vnf_scale = tackerclient.osc.v1.vnfm.vnf:ScaleVNF
|
||||
vnf_graph_descriptor_create = tackerclient.osc.v1.nfvo.vnffgd:CreateVNFFGD
|
||||
vnf_graph_descriptor_delete = tackerclient.osc.v1.nfvo.vnffgd:DeleteVNFFGD
|
||||
vnf_graph_descriptor_list = tackerclient.osc.v1.nfvo.vnffgd:ListVNFFGD
|
||||
vnf_graph_descriptor_show = tackerclient.osc.v1.nfvo.vnffgd:ShowVNFFGD
|
||||
vnf_graph_descriptor_template_show = tackerclient.osc.v1.nfvo.vnffgd:ShowTemplateVNFFGD
|
||||
ns_descriptor_create = tackerclient.osc.v1.nfvo.nsd:CreateNSD
|
||||
ns_descriptor_delete = tackerclient.osc.v1.nfvo.nsd:DeleteNSD
|
||||
ns_descriptor_list = tackerclient.osc.v1.nfvo.nsd:ListNSD
|
||||
ns_descriptor_show = tackerclient.osc.v1.nfvo.nsd:ShowNSD
|
||||
ns_descriptor_template_show = tackerclient.osc.v1.nfvo.nsd:ShowTemplateNSD
|
||||
nfv_event_show = tackerclient.osc.v1.events.events:ShowEvent
|
||||
nfv_event_list = tackerclient.osc.v1.events.events:ListEvent
|
||||
ns_create = tackerclient.osc.v1.nfvo.ns:CreateNS
|
||||
ns_delete = tackerclient.osc.v1.nfvo.ns:DeleteNS
|
||||
ns_list = tackerclient.osc.v1.nfvo.ns:ListNS
|
||||
ns_show = tackerclient.osc.v1.nfvo.ns:ShowNS
|
||||
vnf_graph_create = tackerclient.osc.v1.nfvo.vnffg:CreateVNFFG
|
||||
vnf_graph_delete = tackerclient.osc.v1.nfvo.vnffg:DeleteVNFFG
|
||||
vnf_graph_set = tackerclient.osc.v1.nfvo.vnffg:UpdateVNFFG
|
||||
vnf_graph_list = tackerclient.osc.v1.nfvo.vnffg:ListVNFFG
|
||||
vnf_graph_show = tackerclient.osc.v1.nfvo.vnffg:ShowVNFFG
|
||||
vnf_network_forwarding_path_list = tackerclient.osc.v1.nfvo.vnffg:ListNFP
|
||||
vnf_network_forwarding_path_show = tackerclient.osc.v1.nfvo.vnffg:ShowNFP
|
||||
vnf_classifier_list = tackerclient.osc.v1.nfvo.vnffg:ListFC
|
||||
vnf_classifier_show = tackerclient.osc.v1.nfvo.vnffg:ShowFC
|
||||
vnf_chain_list = tackerclient.osc.v1.nfvo.vnffg:ListSFC
|
||||
vnf_chain_show = tackerclient.osc.v1.nfvo.vnffg:ShowSFC
|
||||
vnf_package_create = tackerclient.osc.v1.vnfpkgm.vnf_package:CreateVnfPackage
|
||||
vnf_package_list = tackerclient.osc.v1.vnfpkgm.vnf_package:ListVnfPackage
|
||||
vnf_package_show = tackerclient.osc.v1.vnfpkgm.vnf_package:ShowVnfPackage
|
||||
|
@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
function die() {
|
||||
local exitcode=$?
|
||||
set +o xtrace
|
||||
echo $@
|
||||
exit $exitcode
|
||||
}
|
||||
|
||||
noauth_tenant_id=me
|
||||
if [ $1 == 'noauth' ]; then
|
||||
NOAUTH="--tenant_id $noauth_tenant_id"
|
||||
else
|
||||
NOAUTH=
|
||||
fi
|
||||
|
||||
FORMAT=" --request-format xml"
|
||||
|
||||
# test the CRUD of xxx
|
||||
# TODO(yamahata)
|
@ -14,24 +14,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
EXT_NS = '_extension_ns'
|
||||
XML_NS_V10 = 'http://openstack.org/tacker/api/v1.0'
|
||||
XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
XSI_ATTR = "xsi:nil"
|
||||
XSI_NIL_ATTR = "xmlns:xsi"
|
||||
TYPE_XMLNS = "xmlns:tacker"
|
||||
TYPE_ATTR = "tacker:type"
|
||||
VIRTUAL_ROOT_KEY = "_v_root"
|
||||
ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
|
||||
ATOM_XMLNS = "xmlns:atom"
|
||||
ATOM_LINK_NOTATION = "{%s}link" % ATOM_NAMESPACE
|
||||
|
||||
TYPE_BOOL = "bool"
|
||||
TYPE_INT = "int"
|
||||
TYPE_FLOAT = "float"
|
||||
TYPE_LIST = "list"
|
||||
TYPE_DICT = "dict"
|
||||
|
||||
|
||||
PLURALS = {'templates': 'template',
|
||||
'devices': 'device'}
|
||||
|
@ -111,55 +111,6 @@ HTTP_EXCEPTION_MAP = {
|
||||
}
|
||||
|
||||
|
||||
# Exceptions mapped to Tacker server exceptions
|
||||
# These are defined if a user of client library needs specific exception.
|
||||
# Exception name should be <Tacker Exception Name> + 'Client'
|
||||
# e.g., NetworkNotFound -> NetworkNotFoundClient
|
||||
|
||||
class NetworkNotFoundClient(NotFound):
|
||||
pass
|
||||
|
||||
|
||||
class PortNotFoundClient(NotFound):
|
||||
pass
|
||||
|
||||
|
||||
class StateInvalidClient(BadRequest):
|
||||
pass
|
||||
|
||||
|
||||
class NetworkInUseClient(Conflict):
|
||||
pass
|
||||
|
||||
|
||||
class PortInUseClient(Conflict):
|
||||
pass
|
||||
|
||||
|
||||
class IpAddressInUseClient(Conflict):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidIpForNetworkClient(BadRequest):
|
||||
pass
|
||||
|
||||
|
||||
class OverQuotaClient(Conflict):
|
||||
pass
|
||||
|
||||
|
||||
class IpAddressGenerationFailureClient(Conflict):
|
||||
pass
|
||||
|
||||
|
||||
class MacAddressInUseClient(Conflict):
|
||||
pass
|
||||
|
||||
|
||||
class ExternalIpAddressExhaustedClient(BadRequest):
|
||||
pass
|
||||
|
||||
|
||||
# Exceptions from client library
|
||||
|
||||
class NoAuthURLProvided(Unauthorized):
|
||||
@ -174,11 +125,6 @@ class EndpointTypeNotFound(TackerClientException):
|
||||
message = _("Could not find endpoint type %(type_)s in Service Catalog.")
|
||||
|
||||
|
||||
class AmbiguousEndpoints(TackerClientException):
|
||||
message = _("Found more than one matching endpoint in Service Catalog: "
|
||||
"%(matching_endpoints)")
|
||||
|
||||
|
||||
class RequestURITooLong(TackerClientException):
|
||||
"""Raised when a request fails with HTTP error 414."""
|
||||
|
||||
|
@ -14,12 +14,9 @@
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
from xml.etree import ElementTree as etree
|
||||
from xml.parsers import expat
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from tackerclient.common import constants
|
||||
from tackerclient.common import exceptions as exception
|
||||
from tackerclient.i18n import _
|
||||
|
||||
@ -58,144 +55,6 @@ class JSONDictSerializer(DictSerializer):
|
||||
return jsonutils.dumps(data, default=sanitizer)
|
||||
|
||||
|
||||
class XMLDictSerializer(DictSerializer):
|
||||
|
||||
def __init__(self, metadata=None, xmlns=None):
|
||||
"""XMLDictSerializer constructor.
|
||||
|
||||
:param metadata: information needed to deserialize XML into
|
||||
a dictionary.
|
||||
:param xmlns: XML namespace to include with serialized XML
|
||||
"""
|
||||
super(XMLDictSerializer, self).__init__()
|
||||
self.metadata = metadata or {}
|
||||
if not xmlns:
|
||||
xmlns = self.metadata.get('xmlns')
|
||||
if not xmlns:
|
||||
xmlns = constants.XML_NS_V10
|
||||
self.xmlns = xmlns
|
||||
|
||||
def default(self, data):
|
||||
"""Default serializer of XMLDictSerializer.
|
||||
|
||||
:param data: expect data to contain a single key as XML root, or
|
||||
contain another '*_links' key as atom links. Other
|
||||
case will use 'VIRTUAL_ROOT_KEY' as XML root.
|
||||
"""
|
||||
try:
|
||||
links = None
|
||||
has_atom = False
|
||||
if data is None:
|
||||
root_key = constants.VIRTUAL_ROOT_KEY
|
||||
root_value = None
|
||||
else:
|
||||
link_keys = [k for k in data.keys() or []
|
||||
if k.endswith('_links')]
|
||||
if link_keys:
|
||||
links = data.pop(link_keys[0], None)
|
||||
has_atom = True
|
||||
root_key = (len(data) == 1 and
|
||||
list(data.keys())[0] or constants.VIRTUAL_ROOT_KEY)
|
||||
root_value = data.get(root_key, data)
|
||||
doc = etree.Element("_temp_root")
|
||||
used_prefixes = []
|
||||
self._to_xml_node(doc, self.metadata, root_key,
|
||||
root_value, used_prefixes)
|
||||
if links:
|
||||
self._create_link_nodes(list(doc)[0], links)
|
||||
return self.to_xml_string(list(doc)[0], used_prefixes, has_atom)
|
||||
except AttributeError as e:
|
||||
LOG.exception(str(e))
|
||||
return ''
|
||||
|
||||
def __call__(self, data):
|
||||
# Provides a migration path to a cleaner WSGI layer, this
|
||||
# "default" stuff and extreme extensibility isn't being used
|
||||
# like originally intended
|
||||
return self.default(data)
|
||||
|
||||
def to_xml_string(self, node, used_prefixes, has_atom=False):
|
||||
self._add_xmlns(node, used_prefixes, has_atom)
|
||||
return etree.tostring(node, encoding='UTF-8')
|
||||
|
||||
# NOTE(ameade): the has_atom should be removed after all of the
|
||||
# XML serializers and view builders have been updated to the current
|
||||
# spec that required all responses include the xmlns:atom, the has_atom
|
||||
# flag is to prevent current tests from breaking
|
||||
def _add_xmlns(self, node, used_prefixes, has_atom=False):
|
||||
node.set('xmlns', self.xmlns)
|
||||
node.set(constants.TYPE_XMLNS, self.xmlns)
|
||||
if has_atom:
|
||||
node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
|
||||
node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
|
||||
ext_ns = self.metadata.get(constants.EXT_NS, {})
|
||||
for prefix in used_prefixes:
|
||||
if prefix in ext_ns:
|
||||
node.set('xmlns:' + prefix, ext_ns[prefix])
|
||||
|
||||
def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
|
||||
"""Recursive method to convert data members to XML nodes."""
|
||||
result = etree.SubElement(parent, nodename)
|
||||
if ":" in nodename:
|
||||
used_prefixes.append(nodename.split(":", 1)[0])
|
||||
# TODO(bcwaldon): accomplish this without a type-check
|
||||
if isinstance(data, list):
|
||||
if not data:
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_LIST)
|
||||
return result
|
||||
singular = metadata.get('plurals', {}).get(nodename, None)
|
||||
if singular is None:
|
||||
if nodename.endswith('s'):
|
||||
singular = nodename[:-1]
|
||||
else:
|
||||
singular = 'item'
|
||||
for item in data:
|
||||
self._to_xml_node(result, metadata, singular, item,
|
||||
used_prefixes)
|
||||
# TODO(bcwaldon): accomplish this without a type-check
|
||||
elif isinstance(data, dict):
|
||||
if not data:
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_DICT)
|
||||
return result
|
||||
attrs = metadata.get('attributes', {}).get(nodename, {})
|
||||
for k, v in sorted(data.items()):
|
||||
if k in attrs:
|
||||
result.set(k, str(v))
|
||||
else:
|
||||
self._to_xml_node(result, metadata, k, v,
|
||||
used_prefixes)
|
||||
elif data is None:
|
||||
result.set(constants.XSI_ATTR, 'true')
|
||||
else:
|
||||
if isinstance(data, bool):
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_BOOL)
|
||||
elif isinstance(data, int):
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_INT)
|
||||
elif isinstance(data, float):
|
||||
result.set(
|
||||
constants.TYPE_ATTR,
|
||||
constants.TYPE_FLOAT)
|
||||
LOG.debug("Data %(data)s type is %(type)s",
|
||||
{'data': data,
|
||||
'type': type(data)})
|
||||
result.text = str(data)
|
||||
return result
|
||||
|
||||
def _create_link_nodes(self, xml_doc, links):
|
||||
for link in links:
|
||||
link_node = etree.SubElement(xml_doc, 'atom:link')
|
||||
link_node.set('rel', link['rel'])
|
||||
link_node.set('href', link['href'])
|
||||
|
||||
|
||||
class TextDeserializer(ActionDispatcher):
|
||||
"""Default request body deserialization."""
|
||||
|
||||
@ -219,138 +78,11 @@ class JSONDeserializer(TextDeserializer):
|
||||
return {'body': self._from_json(datastring)}
|
||||
|
||||
|
||||
class XMLDeserializer(TextDeserializer):
|
||||
|
||||
def __init__(self, metadata=None):
|
||||
"""XMLDeserializer constructor.
|
||||
|
||||
:param metadata: information needed to deserialize XML into
|
||||
a dictionary.
|
||||
"""
|
||||
super(XMLDeserializer, self).__init__()
|
||||
self.metadata = metadata or {}
|
||||
xmlns = self.metadata.get('xmlns')
|
||||
if not xmlns:
|
||||
xmlns = constants.XML_NS_V10
|
||||
self.xmlns = xmlns
|
||||
|
||||
def _get_key(self, tag):
|
||||
tags = tag.split("}", 1)
|
||||
if len(tags) == 2:
|
||||
ns = tags[0][1:]
|
||||
bare_tag = tags[1]
|
||||
ext_ns = self.metadata.get(constants.EXT_NS, {})
|
||||
if ns == self.xmlns:
|
||||
return bare_tag
|
||||
for prefix, _ns in ext_ns.items():
|
||||
if ns == _ns:
|
||||
return prefix + ":" + bare_tag
|
||||
else:
|
||||
return tag
|
||||
|
||||
def _get_links(self, root_tag, node):
|
||||
link_nodes = node.findall(constants.ATOM_LINK_NOTATION)
|
||||
root_tag = self._get_key(node.tag)
|
||||
link_key = "%s_links" % root_tag
|
||||
link_list = []
|
||||
for link in link_nodes:
|
||||
link_list.append({'rel': link.get('rel'),
|
||||
'href': link.get('href')})
|
||||
# Remove link node in order to avoid link node being
|
||||
# processed as an item in _from_xml_node
|
||||
node.remove(link)
|
||||
return link_list and {link_key: link_list} or {}
|
||||
|
||||
def _from_xml(self, datastring):
|
||||
if datastring is None:
|
||||
return None
|
||||
plurals = set(self.metadata.get('plurals', {}))
|
||||
try:
|
||||
node = etree.fromstring(datastring)
|
||||
root_tag = self._get_key(node.tag)
|
||||
links = self._get_links(root_tag, node)
|
||||
result = self._from_xml_node(node, plurals)
|
||||
# There is no case where root_tag = constants.VIRTUAL_ROOT_KEY
|
||||
# and links is not None because of the way data are serialized
|
||||
if root_tag == constants.VIRTUAL_ROOT_KEY:
|
||||
return result
|
||||
return dict({root_tag: result}, **links)
|
||||
except Exception as e:
|
||||
parseError = False
|
||||
# Python2.7
|
||||
if (hasattr(etree, 'ParseError') and
|
||||
isinstance(e, getattr(etree, 'ParseError'))):
|
||||
parseError = True
|
||||
# Python2.6
|
||||
elif isinstance(e, expat.ExpatError):
|
||||
parseError = True
|
||||
if parseError:
|
||||
msg = _("Cannot understand XML")
|
||||
raise exception.MalformedResponseBody(reason=msg)
|
||||
else:
|
||||
raise
|
||||
|
||||
def _from_xml_node(self, node, listnames):
|
||||
"""Convert a minidom node to a simple Python type.
|
||||
|
||||
:param node: minidom node name
|
||||
:param listnames: list of XML node names whose subnodes should
|
||||
be considered list items.
|
||||
|
||||
"""
|
||||
attrNil = node.get(str(etree.QName(constants.XSI_NAMESPACE, "nil")))
|
||||
attrType = node.get(str(etree.QName(
|
||||
self.metadata.get('xmlns'), "type")))
|
||||
if (attrNil and attrNil.lower() == 'true'):
|
||||
return None
|
||||
elif not len(node) and not node.text:
|
||||
if (attrType and attrType == constants.TYPE_DICT):
|
||||
return {}
|
||||
elif (attrType and attrType == constants.TYPE_LIST):
|
||||
return []
|
||||
else:
|
||||
return ''
|
||||
elif (len(node) == 0 and node.text):
|
||||
converters = {constants.TYPE_BOOL:
|
||||
lambda x: x.lower() == 'true',
|
||||
constants.TYPE_INT:
|
||||
lambda x: int(x),
|
||||
constants.TYPE_FLOAT:
|
||||
lambda x: float(x)}
|
||||
if attrType and attrType in converters:
|
||||
return converters[attrType](node.text)
|
||||
else:
|
||||
return node.text
|
||||
elif self._get_key(node.tag) in listnames:
|
||||
return [self._from_xml_node(n, listnames) for n in node]
|
||||
else:
|
||||
result = dict()
|
||||
for attr in node.keys():
|
||||
if (attr == 'xmlns' or
|
||||
attr.startswith('xmlns:') or
|
||||
attr == constants.XSI_ATTR or
|
||||
attr == constants.TYPE_ATTR):
|
||||
continue
|
||||
result[self._get_key(attr)] = node.get(attr)
|
||||
children = list(node)
|
||||
for child in children:
|
||||
result[self._get_key(child.tag)] = self._from_xml_node(
|
||||
child, listnames)
|
||||
return result
|
||||
|
||||
def default(self, datastring):
|
||||
return {'body': self._from_xml(datastring)}
|
||||
|
||||
def __call__(self, datastring):
|
||||
# Adding a migration path to allow us to remove unncessary classes
|
||||
return self.default(datastring)
|
||||
|
||||
|
||||
# NOTE(maru): this class is duplicated from tacker.wsgi
|
||||
class Serializer(object):
|
||||
"""Serializes and deserializes dictionaries to certain MIME types."""
|
||||
|
||||
def __init__(self, metadata=None, default_xmlns=None):
|
||||
def __init__(self, metadata=None):
|
||||
"""Create a serializer based on the given WSGI environment.
|
||||
|
||||
'metadata' is an optional dict mapping MIME types to information
|
||||
@ -358,12 +90,10 @@ class Serializer(object):
|
||||
|
||||
"""
|
||||
self.metadata = metadata or {}
|
||||
self.default_xmlns = default_xmlns
|
||||
|
||||
def _get_serialize_handler(self, content_type):
|
||||
handlers = {
|
||||
'application/json': JSONDictSerializer(),
|
||||
'application/xml': XMLDictSerializer(self.metadata),
|
||||
'application/json': JSONDictSerializer()
|
||||
}
|
||||
|
||||
try:
|
||||
@ -385,8 +115,7 @@ class Serializer(object):
|
||||
|
||||
def get_deserialize_handler(self, content_type):
|
||||
handlers = {
|
||||
'application/json': JSONDeserializer(),
|
||||
'application/xml': XMLDeserializer(self.metadata),
|
||||
'application/json': JSONDeserializer()
|
||||
}
|
||||
|
||||
try:
|
||||
|
@ -20,7 +20,6 @@
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from oslo_log import versionutils
|
||||
from oslo_utils import encodeutils
|
||||
@ -184,15 +183,3 @@ def deprecate_warning(what, as_of, in_favor_of=None, remove_in=1):
|
||||
versionutils.deprecation_warning(as_of=as_of, what=what,
|
||||
in_favor_of=in_favor_of,
|
||||
remove_in=remove_in)
|
||||
|
||||
|
||||
# TODO(ueha): Remove this along with the deprecated commands in the first major
|
||||
# python-tackerclient release after the Tacker server version 9.0.0 (2023.1
|
||||
# Antelope release).
|
||||
def deprecate_legacy_warning():
|
||||
# NOTE(ueha): versionutils has not support Antelope version yet.
|
||||
msg = _(
|
||||
'The Legacy API interface has been deprecated. This command will be '
|
||||
'removed in the first major release after the Tacker server version '
|
||||
'9.0.0 (2023.1 Antelope release).')
|
||||
print(msg, file=sys.stderr)
|
||||
|
@ -1,119 +0,0 @@
|
||||
# Copyright 2018 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 osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
|
||||
from tackerclient.common import utils as tacker_common_utils
|
||||
from tackerclient.i18n import _
|
||||
from tackerclient.osc import sdk_utils
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
from tackerclient.tacker import v1_0 as tackerV10
|
||||
|
||||
_attr_map = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('resource_type', 'Resource Type', tacker_osc_utils.LIST_BOTH),
|
||||
('resource_id', 'Resource ID', tacker_osc_utils.LIST_BOTH),
|
||||
('resource_state', 'Resource State', tacker_osc_utils.LIST_BOTH),
|
||||
('event_type', 'Event Type', tacker_osc_utils.LIST_BOTH),
|
||||
('timestamp', 'Timestamp', tacker_osc_utils.LIST_BOTH),
|
||||
('event_details', 'Event Details', tacker_osc_utils.LIST_LONG_ONLY),
|
||||
)
|
||||
|
||||
_EVENT = "event"
|
||||
|
||||
events_path = '/events'
|
||||
|
||||
|
||||
def _get_columns(item):
|
||||
column_map = {}
|
||||
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
|
||||
|
||||
|
||||
class ShowEvent(command.ShowOne):
|
||||
_description = _("Show event given the event id.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowEvent, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_EVENT,
|
||||
metavar="ID",
|
||||
help=_("ID of event to display")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
obj_id = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _EVENT, parsed_args.event)
|
||||
obj = client.show_event(obj_id)
|
||||
display_columns, columns = _get_columns(obj[_EVENT])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_EVENT]),
|
||||
columns,)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class ListEvent(command.Lister):
|
||||
_description = _("List events of resources.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListEvent, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--id',
|
||||
help=_("id of the event to look up."))
|
||||
parser.add_argument(
|
||||
'--resource-type',
|
||||
help=_("resource type of the events to look up."))
|
||||
parser.add_argument(
|
||||
'--resource-id',
|
||||
help=_("resource id of the events to look up."))
|
||||
parser.add_argument(
|
||||
'--resource-state',
|
||||
help=_("resource state of the events to look up."))
|
||||
parser.add_argument(
|
||||
'--event-type',
|
||||
help=_("event type of the events to look up."))
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
action='store_true',
|
||||
help=_("List additional fields in output"))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
_params = {}
|
||||
if parsed_args.id:
|
||||
_params['id'] = parsed_args.id
|
||||
if parsed_args.resource_id:
|
||||
_params['resource_id'] = parsed_args.resource_id
|
||||
if parsed_args.resource_state:
|
||||
_params['resource_state'] = parsed_args.resource_id
|
||||
if parsed_args.event_type:
|
||||
_params['event_type'] = parsed_args.event_type
|
||||
if parsed_args.resource_type:
|
||||
_params['resource_type'] = parsed_args.resource_type
|
||||
events = client.list('events', events_path, True, **_params)
|
||||
data = {}
|
||||
data['events'] = events['events']
|
||||
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||
_attr_map, long_listing=parsed_args.long)
|
||||
return (headers,
|
||||
(utils.get_dict_properties(
|
||||
s, columns,
|
||||
) for s in data[_EVENT + 's']))
|
@ -1,261 +0,0 @@
|
||||
# Copyright 2018 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.
|
||||
#
|
||||
|
||||
import yaml
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
from tackerclient.common import utils as tacker_common_utils
|
||||
from tackerclient.i18n import _
|
||||
from tackerclient.osc import sdk_utils
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
from tackerclient.tacker import v1_0 as tackerV10
|
||||
|
||||
_attr_map = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('name', 'Name', tacker_osc_utils.LIST_BOTH),
|
||||
('nsd_id', 'NSD ID', tacker_osc_utils.LIST_BOTH),
|
||||
('vnf_ids', 'VNF IDs', tacker_osc_utils.LIST_BOTH),
|
||||
('vnffg_ids', 'VNFFG IDs', tacker_osc_utils.LIST_BOTH),
|
||||
('mgmt_ip_addresses', 'Mgmt Ip Addresses', tacker_osc_utils.LIST_BOTH),
|
||||
('status', 'Status', tacker_osc_utils.LIST_BOTH),
|
||||
)
|
||||
|
||||
_NS = 'ns'
|
||||
_RESOURCE = 'resource'
|
||||
|
||||
|
||||
def _get_columns(item):
|
||||
column_map = {
|
||||
'tenant_id': 'project_id',
|
||||
}
|
||||
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
|
||||
|
||||
|
||||
class CreateNS(command.ShowOne):
|
||||
_description = _("Create a new NS")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateNS, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name', metavar='NAME',
|
||||
help=_('Name for NS'))
|
||||
parser.add_argument(
|
||||
'--tenant-id', metavar='TENANT_ID',
|
||||
help=_('The owner tenant ID'))
|
||||
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-template',
|
||||
help=_('NSD file 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'))
|
||||
return parser
|
||||
|
||||
def args2body(self, parsed_args):
|
||||
body = {_NS: {}}
|
||||
body[_NS]['attributes'] = {}
|
||||
|
||||
if parsed_args.vim_region_name:
|
||||
body[_NS].setdefault('placement_attr', {})['region_name'] = \
|
||||
parsed_args.vim_region_name
|
||||
|
||||
client = self.app.client_manager.tackerclient
|
||||
if parsed_args.vim_name:
|
||||
_id = tackerV10.find_resourceid_by_name_or_id(client, 'vim',
|
||||
parsed_args.vim_name)
|
||||
parsed_args.vim_id = _id
|
||||
if parsed_args.nsd_name:
|
||||
_id = tackerV10.find_resourceid_by_name_or_id(client, 'nsd',
|
||||
parsed_args.nsd_name)
|
||||
parsed_args.nsd_id = _id
|
||||
elif parsed_args.nsd_template:
|
||||
with open(parsed_args.nsd_template) as f:
|
||||
template = f.read()
|
||||
try:
|
||||
template = yaml.load(
|
||||
template, Loader=yaml.SafeLoader)
|
||||
except yaml.YAMLError as e:
|
||||
raise exceptions.InvalidInput(reason=e)
|
||||
if not template:
|
||||
raise exceptions.InvalidInput(
|
||||
reason='The nsd file is empty')
|
||||
body[_NS]['nsd_template'] = template
|
||||
|
||||
if parsed_args.param_file:
|
||||
with open(parsed_args.param_file) as f:
|
||||
param_yaml = f.read()
|
||||
try:
|
||||
param_yaml = yaml.load(
|
||||
param_yaml, Loader=yaml.SafeLoader)
|
||||
except yaml.YAMLError as e:
|
||||
raise exceptions.InvalidInput(reason=e)
|
||||
if not param_yaml:
|
||||
raise exceptions.InvalidInput(
|
||||
reason='The parameter file is empty')
|
||||
body[_NS]['attributes'] = {'param_values': param_yaml}
|
||||
tackerV10.update_dict(parsed_args, body[_NS],
|
||||
['tenant_id', 'name', 'description',
|
||||
'nsd_id', 'vim_id'])
|
||||
return body
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
ns = client.create_ns(self.args2body(parsed_args))
|
||||
display_columns, columns = _get_columns(ns[_NS])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(ns[_NS]),
|
||||
columns)
|
||||
lstdata = list(data)
|
||||
for index, value in enumerate(lstdata):
|
||||
if value is None:
|
||||
lstdata[index] = ''
|
||||
data = tuple(lstdata)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class DeleteNS(command.Command):
|
||||
_description = _("Delete NS(s).")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteNS, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_NS,
|
||||
metavar="<NS>",
|
||||
nargs="+",
|
||||
help=_("NS(s) to delete (name or ID)")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--force',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=_('Force delete Network Service')
|
||||
)
|
||||
return parser
|
||||
|
||||
def args2body(self, parsed_args):
|
||||
if parsed_args.force:
|
||||
body = {_NS: {'attributes': {'force': True}}}
|
||||
else:
|
||||
body = dict()
|
||||
return body
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
failure = False
|
||||
deleted_ids = []
|
||||
failed_items = {}
|
||||
body = self.args2body(parsed_args)
|
||||
for resource_id in parsed_args.ns:
|
||||
try:
|
||||
obj = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _NS, resource_id)
|
||||
client.delete_ns(obj, body)
|
||||
deleted_ids.append(resource_id)
|
||||
except Exception as e:
|
||||
failure = True
|
||||
failed_items[resource_id] = e
|
||||
if failure:
|
||||
msg = ''
|
||||
if deleted_ids:
|
||||
msg = (_('Successfully deleted %(resource)s(s):'
|
||||
' %(deleted_list)s') % {'deleted_list':
|
||||
', '.join(deleted_ids),
|
||||
'resource': _NS})
|
||||
err_msg = _("\n\nUnable to delete the below"
|
||||
" %s(s):") % _NS
|
||||
for failed_id, error in failed_items.items():
|
||||
err_msg += (_('\n Cannot delete %(failed_id)s: %(error)s')
|
||||
% {'failed_id': failed_id,
|
||||
'error': error})
|
||||
msg += err_msg
|
||||
raise exceptions.CommandError(message=msg)
|
||||
else:
|
||||
print((_('All specified %(resource)s(s) deleted successfully')
|
||||
% {'resource': _NS}))
|
||||
return
|
||||
|
||||
|
||||
class ListNS(command.Lister):
|
||||
_description = ("List (NS)s that belong to a given tenant.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListNS, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
data = client.list_nss()
|
||||
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||
_attr_map, long_listing=None)
|
||||
return (headers,
|
||||
(utils.get_dict_properties(
|
||||
s, columns,
|
||||
) for s in data[_NS + 's']))
|
||||
|
||||
|
||||
class ShowNS(command.ShowOne):
|
||||
_description = _("Display NS details")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowNS, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_NS,
|
||||
metavar="<NS>",
|
||||
help=_("NS to display (name or ID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
obj_id = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _NS, parsed_args.ns)
|
||||
obj = client.show_ns(obj_id)
|
||||
display_columns, columns = _get_columns(obj[_NS])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_NS]),
|
||||
columns)
|
||||
lstdata = list(data)
|
||||
for index, value in enumerate(lstdata):
|
||||
if value is None:
|
||||
lstdata[index] = ''
|
||||
data = tuple(lstdata)
|
||||
return (display_columns, data)
|
@ -1,229 +0,0 @@
|
||||
# Copyright 2018 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.
|
||||
#
|
||||
|
||||
import yaml
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
from tackerclient.common import utils as tacker_common_utils
|
||||
from tackerclient.i18n import _
|
||||
from tackerclient.osc import sdk_utils
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
from tackerclient.tacker import v1_0 as tackerV10
|
||||
|
||||
_attr_map = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('name', 'Name', tacker_osc_utils.LIST_BOTH),
|
||||
('template_source', 'Template_Source',
|
||||
tacker_osc_utils.LIST_BOTH),
|
||||
('description', 'Description', tacker_osc_utils.LIST_BOTH),
|
||||
)
|
||||
|
||||
_NSD = 'nsd'
|
||||
|
||||
_formatters = {
|
||||
'attributes': tacker_osc_utils.format_dict_with_indention,
|
||||
}
|
||||
|
||||
|
||||
def _get_columns(item):
|
||||
column_map = {
|
||||
'tenant_id': 'project_id',
|
||||
}
|
||||
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
|
||||
|
||||
|
||||
class CreateNSD(command.ShowOne):
|
||||
_description = _("Create a new NSD.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateNSD, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name', metavar='NAME',
|
||||
help=_('Name for NSD'))
|
||||
parser.add_argument(
|
||||
'--tenant-id', metavar='TENANT_ID',
|
||||
help=_('The owner tenant ID or project ID'))
|
||||
parser.add_argument(
|
||||
'--nsd-file',
|
||||
required=True,
|
||||
help=_('YAML file with NSD parameters'))
|
||||
parser.add_argument(
|
||||
'--description',
|
||||
help=_('Set a description for the NSD'))
|
||||
return parser
|
||||
|
||||
def args2body(self, parsed_args):
|
||||
body = {_NSD: {}}
|
||||
nsd = None
|
||||
if not parsed_args.nsd_file:
|
||||
raise exceptions.InvalidInput(reason="Invalid input for nsd file")
|
||||
with open(parsed_args.nsd_file) as f:
|
||||
nsd = f.read()
|
||||
try:
|
||||
nsd = yaml.load(nsd, Loader=yaml.SafeLoader)
|
||||
except yaml.YAMLError as e:
|
||||
raise exceptions.InvalidInput(reason=e)
|
||||
if not nsd:
|
||||
raise exceptions.InvalidInput(reason="nsd file is empty")
|
||||
body[_NSD]['attributes'] = {'nsd': nsd}
|
||||
tackerV10.update_dict(parsed_args, body[_NSD],
|
||||
['tenant_id', 'name', 'description'])
|
||||
return body
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
nsd = client.create_nsd(self.args2body(parsed_args))
|
||||
display_columns, columns = _get_columns(nsd[_NSD])
|
||||
nsd[_NSD]['attributes']['nsd'] = yaml.load(
|
||||
nsd[_NSD]['attributes']['nsd'])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(nsd[_NSD]),
|
||||
columns, formatters=_formatters)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class DeleteNSD(command.Command):
|
||||
_description = _("Delete NSD(s).")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteNSD, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_NSD,
|
||||
metavar="<NSD>",
|
||||
nargs="+",
|
||||
help=_("NSD(s) to delete (name or ID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
failure = False
|
||||
deleted_ids = []
|
||||
failed_items = {}
|
||||
for resource_id in parsed_args.nsd:
|
||||
try:
|
||||
obj = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _NSD, resource_id)
|
||||
client.delete_nsd(obj)
|
||||
deleted_ids.append(resource_id)
|
||||
except Exception as e:
|
||||
failure = True
|
||||
failed_items[resource_id] = e
|
||||
if failure:
|
||||
msg = ''
|
||||
if deleted_ids:
|
||||
msg = (_('Successfully deleted %(resource)s(s):'
|
||||
' %(deleted_list)s') % {'deleted_list':
|
||||
', '.join(deleted_ids),
|
||||
'resource': _NSD})
|
||||
err_msg = _("\n\nUnable to delete the below"
|
||||
" %s(s):") % _NSD
|
||||
for failed_id, error in failed_items.items():
|
||||
err_msg += (_('\n Cannot delete %(failed_id)s: %(error)s')
|
||||
% {'failed_id': failed_id,
|
||||
'error': error})
|
||||
msg += err_msg
|
||||
raise exceptions.CommandError(message=msg)
|
||||
else:
|
||||
print((_('All specified %(resource)s(s) deleted successfully')
|
||||
% {'resource': _NSD}))
|
||||
return
|
||||
|
||||
|
||||
class ListNSD(command.Lister):
|
||||
_description = ("List (NSD)s that belong to a given tenant.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListNSD, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--template-source',
|
||||
help=_("List NSD with specified template source. Available \
|
||||
options are 'onboared' (default), 'inline' or 'all'"),
|
||||
action='store',
|
||||
default='onboarded')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
data = client.list_nsds()
|
||||
headers, columns = tacker_osc_utils.get_column_definitions(
|
||||
_attr_map, long_listing=None)
|
||||
return (headers,
|
||||
(utils.get_dict_properties(
|
||||
s, columns,
|
||||
) for s in data[_NSD + 's']))
|
||||
|
||||
|
||||
class ShowNSD(command.ShowOne):
|
||||
_description = _("Display NSD details")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowNSD, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_NSD,
|
||||
metavar="<NSD>",
|
||||
help=_("NSD to display (name or ID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
obj_id = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _NSD, parsed_args.nsd)
|
||||
obj = client.show_nsd(obj_id)
|
||||
obj[_NSD]['attributes']['nsd'] = yaml.load(
|
||||
obj[_NSD]['attributes']['nsd'])
|
||||
display_columns, columns = _get_columns(obj[_NSD])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_NSD]),
|
||||
columns,
|
||||
formatters=_formatters)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class ShowTemplateNSD(command.ShowOne):
|
||||
_description = _("Display NSD Template details")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowTemplateNSD, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_NSD,
|
||||
metavar="<NSD>",
|
||||
help=_("NSD to display (name or ID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
obj_id = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _NSD, parsed_args.nsd)
|
||||
obj = client.show_nsd(obj_id)
|
||||
obj[_NSD]['attributes']['nsd'] = yaml.load(
|
||||
obj[_NSD]['attributes']['nsd'])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(obj[_NSD]),
|
||||
('attributes',),
|
||||
formatters=_formatters)
|
||||
data = (data or _('Unable to display NSD template!'))
|
||||
return (('attributes',), data)
|
@ -1,574 +0,0 @@
|
||||
# Copyright 2018 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.
|
||||
#
|
||||
|
||||
import yaml
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
|
||||
from tackerclient.common import exceptions
|
||||
from tackerclient.common import utils as tacker_common_utils
|
||||
from tackerclient.i18n import _
|
||||
from tackerclient.osc import sdk_utils
|
||||
from tackerclient.osc import utils as tacker_osc_utils
|
||||
from tackerclient.tacker import v1_0 as tackerV10
|
||||
|
||||
_VNFFG = 'vnffg' # VNF Forwarding Graph
|
||||
_NFP = 'nfp' # Network Forwarding Path
|
||||
_SFC = 'sfc' # Service Function Chain
|
||||
_FC = 'classifier' # Flow Classifier
|
||||
|
||||
nfps_path = '/nfps'
|
||||
fcs_path = '/classifiers'
|
||||
sfcs_path = '/sfcs'
|
||||
|
||||
DEFAULT_ERROR_REASON_LENGTH = 100
|
||||
|
||||
_attr_map_vnffg = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('name', 'Name', tacker_osc_utils.LIST_BOTH),
|
||||
('ns_id', 'NS ID', tacker_osc_utils.LIST_BOTH),
|
||||
('vnffgd_id', 'VNFFGD ID', tacker_osc_utils.LIST_BOTH),
|
||||
('status', 'Status', tacker_osc_utils.LIST_BOTH),
|
||||
('description', 'Description', tacker_osc_utils.LIST_LONG_ONLY),
|
||||
)
|
||||
|
||||
_attr_map_nfp = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('name', 'Name', tacker_osc_utils.LIST_BOTH),
|
||||
('status', 'Status', tacker_osc_utils.LIST_BOTH),
|
||||
('vnffg_id', 'VNFFG ID', tacker_osc_utils.LIST_BOTH),
|
||||
('path_id', 'Path ID', tacker_osc_utils.LIST_BOTH),
|
||||
)
|
||||
|
||||
_attr_map_sfc = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('status', 'Status', tacker_osc_utils.LIST_BOTH),
|
||||
('nfp_id', 'NFP ID', tacker_osc_utils.LIST_BOTH),
|
||||
)
|
||||
|
||||
_attr_map_fc = (
|
||||
('id', 'ID', tacker_osc_utils.LIST_BOTH),
|
||||
('name', 'Name', tacker_osc_utils.LIST_BOTH),
|
||||
('status', 'Status', tacker_osc_utils.LIST_BOTH),
|
||||
('nfp_id', 'NFP ID', tacker_osc_utils.LIST_BOTH),
|
||||
('chain_id', 'Chain ID', tacker_osc_utils.LIST_BOTH),
|
||||
)
|
||||
|
||||
_formatters = {
|
||||
'attributes': tacker_osc_utils.format_dict_with_indention,
|
||||
'match': tacker_osc_utils.format_dict_with_indention,
|
||||
'chain': tacker_osc_utils.format_dict_with_indention,
|
||||
}
|
||||
|
||||
|
||||
def _get_columns(item):
|
||||
column_map = {
|
||||
'tenant_id': 'project_id',
|
||||
}
|
||||
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
|
||||
|
||||
|
||||
class CreateVNFFG(command.ShowOne):
|
||||
_description = _("Create a new VNFFG.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateVNFFG, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name', metavar='NAME',
|
||||
help=_('Set a name for the VNFFG'))
|
||||
parser.add_argument(
|
||||
'--tenant-id', metavar='TENANT_ID',
|
||||
help=_('The owner tenant ID'))
|
||||
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'))
|
||||
vnffgd_group.add_argument(
|
||||
'--vnffgd-template',
|
||||
help=_('VNFFGD file 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',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Should a reverse path be created for the NFP '
|
||||
'(True or False)'))
|
||||
parser.add_argument(
|
||||
'--param-file',
|
||||
help=_('YAML file with specific VNFFG parameters'))
|
||||
parser.add_argument(
|
||||
'--description',
|
||||
help=_('Set a description for the VNFFG'))
|
||||
return parser
|
||||
|
||||
def args2body(self, parsed_args):
|
||||
body = {_VNFFG: {}}
|
||||
body[_VNFFG]['attributes'] = {}
|
||||
|
||||
client = self.app.client_manager.tackerclient
|
||||
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(
|
||||
client, 'vnf', vnf)
|
||||
parsed_args.vnf_mapping = _vnf_mapping
|
||||
|
||||
if parsed_args.vnffgd_name:
|
||||
_id = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, 'vnffgd', parsed_args.vnffgd_name)
|
||||
parsed_args.vnffgd_id = _id
|
||||
elif parsed_args.vnffgd_template:
|
||||
with open(parsed_args.vnffgd_template) as f:
|
||||
template = f.read()
|
||||
try:
|
||||
template = yaml.load(template, Loader=yaml.SafeLoader)
|
||||
except yaml.YAMLError as e:
|
||||
raise exceptions.InvalidInput(reason=e)
|
||||
if not template:
|
||||
raise exceptions.InvalidInput(
|
||||
reason='The vnffgd file is empty')
|
||||
body[_VNFFG]['vnffgd_template'] = template
|
||||
|
||||
if parsed_args.param_file:
|
||||
with open(parsed_args.param_file) as f:
|
||||
param_yaml = f.read()
|
||||
try:
|
||||
param_yaml = yaml.load(
|
||||
param_yaml, Loader=yaml.SafeLoader)
|
||||
except yaml.YAMLError as e:
|
||||
raise exceptions.InvalidInput(reason=e)
|
||||
if not param_yaml:
|
||||
raise exceptions.InvalidInput(
|
||||
reason='The parameter file is empty')
|
||||
body[_VNFFG]['attributes'] = {'param_values': param_yaml}
|
||||
tackerV10.update_dict(parsed_args, body[_VNFFG],
|
||||
['tenant_id', 'name', 'vnffgd_id',
|
||||
'symmetrical', 'vnf_mapping', 'description'])
|
||||
return body
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
vnffg = client.create_vnffg(self.args2body(parsed_args))
|
||||
display_columns, columns = _get_columns(vnffg[_VNFFG])
|
||||
data = utils.get_item_properties(
|
||||
sdk_utils.DictModel(vnffg[_VNFFG]),
|
||||
columns,
|
||||
formatters=_formatters)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class DeleteVNFFG(command.Command):
|
||||
_description = _("Delete VNFFG(s).")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteVNFFG, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_VNFFG,
|
||||
metavar="<VNFFG>",
|
||||
nargs="+",
|
||||
help=_("VNFFG(s) to delete (name or ID)")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--force',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=_('Force delete VNFFG'))
|
||||
return parser
|
||||
|
||||
def args2body(self, parsed_args):
|
||||
body = dict()
|
||||
if parsed_args.force:
|
||||
body[_VNFFG] = dict()
|
||||
body[_VNFFG]['attributes'] = dict()
|
||||
body[_VNFFG]['attributes']['force'] = True
|
||||
return body
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
tacker_common_utils.deprecate_legacy_warning()
|
||||
client = self.app.client_manager.tackerclient
|
||||
failure = False
|
||||
deleted_ids = []
|
||||
failed_items = {}
|
||||
body = self.args2body(parsed_args)
|
||||
for resource_id in parsed_args.vnffg:
|
||||
try:
|
||||
obj = tackerV10.find_resourceid_by_name_or_id(
|
||||
client, _VNFFG, resource_id)
|
||||
client.delete_vnffg(obj, body)
|
||||
deleted_ids.append(resource_id)
|
||||
except Exception as e:
|
||||
failure = True
|
||||
failed_items[resource_id] = e
|
||||
if failure:
|
||||
msg = ''
|
||||
if deleted_ids:
|
||||
msg = (_('Successfully deleted %(resource)s(s):'
|
||||
' %(deleted_list)s') % {'deleted_list':
|
||||
', '.join(deleted_ids),
|
||||
'resource': _VNFFG})
|
||||
err_msg = _("\n\nUnable to delete the below"
|
||||
" %s(s):") % _VNFFG
|
||||
for failed_id, error in failed_items.items():
|
||||
err_msg += (_('\n Cannot delete %(failed_id)s: %(error)s')
|
||||
% {'failed_id': failed_id,
|
||||
'error': error})
|
||||
msg += err_msg
|
||||
raise exceptions.CommandError(message=msg)
|
||||
else:
|
||||
print((_('All specified %(resource)s(s) deleted successfully')
|
||||
% {'resource': _VNFFG}))
|
||||
return
|
||||
|
||||
|
||||
class UpdateVNFFG(command.ShowOne):
|
||||
_description = _("Update VNFFG.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateVNFFG, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_VNFFG,
|
||||
metavar="<VNFFG>",
|
||||
help=_('VNFFG to update (name or ID)'))
|
||||
parser.add_argument(
|
||||
'--vnffgd-template',
|
||||
help=_('VNFFGD file to update 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',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Should a reverse path be created for the NFP'))
|
||||