summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--releasenotes/notes/neutron_availability_zone_extension-675c2460ebb50a09.yaml8
-rw-r--r--shade/openstackcloud.py27
-rw-r--r--shade/tests/unit/test_network.py40
-rw-r--r--shade/tests/unit/test_router.py42
4 files changed, 115 insertions, 2 deletions
diff --git a/releasenotes/notes/neutron_availability_zone_extension-675c2460ebb50a09.yaml b/releasenotes/notes/neutron_availability_zone_extension-675c2460ebb50a09.yaml
new file mode 100644
index 0000000..80e52f3
--- /dev/null
+++ b/releasenotes/notes/neutron_availability_zone_extension-675c2460ebb50a09.yaml
@@ -0,0 +1,8 @@
1---
2features:
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.
diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py
index 651dc0d..3a0ad86 100644
--- a/shade/openstackcloud.py
+++ b/shade/openstackcloud.py
@@ -3383,7 +3383,8 @@ class OpenStackCloud(
3383 return True 3383 return True
3384 3384
3385 def create_network(self, name, shared=False, admin_state_up=True, 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 """Create a network. 3388 """Create a network.
3388 3389
3389 :param string name: Name of the network being created. 3390 :param string name: Name of the network being created.
@@ -3395,6 +3396,7 @@ class OpenStackCloud(
3395 { 'network_type': 'vlan', 'segmentation_id': 'vlan1' } 3396 { 'network_type': 'vlan', 'segmentation_id': 'vlan1' }
3396 :param string project_id: Specify the project ID this network 3397 :param string project_id: Specify the project ID this network
3397 will be created on (admin-only). 3398 will be created on (admin-only).
3399 :param list availability_zone_hints: A list of availability zone hints.
3398 3400
3399 :returns: The network object. 3401 :returns: The network object.
3400 :raises: OpenStackCloudException on operation error. 3402 :raises: OpenStackCloudException on operation error.
@@ -3410,6 +3412,16 @@ class OpenStackCloud(
3410 if project_id is not None: 3412 if project_id is not None:
3411 network['tenant_id'] = project_id 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 if provider: 3425 if provider:
3414 if not isinstance(provider, dict): 3426 if not isinstance(provider, dict):
3415 raise OpenStackCloudException( 3427 raise OpenStackCloudException(
@@ -4245,7 +4257,8 @@ class OpenStackCloud(
4245 4257
4246 def create_router(self, name=None, admin_state_up=True, 4258 def create_router(self, name=None, admin_state_up=True,
4247 ext_gateway_net_id=None, enable_snat=None, 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 """Create a logical router. 4262 """Create a logical router.
4250 4263
4251 :param string name: The router name. 4264 :param string name: The router name.
@@ -4263,6 +4276,7 @@ class OpenStackCloud(
4263 } 4276 }
4264 ] 4277 ]
4265 :param string project_id: Project ID for the router. 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 :returns: The router object. 4281 :returns: The router object.
4268 :raises: OpenStackCloudException on operation error. 4282 :raises: OpenStackCloudException on operation error.
@@ -4279,6 +4293,15 @@ class OpenStackCloud(
4279 ) 4293 )
4280 if ext_gw_info: 4294 if ext_gw_info:
4281 router['external_gateway_info'] = ext_gw_info 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 data = self._network_client.post( 4306 data = self._network_client.post(
4284 "/routers.json", json={"router": router}, 4307 "/routers.json", json={"router": router},
diff --git a/shade/tests/unit/test_network.py b/shade/tests/unit/test_network.py
index 96af721..bf7275d 100644
--- a/shade/tests/unit/test_network.py
+++ b/shade/tests/unit/test_network.py
@@ -47,6 +47,16 @@ class TestNetwork(base.RequestsMockTestCase):
47 'mtu': 0 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 def test_list_networks(self): 60 def test_list_networks(self):
51 net1 = {'id': '1', 'name': 'net1'} 61 net1 = {'id': '1', 'name': 'net1'}
52 net2 = {'id': '2', 'name': 'net2'} 62 net2 = {'id': '2', 'name': 'net2'}
@@ -151,6 +161,27 @@ class TestNetwork(base.RequestsMockTestCase):
151 self.assertEqual(mock_new_network_rep, network) 161 self.assertEqual(mock_new_network_rep, network)
152 self.assert_calls() 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 def test_create_network_provider_ignored_value(self): 185 def test_create_network_provider_ignored_value(self):
155 provider_opts = {'physical_network': 'mynet', 186 provider_opts = {'physical_network': 'mynet',
156 'network_type': 'vlan', 187 'network_type': 'vlan',
@@ -180,6 +211,15 @@ class TestNetwork(base.RequestsMockTestCase):
180 self.assertEqual(mock_new_network_rep, network) 211 self.assertEqual(mock_new_network_rep, network)
181 self.assert_calls() 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 def test_create_network_provider_wrong_type(self): 223 def test_create_network_provider_wrong_type(self):
184 provider_opts = "invalid" 224 provider_opts = "invalid"
185 with testtools.ExpectedException( 225 with testtools.ExpectedException(
diff --git a/shade/tests/unit/test_router.py b/shade/tests/unit/test_router.py
index f969b90..ee5f20f 100644
--- a/shade/tests/unit/test_router.py
+++ b/shade/tests/unit/test_router.py
@@ -14,6 +14,7 @@
14# limitations under the License. 14# limitations under the License.
15 15
16import copy 16import copy
17import testtools
17 18
18from shade import exc 19from shade import exc
19from shade.tests.unit import base 20from shade.tests.unit import base
@@ -52,6 +53,16 @@ class TestRouter(base.RequestsMockTestCase):
52 'request_ids': ['req-f1b0b1b4-ae51-4ef9-b371-0cc3c3402cf7'] 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 def test_get_router(self): 66 def test_get_router(self):
56 self.register_uris([ 67 self.register_uris([
57 dict(method='GET', 68 dict(method='GET',
@@ -112,6 +123,27 @@ class TestRouter(base.RequestsMockTestCase):
112 project_id=new_router_tenant_id) 123 project_id=new_router_tenant_id)
113 self.assert_calls() 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 def test_create_router_with_enable_snat_True(self): 147 def test_create_router_with_enable_snat_True(self):
116 """Do not send enable_snat when same as neutron default.""" 148 """Do not send enable_snat when same as neutron default."""
117 self.register_uris([ 149 self.register_uris([
@@ -145,6 +177,16 @@ class TestRouter(base.RequestsMockTestCase):
145 name=self.router_name, admin_state_up=True, enable_snat=False) 177 name=self.router_name, admin_state_up=True, enable_snat=False)
146 self.assert_calls() 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 def test_add_router_interface(self): 190 def test_add_router_interface(self):
149 self.register_uris([ 191 self.register_uris([
150 dict(method='PUT', 192 dict(method='PUT',