Configure triggers dynamically

Move EventFilter configuration into the triggers to allow dynamic
inclusion of triggers rather than specifying each one in the sechduler.

Change-Id: I4ed345058ff1ffdd662fafa854e36782cc7f047b
This commit is contained in:
Joshua Hesketh 2015-08-11 23:40:42 +10:00
parent c94afc4605
commit 70b13490a3
6 changed files with 106 additions and 67 deletions

View File

@ -2164,12 +2164,7 @@ class TestScheduler(ZuulTestCase):
def test_test_config(self):
"Test that we can test the config"
sched = zuul.scheduler.Scheduler()
sched.registerSource(None, 'gerrit')
sched.registerTrigger(None, 'gerrit')
sched.registerTrigger(None, 'timer')
sched.registerTrigger(None, 'zuul')
sched.testConfig(self.config.get('zuul', 'layout_config'))
self.sched.testConfig(self.config.get('zuul', 'layout_config'))
def test_build_description(self):
"Test that build descriptions update"

View File

@ -30,7 +30,7 @@ import yaml
import layoutvalidator
import model
from model import ActionReporter, Pipeline, Project, ChangeQueue
from model import EventFilter, ChangeishFilter, NullChange
from model import ChangeishFilter, NullChange
from zuul import change_matcher
from zuul import version as zuul_version
@ -339,63 +339,10 @@ class Scheduler(threading.Thread):
)
manager.changeish_filters.append(f)
# TODO: move this into triggers (may require pluggable
# configuration)
if 'gerrit' in conf_pipeline['trigger']:
for trigger in toList(conf_pipeline['trigger']['gerrit']):
approvals = {}
for approval_dict in toList(trigger.get('approval')):
for k, v in approval_dict.items():
approvals[k] = v
# Backwards compat for *_filter versions of these args
comments = toList(trigger.get('comment'))
if not comments:
comments = toList(trigger.get('comment_filter'))
emails = toList(trigger.get('email'))
if not emails:
emails = toList(trigger.get('email_filter'))
usernames = toList(trigger.get('username'))
if not usernames:
usernames = toList(trigger.get('username_filter'))
ignore_deletes = trigger.get('ignore-deletes', True)
f = EventFilter(
trigger=self.triggers['gerrit'],
types=toList(trigger['event']),
branches=toList(trigger.get('branch')),
refs=toList(trigger.get('ref')),
event_approvals=approvals,
comments=comments,
emails=emails,
usernames=usernames,
required_approvals=(
toList(trigger.get('require-approval'))
),
reject_approvals=toList(
trigger.get('reject-approval')
),
ignore_deletes=ignore_deletes
)
manager.event_filters.append(f)
if 'timer' in conf_pipeline['trigger']:
for trigger in toList(conf_pipeline['trigger']['timer']):
f = EventFilter(trigger=self.triggers['timer'],
types=['timer'],
timespecs=toList(trigger['time']))
manager.event_filters.append(f)
if 'zuul' in conf_pipeline['trigger']:
for trigger in toList(conf_pipeline['trigger']['zuul']):
f = EventFilter(
trigger=self.triggers['zuul'],
types=toList(trigger['event']),
pipelines=toList(trigger.get('pipeline')),
required_approvals=(
toList(trigger.get('require-approval'))
),
reject_approvals=toList(
trigger.get('reject-approval')
),
)
manager.event_filters.append(f)
# TODO(jhesketh): Allow multiple triggers per pipeline
for trigger in self.triggers.values():
manager.event_filters += \
trigger.getEventFilters(conf_pipeline['trigger'])
for project_template in data.get('project-templates', []):
# Make sure the template only contains valid pipelines

View File

@ -30,6 +30,11 @@ class BaseTrigger(object):
def stop(self):
"""Stop the trigger."""
@abc.abstractmethod
def getEventFilters(self, trigger_conf):
"""Return a list of EventFilter's for the scheduler to match against.
"""
def postConfig(self):
"""Called after config is loaded."""

View File

@ -16,7 +16,7 @@ import logging
import threading
import time
import voluptuous
from zuul.model import TriggerEvent
from zuul.model import EventFilter, TriggerEvent
from zuul.trigger import BaseTrigger
@ -136,6 +136,53 @@ class GerritTrigger(BaseTrigger):
self.gerrit_connector.stop()
self.gerrit_connector.join()
def getEventFilters(self, trigger_conf):
def toList(item):
if not item:
return []
if isinstance(item, list):
return item
return [item]
efilters = []
if 'gerrit' in trigger_conf:
for trigger in toList(trigger_conf['gerrit']):
approvals = {}
for approval_dict in toList(trigger.get('approval')):
for k, v in approval_dict.items():
approvals[k] = v
# Backwards compat for *_filter versions of these args
comments = toList(trigger.get('comment'))
if not comments:
comments = toList(trigger.get('comment_filter'))
emails = toList(trigger.get('email'))
if not emails:
emails = toList(trigger.get('email_filter'))
usernames = toList(trigger.get('username'))
if not usernames:
usernames = toList(trigger.get('username_filter'))
ignore_deletes = trigger.get('ignore-deletes', True)
f = EventFilter(
trigger=self,
types=toList(trigger['event']),
branches=toList(trigger.get('branch')),
refs=toList(trigger.get('ref')),
event_approvals=approvals,
comments=comments,
emails=emails,
usernames=usernames,
required_approvals=(
toList(trigger.get('require-approval'))
),
reject_approvals=toList(
trigger.get('reject-approval')
),
ignore_deletes=ignore_deletes
)
efilters.append(f)
return efilters
def validate_trigger(trigger_data):
"""Validates the layout's trigger data."""

View File

@ -15,7 +15,7 @@
import apscheduler.scheduler
import logging
from zuul.model import TriggerEvent
from zuul.model import EventFilter, TriggerEvent
from zuul.trigger import BaseTrigger
@ -42,6 +42,25 @@ class TimerTrigger(BaseTrigger):
def stop(self):
self.apsched.shutdown()
def getEventFilters(self, trigger_conf):
def toList(item):
if not item:
return []
if isinstance(item, list):
return item
return [item]
efilters = []
if 'timer' in trigger_conf:
for trigger in toList(trigger_conf['timer']):
f = EventFilter(trigger=self,
types=['timer'],
timespecs=toList(trigger['time']))
efilters.append(f)
return efilters
def postConfig(self):
for job in self.apsched.get_jobs():
self.apsched.unschedule_job(job)

View File

@ -14,7 +14,7 @@
# under the License.
import logging
from zuul.model import TriggerEvent
from zuul.model import EventFilter, TriggerEvent
from zuul.trigger import BaseTrigger
@ -28,6 +28,32 @@ class ZuulTrigger(BaseTrigger):
self._handle_parent_change_enqueued_events = False
self._handle_project_change_merged_events = False
def getEventFilters(self, trigger_conf):
def toList(item):
if not item:
return []
if isinstance(item, list):
return item
return [item]
efilters = []
if 'zuul' in trigger_conf:
for trigger in toList(trigger_conf['zuul']):
f = EventFilter(
trigger=self,
types=toList(trigger['event']),
pipelines=toList(trigger.get('pipeline')),
required_approvals=(
toList(trigger.get('require-approval'))
),
reject_approvals=toList(
trigger.get('reject-approval')
),
)
efilters.append(f)
return efilters
def onChangeMerged(self, change):
# Called each time zuul merges a change
if self._handle_project_change_merged_events: