Skip to content

Commit

Permalink
Refactor broker and add management commands (#70)
Browse files Browse the repository at this point in the history
* Refactor into a broker abstraction

* Clean up tidbits

* Idk wtf is happening here
  • Loading branch information
UnstoppableMango authored May 12, 2024
1 parent 06b98c9 commit 781df86
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 93 deletions.
11 changes: 5 additions & 6 deletions src/Broker.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
namespace UnMango.Tdl.Broker.Tests;

public class UnitTest1
{
[Fact]
public void Test1()
{

}
{
[Fact]
public void Test1() {

}
}
6 changes: 3 additions & 3 deletions src/Broker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

var socket = builder.Environment.IsDevelopment()
? Path.Combine(Path.GetTempPath(), "broker.sock")
: "/var/run/tdl/broker.sock";

// Would be nice to get rid of the "Overriding address(es) warning"
: "/var/run/tdl/broker.sock";

// Would be nice to get rid of the "Overriding address(es) warning"
builder.WebHost.ConfigureKestrel(kestrel => {
kestrel.ListenUnixSocket(socket, listen => {
listen.Protocols = HttpProtocols.Http2;
Expand Down
2 changes: 1 addition & 1 deletion src/Broker/Services/UmlService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class UmlService : Tdl.UmlService.UmlServiceBase
public override async Task<FromResponse> From(
IAsyncStreamReader<FromRequest> requestStream,
ServerCallContext context) {
await Task.Delay(1); // Get async warning to go away because I'm lazy
await Task.Delay(1); // Get async warning to go away because I'm lazy
return new FromResponse {
Spec = new Spec {
Name = "Hello World!",
Expand Down
9 changes: 4 additions & 5 deletions src/Cli/Broker/BrokerCommands.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.CommandLine;
using UnMango.Tdl.Cli.Docker;
using UnMango.Tdl.Cli.Internal;

namespace UnMango.Tdl.Cli.Broker;
Expand All @@ -8,25 +7,25 @@ internal static class BrokerCommands
{
public static Command Start() {
var command = new Command("start", "Start the broker");
command.SetHandler(Handlers.Start, TokenBinder.Value);
command.SetHandler(Handlers.Start, Binder.Service<IBroker>(), TokenBinder.Value);
return command;
}

public static Command Status() {
var command = new Command("status", "Check the status of the broker");
command.SetHandler(Handlers.Status, Binder.Service<IDocker>(), ConsoleBinder.Value, TokenBinder.Value);
command.SetHandler(Handlers.Status, Binder.Service<IBroker>(), ConsoleBinder.Value, TokenBinder.Value);
return command;
}

public static Command Stop() {
var command = new Command("stop", "Stop the broker");
command.SetHandler(Handlers.Stop, TokenBinder.Value);
command.SetHandler(Handlers.Stop, Binder.Service<IBroker>(), TokenBinder.Value);
return command;
}

public static Command Upgrade() {
var command = new Command("upgrade", "Upgrade the broker");
command.SetHandler(Handlers.Upgrade, TokenBinder.Value);
command.SetHandler(Handlers.Upgrade, Binder.Service<IBroker>(), TokenBinder.Value);
return command;
}
}
85 changes: 85 additions & 0 deletions src/Cli/Broker/DockerBroker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.CommandLine;
using System.Text.RegularExpressions;
using Serilog;
using UnMango.Tdl.Cli.Docker;

namespace UnMango.Tdl.Cli.Broker;

internal static partial class Patterns
{
[GeneratedRegex(".*Application started.*")]
public static partial Regex ApplicationStarted();
}

internal sealed class DockerBroker(IDocker docker) : IBroker
{
private const string OwnerLabel = "tdl.owner", Owner = "tdl-cli";
private static readonly Regex ApplicationStarted = Patterns.ApplicationStarted();

private static readonly IDictionary<string, string> Labels = new Dictionary<string, string> {
[Config.OwnerLabel] = Owner,
};

public async ValueTask<bool> Running(CancellationToken cancellationToken) {
if (File.Exists(Config.Socket)) {
return true;
}

var container = await docker.FindMatching(Labels, cancellationToken);
return container != null;
}

public async ValueTask Start(CancellationToken cancellationToken) {
if (await Running(cancellationToken)) {
Log.Verbose("Broker is already running");
return;
}

var uid = await Config.Uid();
var gid = await Config.Gid();

Log.Debug("Starting broker");
var container = await docker.Start(new StartArgs {
Image = $"{Config.ContainerRepo}/tdl-broker",
Tag = Config.ContainerTag,
User = $"{uid}:{gid}",
Volumes = [$"{Config.SocketDir}:/var/run/tdl"],
Labels = { [OwnerLabel] = Owner },
}, cancellationToken);
Log.Verbose("Started broker");

_ = docker.FollowLogs(container, cancellationToken);
await docker.WaitFor(container, ApplicationStarted.IsMatch, cancellationToken);
}

public async Task<BrokerStatus> Status(CancellationToken cancellationToken) {
var container = await docker.FindMatching(Labels, cancellationToken);
if (container is null) {
return new BrokerStatus {
State = "not found",
Version = "unknown",
};
}

var inspection = await docker.Inspect(container, cancellationToken);
return new BrokerStatus {
Version = inspection.Version,
State = inspection.State,
};
}

public async ValueTask Stop(CancellationToken cancellationToken) {
if (!await Running(cancellationToken))
return;

var container = await docker.FindMatching(Labels, cancellationToken);
if (container is null)
return;

await docker.Stop(container, cancellationToken);
}

public Task Upgrade(string version, CancellationToken cancellationToken) {
throw new NotImplementedException();
}
}
48 changes: 7 additions & 41 deletions src/Cli/Broker/EnsureBroker.cs
Original file line number Diff line number Diff line change
@@ -1,52 +1,18 @@
using System.CommandLine.Invocation;
using System.Text.RegularExpressions;
using System.CommandLine.Parsing;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using UnMango.Tdl.Cli.Docker;

namespace UnMango.Tdl.Cli.Broker;

internal static partial class Patterns
{
[GeneratedRegex(".*Application started.*")]
public static partial Regex ApplicationStarted();
}

internal static class EnsureBroker
{
private const string OwnerLabel = "tdl.owner", Owner = "tdl-cli";
private static readonly Regex ApplicationStarted = Patterns.ApplicationStarted();

public static InvocationMiddleware Middleware => async (context, next) => {
var docker = context.BindingContext.GetRequiredService<IDocker>();
await EnsureStarted(docker, context.GetCancellationToken());
var parentCommand = context.ParseResult.CommandResult.Parent;
if (parentCommand is not CommandResult { Command.Name: "broker" }) {
var broker = context.BindingContext.GetRequiredService<IBroker>();
await broker.Start(context.GetCancellationToken());
}

await next(context);
};

private static Task EnsureStarted(IDocker docker, CancellationToken cancellationToken) {
Log.Verbose("Checking for socket existence");
if (!File.Exists(Config.Socket))
return Start(docker, cancellationToken);

Log.Debug("Socket exists");
return Task.CompletedTask;
}

private static async Task Start(IDocker docker, CancellationToken cancellationToken) {
var uid = await Config.Uid();
var gid = await Config.Gid();

Log.Debug("Starting broker");
var container = await docker.Start(new StartArgs {
Image = $"{Config.ContainerRepo}/tdl-broker",
Tag = Config.ContainerTag,
User = $"{uid}:{gid}",
Volumes = [$"{Config.SocketDir}:/var/run/tdl"],
Labels = { [OwnerLabel] = Owner },
}, cancellationToken);
Log.Verbose("Started broker");

_ = docker.FollowLogs(container, cancellationToken);
await docker.WaitFor(container, ApplicationStarted.IsMatch, cancellationToken);
}
}
50 changes: 25 additions & 25 deletions src/Cli/Broker/Handlers.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
using System.CommandLine;
using UnMango.Tdl.Cli.Docker;
using UnMango.Tdl.Cli.Internal;
using System.Reflection;
using Serilog;

namespace UnMango.Tdl.Cli.Broker;

internal static class Handlers
{
public static Task Start(CancellationToken cancellationToken) {
Console.WriteLine("Not implemented");
return Task.CompletedTask;
public static Task Start(IBroker broker, CancellationToken cancellationToken) {
return broker.Start(cancellationToken).AsTask();
}

public static async Task Status(IDocker docker, IConsole console, CancellationToken cancellationToken) {
var labels = new Dictionary<string, string> {
[Config.OwnerLabel] = Constants.Owner,
};

var container = await docker.FindMatching(labels, cancellationToken);
if (container is null) {
console.WriteLine($"Unable to find matching container: {labels}");
return;
}

var inspection = await docker.Inspect(container, cancellationToken);
console.WriteLine($"Version : {inspection.Version}");
console.WriteLine($"State : {inspection.State}");
public static async Task Status(IBroker broker, IConsole console, CancellationToken cancellationToken) {
var status = await broker.Status(cancellationToken);
console.WriteLine($"Version: {status.Version}");
console.WriteLine($"State: {status.State}");
}

public static Task Stop(CancellationToken cancellationToken) {
Console.WriteLine("Not implemented");
return Task.CompletedTask;
public static Task Stop(IBroker broker, CancellationToken cancellationToken) {
return broker.Stop(cancellationToken).AsTask();
}

public static Task Upgrade(CancellationToken cancellationToken) {
Console.WriteLine("Not implemented");
return Task.CompletedTask;
public static Task Upgrade(IBroker broker, CancellationToken cancellationToken) {
var entryAssembly = Assembly.GetEntryAssembly();
if (entryAssembly is null) {
Log.Error("Failed to retrieve entry assembly");
return Task.CompletedTask;
}

var version = entryAssembly.GetName().Version;
if (version is null) {
Log.Error("Failed to retrieve version");
return Task.CompletedTask;
}

Log.Verbose("Upgrading broker");
return broker.Upgrade(version.ToString(), cancellationToken);
}
}
21 changes: 21 additions & 0 deletions src/Cli/Broker/IBroker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace UnMango.Tdl.Cli.Broker;

public sealed record BrokerStatus
{
public required string State { get; init; }

public required string Version { get; init; }
}

public interface IBroker
{
ValueTask<bool> Running(CancellationToken cancellationToken);

ValueTask Start(CancellationToken cancellationToken);

Task<BrokerStatus> Status(CancellationToken cancellationToken);

ValueTask Stop(CancellationToken cancellationToken);

Task Upgrade(string version, CancellationToken cancellationToken);
}
1 change: 0 additions & 1 deletion src/Cli/Handlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public static async Task<int> Gen(
throw new Exception("Failed waiting for socket");
}


try {
Log.Debug("Sending gen request");
using var stream = client.Gen(new GenRequest(), cancellationToken: cancellationToken);
Expand Down
6 changes: 0 additions & 6 deletions src/Cli/Internal/Constants.cs

This file was deleted.

13 changes: 9 additions & 4 deletions src/Cli/Docker/AddDocker.cs → src/Cli/Internal/Middleware.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
using System.CommandLine.Invocation;
using Docker.DotNet;
using UnMango.Tdl.Cli.Broker;
using UnMango.Tdl.Cli.Docker;

namespace UnMango.Tdl.Cli.Docker;
namespace UnMango.Tdl.Cli.Internal;

internal static class AddDocker
internal static class Middleware
{
public static InvocationMiddleware Middleware => async (context, next) => {
public static InvocationMiddleware Services => async (context, next) => {
// var progress = new ConsoleProgress(context.Console);
var progress = new SerilogProgress();

// Either need to await this method or dispose of this differently
using var client = new DockerClientConfiguration().CreateClient();
var docker = new Docker(client, progress);
var docker = new Docker.Docker(client, progress);
context.BindingContext.AddService<IDocker>(_ => docker);
context.BindingContext.AddService<IBroker>(_ => new DockerBroker(docker));

await next(context);
};
}
3 changes: 2 additions & 1 deletion src/Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using UnMango.Tdl.Cli;
using UnMango.Tdl.Cli.Broker;
using UnMango.Tdl.Cli.Docker;
using UnMango.Tdl.Cli.Internal;

var root = new RootCommand("UnstoppableMango's Type Description Language CLI") {
Commands.Broker(),
Expand All @@ -23,7 +24,7 @@

var builder = new CommandLineBuilder(root).UseDefaults()
.UseExceptionHandler((ex, _) => Log.Fatal(ex, "Invocation error"))
.AddMiddleware(AddDocker.Middleware, MiddlewareOrder.Configuration)
.AddMiddleware(Middleware.Services, MiddlewareOrder.Configuration)
.AddMiddleware(EnsureBroker.Middleware);

Log.Verbose("Building parser");
Expand Down

0 comments on commit 781df86

Please sign in to comment.