Add "Edit Router" to allow to change router type
Neutron DVR implementation allows to change router type from centralized to distributed. This commit adds "Edit Router" form which is not implemented so far to allow this feature. This commit also adds: - admin_state field to the router detail. - documentation on a new option enable_distributed_router Completes blueprint enhance-horizon-for-dvr Change-Id: I4b46e44c417726217ed034e305827b102ba656f8
This commit is contained in:
parent
f3da51632b
commit
6a8ea3385c
@ -493,6 +493,7 @@ by cinder. Currently only the backup service is available.
|
|||||||
Default::
|
Default::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
'enable_distributed_router': False,
|
||||||
'enable_lb': False,
|
'enable_lb': False,
|
||||||
'enable_quotas': False,
|
'enable_quotas': False,
|
||||||
'enable_firewall': False,
|
'enable_firewall': False,
|
||||||
@ -507,6 +508,19 @@ by Neutron and configure Neutron specific features. The following options are
|
|||||||
available.
|
available.
|
||||||
|
|
||||||
|
|
||||||
|
``enable_distributed_router``:
|
||||||
|
|
||||||
|
.. versionadded:: 2014.2(Juno)
|
||||||
|
|
||||||
|
Default: ``False``
|
||||||
|
|
||||||
|
Enable or disable Neutron distributed virtual router (DVR) feature in
|
||||||
|
the Router panel. For the DVR feature to be enabled, this option needs
|
||||||
|
to be set to True and your Neutron deployment must support DVR. Even
|
||||||
|
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_lb``:
|
``enable_lb``:
|
||||||
|
|
||||||
.. versionadded:: 2013.1(Grizzly)
|
.. versionadded:: 2013.1(Grizzly)
|
||||||
|
@ -121,8 +121,8 @@ class Router(NeutronAPIDictWrapper):
|
|||||||
"""Wrapper for neutron routers."""
|
"""Wrapper for neutron routers."""
|
||||||
|
|
||||||
def __init__(self, apiresource):
|
def __init__(self, apiresource):
|
||||||
# apiresource['admin_state'] = \
|
apiresource['admin_state'] = \
|
||||||
# 'UP' if apiresource['admin_state_up'] else 'DOWN'
|
'UP' if apiresource['admin_state_up'] else 'DOWN'
|
||||||
super(Router, self).__init__(apiresource)
|
super(Router, self).__init__(apiresource)
|
||||||
|
|
||||||
|
|
||||||
@ -911,9 +911,11 @@ def get_dvr_permission(request, operation):
|
|||||||
if not network_config.get('enable_distributed_router', False):
|
if not network_config.get('enable_distributed_router', False):
|
||||||
return False
|
return False
|
||||||
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
|
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
|
||||||
if operation not in ("get", "create"):
|
allowed_operations = ("get", "create", "update")
|
||||||
|
if operation not in allowed_operations:
|
||||||
raise ValueError(_("The 'operation' parameter for get_dvr_permission "
|
raise ValueError(_("The 'operation' parameter for get_dvr_permission "
|
||||||
"is invalid. It should be 'get' or 'create'."))
|
"is invalid. It should be one of %s")
|
||||||
|
% ' '.join(allowed_operations))
|
||||||
role = (("network", "%s_router:distributed" % operation),)
|
role = (("network", "%s_router:distributed" % operation),)
|
||||||
if policy_check:
|
if policy_check:
|
||||||
has_permission = policy.check(role, request)
|
has_permission = policy.check(role, request)
|
||||||
|
@ -147,6 +147,7 @@
|
|||||||
"delete_router": "rule:admin_or_owner",
|
"delete_router": "rule:admin_or_owner",
|
||||||
"get_router:distributed": "rule:admin_only",
|
"get_router:distributed": "rule:admin_only",
|
||||||
"create_router:distributed": "rule:admin_only",
|
"create_router:distributed": "rule:admin_only",
|
||||||
|
"update_router:distributed": "rule:admin_only",
|
||||||
|
|
||||||
"create_floatingip": "rule:regular_user",
|
"create_floatingip": "rule:regular_user",
|
||||||
"update_floatingip": "rule:admin_or_owner",
|
"update_floatingip": "rule:admin_or_owner",
|
||||||
|
19
openstack_dashboard/dashboards/admin/routers/forms.py
Normal file
19
openstack_dashboard/dashboards/admin/routers/forms.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# 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 django.core.urlresolvers import reverse_lazy
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.project.routers import forms as r_forms
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateForm(r_forms.UpdateForm):
|
||||||
|
redirect_url = reverse_lazy('horizon:admin:routers:index')
|
@ -42,6 +42,10 @@ class DeleteRouter(r_tables.DeleteRouter):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class EditRouter(r_tables.EditRouter):
|
||||||
|
url = "horizon:admin:routers:update"
|
||||||
|
|
||||||
|
|
||||||
class UpdateRow(tables.Row):
|
class UpdateRow(tables.Row):
|
||||||
ajax = True
|
ajax = True
|
||||||
|
|
||||||
@ -62,5 +66,5 @@ class RoutersTable(r_tables.RoutersTable):
|
|||||||
status_columns = ["status"]
|
status_columns = ["status"]
|
||||||
row_class = UpdateRow
|
row_class = UpdateRow
|
||||||
table_actions = (DeleteRouter,)
|
table_actions = (DeleteRouter,)
|
||||||
row_actions = (DeleteRouter,)
|
row_actions = (EditRouter, DeleteRouter,)
|
||||||
Columns = ('tenant', 'name', 'status', 'distributed', 'ext_net')
|
Columns = ('tenant', 'name', 'status', 'distributed', 'ext_net')
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
<dd>{{ router.tenant_id }}</dd>
|
<dd>{{ router.tenant_id }}</dd>
|
||||||
<dt>{% trans "Status" %}</dt>
|
<dt>{% trans "Status" %}</dt>
|
||||||
<dd>{{ router.status|capfirst }}</dd>
|
<dd>{{ router.status|capfirst }}</dd>
|
||||||
|
<dt>{% trans "Admin State" %}</dt>
|
||||||
|
<dd>{{ router.admin_state|default:_("Unknown") }}</dd>
|
||||||
{% if dvr_supported %}
|
{% if dvr_supported %}
|
||||||
<dt>{% trans "Distributed" %}</dt>
|
<dt>{% trans "Distributed" %}</dt>
|
||||||
<dd>{{ router.distributed|yesno|capfirst }}</dd>
|
<dd>{{ router.distributed|yesno|capfirst }}</dd>
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block form_id %}update_router_form{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:admin:routers:update' router_id %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-header %}{% trans "Edit Router" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<div class="left">
|
||||||
|
<fieldset>
|
||||||
|
{% include "horizon/common/_form_fields.html" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "You may update the editable properties of your router here." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Save Changes" %}" />
|
||||||
|
<a href="{% url 'horizon:admin:routers:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Router" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Update Router") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'admin/routers/_update.html' %}
|
||||||
|
{% endblock %}
|
@ -18,9 +18,15 @@ from django.conf.urls import url # noqa
|
|||||||
from openstack_dashboard.dashboards.admin.routers import views
|
from openstack_dashboard.dashboards.admin.routers import views
|
||||||
|
|
||||||
|
|
||||||
|
ROUTER_URL = r'^(?P<router_id>[^/]+)/%s'
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('horizon.dashboards.admin.routers.views',
|
urlpatterns = patterns('horizon.dashboards.admin.routers.views',
|
||||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
url(r'^(?P<router_id>[^/]+)/$',
|
url(ROUTER_URL % '$',
|
||||||
views.DetailView.as_view(),
|
views.DetailView.as_view(),
|
||||||
name='detail'),
|
name='detail'),
|
||||||
|
url(ROUTER_URL % 'update',
|
||||||
|
views.UpdateView.as_view(),
|
||||||
|
name='update'),
|
||||||
)
|
)
|
||||||
|
@ -22,6 +22,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
from openstack_dashboard.dashboards.admin.networks import views as n_views
|
from openstack_dashboard.dashboards.admin.networks import views as n_views
|
||||||
|
from openstack_dashboard.dashboards.admin.routers import forms as rforms
|
||||||
from openstack_dashboard.dashboards.admin.routers import tables as rtbl
|
from openstack_dashboard.dashboards.admin.routers import tables as rtbl
|
||||||
from openstack_dashboard.dashboards.admin.routers import tabs as rtabs
|
from openstack_dashboard.dashboards.admin.routers import tabs as rtabs
|
||||||
from openstack_dashboard.dashboards.project.routers import views as r_views
|
from openstack_dashboard.dashboards.project.routers import views as r_views
|
||||||
@ -61,3 +62,9 @@ class DetailView(r_views.DetailView):
|
|||||||
tab_group_class = rtabs.RouterDetailTabs
|
tab_group_class = rtabs.RouterDetailTabs
|
||||||
template_name = 'admin/routers/detail.html'
|
template_name = 'admin/routers/detail.html'
|
||||||
failure_url = reverse_lazy('horizon:admin:routers:index')
|
failure_url = reverse_lazy('horizon:admin:routers:index')
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateView(r_views.UpdateView):
|
||||||
|
form_class = rforms.UpdateForm
|
||||||
|
template_name = 'admin/routers/update.html'
|
||||||
|
success_url = reverse_lazy("horizon:admin:routers:index")
|
||||||
|
@ -19,6 +19,7 @@ Views for managing Neutron Routers.
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
@ -66,3 +67,48 @@ class CreateForm(forms.SelfHandlingForm):
|
|||||||
redirect = reverse(self.failure_url)
|
redirect = reverse(self.failure_url)
|
||||||
exceptions.handle(request, msg, redirect=redirect)
|
exceptions.handle(request, msg, redirect=redirect)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateForm(forms.SelfHandlingForm):
|
||||||
|
name = forms.CharField(label=_("Name"), required=False)
|
||||||
|
admin_state = forms.BooleanField(label=_("Admin State"), required=False)
|
||||||
|
router_id = forms.CharField(label=_("ID"),
|
||||||
|
widget=forms.HiddenInput())
|
||||||
|
mode = forms.ChoiceField(label=_("Router Type"))
|
||||||
|
|
||||||
|
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")
|
||||||
|
if not self.dvr_allowed:
|
||||||
|
del self.fields['mode']
|
||||||
|
elif kwargs.get('initial', {}).get('mode') == 'distributed':
|
||||||
|
# Neutron supports only changing from centralized to
|
||||||
|
# distributed now.
|
||||||
|
mode_choices = [('distributed', _('Distributed'))]
|
||||||
|
self.fields['mode'].widget = forms.TextInput(attrs={'readonly':
|
||||||
|
'readonly'})
|
||||||
|
self.fields['mode'].choices = mode_choices
|
||||||
|
else:
|
||||||
|
mode_choices = [('centralized', _('Centralized')),
|
||||||
|
('distributed', _('Distributed'))]
|
||||||
|
self.fields['mode'].choices = mode_choices
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
params = {'admin_state_up': data['admin_state'],
|
||||||
|
'name': data['name']}
|
||||||
|
if self.dvr_allowed:
|
||||||
|
params['distributed'] = (data['mode'] == 'distributed')
|
||||||
|
router = api.neutron.router_update(request, data['router_id'],
|
||||||
|
**params)
|
||||||
|
msg = _('Router %s was successfully updated.') % data['name']
|
||||||
|
LOG.debug(msg)
|
||||||
|
messages.success(request, msg)
|
||||||
|
return router
|
||||||
|
except Exception:
|
||||||
|
msg = _('Failed to update router %s') % data['name']
|
||||||
|
LOG.info(msg)
|
||||||
|
exceptions.handle(request, msg, redirect=self.redirect_url)
|
||||||
|
@ -69,6 +69,21 @@ class CreateRouter(tables.LinkAction):
|
|||||||
policy_rules = (("network", "create_router"),)
|
policy_rules = (("network", "create_router"),)
|
||||||
|
|
||||||
|
|
||||||
|
class EditRouter(tables.LinkAction):
|
||||||
|
name = "update"
|
||||||
|
verbose_name = _("Edit Router")
|
||||||
|
url = "horizon:project:routers:update"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "pencil"
|
||||||
|
policy_rules = (("network", "update_router"),)
|
||||||
|
|
||||||
|
def get_policy_target(self, request, datum=None):
|
||||||
|
project_id = None
|
||||||
|
if datum:
|
||||||
|
project_id = getattr(datum, 'tenant_id', None)
|
||||||
|
return {"project_id": project_id}
|
||||||
|
|
||||||
|
|
||||||
class SetGateway(tables.LinkAction):
|
class SetGateway(tables.LinkAction):
|
||||||
name = "setgateway"
|
name = "setgateway"
|
||||||
verbose_name = _("Set Gateway")
|
verbose_name = _("Set Gateway")
|
||||||
@ -174,4 +189,4 @@ class RoutersTable(tables.DataTable):
|
|||||||
status_columns = ["status"]
|
status_columns = ["status"]
|
||||||
row_class = UpdateRow
|
row_class = UpdateRow
|
||||||
table_actions = (CreateRouter, DeleteRouter)
|
table_actions = (CreateRouter, DeleteRouter)
|
||||||
row_actions = (SetGateway, ClearGateway, DeleteRouter)
|
row_actions = (SetGateway, ClearGateway, EditRouter, DeleteRouter)
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
<dd>{{ router.id|default:_("None") }}</dd>
|
<dd>{{ router.id|default:_("None") }}</dd>
|
||||||
<dt>{% trans "Status" %}</dt>
|
<dt>{% trans "Status" %}</dt>
|
||||||
<dd>{{ router.status|default:_("Unknown") }}</dd>
|
<dd>{{ router.status|default:_("Unknown") }}</dd>
|
||||||
|
<dt>{% trans "Admin State" %}</dt>
|
||||||
|
<dd>{{ router.admin_state|default:_("Unknown") }}</dd>
|
||||||
{% if dvr_supported %}
|
{% if dvr_supported %}
|
||||||
<dt>{% trans "Distributed" %}</dt>
|
<dt>{% trans "Distributed" %}</dt>
|
||||||
<dd>{{ router.distributed|yesno|capfirst }}</dd>
|
<dd>{{ router.distributed|yesno|capfirst }}</dd>
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block form_id %}update_router_form{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:project:routers:update' router_id %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-header %}{% trans "Edit Router" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<div class="left">
|
||||||
|
<fieldset>
|
||||||
|
{% include "horizon/common/_form_fields.html" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "You may update the editable properties of your router here." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Save Changes" %}" />
|
||||||
|
<a href="{% url 'horizon:project:routers:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Router" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Update Router") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'project/routers/_update.html' %}
|
||||||
|
{% endblock %}
|
@ -223,6 +223,107 @@ class RouterActionTests(test.TestCase):
|
|||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, self.INDEX_URL)
|
self.assertRedirectsNoFollow(res, self.INDEX_URL)
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('router_get',
|
||||||
|
'get_dvr_permission')})
|
||||||
|
def _test_router_update_get(self, dvr_enabled=False,
|
||||||
|
current_dvr=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")\
|
||||||
|
.AndReturn(dvr_enabled)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
url = reverse('horizon:%s:routers:update' % self.DASHBOARD,
|
||||||
|
args=[router.id])
|
||||||
|
return self.client.get(url)
|
||||||
|
|
||||||
|
def test_router_update_get_dvr_disabled(self):
|
||||||
|
res = self._test_router_update_get(dvr_enabled=False)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(res, 'project/routers/update.html')
|
||||||
|
self.assertNotContains(res, 'Router Type')
|
||||||
|
self.assertNotContains(res, 'id="id_mode"')
|
||||||
|
|
||||||
|
def test_router_update_get_dvr_enabled_mode_centralized(self):
|
||||||
|
res = self._test_router_update_get(dvr_enabled=True, current_dvr=False)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(res, 'project/routers/update.html')
|
||||||
|
self.assertContains(res, 'Router Type')
|
||||||
|
# Check both menu are displayed.
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<option value="centralized" selected="selected">'
|
||||||
|
'Centralized</option>',
|
||||||
|
html=True)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<option value="distributed">Distributed</option>',
|
||||||
|
html=True)
|
||||||
|
|
||||||
|
def test_router_update_get_dvr_enabled_mode_distributed(self):
|
||||||
|
res = self._test_router_update_get(dvr_enabled=True, current_dvr=True)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(res, 'project/routers/update.html')
|
||||||
|
self.assertContains(res, 'Router Type')
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<input class=" form-control" id="id_mode" name="mode" '
|
||||||
|
'readonly="readonly" type="text" value="distributed" />',
|
||||||
|
html=True)
|
||||||
|
self.assertNotContains(res, 'centralized')
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('router_get',
|
||||||
|
'router_update',
|
||||||
|
'get_dvr_permission')})
|
||||||
|
def test_router_update_post_dvr_disabled(self):
|
||||||
|
router = self.routers.first()
|
||||||
|
api.neutron.get_dvr_permission(IsA(http.HttpRequest), "update")\
|
||||||
|
.AndReturn(False)
|
||||||
|
api.neutron.router_update(IsA(http.HttpRequest), router.id,
|
||||||
|
name=router.name,
|
||||||
|
admin_state_up=router.admin_state_up)\
|
||||||
|
.AndReturn(router)
|
||||||
|
api.neutron.router_get(IsA(http.HttpRequest), router.id)\
|
||||||
|
.AndReturn(router)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {'router_id': router.id,
|
||||||
|
'name': router.name,
|
||||||
|
'admin_state': router.admin_state_up}
|
||||||
|
url = reverse('horizon:%s:routers:update' % self.DASHBOARD,
|
||||||
|
args=[router.id])
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, self.INDEX_URL)
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('router_get',
|
||||||
|
'router_update',
|
||||||
|
'get_dvr_permission')})
|
||||||
|
def test_router_update_post_dvr_enabled(self):
|
||||||
|
router = self.routers.first()
|
||||||
|
api.neutron.get_dvr_permission(IsA(http.HttpRequest), "update")\
|
||||||
|
.AndReturn(True)
|
||||||
|
api.neutron.router_update(IsA(http.HttpRequest), router.id,
|
||||||
|
name=router.name,
|
||||||
|
admin_state_up=router.admin_state_up,
|
||||||
|
distributed=True)\
|
||||||
|
.AndReturn(router)
|
||||||
|
api.neutron.router_get(IsA(http.HttpRequest), router.id)\
|
||||||
|
.AndReturn(router)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {'router_id': router.id,
|
||||||
|
'name': router.name,
|
||||||
|
'admin_state': router.admin_state_up,
|
||||||
|
'mode': 'distributed'}
|
||||||
|
url = reverse('horizon:%s:routers:update' % self.DASHBOARD,
|
||||||
|
args=[router.id])
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, self.INDEX_URL)
|
||||||
|
|
||||||
def _mock_network_list(self, tenant_id):
|
def _mock_network_list(self, tenant_id):
|
||||||
api.neutron.network_list(
|
api.neutron.network_list(
|
||||||
IsA(http.HttpRequest),
|
IsA(http.HttpRequest),
|
||||||
|
@ -22,19 +22,25 @@ from openstack_dashboard.dashboards.project.routers.ports \
|
|||||||
from openstack_dashboard.dashboards.project.routers import views
|
from openstack_dashboard.dashboards.project.routers import views
|
||||||
|
|
||||||
|
|
||||||
|
ROUTER_URL = r'^(?P<router_id>[^/]+)/%s'
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('horizon.dashboards.project.routers.views',
|
urlpatterns = patterns('horizon.dashboards.project.routers.views',
|
||||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
url(r'^create/$', views.CreateView.as_view(), name='create'),
|
url(r'^create/$', views.CreateView.as_view(), name='create'),
|
||||||
url(r'^(?P<router_id>[^/]+)/$',
|
url(ROUTER_URL % '$',
|
||||||
views.DetailView.as_view(),
|
views.DetailView.as_view(),
|
||||||
name='detail'),
|
name='detail'),
|
||||||
url(r'^(?P<router_id>[^/]+)/addinterface',
|
url(ROUTER_URL % 'update',
|
||||||
|
views.UpdateView.as_view(),
|
||||||
|
name='update'),
|
||||||
|
url(ROUTER_URL % 'addinterface',
|
||||||
port_views.AddInterfaceView.as_view(),
|
port_views.AddInterfaceView.as_view(),
|
||||||
name='addinterface'),
|
name='addinterface'),
|
||||||
url(r'^(?P<router_id>[^/]+)/addrouterrule',
|
url(ROUTER_URL % 'addrouterrule',
|
||||||
rr_views.AddRouterRuleView.as_view(),
|
rr_views.AddRouterRuleView.as_view(),
|
||||||
name='addrouterrule'),
|
name='addrouterrule'),
|
||||||
url(r'^(?P<router_id>[^/]+)/setgateway',
|
url(ROUTER_URL % 'setgateway',
|
||||||
port_views.SetGatewayView.as_view(),
|
port_views.SetGatewayView.as_view(),
|
||||||
name='setgateway'),
|
name='setgateway'),
|
||||||
)
|
)
|
||||||
|
@ -136,3 +136,34 @@ class CreateView(forms.ModalFormView):
|
|||||||
form_class = project_forms.CreateForm
|
form_class = project_forms.CreateForm
|
||||||
template_name = 'project/routers/create.html'
|
template_name = 'project/routers/create.html'
|
||||||
success_url = reverse_lazy("horizon:project:routers:index")
|
success_url = reverse_lazy("horizon:project:routers:index")
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.UpdateForm
|
||||||
|
template_name = 'project/routers/update.html'
|
||||||
|
success_url = reverse_lazy("horizon:project:routers:index")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||||
|
context["router_id"] = self.kwargs['router_id']
|
||||||
|
return context
|
||||||
|
|
||||||
|
def _get_object(self, *args, **kwargs):
|
||||||
|
router_id = self.kwargs['router_id']
|
||||||
|
try:
|
||||||
|
return api.neutron.router_get(self.request, router_id)
|
||||||
|
except Exception:
|
||||||
|
redirect = self.success_url
|
||||||
|
msg = _('Unable to retrieve router details.')
|
||||||
|
exceptions.handle(self.request, msg, redirect=redirect)
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
router = self._get_object()
|
||||||
|
initial = {'router_id': router['id'],
|
||||||
|
'tenant_id': router['tenant_id'],
|
||||||
|
'name': router['name'],
|
||||||
|
'admin_state': router['admin_state_up']}
|
||||||
|
if hasattr(router, 'distributed'):
|
||||||
|
initial['mode'] = ('distributed' if router.distributed
|
||||||
|
else 'centralized')
|
||||||
|
return initial
|
||||||
|
@ -276,6 +276,8 @@ def data(TEST):
|
|||||||
router_dict = {'id': '279989f7-54bb-41d9-ba42-0d61f12fda61',
|
router_dict = {'id': '279989f7-54bb-41d9-ba42-0d61f12fda61',
|
||||||
'name': 'router1',
|
'name': 'router1',
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'distributed': True,
|
||||||
'external_gateway_info':
|
'external_gateway_info':
|
||||||
{'network_id': ext_net['id']},
|
{'network_id': ext_net['id']},
|
||||||
'tenant_id': '1'}
|
'tenant_id': '1'}
|
||||||
@ -284,6 +286,8 @@ def data(TEST):
|
|||||||
router_dict = {'id': '10e3dc42-1ce1-4d48-87cf-7fc333055d6c',
|
router_dict = {'id': '10e3dc42-1ce1-4d48-87cf-7fc333055d6c',
|
||||||
'name': 'router2',
|
'name': 'router2',
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'distributed': False,
|
||||||
'external_gateway_info': None,
|
'external_gateway_info': None,
|
||||||
'tenant_id': '1'}
|
'tenant_id': '1'}
|
||||||
TEST.api_routers.add(router_dict)
|
TEST.api_routers.add(router_dict)
|
||||||
@ -291,6 +295,8 @@ def data(TEST):
|
|||||||
router_dict = {'id': '7180cede-bcd8-4334-b19f-f7ef2f331f53',
|
router_dict = {'id': '7180cede-bcd8-4334-b19f-f7ef2f331f53',
|
||||||
'name': 'rulerouter',
|
'name': 'rulerouter',
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'distributed': False,
|
||||||
'external_gateway_info':
|
'external_gateway_info':
|
||||||
{'network_id': ext_net['id']},
|
{'network_id': ext_net['id']},
|
||||||
'tenant_id': '1',
|
'tenant_id': '1',
|
||||||
|
Loading…
Reference in New Issue
Block a user