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