diff --git a/Directory.Packages.props b/Directory.Packages.props
index 90e587f1..663c0087 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -19,6 +19,7 @@
+
diff --git a/src/Aspirate.Cli/Properties/launchSettings.json b/src/Aspirate.Cli/Properties/launchSettings.json
index 277f475a..f4d60186 100644
--- a/src/Aspirate.Cli/Properties/launchSettings.json
+++ b/src/Aspirate.Cli/Properties/launchSettings.json
@@ -3,7 +3,7 @@
"init": {
"commandName": "Project",
"commandLineArgs": "init",
- "workingDirectory": "/Users/prom3theu5/git/test-compose/AspireSample/AspireSample.AppHost",
+ "workingDirectory": "C:\\Users\\MKvamm\\source\\repos\\RIS\\src\\Ris.AppHost",
"hotReloadEnabled": false
},
"init-non-interactive": {
@@ -14,8 +14,8 @@
},
"generate": {
"commandName": "Project",
- "commandLineArgs": "generate --skip-build --output-format compose",
- "workingDirectory": "/Users/prom3theu5/git/tests/new-test/AspireSample/AspireSample.AppHost",
+ "commandLineArgs": "generate --skip-build",
+ "workingDirectory": "C:\\Users\\MKvamm\\source\\repos\\RIS\\src\\Ris.AppHost",
"hotReloadEnabled": false
},
"generate-non-interactive": {
@@ -51,7 +51,7 @@
"apply": {
"commandName": "Project",
"commandLineArgs": "apply",
- "workingDirectory": "/Users/prom3theu5/git/tests/new-test/AspireSample/AspireSample.AppHost",
+ "workingDirectory": "C:\\Users\\MKvamm\\source\\repos\\RIS\\src\\Ris.AppHost",
"hotReloadEnabled": false
},
"apply-non-interactive": {
@@ -63,7 +63,7 @@
"destroy": {
"commandName": "Project",
"commandLineArgs": "destroy",
- "workingDirectory": "/Users/prom3theu5/git/test-compose/AspireSample/AspireSample.AppHost",
+ "workingDirectory": "C:\\Users\\MKvamm\\source\\repos\\RIS\\src\\Ris.AppHost",
"hotReloadEnabled": false
},
"destroy-non-interactive": {
@@ -73,4 +73,4 @@
"hotReloadEnabled": false
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Aspirate.Cli/Templates/deployment.hbs b/src/Aspirate.Cli/Templates/deployment.hbs
index c1bb7710..57d821f9 100644
--- a/src/Aspirate.Cli/Templates/deployment.hbs
+++ b/src/Aspirate.Cli/Templates/deployment.hbs
@@ -78,7 +78,7 @@ spec:
{{#each bindMounts}}
- name: bindmount-{{@index}}
hostPath:
- path: {{source}}
+ path: /mnt{{target}}
type: DirectoryOrCreate
{{/each}}
{{/if}}
\ No newline at end of file
diff --git a/src/Aspirate.Commands/Actions/BindMounts/ApplyMinikubeMountsAction.cs b/src/Aspirate.Commands/Actions/BindMounts/ApplyMinikubeMountsAction.cs
new file mode 100644
index 00000000..72b42b92
--- /dev/null
+++ b/src/Aspirate.Commands/Actions/BindMounts/ApplyMinikubeMountsAction.cs
@@ -0,0 +1,39 @@
+using System.Reflection.Metadata.Ecma335;
+using Aspirate.Shared.Models.AspireManifests.Components.Common;
+using Aspirate.Shared.Models.AspireManifests.Components.Common.Container;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Aspirate.Commands.Actions.BindMounts;
+public sealed class ApplyMinikubeMountsAction(
+ IServiceProvider serviceProvider,
+ IMinikubeCliService minikubeCliService) : BaseAction(serviceProvider)
+{
+ public override async Task ExecuteAsync()
+ {
+ Logger.WriteRuler("[purple]Handling minikube mounts[/]");
+ await Task.Run(HandleMinikubeMounts);
+
+ return true;
+ }
+ private void HandleMinikubeMounts()
+ {
+ if (CurrentState.KubeContext != "minikube" || CurrentState.DisableMinikubeMountAction.Equals(true))
+ {
+ return;
+ }
+
+ Logger.MarkupLine("Applying volume mounts to minikube...");
+
+ var minikubeCliInstalled = minikubeCliService.IsMinikubeCliInstalledOnMachine();
+
+ if (!minikubeCliInstalled)
+ {
+ Logger.MarkupLine("[yellow]Minikube cli is required to perform Minikube volume mounts.[/]");
+ Logger.MarkupLine("[yellow]Please install minikube cli following the guide here:[blue]https://minikube.sigs.k8s.io/docs/start/?arch=%2Fwindows%2Fx86-64%2Fstable%2F.exe+download/[/][/]");
+ Logger.MarkupLine("[yellow]Manifest deployment will continue, but Minikube volume mounts will not be applied by aspirate.[/]");
+ return;
+ }
+
+ minikubeCliService.ActivateMinikubeMount(CurrentState);
+ }
+}
diff --git a/src/Aspirate.Commands/Actions/BindMounts/KillMinikubeMountsAction.cs b/src/Aspirate.Commands/Actions/BindMounts/KillMinikubeMountsAction.cs
new file mode 100644
index 00000000..24eb38a1
--- /dev/null
+++ b/src/Aspirate.Commands/Actions/BindMounts/KillMinikubeMountsAction.cs
@@ -0,0 +1,27 @@
+using System.Reflection.Metadata.Ecma335;
+using Aspirate.Shared.Models.AspireManifests.Components.Common;
+using Aspirate.Shared.Models.AspireManifests.Components.Common.Container;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Aspirate.Commands.Actions.BindMounts;
+public sealed class KillMinikubeMountsAction(
+ IServiceProvider serviceProvider,
+ IMinikubeCliService minikubeCliService) : BaseAction(serviceProvider)
+{
+ public override async Task ExecuteAsync()
+ {
+ Logger.WriteRuler("[purple]Handling minikube mounts[/]");
+
+ await Task.Run(HandleMinikubeMounts);
+
+ return true;
+ }
+ private void HandleMinikubeMounts()
+ {
+ if (minikubeCliService.IsMinikubeCliInstalledOnMachine() && (CurrentState.DisableMinikubeMountAction.Equals(false) || !CurrentState.DisableMinikubeMountAction.HasValue))
+ {
+ minikubeCliService.KillMinikubeMounts(CurrentState);
+ Logger.MarkupLine($"[green]({EmojiLiterals.CheckMark}) Done:[/] Killed minikube mount processes [blue][/]");
+ }
+ }
+}
diff --git a/src/Aspirate.Commands/Actions/BindMounts/SaveBindMountsAction.cs b/src/Aspirate.Commands/Actions/BindMounts/SaveBindMountsAction.cs
new file mode 100644
index 00000000..c7844b4c
--- /dev/null
+++ b/src/Aspirate.Commands/Actions/BindMounts/SaveBindMountsAction.cs
@@ -0,0 +1,42 @@
+using System.Reflection.Metadata.Ecma335;
+using Aspirate.Shared.Models.AspireManifests.Components.Common;
+using Aspirate.Shared.Models.AspireManifests.Components.Common.Container;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Aspirate.Commands.Actions.BindMounts;
+public sealed class SaveBindMountsAction(
+ IServiceProvider serviceProvider) : BaseAction(serviceProvider)
+{
+ public override Task ExecuteAsync()
+ {
+ if (CurrentState.DisableMinikubeMountAction.Equals(false) || !CurrentState.DisableMinikubeMountAction.HasValue)
+ {
+ var values = new Dictionary>();
+ foreach (var resource in CurrentState.AllSelectedSupportedComponents)
+ {
+ var resourceWithBindMounts = resource.Value as IResourceWithBindMounts;
+
+ if (resourceWithBindMounts?.BindMounts.Count > 0)
+ {
+ foreach (var bindMount in resourceWithBindMounts.BindMounts)
+ {
+ if (!values.ContainsKey(bindMount.Source))
+ {
+ values[bindMount.Source] = [];
+ }
+ values[bindMount.Source].TryAdd(bindMount.Target, null);
+ }
+
+ //values.Add(resourceWithBindMounts.Name, resourceWithBindMounts.BindMounts);
+ }
+ }
+
+ if (values.Count > 0)
+ {
+ CurrentState.BindMounts = values;
+ }
+ }
+
+ return Task.FromResult(true);
+ }
+}
diff --git a/src/Aspirate.Commands/Actions/Manifests/RemoveManifestsFromClusterAction.cs b/src/Aspirate.Commands/Actions/Manifests/RemoveManifestsFromClusterAction.cs
index 08024d91..1d8aecd6 100644
--- a/src/Aspirate.Commands/Actions/Manifests/RemoveManifestsFromClusterAction.cs
+++ b/src/Aspirate.Commands/Actions/Manifests/RemoveManifestsFromClusterAction.cs
@@ -5,6 +5,7 @@ public sealed class RemoveManifestsFromClusterAction(
IServiceProvider serviceProvider,
IFileSystem fileSystem,
IDaprCliService daprCliService,
+ IMinikubeCliService minikubeCliService,
ISecretProvider secretProvider) :
BaseActionWithNonInteractiveValidation(serviceProvider)
{
@@ -20,6 +21,7 @@ public override async Task ExecuteAsync()
CreateEmptySecretFiles(secretFiles);
await kubeCtlService.RemoveManifests(CurrentState.KubeContext, CurrentState.InputPath);
+
Logger.MarkupLine(
$"[green]({EmojiLiterals.CheckMark}) Done:[/] Deployments removed from cluster [blue]'{CurrentState.KubeContext}'[/]");
diff --git a/src/Aspirate.Commands/Commands/Apply/ApplyCommand.cs b/src/Aspirate.Commands/Commands/Apply/ApplyCommand.cs
index e757fafe..24543f6a 100644
--- a/src/Aspirate.Commands/Commands/Apply/ApplyCommand.cs
+++ b/src/Aspirate.Commands/Commands/Apply/ApplyCommand.cs
@@ -10,5 +10,6 @@ public ApplyCommand() : base("apply", "Apply the generated kustomize manifest to
AddOption(KubernetesContextOption.Instance);
AddOption(SecretPasswordOption.Instance);
AddOption(RollingRestartOption.Instance);
+ AddOption(DisableMinikubeMountActionOption.Instance);
}
}
diff --git a/src/Aspirate.Commands/Commands/Apply/ApplyCommandHandler.cs b/src/Aspirate.Commands/Commands/Apply/ApplyCommandHandler.cs
index 850e3730..7b63ef90 100644
--- a/src/Aspirate.Commands/Commands/Apply/ApplyCommandHandler.cs
+++ b/src/Aspirate.Commands/Commands/Apply/ApplyCommandHandler.cs
@@ -1,9 +1,12 @@
+using Aspirate.Commands.Actions.BindMounts;
+
namespace Aspirate.Commands.Commands.Apply;
public sealed class ApplyCommandHandler(IServiceProvider serviceProvider) : BaseCommandOptionsHandler(serviceProvider)
{
public override Task HandleAsync(ApplyOptions optionses) =>
ActionExecutor
+ .QueueAction(nameof(ApplyMinikubeMountsAction))
.QueueAction(nameof(ApplyManifestsToClusterAction))
.ExecuteCommandsAsync();
}
diff --git a/src/Aspirate.Commands/Commands/Apply/ApplyOptions.cs b/src/Aspirate.Commands/Commands/Apply/ApplyOptions.cs
index c3bd7a0e..1434601e 100644
--- a/src/Aspirate.Commands/Commands/Apply/ApplyOptions.cs
+++ b/src/Aspirate.Commands/Commands/Apply/ApplyOptions.cs
@@ -1,8 +1,9 @@
namespace Aspirate.Commands.Commands.Apply;
-public sealed class ApplyOptions : BaseCommandOptions, IKubernetesOptions, IApplyOptions
+public sealed class ApplyOptions : BaseCommandOptions, IKubernetesOptions, IApplyOptions, IMinikubeOptions
{
public string? InputPath { get; set; }
public string? KubeContext { get; set; }
public bool? RollingRestart { get; set; }
+ public bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Commands/Commands/Destroy/DestroyCommand.cs b/src/Aspirate.Commands/Commands/Destroy/DestroyCommand.cs
index 8233c53a..ddbc4624 100644
--- a/src/Aspirate.Commands/Commands/Destroy/DestroyCommand.cs
+++ b/src/Aspirate.Commands/Commands/Destroy/DestroyCommand.cs
@@ -8,5 +8,6 @@ public DestroyCommand() : base("destroy", "Removes the manifests from your clust
{
AddOption(InputPathOption.Instance);
AddOption(KubernetesContextOption.Instance);
+ AddOption(DisableMinikubeMountActionOption.Instance);
}
}
diff --git a/src/Aspirate.Commands/Commands/Destroy/DestroyCommandHandler.cs b/src/Aspirate.Commands/Commands/Destroy/DestroyCommandHandler.cs
index dfc1e3d5..c9015c68 100644
--- a/src/Aspirate.Commands/Commands/Destroy/DestroyCommandHandler.cs
+++ b/src/Aspirate.Commands/Commands/Destroy/DestroyCommandHandler.cs
@@ -1,3 +1,5 @@
+using Aspirate.Commands.Actions.BindMounts;
+
namespace Aspirate.Commands.Commands.Destroy;
public sealed class DestroyCommandHandler(IServiceProvider serviceProvider) : BaseCommandOptionsHandler(serviceProvider)
@@ -5,5 +7,6 @@ public sealed class DestroyCommandHandler(IServiceProvider serviceProvider) : Ba
public override Task HandleAsync(DestroyOptions options) =>
ActionExecutor
.QueueAction(nameof(RemoveManifestsFromClusterAction))
+ .QueueAction(nameof(KillMinikubeMountsAction))
.ExecuteCommandsAsync();
}
diff --git a/src/Aspirate.Commands/Commands/Destroy/DestroyOptions.cs b/src/Aspirate.Commands/Commands/Destroy/DestroyOptions.cs
index b939aa56..3d1616cc 100644
--- a/src/Aspirate.Commands/Commands/Destroy/DestroyOptions.cs
+++ b/src/Aspirate.Commands/Commands/Destroy/DestroyOptions.cs
@@ -1,7 +1,8 @@
namespace Aspirate.Commands.Commands.Destroy;
-public sealed class DestroyOptions : BaseCommandOptions, IKubernetesOptions
+public sealed class DestroyOptions : BaseCommandOptions, IKubernetesOptions, IMinikubeOptions
{
public string? InputPath { get; set; }
public string? KubeContext { get; set; }
+ public bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Commands/Commands/Generate/GenerateCommand.cs b/src/Aspirate.Commands/Commands/Generate/GenerateCommand.cs
index 3e30dc7e..1b019783 100644
--- a/src/Aspirate.Commands/Commands/Generate/GenerateCommand.cs
+++ b/src/Aspirate.Commands/Commands/Generate/GenerateCommand.cs
@@ -32,5 +32,6 @@ public GenerateCommand() : base("generate", "Builds, pushes containers, generate
AddOption(ComposeBuildsOption.Instance);
AddOption(ReplaceSecretsOption.Instance);
AddOption(ParameterResourceValueOption.Instance);
+ AddOption(DisableMinikubeMountActionOption.Instance);
}
}
diff --git a/src/Aspirate.Commands/Commands/Generate/GenerateCommandHandler.cs b/src/Aspirate.Commands/Commands/Generate/GenerateCommandHandler.cs
index 2b2573ff..3410a747 100644
--- a/src/Aspirate.Commands/Commands/Generate/GenerateCommandHandler.cs
+++ b/src/Aspirate.Commands/Commands/Generate/GenerateCommandHandler.cs
@@ -1,3 +1,5 @@
+using Aspirate.Commands.Actions.BindMounts;
+
namespace Aspirate.Commands.Commands.Generate;
public sealed class GenerateCommandHandler(IServiceProvider serviceProvider) : BaseCommandOptionsHandler(serviceProvider)
@@ -30,7 +32,8 @@ private ActionExecutor BaseGenerateActionSequence() =>
.QueueAction(nameof(PopulateContainerDetailsForProjectsAction))
.QueueAction(nameof(BuildAndPushContainersFromProjectsAction))
.QueueAction(nameof(BuildAndPushContainersFromDockerfilesAction))
- .QueueAction(nameof(SaveSecretsAction));
+ .QueueAction(nameof(SaveSecretsAction))
+ .QueueAction(nameof(SaveBindMountsAction));
private ActionExecutor BaseKubernetesActionSequence() =>
BaseGenerateActionSequence()
diff --git a/src/Aspirate.Commands/Commands/Generate/GenerateOptions.cs b/src/Aspirate.Commands/Commands/Generate/GenerateOptions.cs
index 1ea40237..802dc8a1 100644
--- a/src/Aspirate.Commands/Commands/Generate/GenerateOptions.cs
+++ b/src/Aspirate.Commands/Commands/Generate/GenerateOptions.cs
@@ -7,7 +7,8 @@ public sealed class GenerateOptions : BaseCommandOptions,
IGenerateOptions,
IPrivateRegistryCredentialsOptions,
IDashboardOptions,
- ISecretState
+ ISecretState,
+ IMinikubeOptions
{
public string? ProjectPath { get; set; }
public string? AspireManifest { get; set; }
@@ -34,4 +35,5 @@ public sealed class GenerateOptions : BaseCommandOptions,
public bool? WithPrivateRegistry { get; set; }
public bool? IncludeDashboard { get; set; }
public bool? ReplaceSecrets { get; set; }
+ public bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Commands/Commands/Run/RunCommand.cs b/src/Aspirate.Commands/Commands/Run/RunCommand.cs
index ffe9a6c5..5b67b1ae 100644
--- a/src/Aspirate.Commands/Commands/Run/RunCommand.cs
+++ b/src/Aspirate.Commands/Commands/Run/RunCommand.cs
@@ -27,5 +27,6 @@ public RunCommand() : base("run", "Builds, pushes containers, and runs the curre
AddOption(PrivateRegistryEmailOption.Instance);
AddOption(IncludeDashboardOption.Instance);
AddOption(AllowClearNamespaceOption.Instance);
+ AddOption(DisableMinikubeMountActionOption.Instance);
}
}
diff --git a/src/Aspirate.Commands/Commands/Run/RunCommandHandler.cs b/src/Aspirate.Commands/Commands/Run/RunCommandHandler.cs
index 1a077006..a4867f9a 100644
--- a/src/Aspirate.Commands/Commands/Run/RunCommandHandler.cs
+++ b/src/Aspirate.Commands/Commands/Run/RunCommandHandler.cs
@@ -1,3 +1,5 @@
+using Aspirate.Commands.Actions.BindMounts;
+
namespace Aspirate.Commands.Commands.Run;
public sealed class RunCommandHandler(IServiceProvider serviceProvider) : BaseCommandOptionsHandler(serviceProvider)
@@ -16,7 +18,9 @@ public override Task HandleAsync(RunOptions options) =>
.QueueAction(nameof(BuildAndPushContainersFromDockerfilesAction))
.QueueAction(nameof(AskImagePullPolicyAction))
.QueueAction(nameof(SaveSecretsAction))
+ .QueueAction(nameof(SaveBindMountsAction))
.QueueAction(nameof(CustomNamespaceAction))
+ .QueueAction(nameof(ApplyMinikubeMountsAction))
.QueueAction(nameof(RunKubernetesObjectsAction))
.ExecuteCommandsAsync();
}
diff --git a/src/Aspirate.Commands/Commands/Run/RunOptions.cs b/src/Aspirate.Commands/Commands/Run/RunOptions.cs
index bdfd2870..d0de88e7 100644
--- a/src/Aspirate.Commands/Commands/Run/RunOptions.cs
+++ b/src/Aspirate.Commands/Commands/Run/RunOptions.cs
@@ -5,7 +5,8 @@ public sealed class RunOptions : BaseCommandOptions,
IAspireOptions,
IPrivateRegistryCredentialsOptions,
IDashboardOptions,
- IRunOptions
+ IRunOptions,
+ IMinikubeOptions
{
public string? ProjectPath { get; set; }
public string? AspireManifest { get; set; }
@@ -26,4 +27,5 @@ public sealed class RunOptions : BaseCommandOptions,
public string? PrivateRegistryEmail { get; set; }
public bool? WithPrivateRegistry { get; set; }
public bool? IncludeDashboard { get; set; }
+ public bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Commands/Commands/Stop/StopCommandHandler.cs b/src/Aspirate.Commands/Commands/Stop/StopCommandHandler.cs
index 64a3c8ad..89ac251a 100644
--- a/src/Aspirate.Commands/Commands/Stop/StopCommandHandler.cs
+++ b/src/Aspirate.Commands/Commands/Stop/StopCommandHandler.cs
@@ -1,3 +1,5 @@
+using Aspirate.Commands.Actions.BindMounts;
+
namespace Aspirate.Commands.Commands.Stop;
public sealed class StopCommandHandler(IServiceProvider serviceProvider) : BaseCommandOptionsHandler(serviceProvider)
@@ -5,5 +7,6 @@ public sealed class StopCommandHandler(IServiceProvider serviceProvider) : BaseC
public override Task HandleAsync(StopOptions options) =>
ActionExecutor
.QueueAction(nameof(StopDeployedKubernetesInstanceAction))
+ .QueueAction(nameof(KillMinikubeMountsAction))
.ExecuteCommandsAsync();
}
diff --git a/src/Aspirate.Commands/Options/DisableMinikubeMountActionOption.cs b/src/Aspirate.Commands/Options/DisableMinikubeMountActionOption.cs
new file mode 100644
index 00000000..0bb0ff50
--- /dev/null
+++ b/src/Aspirate.Commands/Options/DisableMinikubeMountActionOption.cs
@@ -0,0 +1,21 @@
+namespace Aspirate.Commands.Options;
+public sealed class DisableMinikubeMountActionOption : BaseOption
+{
+ private static readonly string[] _aliases =
+ [
+ "-dm",
+ "--disable-minikube-mount"
+ ];
+
+ private DisableMinikubeMountActionOption() : base(_aliases, "ASPIRATE_DISABLE_MINIKUBE_MOUNT_ACTION", null)
+ {
+ Name = nameof(IMinikubeOptions.DisableMinikubeMountAction);
+ Description = "Disables minikube mount actions";
+ Arity = ArgumentArity.ZeroOrOne;
+ IsRequired = false;
+ }
+
+ public static DisableMinikubeMountActionOption Instance { get; } = new();
+
+ public override bool IsSecret => false;
+}
diff --git a/src/Aspirate.Commands/ServiceCollectionExtensions.cs b/src/Aspirate.Commands/ServiceCollectionExtensions.cs
index ee7415a3..ac649d3d 100644
--- a/src/Aspirate.Commands/ServiceCollectionExtensions.cs
+++ b/src/Aspirate.Commands/ServiceCollectionExtensions.cs
@@ -1,4 +1,6 @@
-namespace Aspirate.Commands;
+using Aspirate.Commands.Actions.BindMounts;
+
+namespace Aspirate.Commands;
///
/// Extension methods for IServiceCollection to register services for AspirateState and AspirateActions.
@@ -40,11 +42,14 @@ public static IServiceCollection AddAspirateActions(this IServiceCollection serv
.RegisterAction()
.RegisterAction()
.RegisterAction()
+ .RegisterAction()
.RegisterAction()
.RegisterAction()
.RegisterAction()
.RegisterAction()
.RegisterAction()
+ .RegisterAction()
+ .RegisterAction()
.RegisterAction();
///
diff --git a/src/Aspirate.Services/Aspirate.Services.csproj b/src/Aspirate.Services/Aspirate.Services.csproj
index 5752d6a3..19fcea27 100644
--- a/src/Aspirate.Services/Aspirate.Services.csproj
+++ b/src/Aspirate.Services/Aspirate.Services.csproj
@@ -9,6 +9,7 @@
+
diff --git a/src/Aspirate.Services/Implementations/MinikubeCliService.cs b/src/Aspirate.Services/Implementations/MinikubeCliService.cs
new file mode 100644
index 00000000..5a24105f
--- /dev/null
+++ b/src/Aspirate.Services/Implementations/MinikubeCliService.cs
@@ -0,0 +1,146 @@
+using System.Diagnostics;
+using System.Security.Cryptography;
+using Aspirate.Shared.Models.AspireManifests;
+using Aspirate.Shared.Models.AspireManifests.Components.Common.Container;
+using Aspirate.Shared.Models.AspireManifests.Components.V0.Container;
+using Aspirate.Shared.Models.AspireManifests.Interfaces;
+using Microsoft.Extensions.Logging;
+using System.Management;
+
+namespace Aspirate.Services.Implementations;
+
+public class MinikubeCliService(IShellExecutionService shellExecutionService, IAnsiConsole logger, IServiceProvider serviceProvider) : IMinikubeCliService
+{
+ private string _minikubePath = "minikube";
+
+ private const string DefaultMountPath = "/mnt";
+ private const string MountCommand = "mount";
+
+ public bool IsMinikubeCliInstalledOnMachine()
+ {
+ var result = shellExecutionService.IsCommandAvailable("minikube");
+
+ if (!result.IsAvailable)
+ {
+ return false;
+ }
+
+ _minikubePath = result.FullPath;
+ return true;
+ }
+
+ public void ActivateMinikubeMount(AspirateState state)
+ {
+ int count = 0;
+ foreach (var resourceWithMounts in state.BindMounts)
+ {
+ var source = resourceWithMounts.Key;
+ var targets = resourceWithMounts.Value;
+
+ foreach (var target in targets.Keys)
+ {
+ if (string.IsNullOrWhiteSpace(target))
+ {
+ logger.WriteLine("Mount target was null or empty - skipping this mount.");
+ continue;
+ }
+
+ string args = string.Concat(MountCommand, " ", source, ":", DefaultMountPath, target);
+
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = _minikubePath,
+ Arguments = args,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+
+ logger.MarkupLine($"[cyan]Executing: {_minikubePath} {args}[/]");
+
+ var process = Process.Start(startInfo);
+
+ if (IsChocolateyProcess(process) && count == 0)
+ {
+ logger.MarkupLine($"[blue]minikube runs through Chocolatey shim. Process path: {process.MainModule.FileName}[/]");
+ }
+
+ targets[target] = process.Id;
+ }
+ count++;
+ }
+ logger.MarkupLine($"[green]({EmojiLiterals.CheckMark}) Done:[/] Started minikube mount processes [blue][/]");
+ }
+
+ public bool IsChocolateyProcess(Process process)
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return false;
+ }
+
+ try
+ {
+ string processPath = process.MainModule?.FileName ?? "Unknown";
+
+ if (processPath.Contains("chocolatey"))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ catch (Exception ex)
+ {
+ logger.WriteLine($"Error getting minikube process path: {ex.Message}");
+ }
+ return false;
+ }
+
+ public void KillMinikubeMounts(AspirateState state)
+ {
+ foreach (var resourceWithMounts in state.BindMounts)
+ {
+ var resource = resourceWithMounts.Key;
+ var bindMounts = resourceWithMounts.Value;
+
+ var processIds = bindMounts.Values;
+
+ foreach (var nullableProcessId in processIds)
+ {
+ int processId = nullableProcessId ?? 0;
+
+ if (processId > 0)
+ {
+ var process = Process.GetProcessById(processId);
+
+ if (IsChocolateyProcess(process))
+ {
+#pragma warning disable CA1416
+ using (var searcher = new ManagementObjectSearcher("SELECT ProcessId FROM Win32_Process WHERE ParentProcessId = " + processId))
+ {
+ foreach (var obj in searcher.Get())
+ {
+ try
+ {
+ var childProcessId = Convert.ToInt32(obj["ProcessId"]);
+ var childProcess = Process.GetProcessById(childProcessId);
+
+ childProcess?.Kill();
+ }
+ catch (Exception ex)
+ {
+ logger.WriteLine(ex.Message);
+ logger.WriteLine($"Could not end child process of process Id: {processId}");
+ }
+ }
+ }
+#pragma warning restore CA1416
+ }
+ process.Kill();
+ }
+ }
+ }
+ }
+}
diff --git a/src/Aspirate.Services/ServiceCollectionExtensions.cs b/src/Aspirate.Services/ServiceCollectionExtensions.cs
index 685ae5ea..0765e03a 100644
--- a/src/Aspirate.Services/ServiceCollectionExtensions.cs
+++ b/src/Aspirate.Services/ServiceCollectionExtensions.cs
@@ -1,4 +1,4 @@
-namespace Aspirate.Services;
+namespace Aspirate.Services;
///
/// Extension methods for IServiceCollection to add Aspirate services.
@@ -18,6 +18,7 @@ public static IServiceCollection AddAspirateServices(this IServiceCollection ser
.AddAspirateConfigurationSupport()
.AddContainerSupport()
.AddDaprCliSupport()
+ .AddMinikubeCliSupport()
.AddKubernetesSupport()
.AddStateManagement()
.AddSecretService()
@@ -68,6 +69,10 @@ private static IServiceCollection AddDaprCliSupport(this IServiceCollection serv
services
.AddSingleton();
+ private static IServiceCollection AddMinikubeCliSupport(this IServiceCollection services) =>
+ services
+ .AddSingleton();
+
private static IServiceCollection AddStateManagement(this IServiceCollection services) =>
services
.AddSingleton();
diff --git a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IApplyOptions.cs b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IApplyOptions.cs
index 8b3d80c9..2115b25c 100644
--- a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IApplyOptions.cs
+++ b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IApplyOptions.cs
@@ -3,4 +3,5 @@ namespace Aspirate.Shared.Interfaces.Commands.Contracts;
public interface IApplyOptions
{
bool? RollingRestart { get; set; }
+ //bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IGenerateOptions.cs b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IGenerateOptions.cs
index a77bf23f..fb628a59 100644
--- a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IGenerateOptions.cs
+++ b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IGenerateOptions.cs
@@ -9,4 +9,5 @@ public interface IGenerateOptions
string? ImagePullPolicy { get; set; }
string? OutputFormat { get; set; }
List? Parameters { get; set; }
+ //bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IMinikubeOptions.cs b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IMinikubeOptions.cs
new file mode 100644
index 00000000..409b8184
--- /dev/null
+++ b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IMinikubeOptions.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Aspirate.Shared.Interfaces.Commands.Contracts;
+public interface IMinikubeOptions
+{
+ bool? DisableMinikubeMountAction { get; set; }
+}
diff --git a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IRunOptions.cs b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IRunOptions.cs
index 8fee70f9..1e937e11 100644
--- a/src/Aspirate.Shared/Interfaces/Commands/Contracts/IRunOptions.cs
+++ b/src/Aspirate.Shared/Interfaces/Commands/Contracts/IRunOptions.cs
@@ -7,4 +7,5 @@ public interface IRunOptions
bool? SkipBuild { get; set; }
string? ImagePullPolicy { get; set; }
string? RuntimeIdentifier { get; set; }
+ //bool? DisableMinikubeMountAction { get; set; }
}
diff --git a/src/Aspirate.Shared/Interfaces/Services/IMinikubeCliService.cs b/src/Aspirate.Shared/Interfaces/Services/IMinikubeCliService.cs
new file mode 100644
index 00000000..782f95d3
--- /dev/null
+++ b/src/Aspirate.Shared/Interfaces/Services/IMinikubeCliService.cs
@@ -0,0 +1,8 @@
+namespace Aspirate.Shared.Interfaces.Services;
+
+public interface IMinikubeCliService
+{
+ bool IsMinikubeCliInstalledOnMachine();
+ void ActivateMinikubeMount(AspirateState state);
+ void KillMinikubeMounts(AspirateState state);
+}
diff --git a/src/Aspirate.Shared/Models/Aspirate/AspirateState.cs b/src/Aspirate.Shared/Models/Aspirate/AspirateState.cs
index ead31901..a93b1c97 100644
--- a/src/Aspirate.Shared/Models/Aspirate/AspirateState.cs
+++ b/src/Aspirate.Shared/Models/Aspirate/AspirateState.cs
@@ -129,6 +129,14 @@ public class AspirateState :
[JsonPropertyName("secrets")]
public SecretState? SecretState { get; set; }
+ [RestorableStateProperty]
+ [JsonPropertyName("bindMounts")]
+ public Dictionary>? BindMounts { get; set; }
+
+ [RestorableStateProperty]
+ [JsonPropertyName("disableMinikubeMountAction")]
+ public bool? DisableMinikubeMountAction { get; set; }
+
[RestorableStateProperty]
[JsonPropertyName("processAllComponents")]
public bool? ProcessAllComponents { get; set; }
diff --git a/src/Aspirate.Shared/Models/AspireManifests/Components/Common/BindMount.cs b/src/Aspirate.Shared/Models/AspireManifests/Components/Common/BindMount.cs
index 3db896a3..3c6194e9 100644
--- a/src/Aspirate.Shared/Models/AspireManifests/Components/Common/BindMount.cs
+++ b/src/Aspirate.Shared/Models/AspireManifests/Components/Common/BindMount.cs
@@ -17,36 +17,21 @@ public string? Source
public string? Target { get; set; }
[JsonPropertyName("readOnly")]
- public bool ReadOnly { get; set; }
+ public bool? ReadOnly { get; set; }
+
+ [JsonPropertyName("minikubeMountProcessId")]
+ public int? MinikubeMountProcessId { get; set; }
private static string GetVolumeHostPath(string path)
{
- path = path.Replace('\\', '/').Replace("//", "/");
-
- string dir = Directory.GetCurrentDirectory();
- string[] subPaths = path.Split("/");
-
- for (int i = 0; i < subPaths.Length; i++)
+ if (string.IsNullOrWhiteSpace(path))
{
- string currentSub = subPaths[i];
- if (currentSub == "..")
- {
- dir = Directory.GetParent(dir).FullName;
- }
- else
- {
- if (dir == Directory.GetDirectoryRoot(dir))
- {
- dir += currentSub;
- }
- else
- {
- dir = dir + Path.DirectorySeparatorChar + currentSub;
- }
- }
+ return "";
}
- return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "/run/desktop/mnt/host/" + dir.ToLower().Replace(":", "").Replace('\\', '/') : dir;
+ string currentDir = Directory.GetCurrentDirectory();
+ string resolvedPath = Path.GetFullPath(Path.Combine(currentDir, path));
+
+ return resolvedPath;
}
}
-
diff --git a/src/Aspirate.Shared/Models/AspireManifests/Interfaces/IResourceWithBindMounts.cs b/src/Aspirate.Shared/Models/AspireManifests/Interfaces/IResourceWithBindMounts.cs
index 517f8821..64745fc1 100644
--- a/src/Aspirate.Shared/Models/AspireManifests/Interfaces/IResourceWithBindMounts.cs
+++ b/src/Aspirate.Shared/Models/AspireManifests/Interfaces/IResourceWithBindMounts.cs
@@ -1,6 +1,6 @@
namespace Aspirate.Shared.Models.AspireManifests.Interfaces;
-public interface IResourceWithBindMounts
+public interface IResourceWithBindMounts : IResource
{
List? BindMounts { get; set; }
}