Nsx manager client: return meaningful errors

Change-Id: I03dc53a8aed95d6e8910027e657529170a29fbf5
This commit is contained in:
Roey Chen 2015-07-26 07:12:01 -07:00
parent 86c4ddb502
commit 9de1a96d40
5 changed files with 67 additions and 71 deletions

View File

@ -123,3 +123,17 @@ class DvsNotFound(n_exc.NotFound):
class NoRouterAvailable(n_exc.ResourceExhausted):
message = _("Unable to create the router. "
"No tenant router is available for allocation.")
class ManagerError(NsxPluginException):
message = _("Unexpected error from backend manager (%(manager)s) "
"for %(operation)s")
class ResourceNotFound(ManagerError):
message = _("Resource could not be found on backend (%(manager)s) for "
"%(operation)s")
class StaleRevision(ManagerError):
pass

View File

@ -14,10 +14,7 @@
# under the License.
from oslo_log import log
import requests
from neutron.i18n import _LI
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import client
@ -38,8 +35,7 @@ def create_logical_switch(display_name, transport_zone_id, tags,
'display_name': display_name,
'tags': tags}
result = client.create_resource(resource, body)
return result.json()
return client.create_resource(resource, body)
def delete_logical_switch(lswitch_id):
@ -66,8 +62,7 @@ def create_logical_port(lswitch_id, vif_uuid, tags,
if address_bindings:
body['address_bindings'] = address_bindings
result = client.create_resource(resource, body)
return result.json()
return client.create_resource(resource, body)
def delete_logical_port(logical_port_id):
@ -85,18 +80,14 @@ def create_logical_router(display_name, edge_cluster_uuid, tags, tier_0=False):
'display_name': display_name,
'router_type': router_type,
'tags': tags}
result = client.create_resource(resource, body)
return result.json()
return client.create_resource(resource, body)
def delete_logical_router(lrouter_id):
resource = 'logical-routers/%s/' % lrouter_id
# TODO(salv-orlando): Must handle connection exceptions
result = client.delete_resource(resource)
if result.status_code == requests.codes.not_found:
LOG.info(_LI("Logical router %s not found on NSX backend"), lrouter_id)
raise nsx_exc.LogicalRouterNotFound(entity_id=lrouter_id)
return client.delete_resource(resource)
def create_logical_router_port(logical_router_id,

View File

@ -24,6 +24,12 @@ from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
LOG = log.getLogger(__name__)
NOT_FOUND = 404
PRECONDITION_FAILED = 412
ERRORS = {NOT_FOUND: nsx_exc.ResourceNotFound,
PRECONDITION_FAILED: nsx_exc.StaleRevision}
def _get_manager_endpoint():
manager = _get_manager_ip()
@ -38,16 +44,19 @@ def _get_manager_ip():
return manager
def _validate_result(result, expected, operation):
if result.status_code not in expected:
def _validate_result(result_status_code, expected, operation):
if result_status_code not in expected:
# Do not reveal internal details in the exception message, as it will
# be user-visible
LOG.warning(_LW("The HTTP request returned error code %(result)d, "
"whereas %(expected)s response codes were expected"),
{'result': result.status_code,
{'result': result_status_code,
'expected': '/'.join([str(code) for code in expected])})
raise nsx_exc.NsxPluginException(
err_msg=_("Unexpected error in backend while %s") % operation)
manager_ip = _get_manager_ip()
manager_error = ERRORS.get(result_status_code, nsx_exc.ManagerError)
raise manager_error(manager=manager_ip, operation=operation)
def get_resource(resource):
@ -56,9 +65,9 @@ def get_resource(resource):
headers = {'Accept': 'application/json'}
result = requests.get(url, auth=auth.HTTPBasicAuth(user, password),
verify=False, headers=headers)
_validate_result(
result, [requests.codes.ok], _("reading resource: %s") % resource)
return result
_validate_result(result.status_code, [requests.codes.ok],
_("reading resource: %s") % resource)
return result.json()
def create_resource(resource, data):
@ -69,9 +78,9 @@ def create_resource(resource, data):
result = requests.post(url, auth=auth.HTTPBasicAuth(user, password),
verify=False, headers=headers,
data=jsonutils.dumps(data))
_validate_result(result, [requests.codes.created],
_validate_result(result.status_code, [requests.codes.created],
_("creating resource at: %s") % resource)
return result
return result.json()
def update_resource(resource, data):
@ -82,9 +91,9 @@ def update_resource(resource, data):
result = requests.put(url, auth=auth.HTTPBasicAuth(user, password),
verify=False, headers=headers,
data=jsonutils.dumps(data))
_validate_result(result, [requests.codes.ok],
_validate_result(result.status_code, [requests.codes.ok],
_("updating resource: %s") % resource)
return result
return result.json()
def delete_resource(resource):
@ -92,6 +101,6 @@ def delete_resource(resource):
url = manager + "/api/v1/%s" % resource
result = requests.delete(url, auth=auth.HTTPBasicAuth(user, password),
verify=False)
_validate_result(result, [requests.codes.ok, requests.codes.not_found],
_validate_result(result.status_code, [requests.codes.ok],
_("deleting resource: %s") % resource)
return result
return result.json()

View File

@ -15,7 +15,6 @@
#
import mock
import requests
from oslo_log import log
@ -28,54 +27,45 @@ LOG = log.getLogger(__name__)
class NsxLibPortTestCase(nsxlib_testcase.NsxLibTestCase):
def _create_mock_object(self, fake_object):
"""Construct mock response object"""
mock_response = mock.Mock()
if fake_object is not None:
mock_response.json.return_value = fake_object
return mock_response
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3.requests.post")
def test_create_logical_port(self, mock_post):
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3"
".client.create_resource")
def test_create_logical_port(self, mock_create_resource):
"""
Test creating a port returns the correct response and 200 status
"""
mock_post.return_value = self._create_mock_object(
test_constants_v3.FAKE_PORT)
mock_post.return_value.status_code = requests.codes.created
mock_create_resource.return_value = test_constants_v3.FAKE_PORT
result = nsxlib.create_logical_port(
test_constants_v3.FAKE_PORT['logical_switch_id'],
test_constants_v3.FAKE_PORT['attachment']['id'],
tags={})
test_constants_v3.FAKE_PORT['logical_switch_id'],
test_constants_v3.FAKE_PORT['attachment']['id'],
tags={})
self.assertEqual(test_constants_v3.FAKE_PORT, result)
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3.requests.post")
def test_create_logical_port_admin_down(self, mock_post):
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3"
".client.create_resource")
def test_create_logical_port_admin_down(self, mock_create_resource):
"""
Test creating port with admin_state down
"""
fake_port = test_constants_v3.FAKE_PORT
fake_port['admin_state'] = "DOWN"
mock_post.return_value = self._create_mock_object(fake_port)
mock_post.return_value.status_code = requests.codes.created
mock_create_resource.return_value = fake_port
result = nsxlib.create_logical_port(
test_constants_v3.FAKE_PORT['logical_switch_id'],
test_constants_v3.FAKE_PORT['attachment']['id'],
tags={}, admin_state=False)
test_constants_v3.FAKE_PORT['logical_switch_id'],
test_constants_v3.FAKE_PORT['attachment']['id'],
tags={}, admin_state=False)
self.assertEqual(fake_port, result)
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3.requests.delete")
def test_delete_logical_port(self, mock_delete):
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3"
".client.delete_resource")
def test_delete_logical_port(self, mock_delete_resource):
"""
Test deleting port
"""
mock_delete.return_value = self._create_mock_object(None)
mock_delete.return_value.status_code = requests.codes.ok
mock_delete_resource.return_value = None
result = nsxlib.delete_logical_port(
test_constants_v3.FAKE_PORT['id'])
result = nsxlib.delete_logical_port(test_constants_v3.FAKE_PORT['id'])
self.assertIsNone(result)

View File

@ -15,7 +15,6 @@
#
import mock
import requests
from oslo_log import log
@ -28,22 +27,15 @@ LOG = log.getLogger(__name__)
class NsxLibSwitchTestCase(nsxlib_testcase.NsxLibTestCase):
def _create_mock_object(self, fake_object):
"""Construct mock response object"""
mock_response = mock.Mock()
mock_response.json.return_value = fake_object
return mock_response
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3.requests.post")
def test_create_logical_switch(self, mock_post):
@mock.patch("vmware_nsx.neutron.plugins.vmware.nsxlib.v3"
".client.create_resource")
def test_create_logical_switch(self, mock_create_resource):
"""
Test creating a switch returns the correct response and 200 status
"""
mock_post.return_value = self._create_mock_object(
test_constants_v3.FAKE_SWITCH)
mock_post.return_value.status_code = requests.codes.created
mock_create_resource.return_value = test_constants_v3.FAKE_SWITCH
result = nsxlib.create_logical_switch(
test_constants_v3.FAKE_NAME,
test_constants_v3.FAKE_TZ_UUID, tags={})
result = nsxlib.create_logical_switch(test_constants_v3.FAKE_NAME,
test_constants_v3.FAKE_TZ_UUID,
tags={})
self.assertEqual(test_constants_v3.FAKE_SWITCH, result)