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:
parent
e2efb08994
commit
ff25b8eb3b
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user