diff --git a/doc/source/housekeeper.rst b/doc/source/housekeeper.rst index d50bbc884b..711437505f 100644 --- a/doc/source/housekeeper.rst +++ b/doc/source/housekeeper.rst @@ -39,6 +39,8 @@ A naive devstack example could be:: source devstack/openrc admin demo export AUTH_TOKEN=`openstack token issue | awk '/ id /{print $4}'` + curl -X GET -s -H "X-Auth-Token: $AUTH_TOKEN" -H 'Content-Type: application/json' -d '{"housekeeper": {}}' http://:9696/v2.0/housekeepers/all + curl -X PUT -s -H "X-Auth-Token: $AUTH_TOKEN" -H 'Content-Type: application/json' -d '{"housekeeper": {}}' http://:9696/v2.0/housekeepers/all Where would be the Neutron controller's IP or the virtual IP of @@ -47,6 +49,9 @@ It is important to use the virtual IP in case of a load balanced active-backup Neutron servers, as otherwise the housekeeping request may be handled by the wrong controller. +The GET curl call will run all jobs in readonly mode +the PUT curl call will run all jobs in readwrite mode (for that the housekeeping_readonly should be set to False) + To operate the housekeeper periodically as it should, it should be scheduled via a timing mechanism such as Linux cron. diff --git a/vmware_nsx/plugins/common/housekeeper/base_job.py b/vmware_nsx/plugins/common/housekeeper/base_job.py index c06df71ee1..c2191eabad 100644 --- a/vmware_nsx/plugins/common/housekeeper/base_job.py +++ b/vmware_nsx/plugins/common/housekeeper/base_job.py @@ -16,7 +16,6 @@ import abc from neutron_lib.plugins import directory -from oslo_config import cfg from oslo_log import log import six @@ -28,11 +27,10 @@ class BaseJob(object): _core_plugin = None - def __init__(self, readonly): - self.readonly = readonly or (self.get_name() in - cfg.CONF.nsxv.housekeeping_readonly_jobs) + def __init__(self, global_readonly, readonly_jobs): + job_readonly = global_readonly or (self.get_name() in readonly_jobs) LOG.info('Housekeeping: %s job initialized in %s mode', - self.get_name(), 'RO' if self.readonly else 'RW') + self.get_name(), 'RO' if job_readonly else 'RW') @property def plugin(self): diff --git a/vmware_nsx/plugins/common/housekeeper/housekeeper.py b/vmware_nsx/plugins/common/housekeeper/housekeeper.py index 48044952fc..b2c0b21c19 100644 --- a/vmware_nsx/plugins/common/housekeeper/housekeeper.py +++ b/vmware_nsx/plugins/common/housekeeper/housekeeper.py @@ -26,8 +26,9 @@ from neutron_lib import exceptions as n_exc from vmware_nsx.common import locking LOG = log.getLogger(__name__) +ALL_DUMMY_JOB_NAME = 'all' ALL_DUMMY_JOB = { - 'name': 'all', + 'name': ALL_DUMMY_JOB_NAME, 'description': 'Execute all housekeepers', 'enabled': True, 'error_count': 0, @@ -35,33 +36,35 @@ ALL_DUMMY_JOB = { 'error_info': None} -class NsxvHousekeeper(stevedore.named.NamedExtensionManager): - def __init__(self, hk_ns, hk_jobs): +class NsxHousekeeper(stevedore.named.NamedExtensionManager): + def __init__(self, hk_ns, hk_jobs, hk_readonly, hk_readonly_jobs): + self.global_readonly = hk_readonly + self.readonly_jobs = hk_readonly_jobs self.email_notifier = None if (cfg.CONF.smtp_gateway and cfg.CONF.smtp_from_addr and cfg.CONF.snmp_to_list): self.email_notifier = HousekeeperEmailNotifier() - self.readonly = cfg.CONF.nsxv.housekeeping_readonly self.results = {} - if self.readonly: + if self.global_readonly: LOG.info('Housekeeper initialized in readonly mode') else: LOG.info('Housekeeper initialized') self.jobs = {} - super(NsxvHousekeeper, self).__init__( - hk_ns, hk_jobs, invoke_on_load=True, invoke_args=(self.readonly,)) + super(NsxHousekeeper, self).__init__( + hk_ns, hk_jobs, invoke_on_load=True, + invoke_args=(self.global_readonly, self.readonly_jobs)) LOG.info("Loaded housekeeping job names: %s", self.names()) for job in self: - if job.obj.get_name() in cfg.CONF.nsxv.housekeeping_jobs: + if job.obj.get_name() in hk_jobs: self.jobs[job.obj.get_name()] = job.obj def get(self, job_name): - if job_name == ALL_DUMMY_JOB['name']: + if job_name == ALL_DUMMY_JOB_NAME: return {'name': job_name, 'description': ALL_DUMMY_JOB['description'], 'enabled': job_name in self.jobs, @@ -88,15 +91,15 @@ class NsxvHousekeeper(stevedore.named.NamedExtensionManager): raise n_exc.ObjectNotFound(id=job_name) def list(self): - results = [{'name': ALL_DUMMY_JOB['name'], + results = [{'name': ALL_DUMMY_JOB_NAME, 'description': ALL_DUMMY_JOB['description'], - 'enabled': ALL_DUMMY_JOB['name'] in self.jobs, + 'enabled': ALL_DUMMY_JOB_NAME in self.jobs, 'error_count': self.results.get( - ALL_DUMMY_JOB['name'], {}).get('error_count', 0), + ALL_DUMMY_JOB_NAME, {}).get('error_count', 0), 'fixed_count': self.results.get( - ALL_DUMMY_JOB['name'], {}).get('fixed_count', 0), + ALL_DUMMY_JOB_NAME, {}).get('fixed_count', 0), 'error_info': self.results.get( - ALL_DUMMY_JOB['name'], {}).get('error_info', '')}] + ALL_DUMMY_JOB_NAME, {}).get('error_info', '')}] for job in self: job_name = job.obj.get_name() @@ -112,7 +115,24 @@ class NsxvHousekeeper(stevedore.named.NamedExtensionManager): return results - def run(self, context, job_name): + def readwrite_allowed(self, job_name): + # Check if a job can run in readwrite mode + if self.global_readonly: + return False + + non_readonly_jobs = set(self.jobs.keys()) - set(self.readonly_jobs) + if job_name == ALL_DUMMY_JOB_NAME: + # 'all' readwrite is allowed if it has non readonly jobs + if non_readonly_jobs: + return True + return False + else: + # specific job is allowed if it is not in the readonly list + if job_name in self.readonly_jobs: + return False + return True + + def run(self, context, job_name, readonly=False): self.results = {} if context.is_admin: if self.email_notifier: @@ -122,9 +142,16 @@ class NsxvHousekeeper(stevedore.named.NamedExtensionManager): error_count = 0 fixed_count = 0 error_info = '' - if job_name == ALL_DUMMY_JOB.get('name'): + if job_name == ALL_DUMMY_JOB_NAME: + if (not readonly and + not self.readwrite_allowed(ALL_DUMMY_JOB_NAME)): + raise n_exc.ObjectNotFound(id=ALL_DUMMY_JOB_NAME) for job in self.jobs.values(): - result = job.run(context) + if (not readonly and + not self.readwrite_allowed(job.get_name())): + # skip this job as it is readonly + continue + result = job.run(context, readonly=readonly) if result: if self.email_notifier and result['error_count']: self._add_job_text_to_notifier(job, result) @@ -140,7 +167,10 @@ class NsxvHousekeeper(stevedore.named.NamedExtensionManager): else: job = self.jobs.get(job_name) if job: - result = job.run(context) + if (not readonly and + not self.readwrite_allowed(job_name)): + raise n_exc.ObjectNotFound(id=job_name) + result = job.run(context, readonly=readonly) if result: error_count = result['error_count'] if self.email_notifier: diff --git a/vmware_nsx/plugins/common/plugin.py b/vmware_nsx/plugins/common/plugin.py index a39cfe66dc..e8bc6618a6 100644 --- a/vmware_nsx/plugins/common/plugin.py +++ b/vmware_nsx/plugins/common/plugin.py @@ -359,6 +359,27 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2, err_msg = _("Can not enable DHCP on external network") raise n_exc.InvalidInput(error_message=err_msg) + def get_housekeeper(self, context, name, fields=None): + # run the job in readonly mode and get the results + self.housekeeper.run(context, name, readonly=True) + return self.housekeeper.get(name) + + def get_housekeepers(self, context, filters=None, fields=None, sorts=None, + limit=None, marker=None, page_reverse=False): + return self.housekeeper.list() + + def update_housekeeper(self, context, name, housekeeper): + # run the job in non-readonly mode and get the results + if not self.housekeeper.readwrite_allowed(name): + err_msg = (_("Can not run housekeeper job %s in readwrite " + "mode") % name) + raise n_exc.InvalidInput(error_message=err_msg) + self.housekeeper.run(context, name, readonly=False) + return self.housekeeper.get(name) + + def get_housekeeper_count(self, context, filters=None): + return len(self.housekeeper.list()) + # Register the callback def _validate_network_has_subnet(resource, event, trigger, **kwargs): diff --git a/vmware_nsx/plugins/nsx_v/housekeeper/error_backup_edge.py b/vmware_nsx/plugins/nsx_v/housekeeper/error_backup_edge.py index e0cd749433..258e9bf7ef 100644 --- a/vmware_nsx/plugins/nsx_v/housekeeper/error_backup_edge.py +++ b/vmware_nsx/plugins/nsx_v/housekeeper/error_backup_edge.py @@ -29,8 +29,9 @@ LOG = log.getLogger(__name__) class ErrorBackupEdgeJob(base_job.BaseJob): - def __init__(self, readonly): - super(ErrorBackupEdgeJob, self).__init__(readonly) + def __init__(self, global_readonly, readonly_jobs): + super(ErrorBackupEdgeJob, self).__init__( + global_readonly, readonly_jobs) self.azs = nsx_az.NsxVAvailabilityZones() def get_project_plugin(self, plugin): @@ -42,7 +43,7 @@ class ErrorBackupEdgeJob(base_job.BaseJob): def get_description(self): return 'revalidate backup Edge appliances in ERROR state' - def run(self, context): + def run(self, context, readonly=False): super(ErrorBackupEdgeJob, self).run(context) error_count = 0 fixed_count = 0 @@ -69,7 +70,7 @@ class ErrorBackupEdgeJob(base_job.BaseJob): error_info, 'Backup Edge appliance %s is in ERROR state', binding['edge_id']) - if not self.readonly: + if not readonly: with locking.LockManager.get_lock(binding['edge_id']): if self._handle_backup_edge(context, binding): fixed_count += 1 diff --git a/vmware_nsx/plugins/nsx_v/housekeeper/error_dhcp_edge.py b/vmware_nsx/plugins/nsx_v/housekeeper/error_dhcp_edge.py index 08821f7cfe..c5b9e2e3e9 100644 --- a/vmware_nsx/plugins/nsx_v/housekeeper/error_dhcp_edge.py +++ b/vmware_nsx/plugins/nsx_v/housekeeper/error_dhcp_edge.py @@ -27,8 +27,8 @@ LOG = log.getLogger(__name__) class ErrorDhcpEdgeJob(base_job.BaseJob): - def __init__(self, readonly): - super(ErrorDhcpEdgeJob, self).__init__(readonly) + def __init__(self, global_readonly, readonly_jobs): + super(ErrorDhcpEdgeJob, self).__init__(global_readonly, readonly_jobs) self.error_count = 0 self.fixed_count = 0 self.fixed_sub_if_count = 0 @@ -43,7 +43,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): def get_description(self): return 'revalidate DHCP Edge appliances in ERROR state' - def run(self, context): + def run(self, context, readonly=False): super(ErrorDhcpEdgeJob, self).run(context) self.error_count = 0 self.fixed_count = 0 @@ -80,7 +80,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): for edge_id in edge_dict.keys(): try: self._validate_dhcp_edge( - context, edge_dict, pfx_dict, networks, edge_id) + context, edge_dict, pfx_dict, networks, edge_id, readonly) except Exception as e: self.error_count += 1 self.error_info = base_job.housekeeper_warning( @@ -92,7 +92,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): 'error_info': self.error_info} def _validate_dhcp_edge( - self, context, edge_dict, pfx_dict, networks, edge_id): + self, context, edge_dict, pfx_dict, networks, edge_id, readonly): # Also metadata network should be a valid network for the edge az_name = self.plugin.get_availability_zone_name_by_edge(context, edge_id) @@ -119,7 +119,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): 'router binding %s for edge %s has no matching ' 'neutron network', router_id, edge_id) - if not self.readonly: + if not readonly: nsxv_db.delete_nsxv_router_binding( context.session, binding['router_id']) self.fixed_count += 1 @@ -132,7 +132,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): 'edge %s vnic binding missing for network %s', edge_id, net_id) - if not self.readonly: + if not readonly: nsxv_db.allocate_edge_vnic_with_tunnel_index( context.session, edge_id, net_id, az_name) self.fixed_count += 1 @@ -154,7 +154,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): 'edge vnic binding for edge %s is for invalid ' 'network id %s', edge_id, bind['network_id']) - if not self.readonly: + if not readonly: nsxv_db.free_edge_vnic_by_network( context.session, edge_id, bind['network_id']) self.fixed_count += 1 @@ -178,9 +178,10 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): self._validate_edge_subinterfaces( context, edge_id, backend_vnics, vnic_dict, if_changed) self._add_missing_subinterfaces( - context, edge_id, vnic_binds, backend_vnics, if_changed) + context, edge_id, vnic_binds, backend_vnics, if_changed, + readonly) - if not self.readonly: + if not readonly: for vnic in backend_vnics: if if_changed[vnic['index']]: self.plugin.nsx_v.vcns.update_interface(edge_id, @@ -218,7 +219,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): vnic['subInterfaces']['subInterfaces'].remove(sub_if) def _add_missing_subinterfaces(self, context, edge_id, vnic_binds, - backend_vnics, if_changed): + backend_vnics, if_changed, readonly): # Verify that all the entries in # nsxv_edge_vnic_bindings are attached on the Edge @@ -252,7 +253,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): tunnel_index, vnic['index'], edge_id, network_id) if_changed[vnic['index']] = True - if not self.readonly: + if not readonly: self._recreate_vnic_subinterface( context, network_id, edge_id, vnic, tunnel_index) @@ -267,7 +268,7 @@ class ErrorDhcpEdgeJob(base_job.BaseJob): tunnel_index, vnic['index'], edge_id, network_id) if_changed[vnic['index']] = True - if not self.readonly: + if not readonly: self._recreate_vnic_subinterface( context, network_id, edge_id, vnic, tunnel_index) diff --git a/vmware_nsx/plugins/nsx_v/housekeeper/lbaas_pending.py b/vmware_nsx/plugins/nsx_v/housekeeper/lbaas_pending.py index 1bb693e96e..bbbfa15e63 100644 --- a/vmware_nsx/plugins/nsx_v/housekeeper/lbaas_pending.py +++ b/vmware_nsx/plugins/nsx_v/housekeeper/lbaas_pending.py @@ -46,7 +46,7 @@ class LbaasPendingJob(base_job.BaseJob): def get_description(self): return 'Monitor LBaaS objects in pending states' - def run(self, context): + def run(self, context, readonly=False): super(LbaasPendingJob, self).run(context) curr_time = time.time() error_count = 0 @@ -74,7 +74,7 @@ class LbaasPendingJob(base_job.BaseJob): 'LBaaS %s %s is stuck in pending state', model.NAME, element['id']) - if not self.readonly: + if not readonly: element['provisioning_status'] = constants.ERROR fixed_count += 1 del self.lbaas_objects[element['id']] diff --git a/vmware_nsx/plugins/nsx_v/plugin.py b/vmware_nsx/plugins/nsx_v/plugin.py index dbdf042c54..05d08d26e2 100644 --- a/vmware_nsx/plugins/nsx_v/plugin.py +++ b/vmware_nsx/plugins/nsx_v/plugin.py @@ -358,9 +358,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, nsx_v_md_proxy.NsxVMetadataProxyHandler( self, az)) - self.housekeeper = housekeeper.NsxvHousekeeper( + self.housekeeper = housekeeper.NsxHousekeeper( hk_ns='vmware_nsx.neutron.nsxv.housekeeper.jobs', - hk_jobs=cfg.CONF.nsxv.housekeeping_jobs) + hk_jobs=cfg.CONF.nsxv.housekeeping_jobs, + hk_readonly=cfg.CONF.nsxv.housekeeping_readonly, + hk_readonly_jobs=cfg.CONF.nsxv.housekeeping_readonly_jobs) self.init_is_complete = True @@ -4798,19 +4800,5 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, results.append(self._nsx_policy_to_dict(policy)) return results - def get_housekeeper(self, context, name, fields=None): - return self.housekeeper.get(name) - - def get_housekeepers(self, context, filters=None, fields=None, sorts=None, - limit=None, marker=None, page_reverse=False): - return self.housekeeper.list() - - def update_housekeeper(self, context, name, housekeeper): - self.housekeeper.run(context, name) - return self.housekeeper.get(name) - - def get_housekeeper_count(self, context, filters=None): - return len(self.housekeeper.list()) - def _get_appservice_id(self, name): return self.nsx_v.vcns.get_application_id(name) diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/utils.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/utils.py index fb2cde830f..6185c25095 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv/resources/utils.py +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/utils.py @@ -64,7 +64,7 @@ class NsxVPluginWrapper(plugin.NsxVPlugin): # finish the plugin initialization # (with md-proxy config, but without housekeeping) with mock.patch("vmware_nsx.plugins.common.housekeeper." - "housekeeper.NsxvHousekeeper"): + "housekeeper.NsxHousekeeper"): self.init_complete(0, 0, 0) def _start_rpc_listeners(self): diff --git a/vmware_nsx/tests/unit/common_plugin/__init__.py b/vmware_nsx/tests/unit/common_plugin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vmware_nsx/tests/unit/common_plugin/test_housekeeper.py b/vmware_nsx/tests/unit/common_plugin/test_housekeeper.py new file mode 100644 index 0000000000..cc4da8ba82 --- /dev/null +++ b/vmware_nsx/tests/unit/common_plugin/test_housekeeper.py @@ -0,0 +1,156 @@ +# Copyright 2018 VMware, Inc. +# All Rights Reserved +# +# 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 mock +from neutron.tests import base +from neutron_lib import exceptions as n_exc + +from vmware_nsx.plugins.common.housekeeper import base_job +from vmware_nsx.plugins.common.housekeeper import housekeeper + + +class TestJob1(base_job.BaseJob): + def __init__(self, global_readonly, readonly_jobs): + super(TestJob1, self).__init__(global_readonly, readonly_jobs) + + def get_name(self): + return 'test_job1' + + def get_project_plugin(self, plugin): + return 'Dummy' + + def get_description(self): + return 'test' + + def run(self, context, readonly=False): + pass + + +class TestJob2(TestJob1): + def get_name(self): + return 'test_job2' + + +class TestHousekeeper(base.BaseTestCase): + + def setUp(self): + self.jobs = ['test_job1', 'test_job2'] + self.readonly_jobs = ['test_job1'] + self.readonly = False + self.housekeeper = housekeeper.NsxHousekeeper( + hk_ns='stevedore.test.extension', + hk_jobs=self.jobs, + hk_readonly=self.readonly, + hk_readonly_jobs=self.readonly_jobs) + + self.job1 = TestJob1(self.readonly, self.readonly_jobs) + self.job2 = TestJob2(self.readonly, self.readonly_jobs) + self.housekeeper.jobs = {'test_job1': self.job1, + 'test_job2': self.job2} + self.context = mock.Mock() + self.context.session = mock.Mock() + + super(TestHousekeeper, self).setUp() + + def test_run_job_readonly(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + self.housekeeper.run(self.context, 'test_job1', readonly=True) + run1.assert_called_with(mock.ANY, readonly=True) + + self.housekeeper.run(self.context, 'test_job2', readonly=True) + run2.assert_called_with(mock.ANY, readonly=True) + + def test_run_job_readwrite(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + # job1 is configured as a readonly job so this should fail + self.assertRaises( + n_exc.ObjectNotFound, + self.housekeeper.run, self.context, 'test_job1', + readonly=False) + self.assertFalse(run1.called) + + # job2 should run + self.housekeeper.run(self.context, 'test_job2', readonly=False) + run2.assert_called_with(mock.ANY, readonly=False) + + def test_run_all_readonly(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + self.housekeeper.run(self.context, 'all', readonly=True) + run1.assert_called_with(mock.ANY, readonly=True) + run2.assert_called_with(mock.ANY, readonly=True) + + def test_run_all_readwrite(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + self.housekeeper.run(self.context, 'all', readonly=False) + # job1 is configured as a readonly job so it was not called + self.assertFalse(run1.called) + # job2 should run + run2.assert_called_with(mock.ANY, readonly=False) + + +class TestHousekeeperReadOnly(TestHousekeeper): + + def setUp(self): + super(TestHousekeeperReadOnly, self).setUp() + self.housekeeper.global_readonly = True + + def test_run_job_readonly(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + self.housekeeper.run(self.context, 'test_job1', readonly=True) + run1.assert_called_with(mock.ANY, readonly=True) + + self.housekeeper.run(self.context, 'test_job2', readonly=True) + run2.assert_called_with(mock.ANY, readonly=True) + + def test_run_job_readwrite(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + + # job1 is configured as a readonly job so this should fail + self.assertRaises( + n_exc.ObjectNotFound, + self.housekeeper.run, self.context, 'test_job1', + readonly=False) + self.assertFalse(run1.called) + + # global readonly flag so job2 should also fail + self.assertRaises( + n_exc.ObjectNotFound, + self.housekeeper.run, self.context, 'test_job2', + readonly=False) + self.assertFalse(run2.called) + + def test_run_all_readonly(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + self.housekeeper.run(self.context, 'all', readonly=True) + run1.assert_called_with(mock.ANY, readonly=True) + run2.assert_called_with(mock.ANY, readonly=True) + + def test_run_all_readwrite(self): + with mock.patch.object(self.job1, 'run') as run1,\ + mock.patch.object(self.job2, 'run') as run2: + # global readonly flag so 'all' should fail + self.assertRaises( + n_exc.ObjectNotFound, + self.housekeeper.run, self.context, 'all', + readonly=False) + self.assertFalse(run1.called) + self.assertFalse(run2.called) diff --git a/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_backup_edge.py b/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_backup_edge.py index c0aa9526f3..5691002fa0 100644 --- a/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_backup_edge.py +++ b/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_backup_edge.py @@ -28,8 +28,6 @@ FAKE_ROUTER_BINDINGS = [ class ErrorBackupEdgeTestCaseReadOnly(base.BaseTestCase): - def _is_readonly(self): - return True def setUp(self): def get_plugin_mock(alias=constants.CORE): @@ -44,25 +42,28 @@ class ErrorBackupEdgeTestCaseReadOnly(base.BaseTestCase): side_effect=get_plugin_mock).start() self.log = mock.Mock() base_job.LOG = self.log - self.job = error_backup_edge.ErrorBackupEdgeJob(self._is_readonly()) + self.job = error_backup_edge.ErrorBackupEdgeJob(True, []) + + def run_job(self): + self.job.run(self.context, readonly=True) def test_clean_run(self): mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_router_bindings', return_value=[]).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_not_called() def test_broken_backup_edge(self): mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_router_bindings', return_value=FAKE_ROUTER_BINDINGS).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_called_once() class ErrorBackupEdgeTestCaseReadWrite(ErrorBackupEdgeTestCaseReadOnly): - def _is_readonly(self): - return False + def run_job(self): + self.job.run(self.context, readonly=False) def test_broken_backup_edge(self): upd_binding = mock.patch( diff --git a/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_dhcp_edge.py b/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_dhcp_edge.py index ca4bc4dee3..525f704c98 100644 --- a/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_dhcp_edge.py +++ b/vmware_nsx/tests/unit/nsx_v/housekeeper/test_error_dhcp_edge.py @@ -270,8 +270,6 @@ BAD_INTERFACE = { class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): - def _is_readonly(self): - return True def setUp(self): def get_plugin_mock(alias=constants.CORE): @@ -291,12 +289,15 @@ class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): return_value='default').start() self.log = mock.Mock() base_job.LOG = self.log - self.job = error_dhcp_edge.ErrorDhcpEdgeJob(self._is_readonly()) + self.job = error_dhcp_edge.ErrorDhcpEdgeJob(True, []) + + def run_job(self): + self.job.run(self.context, readonly=True) def test_clean_run(self): mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_router_bindings', return_value=[]).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_not_called() def test_invalid_router_binding(self): @@ -312,7 +313,7 @@ class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): return_value=(None, BACKEND_EDGE_VNICS)).start() mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_internal_networks', return_value=FAKE_INTERNAL_NETWORKS).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_called_once() def test_invalid_edge_vnic_bindings(self): @@ -340,7 +341,7 @@ class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): return_value=(None, BACKEND_EDGE_VNICS)).start() mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_internal_networks', return_value=FAKE_INTERNAL_NETWORKS).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_called_once() def test_invalid_edge_sub_if(self): @@ -357,7 +358,7 @@ class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): return_value=(None, backend_vnics)).start() mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_internal_networks', return_value=FAKE_INTERNAL_NETWORKS).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_called_once() def test_missing_edge_sub_if(self): @@ -373,7 +374,7 @@ class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): return_value=(None, backend_vnics)).start() mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_internal_networks', return_value=FAKE_INTERNAL_NETWORKS).start() - self.job.run(self.context) + self.run_job() self.log.warning.assert_called_once() def test_missing_edge_interface(self): @@ -389,13 +390,14 @@ class ErrorDhcpEdgeTestCaseReadOnly(base.BaseTestCase): return_value=(None, backend_vnics)).start() mock.patch('vmware_nsx.db.nsxv_db.get_nsxv_internal_networks', return_value=FAKE_INTERNAL_NETWORKS).start() - self.job.run(self.context) + self.run_job() self.assertEqual(2, self.log.warning.call_count) class ErrorDhcpEdgeTestCaseReadWrite(ErrorDhcpEdgeTestCaseReadOnly): - def _is_readonly(self): - return False + + def run_job(self): + self.job.run(self.context, readonly=False) def test_invalid_router_binding(self): del_binding = mock.patch(