#529 removed consul deps and introduced delegate to find service discovery provider (#538)

This commit is contained in:
Tom Pallister
2018-08-12 14:46:46 +05:30
committed by GitHub
parent afe322693e
commit a91235b405
26 changed files with 101 additions and 2385 deletions

View File

@ -1,97 +0,0 @@
namespace Ocelot.Configuration.Repository
{
using System;
using System.Text;
using System.Threading.Tasks;
using Consul;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.Infrastructure.Consul;
using Ocelot.Logging;
using Ocelot.Responses;
using Ocelot.ServiceDiscovery.Configuration;
public class ConsulFileConfigurationRepository : IFileConfigurationRepository
{
private readonly IConsulClient _consul;
private readonly string _configurationKey;
private readonly Cache.IOcelotCache<FileConfiguration> _cache;
private readonly IOcelotLogger _logger;
public ConsulFileConfigurationRepository(
Cache.IOcelotCache<FileConfiguration> cache,
IInternalConfigurationRepository repo,
IConsulClientFactory factory,
IOcelotLoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<ConsulFileConfigurationRepository>();
_cache = cache;
var internalConfig = repo.Get();
_configurationKey = "InternalConfiguration";
string token = null;
if (!internalConfig.IsError)
{
token = internalConfig.Data.ServiceProviderConfiguration.Token;
_configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey) ?
internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey : _configurationKey;
}
var config = new ConsulRegistryConfiguration(internalConfig.Data.ServiceProviderConfiguration.Host,
internalConfig.Data.ServiceProviderConfiguration.Port, _configurationKey, token);
_consul = factory.Get(config);
}
public async Task<Response<FileConfiguration>> Get()
{
var config = _cache.Get(_configurationKey, _configurationKey);
if (config != null)
{
return new OkResponse<FileConfiguration>(config);
}
var queryResult = await _consul.KV.Get(_configurationKey);
if (queryResult.Response == null)
{
return new OkResponse<FileConfiguration>(null);
}
var bytes = queryResult.Response.Value;
var json = Encoding.UTF8.GetString(bytes);
var consulConfig = JsonConvert.DeserializeObject<FileConfiguration>(json);
return new OkResponse<FileConfiguration>(consulConfig);
}
public async Task<Response> Set(FileConfiguration ocelotConfiguration)
{
var json = JsonConvert.SerializeObject(ocelotConfiguration, Formatting.Indented);
var bytes = Encoding.UTF8.GetBytes(json);
var kvPair = new KVPair(_configurationKey)
{
Value = bytes
};
var result = await _consul.KV.Put(kvPair);
if (result.Response)
{
_cache.AddAndDelete(_configurationKey, ocelotConfiguration, TimeSpan.FromSeconds(3), _configurationKey);
return new OkResponse();
}
return new ErrorResponse(new UnableToSetConfigInConsulError($"Unable to set FileConfiguration in consul, response status code from consul was {result.StatusCode}"));
}
}
}

View File

@ -10,8 +10,8 @@ namespace Ocelot.DependencyInjection
public interface IOcelotBuilder
{
IServiceCollection Services { get; }
IConfiguration Configuration { get; }
IOcelotBuilder AddStoreOcelotConfigurationInConsul();
IOcelotAdministrationBuilder AddAdministration(string path, string secret);
@ -22,6 +22,7 @@ namespace Ocelot.DependencyInjection
IOcelotBuilder AddSingletonDefinedAggregator<T>()
where T : class, IDefinedAggregator;
IOcelotBuilder AddTransientDefinedAggregator<T>()
where T : class, IDefinedAggregator;
}

View File

@ -40,7 +40,6 @@ namespace Ocelot.DependencyInjection
using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Net.Http;
using Ocelot.Infrastructure;
using Ocelot.Infrastructure.Consul;
using Ocelot.Middleware.Multiplexer;
using ServiceDiscovery.Providers;
using Steeltoe.Common.Discovery;
@ -148,7 +147,6 @@ namespace Ocelot.DependencyInjection
Services.TryAddSingleton<IFileConfigurationPollerOptions, InMemoryFileConfigurationPollerOptions>();
Services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
Services.TryAddSingleton<IPlaceholders, Placeholders>();
Services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
Services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
Services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
Services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
@ -217,13 +215,6 @@ namespace Ocelot.DependencyInjection
return this;
}
public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
{
Services.AddHostedService<FileConfigurationPoller>();
Services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
return this;
}
private void AddIdentityServer(Action<IdentityServerAuthenticationOptions> configOptions)
{
Services

View File

@ -1,22 +0,0 @@
using System;
using Consul;
using Ocelot.ServiceDiscovery.Configuration;
namespace Ocelot.Infrastructure.Consul
{
public class ConsulClientFactory : IConsulClientFactory
{
public IConsulClient Get(ConsulRegistryConfiguration config)
{
return new ConsulClient(c =>
{
c.Address = new Uri($"http://{config.Host}:{config.Port}");
if (!string.IsNullOrEmpty(config?.Token))
{
c.Token = config.Token;
}
});
}
}
}

View File

@ -1,10 +0,0 @@
using Consul;
using Ocelot.ServiceDiscovery.Configuration;
namespace Ocelot.Infrastructure.Consul
{
public interface IConsulClientFactory
{
IConsulClient Get(ConsulRegistryConfiguration config);
}
}

View File

@ -242,7 +242,8 @@
private static bool UsingConsul(IFileConfigurationRepository fileConfigRepo)
{
return fileConfigRepo.GetType() == typeof(ConsulFileConfigurationRepository);
//todo - remove coupling by string
return fileConfigRepo.GetType().Name == "ConsulFileConfigurationRepository";
}
private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)

View File

@ -46,7 +46,6 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
<PackageReference Include="Consul" Version="0.7.2.5" />
<PackageReference Include="Polly" Version="6.0.1" />
<PackageReference Include="IdentityServer4" Version="2.2.0" />
<PackageReference Include="Pivotal.Discovery.ClientCore" Version="2.0.1" />

View File

@ -1,18 +0,0 @@
namespace Ocelot.ServiceDiscovery.Configuration
{
public class ConsulRegistryConfiguration
{
public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token)
{
Host = string.IsNullOrEmpty(host) ? "localhost" : host;
Port = port > 0 ? port : 8500;
KeyOfServiceInConsul = keyOfServiceInConsul;
Token = token;
}
public string KeyOfServiceInConsul { get; }
public string Host { get; }
public int Port { get; }
public string Token { get; }
}
}

View File

@ -1,77 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Consul;
using Ocelot.Infrastructure.Consul;
using Ocelot.Infrastructure.Extensions;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Configuration;
using Ocelot.Values;
namespace Ocelot.ServiceDiscovery.Providers
{
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
{
private readonly ConsulRegistryConfiguration _config;
private readonly IOcelotLogger _logger;
private readonly IConsulClient _consul;
private const string VersionPrefix = "version-";
public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration config, IOcelotLoggerFactory factory, IConsulClientFactory clientFactory)
{;
_logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
_config = config;
_consul = clientFactory.Get(_config);
}
public async Task<List<Service>> Get()
{
var queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul, string.Empty, true);
var services = new List<Service>();
foreach (var serviceEntry in queryResult.Response)
{
if (IsValid(serviceEntry))
{
services.Add(BuildService(serviceEntry));
}
else
{
_logger.LogWarning($"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0");
}
}
return services.ToList();
}
private Service BuildService(ServiceEntry serviceEntry)
{
return new Service(
serviceEntry.Service.Service,
new ServiceHostAndPort(serviceEntry.Service.Address, serviceEntry.Service.Port),
serviceEntry.Service.ID,
GetVersionFromStrings(serviceEntry.Service.Tags),
serviceEntry.Service.Tags ?? Enumerable.Empty<string>());
}
private bool IsValid(ServiceEntry serviceEntry)
{
if (string.IsNullOrEmpty(serviceEntry.Service.Address) || serviceEntry.Service.Address.Contains("http://") || serviceEntry.Service.Address.Contains("https://") || serviceEntry.Service.Port <= 0)
{
return false;
}
return true;
}
private string GetVersionFromStrings(IEnumerable<string> strings)
{
return strings
?.FirstOrDefault(x => x.StartsWith(VersionPrefix, StringComparison.Ordinal))
.TrimStart(VersionPrefix);
}
}
}

View File

@ -1,56 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Consul;
using Ocelot.Infrastructure.Consul;
using Ocelot.Infrastructure.Extensions;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Configuration;
using Ocelot.Values;
namespace Ocelot.ServiceDiscovery.Providers
{
public class PollingConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
{
private readonly IOcelotLogger _logger;
private readonly IServiceDiscoveryProvider _consulServiceDiscoveryProvider;
private readonly Timer _timer;
private bool _polling;
private List<Service> _services;
private string _keyOfServiceInConsul;
public PollingConsulServiceDiscoveryProvider(int pollingInterval, string keyOfServiceInConsul, IOcelotLoggerFactory factory, IServiceDiscoveryProvider consulServiceDiscoveryProvider)
{;
_logger = factory.CreateLogger<PollingConsulServiceDiscoveryProvider>();
_keyOfServiceInConsul = keyOfServiceInConsul;
_consulServiceDiscoveryProvider = consulServiceDiscoveryProvider;
_services = new List<Service>();
_timer = new Timer(async x =>
{
if(_polling)
{
return;
}
_polling = true;
await Poll();
_polling = false;
}, null, pollingInterval, pollingInterval);
}
public Task<List<Service>> Get()
{
return Task.FromResult(_services);
}
private async Task Poll()
{
_services = await _consulServiceDiscoveryProvider.Get();
}
}
}

View File

@ -1,26 +1,31 @@
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Infrastructure.Consul;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Configuration;
using Ocelot.ServiceDiscovery.Providers;
using Ocelot.Values;
namespace Ocelot.ServiceDiscovery
{
{
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Configuration;
using Ocelot.ServiceDiscovery.Providers;
using Ocelot.Values;
using System;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Steeltoe.Common.Discovery;
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
{
private readonly IOcelotLoggerFactory _factory;
private readonly IConsulClientFactory _consulFactory;
private readonly IDiscoveryClient _eurekaClient;
private readonly List<ServiceDiscoveryFinderDelegate> _delegates;
private readonly IServiceProvider _provider;
public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IConsulClientFactory consulFactory, IDiscoveryClient eurekaClient)
public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IDiscoveryClient eurekaClient, IServiceProvider provider)
{
_factory = factory;
_consulFactory = consulFactory;
_eurekaClient = eurekaClient;
_provider = provider;
_delegates = provider
.GetServices<ServiceDiscoveryFinderDelegate>()
.ToList();
}
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, DownstreamReRoute reRoute)
@ -42,29 +47,27 @@ namespace Ocelot.ServiceDiscovery
return new ConfigurationServiceProvider(services);
}
private IServiceDiscoveryProvider GetServiceDiscoveryProvider(ServiceProviderConfiguration serviceConfig, string serviceName)
private IServiceDiscoveryProvider GetServiceDiscoveryProvider(ServiceProviderConfiguration config, string key)
{
if (serviceConfig.Type?.ToLower() == "servicefabric")
if (config.Type?.ToLower() == "servicefabric")
{
var config = new ServiceFabricConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName);
return new ServiceFabricServiceDiscoveryProvider(config);
var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, key);
return new ServiceFabricServiceDiscoveryProvider(sfConfig);
}
if (serviceConfig.Type?.ToLower() == "eureka")
if (config.Type?.ToLower() == "eureka")
{
return new EurekaServiceDiscoveryProvider(serviceName, _eurekaClient);
}
var consulRegistryConfiguration = new ConsulRegistryConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName, serviceConfig.Token);
var consulServiceDiscoveryProvider = new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory, _consulFactory);
if (serviceConfig.Type?.ToLower() == "pollconsul")
{
return new PollingConsulServiceDiscoveryProvider(serviceConfig.PollingInterval, consulRegistryConfiguration.KeyOfServiceInConsul, _factory, consulServiceDiscoveryProvider);
return new EurekaServiceDiscoveryProvider(key, _eurekaClient);
}
return consulServiceDiscoveryProvider;
// Todo - dont just hardcode this...only expect Consul at the momement so works.
var finderDelegate = _delegates.FirstOrDefault();
var provider = finderDelegate?.Invoke(_provider, config, key);
return provider;
}
}
public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, string key);
}