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
This commit is contained in:
Trygve Vea 2017-11-21 19:58:18 +01:00
parent 395d927081
commit c9bfc45844
4 changed files with 115 additions and 2 deletions

View File

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

View File

@ -3383,7 +3383,8 @@ class OpenStackCloud(
return True
def create_network(self, name, shared=False, admin_state_up=True,
external=False, provider=None, project_id=None):
external=False, provider=None, project_id=None,
availability_zone_hints=None):
"""Create a network.
:param string name: Name of the network being created.
@ -3395,6 +3396,7 @@ class OpenStackCloud(
{ 'network_type': 'vlan', 'segmentation_id': 'vlan1' }
:param string project_id: Specify the project ID this network
will be created on (admin-only).
:param list availability_zone_hints: A list of availability zone hints.
:returns: The network object.
:raises: OpenStackCloudException on operation error.
@ -3410,6 +3412,16 @@ class OpenStackCloud(
if project_id is not None:
network['tenant_id'] = project_id
if availability_zone_hints is not None:
if not isinstance(availability_zone_hints, list):
raise OpenStackCloudException(
"Parameter 'availability_zone_hints' must be a list")
if not self._has_neutron_extension('network_availability_zone'):
raise OpenStackCloudUnavailableExtension(
'network_availability_zone extension is not available on '
'target cloud')
network['availability_zone_hints'] = availability_zone_hints
if provider:
if not isinstance(provider, dict):
raise OpenStackCloudException(
@ -4245,7 +4257,8 @@ class OpenStackCloud(
def create_router(self, name=None, admin_state_up=True,
ext_gateway_net_id=None, enable_snat=None,
ext_fixed_ips=None, project_id=None):
ext_fixed_ips=None, project_id=None,
availability_zone_hints=None):
"""Create a logical router.
:param string name: The router name.
@ -4263,6 +4276,7 @@ class OpenStackCloud(
}
]
:param string project_id: Project ID for the router.
:param list availability_zone_hints: A list of availability zone hints.
:returns: The router object.
:raises: OpenStackCloudException on operation error.
@ -4279,6 +4293,15 @@ class OpenStackCloud(
)
if ext_gw_info:
router['external_gateway_info'] = ext_gw_info
if availability_zone_hints is not None:
if not isinstance(availability_zone_hints, list):
raise OpenStackCloudException(
"Parameter 'availability_zone_hints' must be a list")
if not self._has_neutron_extension('router_availability_zone'):
raise OpenStackCloudUnavailableExtension(
'router_availability_zone extension is not available on '
'target cloud')
router['availability_zone_hints'] = availability_zone_hints
data = self._network_client.post(
"/routers.json", json={"router": router},

View File

@ -47,6 +47,16 @@ class TestNetwork(base.RequestsMockTestCase):
'mtu': 0
}
network_availability_zone_extension = {
"alias": "network_availability_zone",
"updated": "2015-01-01T10:00:00-00:00",
"description": "Availability zone support for router.",
"links": [],
"name": "Network Availability Zone"
}
enabled_neutron_extensions = [network_availability_zone_extension]
def test_list_networks(self):
net1 = {'id': '1', 'name': 'net1'}
net2 = {'id': '2', 'name': 'net2'}
@ -151,6 +161,27 @@ class TestNetwork(base.RequestsMockTestCase):
self.assertEqual(mock_new_network_rep, network)
self.assert_calls()
def test_create_network_with_availability_zone_hints(self):
self.register_uris([
dict(method='GET',
uri=self.get_mock_url(
'network', 'public', append=['v2.0', 'extensions.json']),
json={'extensions': self.enabled_neutron_extensions}),
dict(method='POST',
uri=self.get_mock_url(
'network', 'public', append=['v2.0', 'networks.json']),
json={'network': self.mock_new_network_rep},
validate=dict(
json={'network': {
'admin_state_up': True,
'name': 'netname',
'availability_zone_hints': ['nova']}}))
])
network = self.cloud.create_network("netname",
availability_zone_hints=['nova'])
self.assertEqual(self.mock_new_network_rep, network)
self.assert_calls()
def test_create_network_provider_ignored_value(self):
provider_opts = {'physical_network': 'mynet',
'network_type': 'vlan',
@ -180,6 +211,15 @@ class TestNetwork(base.RequestsMockTestCase):
self.assertEqual(mock_new_network_rep, network)
self.assert_calls()
def test_create_network_wrong_availability_zone_hints_type(self):
azh_opts = "invalid"
with testtools.ExpectedException(
shade.OpenStackCloudException,
"Parameter 'availability_zone_hints' must be a list"
):
self.cloud.create_network("netname",
availability_zone_hints=azh_opts)
def test_create_network_provider_wrong_type(self):
provider_opts = "invalid"
with testtools.ExpectedException(

View File

@ -14,6 +14,7 @@
# limitations under the License.
import copy
import testtools
from shade import exc
from shade.tests.unit import base
@ -52,6 +53,16 @@ class TestRouter(base.RequestsMockTestCase):
'request_ids': ['req-f1b0b1b4-ae51-4ef9-b371-0cc3c3402cf7']
}
router_availability_zone_extension = {
"alias": "router_availability_zone",
"updated": "2015-01-01T10:00:00-00:00",
"description": "Availability zone support for router.",
"links": [],
"name": "Router Availability Zone"
}
enabled_neutron_extensions = [router_availability_zone_extension]
def test_get_router(self):
self.register_uris([
dict(method='GET',
@ -112,6 +123,27 @@ class TestRouter(base.RequestsMockTestCase):
project_id=new_router_tenant_id)
self.assert_calls()
def test_create_router_with_availability_zone_hints(self):
self.register_uris([
dict(method='GET',
uri=self.get_mock_url(
'network', 'public', append=['v2.0', 'extensions.json']),
json={'extensions': self.enabled_neutron_extensions}),
dict(method='POST',
uri=self.get_mock_url(
'network', 'public', append=['v2.0', 'routers.json']),
json={'router': self.mock_router_rep},
validate=dict(
json={'router': {
'name': self.router_name,
'admin_state_up': True,
'availability_zone_hints': ['nova']}}))
])
self.cloud.create_router(
name=self.router_name, admin_state_up=True,
availability_zone_hints=['nova'])
self.assert_calls()
def test_create_router_with_enable_snat_True(self):
"""Do not send enable_snat when same as neutron default."""
self.register_uris([
@ -145,6 +177,16 @@ class TestRouter(base.RequestsMockTestCase):
name=self.router_name, admin_state_up=True, enable_snat=False)
self.assert_calls()
def test_create_router_wrong_availability_zone_hints_type(self):
azh_opts = "invalid"
with testtools.ExpectedException(
exc.OpenStackCloudException,
"Parameter 'availability_zone_hints' must be a list"
):
self.cloud.create_router(
name=self.router_name, admin_state_up=True,
availability_zone_hints=azh_opts)
def test_add_router_interface(self):
self.register_uris([
dict(method='PUT',