From 4790feeb248f80228fb71ef51b798c80d4505173 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Sun, 5 Nov 2017 11:06:36 +0200 Subject: [PATCH] NSX|V: Use flavors for load balancer size This patch uses the load blanacer flavor name as the size of the edge to be deployed. Allowed flavors (that should be created by the admin) are 'compact', 'large', 'xlarge' and 'quadlarge' Change-Id: Ie15dcdbe2f268e456a9005b4a67752c6f9e8df47 --- .../services/lbaas/nsx_v/lbaas_common.py | 7 +- .../lbaas/nsx_v/v2/loadbalancer_mgr.py | 22 +++++- .../nsx_v/test_edge_loadbalancer_driver_v2.py | 73 ++++++++++++++++++- 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/vmware_nsx/services/lbaas/nsx_v/lbaas_common.py b/vmware_nsx/services/lbaas/nsx_v/lbaas_common.py index 1bcfb09a46..bbe6967017 100644 --- a/vmware_nsx/services/lbaas/nsx_v/lbaas_common.py +++ b/vmware_nsx/services/lbaas/nsx_v/lbaas_common.py @@ -109,15 +109,16 @@ def delete_lb_interface(context, plugin, lb_id, subnet_id): dist=False) -def get_lbaas_edge_id(context, plugin, lb_id, vip_addr, subnet_id, tenant_id): +def get_lbaas_edge_id(context, plugin, lb_id, vip_addr, subnet_id, tenant_id, + appliance_size): subnet = plugin.get_subnet(context, subnet_id) network_id = subnet.get('network_id') availability_zone = plugin.get_network_az_by_net_id(context, network_id) resource_id = get_lb_resource_id(lb_id) - edge_id = plugin.edge_manager.allocate_lb_edge_appliance( - context, resource_id, availability_zone=availability_zone) + context, resource_id, availability_zone=availability_zone, + appliance_size=appliance_size) create_lb_interface(context, plugin, lb_id, subnet_id, tenant_id, vip_addr=vip_addr, subnet=subnet) diff --git a/vmware_nsx/services/lbaas/nsx_v/v2/loadbalancer_mgr.py b/vmware_nsx/services/lbaas/nsx_v/v2/loadbalancer_mgr.py index 3deeb54b2c..424c3226ba 100644 --- a/vmware_nsx/services/lbaas/nsx_v/v2/loadbalancer_mgr.py +++ b/vmware_nsx/services/lbaas/nsx_v/v2/loadbalancer_mgr.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +from neutron.services.flavors import flavors_plugin from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources @@ -24,6 +25,8 @@ from oslo_utils import excutils from vmware_nsx._i18n import _ from vmware_nsx.db import nsxv_db +from vmware_nsx.plugins.nsx_v.vshield.common import ( + constants as vcns_const) from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as nsxv_exc from vmware_nsx.services.lbaas import base_mgr from vmware_nsx.services.lbaas.nsx_v import lbaas_common as lb_common @@ -39,11 +42,28 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager): self._handle_subnet_gw_change, resources.SUBNET, events.AFTER_UPDATE) + def _get_lb_flavor_size(self, context, flavor_id): + if not flavor_id: + return vcns_const.SERVICE_SIZE_MAPPING['lb'] + else: + flavor = flavors_plugin.FlavorsPlugin.get_flavor( + self.flavor_plugin, context, flavor_id) + flavor_size = flavor['name'] + if flavor_size.lower() in vcns_const.ALLOWED_EDGE_SIZES: + return flavor_size.lower() + else: + err_msg = (_("Invalid flavor size %(flavor)s, only %(sizes)s " + "are supported") % + {'flavor': flavor_size, + 'sizes': vcns_const.ALLOWED_EDGE_SIZES}) + raise n_exc.InvalidInput(error_message=err_msg) + @log_helpers.log_method_call def create(self, context, lb): + lb_size = self._get_lb_flavor_size(context, lb.flavor_id) edge_id = lb_common.get_lbaas_edge_id( context, self.core_plugin, lb.id, lb.vip_address, lb.vip_subnet_id, - lb.tenant_id) + lb.tenant_id, lb_size) if not edge_id: msg = _('Failed to allocate Edge on subnet %(sub)s for ' diff --git a/vmware_nsx/tests/unit/nsx_v/test_edge_loadbalancer_driver_v2.py b/vmware_nsx/tests/unit/nsx_v/test_edge_loadbalancer_driver_v2.py index e52cd2640e..81f23aa724 100644 --- a/vmware_nsx/tests/unit/nsx_v/test_edge_loadbalancer_driver_v2.py +++ b/vmware_nsx/tests/unit/nsx_v/test_edge_loadbalancer_driver_v2.py @@ -15,9 +15,11 @@ import mock +from neutron.services.flavors import flavors_plugin from neutron.tests import base from neutron_lbaas.services.loadbalancer import data_models as lb_models from neutron_lib import context +from neutron_lib import exceptions as n_exc from vmware_nsx.db import nsxv_db from vmware_nsx.plugins.nsx_v.vshield import vcns_driver @@ -102,8 +104,10 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase): self.lbv2_driver = mock.Mock() self.core_plugin = mock.Mock() + self.flavor_plugin = flavors_plugin.FlavorsPlugin() base_mgr.LoadbalancerBaseManager._lbv2_driver = self.lbv2_driver base_mgr.LoadbalancerBaseManager._core_plugin = self.core_plugin + base_mgr.LoadbalancerBaseManager._flavor_plugin = self.flavor_plugin self._patch_lb_plugin(self.lbv2_driver, self._tested_entity) self.lb = lb_models.LoadBalancer(LB_ID, LB_TENANT_ID, 'lb-name', '', @@ -189,7 +193,6 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2): mock_get_edge.return_value = LB_EDGE_ID mock_add_vip_fwr.return_value = LB_VIP_FWR_ID mock_get_lb_binding_by_edge.return_value = [] - self.edge_driver.loadbalancer.create(self.context, self.lb) mock_add_vip_fwr.assert_called_with(self.edge_driver.vcns, @@ -203,6 +206,8 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2): LB_VIP) mock_set_fw_rule.assert_called_with( self.edge_driver.vcns, LB_EDGE_ID, 'accept') + mock_get_edge.assert_called_with(mock.ANY, mock.ANY, LB_ID, LB_VIP, + mock.ANY, LB_TENANT_ID, 'compact') mock_successful_completion = ( self.lbv2_driver.load_balancer.successful_completion) mock_successful_completion.assert_called_with(self.context, @@ -210,6 +215,72 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2): mock_enable_edge_acceleration.assert_called_with( self.edge_driver.vcns, LB_EDGE_ID) + def test_create_with_flavor(self): + flavor_name = 'large' + with mock.patch.object(lb_common, 'get_lbaas_edge_id' + ) as mock_get_edge, \ + mock.patch.object(lb_common, 'add_vip_fw_rule' + ) as mock_add_vip_fwr, \ + mock.patch.object(lb_common, 'set_lb_firewall_default_rule' + ) as mock_set_fw_rule, \ + mock.patch.object(lb_common, 'enable_edge_acceleration' + ) as mock_enable_edge_acceleration, \ + mock.patch.object(nsxv_db, + 'get_nsxv_lbaas_loadbalancer_binding_by_edge' + ) as mock_get_lb_binding_by_edge, \ + mock.patch.object(nsxv_db, 'add_nsxv_lbaas_loadbalancer_binding' + ) as mock_db_binding,\ + mock.patch('neutron.services.flavors.flavors_plugin.FlavorsPlugin.' + 'get_flavor', return_value={'name': flavor_name}): + mock_get_edge.return_value = LB_EDGE_ID + mock_add_vip_fwr.return_value = LB_VIP_FWR_ID + mock_get_lb_binding_by_edge.return_value = [] + self.lb.flavor_id = 'dummy' + self.edge_driver.loadbalancer.create(self.context, self.lb) + + mock_add_vip_fwr.assert_called_with(self.edge_driver.vcns, + LB_EDGE_ID, + LB_ID, + LB_VIP) + mock_db_binding.assert_called_with(self.context.session, + LB_ID, + LB_EDGE_ID, + LB_VIP_FWR_ID, + LB_VIP) + mock_set_fw_rule.assert_called_with( + self.edge_driver.vcns, LB_EDGE_ID, 'accept') + mock_get_edge.assert_called_with( + mock.ANY, mock.ANY, LB_ID, LB_VIP, + mock.ANY, LB_TENANT_ID, flavor_name) + mock_successful_completion = ( + self.lbv2_driver.load_balancer.successful_completion) + mock_successful_completion.assert_called_with(self.context, + self.lb) + mock_enable_edge_acceleration.assert_called_with( + self.edge_driver.vcns, LB_EDGE_ID) + self.lb.flavor_id = None + + def test_create_with_illegal_flavor(self): + flavor_name = 'no_size' + with mock.patch.object(lb_common, 'get_lbaas_edge_id' + ) as mock_get_edge, \ + mock.patch.object(lb_common, 'add_vip_fw_rule' + ) as mock_add_vip_fwr, \ + mock.patch.object(nsxv_db, + 'get_nsxv_lbaas_loadbalancer_binding_by_edge' + ) as mock_get_lb_binding_by_edge, \ + mock.patch('neutron.services.flavors.flavors_plugin.FlavorsPlugin.' + 'get_flavor', return_value={'name': flavor_name}): + mock_get_edge.return_value = LB_EDGE_ID + mock_add_vip_fwr.return_value = LB_VIP_FWR_ID + mock_get_lb_binding_by_edge.return_value = [] + self.lb.flavor_id = 'dummy' + self.assertRaises( + n_exc.InvalidInput, + self.edge_driver.loadbalancer.create, + self.context, self.lb) + self.lb.flavor_id = None + def test_update(self): new_lb = lb_models.LoadBalancer(LB_ID, 'yyy-yyy', 'lb-name', 'heh-huh', 'some-subnet', 'port-id', LB_VIP)