diff --git a/.paket/install.bat b/.paket/install.bat
new file mode 100644
index 00000000..f7942c03
--- /dev/null
+++ b/.paket/install.bat
@@ -0,0 +1,7 @@
+@echo off
+cd /d %~dp0
+paket.bootstrapper.exe
+paket.exe install
+echo.
+echo.
+pause
\ No newline at end of file
diff --git a/Gigya.Microdot.Configuration/Gigya.Microdot.Configuration.csproj b/Gigya.Microdot.Configuration/Gigya.Microdot.Configuration.csproj
index 5acb387e..dc04f4e2 100644
--- a/Gigya.Microdot.Configuration/Gigya.Microdot.Configuration.csproj
+++ b/Gigya.Microdot.Configuration/Gigya.Microdot.Configuration.csproj
@@ -161,5 +161,4 @@
-
\ No newline at end of file
diff --git a/Gigya.Microdot.Fakes/DateTimeFake.cs b/Gigya.Microdot.Fakes/DateTimeFake.cs
index 62c7ebed..73f1980b 100644
--- a/Gigya.Microdot.Fakes/DateTimeFake.cs
+++ b/Gigya.Microdot.Fakes/DateTimeFake.cs
@@ -22,14 +22,15 @@
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
using Gigya.Microdot.Interfaces.SystemWrappers;
namespace Gigya.Microdot.Fakes
{
- public class DateTimeFake: IDateTime
+ public class DateTimeFake : IDateTime
{
- public DateTime UtcNow { get; set; }
+ public DateTime UtcNow { get; set; } = DateTime.UtcNow;
private TaskCompletionSource _delayTask = new TaskCompletionSource();
@@ -46,10 +47,27 @@ public DateTimeFake(bool manualDelay)
_manualDelay = manualDelay;
}
- public Task Delay(TimeSpan delay)
+ public async Task Delay(TimeSpan delay, CancellationToken cancellationToken = default(CancellationToken))
{
DelaysRequested.Add(delay);
- return _manualDelay ? _delayTask.Task : Task.Delay(delay);
+
+ if (_manualDelay)
+ await _delayTask.Task;
+ else
+ await Task.Delay(delay, cancellationToken);
+
+ UtcNow += delay;
+ }
+
+ public async Task DelayUntil(DateTime until, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ TimeSpan delayTime = until - UtcNow;
+
+ if (delayTime > TimeSpan.Zero)
+ {
+ await Delay(delayTime, cancellationToken).ConfigureAwait(false);
+ UtcNow += delayTime;
+ }
}
///
diff --git a/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHost.cs b/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHost.cs
index 329a69f0..8e1d1f1f 100644
--- a/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHost.cs
+++ b/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHost.cs
@@ -27,9 +27,9 @@ namespace Gigya.Microdot.Fakes.Discovery
{
public class AlwaysLocalHost : IDiscoverySourceLoader
{
- public IServiceDiscoverySource GetDiscoverySource(ServiceDeployment serviceDeployment, ServiceDiscoveryConfig serviceDiscoveryConfig)
+ public IServiceDiscoverySource GetDiscoverySource(DeploymentIdentifier deploymentIdentifier, ServiceDiscoveryConfig serviceDiscoveryConfig)
{
- return new LocalDiscoverySource(serviceDeployment);
+ return new LocalDiscoverySource(deploymentIdentifier);
}
}
}
\ No newline at end of file
diff --git a/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHostDiscovery.cs b/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHostDiscovery.cs
new file mode 100644
index 00000000..44d67352
--- /dev/null
+++ b/Gigya.Microdot.Fakes/Discovery/AlwaysLocalHostDiscovery.cs
@@ -0,0 +1,55 @@
+#region Copyright
+// Copyright 2017 Gigya Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Gigya.Microdot.ServiceDiscovery;
+using Gigya.Microdot.ServiceDiscovery.Config;
+using Gigya.Microdot.ServiceDiscovery.Rewrite;
+using Gigya.Microdot.SharedLogic.Rewrite;
+
+namespace Gigya.Microdot.Fakes.Discovery
+{
+ public class AlwaysLocalhostDiscovery : IDiscovery
+ {
+ private Func CreateLoadBalancer {get;}
+
+ public AlwaysLocalhostDiscovery(Func createLoadBalancer)
+ {
+ CreateLoadBalancer = createLoadBalancer;
+ }
+
+ public async Task TryCreateLoadBalancer(DeploymentIdentifier deploymentIdentifier, ReachabilityCheck reachabilityCheck, TrafficRoutingStrategy trafficRoutingStrategy)
+ {
+ return CreateLoadBalancer(deploymentIdentifier, new LocalNodeSource(), reachabilityCheck, trafficRoutingStrategy);
+ }
+
+ public async Task GetNodes(DeploymentIdentifier deploymentIdentifier)
+ {
+ return new LocalNodeSource().GetNodes();
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Gigya.Microdot.Fakes/Discovery/LocalhostServiceDiscovery.cs b/Gigya.Microdot.Fakes/Discovery/LocalhostServiceDiscovery.cs
index 082ce51f..acd1585f 100644
--- a/Gigya.Microdot.Fakes/Discovery/LocalhostServiceDiscovery.cs
+++ b/Gigya.Microdot.Fakes/Discovery/LocalhostServiceDiscovery.cs
@@ -20,31 +20,49 @@
// POSSIBILITY OF SUCH DAMAGE.
#endregion
+using System;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
-using Gigya.Microdot.Interfaces.HttpService;
using Gigya.Microdot.ServiceDiscovery;
+using Gigya.Microdot.ServiceDiscovery.Rewrite;
+using Gigya.Microdot.SharedLogic.HttpService;
+using Gigya.Microdot.SharedLogic.Rewrite;
namespace Gigya.Microdot.Fakes.Discovery
{
- public class LocalhostServiceDiscovery : IServiceDiscovery
+ public class LocalhostServiceDiscovery : INewServiceDiscovery
{
- private static readonly IEndPointHandle handle = new LocalhostEndPointHandle();
+ private readonly ILoadBalancer _localhostLoadBalancer = new LocalhostLoadBalancer();
- private readonly Task _source = Task.FromResult(handle);
+ public Task GetLoadBalancer()
+ {
+ return Task.FromResult(_localhostLoadBalancer);
+ }
- private readonly Task allHosts = Task.FromResult(new[] { new EndPoint { HostName = handle.HostName, Port = handle.Port } });
+ }
+
+ public class LocalhostLoadBalancer : ILoadBalancer
+ {
+ readonly INodeSource _localNodeSource = new LocalNodeSource();
- public Task GetNextHost(string affinityToken = null) => _source;
+ public async Task GetNode()
+ {
+ return _localNodeSource.GetNodes().First();
+ }
- public Task GetOrWaitForNextHost(CancellationToken cancellationToken) => _source;
+ public Task WasUndeployed() => Task.FromResult(false);
- public ISourceBlock EndPointsChanged => new BroadcastBlock(null);
+ public void ReportUnreachable(Node node, Exception ex = null)
+ {
+ }
- public ISourceBlock ReachabilityChanged => new BroadcastBlock(null);
+ public void Dispose()
+ {
- public Task GetAllEndPoints() => allHosts;
+ }
}
+
}
diff --git a/Gigya.Microdot.Fakes/Gigya.Microdot.Fakes.csproj b/Gigya.Microdot.Fakes/Gigya.Microdot.Fakes.csproj
index 9836e256..c5f2f1d7 100644
--- a/Gigya.Microdot.Fakes/Gigya.Microdot.Fakes.csproj
+++ b/Gigya.Microdot.Fakes/Gigya.Microdot.Fakes.csproj
@@ -44,6 +44,7 @@
Properties\SolutionVersion.cs
+
@@ -127,5 +128,4 @@
-
\ No newline at end of file
diff --git a/Gigya.Microdot.Hosting/Events/ServiceCallEvent.cs b/Gigya.Microdot.Hosting/Events/ServiceCallEvent.cs
index 25087d62..6b33d2e8 100644
--- a/Gigya.Microdot.Hosting/Events/ServiceCallEvent.cs
+++ b/Gigya.Microdot.Hosting/Events/ServiceCallEvent.cs
@@ -25,8 +25,8 @@
using System.Linq;
using System.Text.RegularExpressions;
using Gigya.Microdot.Interfaces.Events;
-using Gigya.Microdot.Interfaces.HttpService;
using Gigya.Microdot.SharedLogic.Events;
+using Gigya.Microdot.SharedLogic.HttpService;
namespace Gigya.Microdot.Hosting.Events
{
diff --git a/Gigya.Microdot.Hosting/Gigya.Microdot.Hosting.csproj b/Gigya.Microdot.Hosting/Gigya.Microdot.Hosting.csproj
index 77b80032..85492f94 100644
--- a/Gigya.Microdot.Hosting/Gigya.Microdot.Hosting.csproj
+++ b/Gigya.Microdot.Hosting/Gigya.Microdot.Hosting.csproj
@@ -77,6 +77,7 @@
+
@@ -195,5 +196,4 @@
-
\ No newline at end of file
diff --git a/Gigya.Microdot.Hosting/HttpService/Endpoints/SchemaEndpoint.cs b/Gigya.Microdot.Hosting/HttpService/Endpoints/SchemaEndpoint.cs
index a20a4f1c..26959527 100644
--- a/Gigya.Microdot.Hosting/HttpService/Endpoints/SchemaEndpoint.cs
+++ b/Gigya.Microdot.Hosting/HttpService/Endpoints/SchemaEndpoint.cs
@@ -20,7 +20,6 @@
// POSSIBILITY OF SUCH DAMAGE.
#endregion
-using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Gigya.Common.Contracts.HttpService;
@@ -28,16 +27,14 @@
namespace Gigya.Microdot.Hosting.HttpService.Endpoints
{
-
public class SchemaEndpoint : ICustomEndpoint
{
private readonly string _jsonSchema;
- public SchemaEndpoint(IServiceInterfaceMapper mapper)
+ public SchemaEndpoint(ServiceSchema schemaProvider)
{
- _jsonSchema = JsonConvert.SerializeObject(new ServiceSchema(mapper.ServiceInterfaceTypes.ToArray()), new JsonSerializerSettings{Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore});
- }
-
+ _jsonSchema = JsonConvert.SerializeObject(schemaProvider, new JsonSerializerSettings{Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore});
+ }
public async Task TryHandle(HttpListenerContext context, WriteResponseDelegate writeResponse)
{
diff --git a/Gigya.Microdot.Hosting/HttpService/HttpServiceListener.cs b/Gigya.Microdot.Hosting/HttpService/HttpServiceListener.cs
index 24da1c58..3f783541 100644
--- a/Gigya.Microdot.Hosting/HttpService/HttpServiceListener.cs
+++ b/Gigya.Microdot.Hosting/HttpService/HttpServiceListener.cs
@@ -33,16 +33,17 @@
using System.Threading.Tasks;
using Gigya.Common.Contracts;
using Gigya.Common.Contracts.Exceptions;
+using Gigya.Common.Contracts.HttpService;
using Gigya.Microdot.Hosting.Events;
using Gigya.Microdot.Hosting.HttpService.Endpoints;
using Gigya.Microdot.Interfaces.Configuration;
using Gigya.Microdot.Interfaces.Events;
-using Gigya.Microdot.Interfaces.HttpService;
using Gigya.Microdot.Interfaces.Logging;
using Gigya.Microdot.SharedLogic;
using Gigya.Microdot.SharedLogic.Configurations;
using Gigya.Microdot.SharedLogic.Events;
using Gigya.Microdot.SharedLogic.Exceptions;
+using Gigya.Microdot.SharedLogic.HttpService;
using Gigya.Microdot.SharedLogic.Measurement;
using Gigya.Microdot.SharedLogic.Security;
using Metrics;
@@ -87,6 +88,7 @@ public sealed class HttpServiceListener : IDisposable
private JsonExceptionSerializer ExceptionSerializer { get; }
private Func LoadSheddingConfig { get; }
+ private ServiceSchema ServiceSchema { get; }
private readonly Timer _serializationTime;
private readonly Timer _deserializationTime;
@@ -100,9 +102,13 @@ public sealed class HttpServiceListener : IDisposable
public HttpServiceListener(IActivator activator, IWorker worker, IServiceEndPointDefinition serviceEndPointDefinition,
ICertificateLocator certificateLocator, ILog log, IEventPublisher eventPublisher,
IEnumerable customEndpoints, IEnvironmentVariableProvider environmentVariableProvider,
- IServerRequestPublisher serverRequestPublisher,
- JsonExceptionSerializer exceptionSerializer, Func loadSheddingConfig)
+ JsonExceptionSerializer exceptionSerializer,
+ ServiceSchema serviceSchema,
+ Func loadSheddingConfig,
+ IServerRequestPublisher serverRequestPublisher)
+
{
+ ServiceSchema = serviceSchema;
_serverRequestPublisher = serverRequestPublisher;
ServiceEndPointDefinition = serviceEndPointDefinition;
Worker = worker;
@@ -356,12 +362,12 @@ private static IEnumerable GetAllExceptions(Exception ex)
private void ValidateRequest(HttpListenerContext context)
{
- var clientVersion = context.Request.Headers[GigyaHttpHeaders.Version];
+ var clientVersion = context.Request.Headers[GigyaHttpHeaders.ProtocolVersion];
- if (clientVersion != null && clientVersion != HttpServiceRequest.Version)
+ if (clientVersion != null && clientVersion != HttpServiceRequest.ProtocolVersion)
{
_failureCounter.Increment("ProtocolVersionMismatch");
- throw new RequestException($"Client protocol version {clientVersion} is not supported by the server protocol version {HttpServiceRequest.Version}.");
+ throw new RequestException($"Client protocol version {clientVersion} is not supported by the server protocol version {HttpServiceRequest.ProtocolVersion}.");
}
if (context.Request.HttpMethod != "POST")
@@ -416,7 +422,7 @@ private async Task CheckSecureConnection(HttpListenerContext context)
private async Task TryWriteResponse(HttpListenerContext context, string data, HttpStatusCode httpStatus = HttpStatusCode.OK, string contentType = "application/json")
{
- context.Response.Headers.Add(GigyaHttpHeaders.Version, HttpServiceRequest.Version);
+ context.Response.Headers.Add(GigyaHttpHeaders.ProtocolVersion, HttpServiceRequest.ProtocolVersion);
var body = Encoding.UTF8.GetBytes(data ?? "");
@@ -427,6 +433,8 @@ private async Task TryWriteResponse(HttpListenerContext context, string data, Ht
context.Response.Headers.Add(GigyaHttpHeaders.Environment, EnvironmentVariableProvider.DeploymentEnvironment);
context.Response.Headers.Add(GigyaHttpHeaders.ServiceVersion, CurrentApplicationInfo.Version.ToString());
context.Response.Headers.Add(GigyaHttpHeaders.ServerHostname, CurrentApplicationInfo.HostName);
+ context.Response.Headers.Add(GigyaHttpHeaders.SchemaHash, ServiceSchema.Hash);
+
try
{
await context.Response.OutputStream.WriteAsync(body, 0, body.Length);
diff --git a/Gigya.Microdot.Hosting/HttpService/IServiceEndPointDefinition.cs b/Gigya.Microdot.Hosting/HttpService/IServiceEndPointDefinition.cs
index 9f036857..7748da12 100644
--- a/Gigya.Microdot.Hosting/HttpService/IServiceEndPointDefinition.cs
+++ b/Gigya.Microdot.Hosting/HttpService/IServiceEndPointDefinition.cs
@@ -23,7 +23,7 @@
using System;
using System.Collections.Generic;
using Gigya.Common.Contracts.HttpService;
-using Gigya.Microdot.Interfaces.HttpService;
+using Gigya.Microdot.SharedLogic.HttpService;
namespace Gigya.Microdot.Hosting.HttpService
{
diff --git a/Gigya.Microdot.Hosting/HttpService/ServerRequestPublisher.cs b/Gigya.Microdot.Hosting/HttpService/ServerRequestPublisher.cs
index 3f25809b..9dd1991f 100644
--- a/Gigya.Microdot.Hosting/HttpService/ServerRequestPublisher.cs
+++ b/Gigya.Microdot.Hosting/HttpService/ServerRequestPublisher.cs
@@ -5,9 +5,8 @@
using System.Linq;
using Gigya.Microdot.Hosting.Events;
using Gigya.Microdot.Interfaces.Events;
-using Gigya.Microdot.Interfaces.HttpService;
using Gigya.Microdot.SharedLogic.Events;
-using Newtonsoft.Json;
+using Gigya.Microdot.SharedLogic.HttpService;
namespace Gigya.Microdot.Hosting.HttpService
{
diff --git a/Gigya.Microdot.Hosting/HttpService/ServiceEndPointDefinition.cs b/Gigya.Microdot.Hosting/HttpService/ServiceEndPointDefinition.cs
index 9cf5114d..44b8ed3e 100644
--- a/Gigya.Microdot.Hosting/HttpService/ServiceEndPointDefinition.cs
+++ b/Gigya.Microdot.Hosting/HttpService/ServiceEndPointDefinition.cs
@@ -28,10 +28,10 @@
using Gigya.Common.Contracts.Exceptions;
using Gigya.Common.Contracts.HttpService;
using Gigya.Microdot.Interfaces;
-using Gigya.Microdot.Interfaces.HttpService;
using Gigya.Microdot.ServiceDiscovery.Config;
using Gigya.Microdot.SharedLogic;
using Gigya.Microdot.SharedLogic.Exceptions;
+using Gigya.Microdot.SharedLogic.HttpService;
namespace Gigya.Microdot.Hosting.HttpService
{
@@ -70,7 +70,7 @@ public ServiceEndPointDefinition(IServiceInterfaceMapper mapper,
ServiceNames = serviceInterfaces
.Where(i => i.GetCustomAttribute() != null)
- .ToDictionary(x => x, x => x.GetCustomAttribute().Name ?? x.Name);
+ .ToDictionary(x => x, x => x.Name);
var interfacePorts = serviceInterfaces.Select(i =>
{
diff --git a/Gigya.Microdot.Hosting/HttpService/ServiceMethodResolver.cs b/Gigya.Microdot.Hosting/HttpService/ServiceMethodResolver.cs
index 07e4b758..5ee6b13a 100644
--- a/Gigya.Microdot.Hosting/HttpService/ServiceMethodResolver.cs
+++ b/Gigya.Microdot.Hosting/HttpService/ServiceMethodResolver.cs
@@ -26,7 +26,7 @@
using System.Linq;
using System.Reflection;
using Gigya.Common.Contracts.Exceptions;
-using Gigya.Microdot.Interfaces.HttpService;
+using Gigya.Microdot.SharedLogic.HttpService;
namespace Gigya.Microdot.Hosting.HttpService
{
diff --git a/Gigya.Microdot.Hosting/Validators/LogFieldAttributeValidator.cs b/Gigya.Microdot.Hosting/Validators/LogFieldAttributeValidator.cs
index 7203b0ac..a625387f 100644
--- a/Gigya.Microdot.Hosting/Validators/LogFieldAttributeValidator.cs
+++ b/Gigya.Microdot.Hosting/Validators/LogFieldAttributeValidator.cs
@@ -1,4 +1,26 @@
-using System;
+#region Copyright
+// Copyright 2017 Gigya Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
using System.Linq;
using System.Reflection;
using Gigya.Common.Contracts.Exceptions;
diff --git a/Gigya.Microdot.Hosting/Validators/SensitivityAttributesValidator.cs b/Gigya.Microdot.Hosting/Validators/SensitivityAttributesValidator.cs
new file mode 100644
index 00000000..db18126f
--- /dev/null
+++ b/Gigya.Microdot.Hosting/Validators/SensitivityAttributesValidator.cs
@@ -0,0 +1,90 @@
+#region Copyright
+// Copyright 2017 Gigya Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Gigya.Common.Contracts.Exceptions;
+using Gigya.Microdot.Hosting.HttpService;
+using Gigya.ServiceContract.Attributes;
+
+namespace Gigya.Microdot.Hosting.Validators
+{
+ public class SensitivityAttributesValidator : IValidator
+ {
+ private readonly IServiceInterfaceMapper _serviceInterfaceMapper;
+
+ public SensitivityAttributesValidator(IServiceInterfaceMapper serviceInterfaceMapper)
+ {
+ _serviceInterfaceMapper = serviceInterfaceMapper;
+ }
+
+ public void Validate()
+ {
+ foreach (var serviceInterface in _serviceInterfaceMapper.ServiceInterfaceTypes)
+ {
+ foreach (var method in serviceInterface.GetMethods())
+ {
+ if (method.GetCustomAttribute(typeof(SensitiveAttribute)) != null && method.GetCustomAttribute(typeof(NonSensitiveAttribute)) != null)
+ throw new ProgrammaticException($"[Sensitive] and [NonSensitive] can't both be applied on the same method ({method.Name}) on serviceInterface ({serviceInterface.Name})");
+
+ foreach (var parameter in method.GetParameters())
+ {
+ if (parameter.GetCustomAttribute(typeof(SensitiveAttribute)) != null && parameter.GetCustomAttribute(typeof(NonSensitiveAttribute)) != null)
+ {
+ throw new ProgrammaticException($"[Sensitive] and [NonSensitive] can't both be applied on the same parameter ({parameter.Name}) in method ({method.Name}) on serviceInterface ({serviceInterface.Name})");
+ }
+
+ var logFieldExists = Attribute.IsDefined(parameter, typeof(LogFieldsAttribute));
+ if (parameter.ParameterType.IsClass && parameter.ParameterType.FullName?.StartsWith("System.") == false)
+ VerifyMisplacedSensitiveAttribute(logFieldExists, method.Name, parameter.Name, parameter.ParameterType, new Stack());
+ }
+ }
+ }
+ }
+
+
+ private void VerifyMisplacedSensitiveAttribute(bool logFieldExists, string methodName, string paramName, Type type, Stack path)
+ {
+ if (type.IsClass == false || type.FullName?.StartsWith("System.") == true)
+ return;
+
+ foreach (var memberInfo in type.FindMembers(MemberTypes.Property | MemberTypes.Field, BindingFlags.Public | BindingFlags.Instance, null, null)
+ .Where(x => x is FieldInfo || (x is PropertyInfo propertyInfo) && propertyInfo.CanRead))
+ {
+ path.Push(memberInfo.Name);
+
+ if (memberInfo.GetCustomAttribute(typeof(SensitiveAttribute)) != null || memberInfo.GetCustomAttribute(typeof(NonSensitiveAttribute)) != null)
+ if (!logFieldExists)
+ throw new ProgrammaticException($"The method '{methodName}' parameter '{paramName}' has a member '{string.Join(" --> ", path.Reverse())}' that is marked as [Sensitive] or [NonSensitive], but the method parameter is not marked with [LogFields]");
+ else if (path.Count > 1)
+ throw new ProgrammaticException($"The method '{methodName}' parameter '{paramName}' has a member '{string.Join(" --> ", path.Reverse())}' that is marked as [Sensitive] or [NonSensitive], but only root-level members can be marked as such.");
+
+ Type memberType = memberInfo is PropertyInfo propertyInfo ? propertyInfo.PropertyType : ((FieldInfo)memberInfo).FieldType;
+ VerifyMisplacedSensitiveAttribute(logFieldExists, methodName, paramName, memberType, path);
+
+ path.Pop();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Gigya.Microdot.Interfaces/Gigya.Microdot.Interfaces.csproj b/Gigya.Microdot.Interfaces/Gigya.Microdot.Interfaces.csproj
index 343b3224..0bcef000 100644
--- a/Gigya.Microdot.Interfaces/Gigya.Microdot.Interfaces.csproj
+++ b/Gigya.Microdot.Interfaces/Gigya.Microdot.Interfaces.csproj
@@ -54,10 +54,6 @@
-
-
-
-
diff --git a/Gigya.Microdot.Interfaces/SystemWrappers/IDateTime.cs b/Gigya.Microdot.Interfaces/SystemWrappers/IDateTime.cs
index 3b436ed7..001c92ee 100644
--- a/Gigya.Microdot.Interfaces/SystemWrappers/IDateTime.cs
+++ b/Gigya.Microdot.Interfaces/SystemWrappers/IDateTime.cs
@@ -21,6 +21,7 @@
#endregion
using System;
+using System.Threading;
using System.Threading.Tasks;
namespace Gigya.Microdot.Interfaces.SystemWrappers
@@ -28,6 +29,8 @@ namespace Gigya.Microdot.Interfaces.SystemWrappers
public interface IDateTime
{
DateTime UtcNow { get; }
- Task Delay(TimeSpan delay);
+ Task Delay(TimeSpan delay, CancellationToken cancellationToken = default(CancellationToken));
+
+ Task DelayUntil(DateTime until, CancellationToken cancellationToken = default(CancellationToken));
}
}
diff --git a/Gigya.Microdot.Ninject.Host/Gigya.Microdot.Ninject.Host.csproj b/Gigya.Microdot.Ninject.Host/Gigya.Microdot.Ninject.Host.csproj
index a0ab5ca2..d943aa82 100644
--- a/Gigya.Microdot.Ninject.Host/Gigya.Microdot.Ninject.Host.csproj
+++ b/Gigya.Microdot.Ninject.Host/Gigya.Microdot.Ninject.Host.csproj
@@ -144,5 +144,4 @@
-
\ No newline at end of file
diff --git a/Gigya.Microdot.Ninject/Gigya.Microdot.Ninject.csproj b/Gigya.Microdot.Ninject/Gigya.Microdot.Ninject.csproj
index df58b0a9..ca353d5b 100644
--- a/Gigya.Microdot.Ninject/Gigya.Microdot.Ninject.csproj
+++ b/Gigya.Microdot.Ninject/Gigya.Microdot.Ninject.csproj
@@ -186,5 +186,4 @@
-
\ No newline at end of file
diff --git a/Gigya.Microdot.Ninject/MicrodotModule.cs b/Gigya.Microdot.Ninject/MicrodotModule.cs
index 2d5facee..a24bbac2 100644
--- a/Gigya.Microdot.Ninject/MicrodotModule.cs
+++ b/Gigya.Microdot.Ninject/MicrodotModule.cs
@@ -22,17 +22,24 @@
using System;
using System.Collections.Concurrent;
+using System.Linq;
+using Gigya.Common.Contracts.HttpService;
using Gigya.Microdot.Configuration;
+using Gigya.Microdot.Hosting.HttpService;
using Gigya.Microdot.ServiceDiscovery;
using Gigya.Microdot.ServiceDiscovery.HostManagement;
+using Gigya.Microdot.ServiceDiscovery.Rewrite;
using Gigya.Microdot.ServiceProxy;
using Gigya.Microdot.SharedLogic;
using Gigya.Microdot.SharedLogic.Monitor;
+using Gigya.Microdot.SharedLogic.Rewrite;
using Metrics;
using Ninject;
using Ninject.Activation;
using Ninject.Extensions.Factory;
using Ninject.Modules;
+using ConsulClient = Gigya.Microdot.ServiceDiscovery.ConsulClient;
+using IConsulClient = Gigya.Microdot.ServiceDiscovery.IConsulClient;
namespace Gigya.Microdot.Ninject
{
@@ -46,6 +53,7 @@ public class MicrodotModule : NinjectModule
{
typeof(ConsulDiscoverySource),
typeof(RemoteHostPool),
+ typeof(LoadBalancer),
typeof(ConfigDiscoverySource)
};
@@ -60,10 +68,11 @@ public override void Load()
Kernel.Load();
this.BindClassesAsSingleton(NonSingletonBaseTypes, typeof(ConfigurationAssembly), typeof(ServiceProxyAssembly));
- this.BindInterfacesAsSingleton(NonSingletonBaseTypes, typeof(ConfigurationAssembly), typeof(ServiceProxyAssembly), typeof(SharedLogicAssembly),typeof(ServiceDiscoveryAssembly));
-
+ this.BindInterfacesAsSingleton(NonSingletonBaseTypes, typeof(ConfigurationAssembly), typeof(ServiceProxyAssembly), typeof(SharedLogicAssembly), typeof(ServiceDiscoveryAssembly));
+
Bind().ToFactory();
+ Kernel.BindPerKey();
Kernel.BindPerKey();
Kernel.BindPerString();
Kernel.BindPerString();
@@ -76,9 +85,18 @@ public override void Load()
Bind().To().InTransientScope();
Bind().To().InTransientScope();
+ Rebind().To().InTransientScope();
+ Rebind().To().InTransientScope();
+ Rebind().To().InSingletonScope();
+
+ Rebind().ToSelf().InSingletonScope();
+
Kernel.Rebind().To().InTransientScope();
Kernel.Load();
Kernel.Load();
+
+ Kernel.Rebind().ToMethod(c =>
+ new ServiceSchema(c.Kernel.Get().ServiceInterfaceTypes.ToArray())).InSingletonScope();
}
diff --git a/Gigya.Microdot.Orleans.Ninject.Host/Gigya.Microdot.Orleans.Ninject.Host.csproj b/Gigya.Microdot.Orleans.Ninject.Host/Gigya.Microdot.Orleans.Ninject.Host.csproj
index 5d900353..72f8b158 100644
--- a/Gigya.Microdot.Orleans.Ninject.Host/Gigya.Microdot.Orleans.Ninject.Host.csproj
+++ b/Gigya.Microdot.Orleans.Ninject.Host/Gigya.Microdot.Orleans.Ninject.Host.csproj
@@ -227,5 +227,4 @@
-
\ No newline at end of file
diff --git a/Gigya.Microdot.ServiceDiscovery/Config/ConsulConfig.cs b/Gigya.Microdot.ServiceDiscovery/Config/ConsulConfig.cs
index 6f1f2654..ad10d801 100644
--- a/Gigya.Microdot.ServiceDiscovery/Config/ConsulConfig.cs
+++ b/Gigya.Microdot.ServiceDiscovery/Config/ConsulConfig.cs
@@ -3,6 +3,7 @@
namespace Gigya.Microdot.ServiceDiscovery.Config
{
+
[Serializable]
[ConfigurationRoot("Consul", RootStrategy.ReplaceClassNameWithPath)]
public class ConsulConfig : IConfigObject
@@ -10,23 +11,32 @@ public class ConsulConfig : IConfigObject
///
/// Whether to Call Consul with long-polling, waiting for changes to occur, or to call it periodically
///
+ [Obsolete("To be deleted after discovery refactoring")]
public bool LongPolling { get; set; } = false;
///
/// Interval for reloading endpoints from Consul,
- /// Used only when LongPolling=false
+ /// Used for Consul queries loop
///
public TimeSpan ReloadInterval { get; set; } = TimeSpan.FromSeconds(1);
+ ///
+ /// Timeout passed to Consul telling it when to break long-polling.
+ ///
+ public TimeSpan HttpTimeout { get; set; } = TimeSpan.FromMinutes(2);
+
///
/// Time to wait for http response from Consul.
/// When LongPolling=true, defines the maximum time to wait on long-polling.
/// When LongPolling=false, defines the timeout for Consul http requests.
+ /// We take a few seconds more than to reduce the
+ /// risk of getting task cancelled exceptions before Consul gracefully timed out,
+ /// due to network latency or the process being overloaded.
///
- public TimeSpan HttpTimeout { get; set; } = TimeSpan.FromMinutes(2);
+ public TimeSpan HttpTaskTimeout => HttpTimeout.Add(TimeSpan.FromSeconds(5));
///
- /// Interval for retrying access to surce (e.g. Consul) after an error has occured
+ /// Interval for retrying access to Consul after an error has occured
///
public TimeSpan ErrorRetryInterval { get; set; } = TimeSpan.FromSeconds(1);
}
diff --git a/Gigya.Microdot.ServiceDiscovery/Config/DiscoveryConfig.cs b/Gigya.Microdot.ServiceDiscovery/Config/DiscoveryConfig.cs
index 7fae8f86..b00bf384 100644
--- a/Gigya.Microdot.ServiceDiscovery/Config/DiscoveryConfig.cs
+++ b/Gigya.Microdot.ServiceDiscovery/Config/DiscoveryConfig.cs
@@ -50,20 +50,28 @@ public class DiscoveryConfig : IConfigObject
///
public TimeSpan? RequestTimeout { get; set; }
+ ///
+ /// Time period to keep monitoring a deployed service after it was no longer requested
+ ///
+ public TimeSpan MonitoringLifetime { get; set; } = TimeSpan.FromMinutes(5);
+
///
/// When we lose connection to some endpoint, we wait this delay till we start trying to reconnect.
///
+ [Obsolete("To be deleted after discovery refactoring")]
public double FirstAttemptDelaySeconds { get; set; } = 0.001;
///
/// When retrying to reconnect to an endpoint, we use exponential backoff (e.g. 1,2,4,8ms, etc). Once that
/// backoff reaches this value, it won't increase any more.
///
+ [Obsolete("To be deleted after discovery refactoring")]
public double MaxAttemptDelaySeconds { get; set; } = 10;
///
/// The factor of the exponential backoff when retrying connections to endpoints.
///
+ [Obsolete("To be deleted after discovery refactoring")]
public double DelayMultiplier { get; set; } = 2;
///
diff --git a/Gigya.Microdot.ServiceDiscovery/Config/ServiceDiscoveryConfig.cs b/Gigya.Microdot.ServiceDiscovery/Config/ServiceDiscoveryConfig.cs
index 2f6e8f9e..be63ef07 100644
--- a/Gigya.Microdot.ServiceDiscovery/Config/ServiceDiscoveryConfig.cs
+++ b/Gigya.Microdot.ServiceDiscovery/Config/ServiceDiscoveryConfig.cs
@@ -46,17 +46,20 @@ public class ServiceDiscoveryConfig
///
/// When we lose connection to some endpoint, we wait this delay till we start trying to reconnect.
///
+ [Obsolete("To be deleted after discovery refactoring")]
public double? FirstAttemptDelaySeconds { get; set; }
///
/// When retrying to reconnect to an endpoint, we use exponential backoff (e.g. 1,2,4,8ms, etc). Once that
/// backoff reaches this value, it won't increase any more.
///
+ [Obsolete("To be deleted after discovery refactoring")]
public double? MaxAttemptDelaySeconds { get; set; }
///
/// The factor of the exponential backoff when retrying connections to endpoints.
///
+ [Obsolete("To be deleted after discovery refactoring")]
public double? DelayMultiplier { get; set; }
///
diff --git a/Gigya.Microdot.ServiceDiscovery/ConfigDiscoverySource.cs b/Gigya.Microdot.ServiceDiscovery/ConfigDiscoverySource.cs
index 931c34ec..3f2c1ba3 100644
--- a/Gigya.Microdot.ServiceDiscovery/ConfigDiscoverySource.cs
+++ b/Gigya.Microdot.ServiceDiscovery/ConfigDiscoverySource.cs
@@ -43,7 +43,7 @@ public class ConfigDiscoverySource : ServiceDiscoverySourceBase
private string ConfigPath => $"Discovery.{Deployment}";
- public ConfigDiscoverySource(ServiceDeployment deployment, Func getConfig, ILog log) : base(deployment.ServiceName)
+ public ConfigDiscoverySource(DeploymentIdentifier deployment, Func getConfig, ILog log) : base(deployment.ServiceName)
{
_serviceDiscoveryConfig = getConfig().Services[deployment.ServiceName];
Log = log;
diff --git a/Gigya.Microdot.ServiceDiscovery/ConsulClient.cs b/Gigya.Microdot.ServiceDiscovery/ConsulClient.cs
index faae1b81..36eb8286 100644
--- a/Gigya.Microdot.ServiceDiscovery/ConsulClient.cs
+++ b/Gigya.Microdot.ServiceDiscovery/ConsulClient.cs
@@ -78,6 +78,8 @@ public class ConsulClient : IConsulClient
private bool _disposed;
private int _initialized = 0;
+ private readonly IDisposable _healthCheck;
+ private Func _getHealthStatus;
public ConsulClient(string serviceName, Func getConfig,
ISourceBlock configChanged, IEnvironmentVariableProvider environmentVariableProvider,
@@ -101,6 +103,7 @@ public ConsulClient(string serviceName, Func getConfig,
_resultChanged = new BufferBlock();
_initializedVersion = new TaskCompletionSource();
ShutdownToken = new CancellationTokenSource();
+ _healthCheck = _aggregatedHealthStatus.RegisterCheck(_serviceNameOrigin, ()=>_getHealthStatus());
}
public Task Init()
@@ -197,8 +200,7 @@ private Task ConfigChanged(ConsulConfig c)
private async Task LoadServiceVersion()
{
var config = GetConfig();
- var maxSecondsToWaitForResponse = Math.Max(0, config.HttpTimeout.TotalSeconds - 2);
- var urlCommand = $"v1/kv/service/{_serviceName}?dc={DataCenter}&index={_versionModifyIndex}&wait={maxSecondsToWaitForResponse}s";
+ var urlCommand = $"v1/kv/service/{_serviceName}?dc={DataCenter}&index={_versionModifyIndex}&wait={config.HttpTimeout.TotalSeconds}s";
var response = await CallConsul(urlCommand, ShutdownToken.Token).ConfigureAwait(false);
if (response.ModifyIndex.HasValue)
@@ -239,8 +241,7 @@ private Task ReloadServiceVersion()
private async Task SearchServiceInAllKeys()
{
var config = GetConfig();
- var maxSecondsToWaitForResponse = Math.Max(0, config.HttpTimeout.TotalSeconds - 2);
- var urlCommand = $"v1/kv/service?dc={DataCenter}&keys&index={_allKeysModifyIndex}&wait={maxSecondsToWaitForResponse}s";
+ var urlCommand = $"v1/kv/service?dc={DataCenter}&keys&index={_allKeysModifyIndex}&wait={config.HttpTimeout.TotalSeconds}s";
var response = await CallConsul(urlCommand, ShutdownToken.Token).ConfigureAwait(false);
if (response.ModifyIndex.HasValue)
@@ -283,8 +284,7 @@ private async Task LoadEndpointsByHealth()
return new ConsulResponse { IsDeploymentDefined = false };
var config = GetConfig();
- var maxSecondsToWaitForResponse = Math.Max(0, config.HttpTimeout.TotalSeconds - 2);
- var urlCommand = $"v1/health/service/{_serviceName}?dc={DataCenter}&passing&index={_endpointsModifyIndex}&wait={maxSecondsToWaitForResponse}s";
+ var urlCommand = $"v1/health/service/{_serviceName}?dc={DataCenter}&passing&index={_endpointsModifyIndex}&wait={config.HttpTimeout.TotalSeconds}s";
var response = await CallConsul(urlCommand, _loadEndpointsByHealthCancellationTokenSource.Token).ConfigureAwait(false);
if (response.ModifyIndex.HasValue)
@@ -350,7 +350,7 @@ private async Task LoadEndpointsByQuery()
}
private async Task CallConsul(string urlCommand, CancellationToken cancellationToken)
- {
+ {
var timeout = GetConfig().HttpTimeout;
ulong? modifyIndex = 0;
string requestLog = string.Empty;
@@ -359,8 +359,11 @@ private async Task CallConsul(string urlCommand, CancellationTok
try
{
- if (_httpClient == null)
- _httpClient = new HttpClient { BaseAddress = ConsulAddress };
+ if (_httpClient?.Timeout != timeout)
+ {
+ _httpClient?.Dispose();
+ _httpClient = new HttpClient {BaseAddress = ConsulAddress, Timeout = timeout};
+ }
requestLog = _httpClient.BaseAddress + urlCommand;
using (var timeoutcancellationToken = new CancellationTokenSource(timeout))
@@ -377,7 +380,7 @@ private async Task CallConsul(string urlCommand, CancellationTok
unencrypted: new Tags
{
{"ConsulAddress", ConsulAddress.ToString()},
- {"ServiceDeployment", _serviceName},
+ {"ServiceName", _serviceName},
{"ConsulQuery", urlCommand},
{"ResponseCode", statusCode.ToString()},
{"Content", responseContent}
@@ -443,7 +446,7 @@ internal void SetErrorResult(string requestLog, Exception ex, HttpStatusCode? re
Content = responseContent
});
- _aggregatedHealthStatus.RegisterCheck(_serviceNameOrigin, () => HealthCheckResult.Unhealthy($"{_serviceName} - Consul error: " + ex.Message));
+ _getHealthStatus = ()=>HealthCheckResult.Unhealthy($"Consul error: " + ex.Message);
if (Result != null && Result.Error == null)
return;
@@ -477,8 +480,7 @@ internal void SetServiceMissingResult(string requestLog, string responseContent)
IsQueryDefined = false
};
- _aggregatedHealthStatus.RegisterCheck(_serviceNameOrigin,
- () => HealthCheckResult.Healthy($"{_serviceNameOrigin} - Service doesn't exist on Consul"));
+ _getHealthStatus = ()=>HealthCheckResult.Healthy($"Service doesn't exist on Consul");
}
}
@@ -513,13 +515,13 @@ private void SetResult(ServiceEntry[] nodes, string requestLog, string responseC
}
- _aggregatedHealthStatus.RegisterCheck(_serviceNameOrigin, () =>
+ _getHealthStatus = () =>
{
if (_serviceName == _serviceNameOrigin)
- return HealthCheckResult.Healthy($"{_serviceNameOrigin} - {healthMessage}");
+ return HealthCheckResult.Healthy(healthMessage);
else
- return HealthCheckResult.Healthy($"{_serviceNameOrigin} - Service exists on Consul, but with different casing: '{_serviceName}'. {healthMessage}");
- });
+ return HealthCheckResult.Healthy($"Service exists on Consul, but with different casing: '{_serviceName}'. {healthMessage}");
+ };
Result = new EndPointsResult
{
@@ -552,7 +554,7 @@ public void Dispose()
_loadEndpointsByHealthCancellationTokenSource?.Cancel();
_waitForConfigChange.TrySetCanceled();
_initializedVersion.TrySetCanceled();
- _aggregatedHealthStatus.RemoveCheck(_serviceNameOrigin);
+ _healthCheck.Dispose();
}
@@ -570,117 +572,4 @@ private class ConsulResponse
}
}
- public class ConsulQueryExecuteResponse
- {
- public string Service { get; set; }
-
- public ServiceEntry[] Nodes { get; set; }
-
- public QueryDNSOptions DNS { get; set; }
-
- public string Datacenter { get; set; }
-
- public int Failovers { get; set; }
- }
-
- public class ServiceEntry
- {
- public Node Node { get; set; }
-
- public AgentService Service { get; set; }
-
- public HealthCheck[] Checks { get; set; }
- }
-
- public class Node
- {
- [JsonProperty(PropertyName = "Node")]
- public string Name { get; set; }
-
- public string Address { get; set; }
-
- public ulong ModifyIndex { get; set; }
-
- public Dictionary TaggedAddresses { get; set; }
- }
-
- public class AgentService
- {
- public string ID { get; set; }
-
- public string Service { get; set; }
-
- public string[] Tags { get; set; }
-
- public int Port { get; set; }
-
- public string Address { get; set; }
-
- public bool EnableTagOverride { get; set; }
- }
-
- public class HealthCheck
- {
- public string Node { get; set; }
-
- public string CheckID { get; set; }
-
- public string Name { get; set; }
-
- public string Status { get; set; }
-
- public string Notes { get; set; }
-
- public string Output { get; set; }
-
- public string ServiceID { get; set; }
-
- public string ServiceName { get; set; }
- }
-
- public class QueryDNSOptions
- {
- public string TTL { get; set; }
- }
-
- public class KeyValueResponse
- {
- public int LockIndex { get; set; }
- public string Key { get; set; }
- public int Flags { get; set; }
- public string Value { get; set; }
- public ulong CreateIndex { get; set; }
- public ulong ModifyIndex { get; set; }
-
- public ServiceKeyValue TryDecodeValue()
- {
- if (Value == null)
- return null;
-
- try
- {
- var serialized = Encoding.UTF8.GetString(Convert.FromBase64String(Value));
- return JsonConvert.DeserializeObject(serialized);
- }
- catch
- {
- return null;
- }
- }
- }
-
- public class ServiceKeyValue
- {
- [JsonProperty("basePort")]
- public int BasePort { get; set; }
-
- [JsonProperty("dc")]
- public string DataCenter { get; set; }
-
- [JsonProperty("env")]
- public string Environment { get; set; }
-
- [JsonProperty("version")]
- public string Version { get; set; }
- }
}
\ No newline at end of file
diff --git a/Gigya.Microdot.ServiceDiscovery/ConsulContracts.cs b/Gigya.Microdot.ServiceDiscovery/ConsulContracts.cs
new file mode 100644
index 00000000..1470bb1c
--- /dev/null
+++ b/Gigya.Microdot.ServiceDiscovery/ConsulContracts.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Gigya.Microdot.ServiceDiscovery.Rewrite;
+using Newtonsoft.Json;
+
+namespace Gigya.Microdot.ServiceDiscovery
+{
+ public class ConsulQueryExecuteResponse
+ {
+ public ServiceEntry[] Nodes { get; set; }
+ }
+
+ public class ServiceEntry
+ {
+ public NodeEntry Node { get; set; }
+
+ public AgentService Service { get; set; }
+
+ }
+
+ public class NodeEntry
+ {
+ [JsonProperty(PropertyName = "Node")]
+ public string Name { get; set; }
+ }
+
+ public class AgentService
+ {
+ public string[] Tags { get; set; }
+
+ public int Port { get; set; }
+
+ }
+
+
+ public class KeyValueResponse
+ {
+ public string Value { get; set; }
+
+ public ServiceKeyValue TryDecodeValue()
+ {
+ if (Value == null)
+ return null;
+
+ try
+ {
+ var serialized = Encoding.UTF8.GetString(Convert.FromBase64String(Value));
+ return JsonConvert.DeserializeObject(serialized);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ }
+
+ public class ServiceKeyValue
+ {
+ [JsonProperty("basePort")]
+ public int BasePort { get; set; }
+
+ [JsonProperty("dc")]
+ public string DataCenter { get; set; }
+
+ [JsonProperty("env")]
+ public string Environment { get; set; }
+
+ [JsonProperty("version")]
+ public string Version { get; set; }
+ }
+}
diff --git a/Gigya.Microdot.ServiceDiscovery/ConsulDiscoverySource.cs b/Gigya.Microdot.ServiceDiscovery/ConsulDiscoverySource.cs
index 7b1d3c37..6ecf1117 100644
--- a/Gigya.Microdot.ServiceDiscovery/ConsulDiscoverySource.cs
+++ b/Gigya.Microdot.ServiceDiscovery/ConsulDiscoverySource.cs
@@ -61,11 +61,11 @@ public class ConsulDiscoverySource : ServiceDiscoverySourceBase
private bool _disposed;
- public ConsulDiscoverySource(ServiceDeployment serviceDeployment,
+ public ConsulDiscoverySource(DeploymentIdentifier deploymentIdentifier,
IDateTime dateTime,
Func getConfig,
Func getConsulClient, ILog log)
- : base(GetDeploymentName(serviceDeployment, getConfig().Services[serviceDeployment.ServiceName]))
+ : base(GetDeploymentName(deploymentIdentifier, getConfig().Services[deploymentIdentifier.ServiceName]))
{
DateTime = dateTime;
@@ -194,13 +194,13 @@ public override void ShutDown()
_disposed = true;
}
- public static string GetDeploymentName(ServiceDeployment serviceDeployment, ServiceDiscoveryConfig serviceDiscoverySettings)
+ public static string GetDeploymentName(DeploymentIdentifier deploymentIdentifier, ServiceDiscoveryConfig serviceDiscoverySettings)
{
if (serviceDiscoverySettings.Scope == ServiceScope.DataCenter)
{
- return serviceDeployment.ServiceName;
+ return deploymentIdentifier.ServiceName;
}
- return $"{serviceDeployment.ServiceName}-{serviceDeployment.DeploymentEnvironment}";
+ return deploymentIdentifier.ToString();
}
}
diff --git a/Gigya.Microdot.ServiceDiscovery/ServiceDeployment.cs b/Gigya.Microdot.ServiceDiscovery/DeploymentIdentifier.cs
similarity index 60%
rename from Gigya.Microdot.ServiceDiscovery/ServiceDeployment.cs
rename to Gigya.Microdot.ServiceDiscovery/DeploymentIdentifier.cs
index 4f6da804..573f1ad3 100644
--- a/Gigya.Microdot.ServiceDiscovery/ServiceDeployment.cs
+++ b/Gigya.Microdot.ServiceDiscovery/DeploymentIdentifier.cs
@@ -21,22 +21,28 @@
#endregion
namespace Gigya.Microdot.ServiceDiscovery
{
- public class ServiceDeployment
+ public class DeploymentIdentifier
{
public string DeploymentEnvironment { get; }
public string ServiceName { get; }
+ public bool IsEnvironmentSpecific => string.IsNullOrEmpty(DeploymentEnvironment)==false;
- public ServiceDeployment(string serviceName, string deploymentEnvironment)
+ public DeploymentIdentifier(string serviceName, string deploymentEnvironment)
{
- DeploymentEnvironment = deploymentEnvironment.ToLower();
+ DeploymentEnvironment = deploymentEnvironment?.ToLower();
ServiceName = serviceName;
}
+ public DeploymentIdentifier(string serviceName): this(serviceName, null)
+ { }
public override string ToString()
{
- return $"{ServiceName}-{DeploymentEnvironment}";
+ if (IsEnvironmentSpecific)
+ return $"{ServiceName}-{DeploymentEnvironment}";
+ else
+ return ServiceName;
}
@@ -48,12 +54,15 @@ public override bool Equals(object obj)
if (ReferenceEquals(this, obj))
return true;
- ServiceDeployment other = obj as ServiceDeployment;
-
- if (other == null)
+ if (obj is DeploymentIdentifier other)
+ {
+ if (IsEnvironmentSpecific && other.IsEnvironmentSpecific)
+ return DeploymentEnvironment == other.DeploymentEnvironment && ServiceName == other.ServiceName;
+ else
+ return ServiceName == other.ServiceName;
+ }
+ else
return false;
-
- return DeploymentEnvironment == other.DeploymentEnvironment && ServiceName == other.ServiceName;
}
@@ -61,7 +70,10 @@ public override int GetHashCode()
{
unchecked
{
- return ((DeploymentEnvironment?.GetHashCode() ?? 0) * 397) ^ (ServiceName?.GetHashCode() ?? 0);
+ if (IsEnvironmentSpecific)
+ return ((ServiceName?.GetHashCode() ?? 0) * 397) ^ (DeploymentEnvironment.GetHashCode());
+ else
+ return ServiceName?.GetHashCode() ?? 0;
}
}
}
diff --git a/Gigya.Microdot.ServiceDiscovery/DiscoverySourceLoader.cs b/Gigya.Microdot.ServiceDiscovery/DiscoverySourceLoader.cs
index bf46bb92..f67dd3e6 100644
--- a/Gigya.Microdot.ServiceDiscovery/DiscoverySourceLoader.cs
+++ b/Gigya.Microdot.ServiceDiscovery/DiscoverySourceLoader.cs
@@ -29,16 +29,16 @@ namespace Gigya.Microdot.ServiceDiscovery
{
public class DiscoverySourceLoader : IDiscoverySourceLoader
{
- private readonly Func _getSources;
+ private readonly Func _getSources;
- public DiscoverySourceLoader(Func getSources)
+ public DiscoverySourceLoader(Func getSources)
{
_getSources = getSources;
}
- public IServiceDiscoverySource GetDiscoverySource(ServiceDeployment serviceDeployment, ServiceDiscoveryConfig serviceDiscoveryConfig)
+ public IServiceDiscoverySource GetDiscoverySource(DeploymentIdentifier deploymentIdentifier, ServiceDiscoveryConfig serviceDiscoveryConfig)
{
- var source = _getSources(serviceDeployment).FirstOrDefault(f=>f.SourceName.Equals(serviceDiscoveryConfig.Source, StringComparison.InvariantCultureIgnoreCase));
+ var source = _getSources(deploymentIdentifier).FirstOrDefault(f=>f.SourceName.Equals(serviceDiscoveryConfig.Source, StringComparison.InvariantCultureIgnoreCase));
if (source==null)
throw new ConfigurationException($"Discovery Source '{serviceDiscoveryConfig.Source}' is not supported.");
@@ -49,6 +49,6 @@ public IServiceDiscoverySource GetDiscoverySource(ServiceDeployment serviceDeplo
public interface IDiscoverySourceLoader
{
- IServiceDiscoverySource GetDiscoverySource(ServiceDeployment serviceDeployment, ServiceDiscoveryConfig serviceDiscoveryConfig);
+ IServiceDiscoverySource GetDiscoverySource(DeploymentIdentifier deploymentIdentifier, ServiceDiscoveryConfig serviceDiscoveryConfig);
}
}
\ No newline at end of file
diff --git a/Gigya.Microdot.ServiceDiscovery/Gigya.Microdot.ServiceDiscovery.csproj b/Gigya.Microdot.ServiceDiscovery/Gigya.Microdot.ServiceDiscovery.csproj
index 08e30ce7..30a8cdb6 100644
--- a/Gigya.Microdot.ServiceDiscovery/Gigya.Microdot.ServiceDiscovery.csproj
+++ b/Gigya.Microdot.ServiceDiscovery/Gigya.Microdot.ServiceDiscovery.csproj
@@ -21,6 +21,7 @@
prompt
4
bin\Debug\Gigya.Microdot.ServiceDiscovery.xml
+ MinimumRecommendedRules.ruleset
pdbonly
@@ -56,20 +57,40 @@
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -81,6 +102,10 @@
+
+ {0E3A2422-DD99-4D75-A18C-96329A842742}
+ Gigya.Microdot.Configuration
+
{A90D7C71-EC7C-4328-9DB1-D2C3A30727DB}
Gigya.Microdot.Interfaces
@@ -90,6 +115,10 @@
Gigya.Microdot.SharedLogic
+
+
+
+