Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Discovery/src/Consul/Discovery/ConsulDiscoveryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public class ConsulDiscoveryOptions
/// </summary>
public IList<string> Tags { get; set; }

/// <summary>
/// Gets or sets Metadata to use when registering service.
/// </summary>
public IDictionary<string, string> Metadata { get; set; }

public bool UseNetUtils { get; set; }

public InetUtils NetUtils { get; set; }
Expand Down
18 changes: 15 additions & 3 deletions src/Discovery/src/Consul/Discovery/ConsulServiceInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class ConsulServiceInstance : IServiceInstance
/// <inheritdoc />
public Uri Uri { get; }

public string[] Tags { get; }

/// <inheritdoc />
public IDictionary<string, string> Metadata { get; }

Expand All @@ -40,12 +42,22 @@ public class ConsulServiceInstance : IServiceInstance
public ConsulServiceInstance(ServiceEntry serviceEntry)
{
Host = ConsulServerUtils.FindHost(serviceEntry);
IDictionary<string, string> metadata = ConsulServerUtils.GetMetadata(serviceEntry);
IsSecure = metadata.TryGetValue("secure", out string secureString) && bool.Parse(secureString);
Tags = serviceEntry.Service.Tags;
Metadata = serviceEntry.Service.Meta;
IsSecure = GetIsSecure(serviceEntry);
ServiceId = serviceEntry.Service.Service;
Port = serviceEntry.Service.Port;
Metadata = metadata;
string scheme = IsSecure ? "https" : "http";
Uri = new Uri($"{scheme}://{Host}:{Port}");
}

private static bool GetIsSecure(ServiceEntry serviceEntry)
{
if (serviceEntry.Service.Meta == null)
{
return false;
}

return serviceEntry.Service.Meta.TryGetValue("secure", out string secureString) && bool.Parse(secureString);
}
}
37 changes: 27 additions & 10 deletions src/Discovery/src/Consul/Registry/ConsulRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ internal ConsulDiscoveryOptions Options
/// <inheritdoc />
public Uri Uri => new($"{Options.Scheme}://{Host}:{Port}");

public string[] Tags { get; private set; }

/// <inheritdoc />
public IDictionary<string, string> Metadata { get; private set; }

Expand Down Expand Up @@ -109,7 +111,8 @@ internal void Initialize(AgentServiceRegistration agentServiceRegistration)
ServiceId = agentServiceRegistration.Name;
Host = agentServiceRegistration.Address;
Port = agentServiceRegistration.Port;
Metadata = ConsulServerUtils.GetMetadata(agentServiceRegistration.Tags);
Tags = agentServiceRegistration.Tags;
Metadata = agentServiceRegistration.Meta;
}

/// <summary>
Expand Down Expand Up @@ -141,6 +144,7 @@ public static ConsulRegistration CreateRegistration(ConsulDiscoveryOptions optio

service.Name = NormalizeForConsul(appName);
service.Tags = CreateTags(options);
service.Meta = CreateMetadata(options);

if (options.Port != 0)
{
Expand All @@ -151,31 +155,44 @@ public static ConsulRegistration CreateRegistration(ConsulDiscoveryOptions optio
return new ConsulRegistration(service, options);
}

internal static string[] CreateTags(ConsulDiscoveryOptions options)
internal static IDictionary<string, string> CreateMetadata(ConsulDiscoveryOptions options)
{
var tags = new List<string>();
var metadata = new Dictionary<string, string>();

if (options.Tags != null)
if (options.Metadata != null && options.Metadata.Any())
{
tags.AddRange(options.Tags);
foreach (KeyValuePair<string, string> m in options.Metadata)
{
metadata.Add(m.Key, m.Value);
}
}

if (!string.IsNullOrEmpty(options.InstanceZone))
{
tags.Add($"{options.DefaultZoneMetadataName}={options.InstanceZone}");
metadata.Add(options.DefaultZoneMetadataName, options.InstanceZone);
}

if (!string.IsNullOrEmpty(options.InstanceGroup))
{
tags.Add($"group={options.InstanceGroup}");
metadata.Add("group", options.InstanceGroup);
}

// store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically
// store the secure flag in the metadata so that clients will be able to figure out whether to use http or https automatically
#pragma warning disable S4040 // Strings should be normalized to uppercase
tags.Add($"secure={(options.Scheme == "https").ToString(CultureInfo.InvariantCulture).ToLowerInvariant()}");
metadata.Add("secure", (options.Scheme == "https").ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
#pragma warning restore S4040 // Strings should be normalized to uppercase

return tags.ToArray();
return metadata;
}

internal static string[] CreateTags(ConsulDiscoveryOptions options)
{
if (options.Tags == null || !options.Tags.Any())
{
return Array.Empty<string>();
}

return options.Tags.ToArray();
}

internal static string GetInstanceId(ConsulDiscoveryOptions options, IApplicationInstanceInfo applicationInfo)
Expand Down
34 changes: 0 additions & 34 deletions src/Discovery/src/Consul/Util/ConsulServerUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,38 +48,4 @@ public static string FixIPv6Address(string address)

return address;
}

public static IDictionary<string, string> GetMetadata(ServiceEntry healthService)
{
return GetMetadata(healthService.Service.Tags);
}

public static IDictionary<string, string> GetMetadata(IList<string> tags)
{
var metadata = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

if (tags != null)
{
foreach (string tag in tags)
{
int index = tag.IndexOf('=');
string key;
string value;

if (index == -1 || Equals(index + 1, tag.Length))
{
key = value = tag;
}
else
{
key = tag.Substring(0, index);
value = tag.Substring(index + 1);
}

metadata[key] = value;
}
}

return metadata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ public async Task AddInstancesToListAsync_AddsExpected()
Service = "ServiceId",
Address = "foo.bar.com",
Port = 1234,
Tags = new[]
Meta = new Dictionary<string, string>
{
"foo=bar",
"secure=true"
["foo"] = "bar",
["secure"] = "true"
}
}
},
Expand All @@ -50,10 +50,10 @@ public async Task AddInstancesToListAsync_AddsExpected()
Service = "ServiceId",
Address = "foo1.bar1.com",
Port = 5678,
Tags = new[]
Meta = new Dictionary<string, string>
{
"bar=foo",
"secure=false"
["bar"] = "foo",
["secure"] = "false"
}
}
}
Expand Down Expand Up @@ -206,10 +206,10 @@ public void GetAllInstances_ReturnsExpected()
Service = "ServiceId",
Address = "foo.bar.com",
Port = 1234,
Tags = new[]
Meta = new Dictionary<string, string>
{
"foo=bar",
"secure=true"
["foo"] = "bar",
["secure"] = "true"
}
}
},
Expand All @@ -220,10 +220,10 @@ public void GetAllInstances_ReturnsExpected()
Service = "ServiceId",
Address = "foo1.bar1.com",
Port = 5678,
Tags = new[]
Meta = new Dictionary<string, string>
{
"bar=foo",
"secure=false"
["bar"] = "foo",
["secure"] = "false"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ public void Constructor_Initializes()
Port = 1234,
Tags = new[]
{
"foo=bar",
"secure=true"
"tag1",
"tag2"
},
Meta = new Dictionary<string, string>
{
["foo"] = "bar",
["secure"] = "true"
}
}
};
Expand All @@ -33,11 +38,14 @@ public void Constructor_Initializes()
Assert.Equal("ServiceId", si.ServiceId);
Assert.True(si.IsSecure);
Assert.Equal(1234, si.Port);
Assert.Equal(2, si.Tags.Length);
Assert.Contains("tag1", si.Tags);
Assert.Contains("tag2", si.Tags);
Assert.Equal(2, si.Metadata.Count);
Assert.Contains("foo", si.Metadata.Keys);
Assert.Contains("secure", si.Metadata.Keys);
Assert.Contains("bar", si.Metadata.Values);
Assert.Contains("true", si.Metadata.Values);
Assert.Contains(si.Metadata, x => x.Key == "foo");
Assert.Equal("bar", si.Metadata["foo"]);
Assert.Contains(si.Metadata, x => x.Key == "secure");
Assert.Equal("true", si.Metadata["secure"]);
Assert.Equal(new Uri("https://foo.bar.com:1234"), si.Uri);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public void Constructor_Initializes()
Name = "foobar",
Address = "test.foo.bar",
Port = 1234,
Tags = new[]
Meta = new Dictionary<string, string>
{
"foo=bar"
["foo"] = "bar"
}
};

Expand Down
80 changes: 47 additions & 33 deletions src/Discovery/test/Consul.Test/Registry/ConsulRegistrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ public void Constructor_SetsProperties()
Port = 1234,
Tags = new[]
{
"foo=bar"
"tag1",
"tag2"
},
Meta = new Dictionary<string, string>
{
["foo"] = "bar"
}
};

Expand All @@ -47,6 +52,8 @@ public void Constructor_SetsProperties()
Assert.Equal("name", reg.ServiceId);
Assert.Equal("address", reg.Host);
Assert.Equal(1234, reg.Port);
Assert.Contains("tag1", reg.Tags);
Assert.Contains("tag2", reg.Tags);
Assert.Single(reg.Metadata);
Assert.Contains("foo", reg.Metadata.Keys);
Assert.Contains("bar", reg.Metadata.Values);
Expand All @@ -61,19 +68,52 @@ public void CreateTags_ReturnsExpected()
{
Tags = new List<string>
{
"foo=bar"
"foo",
"bar"
},
InstanceZone = "instancezone",
InstanceGroup = "instancegroup",
Scheme = "https"
};

string[] result = ConsulRegistration.CreateTags(options);
Assert.Equal(4, result.Length);
Assert.Contains("foo=bar", result);
Assert.Contains("zone=instancezone", result);
Assert.Contains("group=instancegroup", result);
Assert.Contains("secure=true", result);
Assert.Equal(2, result.Length);
Assert.Contains("foo", result);
Assert.Contains("bar", result);
}

[Fact]
public void CreateMetadata_ReturnsExpected()
{
var options = new ConsulDiscoveryOptions
{
Metadata = new Dictionary<string, string>
{
["foo"] = "bar",
["baz"] = "qux"
},
InstanceZone = "instancezone",
InstanceGroup = "instancegroup",
Scheme = "https"
};

IDictionary<string, string> result = ConsulRegistration.CreateMetadata(options);
Assert.Equal(5, result.Keys.Count);

Assert.Contains(result, x => x.Key == "foo");
Assert.Equal("bar", result["foo"]);

Assert.Contains(result, x => x.Key == "baz");
Assert.Equal("qux", result["baz"]);

Assert.Contains(result, x => x.Key == "zone");
Assert.Equal("instancezone", result["zone"]);

Assert.Contains(result, x => x.Key == "group");
Assert.Equal("instancegroup", result["group"]);

Assert.Contains(result, x => x.Key == "secure");
Assert.Equal("true", result["secure"]);
}

[Fact]
Expand Down Expand Up @@ -117,32 +157,6 @@ public void AppName_SetAsExpected()
Assert.Equal("ConsulDiscoveryServiceName", result.Service.Name);
}

[Fact]
public void Tags_MapTo_Metadata()
{
// arrange some tags in configuration
IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string>
{
{ "consul:discovery:tags:0", "key0=value0" },
{ "consul:discovery:tags:1", "key1=value1" },
{ "consul:discovery:tags:2", "keyvalue" }
}).Build();

// bind to options
var options = new ConsulDiscoveryOptions();
configurationRoot.Bind(ConsulDiscoveryOptions.ConsulDiscoveryConfigurationPrefix, options);
string[] tags = ConsulRegistration.CreateTags(options);

// act - get metadata from tags
IDictionary<string, string> result = ConsulServerUtils.GetMetadata(tags);
Assert.Contains(result, k => k.Key == "key0");
Assert.Equal("value0", result["key0"]);
Assert.Contains(result, k => k.Key == "key1");
Assert.Equal("value1", result["key1"]);
Assert.Contains(result, k => k.Key == "keyvalue");
Assert.Equal("keyvalue", result["keyvalue"]);
}

[Fact]
public void GetDefaultInstanceId_ReturnsExpected()
{
Expand Down