From 0d6cb04b38e0d27a0828fd6bcf60d21f57c197fd Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Tue, 11 Jun 2024 05:11:40 -0500 Subject: [PATCH 01/33] Added connect/ca/roots endpoint, added the endpoint to IAgentEndpoint.cs, added possible test, changed test_config for the test --- Consul.Test/AgentTest.cs | 9 +++++++++ Consul.Test/test_config.json | 5 ++++- Consul/Agent.cs | 30 +++++++++++++++++++++++++++++ Consul/Interfaces/IAgentEndpoint.cs | 1 + 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 2409a26f5..45d677658 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1025,6 +1025,15 @@ public async Task Agent_Metrics() Assert.NotNull(agentMetrics.Response.Samples); } + [Fact] + public async Task Agent_CARoots() + { + var caRoots = await _client.Agent.GetCARoots(); + Assert.NotEqual((ulong)0, caRoots.LastIndex); + Assert.Single(caRoots.Response.Roots); + Assert.Equal("11111111-2222-3333-4444-555555555555.consul", caRoots.Response.TrustDomain); + } + [SkippableFact] public async Task Agent_Reload() { diff --git a/Consul.Test/test_config.json b/Consul.Test/test_config.json index 74cc6c0ef..01a01faba 100644 --- a/Consul.Test/test_config.json +++ b/Consul.Test/test_config.json @@ -12,7 +12,10 @@ }, "enable_script_checks": true, "connect": { - "enabled": true + "enabled": true, + "ca_config": { + "cluster_id": "11111111-2222-3333-4444-555555555555" + } }, "encrypt": "d8wu8CSUrqgtjVsvcBPmhQ==", "enable_central_service_config": true diff --git a/Consul/Agent.cs b/Consul/Agent.cs index 610ac2fad..7d57fd7df 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -676,6 +676,31 @@ public class Sample public Dictionary Labels { get; set; } } + public class CARoots + { + public string ActiveRootID { get; set; } + public string TrustDomain { get; set; } + public List Roots { get; set; } + } + + public class Root + { + public string ID { get; set; } + public string Name { get; set; } + public long SerialNumber { get; set; } + public string SigningKeyID { get; set; } + public string ExternalTrustDomain { get; set; } + public string NotBefore { get; set; } + public string NotAfter { get; set; } + public string RootCert { get; set; } + public List IntermediateCerts { get; set; } + public bool Active { get; set; } + public string PrivateKeyType { get; set; } + public long PrivateKeyBits { get; set; } + public long CreateIndex { get; set; } + public long ModifyIndex { get; set; } + } + /// /// Agent can be used to query the Agent endpoints /// @@ -1139,6 +1164,11 @@ public async Task> GetServiceConfiguration(str return await _client.Get($"/v1/agent/service/{serviceId}", q).Execute(ct).ConfigureAwait(false); } + public async Task> GetCARoots(CancellationToken ct = default) + { + return await _client.Get("v1/agent/connect/ca/roots", QueryOptions.Default).Execute(ct).ConfigureAwait(false); + } + /// /// Log streamer /// diff --git a/Consul/Interfaces/IAgentEndpoint.cs b/Consul/Interfaces/IAgentEndpoint.cs index 38da97bbf..bfbeba630 100644 --- a/Consul/Interfaces/IAgentEndpoint.cs +++ b/Consul/Interfaces/IAgentEndpoint.cs @@ -63,6 +63,7 @@ public interface IAgentEndpoint Task> GetLocalServiceHealthByID(string serviceID, QueryOptions q, CancellationToken ct = default); Task> GetLocalServiceHealthByID(string serviceID, CancellationToken ct = default); Task> GetAgentMetrics(CancellationToken ct = default); + Task> GetCARoots(CancellationToken ct = default); Task> GetAgentVersion(CancellationToken ct = default); Task Reload(CancellationToken ct = default); [Obsolete] From f483dd41b9de440a1568081a361ffad2f17a4f38 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 12 Jun 2024 04:08:22 -0500 Subject: [PATCH 02/33] Added more test assertions to check all the values of the new added CARoots and Root classes --- Consul.Test/AgentTest.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 45d677658..6e8907a45 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1030,8 +1030,24 @@ public async Task Agent_CARoots() { var caRoots = await _client.Agent.GetCARoots(); Assert.NotEqual((ulong)0, caRoots.LastIndex); - Assert.Single(caRoots.Response.Roots); + Assert.NotNull(caRoots.Response.ActiveRootID); Assert.Equal("11111111-2222-3333-4444-555555555555.consul", caRoots.Response.TrustDomain); + Assert.Single(caRoots.Response.Roots); + var root = caRoots.Response.Roots.First(); + Assert.NotNull(root.ID); + Assert.NotNull(root.Name); + Assert.NotEqual(0, root.SerialNumber); + Assert.NotNull(root.SigningKeyID); + Assert.NotNull(root.ExternalTrustDomain); + Assert.NotNull(root.NotBefore); + Assert.NotNull(root.NotAfter); + Assert.NotNull(root.RootCert); + Assert.Null(root.IntermediateCerts); + Assert.True(root.Active); + Assert.NotNull(root.PrivateKeyType); + Assert.NotEqual(0, root.PrivateKeyBits); + Assert.NotEqual(0, root.CreateIndex); + Assert.NotEqual(0, root.ModifyIndex); } [SkippableFact] From aeccb691db8c599bf1565d58e2f9f52c31df96bb Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 12 Jun 2024 06:53:20 -0500 Subject: [PATCH 03/33] Added AgentVersion check for values CreateIndex, ModifyIndex and SerialNumber of Root class, due to a fail at version 1.6.10 --- Consul.Test/AgentTest.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 6e8907a45..694a0111f 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1036,7 +1036,6 @@ public async Task Agent_CARoots() var root = caRoots.Response.Roots.First(); Assert.NotNull(root.ID); Assert.NotNull(root.Name); - Assert.NotEqual(0, root.SerialNumber); Assert.NotNull(root.SigningKeyID); Assert.NotNull(root.ExternalTrustDomain); Assert.NotNull(root.NotBefore); @@ -1046,8 +1045,11 @@ public async Task Agent_CARoots() Assert.True(root.Active); Assert.NotNull(root.PrivateKeyType); Assert.NotEqual(0, root.PrivateKeyBits); - Assert.NotEqual(0, root.CreateIndex); - Assert.NotEqual(0, root.ModifyIndex); + if (AgentVersion >= SemanticVersion.Parse("1.7.0")) { + Assert.NotEqual(0, root.CreateIndex); + Assert.NotEqual(0, root.ModifyIndex); + Assert.NotEqual(0, root.SerialNumber); + } } [SkippableFact] From d252f6ed232129e1793cdb6b463d219dbba38059 Mon Sep 17 00:00:00 2001 From: octocat Date: Wed, 12 Jun 2024 11:54:03 +0000 Subject: [PATCH 04/33] style: fix whitespaces --- Consul.Test/AgentTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 694a0111f..465041116 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1045,7 +1045,8 @@ public async Task Agent_CARoots() Assert.True(root.Active); Assert.NotNull(root.PrivateKeyType); Assert.NotEqual(0, root.PrivateKeyBits); - if (AgentVersion >= SemanticVersion.Parse("1.7.0")) { + if (AgentVersion >= SemanticVersion.Parse("1.7.0")) + { Assert.NotEqual(0, root.CreateIndex); Assert.NotEqual(0, root.ModifyIndex); Assert.NotEqual(0, root.SerialNumber); From eae745b919ca85cb0a3751a27924ba2091315809 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:47:16 -0500 Subject: [PATCH 05/33] Added PrivateKeyBits to test only if AgentVersion greater or equal than 1.7.0 The field seems to be initialized to 0 in versions <= 1.7.0, which was causing a testing error --- Consul.Test/AgentTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 465041116..0eb07e601 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1044,9 +1044,9 @@ public async Task Agent_CARoots() Assert.Null(root.IntermediateCerts); Assert.True(root.Active); Assert.NotNull(root.PrivateKeyType); - Assert.NotEqual(0, root.PrivateKeyBits); if (AgentVersion >= SemanticVersion.Parse("1.7.0")) { + Assert.NotEqual(0, root.PrivateKeyBits); Assert.NotEqual(0, root.CreateIndex); Assert.NotEqual(0, root.ModifyIndex); Assert.NotEqual(0, root.SerialNumber); From bf727b02ed1005dcd9b3ef44287c927b206d61f5 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 19 Jun 2024 05:18:40 -0500 Subject: [PATCH 06/33] Added to GetCARoots, added GetCARoots with QueryOptions parameter --- Consul/Agent.cs | 16 ++++++++++++++++ Consul/Interfaces/IAgentEndpoint.cs | 1 + 2 files changed, 17 insertions(+) diff --git a/Consul/Agent.cs b/Consul/Agent.cs index 7d57fd7df..9802af599 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -1164,11 +1164,27 @@ public async Task> GetServiceConfiguration(str return await _client.Get($"/v1/agent/service/{serviceId}", q).Execute(ct).ConfigureAwait(false); } + /// + /// GetCARoots returns root certificates in the cluster + /// + /// Cancellation Token + /// Root certificates public async Task> GetCARoots(CancellationToken ct = default) { return await _client.Get("v1/agent/connect/ca/roots", QueryOptions.Default).Execute(ct).ConfigureAwait(false); } + /// + /// GetCARoots returns root certificates in the cluster + /// + /// Query Options + /// Cancellation Token + /// Root certificates + public async Task> GetCARoots(QueryOptions q, CancellationToken ct = default) + { + return await _client.Get("v1/agent/connect/ca/roots", q).Execute(ct).ConfigureAwait(false); + } + /// /// Log streamer /// diff --git a/Consul/Interfaces/IAgentEndpoint.cs b/Consul/Interfaces/IAgentEndpoint.cs index bfbeba630..3408437da 100644 --- a/Consul/Interfaces/IAgentEndpoint.cs +++ b/Consul/Interfaces/IAgentEndpoint.cs @@ -64,6 +64,7 @@ public interface IAgentEndpoint Task> GetLocalServiceHealthByID(string serviceID, CancellationToken ct = default); Task> GetAgentMetrics(CancellationToken ct = default); Task> GetCARoots(CancellationToken ct = default); + Task> GetCARoots(QueryOptions q, CancellationToken ct = default); Task> GetAgentVersion(CancellationToken ct = default); Task Reload(CancellationToken ct = default); [Obsolete] From 07c9b31b561047622a6f085f1d059a7eddf70598 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 19 Jun 2024 06:57:31 -0500 Subject: [PATCH 07/33] Minor fix to GetCaRoots --- Consul/Agent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Consul/Agent.cs b/Consul/Agent.cs index 9802af599..caaaaa05f 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -1171,7 +1171,7 @@ public async Task> GetServiceConfiguration(str /// Root certificates public async Task> GetCARoots(CancellationToken ct = default) { - return await _client.Get("v1/agent/connect/ca/roots", QueryOptions.Default).Execute(ct).ConfigureAwait(false); + return await GetCARoots(QueryOptions.Default, ct).ConfigureAwait(false); } /// From 34a3ccd0684a402d5b3990397b9b9ffeafe96eb3 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 19 Jun 2024 08:26:08 -0500 Subject: [PATCH 08/33] Added GetCALeaf endpoint, added tests for the endpoint in AgentTest.cs, modified IAgentEndpoint.cs to have GetCALeaf --- Consul.Test/AgentTest.cs | 27 ++++++++++++++++++++++ Consul/Agent.cs | 36 +++++++++++++++++++++++++++++ Consul/Interfaces/IAgentEndpoint.cs | 2 ++ 3 files changed, 65 insertions(+) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 0eb07e601..125d89165 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1053,6 +1053,33 @@ public async Task Agent_CARoots() } } + [Fact] + public async Task Agent_CALeaf() + { + var service = new AgentServiceRegistration + { + Name = "test_leaf", + Tags = new[] + { + "bar", + "baz" + }, + Port = 8000, + }; + await _client.Agent.ServiceRegister(service); + var leaf = await _client.Agent.GetCALeaf("test_leaf"); + Assert.True(leaf.LastIndex > 0); + Assert.NotNull(leaf.Response.SerialNumber); + Assert.NotNull(leaf.Response.CertPEM); + Assert.NotNull(leaf.Response.PrivateKeyPEM); + Assert.Equal("test_leaf", leaf.Response.Service); + Assert.Contains("/svc/test_leaf", leaf.Response.ServiceURI); + Assert.True(leaf.Response.ModifyIndex > 0); + Assert.NotEqual(0, leaf.Response.CreateIndex); + Assert.True(leaf.Response.ValidBefore > DateTime.Now); + Assert.True(leaf.Response.ValidAfter < DateTime.Now); + } + [SkippableFact] public async Task Agent_Reload() { diff --git a/Consul/Agent.cs b/Consul/Agent.cs index 7d57fd7df..a64f93c49 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -701,6 +701,19 @@ public class Root public long ModifyIndex { get; set; } } + public class CALeaf + { + public string SerialNumber { get; set; } + public string CertPEM { get; set; } + public string PrivateKeyPEM { get; set; } + public string Service { get; set; } + public string ServiceURI { get; set; } + public DateTime ValidAfter { get; set; } + public DateTime ValidBefore { get; set; } + public long CreateIndex { get; set; } + public long ModifyIndex { get; set; } + } + /// /// Agent can be used to query the Agent endpoints /// @@ -1169,6 +1182,29 @@ public async Task> GetCARoots(CancellationToken ct = defaul return await _client.Get("v1/agent/connect/ca/roots", QueryOptions.Default).Execute(ct).ConfigureAwait(false); } + /// + /// GetCALeaf, returns the leaf certificate representing a single service + /// + /// Id of service to fetch + /// Cancellation Token + /// Leaf certificate + public async Task> GetCALeaf(string serviceId, CancellationToken ct = default) + { + return await GetCALeaf(serviceId, QueryOptions.Default, ct).ConfigureAwait(false); + } + + /// + /// GetCALeaf, returns the leaf certificate representing a single service + /// + /// Id of service to fetch + /// Query Options + /// Cancellation Token + /// Leaf certificate + public async Task> GetCALeaf(string serviceId, QueryOptions q, CancellationToken ct = default) + { + return await _client.Get($"v1/agent/connect/ca/leaf/{serviceId}", q).Execute(ct).ConfigureAwait(false); + } + /// /// Log streamer /// diff --git a/Consul/Interfaces/IAgentEndpoint.cs b/Consul/Interfaces/IAgentEndpoint.cs index bfbeba630..33047f843 100644 --- a/Consul/Interfaces/IAgentEndpoint.cs +++ b/Consul/Interfaces/IAgentEndpoint.cs @@ -64,6 +64,8 @@ public interface IAgentEndpoint Task> GetLocalServiceHealthByID(string serviceID, CancellationToken ct = default); Task> GetAgentMetrics(CancellationToken ct = default); Task> GetCARoots(CancellationToken ct = default); + Task> GetCALeaf(string serviceId, CancellationToken ct = default); + Task> GetCALeaf(string serviceId, QueryOptions q, CancellationToken ct = default); Task> GetAgentVersion(CancellationToken ct = default); Task Reload(CancellationToken ct = default); [Obsolete] From ca745f32076d5c3bfed763802f4ab2215f710dd1 Mon Sep 17 00:00:00 2001 From: octocat Date: Wed, 19 Jun 2024 13:29:48 +0000 Subject: [PATCH 09/33] style: fix whitespaces --- Consul/Agent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Consul/Agent.cs b/Consul/Agent.cs index a1ddd56d9..71617a7dc 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -707,7 +707,7 @@ public class CALeaf public string CertPEM { get; set; } public string PrivateKeyPEM { get; set; } public string Service { get; set; } - public string ServiceURI { get; set; } + public string ServiceURI { get; set; } public DateTime ValidAfter { get; set; } public DateTime ValidBefore { get; set; } public long CreateIndex { get; set; } From f32d8a1e8d6ab3944bc8d75cbdf63748463f69dd Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 26 Jun 2024 01:49:42 -0500 Subject: [PATCH 10/33] Bug fix, repeated code --- Consul/Agent.cs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/Consul/Agent.cs b/Consul/Agent.cs index b43d1ee9b..71617a7dc 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -1221,27 +1221,6 @@ public async Task> GetCALeaf(string serviceId, QueryOptions return await _client.Get($"v1/agent/connect/ca/leaf/{serviceId}", q).Execute(ct).ConfigureAwait(false); } - /// - /// GetCARoots returns root certificates in the cluster - /// - /// Cancellation Token - /// Root certificates - public async Task> GetCARoots(CancellationToken ct = default) - { - return await GetCARoots(QueryOptions.Default, ct).ConfigureAwait(false); - } - - /// - /// GetCARoots returns root certificates in the cluster - /// - /// Query Options - /// Cancellation Token - /// Root certificates - public async Task> GetCARoots(QueryOptions q, CancellationToken ct = default) - { - return await _client.Get("v1/agent/connect/ca/roots", q).Execute(ct).ConfigureAwait(false); - } - /// /// Log streamer /// From eca5c0ea4dadf554a46dd3b07fb8c2eeebc1e3c8 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:48:16 -0500 Subject: [PATCH 11/33] Added POST ConnectAuthorize endpoint, added test for the endpoint, method to IAgendEndpoint.cs --- Consul.Test/AgentTest.cs | 14 ++++++++++++++ Consul/Agent.cs | 24 ++++++++++++++++++++++++ Consul/Interfaces/IAgentEndpoint.cs | 1 + 3 files changed, 39 insertions(+) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index 125d89165..e1b2582a3 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1025,6 +1025,20 @@ public async Task Agent_Metrics() Assert.NotNull(agentMetrics.Response.Samples); } + [Fact] + public async Task Agent_ConnectAuthorize() + { + var parameters = new AgentAuthorizeParams + { + Target = "foo", + ClientCertSerial = "fake", + ClientCertURI = "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/ny1/svc/web", + }; + var result = await _client.Agent.ConnectAuthorize(parameters); + Assert.True(result.Response.Authorized); + Assert.Equal("Default behavior configured by ACLs", result.Response.Reason); + } + [Fact] public async Task Agent_CARoots() { diff --git a/Consul/Agent.cs b/Consul/Agent.cs index 71617a7dc..df306caf7 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -676,6 +676,19 @@ public class Sample public Dictionary Labels { get; set; } } + public class AgentAuthorizeParams + { + public string Target { get; set; } + public string ClientCertURI { get; set; } + public string ClientCertSerial { get; set; } + } + + public class AgentAuthorizeResponse + { + public bool Authorized { get; set; } + public string Reason { get; set; } + } + public class CARoots { public string ActiveRootID { get; set; } @@ -1177,6 +1190,17 @@ public async Task> GetServiceConfiguration(str return await _client.Get($"/v1/agent/service/{serviceId}", q).Execute(ct).ConfigureAwait(false); } + /// + /// ConnectAuthorize tests whether a connection is authorized between two services + /// + /// Parameters for the request + /// Cancellation Token + /// An Authorize Response + public async Task> ConnectAuthorize(AgentAuthorizeParams parameters, CancellationToken ct = default) + { + return await _client.Post("/v1/agent/connect/authorize", parameters, null).Execute(ct).ConfigureAwait(false); + } + /// /// GetCARoots returns root certificates in the cluster /// diff --git a/Consul/Interfaces/IAgentEndpoint.cs b/Consul/Interfaces/IAgentEndpoint.cs index 48f7864a9..39e3df824 100644 --- a/Consul/Interfaces/IAgentEndpoint.cs +++ b/Consul/Interfaces/IAgentEndpoint.cs @@ -63,6 +63,7 @@ public interface IAgentEndpoint Task> GetLocalServiceHealthByID(string serviceID, QueryOptions q, CancellationToken ct = default); Task> GetLocalServiceHealthByID(string serviceID, CancellationToken ct = default); Task> GetAgentMetrics(CancellationToken ct = default); + Task> ConnectAuthorize(AgentAuthorizeParams parameters, CancellationToken ct = default); Task> GetCARoots(CancellationToken ct = default); Task> GetCARoots(QueryOptions q, CancellationToken ct = default); Task> GetCALeaf(string serviceId, CancellationToken ct = default); From b0d1623edb2d0035796273ece390d23da0e5ca70 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Mon, 1 Jul 2024 07:20:06 -0500 Subject: [PATCH 12/33] Changed name AgentAuthorizeParams to AgentAuthorizeParameters, added overload to ConnectAuthorize to support WriteOptions --- Consul.Test/AgentTest.cs | 2 +- Consul/Agent.cs | 18 +++++++++++++++--- Consul/Interfaces/IAgentEndpoint.cs | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Consul.Test/AgentTest.cs b/Consul.Test/AgentTest.cs index e1b2582a3..9f887a6b7 100644 --- a/Consul.Test/AgentTest.cs +++ b/Consul.Test/AgentTest.cs @@ -1028,7 +1028,7 @@ public async Task Agent_Metrics() [Fact] public async Task Agent_ConnectAuthorize() { - var parameters = new AgentAuthorizeParams + var parameters = new AgentAuthorizeParameters { Target = "foo", ClientCertSerial = "fake", diff --git a/Consul/Agent.cs b/Consul/Agent.cs index df306caf7..c403d9471 100644 --- a/Consul/Agent.cs +++ b/Consul/Agent.cs @@ -676,7 +676,7 @@ public class Sample public Dictionary Labels { get; set; } } - public class AgentAuthorizeParams + public class AgentAuthorizeParameters { public string Target { get; set; } public string ClientCertURI { get; set; } @@ -1196,9 +1196,21 @@ public async Task> GetServiceConfiguration(str /// Parameters for the request /// Cancellation Token /// An Authorize Response - public async Task> ConnectAuthorize(AgentAuthorizeParams parameters, CancellationToken ct = default) + public async Task> ConnectAuthorize(AgentAuthorizeParameters parameters, CancellationToken ct = default) { - return await _client.Post("/v1/agent/connect/authorize", parameters, null).Execute(ct).ConfigureAwait(false); + return await ConnectAuthorize(parameters, WriteOptions.Default, ct).ConfigureAwait(false); + } + + /// + /// ConnectAuthorize tests whether a connection is authorized between two services + /// + /// Parameters for the request + /// Write Options + /// Cancellation Token + /// An Authorize Response + public async Task> ConnectAuthorize(AgentAuthorizeParameters parameters, WriteOptions w, CancellationToken ct = default) + { + return await _client.Post("/v1/agent/connect/authorize", parameters, w).Execute(ct).ConfigureAwait(false); } /// diff --git a/Consul/Interfaces/IAgentEndpoint.cs b/Consul/Interfaces/IAgentEndpoint.cs index 39e3df824..a52a70cd2 100644 --- a/Consul/Interfaces/IAgentEndpoint.cs +++ b/Consul/Interfaces/IAgentEndpoint.cs @@ -63,7 +63,8 @@ public interface IAgentEndpoint Task> GetLocalServiceHealthByID(string serviceID, QueryOptions q, CancellationToken ct = default); Task> GetLocalServiceHealthByID(string serviceID, CancellationToken ct = default); Task> GetAgentMetrics(CancellationToken ct = default); - Task> ConnectAuthorize(AgentAuthorizeParams parameters, CancellationToken ct = default); + Task> ConnectAuthorize(AgentAuthorizeParameters parameters, CancellationToken ct = default); + Task> ConnectAuthorize(AgentAuthorizeParameters parameters, WriteOptions w, CancellationToken ct = default); Task> GetCARoots(CancellationToken ct = default); Task> GetCARoots(QueryOptions q, CancellationToken ct = default); Task> GetCALeaf(string serviceId, CancellationToken ct = default); From afd02b74488901ac4db1cd2f8d0e41f517f7b9a1 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:29:27 -0500 Subject: [PATCH 13/33] Added GET GatewayService endpoint, added tests for it Had to Add TerminatingGatewayConfigEntry and IngressGatewayConfigEntry classes for testing purposes --- Consul.Test/CatalogTest.cs | 97 +++++++++++++++++++++++++++ Consul/Catalog.cs | 80 ++++++++++++++++++++++ Consul/Interfaces/ICatalogEndpoint.cs | 2 + 3 files changed, 179 insertions(+) diff --git a/Consul.Test/CatalogTest.cs b/Consul.Test/CatalogTest.cs index c00ba396f..d48086fed 100644 --- a/Consul.Test/CatalogTest.cs +++ b/Consul.Test/CatalogTest.cs @@ -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] + public async Task Catalog_GatewayServices() + { + using (IConsulClient client = new ConsulClient(c => + { + c.Token = TestHelper.MasterToken; + c.Address = TestHelper.HttpUri; + })) + { + var terminatingGatewayName = "terminating-gateway"; + var ingressGatewayName = "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 + { + 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 + { + new IngressListener + { + Port = 8888, + Services = new List + { + new IngressService + { + Name = "api" + } + } + }, + new IngressListener + { + Port = 9999, + Services = new List + { + 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); + + gatewayServices = await client.Catalog.GatewayService(ingressGatewayName); + + Assert.NotEmpty(gatewayServices.Response); + Assert.Equal(ServiceKind.IngressGateway, gatewayServices.Response[0].GatewayKind); + } + } } } diff --git a/Consul/Catalog.cs b/Consul/Catalog.cs index b8fc54bb6..98aeb1f90 100644 --- a/Consul/Catalog.cs +++ b/Consul/Catalog.cs @@ -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 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 + { + public string Kind { get; set; } + public string Name { get; set; } + public List 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 Listeners { get; set; } + } + + public class IngressListener + { + public int Port { get; set; } + public List Services { get; set; } + } + + public class IngressService + { + public string Name { get; set; } + } + /// /// Catalog can be used to query the Catalog endpoints /// @@ -352,6 +408,30 @@ public Task> ServicesForNode(string node, QueryOptions { return _client.Get(string.Format("/v1/catalog/node-services/{0}", node), q).Execute(ct); } + + + /// + /// GatewayServices is used to query for the services associated with an ingress gateway or terminating gateway + /// + /// Gateway name + /// Query Parameters + /// Cancellation Token + /// Gateway services + public Task> GatewayService(string gateway, QueryOptions q, CancellationToken ct = default) + { + return _client.Get($"/v1/catalog/gateway-services/{gateway}", q).Execute(ct); + } + + /// + /// GatewayServices is used to query for the services associated with an ingress gateway or terminating gateway + /// + /// Gateway name + /// Cancellation Token + /// Gateway services + public Task> GatewayService(string gateway, CancellationToken ct = default) + { + return GatewayService(gateway, QueryOptions.Default, ct); + } } public partial class ConsulClient : IConsulClient diff --git a/Consul/Interfaces/ICatalogEndpoint.cs b/Consul/Interfaces/ICatalogEndpoint.cs index 7e7eec77e..413627a24 100644 --- a/Consul/Interfaces/ICatalogEndpoint.cs +++ b/Consul/Interfaces/ICatalogEndpoint.cs @@ -50,5 +50,7 @@ public interface ICatalogEndpoint Task> NodesForMeshCapableService(string service, CancellationToken ct = default); Task> ServicesForNode(string node, QueryOptions q, CancellationToken ct = default); Task> ServicesForNode(string node, CancellationToken ct = default); + Task> GatewayService(string gateway, QueryOptions q, CancellationToken ct = default); + Task> GatewayService(string gateway, CancellationToken ct = default); } } From 8d8b471c3509a2a531c1ed19bf967b991476be9b Mon Sep 17 00:00:00 2001 From: octocat Date: Fri, 12 Jul 2024 09:33:54 +0000 Subject: [PATCH 14/33] style: fix whitespaces --- Consul/Catalog.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Consul/Catalog.cs b/Consul/Catalog.cs index 98aeb1f90..7ecf74acb 100644 --- a/Consul/Catalog.cs +++ b/Consul/Catalog.cs @@ -144,13 +144,13 @@ public class TerminatingGatewayConfigEntry : IConfigurationEntry { public string Kind { get; set; } public string Name { get; set; } - public List Services { get; set; } + public List Services { get; set; } } public class LinkedServiceGateway { public string Name { get; set; } - public string CAFile { get; set; } + public string CAFile { get; set; } public string CertFile { get; set; } public string KeyFile { get; set; } public string SNI { get; set; } @@ -164,7 +164,7 @@ public class IngressGatewayConfigEntry : IConfigurationEntry } public class IngressListener - { + { public int Port { get; set; } public List Services { get; set; } } From e70153c9d5d8caaca7e18822d1150149558e61b9 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Mon, 15 Jul 2024 07:33:49 -0500 Subject: [PATCH 15/33] Deleted custom Termintaing and Ingress gateway config entries. Modified Configuration.cs to have correct classes Changed name TerminalGatewayEntry to TerminatingGatewayEntry --- Consul.Test/CatalogTest.cs | 26 ++++++++++++-------------- Consul/Catalog.cs | 34 ---------------------------------- Consul/Configuration.cs | 22 +++++++++++----------- 3 files changed, 23 insertions(+), 59 deletions(-) diff --git a/Consul.Test/CatalogTest.cs b/Consul.Test/CatalogTest.cs index d48086fed..a687eeba5 100644 --- a/Consul.Test/CatalogTest.cs +++ b/Consul.Test/CatalogTest.cs @@ -344,13 +344,12 @@ public async Task Catalog_GatewayServices() }; await client.Catalog.Register(terminatingGatewayEntry); - var terminatingGatewayConfigEntry = new TerminatingGatewayConfigEntry + var terminatingGatewayConfigEntry = new TerminatingGatewayEntry { - Kind = ServiceKind.TerminatingGateway.ToString(), Name = terminatingGatewayName, - Services = new List + Services = new List { - new LinkedServiceGateway + new LinkedService { Name = "api", CAFile = "api/ca.crt", @@ -358,7 +357,7 @@ public async Task Catalog_GatewayServices() KeyFile = "api/client.key", SNI = "my-domain" }, - new LinkedServiceGateway + new LinkedService { Name = "*", CAFile = "ca.crt", @@ -370,29 +369,28 @@ public async Task Catalog_GatewayServices() }; await client.Configuration.ApplyConfig(terminatingGatewayConfigEntry); - var ingressGatewayConfigEntry = new IngressGatewayConfigEntry + var ingressGatewayConfigEntry = new IngressGatewayEntry { - Kind = ServiceKind.IngressGateway.ToString(), Name = ingressGatewayName, - Listeners = new List + Listeners = new List { - new IngressListener + new GatewayListener { Port = 8888, - Services = new List + Services = new List { - new IngressService + new ExternalService { Name = "api" } } }, - new IngressListener + new GatewayListener { Port = 9999, - Services = new List + Services = new List { - new IngressService + new ExternalService { Name = "redis" } diff --git a/Consul/Catalog.cs b/Consul/Catalog.cs index 7ecf74acb..1324d086a 100644 --- a/Consul/Catalog.cs +++ b/Consul/Catalog.cs @@ -140,40 +140,6 @@ public class GatewayService public bool FromWildcard { get; set; } } - public class TerminatingGatewayConfigEntry : IConfigurationEntry - { - public string Kind { get; set; } - public string Name { get; set; } - public List 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 Listeners { get; set; } - } - - public class IngressListener - { - public int Port { get; set; } - public List Services { get; set; } - } - - public class IngressService - { - public string Name { get; set; } - } - /// /// Catalog can be used to query the Catalog endpoints /// diff --git a/Consul/Configuration.cs b/Consul/Configuration.cs index 1a70e4e80..e34d72ec3 100644 --- a/Consul/Configuration.cs +++ b/Consul/Configuration.cs @@ -215,7 +215,7 @@ public class CacheConfig /// /// IngressGatewayEntry provides configuration for the Ingress Gateway Proxy /// - public class IngressGatewayEntry + public class IngressGatewayEntry : IConfigurationEntry { [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string Kind { get; set; } = "ingress-gateway"; @@ -774,7 +774,7 @@ public class CatalogRateLimit /// /// Configures terminating gateways to proxy traffic from services in the Consul service mesh to services registered with Consul that do not have a service mesh sidecar proxy /// - public class TerminalGatewayEntry : IConfigurationEntry + public class TerminatingGatewayEntry : IConfigurationEntry { [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string Kind { get; set; } = "terminating-gateway"; @@ -793,27 +793,27 @@ public class TerminalGatewayEntry : IConfigurationEntry [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public List Services { get; set; } + } + public class LinkedService + { [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string CAFile { get; set; } + public string Name { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string CertFile { get; set; } + public string Namespace { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string KeyFile { get; set; } + public string CAFile { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string SNI { get; set; } - } + public string CertFile { get; set; } - public class LinkedService - { [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string Name { get; set; } + public string KeyFile { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string Namespace { get; set; } + public string SNI { get; set; } } /// From 4ad25b537b2b5c4e3efb81f8e1364e1faea7f6e7 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Mon, 15 Jul 2024 08:58:03 -0500 Subject: [PATCH 16/33] Added GET Update LAN Coordinates endpoints, added tests for it --- Consul.Test/Consul.Test.csproj | 2 +- Consul.Test/CoordinateTest.cs | 41 ++++++++++++++++++++++++ Consul/Coordinate.cs | 6 ++++ Consul/Interfaces/ICoordinateEndpoint.cs | 1 + 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/Consul.Test/Consul.Test.csproj b/Consul.Test/Consul.Test.csproj index 4f529731e..dc2b0ac98 100644 --- a/Consul.Test/Consul.Test.csproj +++ b/Consul.Test/Consul.Test.csproj @@ -13,7 +13,7 @@ - + diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 3793c0177..1856104e7 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -73,5 +73,46 @@ public async Task Coordinate_GetNode() Assert.IsType(nodeDetails); Assert.NotEmpty(nodeDetails); } + + [Fact] + public async Task Coordinate_Update() + { + var nodeName = "foo-update-lan"; + var registration = new CatalogRegistration + { + Node = nodeName, + Address = "1.1.1.1" + }; + var register = await _client.Catalog.Register(registration); + + var coord = new CoordinateEntry + { + Node = nodeName, + Coord = new SerfCoordinate() + }; + coord.Coord.Error = 1.5; + coord.Coord.Height = 0.5; + coord.Coord.Adjustment = 0.0; + for (int i = 0; i < 8; i++) coord.Coord.Vec.Add(0.0); + + var response = await _client.Coordinate.Update(coord); + Assert.Equal("OK", response.StatusCode.ToString()); + + var newCoordResult = await _client.Coordinate.Node(nodeName); + for (int i = 0; i < 4; i++) + { + if (newCoordResult != null) break; + await Task.Delay(1000); + newCoordResult = await _client.Coordinate.Node(nodeName); + } + + Assert.NotNull(newCoordResult); + var newCoord = newCoordResult.Response[0]; + Assert.Equal(coord.Coord.Vec.Count, newCoord.Coord.Vec.Count); + Assert.Equal(coord.Node, newCoord.Node); + Assert.True(Math.Abs(coord.Coord.Height - newCoord.Coord.Height) <= 0.00001); + Assert.True(Math.Abs(coord.Coord.Adjustment - newCoord.Coord.Adjustment) <= 0.00001); + Assert.True(Math.Abs(coord.Coord.Error - newCoord.Coord.Error) <= 0.00001); + } } } diff --git a/Consul/Coordinate.cs b/Consul/Coordinate.cs index 76b527968..ee77e6c6c 100644 --- a/Consul/Coordinate.cs +++ b/Consul/Coordinate.cs @@ -26,6 +26,7 @@ namespace Consul public class CoordinateEntry { public string Node { get; set; } + public string Segment { get; set; } public SerfCoordinate Coord { get; set; } } @@ -105,6 +106,11 @@ public Task> Node(string node, CancellationToken { return Node(node, QueryOptions.Default, ct); } + + public Task Update(CoordinateEntry entry, CancellationToken ct = default) + { + return _client.Put("/v1/coordinate/update", entry, null).Execute(ct); + } } public partial class ConsulClient : IConsulClient diff --git a/Consul/Interfaces/ICoordinateEndpoint.cs b/Consul/Interfaces/ICoordinateEndpoint.cs index f82dc4b81..9d49de220 100644 --- a/Consul/Interfaces/ICoordinateEndpoint.cs +++ b/Consul/Interfaces/ICoordinateEndpoint.cs @@ -32,5 +32,6 @@ public interface ICoordinateEndpoint Task> Node(string node, QueryOptions q, CancellationToken ct = default); Task> Node(string node, CancellationToken ct = default); Task> Nodes(QueryOptions q, CancellationToken ct = default); + Task Update(CoordinateEntry entry, CancellationToken ct = default); } } From 82627a7040b4067bc09baba1b7b3582a8a632771 Mon Sep 17 00:00:00 2001 From: octocat Date: Mon, 15 Jul 2024 13:59:58 +0000 Subject: [PATCH 17/33] style: fix whitespaces --- Consul.Test/CoordinateTest.cs | 2 +- Consul/Coordinate.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 1856104e7..46fb5b756 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -94,7 +94,7 @@ public async Task Coordinate_Update() coord.Coord.Height = 0.5; coord.Coord.Adjustment = 0.0; for (int i = 0; i < 8; i++) coord.Coord.Vec.Add(0.0); - + var response = await _client.Coordinate.Update(coord); Assert.Equal("OK", response.StatusCode.ToString()); diff --git a/Consul/Coordinate.cs b/Consul/Coordinate.cs index ee77e6c6c..c4a20f2f2 100644 --- a/Consul/Coordinate.cs +++ b/Consul/Coordinate.cs @@ -26,7 +26,7 @@ namespace Consul public class CoordinateEntry { public string Node { get; set; } - public string Segment { get; set; } + public string Segment { get; set; } public SerfCoordinate Coord { get; set; } } From 69e27fba4bae81240c462bf50de10b65ba0e8cc7 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:47:57 -0500 Subject: [PATCH 18/33] Minor changes to time breaks --- Consul.Test/CoordinateTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 1856104e7..63f1c742e 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -99,10 +99,10 @@ public async Task Coordinate_Update() Assert.Equal("OK", response.StatusCode.ToString()); var newCoordResult = await _client.Coordinate.Node(nodeName); - for (int i = 0; i < 4; i++) + for (int i = 0; i < 5; i++) { if (newCoordResult != null) break; - await Task.Delay(1000); + await Task.Delay(1000 * 2); newCoordResult = await _client.Coordinate.Node(nodeName); } From cac8204245da3717544118aabc4ce40a05b5dc07 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:32:17 -0500 Subject: [PATCH 19/33] Possible bug fix --- Consul.Test/CoordinateTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 9d857f7e8..86f36a584 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -101,12 +101,12 @@ public async Task Coordinate_Update() var newCoordResult = await _client.Coordinate.Node(nodeName); for (int i = 0; i < 5; i++) { - if (newCoordResult != null) break; + if (newCoordResult.Response != null) break; await Task.Delay(1000 * 2); newCoordResult = await _client.Coordinate.Node(nodeName); } - Assert.NotNull(newCoordResult); + Assert.NotNull(newCoordResult.Response); var newCoord = newCoordResult.Response[0]; Assert.Equal(coord.Coord.Vec.Count, newCoord.Coord.Vec.Count); Assert.Equal(coord.Node, newCoord.Node); From c9305bd97a47caf49cf31c42cd596c226a0a1aa0 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Tue, 16 Jul 2024 03:03:00 -0500 Subject: [PATCH 20/33] Modified test for List Gateway Services, skippable for versions 1.7.14 and earlier Catalog GET GatewayServices is only supported after 1.7.14 --- Consul.Test/CatalogTest.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Consul.Test/CatalogTest.cs b/Consul.Test/CatalogTest.cs index a687eeba5..4f37ea94b 100644 --- a/Consul.Test/CatalogTest.cs +++ b/Consul.Test/CatalogTest.cs @@ -318,9 +318,11 @@ public async Task Catalog_ServicesForNodes() Assert.DoesNotContain(services.Response.Services, n => n.ID == svcID2); } - [Fact] + [SkippableFact] public async Task Catalog_GatewayServices() { + var cutOffVersion = SemanticVersion.Parse("1.8.0"); + Skip.If(AgentVersion < cutOffVersion, $"Current version is {AgentVersion}, but Terminating and Ingress GatewayEntrys are different since {cutOffVersion}"); using (IConsulClient client = new ConsulClient(c => { c.Token = TestHelper.MasterToken; From 954dbf7ebe13249f7789e87feb3adcd3a4d425cc Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Tue, 16 Jul 2024 03:05:01 -0500 Subject: [PATCH 21/33] Using non-standard name for the testing gateway services --- Consul.Test/CatalogTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Consul.Test/CatalogTest.cs b/Consul.Test/CatalogTest.cs index 4f37ea94b..6624f1411 100644 --- a/Consul.Test/CatalogTest.cs +++ b/Consul.Test/CatalogTest.cs @@ -329,8 +329,8 @@ public async Task Catalog_GatewayServices() c.Address = TestHelper.HttpUri; })) { - var terminatingGatewayName = "terminating-gateway"; - var ingressGatewayName = "ingress-gateway"; + var terminatingGatewayName = "my-terminating-gateway"; + var ingressGatewayName = "my-ingress-gateway"; var terminatingGatewayEntry = new CatalogRegistration { From ed68a0dbe32d9c65cff2a947f94ac422c6452fd4 Mon Sep 17 00:00:00 2001 From: Ivan Kolchanov <83294629+IvanKolchanov@users.noreply.github.com> Date: Tue, 16 Jul 2024 06:17:55 -0500 Subject: [PATCH 22/33] Update Consul.Test/CoordinateTest.cs Co-authored-by: Marcin Krystianc --- Consul.Test/CoordinateTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 86f36a584..c67522856 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -96,7 +96,7 @@ public async Task Coordinate_Update() for (int i = 0; i < 8; i++) coord.Coord.Vec.Add(0.0); var response = await _client.Coordinate.Update(coord); - Assert.Equal("OK", response.StatusCode.ToString()); + Assert.Equal(HttpStatusCode.OK, response.StatusCode);; var newCoordResult = await _client.Coordinate.Node(nodeName); for (int i = 0; i < 5; i++) From 86209c9fec9b0274a3f162f1f739a492176c79ad Mon Sep 17 00:00:00 2001 From: Ivan Kolchanov <83294629+IvanKolchanov@users.noreply.github.com> Date: Tue, 16 Jul 2024 06:18:05 -0500 Subject: [PATCH 23/33] Update Consul.Test/CoordinateTest.cs Co-authored-by: Marcin Krystianc --- Consul.Test/CoordinateTest.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index c67522856..5e2766c36 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -88,12 +88,14 @@ public async Task Coordinate_Update() var coord = new CoordinateEntry { Node = nodeName, - Coord = new SerfCoordinate() + Coord = new SerfCoordinate + { + Error = 1.5, + Height = 0.5, + Adjustment = 0.0, + Vec = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + } }; - coord.Coord.Error = 1.5; - coord.Coord.Height = 0.5; - coord.Coord.Adjustment = 0.0; - for (int i = 0; i < 8; i++) coord.Coord.Vec.Add(0.0); var response = await _client.Coordinate.Update(coord); Assert.Equal(HttpStatusCode.OK, response.StatusCode);; From cc4be02a91dd652bedb2de24242d47facc7ea8f3 Mon Sep 17 00:00:00 2001 From: octocat Date: Tue, 16 Jul 2024 11:18:38 +0000 Subject: [PATCH 24/33] style: fix whitespaces --- Consul.Test/CoordinateTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 5e2766c36..5aa14522f 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -93,12 +93,12 @@ public async Task Coordinate_Update() Error = 1.5, Height = 0.5, Adjustment = 0.0, - Vec = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + Vec = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, } }; var response = await _client.Coordinate.Update(coord); - Assert.Equal(HttpStatusCode.OK, response.StatusCode);; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); ; var newCoordResult = await _client.Coordinate.Node(nodeName); for (int i = 0; i < 5; i++) From 500040cafeac329b25aa9f7ca4d36a3af55e92d1 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Tue, 16 Jul 2024 06:26:09 -0500 Subject: [PATCH 25/33] Some test fixes, a version of Update with WriteOptions --- Consul.Test/CoordinateTest.cs | 17 ++++++++--------- Consul/Coordinate.cs | 20 +++++++++++++++++++- Consul/Interfaces/ICoordinateEndpoint.cs | 1 + 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 5e2766c36..62449d3dd 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -19,6 +19,7 @@ using System; using System.Threading.Tasks; +using System.Net; using Xunit; namespace Consul.Test @@ -84,6 +85,8 @@ public async Task Coordinate_Update() Address = "1.1.1.1" }; var register = await _client.Catalog.Register(registration); + var nodeResult = await _client.Catalog.Node(nodeName); + Assert.Equal(HttpStatusCode.OK, nodeResult.StatusCode); var coord = new CoordinateEntry { @@ -98,17 +101,13 @@ public async Task Coordinate_Update() }; var response = await _client.Coordinate.Update(coord); - Assert.Equal(HttpStatusCode.OK, response.StatusCode);; - - var newCoordResult = await _client.Coordinate.Node(nodeName); - for (int i = 0; i < 5; i++) - { - if (newCoordResult.Response != null) break; - await Task.Delay(1000 * 2); - newCoordResult = await _client.Coordinate.Node(nodeName); - } + Assert.Equal(HttpStatusCode.OK, response.StatusCode);; + var q = new QueryOptions { WaitIndex = nodeResult.LastIndex, }; + var newCoordResult = await _client.Coordinate.Node(nodeName, q); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(newCoordResult.Response); + var newCoord = newCoordResult.Response[0]; Assert.Equal(coord.Coord.Vec.Count, newCoord.Coord.Vec.Count); Assert.Equal(coord.Node, newCoord.Node); diff --git a/Consul/Coordinate.cs b/Consul/Coordinate.cs index c4a20f2f2..6c3e7b42b 100644 --- a/Consul/Coordinate.cs +++ b/Consul/Coordinate.cs @@ -107,9 +107,27 @@ public Task> Node(string node, CancellationToken return Node(node, QueryOptions.Default, ct); } + /// + /// Updates the LAN network coordinates for a node in a given datacenter. + /// + /// A coordinate entry + /// Customized write options + /// Cancellation Token + /// An empty write result + public Task Update(CoordinateEntry entry, WriteOptions q, CancellationToken ct = default) + { + return _client.Put("/v1/coordinate/update", entry, q).Execute(ct); + } + + /// + /// Updates the LAN network coordinates for a node in a given datacenter. + /// + /// A coordinate entry + /// Cancellation Token + /// An empty write result public Task Update(CoordinateEntry entry, CancellationToken ct = default) { - return _client.Put("/v1/coordinate/update", entry, null).Execute(ct); + return Update(entry, WriteOptions.Default, ct); } } diff --git a/Consul/Interfaces/ICoordinateEndpoint.cs b/Consul/Interfaces/ICoordinateEndpoint.cs index 9d49de220..6465c38d1 100644 --- a/Consul/Interfaces/ICoordinateEndpoint.cs +++ b/Consul/Interfaces/ICoordinateEndpoint.cs @@ -32,6 +32,7 @@ public interface ICoordinateEndpoint Task> Node(string node, QueryOptions q, CancellationToken ct = default); Task> Node(string node, CancellationToken ct = default); Task> Nodes(QueryOptions q, CancellationToken ct = default); + Task Update(CoordinateEntry entry, WriteOptions q, CancellationToken ct = default); Task Update(CoordinateEntry entry, CancellationToken ct = default); } } From f85e68f4c596dd37db33d5f465adf367420e310f Mon Sep 17 00:00:00 2001 From: octocat Date: Tue, 16 Jul 2024 11:30:21 +0000 Subject: [PATCH 26/33] style: fix whitespaces --- Consul.Test/CoordinateTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Consul.Test/CoordinateTest.cs b/Consul.Test/CoordinateTest.cs index 17a65e471..aa33a6326 100644 --- a/Consul.Test/CoordinateTest.cs +++ b/Consul.Test/CoordinateTest.cs @@ -18,8 +18,8 @@ // ----------------------------------------------------------------------- using System; -using System.Threading.Tasks; using System.Net; +using System.Threading.Tasks; using Xunit; namespace Consul.Test From 51a1e9b51ba8f7668f57264a519ece0efcab364c Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Tue, 16 Jul 2024 07:44:06 -0500 Subject: [PATCH 27/33] Dummy changes to merge --- Consul/Coordinate.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Consul/Coordinate.cs b/Consul/Coordinate.cs index 6c3e7b42b..ea70009e4 100644 --- a/Consul/Coordinate.cs +++ b/Consul/Coordinate.cs @@ -110,7 +110,7 @@ public Task> Node(string node, CancellationToken /// /// Updates the LAN network coordinates for a node in a given datacenter. /// - /// A coordinate entry + /// The coordinate entry to update /// Customized write options /// Cancellation Token /// An empty write result @@ -122,7 +122,7 @@ public Task Update(CoordinateEntry entry, WriteOptions q, Cancellat /// /// Updates the LAN network coordinates for a node in a given datacenter. /// - /// A coordinate entry + /// The coordinate entry to update /// Cancellation Token /// An empty write result public Task Update(CoordinateEntry entry, CancellationToken ct = default) From a80f67f03a6d75f0528f888c558673b422b93eb9 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:31:02 -0500 Subject: [PATCH 28/33] Some field checks for GatewayService results --- Consul.Test/CatalogTest.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Consul.Test/CatalogTest.cs b/Consul.Test/CatalogTest.cs index 6624f1411..7c1e814d6 100644 --- a/Consul.Test/CatalogTest.cs +++ b/Consul.Test/CatalogTest.cs @@ -404,14 +404,26 @@ public async Task Catalog_GatewayServices() await client.Configuration.ApplyConfig(ingressGatewayConfigEntry); var gatewayServices = await client.Catalog.GatewayService(terminatingGatewayName); - Assert.NotEmpty(gatewayServices.Response); - Assert.Equal(ServiceKind.TerminatingGateway, gatewayServices.Response[0].GatewayKind); - gatewayServices = await client.Catalog.GatewayService(ingressGatewayName); + var terminatingService = gatewayServices.Response[0]; + Assert.NotNull(terminatingService.Gateway); + Assert.Equal(terminatingGatewayName, terminatingService.Gateway.Name); + Assert.NotNull(terminatingService.Service); + Assert.Equal(ServiceKind.TerminatingGateway, terminatingService.GatewayKind); + Assert.NotNull(terminatingService.CAFile); + Assert.NotNull(terminatingService.CertFile); + Assert.NotNull(terminatingService.KeyFile); + Assert.NotNull(terminatingService.SNI); + gatewayServices = await client.Catalog.GatewayService(ingressGatewayName); Assert.NotEmpty(gatewayServices.Response); - Assert.Equal(ServiceKind.IngressGateway, gatewayServices.Response[0].GatewayKind); + + var ingressService = gatewayServices.Response[0]; + Assert.NotNull(ingressService.Gateway); + Assert.Equal(ingressGatewayName, ingressService.Gateway.Name); + Assert.NotNull(ingressService.Service); + Assert.Equal(ServiceKind.IngressGateway, ingressService.GatewayKind); } } } From 7705e0ad44de6ac55ea688bcc44b411b61086f08 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:48:48 -0500 Subject: [PATCH 29/33] Minor test change --- Consul.Test/CatalogTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Consul.Test/CatalogTest.cs b/Consul.Test/CatalogTest.cs index 7c1e814d6..483a265e7 100644 --- a/Consul.Test/CatalogTest.cs +++ b/Consul.Test/CatalogTest.cs @@ -424,6 +424,8 @@ public async Task Catalog_GatewayServices() Assert.Equal(ingressGatewayName, ingressService.Gateway.Name); Assert.NotNull(ingressService.Service); Assert.Equal(ServiceKind.IngressGateway, ingressService.GatewayKind); + Assert.Equal(8888, ingressService.Port); + Assert.NotNull(ingressService.Protocol); } } } From 0c93a3213e453943124a2c25a4d7dd509aecc9b0 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:09:11 -0500 Subject: [PATCH 30/33] Added GET List Ingress Health for Service Added endpoint and tests, had to change Node in Catalog.cs because it lacked a field --- Consul.Test/HealthTest.cs | 45 ++++++++++++++++++++++++++ Consul/Catalog.cs | 1 + Consul/Health.cs | 48 ++++++++++++++++++++++++++++ Consul/Interfaces/IHealthEndpoint.cs | 3 ++ 4 files changed, 97 insertions(+) diff --git a/Consul.Test/HealthTest.cs b/Consul.Test/HealthTest.cs index 5608b3965..22dcecc97 100644 --- a/Consul.Test/HealthTest.cs +++ b/Consul.Test/HealthTest.cs @@ -157,6 +157,51 @@ public async Task Health_Connect() } } + [Fact] + public async void Health_Ingress() + { + var registration = new AgentServiceRegistration + { + Name = "foo-ingress", + Port = 8000 + }; + await _client.Agent.ServiceRegister(registration); + + var gatewayRegistration = new AgentServiceRegistration + { + Name = "foo-ingress-gateway", + Port = 8001, + Kind = ServiceKind.IngressGateway + }; + await _client.Agent.ServiceRegister(gatewayRegistration); + + var ingressGatewayConfigEntry = new IngressGatewayEntry + { + Name = "foo-ingress-gateway", + Listeners = new List + { + new GatewayListener + { + Port = 2222, + Protocol = "tcp", + Services = new List + { + new ExternalService + { + Name = "foo-ingress" + } + } + } + } + }; + await _client.Configuration.ApplyConfig(ingressGatewayConfigEntry); + + var services = await _client.Health.Ingress("foo-ingress", "", false); + Assert.Single(services.Response); + Assert.Equal("dc1", services.Response[0].Node.Datacenter); + Assert.Equal(gatewayRegistration.Name, services.Response[0].Service.Service); + } + [Fact] public void Health_GetAggregatedStatus() { diff --git a/Consul/Catalog.cs b/Consul/Catalog.cs index 1324d086a..0ea2e3f19 100644 --- a/Consul/Catalog.cs +++ b/Consul/Catalog.cs @@ -32,6 +32,7 @@ public class Node [JsonProperty(PropertyName = "Node")] public string Name { get; set; } public string Address { get; set; } + public string Datacenter { get; set; } public Dictionary TaggedAddresses { get; set; } } diff --git a/Consul/Health.cs b/Consul/Health.cs index 51f447eeb..ceee4ab01 100644 --- a/Consul/Health.cs +++ b/Consul/Health.cs @@ -337,6 +337,54 @@ public Task> Connect(string service, string tag, boo return Connect(service, tag, passingOnly, q, null, ct); } + /// + /// Ingress is equivalent to Service and Connect, except that it will only return ingress services + /// The service ID + /// The service member tag + /// Only return if the health check is in the Passing state + /// Customized query options + /// Specifies the expression used to filter the queries results prior to returning the data + /// Cancellation token for long poll request. If set, OperationCanceledException will be thrown if the request is cancelled before completing + /// This endpoint returns the nodes providing an ingress service in a given datacenter, or a query result with a null response + public Task> Ingress(string service, string tag, bool passingOnly, QueryOptions q, Filter filter, CancellationToken ct = default) + { + var req = _client.Get(string.Format("/v1/health/ingress/{0}", service), q, filter); + if (!string.IsNullOrEmpty(tag)) + { + req.Params["tag"] = tag; + } + if (passingOnly) + { + req.Params["passing"] = "1"; + } + return req.Execute(ct); + } + + /// + /// Ingress is equivalent to Service and Connect, except that it will only return ingress services + /// The service ID + /// The service member tag + /// Only return if the health check is in the Passing state + /// Customized query options + /// Cancellation token for long poll request. If set, OperationCanceledException will be thrown if the request is cancelled before completing + /// This endpoint returns the nodes providing an ingress service in a given datacenter, or a query result with a null response + public Task> Ingress(string service, string tag, bool passingOnly, QueryOptions q, CancellationToken ct = default) + { + return Ingress(service, tag, passingOnly, q, null, ct); + } + + /// + /// Ingress is equivalent to Service and Connect, except that it will only return ingress services + /// The service ID + /// The service member tag + /// Only return if the health check is in the Passing state + /// Cancellation token for long poll request. If set, OperationCanceledException will be thrown if the request is cancelled before completing + /// This endpoint returns the nodes providing an ingress service in a given datacenter, or a query result with a null response + public Task> Ingress(string service, string tag, bool passingOnly, CancellationToken ct = default) + { + return Ingress(service, tag, passingOnly, QueryOptions.Default, null, ct); + } + /// /// State is used to retrieve all the checks in a given state. The wildcard "any" state can also be used for all checks. /// diff --git a/Consul/Interfaces/IHealthEndpoint.cs b/Consul/Interfaces/IHealthEndpoint.cs index d0dcbcfcf..62cf9e458 100644 --- a/Consul/Interfaces/IHealthEndpoint.cs +++ b/Consul/Interfaces/IHealthEndpoint.cs @@ -39,6 +39,9 @@ public interface IHealthEndpoint Task> Service(string service, string tag, bool passingOnly, QueryOptions q, Filter filter, CancellationToken ct = default); Task> Connect(string service, string tag, bool passingOnly, QueryOptions q, Filter filter, CancellationToken ct = default); Task> Connect(string service, string tag, bool passingOnly, QueryOptions q, CancellationToken ct = default); + Task> Ingress(string service, string tag, bool passingOnly, QueryOptions q, Filter filter, CancellationToken ct = default); + Task> Ingress(string service, string tag, bool passingOnly, QueryOptions q, CancellationToken ct = default); + Task> Ingress(string service, string tag, bool passingOnly, CancellationToken ct = default); Task> State(HealthStatus status, CancellationToken ct = default); Task> State(HealthStatus status, QueryOptions q, CancellationToken ct = default); } From 75b950b2b7f76efe110ce7509f02f9d44a20af58 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:29:55 -0500 Subject: [PATCH 31/33] Skip test for outdated server versions --- Consul.Test/HealthTest.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Consul.Test/HealthTest.cs b/Consul.Test/HealthTest.cs index 22dcecc97..91b0b5b78 100644 --- a/Consul.Test/HealthTest.cs +++ b/Consul.Test/HealthTest.cs @@ -157,9 +157,12 @@ public async Task Health_Connect() } } - [Fact] + [SkippableFact] public async void Health_Ingress() { + var cutOffVersion = SemanticVersion.Parse("1.8.0"); + Skip.If(AgentVersion < cutOffVersion, $"Current version is {AgentVersion}, but Terminating and Ingress GatewayEntrys are different since {cutOffVersion}"); + var registration = new AgentServiceRegistration { Name = "foo-ingress", From 3bab63d9b93f8cc7245f2c3b92c3b20aafd576e9 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:34:58 -0500 Subject: [PATCH 32/33] Import Versioning into HealthTest.cs to skip a test in some versions --- Consul.Test/HealthTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Consul.Test/HealthTest.cs b/Consul.Test/HealthTest.cs index 91b0b5b78..87753c9d3 100644 --- a/Consul.Test/HealthTest.cs +++ b/Consul.Test/HealthTest.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Consul.Filtering; +using NuGet.Versioning; using Xunit; namespace Consul.Test From 0f9a6c5d4d951c456a3791c44655621e0994c2b5 Mon Sep 17 00:00:00 2001 From: w1ano <83294629+w1ano@users.noreply.github.com> Date: Thu, 18 Jul 2024 08:04:34 -0500 Subject: [PATCH 33/33] Little fixes --- Consul.Test/HealthTest.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Consul.Test/HealthTest.cs b/Consul.Test/HealthTest.cs index 87753c9d3..ece58576b 100644 --- a/Consul.Test/HealthTest.cs +++ b/Consul.Test/HealthTest.cs @@ -183,26 +183,26 @@ public async void Health_Ingress() { Name = "foo-ingress-gateway", Listeners = new List + { + new GatewayListener { - new GatewayListener + Port = 2222, + Protocol = "tcp", + Services = new List { - Port = 2222, - Protocol = "tcp", - Services = new List + new ExternalService { - new ExternalService - { - Name = "foo-ingress" - } + Name = "foo-ingress" } } } + } }; await _client.Configuration.ApplyConfig(ingressGatewayConfigEntry); var services = await _client.Health.Ingress("foo-ingress", "", false); Assert.Single(services.Response); - Assert.Equal("dc1", services.Response[0].Node.Datacenter); + Assert.NotEmpty(services.Response[0].Node.Datacenter); Assert.Equal(gatewayRegistration.Name, services.Response[0].Service.Service); }