Merge branch 'snb83-feature/config_grow_when_merged' into develop

This commit is contained in:
Tom Gardham-Pallister 2018-09-20 18:33:17 +01:00
commit f16d201906
3 changed files with 120 additions and 22 deletions

View File

@ -107,7 +107,7 @@ Instead of adding the configuration directly e.g. AddJsonFile("ocelot.json") you
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true) .AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddOcelot() .AddOcelot(hostingContext.HostingEnvironment)
.AddEnvironmentVariables(); .AddEnvironmentVariables();
}) })
@ -117,6 +117,22 @@ The way Ocelot merges the files is basically load them, loop over them, add any
At the moment there is no validation at this stage it only happens when Ocelot validates the final merged configuration. This is something to be aware of when you are investigating problems. I would advise always checking what is in ocelot.json if you have any problems. At the moment there is no validation at this stage it only happens when Ocelot validates the final merged configuration. This is something to be aware of when you are investigating problems. I would advise always checking what is in ocelot.json if you have any problems.
You can also give Ocelot a specific path to look in for the configuration files like below.
.. code-block:: csharp
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddOcelot("/foo/bar", hostingContext.HostingEnvironment)
.AddEnvironmentVariables();
})
Ocelot needs the HostingEnvironment so it know's to exclude anything environment specific from the algorithm.
Store configuration in consul Store configuration in consul
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -9,6 +9,7 @@ namespace Ocelot.DependencyInjection
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Configuration.File; using Configuration.File;
using Newtonsoft.Json; using Newtonsoft.Json;
using Microsoft.AspNetCore.Hosting;
public static class ConfigurationBuilderExtensions public static class ConfigurationBuilderExtensions
{ {
@ -28,37 +29,42 @@ namespace Ocelot.DependencyInjection
return builder; return builder;
} }
public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder) public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, IHostingEnvironment env)
{ {
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)
{ {
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) const string subConfigPattern = @"^ocelot\.[a-zA-Z0-9]+\.json$";
.Where(path => reg.IsMatch(path))
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(); .ToList();
var fileConfiguration = new FileConfiguration(); var fileConfiguration = new FileConfiguration();
foreach (var file in files) foreach (var file in files)
{ {
// windows and unix sigh... if(files.Count > 1 && file.Name.Equals(primaryConfigFile, StringComparison.OrdinalIgnoreCase))
if(files.Count > 1 && (Path.GetFileName(file) == "ocelot.json"))
{ {
continue; continue;
} }
var lines = File.ReadAllText(file); var lines = File.ReadAllText(file.FullName);
var config = JsonConvert.DeserializeObject<FileConfiguration>(lines); var config = JsonConvert.DeserializeObject<FileConfiguration>(lines);
// windows and unix sigh... if (file.Name.Equals(globalConfigFile, StringComparison.OrdinalIgnoreCase))
if (Path.GetFileName(file) == "ocelot.global.json")
{ {
fileConfiguration.GlobalConfiguration = config.GlobalConfiguration; fileConfiguration.GlobalConfiguration = config.GlobalConfiguration;
} }
@ -69,9 +75,9 @@ namespace Ocelot.DependencyInjection
var json = JsonConvert.SerializeObject(fileConfiguration); 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; return builder;
} }

View File

@ -9,6 +9,8 @@
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Moq;
using Microsoft.AspNetCore.Hosting;
public class ConfigurationBuilderExtensionsTests public class ConfigurationBuilderExtensionsTests
{ {
@ -19,6 +21,21 @@
private FileConfiguration _reRouteA; private FileConfiguration _reRouteA;
private FileConfiguration _reRouteB; private FileConfiguration _reRouteB;
private FileConfiguration _aggregate; private FileConfiguration _aggregate;
private FileConfiguration _envSpecific;
private Mock<IHostingEnvironment> _hostingEnvironment;
public ConfigurationBuilderExtensionsTests()
{
_hostingEnvironment = new Mock<IHostingEnvironment>();
// Clean up config files before each test
var subConfigFiles = new DirectoryInfo(".").GetFiles("ocelot.*.json");
foreach(var config in subConfigFiles)
{
config.Delete();
}
}
[Fact] [Fact]
public void should_add_base_url_to_config() public void should_add_base_url_to_config()
@ -32,23 +49,35 @@
[Fact] [Fact]
public void should_merge_files() public void should_merge_files()
{ {
this.Given(_ => GivenMultipleConfigurationFiles("")) this.Given(_ => GivenMultipleConfigurationFiles("", false))
.And(_ => GivenTheEnvironmentIs(null))
.When(_ => WhenIAddOcelotConfiguration()) .When(_ => WhenIAddOcelotConfiguration())
.Then(_ => ThenTheConfigsAreMerged()) .Then(_ => ThenTheConfigsAreMerged())
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_merge_files_except_env()
{
this.Given(_ => GivenMultipleConfigurationFiles("", true))
.And(_ => GivenTheEnvironmentIs("Env"))
.When(_ => WhenIAddOcelotConfiguration())
.Then(_ => ThenTheConfigsAreMerged())
.And(_ => NotContainsEnvSpecificConfig())
.BDDfy();
}
[Fact] [Fact]
public void should_merge_files_in_specific_folder() public void should_merge_files_in_specific_folder()
{ {
string configFolder = "ConfigFiles"; string configFolder = "ConfigFiles";
this.Given(_ => GivenMultipleConfigurationFiles(configFolder)) this.Given(_ => GivenMultipleConfigurationFiles(configFolder, false))
.When(_ => WhenIAddOcelotConfigurationWithSpecificFolder(configFolder)) .When(_ => WhenIAddOcelotConfigurationWithSpecificFolder(configFolder))
.Then(_ => ThenTheConfigsAreMerged()) .Then(_ => ThenTheConfigsAreMerged())
.BDDfy(); .BDDfy();
} }
private void GivenMultipleConfigurationFiles(string folder) private void GivenMultipleConfigurationFiles(string folder, bool addEnvSpecificConfig)
{ {
if (!string.IsNullOrEmpty(folder)) if (!string.IsNullOrEmpty(folder))
{ {
@ -174,6 +203,32 @@
} }
}; };
_envSpecific = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamScheme = "DownstreamSchemeSpec",
DownstreamPathTemplate = "DownstreamPathTemplateSpec",
Key = "KeySpec",
UpstreamHost = "UpstreamHostSpec",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodSpec"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostSpec",
Port = 80
}
}
}
}
};
string globalFilename = Path.Combine(folder, "ocelot.global.json"); string globalFilename = Path.Combine(folder, "ocelot.global.json");
string reroutesAFilename = Path.Combine(folder, "ocelot.reRoutesA.json"); string reroutesAFilename = Path.Combine(folder, "ocelot.reRoutesA.json");
string reroutesBFilename = Path.Combine(folder, "ocelot.reRoutesB.json"); string reroutesBFilename = Path.Combine(folder, "ocelot.reRoutesB.json");
@ -183,19 +238,32 @@
File.WriteAllText(reroutesAFilename, JsonConvert.SerializeObject(_reRouteA)); File.WriteAllText(reroutesAFilename, JsonConvert.SerializeObject(_reRouteA));
File.WriteAllText(reroutesBFilename, JsonConvert.SerializeObject(_reRouteB)); File.WriteAllText(reroutesBFilename, JsonConvert.SerializeObject(_reRouteB));
File.WriteAllText(aggregatesFilename, JsonConvert.SerializeObject(_aggregate)); File.WriteAllText(aggregatesFilename, JsonConvert.SerializeObject(_aggregate));
if (addEnvSpecificConfig)
{
string envSpecificFilename = Path.Combine(folder, "ocelot.Env.json");
File.WriteAllText(envSpecificFilename, JsonConvert.SerializeObject(_envSpecific));
}
}
private void GivenTheEnvironmentIs(string env)
{
_hostingEnvironment.SetupGet(x => x.EnvironmentName).Returns(env);
} }
private void WhenIAddOcelotConfiguration() private void WhenIAddOcelotConfiguration()
{ {
IConfigurationBuilder builder = new ConfigurationBuilder(); IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddOcelot();
builder.AddOcelot(_hostingEnvironment.Object);
_configRoot = builder.Build(); _configRoot = builder.Build();
} }
private void WhenIAddOcelotConfigurationWithSpecificFolder(string folder) private void WhenIAddOcelotConfigurationWithSpecificFolder(string folder)
{ {
IConfigurationBuilder builder = new ConfigurationBuilder(); IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddOcelot(folder); builder.AddOcelot(folder, _hostingEnvironment.Object);
_configRoot = builder.Build(); _configRoot = builder.Build();
} }
@ -235,6 +303,14 @@
fc.Aggregates.Count.ShouldBe(_aggregate.Aggregates.Count); 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) private void GivenTheBaseUrl(string baseUrl)
{ {
#pragma warning disable CS0618 #pragma warning disable CS0618