diff --git a/doc/source/topics/settings.rst b/doc/source/topics/settings.rst
index f2dfa04e5d..9e3c4d6b2e 100644
--- a/doc/source/topics/settings.rst
+++ b/doc/source/topics/settings.rst
@@ -474,6 +474,7 @@ Default::
{
'enable_router': True,
'enable_distributed_router': False,
+ 'enable_ha_router': False,
'enable_lb': True,
'enable_quotas': False,
'enable_firewall': True,
@@ -512,6 +513,19 @@ when your Neutron plugin (like ML2 plugin) supports DVR feature, DVR
feature depends on l3-agent configuration, so deployers should set this
option appropriately depending on your deployment.
+``enable_ha_router``:
+
+.. versionadded:: 2014.2(Juno)
+
+Default: ``False``
+
+Enable or disable HA (High Availability) mode in Neutron virtual router
+in the Router panel. For the HA router mode to be enabled, this option needs
+to be set to True and your Neutron deployment must support HA router mode.
+Even when your Neutron plugin (like ML2 plugin) supports HA router mode,
+the feature depends on l3-agent configuration, so deployers should set this
+option appropriately depending on your deployment.
+
``enable_lb``:
.. versionadded:: 2013.1(Grizzly)
diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py
index b0ad7d7dcb..1295f76e33 100644
--- a/openstack_dashboard/api/neutron.py
+++ b/openstack_dashboard/api/neutron.py
@@ -943,31 +943,90 @@ def is_port_profiles_supported():
return True
-def get_dvr_permission(request, operation):
- """Check if "distributed" field can be displayed.
+# FEATURE_MAP is used to define:
+# - related neutron extension name (key: "extension")
+# - corresponding dashboard config (key: "config")
+# - RBAC policies (key: "poclies")
+# If a key is not contained, the corresponding permission check is skipped.
+FEATURE_MAP = {
+ 'dvr': {
+ 'extension': 'dvr',
+ 'config': {
+ 'name': 'enable_distributed_router',
+ 'default': False,
+ },
+ 'policies': {
+ 'get': 'get_router:distributed',
+ 'create': 'create_router:distributed',
+ 'update': 'update_router:distributed',
+ }
+ },
+ 'l3-ha': {
+ 'extension': 'l3-ha',
+ 'config': {'name': 'enable_ha_router',
+ 'default': False},
+ 'policies': {
+ 'get': 'get_router:ha',
+ 'create': 'create_router:ha',
+ 'update': 'update_router:ha',
+ }
+ },
+}
+
+
+def get_feature_permission(request, feature, operation=None):
+ """Check if a feature-specific field can be displayed.
+
+ This method check a permission for a feature-specific field.
+ Such field is usually provided through Neutron extension.
:param request: Request Object
- :param operation: Operation type. The valid value is "get" or "create"
+ :param feature: feature name defined in FEATURE_MAP
+ :param operation (optional): Operation type. The valid value should be
+ defined in FEATURE_MAP[feature]['policies']
+ It must be specified if FEATURE_MAP[feature] has 'policies'.
"""
network_config = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {})
- if not network_config.get('enable_distributed_router', False):
- return False
+ feature_info = FEATURE_MAP.get(feature)
+ if not feature_info:
+ # Translators: Only used inside Horizon code and invisible to users
+ raise ValueError(_("The requested feature '%(feature)s' is unknown. "
+ "Please make sure to specify a feature defined "
+ "in FEATURE_MAP."))
+
+ # Check dashboard settings
+ feature_config = feature_info.get('config')
+ if feature_config:
+ if not network_config.get(feature_config['name'],
+ feature_config['default']):
+ return False
+
+ # Check policy
+ feature_policies = feature_info.get('policies')
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
- allowed_operations = ("get", "create", "update")
- if operation not in allowed_operations:
- raise ValueError(_("The 'operation' parameter for get_dvr_permission "
- "is invalid. It should be one of %s")
- % ' '.join(allowed_operations))
- role = (("network", "%s_router:distributed" % operation),)
- if policy_check:
- has_permission = policy.check(role, request)
- else:
- has_permission = True
- if not has_permission:
- return False
- try:
- return is_extension_supported(request, 'dvr')
- except Exception:
- msg = _('Failed to check Neutron "dvr" extension is not supported')
- LOG.info(msg)
- return False
+ if feature_policies and policy_check:
+ policy_name = feature_policies.get(operation)
+ if not policy_name:
+ # Translators: Only used inside Horizon code and invisible to users
+ raise ValueError(_("The 'operation' parameter for "
+ "get_feature_permission '%(feature)s' "
+ "is invalid. It should be one of %(allowed)s")
+ % {'feature': feature,
+ 'allowed': ' '.join(feature_policies.keys())})
+ role = (('network', policy_name),)
+ if not policy.check(role, request):
+ return False
+
+ # Check if a required extension is enabled
+ feature_extension = feature_info.get('extension')
+ if feature_extension:
+ try:
+ return is_extension_supported(request, feature_extension)
+ except Exception:
+ msg = (_("Failed to check Neutron '%s' extension is not supported")
+ % feature_extension)
+ LOG.info(msg)
+ return False
+
+ # If all checks are passed, now a given feature is allowed.
+ return True
diff --git a/openstack_dashboard/conf/neutron_policy.json b/openstack_dashboard/conf/neutron_policy.json
index 2ead473f2e..79f0b6b33f 100644
--- a/openstack_dashboard/conf/neutron_policy.json
+++ b/openstack_dashboard/conf/neutron_policy.json
@@ -148,6 +148,9 @@
"get_router:distributed": "rule:admin_only",
"create_router:distributed": "rule:admin_only",
"update_router:distributed": "rule:admin_only",
+ "get_router:ha": "rule:admin_only",
+ "create_router:ha": "rule:admin_only",
+ "update_router:ha": "rule:admin_only",
"create_floatingip": "rule:regular_user",
"update_floatingip": "rule:admin_or_owner",
diff --git a/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html b/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html
index 6bf3ecd68c..60fc8440d0 100644
--- a/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html
+++ b/openstack_dashboard/dashboards/admin/routers/templates/routers/_detail_overview.html
@@ -18,6 +18,10 @@
{% trans "Distributed" %}
{{ router.distributed|yesno|capfirst }}
{% endif %}
+ {% if ha_supported %}
+ {% trans "High Availability Mode" %}
+ {{ router.ha|yesno|capfirst }}
+ {% endif %}
{% if router.external_gateway_info %}
{% trans "External Gateway Information" %}
{% trans "Connected External Network" %}:
diff --git a/openstack_dashboard/dashboards/project/routers/forms.py b/openstack_dashboard/dashboards/project/routers/forms.py
index adb260ca50..f4e77f2d9c 100644
--- a/openstack_dashboard/dashboards/project/routers/forms.py
+++ b/openstack_dashboard/dashboards/project/routers/forms.py
@@ -34,26 +34,38 @@ LOG = logging.getLogger(__name__)
class CreateForm(forms.SelfHandlingForm):
name = forms.CharField(max_length=255, label=_("Router Name"))
mode = forms.ChoiceField(label=_("Router Type"))
+ ha = forms.ChoiceField(label=_("High Availability Mode"))
failure_url = 'horizon:project:routers:index'
def __init__(self, request, *args, **kwargs):
super(CreateForm, self).__init__(request, *args, **kwargs)
- self.dvr_enabled = api.neutron.get_dvr_permission(self.request,
- "create")
- if self.dvr_enabled:
+ self.dvr_allowed = api.neutron.get_feature_permission(self.request,
+ "dvr", "create")
+ if self.dvr_allowed:
mode_choices = [('server_default', _('Use Server Default')),
('centralized', _('Centralized')),
('distributed', _('Distributed'))]
self.fields['mode'].choices = mode_choices
else:
- self.fields['mode'].widget = forms.HiddenInput()
- self.fields['mode'].required = False
+ del self.fields['mode']
+
+ self.ha_allowed = api.neutron.get_feature_permission(self.request,
+ "l3-ha", "create")
+ if self.ha_allowed:
+ ha_choices = [('server_default', _('Use Server Default')),
+ ('enabled', _('Enable HA mode')),
+ ('disabled', _('Disable HA mode'))]
+ self.fields['ha'].choices = ha_choices
+ else:
+ del self.fields['ha']
def handle(self, request, data):
try:
params = {'name': data['name']}
- if (self.dvr_enabled and data['mode'] != 'server_default'):
+ if (self.dvr_allowed and data['mode'] != 'server_default'):
params['distributed'] = (data['mode'] == 'distributed')
+ if (self.ha_allowed and data['ha'] != 'server_default'):
+ params['ha'] = (data['ha'] == 'enabled')
router = api.neutron.router_create(request, **params)
message = _('Router %s was successfully created.') % data['name']
messages.success(request, message)
@@ -77,13 +89,14 @@ class UpdateForm(forms.SelfHandlingForm):
router_id = forms.CharField(label=_("ID"),
widget=forms.HiddenInput())
mode = forms.ChoiceField(label=_("Router Type"))
+ ha = forms.BooleanField(label=_("High Availability Mode"), required=False)
redirect_url = reverse_lazy('horizon:project:routers:index')
def __init__(self, request, *args, **kwargs):
super(UpdateForm, self).__init__(request, *args, **kwargs)
- self.dvr_allowed = api.neutron.get_dvr_permission(self.request,
- "update")
+ self.dvr_allowed = api.neutron.get_feature_permission(self.request,
+ "dvr", "update")
if not self.dvr_allowed:
del self.fields['mode']
elif kwargs.get('initial', {}).get('mode') == 'distributed':
@@ -98,12 +111,19 @@ class UpdateForm(forms.SelfHandlingForm):
('distributed', _('Distributed'))]
self.fields['mode'].choices = mode_choices
+ self.ha_allowed = api.neutron.get_feature_permission(self.request,
+ "l3-ha", "update")
+ if not self.ha_allowed:
+ del self.fields['ha']
+
def handle(self, request, data):
try:
params = {'admin_state_up': (data['admin_state'] == 'True'),
'name': data['name']}
if self.dvr_allowed:
params['distributed'] = (data['mode'] == 'distributed')
+ if self.ha_allowed:
+ params['ha'] = data['ha']
router = api.neutron.router_update(request, data['router_id'],
**params)
msg = _('Router %s was successfully updated.') % data['name']
diff --git a/openstack_dashboard/dashboards/project/routers/tables.py b/openstack_dashboard/dashboards/project/routers/tables.py
index 7924f06001..3a169f7755 100644
--- a/openstack_dashboard/dashboards/project/routers/tables.py
+++ b/openstack_dashboard/dashboards/project/routers/tables.py
@@ -159,6 +159,10 @@ class RoutersTable(tables.DataTable):
distributed = tables.Column("distributed",
filters=(filters.yesno, filters.capfirst),
verbose_name=_("Distributed"))
+ ha = tables.Column("ha",
+ filters=(filters.yesno, filters.capfirst),
+ # Translators: High Availability mode of Neutron router
+ verbose_name=_("HA mode"))
ext_net = tables.Column(get_external_network,
verbose_name=_("External Network"))
@@ -168,8 +172,10 @@ class RoutersTable(tables.DataTable):
data=data,
needs_form_wrapper=needs_form_wrapper,
**kwargs)
- if not api.neutron.get_dvr_permission(request, "get"):
+ if not api.neutron.get_feature_permission(request, "dvr", "get"):
del self.columns["distributed"]
+ if not api.neutron.get_feature_permission(request, "l3-ha", "get"):
+ del self.columns["ha"]
def get_object_display(self, obj):
return obj.name
diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html b/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html
index 4816322cfc..9c1721dc5b 100644
--- a/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html
+++ b/openstack_dashboard/dashboards/project/routers/templates/routers/_detail_overview.html
@@ -16,6 +16,10 @@
{% trans "Distributed" %}
{{ router.distributed|yesno|capfirst }}
{% endif %}
+ {% if ha_supported %}
+ {% trans "High Availability Mode" %}
+ {{ router.ha|yesno|capfirst }}
+ {% endif %}
{% if router.external_gateway_info %}
{% trans "External Gateway Information" %}
{% trans "Connected External Network" %}:
diff --git a/openstack_dashboard/dashboards/project/routers/tests.py b/openstack_dashboard/dashboards/project/routers/tests.py
index 5706de0a3a..3d4c30ed9e 100644
--- a/openstack_dashboard/dashboards/project/routers/tests.py
+++ b/openstack_dashboard/dashboards/project/routers/tests.py
@@ -133,10 +133,14 @@ class RouterActionTests(test.TestCase):
DETAIL_PATH = 'horizon:%s:routers:detail' % DASHBOARD
@test.create_stubs({api.neutron: ('router_create',
- 'get_dvr_permission',)})
+ 'get_feature_permission',)})
def test_router_create_post(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "create")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "create")\
+ .AndReturn(False)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "create")\
.AndReturn(False)
api.neutron.router_create(IsA(http.HttpRequest), name=router.name)\
.AndReturn(router)
@@ -150,17 +154,22 @@ class RouterActionTests(test.TestCase):
self.assertRedirectsNoFollow(res, self.INDEX_URL)
@test.create_stubs({api.neutron: ('router_create',
- 'get_dvr_permission',)})
+ 'get_feature_permission',)})
def test_router_create_post_mode_server_default(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "create")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "create")\
+ .AndReturn(True)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "create")\
.AndReturn(True)
api.neutron.router_create(IsA(http.HttpRequest), name=router.name)\
.AndReturn(router)
self.mox.ReplayAll()
form_data = {'name': router.name,
- 'mode': 'server_default'}
+ 'mode': 'server_default',
+ 'ha': 'server_default'}
url = reverse('horizon:%s:routers:create' % self.DASHBOARD)
res = self.client.post(url, form_data)
@@ -168,19 +177,25 @@ class RouterActionTests(test.TestCase):
self.assertRedirectsNoFollow(res, self.INDEX_URL)
@test.create_stubs({api.neutron: ('router_create',
- 'get_dvr_permission',)})
- def test_dvr_router_create_post(self):
+ 'get_feature_permission',)})
+ def test_dvr_ha_router_create_post(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "create")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "create")\
+ .MultipleTimes().AndReturn(True)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "create")\
.MultipleTimes().AndReturn(True)
param = {'name': router.name,
- 'distributed': True}
+ 'distributed': True,
+ 'ha': True}
api.neutron.router_create(IsA(http.HttpRequest), **param)\
.AndReturn(router)
self.mox.ReplayAll()
form_data = {'name': router.name,
- 'mode': 'distributed'}
+ 'mode': 'distributed',
+ 'ha': 'enabled'}
url = reverse('horizon:%s:routers:create' % self.DASHBOARD)
res = self.client.post(url, form_data)
@@ -188,11 +203,15 @@ class RouterActionTests(test.TestCase):
self.assertRedirectsNoFollow(res, self.INDEX_URL)
@test.create_stubs({api.neutron: ('router_create',
- 'get_dvr_permission',)})
+ 'get_feature_permission',)})
def test_router_create_post_exception_error_case_409(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "create")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "create")\
.MultipleTimes().AndReturn(False)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "create")\
+ .AndReturn(False)
self.exceptions.neutron.status_code = 409
api.neutron.router_create(IsA(http.HttpRequest), name=router.name)\
.AndRaise(self.exceptions.neutron)
@@ -206,10 +225,14 @@ class RouterActionTests(test.TestCase):
self.assertRedirectsNoFollow(res, self.INDEX_URL)
@test.create_stubs({api.neutron: ('router_create',
- 'get_dvr_permission',)})
+ 'get_feature_permission',)})
def test_router_create_post_exception_error_case_non_409(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "create")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "create")\
+ .MultipleTimes().AndReturn(False)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "create")\
.MultipleTimes().AndReturn(False)
self.exceptions.neutron.status_code = 999
api.neutron.router_create(IsA(http.HttpRequest), name=router.name)\
@@ -224,15 +247,20 @@ class RouterActionTests(test.TestCase):
self.assertRedirectsNoFollow(res, self.INDEX_URL)
@test.create_stubs({api.neutron: ('router_get',
- 'get_dvr_permission')})
+ 'get_feature_permission')})
def _test_router_update_get(self, dvr_enabled=False,
- current_dvr=False):
+ current_dvr=False,
+ ha_enabled=False):
router = [r for r in self.routers.list()
if r.distributed == current_dvr][0]
api.neutron.router_get(IsA(http.HttpRequest), router.id)\
.AndReturn(router)
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "update")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "update")\
.AndReturn(dvr_enabled)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "update")\
+ .AndReturn(ha_enabled)
self.mox.ReplayAll()
url = reverse('horizon:%s:routers:update' % self.DASHBOARD,
@@ -276,10 +304,14 @@ class RouterActionTests(test.TestCase):
@test.create_stubs({api.neutron: ('router_get',
'router_update',
- 'get_dvr_permission')})
- def test_router_update_post_dvr_disabled(self):
+ 'get_feature_permission')})
+ def test_router_update_post_dvr_ha_disabled(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "update")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "update")\
+ .AndReturn(False)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "update")\
.AndReturn(False)
api.neutron.router_update(IsA(http.HttpRequest), router.id,
name=router.name,
@@ -300,15 +332,20 @@ class RouterActionTests(test.TestCase):
@test.create_stubs({api.neutron: ('router_get',
'router_update',
- 'get_dvr_permission')})
- def test_router_update_post_dvr_enabled(self):
+ 'get_feature_permission')})
+ def test_router_update_post_dvr_ha_enabled(self):
router = self.routers.first()
- api.neutron.get_dvr_permission(IsA(http.HttpRequest), "update")\
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "dvr", "update")\
+ .AndReturn(True)
+ api.neutron.get_feature_permission(IsA(http.HttpRequest),
+ "l3-ha", "update")\
.AndReturn(True)
api.neutron.router_update(IsA(http.HttpRequest), router.id,
name=router.name,
admin_state_up=router.admin_state_up,
- distributed=True)\
+ distributed=True,
+ ha=True)\
.AndReturn(router)
api.neutron.router_get(IsA(http.HttpRequest), router.id)\
.AndReturn(router)
@@ -317,7 +354,8 @@ class RouterActionTests(test.TestCase):
form_data = {'router_id': router.id,
'name': router.name,
'admin_state': router.admin_state_up,
- 'mode': 'distributed'}
+ 'mode': 'distributed',
+ 'ha': True}
url = reverse('horizon:%s:routers:update' % self.DASHBOARD,
args=[router.id])
res = self.client.post(url, form_data)
diff --git a/openstack_dashboard/dashboards/project/routers/views.py b/openstack_dashboard/dashboards/project/routers/views.py
index bc82fe1018..62ed37a566 100644
--- a/openstack_dashboard/dashboards/project/routers/views.py
+++ b/openstack_dashboard/dashboards/project/routers/views.py
@@ -126,8 +126,10 @@ class DetailView(tabs.TabbedTableView):
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context["router"] = self._get_data()
- context['dvr_supported'] = api.neutron.get_dvr_permission(self.request,
- "get")
+ context['dvr_supported'] = api.neutron.get_feature_permission(
+ self.request, "dvr", "get")
+ context['ha_supported'] = api.neutron.get_feature_permission(
+ self.request, "l3-ha", "get")
return context
def get(self, request, *args, **kwargs):
@@ -170,4 +172,6 @@ class UpdateView(forms.ModalFormView):
if hasattr(router, 'distributed'):
initial['mode'] = ('distributed' if router.distributed
else 'centralized')
+ if hasattr(router, 'ha'):
+ initial['ha'] = router.ha
return initial
diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example
index 58597a5861..08766cfb7a 100644
--- a/openstack_dashboard/local/local_settings.py.example
+++ b/openstack_dashboard/local/local_settings.py.example
@@ -182,7 +182,8 @@ OPENSTACK_NEUTRON_NETWORK = {
'enable_router': True,
'enable_quotas': True,
'enable_ipv6': True,
- 'enable_distributed_router': True,
+ 'enable_distributed_router': False,
+ 'enable_ha_router': False,
'enable_lb': True,
'enable_firewall': True,
'enable_vpn': True,
diff --git a/openstack_dashboard/test/api_tests/neutron_tests.py b/openstack_dashboard/test/api_tests/neutron_tests.py
index ff88dcf491..015518a011 100644
--- a/openstack_dashboard/test/api_tests/neutron_tests.py
+++ b/openstack_dashboard/test/api_tests/neutron_tests.py
@@ -283,6 +283,11 @@ class NeutronApiTests(test.APITestCase):
self.assertFalse(
api.neutron.is_extension_supported(self.request, 'doesntexist'))
+ # NOTE(amotoki): "dvr" permission tests check most of
+ # get_feature_permission features.
+ # These tests are not specific to "dvr" extension.
+ # Please be careful if you drop "dvr" extension in future.
+
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_distributed_router':
True},
POLICY_CHECK_FUNCTION=None)
@@ -295,10 +300,11 @@ class NeutronApiTests(test.APITestCase):
.AndReturn({'extensions': extensions})
self.mox.ReplayAll()
self.assertEqual(dvr_enabled,
- api.neutron.get_dvr_permission(self.request, 'get'))
+ api.neutron.get_feature_permission(self.request,
+ 'dvr', 'get'))
def test_get_dvr_permission_dvr_supported(self):
- self._test_get_dvr_permission_dvr_supported(dvr_enabled=True, )
+ self._test_get_dvr_permission_dvr_supported(dvr_enabled=True)
def test_get_dvr_permission_dvr_not_supported(self):
self._test_get_dvr_permission_dvr_supported(dvr_enabled=False)
@@ -320,8 +326,8 @@ class NeutronApiTests(test.APITestCase):
.AndReturn({'extensions': self.api_extensions.list()})
self.mox.ReplayAll()
self.assertEqual(policy_check_allowed,
- api.neutron.get_dvr_permission(self.request,
- operation))
+ api.neutron.get_feature_permission(self.request,
+ 'dvr', operation))
def test_get_dvr_permission_with_policy_check_allowed(self):
self._test_get_dvr_permission_with_policy_check(True, "get")
@@ -338,11 +344,49 @@ class NeutronApiTests(test.APITestCase):
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_distributed_router':
False})
def test_get_dvr_permission_dvr_disabled_by_config(self):
- self.assertFalse(api.neutron.get_dvr_permission(self.request, 'get'))
+ self.assertFalse(api.neutron.get_feature_permission(self.request,
+ 'dvr', 'get'))
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_distributed_router':
- True})
+ True},
+ POLICY_CHECK_FUNCTION=policy.check)
def test_get_dvr_permission_dvr_unsupported_operation(self):
self.assertRaises(ValueError,
- api.neutron.get_dvr_permission,
- self.request, 'unSupported')
+ api.neutron.get_feature_permission,
+ self.request, 'dvr', 'unSupported')
+
+ @override_settings(OPENSTACK_NEUTRON_NETWORK={})
+ def test_get_dvr_permission_dvr_default_config(self):
+ self.assertFalse(api.neutron.get_feature_permission(self.request,
+ 'dvr', 'get'))
+
+ @override_settings(OPENSTACK_NEUTRON_NETWORK={})
+ def test_get_dvr_permission_router_ha_default_config(self):
+ self.assertFalse(api.neutron.get_feature_permission(self.request,
+ 'l3-ha', 'get'))
+
+ # NOTE(amotoki): Most of get_feature_permission are checked by "dvr" check
+ # above. l3-ha check only checks l3-ha specific code.
+
+ @override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_ha_router': True},
+ POLICY_CHECK_FUNCTION=policy.check)
+ def _test_get_router_ha_permission_with_policy_check(self, ha_enabled):
+ self.mox.StubOutWithMock(policy, 'check')
+ role = (("network", "create_router:ha"),)
+ policy.check(role, self.request).AndReturn(True)
+ neutronclient = self.stub_neutronclient()
+ if ha_enabled:
+ extensions = self.api_extensions.list()
+ else:
+ extensions = {}
+ neutronclient.list_extensions().AndReturn({'extensions': extensions})
+ self.mox.ReplayAll()
+ self.assertEqual(ha_enabled,
+ api.neutron.get_feature_permission(self.request,
+ 'l3-ha', 'create'))
+
+ def test_get_router_ha_permission_with_l3_ha_extension(self):
+ self._test_get_router_ha_permission_with_policy_check(True)
+
+ def test_get_router_ha_permission_without_l3_ha_extension(self):
+ self._test_get_router_ha_permission_with_policy_check(False)
diff --git a/openstack_dashboard/test/test_data/neutron_data.py b/openstack_dashboard/test/test_data/neutron_data.py
index a9ed60c573..d3b568b8c2 100644
--- a/openstack_dashboard/test/test_data/neutron_data.py
+++ b/openstack_dashboard/test/test_data/neutron_data.py
@@ -642,10 +642,14 @@ def data(TEST):
"alias": "dvr",
"description":
"Enables configuration of Distributed Virtual Routers."}
+ extension_5 = {"name": "HA Router extension",
+ "alias": "l3-ha",
+ "description": "Add HA capability to routers."}
TEST.api_extensions.add(extension_1)
TEST.api_extensions.add(extension_2)
TEST.api_extensions.add(extension_3)
TEST.api_extensions.add(extension_4)
+ TEST.api_extensions.add(extension_5)
# 1st agent.
agent_dict = {"binary": "neutron-openvswitch-agent",