- Table Of Contents
- 1. Buildbot Tutorial
- 2. Buildbot Manual
- 2.1. Introduction
- 2.2. Installation
- 2.3. Concepts
- 2.4. Secret Management
- 2.5. Configuration
- 2.5.1. Configuring Buildbot
- 2.5.2. Global Configuration
- 2.5.3. Change Sources and Changes
- 2.5.5. Schedulers
- 2.5.6. Workers
- 2.5.7. Builder Configuration
- 2.5.8. Projects
- 2.5.9. Build Factories
- 2.5.10. Build Sets
- 2.5.11. Properties
- 2.5.12. Build Steps
- 2.5.12.1. Parameters Common to all Steps
- 2.5.12.2. Common Parameters of source checkout operations
- 2.5.12.3. Bzr
- 2.5.12.4. CVS
- 2.5.12.5. Darcs
- 2.5.12.6. Gerrit
- 2.5.12.7. GitHub
- 2.5.12.8. GitLab
- 2.5.12.9. Git
- 2.5.12.10. Mercurial
- 2.5.12.11. Monotone
- 2.5.12.12. P4
- 2.5.12.13. Repo
- 2.5.12.14. SVN
- 2.5.12.15. GitCommit
- 2.5.12.16. GitTag
- 2.5.12.17. GitPush
- 2.5.12.18. GitDiffInfo
- 2.5.12.19. ShellCommand
- 2.5.12.20. Shell Sequence
- 2.5.12.21. Compile
- 2.5.12.21. Compile
- 2.5.12.22. Configure
- 2.5.12.23. CMake
- 2.5.12.24. Visual C++
- 2.5.12.25. Cppcheck
- 2.5.12.26. Robocopy
- 2.5.12.27. Test
- 2.5.12.28. TreeSize
- 2.5.12.29. PerlModuleTest
- 2.5.12.30. SubunitShellCommand
- 2.5.12.31. HLint
- 2.5.12.32. MaxQ
- 2.5.12.33. Trigger
- 2.5.12.34. BuildEPYDoc
- 2.5.12.35. PyFlakes
- 2.5.12.36. Sphinx
- 2.5.12.37. PyLint
- 2.5.12.38. Trial
- 2.5.12.39. RemovePYCs
- 2.5.12.40. HTTP Requests
- 2.5.12.41. Worker Filesystem Steps
- 2.5.12.42. Transferring Files
- 2.5.12.44. MasterShellCommand
- 2.5.12.45. LogRenderable
- 2.5.12.47. SetProperty
- 2.5.12.46. Assert
- 2.5.12.48. SetProperties
- 2.5.12.49. SetPropertyFromCommand
- 2.5.12.51. RpmBuild
- 2.5.12.52. RpmLint
- 2.5.12.53. MockBuildSRPM Step
- 2.5.12.54. MockRebuild
- 2.5.12.55. DebPbuilder
- 2.5.12.57. DebLintian
- 2.5.13. Interlocks
- 2.5.14. Report Generators
- 2.5.15. Reporters
- 2.5.15.1. ReporterBase
- 2.5.15.2. BitbucketServerCoreAPIStatusPush
- 2.5.15.2. BitbucketServerCoreAPIStatusPush
- 2.5.15.3. BitbucketServerPRCommentPush
- 2.5.15.4. BitbucketServerStatusPush
- 2.5.15.6. GerritStatusPush
- 2.5.15.5. BitbucketStatusPush
- 2.5.15.7. GerritVerifyStatusPush
- 2.5.15.9. GitHubStatusPush
- 2.5.15.10. GitLabStatusPush
- 2.5.15.11. HttpStatusPush
- 2.5.15.12. IRC Bot
- 2.5.15.13. MailNotifier
- 2.5.15.14. PushjetNotifier
- 2.5.15.15. PushoverNotifier
- 2.5.15.16. Telegram Bot
- 2.5.15.17. ZulipStatusPush
- 2.5.16. Web Server
- 2.5.17. Change Hooks
- 2.5.18. Custom Services
- 2.5.19. DbConfig
- 2.5.20. Configurators
- 2.5.21. Manhole
- 2.5.22. Multimaster
- 2.5.23. Multiple-Codebase Builds
- 2.5.24. Miscellaneous Configuration
- 2.5.25. Testing Utilities
- 2.6. Customization
- 2.7. Command-line Tool
- 2.8. Resources
- 2.9. Optimization
- 2.10. Plugin Infrastructure in Buildbot
- 2.11. Deployment
- 2.12. Upgrading
- 3. Buildbot Development
- 3.1. Development Quick-start
- 3.2. Submitting Pull Requests
- 3.3. General Documents
- 3.3.1. Master Organization
- 3.3.2. Buildbot Coding Style
- 3.3.3. Buildbot’s Test Suite
- 3.3.4. Configuration
- 3.3.6. Writing Schedulers
- 3.3.7. Utilities
- 3.3.8. Build Result Codes
- 3.3.9. WWW Server
- 3.3.10. Javascript Data Module
- 3.3.11. Base web application
- 3.3.12. Authentication
- 3.3.13. Authorization
- 3.3.14. Master-Worker API
- 3.3.15. Master-Worker connection with MessagePack over WebSocket protocol
- 3.3.16. Claiming Build Requests
- 3.3.17. String Encodings
- 3.3.18. Metrics
- 3.3.19. Secrets
- 3.3.22. Statistics Service
- 3.3.23. How to package Buildbot plugins
- 3.4. REST API
- 3.5. REST API Specification
- 3.5.1. builder
- 3.5.2. buildrequest
- 3.5.3. build
- 3.5.4. buildset
- 3.5.5. build_data
- 3.5.6. change
- 3.5.7. changesource
- 3.5.8. forcescheduler
- 3.5.9. identifier
- 3.5.10. logchunk
- 3.5.11. log
- 3.5.12. master
- 3.5.13. patch
- 3.5.14. project
- 3.5.15. rootlink
- 3.5.16. scheduler
- 3.5.17. sourcedproperties
- 3.5.18. sourcestamp
- 3.5.19. spec
- 3.5.20. step
- 3.5.21. worker
- 3.5.22. test_result
- 3.5.23. testresultset
- 3.5.24. Raw endpoints
- 3.6. Data API
- 3.7. Database
- 3.8.1. Buildsets connector
- 3.8.2. Buildrequests connector
- 3.8.3. Builders connector
- 3.8.4. Builds connector
- 3.8.5. Build data connector
- 3.8.6. Steps connector
- 3.8.7. Logs connector
- 3.8.8. Changes connector
- 3.8.9. Change sources connector
- 3.8.10. Schedulers connector
- 3.8.11. Source stamps connector
- 3.8.12. State connector
- 3.8.13. Users connector
- 3.8.14. Masters connector
- 3.8.15. Workers connector
- 3.8. Database connectors API
- 3.9. Messaging and Queues
- 3.10. Classes
- 3.10.1. Builds
- 3.10.2. Workers
- 3.10.3. BuildFactory
- 3.10.4. Change Sources
- 3.10.5. RemoteCommands
- 3.10.6. BuildSteps
- 3.10.7. BaseScheduler
- 3.10.8. ForceScheduler
- 3.10.9. IRenderable
- 3.10.10. IProperties
- 3.10.11. IConfigurator
- 3.10.12. ResultSpecs
- 3.10.13. Protocols
- 3.10.14. WorkerManager
- 3.10.15. Logs
- 3.10.16. LogObservers
- 3.10.17. Authentication
- 3.10.18. Avatars
- 3.10.19. Web Server Classes
- 4. Release Notes
- 6. API Indices
- Release Notes
- 5.1. Buildbot 2.10.5 ( 2021-04-05 )
- 5.29. Release Notes for Buildbot 1.8.2 ( 2019-05-22 )
- 5.42. Release Notes for Buildbot 0.9.15.post1 ( 2018-01-07 )
- 5.60. Release Notes for Buildbot 0.9.1
- 5.61. Release Notes for Buildbot 0.9.0
- 5.62. Release Notes for Buildbot 0.9.0rc4
- 5.63. Release Notes for Buildbot 0.9.0rc3
- 5.64. Release Notes for Buildbot 0.9.0rc2
- 5.65. Release Notes for Buildbot 0.9.0rc1
- 5.66. Release Notes for Buildbot 0.9.0b9
- 5.67. Release Notes for Buildbot 0.9.0b8
- 5.68. Release Notes for Buildbot 0.9.0b7
- 5.69. Release Notes for Buildbot 0.9.0b6
- 5.70. Release Notes for Buildbot 0.9.0b5
- 5.71. Release Notes for Buildbot 0.9.0b4
- 5.72. Release Notes for Buildbot 0.9.0b3
- 5.73. Release Notes for Buildbot 0.9.0b2
- 5.74. Release Notes for Buildbot 0.9.0b1
- 5.75. Release Notes for Buildbot 0.8.11
- 5.76. Release Notes for Buildbot 0.8.10
- 5.77. Release Notes for Buildbot 0.8.9
- 5.78. Release Notes for Buildbot v0.8.8
- 5.79. Release Notes for Buildbot v0.8.7
- 5.80. Release Notes for Buildbot v0.8.6p1
- Other
3.7. Database
Caution
Buildbot no longer supports Python 2.7 on the Buildbot master.
3.7. Database
Buildbot stores most of its state in a database. This section describes the database connector classes, which allow other parts of Buildbot to access the database. It also describes how to modify the database schema and the connector classes themselves.
3.7.1. Database Overview
All access to the Buildbot database is mediated by database connector classes. These classes provide a functional, asynchronous interface to other parts of Buildbot, and encapsulate the database-specific details in a single location in the codebase.
The connector API, defined below, is a stable API in Buildbot, and can be called from any other component. Given a master master
, the root of the database connectors is available at master.db
, so, for example, the state connector’s getState
method is master.db.state.getState
.
All the connectors use SQLAlchemy Core to achieve (almost) database-independent operation. Note that the SQLAlchemy ORM is not used in Buildbot. Database queries are carried out in threads, and report their results back to the main thread via Twisted Deferreds.
3.7.2. Schema
Changes to the schema are accomplished through migration scripts, supported by Alembic.
The schema itself is considered an implementation detail, and may change significantly from version to version. Users should rely on the API (below), rather than performing queries against the database itself.
3.7.3. Identifier
Restrictions on many string fields in the database are referred to as the Identifier concept. An “identifier” is a nonempty unicode string of limited length, containing only UTF-8 alphanumeric characters along with -
(dash) and _
(underscore), and not beginning with a digit. Wherever an identifier is used, the documentation will give the maximum length in characters. The function buildbot.util.identifiers.isIdentifier
is useful to verify a well-formed identifier.
3.7.4. Writing Database Connector Methods
The information above is intended for developers working on the rest of Buildbot, and treating the database layer as an abstraction. The remainder of this section describes the internals of the database implementation, and is intended for developers modifying the schema or adding new methods to the database layer.
Warning
It’s difficult to change the database schema, especially after it has been released. Changing the database API is disruptive to users. Consider very carefully the future-proofing of any changes here!
3.7.4.1. The DB Connector and Components
- class buildbot.db.connector.DBConnector
The connectors all use SQLAlchemy Core as a wrapper around database client drivers. Unfortunately, SQLAlchemy is a synchronous library, so some extra work is required to use it in an asynchronous context, like in Buildbot. This is accomplished by deferring all database operations to threads, and returning a Deferred. The
Pool
class takes care of the details.A connector method should look like this:
def myMethod(self, arg1, arg2): def thd(conn): q = ... # construct a query for row in conn.execute(q): ... # do something with the results return ... # return an interesting value return self.db.pool.do(thd)
Picking that apart, the body of the method defines a function named
thd
taking one argument, aConnection
object. It then callsself.db.pool.do
, passing thethd
function. This function is called in a thread, and can make blocking calls to SQLAlchemy as desired. Thedo
method will return a Deferred that will fire with the return value ofthd
, or with a failure representing any exception raised bythd
.The return value of
thd
must not be an SQLAlchemy object - in particular, anyResultProxy
objects must be parsed into lists or other data structures before they are returned.Warning
As the name
thd
indicates, the function runs in a thread. It should not interact with any other part of Buildbot, nor with any of the Twisted components that expect to be accessed from the main thread – the reactor, Deferreds, etc.Queries can be constructed using any of the SQLAlchemy core methods, using tables from
Database connector methods access the database through SQLAlchemy, which requires access to Python objects representing the database tables. That is handled through the model.
- class buildbot.db.model.Model
Connector component methods that get an object based on an ID are good candidates for caching. The
It goes without saying that any new connector methods must be fully tested!
You will also want to add an in-memory implementation of the methods to the fake classes in
master/buildbot/test/fake/fakedb.py
. Non-DB Buildbot code is tested using these fake implementations in order to isolate that code from the database code, and to speed-up tests.The keys and types used in the return value from a connector’s
get
methods are described in master/buildbot/test/util/validation.py, via thedbdict
module-level value. This is a dictionary ofDictValidator
objects, one for each return value.These values are used within test methods like this:
rv = yield self.db.masters.getMaster(7) validation.verifyDbDict(self, 'masterdict', rv)
3.7.5. Modifying the Database Schema
Changes to the schema are accomplished through migration scripts, supported by Alembic.
The schema is tracked by a revision number, stored in the
alembic_version
table. It can be anything, but by convention Buildbot uses revision numbers that are numbers incremented by one for each revision. The master will refuse to run with an outdated database.To make a change to the schema, first consider how to handle any existing data. When adding new columns, this may not be necessary, but table refactorings can be complex and require caution so as not to lose information.
Refer to the documentation of Alembic for details of how database migration scripts should be written.
The database schema itself is stored in master/buildbot/db/model.py which should be updated to represent the new schema. Buildbot’s automated tests perform a rudimentary comparison of an upgraded database with the model, but it is important to check the details - key length, nullability, and so on can sometimes be missed by the checks. If the schema and the upgrade scripts get out of sync, bizarre behavior can result.
Changes to database schema should be reflected in corresponding fake database table definitions in master/buildbot/test/fakedb
The upgrade scripts should have unit tests. The classes in master/buildbot/test/util/migration.py make this straightforward. Unit test scripts should be named e.g.,
test_db_migrate_versions_015_remove_bad_master_objectid.py
.The master/buildbot/test/integration/test_upgrade.py also tests upgrades, and will confirm that the resulting database matches the model. If you encounter implicit indexes on MySQL, that do not appear on SQLite or Postgres, add them to
implied_indexes
inmaster/buidlbot/db/model.py
.3.7.6. Foreign key checking
PostgreSQL and SQlite db backends check the foreign keys consistency. bug #2248 needs to be fixed so that we can support foreign key checking for MySQL.
To maintain consistency with real db, fakedb can check the foreign key consistency of your test data. For this, just enable it with:
self.db = fakedb.FakeDBConnector(self.master, self) self.db.checkForeignKeys = True
Note that tests that only use fakedb do not really need foreign key consistency, even if this is a good practice to enable it in new code.
3.7.7. Database Compatibility Notes
Or: “If you thought any database worked right, think again”
Because Buildbot works over a wide range of databases, it is generally limited to database features present in all supported backends. This section highlights a few things to watch out for.
In general, Buildbot should be functional on all supported database backends. If use of a backend adds minor usage restrictions, or cannot implement some kinds of error checking, that is acceptable if the restrictions are well-documented in the manual.
The metabuildbot tests Buildbot against all supported databases, so most compatibility errors will be caught before a release.
3.7.7.1. Index Length in MySQL
MySQL only supports about 330-character indexes. The actual index length is 1000 bytes, but MySQL uses 3-byte encoding for UTF8 strings. This is a longstanding bug in MySQL - see “Specified key was too long; max key length is 1000 bytes” with utf8. While this makes sense for indexes used for record lookup, it limits the ability to use unique indexes to prevent duplicate rows.
InnoDB only supports indexes up to 255 unicode characters, which is why all indexed columns are limited to 255 characters in Buildbot.
3.7.7.2. Transactions in MySQL
Unfortunately, use of the MyISAM storage engine precludes real transactions in MySQL.
transaction.commit()
andtransaction.rollback()
are essentially no-ops: modifications to data in the database are visible to other users immediately, and are not reverted in a rollback.3.7.7.3. Referential Integrity in SQLite and MySQL
Neither MySQL nor SQLite enforce referential integrity based on foreign keys. Postgres does enforce it, however. If possible, test your changes on Postgres before committing, to check that tables are added and removed in the proper order.
3.7.7.4. Subqueries in MySQL
MySQL’s query planner is easily confused by subqueries. For example, a DELETE query specifying id’s that are IN a subquery will not work. The workaround is to run the subquery directly, and then execute a DELETE query for each returned id.
If this weakness has a significant performance impact, it would be acceptable to conditionalize use of the subquery on the database dialect.
3.7.7.5. Too Many Variables in SQLite
Sqlite has a limitation on the number of variables it can use. This limitation is usually SQLITE_LIMIT_VARIABLE_NUMBER=999. There is currently no way with pysqlite to query the value of this limit. The C-api
sqlite_limit
is just not bound to the python.When you hit this problem, you will get error like the following:
sqlalchemy.exc.OperationalError: (OperationalError) too many SQL variables u'DELETE FROM scheduler_changes WHERE scheduler_changes.changeid IN (?, ?, ?, ..., ?)
You can use the method
doBatch
in order to write batching code in a consistent manner.3.7.8. Testing migrations with real databases
By default Buildbot test suite uses SQLite database for testing database migrations. To use other database set
BUILDBOT_TEST_DB_URL
environment variable to value in SQLAlchemy database URL specification.For example, to run tests with file-based SQLite database you can start tests in the following way:
BUILDBOT_TEST_DB_URL=sqlite:////tmp/test_db.sqlite trial buildbot.test
3.7.8.1. Run databases in Docker
Docker allows to easily install and configure different databases locally in containers.
To run tests with PostgreSQL:
# Install psycopg pip install psycopg2 # Start container with PostgreSQL 9.5 # It will listen on port 15432 on localhost sudo docker run --name bb-test-postgres -e POSTGRES_PASSWORD=password \ -p 127.0.0.1:15432:5432 -d postgres:9.5 # Start interesting tests BUILDBOT_TEST_DB_URL=postgresql://postgres:password@localhost:15432/postgres \ trial buildbot.test
To run tests with MySQL:
# Install mysqlclient pip install mysqlclient # Start container with MySQL 5.5 # It will listen on port 13306 on localhost sudo docker run --name bb-test-mysql -e MYSQL_ROOT_PASSWORD=password \ -p 127.0.0.1:13306:3306 -d mysql:5.5 # Start interesting tests BUILDBOT_TEST_DB_URL=mysql+mysqldb://root:password@127.0.0.1:13306/mysql \ trial buildbot.test
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论