From aea4f266ee166730e65f2292c072096b738b96d6 Mon Sep 17 00:00:00 2001 From: Michael Johnson Date: Tue, 20 Jun 2017 14:35:01 -0700 Subject: [PATCH] Add RBAC enforcement to health monitors v2 API This patch adds policies and enforcement to the Octavia v2 API for health monitors. Change-Id: I5bd48b0f451b1543fd9710c949d44d2c159ef91f Partial-Bug: #1690481 --- octavia/api/v2/controllers/health_monitor.py | 55 ++- octavia/common/constants.py | 1 + octavia/policies/__init__.py | 2 + octavia/policies/healthmonitor.py | 67 ++++ .../functional/api/v2/test_health_monitor.py | 359 +++++++++++++++++- 5 files changed, 476 insertions(+), 8 deletions(-) create mode 100644 octavia/policies/healthmonitor.py diff --git a/octavia/api/v2/controllers/health_monitor.py b/octavia/api/v2/controllers/health_monitor.py index 2feeb810ce..16b99b67cc 100644 --- a/octavia/api/v2/controllers/health_monitor.py +++ b/octavia/api/v2/controllers/health_monitor.py @@ -58,6 +58,13 @@ class HealthMonitorController(base.BaseController): """Gets a single healthmonitor's details.""" context = pecan.request.context.get('octavia_context') db_hm = self._get_db_hm(context.session, id) + + # Check that the user is authorized to show this health monitor + action = '{rbac_obj}{action}'.format( + rbac_obj=constants.RBAC_HEALTHMONITOR, action='get_one') + target = {'project_id': db_hm.project_id} + context.policy.authorize(action, target) + result = self._convert_db_to_type( db_hm, hm_types.HealthMonitorResponse) return hm_types.HealthMonitorRootResponse(healthmonitor=result) @@ -68,17 +75,31 @@ class HealthMonitorController(base.BaseController): """Gets all health monitors.""" pcontext = pecan.request.context context = pcontext.get('octavia_context') - if context.is_admin or CONF.auth_strategy == constants.NOAUTH: - if project_id: - project_id = {'project_id': project_id} - else: - project_id = {} + + # Check if user is authorized to list health mons under all projects + action = '{rbac_obj}{action}'.format( + rbac_obj=constants.RBAC_HEALTHMONITOR, action='get_all-global') + target = {'project_id': project_id} + if not context.policy.authorize(action, target, do_raise=False): + # Not a global observer or admin + if project_id is None: + project_id = context.project_id + + # Check that the user is authorized to list lbs under this project + action = '{rbac_obj}{action}'.format( + rbac_obj=constants.RBAC_HEALTHMONITOR, action='get_all') + target = {'project_id': project_id} + context.policy.authorize(action, target) + + if project_id is None: + query_filter = {} else: - project_id = {'project_id': context.project_id} + query_filter = {'project_id': project_id} + db_hm, links = self.repositories.health_monitor.get_all( context.session, show_deleted=False, pagination_helper=pcontext.get(constants.PAGINATION_HELPER), - **project_id) + **query_filter) result = self._convert_db_to_type( db_hm, [hm_types.HealthMonitorResponse]) return hm_types.HealthMonitorsRootResponse( @@ -163,6 +184,12 @@ class HealthMonitorController(base.BaseController): pool = self._get_db_pool(context.session, health_monitor.pool_id) health_monitor.project_id = pool.project_id + # Check that the user is authorized to create under this project + action = '{rbac_obj}{action}'.format( + rbac_obj=constants.RBAC_HEALTHMONITOR, action='post') + target = {'project_id': health_monitor.project_id} + context.policy.authorize(action, target) + lock_session = db_api.get_session(autocommit=False) if self.repositories.check_quota_met( context.session, @@ -198,6 +225,13 @@ class HealthMonitorController(base.BaseController): context = pecan.request.context.get('octavia_context') health_monitor = health_monitor_.healthmonitor db_hm = self._get_db_hm(context.session, id) + + # Check that the user is authorized to update this health monitor + action = '{rbac_obj}{action}'.format( + rbac_obj=constants.RBAC_HEALTHMONITOR, action='put') + target = {'project_id': db_hm.project_id} + context.policy.authorize(action, target) + self._test_lb_and_listener_and_pool_statuses(context.session, db_hm) self.repositories.health_monitor.update( @@ -227,6 +261,13 @@ class HealthMonitorController(base.BaseController): """Deletes a health monitor.""" context = pecan.request.context.get('octavia_context') db_hm = self._get_db_hm(context.session, id) + + # Check that the user is authorized to delete this health monitor + action = '{rbac_obj}{action}'.format( + rbac_obj=constants.RBAC_HEALTHMONITOR, action='delete') + target = {'project_id': db_hm.project_id} + context.policy.authorize(action, target) + self._test_lb_and_listener_and_pool_statuses(context.session, db_hm) self.repositories.health_monitor.update( diff --git a/octavia/common/constants.py b/octavia/common/constants.py index ce72881f44..d0dc924ff7 100644 --- a/octavia/common/constants.py +++ b/octavia/common/constants.py @@ -432,3 +432,4 @@ RBAC_LOADBALANCER = '{}:loadbalancer:'.format(LOADBALANCER_API) RBAC_LISTENER = '{}:listener:'.format(LOADBALANCER_API) RBAC_POOL = '{}:pool:'.format(LOADBALANCER_API) RBAC_MEMBER = '{}:member:'.format(LOADBALANCER_API) +RBAC_HEALTHMONITOR = '{}:healthmonitor:'.format(LOADBALANCER_API) diff --git a/octavia/policies/__init__.py b/octavia/policies/__init__.py index 44d09ad7b4..3718f0ab62 100644 --- a/octavia/policies/__init__.py +++ b/octavia/policies/__init__.py @@ -14,6 +14,7 @@ import itertools from octavia.policies import base +from octavia.policies import healthmonitor from octavia.policies import listener from octavia.policies import loadbalancer from octavia.policies import member @@ -23,6 +24,7 @@ from octavia.policies import pool def list_rules(): return itertools.chain( base.list_rules(), + healthmonitor.list_rules(), listener.list_rules(), loadbalancer.list_rules(), member.list_rules(), diff --git a/octavia/policies/healthmonitor.py b/octavia/policies/healthmonitor.py new file mode 100644 index 0000000000..d27061d795 --- /dev/null +++ b/octavia/policies/healthmonitor.py @@ -0,0 +1,67 @@ +# Copyright 2017 Rackspace, US Inc. +# 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 octavia.common import constants +from oslo_policy import policy + +rules = [ + policy.DocumentedRuleDefault( + '{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR, + action='get_all'), + constants.RULE_API_READ, + "List Health Monitors of a Pool", + [{'method': 'GET', 'path': '/v2.0/lbaas/healthmonitors'}] + ), + policy.DocumentedRuleDefault( + '{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR, + action='get_all-global'), + constants.RULE_API_READ_GLOBAL, + "List Health Monitors including resources owned by others", + [{'method': 'GET', 'path': '/v2.0/lbaas/healthmonitors'}] + ), + policy.DocumentedRuleDefault( + '{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR, + action='post'), + constants.RULE_API_WRITE, + "Create a Health Monitor", + [{'method': 'POST', 'path': '/v2.0/lbaas/healthmonitors'}] + ), + policy.DocumentedRuleDefault( + '{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR, + action='get_one'), + constants.RULE_API_READ, + "Show Health Monitor details", + [{'method': 'GET', + 'path': '/v2.0/lbaas/healthmonitors/{healthmonitor_id}'}] + ), + policy.DocumentedRuleDefault( + '{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR, + action='put'), + constants.RULE_API_WRITE, + "Update a Health Monitor", + [{'method': 'PUT', + 'path': '/v2.0/lbaas/healthmonitors/{healthmonitor_id}'}] + ), + policy.DocumentedRuleDefault( + '{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR, + action='delete'), + constants.RULE_API_WRITE, + "Remove a Health Monitor", + [{'method': 'DELETE', + 'path': '/v2.0/lbaas/healthmonitors/{healthmonitor_id}'}] + ), +] + + +def list_rules(): + return rules diff --git a/octavia/tests/functional/api/v2/test_health_monitor.py b/octavia/tests/functional/api/v2/test_health_monitor.py index 39ba2f8c98..f337a8df03 100644 --- a/octavia/tests/functional/api/v2/test_health_monitor.py +++ b/octavia/tests/functional/api/v2/test_health_monitor.py @@ -14,6 +14,8 @@ import mock +from oslo_config import cfg +from oslo_config import fixture as oslo_fixture from oslo_utils import uuidutils from octavia.common import constants @@ -33,6 +35,7 @@ class TestHealthMonitor(base.BaseAPITest): self.lb = self.create_load_balancer( uuidutils.generate_uuid()).get('loadbalancer') self.lb_id = self.lb.get('id') + self.project_id = self.lb.get('project_id') self.set_lb_status(self.lb_id) self.listener = self.create_listener( constants.PROTOCOL_HTTP, 80, @@ -64,6 +67,65 @@ class TestHealthMonitor(base.BaseAPITest): response.pop('updated_at') self.assertEqual(api_hm, response) + def test_get_authorized(self): + api_hm = self.create_health_monitor( + self.pool_id, constants.HEALTH_MONITOR_HTTP, + 1, 1, 1, 1).get(self.root_tag) + # Set status to ACTIVE/ONLINE because set_lb_status did it in the db + api_hm['provisioning_status'] = constants.ACTIVE + api_hm['operating_status'] = constants.ONLINE + api_hm.pop('updated_at') + self.set_lb_status(self.lb_id) + + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + self.project_id): + override_credentials = { + 'service_user_id': None, + 'user_domain_id': None, + 'is_admin_project': True, + 'service_project_domain_id': None, + 'service_project_id': None, + 'roles': ['load-balancer_member'], + 'user_id': None, + 'is_admin': False, + 'service_user_domain_id': None, + 'project_domain_id': None, + 'service_roles': [], + 'project_id': self.project_id} + with mock.patch( + "oslo_context.context.RequestContext.to_policy_values", + return_value=override_credentials): + + response = self.get(self.HM_PATH.format( + healthmonitor_id=api_hm.get('id'))).json.get(self.root_tag) + self.conf.config(auth_strategy=auth_strategy) + + response.pop('updated_at') + self.assertEqual(api_hm, response) + + def test_get_not_authorized(self): + api_hm = self.create_health_monitor( + self.pool_id, constants.HEALTH_MONITOR_HTTP, + 1, 1, 1, 1).get(self.root_tag) + # Set status to ACTIVE/ONLINE because set_lb_status did it in the db + api_hm['provisioning_status'] = constants.ACTIVE + api_hm['operating_status'] = constants.ONLINE + api_hm.pop('updated_at') + self.set_lb_status(self.lb_id) + + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + uuidutils.generate_uuid()): + response = self.get(self.HM_PATH.format( + healthmonitor_id=api_hm.get('id')), status=401) + self.conf.config(auth_strategy=auth_strategy) + self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json) + def test_get_hides_deleted(self): api_hm = self.create_health_monitor( self.pool_id, constants.HEALTH_MONITOR_HTTP, @@ -92,6 +154,21 @@ class TestHealthMonitor(base.BaseAPITest): self.assertEqual(1, len(hms)) self.assertEqual(api_hm.get('id'), hms[0].get('id')) + def test_get_all_not_authorized(self): + self.create_health_monitor( + self.pool_id, constants.HEALTH_MONITOR_HTTP, + 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(self.lb_id) + + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + uuidutils.generate_uuid()): + hms = self.get(self.HMS_PATH, status=401).json + + self.conf.config(auth_strategy=auth_strategy) + self.assertEqual(self.NOT_AUTHORIZED_BODY, hms) + def test_get_all_admin(self): project_id = uuidutils.generate_uuid() lb1 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb1', @@ -160,13 +237,90 @@ class TestHealthMonitor(base.BaseAPITest): self.conf.config(auth_strategy=constants.KEYSTONE) with mock.patch.object(octavia.common.context.Context, 'project_id', hm3['project_id']): - hms = self.get(self.HMS_PATH).json.get(self.root_tag_list) + override_credentials = { + 'service_user_id': None, + 'user_domain_id': None, + 'is_admin_project': True, + 'service_project_domain_id': None, + 'service_project_id': None, + 'roles': ['load-balancer_member'], + 'user_id': None, + 'is_admin': False, + 'service_user_domain_id': None, + 'project_domain_id': None, + 'service_roles': [], + 'project_id': self.project_id} + with mock.patch( + "oslo_context.context.RequestContext.to_policy_values", + return_value=override_credentials): + hms = self.get(self.HMS_PATH).json.get(self.root_tag_list) self.conf.config(auth_strategy=auth_strategy) self.assertEqual(1, len(hms)) hm_id_protocols = [(hm.get('id'), hm.get('type')) for hm in hms] self.assertIn((hm3.get('id'), hm3.get('type')), hm_id_protocols) + def test_get_all_non_admin_global_observer(self): + project_id = uuidutils.generate_uuid() + lb1 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb1', + project_id=project_id) + lb1_id = lb1.get('loadbalancer').get('id') + self.set_lb_status(lb1_id) + pool1 = self.create_pool( + lb1_id, constants.PROTOCOL_HTTP, + constants.LB_ALGORITHM_ROUND_ROBIN).get('pool') + self.set_lb_status(lb1_id) + pool2 = self.create_pool( + lb1_id, constants.PROTOCOL_HTTPS, + constants.LB_ALGORITHM_ROUND_ROBIN).get('pool') + self.set_lb_status(lb1_id) + pool3 = self.create_pool( + lb1_id, constants.PROTOCOL_TCP, + constants.LB_ALGORITHM_ROUND_ROBIN).get('pool') + self.set_lb_status(lb1_id) + hm1 = self.create_health_monitor( + pool1.get('id'), constants.HEALTH_MONITOR_HTTP, + 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(lb1_id) + hm2 = self.create_health_monitor( + pool2.get('id'), constants.HEALTH_MONITOR_PING, + 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(lb1_id) + hm3 = self.create_health_monitor( + pool3.get('id'), constants.HEALTH_MONITOR_TCP, + 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(lb1_id) + + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.KEYSTONE) + with mock.patch.object(octavia.common.context.Context, 'project_id', + hm3['project_id']): + override_credentials = { + 'service_user_id': None, + 'user_domain_id': None, + 'is_admin_project': True, + 'service_project_domain_id': None, + 'service_project_id': None, + 'roles': ['load-balancer_global_observer'], + 'user_id': None, + 'is_admin': False, + 'service_user_domain_id': None, + 'project_domain_id': None, + 'service_roles': [], + 'project_id': self.project_id} + with mock.patch( + "oslo_context.context.RequestContext.to_policy_values", + return_value=override_credentials): + + hms = self.get(self.HMS_PATH).json.get(self.root_tag_list) + + self.conf.config(auth_strategy=auth_strategy) + self.assertEqual(3, len(hms)) + hm_id_protocols = [(hm.get('id'), hm.get('type')) for hm in hms] + self.assertIn((hm1.get('id'), hm1.get('type')), hm_id_protocols) + self.assertIn((hm2.get('id'), hm2.get('type')), hm_id_protocols) + self.assertIn((hm3.get('id'), hm3.get('type')), hm_id_protocols) + def test_get_by_project_id(self): project1_id = uuidutils.generate_uuid() project2_id = uuidutils.generate_uuid() @@ -362,6 +516,68 @@ class TestHealthMonitor(base.BaseAPITest): self.assertEqual('/', api_hm.get('url_path')) self.assertEqual('200', api_hm.get('expected_codes')) + def test_create_authorized(self): + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + + with mock.patch.object(octavia.common.context.Context, 'project_id', + self.project_id): + override_credentials = { + 'service_user_id': None, + 'user_domain_id': None, + 'is_admin_project': True, + 'service_project_domain_id': None, + 'service_project_id': None, + 'roles': ['load-balancer_member'], + 'user_id': None, + 'is_admin': False, + 'service_user_domain_id': None, + 'project_domain_id': None, + 'service_roles': [], + 'project_id': self.project_id} + with mock.patch( + "oslo_context.context.RequestContext.to_policy_values", + return_value=override_credentials): + + api_hm = self.create_health_monitor( + self.pool_id, constants.HEALTH_MONITOR_HTTP, + 1, 1, 1, 1).get(self.root_tag) + + self.conf.config(auth_strategy=auth_strategy) + self.assert_correct_status( + lb_id=self.lb_id, listener_id=self.listener_id, + pool_id=self.pool_id, hm_id=api_hm.get('id'), + lb_prov_status=constants.PENDING_UPDATE, + listener_prov_status=constants.ACTIVE, + pool_prov_status=constants.PENDING_UPDATE, + hm_prov_status=constants.PENDING_CREATE, + hm_op_status=constants.OFFLINE) + self.set_lb_status(self.lb_id) + self.assertEqual(constants.HEALTH_MONITOR_HTTP, api_hm.get('type')) + self.assertEqual(1, api_hm.get('delay')) + self.assertEqual(1, api_hm.get('timeout')) + self.assertEqual(1, api_hm.get('max_retries_down')) + self.assertEqual(1, api_hm.get('max_retries')) + # Verify optional field defaults + self.assertEqual('GET', api_hm.get('http_method')) + self.assertEqual('/', api_hm.get('url_path')) + self.assertEqual('200', api_hm.get('expected_codes')) + + def test_create_not_authorized(self): + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + + with mock.patch.object(octavia.common.context.Context, 'project_id', + uuidutils.generate_uuid()): + api_hm = self.create_health_monitor( + self.pool_id, constants.HEALTH_MONITOR_HTTP, + 1, 1, 1, 1, status=401) + + self.conf.config(auth_strategy=auth_strategy) + self.assertEqual(self.NOT_AUTHORIZED_BODY, api_hm) + def test_create_with_listener(self): api_hm = self.create_health_monitor( self.pool_with_listener_id, constants.HEALTH_MONITOR_HTTP, @@ -465,6 +681,72 @@ class TestHealthMonitor(base.BaseAPITest): pool_prov_status=constants.PENDING_UPDATE, hm_prov_status=constants.PENDING_UPDATE) + def test_update_authorized(self): + api_hm = self.create_health_monitor( + self.pool_with_listener_id, + constants.HEALTH_MONITOR_HTTP, 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(self.lb_id) + new_hm = {'max_retries': 2} + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + self.project_id): + override_credentials = { + 'service_user_id': None, + 'user_domain_id': None, + 'is_admin_project': True, + 'service_project_domain_id': None, + 'service_project_id': None, + 'roles': ['load-balancer_member'], + 'user_id': None, + 'is_admin': False, + 'service_user_domain_id': None, + 'project_domain_id': None, + 'service_roles': [], + 'project_id': self.project_id} + with mock.patch( + "oslo_context.context.RequestContext.to_policy_values", + return_value=override_credentials): + + self.put( + self.HM_PATH.format(healthmonitor_id=api_hm.get('id')), + self._build_body(new_hm)) + + self.conf.config(auth_strategy=auth_strategy) + self.assert_correct_status( + lb_id=self.lb_id, listener_id=self.listener_id, + pool_id=self.pool_with_listener_id, hm_id=api_hm.get('id'), + lb_prov_status=constants.PENDING_UPDATE, + listener_prov_status=constants.PENDING_UPDATE, + pool_prov_status=constants.PENDING_UPDATE, + hm_prov_status=constants.PENDING_UPDATE) + + def test_update_not_authorized(self): + api_hm = self.create_health_monitor( + self.pool_with_listener_id, + constants.HEALTH_MONITOR_HTTP, 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(self.lb_id) + new_hm = {'max_retries': 2} + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + uuidutils.generate_uuid()): + response = self.put( + self.HM_PATH.format(healthmonitor_id=api_hm.get('id')), + self._build_body(new_hm), status=401) + + self.conf.config(auth_strategy=auth_strategy) + self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json) + self.assert_correct_status( + lb_id=self.lb_id, listener_id=self.listener_id, + pool_id=self.pool_with_listener_id, hm_id=api_hm.get('id'), + lb_prov_status=constants.ACTIVE, + listener_prov_status=constants.ACTIVE, + pool_prov_status=constants.ACTIVE, + hm_prov_status=constants.ACTIVE) + def test_bad_update(self): self.skip("This test will need reviewed after a validation layer is " "built") @@ -511,6 +793,81 @@ class TestHealthMonitor(base.BaseAPITest): pool_prov_status=constants.PENDING_UPDATE, hm_prov_status=constants.PENDING_DELETE) + def test_delete_authorized(self): + api_hm = self.create_health_monitor( + self.pool_with_listener_id, + constants.HEALTH_MONITOR_HTTP, 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(self.lb_id) + hm = self.get(self.HM_PATH.format( + healthmonitor_id=api_hm.get('id'))).json.get(self.root_tag) + api_hm['provisioning_status'] = constants.ACTIVE + api_hm['operating_status'] = constants.ONLINE + self.assertIsNone(api_hm.pop('updated_at')) + self.assertIsNotNone(hm.pop('updated_at')) + self.assertEqual(api_hm, hm) + + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + self.project_id): + override_credentials = { + 'service_user_id': None, + 'user_domain_id': None, + 'is_admin_project': True, + 'service_project_domain_id': None, + 'service_project_id': None, + 'roles': ['load-balancer_member'], + 'user_id': None, + 'is_admin': False, + 'service_user_domain_id': None, + 'project_domain_id': None, + 'service_roles': [], + 'project_id': self.project_id} + with mock.patch( + "oslo_context.context.RequestContext.to_policy_values", + return_value=override_credentials): + self.delete( + self.HM_PATH.format(healthmonitor_id=api_hm.get('id'))) + self.conf.config(auth_strategy=auth_strategy) + self.assert_correct_status( + lb_id=self.lb_id, listener_id=self.listener_id, + pool_id=self.pool_with_listener_id, hm_id=api_hm.get('id'), + lb_prov_status=constants.PENDING_UPDATE, + listener_prov_status=constants.PENDING_UPDATE, + pool_prov_status=constants.PENDING_UPDATE, + hm_prov_status=constants.PENDING_DELETE) + + def test_delete_not_authorized(self): + api_hm = self.create_health_monitor( + self.pool_with_listener_id, + constants.HEALTH_MONITOR_HTTP, 1, 1, 1, 1).get(self.root_tag) + self.set_lb_status(self.lb_id) + hm = self.get(self.HM_PATH.format( + healthmonitor_id=api_hm.get('id'))).json.get(self.root_tag) + api_hm['provisioning_status'] = constants.ACTIVE + api_hm['operating_status'] = constants.ONLINE + self.assertIsNone(api_hm.pop('updated_at')) + self.assertIsNotNone(hm.pop('updated_at')) + self.assertEqual(api_hm, hm) + + self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF)) + auth_strategy = self.conf.conf.get('auth_strategy') + self.conf.config(auth_strategy=constants.TESTING) + with mock.patch.object(octavia.common.context.Context, 'project_id', + uuidutils.generate_uuid()): + self.delete( + self.HM_PATH.format(healthmonitor_id=api_hm.get('id')), + status=401) + self.conf.config(auth_strategy=auth_strategy) + self.assert_correct_status( + lb_id=self.lb_id, listener_id=self.listener_id, + pool_id=self.pool_with_listener_id, hm_id=api_hm.get('id'), + lb_prov_status=constants.ACTIVE, + listener_prov_status=constants.ACTIVE, + pool_prov_status=constants.ACTIVE, + hm_prov_status=constants.ACTIVE) + def test_bad_delete(self): self.delete( self.HM_PATH.format(healthmonitor_id=uuidutils.generate_uuid()),