Skip to content

Commit

Permalink
Merge pull request #85 from TomPallister/feature/config-in-consul
Browse files Browse the repository at this point in the history
added a new implementation that stores the ocelot config in consul kv…
  • Loading branch information
TomPallister authored Apr 16, 2017
2 parents ab9c8e3 + c3cd181 commit 8d31b40
Show file tree
Hide file tree
Showing 34 changed files with 623 additions and 309 deletions.
1 change: 1 addition & 0 deletions src/Ocelot/Cache/IOcelotCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Ocelot.Cache
public interface IOcelotCache<T>
{
void Add(string key, T value, TimeSpan ttl);
void AddAndDelete(string key, T value, TimeSpan ttl);
T Get(string key);
}
}
12 changes: 12 additions & 0 deletions src/Ocelot/Cache/OcelotCacheManagerCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ public void Add(string key, T value, TimeSpan ttl)
_cacheManager.Add(new CacheItem<T>(key, value, ExpirationMode.Absolute, ttl));
}

public void AddAndDelete(string key, T value, TimeSpan ttl)
{
var exists = _cacheManager.Get(key);

if (exists != null)
{
_cacheManager.Remove(key);
}

_cacheManager.Add(new CacheItem<T>(key, value, ExpirationMode.Absolute, ttl));
}

public T Get(string key)
{
return _cacheManager.Get<T>(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public RateLimitOptions Create(FileReRoute fileReRoute, FileGlobalConfiguration
.WithQuotaExceededMessage(globalConfiguration.RateLimitOptions.QuotaExceededMessage)
.WithRateLimitCounterPrefix(globalConfiguration.RateLimitOptions.RateLimitCounterPrefix)
.WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan),
fileReRoute.RateLimitOptions.PeriodTimespan,
fileReRoute.RateLimitOptions.Limit))
.Build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Ocelot.Responses;
using System.Threading.Tasks;
using Ocelot.Responses;

namespace Ocelot.Configuration.Provider
{
public interface IOcelotConfigurationProvider
{
Response<IOcelotConfiguration> Get();
Task<Response<IOcelotConfiguration>> Get();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Ocelot.Configuration.Repository;
using System.Threading.Tasks;
using Ocelot.Configuration.Repository;
using Ocelot.Responses;

namespace Ocelot.Configuration.Provider
Expand All @@ -15,9 +16,9 @@ public OcelotConfigurationProvider(IOcelotConfigurationRepository repo)
_repo = repo;
}

public Response<IOcelotConfiguration> Get()
public async Task<Response<IOcelotConfiguration>> Get()
{
var repoConfig = _repo.Get();
var repoConfig = await _repo.Get();

if (repoConfig.IsError)
{
Expand Down
11 changes: 5 additions & 6 deletions src/Ocelot/Configuration/QoSOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using Polly.Timeout;
using Polly.Timeout;

namespace Ocelot.Configuration
{
Expand All @@ -12,17 +11,17 @@ public QoSOptions(
TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
{
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
DurationOfBreak = TimeSpan.FromMilliseconds(durationofBreak);
TimeoutValue = TimeSpan.FromMilliseconds(timeoutValue);
DurationOfBreak = durationofBreak;
TimeoutValue = timeoutValue;
TimeoutStrategy = timeoutStrategy;
}


public int ExceptionsAllowedBeforeBreaking { get; private set; }

public TimeSpan DurationOfBreak { get; private set; }
public int DurationOfBreak { get; private set; }

public TimeSpan TimeoutValue { get; private set; }
public int TimeoutValue { get; private set; }

public TimeoutStrategy TimeoutStrategy { get; private set; }

Expand Down
24 changes: 1 addition & 23 deletions src/Ocelot/Configuration/RateLimitOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

Expand Down Expand Up @@ -59,25 +58,4 @@ public RateLimitOptions(bool enbleRateLimiting, string clientIdHeader, List<stri
/// </summary>
public bool DisableRateLimitHeaders { get; private set; }
}

public class RateLimitRule
{
public RateLimitRule(string period, TimeSpan periodTimespan, long limit)
{
Period = period;
PeriodTimespan = periodTimespan;
Limit = limit;
}

/// <summary>
/// Rate limit period as in 1s, 1m, 1h,1d
/// </summary>
public string Period { get; private set; }

public TimeSpan PeriodTimespan { get; private set; }
/// <summary>
/// Maximum number of requests that a client can make in a defined period
/// </summary>
public long Limit { get; private set; }
}
}
25 changes: 25 additions & 0 deletions src/Ocelot/Configuration/RateLimitRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;

namespace Ocelot.Configuration
{
public class RateLimitRule
{
public RateLimitRule(string period, double periodTimespan, long limit)
{
Period = period;
PeriodTimespan = periodTimespan;
Limit = limit;
}

/// <summary>
/// Rate limit period as in 1s, 1m, 1h,1d
/// </summary>
public string Period { get; private set; }

public double PeriodTimespan { get; private set; }
/// <summary>
/// Maximum number of requests that a client can make in a defined period
/// </summary>
public long Limit { get; private set; }
}
}
22 changes: 11 additions & 11 deletions src/Ocelot/Configuration/ReRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace Ocelot.Configuration
public class ReRoute
{
public ReRoute(PathTemplate downstreamPathTemplate,
PathTemplate upstreamTemplate,
PathTemplate upstreamPathTemplate,
HttpMethod upstreamHttpMethod,
string upstreamTemplatePattern,
bool isAuthenticated,
AuthenticationOptions authenticationOptions,
List<ClaimToThing> configurationHeaderExtractorProperties,
List<ClaimToThing> claimsToHeaders,
List<ClaimToThing> claimsToClaims,
Dictionary<string, string> routeClaimsRequirement,
bool isAuthorised,
Expand All @@ -27,8 +27,8 @@ public ReRoute(PathTemplate downstreamPathTemplate,
string reRouteKey,
ServiceProviderConfiguration serviceProviderConfiguraion,
bool isQos,
QoSOptions qos,
bool enableRateLimit,
QoSOptions qosOptions,
bool enableEndpointRateLimiting,
RateLimitOptions ratelimitOptions)
{
ReRouteKey = reRouteKey;
Expand All @@ -37,7 +37,7 @@ public ReRoute(PathTemplate downstreamPathTemplate,
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
DownstreamPathTemplate = downstreamPathTemplate;
UpstreamPathTemplate = upstreamTemplate;
UpstreamPathTemplate = upstreamPathTemplate;
UpstreamHttpMethod = upstreamHttpMethod;
UpstreamTemplatePattern = upstreamTemplatePattern;
IsAuthenticated = isAuthenticated;
Expand All @@ -51,12 +51,12 @@ public ReRoute(PathTemplate downstreamPathTemplate,
?? new List<ClaimToThing>();
ClaimsToClaims = claimsToClaims
?? new List<ClaimToThing>();
ClaimsToHeaders = configurationHeaderExtractorProperties
ClaimsToHeaders = claimsToHeaders
?? new List<ClaimToThing>();
DownstreamScheme = downstreamScheme;
DownstreamScheme = downstreamScheme;
IsQos = isQos;
QosOptions = qos;
EnableEndpointRateLimiting = enableRateLimit;
QosOptionsOptions = qosOptions;
EnableEndpointEndpointRateLimiting = enableEndpointRateLimiting;
RateLimitOptions = ratelimitOptions;
}

Expand All @@ -77,12 +77,12 @@ public ReRoute(PathTemplate downstreamPathTemplate,
public CacheOptions FileCacheOptions { get; private set; }
public string DownstreamScheme {get;private set;}
public bool IsQos { get; private set; }
public QoSOptions QosOptions { get; private set; }
public QoSOptions QosOptionsOptions { get; private set; }
public string LoadBalancer {get;private set;}
public string DownstreamHost { get; private set; }
public int DownstreamPort { get; private set; }
public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
public bool EnableEndpointRateLimiting { get; private set; }
public bool EnableEndpointEndpointRateLimiting { get; private set; }
public RateLimitOptions RateLimitOptions { get; private set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Consul;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Ocelot.Responses;
using Ocelot.ServiceDiscovery;

namespace Ocelot.Configuration.Repository
{
public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository
{
private readonly ConsulClient _consul;
private ConsulRegistryConfiguration _configuration;
private string _ocelotConfiguration = "OcelotConfiguration";
private Cache.IOcelotCache<IOcelotConfiguration> _cache;

public ConsulOcelotConfigurationRepository(ConsulRegistryConfiguration consulRegistryConfiguration, Cache.IOcelotCache<IOcelotConfiguration> cache)
{
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
_configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName);
_cache = cache;
_consul = new ConsulClient(config =>
{
config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}");
});
}

public async Task<Response<IOcelotConfiguration>> Get()
{
var config = _cache.Get(_ocelotConfiguration);

if (config != null)
{
return new OkResponse<IOcelotConfiguration>(config);
}

var queryResult = await _consul.KV.Get(_ocelotConfiguration);

if (queryResult.Response == null)
{
return new OkResponse<IOcelotConfiguration>(null);
}

var bytes = queryResult.Response.Value;

var json = Encoding.UTF8.GetString(bytes);

var consulConfig = JsonConvert.DeserializeObject<OcelotConfiguration>(json);

return new OkResponse<IOcelotConfiguration>(consulConfig);
}

public async Task<Response> AddOrReplace(IOcelotConfiguration ocelotConfiguration)
{
var json = JsonConvert.SerializeObject(ocelotConfiguration);

var bytes = Encoding.UTF8.GetBytes(json);

var kvPair = new KVPair(_ocelotConfiguration)
{
Value = bytes
};

var result = await _consul.KV.Put(kvPair);

if (result.Response)
{
_cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3));

return new OkResponse();
}

return new ErrorResponse(new UnableToSetConfigInConsulError("Unable to set config in consul"));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using Ocelot.Responses;
using System.Threading.Tasks;
using Ocelot.Responses;

namespace Ocelot.Configuration.Repository
{
public interface IOcelotConfigurationRepository
{
Response<IOcelotConfiguration> Get();
Response AddOrReplace(IOcelotConfiguration ocelotConfiguration);
Task<Response<IOcelotConfiguration>> Get();
Task<Response> AddOrReplace(IOcelotConfiguration ocelotConfiguration);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Ocelot.Responses;
using System.Threading.Tasks;
using Ocelot.Responses;

namespace Ocelot.Configuration.Repository
{
Expand All @@ -11,12 +12,12 @@ public class InMemoryOcelotConfigurationRepository : IOcelotConfigurationReposit

private IOcelotConfiguration _ocelotConfiguration;

public Response<IOcelotConfiguration> Get()
public async Task<Response<IOcelotConfiguration>> Get()
{
return new OkResponse<IOcelotConfiguration>(_ocelotConfiguration);
}

public Response AddOrReplace(IOcelotConfiguration ocelotConfiguration)
public async Task<Response> AddOrReplace(IOcelotConfiguration ocelotConfiguration)
{
lock (LockObject)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Ocelot.Errors;

namespace Ocelot.Configuration.Repository
{
public class UnableToSetConfigInConsulError : Error
{
public UnableToSetConfigInConsulError(string message)
: base(message, OcelotErrorCode.UnableToSetConfigInConsulError)
{
}
}
}
2 changes: 1 addition & 1 deletion src/Ocelot/Configuration/Setter/FileConfigurationSetter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async Task<Response> Set(FileConfiguration fileConfig)

if(!config.IsError)
{
_configRepo.AddOrReplace(config.Data);
await _configRepo.AddOrReplace(config.Data);
}

return new ErrorResponse(config.Errors);
Expand Down
Loading

0 comments on commit 8d31b40

Please sign in to comment.