internal void Launcher ( [Required, Description("Path to LauncherSettings file")] string settingsPath, [DefaultValue(false)] bool debug, [DefaultValue(false)] bool shutdown = false ) { Initialize(); if (debug) { System.Diagnostics.Debugger.Launch(); } try { Validate(); var configJson = File.ReadAllText(settingsPath); var settings = JsonSerializer.Deserialize <LauncherApplicationSettings>(configJson, DeploymentUtilities.ConfigurationSerializationOptions); var launcher = new DeploymentLauncher(settings, _fileSystem); runAsync().GetAwaiter().GetResult(); async Task runAsync() { if (shutdown) { var context = new OperationContext(new Context(_logger), _cancellationToken); await launcher.LifetimeManager.ShutdownServiceAsync(context, settings.LauncherServiceId); return; } var host = new EnvironmentVariableHost(new Context(_logger)); settings.DeploymentParameters.AuthorizationSecret ??= await host.GetPlainSecretAsync(settings.DeploymentParameters.AuthorizationSecretName, _cancellationToken); var telemetryFieldsProvider = new HostTelemetryFieldsProvider(settings.DeploymentParameters) { ServiceName = "DeploymentLauncher" }; var arguments = new LoggerFactoryArguments(_logger, host, settings.LoggingSettings, telemetryFieldsProvider); var replacementLogger = LoggerFactory.CreateReplacementLogger(arguments); using (replacementLogger.DisposableToken) { var token = _cancellationToken; var context = new OperationContext(new Context(replacementLogger.Logger), token); await launcher.LifetimeManager.RunInterruptableServiceAsync(context, settings.LauncherServiceId, async token => { try { await launcher.StartupAsync(context).ThrowIfFailureAsync(); using var tokenAwaitable = token.ToAwaitable(); await tokenAwaitable.CompletionTask; } finally { await launcher.ShutdownAsync(context).ThrowIfFailureAsync(); } return(true); }); } } } catch (Exception e) { Console.WriteLine(e); throw; } }
public async Task TestDeployAndRun() { var host = new TestHost(); string serviceUrl = "casaas://service"; var settings = new LauncherSettings() { ServiceUrl = serviceUrl, RetentionSizeGb = 1, RunInBackgroundOnStartup = false, DeploymentParameters = new DeploymentParameters() { }, ServiceLifetimePollingIntervalSeconds = 0.01, DownloadConcurrency = 1, TargetDirectory = TestRootDirectoryPath.Path }; var executableRelativePath = @"bin\casaas.exe"; var serviceId = "testcasaas"; var firstRunExecutableContent = "This is the content of casaas.exe for run 1"; var manifest = new LauncherManifestWithExtraMembers() { IsComplete = true, ContentId = "Deployment 1", Deployment = new DeploymentManifest.LayoutSpec() { { executableRelativePath, host.TestClient.AddContent(firstRunExecutableContent) }, { @"bin\lib.dll", host.TestClient.AddContent("This is the content of lib.dll") } }, Tool = new ServiceLaunchConfiguration() { ServiceId = serviceId, Arguments = new[] { "arg1", "arg2", "arg3 with spaces" }, EnvironmentVariables = { { "hello", "world" }, { "foo", "bar" } }, Executable = @"bin\casaas.exe", ShutdownTimeoutSeconds = 60, } }; host.TestClient.GetManifest = launcherSettings => { // Use JSON serialization and deserialization to clone manifest // Also tests JSON roundtripping var manifestText = JsonSerializer.Serialize(manifest); return(JsonSerializer.Deserialize <LauncherManifest>(manifestText)); }; var launcher = new DeploymentLauncher(settings, FileSystem, host); using var cts = new CancellationTokenSource(); var context = new OperationContext(new Context(Logger), cts.Token); await launcher.StartupAsync(context).ThrowIfFailureAsync(); await launcher.GetDownloadAndRunDeployment(context).ShouldBeSuccess(); // Test the process is launched. (launcher.CurrentRun?.RunningProcess).Should().NotBeNull(); launcher.CurrentRun.IsActive.Should().BeTrue(); var testProcess1 = (TestProcess)launcher.CurrentRun.RunningProcess; testProcess1.IsRunningService.Should().BeTrue(); // Verify executable, arguments, enviroment variables ReadAllText(testProcess1.StartInfo.FileName).Should().Be(firstRunExecutableContent); testProcess1.StartInfo.Arguments.Should().Be("arg1 arg2 \"arg3 with spaces\""); testProcess1.StartInfo.Environment["hello"].Should().Be("world"); testProcess1.StartInfo.Environment["foo"].Should().Be("bar"); // Verify that same manifest does not launch new process await launcher.GetDownloadAndRunDeployment(context).ShouldBeSuccess(); (launcher.CurrentRun?.RunningProcess).Should().Be(testProcess1); testProcess1.IsRunningService.Should().BeTrue(); // Modify manifest and mark as incomplete to signify case where all files have not yet been // replicated to region-specific storage manifest.IsComplete = false; manifest.ContentId = "Deployment 2"; var secondRunExecutableContent = "This is the content of casaas.exe for run 2"; manifest.Deployment[executableRelativePath] = host.TestClient.AddContent(secondRunExecutableContent); // Verify that incomplete updated manifest does not launch new process await launcher.GetDownloadAndRunDeployment(context).ShouldBeSuccess(); ReadAllText(testProcess1.StartInfo.FileName).Should().Be(firstRunExecutableContent); (launcher.CurrentRun?.RunningProcess).Should().Be(testProcess1); testProcess1.IsRunningService.Should().BeTrue(); // Verify that complete updated manifest launches new process manifest.IsComplete = true; await launcher.GetDownloadAndRunDeployment(context).ShouldBeSuccess(); (launcher.CurrentRun?.RunningProcess).Should().NotBe(testProcess1); testProcess1.IsRunningService.Should().BeFalse(); var testProcess2 = (TestProcess)launcher.CurrentRun.RunningProcess; testProcess2.IsRunningService.Should().BeTrue(); // Verify updated casaas.exe file ReadAllText(testProcess2.StartInfo.FileName).Should().Be(secondRunExecutableContent); // Verify shutdown launches new processes await launcher.LifetimeManager.ShutdownServiceAsync(context, serviceId); await launcher.ShutdownAsync(context).ThrowIfFailureAsync(); }