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

Proc macro for tedge config #1936

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
375bc6c
POC proc macro for tedge config
jarhodes314 Apr 28, 2023
fb59fda
Make example realistic
jarhodes314 Apr 28, 2023
5e9b80d
Refactor tests and example into appropriate places
jarhodes314 May 2, 2023
f4c67a1
Ensure missing key error contains the field name
jarhodes314 May 2, 2023
1aab677
Store the key regardless of success/failure
jarhodes314 May 2, 2023
771db4c
Replace all or nothing logic in macro with library function
jarhodes314 May 3, 2023
80fe910
Add doc comments and support for read only configurations
jarhodes314 May 3, 2023
ffff8d1
Begin to use new macro in tedge_config
jarhodes314 May 9, 2023
8d59006
Migrate old accessors to new DTOs
jarhodes314 May 9, 2023
c7490e9
Fix test failures in tedge
jarhodes314 May 9, 2023
1868294
Merge remote-tracking branch 'upstream/main' into feat/tedge-config-r…
jarhodes314 May 9, 2023
86af093
Update tedge config set to use the new dto
jarhodes314 May 9, 2023
28dcee3
Migrate `tedge config unset` to new dto
jarhodes314 May 9, 2023
8cd46ad
Fix clippy warning
jarhodes314 May 9, 2023
6471e1f
Migrate `tedge config list` to new dto/reader
jarhodes314 May 9, 2023
98f4a85
Run formatter
jarhodes314 May 9, 2023
6e2e3d0
Actually support renaming
jarhodes314 May 9, 2023
6556d1c
Update references to renamed keys
jarhodes314 May 9, 2023
98e5201
Migrate `tedge cert` to new dto
jarhodes314 May 10, 2023
5b513a0
Fix integration tests and add some tests for backwards compatibility
jarhodes314 May 10, 2023
4696954
Merge remote-tracking branch 'upstream/main' into feat/tedge-config-r…
jarhodes314 May 11, 2023
5d3e4e4
Finish implementing private reader fields and optional paths
jarhodes314 May 11, 2023
81b7193
Support renaming groups
jarhodes314 May 11, 2023
ce77b22
Log only if we actually migrate tedge.toml
jarhodes314 May 11, 2023
b2ef8fa
Add more documentation and tests for the macro, fix clippy errors
jarhodes314 May 11, 2023
3b95375
Add documentation
jarhodes314 May 12, 2023
501b756
Fix unused dependency error
jarhodes314 May 15, 2023
d2063d5
Merge remote-tracking branch 'upstream/main' into feat/tedge-config-r…
jarhodes314 May 15, 2023
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
101 changes: 93 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ci/configure_bridge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ sudo tedge cert show

sudo tedge config set c8y.url "$URL"

sudo tedge config set c8y.root.cert.path /etc/ssl/certs
sudo tedge config set c8y.root_cert_path /etc/ssl/certs

sudo tedge config set az.url "$IOTHUBNAME.azure-devices.net"

sudo tedge config set az.root.cert.path /etc/ssl/certs/Baltimore_CyberTrust_Root.pem
sudo tedge config set az.root_cert_path /etc/ssl/certs/Baltimore_CyberTrust_Root.pem

sudo tedge config list

Expand Down
4 changes: 3 additions & 1 deletion crates/common/tedge_config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ repository = { workspace = true }
[dependencies]
camino = { version = "1.1.4", features = ["serde", "serde1"] }
certificate = { path = "../certificate" }
doku = "0.20.0"
doku = "0.21"
figment = { version = "0.10", features = ["env", "toml"] }
mqtt_channel = { path = "../mqtt_channel" }
once_cell = "1.17"
serde = { version = "1.0", features = ["derive"] }
serde_ignored = "0.1"
strum_macros = { version = "0.24" }
tedge_config_macros = { path = "../tedge_config_macros" }
tedge_utils = { path = "../tedge_utils" }
thiserror = "1.0"
toml = "0.7"
Expand Down
2 changes: 1 addition & 1 deletion crates/common/tedge_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ pub mod tedge_config_cli;
pub use self::tedge_config_cli::config_setting::*;
pub use self::tedge_config_cli::error::*;
pub use self::tedge_config_cli::models::*;
pub use self::tedge_config_cli::new;
pub use self::tedge_config_cli::settings::*;
pub use self::tedge_config_cli::tedge_config::*;
pub use self::tedge_config_cli::tedge_config_defaults::*;
use self::tedge_config_cli::tedge_config_dto::*;
pub use self::tedge_config_cli::tedge_config_location::*;
pub use self::tedge_config_cli::tedge_config_repository::*;
pub use camino::Utf8Path as Path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,7 @@ pub enum ConfigSettingError {

#[error("An error occurred: {msg}")]
Other { msg: &'static str },

#[error(transparent)]
Write(#[from] crate::new::WriteError),
}
61 changes: 50 additions & 11 deletions crates/common/tedge_config/src/tedge_config_cli/figment.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::borrow::Cow;
use std::collections::HashSet;
use std::fmt::Display;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Mutex;

use figment::providers::Format;
use figment::providers::Toml;
use figment::value::Uncased;
use figment::Figment;
use figment::Metadata;
use once_cell::sync::Lazy;
use serde::de::DeserializeOwned;

use crate::TEdgeConfigError;
Expand All @@ -28,10 +32,22 @@ impl ConfigSources for FileOnly {
const INCLUDE_ENVIRONMENT: bool = false;
}

#[derive(Default, Debug, PartialEq, Eq)]
#[must_use]
pub struct UnusedValueWarnings(Vec<String>);

impl UnusedValueWarnings {
pub fn emit(self) {
for warning in self.0 {
tracing::warn!("{warning}");
}
}
}

/// Extract the configuration data from the provided TOML path and `TEDGE_` prefixed environment variables
pub fn extract_data<T: DeserializeOwned, Sources: ConfigSources>(
path: impl AsRef<Path>,
) -> Result<T, TEdgeConfigError> {
) -> Result<(T, UnusedValueWarnings), TEdgeConfigError> {
let env = TEdgeEnv::default();
let figment = Figment::new().merge(Toml::file(path));

Expand All @@ -43,14 +59,18 @@ pub fn extract_data<T: DeserializeOwned, Sources: ConfigSources>(

let data = extract_exact(&figment, &env);

for warning in unused_value_warnings::<T>(&figment, &env)
let warnings = unused_value_warnings::<T>(&figment, &env)
.ok()
.unwrap_or_default()
{
tracing::warn!("{warning}");
.map(UnusedValueWarnings)
.unwrap_or_default();

match data {
Ok(data) => Ok((data, warnings)),
Err(e) => {
warnings.emit();
Err(e)
}
}

data
}

fn unused_value_warnings<T: DeserializeOwned>(
Expand Down Expand Up @@ -172,9 +192,27 @@ impl TEdgeEnv {
}

fn provider(&self) -> figment::providers::Env {
let pattern = self.separator;
figment::providers::Env::prefixed(self.prefix)
.map(move |name| name.as_str().replacen(pattern, ".", 1).into())
static WARNINGS: Lazy<Mutex<HashSet<String>>> = Lazy::new(<_>::default);
figment::providers::Env::prefixed(self.prefix).map(move |name| {
let lowercase_name = name.as_str().to_ascii_lowercase();
Uncased::new(
tracing::subscriber::with_default(
tracing::subscriber::NoSubscriber::default(),
|| lowercase_name.parse::<crate::new::WritableKey>(),
)
.map(|key| key.as_str().to_owned())
.map_err(|err| {
let is_read_only_key = matches!(err, crate::new::ParseKeyError::ReadOnly(_));
if is_read_only_key && !WARNINGS.lock().unwrap().insert(lowercase_name.clone()) {
tracing::error!(
"Failed to configure tedge with environment variable `TEDGE_{name}`: {}",
err.to_string().replace('\n', " ")
)
}
})
.unwrap_or(lowercase_name),
)
})
}
}

Expand Down Expand Up @@ -212,6 +250,7 @@ mod tests {
assert_eq!(
extract_data::<Config, FileAndEnvironment>(&PathBuf::from("tedge.toml"))
.unwrap()
.0
.c8y
.url,
"override.c8y.io"
Expand Down Expand Up @@ -298,7 +337,7 @@ mod tests {
jail.set_env(variable_name, "environment");

let data = extract_data::<Config, FileOnly>("tedge.toml").unwrap();
assert_eq!(data.value, "config");
assert_eq!(data.0.value, "config");
Ok(())
})
}
Expand Down
2 changes: 1 addition & 1 deletion crates/common/tedge_config/src/tedge_config_cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ pub mod error;
pub mod settings;
pub mod tedge_config;
pub mod tedge_config_defaults;
pub mod tedge_config_dto;
pub mod tedge_config_location;
pub mod tedge_config_repository;

mod figment;
pub mod models;
pub mod new;
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;
use url::Host;

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
Expand Down Expand Up @@ -29,6 +31,26 @@ impl TryFrom<String> for ConnectUrl {
}
}

impl FromStr for ConnectUrl {
type Err = InvalidConnectUrl;

fn from_str(input: &str) -> Result<Self, Self::Err> {
ConnectUrl::try_from(input.to_string())
}
}

impl fmt::Display for ConnectUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.input.fmt(f)
}
}

impl doku::Document for ConnectUrl {
fn ty() -> doku::Type {
String::ty()
}
}

impl TryFrom<&str> for ConnectUrl {
type Error = InvalidConnectUrl;

Expand Down
Loading