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:
parent
6828656bab
commit
0029267403
|
@ -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
|
|
@ -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'}}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue