use std::path::Path;
use k8s_openapi::api::core::v1::{KeyToPath, Secret, Volume as KubeVolume};
use k8s_openapi::ByteString;
use tracing::warn;
use super::*;
pub struct SecretVolume {
vol_name: String,
sec_name: String,
client: kube::Api<Secret>,
items: Vec<KeyToPath>,
mounted_path: Option<PathBuf>,
}
impl SecretVolume {
pub fn new(vol: &KubeVolume, namespace: &str, client: kube::Client) -> anyhow::Result<Self> {
let sec_source = vol.secret.as_ref().ok_or_else(|| {
anyhow::anyhow!("Called a Secret volume constructor with a non-Secret volume")
})?;
Ok(SecretVolume {
vol_name: vol.name.clone(),
sec_name: sec_source
.secret_name
.clone()
.ok_or_else(|| anyhow::anyhow!("Secret volume does not have a name"))?,
client: Api::namespaced(client, namespace),
items: sec_source.items.clone(),
mounted_path: None,
})
}
pub fn get_path(&self) -> Option<&Path> {
self.mounted_path.as_deref()
}
pub async fn mount(&mut self, base_path: impl AsRef<Path>) -> anyhow::Result<()> {
let path = base_path.as_ref().join(&self.vol_name);
tokio::fs::create_dir_all(&path).await?;
self.mount_at(path.clone()).await?;
let mut perms = tokio::fs::metadata(&path).await?.permissions();
perms.set_readonly(true);
tokio::fs::set_permissions(path, perms).await?;
Ok(())
}
pub(crate) async fn mount_at(&mut self, path: PathBuf) -> anyhow::Result<()> {
let secret = self.client.get(&self.sec_name).await?;
let data = secret.data;
let data = data
.into_iter()
.filter_map(
|(key, ByteString(data))| match mount_setting_for(&key, &self.items) {
ItemMount::MountAt(mount_path) => Some((path.join(mount_path), data)),
ItemMount::DoNotMount => None,
},
)
.map(|(file_path, data)| async move { tokio::fs::write(file_path, &data).await });
futures::future::join_all(data)
.await
.into_iter()
.collect::<tokio::io::Result<_>>()?;
self.mounted_path = Some(path);
Ok(())
}
pub async fn unmount(&mut self) -> anyhow::Result<()> {
match self.mounted_path.take() {
Some(p) => {
let mut perms = tokio::fs::metadata(&p).await?.permissions();
perms.set_readonly(false);
tokio::fs::set_permissions(&p, perms).await?;
#[cfg(target_family = "windows")]
tokio::task::spawn_blocking(|| remove_dir_all::remove_dir_all(p)).await??;
#[cfg(target_family = "unix")]
tokio::fs::remove_dir_all(p).await?;
}
None => {
warn!("Attempted to unmount ConfigMap directory that wasn't mounted, this generally shouldn't happen");
}
}
Ok(())
}
}