Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support device profile operation #2920

Merged

Conversation

reubenmiller
Copy link
Contributor

@reubenmiller reubenmiller commented Jun 5, 2024

Proposed changes

An initial proof of concept to demonstrate one way of processing a device profile operations on the tedge /cmd/ topic. This PR can be taken over by someone else to work on Rust implementation.

The current example device profile workflow uses a complex set of actions (to push the limits of this feature), the following highlights the nested workflows which are called through-out the process:

  • device_profile
    • firmware_update
      • restart (device)
      • software_update (to update thin-edge.io components)
    • software_update (install other packages)
    • config_update

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

@albinsuresh albinsuresh self-assigned this Jun 20, 2024
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
Comment on lines +44 to +60
"name": "prod-profile",
"version: "v1"
Copy link
Contributor

Choose a reason for hiding this comment

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

From where are coming these name and version?

I guess from a previous successful device profile update. But what if meantime, some configuration files have been updated?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, the last applied device profile or the device profile with which the device was initially flashed in the factory. If such a factory profile is unavailable, that's when the agent can declare the empty JSON payload.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess from a previous successful device profile update. But what if meantime, some configuration files have been updated?

The question of "has anything changed since applying the device profile" is a tricky one, as I don't think there is one-way here, as there are multiple ways that the device profile state could get "out of sync" (e.g. sending individual firmware/software/config operations, user running manual commands via ssh etc.)

Though I don't think that device profiles are always used to control the whole on-device setup (as this usually leads to have an unwieldy amount of device profiles to manage, especially if a single device only needs 1 extra software package or configuration)

Below are some options (not exhaustive) that thin-edge.io could do:

Option 1: Do nothing

thin-edge.io doesn't do anything, and it is up to the device maintainer to control how the device is managed

Option 2: Flag profile as "dirty" after other operations

We introduce a "dirty" flag to the device profile current state (e.g. in the /twin setting), which is set anytime a single firmware/software/configuration operation is sent after a device profile is applied. The "dirty" flag would work similar to git, where it just indicates that something has changed (but does not say what).

There could also be a possible option made to even disable individual cloud operations, e.g. only accept cloud device profile operations, and reject cloud based firmware/software/configuration operations.

Option 3: Add interface which can be executed to check if the device profile is still

Similar to the sm-plugin "list" command, a device profile handler could be used to indicate whether a device profile is still in the desired state (e.g. has not been affected by individual firmware/software/configuration operations). This would give a lot of control over the user deciding what is correct to do here (which could be nice).

docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
Copy link
Contributor

github-actions bot commented Jul 2, 2024

Robot Results

✅ Passed ❌ Failed ⏭️ Skipped Total Pass % ⏱️ Duration
495 0 2 495 100 1h22m36.179478999s

docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
Copy link
Contributor

@didier-wenzek didier-wenzek left a comment

Choose a reason for hiding this comment

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

I'm not happy with the current proposal, even if I appreciate the intent.

Yes, it would be good to liberate the user from defining the looping logic, but not at the price of a fragile and complicated logic scattered over all the states.

I would address the problem starting from the tests/device_profile.sh script and tests/device_profile.toml workflow. Can the script be built-in, producing the next operation at each invocation? The user would have then only to provide a preparation script that groups and sequences the operations.

docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
Comment on lines 190 to 193
action = "iterator"
on_next = "apply_operation"
on_success = "successful"
on_error = { status = "failed", reason = "Failed to compute the next operation to be executed" }
Copy link
Contributor

Choose a reason for hiding this comment

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

The current proposal is far better but still a bit too adhoc.

  • The iterator action implicitly works on a list named operations yielding operation in turn. Why not iterating over any list yielding the items of this list in turn. For example action = "iterate @next_operation ${.operations}" where the user can choose for the list to iterate over as well as the current item name.
  • Introducing a specific on_next handler makes impossible to substitute a script for iterate action.

Copy link
Contributor

Choose a reason for hiding this comment

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

The iterator action implicitly works on a list named operations yielding operation in turn. Why not iterating over any list yielding the items of this list in turn. For example action = "iterate @next_operation ${.operations}" where the user can choose for the list to iterate over as well as the current item name.

Yeah, I can make this a generic iterator that takes any array as input, with the @next value generated on each iteration.

Introducing a specific on_next handler makes impossible to substitute a script for iterate action.

I didn't fully get that point. If a user overrides this action with a script, then they don't need to use the on_next handle at all, but can use any number of target states using either the on_stdout directive or on_exit.n directives, right? So, I didn't really understand how this special on_next handle exclusive to the iterator action can hinder any overriding possibilities.

Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't really understand how this special on_next handle exclusive to the iterator action can hinder any overriding possibilities.

You are correct, my wording was a bit too strong. This is very specific but doesn't prevent the user using another approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though the idea of reusing the on_exit.n properties is to also reduce the API, so we're not adding yet another property (which is only used in a very specific use-case).

Copy link
Contributor

@gligorisaev gligorisaev left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@didier-wenzek didier-wenzek left a comment

Choose a reason for hiding this comment

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

Approved. Great achievement!

docs/src/references/agent/device-profile.md Outdated Show resolved Hide resolved
Comment on lines 73 to 84
# ... {
# ... "operation": "firmware_update",
# ... "skip": false,
# ... "payload": {
# ... "name": "core-image-tedge-rauc",
# ... "remoteUrl": "https://abc.com/some/firmware/url",
# ... "version": "20240430.1139"
# ... }
# ... },
Copy link
Contributor

Choose a reason for hiding this comment

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

Just realised that I missed the "skipping" logic in the iterator impl. Will do.

This can be done is a follow-up PR.

@albinsuresh albinsuresh added this pull request to the merge queue Aug 20, 2024
Merged via the queue into thin-edge:main with commit 059dd8c Aug 20, 2024
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme:profile Device Profile
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants