Browse Source

Implement availability_zone_hints for networks and routers.

Adds an optional parameter to the create_network and
create_router-methods, for use with availability zone-scheduling of
network agents.

Change-Id: Ifb93a10415dc676f5cc56b5315f2dff24fc395b8
Trygve Vea 1 year ago
parent
commit
c9bfc45844

+ 8
- 0
releasenotes/notes/neutron_availability_zone_extension-675c2460ebb50a09.yaml View File

@@ -0,0 +1,8 @@
1
+---
2
+features:
3
+  - |
4
+    availability_zone_hints now accepted for create_network() when
5
+    network_availability_zone extension is enabled on target cloud.
6
+  - |
7
+    availability_zone_hints now accepted for create_router() when
8
+    router_availability_zone extension is enabled on target cloud.

+ 25
- 2
shade/openstackcloud.py View File

@@ -3383,7 +3383,8 @@ class OpenStackCloud(
3383 3383
         return True
3384 3384
 
3385 3385
     def create_network(self, name, shared=False, admin_state_up=True,
3386
-                       external=False, provider=None, project_id=None):
3386
+                       external=False, provider=None, project_id=None,
3387
+                       availability_zone_hints=None):
3387 3388
         """Create a network.
3388 3389
 
3389 3390
         :param string name: Name of the network being created.
@@ -3395,6 +3396,7 @@ class OpenStackCloud(
3395 3396
            { 'network_type': 'vlan', 'segmentation_id': 'vlan1' }
3396 3397
         :param string project_id: Specify the project ID this network
3397 3398
             will be created on (admin-only).
3399
+        :param list availability_zone_hints: A list of availability zone hints.
3398 3400
 
3399 3401
         :returns: The network object.
3400 3402
         :raises: OpenStackCloudException on operation error.
@@ -3410,6 +3412,16 @@ class OpenStackCloud(
3410 3412
         if project_id is not None:
3411 3413
             network['tenant_id'] = project_id
3412 3414
 
3415
+        if availability_zone_hints is not None:
3416
+            if not isinstance(availability_zone_hints, list):
3417
+                raise OpenStackCloudException(
3418
+                    "Parameter 'availability_zone_hints' must be a list")
3419
+            if not self._has_neutron_extension('network_availability_zone'):
3420
+                raise OpenStackCloudUnavailableExtension(
3421
+                    'network_availability_zone extension is not available on '
3422
+                    'target cloud')
3423
+            network['availability_zone_hints'] = availability_zone_hints
3424
+
3413 3425
         if provider:
3414 3426
             if not isinstance(provider, dict):
3415 3427
                 raise OpenStackCloudException(
@@ -4245,7 +4257,8 @@ class OpenStackCloud(
4245 4257
 
4246 4258
     def create_router(self, name=None, admin_state_up=True,
4247 4259
                       ext_gateway_net_id=None, enable_snat=None,
4248
-                      ext_fixed_ips=None, project_id=None):
4260
+                      ext_fixed_ips=None, project_id=None,
4261
+                      availability_zone_hints=None):
4249 4262
         """Create a logical router.
4250 4263
 
4251 4264
         :param string name: The router name.
@@ -4263,6 +4276,7 @@ class OpenStackCloud(
4263 4276
                 }
4264 4277
               ]
4265 4278
         :param string project_id: Project ID for the router.
4279
+        :param list availability_zone_hints: A list of availability zone hints.
4266 4280
 
4267 4281
         :returns: The router object.
4268 4282
         :raises: OpenStackCloudException on operation error.
@@ -4279,6 +4293,15 @@ class OpenStackCloud(
4279 4293
         )
4280 4294
         if ext_gw_info:
4281 4295
             router['external_gateway_info'] = ext_gw_info
4296
+        if availability_zone_hints is not None:
4297
+            if not isinstance(availability_zone_hints, list):
4298
+                raise OpenStackCloudException(
4299
+                    "Parameter 'availability_zone_hints' must be a list")
4300
+            if not self._has_neutron_extension('router_availability_zone'):
4301
+                raise OpenStackCloudUnavailableExtension(
4302
+                    'router_availability_zone extension is not available on '
4303
+                    'target cloud')
4304
+            router['availability_zone_hints'] = availability_zone_hints
4282 4305
 
4283 4306
         data = self._network_client.post(
4284 4307
             "/routers.json", json={"router": router},

+ 40
- 0
shade/tests/unit/test_network.py View File

@@ -47,6 +47,16 @@ class TestNetwork(base.RequestsMockTestCase):
47 47
         'mtu': 0
48 48
     }
49 49
 
50
+    network_availability_zone_extension = {
51
+        "alias": "network_availability_zone",
52
+        "updated": "2015-01-01T10:00:00-00:00",
53
+        "description": "Availability zone support for router.",
54
+        "links": [],
55
+        "name": "Network Availability Zone"
56
+    }
57
+
58
+    enabled_neutron_extensions = [network_availability_zone_extension]
59
+
50 60
     def test_list_networks(self):
51 61
         net1 = {'id': '1', 'name': 'net1'}
52 62
         net2 = {'id': '2', 'name': 'net2'}
@@ -151,6 +161,27 @@ class TestNetwork(base.RequestsMockTestCase):
151 161
         self.assertEqual(mock_new_network_rep, network)
152 162
         self.assert_calls()
153 163
 
164
+    def test_create_network_with_availability_zone_hints(self):
165
+        self.register_uris([
166
+            dict(method='GET',
167
+                 uri=self.get_mock_url(
168
+                     'network', 'public', append=['v2.0', 'extensions.json']),
169
+                 json={'extensions': self.enabled_neutron_extensions}),
170
+            dict(method='POST',
171
+                 uri=self.get_mock_url(
172
+                     'network', 'public', append=['v2.0', 'networks.json']),
173
+                 json={'network': self.mock_new_network_rep},
174
+                 validate=dict(
175
+                     json={'network': {
176
+                         'admin_state_up': True,
177
+                         'name': 'netname',
178
+                         'availability_zone_hints': ['nova']}}))
179
+        ])
180
+        network = self.cloud.create_network("netname",
181
+                                            availability_zone_hints=['nova'])
182
+        self.assertEqual(self.mock_new_network_rep, network)
183
+        self.assert_calls()
184
+
154 185
     def test_create_network_provider_ignored_value(self):
155 186
         provider_opts = {'physical_network': 'mynet',
156 187
                          'network_type': 'vlan',
@@ -180,6 +211,15 @@ class TestNetwork(base.RequestsMockTestCase):
180 211
         self.assertEqual(mock_new_network_rep, network)
181 212
         self.assert_calls()
182 213
 
214
+    def test_create_network_wrong_availability_zone_hints_type(self):
215
+        azh_opts = "invalid"
216
+        with testtools.ExpectedException(
217
+            shade.OpenStackCloudException,
218
+            "Parameter 'availability_zone_hints' must be a list"
219
+        ):
220
+            self.cloud.create_network("netname",
221
+                                      availability_zone_hints=azh_opts)
222
+
183 223
     def test_create_network_provider_wrong_type(self):
184 224
         provider_opts = "invalid"
185 225
         with testtools.ExpectedException(

+ 42
- 0
shade/tests/unit/test_router.py View File

@@ -14,6 +14,7 @@
14 14
 # limitations under the License.
15 15
 
16 16
 import copy
17
+import testtools
17 18
 
18 19
 from shade import exc
19 20
 from shade.tests.unit import base
@@ -52,6 +53,16 @@ class TestRouter(base.RequestsMockTestCase):
52 53
         'request_ids': ['req-f1b0b1b4-ae51-4ef9-b371-0cc3c3402cf7']
53 54
     }
54 55
 
56
+    router_availability_zone_extension = {
57
+        "alias": "router_availability_zone",
58
+        "updated": "2015-01-01T10:00:00-00:00",
59
+        "description": "Availability zone support for router.",
60
+        "links": [],
61
+        "name": "Router Availability Zone"
62
+    }
63
+
64
+    enabled_neutron_extensions = [router_availability_zone_extension]
65
+
55 66
     def test_get_router(self):
56 67
         self.register_uris([
57 68
             dict(method='GET',
@@ -112,6 +123,27 @@ class TestRouter(base.RequestsMockTestCase):
112 123
                                  project_id=new_router_tenant_id)
113 124
         self.assert_calls()
114 125
 
126
+    def test_create_router_with_availability_zone_hints(self):
127
+        self.register_uris([
128
+            dict(method='GET',
129
+                 uri=self.get_mock_url(
130
+                     'network', 'public', append=['v2.0', 'extensions.json']),
131
+                 json={'extensions': self.enabled_neutron_extensions}),
132
+            dict(method='POST',
133
+                 uri=self.get_mock_url(
134
+                     'network', 'public', append=['v2.0', 'routers.json']),
135
+                 json={'router': self.mock_router_rep},
136
+                 validate=dict(
137
+                     json={'router': {
138
+                         'name': self.router_name,
139
+                         'admin_state_up': True,
140
+                         'availability_zone_hints': ['nova']}}))
141
+        ])
142
+        self.cloud.create_router(
143
+            name=self.router_name, admin_state_up=True,
144
+            availability_zone_hints=['nova'])
145
+        self.assert_calls()
146
+
115 147
     def test_create_router_with_enable_snat_True(self):
116 148
         """Do not send enable_snat when same as neutron default."""
117 149
         self.register_uris([
@@ -145,6 +177,16 @@ class TestRouter(base.RequestsMockTestCase):
145 177
             name=self.router_name, admin_state_up=True, enable_snat=False)
146 178
         self.assert_calls()
147 179
 
180
+    def test_create_router_wrong_availability_zone_hints_type(self):
181
+        azh_opts = "invalid"
182
+        with testtools.ExpectedException(
183
+            exc.OpenStackCloudException,
184
+            "Parameter 'availability_zone_hints' must be a list"
185
+        ):
186
+            self.cloud.create_router(
187
+                name=self.router_name, admin_state_up=True,
188
+                availability_zone_hints=azh_opts)
189
+
148 190
     def test_add_router_interface(self):
149 191
         self.register_uris([
150 192
             dict(method='PUT',

Loading…
Cancel
Save