Skip to content

Commit

Permalink
Add an error counter
Browse files Browse the repository at this point in the history
  • Loading branch information
olix0r committed Jan 5, 2024
1 parent e3ae992 commit 3f4b7ae
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,7 @@ dependencies = [
"linkerd-dns-name",
"linkerd-error",
"linkerd-metrics",
"prometheus-client",
"thiserror",
"tracing",
"url",
Expand Down
8 changes: 5 additions & 3 deletions linkerd/identity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ edition = "2021"
publish = false

[dependencies]
prometheus-client = "0.22"
thiserror = "1"
tracing = "0.1"
url = "2.5.0"

linkerd-dns-name = { path = "../dns/name" }
linkerd-metrics = { path = "../metrics" }
linkerd-error = { path = "../error" }
url = "2.5.0"
thiserror = "1"
tracing = "0.1"
67 changes: 61 additions & 6 deletions linkerd/identity/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct CertMetrics {
refresh_ts: prom::Gauge<f64, AtomicU64>,
expiry_ts: prom::Gauge<f64, AtomicU64>,
refreshes: prom::Counter,
errors: prom::Counter,
}

/// Implements `Credentials`, recording metrics about certificate updates.
Expand All @@ -36,17 +37,38 @@ impl CertMetrics {
refresh_ts.clone(),
);

let refreshes = prom::Counter::default();
#[derive(Clone, Debug, PartialEq, Eq, Hash, prom::encoding::EncodeLabelSet)]
struct RefreshLabelSet {
result: RefreshResult,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, prom::encoding::EncodeLabelValue)]
#[allow(non_camel_case_types)]
enum RefreshResult {
ok,
error,
}
let refreshes_fam = prom::Family::<_, prom::Counter>::default();
registry.register(
"refreshes",
"The total number of times this proxy's mTLS identity certificate has been refreshed by the Identity provider",
refreshes.clone(),
refreshes_fam.clone(),
);
let refreshes = refreshes_fam
.get_or_create(&RefreshLabelSet {
result: RefreshResult::ok,
})
.clone();
let errors = refreshes_fam
.get_or_create(&RefreshLabelSet {
result: RefreshResult::error,
})
.clone();

Self {
refresh_ts,
expiry_ts,
refreshes,
errors,
}
}
}
Expand All @@ -68,7 +90,10 @@ where
key: Vec<u8>,
expiry: SystemTime,
) -> Result<()> {
self.inner.set_certificate(leaf, chain, key, expiry)?;
if let Err(err) = self.inner.set_certificate(leaf, chain, key, expiry) {
self.metrics.errors.inc();
return Err(err);
}

self.metrics.refreshes.inc();

Expand Down Expand Up @@ -98,7 +123,7 @@ mod tests {
use super::*;
use std::{sync::Arc, time::Duration};

struct StubCreds(Arc<AtomicU64>);
struct StubCreds(Arc<AtomicU64>, Result<(), ()>);

impl Credentials for StubCreds {
fn set_certificate(
Expand All @@ -109,7 +134,7 @@ mod tests {
_expiry: SystemTime,
) -> Result<()> {
self.0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Ok(())
self.1.map_err(|()| "boop".into())
}
}

Expand All @@ -119,9 +144,10 @@ mod tests {

let called = Arc::new(AtomicU64::new(0));
let mut with_cert_metrics =
WithCertMetrics::new(metrics.clone(), StubCreds(called.clone()));
WithCertMetrics::new(metrics.clone(), StubCreds(called.clone(), Ok(())));

assert_eq!(with_cert_metrics.metrics.refreshes.get(), 0);
assert_eq!(with_cert_metrics.metrics.errors.get(), 0);
assert_eq!(with_cert_metrics.metrics.refresh_ts.get(), 0.0);
assert_eq!(with_cert_metrics.metrics.expiry_ts.get(), 0.0);

Expand All @@ -134,6 +160,7 @@ mod tests {
.is_ok());

assert_eq!(with_cert_metrics.metrics.refreshes.get(), 1);
assert_eq!(with_cert_metrics.metrics.errors.get(), 0);
assert!(
with_cert_metrics.metrics.refresh_ts.get()
< SystemTime::now()
Expand All @@ -147,4 +174,32 @@ mod tests {
);
assert_eq!(called.load(std::sync::atomic::Ordering::Relaxed), 1);
}

#[test]
fn test_set_certificate_error() {
let metrics = CertMetrics::register(&mut prom::Registry::default());

let called = Arc::new(AtomicU64::new(0));
let mut with_cert_metrics =
WithCertMetrics::new(metrics.clone(), StubCreds(called.clone(), Err(())));

assert_eq!(with_cert_metrics.metrics.refreshes.get(), 0);
assert_eq!(with_cert_metrics.metrics.errors.get(), 0);
assert_eq!(with_cert_metrics.metrics.refresh_ts.get(), 0.0);
assert_eq!(with_cert_metrics.metrics.expiry_ts.get(), 0.0);

let leaf = DerX509(b"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----".to_vec());
let chain = vec![leaf.clone()];
let key = vec![0, 1, 2, 3, 4];
let expiry = SystemTime::now() + Duration::from_secs(60 * 60 * 24); // 1 day from now
assert!(with_cert_metrics
.set_certificate(leaf, chain, key, expiry)
.is_err());

assert_eq!(with_cert_metrics.metrics.refreshes.get(), 0);
assert_eq!(with_cert_metrics.metrics.errors.get(), 1);
assert_eq!(with_cert_metrics.metrics.refresh_ts.get(), 0.0);
assert_eq!(with_cert_metrics.metrics.expiry_ts.get(), 0.0);
assert_eq!(called.load(std::sync::atomic::Ordering::Relaxed), 1);
}
}

0 comments on commit 3f4b7ae

Please sign in to comment.