Fix broken templates for projects in dependent pipelines

A project referencing a template which did not exist could cause
an exception during reconfiguration causing it to fail.

If a project references a template which does not exist, and Zuul
then attempts to add that project to a dependent pipeline, or
build a job graph for it, an uncaught exception will be thrown
(including during the final phase of reconfiguration).

It is safest to treat it as if the project were unconfigured until
the problem is corrected, so this change causes getAllProjectConfigs
to return the empty list if there is such an error.

Change-Id: I36c011a7c17646d20c816e44a89f075415217bfb
This commit is contained in:
James E. Blair 2018-07-11 14:13:26 -07:00
parent 19afda37a3
commit c163a80565
3 changed files with 62 additions and 9 deletions

View File

@ -0,0 +1,27 @@
- pipeline:
name: gate
manager: dependent
trigger:
gerrit:
- event: comment-added
approval:
- Approved: 1
success:
gerrit:
Verified: 2
submit: true
failure:
gerrit:
Verified: -2
start:
gerrit:
Verified: 0
- job:
name: base
parent: null
- project:
name: org/project
templates:
- does-not-exist

View File

@ -25,7 +25,12 @@ from unittest import skip
import zuul.configloader
from zuul.lib import encryption
from tests.base import AnsibleZuulTestCase, ZuulTestCase, FIXTURE_DIR
from tests.base import (
AnsibleZuulTestCase,
ZuulTestCase,
FIXTURE_DIR,
simple_layout,
)
class TestMultipleTenants(AnsibleZuulTestCase):
@ -2462,6 +2467,18 @@ class TestBrokenConfig(ZuulTestCase):
"Zuul encountered a syntax error",
str(tenant.layout.loading_errors[0].error))
@simple_layout('layouts/broken-template.yaml')
def test_broken_config_on_startup_template(self):
# Verify that a missing project-template doesn't break gate
# pipeline construction.
tenant = self.sched.abide.tenants.get('tenant-one')
self.assertEquals(
len(tenant.layout.loading_errors), 1,
"An error should have been stored")
self.assertIn(
"Zuul encountered a syntax error",
str(tenant.layout.loading_errors[0].error))
def test_dynamic_ignore(self):
# Verify dynamic config behaviors inside a tenant broken config
tenant = self.sched.abide.tenants.get('tenant-one')

View File

@ -159,6 +159,11 @@ class NoMatchingParentError(Exception):
pass
class TemplateNotFoundError(Exception):
"""A project referenced a template that does not exist."""
pass
class Attributes(object):
"""A class to hold attributes for string formatting."""
@ -3098,7 +3103,7 @@ class Layout(object):
def getProjectTemplates(self, name):
pt = self.project_templates.get(name, None)
if pt is None:
raise Exception("Project template %s not found" % name)
raise TemplateNotFoundError("Project template %s not found" % name)
return pt
def addProjectConfig(self, project_config):
@ -3120,13 +3125,17 @@ class Layout(object):
def getAllProjectConfigs(self, name):
# Get all the project configs (project and project-template
# stanzas) for a project.
ret = []
for pc in self.getProjectConfigs(name):
ret.append(pc)
for template_name in pc.templates:
templates = self.getProjectTemplates(template_name)
ret.extend(templates)
return ret
try:
ret = []
for pc in self.getProjectConfigs(name):
ret.append(pc)
for template_name in pc.templates:
templates = self.getProjectTemplates(template_name)
ret.extend(templates)
return ret
except TemplateNotFoundError as e:
self.log.warning("%s for project %s" % (e, name))
return []
def getProjectMetadata(self, name):
if name in self.project_metadata: