Skip to content

Commit 55dcd24

Browse files
database: Add vitess + mysql 8.0 to our development environment
1 parent 88ed5e7 commit 55dcd24

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+567
-216
lines changed

.github/workflows/boulder-ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,19 @@ jobs:
5454
- "./t.sh --unit --enable-race-detection"
5555
- "./tn.sh --unit --enable-race-detection"
5656
- "./t.sh --start-py"
57+
# Same cases but backed by Vitess + MySQL 8 instead of ProxySQL + MariaDB
58+
- "./t.sh --use-vitess --integration"
59+
- "./tn.sh --use-vitess --integration"
60+
- "./t.sh --use-vitess --unit --enable-race-detection"
61+
- "./tn.sh --use-vitess --unit --enable-race-detection"
62+
- "./t.sh --use-vitess --start-py"
5763

5864
env:
5965
# This sets the docker image tag for the boulder-tools repository to
6066
# use in tests. It will be set appropriately for each tag in the list
6167
# defined in the matrix.
6268
BOULDER_TOOLS_TAG: ${{ matrix.BOULDER_TOOLS_TAG }}
69+
BOULDER_VTCOMBOSERVER_TAG: vitessv22.0.0_2025-11-03
6370

6471
# Sequence of tasks that will be executed as part of the job.
6572
steps:

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,16 @@ test/proxysql/*.log*
4343

4444
# Coverage files
4545
test/coverage
46+
47+
# Database config symlinks
48+
sa/db/dbconfig.yml
49+
test/secrets/backfiller_dburl
50+
test/secrets/badkeyrevoker_dburl
51+
test/secrets/cert_checker_dburl
52+
test/secrets/expiration_mailer_dburl
53+
test/secrets/incidents_dburl
54+
test/secrets/mailer_dburl
55+
test/secrets/ocsp_responder_dburl
56+
test/secrets/revoker_dburl
57+
test/secrets/sa_dburl
58+
test/secrets/sa_ro_dburl

docker-compose.yml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ services:
5050
- 4001:4001 # ACMEv2
5151
- 4003:4003 # SFE
5252
depends_on:
53-
- bmysql
53+
- bmariadb
5454
- bproxysql
55+
- bvitess
5556
- bredis_1
5657
- bredis_2
5758
- bconsul
@@ -74,12 +75,12 @@ services:
7475
# with a "docker compose up bsetup".
7576
- setup
7677

77-
bmysql:
78+
bmariadb:
7879
image: mariadb:10.11.13
7980
networks:
8081
bouldernet:
8182
aliases:
82-
- boulder-mysql
83+
- boulder-mariadb
8384
environment:
8485
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
8586
# Send slow queries to a table so we can check for them in the
@@ -101,7 +102,7 @@ services:
101102
volumes:
102103
- ./test/:/test/:cached
103104
depends_on:
104-
- bmysql
105+
- bmariadb
105106
networks:
106107
bouldernet:
107108
aliases:
@@ -144,6 +145,21 @@ services:
144145
networks:
145146
- bouldernet
146147

148+
bvitess:
149+
# The `letsencrypt/boulder-vtcomboserver:latest` tag is automatically built
150+
# in local dev environments. In CI a specific BOULDER_VTCOMBOSERVER_TAG is
151+
# passed, and it is pulled with `docker compose pull`.
152+
image: letsencrypt/boulder-vtcomboserver:${BOULDER_VTCOMBOSERVER_TAG:-latest}
153+
environment:
154+
# By specifying KEYSPACES vttestserver will create the corresponding
155+
# databases on startup.
156+
KEYSPACES: boulder_sa_test,boulder_sa_integration,incidents_sa_test,incidents_sa_integration
157+
NUM_SHARDS: 1,1,1,1
158+
networks:
159+
bouldernet:
160+
aliases:
161+
- boulder-vitess
162+
147163
networks:
148164
# This network represents the data-center internal network. It is used for
149165
# boulder services and their infrastructure, such as consul, mariadb, and

sa/database.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,6 @@ func adjustMySQLConfig(conf *mysql.Config) error {
201201
}
202202
}
203203

204-
// If a given parameter has the value "0", delete it from conf.Params.
205-
omitZero := func(name string) {
206-
if conf.Params[name] == "0" {
207-
delete(conf.Params, name)
208-
}
209-
}
210-
211204
// Ensures that MySQL/MariaDB warnings are treated as errors. This
212205
// avoids a number of nasty edge conditions we could wander into.
213206
// Common things this discovers includes places where data being sent
@@ -216,26 +209,6 @@ func adjustMySQLConfig(conf *mysql.Config) error {
216209
// <https://dev.mysql.com/doc/refman/5.0/en/sql-mode.html#sql-mode-strict>.
217210
setDefault("sql_mode", "'STRICT_ALL_TABLES'")
218211

219-
// If a read timeout is set, we set max_statement_time to 95% of that, and
220-
// long_query_time to 80% of that. That way we get logs of queries that are
221-
// close to timing out but not yet doing so, and our queries get stopped by
222-
// max_statement_time before timing out the read. This generates clearer
223-
// errors, and avoids unnecessary reconnects.
224-
// To override these values, set them in the DSN, e.g.
225-
// `?max_statement_time=2`. A zero value in the DSN means these won't be
226-
// sent on new connections.
227-
if conf.ReadTimeout != 0 {
228-
// In MariaDB, max_statement_time and long_query_time are both seconds,
229-
// but can have up to microsecond granularity.
230-
// Note: in MySQL (which we don't use), max_statement_time is millis.
231-
readTimeout := conf.ReadTimeout.Seconds()
232-
setDefault("max_statement_time", fmt.Sprintf("%.6f", readTimeout*0.95))
233-
setDefault("long_query_time", fmt.Sprintf("%.6f", readTimeout*0.80))
234-
}
235-
236-
omitZero("max_statement_time")
237-
omitZero("long_query_time")
238-
239212
// Finally, perform validation over all variables set by the DSN and via Boulder.
240213
for k, v := range conf.Params {
241214
err := checkMariaDBSystemVariables(k, v)

sa/database_test.go

Lines changed: 10 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,38 @@ import (
44
"context"
55
"database/sql"
66
"errors"
7+
"fmt"
78
"os"
89
"path"
910
"strings"
1011
"testing"
1112
"time"
1213

13-
"github.com/go-sql-driver/mysql"
1414
"github.com/letsencrypt/boulder/cmd"
1515
"github.com/letsencrypt/boulder/config"
1616
"github.com/letsencrypt/boulder/test"
1717
"github.com/letsencrypt/boulder/test/vars"
1818
)
1919

20+
var dbHost = os.Getenv("MYSQL_ADDR")
21+
2022
func TestInvalidDSN(t *testing.T) {
2123
_, err := DBMapForTest("invalid")
2224
test.AssertError(t, err, "DB connect string missing the slash separating the database name")
2325

24-
DSN := "policy:password@tcp(boulder-proxysql:6033)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&stringVarThatDoesntExist=%27whoopsidaisies"
26+
DSN := fmt.Sprintf("policy:password@tcp(%s)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&stringVarThatDoesntExist=%%27whoopsidaisies", dbHost)
2527
_, err = DBMapForTest(DSN)
2628
test.AssertError(t, err, "Variable does not exist in curated system var list, but didn't return an error and should have")
2729

28-
DSN = "policy:password@tcp(boulder-proxysql:6033)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&concurrent_insert=2"
30+
DSN = fmt.Sprintf("policy:password@tcp(%s)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&concurrent_insert=2", dbHost)
2931
_, err = DBMapForTest(DSN)
3032
test.AssertError(t, err, "Variable is unable to be set in the SESSION scope, but was declared")
3133

32-
DSN = "policy:password@tcp(boulder-proxysql:6033)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&optimizer_switch=incorrect-quoted-string"
34+
DSN = fmt.Sprintf("policy:password@tcp(%s)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&optimizer_switch=incorrect-quoted-string", dbHost)
3335
_, err = DBMapForTest(DSN)
3436
test.AssertError(t, err, "Variable declared with incorrect quoting")
3537

36-
DSN = "policy:password@tcp(boulder-proxysql:6033)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&concurrent_insert=%272%27"
38+
DSN = fmt.Sprintf("policy:password@tcp(%s)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms&concurrent_insert=%%272%%27", dbHost)
3739
_, err = DBMapForTest(DSN)
3840
test.AssertError(t, err, "Integer enum declared, but should not have been quoted")
3941
}
@@ -76,7 +78,7 @@ func TestDbSettings(t *testing.T) {
7678
}
7779
dsnFile := path.Join(t.TempDir(), "dbconnect")
7880
err := os.WriteFile(dsnFile,
79-
[]byte("sa@tcp(boulder-proxysql:6033)/boulder_sa_integration"),
81+
[]byte(fmt.Sprintf("sa@tcp(%s)/boulder_sa_integration", dbHost)),
8082
os.ModeAppend)
8183
test.AssertNotError(t, err, "writing dbconnect file")
8284

@@ -107,8 +109,8 @@ func TestDbSettings(t *testing.T) {
107109

108110
// TODO: Change this to test `newDbMapFromMySQLConfig` instead?
109111
func TestNewDbMap(t *testing.T) {
110-
const mysqlConnectURL = "policy:password@tcp(boulder-proxysql:6033)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms"
111-
const expected = "policy:password@tcp(boulder-proxysql:6033)/boulder_policy_integration?clientFoundRows=true&parseTime=true&readTimeout=800ms&writeTimeout=800ms&long_query_time=0.640000&max_statement_time=0.760000&sql_mode=%27STRICT_ALL_TABLES%27"
112+
mysqlConnectURL := fmt.Sprintf("policy:password@tcp(%s)/boulder_policy_integration?readTimeout=800ms&writeTimeout=800ms", dbHost)
113+
expected := fmt.Sprintf("policy:password@tcp(%s)/boulder_policy_integration?clientFoundRows=true&parseTime=true&readTimeout=800ms&writeTimeout=800ms&sql_mode=%%27STRICT_ALL_TABLES%%27", dbHost)
112114
oldSQLOpen := sqlOpen
113115
defer func() {
114116
sqlOpen = oldSQLOpen
@@ -146,27 +148,6 @@ func TestStrictness(t *testing.T) {
146148
}
147149
}
148150

149-
func TestTimeouts(t *testing.T) {
150-
dbMap, err := DBMapForTest(vars.DBConnSA + "?max_statement_time=1")
151-
if err != nil {
152-
t.Fatal("Error setting up DB:", err)
153-
}
154-
// SLEEP is defined to return 1 if it was interrupted, but we want to actually
155-
// get an error to simulate what would happen with a slow query. So we wrap
156-
// the SLEEP in a subselect.
157-
_, err = dbMap.ExecContext(ctx, `SELECT 1 FROM (SELECT SLEEP(5)) as subselect;`)
158-
if err == nil {
159-
t.Fatal("Expected error when running slow query, got none.")
160-
}
161-
162-
// We expect to get:
163-
// Error 1969: Query execution was interrupted (max_statement_time exceeded)
164-
// https://mariadb.com/kb/en/mariadb/mariadb-error-codes/
165-
if !strings.Contains(err.Error(), "Error 1969") {
166-
t.Fatalf("Got wrong type of error: %s", err)
167-
}
168-
}
169-
170151
// TestAutoIncrementSchema tests that all of the tables in the boulder_*
171152
// databases that have auto_increment columns use BIGINT for the data type. Our
172153
// data is too big for INT.
@@ -185,45 +166,3 @@ func TestAutoIncrementSchema(t *testing.T) {
185166
test.AssertNotError(t, err, "unexpected err querying columns")
186167
test.AssertEquals(t, count, int64(0))
187168
}
188-
189-
func TestAdjustMySQLConfig(t *testing.T) {
190-
conf := &mysql.Config{}
191-
err := adjustMySQLConfig(conf)
192-
test.AssertNotError(t, err, "unexpected err setting server variables")
193-
test.AssertDeepEquals(t, conf.Params, map[string]string{
194-
"sql_mode": "'STRICT_ALL_TABLES'",
195-
})
196-
197-
conf = &mysql.Config{ReadTimeout: 100 * time.Second}
198-
err = adjustMySQLConfig(conf)
199-
test.AssertNotError(t, err, "unexpected err setting server variables")
200-
test.AssertDeepEquals(t, conf.Params, map[string]string{
201-
"sql_mode": "'STRICT_ALL_TABLES'",
202-
"max_statement_time": "95.000000",
203-
"long_query_time": "80.000000",
204-
})
205-
206-
conf = &mysql.Config{
207-
ReadTimeout: 100 * time.Second,
208-
Params: map[string]string{
209-
"max_statement_time": "0",
210-
},
211-
}
212-
err = adjustMySQLConfig(conf)
213-
test.AssertNotError(t, err, "unexpected err setting server variables")
214-
test.AssertDeepEquals(t, conf.Params, map[string]string{
215-
"sql_mode": "'STRICT_ALL_TABLES'",
216-
"long_query_time": "80.000000",
217-
})
218-
219-
conf = &mysql.Config{
220-
Params: map[string]string{
221-
"max_statement_time": "0",
222-
},
223-
}
224-
err = adjustMySQLConfig(conf)
225-
test.AssertNotError(t, err, "unexpected err setting server variables")
226-
test.AssertDeepEquals(t, conf.Params, map[string]string{
227-
"sql_mode": "'STRICT_ALL_TABLES'",
228-
})
229-
}

sa/db-next/boulder_sa/20230419000003_OrderToAuthzID.sql

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ CREATE TABLE `orderToAuthz2` (
99
PRIMARY KEY (`id`),
1010
KEY `orderID_idx` (`orderID`),
1111
KEY `authzID_idx` (`authzID`)
12-
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4
13-
PARTITION BY RANGE (`id`)
14-
(PARTITION p_start VALUES LESS THAN (MAXVALUE));
12+
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4;
1513

1614
-- +migrate Down
1715
-- SQL section 'Down' is executed when this migration is rolled back
@@ -22,6 +20,4 @@ CREATE TABLE `orderToAuthz2` (
2220
`authzID` bigint(20) NOT NULL,
2321
PRIMARY KEY (`orderID`,`authzID`),
2422
KEY `authzID` (`authzID`)
25-
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
26-
PARTITION BY RANGE COLUMNS(orderID, authzID)
27-
(PARTITION p_start VALUES LESS THAN (MAXVALUE, MAXVALUE));
23+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

0 commit comments

Comments
 (0)