diff options
Diffstat (limited to 'zuul/model.py')
-rw-r--r-- | zuul/model.py | 129 |
1 files changed, 94 insertions, 35 deletions
diff --git a/zuul/model.py b/zuul/model.py index 1d82b5f2c..e36f9d670 100644 --- a/zuul/model.py +++ b/zuul/model.py @@ -1408,6 +1408,7 @@ class Node(ConfigObject): self.private_ipv6 = None self.connection_port = 22 self.connection_type = None + self.slot = None self._keys = [] self.az = None self.provider = None @@ -3006,20 +3007,30 @@ class Job(ConfigObject): # possibility of success, which may help prevent errors in # most cases. If we don't raise an error here, the # possibility of later failure still remains. - nonfinal_parents = [p for p in parents if not p.final] - if not nonfinal_parents: + nonfinal_parent_found = False + nonintermediate_parent_found = False + nonprotected_parent_found = False + for p in parents: + if not p.final: + nonfinal_parent_found = True + if not p.intermediate: + nonintermediate_parent_found = True + if not p.protected: + nonprotected_parent_found = True + if (nonfinal_parent_found and + nonintermediate_parent_found and + nonprotected_parent_found): + break + + if not nonfinal_parent_found: raise Exception( f'The parent of job "{self.name}", "{self.parent}" ' 'is final and can not act as a parent') - nonintermediate_parents = [ - p for p in parents if not p.intermediate] - if not nonintermediate_parents and not self.abstract: + if not nonintermediate_parent_found and not self.abstract: raise Exception( f'The parent of job "{self.name}", "{self.parent}" ' f'is intermediate but "{self.name}" is not abstract') - nonprotected_parents = [ - p for p in parents if not p.protected] - if (not nonprotected_parents and + if (not nonprotected_parent_found and parents[0].source_context.project_canonical_name != self.source_context.project_canonical_name): raise Exception( @@ -4666,6 +4677,37 @@ class BuildSet(zkobject.ZKObject): return Attributes(uuid=self.uuid) +class EventInfo: + + def __init__(self): + self.zuul_event_id = None + self.timestamp = time.time() + self.span_context = None + + @classmethod + def fromEvent(cls, event): + tinfo = cls() + tinfo.zuul_event_id = event.zuul_event_id + tinfo.timestamp = event.timestamp + tinfo.span_context = event.span_context + return tinfo + + @classmethod + def fromDict(cls, d): + tinfo = cls() + tinfo.zuul_event_id = d["zuul_event_id"] + tinfo.timestamp = d["timestamp"] + tinfo.span_context = d["span_context"] + return tinfo + + def toDict(self): + return { + "zuul_event_id": self.zuul_event_id, + "timestamp": self.timestamp, + "span_context": self.span_context, + } + + class QueueItem(zkobject.ZKObject): """Represents the position of a Change in a ChangeQueue. @@ -4700,7 +4742,7 @@ class QueueItem(zkobject.ZKObject): live=True, # Whether an item is intended to be processed at all layout_uuid=None, _cached_sql_results={}, - event=None, # The trigger event that lead to this queue item + event=None, # Info about the event that lead to this queue item # Additional container for connection specifig information to be # used by reporters throughout the lifecycle @@ -4722,6 +4764,9 @@ class QueueItem(zkobject.ZKObject): def new(klass, context, **kw): obj = klass() obj._set(**kw) + if COMPONENT_REGISTRY.model_api >= 13: + obj._set(event=obj.event and EventInfo.fromEvent(obj.event)) + data = obj._trySerialize(context) obj._save(context, data, create=True) files_state = (BuildSet.COMPLETE if obj.change.files is not None @@ -4750,10 +4795,18 @@ class QueueItem(zkobject.ZKObject): return (tenant, pipeline, uuid) def serialize(self, context): - if isinstance(self.event, TriggerEvent): - event_type = "TriggerEvent" + if COMPONENT_REGISTRY.model_api < 13: + if isinstance(self.event, TriggerEvent): + event_type = "TriggerEvent" + else: + event_type = self.event.__class__.__name__ else: - event_type = self.event.__class__.__name__ + event_type = "EventInfo" + if not isinstance(self.event, EventInfo): + # Convert our local trigger event to a trigger info + # object. This will only happen on the transition to + # model API version 13. + self._set(event=EventInfo.fromEvent(self.event)) data = { "uuid": self.uuid, @@ -4795,14 +4848,18 @@ class QueueItem(zkobject.ZKObject): # child objects. self._set(uuid=data["uuid"]) - event_type = data["event"]["type"] - if event_type == "TriggerEvent": - event_class = ( - self.pipeline.manager.sched.connections.getTriggerEventClass( - data["event"]["data"]["driver_name"]) - ) + if COMPONENT_REGISTRY.model_api < 13: + event_type = data["event"]["type"] + if event_type == "TriggerEvent": + event_class = ( + self.pipeline.manager.sched.connections + .getTriggerEventClass( + data["event"]["data"]["driver_name"]) + ) + else: + event_class = EventTypeIndex.event_type_mapping.get(event_type) else: - event_class = EventTypeIndex.event_type_mapping.get(event_type) + event_class = EventInfo if event_class is None: raise NotImplementedError( @@ -7740,31 +7797,33 @@ class Layout(object): def addJob(self, job): # We can have multiple variants of a job all with the same # name, but these variants must all be defined in the same repo. - prior_jobs = [j for j in self.getJobs(job.name) if - j.source_context.project_canonical_name != - job.source_context.project_canonical_name] # Unless the repo is permitted to shadow another. If so, and # the job we are adding is from a repo that is permitted to # shadow the one with the older jobs, skip adding this job. job_project = job.source_context.project_canonical_name job_tpc = self.tenant.project_configs[job_project] skip_add = False - for prior_job in prior_jobs[:]: - prior_project = prior_job.source_context.project_canonical_name - if prior_project in job_tpc.shadow_projects: - prior_jobs.remove(prior_job) - skip_add = True - + prior_jobs = self.jobs.get(job.name, []) if prior_jobs: - raise Exception("Job %s in %s is not permitted to shadow " - "job %s in %s" % ( - job, - job.source_context.project_name, - prior_jobs[0], - prior_jobs[0].source_context.project_name)) + # All jobs we've added so far should be from the same + # project, so pick the first one. + prior_job = prior_jobs[0] + if (prior_job.source_context.project_canonical_name != + job.source_context.project_canonical_name): + prior_project = prior_job.source_context.project_canonical_name + if prior_project in job_tpc.shadow_projects: + skip_add = True + else: + raise Exception("Job %s in %s is not permitted to shadow " + "job %s in %s" % ( + job, + job.source_context.project_name, + prior_job, + prior_job.source_context.project_name)) + if skip_add: return False - if job.name in self.jobs: + if prior_jobs: self.jobs[job.name].append(job) else: self.jobs[job.name] = [job] |