Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elasticsearch Version Resolve Capabilities #21

Merged
merged 10 commits into from
Nov 6, 2017
11 changes: 10 additions & 1 deletion integration-tests/NAME.IntegrationTests/Constants.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;

public static class Constants {
public static string ExpectedOperatingSystem;
Expand All @@ -17,6 +17,11 @@ public static class Constants {
public static string SpecificRabbitVersion;
public static string SpecificServiceVersion;

// Elasticsearch variables
public static string LatestElasticHostname;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the full name of Elasticsearch, should be LatestElasticsearchHostname

public static string SpecificElasticHostname;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

public static string SpecificElasticVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above


static Constants() {
ExpectedOperatingSystem = Environment.GetEnvironmentVariable("OPERATING_SYSTEM") ?? "windows";

Expand All @@ -31,5 +36,9 @@ public static class Constants {
SpecificMongoVersion = Environment.GetEnvironmentVariable("SPECIFIC_MONGO_VERSION") ?? "3.0.0";
SpecificRabbitVersion = Environment.GetEnvironmentVariable("SPECIFIC_RABBIT_VERSION") ?? "3.6.5";
SpecificServiceVersion = Environment.GetEnvironmentVariable("SPECIFIC_SERVICE_VERSION") ?? "1.0.0";

LatestElasticHostname = Environment.GetEnvironmentVariable("LATEST_ELASTIC_HOSTNAME") ?? "localhost";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Environment Variables should also contain the full name of Elasticsearch, should be LATEST_ELASTICSEARCH_HOSTNAME

SpecificElasticHostname = Environment.GetEnvironmentVariable("SPECIFIC_ELASTIC_HOSTNAME") ?? "localhost";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

SpecificElasticVersion = Environment.GetEnvironmentVariable("SPECIFIC_ELASTIC_VERSION") ?? "5.5.1";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using NAME.ConnectionStrings;
using NAME.Core;
using NAME.Elasticsearch;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

namespace NAME.IntegrationTests.Elasticsearch
{
public class ElasticsearchVersionResolverTests
{
[Fact]
[Trait("TestCategory", "Integration")]
public async Task GetVersions_SpecificVersion()
{
ElasticsearchVersionResolver resolver = new ElasticsearchVersionResolver(new StaticConnectionStringProvider($"http://{ Constants.SpecificMongoHostname }:9200"), 10000, 10000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo, should be SpecificElasticsearchHostname instead of SpecificMongoHostname


var versions = await resolver.GetVersions().ConfigureAwait(false);

Assert.Equal(1, versions.Count());
Assert.Equal(versions.First(), DependencyVersion.Parse(Constants.SpecificElasticVersion));
}

[Fact]
[Trait("TestCategory", "Integration")]
public async Task GetVersions_LatestVersion()
{
ElasticsearchVersionResolver resolver = new ElasticsearchVersionResolver(new StaticConnectionStringProvider($"http://{ Constants.LatestMongoHostname }:9200"), 10000, 10000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


var versions = await resolver.GetVersions().ConfigureAwait(false);

Assert.Equal(1, versions.Count());
// Latest GA RELEASE: https://www.elastic.co/downloads/elasticsearch#ga-release
Assert.Equal(versions.First(), DependencyVersion.Parse("5.6.3"));
}
}
}
22 changes: 21 additions & 1 deletion integration-tests/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ services:
- specific-mongo
- specific-rabbitmq
- dummy-service
- elastic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, use the full name of elasticsearch, to keep things consistent.
The same for the rest of the file.

- specific-elastic
environment:
- LATEST_MONGO_HOSTNAME=mongo
- LATEST_RABBIT_HOSTNAME=rabbitmq
Expand All @@ -21,6 +23,9 @@ services:
- SPECIFIC_SERVICE_VERSION=1.0.0
- OPERATING_SYSTEM=debian
- RUNNING_ON_DOCKER=true
- LATEST_ELASTIC_HOSTNAME=elastic
- SPECIFIC_ELASTIC_HOSTNAME=specific-elastic
- SPECIFIC_ELASTIC_VERSION=5.5.1
volumes:
- ../Output/Artifacts/NuGets/Release:/integration/nugets
- ../Output/IntegrationTestsResults:/integration/TestResults
Expand All @@ -31,6 +36,8 @@ services:
- specific-mongo
- specific-rabbitmq
- dummy-service
- elastic
- specific-elastic
dummy-service:
build: ./NAME.DummyService
environment:
Expand Down Expand Up @@ -61,4 +68,17 @@ services:
- "1433"
environment:
- SA_PASSWORD=W1#llnotbeused
- ACCEPT_EULA=Y
- ACCEPT_EULA=Y
elastic:
image: docker.elastic.co/elasticsearch/elasticsearch:5.6.3
expose:
- "9200"
environment:
- xpack.security.enabled=false
specific-elastic:
image: docker.elastic.co/elasticsearch/elasticsearch:5.5.1
expose:
- "9200"
environment:
- xpack.security.enabled=false

28 changes: 26 additions & 2 deletions src/NAME.Core/ConnectedVersionResolver.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using NAME.Core.Exceptions;
using NAME.Core.Exceptions;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

Expand Down Expand Up @@ -80,5 +82,27 @@ protected async Task<TcpClient> OpenTcpClient(string host, int port, string depe
throw new DependencyNotReachableException(dependencyName, ex);
}
}

/// <summary>
/// Gets a HttpWebRequest
/// </summary>
/// <param name="requestUriString">Request Uri String</param>
/// <param name="dependencyName">Dependency Name</param>
/// <returns>Returns a HttpWebRequest</returns>
protected HttpWebRequest GetHttpWebRequest(string requestUriString, string dependencyName)
{
HttpWebRequest request = null;
try
{
request = WebRequest.CreateHttp(requestUriString);
request.ContinueTimeout = this.ConnectTimeout;
request.ContentType = "application/json; charset=utf-8";
return request;
}
catch (Exception e)
{
throw new DependencyNotReachableException(dependencyName, e);
}
}
}
}
}
22 changes: 11 additions & 11 deletions src/NAME.Core/SupportedDependencies.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NAME.Core
{
/// <summary>
Expand All @@ -14,25 +9,30 @@ public enum SupportedDependencies
/// MongoDb
/// </summary>
MongoDb = 10,

/// <summary>
/// Operating System
/// </summary>
OperatingSystem = 20,

/// <summary>
/// RabbitMq
/// </summary>
RabbitMq = 30,

/// <summary>
/// SQL Server
/// </summary>
SqlServer = 40,

/// <summary>
/// A service with NAME
/// </summary>
Service = 50
Service = 50,

/// <summary>
/// Elasticsearch
/// </summary>
Elasticsearch = 60
}
}
}
4 changes: 3 additions & 1 deletion src/NAME/DependenciesReader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using NAME.Core.Exceptions;
using NAME.Core.Exceptions;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -265,6 +265,8 @@ private static IVersionResolver GetConnectedDependencyVersionResolver(SupportedD
return new SqlServer.SqlServerVersionResolver(connectionStringProvider, configuration.DependencyConnectTimeout, configuration.DependencyReadWriteTimeout);
case SupportedDependencies.Service:
return new Service.ServiceVersionResolver(connectionStringProvider, context.ServiceDependencyCurrentNumberOfHops, configuration.ServiceDependencyMaxHops, configuration.DependencyConnectTimeout, configuration.DependencyReadWriteTimeout);
case SupportedDependencies.Elasticsearch:
return new Elasticsearch.ElasticsearchVersionResolver(connectionStringProvider, configuration.DependencyConnectTimeout, configuration.DependencyReadWriteTimeout);
default:
throw new NAMEException($"The dependency of type {dependencyType} is not supported as a connected dependency.");
}
Expand Down
65 changes: 65 additions & 0 deletions src/NAME/Elasticsearch/ElasticsearchVersionResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using NAME.Core;
using NAME.Core.Exceptions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;

namespace NAME.Elasticsearch
{
internal class ElasticsearchVersionResolver : ConnectedVersionResolver
{
private IConnectionStringProvider connectionStringProvider;

public ElasticsearchVersionResolver(IConnectionStringProvider connectionStringProvider, int connectTimeout, int readWriteTimeout)
: base(connectTimeout, readWriteTimeout)
{
this.connectionStringProvider = connectionStringProvider;
}

public override async Task<IEnumerable<DependencyVersion>> GetVersions()
{
var versions = new List<DependencyVersion>();
var connectionString = string.Empty;

if (!this.connectionStringProvider.TryGetConnectionString(out connectionString))
{
throw new ConnectionStringNotFoundException(this.connectionStringProvider.ToString());
}

HttpWebResponse response;
try
{
var request = this.GetHttpWebRequest(connectionString, SupportedDependencies.Elasticsearch.ToString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although you set the ContinueTimeout in the GetHttpWebRequest, it is not enough, because the Elasticsearch HTTP server may accept the connection and not send the response, so we need a read write timeout here, take a look at the ServiceVersionResolver for clues on how to do that.

response = await request.GetResponseAsync() as HttpWebResponse;
}
catch (Exception e)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should catch the most relevant exception instead of the base Exception, in this case it is System.Net.WebException.

{
throw new DependencyNotReachableException($"{SupportedDependencies.Elasticsearch}: {e.Message}");
}
using (var reader = new StreamReader(response.GetResponseStream()))
{
var body = await reader.ReadToEndAsync();
var version = string.Empty;
try
{
version = this.DeserializeJsonResponse(body);
versions.Add(DependencyVersion.Parse(version));
}
catch (Exception e)
{
throw new VersionParsingException(version, e.Message);
}
}

return versions;
}

private string DeserializeJsonResponse(string result)
{
var jsonResult = Json.Json.Parse(result);
return jsonResult["version"]["number"];
}
}
}
9 changes: 3 additions & 6 deletions src/NAME/MongoDb/MongoDBVersionResolver.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
using NAME.Core.Exceptions;
using NAME.Core;
using NAME.Core.Exceptions;
using NAME.MongoDb.Bson;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NAME.Core.Utils;
using NAME.Core;

namespace NAME.MongoDb
{
Expand Down Expand Up @@ -148,4 +145,4 @@ private byte[] CreateServerStatusMessagePayload(MongoConnectionStringBuilder con
return message;
}
}
}
}
9 changes: 9 additions & 0 deletions src/NAME/Nuget/Content/dependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
// "locator": "ConnectionStrings",
// "key": "EventaConnectionString"
// }
//},
//{
// "type": "Elasticsearch",
// "min_version": "5.5.1",
// "max_version": "5.6.3",
// "connection_string": {
// "locator": "ConnectionStrings",
// "key": "ElasticConnectionString"
// }
//}
],
"service_dependencies": [
Expand Down
18 changes: 6 additions & 12 deletions src/NAME/Service/ServiceVersionResolver.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using NAME.Core;
using NAME.Core;
using NAME.Core.Exceptions;
using NAME.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace NAME.Service
Expand All @@ -18,7 +16,7 @@ namespace NAME.Service
public class ServiceVersionResolver : ConnectedVersionResolver
{
private readonly IConnectionStringProvider _connectionStringProvider;
private readonly Func<string, HttpWebRequest> _webRequestFactory;

private const string InfrastructureDependenciesKey = "infrastructure_dependencies";
private const string ServiceDependenciesKey = "service_dependencies";

Expand Down Expand Up @@ -46,15 +44,12 @@ public class ServiceVersionResolver : ConnectedVersionResolver
/// <param name="maxHopCount">The maximum hop count.</param>
/// <param name="connectTimeout">The connect timeout.</param>
/// <param name="readWriteTimeout">The read write timeout.</param>
/// <param name="webRequestFactory">The web request factory.</param>
public ServiceVersionResolver(IConnectionStringProvider connectionStringProvider, int currentHopNumber, int maxHopCount, int connectTimeout, int readWriteTimeout, Func<string, HttpWebRequest> webRequestFactory = null)
public ServiceVersionResolver(IConnectionStringProvider connectionStringProvider, int currentHopNumber, int maxHopCount, int connectTimeout, int readWriteTimeout)
: base(connectTimeout, readWriteTimeout)
{
this._connectionStringProvider = connectionStringProvider;
this.HopNumber = currentHopNumber;
this.MaxHopCount = maxHopCount;

this._webRequestFactory = webRequestFactory ?? WebRequest.CreateHttp;
}

/// <summary>
Expand Down Expand Up @@ -150,12 +145,11 @@ public async Task GetDependantManifests(DependencyVersion rootDependency)

private async Task<string> GetManifest(Uri endpointUri, bool retry, int hop)
{
HttpWebRequest request = this._webRequestFactory.Invoke(endpointUri.AbsoluteUri);
request.ContentType = "application/json; charset=utf-8";
HttpWebRequest request = this.GetHttpWebRequest(endpointUri.AbsoluteUri, SupportedDependencies.Service.ToString());
request.Headers[Constants.HOP_COUNT_HEADER_NAME] = hop.ToString();

// This timeout defines the time it should take to connect to the instance.
request.ContinueTimeout = this.ConnectTimeout;

try
{
var getResponseTask = request.GetResponseAsync();
Expand Down Expand Up @@ -225,4 +219,4 @@ private async Task<string> GetManifest(Uri endpointUri, bool retry, int hop)
}
}
}
}
}
Loading