summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-06-15 21:12:47 +0000
committerGerrit Code Review <review@openstack.org>2017-06-15 21:12:47 +0000
commiteb4ffe1010f719ee420c2c4834fabe688e407a00 (patch)
tree569b309236c5e4061c7f5944813ac046bbd5f7f6
parent512c8d0721c870c7235bdc5ef8e2a52f5048d0ca (diff)
parent00e088b8307e4aac4be2c86d33571c64a7d56e4b (diff)
Merge "Reject REST API operations on L3 resources owned by ASR1k L3 router plugin"
-rw-r--r--networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py34
-rw-r--r--networking_cisco/tests/unit/cisco/l3/test_ha_l3_router_appliance_plugin.py29
-rw-r--r--networking_cisco/tests/unit/cisco/l3/test_l3_router_appliance_plugin.py36
3 files changed, 70 insertions, 29 deletions
diff --git a/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py b/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py
index 60e401f..ca191cf 100644
--- a/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py
+++ b/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py
@@ -13,6 +13,7 @@
13# under the License. 13# under the License.
14 14
15import copy 15import copy
16import inspect
16import os 17import os
17import subprocess 18import subprocess
18 19
@@ -105,6 +106,11 @@ class RouterBindingInfoError(n_exc.NeutronException):
105 message = _("Could not get binding information for router %(router_id)s.") 106 message = _("Could not get binding information for router %(router_id)s.")
106 107
107 108
109class PluginManagedRouterError(n_exc.NotAuthorized):
110 message = _("Router %(router_id)s is managed by the L3 router service "
111 "plugin and cannot be modified by users (including admins).")
112
113
108class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin): 114class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
109 """Mixin class implementing Neutron's routing service using appliances.""" 115 """Mixin class implementing Neutron's routing service using appliances."""
110 116
@@ -231,6 +237,7 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
231 return router_created 237 return router_created
232 238
233 def update_router(self, context, id, router): 239 def update_router(self, context, id, router):
240 self._validate_caller(context, id)
234 router_type_id = self.get_router_type_id(context, id) 241 router_type_id = self.get_router_type_id(context, id)
235 driver = self._get_router_type_driver(context, 242 driver = self._get_router_type_driver(context,
236 router_type_id) 243 router_type_id)
@@ -333,6 +340,11 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
333 340
334 def delete_router(self, context, router_id, unschedule=True): 341 def delete_router(self, context, router_id, unschedule=True):
335 try: 342 try:
343 self._validate_caller(context, router_id)
344 except RouterBindingInfoError:
345 LOG.debug('Router %s to be deleted has no binding information '
346 'so assuming it is a regular router')
347 try:
336 router_db = self._ensure_router_not_in_use(context, router_id) 348 router_db = self._ensure_router_not_in_use(context, router_id)
337 except sa_exc.InvalidRequestError: 349 except sa_exc.InvalidRequestError:
338 # Perform router deletion for a partially failed router creation 350 # Perform router deletion for a partially failed router creation
@@ -397,8 +409,14 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
397 if is_ha: 409 if is_ha:
398 # process any HA 410 # process any HA
399 self._delete_redundancy_routers(context, router_db) 411 self._delete_redundancy_routers(context, router_db)
400 super(L3RouterApplianceDBMixin, self).delete_router(context, 412 try:
401 router_id) 413 super(L3RouterApplianceDBMixin, self).delete_router(context,
414 router_id)
415 except l3.RouterNotFound as e:
416 LOG.debug('Ignorable error: %(err)s as it only indicates that '
417 'router was already concurrently deleted just '
418 'before this deletion attempt', {'err': e})
419 return
402 if driver: 420 if driver:
403 driver.delete_router_postcommit(context, router_ctxt) 421 driver.delete_router_postcommit(context, router_ctxt)
404 except n_exc.NeutronException: 422 except n_exc.NeutronException:
@@ -425,6 +443,7 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
425 {'router_interface': router_interface_info}) 443 {'router_interface': router_interface_info})
426 444
427 def add_router_interface(self, context, router_id, interface_info): 445 def add_router_interface(self, context, router_id, interface_info):
446 self._validate_caller(context, router_id)
428 router_type_id = self.get_router_type_id(context, router_id) 447 router_type_id = self.get_router_type_id(context, router_id)
429 r_hd_binding_db = self._get_router_binding_info(context.elevated(), 448 r_hd_binding_db = self._get_router_binding_info(context.elevated(),
430 router_id) 449 router_id)
@@ -484,6 +503,7 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
484 port_subnet_id) 503 port_subnet_id)
485 504
486 def remove_router_interface(self, context, router_id, interface_info): 505 def remove_router_interface(self, context, router_id, interface_info):
506 self._validate_caller(context, router_id)
487 remove_by_port, remove_by_subnet = self._validate_interface_info( 507 remove_by_port, remove_by_subnet = self._validate_interface_info(
488 interface_info, for_removal=True) 508 interface_info, for_removal=True)
489 e_context = context.elevated() 509 e_context = context.elevated()
@@ -528,6 +548,16 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin):
528 driver.remove_router_interface_postcommit(context, port_ctxt) 548 driver.remove_router_interface_postcommit(context, port_ctxt)
529 return info 549 return info
530 550
551 def _validate_caller(self, context, router_id):
552 frm = inspect.stack()[2]
553 module_name = inspect.getmodule(frm[0]).__name__
554 role = self._get_router_binding_info(context.elevated(),
555 router_id).role
556 if module_name.endswith('api.v2.base') and role is not None:
557 # nobody, not even admins are allowed to operate directly on
558 # HA redundancy routers or Global routers
559 raise PluginManagedRouterError(router_id=router_id)
560
531 @property 561 @property
532 def is_gbp_workflow(self): 562 def is_gbp_workflow(self):
533 """Determine if Group Based Policy service plugin is used. 563 """Determine if Group Based Policy service plugin is used.
diff --git a/networking_cisco/tests/unit/cisco/l3/test_ha_l3_router_appliance_plugin.py b/networking_cisco/tests/unit/cisco/l3/test_ha_l3_router_appliance_plugin.py
index aa2d1d2..c85c2e7 100644
--- a/networking_cisco/tests/unit/cisco/l3/test_ha_l3_router_appliance_plugin.py
+++ b/networking_cisco/tests/unit/cisco/l3/test_ha_l3_router_appliance_plugin.py
@@ -1436,21 +1436,13 @@ class HAL3RouterApplianceVMTestCase(
1436 routes1 = [{'destination': '135.207.0.0/16', 'nexthop': '10.0.1.199'}, 1436 routes1 = [{'destination': '135.207.0.0/16', 'nexthop': '10.0.1.199'},
1437 {'destination': '12.0.0.0/8', 'nexthop': '10.0.1.200'}, 1437 {'destination': '12.0.0.0/8', 'nexthop': '10.0.1.200'},
1438 {'destination': '141.212.0.0/16', 'nexthop': '10.0.1.201'}] 1438 {'destination': '141.212.0.0/16', 'nexthop': '10.0.1.201'}]
1439 routes2 = [{'destination': '155.210.0.0/28', 'nexthop': '11.0.1.199'},
1440 {'destination': '130.238.5.0/24', 'nexthop': '11.0.1.199'}]
1441 with self.router() as router,\ 1439 with self.router() as router,\
1442 self.subnet(cidr='10.0.1.0/24') as subnet1,\ 1440 self.subnet(cidr='10.0.1.0/24') as subnet1,\
1443 self.subnet(cidr='11.0.1.0/24') as subnet2,\ 1441 self.port(subnet=subnet1) as port1:
1444 self.port(subnet=subnet1) as port1,\
1445 self.port(subnet=subnet2) as port2:
1446 r = router['router'] 1442 r = router['router']
1447 p1 = port1['port'] 1443 p1 = port1['port']
1448 p2 = port2['port']
1449 updated_r = self._routes_update_prepare(r['id'], None, p1['id'], 1444 updated_r = self._routes_update_prepare(r['id'], None, p1['id'],
1450 routes1)['router'] 1445 routes1)['router']
1451 rr1_id = r[ha.DETAILS][ha.REDUNDANCY_ROUTERS][0]['id']
1452 updated_rr1 = self._rr_routes_update_prepare(
1453 r['id'], None, p2['id'], rr1_id, routes2)['router']
1454 params = "id=%s" % r[ha.DETAILS][ha.REDUNDANCY_ROUTERS][1]['id'] 1446 params = "id=%s" % r[ha.DETAILS][ha.REDUNDANCY_ROUTERS][1]['id']
1455 routers = self._list('routers', query_params=params)['routers'] 1447 routers = self._list('routers', query_params=params)['routers']
1456 routers.append(updated_r) 1448 routers.append(updated_r)
@@ -1458,10 +1450,6 @@ class HAL3RouterApplianceVMTestCase(
1458 for router in routers: 1450 for router in routers:
1459 self.assertEqual(_sort_routes(router['routes']), 1451 self.assertEqual(_sort_routes(router['routes']),
1460 correct_routes1) 1452 correct_routes1)
1461 routes1.extend(routes2)
1462 self.assertEqual(_sort_routes(updated_rr1['routes']),
1463 _sort_routes(routes1))
1464 self._rr_routes_update_cleanup(p2['id'], None, r['id'], rr1_id, [])
1465 self._routes_update_cleanup(p1['id'], None, r['id'], []) 1453 self._routes_update_cleanup(p1['id'], None, r['id'], [])
1466 1454
1467 def test_router_update_change_name_changes_redundancy_routers(self): 1455 def test_router_update_change_name_changes_redundancy_routers(self):
@@ -1662,21 +1650,13 @@ class L3CfgAgentHARouterApplianceTestCase(
1662 routes1 = [{'destination': '135.207.0.0/16', 'nexthop': '10.0.1.199'}, 1650 routes1 = [{'destination': '135.207.0.0/16', 'nexthop': '10.0.1.199'},
1663 {'destination': '12.0.0.0/8', 'nexthop': '10.0.1.200'}, 1651 {'destination': '12.0.0.0/8', 'nexthop': '10.0.1.200'},
1664 {'destination': '141.212.0.0/16', 'nexthop': '10.0.1.201'}] 1652 {'destination': '141.212.0.0/16', 'nexthop': '10.0.1.201'}]
1665 routes2 = [{'destination': '155.210.0.0/28', 'nexthop': '11.0.1.202'},
1666 {'destination': '130.238.5.0/24', 'nexthop': '11.0.1.202'}]
1667 with self.router() as router,\ 1653 with self.router() as router,\
1668 self.subnet(cidr='10.0.1.0/24') as subnet1,\ 1654 self.subnet(cidr='10.0.1.0/24') as subnet1,\
1669 self.subnet(cidr='11.0.1.0/24') as subnet2,\ 1655 self.port(subnet=subnet1) as port1:
1670 self.port(subnet=subnet1) as port1,\
1671 self.port(subnet=subnet2) as port2:
1672 r = router['router'] 1656 r = router['router']
1673 p1 = port1['port'] 1657 p1 = port1['port']
1674 p2 = port2['port']
1675 self._routes_update_prepare(r['id'], None, p1['id'], r['id'], 1658 self._routes_update_prepare(r['id'], None, p1['id'], r['id'],
1676 routes1) 1659 routes1)
1677 rr1_id = r[ha.DETAILS][ha.REDUNDANCY_ROUTERS][0]['id']
1678 self._routes_update_prepare(r['id'], None, p2['id'], rr1_id,
1679 routes2)
1680 router_ids = [r['id'], 1660 router_ids = [r['id'],
1681 r[ha.DETAILS][ha.REDUNDANCY_ROUTERS][1]['id']] 1661 r[ha.DETAILS][ha.REDUNDANCY_ROUTERS][1]['id']]
1682 e_context = bc.context.get_admin_context() 1662 e_context = bc.context.get_admin_context()
@@ -1686,11 +1666,6 @@ class L3CfgAgentHARouterApplianceTestCase(
1686 for router in routers: 1666 for router in routers:
1687 self.assertEqual(_sort_routes(router['routes']), 1667 self.assertEqual(_sort_routes(router['routes']),
1688 correct_routes1) 1668 correct_routes1)
1689 routers = self.l3_plugin.get_sync_data_ext(e_context, [rr1_id])
1690 routes1.extend(routes2)
1691 self.assertEqual(_sort_routes(routers[0]['routes']),
1692 _sort_routes(routes1))
1693 self._routes_update_cleanup(p2['id'], None, r['id'], rr1_id, [])
1694 self._routes_update_cleanup(p1['id'], None, r['id'], r['id'], []) 1669 self._routes_update_cleanup(p1['id'], None, r['id'], r['id'], [])
1695 1670
1696 def test_l3_cfg_agent_query_ha_router_with_fips(self): 1671 def test_l3_cfg_agent_query_ha_router_with_fips(self):
diff --git a/networking_cisco/tests/unit/cisco/l3/test_l3_router_appliance_plugin.py b/networking_cisco/tests/unit/cisco/l3/test_l3_router_appliance_plugin.py
index 3113428..1e48729 100644
--- a/networking_cisco/tests/unit/cisco/l3/test_l3_router_appliance_plugin.py
+++ b/networking_cisco/tests/unit/cisco/l3/test_l3_router_appliance_plugin.py
@@ -33,6 +33,7 @@ from oslo_db import exception as db_exc
33from oslo_utils import uuidutils 33from oslo_utils import uuidutils
34import six 34import six
35from sqlalchemy import exc as inner_db_exc 35from sqlalchemy import exc as inner_db_exc
36from webob import exc
36 37
37from networking_cisco._i18n import _ 38from networking_cisco._i18n import _
38from networking_cisco import backwards_compatibility as bc 39from networking_cisco import backwards_compatibility as bc
@@ -553,6 +554,41 @@ class L3RouterApplianceNamespaceTestCase(
553 'test_router_update_gateway_to_empty_with_existed_floatingip', 1, 554 'test_router_update_gateway_to_empty_with_existed_floatingip', 1,
554 1) 555 1)
555 556
557 def _test_rest_api_operations_denied_for_plugin_managed_router(
558 self, func, *args, **kwargs):
559 with mock.patch.object(self.l3_plugin, '_get_router_binding_info',
560 return_value=lambda: None) as m:
561 # for now operations on routers of any role != None are not
562 # permitted for anyone but the l3plugin itself
563 setattr(m.return_value, 'role', 'some_role')
564 func(*args, **kwargs)
565
566 def test_router_update_denied_for_plugin_managed_router(self):
567 with self.router() as router:
568 self._test_rest_api_operations_denied_for_plugin_managed_router(
569 self._update, 'routers', router['router']['id'],
570 {'router': {'name': 'new_name'}},
571 expected_code=exc.HTTPForbidden.code)
572
573 def test_router_delete_denied_for_plugin_managed_router(self):
574 with self.router() as router:
575 self._test_rest_api_operations_denied_for_plugin_managed_router(
576 self._delete, 'routers', router['router']['id'],
577 expected_code=exc.HTTPForbidden.code)
578
579 def test_router_interface_add_denied_for_plugin_managed_router(self):
580 with self.router() as router:
581 self._test_rest_api_operations_denied_for_plugin_managed_router(
582 self._router_interface_action, 'add', router['router']['id'],
583 'some_subnet_id', None, expected_code=exc.HTTPForbidden.code)
584
585 def router_interface_remove_denied_for_plugin_managed_router(self):
586 with self.router() as router:
587 self._test_rest_api_operations_denied_for_plugin_managed_router(
588 self._router_interface_action, 'remove',
589 router['router']['id'], 'some_subnet_id', None,
590 expected_code=exc.HTTPForbidden.code)
591
556 592
557class L3RouterApplianceVMTestCase(L3RouterApplianceNamespaceTestCase): 593class L3RouterApplianceVMTestCase(L3RouterApplianceNamespaceTestCase):
558 594