cloud/bmaas: implement BMDB reflection

This is the foundation for runtime introspection of BMDBs, to be used in
debug and operator tooling.

Change-Id: Id1eb0cd1dfd94c5d4dafde82448695497525e24f
Reviewed-on: https://review.monogon.dev/c/monogon/+/1131
Tested-by: Jenkins CI
Reviewed-by: Leopold Schabel <leo@monogon.tech>
diff --git a/cloud/bmaas/bmdb/connection.go b/cloud/bmaas/bmdb/connection.go
index 3db869d..c07bf15 100644
--- a/cloud/bmaas/bmdb/connection.go
+++ b/cloud/bmaas/bmdb/connection.go
@@ -1,12 +1,14 @@
 package bmdb
 
 import (
+	"context"
 	"database/sql"
 	"fmt"
 
 	"k8s.io/klog/v2"
 
 	"source.monogon.dev/cloud/bmaas/bmdb/model"
+	"source.monogon.dev/cloud/bmaas/bmdb/reflection"
 )
 
 // Open creates a new Connection to the BMDB for the calling component. Multiple
@@ -58,3 +60,21 @@
 	// still be false.
 	InMemory bool
 }
+
+// Reflect returns a reflection.Schema as detected by inspecting the table
+// information of this connection to the BMDB. The Schema can then be used to
+// retrieve arbitrary tag/machine information without going through the
+// concurrency/ordering mechanism of the BMDB.
+//
+// This should only be used to implement debugging tooling and should absolutely
+// not be in the path of any user requests.
+//
+// This Connection will be used not only to query the Schema information, but
+// also for all subsequent data retrieval operations on it. Please ensure that
+// the Schema is rebuilt in the event of a database connection failure. Ideally,
+// you should be rebuilding the schema often, to follow what is currently
+// available on the production database - but not for every request. Use a cache
+// or something.
+func (c *Connection) Reflect(ctx context.Context) (*reflection.Schema, error) {
+	return reflection.Reflect(ctx, c.db)
+}