m/n/core/mgmt: implement node-local management service

Change-Id: I1e8a8ff46d1172e00f2d991ae3cc3af1929b6e4e
Reviewed-on: https://review.monogon.dev/c/monogon/+/1428
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/node/core/mgmt/mgmt.go b/metropolis/node/core/mgmt/mgmt.go
new file mode 100644
index 0000000..5fa12a0
--- /dev/null
+++ b/metropolis/node/core/mgmt/mgmt.go
@@ -0,0 +1,46 @@
+// Package mgmt implements the node-local management service, a.k.a.
+// metropolis.proto.api.NodeManagement.
+package mgmt
+
+import (
+	"context"
+	"fmt"
+	"net"
+
+	"google.golang.org/grpc"
+
+	"source.monogon.dev/metropolis/node"
+	"source.monogon.dev/metropolis/node/core/identity"
+	"source.monogon.dev/metropolis/node/core/rpc"
+	"source.monogon.dev/metropolis/pkg/supervisor"
+
+	apb "source.monogon.dev/metropolis/proto/api"
+)
+
+type Service struct {
+	NodeCredentials *identity.NodeCredentials
+}
+
+func (s *Service) Run(ctx context.Context) error {
+	sec := rpc.ServerSecurity{
+		NodeCredentials: s.NodeCredentials,
+	}
+	logger := supervisor.MustSubLogger(ctx, "rpc")
+	opts := sec.GRPCOptions(logger)
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", node.NodeManagement))
+	if err != nil {
+		return fmt.Errorf("failed to listen on node management socket socket: %w", err)
+	}
+	defer lis.Close()
+
+	srv := grpc.NewServer(opts...)
+	apb.RegisterNodeManagementServer(srv, s)
+
+	runnable := supervisor.GRPCServer(srv, lis, false)
+	if err := supervisor.Run(ctx, "server", runnable); err != nil {
+		return fmt.Errorf("could not run server: %w", err)
+	}
+	supervisor.Signal(ctx, supervisor.SignalHealthy)
+	<-ctx.Done()
+	return ctx.Err()
+}