Skip to content

Commit 74947b0

Browse files
authored
Merge pull request #3326 from rina23q/feature/3242/writable-device-id-3
feat: support read-write device.id in tedge cert/connect
2 parents e44a0ff + 2f61a0a commit 74947b0

File tree

26 files changed

+1486
-234
lines changed

26 files changed

+1486
-234
lines changed

Cargo.lock

Lines changed: 12 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,8 @@ define_tedge_config! {
154154
device: {
155155
/// Identifier of the device within the fleet. It must be globally
156156
/// unique and is derived from the device certificate.
157-
#[tedge_config(readonly(
158-
write_error = "\
159-
The device id is read from the device certificate and cannot be set directly.\n\
160-
To set 'device.id' to some <id>, you can use `tedge cert create --device-id <id>`.",
161-
function = "device_id",
162-
))]
157+
#[tedge_config(reader(function = "device_id", private))]
163158
#[tedge_config(example = "Raspberrypi-4d18303a-6d3a-11eb-b1a6-175f6bb72665")]
164-
#[tedge_config(note = "This setting is derived from the device certificate and is therefore read only.")]
165-
#[tedge_config(reader(private))]
166159
#[doku(as = "String")]
167160
id: Result<String, ReadError>,
168161

@@ -215,14 +208,9 @@ define_tedge_config! {
215208
device: {
216209
/// Identifier of the device within the fleet. It must be globally
217210
/// unique and is derived from the device certificate.
218-
#[tedge_config(readonly(
219-
write_error = "\
220-
The device id is read from the device certificate and cannot be set directly.\n\
221-
To set 'device.id' to some <id>, you can use `tedge cert create --device-id <id>`.",
222-
function = "c8y_device_id",
223-
))]
211+
#[tedge_config(reader(function = "c8y_device_id"))]
212+
#[tedge_config(default(from_optional_key = "device.id"))]
224213
#[tedge_config(example = "Raspberrypi-4d18303a-6d3a-11eb-b1a6-175f6bb72665")]
225-
#[tedge_config(note = "This setting is derived from the device certificate and is therefore read only.")]
226214
#[doku(as = "String")]
227215
id: Result<String, ReadError>,
228216

@@ -411,14 +399,9 @@ define_tedge_config! {
411399
device: {
412400
/// Identifier of the device within the fleet. It must be globally
413401
/// unique and is derived from the device certificate.
414-
#[tedge_config(readonly(
415-
write_error = "\
416-
The device id is read from the device certificate and cannot be set directly.\n\
417-
To set 'device.id' to some <id>, you can use `tedge cert create --device-id <id>`.",
418-
function = "az_device_id",
419-
))]
402+
#[tedge_config(reader(function = "az_device_id"))]
403+
#[tedge_config(default(from_optional_key = "device.id"))]
420404
#[tedge_config(example = "Raspberrypi-4d18303a-6d3a-11eb-b1a6-175f6bb72665")]
421-
#[tedge_config(note = "This setting is derived from the device certificate and is therefore read only.")]
422405
#[doku(as = "String")]
423406
id: Result<String, ReadError>,
424407

@@ -481,14 +464,9 @@ define_tedge_config! {
481464
device: {
482465
/// Identifier of the device within the fleet. It must be globally
483466
/// unique and is derived from the device certificate.
484-
#[tedge_config(readonly(
485-
write_error = "\
486-
The device id is read from the device certificate and cannot be set directly.\n\
487-
To set 'device.id' to some <id>, you can use `tedge cert create --device-id <id>`.",
488-
function = "aws_device_id",
489-
))]
467+
#[tedge_config(reader(function = "aws_device_id"))]
468+
#[tedge_config(default(from_optional_key = "device.id"))]
490469
#[tedge_config(example = "Raspberrypi-4d18303a-6d3a-11eb-b1a6-175f6bb72665")]
491-
#[tedge_config(note = "This setting is derived from the device certificate and is therefore read only.")]
492470
#[doku(as = "String")]
493471
id: Result<String, ReadError>,
494472

@@ -929,6 +907,15 @@ impl TEdgeConfigReader {
929907
Some(Cloud::Aws(profile)) => &self.aws.try_get(profile)?.device.cert_path,
930908
})
931909
}
910+
911+
pub fn device_id<'a>(&self, cloud: Option<impl Into<Cloud<'a>>>) -> Result<&str, ReadError> {
912+
Ok(match cloud.map(<_>::into) {
913+
None => self.device.id()?,
914+
Some(Cloud::C8y(profile)) => self.c8y.try_get(profile)?.device.id()?,
915+
Some(Cloud::Az(profile)) => self.az.try_get(profile)?.device.id()?,
916+
Some(Cloud::Aws(profile)) => self.aws.try_get(profile)?.device.id()?,
917+
})
918+
}
932919
}
933920

934921
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -1019,27 +1006,77 @@ fn default_http_bind_address(dto: &TEdgeConfigDto) -> IpAddr {
10191006

10201007
fn device_id_from_cert(cert_path: &Utf8Path) -> Result<String, ReadError> {
10211008
let pem = PemCertificate::from_pem_file(cert_path)
1022-
.map_err(|err| cert_error_into_config_error(ReadOnlyKey::DeviceId.to_cow_str(), err))?;
1009+
.map_err(|err| cert_error_into_config_error(ReadableKey::DeviceId.to_cow_str(), err))?;
10231010
let device_id = pem
10241011
.subject_common_name()
1025-
.map_err(|err| cert_error_into_config_error(ReadOnlyKey::DeviceId.to_cow_str(), err))?;
1012+
.map_err(|err| cert_error_into_config_error(ReadableKey::DeviceId.to_cow_str(), err))?;
10261013
Ok(device_id)
10271014
}
10281015

1029-
fn device_id(device: &TEdgeConfigReaderDevice) -> Result<String, ReadError> {
1030-
device_id_from_cert(&device.cert_path)
1016+
fn device_id(
1017+
device: &TEdgeConfigReaderDevice,
1018+
dto_value: &OptionalConfig<String>,
1019+
) -> Result<String, ReadError> {
1020+
match dto_value.or_none() {
1021+
Some(id) => Ok(id.clone()),
1022+
None => device_id_from_cert(&device.cert_path),
1023+
}
10311024
}
10321025

1033-
fn c8y_device_id(device: &TEdgeConfigReaderC8yDevice) -> Result<String, ReadError> {
1034-
device_id_from_cert(&device.cert_path)
1026+
fn c8y_device_id(
1027+
c8y_device: &TEdgeConfigReaderC8yDevice,
1028+
dto_value: &OptionalConfig<String>,
1029+
) -> Result<String, ReadError> {
1030+
match dto_value.or_none() {
1031+
Some(id) => Ok(id.clone()),
1032+
None => device_id_from_cert(&c8y_device.cert_path),
1033+
}
10351034
}
10361035

1037-
fn az_device_id(device: &TEdgeConfigReaderAzDevice) -> Result<String, ReadError> {
1038-
device_id_from_cert(&device.cert_path)
1036+
fn az_device_id(
1037+
az_device: &TEdgeConfigReaderAzDevice,
1038+
dto_value: &OptionalConfig<String>,
1039+
) -> Result<String, ReadError> {
1040+
match dto_value.or_none() {
1041+
Some(id) => Ok(id.clone()),
1042+
None => device_id_from_cert(&az_device.cert_path),
1043+
}
10391044
}
10401045

1041-
fn aws_device_id(device: &TEdgeConfigReaderAwsDevice) -> Result<String, ReadError> {
1042-
device_id_from_cert(&device.cert_path)
1046+
fn aws_device_id(
1047+
aws_device: &TEdgeConfigReaderAwsDevice,
1048+
dto_value: &OptionalConfig<String>,
1049+
) -> Result<String, ReadError> {
1050+
match dto_value.or_none() {
1051+
Some(id) => Ok(id.clone()),
1052+
None => device_id_from_cert(&aws_device.cert_path),
1053+
}
1054+
}
1055+
1056+
pub fn explicit_device_id(
1057+
config_location: &TEdgeConfigLocation,
1058+
cloud: &Option<Cloud>,
1059+
) -> Option<String> {
1060+
let dto = config_location.load_dto_from_toml_and_env().ok()?;
1061+
1062+
match cloud {
1063+
None => dto.device.id.clone(),
1064+
Some(Cloud::C8y(profile)) => {
1065+
let key = profile.map(|name| name.to_string());
1066+
let c8y_dto = dto.c8y.try_get(key.as_deref(), "c8y").ok()?;
1067+
c8y_dto.device.id.clone()
1068+
}
1069+
Some(Cloud::Az(profile)) => {
1070+
let key = profile.map(|name| name.to_string());
1071+
let az_dto = dto.az.try_get(key.as_deref(), "az").ok()?;
1072+
az_dto.device.id.clone()
1073+
}
1074+
Some(Cloud::Aws(profile)) => {
1075+
let key = profile.map(|name| name.to_string());
1076+
let aws_dto = dto.aws.try_get(key.as_deref(), "aws").ok()?;
1077+
aws_dto.device.id.clone()
1078+
}
1079+
}
10431080
}
10441081

10451082
fn cert_error_into_config_error(key: Cow<'static, str>, err: CertificateError) -> ReadError {

crates/common/tedge_config/src/tedge_config_cli/tedge_config_location.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ impl TEdgeConfigLocation {
102102
Ok(TEdgeConfig::from_dto(&dto, self))
103103
}
104104

105+
pub fn load_dto_from_toml_and_env(&self) -> Result<TEdgeConfigDto, TEdgeConfigError> {
106+
self.load_dto::<FileAndEnvironment>(self.toml_path())
107+
}
108+
105109
fn load_dto<Sources: ConfigSources>(
106110
&self,
107111
path: &Utf8Path,

crates/common/tedge_config_macros/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ tracing = { workspace = true }
2222
url = { workspace = true }
2323

2424
[dev-dependencies]
25+
certificate = { workspace = true, features = ["reqwest"] }
2526
clap = { workspace = true }
2627
serde = { workspace = true, features = ["rc"] }
2728
serde_json = { workspace = true }

crates/common/tedge_config_macros/examples/macro.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ define_tedge_config! {
189189
}
190190
}
191191

192-
fn device_id(_reader: &TEdgeConfigReaderDevice) -> Result<String, ReadError> {
192+
fn device_id(_reader: &TEdgeConfigReaderDevice, _: &()) -> Result<String, ReadError> {
193193
Ok("dummy-device-id".to_owned())
194194
}
195195

crates/common/tedge_config_macros/examples/multi.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ fn main() {
111111
keys,
112112
[
113113
"c8y.http",
114-
"c8y.smartrest.use_operation_id",
115-
"c8y.url",
116114
"c8y.profiles.cloud.http",
117115
"c8y.profiles.cloud.smartrest.use_operation_id",
118116
"c8y.profiles.cloud.url",
119117
"c8y.profiles.edge.http",
120118
"c8y.profiles.edge.smartrest.use_operation_id",
121-
"c8y.profiles.edge.url"
119+
"c8y.profiles.edge.url",
120+
"c8y.smartrest.use_operation_id",
121+
"c8y.url",
122122
]
123123
);
124124
}

0 commit comments

Comments
 (0)