cloud/bmaas/server: init

This adds the BMaaS server alongside its first functionality: serving an
Agent heartbeat API.

This allows (untrusted) Agents to communicate with the rest of the
system by submitting heartbeats which may include a hardware report.

The BMaaS server will likely grow to implement further functionality as
described in its README.

Change-Id: I1ede02121b3700079cbb11295525f4c167ee1e7d
Reviewed-on: https://review.monogon.dev/c/monogon/+/988
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/cloud/bmaas/bmdb/model/migrations/1667232160_agent_tags.up.sql b/cloud/bmaas/bmdb/model/migrations/1667232160_agent_tags.up.sql
index 14701a6..ccf1ab3 100644
--- a/cloud/bmaas/bmdb/model/migrations/1667232160_agent_tags.up.sql
+++ b/cloud/bmaas/bmdb/model/migrations/1667232160_agent_tags.up.sql
@@ -42,5 +42,16 @@
     CONSTRAINT "primary" PRIMARY KEY(machine_id)
 );
 
+-- tag HardwareReport {
+--     Raw []byte
+-- }
+-- Represents a hardware report submitted by an Agent running on a machine.
+-- Usually a report is submitted only once after an agent has been started.
+CREATE TABLE machine_hardware_report (
+    machine_id UUID NOT NULL REFERENCES machines(machine_id) ON DELETE RESTRICT,
+    hardware_report_raw BYTES NOT NULL,
+    CONSTRAINT "primary" PRIMARY KEY(machine_id)
+);
+
 -- Used by the Shepherd when performing direct actions against a machine.
 ALTER TYPE process ADD VALUE IF NOT EXISTS 'ShepherdInstall';
\ No newline at end of file
diff --git a/cloud/bmaas/bmdb/model/queries.sql b/cloud/bmaas/bmdb/model/queries.sql
index 4d15a79..4e32cff 100644
--- a/cloud/bmaas/bmdb/model/queries.sql
+++ b/cloud/bmaas/bmdb/model/queries.sql
@@ -70,6 +70,15 @@
     agent_heartbeat_at = $2
 ;
 
+-- name: MachineSetHardwareReport :exec
+INSERT INTO machine_hardware_report (
+    machine_id, hardware_report_raw
+) VALUES (
+    $1, $2
+) ON CONFLICT (machine_id) DO UPDATE SET
+    hardware_report_raw = $2
+;
+
 -- name: GetMachinesForAgentStart :many
 -- Get machines that need agent installed for the first time. Machine can be
 -- assumed to be 'new', with no previous attempts or failures.
@@ -116,3 +125,12 @@
   )
   AND work.machine_id IS NULL
 LIMIT $1;
+
+-- name: AuthenticateAgentConnection :many
+SELECT
+    machine_agent_started.*
+FROM machines
+INNER JOIN machine_agent_started ON machines.machine_id = machine_agent_started.machine_id
+WHERE
+    machines.machine_id = $1
+    AND machine_agent_started.agent_public_key = $2;
\ No newline at end of file