Files
zuul/zuul/driver/zuul/__init__.py
T
Simon Westphahl cb3cc6bd4b Consider queue settings for topic dependencies
Most of a change's attributes are tenant-independent. This however is
different for topic dependencies, which should only be considered in
tenants where the dependencies-by-topic feature is enabled.

This is mainly a problem when a project is part of multiple tenants as
the dependencies-by-topic setting might be different for each tenant. To
fix this we will only return the topic dependencies for a change in
tenants where the feature has been activated.

Since the `needs_changes` property is now a method called
`getNeedsChanges()`, we also changed `needed_by_changes` to
`getNeededByChanges()` so they match.

Change-Id: I343306db0abbe2fbf98ddb3f81b6d509eaf4a2bf
2022-11-30 07:11:10 +01:00

173 lines
7.1 KiB
Python

# Copyright 2016 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
import time
from uuid import uuid4
from opentelemetry import trace
from zuul.driver import Driver, TriggerInterface
from zuul.driver.zuul.zuulmodel import ZuulTriggerEvent
from zuul.driver.zuul import zuulmodel
from zuul.driver.zuul import zuultrigger
from zuul.lib.logutil import get_annotated_logger
from zuul.model import Change
PARENT_CHANGE_ENQUEUED = 'parent-change-enqueued'
PROJECT_CHANGE_MERGED = 'project-change-merged'
class ZuulDriver(Driver, TriggerInterface):
name = 'zuul'
log = logging.getLogger("zuul.ZuulTrigger")
tracer = trace.get_tracer("zuul")
def __init__(self):
self.parent_change_enqueued_events = {}
self.project_change_merged_events = {}
def registerScheduler(self, scheduler):
self.sched = scheduler
def reconfigure(self, tenant):
for pipeline in tenant.layout.pipelines.values():
for ef in pipeline.manager.event_filters:
if not isinstance(ef.trigger, zuultrigger.ZuulTrigger):
continue
if PARENT_CHANGE_ENQUEUED in ef._types:
# parent-change-enqueued events need to be filtered by
# pipeline
for pipeline in ef._pipelines:
key = (tenant.name, pipeline)
self.parent_change_enqueued_events[key] = True
elif PROJECT_CHANGE_MERGED in ef._types:
self.project_change_merged_events[tenant.name] = True
def onChangeMerged(self, tenant, change, source):
# Called each time zuul merges a change
if self.project_change_merged_events.get(tenant.name):
span = trace.get_current_span()
link_attributes = {"rel": "ChangeMerged"}
link = trace.Link(span.get_span_context(),
attributes=link_attributes)
attributes = {"event_type": PROJECT_CHANGE_MERGED}
with self.tracer.start_as_current_span(
"ZuulEvent", links=[link], attributes=attributes):
try:
self._createProjectChangeMergedEvents(change, source)
except Exception:
self.log.exception(
"Unable to create project-change-merged events for "
"%s" % (change,))
def onChangeEnqueued(self, tenant, change, pipeline, event):
log = get_annotated_logger(self.log, event)
# Called each time a change is enqueued in a pipeline
tenant_events = self.parent_change_enqueued_events.get(
(tenant.name, pipeline.name))
log.debug("onChangeEnqueued %s", tenant_events)
if tenant_events:
span = trace.get_current_span()
link_attributes = {"rel": "ChangeEnqueued"}
link = trace.Link(span.get_span_context(),
attributes=link_attributes)
attributes = {"event_type": PARENT_CHANGE_ENQUEUED}
with self.tracer.start_as_current_span(
"ZuulEvent", links=[link], attributes=attributes):
try:
self._createParentChangeEnqueuedEvents(
change, pipeline, tenant, event)
except Exception:
log.exception(
"Unable to create parent-change-enqueued events for "
"%s in %s" % (change, pipeline))
def _createProjectChangeMergedEvents(self, change, source):
changes = source.getProjectOpenChanges(
change.project)
for open_change in changes:
self._createProjectChangeMergedEvent(open_change)
def _createProjectChangeMergedEvent(self, change):
event = ZuulTriggerEvent()
event.type = PROJECT_CHANGE_MERGED
event.trigger_name = self.name
event.connection_name = "zuul"
event.project_hostname = change.project.canonical_hostname
event.project_name = change.project.name
event.change_number = change.number
event.branch = change.branch
event.change_url = change.url
event.patch_number = change.patchset
event.ref = change.ref
event.zuul_event_id = str(uuid4().hex)
event.timestamp = time.time()
self.sched.addTriggerEvent(self.name, event)
def _createParentChangeEnqueuedEvents(self, change, pipeline, tenant,
event):
log = get_annotated_logger(self.log, event)
log.debug("Checking for changes needing %s:" % change)
if not isinstance(change, Change):
log.debug(" %s does not support dependencies" % type(change))
return
# This is very inefficient, especially on systems with large
# numbers of github installations. This can be improved later
# with persistent storage of dependency information.
needed_by_changes = set(
pipeline.manager.resolveChangeReferences(
change.getNeededByChanges()))
for source in self.sched.connections.getSources():
log.debug(" Checking source: %s",
source.connection.connection_name)
new_changes = source.getChangesDependingOn(change, None, tenant)
log.debug(" Source %s found %s changes",
source.connection.connection_name,
len(new_changes))
needed_by_changes.update(new_changes)
log.debug(" Following changes: %s", needed_by_changes)
for needs in needed_by_changes:
self._createParentChangeEnqueuedEvent(needs, pipeline)
def _createParentChangeEnqueuedEvent(self, change, pipeline):
event = ZuulTriggerEvent()
event.type = PARENT_CHANGE_ENQUEUED
event.connection_name = "zuul"
event.trigger_name = self.name
event.pipeline_name = pipeline.name
event.project_hostname = change.project.canonical_hostname
event.project_name = change.project.name
event.change_number = change.number
event.branch = change.branch
event.change_url = change.url
event.patch_number = change.patchset
event.ref = change.ref
event.zuul_event_id = str(uuid4().hex)
event.timestamp = time.time()
self.sched.addTriggerEvent(self.name, event)
def getTrigger(self, connection_name, config=None):
return zuultrigger.ZuulTrigger(self, config)
def getTriggerSchema(self):
return zuultrigger.getSchema()
def getTriggerEventClass(self):
return zuulmodel.ZuulTriggerEvent