Add router-size when creating an exclusive router

Enables a user to specify router-size while creating an exclusive router for
creating a load-balancer service

Change-Id: If03b51ce0bc61a8e2aa46de4f1b5869306e1bd7e
This commit is contained in:
Amey Bhide 2015-09-14 15:51:09 -07:00
parent e56011b06d
commit 9329762d3e
9 changed files with 140 additions and 13 deletions

View File

@ -20,6 +20,9 @@ XLARGE = 'xlarge'
QUADLARGE = 'quadlarge' QUADLARGE = 'quadlarge'
SHARED = "shared"
EXCLUSIVE = "exclusive"
# Edge type # Edge type
SERVICE_EDGE = 'service' SERVICE_EDGE = 'service'
VDR_EDGE = 'vdr' VDR_EDGE = 'vdr'

View File

@ -0,0 +1,56 @@
# Copyright 2015 VMware, Inc. 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 neutron.api import extensions
from neutron.api.v2 import attributes
ROUTER_SIZE = 'router_size'
EXTENDED_ATTRIBUTES_2_0 = {
'routers': {
ROUTER_SIZE: {'allow_post': True, 'allow_put': False,
'validate': {'type:values': ['compact', 'large',
'xlarge', 'quadlarge']},
'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True},
}
}
class Routersize(extensions.ExtensionDescriptor):
"""Extension class supporting router size."""
@classmethod
def get_name(cls):
return "Router Size"
@classmethod
def get_alias(cls):
return "nsxv-router-size"
@classmethod
def get_description(cls):
return "Enables configuration of NSXv Edge Size"
@classmethod
def get_updated(cls):
return "2015-9-22T10:00:00-00:00"
def get_required_extensions(self):
return ["router"]
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
return {}

View File

@ -26,7 +26,8 @@ class RouterAbstractDriver(object):
pass pass
@abc.abstractmethod @abc.abstractmethod
def create_router(self, context, lrouter): def create_router(self, context, lrouter, appliance_size=None,
allow_metadata=True):
pass pass
@abc.abstractmethod @abc.abstractmethod

View File

@ -86,7 +86,8 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
router_id, routes, newnexthop, router_id, routes, newnexthop,
gateway_vnic_index=internal_vnic_index) gateway_vnic_index=internal_vnic_index)
def create_router(self, context, lrouter, allow_metadata=True): def create_router(self, context, lrouter, appliance_size=None,
allow_metadata=True):
self.edge_manager.create_lrouter(context, lrouter, dist=True) self.edge_manager.create_lrouter(context, lrouter, dist=True)
def update_router(self, context, router_id, router): def update_router(self, context, router_id, router):

View File

@ -32,8 +32,10 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
def get_type(self): def get_type(self):
return "exclusive" return "exclusive"
def create_router(self, context, lrouter, allow_metadata=True): def create_router(self, context, lrouter, appliance_size=None,
self.edge_manager.create_lrouter(context, lrouter, dist=False) allow_metadata=True):
self.edge_manager.create_lrouter(
context, lrouter, dist=False, appliance_size=appliance_size)
if allow_metadata: if allow_metadata:
self.plugin.metadata_proxy_handler.configure_router_edge( self.plugin.metadata_proxy_handler.configure_router_edge(
lrouter['id']) lrouter['id'])

View File

@ -41,7 +41,8 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
def get_type(self): def get_type(self):
return "shared" return "shared"
def create_router(self, context, lrouter, allow_metadata=True): def create_router(self, context, lrouter,
appliance_size=None, allow_metadata=True):
pass pass
def update_router(self, context, router_id, router): def update_router(self, context, router_id, router):

View File

@ -55,6 +55,7 @@ from vmware_nsx.common import config # noqa
from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.common import locking from vmware_nsx.common import locking
from vmware_nsx.common import nsx_constants from vmware_nsx.common import nsx_constants
from vmware_nsx.common import nsxv_constants
from vmware_nsx.common import utils as c_utils from vmware_nsx.common import utils as c_utils
from vmware_nsx.db import ( from vmware_nsx.db import (
routertype as rt_rtr) routertype as rt_rtr)
@ -65,6 +66,7 @@ from vmware_nsx.extensions import (
advancedserviceproviders as as_providers) advancedserviceproviders as as_providers)
from vmware_nsx.extensions import ( from vmware_nsx.extensions import (
vnicindex as ext_vnic_idx) vnicindex as ext_vnic_idx)
from vmware_nsx.extensions import routersize
from vmware_nsx.plugins.nsx_v import managers from vmware_nsx.plugins.nsx_v import managers
from vmware_nsx.plugins.nsx_v import md_proxy as nsx_v_md_proxy from vmware_nsx.plugins.nsx_v import md_proxy as nsx_v_md_proxy
from vmware_nsx.plugins.nsx_v.vshield.common import ( from vmware_nsx.plugins.nsx_v.vshield.common import (
@ -77,6 +79,7 @@ from vmware_nsx.plugins.nsx_v.vshield import vcns_driver
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
PORTGROUP_PREFIX = 'dvportgroup' PORTGROUP_PREFIX = 'dvportgroup'
ROUTER_SIZE = routersize.ROUTER_SIZE
class NsxVPluginV2(agents_db.AgentDbMixin, class NsxVPluginV2(agents_db.AgentDbMixin,
@ -103,6 +106,7 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
"router", "router",
"security-group", "security-group",
"nsxv-router-type", "nsxv-router-type",
"nsxv-router-size",
"vnic-index", "vnic-index",
"advanced-service-providers"] "advanced-service-providers"]
@ -1347,19 +1351,43 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
raise n_exc.BadRequest(resource='router', msg=msg) raise n_exc.BadRequest(resource='router', msg=msg)
return gw_info return gw_info
def _validate_router_size(self, router):
# Check if router-size is specified. router-size can only be specified
# for a exclusive non-distributed router; else raise a BadRequest
# exception.
r = router['router']
if r.get(ROUTER_SIZE) != attr.ATTR_NOT_SPECIFIED:
if r.get('router_type') == nsxv_constants.SHARED:
msg = _("Cannot specify router-size for shared router")
raise n_exc.BadRequest(resource="router", msg=msg)
elif r.get('distributed') is True:
msg = _("Cannot specify router-size for distributed router")
raise n_exc.BadRequest(resource="router", msg=msg)
elif r.get(ROUTER_SIZE) == attr.ATTR_NOT_SPECIFIED:
if r.get('router_type') == nsxv_constants.EXCLUSIVE:
r[ROUTER_SIZE] = nsxv_constants.COMPACT
def create_router(self, context, router, allow_metadata=True): def create_router(self, context, router, allow_metadata=True):
self._validate_router_size(router)
r = router['router']
self._decide_router_type(context, r)
# First extract the gateway info in case of updating # First extract the gateway info in case of updating
# gateway before edge is deployed. # gateway before edge is deployed.
# TODO(berlin): admin_state_up and routes update # TODO(berlin): admin_state_up and routes update
r = router['router']
gw_info = self._extract_external_gw(context, router) gw_info = self._extract_external_gw(context, router)
self._decide_router_type(context, r)
lrouter = super(NsxVPluginV2, self).create_router(context, router) lrouter = super(NsxVPluginV2, self).create_router(context, router)
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
router_db = self._get_router(context, lrouter['id']) router_db = self._get_router(context, lrouter['id'])
self._process_nsx_router_create(context, router_db, r) self._process_nsx_router_create(context, router_db, r)
try: try:
router_driver = self._get_router_driver(context, router_db) router_driver = self._get_router_driver(context, router_db)
if router_driver.get_type() == nsxv_constants.EXCLUSIVE:
router_driver.create_router(
context, lrouter,
appliance_size=r.get(ROUTER_SIZE),
allow_metadata=(allow_metadata and
self.metadata_proxy_handler))
else:
router_driver.create_router( router_driver.create_router(
context, lrouter, context, lrouter,
allow_metadata=(allow_metadata and allow_metadata=(allow_metadata and
@ -1413,6 +1441,10 @@ class NsxVPluginV2(agents_db.AgentDbMixin,
router = super(NsxVPluginV2, self).get_router(context, id, fields) router = super(NsxVPluginV2, self).get_router(context, id, fields)
if router.get("distributed") and 'router_type' in router: if router.get("distributed") and 'router_type' in router:
del router['router_type'] del router['router_type']
if router.get("router_type") == nsxv_constants.EXCLUSIVE:
binding = nsxv_db.get_nsxv_router_binding(context.session,
router.get("id"))
router[ROUTER_SIZE] = binding.get("appliance_size")
return router return router
def _get_external_attachment_info(self, context, router): def _get_external_attachment_info(self, context, router):

View File

@ -641,12 +641,14 @@ class EdgeManager(object):
router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36] router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
self._free_edge_appliance(context, router_id) self._free_edge_appliance(context, router_id)
def create_lrouter(self, context, lrouter, lswitch=None, dist=False): def create_lrouter(
self, context, lrouter, lswitch=None, dist=False,
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router']):
"""Create an edge for logical router support.""" """Create an edge for logical router support."""
router_name = lrouter['name'] + '-' + lrouter['id'] router_name = lrouter['name'] + '-' + lrouter['id']
self._allocate_edge_appliance( self._allocate_edge_appliance(
context, lrouter['id'], router_name, context, lrouter['id'], router_name,
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router'], appliance_size=appliance_size,
dist=dist) dist=dist)
def delete_lrouter(self, context, router_id, dist=False): def delete_lrouter(self, context, router_id, dist=False):

View File

@ -47,6 +47,8 @@ import webob.exc
from vmware_nsx.common import nsx_constants from vmware_nsx.common import nsx_constants
from vmware_nsx.db import nsxv_db from vmware_nsx.db import nsxv_db
from vmware_nsx.extensions import (
routersize as router_size)
from vmware_nsx.extensions import ( from vmware_nsx.extensions import (
routertype as router_type) routertype as router_type)
from vmware_nsx.extensions import ( from vmware_nsx.extensions import (
@ -1159,6 +1161,8 @@ class TestL3ExtensionManager(object):
dist_router.EXTENDED_ATTRIBUTES_2_0.get(key, {})) dist_router.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
l3.RESOURCE_ATTRIBUTE_MAP[key].update( l3.RESOURCE_ATTRIBUTE_MAP[key].update(
router_type.EXTENDED_ATTRIBUTES_2_0.get(key, {})) router_type.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
l3.RESOURCE_ATTRIBUTE_MAP[key].update(
router_size.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
# Finally add l3 resources to the global attribute map # Finally add l3 resources to the global attribute map
attributes.RESOURCE_ATTRIBUTE_MAP.update( attributes.RESOURCE_ATTRIBUTE_MAP.update(
l3.RESOURCE_ATTRIBUTE_MAP) l3.RESOURCE_ATTRIBUTE_MAP)
@ -1626,6 +1630,18 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self): def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self):
self._test_router_create_with_gwinfo_and_l3_ext_net(444) self._test_router_create_with_gwinfo_and_l3_ext_net(444)
def test_router_create_with_different_sizes(self):
data = {'router': {
'tenant_id': 'whatever',
'name': 'test_router',
'router_type': 'exclusive'}}
for size in ['compact', 'large', 'xlarge', 'quadlarge']:
data['router']['router_size'] = size
router_req = self.new_create_request('routers', data, self.fmt)
res = router_req.get_response(self.ext_api)
router = self.deserialize(self.fmt, res)
self.assertEqual(size, router['router']['router_size'])
def test_router_add_gateway_invalid_network_returns_404(self): def test_router_add_gateway_invalid_network_returns_404(self):
# NOTE(salv-orlando): This unit test has been overriden # NOTE(salv-orlando): This unit test has been overriden
# as the nsx plugin support the ext_gw_mode extension # as the nsx plugin support the ext_gw_mode extension
@ -2298,6 +2314,19 @@ class TestSharedRouterTestCase(L3NatTest, L3NatTestCaseBase,
self.plugin_instance.edge_manager.get_routers_on_same_edge( self.plugin_instance.edge_manager.get_routers_on_same_edge(
context.get_admin_context(), router['router']['id'])) context.get_admin_context(), router['router']['id']))
def test_router_create_with_size_fail_at_backend(self):
data = {'router': {
'tenant_id': 'whatever',
'router_type': 'shared',
'router_size': 'large'}}
router_req = self.new_create_request('routers', data, self.fmt)
res = router_req.get_response(self.ext_api)
router = self.deserialize(self.fmt, res)
msg = ('Bad router request: '
'Cannot specify router-size for shared router')
self.assertEqual("BadRequest", router['NeutronError']['type'])
self.assertEqual(msg, router['NeutronError']['message'])
def test_router_create_with_gwinfo_with_no_edge(self): def test_router_create_with_gwinfo_with_no_edge(self):
with self._create_l3_ext_network() as net: with self._create_l3_ext_network() as net:
with self.subnet(network=net, enable_dhcp=False) as s: with self.subnet(network=net, enable_dhcp=False) as s: