Skip to content

Commit

Permalink
Merge pull request #7199 from p12tic/www-improve-worker-actions
Browse files Browse the repository at this point in the history
Implement worker pause reason
  • Loading branch information
p12tic committed Nov 6, 2023
2 parents 1f36d7f + 5106d7f commit 2b8d868
Show file tree
Hide file tree
Showing 17 changed files with 384 additions and 38 deletions.
25 changes: 23 additions & 2 deletions master/buildbot/data/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from buildbot.data import exceptions
from buildbot.data import types
from buildbot.util import identifiers
from buildbot.warnings import warn_deprecated


class Db2DataMixin:
Expand All @@ -30,6 +31,7 @@ def db2data(self, dbdict):
'name': dbdict['name'],
'workerinfo': dbdict['workerinfo'],
'paused': dbdict['paused'],
"pause_reason": dbdict["pause_reason"],
'graceful': dbdict['graceful'],
'connected_to': [
{'masterid': id}
Expand Down Expand Up @@ -131,6 +133,7 @@ class EntityType(types.Entity):
configured_on = types.List(of=MasterBuilderEntityType("master_builder", 'MasterBuilder'))
workerinfo = types.JsonObject()
paused = types.Boolean()
pause_reason = types.NoneOk(types.String())
graceful = types.Boolean()
entityType = EntityType(name, 'Worker')

Expand Down Expand Up @@ -178,10 +181,28 @@ def workerMissing(self, workerid, masterid, last_connection, notify):
@base.updateMethod
@defer.inlineCallbacks
def setWorkerState(self, workerid, paused, graceful):
yield self.master.db.workers.setWorkerState(
warn_deprecated("3.10.0", "setWorkerState() has been deprecated, "
"please use set_worker_paused() and/or set_worker_graceful()")
yield self.master.db.workers.set_worker_paused(workerid=workerid, paused=paused)
yield self.master.db.workers.set_worker_graceful(workerid=workerid, graceful=graceful)
bs = yield self.master.data.get(('workers', workerid))
self.produceEvent(bs, 'state_updated')

@base.updateMethod
@defer.inlineCallbacks
def set_worker_paused(self, workerid, paused, pause_reason=None):
yield self.master.db.workers.set_worker_paused(
workerid=workerid,
paused=paused,
graceful=graceful)
pause_reason=pause_reason
)
bs = yield self.master.data.get(('workers', workerid))
self.produceEvent(bs, 'state_updated')

@base.updateMethod
@defer.inlineCallbacks
def set_worker_graceful(self, workerid, graceful):
yield self.master.db.workers.set_worker_graceful(workerid=workerid, graceful=graceful)
bs = yield self.master.data.get(('workers', workerid))
self.produceEvent(bs, 'state_updated')

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members

"""add pause_reason column to workers table
Revision ID: 064
Revises: 063
"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = '064'
down_revision = '063'
branch_labels = None
depends_on = None


def upgrade():
op.add_column("workers", sa.Column("pause_reason", sa.Text, nullable=True))


def downgrade():
op.drop_column("workers", "pause_reason")
1 change: 1 addition & 0 deletions master/buildbot/db/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ class Model(base.DBConnectorComponent):
sa.Column("name", sa.String(50), nullable=False),
sa.Column("info", JsonObject, nullable=False),
sa.Column("paused", sa.SmallInteger, nullable=False, server_default="0"),
sa.Column("pause_reason", sa.Text, nullable=True),
sa.Column("graceful", sa.SmallInteger, nullable=False, server_default="0"),
)

Expand Down
25 changes: 21 additions & 4 deletions master/buildbot/db/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ def findWorkerId(self, name):
return self.findSomethingId(
tbl=tbl,
whereclause=(tbl.c.name == name),
insert_values={"name": name, "info": {}, "paused": 0, "graceful": 0}
insert_values={
"name": name,
"info": {},
"paused": 0,
"pause_reason": None,
"graceful": 0
}
)

def _deleteFromConfiguredWorkers_thd(self, conn, buildermasterids, workerid=None):
Expand Down Expand Up @@ -135,7 +141,9 @@ def thd(conn):
j = j.outerjoin(bm_tbl)
q = sa.select(
[workers_tbl.c.id, workers_tbl.c.name, workers_tbl.c.info,
workers_tbl.c.paused, workers_tbl.c.graceful,
workers_tbl.c.paused,
workers_tbl.c.pause_reason,
workers_tbl.c.graceful,
bm_tbl.c.builderid, bm_tbl.c.masterid],
from_obj=[j],
order_by=[workers_tbl.c.id])
Expand Down Expand Up @@ -168,6 +176,7 @@ def thd(conn):
'connected_to': [],
'workerinfo': row.info,
'paused': bool(row.paused),
"pause_reason": row.pause_reason,
'graceful': bool(row.graceful)}
rv[lastId] = res
if row.builderid and row.masterid:
Expand Down Expand Up @@ -229,9 +238,17 @@ def thd(conn):
return self.db.pool.do(thd)

# returns a Deferred that returns None
def setWorkerState(self, workerid, paused, graceful):
def set_worker_paused(self, workerid, paused, pause_reason=None):
def thd(conn):
tbl = self.db.model.workers
q = tbl.update(whereclause=tbl.c.id == workerid)
conn.execute(q, paused=int(paused), graceful=int(graceful))
conn.execute(q, paused=int(paused), pause_reason=pause_reason)
return self.db.pool.do(thd)

# returns a Deferred that returns None
def set_worker_graceful(self, workerid, graceful):
def thd(conn):
tbl = self.db.model.workers
q = tbl.update(whereclause=tbl.c.id == workerid)
conn.execute(q, graceful=int(graceful))
return self.db.pool.do(thd)
3 changes: 3 additions & 0 deletions master/buildbot/spec/types/worker.raml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ properties:
paused:
description: the worker is paused if it is connected but doesn't accept new builds
type: bool
pause_reason?:
description: the reason for pausing the worker, if the worker is paused
type: string
graceful:
description: the worker is graceful if it doesn't accept new builds, and will shutdown when builds are finished
type: bool
Expand Down
13 changes: 9 additions & 4 deletions master/buildbot/test/fake/fakedata.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,11 +448,16 @@ def workerMissing(self, workerid, masterid, last_connection, notify):
def schedulerEnable(self, schedulerid, v):
return self.master.db.schedulers.enable(schedulerid, v)

@defer.inlineCallbacks
def setWorkerState(self, workerid, paused, graceful):
return self.master.db.workers.setWorkerState(
workerid=workerid,
paused=paused,
graceful=graceful)
yield self.master.db.workers.set_worker_paused(workerid=workerid, paused=paused)
yield self.master.db.workers.set_worker_graceful(workerid=workerid, graceful=graceful)

def set_worker_paused(self, workerid, paused, pause_reason=None):
return self.master.db.workers.set_worker_paused(workerid, paused, pause_reason=pause_reason)

def set_worker_graceful(self, workerid, graceful):
return self.master.db.workers.set_worker_graceful(workerid, graceful)

# methods form BuildData resource
@defer.inlineCallbacks
Expand Down
33 changes: 29 additions & 4 deletions master/buildbot/test/fakedb/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,25 @@ class Worker(Row):
id_column = 'id'
required_columns = ('name', )

def __init__(self, id=None, name='some:worker', info=None, paused=0, graceful=0):
def __init__(
self,
id=None,
name='some:worker',
info=None,
paused=0,
pause_reason=None,
graceful=0
):
if info is None:
info = {"a": "b"}
super().__init__(id=id, name=name, info=info, paused=paused, graceful=graceful)
super().__init__(
id=id,
name=name,
info=info,
paused=paused,
pause_reason=pause_reason,
graceful=graceful
)


class ConnectedWorker(Row):
Expand Down Expand Up @@ -69,6 +84,7 @@ def insert_test_data(self, rows):
"id": row.id,
"name": row.name,
"paused": row.paused,
"pause_reason": row.pause_reason,
"graceful": row.graceful,
"info": row.info
}
Expand All @@ -94,7 +110,10 @@ def findWorkerId(self, name):
self.workers[id] = {
"id": id,
"name": name,
"info": {}
"info": {},
"paused": 0,
"pause_reason": None,
"graceful": 0
}
return defer.succeed(id)

Expand Down Expand Up @@ -202,10 +221,15 @@ def workerDisconnected(self, workerid, masterid):
break
return defer.succeed(None)

def setWorkerState(self, workerid, paused, graceful):
def set_worker_paused(self, workerid, paused, pause_reason=None):
worker = self.workers.get(workerid)
if worker is not None:
worker['paused'] = int(paused)
worker['pause_reason'] = pause_reason

def set_worker_graceful(self, workerid, graceful):
worker = self.workers.get(workerid)
if worker is not None:
worker['graceful'] = int(graceful)

def _configuredOn(self, workerid, builderid=None, masterid=None):
Expand Down Expand Up @@ -237,6 +261,7 @@ def _mkdict(self, w, builderid, masterid):
'workerinfo': w['info'],
'name': w['name'],
'paused': bool(w.get('paused')),
'pause_reason': w.get("pause_reason"),
'graceful': bool(w.get('graceful')),
'configured_on': self._configuredOn(w['id'], builderid, masterid),
'connected_to': self._connectedTo(w['id'], masterid),
Expand Down
32 changes: 30 additions & 2 deletions master/buildbot/test/unit/data/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def w1(builderid=None, masterid=None):
'workerinfo': {},
'paused': False,
'graceful': False,
"pause_reason": None,
'connected_to': [
{'masterid': 13},
],
Expand All @@ -93,6 +94,7 @@ def w2(builderid=None, masterid=None):
'name': 'windows',
'workerinfo': {'a': 'b'},
'paused': False,
"pause_reason": None,
'graceful': False,
'connected_to': [
{'masterid': 14},
Expand Down Expand Up @@ -174,6 +176,22 @@ def test_setWorkerState(self):
worker = yield self.callGet(('workers', 2))
self.validateData(worker)
self.assertEqual(worker['paused'], True)
self.assertEqual(worker['graceful'], False)

@defer.inlineCallbacks
def test_set_worker_paused(self):
yield self.master.data.updates.set_worker_paused(2, True, "reason")
worker = yield self.callGet(('workers', 2))
self.validateData(worker)
self.assertEqual(worker['paused'], True)
self.assertEqual(worker["pause_reason"], "reason")

@defer.inlineCallbacks
def test_set_worker_graceful(self):
yield self.master.data.updates.set_worker_graceful(2, True)
worker = yield self.callGet(('workers', 2))
self.validateData(worker)
self.assertEqual(worker['graceful'], True)

@defer.inlineCallbacks
def test_actions(self):
Expand Down Expand Up @@ -244,8 +262,8 @@ def test_get_masterid_builderid(self):
sorted([w2(masterid=13, builderid=41)], key=configuredOnKey))

@defer.inlineCallbacks
def test_setWorkerStateFindByPaused(self):
yield self.master.data.updates.setWorkerState(2, True, False)
def test_set_worker_paused_find_by_paused(self):
yield self.master.data.updates.set_worker_paused(2, True, None)
resultSpec = resultspec.OptimisedResultSpec(
filters=[resultspec.Filter('paused', 'eq', [True])])

Expand Down Expand Up @@ -282,6 +300,16 @@ def test_signature_workerConfigured(self):
def workerConfigured(self, workerid, masterid, builderids):
pass

def test_signature_set_worker_paused(self):
@self.assertArgSpecMatches(self.master.data.updates.set_worker_paused)
def set_worker_paused(self, workerid, paused, pause_reason=None):
pass

def test_signature_set_worker_graceful(self):
@self.assertArgSpecMatches(self.master.data.updates.set_worker_graceful)
def set_worker_graceful(self, workerid, graceful):
pass

def test_findWorkerId(self):
# this just passes through to the db method, so test that
rv = defer.succeed(None)
Expand Down

0 comments on commit 2b8d868

Please sign in to comment.