Skip to content

Commit 83b65bd

Browse files
authored
Merge pull request #3362 from Ruadhri17/operation-fragments-fix
fix: c8y operation fragments for firmware/software update and device profile
2 parents 1f4e5d1 + 580e897 commit 83b65bd

File tree

11 files changed

+313
-116
lines changed

11 files changed

+313
-116
lines changed

crates/core/c8y_api/src/json_c8y_deserializer.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use std::collections::HashMap;
66
use tedge_api::commands::SoftwareModuleAction;
77
use tedge_api::commands::SoftwareModuleItem;
88
use tedge_api::commands::SoftwareRequestResponseSoftwareList;
9-
use tedge_api::device_profile::ConfigPayload;
109
use tedge_api::device_profile::FirmwarePayload;
1110
use tedge_api::device_profile::SoftwarePayload;
1211
use tedge_api::mqtt_topics::EntityTopicId;
@@ -440,6 +439,7 @@ pub struct C8yUploadConfigFile {
440439
/// use c8y_api::json_c8y_deserializer::C8yDownloadConfigFile;
441440
///
442441
/// // Example input from c8y
442+
/// // Note: Name property is available only when JSON object is created from the device profile payload
443443
/// // Note: Legacy config download operations will not have the type property
444444
/// let data = r#"
445445
/// {
@@ -453,20 +453,13 @@ pub struct C8yUploadConfigFile {
453453
#[derive(Debug, Deserialize, Eq, PartialEq)]
454454
#[serde(rename_all = "camelCase")]
455455
pub struct C8yDownloadConfigFile {
456+
#[serde(default = "Default::default")]
457+
pub name: String,
456458
#[serde(rename = "type", default = "default_config_type")]
457459
pub config_type: String,
458460
pub url: String,
459461
}
460462

461-
impl From<C8yDownloadConfigFile> for ConfigPayload {
462-
fn from(value: C8yDownloadConfigFile) -> Self {
463-
ConfigPayload {
464-
config_type: value.config_type,
465-
remote_url: Some(value.url),
466-
}
467-
}
468-
}
469-
470463
/// Representation of c8y_Firmware JSON object
471464
///
472465
/// ```rust
@@ -593,6 +586,7 @@ mod tests {
593586
use crate::json_c8y_deserializer::C8ySoftwareUpdateModule;
594587
use assert_json_diff::assert_json_eq;
595588
use serde_json::json;
589+
use tedge_api::device_profile::ConfigPayload;
596590
use tedge_api::device_profile::DeviceProfileCmdPayload;
597591
use tedge_api::mqtt_topics::EntityTopicId;
598592
use tedge_api::CommandStatus;
@@ -1012,7 +1006,12 @@ mod tests {
10121006
.expect("failed to extract software info"),
10131007
);
10141008
for config in req.configuration {
1015-
thin_edge_json.add_config(config.into());
1009+
thin_edge_json.add_config(ConfigPayload {
1010+
name: config.name,
1011+
config_type: config.config_type,
1012+
remote_url: Some(config.url.clone()),
1013+
server_url: Some(config.url),
1014+
});
10161015
}
10171016
let expected_thin_edge_json = json!({
10181017
"status": "init",
@@ -1054,8 +1053,10 @@ mod tests {
10541053
"operation": "config_update",
10551054
"skip": false,
10561055
"payload": {
1056+
"name": "collectd-v2",
10571057
"type": "collectd.conf",
1058-
"remoteUrl": "http://www.example.url/inventory/binaries/88395"
1058+
"remoteUrl": "http://www.example.url/inventory/binaries/88395",
1059+
"serverUrl": "http://www.example.url/inventory/binaries/88395"
10591060
}
10601061
}
10611062
]

crates/core/c8y_api/src/smartrest/inventory.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use tedge_config::TopicPrefix;
1717

1818
use super::message_ids::CHILD_DEVICE_CREATION;
1919
use super::message_ids::SERVICE_CREATION;
20+
use super::message_ids::SET_CURRENTLY_INSTALLED_CONFIGURATION;
2021
use super::message_ids::SET_DEVICE_PROFILE_THAT_IS_BEING_APPLIED;
2122
use super::message_ids::SET_REQUIRED_AVAILABILITY;
2223
use super::payload::SmartrestPayload;
@@ -134,6 +135,20 @@ pub fn service_creation_message_payload(
134135
Ok(payload)
135136
}
136137

138+
pub fn set_c8y_config_fragment(
139+
config_type: &str,
140+
remote_url: &str,
141+
name: Option<&str>,
142+
) -> SmartrestPayload {
143+
SmartrestPayload::serialize((
144+
SET_CURRENTLY_INSTALLED_CONFIGURATION,
145+
config_type,
146+
remote_url,
147+
name,
148+
))
149+
.expect("shouldn't put payload over size limit")
150+
}
151+
137152
/// Create a SmartREST message to set a response interval for c8y_RequiredAvailability.
138153
///
139154
/// In the SmartREST 117 message, the interval must be in MINUTES, and can be <=0,

crates/core/tedge_api/src/commands.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,7 @@ pub struct ConfigUpdateCmdPayload {
877877
#[serde(skip_serializing_if = "Option::is_none")]
878878
pub tedge_url: Option<String>,
879879
pub remote_url: String,
880+
pub server_url: String,
880881
#[serde(rename = "type")]
881882
pub config_type: String,
882883
#[serde(skip_serializing_if = "Option::is_none")]

crates/core/tedge_api/src/device_profile.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,19 @@ impl CommandPayload for DeviceProfileCmdPayload {
3939
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)]
4040
#[serde(rename_all = "camelCase")]
4141
pub struct DeviceProfileOperation {
42-
operation: OperationType,
43-
skip: bool,
4442
#[serde(flatten)]
45-
payload: OperationPayload,
43+
pub operation: OperationPayload,
44+
pub skip: bool,
4645
}
4746

4847
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
49-
#[serde(rename_all = "camelCase")]
48+
#[serde(tag = "operation", content = "payload")]
5049
pub enum OperationPayload {
51-
#[serde(rename = "payload")]
50+
#[serde(rename = "firmware_update")]
5251
Firmware(FirmwarePayload),
53-
#[serde(rename = "payload")]
52+
#[serde(rename = "software_update")]
5453
Software(SoftwarePayload),
55-
#[serde(rename = "payload")]
54+
#[serde(rename = "config_update")]
5655
Config(ConfigPayload),
5756
}
5857

@@ -64,6 +63,8 @@ pub struct FirmwarePayload {
6463
pub remote_url: Option<String>,
6564
}
6665

66+
impl Jsonify for FirmwarePayload {}
67+
6768
#[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)]
6869
#[serde(rename_all = "camelCase")]
6970
pub struct SoftwarePayload {
@@ -73,37 +74,36 @@ pub struct SoftwarePayload {
7374
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)]
7475
#[serde(rename_all = "camelCase")]
7576
pub struct ConfigPayload {
77+
pub name: String,
7678
#[serde(rename = "type")]
7779
pub config_type: String,
7880
pub remote_url: Option<String>,
81+
pub server_url: Option<String>,
7982
}
8083

8184
impl DeviceProfileCmdPayload {
8285
pub fn add_firmware(&mut self, firmware: FirmwarePayload) {
8386
let firmware_operation = DeviceProfileOperation {
84-
operation: OperationType::FirmwareUpdate,
87+
operation: OperationPayload::Firmware(firmware),
8588
skip: false,
86-
payload: OperationPayload::Firmware(firmware),
8789
};
8890

8991
self.operations.push(firmware_operation);
9092
}
9193

9294
pub fn add_software(&mut self, software: SoftwarePayload) {
9395
let software_operation = DeviceProfileOperation {
94-
operation: OperationType::SoftwareUpdate,
96+
operation: OperationPayload::Software(software),
9597
skip: false,
96-
payload: OperationPayload::Software(software),
9798
};
9899

99100
self.operations.push(software_operation);
100101
}
101102

102103
pub fn add_config(&mut self, config: ConfigPayload) {
103104
let config_operation = DeviceProfileOperation {
104-
operation: OperationType::ConfigUpdate,
105+
operation: OperationPayload::Config(config),
105106
skip: false,
106-
payload: OperationPayload::Config(config),
107107
};
108108

109109
self.operations.push(config_operation);

crates/extensions/c8y_mapper_ext/src/operations/convert.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use tedge_api::commands::ConfigUpdateCmdPayload;
1717
use tedge_api::commands::FirmwareUpdateCmdPayload;
1818
use tedge_api::commands::LogMetadata;
1919
use tedge_api::commands::LogUploadCmdPayload;
20+
use tedge_api::device_profile::ConfigPayload;
2021
use tedge_api::device_profile::DeviceProfileCmdPayload;
2122
use tedge_api::entity::EntityExternalId;
2223
use tedge_api::mqtt_topics::Channel;
@@ -288,6 +289,7 @@ impl CumulocityConverter {
288289
status: CommandStatus::Init,
289290
tedge_url: None,
290291
remote_url,
292+
server_url: config_download_request.url.clone(),
291293
config_type: config_download_request.config_type.clone(),
292294
path: None,
293295
log_path: None,
@@ -368,11 +370,21 @@ impl CumulocityConverter {
368370
request.add_software(software.try_into()?);
369371
}
370372

371-
for mut config in device_profile_request.configuration {
372-
if let Ok(cumulocity_url) = self.http_proxy.local_proxy_url(&config.url) {
373-
config.url = cumulocity_url.into();
374-
}
375-
request.add_config(config.into());
373+
for config in device_profile_request.configuration {
374+
let remote_url = if let Ok(c8y_url) = self.http_proxy.local_proxy_url(&config.url) {
375+
c8y_url.to_string()
376+
} else {
377+
config.url.clone()
378+
};
379+
380+
let config = ConfigPayload {
381+
name: config.name,
382+
config_type: config.config_type,
383+
remote_url: Some(remote_url),
384+
server_url: Some(config.url),
385+
};
386+
387+
request.add_config(config);
376388
}
377389

378390
// Command messages must be retained

crates/extensions/c8y_mapper_ext/src/operations/handlers/config_update.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::Context;
2+
use c8y_api::smartrest::inventory::set_c8y_config_fragment;
23
use c8y_api::smartrest::smartrest_serializer::CumulocitySupportedOperations;
34
use tedge_api::commands::CommandStatus;
45
use tedge_api::commands::ConfigUpdateCmd;
@@ -47,14 +48,23 @@ impl OperationContext {
4748
extra_messages: vec![],
4849
}),
4950
CommandStatus::Successful => {
51+
let config_fragment = MqttMessage::new(
52+
sm_topic,
53+
set_c8y_config_fragment(
54+
&command.payload.config_type,
55+
&command.payload.server_url,
56+
None, // Config update payload is not provided with name field
57+
),
58+
);
59+
5060
let smartrest_operation_status = self.get_smartrest_successful_status_payload(
5161
CumulocitySupportedOperations::C8yDownloadConfigFile,
5262
cmd_id,
5363
);
5464
let c8y_notification = MqttMessage::new(sm_topic, smartrest_operation_status);
5565

5666
Ok(OperationOutcome::Finished {
57-
messages: vec![c8y_notification],
67+
messages: vec![config_fragment, c8y_notification],
5868
})
5969
}
6070
CommandStatus::Failed { reason } => Err(anyhow::anyhow!(reason).into()),
@@ -196,6 +206,7 @@ mod tests {
196206
"status": "executing",
197207
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/test-device/config_update/typeA-c8y-mapper-1234",
198208
"remoteUrl": "http://www.my.url",
209+
"serverUrl": "http://www.my.url",
199210
"type": "typeA",
200211
})
201212
.to_string(),
@@ -213,6 +224,7 @@ mod tests {
213224
"status": "failed",
214225
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/test-device/config_update/typeA-c8y-mapper-1234",
215226
"remoteUrl": "http://www.my.url",
227+
"serverUrl": "http://www.my.url",
216228
"type": "typeA",
217229
"reason": "Something went wrong"
218230
})
@@ -258,6 +270,7 @@ mod tests {
258270
"status": "executing",
259271
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/child1/config_update/typeA-c8y-mapper-1234",
260272
"remoteUrl": "http://www.my.url",
273+
"serverUrl": "http://www.my.url",
261274
"type": "typeA",
262275
})
263276
.to_string(),
@@ -279,6 +292,7 @@ mod tests {
279292
"status": "failed",
280293
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/child1/config_update/typeA-c8y-mapper-1234",
281294
"remoteUrl": "http://www.my.url",
295+
"serverUrl": "http://www.my.url",
282296
"type": "typeA",
283297
"reason": "Something went wrong"
284298
})
@@ -318,6 +332,7 @@ mod tests {
318332
"status": "executing",
319333
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/test-device/config_update/typeA-c8y-mapper-1234",
320334
"remoteUrl": "http://www.my.url",
335+
"serverUrl": "http://www.my.url",
321336
"type": "typeA",
322337
})
323338
.to_string(),
@@ -335,6 +350,7 @@ mod tests {
335350
"status": "failed",
336351
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/test-device/config_update/typeA-c8y-mapper-1234",
337352
"remoteUrl": "http://www.my.url",
353+
"serverUrl": "http://www.my.url",
338354
"type": "typeA",
339355
"reason": "Something went wrong"
340356
})
@@ -364,13 +380,21 @@ mod tests {
364380
"status": "successful",
365381
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/test-device/config_update/path:type:A-c8y-mapper-1234",
366382
"remoteUrl": "http://www.my.url",
383+
"serverUrl": "http://www.my.url",
367384
"type": "path/type/A",
368385
})
369386
.to_string(),
370387
))
371388
.await
372389
.expect("Send failed");
373390

391+
// Expect `120` smartrest message on `c8y/s/us`.
392+
assert_received_contains_str(
393+
&mut mqtt,
394+
[("c8y/s/us", "120,path/type/A,http://www.my.url")],
395+
)
396+
.await;
397+
374398
// Expect `503` smartrest message on `c8y/s/us`.
375399
assert_received_contains_str(&mut mqtt, [("c8y/s/us", "503,c8y_DownloadConfigFile")]).await;
376400
}
@@ -401,13 +425,21 @@ mod tests {
401425
"status": "successful",
402426
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/child1/config_update/typeA-c8y-mapper-1234",
403427
"remoteUrl": "http://www.my.url",
428+
"serverUrl": "http://www.my.url",
404429
"type": "typeA",
405430
})
406431
.to_string(),
407432
))
408433
.await
409434
.expect("Send failed");
410435

436+
// Expect `120` smartrest message on `c8y/s/us`.
437+
assert_received_contains_str(
438+
&mut mqtt,
439+
[("c8y/s/us/child1", "120,typeA,http://www.my.url")],
440+
)
441+
.await;
442+
411443
// Expect `503` smartrest message on child topic.
412444
assert_received_contains_str(
413445
&mut mqtt,
@@ -436,13 +468,21 @@ mod tests {
436468
"status": "successful",
437469
"tedgeUrl": "http://localhost:8888/tedge/file-transfer/test-device/config_update/path:type:A-c8y-mapper-1234",
438470
"remoteUrl": "http://www.my.url",
471+
"serverUrl": "http://www.my.url",
439472
"type": "path/type/A",
440473
})
441474
.to_string(),
442475
))
443476
.await
444477
.expect("Send failed");
445478

479+
// Expect `120` smartrest message on `c8y/s/us`.
480+
assert_received_contains_str(
481+
&mut mqtt,
482+
[("c8y/s/us", "120,path/type/A,http://www.my.url")],
483+
)
484+
.await;
485+
446486
// Expect `503` smartrest message on `c8y/s/us`.
447487
assert_received_contains_str(&mut mqtt, [("c8y/s/us", "506,1234")]).await;
448488
}

0 commit comments

Comments
 (0)