-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootstrap.go
81 lines (67 loc) · 2.3 KB
/
bootstrap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Copyright 2022 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package database
import (
"context"
"database/sql"
"github.com/juju/errors"
"github.com/juju/juju/database/app"
"github.com/juju/juju/database/schema"
)
type bootstrapOptFactory interface {
// EnsureDataDir ensures that a directory for Dqlite data exists at
// a path determined by the agent config, then returns that path.
EnsureDataDir() (string, error)
// WithLoopbackAddressOption returns a Dqlite application
// Option that will bind Dqlite to the loopback IP.
WithLoopbackAddressOption() app.Option
// WithLogFuncOption returns a Dqlite application Option
// that will proxy Dqlite log output via this factory's
// logger where the level is recognised.
WithLogFuncOption() app.Option
}
// BootstrapDqlite opens a new database for the controller, and runs the
// DDL to create its schema.
//
// It accepts an optional list of functions to perform operations on the
// controller database.
//
// At this point we know there are no peers and that we are the only user
// of Dqlite, so we can eschew external address and clustering concerns.
// Those will be handled by the db-accessor worker.
func BootstrapDqlite(ctx context.Context, opt bootstrapOptFactory, logger Logger, ops ...func(db *sql.DB) error) error {
dir, err := opt.EnsureDataDir()
if err != nil {
return errors.Trace(err)
}
dqlite, err := app.New(dir, opt.WithLoopbackAddressOption(), opt.WithLogFuncOption())
if err != nil {
return errors.Annotate(err, "creating Dqlite app")
}
defer func() {
if err := dqlite.Close(); err != nil {
logger.Errorf("closing dqlite: %v", err)
}
}()
if err := dqlite.Ready(ctx); err != nil {
return errors.Annotatef(err, "waiting for Dqlite readiness")
}
db, err := dqlite.Open(ctx, "controller")
if err != nil {
return errors.Annotatef(err, "opening controller database")
}
defer func() {
if err := db.Close(); err != nil {
logger.Errorf("closing controller database: %v", err)
}
}()
if err := NewDBMigration(db, logger, schema.ControllerDDL()).Apply(); err != nil {
return errors.Annotate(err, "creating controller database schema")
}
for i, op := range ops {
if err := op(db); err != nil {
return errors.Annotatef(err, "running bootstrap operation at index %d", i)
}
}
return nil
}