diff --git a/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs b/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs index d3409ee8..af6351ea 100644 --- a/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs +++ b/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs @@ -9,6 +9,7 @@ namespace Ocelot.DependencyInjection using System.Text.RegularExpressions; using Configuration.File; using Newtonsoft.Json; + using Microsoft.AspNetCore.Hosting; public static class ConfigurationBuilderExtensions { @@ -28,37 +29,42 @@ namespace Ocelot.DependencyInjection return builder; } - public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder) + public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, IHostingEnvironment env = null) { - return builder.AddOcelot("."); + return builder.AddOcelot(".", env); } - public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, string folder) + public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, string folder, IHostingEnvironment env = null) { - const string pattern = "(?i)ocelot\\.([a-zA-Z0-9]*)(\\.json)$"; + const string primaryConfigFile = "ocelot.json"; - var reg = new Regex(pattern); + const string globalConfigFile = "ocelot.global.json"; - var files = Directory.GetFiles(folder) - .Where(path => reg.IsMatch(path)) + const string subConfigPattern = @"^ocelot\.[a-zA-Z0-9]+\.json$"; + + string excludeConfigName = env?.EnvironmentName != null ? $"ocelot.{env.EnvironmentName}.json" : string.Empty; + + var reg = new Regex(subConfigPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline); + + var files = new DirectoryInfo(folder) + .EnumerateFiles() + .Where(fi => reg.IsMatch(fi.Name) && (fi.Name != excludeConfigName)) .ToList(); var fileConfiguration = new FileConfiguration(); foreach (var file in files) { - // windows and unix sigh... - if(files.Count > 1 && (Path.GetFileName(file) == "ocelot.json")) + if(files.Count > 1 && file.Name.Equals(primaryConfigFile, StringComparison.OrdinalIgnoreCase)) { continue; } - var lines = File.ReadAllText(file); + var lines = File.ReadAllText(file.FullName); var config = JsonConvert.DeserializeObject(lines); - // windows and unix sigh... - if (Path.GetFileName(file) == "ocelot.global.json") + if (file.Name.Equals(globalConfigFile, StringComparison.OrdinalIgnoreCase)) { fileConfiguration.GlobalConfiguration = config.GlobalConfiguration; } @@ -69,9 +75,9 @@ namespace Ocelot.DependencyInjection var json = JsonConvert.SerializeObject(fileConfiguration); - File.WriteAllText("ocelot.json", json); + File.WriteAllText(primaryConfigFile, json); - builder.AddJsonFile("ocelot.json", false, false); + builder.AddJsonFile(primaryConfigFile, false, false); return builder; } diff --git a/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs index 43176e5a..da2bc341 100644 --- a/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs @@ -9,6 +9,8 @@ using Shouldly; using TestStack.BDDfy; using Xunit; + using Moq; + using Microsoft.AspNetCore.Hosting; public class ConfigurationBuilderExtensionsTests { @@ -19,6 +21,18 @@ private FileConfiguration _reRouteA; private FileConfiguration _reRouteB; private FileConfiguration _aggregate; + private FileConfiguration _envSpecific; + + public ConfigurationBuilderExtensionsTests() + { + // Clean up config files before each test + var subConfigFiles = new DirectoryInfo(".").GetFiles("ocelot.*.json"); + + foreach(var config in subConfigFiles) + { + config.Delete(); + } + } [Fact] public void should_add_base_url_to_config() @@ -32,23 +46,33 @@ [Fact] public void should_merge_files() { - this.Given(_ => GivenMultipleConfigurationFiles("")) - .When(_ => WhenIAddOcelotConfiguration()) + this.Given(_ => GivenMultipleConfigurationFiles("", false)) + .When(_ => WhenIAddOcelotConfiguration(false)) .Then(_ => ThenTheConfigsAreMerged()) .BDDfy(); } + [Fact] + public void should_merge_files_except_env() + { + this.Given(_ => GivenMultipleConfigurationFiles("", true)) + .When(_ => WhenIAddOcelotConfiguration(true)) + .Then(_ => ThenTheConfigsAreMerged()) + .And(_ => NotContainsEnvSpecificConfig()) + .BDDfy(); + } + [Fact] public void should_merge_files_in_specific_folder() { string configFolder = "ConfigFiles"; - this.Given(_ => GivenMultipleConfigurationFiles(configFolder)) + this.Given(_ => GivenMultipleConfigurationFiles(configFolder, false)) .When(_ => WhenIAddOcelotConfigurationWithSpecificFolder(configFolder)) .Then(_ => ThenTheConfigsAreMerged()) .BDDfy(); } - private void GivenMultipleConfigurationFiles(string folder) + private void GivenMultipleConfigurationFiles(string folder, bool addEnvSpecificConfig) { if (!string.IsNullOrEmpty(folder)) { @@ -155,7 +179,7 @@ { new FileAggregateReRoute { - ReRouteKeys = new List + ReRouteKeys = new List { "KeyB", "KeyBB" @@ -164,7 +188,7 @@ }, new FileAggregateReRoute { - ReRouteKeys = new List + ReRouteKeys = new List { "KeyB", "KeyBB" @@ -174,6 +198,32 @@ } }; + _envSpecific = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamScheme = "DownstreamSchemeSpec", + DownstreamPathTemplate = "DownstreamPathTemplateSpec", + Key = "KeySpec", + UpstreamHost = "UpstreamHostSpec", + UpstreamHttpMethod = new List + { + "UpstreamHttpMethodSpec" + }, + DownstreamHostAndPorts = new List + { + new FileHostAndPort + { + Host = "HostSpec", + Port = 80 + } + } + } + } + }; + string globalFilename = Path.Combine(folder, "ocelot.global.json"); string reroutesAFilename = Path.Combine(folder, "ocelot.reRoutesA.json"); string reroutesBFilename = Path.Combine(folder, "ocelot.reRoutesB.json"); @@ -183,12 +233,23 @@ File.WriteAllText(reroutesAFilename, JsonConvert.SerializeObject(_reRouteA)); File.WriteAllText(reroutesBFilename, JsonConvert.SerializeObject(_reRouteB)); File.WriteAllText(aggregatesFilename, JsonConvert.SerializeObject(_aggregate)); + + if (addEnvSpecificConfig) + { + string envSpecificFilename = Path.Combine(folder, "ocelot.Env.json"); + File.WriteAllText(envSpecificFilename, JsonConvert.SerializeObject(_envSpecific)); + } } - private void WhenIAddOcelotConfiguration() + private void WhenIAddOcelotConfiguration(bool addEnv) { IConfigurationBuilder builder = new ConfigurationBuilder(); - builder.AddOcelot(); + + var hostingEnvironment = new Mock(); + hostingEnvironment.SetupGet(x => x.EnvironmentName).Returns(addEnv ? "Env" : null); + + builder.AddOcelot(hostingEnvironment.Object); + _configRoot = builder.Build(); } @@ -235,6 +296,14 @@ fc.Aggregates.Count.ShouldBe(_aggregate.Aggregates.Count); } + private void NotContainsEnvSpecificConfig() + { + var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration)); + fc.ReRoutes.ShouldNotContain(x => x.DownstreamScheme == _envSpecific.ReRoutes[0].DownstreamScheme); + fc.ReRoutes.ShouldNotContain(x => x.DownstreamPathTemplate == _envSpecific.ReRoutes[0].DownstreamPathTemplate); + fc.ReRoutes.ShouldNotContain(x => x.Key == _envSpecific.ReRoutes[0].Key); + } + private void GivenTheBaseUrl(string baseUrl) { #pragma warning disable CS0618