Merge "Builds: add "held" attribute"

This commit is contained in:
Zuul 2020-09-09 19:41:43 +00:00 committed by Gerrit Code Review
commit 6a5b97572f
9 changed files with 106 additions and 8 deletions

View File

@ -0,0 +1,10 @@
---
features:
- |
Builds in the SQL reporter have a "held" attribute set to True if the build
triggered a autohold request. Builds can be filtered by held status.
upgrade:
- |
If using a SQL reporter, the zuul_builds table will be updated with a new
'held' column. The `zuul-scheduler` and `zuul-web` services need to be restarted
together for the change to take effect.

View File

@ -75,7 +75,7 @@ class TestSQLConnection(ZuulDBTestCase):
build_table = table_prefix + 'zuul_build'
self.assertEqual(16, len(insp.get_columns(buildset_table)))
self.assertEqual(12, len(insp.get_columns(build_table)))
self.assertEqual(13, len(insp.get_columns(build_table)))
def test_sql_tables_created(self):
"Test the tables for storing results are created properly"

View File

@ -2080,6 +2080,46 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
self.assertEqual("some reason", ah_request['reason'])
class TestHeldAttributeInBuildInfo(ZuulDBTestCase, BaseTestWeb):
config_file = 'zuul-sql-driver.conf'
tenant_config_file = 'config/sql-driver/main.yaml'
def test_autohold_and_retrieve_held_build_info(self):
"""Ensure the "held" attribute can be used to filter builds"""
client = zuul.rpcclient.RPCClient('127.0.0.1',
self.gearman_server.port)
self.addCleanup(client.shutdown)
r = client.autohold('tenant-one', 'org/project', 'project-test2',
"", "", "reason text", 1)
self.assertTrue(r)
B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
self.executor_server.failJob('project-test2', B)
self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.executor_server.hold_jobs_in_build = False
self.executor_server.release()
self.waitUntilSettled()
all_builds_resp = self.get_url("api/tenant/tenant-one/builds?"
"project=org/project")
held_builds_resp = self.get_url("api/tenant/tenant-one/builds?"
"project=org/project&"
"held=1")
self.assertEqual(200,
all_builds_resp.status_code,
all_builds_resp.text)
self.assertEqual(200,
held_builds_resp.status_code,
held_builds_resp.text)
all_builds = all_builds_resp.json()
held_builds = held_builds_resp.json()
self.assertEqual(len(held_builds), 1, all_builds)
held_build = held_builds[0]
self.assertEqual('project-test2', held_build['job_name'], held_build)
self.assertEqual(True, held_build['held'], held_build)
class TestWebMulti(BaseTestWeb):
config_file = 'zuul-gerrit-github.conf'

View File

@ -0,0 +1,39 @@
# 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.
"""add held attribute to builds
Revision ID: 32e28a297c3e
Revises: 16c1dc9054d0
Create Date: 2020-05-19 11:19:19.263236
"""
# revision identifiers, used by Alembic.
revision = '32e28a297c3e'
down_revision = '269691d2220e'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade(table_prefix=''):
op.add_column(
table_prefix + 'zuul_build',
sa.Column('held', sa.Boolean)
)
def downgrade():
raise Exception("Downgrades not supported")

View File

@ -60,7 +60,7 @@ class DatabaseSession(object):
change=None, branch=None, patchset=None, ref=None,
newrev=None, event_id=None, uuid=None, job_name=None,
voting=None, node_name=None, result=None, provides=None,
final=None, limit=50, offset=0):
final=None, held=None, limit=50, offset=0):
build_table = self.connection.zuul_build_table
buildset_table = self.connection.zuul_buildset_table
@ -104,6 +104,7 @@ class DatabaseSession(object):
q = self.listFilter(q, build_table.c.result, result)
q = self.listFilter(q, build_table.c.final, final)
q = self.listFilter(q, provides_table.c.name, provides)
q = self.listFilter(q, build_table.c.held, held)
q = q.order_by(build_table.c.id.desc()).\
limit(limit).\
@ -296,6 +297,7 @@ class SQLConnection(BaseConnection):
uuid = sa.Column(sa.String(36))
job_name = sa.Column(sa.String(255))
result = sa.Column(sa.String(255))
held = sa.Column(sa.Boolean)
start_time = sa.Column(sa.DateTime)
end_time = sa.Column(sa.DateTime)
voting = sa.Column(sa.Boolean)

View File

@ -59,6 +59,7 @@ class SQLReporter(BaseReporter):
node_name=build.node_name,
error_detail=build.error_detail,
final=final,
held=build.held,
)
return db_build
@ -100,7 +101,6 @@ class SQLReporter(BaseReporter):
# stats about builds. It doesn't understand how to store
# information about the change.
continue
retry_builds = item.current_build_set.getRetryBuildsForJob(
job.name
)

View File

@ -1882,6 +1882,7 @@ class Build(object):
self.canceled = False
self.paused = False
self.retry = False
self.held = False
self.parameters = {}
self.worker = Worker()
self.node_labels = []

View File

@ -1565,12 +1565,14 @@ class Scheduler(threading.Thread):
# failed / retry_limit / post_failure and have an autohold request.
hold_list = ["FAILURE", "RETRY_LIMIT", "POST_FAILURE", "TIMED_OUT"]
if build.result not in hold_list:
return
return False
request = self._getAutoholdRequest(build)
self.log.debug("Got autohold %s", request)
if request is not None:
self.log.debug("Got autohold %s", request)
self.nodepool.holdNodeSet(build.nodeset, request, build)
return True
return False
def _doBuildCompletedEvent(self, event):
build = event.build
@ -1582,7 +1584,10 @@ class Scheduler(threading.Thread):
# to pass this on to the pipeline manager, make sure we return
# the nodes to nodepool.
try:
self._processAutohold(build)
event.build.held = self._processAutohold(build)
self.log.debug(
'build "%s" held status set to %s' % (event.build,
event.build.held))
except Exception:
log.exception("Unable to process autohold for %s" % build)
try:

View File

@ -875,6 +875,7 @@ class ZuulWebAPI(object):
'uuid': build.uuid,
'job_name': build.job_name,
'result': build.result,
'held': build.held,
'start_time': start_time,
'end_time': end_time,
'duration': duration,
@ -934,7 +935,7 @@ class ZuulWebAPI(object):
def builds(self, tenant, project=None, pipeline=None, change=None,
branch=None, patchset=None, ref=None, newrev=None,
uuid=None, job_name=None, voting=None, node_name=None,
result=None, final=None, limit=50, skip=0):
result=None, final=None, held=None, limit=50, skip=0):
connection = self._get_connection(tenant)
# If final is None, we return all builds, both final and non-final
@ -945,7 +946,7 @@ class ZuulWebAPI(object):
tenant=tenant, project=project, pipeline=pipeline, change=change,
branch=branch, patchset=patchset, ref=ref, newrev=newrev,
uuid=uuid, job_name=job_name, voting=voting, node_name=node_name,
result=result, final=final, limit=limit, offset=skip)
result=result, final=final, held=held, limit=limit, offset=skip)
resp = cherrypy.response
resp.headers['Access-Control-Allow-Origin'] = '*'