Serge Bazanski | de4e841 | 2023-02-15 23:28:04 +0100 | [diff] [blame] | 1 | package bmdb |
| 2 | |
| 3 | import ( |
Serge Bazanski | 424e201 | 2023-02-15 23:31:49 +0100 | [diff] [blame] | 4 | "context" |
Serge Bazanski | de4e841 | 2023-02-15 23:28:04 +0100 | [diff] [blame] | 5 | "database/sql" |
| 6 | "fmt" |
| 7 | |
Serge Bazanski | 7762831 | 2023-02-15 23:33:22 +0100 | [diff] [blame] | 8 | "github.com/google/uuid" |
Serge Bazanski | de4e841 | 2023-02-15 23:28:04 +0100 | [diff] [blame] | 9 | "k8s.io/klog/v2" |
| 10 | |
| 11 | "source.monogon.dev/cloud/bmaas/bmdb/model" |
Serge Bazanski | 424e201 | 2023-02-15 23:31:49 +0100 | [diff] [blame] | 12 | "source.monogon.dev/cloud/bmaas/bmdb/reflection" |
Serge Bazanski | de4e841 | 2023-02-15 23:28:04 +0100 | [diff] [blame] | 13 | ) |
| 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). |
| 19 | func (b *BMDB) Open(migrate bool) (*Connection, error) { |
Serge Bazanski | c8fc902 | 2023-02-20 15:28:12 +0100 | [diff] [blame^] | 20 | if b.Config.Database.Migrations == nil { |
| 21 | klog.Infof("Using default migrations source.") |
| 22 | m, err := model.MigrationsSource() |
| 23 | if err != nil { |
| 24 | klog.Exitf("failed to prepare migrations source: %w", err) |
Serge Bazanski | de4e841 | 2023-02-15 23:28:04 +0100 | [diff] [blame] | 25 | } |
Serge Bazanski | c8fc902 | 2023-02-20 15:28:12 +0100 | [diff] [blame^] | 26 | b.Config.Database.Migrations = m |
| 27 | } |
| 28 | if migrate { |
Serge Bazanski | de4e841 | 2023-02-15 23:28:04 +0100 | [diff] [blame] | 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. |
| 50 | type 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 Bazanski | 424e201 | 2023-02-15 23:31:49 +0100 | [diff] [blame] | 64 | |
| 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. |
| 79 | func (c *Connection) Reflect(ctx context.Context) (*reflection.Schema, error) { |
| 80 | return reflection.Reflect(ctx, c.db) |
| 81 | } |
Serge Bazanski | 7762831 | 2023-02-15 23:33:22 +0100 | [diff] [blame] | 82 | |
| 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. |
| 86 | func (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. |
| 92 | func (c *Connection) GetSession(ctx context.Context, session uuid.UUID) ([]model.Session, error) { |
| 93 | return model.New(c.db).GetSession(ctx, session) |
| 94 | } |