Add a checkbox to disable SNAT on routers
When creating a router, or when setting a gateway on a router - a checkbox is displayed, which can be unchecked to disable SNAT. Change-Id: I8bc040018645fe2bde534b7d48e14c17984cc9c4 Closes-bug: #1673076
This commit is contained in:
parent
6941262e03
commit
edcd22244f
|
@ -1264,8 +1264,10 @@ def router_remove_interface(request, router_id, subnet_id=None, port_id=None):
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def router_add_gateway(request, router_id, network_id):
|
def router_add_gateway(request, router_id, network_id, enable_snat=None):
|
||||||
body = {'network_id': network_id}
|
body = {'network_id': network_id}
|
||||||
|
if enable_snat is not None:
|
||||||
|
body['enable_snat'] = enable_snat
|
||||||
neutronclient(request).add_gateway_router(router_id, body)
|
neutronclient(request).add_gateway_router(router_id, body)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1640,6 +1642,15 @@ FEATURE_MAP = {
|
||||||
'update': 'update_router:ha',
|
'update': 'update_router:ha',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'ext-gw-mode': {
|
||||||
|
'extension': 'ext-gw-mode',
|
||||||
|
'policies': {
|
||||||
|
'create_router_enable_snat':
|
||||||
|
'create_router:external_gateway_info:enable_snat',
|
||||||
|
'update_router_enable_snat':
|
||||||
|
'update_router:external_gateway_info:enable_snat',
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@ class CreateForm(forms.SelfHandlingForm):
|
||||||
required=False)
|
required=False)
|
||||||
external_network = forms.ThemableChoiceField(label=_("External Network"),
|
external_network = forms.ThemableChoiceField(label=_("External Network"),
|
||||||
required=False)
|
required=False)
|
||||||
|
enable_snat = forms.BooleanField(label=_("Enable SNAT"),
|
||||||
|
initial=True,
|
||||||
|
required=False)
|
||||||
mode = forms.ChoiceField(label=_("Router Type"))
|
mode = forms.ChoiceField(label=_("Router Type"))
|
||||||
ha = forms.ChoiceField(label=_("High Availability Mode"))
|
ha = forms.ChoiceField(label=_("High Availability Mode"))
|
||||||
az_hints = forms.MultipleChoiceField(
|
az_hints = forms.MultipleChoiceField(
|
||||||
|
@ -76,6 +79,10 @@ class CreateForm(forms.SelfHandlingForm):
|
||||||
else:
|
else:
|
||||||
del self.fields['external_network']
|
del self.fields['external_network']
|
||||||
|
|
||||||
|
self.enable_snat_allowed = self.initial['enable_snat_allowed']
|
||||||
|
if (not networks or not self.enable_snat_allowed):
|
||||||
|
del self.fields['enable_snat']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
az_supported = api.neutron.is_extension_supported(
|
az_supported = api.neutron.is_extension_supported(
|
||||||
self.request, 'router_availability_zone')
|
self.request, 'router_availability_zone')
|
||||||
|
@ -116,6 +123,9 @@ class CreateForm(forms.SelfHandlingForm):
|
||||||
if 'external_network' in data and data['external_network']:
|
if 'external_network' in data and data['external_network']:
|
||||||
params['external_gateway_info'] = {'network_id':
|
params['external_gateway_info'] = {'network_id':
|
||||||
data['external_network']}
|
data['external_network']}
|
||||||
|
if self.ext_gw_mode_supported and self.enable_snat_allowed:
|
||||||
|
params['external_gateway_info']['enable_snat'] = \
|
||||||
|
data['enable_snat']
|
||||||
if 'az_hints' in data and data['az_hints']:
|
if 'az_hints' in data and data['az_hints']:
|
||||||
params['availability_zone_hints'] = data['az_hints']
|
params['availability_zone_hints'] = data['az_hints']
|
||||||
if (self.dvr_allowed and data['mode'] != 'server_default'):
|
if (self.dvr_allowed and data['mode'] != 'server_default'):
|
||||||
|
|
|
@ -145,12 +145,23 @@ class AddInterface(forms.SelfHandlingForm):
|
||||||
|
|
||||||
class SetGatewayForm(forms.SelfHandlingForm):
|
class SetGatewayForm(forms.SelfHandlingForm):
|
||||||
network_id = forms.ThemableChoiceField(label=_("External Network"))
|
network_id = forms.ThemableChoiceField(label=_("External Network"))
|
||||||
|
enable_snat = forms.BooleanField(label=_("Enable SNAT"),
|
||||||
|
initial=True,
|
||||||
|
required=False)
|
||||||
failure_url = 'horizon:project:routers:index'
|
failure_url = 'horizon:project:routers:index'
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(SetGatewayForm, self).__init__(request, *args, **kwargs)
|
super(SetGatewayForm, self).__init__(request, *args, **kwargs)
|
||||||
c = self.populate_network_id_choices(request)
|
networks = self.populate_network_id_choices(request)
|
||||||
self.fields['network_id'].choices = c
|
self.fields['network_id'].choices = networks
|
||||||
|
self.ext_gw_mode = api.neutron.is_extension_supported(
|
||||||
|
self.request, 'ext-gw-mode')
|
||||||
|
self.enable_snat_allowed = api.neutron.get_feature_permission(
|
||||||
|
self.request,
|
||||||
|
"ext-gw-mode",
|
||||||
|
"update_router_enable_snat")
|
||||||
|
if not self.ext_gw_mode or not self.enable_snat_allowed:
|
||||||
|
del self.fields['enable_snat']
|
||||||
|
|
||||||
def populate_network_id_choices(self, request):
|
def populate_network_id_choices(self, request):
|
||||||
search_opts = {'router:external': True}
|
search_opts = {'router:external': True}
|
||||||
|
@ -173,9 +184,13 @@ class SetGatewayForm(forms.SelfHandlingForm):
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
try:
|
try:
|
||||||
|
enable_snat = None
|
||||||
|
if 'enable_snat' in data:
|
||||||
|
enable_snat = data['enable_snat']
|
||||||
api.neutron.router_add_gateway(request,
|
api.neutron.router_add_gateway(request,
|
||||||
self.initial['router_id'],
|
self.initial['router_id'],
|
||||||
data['network_id'])
|
data['network_id'],
|
||||||
|
enable_snat)
|
||||||
msg = _('Gateway interface is added')
|
msg = _('Gateway interface is added')
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -4,4 +4,7 @@
|
||||||
{% block modal-body-right %}
|
{% block modal-body-right %}
|
||||||
<h3>{% trans "Description:" %}</h3>
|
<h3>{% trans "Description:" %}</h3>
|
||||||
<p>{% trans "Creates a router with specified parameters." %}</p>
|
<p>{% trans "Creates a router with specified parameters." %}</p>
|
||||||
|
{% if enable_snat_allowed %}
|
||||||
|
<p>{% trans "Enable SNAT will only have an effect if an external network is set." %}</p>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -284,6 +284,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
'is_extension_supported')})
|
'is_extension_supported')})
|
||||||
def test_router_create_post(self):
|
def test_router_create_post(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"create_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
"dvr", "create")\
|
"dvr", "create")\
|
||||||
.AndReturn(False)
|
.AndReturn(False)
|
||||||
|
@ -315,6 +319,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
'is_extension_supported')})
|
'is_extension_supported')})
|
||||||
def test_router_create_post_mode_server_default(self):
|
def test_router_create_post_mode_server_default(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"create_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
"dvr", "create")\
|
"dvr", "create")\
|
||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
|
@ -348,6 +356,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
'is_extension_supported')})
|
'is_extension_supported')})
|
||||||
def test_dvr_ha_router_create_post(self):
|
def test_dvr_ha_router_create_post(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"create_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
"dvr", "create")\
|
"dvr", "create")\
|
||||||
.MultipleTimes().AndReturn(True)
|
.MultipleTimes().AndReturn(True)
|
||||||
|
@ -384,6 +396,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
'list_availability_zones')})
|
'list_availability_zones')})
|
||||||
def test_az_router_create_post(self):
|
def test_az_router_create_post(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"create_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
"dvr", "create")\
|
"dvr", "create")\
|
||||||
.MultipleTimes().AndReturn(False)
|
.MultipleTimes().AndReturn(False)
|
||||||
|
@ -422,6 +438,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
'is_extension_supported')})
|
'is_extension_supported')})
|
||||||
def test_router_create_post_exception_error_case_409(self):
|
def test_router_create_post_exception_error_case_409(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"create_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
"dvr", "create")\
|
"dvr", "create")\
|
||||||
.MultipleTimes().AndReturn(False)
|
.MultipleTimes().AndReturn(False)
|
||||||
|
@ -454,6 +474,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
'network_list')})
|
'network_list')})
|
||||||
def test_router_create_post_exception_error_case_non_409(self):
|
def test_router_create_post_exception_error_case_non_409(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"create_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
"dvr", "create")\
|
"dvr", "create")\
|
||||||
.MultipleTimes().AndReturn(False)
|
.MultipleTimes().AndReturn(False)
|
||||||
|
@ -730,24 +754,34 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('router_get',
|
@test.create_stubs({api.neutron: ('router_get',
|
||||||
'router_add_gateway',
|
'router_add_gateway',
|
||||||
'network_list')})
|
'network_list',
|
||||||
|
'is_extension_supported')})
|
||||||
def test_router_add_gateway(self):
|
def test_router_add_gateway(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.neutron.router_add_gateway(
|
api.neutron.router_add_gateway(
|
||||||
IsA(http.HttpRequest),
|
IsA(http.HttpRequest),
|
||||||
router.id,
|
router.id,
|
||||||
network.id).AndReturn(None)
|
network.id,
|
||||||
|
True).AndReturn(None)
|
||||||
api.neutron.router_get(
|
api.neutron.router_get(
|
||||||
IsA(http.HttpRequest), router.id).AndReturn(router)
|
IsA(http.HttpRequest), router.id).AndReturn(router)
|
||||||
search_opts = {'router:external': True}
|
search_opts = {'router:external': True}
|
||||||
api.neutron.network_list(
|
api.neutron.network_list(
|
||||||
IsA(http.HttpRequest), **search_opts).AndReturn([network])
|
IsA(http.HttpRequest), **search_opts).AndReturn([network])
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'ext-gw-mode')\
|
||||||
|
.AndReturn(True)
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"update_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
form_data = {'router_id': router.id,
|
form_data = {'router_id': router.id,
|
||||||
'router_name': router.name,
|
'router_name': router.name,
|
||||||
'network_id': network.id}
|
'network_id': network.id,
|
||||||
|
'enable_snat': True}
|
||||||
|
|
||||||
url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
|
url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
|
||||||
args=[router.id])
|
args=[router.id])
|
||||||
|
@ -758,24 +792,34 @@ class RouterActionTests(RouterMixin, test.TestCase):
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('router_get',
|
@test.create_stubs({api.neutron: ('router_get',
|
||||||
'router_add_gateway',
|
'router_add_gateway',
|
||||||
'network_list')})
|
'network_list',
|
||||||
|
'is_extension_supported')})
|
||||||
def test_router_add_gateway_exception(self):
|
def test_router_add_gateway_exception(self):
|
||||||
router = self.routers.first()
|
router = self.routers.first()
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.neutron.router_add_gateway(
|
api.neutron.router_add_gateway(
|
||||||
IsA(http.HttpRequest),
|
IsA(http.HttpRequest),
|
||||||
router.id,
|
router.id,
|
||||||
network.id).AndRaise(self.exceptions.neutron)
|
network.id,
|
||||||
|
True).AndRaise(self.exceptions.neutron)
|
||||||
api.neutron.router_get(
|
api.neutron.router_get(
|
||||||
IsA(http.HttpRequest), router.id).AndReturn(router)
|
IsA(http.HttpRequest), router.id).AndReturn(router)
|
||||||
search_opts = {'router:external': True}
|
search_opts = {'router:external': True}
|
||||||
api.neutron.network_list(
|
api.neutron.network_list(
|
||||||
IsA(http.HttpRequest), **search_opts).AndReturn([network])
|
IsA(http.HttpRequest), **search_opts).AndReturn([network])
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'ext-gw-mode')\
|
||||||
|
.AndReturn(True)
|
||||||
|
api.neutron.get_feature_permission(IsA(http.HttpRequest),
|
||||||
|
"ext-gw-mode",
|
||||||
|
"update_router_enable_snat")\
|
||||||
|
.AndReturn(True)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
form_data = {'router_id': router.id,
|
form_data = {'router_id': router.id,
|
||||||
'router_name': router.name,
|
'router_name': router.name,
|
||||||
'network_id': network.id}
|
'network_id': network.id,
|
||||||
|
'enable_snat': True}
|
||||||
|
|
||||||
url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
|
url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
|
||||||
args=[router.id])
|
args=[router.id])
|
||||||
|
|
|
@ -180,6 +180,17 @@ class CreateView(forms.ModalFormView):
|
||||||
submit_label = _("Create Router")
|
submit_label = _("Create Router")
|
||||||
submit_url = reverse_lazy("horizon:project:routers:create")
|
submit_url = reverse_lazy("horizon:project:routers:create")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(CreateView, self).get_context_data(**kwargs)
|
||||||
|
context['enable_snat_allowed'] = self.initial['enable_snat_allowed']
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
enable_snat_allowed = api.neutron.get_feature_permission(
|
||||||
|
self.request, 'ext-gw-mode', 'create_router_enable_snat')
|
||||||
|
self.initial['enable_snat_allowed'] = enable_snat_allowed
|
||||||
|
return super(CreateView, self).get_initial()
|
||||||
|
|
||||||
|
|
||||||
class UpdateView(forms.ModalFormView):
|
class UpdateView(forms.ModalFormView):
|
||||||
form_class = project_forms.UpdateForm
|
form_class = project_forms.UpdateForm
|
||||||
|
|
Loading…
Reference in New Issue