Quantum should use openstack.common.jsonutils
Implements blueprint use-common-jsonutils 1. Edit openstack-common.conf and import quantum/openstack/common/jsonutils.py 2. Remove json package imports and replace with jsonutils 3. Remove json related functions in common/utils.py Change-Id: Id5abc49175899fa4d83e613f852aaaac539ecfcb
This commit is contained in:
parent
06e1e75ecc
commit
dedefaeea3
@ -1,7 +1,7 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
|
|
||||||
# The list of modules to copy from openstack-common
|
# The list of modules to copy from openstack-common
|
||||||
modules=cfg,importutils,iniparser,setup
|
modules=cfg,importutils,iniparser,jsonutils,setup
|
||||||
|
|
||||||
# The base module to hold the copy of openstack.common
|
# The base module to hold the copy of openstack.common
|
||||||
base=quantum
|
base=quantum
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
import ConfigParser
|
import ConfigParser
|
||||||
import datetime
|
import datetime
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
@ -36,14 +35,6 @@ from quantum.common.exceptions import ProcessExecutionError
|
|||||||
from quantum.common import flags
|
from quantum.common import flags
|
||||||
|
|
||||||
|
|
||||||
def dumps(value):
|
|
||||||
return json.dumps(value)
|
|
||||||
|
|
||||||
|
|
||||||
def loads(value):
|
|
||||||
return json.loads(value)
|
|
||||||
|
|
||||||
|
|
||||||
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
133
quantum/openstack/common/jsonutils.py
Normal file
133
quantum/openstack/common/jsonutils.py
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2010 United States Government as represented by the
|
||||||
|
# Administrator of the National Aeronautics and Space Administration.
|
||||||
|
# Copyright 2011 Justin Santa Barbara
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
'''
|
||||||
|
JSON related utilities.
|
||||||
|
|
||||||
|
This module provides a few things:
|
||||||
|
|
||||||
|
1) A handy function for getting an object down to something that can be
|
||||||
|
JSON serialized. See to_primitive().
|
||||||
|
|
||||||
|
2) Wrappers around loads() and dumps(). The dumps() wrapper will
|
||||||
|
automatically use to_primitive() for you if needed.
|
||||||
|
|
||||||
|
3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson
|
||||||
|
is available.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import inspect
|
||||||
|
import itertools
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def to_primitive(value, convert_instances=False, level=0):
|
||||||
|
"""Convert a complex object into primitives.
|
||||||
|
|
||||||
|
Handy for JSON serialization. We can optionally handle instances,
|
||||||
|
but since this is a recursive function, we could have cyclical
|
||||||
|
data structures.
|
||||||
|
|
||||||
|
To handle cyclical data structures we could track the actual objects
|
||||||
|
visited in a set, but not all objects are hashable. Instead we just
|
||||||
|
track the depth of the object inspections and don't go too deep.
|
||||||
|
|
||||||
|
Therefore, convert_instances=True is lossy ... be aware.
|
||||||
|
|
||||||
|
"""
|
||||||
|
nasty = [inspect.ismodule, inspect.isclass, inspect.ismethod,
|
||||||
|
inspect.isfunction, inspect.isgeneratorfunction,
|
||||||
|
inspect.isgenerator, inspect.istraceback, inspect.isframe,
|
||||||
|
inspect.iscode, inspect.isbuiltin, inspect.isroutine,
|
||||||
|
inspect.isabstract]
|
||||||
|
for test in nasty:
|
||||||
|
if test(value):
|
||||||
|
return unicode(value)
|
||||||
|
|
||||||
|
# value of itertools.count doesn't get caught by inspects
|
||||||
|
# above and results in infinite loop when list(value) is called.
|
||||||
|
if type(value) == itertools.count:
|
||||||
|
return unicode(value)
|
||||||
|
|
||||||
|
# FIXME(vish): Workaround for LP bug 852095. Without this workaround,
|
||||||
|
# tests that raise an exception in a mocked method that
|
||||||
|
# has a @wrap_exception with a notifier will fail. If
|
||||||
|
# we up the dependency to 0.5.4 (when it is released) we
|
||||||
|
# can remove this workaround.
|
||||||
|
if getattr(value, '__module__', None) == 'mox':
|
||||||
|
return 'mock'
|
||||||
|
|
||||||
|
if level > 3:
|
||||||
|
return '?'
|
||||||
|
|
||||||
|
# The try block may not be necessary after the class check above,
|
||||||
|
# but just in case ...
|
||||||
|
try:
|
||||||
|
if isinstance(value, (list, tuple)):
|
||||||
|
o = []
|
||||||
|
for v in value:
|
||||||
|
o.append(to_primitive(v, convert_instances=convert_instances,
|
||||||
|
level=level))
|
||||||
|
return o
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
o = {}
|
||||||
|
for k, v in value.iteritems():
|
||||||
|
o[k] = to_primitive(v, convert_instances=convert_instances,
|
||||||
|
level=level)
|
||||||
|
return o
|
||||||
|
elif isinstance(value, datetime.datetime):
|
||||||
|
return str(value)
|
||||||
|
elif hasattr(value, 'iteritems'):
|
||||||
|
return to_primitive(dict(value.iteritems()),
|
||||||
|
convert_instances=convert_instances,
|
||||||
|
level=level)
|
||||||
|
elif hasattr(value, '__iter__'):
|
||||||
|
return to_primitive(list(value), level)
|
||||||
|
elif convert_instances and hasattr(value, '__dict__'):
|
||||||
|
# Likely an instance of something. Watch for cycles.
|
||||||
|
# Ignore class member vars.
|
||||||
|
return to_primitive(value.__dict__,
|
||||||
|
convert_instances=convert_instances,
|
||||||
|
level=level + 1)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
except TypeError, e:
|
||||||
|
# Class objects are tricky since they may define something like
|
||||||
|
# __iter__ defined but it isn't callable as list().
|
||||||
|
return unicode(value)
|
||||||
|
|
||||||
|
|
||||||
|
def dumps(value):
|
||||||
|
return json.dumps(value, default=to_primitive)
|
||||||
|
|
||||||
|
|
||||||
|
def loads(s):
|
||||||
|
return json.loads(s)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import anyjson
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
anyjson._modules.append((__name__, 'dumps', TypeError,
|
||||||
|
'loads', ValueError))
|
||||||
|
anyjson.force_implementation(__name__)
|
@ -18,7 +18,6 @@
|
|||||||
# Peter Strunk , Cisco Systems, Inc.
|
# Peter Strunk , Cisco Systems, Inc.
|
||||||
# Shubhangi Satras , Cisco Systems, Inc.
|
# Shubhangi Satras , Cisco Systems, Inc.
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
import unittest
|
import unittest
|
||||||
@ -42,6 +41,7 @@ from quantum.extensions.extensions import (
|
|||||||
PluginAwareExtensionManager,
|
PluginAwareExtensionManager,
|
||||||
)
|
)
|
||||||
from quantum.manager import QuantumManager
|
from quantum.manager import QuantumManager
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.plugins.cisco.db import api as db
|
from quantum.plugins.cisco.db import api as db
|
||||||
from quantum.plugins.cisco import l2network_plugin
|
from quantum.plugins.cisco import l2network_plugin
|
||||||
from quantum.plugins.cisco.l2network_plugin import L2Network
|
from quantum.plugins.cisco.l2network_plugin import L2Network
|
||||||
@ -108,11 +108,11 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
""" Test List Portprofile"""
|
""" Test List Portprofile"""
|
||||||
|
|
||||||
LOG.debug("test_list_portprofile - START")
|
LOG.debug("test_list_portprofile - START")
|
||||||
req_body1 = json.dumps(self.test_port_profile)
|
req_body1 = jsonutils.dumps(self.test_port_profile)
|
||||||
create_response1 = self.test_app.post(
|
create_response1 = self.test_app.post(
|
||||||
self.profile_path, req_body1,
|
self.profile_path, req_body1,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
req_body2 = json.dumps({
|
req_body2 = jsonutils.dumps({
|
||||||
'portprofile': {
|
'portprofile': {
|
||||||
'portprofile_name': 'cisco_test_portprofile2',
|
'portprofile_name': 'cisco_test_portprofile2',
|
||||||
'qos_name': 'test-qos2',
|
'qos_name': 'test-qos2',
|
||||||
@ -156,7 +156,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
""" Test create Portprofile"""
|
""" Test create Portprofile"""
|
||||||
|
|
||||||
LOG.debug("test_create_portprofile - START")
|
LOG.debug("test_create_portprofile - START")
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(self.profile_path, req_body,
|
index_response = self.test_app.post(self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
self.assertEqual(200, index_response.status_int)
|
self.assertEqual(200, index_response.status_int)
|
||||||
@ -187,7 +187,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
""" Test show Portprofile """
|
""" Test show Portprofile """
|
||||||
|
|
||||||
LOG.debug("test_show_portprofile - START")
|
LOG.debug("test_show_portprofile - START")
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(self.profile_path, req_body,
|
index_response = self.test_app.post(self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
||||||
@ -226,7 +226,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
""" Test update Portprofile"""
|
""" Test update Portprofile"""
|
||||||
|
|
||||||
LOG.debug("test_update_portprofile - START")
|
LOG.debug("test_update_portprofile - START")
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.profile_path, req_body,
|
self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -238,7 +238,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
'qos_name': 'test-qos1',
|
'qos_name': 'test-qos1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
rename_req_body = json.dumps(rename_port_profile)
|
rename_req_body = jsonutils.dumps(rename_port_profile)
|
||||||
rename_path_temp = (self.portprofile_path +
|
rename_path_temp = (self.portprofile_path +
|
||||||
resp_body['portprofiles']['portprofile']['id'])
|
resp_body['portprofiles']['portprofile']['id'])
|
||||||
rename_path = str(rename_path_temp)
|
rename_path = str(rename_path_temp)
|
||||||
@ -263,7 +263,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
""" Test update Portprofile Bad Request"""
|
""" Test update Portprofile Bad Request"""
|
||||||
|
|
||||||
LOG.debug("test_update_portprofileBADRequest - START")
|
LOG.debug("test_update_portprofileBADRequest - START")
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.profile_path, req_body,
|
self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -291,7 +291,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
'qos_name': 'test-qos1',
|
'qos_name': 'test-qos1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
rename_req_body = json.dumps(rename_port_profile)
|
rename_req_body = jsonutils.dumps(rename_port_profile)
|
||||||
update_path_temp = self.portprofile_path + portprofile_id
|
update_path_temp = self.portprofile_path + portprofile_id
|
||||||
update_path = str(update_path_temp)
|
update_path = str(update_path_temp)
|
||||||
update_response = self.test_app.put(update_path, rename_req_body,
|
update_response = self.test_app.put(update_path, rename_req_body,
|
||||||
@ -305,7 +305,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
""" Test delete Portprofile"""
|
""" Test delete Portprofile"""
|
||||||
|
|
||||||
LOG.debug("test_delete_portprofile - START")
|
LOG.debug("test_delete_portprofile - START")
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.profile_path, req_body,
|
self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -406,7 +406,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
LOG.debug("test_associate_portprofile - START")
|
LOG.debug("test_associate_portprofile - START")
|
||||||
net_id = self._create_network()
|
net_id = self._create_network()
|
||||||
port_id = self._create_port(net_id, "ACTIVE")
|
port_id = self._create_port(net_id, "ACTIVE")
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.profile_path, req_body,
|
self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -418,7 +418,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
'port-id': port_id,
|
'port-id': port_id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
req_assign_body = json.dumps(test_port_assign_data)
|
req_assign_body = jsonutils.dumps(test_port_assign_data)
|
||||||
associate_path_temp = (
|
associate_path_temp = (
|
||||||
self.portprofile_path +
|
self.portprofile_path +
|
||||||
resp_body['portprofiles']['portprofile']['id'] +
|
resp_body['portprofiles']['portprofile']['id'] +
|
||||||
@ -454,7 +454,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
'port-id': '1',
|
'port-id': '1',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
req_assign_body = json.dumps(test_port_assign_data)
|
req_assign_body = jsonutils.dumps(test_port_assign_data)
|
||||||
associate_path = (self.portprofile_path +
|
associate_path = (self.portprofile_path +
|
||||||
portprofile_id +
|
portprofile_id +
|
||||||
"/associate_portprofile")
|
"/associate_portprofile")
|
||||||
@ -472,7 +472,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
net_id = self._create_network()
|
net_id = self._create_network()
|
||||||
port_id = self._create_port(net_id, "ACTIVE")
|
port_id = self._create_port(net_id, "ACTIVE")
|
||||||
|
|
||||||
req_body = json.dumps(self.test_port_profile)
|
req_body = jsonutils.dumps(self.test_port_profile)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.profile_path, req_body,
|
self.profile_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -485,7 +485,7 @@ class PortprofileExtensionTest(unittest.TestCase):
|
|||||||
'port-id': port_id,
|
'port-id': port_id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
req_assign_body = json.dumps(test_port_assign_data)
|
req_assign_body = jsonutils.dumps(test_port_assign_data)
|
||||||
associate_path_temp = (self.portprofile_path +
|
associate_path_temp = (self.portprofile_path +
|
||||||
resp_body['portprofiles']['portprofile']['id'] +
|
resp_body['portprofiles']['portprofile']['id'] +
|
||||||
"/associate_portprofile")
|
"/associate_portprofile")
|
||||||
@ -582,7 +582,7 @@ class NovatenantExtensionTest(unittest.TestCase):
|
|||||||
def test_schedule_host(self):
|
def test_schedule_host(self):
|
||||||
""" Test get host"""
|
""" Test get host"""
|
||||||
LOG.debug("test_schedule_host - START")
|
LOG.debug("test_schedule_host - START")
|
||||||
req_body = json.dumps(self.test_associate_data)
|
req_body = jsonutils.dumps(self.test_associate_data)
|
||||||
host_path = self.novatenants_path + "001/schedule_host"
|
host_path = self.novatenants_path + "001/schedule_host"
|
||||||
host_response = self.test_app.put(
|
host_response = self.test_app.put(
|
||||||
host_path, req_body,
|
host_path, req_body,
|
||||||
@ -603,7 +603,7 @@ class NovatenantExtensionTest(unittest.TestCase):
|
|||||||
def test_associate_port(self):
|
def test_associate_port(self):
|
||||||
""" Test get associate port """
|
""" Test get associate port """
|
||||||
LOG.debug("test_associate_port - START")
|
LOG.debug("test_associate_port - START")
|
||||||
req_body = json.dumps(self.test_associate_port_data)
|
req_body = jsonutils.dumps(self.test_associate_port_data)
|
||||||
associate_port_path = self.novatenants_path + "001/associate_port"
|
associate_port_path = self.novatenants_path + "001/associate_port"
|
||||||
associate_port_response = self.test_app.put(
|
associate_port_response = self.test_app.put(
|
||||||
associate_port_path, req_body,
|
associate_port_path, req_body,
|
||||||
@ -650,7 +650,7 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test create qos """
|
""" Test create qos """
|
||||||
|
|
||||||
LOG.debug("test_create_qos - START")
|
LOG.debug("test_create_qos - START")
|
||||||
req_body = json.dumps(self.test_qos_data)
|
req_body = jsonutils.dumps(self.test_qos_data)
|
||||||
index_response = self.test_app.post(self.qos_path,
|
index_response = self.test_app.post(self.qos_path,
|
||||||
req_body,
|
req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -681,10 +681,10 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test list qoss """
|
""" Test list qoss """
|
||||||
|
|
||||||
LOG.debug("test_list_qoss - START")
|
LOG.debug("test_list_qoss - START")
|
||||||
req_body1 = json.dumps(self.test_qos_data)
|
req_body1 = jsonutils.dumps(self.test_qos_data)
|
||||||
create_resp1 = self.test_app.post(self.qos_path, req_body1,
|
create_resp1 = self.test_app.post(self.qos_path, req_body1,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
req_body2 = json.dumps({
|
req_body2 = jsonutils.dumps({
|
||||||
'qos': {
|
'qos': {
|
||||||
'qos_name': 'cisco_test_qos2',
|
'qos_name': 'cisco_test_qos2',
|
||||||
'qos_desc': {
|
'qos_desc': {
|
||||||
@ -721,7 +721,7 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test show qos """
|
""" Test show qos """
|
||||||
|
|
||||||
LOG.debug("test_show_qos - START")
|
LOG.debug("test_show_qos - START")
|
||||||
req_body = json.dumps(self.test_qos_data)
|
req_body = jsonutils.dumps(self.test_qos_data)
|
||||||
index_response = self.test_app.post(self.qos_path, req_body,
|
index_response = self.test_app.post(self.qos_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
||||||
@ -756,12 +756,12 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test update qos """
|
""" Test update qos """
|
||||||
|
|
||||||
LOG.debug("test_update_qos - START")
|
LOG.debug("test_update_qos - START")
|
||||||
req_body = json.dumps(self.test_qos_data)
|
req_body = jsonutils.dumps(self.test_qos_data)
|
||||||
index_response = self.test_app.post(self.qos_path, req_body,
|
index_response = self.test_app.post(self.qos_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
||||||
self.contenttype)
|
self.contenttype)
|
||||||
rename_req_body = json.dumps({
|
rename_req_body = jsonutils.dumps({
|
||||||
'qos': {
|
'qos': {
|
||||||
'qos_name': 'cisco_rename_qos',
|
'qos_name': 'cisco_rename_qos',
|
||||||
'qos_desc': {
|
'qos_desc': {
|
||||||
@ -789,7 +789,7 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test update qos does not exist """
|
""" Test update qos does not exist """
|
||||||
|
|
||||||
LOG.debug("test_update_qosDNE - START")
|
LOG.debug("test_update_qosDNE - START")
|
||||||
rename_req_body = json.dumps({
|
rename_req_body = jsonutils.dumps({
|
||||||
'qos': {
|
'qos': {
|
||||||
'qos_name': 'cisco_rename_qos',
|
'qos_name': 'cisco_rename_qos',
|
||||||
'qos_desc': {
|
'qos_desc': {
|
||||||
@ -811,7 +811,7 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test update qos bad request """
|
""" Test update qos bad request """
|
||||||
|
|
||||||
LOG.debug("test_update_qosBADRequest - START")
|
LOG.debug("test_update_qosBADRequest - START")
|
||||||
req_body = json.dumps(self.test_qos_data)
|
req_body = jsonutils.dumps(self.test_qos_data)
|
||||||
index_response = self.test_app.post(self.qos_path, req_body,
|
index_response = self.test_app.post(self.qos_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
||||||
@ -832,7 +832,7 @@ class QosExtensionTest(unittest.TestCase):
|
|||||||
""" Test delte qos """
|
""" Test delte qos """
|
||||||
|
|
||||||
LOG.debug("test_delete_qos - START")
|
LOG.debug("test_delete_qos - START")
|
||||||
req_body = json.dumps({
|
req_body = jsonutils.dumps({
|
||||||
'qos': {
|
'qos': {
|
||||||
'qos_name': 'cisco_test_qos',
|
'qos_name': 'cisco_test_qos',
|
||||||
'qos_desc': {
|
'qos_desc': {
|
||||||
@ -905,11 +905,11 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
|
|
||||||
#Create Credential before listing
|
#Create Credential before listing
|
||||||
LOG.debug("test_list_credentials - START")
|
LOG.debug("test_list_credentials - START")
|
||||||
req_body1 = json.dumps(self.test_credential_data)
|
req_body1 = jsonutils.dumps(self.test_credential_data)
|
||||||
create_response1 = self.test_app.post(
|
create_response1 = self.test_app.post(
|
||||||
self.credential_path, req_body1,
|
self.credential_path, req_body1,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
req_body2 = json.dumps({
|
req_body2 = jsonutils.dumps({
|
||||||
'credential': {
|
'credential': {
|
||||||
'credential_name': 'cred9',
|
'credential_name': 'cred9',
|
||||||
'user_name': 'newUser2',
|
'user_name': 'newUser2',
|
||||||
@ -949,7 +949,7 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
""" Test create credential """
|
""" Test create credential """
|
||||||
|
|
||||||
LOG.debug("test_create_credential - START")
|
LOG.debug("test_create_credential - START")
|
||||||
req_body = json.dumps(self.test_credential_data)
|
req_body = jsonutils.dumps(self.test_credential_data)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.credential_path, req_body,
|
self.credential_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -979,7 +979,7 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
""" Test show credential """
|
""" Test show credential """
|
||||||
|
|
||||||
LOG.debug("test_show_credential - START")
|
LOG.debug("test_show_credential - START")
|
||||||
req_body = json.dumps(self.test_credential_data)
|
req_body = jsonutils.dumps(self.test_credential_data)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.credential_path, req_body,
|
self.credential_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -1015,14 +1015,14 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
""" Test update credential """
|
""" Test update credential """
|
||||||
|
|
||||||
LOG.debug("test_update_credential - START")
|
LOG.debug("test_update_credential - START")
|
||||||
req_body = json.dumps(self.test_credential_data)
|
req_body = jsonutils.dumps(self.test_credential_data)
|
||||||
|
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.credential_path, req_body,
|
self.credential_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
resp_body = wsgi.Serializer().deserialize(
|
resp_body = wsgi.Serializer().deserialize(
|
||||||
index_response.body, self.contenttype)
|
index_response.body, self.contenttype)
|
||||||
rename_req_body = json.dumps({
|
rename_req_body = jsonutils.dumps({
|
||||||
'credential': {
|
'credential': {
|
||||||
'credential_name': 'cred3',
|
'credential_name': 'cred3',
|
||||||
'user_name': 'RenamedUser',
|
'user_name': 'RenamedUser',
|
||||||
@ -1051,7 +1051,7 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
""" Test update credential bad request """
|
""" Test update credential bad request """
|
||||||
|
|
||||||
LOG.debug("test_update_credBADReq - START")
|
LOG.debug("test_update_credBADReq - START")
|
||||||
req_body = json.dumps(self.test_credential_data)
|
req_body = jsonutils.dumps(self.test_credential_data)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.credential_path, req_body,
|
self.credential_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -1070,7 +1070,7 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
""" Test update credential does not exist"""
|
""" Test update credential does not exist"""
|
||||||
|
|
||||||
LOG.debug("test_update_credentialDNE - START")
|
LOG.debug("test_update_credentialDNE - START")
|
||||||
rename_req_body = json.dumps({
|
rename_req_body = jsonutils.dumps({
|
||||||
'credential': {
|
'credential': {
|
||||||
'credential_name': 'cred3',
|
'credential_name': 'cred3',
|
||||||
'user_name': 'RenamedUser',
|
'user_name': 'RenamedUser',
|
||||||
@ -1090,7 +1090,7 @@ class CredentialExtensionTest(unittest.TestCase):
|
|||||||
""" Test delete credential """
|
""" Test delete credential """
|
||||||
|
|
||||||
LOG.debug("test_delete_credential - START")
|
LOG.debug("test_delete_credential - START")
|
||||||
req_body = json.dumps(self.test_credential_data)
|
req_body = jsonutils.dumps(self.test_credential_data)
|
||||||
index_response = self.test_app.post(
|
index_response = self.test_app.post(
|
||||||
self.credential_path, req_body,
|
self.credential_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
@ -1212,7 +1212,7 @@ class MultiPortExtensionTest(unittest.TestCase):
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
req_body = json.dumps(test_multi_port)
|
req_body = jsonutils.dumps(test_multi_port)
|
||||||
index_response = self.test_app.post(self.multiport_path, req_body,
|
index_response = self.test_app.post(self.multiport_path, req_body,
|
||||||
content_type=self.contenttype)
|
content_type=self.contenttype)
|
||||||
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
resp_body = wsgi.Serializer().deserialize(index_response.body,
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import httplib
|
import httplib
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
@ -22,6 +21,7 @@ import urlparse
|
|||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import timeout
|
from eventlet import timeout
|
||||||
|
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.plugins.nicira.nicira_nvp_plugin.api_client.common import (
|
from quantum.plugins.nicira.nicira_nvp_plugin.api_client.common import (
|
||||||
_conn_str,
|
_conn_str,
|
||||||
)
|
)
|
||||||
@ -332,7 +332,7 @@ class NvpGetApiProvidersRequestEventlet(NvpApiRequestEventlet):
|
|||||||
try:
|
try:
|
||||||
if self.successful():
|
if self.successful():
|
||||||
ret = []
|
ret = []
|
||||||
body = json.loads(self.value.body)
|
body = jsonutils.loads(self.value.body)
|
||||||
for node in body.get('results', []):
|
for node in body.get('results', []):
|
||||||
for role in node.get('roles', []):
|
for role in node.get('roles', []):
|
||||||
if role.get('role') == 'api_provider':
|
if role.get('role') == 'api_provider':
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
#
|
#
|
||||||
# @author: Brad Hall, Nicira Networks, Inc.
|
# @author: Brad Hall, Nicira Networks, Inc.
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from quantum.common import exceptions as exception
|
from quantum.common import exceptions as exception
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.plugins.nicira.nicira_nvp_plugin import NvpApiClient
|
from quantum.plugins.nicira.nicira_nvp_plugin import NvpApiClient
|
||||||
|
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ def check_default_transport_zone(c):
|
|||||||
"GET",
|
"GET",
|
||||||
"/ws.v1/transport-zone?uuid=%s" % c.default_tz_uuid,
|
"/ws.v1/transport-zone?uuid=%s" % c.default_tz_uuid,
|
||||||
controller=c)
|
controller=c)
|
||||||
result = json.loads(resp)
|
result = jsonutils.loads(resp)
|
||||||
if int(result["result_count"]) == 0:
|
if int(result["result_count"]) == 0:
|
||||||
msg.append("Unable to find zone \"%s\" for controller \"%s\"" %
|
msg.append("Unable to find zone \"%s\" for controller \"%s\"" %
|
||||||
(c.default_tz_uuid, c.name))
|
(c.default_tz_uuid, c.name))
|
||||||
@ -67,7 +67,7 @@ def get_network(controller, net_id):
|
|||||||
path = "/ws.v1/lswitch/%s" % net_id
|
path = "/ws.v1/lswitch/%s" % net_id
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request("GET", path, controller=controller)
|
resp_obj = do_single_request("GET", path, controller=controller)
|
||||||
network = json.loads(resp_obj)
|
network = jsonutils.loads(resp_obj)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
raise exception.NetworkNotFound(net_id=net_id)
|
raise exception.NetworkNotFound(net_id=net_id)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
@ -86,12 +86,12 @@ def create_lswitch(controller, lswitch_obj):
|
|||||||
uri = "/ws.v1/lswitch"
|
uri = "/ws.v1/lswitch"
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request("POST", uri,
|
resp_obj = do_single_request("POST", uri,
|
||||||
json.dumps(lswitch_obj),
|
jsonutils.dumps(lswitch_obj),
|
||||||
controller=controller)
|
controller=controller)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
|
|
||||||
r = json.loads(resp_obj)
|
r = jsonutils.loads(resp_obj)
|
||||||
d = {}
|
d = {}
|
||||||
d["net-id"] = r["uuid"]
|
d["net-id"] = r["uuid"]
|
||||||
d["net-name"] = r["display_name"]
|
d["net-name"] = r["display_name"]
|
||||||
@ -105,15 +105,17 @@ def update_network(controller, network, **kwargs):
|
|||||||
if "name" in kwargs:
|
if "name" in kwargs:
|
||||||
lswitch_obj["display_name"] = kwargs["name"]
|
lswitch_obj["display_name"] = kwargs["name"]
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request(
|
resp_obj = do_single_request("PUT",
|
||||||
"PUT", uri, json.dumps(lswitch_obj), controller=controller)
|
uri,
|
||||||
|
jsonutils.dumps(lswitch_obj),
|
||||||
|
controller=controller)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Network not found, Error: %s" % str(e))
|
LOG.error("Network not found, Error: %s" % str(e))
|
||||||
raise exception.NetworkNotFound(net_id=network)
|
raise exception.NetworkNotFound(net_id=network)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
|
|
||||||
obj = json.loads(resp_obj)
|
obj = jsonutils.loads(resp_obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +130,7 @@ def get_all_networks(controller, tenant_id, networks):
|
|||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
if not resp_obj:
|
if not resp_obj:
|
||||||
return []
|
return []
|
||||||
lswitches = json.loads(resp_obj)["results"]
|
lswitches = jsonutils.loads(resp_obj)["results"]
|
||||||
for lswitch in lswitches:
|
for lswitch in lswitches:
|
||||||
net_id = lswitch["uuid"]
|
net_id = lswitch["uuid"]
|
||||||
if net_id not in [x["net-id"] for x in networks]:
|
if net_id not in [x["net-id"] for x in networks]:
|
||||||
@ -148,7 +150,7 @@ def query_networks(controller, tenant_id, fields="*", tags=None):
|
|||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
if not resp_obj:
|
if not resp_obj:
|
||||||
return []
|
return []
|
||||||
lswitches = json.loads(resp_obj)["results"]
|
lswitches = jsonutils.loads(resp_obj)["results"]
|
||||||
nets = [{'net-id': lswitch["uuid"],
|
nets = [{'net-id': lswitch["uuid"],
|
||||||
'net-name': lswitch["display_name"]}
|
'net-name': lswitch["display_name"]}
|
||||||
for lswitch in lswitches]
|
for lswitch in lswitches]
|
||||||
@ -208,7 +210,7 @@ def get_port_stats(controller, network_id, port_id):
|
|||||||
try:
|
try:
|
||||||
path = "/ws.v1/lswitch/%s/lport/%s/statistic" % (network_id, port_id)
|
path = "/ws.v1/lswitch/%s/lport/%s/statistic" % (network_id, port_id)
|
||||||
resp = do_single_request("GET", path, controller=controller)
|
resp = do_single_request("GET", path, controller=controller)
|
||||||
stats = json.loads(resp)
|
stats = jsonutils.loads(resp)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Port not found, Error: %s" % str(e))
|
LOG.error("Port not found, Error: %s" % str(e))
|
||||||
raise exception.PortNotFound(port_id=port_id, net_id=network_id)
|
raise exception.PortNotFound(port_id=port_id, net_id=network_id)
|
||||||
@ -242,7 +244,7 @@ def query_ports(controller, network, relations=None, fields="*", filters=None):
|
|||||||
raise exception.NetworkNotFound(net_id=network)
|
raise exception.NetworkNotFound(net_id=network)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
return json.loads(resp_obj)["results"]
|
return jsonutils.loads(resp_obj)["results"]
|
||||||
|
|
||||||
|
|
||||||
def delete_port(controller, network, port):
|
def delete_port(controller, network, port):
|
||||||
@ -260,7 +262,7 @@ def delete_all_ports(controller, ls_uuid):
|
|||||||
res = do_single_request("GET",
|
res = do_single_request("GET",
|
||||||
"/ws.v1/lswitch/%s/lport?fields=uuid" % ls_uuid,
|
"/ws.v1/lswitch/%s/lport?fields=uuid" % ls_uuid,
|
||||||
controller=controller)
|
controller=controller)
|
||||||
res = json.loads(res)
|
res = jsonutils.loads(res)
|
||||||
for r in res["results"]:
|
for r in res["results"]:
|
||||||
do_single_request(
|
do_single_request(
|
||||||
"DELETE",
|
"DELETE",
|
||||||
@ -274,7 +276,7 @@ def get_port(controller, network, port, relations=None):
|
|||||||
uri += "relations=%s" % relations
|
uri += "relations=%s" % relations
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request("GET", uri, controller=controller)
|
resp_obj = do_single_request("GET", uri, controller=controller)
|
||||||
port = json.loads(resp_obj)
|
port = jsonutils.loads(resp_obj)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Port or Network not found, Error: %s" % str(e))
|
LOG.error("Port or Network not found, Error: %s" % str(e))
|
||||||
raise exception.PortNotFound(port_id=port, net_id=network)
|
raise exception.PortNotFound(port_id=port, net_id=network)
|
||||||
@ -292,8 +294,10 @@ def plug_interface(controller, network, port, type, attachment=None):
|
|||||||
|
|
||||||
lport_obj["type"] = type
|
lport_obj["type"] = type
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request("PUT", uri,
|
resp_obj = do_single_request("PUT",
|
||||||
json.dumps(lport_obj), controller=controller)
|
uri,
|
||||||
|
jsonutils.dumps(lport_obj),
|
||||||
|
controller=controller)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Port or Network not found, Error: %s" % str(e))
|
LOG.error("Port or Network not found, Error: %s" % str(e))
|
||||||
raise exception.PortNotFound(port_id=port, net_id=network)
|
raise exception.PortNotFound(port_id=port, net_id=network)
|
||||||
@ -307,7 +311,7 @@ def plug_interface(controller, network, port, type, attachment=None):
|
|||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
|
|
||||||
result = json.dumps(resp_obj)
|
result = jsonutils.dumps(resp_obj)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -315,14 +319,16 @@ def unplug_interface(controller, network, port):
|
|||||||
uri = "/ws.v1/lswitch/" + network + "/lport/" + port + "/attachment"
|
uri = "/ws.v1/lswitch/" + network + "/lport/" + port + "/attachment"
|
||||||
lport_obj = {"type": "NoAttachment"}
|
lport_obj = {"type": "NoAttachment"}
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request(
|
resp_obj = do_single_request("PUT",
|
||||||
"PUT", uri, json.dumps(lport_obj), controller=controller)
|
uri,
|
||||||
|
jsonutils.dumps(lport_obj),
|
||||||
|
controller=controller)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Port or Network not found, Error: %s" % str(e))
|
LOG.error("Port or Network not found, Error: %s" % str(e))
|
||||||
raise exception.PortNotFound(port_id=port, net_id=network)
|
raise exception.PortNotFound(port_id=port, net_id=network)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
return json.loads(resp_obj)
|
return jsonutils.loads(resp_obj)
|
||||||
|
|
||||||
|
|
||||||
def update_port(network, port_id, **params):
|
def update_port(network, port_id, **params):
|
||||||
@ -339,15 +345,17 @@ def update_port(network, port_id, **params):
|
|||||||
|
|
||||||
uri = "/ws.v1/lswitch/" + network + "/lport/" + port_id
|
uri = "/ws.v1/lswitch/" + network + "/lport/" + port_id
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request(
|
resp_obj = do_single_request("PUT",
|
||||||
"PUT", uri, json.dumps(lport_obj), controller=controller)
|
uri,
|
||||||
|
jsonutils.dumps(lport_obj),
|
||||||
|
controller=controller)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Port or Network not found, Error: %s" % str(e))
|
LOG.error("Port or Network not found, Error: %s" % str(e))
|
||||||
raise exception.PortNotFound(port_id=port_id, net_id=network)
|
raise exception.PortNotFound(port_id=port_id, net_id=network)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
|
|
||||||
obj = json.loads(resp_obj)
|
obj = jsonutils.loads(resp_obj)
|
||||||
obj["port-op-status"] = get_port_status(controller, network, obj["uuid"])
|
obj["port-op-status"] = get_port_status(controller, network, obj["uuid"])
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
@ -368,15 +376,17 @@ def create_port(tenant, network, port_init_state, **params):
|
|||||||
|
|
||||||
path = "/ws.v1/lswitch/" + ls_uuid + "/lport"
|
path = "/ws.v1/lswitch/" + ls_uuid + "/lport"
|
||||||
try:
|
try:
|
||||||
resp_obj = do_single_request(
|
resp_obj = do_single_request("POST",
|
||||||
"POST", path, json.dumps(lport_obj), controller=controller)
|
path,
|
||||||
|
jsonutils.dumps(lport_obj),
|
||||||
|
controller=controller)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Network not found, Error: %s" % str(e))
|
LOG.error("Network not found, Error: %s" % str(e))
|
||||||
raise exception.NetworkNotFound(net_id=network)
|
raise exception.NetworkNotFound(net_id=network)
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
|
|
||||||
result = json.loads(resp_obj)
|
result = jsonutils.loads(resp_obj)
|
||||||
result['port-op-status'] = get_port_status(controller, ls_uuid,
|
result['port-op-status'] = get_port_status(controller, ls_uuid,
|
||||||
result['uuid'])
|
result['uuid'])
|
||||||
return result
|
return result
|
||||||
@ -398,7 +408,7 @@ def get_port_status(controller, lswitch_id, port_id):
|
|||||||
"GET",
|
"GET",
|
||||||
"/ws.v1/lswitch/%s/lport/%s/status" % (lswitch_id, port_id),
|
"/ws.v1/lswitch/%s/lport/%s/status" % (lswitch_id, port_id),
|
||||||
controller=controller)
|
controller=controller)
|
||||||
r = json.loads(r)
|
r = jsonutils.loads(r)
|
||||||
except NvpApiClient.ResourceNotFound as e:
|
except NvpApiClient.ResourceNotFound as e:
|
||||||
LOG.error("Port not found, Error: %s" % str(e))
|
LOG.error("Port not found, Error: %s" % str(e))
|
||||||
raise exception.PortNotFound(port_id=port_id, net_id=lswitch_id)
|
raise exception.PortNotFound(port_id=port_id, net_id=lswitch_id)
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
# @author: Somik Behera, Nicira Networks, Inc.
|
# @author: Somik Behera, Nicira Networks, Inc.
|
||||||
# @author: Brad Hall, Nicira Networks, Inc.
|
# @author: Brad Hall, Nicira Networks, Inc.
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from quantum.common import exceptions as exception
|
from quantum.common import exceptions as exception
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin import NvpPlugin
|
from quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin import NvpPlugin
|
||||||
from quantum.plugins.nicira.nicira_nvp_plugin import (
|
from quantum.plugins.nicira.nicira_nvp_plugin import (
|
||||||
NvpApiClient,
|
NvpApiClient,
|
||||||
@ -56,11 +56,11 @@ class NvpTests(unittest.TestCase):
|
|||||||
"tags": [{"tag": "plugin-test"}]}
|
"tags": [{"tag": "plugin-test"}]}
|
||||||
try:
|
try:
|
||||||
resp_obj = self.quantum.api_client.request("POST",
|
resp_obj = self.quantum.api_client.request("POST",
|
||||||
post_uri, json.dumps(body))
|
post_uri, jsonutils.dumps(body))
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
print("Unknown API Error: %s" % str(e))
|
print("Unknown API Error: %s" % str(e))
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
return json.loads(resp_obj)["uuid"]
|
return jsonutils.loads(resp_obj)["uuid"]
|
||||||
|
|
||||||
def _delete_tz(self, uuid):
|
def _delete_tz(self, uuid):
|
||||||
post_uri = "/ws.v1/transport-zone/%s" % uuid
|
post_uri = "/ws.v1/transport-zone/%s" % uuid
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
#
|
#
|
||||||
# @author: Somik Behera, Nicira Networks, Inc.
|
# @author: Somik Behera, Nicira Networks, Inc.
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from quantum.common import exceptions as exception
|
from quantum.common import exceptions as exception
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin import NvpPlugin
|
from quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin import NvpPlugin
|
||||||
from quantum.plugins.nicira.nicira_nvp_plugin import (
|
from quantum.plugins.nicira.nicira_nvp_plugin import (
|
||||||
NvpApiClient,
|
NvpApiClient,
|
||||||
@ -61,12 +61,13 @@ class NvpTests(unittest.TestCase):
|
|||||||
post_uri = "/ws.v1/transport-zone"
|
post_uri = "/ws.v1/transport-zone"
|
||||||
body = {"display_name": name, "tags": [{"tag": "plugin-test"}]}
|
body = {"display_name": name, "tags": [{"tag": "plugin-test"}]}
|
||||||
try:
|
try:
|
||||||
resp_obj = self.quantum.api_client.request(
|
resp_obj = self.quantum.api_client.request("POST",
|
||||||
"POST", post_uri, json.dumps(body))
|
post_uri,
|
||||||
|
jsonutils.dumps(body))
|
||||||
except NvpApiClient.NvpApiException as e:
|
except NvpApiClient.NvpApiException as e:
|
||||||
LOG.error("Unknown API Error: %s" % str(e))
|
LOG.error("Unknown API Error: %s" % str(e))
|
||||||
raise exception.QuantumException()
|
raise exception.QuantumException()
|
||||||
return json.loads(resp_obj)["uuid"]
|
return jsonutils.loads(resp_obj)["uuid"]
|
||||||
|
|
||||||
def _delete_tz(self, uuid):
|
def _delete_tz(self, uuid):
|
||||||
post_uri = "/ws.v1/transport-zone/%s" % uuid
|
post_uri = "/ws.v1/transport-zone/%s" % uuid
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
import json
|
|
||||||
|
|
||||||
from quantum.extensions import extensions
|
from quantum.extensions import extensions
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum import wsgi
|
from quantum import wsgi
|
||||||
|
|
||||||
|
|
||||||
@ -79,9 +79,9 @@ class Foxinsocks(object):
|
|||||||
def _goose_handler(req, res):
|
def _goose_handler(req, res):
|
||||||
#NOTE: This only handles JSON responses.
|
#NOTE: This only handles JSON responses.
|
||||||
# You can use content type header to test for XML.
|
# You can use content type header to test for XML.
|
||||||
data = json.loads(res.body)
|
data = jsonutils.loads(res.body)
|
||||||
data['FOXNSOX:googoose'] = req.GET.get('chewing')
|
data['FOXNSOX:googoose'] = req.GET.get('chewing')
|
||||||
res.body = json.dumps(data)
|
res.body = jsonutils.dumps(data)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
req_ext1 = extensions.RequestExtension('GET', '/dummy_resources/:(id)',
|
req_ext1 = extensions.RequestExtension('GET', '/dummy_resources/:(id)',
|
||||||
@ -91,9 +91,9 @@ class Foxinsocks(object):
|
|||||||
def _bands_handler(req, res):
|
def _bands_handler(req, res):
|
||||||
#NOTE: This only handles JSON responses.
|
#NOTE: This only handles JSON responses.
|
||||||
# You can use content type header to test for XML.
|
# You can use content type header to test for XML.
|
||||||
data = json.loads(res.body)
|
data = jsonutils.loads(res.body)
|
||||||
data['FOXNSOX:big_bands'] = 'Pig Bands!'
|
data['FOXNSOX:big_bands'] = 'Pig Bands!'
|
||||||
res.body = json.dumps(data)
|
res.body = jsonutils.dumps(data)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
req_ext2 = extensions.RequestExtension('GET', '/dummy_resources/:(id)',
|
req_ext2 = extensions.RequestExtension('GET', '/dummy_resources/:(id)',
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
# @author: Salvatore Orlando, Citrix Systems
|
# @author: Salvatore Orlando, Citrix Systems
|
||||||
|
|
||||||
import json
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
@ -27,6 +26,7 @@ import quantum.api.networks as nets
|
|||||||
import quantum.api.ports as ports
|
import quantum.api.ports as ports
|
||||||
import quantum.api.versions as versions
|
import quantum.api.versions as versions
|
||||||
from quantum.common.test_lib import test_config
|
from quantum.common.test_lib import test_config
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
import quantum.tests.unit._test_api as test_api
|
import quantum.tests.unit._test_api as test_api
|
||||||
import quantum.tests.unit.testlib_api as testlib
|
import quantum.tests.unit.testlib_api as testlib
|
||||||
|
|
||||||
@ -353,7 +353,7 @@ class APIRootTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_root_responds_with_versions_json(self):
|
def test_root_responds_with_versions_json(self):
|
||||||
body = self._test_root_responds_with_versions('application/json')
|
body = self._test_root_responds_with_versions('application/json')
|
||||||
data = json.loads(body)
|
data = jsonutils.loads(body)
|
||||||
self.assertEquals('versions', data.keys()[0])
|
self.assertEquals('versions', data.keys()[0])
|
||||||
|
|
||||||
def test_root_responds_with_versions_xml(self):
|
def test_root_responds_with_versions_xml(self):
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import json
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import routes
|
import routes
|
||||||
@ -30,6 +29,7 @@ from quantum.extensions.extensions import (
|
|||||||
ExtensionMiddleware,
|
ExtensionMiddleware,
|
||||||
PluginAwareExtensionManager,
|
PluginAwareExtensionManager,
|
||||||
)
|
)
|
||||||
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.plugins.sample.SamplePlugin import QuantumEchoPlugin
|
from quantum.plugins.sample.SamplePlugin import QuantumEchoPlugin
|
||||||
from quantum.tests.unit import BaseTest
|
from quantum.tests.unit import BaseTest
|
||||||
from quantum.tests.unit.extension_stubs import (
|
from quantum.tests.unit.extension_stubs import (
|
||||||
@ -114,7 +114,8 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
|
|
||||||
response = test_app.get("/tweedles/some_id/custom_member_action")
|
response = test_app.get("/tweedles/some_id/custom_member_action")
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['member_action'], "value")
|
self.assertEqual(jsonutils.loads(response.body)['member_action'],
|
||||||
|
"value")
|
||||||
|
|
||||||
def test_resource_extension_for_get_custom_collection_action(self):
|
def test_resource_extension_for_get_custom_collection_action(self):
|
||||||
controller = self.ResourceExtensionController()
|
controller = self.ResourceExtensionController()
|
||||||
@ -125,7 +126,7 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
|
|
||||||
response = test_app.get("/tweedles/custom_collection_action")
|
response = test_app.get("/tweedles/custom_collection_action")
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['collection'], "value")
|
self.assertEqual(jsonutils.loads(response.body)['collection'], "value")
|
||||||
|
|
||||||
def test_resource_extension_for_put_custom_collection_action(self):
|
def test_resource_extension_for_put_custom_collection_action(self):
|
||||||
controller = self.ResourceExtensionController()
|
controller = self.ResourceExtensionController()
|
||||||
@ -137,7 +138,7 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
response = test_app.put("/tweedles/custom_collection_action")
|
response = test_app.put("/tweedles/custom_collection_action")
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['collection'], 'value')
|
self.assertEqual(jsonutils.loads(response.body)['collection'], 'value')
|
||||||
|
|
||||||
def test_resource_extension_for_post_custom_collection_action(self):
|
def test_resource_extension_for_post_custom_collection_action(self):
|
||||||
controller = self.ResourceExtensionController()
|
controller = self.ResourceExtensionController()
|
||||||
@ -149,7 +150,7 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
response = test_app.post("/tweedles/custom_collection_action")
|
response = test_app.post("/tweedles/custom_collection_action")
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['collection'], 'value')
|
self.assertEqual(jsonutils.loads(response.body)['collection'], 'value')
|
||||||
|
|
||||||
def test_resource_extension_for_delete_custom_collection_action(self):
|
def test_resource_extension_for_delete_custom_collection_action(self):
|
||||||
controller = self.ResourceExtensionController()
|
controller = self.ResourceExtensionController()
|
||||||
@ -161,7 +162,7 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
response = test_app.delete("/tweedles/custom_collection_action")
|
response = test_app.delete("/tweedles/custom_collection_action")
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['collection'], 'value')
|
self.assertEqual(jsonutils.loads(response.body)['collection'], 'value')
|
||||||
|
|
||||||
def test_resource_ext_for_formatted_req_on_custom_collection_action(self):
|
def test_resource_ext_for_formatted_req_on_custom_collection_action(self):
|
||||||
controller = self.ResourceExtensionController()
|
controller = self.ResourceExtensionController()
|
||||||
@ -173,7 +174,7 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
response = test_app.get("/tweedles/custom_collection_action.json")
|
response = test_app.get("/tweedles/custom_collection_action.json")
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['collection'], "value")
|
self.assertEqual(jsonutils.loads(response.body)['collection'], "value")
|
||||||
|
|
||||||
def test_resource_ext_for_nested_resource_custom_collection_action(self):
|
def test_resource_ext_for_nested_resource_custom_collection_action(self):
|
||||||
controller = self.ResourceExtensionController()
|
controller = self.ResourceExtensionController()
|
||||||
@ -188,7 +189,7 @@ class ResourceExtensionTest(unittest.TestCase):
|
|||||||
"/tweedles/custom_collection_action")
|
"/tweedles/custom_collection_action")
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual(json.loads(response.body)['collection'], "value")
|
self.assertEqual(jsonutils.loads(response.body)['collection'], "value")
|
||||||
|
|
||||||
def test_returns_404_for_non_existant_extension(self):
|
def test_returns_404_for_non_existant_extension(self):
|
||||||
test_app = setup_extensions_test_app(SimpleExtensionManager(None))
|
test_app = setup_extensions_test_app(SimpleExtensionManager(None))
|
||||||
@ -207,7 +208,7 @@ class ActionExtensionTest(unittest.TestCase):
|
|||||||
def test_extended_action_for_adding_extra_data(self):
|
def test_extended_action_for_adding_extra_data(self):
|
||||||
action_name = 'FOXNSOX:add_tweedle'
|
action_name = 'FOXNSOX:add_tweedle'
|
||||||
action_params = dict(name='Beetle')
|
action_params = dict(name='Beetle')
|
||||||
req_body = json.dumps({action_name: action_params})
|
req_body = jsonutils.dumps({action_name: action_params})
|
||||||
response = self.extension_app.post('/dummy_resources/1/action',
|
response = self.extension_app.post('/dummy_resources/1/action',
|
||||||
req_body,
|
req_body,
|
||||||
content_type='application/json')
|
content_type='application/json')
|
||||||
@ -216,7 +217,7 @@ class ActionExtensionTest(unittest.TestCase):
|
|||||||
def test_extended_action_for_deleting_extra_data(self):
|
def test_extended_action_for_deleting_extra_data(self):
|
||||||
action_name = 'FOXNSOX:delete_tweedle'
|
action_name = 'FOXNSOX:delete_tweedle'
|
||||||
action_params = dict(name='Bailey')
|
action_params = dict(name='Bailey')
|
||||||
req_body = json.dumps({action_name: action_params})
|
req_body = jsonutils.dumps({action_name: action_params})
|
||||||
response = self.extension_app.post("/dummy_resources/1/action",
|
response = self.extension_app.post("/dummy_resources/1/action",
|
||||||
req_body,
|
req_body,
|
||||||
content_type='application/json')
|
content_type='application/json')
|
||||||
@ -225,7 +226,7 @@ class ActionExtensionTest(unittest.TestCase):
|
|||||||
def test_returns_404_for_non_existant_action(self):
|
def test_returns_404_for_non_existant_action(self):
|
||||||
non_existant_action = 'blah_action'
|
non_existant_action = 'blah_action'
|
||||||
action_params = dict(name="test")
|
action_params = dict(name="test")
|
||||||
req_body = json.dumps({non_existant_action: action_params})
|
req_body = jsonutils.dumps({non_existant_action: action_params})
|
||||||
|
|
||||||
response = self.extension_app.post("/dummy_resources/1/action",
|
response = self.extension_app.post("/dummy_resources/1/action",
|
||||||
req_body,
|
req_body,
|
||||||
@ -237,7 +238,7 @@ class ActionExtensionTest(unittest.TestCase):
|
|||||||
def test_returns_404_for_non_existant_resource(self):
|
def test_returns_404_for_non_existant_resource(self):
|
||||||
action_name = 'add_tweedle'
|
action_name = 'add_tweedle'
|
||||||
action_params = dict(name='Beetle')
|
action_params = dict(name='Beetle')
|
||||||
req_body = json.dumps({action_name: action_params})
|
req_body = jsonutils.dumps({action_name: action_params})
|
||||||
|
|
||||||
response = self.extension_app.post("/asdf/1/action", req_body,
|
response = self.extension_app.post("/asdf/1/action", req_body,
|
||||||
content_type='application/json',
|
content_type='application/json',
|
||||||
@ -262,16 +263,16 @@ class RequestExtensionTest(BaseTest):
|
|||||||
|
|
||||||
def test_extend_get_resource_response(self):
|
def test_extend_get_resource_response(self):
|
||||||
def extend_response_data(req, res):
|
def extend_response_data(req, res):
|
||||||
data = json.loads(res.body)
|
data = jsonutils.loads(res.body)
|
||||||
data['FOXNSOX:extended_key'] = req.GET.get('extended_key')
|
data['FOXNSOX:extended_key'] = req.GET.get('extended_key')
|
||||||
res.body = json.dumps(data)
|
res.body = jsonutils.dumps(data)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
app = self._setup_app_with_request_handler(extend_response_data, 'GET')
|
app = self._setup_app_with_request_handler(extend_response_data, 'GET')
|
||||||
response = app.get("/dummy_resources/1?extended_key=extended_data")
|
response = app.get("/dummy_resources/1?extended_key=extended_data")
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
response_data = json.loads(response.body)
|
response_data = jsonutils.loads(response.body)
|
||||||
self.assertEqual('extended_data',
|
self.assertEqual('extended_data',
|
||||||
response_data['FOXNSOX:extended_key'])
|
response_data['FOXNSOX:extended_key'])
|
||||||
self.assertEqual('knox', response_data['fort'])
|
self.assertEqual('knox', response_data['fort'])
|
||||||
@ -281,16 +282,16 @@ class RequestExtensionTest(BaseTest):
|
|||||||
|
|
||||||
response = app.get("/dummy_resources/1?chewing=newblue")
|
response = app.get("/dummy_resources/1?chewing=newblue")
|
||||||
|
|
||||||
response_data = json.loads(response.body)
|
response_data = jsonutils.loads(response.body)
|
||||||
self.assertEqual('newblue', response_data['FOXNSOX:googoose'])
|
self.assertEqual('newblue', response_data['FOXNSOX:googoose'])
|
||||||
self.assertEqual("Pig Bands!", response_data['FOXNSOX:big_bands'])
|
self.assertEqual("Pig Bands!", response_data['FOXNSOX:big_bands'])
|
||||||
|
|
||||||
def test_edit_previously_uneditable_field(self):
|
def test_edit_previously_uneditable_field(self):
|
||||||
|
|
||||||
def _update_handler(req, res):
|
def _update_handler(req, res):
|
||||||
data = json.loads(res.body)
|
data = jsonutils.loads(res.body)
|
||||||
data['uneditable'] = req.params['uneditable']
|
data['uneditable'] = req.params['uneditable']
|
||||||
res.body = json.dumps(data)
|
res.body = jsonutils.dumps(data)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
base_app = TestApp(setup_base_app())
|
base_app = TestApp(setup_base_app())
|
||||||
|
@ -32,7 +32,7 @@ import webob.dec
|
|||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from quantum.common import exceptions as exception
|
from quantum.common import exceptions as exception
|
||||||
from quantum.common import utils
|
from quantum.openstack.common import jsonutils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -181,7 +181,7 @@ class JSONDictSerializer(DictSerializer):
|
|||||||
"""Default JSON request body serialization"""
|
"""Default JSON request body serialization"""
|
||||||
|
|
||||||
def default(self, data):
|
def default(self, data):
|
||||||
return utils.dumps(data)
|
return jsonutils.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
class XMLDictSerializer(DictSerializer):
|
class XMLDictSerializer(DictSerializer):
|
||||||
@ -354,7 +354,7 @@ class JSONDeserializer(TextDeserializer):
|
|||||||
|
|
||||||
def _from_json(self, datastring):
|
def _from_json(self, datastring):
|
||||||
try:
|
try:
|
||||||
return utils.loads(datastring)
|
return jsonutils.loads(datastring)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
msg = _("cannot understand JSON")
|
msg = _("cannot understand JSON")
|
||||||
raise exception.MalformedRequestBody(reason=msg)
|
raise exception.MalformedRequestBody(reason=msg)
|
||||||
@ -956,7 +956,7 @@ class Serializer(object):
|
|||||||
raise exception.InvalidContentType(content_type=content_type)
|
raise exception.InvalidContentType(content_type=content_type)
|
||||||
|
|
||||||
def _from_json(self, datastring):
|
def _from_json(self, datastring):
|
||||||
return utils.loads(datastring)
|
return jsonutils.loads(datastring)
|
||||||
|
|
||||||
def _from_xml(self, datastring):
|
def _from_xml(self, datastring):
|
||||||
xmldata = self.metadata.get('application/xml', {})
|
xmldata = self.metadata.get('application/xml', {})
|
||||||
@ -987,7 +987,7 @@ class Serializer(object):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def _to_json(self, data):
|
def _to_json(self, data):
|
||||||
return utils.dumps(data)
|
return jsonutils.dumps(data)
|
||||||
|
|
||||||
def _to_xml(self, data):
|
def _to_xml(self, data):
|
||||||
metadata = self.metadata.get('application/xml', {})
|
metadata = self.metadata.get('application/xml', {})
|
||||||
|
Loading…
Reference in New Issue
Block a user