Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
97 changes: 97 additions & 0 deletions Consul.Test/CatalogTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,5 +317,102 @@ public async Task Catalog_ServicesForNodes()
Assert.Contains(services.Response.Services, n => n.ID == svcID);
Assert.DoesNotContain(services.Response.Services, n => n.ID == svcID2);
}

[Fact]
Copy link
Contributor

Choose a reason for hiding this comment

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

That test fails for consul 1.6 and 1.7, you can skip running it for these consul versions: see

[SkippableFact]
public async Task Agent_MonitorJSON()
{
var cutOffVersion = SemanticVersion.Parse("1.7.0");
Skip.If(AgentVersion < cutOffVersion, $"Current version is {AgentVersion}, but `logjson` is only supported from Consul {cutOffVersion}");
for an example how to do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okey, let me fix that!

public async Task Catalog_GatewayServices()
{
using (IConsulClient client = new ConsulClient(c =>
{
c.Token = TestHelper.MasterToken;
c.Address = TestHelper.HttpUri;
}))
{
var terminatingGatewayName = "terminating-gateway";
Copy link
Contributor

Choose a reason for hiding this comment

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

I would use a non-standard name, e.g.:

Suggested change
var terminatingGatewayName = "terminating-gateway";
var terminatingGatewayName = "my-terminating-gateway";

var ingressGatewayName = "ingress-gateway";
Copy link
Contributor

Choose a reason for hiding this comment

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

I would use a non-standard name, e.g.:

Suggested change
var ingressGatewayName = "ingress-gateway";
var ingressGatewayName = "my-ingress-gateway";


var terminatingGatewayEntry = new CatalogRegistration
{
Datacenter = "dc1",
Node = "bar",
Address = "192.168.10.11",
Service = new AgentService
{
ID = "redis",
Service = "redis",
Port = 6379
}
};
await client.Catalog.Register(terminatingGatewayEntry);

var terminatingGatewayConfigEntry = new TerminatingGatewayConfigEntry
{
Kind = ServiceKind.TerminatingGateway.ToString(),
Name = terminatingGatewayName,
Services = new List<LinkedServiceGateway>
{
new LinkedServiceGateway
{
Name = "api",
CAFile = "api/ca.crt",
CertFile = "api/client.crt",
KeyFile = "api/client.key",
SNI = "my-domain"
},
new LinkedServiceGateway
{
Name = "*",
CAFile = "ca.crt",
CertFile = "client.crt",
KeyFile = "client.key",
SNI = "my-alt-domain"
}
}
};
await client.Configuration.ApplyConfig(terminatingGatewayConfigEntry);

var ingressGatewayConfigEntry = new IngressGatewayConfigEntry
{
Kind = ServiceKind.IngressGateway.ToString(),
Name = ingressGatewayName,
Listeners = new List<IngressListener>
{
new IngressListener
{
Port = 8888,
Services = new List<IngressService>
{
new IngressService
{
Name = "api"
}
}
},
new IngressListener
{
Port = 9999,
Services = new List<IngressService>
{
new IngressService
{
Name = "redis"
}
}
}
}
};

await client.Configuration.ApplyConfig(ingressGatewayConfigEntry);

var gatewayServices = await client.Catalog.GatewayService(terminatingGatewayName);

Assert.NotEmpty(gatewayServices.Response);
Assert.Equal(ServiceKind.TerminatingGateway, gatewayServices.Response[0].GatewayKind);
Copy link
Contributor

Choose a reason for hiding this comment

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

It would also be good to check if other fields in the response are non-null, hence we know that the struct is correctly defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, that's a good idea, let me do that real quick

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would also be good to check if other fields in the response are non-null, hence we know that the struct is correctly defined.

Just added the checks, you can see that we can't check all fields, cause some fields are just not present in the response for both gateways, and some just for ingress one

Copy link
Contributor

Choose a reason for hiding this comment

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

We can add checks for port and protocol for the ingress one. Apart from that, it looks good.

Copy link
Contributor Author

@IvanKolchanov IvanKolchanov Jul 17, 2024

Choose a reason for hiding this comment

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

@marcin-krystianc
Sorry, just saw your message, added the assertions, tests went good

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

Thanks for help with the PRs!


gatewayServices = await client.Catalog.GatewayService(ingressGatewayName);

Assert.NotEmpty(gatewayServices.Response);
Assert.Equal(ServiceKind.IngressGateway, gatewayServices.Response[0].GatewayKind);
}
}
}
}
80 changes: 80 additions & 0 deletions Consul/Catalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,62 @@ public class ServiceAddress
public int Port { get; set; }
}

public class CompoundServiceName
{
public string Namespace { get; set; }
public string Partition { get; set; }
public string Name { get; set; }
}

public class GatewayService
{
public CompoundServiceName Gateway { get; set; }
public CompoundServiceName Service { get; set; }
public ServiceKind GatewayKind { get; set; }
public int Port { get; set; }
public string Protocol { get; set; }
public List<string> Hosts { get; set; }
public string CAFile { get; set; }
public string CertFile { get; set; }
public string KeyFile { get; set; }
public string SNI { get; set; }
public bool FromWildcard { get; set; }
}

public class TerminatingGatewayConfigEntry : IConfigurationEntry
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have a TerminalGatewayEntry in the Configuration.cs file so there is no need to re-define it.
I think the TerminalGatewayEntry and associated LinkedService are incorrectly defined, but feel free to fix them.
It will break backward compatibility, but those structs are likely not used by anyone since they are not correctly defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I am surprised how I missed it. Some of the classes were a bit incorrect. TerminatingGatewayEntry had a wrong name, LinkedService has wrong class structure, TerminatingGatewayEntry had excess fields. IngressGatewayEntry wasn't implementing IConfigEntry. Also I could rename them to TerminatingGatewayConfigEntry and IngressGatewayConfigEntry as in Golang client code, but that isn't critical.

{
public string Kind { get; set; }
public string Name { get; set; }
public List<LinkedServiceGateway> Services { get; set; }
}

public class LinkedServiceGateway
{
public string Name { get; set; }
public string CAFile { get; set; }
public string CertFile { get; set; }
public string KeyFile { get; set; }
public string SNI { get; set; }
}

public class IngressGatewayConfigEntry : IConfigurationEntry
{
public string Kind { get; set; }
public string Name { get; set; }
public List<IngressListener> Listeners { get; set; }
}

public class IngressListener
{
public int Port { get; set; }
public List<IngressService> Services { get; set; }
}

public class IngressService
{
public string Name { get; set; }
}

/// <summary>
/// Catalog can be used to query the Catalog endpoints
/// </summary>
Expand Down Expand Up @@ -352,6 +408,30 @@ public Task<QueryResult<NodeService>> ServicesForNode(string node, QueryOptions
{
return _client.Get<NodeService>(string.Format("/v1/catalog/node-services/{0}", node), q).Execute(ct);
}


/// <summary>
/// GatewayServices is used to query for the services associated with an ingress gateway or terminating gateway
/// </summary>
/// <param name="gateway">Gateway name</param>
/// <param name="q">Query Parameters</param>
/// <param name="ct">Cancellation Token</param>
/// <returns>Gateway services</returns>
public Task<QueryResult<GatewayService[]>> GatewayService(string gateway, QueryOptions q, CancellationToken ct = default)
{
return _client.Get<GatewayService[]>($"/v1/catalog/gateway-services/{gateway}", q).Execute(ct);
}

/// <summary>
/// GatewayServices is used to query for the services associated with an ingress gateway or terminating gateway
/// </summary>
/// <param name="gateway">Gateway name</param>
/// <param name="ct">Cancellation Token</param>
/// <returns>Gateway services</returns>
public Task<QueryResult<GatewayService[]>> GatewayService(string gateway, CancellationToken ct = default)
{
return GatewayService(gateway, QueryOptions.Default, ct);
}
}

public partial class ConsulClient : IConsulClient
Expand Down
2 changes: 2 additions & 0 deletions Consul/Interfaces/ICatalogEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@ public interface ICatalogEndpoint
Task<QueryResult<CatalogService[]>> NodesForMeshCapableService(string service, CancellationToken ct = default);
Task<QueryResult<NodeService>> ServicesForNode(string node, QueryOptions q, CancellationToken ct = default);
Task<QueryResult<NodeService>> ServicesForNode(string node, CancellationToken ct = default);
Task<QueryResult<GatewayService[]>> GatewayService(string gateway, QueryOptions q, CancellationToken ct = default);
Task<QueryResult<GatewayService[]>> GatewayService(string gateway, CancellationToken ct = default);
}
}