Skip to content

Commit

Permalink
Inventorize disks in eryph storage independently of catlets (#293)
Browse files Browse the repository at this point in the history
* Inventory disks independently of catlets
* Monitor disk stores for changes and trigger inventory
* Use database transactions for Rebus unit-of-work
* Introduce deleted flag for disks
* Block inventory updates when the project is being deleted
* Fix incorrect status tracking in DestroyResourcesSaga

Closes #211
  • Loading branch information
ChristopherMann authored Jan 28, 2025
1 parent 140ab15 commit 738c777
Show file tree
Hide file tree
Showing 65 changed files with 1,513 additions and 677 deletions.
17 changes: 16 additions & 1 deletion src/apps/src/Eryph-zero/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -939,10 +939,25 @@ private static Task<int> ImportAgentSettings(
RunAsAdmin(
from configString in ReadInput(inFile)
from hostSettings in HostSettingsProvider<SimpleConsoleRuntime>.getHostSettings()
from _ in VmHostAgentConfigurationUpdate<SimpleConsoleRuntime>.updateConfig(
from _1 in AnsiConsole<SimpleConsoleRuntime>.writeLine("Updating agent settings...")
from _2 in VmHostAgentConfigurationUpdate<SimpleConsoleRuntime>.updateConfig(
configString,
Path.Combine(ZeroConfig.GetVmHostAgentConfigPath(), "agentsettings.yml"),
hostSettings)
// Check that the sync service is available (and hence the VM host agent is running).
// When the VM host agent is not running, we do not need to sync the configuration.
from canConnect in use(
Eff(() => new CancellationTokenSource(TimeSpan.FromSeconds(2))),
cts => default(SimpleConsoleRuntime).SyncClientEff
.Bind(sc => sc.CheckRunning(cts.Token))
.IfFail(_ => false))
from _3 in canConnect
? from _1 in AnsiConsole<SimpleConsoleRuntime>.writeLine(
"eryph is running. Syncing agent settings...")
from _2 in default(SimpleConsoleRuntime).SyncClientEff.Bind(
sc => sc.SendSyncCommand("SYNC_AGENT_SETTINGS", CancellationToken.None))
select unit
: SuccessAff(unit)
select unit,
SimpleConsoleRuntime.New());

Expand Down
9 changes: 9 additions & 0 deletions src/apps/src/Eryph-zero/SimpleConsoleRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Eryph.AnsiConsole.Sys;
using Eryph.Core;
using Eryph.Core.Sys;
using Eryph.Modules.VmHostAgent;
using Eryph.Modules.VmHostAgent.Inventory;
using Eryph.VmManagement.Inventory;
using Eryph.VmManagement.Sys;
Expand Down Expand Up @@ -38,11 +39,13 @@ public static SimpleConsoleRuntime New() =>
new(new SimpleConsoleRuntimeEnv(
new ZeroApplicationInfoProvider(),
new HardwareIdProvider(new NullLoggerFactory()),
new SyncClient(),
new CancellationTokenSource()));

public SimpleConsoleRuntime LocalCancel => new(new SimpleConsoleRuntimeEnv(
_env.ApplicationInfoProvider,
_env.HardwareIdProvider,
_env.SyncClient,
new CancellationTokenSource()));

public CancellationToken CancellationToken => _env.CancellationTokenSource.Token;
Expand All @@ -65,17 +68,23 @@ public static SimpleConsoleRuntime New() =>
public Eff<SimpleConsoleRuntime, IHardwareIdProvider> HardwareIdProviderEff =>
Eff<SimpleConsoleRuntime, IHardwareIdProvider>(rt => rt._env.HardwareIdProvider);

public Eff<SimpleConsoleRuntime, ISyncClient> SyncClientEff =>
Eff<SimpleConsoleRuntime, ISyncClient>(rt => rt._env.SyncClient);

public Eff<SimpleConsoleRuntime, WmiIO> WmiEff => SuccessEff(LiveWmiIO.Default);
}

public class SimpleConsoleRuntimeEnv(
IApplicationInfoProvider applicationInfoProvider,
IHardwareIdProvider hardwareIdProvider,
ISyncClient syncClient,
CancellationTokenSource cancellationTokenSource)
{
public IApplicationInfoProvider ApplicationInfoProvider { get; } = applicationInfoProvider;

public CancellationTokenSource CancellationTokenSource { get; } = cancellationTokenSource;

public IHardwareIdProvider HardwareIdProvider { get; } = hardwareIdProvider;

public ISyncClient SyncClient { get; } = syncClient;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ public class VmHostAgentDataStoreConfiguration
public string Name { get; init; } = string.Empty;

public string Path { get; init; } = string.Empty;

public bool WatchFileSystem { get; init; } = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ public class VmHostAgentDefaultsConfiguration
public string Vms { get; init; }

public string Volumes { get; init; }

public bool WatchFileSystem { get; init; } = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Eryph.Messages.Resources.Catlets.Commands;

public class RemoveVirtualDiskCommandResponse
{
public DateTimeOffset Timestamp { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Eryph.ConfigModel;
using Eryph.Resources.Machines;

Expand All @@ -11,7 +10,8 @@ public class UpdateInventoryCommand
[PrivateIdentifier]
public string AgentName { get; set; }

public List<VirtualMachineData> Inventory { get; set; }
public VirtualMachineData Inventory { get; set; }

public DateTimeOffset Timestamp { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Eryph.Resources.Disks;
using Eryph.Resources.Machines;
using JetBrains.Annotations;

Expand All @@ -13,6 +14,8 @@ public class UpdateVMHostInventoryCommand

public List<VirtualMachineData> VMInventory { get; set; }

public List<DiskInfo> DiskInventory { get; set; }

public DateTimeOffset Timestamp { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Eryph.Messages.Resources.Commands
public class DestroyResourcesCommand : IGenericResourcesCommand, IHasResources, ICommandWithName
{
public Resource[] Resources { get; set; }

public string GetCommandName() => "Destroy Resources";
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using Eryph.Resources;
using System.Collections.Generic;
using Eryph.Resources;

namespace Eryph.Messages.Resources.Commands
namespace Eryph.Messages.Resources.Commands;

public class DestroyResourcesResponse
{
public class DestroyResourcesResponse
{
public Resource[] DestroyedResources { get; set; }
public Resource[] DetachedResources { get; set; }
}
}
public required IReadOnlyList<Resource> DestroyedResources { get; set; }

public required IReadOnlyList<Resource> DetachedResources { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using Eryph.Resources.Disks;
using System;
using System.Collections.Generic;
using Eryph.Resources.Disks;

namespace Eryph.Messages.Resources.Disks;

public class CheckDisksExistsReply
{
public DiskInfo[] MissingDisks { get; set; }
}
public IReadOnlyList<DiskInfo> MissingDisks { get; set; }

public DateTimeOffset Timestamp { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Eryph.Resources.Disks;

namespace Eryph.Messages.Resources.Disks;

public class UpdateDiskInventoryCommand
{
public string AgentName { get; init; }

public DateTimeOffset Timestamp { get; init; }

public IList<DiskInfo> Inventory { get; init; }
}
61 changes: 61 additions & 0 deletions src/core/src/Eryph.VmManagement/Inventory/DiskStoreInventory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Eryph.Core;
using Eryph.Core.VmAgent;
using Eryph.Resources.Disks;
using Eryph.VmManagement.Storage;
using LanguageExt;
using LanguageExt.Common;

using static LanguageExt.Prelude;
using static LanguageExt.Seq;

namespace Eryph.VmManagement.Inventory;

public static class DiskStoreInventory
{
public static Aff<Seq<Either<Error, DiskInfo>>> InventoryStores(
IFileSystemService fileSystemService,
IPowershellEngine powershellEngine,
VmHostAgentConfiguration vmHostAgentConfig) =>
from _ in SuccessAff(unit)
let storePaths = append(
vmHostAgentConfig.Environments.ToSeq()
.Bind(e => e.Datastores.ToSeq())
.Map(ds => ds.Path),
vmHostAgentConfig.Environments.ToSeq()
.Map(e => e.Defaults.Volumes),
vmHostAgentConfig.Datastores.ToSeq()
.Map(ds => ds.Path),
Seq1(vmHostAgentConfig.Defaults.Volumes))
from diskInfos in storePaths
.Map(storePath => InventoryStore(fileSystemService, powershellEngine, vmHostAgentConfig, storePath))
.SequenceSerial()
select diskInfos.Flatten();

public static Aff<Seq<Either<Error, DiskInfo>>> InventoryStore(
IFileSystemService fileSystemService,
IPowershellEngine powershellEngine,
VmHostAgentConfiguration vmHostAgentConfig,
string path) =>
from vhdFiles in Eff(() => fileSystemService.GetFiles(path, "*.vhdx", SearchOption.AllDirectories))
from diskInfos in vhdFiles.ToSeq()
.Map(vhdFile => InventoryDisk(powershellEngine, vmHostAgentConfig, vhdFile))
.SequenceParallel()
select diskInfos;

private static Aff<Either<Error, DiskInfo>> InventoryDisk(
IPowershellEngine powershellEngine,
VmHostAgentConfiguration vmHostAgentConfig,
string diskPath) =>
from diskSettings in DiskStorageSettings.FromVhdPath(powershellEngine, vmHostAgentConfig, diskPath)
.ToAff(identity)
.Map(Right<Error, DiskStorageSettings>)
| @catch(e => SuccessAff(Left<Error, DiskStorageSettings>(
Error.New($"Inventory of virtual disk '{diskPath}' failed", e))))
select diskSettings.Map(s => s.CreateDiskInfo());
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Name = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
BeingDeleted = table.Column<bool>(type: "tinyint(1)", nullable: false),
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
},
constraints: table =>
Expand All @@ -164,7 +165,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
Environment = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
HardwareId = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
.Annotation("MySql:CharSet", "utf8mb4"),
LastInventory = table.Column<DateTimeOffset>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
Expand Down Expand Up @@ -281,6 +283,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
.Annotation("MySql:CharSet", "utf8mb4"),
DiskIdentifier = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Frozen = table.Column<bool>(type: "tinyint(1)", nullable: false),
Deleted = table.Column<bool>(type: "tinyint(1)", nullable: false),
Path = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
FileName = table.Column<string>(type: "longtext", nullable: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");

b.Property<bool>("BeingDeleted")
.HasColumnType("tinyint(1)");

b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
Expand Down Expand Up @@ -715,6 +718,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.IsRequired()
.HasColumnType("longtext");

b.Property<DateTimeOffset>("LastInventory")
.HasColumnType("datetime(6)");

b.ToTable("CatletFarms");
});

Expand All @@ -726,6 +732,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.IsRequired()
.HasColumnType("longtext");

b.Property<bool>("Deleted")
.HasColumnType("tinyint(1)");

b.Property<Guid>("DiskIdentifier")
.HasColumnType("char(36)");

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 738c777

Please sign in to comment.