Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions crates/common/tedge_config/src/tedge_toml/tedge_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,10 @@ define_tedge_config! {
/// Enable device_profile feature
#[tedge_config(example = "true", default(value = true))]
device_profile: bool,

/// Enable device restart feature
#[tedge_config(example = "true", default(value = true))]
device_restart: bool,
Comment on lines +703 to +705
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'm not sure whether we should use device_restart or just restart. I opted for a more explicit approach given that some time in the future we'll probably have a "service_restart" command.

},

mapper: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ impl FromCloudConfig for C8yMapperSpecificConfig {
config_update: c8y.enable.config_update,
firmware_update: c8y.enable.firmware_update,
device_profile: c8y.enable.device_profile,
device_restart: c8y.enable.device_restart,
},
mqtt_service: MqttServiceConfig {
enabled: c8y.mqtt_service.enabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ pub struct EnableConfig {

/// Enable device_profile feature
pub device_profile: bool,

/// Enable device restart feature
pub device_restart: bool,
}

/// Bridge include configuration
Expand Down
1 change: 1 addition & 0 deletions crates/extensions/c8y_mapper_ext/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ impl C8yMapperConfig {
config_update: c8y_config.cloud_specific.enable.config_update,
firmware_update: c8y_config.cloud_specific.enable.firmware_update,
device_profile: c8y_config.cloud_specific.enable.device_profile,
device_restart: c8y_config.cloud_specific.enable.device_restart,
};
let bridge_config = BridgeConfig {
c8y_prefix: c8y_config.bridge.topic_prefix.clone(),
Expand Down
12 changes: 11 additions & 1 deletion crates/extensions/c8y_mapper_ext/src/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,12 @@ impl CumulocityConverter {

let msgs = match C8yDeviceControlOperation::from_json_object(extras)? {
C8yDeviceControlOperation::Restart(_) => {
self.forward_restart_request(device_xid, cmd_id)?
if self.config.capabilities.device_restart {
self.forward_restart_request(device_xid, cmd_id)?
} else {
warn!("Received a c8y_Restart operation, however, device_restart feature is disabled");
vec![]
}
}
C8yDeviceControlOperation::SoftwareUpdate(request) => {
self.forward_software_request(device_xid, cmd_id, request)
Expand Down Expand Up @@ -1540,6 +1545,11 @@ impl CumulocityConverter {
&mut self,
target: &EntityTopicId,
) -> Result<Vec<MqttMessage>, ConversionError> {
if !self.config.capabilities.device_restart {
warn!("Received restart metadata, however, device restart feature is disabled");
return Ok(vec![]);
}

match self.register_operation(target, "c8y_Restart").await {
Err(_) => {
error!("Fail to register `restart` operation for unknown device: {target}");
Expand Down
2 changes: 2 additions & 0 deletions crates/extensions/c8y_mapper_ext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct Capabilities {
pub config_update: bool,
pub firmware_update: bool,
pub device_profile: bool,
pub device_restart: bool,
}

#[cfg(test)]
Expand All @@ -37,6 +38,7 @@ impl Default for Capabilities {
config_update: true,
firmware_update: true,
device_profile: true,
device_restart: true,
}
}
}
6 changes: 6 additions & 0 deletions crates/extensions/c8y_mapper_ext/src/operations/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ impl OperationHandler {
(AnyEntity, CommandMetadata(OperationType::DeviceProfile)),
]);
}
if capabilities.device_restart {
topics.extend([
(AnyEntity, Command(OperationType::Restart)),
(AnyEntity, CommandMetadata(OperationType::Restart)),
]);
}

topics
}
Expand Down
2 changes: 1 addition & 1 deletion tests/RobotFramework/requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
paho-mqtt~=1.6.1
python-dotenv~=1.0.0
robotframework~=7.0.0
robotframework-c8y @ git+https://github.com/thin-edge/robotframework-c8y.git@0.49.0
robotframework-c8y @ git+https://github.com/thin-edge/robotframework-c8y.git@0.51.0
robotframework-aws @ git+https://github.com/thin-edge/[email protected]
robotframework-debuglibrary~=2.5.0
robotframework-jsonlibrary~=0.5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ tedge-mapper-c8y does not react to local restart operations transitions
topic=te/device/main///cmd/restart/local-2222 payload={"status":"failed"} expected_status=failed c8y_fragment=c8y_Restart
topic=te/device/main///cmd/restart/local-3333 payload={"status":"successful"} expected_status=successful c8y_fragment=c8y_Restart

Supports disabling the Cumulocity c8y_Restart Command
Execute Command tedge config set c8y.enable.device_restart false
Execute Command rm -f /etc/tedge/operations/c8y/c8y_Restart
Comment on lines +36 to +37
Copy link
Contributor

Choose a reason for hiding this comment

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

Does a user need to do both these actions to disable the operation, or is deleting the file just done so we can verify it doesn't reappear after restarting the mapper?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I think the file still needs to be deleted if the tedge-mapper-c8y service has already been started (with the setting on)...though I didn't verify this, so maybe I'm wrong.

Copy link
Contributor Author

@reubenmiller reubenmiller Jan 27, 2026

Choose a reason for hiding this comment

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

I just confirmed that once the c8y_Restart file is created, then the user has to manually remove it as disabling the feature does not affect the supported operations list that is sent to Cumulocity. However the mapper won't react to the operation if it is sent to the cloud.

We could delete the operation if present on startup though. Previously we avoided this as we thought that people might want to customize the operation handler (e.g. create the file themselves), however I don't think anyone is doing this now that we can customize the tedge-agent workflows instead.

The code shows that there is only an "add_operation" function, and nothing to remove an already existing one.

pub async fn add_operation(


Restart Service tedge-mapper-c8y
Service Health Status Should Be Up tedge-mapper-c8y
File Should Not Exist /etc/tedge/operations/c8y/c8y_Restart
Should Not Contain Supported Operations c8y_Restart
${operation}= Cumulocity.Restart Device
Operation Should Be PENDING ${operation} timeout=30

# Cleanup operation for cleaner logs (as pending operations pollute the test report output)
# Note: It does not need to be run under a TearDown hook as this code will only run
# if the operation is not processed, otherwise it would of been processed and thus not need cleaning up
Execute Command tedge mqtt pub c8y/s/us '505,${operation.to_json()["id"]},Cancelled operation'
Operation Should Be FAILED ${operation}


*** Keywords ***
Set Service User
Expand Down