cloud/bmaas/bmdb: correctly handle installation report

Previously we ignored the result of an installation report.
The bmdb does now store the result and correctly triggers
a recovery flow of the installation fails.

Change-Id: Ie8445cf9178ba84c6362b61ef8fa47208ab690be
Reviewed-on: https://review.monogon.dev/c/monogon/+/1865
Reviewed-by: Serge Bazanski <serge@monogon.tech>
Tested-by: Jenkins CI
diff --git a/cloud/bmaas/server/agent_callback_service.go b/cloud/bmaas/server/agent_callback_service.go
index 27ce9af..97636f7 100644
--- a/cloud/bmaas/server/agent_callback_service.go
+++ b/cloud/bmaas/server/agent_callback_service.go
@@ -14,8 +14,9 @@
 	"google.golang.org/protobuf/proto"
 	"k8s.io/klog/v2"
 
-	"source.monogon.dev/cloud/bmaas/bmdb/model"
 	apb "source.monogon.dev/cloud/bmaas/server/api"
+
+	"source.monogon.dev/cloud/bmaas/bmdb/model"
 	"source.monogon.dev/metropolis/node/core/rpc"
 )
 
@@ -81,10 +82,18 @@
 		}
 	}
 
+	var installRaw []byte
+	if req.InstallationReport != nil {
+		installRaw, err = proto.Marshal(req.InstallationReport)
+		if err != nil {
+			return nil, status.Errorf(codes.InvalidArgument, "could not serialize installation report: %v", err)
+		}
+	}
+
 	// Upsert heartbeat time and hardware report.
 	err = session.Transact(ctx, func(q *model.Queries) error {
 		// Upsert hardware report if submitted.
-		if hwraw != nil {
+		if len(hwraw) != 0 {
 			err = q.MachineSetHardwareReport(ctx, model.MachineSetHardwareReportParams{
 				MachineID:         machineId,
 				HardwareReportRaw: hwraw,
@@ -94,10 +103,21 @@
 			}
 		}
 		// Upsert os installation report if submitted.
-		if req.InstallationReport != nil {
+		if len(installRaw) != 0 {
+			var result model.MachineOsInstallationResult
+			switch req.InstallationReport.Result.(type) {
+			case *apb.OSInstallationReport_Success_:
+				result = model.MachineOsInstallationResultSuccess
+			case *apb.OSInstallationReport_Error_:
+				result = model.MachineOsInstallationResultError
+			default:
+				return fmt.Errorf("unknown installation report result: %T", req.InstallationReport.Result)
+			}
 			err = q.MachineSetOSInstallationReport(ctx, model.MachineSetOSInstallationReportParams{
-				MachineID:  machineId,
-				Generation: req.InstallationReport.Generation,
+				MachineID:               machineId,
+				Generation:              req.InstallationReport.Generation,
+				OsInstallationResult:    result,
+				OsInstallationReportRaw: installRaw,
 			})
 		}
 		return q.MachineSetAgentHeartbeat(ctx, model.MachineSetAgentHeartbeatParams{
diff --git a/cloud/bmaas/server/agent_callback_service_test.go b/cloud/bmaas/server/agent_callback_service_test.go
index 320bb68..3bd3df9 100644
--- a/cloud/bmaas/server/agent_callback_service_test.go
+++ b/cloud/bmaas/server/agent_callback_service_test.go
@@ -11,9 +11,10 @@
 	"google.golang.org/grpc"
 	"google.golang.org/protobuf/proto"
 
+	apb "source.monogon.dev/cloud/bmaas/server/api"
+
 	"source.monogon.dev/cloud/bmaas/bmdb"
 	"source.monogon.dev/cloud/bmaas/bmdb/model"
-	apb "source.monogon.dev/cloud/bmaas/server/api"
 	"source.monogon.dev/cloud/lib/component"
 	"source.monogon.dev/metropolis/node/core/rpc"
 )
@@ -215,7 +216,7 @@
 	}
 
 	// Submit a report, expect no more request.
-	hbr, err = heartbeat(machine.MachineID, &apb.OSInstallationReport{Generation: 123})
+	hbr, err = heartbeat(machine.MachineID, &apb.OSInstallationReport{Generation: 123, Result: &apb.OSInstallationReport_Success_{}})
 	if err != nil {
 		t.Fatalf("heartbeat: %v", err)
 	}