Add methods for logical router management

Adds API methods to list existing routers, create a new logical
router, update an existing router, and delete an existing logical
router by name or UUID.

It is considered an error if more than one router with the same
name exists and you attempt to delete by name.

Also... MOAR TESTS!!! ZOMG

Change-Id: Ie6ea4eb5f2322bdda07e6db87e2cdbabea492ee9
This commit is contained in:
David Shrewsbury 2015-03-24 19:07:31 +00:00
parent e2efb08994
commit ff25b8eb3b
3 changed files with 170 additions and 1 deletions

View File

@ -652,6 +652,15 @@ class OpenStackCloud(object):
return network
return None
def list_routers(self):
return self.neutron_client.list_routers()['routers']
def get_router(self, name_or_id):
for router in self.list_routers():
if name_or_id in (router['id'], router['name']):
return router
return None
# TODO(Shrews): This will eventually need to support tenant ID and
# provider networks, which are admin-level params.
def create_network(self, name, shared=False, admin_state_up=True):
@ -698,6 +707,97 @@ class OpenStackCloud(object):
raise OpenStackCloudException(
"Error in deleting network %s: %s" % (name_or_id, e.message))
def create_router(self, name=None, admin_state_up=True):
"""Create a logical router.
:param name: The router name.
:param admin_state_up: The administrative state of the router.
:returns: The router object.
:raises: OpenStackCloudException on operation error.
"""
neutron = self.neutron_client
router = {
'admin_state_up': admin_state_up
}
if name:
router['name'] = name
try:
new_router = neutron.create_router(dict(router=router))
except Exception as e:
self.log.debug("Router create failed", exc_info=True)
raise OpenStackCloudException(
"Error creating router %s: %s" % (name, e))
# Turns out neutron returns an actual dict, so no need for the
# use of meta.obj_to_dict() here (which would not work against
# a dict).
return new_router['router']
def update_router(self, router_id, name=None, admin_state_up=None):
"""Update an existing logical router.
:param router_id: The router UUID.
:param name: The router name.
:param admin_state_up: The administrative state of the router.
:returns: The router object.
:raises: OpenStackCloudException on operation error.
"""
neutron = self.neutron_client
router = {}
if name:
router['name'] = name
if admin_state_up:
router['admin_state_up'] = admin_state_up
if not router:
self.log.debug("No router data to update")
return
try:
new_router = neutron.update_router(router_id, dict(router=router))
except Exception as e:
self.log.debug("Router update failed", exc_info=True)
raise OpenStackCloudException(
"Error updating router %s: %s" % (name, e))
# Turns out neutron returns an actual dict, so no need for the
# use of meta.obj_to_dict() here (which would not work against
# a dict).
return new_router['router']
def delete_router(self, name_or_id):
"""Delete a logical router.
If a name, instead of a unique UUID, is supplied, it is possible
that we could find more than one matching router since names are
not required to be unique. An error will be raised in this case.
:param name_or_id: Name or ID of the router being deleted.
:raises: OpenStackCloudException on operation error.
"""
neutron = self.neutron_client
routers = []
for router in self.list_routers():
if name_or_id in (router['id'], router['name']):
routers.append(router)
if not routers:
raise OpenStackCloudException(
"Router %s not found." % name_or_id)
if len(routers) > 1:
raise OpenStackCloudException(
"More than one router named %s. Use ID." % name_or_id)
try:
neutron.delete_router(routers[0]['id'])
except Exception as e:
self.log.debug("Router delete failed", exc_info=True)
raise OpenStackCloudException(
"Error deleting router %s: %s" % (name_or_id, e))
def _get_images_from_cloud(self, filter_deleted):
# First, try to actually get images from glance, it's more efficient
images = dict()

View File

@ -12,11 +12,79 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import shade
from shade.tests import base
class TestShade(base.TestCase):
def setUp(self):
super(TestShade, self).setUp()
self.cloud = shade.openstack_cloud()
def test_openstack_cloud(self):
self.assertIsInstance(shade.openstack_cloud(), shade.OpenStackCloud)
self.assertIsInstance(self.cloud, shade.OpenStackCloud)
@mock.patch.object(shade.OpenStackCloud, 'list_routers')
def test_get_router(self, mock_list):
router1 = dict(id='123', name='mickey')
mock_list.return_value = [router1]
r = self.cloud.get_router('mickey')
self.assertIsNotNone(r)
self.assertDictEqual(router1, r)
@mock.patch.object(shade.OpenStackCloud, 'list_routers')
def test_get_router_not_found(self, mock_list):
mock_list.return_value = []
r = self.cloud.get_router('goofy')
self.assertIsNone(r)
@mock.patch.object(shade.OpenStackCloud, 'neutron_client')
def test_create_router(self, mock_client):
self.cloud.create_router(name='goofy', admin_state_up=True)
self.assertTrue(mock_client.create_router.called)
@mock.patch.object(shade.OpenStackCloud, 'neutron_client')
def test_update_router(self, mock_client):
self.cloud.update_router(router_id=123, name='goofy')
self.assertTrue(mock_client.update_router.called)
@mock.patch.object(shade.OpenStackCloud, 'list_routers')
@mock.patch.object(shade.OpenStackCloud, 'neutron_client')
def test_delete_router(self, mock_client, mock_list):
router1 = dict(id='123', name='mickey')
mock_list.return_value = [router1]
self.cloud.delete_router('mickey')
self.assertTrue(mock_client.delete_router.called)
@mock.patch.object(shade.OpenStackCloud, 'list_routers')
@mock.patch.object(shade.OpenStackCloud, 'neutron_client')
def test_delete_router_not_found(self, mock_client, mock_list):
router1 = dict(id='123', name='mickey')
mock_list.return_value = [router1]
self.assertRaises(shade.OpenStackCloudException,
self.cloud.delete_router,
'goofy')
self.assertFalse(mock_client.delete_router.called)
@mock.patch.object(shade.OpenStackCloud, 'list_routers')
@mock.patch.object(shade.OpenStackCloud, 'neutron_client')
def test_delete_router_multiple_found(self, mock_client, mock_list):
router1 = dict(id='123', name='mickey')
router2 = dict(id='456', name='mickey')
mock_list.return_value = [router1, router2]
self.assertRaises(shade.OpenStackCloudException,
self.cloud.delete_router,
'mickey')
self.assertFalse(mock_client.delete_router.called)
@mock.patch.object(shade.OpenStackCloud, 'list_routers')
@mock.patch.object(shade.OpenStackCloud, 'neutron_client')
def test_delete_router_multiple_using_id(self, mock_client, mock_list):
router1 = dict(id='123', name='mickey')
router2 = dict(id='456', name='mickey')
mock_list.return_value = [router1, router2]
self.cloud.delete_router('123')
self.assertTrue(mock_client.delete_router.called)

View File

@ -3,6 +3,7 @@ hacking>=0.5.6,<0.8
coverage>=3.6
discover
fixtures>=0.3.14
mock>=1.0
python-subunit
sphinx>=1.1.2
oslo.sphinx