mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
Feature/removed consul and its deps to other package (#539)
* #529 removed consul deps and introduced delegate to find service discovery provider * +semver: breaking moved consul configuration to package..introduced mechanism for packages to configure Ocelot pipeline
This commit is contained in:
parent
a91235b405
commit
87348e5d1b
@ -121,13 +121,18 @@ At the moment there is no validation at this stage it only happens when Ocelot v
|
|||||||
Store configuration in consul
|
Store configuration in consul
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
If you add the following when you register your services Ocelot will attempt to store and retrieve its configuration in consul KV store.
|
The first thing you need to do is install the NuGet package that provides Consul support in Ocelot.
|
||||||
|
|
||||||
|
``Install-Package Ocelot.Provider.Consul``
|
||||||
|
|
||||||
|
Then you add the following when you register your services Ocelot will attempt to store and retrieve its configuration in consul KV store.
|
||||||
|
|
||||||
.. code-block:: csharp
|
.. code-block:: csharp
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddOcelot()
|
.AddOcelot()
|
||||||
.AddStoreOcelotConfigurationInConsul();
|
.AddConsul()
|
||||||
|
.AddConfigStoredInConsul();
|
||||||
|
|
||||||
You also need to add the following to your ocelot.json. This is how Ocelot
|
You also need to add the following to your ocelot.json. This is how Ocelot
|
||||||
finds your Consul agent and interacts to load and store the configuration from Consul.
|
finds your Consul agent and interacts to load and store the configuration from Consul.
|
||||||
|
@ -11,6 +11,17 @@ you specify a ServiceName for at ReRoute level.
|
|||||||
Consul
|
Consul
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
|
The first thing you need to do is install the NuGet package that provides Consul support in Ocelot.
|
||||||
|
|
||||||
|
``Install-Package Ocelot.Provider.Consul``
|
||||||
|
|
||||||
|
Then add the following to your ConfigureServices method.
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
s.AddOcelot()
|
||||||
|
.AddConsul();
|
||||||
|
|
||||||
The following is required in the GlobalConfiguration. The Provider is required and if you do not specify a host and port the Consul default
|
The following is required in the GlobalConfiguration. The Provider is required and if you do not specify a host and port the Consul default
|
||||||
will be used.
|
will be used.
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace Ocelot.Configuration.Repository
|
|||||||
|
|
||||||
private async Task Poll()
|
private async Task Poll()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Started polling consul");
|
_logger.LogInformation("Started polling");
|
||||||
|
|
||||||
var fileConfig = await _repo.Get();
|
var fileConfig = await _repo.Get();
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ namespace Ocelot.Configuration.Repository
|
|||||||
_previousAsJson = asJson;
|
_previousAsJson = asJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Finished polling consul");
|
_logger.LogInformation("Finished polling");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
using Ocelot.Errors;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Repository
|
|
||||||
{
|
|
||||||
public class UnableToSetConfigInConsulError : Error
|
|
||||||
{
|
|
||||||
public UnableToSetConfigInConsulError(string message)
|
|
||||||
: base(message, OcelotErrorCode.UnableToSetConfigInConsulError)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,7 +29,6 @@
|
|||||||
UnableToFindLoadBalancerError,
|
UnableToFindLoadBalancerError,
|
||||||
RequestTimedOutError,
|
RequestTimedOutError,
|
||||||
UnableToFindQoSProviderError,
|
UnableToFindQoSProviderError,
|
||||||
UnableToSetConfigInConsulError,
|
|
||||||
UnmappableRequestError,
|
UnmappableRequestError,
|
||||||
RateLimitOptionsError,
|
RateLimitOptionsError,
|
||||||
PathTemplateDoesntStartWithForwardSlash,
|
PathTemplateDoesntStartWithForwardSlash,
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Ocelot.Middleware
|
||||||
|
{
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
||||||
|
public delegate Task OcelotMiddlewareConfigurationDelegate(IApplicationBuilder builder);
|
||||||
|
}
|
@ -134,16 +134,17 @@
|
|||||||
internalConfigRepo.AddOrReplace(newInternalConfig.Data);
|
internalConfigRepo.AddOrReplace(newInternalConfig.Data);
|
||||||
});
|
});
|
||||||
|
|
||||||
var fileConfigRepo = builder.ApplicationServices.GetService<IFileConfigurationRepository>();
|
|
||||||
|
|
||||||
var adminPath = builder.ApplicationServices.GetService<IAdministrationPath>();
|
var adminPath = builder.ApplicationServices.GetService<IAdministrationPath>();
|
||||||
|
|
||||||
if (UsingConsul(fileConfigRepo))
|
var configurations = builder.ApplicationServices.GetServices<OcelotMiddlewareConfigurationDelegate>();
|
||||||
|
|
||||||
|
// Todo - this has just been added for consul so far...will there be an ordering problem in the future? Should refactor all config into this pattern?
|
||||||
|
foreach (var configuration in configurations)
|
||||||
{
|
{
|
||||||
//Lots of jazz happens in here..check it out if you are using consul to store your config.
|
await configuration(builder);
|
||||||
await SetFileConfigInConsul(builder, fileConfigRepo, fileConfig, internalConfigCreator, internalConfigRepo);
|
|
||||||
}
|
}
|
||||||
else if(AdministrationApiInUse(adminPath))
|
|
||||||
|
if(AdministrationApiInUse(adminPath))
|
||||||
{
|
{
|
||||||
//We have to make sure the file config is set for the ocelot.env.json and ocelot.json so that if we pull it from the
|
//We have to make sure the file config is set for the ocelot.env.json and ocelot.json so that if we pull it from the
|
||||||
//admin api it works...boy this is getting a spit spags boll.
|
//admin api it works...boy this is getting a spit spags boll.
|
||||||
@ -160,49 +161,6 @@
|
|||||||
return adminPath != null;
|
return adminPath != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetFileConfigInConsul(IApplicationBuilder builder,
|
|
||||||
IFileConfigurationRepository fileConfigRepo, IOptionsMonitor<FileConfiguration> fileConfig,
|
|
||||||
IInternalConfigurationCreator internalConfigCreator, IInternalConfigurationRepository internalConfigRepo)
|
|
||||||
{
|
|
||||||
// get the config from consul.
|
|
||||||
var fileConfigFromConsul = await fileConfigRepo.Get();
|
|
||||||
|
|
||||||
if (IsError(fileConfigFromConsul))
|
|
||||||
{
|
|
||||||
ThrowToStopOcelotStarting(fileConfigFromConsul);
|
|
||||||
}
|
|
||||||
else if (ConfigNotStoredInConsul(fileConfigFromConsul))
|
|
||||||
{
|
|
||||||
//there was no config in consul set the file in config in consul
|
|
||||||
await fileConfigRepo.Set(fileConfig.CurrentValue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// create the internal config from consul data
|
|
||||||
var internalConfig = await internalConfigCreator.Create(fileConfigFromConsul.Data);
|
|
||||||
|
|
||||||
if (IsError(internalConfig))
|
|
||||||
{
|
|
||||||
ThrowToStopOcelotStarting(internalConfig);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// add the internal config to the internal repo
|
|
||||||
var response = internalConfigRepo.AddOrReplace(internalConfig.Data);
|
|
||||||
|
|
||||||
if (IsError(response))
|
|
||||||
{
|
|
||||||
ThrowToStopOcelotStarting(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsError(internalConfig))
|
|
||||||
{
|
|
||||||
ThrowToStopOcelotStarting(internalConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptionsMonitor<FileConfiguration> fileConfig)
|
private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptionsMonitor<FileConfiguration> fileConfig)
|
||||||
{
|
{
|
||||||
var response = await fileConfigSetter.Set(fileConfig.CurrentValue);
|
var response = await fileConfigSetter.Set(fileConfig.CurrentValue);
|
||||||
@ -213,11 +171,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ConfigNotStoredInConsul(Responses.Response<FileConfiguration> fileConfigFromConsul)
|
|
||||||
{
|
|
||||||
return fileConfigFromConsul.Data == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsError(Response response)
|
private static bool IsError(Response response)
|
||||||
{
|
{
|
||||||
return response == null || response.IsError;
|
return response == null || response.IsError;
|
||||||
@ -240,12 +193,6 @@
|
|||||||
throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
|
throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool UsingConsul(IFileConfigurationRepository fileConfigRepo)
|
|
||||||
{
|
|
||||||
//todo - remove coupling by string
|
|
||||||
return fileConfigRepo.GetType().Name == "ConsulFileConfigurationRepository";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)
|
private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(configuration.AdministrationPath))
|
if (!string.IsNullOrEmpty(configuration.AdministrationPath))
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace Ocelot.ServiceDiscovery
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Providers;
|
||||||
|
|
||||||
|
public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, string key);
|
||||||
|
}
|
@ -60,14 +60,16 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
return new EurekaServiceDiscoveryProvider(key, _eurekaClient);
|
return new EurekaServiceDiscoveryProvider(key, _eurekaClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo - dont just hardcode this...only expect Consul at the momement so works.
|
foreach (var serviceDiscoveryFinderDelegate in _delegates)
|
||||||
var finderDelegate = _delegates.FirstOrDefault();
|
{
|
||||||
|
var provider = serviceDiscoveryFinderDelegate?.Invoke(_provider, config, key);
|
||||||
|
if (provider != null)
|
||||||
|
{
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var provider = finderDelegate?.Invoke(_provider, config, key);
|
return null;
|
||||||
|
|
||||||
return provider;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, string key);
|
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => WhenTheConfigIsChangedInConsul(newConfig, 0))
|
this.Given(x => WhenTheConfigIsChanged(newConfig, 0))
|
||||||
.Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1))
|
.Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -96,13 +96,13 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => WhenTheConfigIsChangedInConsul(newConfig, 10))
|
this.Given(x => WhenTheConfigIsChanged(newConfig, 10))
|
||||||
.Then(x => ThenTheSetterIsCalled(newConfig, 1))
|
.Then(x => ThenTheSetterIsCalled(newConfig, 1))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_do_nothing_if_call_to_consul_fails()
|
public void should_do_nothing_if_call_to_provider_fails()
|
||||||
{
|
{
|
||||||
var newConfig = new FileConfiguration
|
var newConfig = new FileConfiguration
|
||||||
{
|
{
|
||||||
@ -121,19 +121,19 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => WhenConsulErrors())
|
this.Given(x => WhenProviderErrors())
|
||||||
.Then(x => ThenTheSetterIsCalled(newConfig, 0))
|
.Then(x => ThenTheSetterIsCalled(newConfig, 0))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenConsulErrors()
|
private void WhenProviderErrors()
|
||||||
{
|
{
|
||||||
_repo
|
_repo
|
||||||
.Setup(x => x.Get())
|
.Setup(x => x.Get())
|
||||||
.ReturnsAsync(new ErrorResponse<FileConfiguration>(new AnyError()));
|
.ReturnsAsync(new ErrorResponse<FileConfiguration>(new AnyError()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenTheConfigIsChangedInConsul(FileConfiguration newConfig, int delay)
|
private void WhenTheConfigIsChanged(FileConfiguration newConfig, int delay)
|
||||||
{
|
{
|
||||||
_repo
|
_repo
|
||||||
.Setup(x => x.Get())
|
.Setup(x => x.Get())
|
||||||
|
@ -72,7 +72,6 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
[InlineData(OcelotErrorCode.UnableToFindLoadBalancerError)]
|
[InlineData(OcelotErrorCode.UnableToFindLoadBalancerError)]
|
||||||
[InlineData(OcelotErrorCode.UnableToFindServiceDiscoveryProviderError)]
|
[InlineData(OcelotErrorCode.UnableToFindServiceDiscoveryProviderError)]
|
||||||
[InlineData(OcelotErrorCode.UnableToFindQoSProviderError)]
|
[InlineData(OcelotErrorCode.UnableToFindQoSProviderError)]
|
||||||
[InlineData(OcelotErrorCode.UnableToSetConfigInConsulError)]
|
|
||||||
[InlineData(OcelotErrorCode.UnknownError)]
|
[InlineData(OcelotErrorCode.UnknownError)]
|
||||||
[InlineData(OcelotErrorCode.UnmappableRequestError)]
|
[InlineData(OcelotErrorCode.UnmappableRequestError)]
|
||||||
[InlineData(OcelotErrorCode.UnsupportedAuthenticationProviderError)]
|
[InlineData(OcelotErrorCode.UnsupportedAuthenticationProviderError)]
|
||||||
@ -126,7 +125,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
// If this test fails then it's because the number of error codes has changed.
|
// If this test fails then it's because the number of error codes has changed.
|
||||||
// You should make the appropriate changes to the test cases here to ensure
|
// You should make the appropriate changes to the test cases here to ensure
|
||||||
// they cover all the error codes, and then modify this assertion.
|
// they cover all the error codes, and then modify this assertion.
|
||||||
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(35, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
|
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(34, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
|
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user