LOG.setLevel(logging.INFO)
+def _find_nvp_version_in_headers(headers):
+ # be safe if headers is None - do not cause a failure
+ for (header_name, header_value) in (headers or ()):
+ try:
+ if header_name == 'server':
+ return header_value.split('/')[1]
+ except IndexError:
+ LOG.warning(_("Unable to fetch NVP version from response "
+ "headers:%s"), headers)
+
+
class NVPApiHelper(client_eventlet.NvpApiClientEventlet):
'''
Helper class to do basic login, cookie management, and provide base
self._http_timeout = http_timeout
self._retries = retries
self._redirects = redirects
+ self._nvp_version = None
+ # NOTE(salvatore-orlando): This method is not used anymore. Login is now
+ # performed automatically inside the request eventlet if necessary.
def login(self, user=None, password=None):
'''Login to NVP controller.
'status': response.status, 'body': response.body})
return None
+ if not self._nvp_version:
+ self._nvp_version = _find_nvp_version_in_headers(response.headers)
+
return response.body
+ def get_nvp_version(self):
+ if not self._nvp_version:
+ # generate a simple request (/ws.v1/log)
+ # this will cause nvp_version to be fetched
+ # don't bother about response
+ self.request('GET', '/ws.v1/log')
+ return self._nvp_version
+
def fourZeroFour(self):
raise ResourceNotFound()
PLUGIN_VERSION)
LOG = logging.getLogger("QuantumPlugin")
+NVP_FLOATINGIP_NAT_RULES_ORDER = 200
+NVP_EXTGW_NAT_RULES_ORDER = 255
# Provider network extension - allowed network types for the NVP Plugin
cluster, router_id,
ip_addresses[0].split('/')[0],
ip_addresses[0].split('/')[0],
- source_ip_addresses=cidr)
+ order=NVP_EXTGW_NAT_RULES_ORDER,
+ match_criteria={'source_ip_addresses': cidr})
LOG.debug(_("_nvp_create_ext_gw_port completed on external network "
"%(ext_net_id)s, attached to router:%(router_id)s. "
subnet = self._get_subnet(context, subnet_id)
nvplib.create_lrouter_snat_rule(
cluster, router_id, snat_ip, snat_ip,
- source_ip_addresses=subnet['cidr'])
+ order=NVP_EXTGW_NAT_RULES_ORDER,
+ match_criteria={'source_ip_addresses': subnet['cidr']})
LOG.debug(_("Add_router_interface completed for subnet:%(subnet_id)s "
"and router:%(router_id)s"),
try:
# Create new NAT rules
nvplib.create_lrouter_dnat_rule(
- cluster, router_id, internal_ip, internal_ip,
- destination_ip_addresses=floating_ip)
+ cluster, router_id, internal_ip,
+ order=NVP_FLOATINGIP_NAT_RULES_ORDER,
+ match_criteria={'destination_ip_addresses':
+ floating_ip})
# setup snat rule such that src ip of a IP packet when
# using floating is the floating ip itself.
nvplib.create_lrouter_snat_rule(
cluster, router_id, floating_ip, floating_ip,
- source_ip_addresses=internal_ip)
+ order=NVP_FLOATINGIP_NAT_RULES_ORDER,
+ match_criteria={'source_ip_addresses': internal_ip})
# Add Floating IP address to router_port
nvplib.update_lrouter_port_ips(cluster,
router_id,
from copy import copy
import hashlib
+import inspect
import json
import logging
_lqueue_cache = {}
+def version_dependent(func):
+ func_name = func.__name__
+
+ def dispatch_version_dependent_function(cluster, *args, **kwargs):
+ nvp_ver = cluster.api_client.get_nvp_version()
+ if nvp_ver:
+ ver_major = int(nvp_ver.split('.')[0])
+ real_func = NVPLIB_FUNC_DICT[func_name][ver_major]
+ func_kwargs = kwargs
+ arg_spec = inspect.getargspec(real_func)
+ if not arg_spec.keywords and not arg_spec.varargs:
+ # drop args unknown to function from func_args
+ arg_set = set(func_kwargs.keys())
+ for arg in arg_set - set(arg_spec.args):
+ del func_kwargs[arg]
+ # NOTE(salvatore-orlando): shall we fail here if a required
+ # argument is not passed, or let the called function raise?
+ real_func(cluster, *args, **func_kwargs)
+
+ return dispatch_version_dependent_function
+
+
def _build_uri_path(resource,
resource_id=None,
parent_resource_id=None,
return rule
-def create_lrouter_snat_rule(cluster, router_id,
- min_src_ip, max_src_ip, **kwargs):
+def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
+ return {"to_source_ip_address_min": min_src_ip,
+ "to_source_ip_address_max": max_src_ip,
+ "type": "SourceNatRule",
+ "match": nat_match_obj}
+
+
+def create_lrouter_snat_rule_v2(cluster, router_id,
+ min_src_ip, max_src_ip, match_criteria=None):
- nat_match_obj = _create_nat_match_obj(**kwargs)
+ nat_match_obj = _create_nat_match_obj(**match_criteria)
+ nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
+ return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
+ to_dst_port=None, match_criteria=None):
+
+ nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
- "to_source_ip_address_min": min_src_ip,
- "to_source_ip_address_max": max_src_ip,
- "type": "SourceNatRule",
+ "to_destination_ip_address_min": dst_ip,
+ "to_destination_ip_address_max": dst_ip,
+ "type": "DestinationNatRule",
"match": nat_match_obj
}
+ if to_dst_port:
+ nat_rule_obj['to_destination_port'] = to_dst_port
+ return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
+ order=None, match_criteria=None):
+ nat_match_obj = _create_nat_match_obj(**match_criteria)
+ nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
+ if order:
+ nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-def create_lrouter_dnat_rule(cluster, router_id, to_min_dst_ip,
- to_max_dst_ip, to_dst_port=None, **kwargs):
+def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
+ order=None, match_criteria=None):
- nat_match_obj = _create_nat_match_obj(**kwargs)
+ nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
- "to_destination_ip_address_min": to_min_dst_ip,
- "to_destination_ip_address_max": to_max_dst_ip,
+ "to_destination_ip_address": dst_ip,
"type": "DestinationNatRule",
"match": nat_match_obj
}
if to_dst_port:
nat_rule_obj['to_destination_port'] = to_dst_port
+ if order:
+ nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+@version_dependent
+def create_lrouter_dnat_rule(cluster, *args, **kwargs):
+ pass
+
+
+@version_dependent
+def create_lrouter_snat_rule(cluster, *args, **kwargs):
+ pass
+
+
def delete_nat_rules_by_match(cluster, router_id, rule_type,
max_num_expected,
min_num_expected=0,
"router logical port:%s") % str(e)
LOG.exception(msg)
raise nvp_exc.NvpPluginException(err_desc=msg)
+
+
+# TODO(salvatore-orlando): Also handle changes in minor versions
+NVPLIB_FUNC_DICT = {
+ 'create_lrouter_dnat_rule': {2: create_lrouter_dnat_rule_v2,
+ 3: create_lrouter_dnat_rule_v3},
+ 'create_lrouter_snat_rule': {2: create_lrouter_snat_rule_v2,
+ 3: create_lrouter_snat_rule_v3}
+}
self.mock_nvpapi = mock.patch('%s.NvpApiClient.NVPApiHelper'
% NICIRA_PKG_PATH, autospec=True)
instance = self.mock_nvpapi.start()
- instance.return_value.login.return_value = "the_cookie"
def _fake_request(*args, **kwargs):
return self.fc.fake_request(*args, **kwargs)
+ # Emulate tests against NVP 2.x
+ instance.return_value.get_nvp_version.return_value = "2.999"
instance.return_value.request.side_effect = _fake_request
super(NiciraPluginV2TestCase, self).setUp(self._plugin_name)
--- /dev/null
+# Copyright (c) 2013 OpenStack, LLC.
+#
+# 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.
+#
+# @author: Salvatore Orlando, VMware
+
+import json
+import os
+
+import mock
+import unittest2 as unittest
+
+from quantum.openstack.common import log as logging
+from quantum.plugins.nicira.nicira_nvp_plugin import NvpApiClient
+from quantum.plugins.nicira.nicira_nvp_plugin import nvp_cluster
+from quantum.plugins.nicira.nicira_nvp_plugin import nvplib
+import quantum.plugins.nicira.nicira_nvp_plugin as nvp_plugin
+from quantum.tests.unit.nicira import fake_nvpapiclient
+from quantum.tests.unit import test_api_v2
+
+LOG = logging.getLogger(__name__)
+NICIRA_PKG_PATH = nvp_plugin.__name__
+_uuid = test_api_v2._uuid
+
+
+class TestNvplibNatRules(unittest.TestCase):
+
+ def setUp(self):
+ # mock nvp api client
+ etc_path = os.path.join(os.path.dirname(__file__), 'etc')
+ self.fc = fake_nvpapiclient.FakeClient(etc_path)
+ self.mock_nvpapi = mock.patch('%s.NvpApiClient.NVPApiHelper'
+ % NICIRA_PKG_PATH, autospec=True)
+ instance = self.mock_nvpapi.start()
+
+ def _fake_request(*args, **kwargs):
+ return self.fc.fake_request(*args, **kwargs)
+
+ instance.return_value.request.side_effect = _fake_request
+ self.fake_cluster = nvp_cluster.NVPCluster('fake-cluster')
+ self.fake_cluster.add_controller('1.1.1.1', '999', 'foo', 'bar',
+ 9, 9, 9, 9, _uuid())
+ self.fake_cluster.api_client = NvpApiClient.NVPApiHelper(
+ ('1.1.1.1', '999', True),
+ self.fake_cluster.user, self.fake_cluster.password,
+ self.fake_cluster.request_timeout, self.fake_cluster.http_timeout,
+ self.fake_cluster.retries, self.fake_cluster.redirects)
+
+ super(TestNvplibNatRules, self).setUp()
+
+ def tearDown(self):
+ self.fc.reset_all()
+ self.mock_nvpapi.stop()
+
+ def _test_create_lrouter_dnat_rule(self, func):
+ tenant_id = 'pippo'
+ lrouter = nvplib.create_lrouter(self.fake_cluster,
+ tenant_id,
+ 'fake_router',
+ '192.168.0.1')
+ nat_rule = func(self.fake_cluster, lrouter['uuid'], '10.0.0.99',
+ match_criteria={'destination_ip_addresses':
+ '192.168.0.5'})
+ uri = nvplib._build_uri_path(nvplib.LROUTERNAT_RESOURCE,
+ nat_rule['uuid'],
+ lrouter['uuid'])
+ return json.loads(nvplib.do_single_request("GET", uri,
+ cluster=self.fake_cluster))
+
+ def test_create_lrouter_dnat_rule_v2(self):
+ resp_obj = self._test_create_lrouter_dnat_rule(
+ nvplib.create_lrouter_dnat_rule_v2)
+ self.assertEquals('DestinationNatRule', resp_obj['type'])
+ self.assertEquals('192.168.0.5',
+ resp_obj['match']['destination_ip_addresses'])
+
+ def test_create_lrouter_dnat_rule_v3(self):
+ resp_obj = self._test_create_lrouter_dnat_rule(
+ nvplib.create_lrouter_dnat_rule_v2)
+ # TODO(salvatore-orlando): Extend FakeNVPApiClient to deal with
+ # different versions of NVP API
+ self.assertEquals('DestinationNatRule', resp_obj['type'])
+ self.assertEquals('192.168.0.5',
+ resp_obj['match']['destination_ip_addresses'])