Skip to content

Refactor: Simplify entity auto-registration#3139

Merged
didier-wenzek merged 2 commits intothin-edge:mainfrom
didier-wenzek:refactor/default-entity-scheme
Sep 27, 2024
Merged

Refactor: Simplify entity auto-registration#3139
didier-wenzek merged 2 commits intothin-edge:mainfrom
didier-wenzek:refactor/default-entity-scheme

Conversation

@didier-wenzek
Copy link
Copy Markdown
Contributor

Proposed changes

Introduce a new function mqtt_topic::default_topic_schema::parse() taking an entity topic id and returning the registration messages matching the auto-registration behavior.

Using this parse function simplifies the auto-registration logic which has no more to parse again and again the entity topic id to extract registration info.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Improvement (general improvements like code refactoring that doesn't explicitly fix a bug or add any new functionality)
  • Documentation Update (if none of the other choices apply)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Paste Link to the issue


Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA (in all commits with git commit -s)
  • I ran cargo fmt as mentioned in CODING_GUIDELINES
  • I used cargo clippy as mentioned in CODING_GUIDELINES
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

Comment on lines -1404 to +1379
parent: None,
parent: Some(EntityTopicId::from_str("device/main//").unwrap()),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was surprised by this. Why the parent of child device was expected to be None? Because no registration is required for the main device?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

EntityRegistrationMessage is supposed to be a subtype of MqttMessage, but with required fields like type or external_id present. Because it was supposed to be only created by converting from MqttMessage, it was to have only the same information that MqttMessage had, and actual filling of fallbacks and defaults was to be done in entity store when adding the entity (because only the entity store knows what's the actual name of main device and has a function to generate the entity's external id).

So in this case MqttMessage payload that contained no parent field would be converted to EntityRegistrationMessage that didn't contain it as well, and the parent would be resolved by the entity store when registering the child.

So I think it'd be better to leave it as None.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

and the parent would be resolved by the entity store when registering the child.

This is what I would like to fix with this PR. Indeed, for auto registration, the entity store starts with a topic matching the default topic scheme (starting with a validation) and then extracts sub data (type, names, relationship) using misc functions assuming each the default topic scheme.

With this PR, the entity store can parse an entity topic id into all the info required for auto-registration is applicable.

This also addresses what you noted : currently it seems it has a very large surface with lots of methods that are ultimately a bit shallow

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So I think it'd be better to leave it as None.

However, I will opt for the other way, i.e. setting the parent. Indeed, the point of the parse(entity_topic_id)
is to provide an explicit representation of all what is implied by an entity topic of the default topic scheme.

@codecov
Copy link
Copy Markdown

codecov bot commented Sep 25, 2024

Codecov Report

Attention: Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/core/tedge_api/src/entity_store.rs 95.65% 0 Missing and 1 partial ⚠️
Additional details and impacted files

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Sep 25, 2024

Robot Results

✅ Passed ❌ Failed ⏭️ Skipped Total Pass % ⏱️ Duration
506 0 2 506 100 1h30m52.977191s

Copy link
Copy Markdown
Member

@Bravo555 Bravo555 left a comment

Choose a reason for hiding this comment

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

Seems a small simplification with no functional changes, approving with a small comment regarding the changed unit test.

But I'm reminded how entity store and entity topic id logic could be made simpler, as currently it seems it has a very large surface with lots of methods that are ultimately a bit shallow.

Comment on lines +463 to +477
["device", child, "service", service] if !child.is_empty() && !service.is_empty() => {
// The device of a service has to be registered fist
let child_topic_id = EntityTopicId::default_child_device(child).unwrap();
let mut registrations = parse(&child_topic_id);

// Then the service can be registered
registrations.push(EntityRegistrationMessage {
topic_id: topic_id.clone(),
external_id: None,
r#type: EntityType::Service,
parent: Some(EntityTopicId::default_child_device(child).unwrap()),
other: json!({ "name": service }).as_object().unwrap().to_owned(),
});
registrations
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion: this branch also covers the case when child = "main", so service for the main device, perhaps rename child to device to make it more clear

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or even a dedicated arm for the main device service case, as the parent (main device) need not be registered in that case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed by 1d3f707

Comment on lines 612 to 616
if auto_entity.r#type == EntityType::Service {
auto_entity
.other
.insert("type".to_string(), self.default_service_type.clone().into());
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thought: Bit awkward we still need this branch here because c8y needs to have a service type, which I reckon doesn't have much use in a local entity store, but we only have access to fallback default service type in the entity store.

In the future it'd be good to move it either up to c8y mapper (I think it was there before, but can't remember the reason why I pulled it into the entity store, perhaps I was wrong to do so) or down somewhere, but in any case it feels kind of out of place in here.

Comment on lines -1404 to +1379
parent: None,
parent: Some(EntityTopicId::from_str("device/main//").unwrap()),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

EntityRegistrationMessage is supposed to be a subtype of MqttMessage, but with required fields like type or external_id present. Because it was supposed to be only created by converting from MqttMessage, it was to have only the same information that MqttMessage had, and actual filling of fallbacks and defaults was to be done in entity store when adding the entity (because only the entity store knows what's the actual name of main device and has a function to generate the entity's external id).

So in this case MqttMessage payload that contained no parent field would be converted to EntityRegistrationMessage that didn't contain it as well, and the parent would be resolved by the entity store when registering the child.

So I think it'd be better to leave it as None.

Copy link
Copy Markdown
Contributor

@albinsuresh albinsuresh left a comment

Choose a reason for hiding this comment

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

The refactoring looks fine to me. Yet there are some test failures.

.default_source_device_identifier()
.expect("device id must be present as the topic id follows the default scheme");

if !parent_device_id.is_default_main_device() && self.get(&parent_device_id).is_none() {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oops, I removed this check that the device should not already be registered.

self.get(&parent_device_id).is_none()

This explains why the system tests are failing.

For instance for :

Before, only the service where registered:

c8y/s/us/foo_child1   102,foo:device:foo_child1:service:app1,service,app1,up

But this check missing service is also registered, while already known by c8y:

c8y/s/us                       101,foo:device:foo_child1,foo_child1,thin-edge.io-child
c8y/s/us/foo_child1   102,foo:device:foo_child1:service:app1,service,app1,up

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed by eaf5a8f (with a following simplification: 1d3f707)

Copy link
Copy Markdown
Contributor

@albinsuresh albinsuresh left a comment

Choose a reason for hiding this comment

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

LGTM.

Introduce a new function `mqtt_topic::default_topic_schema::parse()`
taking an entity topic id and returning the registration messages
matching the auto-registration behavior.

Using this parse function simplifies the auto-registration logic which has
no more to parse again and again the entity topic id to extract
registration info.

Signed-off-by: Didier Wenzek <didier.wenzek@free.fr>
Signed-off-by: Didier Wenzek <didier.wenzek@free.fr>
Merged via the queue into thin-edge:main with commit 084fa38 Sep 27, 2024
@didier-wenzek didier-wenzek added refactoring Developer value theme:registration Theme: Device registration and device certificate related topics labels Sep 27, 2024
@didier-wenzek didier-wenzek deleted the refactor/default-entity-scheme branch September 27, 2024 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactoring Developer value theme:registration Theme: Device registration and device certificate related topics

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants