Skip to content

Commit

Permalink
Merge pull request buildbot#7625 from tdesveaux/typing/db/workers
Browse files Browse the repository at this point in the history
 typing: Add WorkerModel dataclass
  • Loading branch information
p12tic authored May 19, 2024
2 parents acb4470 + ad05759 commit f0a073b
Show file tree
Hide file tree
Showing 11 changed files with 540 additions and 453 deletions.
5 changes: 3 additions & 2 deletions master/buildbot/data/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
if TYPE_CHECKING:
from buildbot.db.builders import BuilderModel
from buildbot.db.builds import BuildModel
from buildbot.db.workers import WorkerModel


class EndpointKind(enum.Enum):
Expand Down Expand Up @@ -200,7 +201,7 @@ def __init__(self, master, args) -> None:
self.build_dict: BuildModel | None | False = False
self.builder_dict: BuilderModel | None | False = False
self.log_dict = False
self.worker_dict = False
self.worker_dict: WorkerModel | None | False = False

@async_to_deferred
async def get_step_dict(self):
Expand Down Expand Up @@ -341,7 +342,7 @@ async def get_log_id(self):
return log_dict['id']

@async_to_deferred
async def get_worker_dict(self):
async def get_worker_dict(self) -> WorkerModel | None:
if self.worker_dict is not False:
return self.worker_dict

Expand Down
2 changes: 1 addition & 1 deletion master/buildbot/data/logchunks.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def get_info():
if build_dict is not None:
log_prefix += f'Build number: {build_dict.number}\n'
if worker_dict is not None:
log_prefix += f'Worker name: {worker_dict["name"]}\n'
log_prefix += f'Worker name: {worker_dict.name}\n'

log_lines = log_prefix + "\n".join([line[1:] for line in log_lines.splitlines()])

Expand Down
25 changes: 15 additions & 10 deletions master/buildbot/data/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#
# Copyright Buildbot Team Members

from __future__ import annotations

from typing import TYPE_CHECKING

from twisted.internet import defer

Expand All @@ -21,20 +24,22 @@
from buildbot.data import types
from buildbot.util import identifiers

if TYPE_CHECKING:
from buildbot.db.workers import WorkerModel


class Db2DataMixin:
def db2data(self, dbdict):
def db2data(self, model: WorkerModel):
return {
'workerid': dbdict['id'],
'name': dbdict['name'],
'workerinfo': dbdict['workerinfo'],
'paused': dbdict['paused'],
"pause_reason": dbdict["pause_reason"],
'graceful': dbdict['graceful'],
'connected_to': [{'masterid': id} for id in dbdict['connected_to']],
'workerid': model.id,
'name': model.name,
'workerinfo': model.workerinfo,
'paused': model.paused,
"pause_reason": model.pause_reason,
'graceful': model.graceful,
'connected_to': [{'masterid': id} for id in model.connected_to],
'configured_on': [
{'masterid': c['masterid'], 'builderid': c['builderid']}
for c in dbdict['configured_on']
{'masterid': c.masterid, 'builderid': c.builderid} for c in model.configured_on
],
}

Expand Down
121 changes: 97 additions & 24 deletions master/buildbot/db/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,74 @@
#
# Copyright Buildbot Team Members

from __future__ import annotations

from dataclasses import dataclass
from dataclasses import field
from typing import TYPE_CHECKING

import sqlalchemy as sa
from twisted.internet import defer

from buildbot.db import base
from buildbot.util import identifiers
from buildbot.warnings import warn_deprecated

if TYPE_CHECKING:
from typing import Any


@dataclass
class BuilderMasterModel:
builderid: int
masterid: int

# For backward compatibility
def __getitem__(self, key: str):
warn_deprecated(
'4.1.0',
(
'WorkersConnectorComponent '
'getWorker, and getWorkers '
'no longer return Worker as dictionnaries. '
'Usage of [] accessor is deprecated: please access the member directly'
),
)

if hasattr(self, key):
return getattr(self, key)

raise KeyError(key)


@dataclass
class WorkerModel:
id: int
name: str
workerinfo: dict[str, Any]
paused: bool = False
pause_reason: str | None = None
graceful: bool = False

configured_on: list[BuilderMasterModel] = field(default_factory=list)
connected_to: list[int] = field(default_factory=list)

# For backward compatibility
def __getitem__(self, key: str):
warn_deprecated(
'4.1.0',
(
'WorkersConnectorComponent '
'getWorker, and getWorkers '
'no longer return Worker as dictionnaries. '
'Usage of [] accessor is deprecated: please access the member directly'
),
)

if hasattr(self, key):
return getattr(self, key)

raise KeyError(key)


class WorkersConnectorComponent(base.DBConnectorComponent):
Expand Down Expand Up @@ -113,7 +176,13 @@ def thd(conn):
return self.db.pool.do(thd)

@defer.inlineCallbacks
def getWorker(self, workerid=None, name=None, masterid=None, builderid=None):
def getWorker(
self,
workerid: int | None = None,
name: str | None = None,
masterid: int | None = None,
builderid: int | None = None,
):
if workerid is None and name is None:
return None
workers = yield self.getWorkers(
Expand All @@ -123,11 +192,16 @@ def getWorker(self, workerid=None, name=None, masterid=None, builderid=None):
return workers[0]
return None

# returns a Deferred that returns a value
def getWorkers(
self, _workerid=None, _name=None, masterid=None, builderid=None, paused=None, graceful=None
):
def thd(conn):
self,
_workerid: int | None = None,
_name: str | None = None,
masterid: int | None = None,
builderid: int | None = None,
paused: bool | None = None,
graceful: bool | None = None,
) -> defer.Deferred[list[WorkerModel]]:
def thd(conn) -> list[WorkerModel]:
workers_tbl = self.db.model.workers
conn_tbl = self.db.model.connected_workers
cfg_tbl = self.db.model.configured_workers
Expand Down Expand Up @@ -167,27 +241,18 @@ def thd(conn):
if graceful is not None:
q = q.where(workers_tbl.c.graceful == int(graceful))

rv = {}
rv: dict[int, WorkerModel] = {}
res = None
lastId = None
cfgs = None
for row in conn.execute(q):
if row.id != lastId:
lastId = row.id
cfgs = []
res = {
'id': lastId,
'name': row.name,
'configured_on': cfgs,
'connected_to': [],
'workerinfo': row.info,
'paused': bool(row.paused),
"pause_reason": row.pause_reason,
'graceful': bool(row.graceful),
}
res = self._model_from_row(row)
rv[lastId] = res
if row.builderid and row.masterid:
cfgs.append({'builderid': row.builderid, 'masterid': row.masterid})
rv[lastId].configured_on.append(
BuilderMasterModel(builderid=row.builderid, masterid=row.masterid)
)

# now go back and get the connection info for the same set of
# workers
Expand All @@ -203,20 +268,18 @@ def thd(conn):
)
.select_from(j)
.order_by(conn_tbl.c.workerid)
.where(conn_tbl.c.workerid.in_(rv.keys()))
)

if _workerid is not None:
q = q.where(conn_tbl.c.workerid == _workerid)
if _name is not None:
q = q.where(workers_tbl.c.name == _name)
if masterid is not None:
q = q.where(conn_tbl.c.masterid == masterid)

for row in conn.execute(q):
id = row.workerid
if id not in rv:
if row.workerid not in rv:
continue
rv[row.workerid]['connected_to'].append(row.masterid)
rv[row.workerid].connected_to.append(row.masterid)

return list(rv.values())

Expand Down Expand Up @@ -265,3 +328,13 @@ def thd(conn):
conn.execute(q.values(graceful=int(graceful)))

return self.db.pool.do(thd)

def _model_from_row(self, row):
return WorkerModel(
id=row.id,
name=row.name,
workerinfo=row.info,
paused=bool(row.paused),
pause_reason=row.pause_reason,
graceful=bool(row.graceful),
)
57 changes: 36 additions & 21 deletions master/buildbot/test/fakedb/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
#
# Copyright Buildbot Team Members

from __future__ import annotations

import json

from twisted.internet import defer

from buildbot.db.workers import BuilderMasterModel
from buildbot.db.workers import WorkerModel
from buildbot.test.fakedb.base import FakeDBComponent
from buildbot.test.fakedb.row import Row
from buildbot.test.util import validation
Expand Down Expand Up @@ -107,17 +110,21 @@ def _getWorkerByName(self, name):
return worker
return None

def getWorker(self, workerid=None, name=None, masterid=None, builderid=None):
def getWorker(
self,
workerid: int | None = None,
name: str | None = None,
masterid: int | None = None,
builderid: int | None = None,
) -> defer.Deferred[WorkerModel | None]:
# get the id and the worker
if workerid is None:
for worker in self.workers.values():
if worker['name'] == name:
workerid = worker['id']
break
else:
worker = None
else:
worker = self.workers.get(workerid)

worker = self.workers.get(workerid)

if not worker:
return defer.succeed(None)
Expand All @@ -126,7 +133,13 @@ def getWorker(self, workerid=None, name=None, masterid=None, builderid=None):
# by builderid and masterid
return defer.succeed(self._mkdict(worker, builderid, masterid))

def getWorkers(self, masterid=None, builderid=None, paused=None, graceful=None):
def getWorkers(
self,
masterid: int | None = None,
builderid: int | None = None,
paused: bool | None = None,
graceful: bool | None = None,
) -> defer.Deferred[list[WorkerModel]]:
if masterid is not None or builderid is not None:
builder_masters = self.db.builders.builder_masters
workers = []
Expand Down Expand Up @@ -223,8 +236,10 @@ def set_worker_graceful(self, workerid, graceful):
if worker is not None:
worker['graceful'] = int(graceful)

def _configuredOn(self, workerid, builderid=None, masterid=None):
cfg = []
def _configuredOn(
self, workerid: int, builderid: int | None = None, masterid: int | None = None
) -> list[BuilderMasterModel]:
cfg: list[BuilderMasterModel] = []
for cs in self.configured.values():
if cs['workerid'] != workerid:
continue
Expand All @@ -233,10 +248,10 @@ def _configuredOn(self, workerid, builderid=None, masterid=None):
continue
if masterid is not None and mid != masterid:
continue
cfg.append({'builderid': bid, 'masterid': mid})
cfg.append(BuilderMasterModel(builderid=bid, masterid=mid))
return cfg

def _connectedTo(self, workerid, masterid=None):
def _connectedTo(self, workerid: int, masterid: int | None = None) -> list[int]:
conns = []
for cs in self.connected.values():
if cs['workerid'] != workerid:
Expand All @@ -246,14 +261,14 @@ def _connectedTo(self, workerid, masterid=None):
conns.append(cs['masterid'])
return conns

def _mkdict(self, w, builderid, masterid):
return {
'id': w['id'],
'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),
}
def _mkdict(self, w, builderid: int | None, masterid: int | None):
return WorkerModel(
id=w['id'],
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),
)
Loading

0 comments on commit f0a073b

Please sign in to comment.