Merge "NSX plugin: return 400 for invalid gw certificate"

This commit is contained in:
Jenkins 2014-04-02 08:56:01 +00:00 committed by Gerrit Code Review
commit dade375698
5 changed files with 99 additions and 41 deletions

View File

@ -68,6 +68,21 @@ class RequestTimeout(NsxApiException):
message = _("The request has timed out.") message = _("The request has timed out.")
class BadRequest(NsxApiException):
message = _("The server is unable to fulfill the request due "
"to a bad syntax")
class InvalidSecurityCertificate(BadRequest):
message = _("The backend received an invalid security certificate.")
def fourZeroZero(response=None):
if response and "Invalid SecurityCertificate" in response.body:
raise InvalidSecurityCertificate()
raise BadRequest()
def fourZeroFour(response=None): def fourZeroFour(response=None):
raise ResourceNotFound() raise ResourceNotFound()
@ -92,6 +107,7 @@ def zero(self, response=None):
ERROR_MAPPINGS = { ERROR_MAPPINGS = {
400: fourZeroZero,
404: fourZeroFour, 404: fourZeroFour,
405: zero, 405: zero,
409: fourZeroNine, 409: fourZeroNine,
@ -99,7 +115,6 @@ ERROR_MAPPINGS = {
403: fourZeroThree, 403: fourZeroThree,
301: zero, 301: zero,
307: zero, 307: zero,
400: zero,
500: zero, 500: zero,
501: zero, 501: zero,
503: zero 503: zero

View File

@ -65,6 +65,13 @@ class L2GatewayAlreadyInUse(n_exc.Conflict):
message = _("Gateway Service %(gateway)s is already in use") message = _("Gateway Service %(gateway)s is already in use")
class InvalidSecurityCertificate(NsxPluginException):
message = _("An invalid security certificate was specified for the "
"gateway device. Certificates must be enclosed between "
"'-----BEGIN CERTIFICATE-----' and "
"'-----END CERTIFICATE-----'")
class ServiceOverQuota(n_exc.Conflict): class ServiceOverQuota(n_exc.Conflict):
message = _("Quota exceeded for Vcns resource: %(overs)s: %(err_msg)s") message = _("Quota exceeded for Vcns resource: %(overs)s: %(err_msg)s")

View File

@ -17,6 +17,8 @@
import json import json
from neutron.openstack.common import log from neutron.openstack.common import log
from neutron.plugins.vmware.api_client import exception as api_exc
from neutron.plugins.vmware.common import exceptions as nsx_exc
from neutron.plugins.vmware.common import utils from neutron.plugins.vmware.common import utils
from neutron.plugins.vmware.nsxlib import _build_uri_path from neutron.plugins.vmware.nsxlib import _build_uri_path
from neutron.plugins.vmware.nsxlib import do_request from neutron.plugins.vmware.nsxlib import do_request
@ -145,9 +147,12 @@ def create_gateway_device(cluster, tenant_id, display_name, neutron_id,
body = _build_gateway_device_body(tenant_id, display_name, neutron_id, body = _build_gateway_device_body(tenant_id, display_name, neutron_id,
connector_type, connector_ip, connector_type, connector_ip,
client_certificate, tz_uuid) client_certificate, tz_uuid)
return do_request( try:
HTTP_POST, _build_uri_path(TRANSPORTNODE_RESOURCE), return do_request(
json.dumps(body), cluster=cluster) HTTP_POST, _build_uri_path(TRANSPORTNODE_RESOURCE),
json.dumps(body), cluster=cluster)
except api_exc.InvalidSecurityCertificate:
raise nsx_exc.InvalidSecurityCertificate()
def update_gateway_device(cluster, gateway_id, tenant_id, def update_gateway_device(cluster, gateway_id, tenant_id,
@ -157,10 +162,13 @@ def update_gateway_device(cluster, gateway_id, tenant_id,
body = _build_gateway_device_body(tenant_id, display_name, neutron_id, body = _build_gateway_device_body(tenant_id, display_name, neutron_id,
connector_type, connector_ip, connector_type, connector_ip,
client_certificate, tz_uuid) client_certificate, tz_uuid)
return do_request( try:
HTTP_PUT, return do_request(
_build_uri_path(TRANSPORTNODE_RESOURCE, resource_id=gateway_id), HTTP_PUT,
json.dumps(body), cluster=cluster) _build_uri_path(TRANSPORTNODE_RESOURCE, resource_id=gateway_id),
json.dumps(body), cluster=cluster)
except api_exc.InvalidSecurityCertificate:
raise nsx_exc.InvalidSecurityCertificate()
def delete_gateway_device(cluster, device_uuid): def delete_gateway_device(cluster, device_uuid):

View File

@ -738,7 +738,9 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
nsx_exc.NoMorePortsException: nsx_exc.NoMorePortsException:
webob.exc.HTTPBadRequest, webob.exc.HTTPBadRequest,
nsx_exc.MaintenanceInProgress: nsx_exc.MaintenanceInProgress:
webob.exc.HTTPServiceUnavailable}) webob.exc.HTTPServiceUnavailable,
nsx_exc.InvalidSecurityCertificate:
webob.exc.HTTPBadRequest})
def _validate_provider_create(self, context, network): def _validate_provider_create(self, context, network):
if not attr.is_attr_set(network.get(mpnet.SEGMENTS)): if not attr.is_attr_set(network.get(mpnet.SEGMENTS)):
@ -2098,6 +2100,26 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def _get_nsx_device_id(self, context, device_id): def _get_nsx_device_id(self, context, device_id):
return self._get_gateway_device(context, device_id)['nsx_id'] return self._get_gateway_device(context, device_id)['nsx_id']
def _rollback_gw_device(self, context, device_id,
gw_data=None, new_status=None,
is_create=False, log_level=logging.ERROR):
LOG.log(log_level,
_("Rolling back database changes for gateway device %s "
"because of an error in the NSX backend"), device_id)
with context.session.begin(subtransactions=True):
query = self._model_query(
context, networkgw_db.NetworkGatewayDevice).filter(
networkgw_db.NetworkGatewayDevice.id == device_id)
if is_create:
query.delete(synchronize_session=False)
else:
super(NsxPluginV2, self).update_gateway_device(
context, device_id,
{networkgw.DEVICE_RESOURCE_NAME: gw_data})
if new_status:
query.update({'status': new_status},
synchronize_session=False)
# TODO(salv-orlando): Handlers for Gateway device operations should be # TODO(salv-orlando): Handlers for Gateway device operations should be
# moved into the appropriate nsx_handlers package once the code for the # moved into the appropriate nsx_handlers package once the code for the
# blueprint nsx-async-backend-communication merges # blueprint nsx-async-backend-communication merges
@ -2134,16 +2156,9 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'nsx_id': nsx_res['uuid'], 'nsx_id': nsx_res['uuid'],
'status': device_status}) 'status': device_status})
return device_status return device_status
except api_exc.NsxApiException: except (nsx_exc.InvalidSecurityCertificate, api_exc.NsxApiException):
# Remove gateway device from neutron database
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
LOG.exception(_("Unable to create gateway device: %s on NSX " self._rollback_gw_device(context, neutron_id, is_create=True)
"backend."), neutron_id)
with context.session.begin(subtransactions=True):
query = self._model_query(
context, networkgw_db.NetworkGatewayDevice).filter(
networkgw_db.NetworkGatewayDevice.id == neutron_id)
query.delete(synchronize_session=False)
def update_gateway_device_handler(self, context, gateway_device, def update_gateway_device_handler(self, context, gateway_device,
old_gateway_device_data, old_gateway_device_data,
@ -2165,7 +2180,6 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# Fetch status (it needs another NSX API call) # Fetch status (it needs another NSX API call)
device_status = nsx_utils.get_nsx_device_status(self.cluster, device_status = nsx_utils.get_nsx_device_status(self.cluster,
nsx_id) nsx_id)
# update status # update status
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
query = self._model_query( query = self._model_query(
@ -2180,31 +2194,18 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'nsx_id': nsx_id, 'nsx_id': nsx_id,
'status': device_status}) 'status': device_status})
return device_status return device_status
except api_exc.NsxApiException: except (nsx_exc.InvalidSecurityCertificate, api_exc.NsxApiException):
# Rollback gateway device on neutron database
# As the NSX failure could be transient, we don't put the
# gateway device in error status here.
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
LOG.exception(_("Unable to update gateway device: %s on NSX " self._rollback_gw_device(context, neutron_id,
"backend."), neutron_id) gw_data=old_gateway_device_data)
super(NsxPluginV2, self).update_gateway_device(
context, neutron_id, old_gateway_device_data)
except n_exc.NotFound: except n_exc.NotFound:
# The gateway device was probably deleted in the backend. # The gateway device was probably deleted in the backend.
# The DB change should be rolled back and the status must # The DB change should be rolled back and the status must
# be put in error # be put in error
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
LOG.exception(_("Unable to update gateway device: %s on NSX " self._rollback_gw_device(context, neutron_id,
"backend, as the gateway was not found on " gw_data=old_gateway_device_data,
"the NSX backend."), neutron_id) new_status=networkgw_db.ERROR)
with context.session.begin(subtransactions=True):
super(NsxPluginV2, self).update_gateway_device(
context, neutron_id, old_gateway_device_data)
query = self._model_query(
context, networkgw_db.NetworkGatewayDevice).filter(
networkgw_db.NetworkGatewayDevice.id == neutron_id)
query.update({'status': networkgw_db.ERROR},
synchronize_session=False)
def get_gateway_device(self, context, device_id, fields=None): def get_gateway_device(self, context, device_id, fields=None):
# Get device from database # Get device from database

View File

@ -28,6 +28,7 @@ from neutron.db import api as db_api
from neutron.db import db_base_plugin_v2 from neutron.db import db_base_plugin_v2
from neutron import manager from neutron import manager
from neutron.plugins.vmware.api_client import exception as api_exc from neutron.plugins.vmware.api_client import exception as api_exc
from neutron.plugins.vmware.common import exceptions as nsx_exc
from neutron.plugins.vmware.dbexts import networkgw_db from neutron.plugins.vmware.dbexts import networkgw_db
from neutron.plugins.vmware.extensions import networkgw from neutron.plugins.vmware.extensions import networkgw
from neutron.plugins.vmware import nsxlib from neutron.plugins.vmware import nsxlib
@ -861,9 +862,9 @@ class TestNetworkGateway(NsxPluginV2TestCase,
l2gwlib, 'delete_gateway_device') l2gwlib, 'delete_gateway_device')
get_gw_dev_status_patcher = mock.patch.object( get_gw_dev_status_patcher = mock.patch.object(
l2gwlib, 'get_gateway_device_status') l2gwlib, 'get_gateway_device_status')
mock_create_gw_dev = create_gw_dev_patcher.start() self.mock_create_gw_dev = create_gw_dev_patcher.start()
mock_create_gw_dev.return_value = {'uuid': 'callejon'} self.mock_create_gw_dev.return_value = {'uuid': 'callejon'}
update_gw_dev_patcher.start() self.mock_update_gw_dev = update_gw_dev_patcher.start()
delete_gw_dev_patcher.start() delete_gw_dev_patcher.start()
self.mock_get_gw_dev_status = get_gw_dev_status_patcher.start() self.mock_get_gw_dev_status = get_gw_dev_status_patcher.start()
@ -969,6 +970,18 @@ class TestNetworkGateway(NsxPluginV2TestCase,
super(TestNetworkGateway, self).test_create_gateway_device( super(TestNetworkGateway, self).test_create_gateway_device(
expected_status=networkgw_db.STATUS_DOWN) expected_status=networkgw_db.STATUS_DOWN)
def test_create_gateway_device_invalid_cert_returns_400(self):
self.mock_create_gw_dev.side_effect = (
nsx_exc.InvalidSecurityCertificate)
res = self._create_gateway_device(
'json',
_uuid(),
connector_type='stt',
connector_ip='1.1.1.1',
client_certificate='invalid_certificate',
name='whatever')
self.assertEqual(res.status_int, 400)
def test_get_gateway_device(self): def test_get_gateway_device(self):
self.mock_get_gw_dev_status.return_value = True self.mock_get_gw_dev_status.return_value = True
super(TestNetworkGateway, self).test_get_gateway_device( super(TestNetworkGateway, self).test_get_gateway_device(
@ -989,6 +1002,20 @@ class TestNetworkGateway(NsxPluginV2TestCase,
super(TestNetworkGateway, self).test_update_gateway_device( super(TestNetworkGateway, self).test_update_gateway_device(
expected_status=networkgw_db.STATUS_DOWN) expected_status=networkgw_db.STATUS_DOWN)
def test_update_gateway_device_invalid_cert_returns_400(self):
with self._gateway_device(
name='whaterver',
connector_type='stt',
connector_ip='1.1.1.1',
client_certificate='iminvalidbutiitdoesnotmatter') as dev:
self.mock_update_gw_dev.side_effect = (
nsx_exc.InvalidSecurityCertificate)
res = self._update_gateway_device(
'json',
dev[self.dev_resource]['id'],
client_certificate='invalid_certificate')
self.assertEqual(res.status_int, 400)
class TestNetworkGatewayPlugin(db_base_plugin_v2.NeutronDbPluginV2, class TestNetworkGatewayPlugin(db_base_plugin_v2.NeutronDbPluginV2,
networkgw_db.NetworkGatewayMixin): networkgw_db.NetworkGatewayMixin):