Validate that a job has a run playbook on freeze

We now know, before attempting to run a job, whether the inheritance
hierarchy has produced a main playbook for the job.  If there is none,
error early.

Also, in the executor, assume that any specified playbooks are
required to exist, and use the more specific version of the error
message if they don't.

Change-Id: Id7dc5934c665cf939820b12b5ded53adeb60c0a8
This commit is contained in:
James E. Blair 2017-10-26 15:29:39 -07:00
parent 6828656bab
commit 0029267403
5 changed files with 44 additions and 14 deletions

22
tests/fixtures/layouts/no-run.yaml vendored Normal file
View File

@ -0,0 +1,22 @@
- pipeline:
name: check
manager: independent
trigger:
gerrit:
- event: patchset-created
success:
gerrit:
Verified: 1
failure:
gerrit:
Verified: -1
- job:
name: base
parent: null
- project:
name: org/project
check:
jobs:
- base

View File

@ -194,7 +194,8 @@ class TestJob(BaseTestCase):
'name': 'project', 'name': 'project',
'gate': { 'gate': {
'jobs': [ 'jobs': [
{'python27': {'timeout': 70}} {'python27': {'timeout': 70,
'run': 'playbooks/python27.yaml'}}
] ]
} }
}]) }])

View File

@ -2486,6 +2486,15 @@ class TestScheduler(ZuulTestCase):
self.assertEqual([x['path'] for x in p['playbooks']], self.assertEqual([x['path'] for x in p['playbooks']],
['playbooks/python27.yaml']) ['playbooks/python27.yaml'])
@simple_layout("layouts/no-run.yaml")
def test_job_without_run(self):
"Test that a job without a run playbook errors"
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertIn('Job base does not specify a run playbook',
A.messages[-1])
def test_queue_names(self): def test_queue_names(self):
"Test shared change queue names" "Test shared change queue names"
tenant = self.sched.abide.tenants.get('tenant-one') tenant = self.sched.abide.tenants.get('tenant-one')

View File

@ -935,7 +935,7 @@ class AnsibleJob(object):
"Ansible plugin dir %s found adjacent to playbook %s in " "Ansible plugin dir %s found adjacent to playbook %s in "
"non-trusted repo." % (entry, path)) "non-trusted repo." % (entry, path))
def findPlaybook(self, path, required=False, trusted=False): def findPlaybook(self, path, trusted=False):
for ext in ['', '.yaml', '.yml']: for ext in ['', '.yaml', '.yml']:
fn = path + ext fn = path + ext
if os.path.exists(fn): if os.path.exists(fn):
@ -943,35 +943,30 @@ class AnsibleJob(object):
playbook_dir = os.path.dirname(os.path.abspath(fn)) playbook_dir = os.path.dirname(os.path.abspath(fn))
self._blockPluginDirs(playbook_dir) self._blockPluginDirs(playbook_dir)
return fn return fn
if required: raise ExecutorError("Unable to find playbook %s" % path)
raise ExecutorError("Unable to find playbook %s" % path)
return None
def preparePlaybooks(self, args): def preparePlaybooks(self, args):
self.writeAnsibleConfig(self.jobdir.setup_playbook) self.writeAnsibleConfig(self.jobdir.setup_playbook)
for playbook in args['pre_playbooks']: for playbook in args['pre_playbooks']:
jobdir_playbook = self.jobdir.addPrePlaybook() jobdir_playbook = self.jobdir.addPrePlaybook()
self.preparePlaybook(jobdir_playbook, playbook, self.preparePlaybook(jobdir_playbook, playbook, args)
args, required=True)
for playbook in args['playbooks']: for playbook in args['playbooks']:
jobdir_playbook = self.jobdir.addPlaybook() jobdir_playbook = self.jobdir.addPlaybook()
self.preparePlaybook(jobdir_playbook, playbook, self.preparePlaybook(jobdir_playbook, playbook, args)
args, required=False)
if jobdir_playbook.path is not None: if jobdir_playbook.path is not None:
self.jobdir.playbook = jobdir_playbook self.jobdir.playbook = jobdir_playbook
break break
if self.jobdir.playbook is None: if self.jobdir.playbook is None:
raise ExecutorError("No valid playbook found") raise ExecutorError("No playbook specified")
for playbook in args['post_playbooks']: for playbook in args['post_playbooks']:
jobdir_playbook = self.jobdir.addPostPlaybook() jobdir_playbook = self.jobdir.addPostPlaybook()
self.preparePlaybook(jobdir_playbook, playbook, self.preparePlaybook(jobdir_playbook, playbook, args)
args, required=True)
def preparePlaybook(self, jobdir_playbook, playbook, args, required): def preparePlaybook(self, jobdir_playbook, playbook, args):
self.log.debug("Prepare playbook repo for %s" % self.log.debug("Prepare playbook repo for %s" %
(playbook['project'],)) (playbook['project'],))
# Check out the playbook repo if needed and set the path to # Check out the playbook repo if needed and set the path to
@ -1006,7 +1001,6 @@ class AnsibleJob(object):
jobdir_playbook.path = self.findPlaybook( jobdir_playbook.path = self.findPlaybook(
path, path,
required=required,
trusted=playbook['trusted']) trusted=playbook['trusted'])
# If this playbook doesn't exist, don't bother preparing # If this playbook doesn't exist, don't bother preparing

View File

@ -2410,6 +2410,7 @@ class Layout(object):
# inherit from the reference definition. # inherit from the reference definition.
noop = Job('noop') noop = Job('noop')
noop.parent = noop.BASE_JOB_MARKER noop.parent = noop.BASE_JOB_MARKER
noop.run = 'noop.yaml'
self.jobs = {'noop': [noop]} self.jobs = {'noop': [noop]}
self.nodesets = {} self.nodesets = {}
self.secrets = {} self.secrets = {}
@ -2558,6 +2559,9 @@ class Layout(object):
raise Exception("Pre-review pipeline %s does not allow " raise Exception("Pre-review pipeline %s does not allow "
"post-review job %s" % ( "post-review job %s" % (
pipeline.name, frozen_job.name)) pipeline.name, frozen_job.name))
if not frozen_job.run:
raise Exception("Job %s does not specify a run playbook" % (
frozen_job.name,))
job_graph.addJob(frozen_job) job_graph.addJob(frozen_job)
def createJobGraph(self, item): def createJobGraph(self, item):