From 0e12cb2755b1bd5c681b48ad8a3377a048638f8d Mon Sep 17 00:00:00 2001 From: Gilad Wolff Date: Tue, 13 May 2025 17:10:02 -0700 Subject: [PATCH 1/3] move to checks --- examples/register_service.rs | 2 +- src/types.rs | 5 ++-- tests/test_runner.rs | 32 +++++++++++++++++++++++++ tests/utils/test_setup.rs | 46 +++++++++++++++++++++++++++++++++++- 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/examples/register_service.rs b/examples/register_service.rs index ea5eba6..289ac2b 100644 --- a/examples/register_service.rs +++ b/examples/register_service.rs @@ -27,7 +27,7 @@ async fn main() { Port: Some(42424), Namespace: None, }), - Check: None, + Checks: Vec::new(), SkipNodeUpdate: None, }; consul.register_entity(&payload).await.unwrap(); diff --git a/src/types.rs b/src/types.rs index e6375fe..e218911 100644 --- a/src/types.rs +++ b/src/types.rs @@ -312,9 +312,8 @@ pub struct RegisterEntityPayload { /// Optional service to register. #[serde(skip_serializing_if = "Option::is_none")] pub Service: Option, - /// Optional check to register - #[serde(skip_serializing_if = "Option::is_none")] - pub Check: Option, + /// Checks to register. + pub Checks: Vec, /// Whether to skip updating the nodes information in the registration. #[serde(skip_serializing_if = "Option::is_none")] pub SkipNodeUpdate: Option, diff --git a/tests/test_runner.rs b/tests/test_runner.rs index d9ac7be..a15755c 100644 --- a/tests/test_runner.rs +++ b/tests/test_runner.rs @@ -1,4 +1,5 @@ use rs_consul::*; +use std::collections::HashMap; #[path = "utils/test_setup.rs"] mod test_setup; @@ -304,4 +305,35 @@ mod tests { assert_eq!(string_value4, &value.unwrap()); assert_ne!(mod_idx3, mod_idx4); } + + #[tokio::test(flavor = "multi_thread")] + async fn test_register_with_health_checks() { + let consul = get_client(); + + let new_service_name = "test-service-99".to_string(); + let checks = [ + RegisterEntityCheck { + Node: None, + CheckID: None, + Name: "Service Check".to_string(), + Notes: None, + Status: Some("passing".to_string()), + ServiceID: Some(service_id(&new_service_name)), + Definition: HashMap::new(), + }, + RegisterEntityCheck { + Node: Some("local".to_string()), + CheckID: None, + Name: "Node check".to_string(), + Notes: None, + Status: Some("passing".to_string()), + ServiceID: None, + Definition: HashMap::new(), + }, + ] + .to_vec(); + register_entity_with_checks(&consul, &new_service_name, "local", checks).await; + + assert!(is_registered(&consul, &new_service_name).await); + } } diff --git a/tests/utils/test_setup.rs b/tests/utils/test_setup.rs index 7f71654..ddccf23 100644 --- a/tests/utils/test_setup.rs +++ b/tests/utils/test_setup.rs @@ -31,7 +31,7 @@ pub(crate) async fn register_entity(consul: &Consul, service_name: &String, node Port: Some(42424), Namespace: None, }), - Check: None, + Checks: Vec::new(), SkipNodeUpdate: None, }; consul @@ -40,6 +40,50 @@ pub(crate) async fn register_entity(consul: &Consul, service_name: &String, node .expect("expected register_entity request to succeed"); } +pub(crate) async fn register_entity_with_checks( + consul: &Consul, + service_name: &String, + node_id: &str, + checks: Vec, +) { + let ResponseMeta { + response: service_names_before_register, + .. + } = consul + .get_all_registered_service_names(None) + .await + .expect("expected get_registered_service_names request to succeed"); + assert!(!service_names_before_register.contains(service_name)); + + let payload = RegisterEntityPayload { + ID: None, + Node: node_id.to_string(), + Address: "127.0.0.1".to_string(), + Datacenter: None, + TaggedAddresses: Default::default(), + NodeMeta: Default::default(), + Service: Some(RegisterEntityService { + ID: Some(service_id(service_name)), + Service: service_name.clone(), + Tags: vec![], + TaggedAddresses: Default::default(), + Meta: Default::default(), + Port: Some(42424), + Namespace: None, + }), + Checks: checks, + SkipNodeUpdate: None, + }; + consul + .register_entity(&payload) + .await + .expect("expected register_entity request to succeed"); +} + +pub(crate) fn service_id(service_name: &str) -> String { + format!("{service_name}-ID") +} + pub(crate) async fn is_registered(consul: &Consul, service_name: &String) -> bool { let ResponseMeta { response: service_names_after_register, From 43ffbff818fea17ba8d3ab7947a0c4a2ac305c3d Mon Sep 17 00:00:00 2001 From: Gilad Wolff Date: Tue, 13 May 2025 17:30:36 -0700 Subject: [PATCH 2/3] bump version and update CHANGELOG --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eee6ed..53db7e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## Unreleased +## 0.10.0 - 2025-05-13 +- Supports registering multiple health checks. This breaks backward compatibility and drops supports to consul servers +older than 0.5.0 that do not have this commit: [674be58e55f](https://github.com/hashicorp/consul/commit/674be58e55f3f2b1f1c64ef2f52bfbd577db0c7c) + ## 0.9.0 - 2025-02-12 - Upgrade `opentelemetry` to `0.28` from `0.27`. diff --git a/Cargo.toml b/Cargo.toml index 26f4844..8287db4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rs-consul" # Don't forget to update the readme with the new version! -version = "0.9.0" +version = "0.10.0" authors = ["Roblox"] edition = "2021" description = "This crate provides access to a set of strongly typed apis to interact with consul (https://www.consul.io/)" From 4fae9ead4b5cdf49908176d51b8f1cfd1398b4ef Mon Sep 17 00:00:00 2001 From: Gilad Wolff Date: Tue, 13 May 2025 20:30:41 -0700 Subject: [PATCH 3/3] skip serizlizing --- src/types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types.rs b/src/types.rs index e218911..d9419cb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -313,6 +313,7 @@ pub struct RegisterEntityPayload { #[serde(skip_serializing_if = "Option::is_none")] pub Service: Option, /// Checks to register. + #[serde(skip_serializing_if = "Vec::is_empty")] pub Checks: Vec, /// Whether to skip updating the nodes information in the registration. #[serde(skip_serializing_if = "Option::is_none")]