Add --disable-pipelines option
This facilitaties the creation of a Zuul system with a running config (that will be kept up to date as long as it receives events) but does not run any jobs or make any reports. This can be used in conjunction with zuul-web to serve REST API requests for introspection, or to create a standby Zuul system with a warmed config cache, or to support other debugging techniques. This change adds an extra assertion to the wait-for-init test since it would be too similar otherwise. It also adds some documentation for wait-for-init (so that both similar options are documented) and support for setting both options by environment variables for ease of use in k8s environments. Change-Id: I3ee83b08c8280066cfa0744f2e30e41edd0f364c
This commit is contained in:
parent
9aea549305
commit
7028745bbe
@ -65,6 +65,32 @@ changes to the configuration stored in ZooKeeper and automatically
|
||||
update their configuration in the background without interrupting
|
||||
processing.
|
||||
|
||||
Advanced Options
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
These options are not necessary under normal conditions, but may be
|
||||
useful in some complex environments.
|
||||
|
||||
The ``--wait-for-init`` option (or ``ZUUL_WAIT_FOR_INIT`` environment
|
||||
variable) will cause the scheduler to wait until all tenants
|
||||
have been initialized before it begins processing pipelines. This may
|
||||
help large systems with excess scheduler capacity perform a rolling
|
||||
restart of schedulers more quickly.
|
||||
|
||||
The ``--disable-pipelines`` option (or ``ZUUL_DISABLE_PIPELINES``
|
||||
environment variable) will cause the scheduler to silently discard all
|
||||
pipeline related events. This allows the scheduler to create and
|
||||
maintain all of the configuration of a running system without running
|
||||
any jobs or making any reports.
|
||||
|
||||
This option is not intended for normal use, and is only useful for
|
||||
certain testing and backup-related activities. Because any scheduler
|
||||
connected to ZooKeeper can process events, it does not make sense to
|
||||
mix values of this option. Normal production Zuul systems that are
|
||||
intended to process events should not set this option on any
|
||||
schedulers. To use this option on a standby or testing cluster, set
|
||||
it on all schedulers.
|
||||
|
||||
.. _backup:
|
||||
|
||||
Backup and Restoration
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The scheduler now accepts the argument ``--disable-pipelines``
|
||||
which will instruct it to discard all pipeline events. This
|
||||
facilitaties the creation of a system with a running Zuul config
|
||||
that does not start any jobs or make any reports.
|
@ -4543,12 +4543,13 @@ class SchedulerTestApp:
|
||||
def __init__(self, log, config, changes, additional_event_queues,
|
||||
upstream_root, poller_events,
|
||||
git_url_with_auth, add_cleanup, validate_tenants,
|
||||
wait_for_init, instance_id):
|
||||
wait_for_init, disable_pipelines, instance_id):
|
||||
self.log = log
|
||||
self.config = config
|
||||
self.changes = changes
|
||||
self.validate_tenants = validate_tenants
|
||||
self.wait_for_init = wait_for_init
|
||||
self.disable_pipelines = disable_pipelines
|
||||
|
||||
# Register connections from the config using fakes
|
||||
self.connections = TestConnectionRegistry(
|
||||
@ -4563,7 +4564,7 @@ class SchedulerTestApp:
|
||||
self.connections.configure(self.config)
|
||||
|
||||
self.sched = TestScheduler(self.config, self.connections, self,
|
||||
wait_for_init)
|
||||
wait_for_init, disable_pipelines)
|
||||
self.sched.log = logging.getLogger(f"zuul.Scheduler-{instance_id}")
|
||||
self.sched._stats_interval = 1
|
||||
|
||||
@ -4629,12 +4630,13 @@ class SchedulerTestApp:
|
||||
|
||||
|
||||
class SchedulerTestManager:
|
||||
def __init__(self, validate_tenants, wait_for_init):
|
||||
def __init__(self, validate_tenants, wait_for_init, disable_pipelines):
|
||||
self.instances = []
|
||||
|
||||
def create(self, log, config, changes, additional_event_queues,
|
||||
upstream_root, poller_events, git_url_with_auth,
|
||||
add_cleanup, validate_tenants, wait_for_init):
|
||||
add_cleanup, validate_tenants, wait_for_init,
|
||||
disable_pipelines):
|
||||
# Since the config contains a regex we cannot use copy.deepcopy()
|
||||
# as this will raise an exception with Python <3.7
|
||||
config_data = StringIO()
|
||||
@ -4653,9 +4655,10 @@ class SchedulerTestManager:
|
||||
|
||||
app = SchedulerTestApp(log, scheduler_config, changes,
|
||||
additional_event_queues, upstream_root,
|
||||
poller_events,
|
||||
git_url_with_auth, add_cleanup,
|
||||
validate_tenants, wait_for_init, instance_id)
|
||||
poller_events, git_url_with_auth,
|
||||
add_cleanup, validate_tenants,
|
||||
wait_for_init, disable_pipelines,
|
||||
instance_id)
|
||||
self.instances.append(app)
|
||||
return app
|
||||
|
||||
@ -4760,6 +4763,7 @@ class ZuulTestCase(BaseTestCase):
|
||||
log_console_port: int = 19885
|
||||
validate_tenants = None
|
||||
wait_for_init = None
|
||||
disable_pipelines = False
|
||||
scheduler_count = SCHEDULER_COUNT
|
||||
|
||||
def __getattr__(self, name):
|
||||
@ -4925,7 +4929,8 @@ class ZuulTestCase(BaseTestCase):
|
||||
self.builds = self.executor_server.running_builds
|
||||
|
||||
self.scheds = SchedulerTestManager(self.validate_tenants,
|
||||
self.wait_for_init)
|
||||
self.wait_for_init,
|
||||
self.disable_pipelines)
|
||||
for _ in range(self.scheduler_count):
|
||||
self.createScheduler()
|
||||
|
||||
@ -4944,7 +4949,8 @@ class ZuulTestCase(BaseTestCase):
|
||||
self.log, self.config, self.changes,
|
||||
self.additional_event_queues, self.upstream_root,
|
||||
self.poller_events, self.git_url_with_auth,
|
||||
self.addCleanup, self.validate_tenants, self.wait_for_init)
|
||||
self.addCleanup, self.validate_tenants, self.wait_for_init,
|
||||
self.disable_pipelines)
|
||||
|
||||
def createZKContext(self, lock=None):
|
||||
if lock is None:
|
||||
|
@ -9423,3 +9423,20 @@ class TestWaitForInit(ZuulTestCase):
|
||||
A.addApproval('Code-Review', 2)
|
||||
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
|
||||
self.waitUntilSettled()
|
||||
self.assertHistory([
|
||||
dict(name='project-merge', result='SUCCESS', changes='1,1'),
|
||||
dict(name='project-test1', result='SUCCESS', changes='1,1'),
|
||||
dict(name='project-test2', result='SUCCESS', changes='1,1'),
|
||||
], ordered=False)
|
||||
|
||||
|
||||
class TestDisablePipelines(ZuulTestCase):
|
||||
tenant_config_file = 'config/single-tenant/main.yaml'
|
||||
disable_pipelines = True
|
||||
|
||||
def test_disable_pipelines(self):
|
||||
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
|
||||
A.addApproval('Code-Review', 2)
|
||||
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
|
||||
self.waitUntilSettled()
|
||||
self.assertHistory([])
|
||||
|
@ -162,6 +162,16 @@ class ZuulApp(object):
|
||||
|
||||
return parser
|
||||
|
||||
def envBool(self, name, default=None):
|
||||
"""Get the named variable from the environment and
|
||||
convert to boolean"""
|
||||
val = os.getenv(name)
|
||||
if val is None:
|
||||
return default
|
||||
if val.lower() in ['false', '0']:
|
||||
return False
|
||||
return True
|
||||
|
||||
def readConfig(self):
|
||||
safe_env = {
|
||||
k: v for k, v in os.environ.items()
|
||||
|
@ -41,8 +41,15 @@ class Scheduler(zuul.cmd.ZuulDaemonApp):
|
||||
'will distribute work to mergers.')
|
||||
parser.add_argument('--wait-for-init', dest='wait_for_init',
|
||||
action='store_true',
|
||||
default=self.envBool('ZUUL_WAIT_FOR_INIT'),
|
||||
help='Wait until all tenants are fully loaded '
|
||||
'before beginning to process events.')
|
||||
'before beginning to process events. '
|
||||
'(also available as ZUUL_WAIT_FOR_INIT).')
|
||||
parser.add_argument('--disable-pipelines', dest='disable_pipelines',
|
||||
action='store_true',
|
||||
default=self.envBool('ZUUL_DISABLE_PIPELINES'),
|
||||
help='Discard all pipeline related events '
|
||||
'(also available as ZUUL_DISABLE_PIPELINES).')
|
||||
self.addSubCommands(parser, zuul.scheduler.COMMANDS)
|
||||
return parser
|
||||
|
||||
@ -86,7 +93,8 @@ class Scheduler(zuul.cmd.ZuulDaemonApp):
|
||||
self.configure_connections(require_sql=True)
|
||||
self.sched = zuul.scheduler.Scheduler(self.config,
|
||||
self.connections, self,
|
||||
self.args.wait_for_init)
|
||||
self.args.wait_for_init,
|
||||
self.args.disable_pipelines)
|
||||
if self.args.validate_tenants is None:
|
||||
self.connections.registerScheduler(self.sched)
|
||||
self.connections.load(self.sched.zk_client,
|
||||
|
@ -211,9 +211,10 @@ class Scheduler(threading.Thread):
|
||||
_executor_client_class = ExecutorClient
|
||||
|
||||
def __init__(self, config, connections, app, wait_for_init,
|
||||
testonly=False):
|
||||
disable_pipelines=False, testonly=False):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.disable_pipelines = disable_pipelines
|
||||
self._profile_pipelines = set()
|
||||
self.wait_for_init = wait_for_init
|
||||
self.hostname = socket.getfqdn()
|
||||
@ -2589,10 +2590,11 @@ class Scheduler(threading.Thread):
|
||||
return
|
||||
log.debug("Processing trigger event %s", event)
|
||||
try:
|
||||
if isinstance(event, SupercedeEvent):
|
||||
self._doSupercedeEvent(event)
|
||||
else:
|
||||
self._process_trigger_event(tenant, pipeline, event)
|
||||
if not self.disable_pipelines:
|
||||
if isinstance(event, SupercedeEvent):
|
||||
self._doSupercedeEvent(event)
|
||||
else:
|
||||
self._process_trigger_event(tenant, pipeline, event)
|
||||
finally:
|
||||
self.pipeline_trigger_events[tenant.name][
|
||||
pipeline.name
|
||||
@ -2709,7 +2711,8 @@ class Scheduler(threading.Thread):
|
||||
log = get_annotated_logger(self.log, event.zuul_event_id)
|
||||
log.debug("Processing management event %s", event)
|
||||
try:
|
||||
self._process_management_event(event)
|
||||
if not self.disable_pipelines:
|
||||
self._process_management_event(event)
|
||||
finally:
|
||||
self.pipeline_management_events[tenant.name][
|
||||
pipeline.name
|
||||
@ -2751,7 +2754,8 @@ class Scheduler(threading.Thread):
|
||||
)
|
||||
log.debug("Processing result event %s", event)
|
||||
try:
|
||||
self._process_result_event(event, pipeline)
|
||||
if not self.disable_pipelines:
|
||||
self._process_result_event(event, pipeline)
|
||||
finally:
|
||||
self.pipeline_result_events[tenant.name][
|
||||
pipeline.name
|
||||
|
Loading…
Reference in New Issue
Block a user