namespace MoonlightServers.Daemon.ServerSystem; public partial class Server { public async Task InstallAsync() { await Lock.WaitAsync(); try { if (State != ServerState.Offline) throw new InvalidOperationException("Server is not offline"); // Check if any pre-existing install env exists, if we don't have a reference to it already InstallEnvironment ??= await InstallEnvironmentService.FindAsync(Uuid); // Check if storages exist InstallStorage ??= await InstallStorageService.FindAsync(Uuid); RuntimeStorage ??= await RuntimeStorageService.FindAsync(Uuid); // Remove any pre-existing installation env if (InstallEnvironment != null) { Logger.LogTrace("Destroying pre-existing install environment"); if (await InstallEnvironment.IsRunningAsync()) { Logger.LogTrace("Pre-existing install environment is still running, killing it"); await InstallEnvironment.KillAsync(); } // Remove any event handlers if existing InstallEnvironment.Console.OnOutput -= OnConsoleMessageAsync; InstallEnvironment.Statistics.OnStatisticsReceived -= OnStatisticsReceivedAsync; InstallEnvironment.OnExited -= OnInstallExitedAsync; // Now remove it // Finally remove it await InstallEnvironmentService.DeleteAsync(InstallEnvironment); InstallEnvironment = null; Logger.LogTrace("Pre-existing install environment destroyed"); } // Remove pre-existing installation storage if (InstallStorage != null) { Logger.LogTrace("Destroying pre-existing installation storage"); await InstallStorageService.DeleteAsync(InstallStorage); InstallStorage = null; } // Fetch the latest configuration Logger.LogTrace("Fetching latest configuration"); RuntimeConfiguration = await ConfigurationService.GetRuntimeConfigurationAsync(Uuid); InstallConfiguration = await ConfigurationService.GetInstallConfigurationAsync(Uuid); // Ensure runtime storage if (RuntimeStorage == null) { Logger.LogTrace("Creating runtime storage"); RuntimeStorage = await RuntimeStorageService.CreateAsync(Uuid, RuntimeConfiguration); } else { Logger.LogTrace("Updating runtime storage"); await RuntimeStorageService.UpdateAsync(RuntimeStorage, RuntimeConfiguration); } // Create installation storage Logger.LogTrace("Creating installation storage"); InstallStorage = await InstallStorageService.CreateAsync(Uuid, RuntimeConfiguration, InstallConfiguration); // Write install script var installStoragePath = await InstallStorage.GetHostPathAsync(); await File.WriteAllTextAsync( Path.Combine(installStoragePath, "install.sh"), InstallConfiguration.Script ); // Create env Logger.LogTrace("Creating install environment"); InstallEnvironment = await InstallEnvironmentService.CreateAsync( Uuid, RuntimeConfiguration, InstallConfiguration, InstallStorage, RuntimeStorage ); // Add event handlers Logger.LogTrace("Attaching to install environment"); InstallEnvironment.Console.OnOutput += OnConsoleMessageAsync; InstallEnvironment.Statistics.OnStatisticsReceived += OnStatisticsReceivedAsync; InstallEnvironment.OnExited += OnInstallExitedAsync; // Attach console and statistics await InstallEnvironment.Console.AttachAsync(); await InstallEnvironment.Statistics.AttachAsync(); // Finally start the env Logger.LogTrace("Starting install environment"); await InstallEnvironment.StartAsync(); await ChangeStateAsync(ServerState.Installing); } finally { Lock.Release(); } } private async Task OnInstallExitedAsync() { Logger.LogTrace("Install environment exited, checking result and cleaning up"); await Lock.WaitAsync(); try { // TODO: Handle crash if (InstallEnvironment == null) throw new InvalidOperationException("Install environment is not set"); // Make sure no event handler is there InstallEnvironment.Console.OnOutput -= OnConsoleMessageAsync; InstallEnvironment.Statistics.OnStatisticsReceived -= OnStatisticsReceivedAsync; InstallEnvironment.OnExited -= OnInstallExitedAsync; // Remove env await InstallEnvironmentService.DeleteAsync(InstallEnvironment); InstallEnvironment = null; Logger.LogTrace("Install environment cleaned up"); if(InstallStorage == null) throw new InvalidOperationException("Install storage is not set"); Logger.LogTrace("Cleaned up install storage"); await InstallStorageService.DeleteAsync(InstallStorage); InstallStorage = null; } finally { Lock.Release(); } await ChangeStateAsync(ServerState.Offline); } }