fix: minor fixes, bring LLM for reviewing as a test

This commit is contained in:
spushk 2026-05-16 18:36:41 +05:00 • committed by spushk
commit e15bb3bbc6
Signed by: spushk
GPG key ID: 7797B761E105E8AA
7 changed files with 264 additions and 43 deletions

View file

@ -37,6 +37,7 @@ pub fn str_bytes<G: CryptoRng>(
) -> Result<Vec<u8>, GeneratorErr> {
let mut buf = String::with_capacity(length);
// TODO: unique may leak dictionary..?
let dictionary = Zeroizing::new(dictionary.unique().collect::<Vec<char>>());
let distribution = rand::distr::slice::Choose::new(&dictionary).map_err(|_| GeneratorErr::EmptyDistribution)?;
@ -69,12 +70,12 @@ pub fn str_bytes<G: CryptoRng>(
}
if buf.len() != length {
Err(GeneratorErr::RngStuck {
return Err(GeneratorErr::RngStuck {
reason: format!("Unable to sample {length} characters"),
})
} else {
Ok(buf.into_bytes())
});
}
Ok(buf.into_bytes())
}
/// Generate SSH keypair, encoded for OpenSSH

View file

@ -25,7 +25,7 @@ impl K8sEventRecorder {
.recorder
.publish(&event.event, &event.object)
.await
.inspect_err(|e| tracing::error!(no_event=true, error=?e, "Failed to record K8s event"));
.inspect_err(|e| tracing::error!(k8s_no_event=true, error=?e, "Failed to record K8s event"));
}
}

View file

@ -126,7 +126,7 @@ fn init_k8s_events(client: kube::Client, joinset: &mut JoinSet<()>, ct: Cancella
}
queue.push_back(ev);
if queue.len() > WARN_THRESHOLD && !warned {
tracing::warn!(no_event=true, queue_len=queue.len(), "K8s event queue exceeded threshold");
tracing::warn!(k8s_no_event=true, queue_len=queue.len(), "K8s event queue exceeded threshold");
warned = true;
} else if queue.len() <= WARN_THRESHOLD {
warned = false;
@ -135,7 +135,7 @@ fn init_k8s_events(client: kube::Client, joinset: &mut JoinSet<()>, ct: Cancella
rec_limit = 4;
}
Err(e) => {
tracing::error!(no_event=true, debug=?e, "Failed to receive k8s event from tracing");
tracing::error!(k8s_no_event=true, debug=?e, "Failed to receive k8s event from tracing");
rx = rtx.subscribe(); // dumb recover strategy
tokio::time::sleep(Duration::from_secs(3)).await;
rec_limit -= 1;
@ -180,7 +180,7 @@ fn init_pro_metrics(joinset: &mut JoinSet<()>, ct: CancellationToken) -> Sender<
rec_limit = 4;
}
Err(e) => {
tracing::error!(no_pro=true, debug=?e, "Failed to receive prometheus measurement from tracing");
tracing::error!(k8s_no_pro=true, debug=?e, "Failed to receive prometheus measurement from tracing");
rx = rtx.subscribe(); // dumb recover strategy;
tokio::time::sleep(Duration::from_secs(3)).await;
rec_limit -= 1;
@ -205,11 +205,11 @@ fn init_pro_metrics(joinset: &mut JoinSet<()>, ct: CancellationToken) -> Sender<
metrics.register(&mut registry);
},
_ = registration_cancellation.cancelled() => {
tracing::warn!(no_pro=true, "Stopped publishing prometheus metrics: consumer job cancelled");
tracing::warn!(k8s_no_pro=true, "Stopped publishing prometheus metrics: consumer job cancelled");
break;
}
_ = ctk.cancelled() => {
tracing::warn!(no_pro=true, "Stopped publishing prometheus metrics: shutdown");
tracing::warn!(k8s_no_pro=true, "Stopped publishing prometheus metrics: shutdown");
break;
}
}
@ -251,7 +251,7 @@ fn init_otel(joinset: &mut JoinSet<()>, ct: CancellationToken) -> anyhow::Result
}
Err(e) => {
tracing::error!(
no_otel = true,
k8s_no_otel = true,
debug = ?e,
"Failed to receive otel observation from tracing"
);
@ -263,7 +263,7 @@ fn init_otel(joinset: &mut JoinSet<()>, ct: CancellationToken) -> anyhow::Result
}
}
}
tracing::error!(no_otel = true, "OpenTelemetry reporting from tracing stopped");
tracing::error!(k8s_no_otel = true, "OpenTelemetry reporting from tracing stopped");
});
Ok(tx)

View file

@ -47,6 +47,7 @@ impl ProMetrics {
}
/// Start measuring reconcile duration. Registers on `TimedMeasurer` drop
// TODO: use this
pub fn measure_reconcilation(&self) -> TimedMeasurer {
self.reconcile_metrics.measure()
}

View file

@ -302,9 +302,9 @@ impl Visit for SpanFields {
fn record_bool(&mut self, field: &tracing::field::Field, value: bool) {
match field.name() {
"no_event" => self.no_event = Some(value),
"no_pro" => self.no_pro = Some(value),
"no_otel" => self.no_otel = Some(value),
"k8s_no_event" => self.no_event = Some(value),
"k8s_no_pro" => self.no_pro = Some(value),
"k8s_no_otel" => self.no_otel = Some(value),
_ => {}
}
}
@ -361,9 +361,9 @@ impl Visit for EventFields {
fn record_bool(&mut self, field: &tracing::field::Field, value: bool) {
match field.name() {
"critical" => self.critical = Some(value),
"no_event" => self.no_event = Some(value),
"no_pro" => self.no_pro = Some(value),
"no_otel" => self.no_otel = Some(value),
"k8s_no_event" => self.no_event = Some(value),
"k8s_no_pro" => self.no_pro = Some(value),
"k8s_no_otel" => self.no_otel = Some(value),
_ => {}
}
}

View file

@ -52,12 +52,7 @@ impl GeneratedSecretStatus {
return false;
};
(stored.0 == spec.version)
&& aws_lc_rs::constant_time::verify_slices_are_equal(
stored.1.as_bytes(),
spec.shape.stable_hash().as_bytes(),
)
.is_ok()
(stored.0 == spec.version) && (stored.1 == spec.shape.stable_hash())
}
}
@ -68,7 +63,13 @@ impl GeneratedSecretSpec {
/// This method family assumes that upstream resource has `GeneratedSecretStatus` status.
///
/// I wrote this because - hell no - I won't write this code twice for both Random and Deterministic secrets!
async fn reconcile_spec<T>(&self, name: &str, namespace: &str, client: kube::Client) -> anyhow::Result<()>
async fn reconcile_spec<T>(
&self,
name: &str,
namespace: &str,
client: kube::Client,
uid: Option<&str>,
) -> anyhow::Result<()>
where
T: HasSecretGenerator
+ Resource<DynamicType = (), Scope = k8s_openapi::NamespaceResourceScope>
@ -103,20 +104,28 @@ impl GeneratedSecretSpec {
.await
.context("Update existing Secret")?,
None => self
.create_new_from_spec::<T>(name, namespace, client)
.create_new_from_spec::<T>(name, namespace, client, uid)
.await
.context("Update existing Secret")?,
.context("Create new Secret")?,
}
Ok(())
}
async fn create_new_from_spec<T>(&self, name: &str, namespace: &str, client: kube::Client) -> anyhow::Result<()>
async fn create_new_from_spec<T>(
&self,
name: &str,
namespace: &str,
client: kube::Client,
uid: Option<&str>,
) -> anyhow::Result<()>
where
T: HasSecretGenerator
+ Resource<DynamicType = (), Scope = k8s_openapi::NamespaceResourceScope>
+ DeserializeOwned,
{
use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference;
let self_api = Api::<T>::namespaced(client.clone(), namespace);
let target_api = Api::<k8s_openapi::api::core::v1::Secret>::namespaced(client.clone(), namespace);
@ -127,7 +136,19 @@ impl GeneratedSecretSpec {
.collect::<BTreeMap<_, _>>();
// first we try with dry-run, no need to guard as no data here
let partial_target = self.template.to_safe_partial_secret(Some(false), Some("Opaque".into()));
let owner_ref = uid.map(|uid| OwnerReference {
api_version: T::api_version(&()).to_string(),
kind: T::kind(&()).to_string(),
name: name.to_string(),
uid: uid.to_string(),
controller: Some(true),
..Default::default()
});
let partial_target = {
let mut secret = self.template.to_safe_partial_secret(Some(false), Some("Opaque".into()));
secret.metadata.owner_references = owner_ref.as_ref().map(|oref| vec![oref.clone()]);
secret
};
let patch = kube::api::Patch::Apply(json!({
"apiVersion": T::api_version(&()),
"kind": T::kind(&()),
@ -201,8 +222,7 @@ impl GeneratedSecretSpec {
})
.context("Create Secret")?;
// TODO: delete created secret if this fails or not..?
self_api
if let Err(e) = self_api
.patch_status(
name,
&kube::api::PatchParams {
@ -213,8 +233,18 @@ impl GeneratedSecretSpec {
},
&patch,
)
.await.inspect_err(|e| tracing::error!(debug=?e, reason="SelfUpdateFailed", action = "CreateNew", "Failed to update self status"))
.context("Update status")?;
.await
.inspect_err(|e| tracing::error!(debug=?e, reason="SelfUpdateFailed", action = "CreateNew", "Failed to update self status"))
.context("Update status")
{
tracing::error!(
reason = "SecretOrphanCleanup",
action = "CreateNew",
"Deleting orphan secret after failed status update"
);
target_api.delete(name, &kube::api::DeleteParams::default()).await.context("Orphan secret on fail")?;
return Err(e);
}
}
Ok(())
@ -344,9 +374,11 @@ impl GeneratedSecretShape {
let mut hasher = blake3::Hasher::new();
match self {
Self::Bytes { size } => {
hasher.update(b"bytes");
hasher.update(&size.to_le_bytes());
}
Self::Password { length, dictionary } => {
hasher.update(b"password");
hasher.update(&length.to_le_bytes());
hasher.update(dictionary.as_bytes());
}

View file

@ -58,8 +58,14 @@ impl RandomSecret {
let kind = Self::kind(&());
let api = Self::api_version(&());
let name = &self.name_any();
let _span_nons =
tracing::info_span!("RandomSecret.reconcile", kind = kind.as_ref(), api = api.as_ref(), name).entered();
let _span_nons = tracing::info_span!(
"RandomSecret.reconcile",
k8s_kind = kind.as_ref(),
k8s_api = api.as_ref(),
k8s_name = name,
k8s_uid = self.uid(),
)
.entered();
let Some(namespace) = self.namespace() else {
tracing::error!(
@ -69,10 +75,11 @@ impl RandomSecret {
);
return Err(anyhow::Error::msg("RandomSecret needed namespace"));
};
let _span = tracing::info_span!("RandomSecret.reconcile.ns", ns = namespace).entered();
let _span = tracing::info_span!("RandomSecret.reconcile.ns", k8s_ns = namespace).entered();
self.spec.0.reconcile_spec::<Self>(name, &namespace, client).await.inspect_err(|e| tracing::error!(debug=?e, reason="RandomSecretReconcilationFailed", action = "Reconcile", "Failed to reconcile RandomSecret {namespace}{name}")).context("Reconcile")?;
self.spec.0.reconcile_spec::<Self>(name, &namespace, client, self.uid().as_deref()).await.inspect_err(|e| tracing::error!(debug=?e, reason="RandomSecretReconciliationFailed", action = "Reconcile", "Failed to reconcile RandomSecret {namespace}{name}")).context("Reconcile")?;
// TODO: verify if all desired events fire
Ok(Action::await_change())
}
}
@ -130,9 +137,10 @@ impl DeterministicSecret {
let name = &self.name_any();
let _span_nons = tracing::info_span!(
"DeterministicSecret.reconcile",
kind = kind.as_ref(),
api = api.as_ref(),
name
k8s_kind = kind.as_ref(),
k8s_api = api.as_ref(),
k8s_name = name,
k8s_uid = self.uid(),
)
.entered();
@ -144,17 +152,18 @@ impl DeterministicSecret {
);
return Err(anyhow::Error::msg("DeterministicSecret needed namespace"));
};
let _span = tracing::info_span!("DeterministicSecret.reconcile.ns", ns = namespace).entered();
let _span = tracing::info_span!("DeterministicSecret.reconcile.ns", k8s_ns = namespace).entered();
self.spec.0.reconcile_spec::<Self>(name, &namespace, client).await.inspect_err(|e| tracing::error!(debug=?e, reason="DeterministicSecretReconcilationFailed", action = "Reconcile", "Failed to reconcile DeterministicSecret {namespace}{name}")).context("Reconcile")?;
self.spec.0.reconcile_spec::<Self>(name, &namespace, client, self.uid().as_deref()).await.inspect_err(|e| tracing::error!(debug=?e, reason="DeterministicSecretReconciliationFailed", action = "Reconcile", "Failed to reconcile DeterministicSecret {namespace}{name}")).context("Reconcile")?;
// TODO: verify if all desired events fire
Ok(Action::await_change())
}
}
impl HasSecretGenerator for DeterministicSecret {
fn generate_data(spec: &GeneratedSecretSpec) -> anyhow::Result<BTreeMap<String, ByteString>> {
let seed = std::env::var("KUYASEG_SEED").inspect_err(|e| tracing::error!(debug=?e, reason="DeterministicSecretNeedSeed", "Refuse to generate deterministic secret without seet. Set with KUYASEG_SEED env")).context("Get external seed")?;
let seed = std::env::var("KUYASEG_SEED").inspect_err(|e| tracing::error!(debug=?e, reason="DeterministicSecretNeedSeed", "Refuse to generate deterministic secret without seed. Set with KUYASEG_SEED env")).context("Get external seed")?;
let mut data = BTreeMap::new();
for key in spec.keys.iter() {