blob: acf226f46f198bfdeebce0dfa49440c99a344414 [file] [log] [blame]
Serge Bazanskide4e8412023-02-15 23:28:04 +01001package bmdb
2
3import (
Serge Bazanski424e2012023-02-15 23:31:49 +01004 "context"
Serge Bazanskide4e8412023-02-15 23:28:04 +01005 "database/sql"
6 "fmt"
7
Serge Bazanski77628312023-02-15 23:33:22 +01008 "github.com/google/uuid"
Serge Bazanskide4e8412023-02-15 23:28:04 +01009 "k8s.io/klog/v2"
10
11 "source.monogon.dev/cloud/bmaas/bmdb/model"
Serge Bazanski424e2012023-02-15 23:31:49 +010012 "source.monogon.dev/cloud/bmaas/bmdb/reflection"
Serge Bazanskide4e8412023-02-15 23:28:04 +010013)
14
15// Open creates a new Connection to the BMDB for the calling component. Multiple
16// connections can be opened (although there is no advantage to doing so, as
17// Connections manage an underlying CockroachDB connection pool, which performs
18// required reconnects and connection pooling automatically).
19func (b *BMDB) Open(migrate bool) (*Connection, error) {
20 if migrate {
21 if b.Config.Database.Migrations == nil {
22 klog.Infof("Using default migrations source.")
23 m, err := model.MigrationsSource()
24 if err != nil {
25 klog.Exitf("failed to prepare migrations source: %w", err)
26 }
27 b.Config.Database.Migrations = m
28 }
29 if err := b.Database.MigrateUp(); err != nil {
30 return nil, fmt.Errorf("migration failed: %w", err)
31 }
32 }
33 db, err := b.Database.Connect()
34 if err != nil {
35 return nil, err
36 }
37 return &Connection{
38 bmdb: b,
39 db: db,
40
41 DatabaseName: b.Config.Database.DatabaseName,
42 Address: b.Config.Database.EndpointHost,
43 InMemory: b.Config.Database.InMemory,
44 }, nil
45}
46
47// Connection to the BMDB. Internally, this contains a sql.DB connection pool,
48// so components can (and likely should) reuse Connections as much as possible
49// internally.
50type Connection struct {
51 bmdb *BMDB
52 db *sql.DB
53
54 // The database name that we're connected to.
55 DatabaseName string
56 // The address of the CockroachDB endpoint we've connected to.
57 Address string
58 // Whether this connection is to an in-memory database. Note: this only works if
59 // this Connection came directly from calling Open on a BMDB that was defined to
60 // be in-memory. If you just connect to an in-memory CRDB manually, this will
61 // still be false.
62 InMemory bool
63}
Serge Bazanski424e2012023-02-15 23:31:49 +010064
65// Reflect returns a reflection.Schema as detected by inspecting the table
66// information of this connection to the BMDB. The Schema can then be used to
67// retrieve arbitrary tag/machine information without going through the
68// concurrency/ordering mechanism of the BMDB.
69//
70// This should only be used to implement debugging tooling and should absolutely
71// not be in the path of any user requests.
72//
73// This Connection will be used not only to query the Schema information, but
74// also for all subsequent data retrieval operations on it. Please ensure that
75// the Schema is rebuilt in the event of a database connection failure. Ideally,
76// you should be rebuilding the schema often, to follow what is currently
77// available on the production database - but not for every request. Use a cache
78// or something.
79func (c *Connection) Reflect(ctx context.Context) (*reflection.Schema, error) {
80 return reflection.Reflect(ctx, c.db)
81}
Serge Bazanski77628312023-02-15 23:33:22 +010082
83// ListHistoryOf retrieves a full audit history of a machine, sorted
84// chronologically. It can be read without a session / transaction for debugging
85// purposes.
86func (c *Connection) ListHistoryOf(ctx context.Context, machine uuid.UUID) ([]model.WorkHistory, error) {
87 return model.New(c.db).ListHistoryOf(ctx, machine)
88}
89
90// GetSession retrieves all information about a session. It can be read without a
91// session/transaction for debugging purposes.
92func (c *Connection) GetSession(ctx context.Context, session uuid.UUID) ([]model.Session, error) {
93 return model.New(c.db).GetSession(ctx, session)
94}