Merge "Add network availability zone support"
This commit is contained in:
@@ -4,6 +4,7 @@ Network Resources
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
v2/availability_zone
|
||||||
v2/extension
|
v2/extension
|
||||||
v2/floating_ip
|
v2/floating_ip
|
||||||
v2/health_monitor
|
v2/health_monitor
|
||||||
|
|||||||
12
doc/source/users/resources/network/v2/availability_zone.rst
Normal file
12
doc/source/users/resources/network/v2/availability_zone.rst
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
openstack.network.v2.availability_zone
|
||||||
|
======================================
|
||||||
|
|
||||||
|
.. automodule:: openstack.network.v2.availability_zone
|
||||||
|
|
||||||
|
The AvailabilityZone Class
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The ``AvailabilityZone`` class inherits from :class:`~openstack.resource.Resource`.
|
||||||
|
|
||||||
|
.. autoclass:: openstack.network.v2.availability_zone.AvailabilityZone
|
||||||
|
:members:
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from openstack.network.v2 import availability_zone
|
||||||
from openstack.network.v2 import extension
|
from openstack.network.v2 import extension
|
||||||
from openstack.network.v2 import floating_ip as _floating_ip
|
from openstack.network.v2 import floating_ip as _floating_ip
|
||||||
from openstack.network.v2 import health_monitor as _health_monitor
|
from openstack.network.v2 import health_monitor as _health_monitor
|
||||||
@@ -34,6 +35,15 @@ from openstack import resource
|
|||||||
|
|
||||||
class Proxy(proxy.BaseProxy):
|
class Proxy(proxy.BaseProxy):
|
||||||
|
|
||||||
|
def availability_zones(self):
|
||||||
|
"""Return a generator of availability zones
|
||||||
|
|
||||||
|
:returns: A generator of availability zone objects
|
||||||
|
:rtype:
|
||||||
|
:class:`~openstack.network.v2.availability_zone.AvailabilityZone`
|
||||||
|
"""
|
||||||
|
return self._list(availability_zone.AvailabilityZone, paginated=False)
|
||||||
|
|
||||||
def find_extension(self, name_or_id, ignore_missing=True):
|
def find_extension(self, name_or_id, ignore_missing=True):
|
||||||
"""Find a single extension
|
"""Find a single extension
|
||||||
|
|
||||||
|
|||||||
37
openstack/network/v2/availability_zone.py
Normal file
37
openstack/network/v2/availability_zone.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from openstack.network import network_service
|
||||||
|
from openstack import resource as _resource
|
||||||
|
|
||||||
|
|
||||||
|
class AvailabilityZone(_resource.Resource):
|
||||||
|
resource_key = 'availability_zone'
|
||||||
|
resources_key = 'availability_zones'
|
||||||
|
base_path = '/availability_zones'
|
||||||
|
service = network_service.NetworkService()
|
||||||
|
|
||||||
|
# capabilities
|
||||||
|
allow_create = False
|
||||||
|
allow_retrieve = False
|
||||||
|
allow_update = False
|
||||||
|
allow_delete = False
|
||||||
|
allow_list = True
|
||||||
|
|
||||||
|
# Properties
|
||||||
|
#: Name of the availability zone.
|
||||||
|
name = _resource.prop('name')
|
||||||
|
#: Type of resource for the availability zone, such as ``network``.
|
||||||
|
resource = _resource.prop('resource')
|
||||||
|
#: State of the availability zone, either ``available`` or
|
||||||
|
#: ``unavailable``.
|
||||||
|
state = _resource.prop('state')
|
||||||
@@ -31,6 +31,12 @@ class Network(resource.Resource):
|
|||||||
#: The administrative state of the network, which is up ``True`` or
|
#: The administrative state of the network, which is up ``True`` or
|
||||||
#: down ``False``. *Type: bool*
|
#: down ``False``. *Type: bool*
|
||||||
admin_state_up = resource.prop('admin_state_up', type=bool)
|
admin_state_up = resource.prop('admin_state_up', type=bool)
|
||||||
|
#: Availability zone hints to use when scheduling the network.
|
||||||
|
#: *Type: list of availability zone names*
|
||||||
|
availability_zone_hints = resource.prop('availability_zone_hints')
|
||||||
|
#: Availability zones for the network.
|
||||||
|
#: *Type: list of availability zone names*
|
||||||
|
availability_zones = resource.prop('availability_zones')
|
||||||
#: The network name.
|
#: The network name.
|
||||||
name = resource.prop('name')
|
name = resource.prop('name')
|
||||||
#: The project this network is associated with.
|
#: The project this network is associated with.
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ class Router(resource.Resource):
|
|||||||
#: The administrative state of the router, which is up ``True``
|
#: The administrative state of the router, which is up ``True``
|
||||||
#: or down ``False``. *Type: bool*
|
#: or down ``False``. *Type: bool*
|
||||||
admin_state_up = resource.prop('admin_state_up', type=bool)
|
admin_state_up = resource.prop('admin_state_up', type=bool)
|
||||||
|
#: Availability zone hints to use when scheduling the router.
|
||||||
|
#: *Type: list of availability zone names*
|
||||||
|
availability_zone_hints = resource.prop('availability_zone_hints')
|
||||||
|
#: Availability zones for the router.
|
||||||
|
#: *Type: list of availability zone names*
|
||||||
|
availability_zones = resource.prop('availability_zones')
|
||||||
#: The ``network_id``, for the external gateway. *Type: dict*
|
#: The ``network_id``, for the external gateway. *Type: dict*
|
||||||
external_gateway_info = resource.prop('external_gateway_info', type=dict)
|
external_gateway_info = resource.prop('external_gateway_info', type=dict)
|
||||||
#: The router name.
|
#: The router name.
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from openstack.tests.functional import base
|
||||||
|
|
||||||
|
|
||||||
|
class TestAvailabilityZone(base.BaseFunctionalTest):
|
||||||
|
|
||||||
|
def test_list(self):
|
||||||
|
availability_zones = list(self.conn.network.availability_zones())
|
||||||
|
self.assertGreater(len(availability_zones), 0)
|
||||||
|
|
||||||
|
for az in availability_zones:
|
||||||
|
self.assertIsInstance(az.name, six.string_types)
|
||||||
|
self.assertIsInstance(az.resource, six.string_types)
|
||||||
|
self.assertIsInstance(az.state, six.string_types)
|
||||||
45
openstack/tests/unit/network/v2/test_availability_zone.py
Normal file
45
openstack/tests/unit/network/v2/test_availability_zone.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
from openstack.network.v2 import availability_zone
|
||||||
|
|
||||||
|
IDENTIFIER = 'IDENTIFIER'
|
||||||
|
EXAMPLE = {
|
||||||
|
'id': IDENTIFIER,
|
||||||
|
'name': '1',
|
||||||
|
'resource': '2',
|
||||||
|
'state': '3',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestAvailabilityZone(testtools.TestCase):
|
||||||
|
|
||||||
|
def test_basic(self):
|
||||||
|
sot = availability_zone.AvailabilityZone()
|
||||||
|
self.assertEqual('availability_zone', sot.resource_key)
|
||||||
|
self.assertEqual('availability_zones', sot.resources_key)
|
||||||
|
self.assertEqual('/availability_zones', sot.base_path)
|
||||||
|
self.assertEqual('network', sot.service.service_type)
|
||||||
|
self.assertFalse(sot.allow_create)
|
||||||
|
self.assertFalse(sot.allow_retrieve)
|
||||||
|
self.assertFalse(sot.allow_update)
|
||||||
|
self.assertFalse(sot.allow_delete)
|
||||||
|
self.assertTrue(sot.allow_list)
|
||||||
|
|
||||||
|
def test_make_it(self):
|
||||||
|
sot = availability_zone.AvailabilityZone(EXAMPLE)
|
||||||
|
self.assertEqual(EXAMPLE['id'], sot.id)
|
||||||
|
self.assertEqual(EXAMPLE['name'], sot.name)
|
||||||
|
self.assertEqual(EXAMPLE['resource'], sot.resource)
|
||||||
|
self.assertEqual(EXAMPLE['state'], sot.state)
|
||||||
@@ -30,6 +30,8 @@ EXAMPLE = {
|
|||||||
'subnets': '12',
|
'subnets': '12',
|
||||||
'mtu': 1400,
|
'mtu': 1400,
|
||||||
'port_security_enabled': True,
|
'port_security_enabled': True,
|
||||||
|
'availability_zone_hints': ['15', '16'],
|
||||||
|
'availability_zones': ['16'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -67,6 +69,10 @@ class TestNetwork(testtools.TestCase):
|
|||||||
self.assertEqual(EXAMPLE['mtu'], sot.mtu)
|
self.assertEqual(EXAMPLE['mtu'], sot.mtu)
|
||||||
self.assertEqual(EXAMPLE['port_security_enabled'],
|
self.assertEqual(EXAMPLE['port_security_enabled'],
|
||||||
sot.is_port_security_enabled)
|
sot.is_port_security_enabled)
|
||||||
|
self.assertEqual(EXAMPLE['availability_zone_hints'],
|
||||||
|
sot.availability_zone_hints)
|
||||||
|
self.assertEqual(EXAMPLE['availability_zones'],
|
||||||
|
sot.availability_zones)
|
||||||
|
|
||||||
def test_external(self):
|
def test_external(self):
|
||||||
sot = network.Network(EXAMPLE)
|
sot = network.Network(EXAMPLE)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from openstack.network.v2 import _proxy
|
from openstack.network.v2 import _proxy
|
||||||
|
from openstack.network.v2 import availability_zone
|
||||||
from openstack.network.v2 import extension
|
from openstack.network.v2 import extension
|
||||||
from openstack.network.v2 import floating_ip
|
from openstack.network.v2 import floating_ip
|
||||||
from openstack.network.v2 import health_monitor
|
from openstack.network.v2 import health_monitor
|
||||||
@@ -39,6 +40,11 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase):
|
|||||||
super(TestNetworkProxy, self).setUp()
|
super(TestNetworkProxy, self).setUp()
|
||||||
self.proxy = _proxy.Proxy(self.session)
|
self.proxy = _proxy.Proxy(self.session)
|
||||||
|
|
||||||
|
def test_availability_zones(self):
|
||||||
|
self.verify_list_no_kwargs(self.proxy.availability_zones,
|
||||||
|
availability_zone.AvailabilityZone,
|
||||||
|
paginated=False)
|
||||||
|
|
||||||
def test_extension_find(self):
|
def test_extension_find(self):
|
||||||
self.verify_find(self.proxy.find_extension, extension.Extension)
|
self.verify_find(self.proxy.find_extension, extension.Extension)
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ EXAMPLE = {
|
|||||||
'tenant_id': '5',
|
'tenant_id': '5',
|
||||||
'status': '6',
|
'status': '6',
|
||||||
'routes': [],
|
'routes': [],
|
||||||
|
'availability_zone_hints': [],
|
||||||
|
'availability_zones': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
EXAMPLE_WITH_OPTIONAL = {
|
EXAMPLE_WITH_OPTIONAL = {
|
||||||
@@ -38,6 +40,8 @@ EXAMPLE_WITH_OPTIONAL = {
|
|||||||
'routes': [{'nexthop': '172.24.4.20', 'destination': '10.0.3.1/24'}],
|
'routes': [{'nexthop': '172.24.4.20', 'destination': '10.0.3.1/24'}],
|
||||||
'ha': True,
|
'ha': True,
|
||||||
'distributed': True,
|
'distributed': True,
|
||||||
|
'availability_zone_hints': ['zone-1', 'zone-2'],
|
||||||
|
'availability_zones': ['zone-2'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -67,6 +71,10 @@ class TestRouter(testtools.TestCase):
|
|||||||
self.assertFalse(sot.is_ha)
|
self.assertFalse(sot.is_ha)
|
||||||
self.assertFalse(sot.is_distributed)
|
self.assertFalse(sot.is_distributed)
|
||||||
self.assertEqual(EXAMPLE['routes'], sot.routes)
|
self.assertEqual(EXAMPLE['routes'], sot.routes)
|
||||||
|
self.assertEqual(EXAMPLE['availability_zone_hints'],
|
||||||
|
sot.availability_zone_hints)
|
||||||
|
self.assertEqual(EXAMPLE['availability_zones'],
|
||||||
|
sot.availability_zones)
|
||||||
|
|
||||||
def test_make_it_with_optional(self):
|
def test_make_it_with_optional(self):
|
||||||
sot = router.Router(EXAMPLE_WITH_OPTIONAL)
|
sot = router.Router(EXAMPLE_WITH_OPTIONAL)
|
||||||
@@ -82,6 +90,10 @@ class TestRouter(testtools.TestCase):
|
|||||||
self.assertEqual(EXAMPLE_WITH_OPTIONAL['distributed'],
|
self.assertEqual(EXAMPLE_WITH_OPTIONAL['distributed'],
|
||||||
sot.is_distributed)
|
sot.is_distributed)
|
||||||
self.assertEqual(EXAMPLE_WITH_OPTIONAL['routes'], sot.routes)
|
self.assertEqual(EXAMPLE_WITH_OPTIONAL['routes'], sot.routes)
|
||||||
|
self.assertEqual(EXAMPLE_WITH_OPTIONAL['availability_zone_hints'],
|
||||||
|
sot.availability_zone_hints)
|
||||||
|
self.assertEqual(EXAMPLE_WITH_OPTIONAL['availability_zones'],
|
||||||
|
sot.availability_zones)
|
||||||
|
|
||||||
def test_add_interface(self):
|
def test_add_interface(self):
|
||||||
sot = router.Router(EXAMPLE)
|
sot = router.Router(EXAMPLE)
|
||||||
|
|||||||
@@ -172,6 +172,15 @@ class TestProxyBase(base.TestCase):
|
|||||||
expected_result=["result"],
|
expected_result=["result"],
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
|
def verify_list_no_kwargs(self, test_method, resource_type,
|
||||||
|
paginated=False,
|
||||||
|
mock_method="openstack.proxy.BaseProxy._list"):
|
||||||
|
self._verify2(mock_method, test_method,
|
||||||
|
method_kwargs={},
|
||||||
|
expected_args=[resource_type],
|
||||||
|
expected_kwargs={"paginated": paginated},
|
||||||
|
expected_result=["result"])
|
||||||
|
|
||||||
def verify_update(self, test_method, resource_type,
|
def verify_update(self, test_method, resource_type,
|
||||||
mock_method="openstack.proxy.BaseProxy._update",
|
mock_method="openstack.proxy.BaseProxy._update",
|
||||||
expected_result="result", **kwargs):
|
expected_result="result", **kwargs):
|
||||||
|
|||||||
Reference in New Issue
Block a user