public void ReadConfiguration() { #if NET452 System.Configuration.ConfigurationManager.ConnectionStrings.SetWritable().Add(new System.Configuration.ConnectionStringSettings("RabbitMQConnectionString", "ConnString")); #endif int overrideCallsCount = 0; var settings = new NAMESettings() { ConnectionStringProviderOverride = (node) => { overrideCallsCount = overrideCallsCount + 1; return(null); } }; ParsedDependencies configuration = DependenciesReader.ReadDependencies(CONFIGURATION_FILE, new DummyFilePathMapper(), settings, new NAMEContext()); #if NET452 Assert.Equal(4, configuration.InfrastructureDependencies.Count()); Assert.Equal(2, configuration.ServiceDependencies.Count()); Assert.Equal(1, overrideCallsCount); #else Assert.Equal(3, configuration.InfrastructureDependencies.Count()); Assert.Equal(2, configuration.ServiceDependencies.Count()); Assert.Equal(0, overrideCallsCount); #endif var elasticsearchDependency = configuration.InfrastructureDependencies.OfType <VersionedDependency>().Single(d => d.Type == SupportedDependencies.Elasticsearch); var castedMaxVersion = Assert.IsAssignableFrom <WildcardDependencyVersion>(elasticsearchDependency.MaximumVersion); Assert.False(castedMaxVersion.IsMajorWildcard); Assert.True(castedMaxVersion.IsMinorWildcard); }
public async Task GenerateJson() { string fileName = Guid.NewGuid().ToString() + ".json"; try { File.WriteAllText(fileName, CONFIGURATION_CONTENTS); string expectedManifest = @"{ ""nameVersion"": """ + Constants.NAME_ASSEMBLY_VERSION + @""", ""name"":""NAME.Tests"", ""version"":""1.0.0"", ""infrastructure_dependencies"":[ ], ""service_dependencies"":[ ] }"; string appName = "NAME.Tests"; string appVersion = "123.1.2"; ParsedDependencies dependencies = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), new NAMESettings(), new NAMEContext()); string manifest = await ManifestGenerator.GenerateJson(appName, appVersion, dependencies); var manifestObject = (JObject)JsonConvert.DeserializeObject(manifest); Assert.Equal(Constants.NAME_ASSEMBLY_VERSION, manifestObject["nameVersion"]); Assert.Equal(appName, manifestObject["name"]); Assert.Equal(appVersion, manifestObject["version"]); } finally { File.Delete(fileName); } }
public async Task GenerateJson() { var runningVersion = typeof(Core.Constants).GetTypeInfo().Assembly.GetName().Version.ToString(3); string expectedManifest = @"{ ""nameVersion"": """ + runningVersion + @""", ""name"":""NAME.Tests"", ""version"":""1.0.0"", ""infrastructure_dependencies"":[ { ""name"":""Mongo"", ""version"":""" + Constants.SpecificMongoVersion + @""", ""min_version"":""2.6.0"", ""max_version"":""*"", ""value"":""mongodb://" + Constants.SpecificMongoHostname + @":27017/nPVR_Dev_TST"" } ], ""service_dependencies"":[ ] }"; ParsedDependencies dependencies = DependenciesReader.ReadDependencies(CONFIGURATION_FILE, new DummyFilePathMapper(), new Core.NAMESettings(), new Core.NAMEContext()); string manifest = await ManifestGenerator.GenerateJson("NAME.Tests", runningVersion, dependencies); Assert.Equal( expectedManifest.Replace(" ", string.Empty).Replace("\t", "").Replace("\r", "").Replace("\n", ""), manifest.Replace(" ", string.Empty).Replace("\t", "").Replace("\r", "").Replace("\n", "")); }
public async Task GenerateJson_ServiceWithoutNAME() { var runningVersion = typeof(ManifestGeneratorTests).GetTypeInfo().Assembly.GetName().Version.ToString(3); string expectedManifest = @"{ ""nameVersion"": """ + NAME.Core.Constants.NAME_ASSEMBLY_VERSION + @""", ""name"":""NAME.Tests"", ""version"":""" + runningVersion + @""", ""infrastructure_dependencies"":[ ], ""service_dependencies"":[ { ""name"": ""dummy"", ""error"": ""Dependency does not have NAME installed!"", ""status"":""" + NAMEStatusLevel.Warn.ToString() + @""", ""min_version"": ""1.0.0"", ""max_version"": ""2.*"", ""value"": ""http://" + Constants.SpecificServiceHostname + @":5000/endpoint/before/name/middleware"" } ] }"; ParsedDependencies dependencies = DependenciesReader.ReadDependencies(SERVICE_WITHOUT_NAME_CONFIGURATION_FILE, new DummyFilePathMapper(), new Core.NAMESettings(), new Core.NAMEContext()); string manifest = await ManifestGenerator.GenerateJson("NAME.Tests", runningVersion, dependencies); Assert.Equal( expectedManifest.Replace(" ", string.Empty).Replace("\t", "").Replace("\r", "").Replace("\n", ""), manifest.Replace(" ", string.Empty).Replace("\t", "").Replace("\r", "").Replace("\n", "")); }
public void ReadConfiguration_WithTabulationComments() { string fileContents = @"{ ""$schema"": ""./config-manifest.schema.json"", ""infrastructure_dependencies"": [ //Comment this yeah! ], ""service_dependencies"": [ //Comment this yeah! ] //}"; string fileName = Guid.NewGuid() + ".json"; File.WriteAllText(fileName, fileContents); try { ParsedDependencies configuration = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), new NAMESettings(), new NAMEContext()); Assert.Equal(0, configuration.InfrastructureDependencies.Count()); Assert.Equal(0, configuration.ServiceDependencies.Count()); } finally { File.Delete(fileName); } }
public void ReadConfiguration_CallsMultipleTimes_ConnectionStringProviderOverride() { string fileContents = @"{ ""infrastructure_dependencies"": [ ], ""service_dependencies"": [ { ""name"": ""Some Service0"", ""min_version"": ""0.3"", ""max_version"": ""*"", ""connection_string"": { ""unrecognizedString"": 0 } }, { ""name"": ""Some Service1"", ""min_version"": ""0.3"", ""max_version"": ""*"", ""connection_string"": { ""unrecognizedString"": 1 } } ] }"; string fileName = Guid.NewGuid() + ".json"; File.WriteAllText(fileName, fileContents); try { int iterationsCount = 0; var settings = new NAMESettings() { ConnectionStringProviderOverride = (node) => { Assert.Equal(iterationsCount, node["unrecognizedString"].AsInt); iterationsCount++; return(new StaticConnectionStringProvider(iterationsCount.ToString())); } }; ParsedDependencies configuration = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), settings, new NAMEContext()); Assert.Equal(0, configuration.InfrastructureDependencies.Count()); Assert.Equal(2, configuration.ServiceDependencies.Count()); Assert.Equal(2, iterationsCount); var firstDependency = (ConnectedDependency)configuration.ServiceDependencies.First(); var secondDependency = (ConnectedDependency)configuration.ServiceDependencies.Skip(1).First(); Assert.IsType <StaticConnectionStringProvider>(firstDependency.ConnectionStringProvider); Assert.IsType <StaticConnectionStringProvider>(secondDependency.ConnectionStringProvider); } finally { File.Delete(fileName); } }
public void ReadConfiguration_WithAllOverrides() { string fileContents = @"{ ""$schema"": ""./config-manifest.schema.json"", ""Overrides"": { ""RunningMode"": ""NAMEDisabled"", ""RegistryEndpoints"": [ ""http://name:80/api"", ""http://name2:80/api"" ], ""SelfHostPortRangeFirst"": 1, ""SelfHostPortRangeLast"": 10, ""ServiceDependencyMaxHops"": 2, ""ConnectedDependencyShowConnectionString"": false, ""DependencyConnectTimeout"": 429496721, ""DependencyReadWriteTimeout"": 429496722, ""RegistryBootstrapRetryFrequency"": ""00.02:00:00"", ""RegistryBootstrapTimeout"": ""00.00:00:31"" }, ""infrastructure_dependencies"": [ ], ""service_dependencies"": [ ] }"; string fileName = Guid.NewGuid() + ".json"; File.WriteAllText(fileName, fileContents); try { NAMESettings settings = DependenciesReader.ReadNAMESettingsOverrides(fileName, new DummyFilePathMapper()); ParsedDependencies configuration = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), settings, new NAMEContext()); Assert.Equal(0, configuration.InfrastructureDependencies.Count()); Assert.Equal(0, configuration.ServiceDependencies.Count()); Assert.Equal(SupportedNAMEBehaviours.NAMEDisabled, settings.RunningMode); Assert.Equal(new[] { "http://name:80/api", "http://name2:80/api" }, settings.RegistryEndpoints); Assert.Equal(1, settings.SelfHostPortRangeFirst); Assert.Equal(10, settings.SelfHostPortRangeLast); Assert.Equal(2, settings.ServiceDependencyMaxHops); Assert.False(settings.ConnectedDependencyShowConnectionString); Assert.Equal(429496721, settings.DependencyConnectTimeout); Assert.Equal(429496722, settings.DependencyReadWriteTimeout); Assert.Equal(TimeSpan.FromHours(2), settings.RegistryBootstrapRetryFrequency); Assert.Equal(TimeSpan.FromSeconds(31), settings.RegistryBootstrapTimeout); } finally { File.Delete(fileName); } }
public void ReadConfiguration() { #if NET452 System.Configuration.ConfigurationManager.ConnectionStrings.SetWritable().Add(new System.Configuration.ConnectionStringSettings("RabbitMQConnectionString", "ConnString")); #endif ParsedDependencies configuration = DependenciesReader.ReadDependencies(CONFIGURATION_FILE, new DummyFilePathMapper(), new NAMESettings(), new NAMEContext()); #if NET452 Assert.Equal(3, configuration.InfrastructureDependencies.Count()); Assert.Equal(2, configuration.ServiceDependencies.Count()); #else Assert.Equal(2, configuration.InfrastructureDependencies.Count()); Assert.Equal(2, configuration.ServiceDependencies.Count()); #endif }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (!this.settings.IsManifestEndpointEnabled()) { return(new HttpResponseMessage(HttpStatusCode.NotFound)); } int currentHopCount; if (request.Headers.TryGetValues(Constants.HOP_COUNT_HEADER_NAME, out IEnumerable <string> headerValues)) { if (!int.TryParse(headerValues.First(), out currentHopCount)) { currentHopCount = 0; LogWarning($"The received hop count header it not a valid int value ({headerValues.First()}), defaulting to 0.", false); } } else { currentHopCount = 0; } currentHopCount++; if (currentHopCount == this.settings.ServiceDependencyMaxHops) { return new HttpResponseMessage { StatusCode = (HttpStatusCode)Constants.SERVICE_HOPS_ERROR_STATUS_CODE } } ; var context = new NAMEContext() { ServiceDependencyCurrentNumberOfHops = currentHopCount }; ParsedDependencies innerDependencies = DependenciesReader.ReadDependencies(this.dependenciesFile, this.pathMapper, this.settings, context); var manifest = await ManifestGenerator.GenerateJson(this.apiName, this.apiVersion, innerDependencies).ConfigureAwait(false); var content = new StringContent(manifest); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); return(new HttpResponseMessage { Content = content }); } }
public void ReadConfiguration_UsesConnectionStringProviderReturnedFromOverride() { string fileContents = @"{ ""infrastructure_dependencies"": [ { ""type"": ""RabbitMq"", ""name"": ""rabbitmq"", ""min_version"": ""2.0"", ""max_version"": ""3.3"", ""connection_string"": { ""locator"": ""JSONPath"", ""key"": ""shouldn't matter"" } } ], ""service_dependencies"": [ ] }"; string fileName = Guid.NewGuid() + ".json"; File.WriteAllText(fileName, fileContents); try { int iterationsCount = 0; var settings = new NAMESettings() { ConnectionStringProviderOverride = (node) => { iterationsCount++; return(new StaticConnectionStringProvider(string.Empty)); } }; ParsedDependencies configuration = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), settings, new NAMEContext()); Assert.Equal(1, configuration.InfrastructureDependencies.Count()); Assert.Equal(0, configuration.ServiceDependencies.Count()); Assert.Equal(1, iterationsCount); var firstDependency = (ConnectedDependency)configuration.InfrastructureDependencies.First(); Assert.IsType <StaticConnectionStringProvider>(firstDependency.ConnectionStringProvider); } finally { File.Delete(fileName); } }
/// <summary> /// Reads the and log dependencies. /// </summary> /// <param name="configuration">The configuration.</param> /// <param name="logToConsole">if set to <c>true</c> [log to console].</param> /// <param name="pathMapper">The path mapper.</param> /// <param name="settings">The context information.</param> /// <returns> /// The <see cref="ParsedDependencies" /> object populated from the dependencies file /// </returns> /// <exception cref="NAMEException">Error parsing the dependencies file.</exception> /// <exception cref="DependenciesCheckException">Wrapper for all possible exceptions in the NAME process</exception> public static ParsedDependencies ReadAndLogDependencies(NAMEBaseConfiguration configuration, bool logToConsole, IFilePathMapper pathMapper, out NAMESettings settings) { var dependencies = new ParsedDependencies(null, null); settings = DependenciesReader.ReadNAMESettingsOverrides(configuration.DependenciesFilePath, pathMapper); try { dependencies = DependenciesReader.ReadDependencies(configuration.DependenciesFilePath, pathMapper, settings, new NAMEContext()); } catch (NAMEException ex) { LogWarning($"Could not parse the dependencies file: {ex.Message}.", logToConsole); if (configuration.ThrowOnDependenciesFail) { if (ex is NAMEException) { throw; } else { throw new NAMEException("Error parsing the dependencies file.", ex); } } return(dependencies); } if (settings.RunningMode == SupportedNAMEBehaviours.NAMEDisabled) { LogInfo("NAME was disabled in the dependencies file.", logToConsole); return(dependencies); } LogInfo("Starting the dependencies state logs.", logToConsole); var allStatuses = LogDependenciesStatuses(dependencies.InfrastructureDependencies, logToConsole); allStatuses.AddRange(LogDependenciesStatuses(dependencies.ServiceDependencies, logToConsole)); if (configuration.ThrowOnDependenciesFail && allStatuses.Any(s => !s.CheckPassed)) { throw new DependenciesCheckException(allStatuses); } return(dependencies); }
public async Task TestExplorer() { const string manifest = @"{ ""infrastructure_dependencies"": [ ], ""service_dependencies"": [ { ""name"":""DummyConsoleKestrel"", ""min_version"": ""1.0.0"", ""max_version"": ""2.0.0"", ""connection_string"": ""http://dummy-console-kestrel:40500"" } ] }"; var memoryStream = new MemoryStream(); using (var streamWriter = new StreamWriter(memoryStream)) { await streamWriter.WriteAsync(manifest).ConfigureAwait(false); await streamWriter.FlushAsync().ConfigureAwait(false); memoryStream.Seek(0, SeekOrigin.Begin); ParsedDependencies parsedDependencies = DependenciesReader.ReadDependencies(memoryStream, new DummyFilePathMapper(), new Core.NAMESettings(), new Core.NAMEContext()); Assert.True(1 == parsedDependencies.ServiceDependencies.Count(), "The number of service dependencies did not match."); Assert.Empty(parsedDependencies.InfrastructureDependencies); var serviceDependency = parsedDependencies.ServiceDependencies.First(); DependencyCheckStatus status = await serviceDependency.GetStatus().ConfigureAwait(false); // we still need to test for backwards compatibility #pragma warning disable CS0618 // Type or member is obsolete Assert.True(status.CheckPassed); #pragma warning restore CS0618 // Type or member is obsolete Assert.Equal(NAMEStatusLevel.Ok, status.CheckStatus); Assert.NotNull(status.Version.ManifestNode); Assert.Equal("1.0.0", status.Version.ToString()); Assert.Equal("NAME.DummyService", status.Version.ManifestNode["name"]); Assert.Empty(status.Version.ManifestNode["infrastructure_dependencies"].Children); Assert.Empty(status.Version.ManifestNode["service_dependencies"].Children); } }
public async Task TestExplorer() { const string manifest = @"{ ""infrastructure_dependencies"": [ ], ""service_dependencies"": [ { ""name"":""DummyService2"", ""min_version"": ""1.0.0"", ""max_version"": ""2.0.0"", ""connection_string"": ""http://dummy-service:5000"" } ] }"; var memoryStream = new MemoryStream(); using (var streamWriter = new StreamWriter(memoryStream)) { await streamWriter.WriteAsync(manifest).ConfigureAwait(false); await streamWriter.FlushAsync().ConfigureAwait(false); memoryStream.Seek(0, SeekOrigin.Begin); ParsedDependencies parsedDependencies = DependenciesReader.ReadDependencies(memoryStream, new DummyFilePathMapper(), new Core.NAMESettings(), new Core.NAMEContext()); Assert.True(parsedDependencies.ServiceDependencies.Any()); Assert.False(parsedDependencies.InfrastructureDependencies.Any()); foreach (Dependency dependency in parsedDependencies.ServiceDependencies) { DependencyCheckStatus status = await dependency.GetStatus().ConfigureAwait(false); Assert.True(status.CheckPassed); Assert.NotNull(status.Version.ManifestNode); Assert.Equal("NAME.DummyService", status.Version.ManifestNode["name"]); ////Assert.NotEmpty(status.Version.ManifestNode["infrastructure_dependencies"].Children); Assert.NotEmpty(status.Version.ManifestNode["service_dependencies"].Children); } } }
public void ReadConfiguration_OperatingSystemDependency_SkipsOverride() { string fileContents = @"{ ""infrastructure_dependencies"": [ { ""os_name"": ""Ubuntu"", ""type"": ""OperatingSystem"", ""min_version"": ""16.04"", ""max_version"": ""14.04"" } ], ""service_dependencies"": [ ] }"; string fileName = Guid.NewGuid() + ".json"; File.WriteAllText(fileName, fileContents); try { int iterationsCount = 0; var settings = new NAMESettings() { ConnectionStringProviderOverride = (node) => { iterationsCount++; return(null); } }; ParsedDependencies configuration = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), settings, new NAMEContext()); Assert.Equal(1, configuration.InfrastructureDependencies.Count()); Assert.Equal(0, configuration.ServiceDependencies.Count()); Assert.Equal(0, iterationsCount); } finally { File.Delete(fileName); } }
public void ReadConfiguration_EmptyArrays() { string fileContents = @"{ ""infrastructure_dependencies"": [ ], ""service_dependencies"": [ ] }"; string fileName = Guid.NewGuid() + ".json"; File.WriteAllText(fileName, fileContents); try { ParsedDependencies configuration = DependenciesReader.ReadDependencies(fileName, new DummyFilePathMapper(), new NAMESettings(), new NAMEContext()); Assert.Equal(0, configuration.InfrastructureDependencies.Count()); Assert.Equal(0, configuration.ServiceDependencies.Count()); } finally { File.Delete(fileName); } }
public static ParsedDependencies Initialize(ISelfHostServer server, IFilePathMapper pathMapper, NAMESelfHostConfiguration configuration) { NAMESettings settings; ParsedDependencies dependencies = ReadAndLogDependencies(configuration, configuration.LogHealthCheckToConsole, pathMapper, out settings); if (settings.RunningMode == SupportedNAMEBehaviours.NAMEDisabled) { LogInfo("Not starting NAME since it is disabled in the dependencies file.", configuration.LogHealthCheckToConsole); return(dependencies); } int portNumber = settings.SelfHostPortRangeFirst; try { bool result = false; LogInfo($"Starting the server", configuration.LogHealthCheckToConsole); while (portNumber <= settings.SelfHostPortRangeLast) { result = server.Start(portNumber, settings); if (result) { break; } portNumber++; } if (result == false) { throw new NAMEException("Tried all ports, without success."); } Console.WriteLine($"Succesfully started the server. Listening on {portNumber}."); } catch (Exception ex) { LogWarning($"Could not bind to the SelfHost address: {ex.Message}.", configuration.LogHealthCheckToConsole); if (configuration.ThrowOnDependenciesFail) { if (ex is NAMEException) { throw; } else { throw new NAMEException("Could not bind to the SelfHost address.", ex); } } return(dependencies); } if (settings.RunningMode < SupportedNAMEBehaviours.BootstrapDisabled) { var register = new Registration.Register(); register.RegisterInstance( pathMapper, configuration.APIName, configuration.APIVersion, configuration.DependenciesFilePath, settings, Environment.MachineName, (uint)portNumber, typeof(SelfHostInitializer).GetTypeInfo().Assembly.GetName().Version.ToString(), (configuration.ManifestUriPrefix?.TrimEnd('/') ?? string.Empty) + Constants.MANIFEST_ENDPOINT, Constants.REGISTRY_SUPPORTED_PROTOCOL_VERSIONS); } if (settings.RunningMode == SupportedNAMEBehaviours.NAMEDisabled) { LogInfo("Stopping the NAME self host server since it is disabled in the Registry.", configuration.LogHealthCheckToConsole); server.Dispose(); return(dependencies); } return(dependencies); }
private async Task <string> GetManifest(NAMEContext context) { ParsedDependencies innerDependencies = DependenciesReader.ReadDependencies(this.dependenciesFileLocation, this.pathMapper, this.settings, context); return(await ManifestGenerator.GenerateJson(this.ApiName, this.ApiVersion, innerDependencies).ConfigureAwait(false)); }
internal SelfHostResult(ParsedDependencies parsedDependencies, IDisposable selfHostServer) { this.ParsedDependencies = parsedDependencies; this.selfHostServer = selfHostServer; }
internal SelfHostResult(ParsedDependencies parsedDependencies) { this.ParsedDependencies = parsedDependencies; this.selfHostServer = null; }
/// <summary> /// Reads the and log dependencies. /// </summary> /// <param name="configuration">The configuration.</param> /// <param name="logToConsole">if set to <c>true</c> [log to console].</param> /// <param name="pathMapper">The path mapper.</param> /// <param name="settings">The context information.</param> /// <returns> /// The <see cref="ParsedDependencies" /> object populated from the dependencies file /// </returns> /// <exception cref="NAMEException">Error parsing the dependencies file.</exception> /// <exception cref="DependenciesCheckException">Wrapper for all possible exceptions in the NAME process</exception> public static ParsedDependencies ReadAndLogDependencies(NAMEBaseConfiguration configuration, bool logToConsole, IFilePathMapper pathMapper, out NAMESettings settings) { var dependencies = new ParsedDependencies(null, null); settings = DependenciesReader.ReadNAMESettingsOverrides(configuration.DependenciesFilePath, pathMapper); try { dependencies = DependenciesReader.ReadDependencies(configuration.DependenciesFilePath, pathMapper, settings, new NAMEContext()); } catch (NAMEException ex) { LogWarning($"Could not parse the dependencies file: {ex.Message}.", logToConsole); if (configuration.ThrowOnDependenciesFail) { if (ex is NAMEException) { throw; } else { throw new NAMEException("Error parsing the dependencies file.", ex, NAMEStatusLevel.Error); } } return(dependencies); } if (settings.RunningMode == SupportedNAMEBehaviours.NAMEDisabled) { LogInfo("NAME was disabled in the dependencies file.", logToConsole); return(dependencies); } LogInfo("Starting the dependencies state logs.", logToConsole); Func <IEnumerable <DependencyCheckStatus> > logStatusesAction = () => { var allStatuses = LogDependenciesStatuses(dependencies.InfrastructureDependencies, logToConsole); allStatuses.AddRange(LogDependenciesStatuses(dependencies.ServiceDependencies, logToConsole)); return(allStatuses); }; if (configuration.ThrowOnDependenciesFail) { var allStatuses = logStatusesAction(); if (allStatuses.Any(s => s.CheckStatus != NAMEStatusLevel.Ok)) { throw new DependenciesCheckException(allStatuses); } } else { Task.Factory .StartNew(logStatusesAction) .ContinueWith( task => { LogWarning("Exception logging dependencies status:", logToConsole); var flattened = task.Exception.Flatten(); flattened.Handle(ex => { LogWarning(ex.Message, logToConsole); return(true); }); }, TaskContinuationOptions.OnlyOnFaulted); } return(dependencies); }