NSX|V3: create dhcp profile at boot time

This profile will be applied to the DHCP ports if the DHCP service
is enabled.

The change remove the requirement that the admin create this out of
band.

This is now possible due to the fact that we are using a distributed
locking mechanism.

Change-Id: I12538af5849226ae3d8aeaea94bdd80be6ed0605
This commit is contained in:
Gary Kotton 2015-10-19 07:36:38 -07:00 committed by Abhishek Raut
parent 5b8e132cfb
commit dd7dd97bed
10 changed files with 111 additions and 100 deletions

View File

@ -114,7 +114,6 @@ function neutron_plugin_configure_service {
_nsxv3_ini_set insecure $NSX_INSECURE
_nsxv3_ini_set ca_file $NSX_CA_FILE
_nsxv3_ini_set default_bridge_cluster_uuid $DEFAULT_BRIDGE_CLUSTER_UUID
_nsxv3_ini_set default_switching_profile_dhcp_uuid $DEFAULT_SWITCHING_PROFILE_DHCP_UUID
}
function neutron_plugin_setup_interface_driver {

View File

@ -346,12 +346,3 @@
# L2 gateway APIs.
# This field must be specified on one of the active neutron servers only.
# default_bridge_cluster_uuid =
# UUID of the default NSX switching profile to allow DHCP traffic. This will be
# applied on the DHCP ports, if neutron's DHCP service is enabled.
# In order to create the DHCP switching profile, go the NSX manager and perform
# the following steps:
# Create a new Switching Profile of type 'Switch Security'.
# Disable DHCP Client Block and DHCP Server Block options for this profile.
# Save the profile and copy the Switching Profile's UUID below.
# default_switching_profile_dhcp_uuid =

View File

@ -204,12 +204,6 @@ nsx_v3_opts = [
'"ca_file" is set.')),
cfg.StrOpt('default_tier0_router_uuid',
help=_("Default tier0 router identifier")),
cfg.StrOpt('default_switching_profile_dhcp_uuid',
help=_("UUID of the default NSX switching profile to allow "
"DHCP traffic. This will be applied on the DHCP ports, "
"if neutron's DHCP service is enabled. This profile "
"must be created on the backend, out of band, with DHCP "
"Server/Client Block disabled.")),
]
DEFAULT_STATUS_CHECK_INTERVAL = 2000

View File

@ -170,7 +170,7 @@ class JSONRESTClient(RESTClient):
def _rest_call(self, *args, **kwargs):
if kwargs.get('body') is not None:
kwargs['body'] = jsonutils.dumps(kwargs['body'])
kwargs['body'] = jsonutils.dumps(kwargs['body'], sort_keys=True)
result = super(JSONRESTClient, self)._rest_call(*args, **kwargs)
return result.json() if result.content else result

View File

@ -122,6 +122,30 @@ class SwitchingProfile(AbstractRESTResource):
white_list_providers=whitelist_providers,
tags=tags or [])
def create_dhcp_profile(self, display_name,
description, tags=None):
dhcp_filter = {
'client_block_enabled': False,
'server_block_enabled': False
}
rate_limits = {
'rx_broadcast': 0,
'tx_broadcast': 0,
'rx_multicast': 0,
'tx_multicast': 0
}
bpdu_filter = {
'enabled': False,
'white_list': []
}
return self.create(SwitchingProfileTypes.SWITCH_SECURITY,
display_name=display_name,
description=description,
tags=tags or [],
dhcp_filter=dhcp_filter,
rate_limits=rate_limits,
bpdu_filter=bpdu_filter)
@classmethod
def build_switch_profile_ids(cls, client, *profiles):
ids = []

View File

@ -73,6 +73,7 @@ from vmware_nsx.nsxlib.v3 import security
LOG = log.getLogger(__name__)
NSX_V3_PSEC_PROFILE_NAME = 'neutron_port_spoof_guard_profile'
NSX_V3_DHCP_PROFILE_NAME = 'neutron_port_dhcp_profile'
class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
@ -133,11 +134,16 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
self._psec_profile = None
self._psec_profile = self._init_port_security_profile()
if not self._psec_profile:
msg = (_("Unable to initialize NSX v3 port spoofguard "
"switching profile: %s") % NSX_V3_PSEC_PROFILE_NAME)
msg = _("Unable to initialize NSX v3 port spoofguard "
"switching profile: %s") % NSX_V3_PSEC_PROFILE_NAME
raise nsx_exc.NsxPluginException(msg)
LOG.debug("Initializing NSX v3 DHCP switching profile")
self._dhcp_profile = None
self._dhcp_profile = self._init_dhcp_switching_profile()
if not self._dhcp_profile:
msg = _("Unable to initialize NSX v3 DHCP "
"switching profile: %s") % NSX_V3_DHCP_PROFILE_NAME
raise nsx_exc.NsxPluginException(msg)
self._unsubscribe_callback_events()
def _unsubscribe_callback_events(self):
@ -165,22 +171,27 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin,
"must be disabled") % dhcp_profile_uuid
raise n_exc.InvalidInput(error_message=msg)
@utils.retry_upon_exception_nsxv3(Exception)
def _init_dhcp_switching_profile(self):
dhcp_profile_uuid = cfg.CONF.nsx_v3.default_switching_profile_dhcp_uuid
if not dhcp_profile_uuid:
LOG.warning(_LW("Switching profile for DHCP ports not configured "
"in the config file."))
return
if not uuidutils.is_uuid_like(dhcp_profile_uuid):
LOG.warning(_LW("default_switching_profile_dhcp_uuid: %s. DHCP "
"profile must be configured with a UUID"),
dhcp_profile_uuid)
return
self._validate_dhcp_profile(dhcp_profile_uuid)
with locking.LockManager.get_lock('nsxv3_dhcp_profile_init'):
profile = self._get_dhcp_security_profile()
if not profile:
self._switching_profiles.create_dhcp_profile(
NSX_V3_DHCP_PROFILE_NAME, 'Neutron DHCP Security Profile',
tags=utils.build_v3_tags_payload({
'id': NSX_V3_DHCP_PROFILE_NAME,
'tenant_id': 'neutron-nsx-plugin'}))
return self._get_dhcp_security_profile()
def _get_dhcp_security_profile(self):
if self._dhcp_profile:
return self._dhcp_profile
profile = self._switching_profiles.find_by_display_name(
NSX_V3_DHCP_PROFILE_NAME)
return nsx_resources.SwitchingProfileTypeId(
profile_type=(nsx_resources.SwitchingProfileTypes.
SWITCH_SECURITY),
profile_id=dhcp_profile_uuid)
profile_id=profile[0]['id']) if profile else None
def _get_port_security_profile_id(self):
return nsx_resources.SwitchingProfile.build_switch_profile_ids(

View File

@ -12,7 +12,6 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
import six
from neutron.api.v2 import attributes
@ -41,7 +40,6 @@ from oslo_utils import uuidutils
from vmware_nsx.common import utils
from vmware_nsx.nsxlib.v3 import client as nsx_client
from vmware_nsx.nsxlib.v3 import resources as nsx_resources
from vmware_nsx.plugins.nsx_v3 import plugin as nsx_plugin
from vmware_nsx.tests import unit as vmware
from vmware_nsx.tests.unit.nsx_v3 import mocks as nsx_v3_mocks
@ -80,11 +78,6 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase,
if getattr(self.plugin, '_port_client', None):
self.plugin._port_client._client._session = self.mock_api
mocked_locking = mock.patch.object(
nsx_plugin, 'locking', new=mock.Mock())
mocked_locking.start()
self._patchers.append(mocked_locking)
self.maxDiff = None
def tearDown(self):
@ -354,54 +347,3 @@ class TestNsxV3Utils(NsxV3PluginTestCaseMixin):
{'scope': 'os-api-version',
'tag': version.version_info.release_string()}]
self.assertEqual(expected, result)
class TestNsxV3DHCPSwitchingProfile(TestPortsV2):
def setUp(self, plugin=PLUGIN_NAME,
ext_mgr=None,
service_plugins=None):
super(TestNsxV3DHCPSwitchingProfile, self).setUp(plugin=plugin,
ext_mgr=ext_mgr)
dhcp_profile_uuid = uuidutils.generate_uuid()
cfg.CONF.set_override('default_switching_profile_dhcp_uuid',
dhcp_profile_uuid, 'nsx_v3')
self.plugin._dhcp_profile = nsx_resources.SwitchingProfileTypeId(
profile_type=(nsx_resources.SwitchingProfileTypes.
SWITCH_SECURITY),
profile_id=dhcp_profile_uuid)
def test_create_port_dhcp_profile(self):
with mock.patch.object(self.plugin._port_client,
'create') as port_create:
with self.network() as network:
with self.subnet(network=network):
data = {'port': {'network_id': network['network']['id'],
'tenant_id':
network['network']['tenant_id'],
'name': 'port1',
'admin_state_up': True,
'device_owner':
constants.DEVICE_OWNER_DHCP}}
port_req = self.new_create_request('ports', data)
port_req.get_response(self.api)
args, kwargs = port_create.call_args
self.assertEqual(kwargs['switch_profile_ids'],
[self.plugin._dhcp_profile])
def test_create_non_dhcp_port_with_dhcp_profile(self):
with mock.patch.object(self.plugin._port_client,
'create') as port_create:
with self.network() as network:
with self.subnet(network=network):
data = {'port': {'network_id': network['network']['id'],
'tenant_id':
network['network']['tenant_id'],
'name': 'port1',
'admin_state_up': True,
'device_owner': 'not-dhcp'}}
port_req = self.new_create_request('ports', data)
port_req.get_response(self.api)
args, kwargs = port_create.call_args
self.assertNotEqual(kwargs['switch_profile_ids'],
[self.plugin._dhcp_profile])

View File

@ -58,7 +58,8 @@ class NsxLibQosTestCase(nsxlib_testcase.NsxClientTestCase):
mocked.get('post'),
'https://1.2.3.4/api/v1/switching-profiles',
False,
jsonutils.dumps(self._body(qos_marking='UNTRUSTED', dscp=25)),
jsonutils.dumps(self._body(qos_marking='UNTRUSTED', dscp=25),
sort_keys=True),
_JSON_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -77,7 +78,8 @@ class NsxLibQosTestCase(nsxlib_testcase.NsxClientTestCase):
mocked.get('post'),
'https://1.2.3.4/api/v1/switching-profiles',
False,
jsonutils.dumps(self._body(qos_marking='trusted', dscp=0)),
jsonutils.dumps(self._body(qos_marking='trusted', dscp=0),
sort_keys=True),
_JSON_HEADERS,
nsxlib_testcase.NSX_CERT)

View File

@ -44,7 +44,7 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase):
'resource_type': profile_types.PORT_MIRRORING,
'display_name': 'pm-profile',
'description': 'port mirror prof'
}),
}, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -71,7 +71,7 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase):
False, jsonutils.dumps({
'resource_type': profile_types.PORT_MIRRORING,
'tags': tags
}),
}, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -104,7 +104,53 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase):
'description': 'spoofguard-for-neutron',
'white_list_providers': ['LPORT_BINDINGS'],
'tags': tags
}),
}, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
def test_create_dhcp_profile(self):
tags = [
{
'scope': 'os-tid',
'tag': 'tenant-1'
},
{
'scope': 'os-api-version',
'tag': '2.1.1.0'
}
]
api = resources.SwitchingProfile(client.NSX3Client())
with self.mocked_resource(api) as mocked:
api.create_dhcp_profile(
'neutron-dhcp', 'dhcp-for-neutron',
tags=tags)
test_client.assert_session_call(
mocked.get('post'),
'https://1.2.3.4/api/v1/switching-profiles',
False,
jsonutils.dumps({
'bpdu_filter': {
'enabled': False,
'white_list': []
},
'resource_type': profile_types.SWITCH_SECURITY,
'display_name': 'neutron-dhcp',
'description': 'dhcp-for-neutron',
'tags': tags,
'dhcp_filter': {
'client_block_enabled': False,
'server_block_enabled': False
},
'rate_limits': {
'rx_broadcast': 0,
'tx_broadcast': 0,
'rx_multicast': 0,
'tx_multicast': 0
}
}, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -200,7 +246,7 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase):
mocked.get('post'),
'https://1.2.3.4/api/v1/logical-ports',
False,
jsonutils.dumps(resp_body),
jsonutils.dumps(resp_body, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -271,7 +317,7 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase):
mocked.get('post'),
'https://1.2.3.4/api/v1/logical-routers',
False,
jsonutils.dumps(data),
jsonutils.dumps(data, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -325,7 +371,7 @@ class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase):
mocked.get('post'),
'https://1.2.3.4/api/v1/logical-router-ports',
False,
jsonutils.dumps(data),
jsonutils.dumps(data, sort_keys=True),
client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)

View File

@ -53,7 +53,7 @@ class NsxLibSwitchTestCase(nsxlib_testcase.NsxClientTestCase):
test_client.assert_session_call(
mocked.get('post'),
'https://1.2.3.4/api/v1/logical-switches',
False, jsonutils.dumps(self._create_body()),
False, jsonutils.dumps(self._create_body(), sort_keys=True),
nsxlib.client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -71,7 +71,8 @@ class NsxLibSwitchTestCase(nsxlib_testcase.NsxClientTestCase):
'https://1.2.3.4/api/v1/logical-switches',
False,
jsonutils.dumps(self._create_body(
admin_state=nsx_constants.ADMIN_STATE_DOWN)),
admin_state=nsx_constants.ADMIN_STATE_DOWN),
sort_keys=True),
nsxlib.client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)
@ -87,7 +88,8 @@ class NsxLibSwitchTestCase(nsxlib_testcase.NsxClientTestCase):
test_client.assert_session_call(
mocked.get('post'),
'https://1.2.3.4/api/v1/logical-switches',
False, jsonutils.dumps(self._create_body(vlan_id='123')),
False, jsonutils.dumps(self._create_body(vlan_id='123'),
sort_keys=True),
nsxlib.client.JSONRESTClient._DEFAULT_HEADERS,
nsxlib_testcase.NSX_CERT)