summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2017-10-24 16:24:52 +0000
committerGerrit Code Review <review@openstack.org>2017-10-24 16:24:52 +0000
commit5d386afb1a14248c1c6b655056a4afceb7a0a0bd (patch)
tree07af0d21f80b70866a96fd5136d0ef834d926e7e
parentbed7a2194da8cfe3243de6bafb1908d89ffe5a84 (diff)
parentedcd22244fbbf939f22575d4070c317c3b08067f (diff)
Merge "Add a checkbox to disable SNAT on routers"
-rw-r--r--openstack_dashboard/api/neutron.py13
-rw-r--r--openstack_dashboard/dashboards/project/routers/forms.py10
-rw-r--r--openstack_dashboard/dashboards/project/routers/ports/forms.py21
-rw-r--r--openstack_dashboard/dashboards/project/routers/templates/routers/_create.html3
-rw-r--r--openstack_dashboard/dashboards/project/routers/tests.py56
-rw-r--r--openstack_dashboard/dashboards/project/routers/views.py11
6 files changed, 104 insertions, 10 deletions
diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py
index 29c2336..6ece998 100644
--- a/openstack_dashboard/api/neutron.py
+++ b/openstack_dashboard/api/neutron.py
@@ -1264,8 +1264,10 @@ def router_remove_interface(request, router_id, subnet_id=None, port_id=None):
1264 1264
1265 1265
1266@profiler.trace 1266@profiler.trace
1267def router_add_gateway(request, router_id, network_id): 1267def router_add_gateway(request, router_id, network_id, enable_snat=None):
1268 body = {'network_id': network_id} 1268 body = {'network_id': network_id}
1269 if enable_snat is not None:
1270 body['enable_snat'] = enable_snat
1269 neutronclient(request).add_gateway_router(router_id, body) 1271 neutronclient(request).add_gateway_router(router_id, body)
1270 1272
1271 1273
@@ -1640,6 +1642,15 @@ FEATURE_MAP = {
1640 'update': 'update_router:ha', 1642 'update': 'update_router:ha',
1641 } 1643 }
1642 }, 1644 },
1645 'ext-gw-mode': {
1646 'extension': 'ext-gw-mode',
1647 'policies': {
1648 'create_router_enable_snat':
1649 'create_router:external_gateway_info:enable_snat',
1650 'update_router_enable_snat':
1651 'update_router:external_gateway_info:enable_snat',
1652 }
1653 },
1643} 1654}
1644 1655
1645 1656
diff --git a/openstack_dashboard/dashboards/project/routers/forms.py b/openstack_dashboard/dashboards/project/routers/forms.py
index 00000a8..c834388 100644
--- a/openstack_dashboard/dashboards/project/routers/forms.py
+++ b/openstack_dashboard/dashboards/project/routers/forms.py
@@ -39,6 +39,9 @@ class CreateForm(forms.SelfHandlingForm):
39 required=False) 39 required=False)
40 external_network = forms.ThemableChoiceField(label=_("External Network"), 40 external_network = forms.ThemableChoiceField(label=_("External Network"),
41 required=False) 41 required=False)
42 enable_snat = forms.BooleanField(label=_("Enable SNAT"),
43 initial=True,
44 required=False)
42 mode = forms.ChoiceField(label=_("Router Type")) 45 mode = forms.ChoiceField(label=_("Router Type"))
43 ha = forms.ChoiceField(label=_("High Availability Mode")) 46 ha = forms.ChoiceField(label=_("High Availability Mode"))
44 az_hints = forms.MultipleChoiceField( 47 az_hints = forms.MultipleChoiceField(
@@ -76,6 +79,10 @@ class CreateForm(forms.SelfHandlingForm):
76 else: 79 else:
77 del self.fields['external_network'] 80 del self.fields['external_network']
78 81
82 self.enable_snat_allowed = self.initial['enable_snat_allowed']
83 if (not networks or not self.enable_snat_allowed):
84 del self.fields['enable_snat']
85
79 try: 86 try:
80 az_supported = api.neutron.is_extension_supported( 87 az_supported = api.neutron.is_extension_supported(
81 self.request, 'router_availability_zone') 88 self.request, 'router_availability_zone')
@@ -116,6 +123,9 @@ class CreateForm(forms.SelfHandlingForm):
116 if 'external_network' in data and data['external_network']: 123 if 'external_network' in data and data['external_network']:
117 params['external_gateway_info'] = {'network_id': 124 params['external_gateway_info'] = {'network_id':
118 data['external_network']} 125 data['external_network']}
126 if self.ext_gw_mode_supported and self.enable_snat_allowed:
127 params['external_gateway_info']['enable_snat'] = \
128 data['enable_snat']
119 if 'az_hints' in data and data['az_hints']: 129 if 'az_hints' in data and data['az_hints']:
120 params['availability_zone_hints'] = data['az_hints'] 130 params['availability_zone_hints'] = data['az_hints']
121 if (self.dvr_allowed and data['mode'] != 'server_default'): 131 if (self.dvr_allowed and data['mode'] != 'server_default'):
diff --git a/openstack_dashboard/dashboards/project/routers/ports/forms.py b/openstack_dashboard/dashboards/project/routers/ports/forms.py
index b7d9f5d..fd15fa2 100644
--- a/openstack_dashboard/dashboards/project/routers/ports/forms.py
+++ b/openstack_dashboard/dashboards/project/routers/ports/forms.py
@@ -145,12 +145,23 @@ class AddInterface(forms.SelfHandlingForm):
145 145
146class SetGatewayForm(forms.SelfHandlingForm): 146class SetGatewayForm(forms.SelfHandlingForm):
147 network_id = forms.ThemableChoiceField(label=_("External Network")) 147 network_id = forms.ThemableChoiceField(label=_("External Network"))
148 enable_snat = forms.BooleanField(label=_("Enable SNAT"),
149 initial=True,
150 required=False)
148 failure_url = 'horizon:project:routers:index' 151 failure_url = 'horizon:project:routers:index'
149 152
150 def __init__(self, request, *args, **kwargs): 153 def __init__(self, request, *args, **kwargs):
151 super(SetGatewayForm, self).__init__(request, *args, **kwargs) 154 super(SetGatewayForm, self).__init__(request, *args, **kwargs)
152 c = self.populate_network_id_choices(request) 155 networks = self.populate_network_id_choices(request)
153 self.fields['network_id'].choices = c 156 self.fields['network_id'].choices = networks
157 self.ext_gw_mode = api.neutron.is_extension_supported(
158 self.request, 'ext-gw-mode')
159 self.enable_snat_allowed = api.neutron.get_feature_permission(
160 self.request,
161 "ext-gw-mode",
162 "update_router_enable_snat")
163 if not self.ext_gw_mode or not self.enable_snat_allowed:
164 del self.fields['enable_snat']
154 165
155 def populate_network_id_choices(self, request): 166 def populate_network_id_choices(self, request):
156 search_opts = {'router:external': True} 167 search_opts = {'router:external': True}
@@ -173,9 +184,13 @@ class SetGatewayForm(forms.SelfHandlingForm):
173 184
174 def handle(self, request, data): 185 def handle(self, request, data):
175 try: 186 try:
187 enable_snat = None
188 if 'enable_snat' in data:
189 enable_snat = data['enable_snat']
176 api.neutron.router_add_gateway(request, 190 api.neutron.router_add_gateway(request,
177 self.initial['router_id'], 191 self.initial['router_id'],
178 data['network_id']) 192 data['network_id'],
193 enable_snat)
179 msg = _('Gateway interface is added') 194 msg = _('Gateway interface is added')
180 messages.success(request, msg) 195 messages.success(request, msg)
181 return True 196 return True
diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/_create.html b/openstack_dashboard/dashboards/project/routers/templates/routers/_create.html
index b52b7e1..c790673 100644
--- a/openstack_dashboard/dashboards/project/routers/templates/routers/_create.html
+++ b/openstack_dashboard/dashboards/project/routers/templates/routers/_create.html
@@ -4,4 +4,7 @@
4{% block modal-body-right %} 4{% block modal-body-right %}
5 <h3>{% trans "Description:" %}</h3> 5 <h3>{% trans "Description:" %}</h3>
6 <p>{% trans "Creates a router with specified parameters." %}</p> 6 <p>{% trans "Creates a router with specified parameters." %}</p>
7 {% if enable_snat_allowed %}
8 <p>{% trans "Enable SNAT will only have an effect if an external network is set." %}</p>
9 {% endif %}
7{% endblock %} 10{% endblock %}
diff --git a/openstack_dashboard/dashboards/project/routers/tests.py b/openstack_dashboard/dashboards/project/routers/tests.py
index 4b8738e..db3eb40 100644
--- a/openstack_dashboard/dashboards/project/routers/tests.py
+++ b/openstack_dashboard/dashboards/project/routers/tests.py
@@ -285,6 +285,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
285 def test_router_create_post(self): 285 def test_router_create_post(self):
286 router = self.routers.first() 286 router = self.routers.first()
287 api.neutron.get_feature_permission(IsA(http.HttpRequest), 287 api.neutron.get_feature_permission(IsA(http.HttpRequest),
288 "ext-gw-mode",
289 "create_router_enable_snat")\
290 .AndReturn(True)
291 api.neutron.get_feature_permission(IsA(http.HttpRequest),
288 "dvr", "create")\ 292 "dvr", "create")\
289 .AndReturn(False) 293 .AndReturn(False)
290 api.neutron.get_feature_permission(IsA(http.HttpRequest), 294 api.neutron.get_feature_permission(IsA(http.HttpRequest),
@@ -316,6 +320,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
316 def test_router_create_post_mode_server_default(self): 320 def test_router_create_post_mode_server_default(self):
317 router = self.routers.first() 321 router = self.routers.first()
318 api.neutron.get_feature_permission(IsA(http.HttpRequest), 322 api.neutron.get_feature_permission(IsA(http.HttpRequest),
323 "ext-gw-mode",
324 "create_router_enable_snat")\
325 .AndReturn(True)
326 api.neutron.get_feature_permission(IsA(http.HttpRequest),
319 "dvr", "create")\ 327 "dvr", "create")\
320 .AndReturn(True) 328 .AndReturn(True)
321 api.neutron.get_feature_permission(IsA(http.HttpRequest), 329 api.neutron.get_feature_permission(IsA(http.HttpRequest),
@@ -349,6 +357,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
349 def test_dvr_ha_router_create_post(self): 357 def test_dvr_ha_router_create_post(self):
350 router = self.routers.first() 358 router = self.routers.first()
351 api.neutron.get_feature_permission(IsA(http.HttpRequest), 359 api.neutron.get_feature_permission(IsA(http.HttpRequest),
360 "ext-gw-mode",
361 "create_router_enable_snat")\
362 .AndReturn(True)
363 api.neutron.get_feature_permission(IsA(http.HttpRequest),
352 "dvr", "create")\ 364 "dvr", "create")\
353 .MultipleTimes().AndReturn(True) 365 .MultipleTimes().AndReturn(True)
354 api.neutron.get_feature_permission(IsA(http.HttpRequest), 366 api.neutron.get_feature_permission(IsA(http.HttpRequest),
@@ -385,6 +397,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
385 def test_az_router_create_post(self): 397 def test_az_router_create_post(self):
386 router = self.routers.first() 398 router = self.routers.first()
387 api.neutron.get_feature_permission(IsA(http.HttpRequest), 399 api.neutron.get_feature_permission(IsA(http.HttpRequest),
400 "ext-gw-mode",
401 "create_router_enable_snat")\
402 .AndReturn(True)
403 api.neutron.get_feature_permission(IsA(http.HttpRequest),
388 "dvr", "create")\ 404 "dvr", "create")\
389 .MultipleTimes().AndReturn(False) 405 .MultipleTimes().AndReturn(False)
390 api.neutron.get_feature_permission(IsA(http.HttpRequest), 406 api.neutron.get_feature_permission(IsA(http.HttpRequest),
@@ -423,6 +439,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
423 def test_router_create_post_exception_error_case_409(self): 439 def test_router_create_post_exception_error_case_409(self):
424 router = self.routers.first() 440 router = self.routers.first()
425 api.neutron.get_feature_permission(IsA(http.HttpRequest), 441 api.neutron.get_feature_permission(IsA(http.HttpRequest),
442 "ext-gw-mode",
443 "create_router_enable_snat")\
444 .AndReturn(True)
445 api.neutron.get_feature_permission(IsA(http.HttpRequest),
426 "dvr", "create")\ 446 "dvr", "create")\
427 .MultipleTimes().AndReturn(False) 447 .MultipleTimes().AndReturn(False)
428 api.neutron.get_feature_permission(IsA(http.HttpRequest), 448 api.neutron.get_feature_permission(IsA(http.HttpRequest),
@@ -455,6 +475,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
455 def test_router_create_post_exception_error_case_non_409(self): 475 def test_router_create_post_exception_error_case_non_409(self):
456 router = self.routers.first() 476 router = self.routers.first()
457 api.neutron.get_feature_permission(IsA(http.HttpRequest), 477 api.neutron.get_feature_permission(IsA(http.HttpRequest),
478 "ext-gw-mode",
479 "create_router_enable_snat")\
480 .AndReturn(True)
481 api.neutron.get_feature_permission(IsA(http.HttpRequest),
458 "dvr", "create")\ 482 "dvr", "create")\
459 .MultipleTimes().AndReturn(False) 483 .MultipleTimes().AndReturn(False)
460 api.neutron.get_feature_permission(IsA(http.HttpRequest), 484 api.neutron.get_feature_permission(IsA(http.HttpRequest),
@@ -730,24 +754,34 @@ class RouterActionTests(RouterMixin, test.TestCase):
730 754
731 @test.create_stubs({api.neutron: ('router_get', 755 @test.create_stubs({api.neutron: ('router_get',
732 'router_add_gateway', 756 'router_add_gateway',
733 'network_list')}) 757 'network_list',
758 'is_extension_supported')})
734 def test_router_add_gateway(self): 759 def test_router_add_gateway(self):
735 router = self.routers.first() 760 router = self.routers.first()
736 network = self.networks.first() 761 network = self.networks.first()
737 api.neutron.router_add_gateway( 762 api.neutron.router_add_gateway(
738 IsA(http.HttpRequest), 763 IsA(http.HttpRequest),
739 router.id, 764 router.id,
740 network.id).AndReturn(None) 765 network.id,
766 True).AndReturn(None)
741 api.neutron.router_get( 767 api.neutron.router_get(
742 IsA(http.HttpRequest), router.id).AndReturn(router) 768 IsA(http.HttpRequest), router.id).AndReturn(router)
743 search_opts = {'router:external': True} 769 search_opts = {'router:external': True}
744 api.neutron.network_list( 770 api.neutron.network_list(
745 IsA(http.HttpRequest), **search_opts).AndReturn([network]) 771 IsA(http.HttpRequest), **search_opts).AndReturn([network])
772 api.neutron.is_extension_supported(IsA(http.HttpRequest),
773 'ext-gw-mode')\
774 .AndReturn(True)
775 api.neutron.get_feature_permission(IsA(http.HttpRequest),
776 "ext-gw-mode",
777 "update_router_enable_snat")\
778 .AndReturn(True)
746 self.mox.ReplayAll() 779 self.mox.ReplayAll()
747 780
748 form_data = {'router_id': router.id, 781 form_data = {'router_id': router.id,
749 'router_name': router.name, 782 'router_name': router.name,
750 'network_id': network.id} 783 'network_id': network.id,
784 'enable_snat': True}
751 785
752 url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD, 786 url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
753 args=[router.id]) 787 args=[router.id])
@@ -758,24 +792,34 @@ class RouterActionTests(RouterMixin, test.TestCase):
758 792
759 @test.create_stubs({api.neutron: ('router_get', 793 @test.create_stubs({api.neutron: ('router_get',
760 'router_add_gateway', 794 'router_add_gateway',
761 'network_list')}) 795 'network_list',
796 'is_extension_supported')})
762 def test_router_add_gateway_exception(self): 797 def test_router_add_gateway_exception(self):
763 router = self.routers.first() 798 router = self.routers.first()
764 network = self.networks.first() 799 network = self.networks.first()
765 api.neutron.router_add_gateway( 800 api.neutron.router_add_gateway(
766 IsA(http.HttpRequest), 801 IsA(http.HttpRequest),
767 router.id, 802 router.id,
768 network.id).AndRaise(self.exceptions.neutron) 803 network.id,
804 True).AndRaise(self.exceptions.neutron)
769 api.neutron.router_get( 805 api.neutron.router_get(
770 IsA(http.HttpRequest), router.id).AndReturn(router) 806 IsA(http.HttpRequest), router.id).AndReturn(router)
771 search_opts = {'router:external': True} 807 search_opts = {'router:external': True}
772 api.neutron.network_list( 808 api.neutron.network_list(
773 IsA(http.HttpRequest), **search_opts).AndReturn([network]) 809 IsA(http.HttpRequest), **search_opts).AndReturn([network])
810 api.neutron.is_extension_supported(IsA(http.HttpRequest),
811 'ext-gw-mode')\
812 .AndReturn(True)
813 api.neutron.get_feature_permission(IsA(http.HttpRequest),
814 "ext-gw-mode",
815 "update_router_enable_snat")\
816 .AndReturn(True)
774 self.mox.ReplayAll() 817 self.mox.ReplayAll()
775 818
776 form_data = {'router_id': router.id, 819 form_data = {'router_id': router.id,
777 'router_name': router.name, 820 'router_name': router.name,
778 'network_id': network.id} 821 'network_id': network.id,
822 'enable_snat': True}
779 823
780 url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD, 824 url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
781 args=[router.id]) 825 args=[router.id])
diff --git a/openstack_dashboard/dashboards/project/routers/views.py b/openstack_dashboard/dashboards/project/routers/views.py
index 31b927f..4c428f3 100644
--- a/openstack_dashboard/dashboards/project/routers/views.py
+++ b/openstack_dashboard/dashboards/project/routers/views.py
@@ -180,6 +180,17 @@ class CreateView(forms.ModalFormView):
180 submit_label = _("Create Router") 180 submit_label = _("Create Router")
181 submit_url = reverse_lazy("horizon:project:routers:create") 181 submit_url = reverse_lazy("horizon:project:routers:create")
182 182
183 def get_context_data(self, **kwargs):
184 context = super(CreateView, self).get_context_data(**kwargs)
185 context['enable_snat_allowed'] = self.initial['enable_snat_allowed']
186 return context
187
188 def get_initial(self):
189 enable_snat_allowed = api.neutron.get_feature_permission(
190 self.request, 'ext-gw-mode', 'create_router_enable_snat')
191 self.initial['enable_snat_allowed'] = enable_snat_allowed
192 return super(CreateView, self).get_initial()
193
183 194
184class UpdateView(forms.ModalFormView): 195class UpdateView(forms.ModalFormView):
185 form_class = project_forms.UpdateForm 196 form_class = project_forms.UpdateForm