Merge "Add housekeeper GET/PUT run options"
This commit is contained in:
commit
b09de3485d
@ -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://<IP address>:9696/v2.0/housekeepers/all
|
||||
|
||||
curl -X PUT -s -H "X-Auth-Token: $AUTH_TOKEN" -H 'Content-Type: application/json' -d '{"housekeeper": {}}' http://<IP address>:9696/v2.0/housekeepers/all
|
||||
|
||||
Where <IP address> 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.
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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']]
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
0
vmware_nsx/tests/unit/common_plugin/__init__.py
Normal file
0
vmware_nsx/tests/unit/common_plugin/__init__.py
Normal file
156
vmware_nsx/tests/unit/common_plugin/test_housekeeper.py
Normal file
156
vmware_nsx/tests/unit/common_plugin/test_housekeeper.py
Normal file
@ -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)
|
@ -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(
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user