metropolis: implement NodeManagement.Logs

This takes the implementation from the debug service, dusts it off a
bit, adds tests and moves eerything to the new node mgmt service.

Change-Id: Id3b70126a2551775d8328c0c4e424ec0e675f40f
Reviewed-on: https://review.monogon.dev/c/monogon/+/1439
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/pkg/cmd/run.go b/metropolis/pkg/cmd/run.go
index 9f554b5..7834c99 100644
--- a/metropolis/pkg/cmd/run.go
+++ b/metropolis/pkg/cmd/run.go
@@ -33,13 +33,18 @@
 	// after the reader loop is broken, avoid deadlocks by making lineC a
 	// buffered channel.
 	lineC := make(chan string, 2)
-	outBuffer := logbuffer.NewLineBuffer(1024, func(l *logbuffer.Line) {
-		lineC <- l.Data
-	})
+	lineCB := func(l *logbuffer.Line) {
+		// If the context is canceled, no-one is listening on lineC anymore, so we would
+		// block.
+		select {
+		case <-ctx.Done():
+			return
+		case lineC <- l.Data:
+		}
+	}
+	outBuffer := logbuffer.NewLineBuffer(1024, lineCB)
 	defer outBuffer.Close()
-	errBuffer := logbuffer.NewLineBuffer(1024, func(l *logbuffer.Line) {
-		lineC <- l.Data
-	})
+	errBuffer := logbuffer.NewLineBuffer(1024, lineCB)
 	defer errBuffer.Close()
 
 	// Prepare the command context, and start the process.