Remove tenant argument from UnparsedTenantConfig

This allows UnparsedTenantConfig to be a simple data structure
which doesn't perform any project name resolution during loading.
This simplifies arguments to several functions.

Change-Id: I658453e7b4320b369388796edd246f90fb551d84
This commit is contained in:
James E. Blair 2018-02-15 16:56:18 -08:00
parent d83ebfb65e
commit 71f275670f
2 changed files with 44 additions and 39 deletions

View File

@ -1265,8 +1265,8 @@ class TenantParser(object):
self._loadTenantInRepoLayouts(tenant.config_projects,
tenant.untrusted_projects,
cached, tenant)
unparsed_config.extend(tenant.config_projects_config, tenant)
unparsed_config.extend(tenant.untrusted_projects_config, tenant)
unparsed_config.extend(tenant.config_projects_config)
unparsed_config.extend(tenant.untrusted_projects_config)
tenant.layout = self._parseLayout(base, tenant, unparsed_config)
return tenant
@ -1514,10 +1514,10 @@ class TenantParser(object):
(job.project,))
if job.config_project:
config_projects_config.extend(
job.project.unparsed_config, tenant)
job.project.unparsed_config)
else:
untrusted_projects_config.extend(
job.project.unparsed_config, tenant)
job.project.unparsed_config)
continue
self.log.debug("Waiting for cat job %s" % (job,))
job.wait()
@ -1548,18 +1548,18 @@ class TenantParser(object):
branch = source_context.branch
if source_context.trusted:
incdata = self.loadConfigProjectLayout(
job.files[fn], source_context, tenant)
config_projects_config.extend(incdata, tenant)
job.files[fn], source_context)
config_projects_config.extend(incdata)
else:
incdata = self.loadUntrustedProjectLayout(
job.files[fn], source_context, tenant)
untrusted_projects_config.extend(incdata, tenant)
job.files[fn], source_context)
untrusted_projects_config.extend(incdata)
new_project_unparsed_config[project].extend(
incdata, tenant)
incdata)
if branch in new_project_unparsed_branch_config.get(
project, {}):
new_project_unparsed_branch_config[project][branch].\
extend(incdata, tenant)
extend(incdata)
# Now that we've sucessfully loaded all of the configuration,
# cache the unparsed data on the project objects.
for project, data in new_project_unparsed_config.items():
@ -1569,17 +1569,17 @@ class TenantParser(object):
project.unparsed_branch_config = branch_config
return config_projects_config, untrusted_projects_config
def loadConfigProjectLayout(self, data, source_context, tenant):
def loadConfigProjectLayout(self, data, source_context):
# This is the top-level configuration for a tenant.
config = model.UnparsedTenantConfig()
with early_configuration_exceptions(source_context):
config.extend(safe_load_yaml(data, source_context), tenant)
config.extend(safe_load_yaml(data, source_context))
return config
def loadUntrustedProjectLayout(self, data, source_context, tenant):
def loadUntrustedProjectLayout(self, data, source_context):
config = model.UnparsedTenantConfig()
with early_configuration_exceptions(source_context):
config.extend(safe_load_yaml(data, source_context), tenant)
config.extend(safe_load_yaml(data, source_context))
if config.pipelines:
with configuration_exceptions('pipeline', config.pipelines[0]):
raise PipelineNotPermittedError()
@ -1674,8 +1674,9 @@ class TenantParser(object):
layout.addProjectTemplate(project_template_parser.fromYaml(
config_template))
flattened_projects = self._flattenProjects(data.projects, tenant)
project_parser = ProjectParser(tenant, layout, project_template_parser)
for config_projects in data.projects.values():
for config_projects in flattened_projects.values():
# Unlike other config classes, we expect multiple project
# stanzas with the same name, so that a config repo can
# define a project-pipeline and the project itself can
@ -1695,6 +1696,26 @@ class TenantParser(object):
layout.addProjectConfig(project_parser.fromYaml(
filtered_projects))
def _flattenProjects(self, projects, tenant):
# Group together all of the project stanzas for each project.
result_projects = {}
for config_project in projects:
with configuration_exceptions('project', config_project):
name = config_project.get('name')
if not name:
# There is no name defined so implicitly add the name
# of the project where it is defined.
name = (config_project['_source_context'].
project.canonical_name)
else:
trusted, project = tenant.getProject(name)
if project is None:
raise ProjectNotFoundError(name)
name = project.canonical_name
config_project['name'] = name
result_projects.setdefault(name, []).append(config_project)
return result_projects
def _parseLayout(self, base, tenant, data):
# Don't call this method from dynamic reconfiguration because
# it interacts with drivers and connections.
@ -1784,7 +1805,7 @@ class ConfigLoader(object):
else:
incdata = project.unparsed_branch_config.get(branch)
if incdata:
config.extend(incdata, tenant)
config.extend(incdata)
continue
# Otherwise, do not use the cached config (even if the
# files are empty as that likely means they were deleted).
@ -1814,13 +1835,13 @@ class ConfigLoader(object):
if trusted:
incdata = (self.tenant_parser.
loadConfigProjectLayout(
data, source_context, tenant))
data, source_context))
else:
incdata = (self.tenant_parser.
loadUntrustedProjectLayout(
data, source_context, tenant))
data, source_context))
config.extend(incdata, tenant)
config.extend(incdata)
def createDynamicLayout(self, tenant, files,
include_config_projects=False,

View File

@ -2478,7 +2478,7 @@ class UnparsedTenantConfig(object):
self.pipelines = []
self.jobs = []
self.project_templates = []
self.projects = {}
self.projects = []
self.nodesets = []
self.secrets = []
self.semaphores = []
@ -2495,23 +2495,13 @@ class UnparsedTenantConfig(object):
r.semaphores = copy.deepcopy(self.semaphores)
return r
def extend(self, conf, tenant):
def extend(self, conf):
if isinstance(conf, UnparsedTenantConfig):
self.pragmas.extend(conf.pragmas)
self.pipelines.extend(conf.pipelines)
self.jobs.extend(conf.jobs)
self.project_templates.extend(conf.project_templates)
for k, v in conf.projects.items():
name = k
# Add the projects to the according canonical name instead of
# the given project name. If it is not found, it's ok to add
# this to the given name. We also don't need to throw the
# ProjectNotFoundException here as semantic validation occurs
# later where it will fail then.
trusted, project = tenant.getProject(k)
if project is not None:
name = project.canonical_name
self.projects.setdefault(name, []).extend(v)
self.projects.extend(conf.projects)
self.nodesets.extend(conf.nodesets)
self.secrets.extend(conf.secrets)
self.semaphores.extend(conf.semaphores)
@ -2527,13 +2517,7 @@ class UnparsedTenantConfig(object):
raise ConfigItemMultipleKeysError()
key, value = list(item.items())[0]
if key == 'project':
name = value.get('name')
if not name:
# There is no name defined so implicitly add the name
# of the project where it is defined.
name = value['_source_context'].project.canonical_name
value['name'] = name
self.projects.setdefault(name, []).append(value)
self.projects.append(value)
elif key == 'job':
self.jobs.append(value)
elif key == 'project-template':