Browse Source

Merge "Add a checkbox to disable SNAT on routers"

Zuul 1 year ago
parent
commit
5d386afb1a

+ 12
- 1
openstack_dashboard/api/neutron.py View File

@@ -1264,8 +1264,10 @@ def router_remove_interface(request, router_id, subnet_id=None, port_id=None):
1264 1264
 
1265 1265
 
1266 1266
 @profiler.trace
1267
-def router_add_gateway(request, router_id, network_id):
1267
+def router_add_gateway(request, router_id, network_id, enable_snat=None):
1268 1268
     body = {'network_id': network_id}
1269
+    if enable_snat is not None:
1270
+        body['enable_snat'] = enable_snat
1269 1271
     neutronclient(request).add_gateway_router(router_id, body)
1270 1272
 
1271 1273
 
@@ -1640,6 +1642,15 @@ FEATURE_MAP = {
1640 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
 

+ 10
- 0
openstack_dashboard/dashboards/project/routers/forms.py View File

@@ -39,6 +39,9 @@ class CreateForm(forms.SelfHandlingForm):
39 39
                                         required=False)
40 40
     external_network = forms.ThemableChoiceField(label=_("External Network"),
41 41
                                                  required=False)
42
+    enable_snat = forms.BooleanField(label=_("Enable SNAT"),
43
+                                     initial=True,
44
+                                     required=False)
42 45
     mode = forms.ChoiceField(label=_("Router Type"))
43 46
     ha = forms.ChoiceField(label=_("High Availability Mode"))
44 47
     az_hints = forms.MultipleChoiceField(
@@ -76,6 +79,10 @@ class CreateForm(forms.SelfHandlingForm):
76 79
         else:
77 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 86
         try:
80 87
             az_supported = api.neutron.is_extension_supported(
81 88
                 self.request, 'router_availability_zone')
@@ -116,6 +123,9 @@ class CreateForm(forms.SelfHandlingForm):
116 123
             if 'external_network' in data and data['external_network']:
117 124
                 params['external_gateway_info'] = {'network_id':
118 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 129
             if 'az_hints' in data and data['az_hints']:
120 130
                 params['availability_zone_hints'] = data['az_hints']
121 131
             if (self.dvr_allowed and data['mode'] != 'server_default'):

+ 18
- 3
openstack_dashboard/dashboards/project/routers/ports/forms.py View File

@@ -145,12 +145,23 @@ class AddInterface(forms.SelfHandlingForm):
145 145
 
146 146
 class SetGatewayForm(forms.SelfHandlingForm):
147 147
     network_id = forms.ThemableChoiceField(label=_("External Network"))
148
+    enable_snat = forms.BooleanField(label=_("Enable SNAT"),
149
+                                     initial=True,
150
+                                     required=False)
148 151
     failure_url = 'horizon:project:routers:index'
149 152
 
150 153
     def __init__(self, request, *args, **kwargs):
151 154
         super(SetGatewayForm, self).__init__(request, *args, **kwargs)
152
-        c = self.populate_network_id_choices(request)
153
-        self.fields['network_id'].choices = c
155
+        networks = self.populate_network_id_choices(request)
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 166
     def populate_network_id_choices(self, request):
156 167
         search_opts = {'router:external': True}
@@ -173,9 +184,13 @@ class SetGatewayForm(forms.SelfHandlingForm):
173 184
 
174 185
     def handle(self, request, data):
175 186
         try:
187
+            enable_snat = None
188
+            if 'enable_snat' in data:
189
+                enable_snat = data['enable_snat']
176 190
             api.neutron.router_add_gateway(request,
177 191
                                            self.initial['router_id'],
178
-                                           data['network_id'])
192
+                                           data['network_id'],
193
+                                           enable_snat)
179 194
             msg = _('Gateway interface is added')
180 195
             messages.success(request, msg)
181 196
             return True

+ 3
- 0
openstack_dashboard/dashboards/project/routers/templates/routers/_create.html View File

@@ -4,4 +4,7 @@
4 4
 {% block modal-body-right %}
5 5
   <h3>{% trans "Description:" %}</h3>
6 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 10
 {% endblock %}

+ 50
- 6
openstack_dashboard/dashboards/project/routers/tests.py View File

@@ -284,6 +284,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
284 284
                                       'is_extension_supported')})
285 285
     def test_router_create_post(self):
286 286
         router = self.routers.first()
287
+        api.neutron.get_feature_permission(IsA(http.HttpRequest),
288
+                                           "ext-gw-mode",
289
+                                           "create_router_enable_snat")\
290
+            .AndReturn(True)
287 291
         api.neutron.get_feature_permission(IsA(http.HttpRequest),
288 292
                                            "dvr", "create")\
289 293
             .AndReturn(False)
@@ -315,6 +319,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
315 319
                                       'is_extension_supported')})
316 320
     def test_router_create_post_mode_server_default(self):
317 321
         router = self.routers.first()
322
+        api.neutron.get_feature_permission(IsA(http.HttpRequest),
323
+                                           "ext-gw-mode",
324
+                                           "create_router_enable_snat")\
325
+            .AndReturn(True)
318 326
         api.neutron.get_feature_permission(IsA(http.HttpRequest),
319 327
                                            "dvr", "create")\
320 328
             .AndReturn(True)
@@ -348,6 +356,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
348 356
                                       'is_extension_supported')})
349 357
     def test_dvr_ha_router_create_post(self):
350 358
         router = self.routers.first()
359
+        api.neutron.get_feature_permission(IsA(http.HttpRequest),
360
+                                           "ext-gw-mode",
361
+                                           "create_router_enable_snat")\
362
+            .AndReturn(True)
351 363
         api.neutron.get_feature_permission(IsA(http.HttpRequest),
352 364
                                            "dvr", "create")\
353 365
             .MultipleTimes().AndReturn(True)
@@ -384,6 +396,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
384 396
                                       'list_availability_zones')})
385 397
     def test_az_router_create_post(self):
386 398
         router = self.routers.first()
399
+        api.neutron.get_feature_permission(IsA(http.HttpRequest),
400
+                                           "ext-gw-mode",
401
+                                           "create_router_enable_snat")\
402
+            .AndReturn(True)
387 403
         api.neutron.get_feature_permission(IsA(http.HttpRequest),
388 404
                                            "dvr", "create")\
389 405
             .MultipleTimes().AndReturn(False)
@@ -422,6 +438,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
422 438
                                       'is_extension_supported')})
423 439
     def test_router_create_post_exception_error_case_409(self):
424 440
         router = self.routers.first()
441
+        api.neutron.get_feature_permission(IsA(http.HttpRequest),
442
+                                           "ext-gw-mode",
443
+                                           "create_router_enable_snat")\
444
+            .AndReturn(True)
425 445
         api.neutron.get_feature_permission(IsA(http.HttpRequest),
426 446
                                            "dvr", "create")\
427 447
             .MultipleTimes().AndReturn(False)
@@ -454,6 +474,10 @@ class RouterActionTests(RouterMixin, test.TestCase):
454 474
                                       'network_list')})
455 475
     def test_router_create_post_exception_error_case_non_409(self):
456 476
         router = self.routers.first()
477
+        api.neutron.get_feature_permission(IsA(http.HttpRequest),
478
+                                           "ext-gw-mode",
479
+                                           "create_router_enable_snat")\
480
+            .AndReturn(True)
457 481
         api.neutron.get_feature_permission(IsA(http.HttpRequest),
458 482
                                            "dvr", "create")\
459 483
             .MultipleTimes().AndReturn(False)
@@ -730,24 +754,34 @@ class RouterActionTests(RouterMixin, test.TestCase):
730 754
 
731 755
     @test.create_stubs({api.neutron: ('router_get',
732 756
                                       'router_add_gateway',
733
-                                      'network_list')})
757
+                                      'network_list',
758
+                                      'is_extension_supported')})
734 759
     def test_router_add_gateway(self):
735 760
         router = self.routers.first()
736 761
         network = self.networks.first()
737 762
         api.neutron.router_add_gateway(
738 763
             IsA(http.HttpRequest),
739 764
             router.id,
740
-            network.id).AndReturn(None)
765
+            network.id,
766
+            True).AndReturn(None)
741 767
         api.neutron.router_get(
742 768
             IsA(http.HttpRequest), router.id).AndReturn(router)
743 769
         search_opts = {'router:external': True}
744 770
         api.neutron.network_list(
745 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 779
         self.mox.ReplayAll()
747 780
 
748 781
         form_data = {'router_id': router.id,
749 782
                      'router_name': router.name,
750
-                     'network_id': network.id}
783
+                     'network_id': network.id,
784
+                     'enable_snat': True}
751 785
 
752 786
         url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
753 787
                       args=[router.id])
@@ -758,24 +792,34 @@ class RouterActionTests(RouterMixin, test.TestCase):
758 792
 
759 793
     @test.create_stubs({api.neutron: ('router_get',
760 794
                                       'router_add_gateway',
761
-                                      'network_list')})
795
+                                      'network_list',
796
+                                      'is_extension_supported')})
762 797
     def test_router_add_gateway_exception(self):
763 798
         router = self.routers.first()
764 799
         network = self.networks.first()
765 800
         api.neutron.router_add_gateway(
766 801
             IsA(http.HttpRequest),
767 802
             router.id,
768
-            network.id).AndRaise(self.exceptions.neutron)
803
+            network.id,
804
+            True).AndRaise(self.exceptions.neutron)
769 805
         api.neutron.router_get(
770 806
             IsA(http.HttpRequest), router.id).AndReturn(router)
771 807
         search_opts = {'router:external': True}
772 808
         api.neutron.network_list(
773 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 817
         self.mox.ReplayAll()
775 818
 
776 819
         form_data = {'router_id': router.id,
777 820
                      'router_name': router.name,
778
-                     'network_id': network.id}
821
+                     'network_id': network.id,
822
+                     'enable_snat': True}
779 823
 
780 824
         url = reverse('horizon:%s:routers:setgateway' % self.DASHBOARD,
781 825
                       args=[router.id])

+ 11
- 0
openstack_dashboard/dashboards/project/routers/views.py View File

@@ -180,6 +180,17 @@ class CreateView(forms.ModalFormView):
180 180
     submit_label = _("Create Router")
181 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
 
184 195
 class UpdateView(forms.ModalFormView):
185 196
     form_class = project_forms.UpdateForm

Loading…
Cancel
Save