git.delta.rocks / jrsonnet / refs/commits / 48f2bca6ca28

difftreelog

feat fleet secret prune command implementation

owzlypyvYaroslav Bolyukin2026-04-18parent: #c4cd98e.patch.diff
in: trunk

1 file changed

modifiedcmds/fleet/src/cmds/secrets.rsdiffbeforeafterboth
1use std::collections::BTreeSet;
1use std::io::{Write as _, stdout};2use std::io::{Write as _, stdout};
23
3use anyhow::{Context as _, Result, anyhow, bail};4use anyhow::{Context as _, Result, anyhow, bail};
34 #[clap(short = 'm', long)]35 #[clap(short = 'm', long)]
35 machine: Vec<String>,36 machine: Vec<String>,
37
38 /// If set - distributions containing the specified machines will be pruned fully
39 #[clap(long)]
40 whole_dist: bool,
36 },41 },
37 /// Ensure secret is generated and not expired42 /// Ensure secret is generated and not expired
38 Ensure {43 Ensure {
159 */164 */
160 todo!()165 todo!()
161 }166 }
162 Secret::Prune { name, machine } => todo!(),167 Secret::Prune {
168 name,
169 machine,
170 whole_dist,
171 } => {
172 let mut secrets = config.data.secrets.write().expect("not poisoned");
173 let Some(dists) = secrets.get_mut(&name) else {
174 bail!("secret {name} not found");
175 };
176 if machine.is_empty() && whole_dist {
177 for dist in dists.distributions_mut() {
178 dist.prune("manual prune".to_owned());
179 }
180 } else if machine.is_empty() {
181 let dist = dists
182 .distributions_mut()
183 .exactly_one()
184 .map_err(|e| anyhow!("{e}"))
185 .context(
186 "with no machine specified, there should be exactly one distribution",
187 )?;
188 dist.prune("manual prune".to_owned());
189 } else if whole_dist {
190 for dist in dists.distributions_mut() {
191 if machine
192 .iter()
193 .any(|m| dist.owners().any(|o| o.as_host() == Some(m.as_str())))
194 {
195 dist.prune(format!(
196 "manual prune of distribution containing {}",
197 machine.join(", ")
198 ));
199 }
200 }
201 } else {
202 let owners: BTreeSet<SecretOwner> =
203 machine.iter().map(SecretOwner::host).collect();
204 for dist in dists.distributions_mut() {
205 dist.prune_owners(&owners, "manual prune".to_owned());
206 }
207 }
208 }
163 Secret::Ensure { name, machine } => todo!(),209 Secret::Ensure { name, machine } => todo!(),
164 }210 }
165 Ok(())211 Ok(())
166 }212 }
167}213}
168
169/*
170async fn edit_temp_file(
171 builder: tempfile::Builder<'_, '_>,
172 r: Vec<u8>,
173 header: &str,
174 comment: &str,
175) -> Result<(Vec<u8>, Option<String>), anyhow::Error> {
176 if !stdin().is_tty() {
177 // TODO: Also try to open /dev/tty directly?
178 bail!("stdin is not tty, can't open editor");
179 }
180
181 use std::fmt::Write;
182 let mut file = builder.tempfile()?;
183
184 let mut full_header = String::new();
185 let mut had = false;
186 for line in header.trim_end().lines() {
187 had = true;
188 writeln!(&mut full_header, "{comment}{line}")?;
189 }
190 if had {
191 writeln!(&mut full_header, "{}", comment.trim_end())?;
192 }
193 writeln!(
194 &mut full_header,
195 "{comment}Do not touch this header! It will be removed automatically"
196 )?;
197
198 file.write_all(full_header.as_bytes())?;
199 file.write_all(&r)?;
200
201 let abs_path = file.into_temp_path();
202 let editor = std::env::var_os("VISUAL")
203 .or_else(|| std::env::var_os("EDITOR"))
204 .unwrap_or_else(|| "vi".into());
205 let editor_args = shlex::bytes::split(editor.as_encoded_bytes())
206 .ok_or_else(|| anyhow!("EDITOR env var has wrong syntax"))?;
207 let editor_args = editor_args
208 .into_iter()
209 .map(|v| {
210 // Only ASCII subsequences are replaced
211 unsafe { OsString::from_encoded_bytes_unchecked(v) }
212 })
213 .collect_vec();
214 let Some((editor, args)) = editor_args.split_first() else {
215 bail!("EDITOR env var has no command");
216 };
217 let mut command = Command::new(editor);
218 command.args(args);
219
220 let path_arg = abs_path.canonicalize()?;
221
222 // TODO: Save full state, using tcget/_getmode/_setmode
223 let was_raw = terminal::is_raw_mode_enabled()?;
224 terminal::enable_raw_mode()?;
225
226 let status = command.arg(path_arg).status().await;
227
228 if !was_raw {
229 terminal::disable_raw_mode()?;
230 }
231
232 let success = match status {
233 Ok(s) => s.success(),
234 Err(e) if e.kind() == io::ErrorKind::NotFound => {
235 bail!("editor not found")
236 }
237 Err(e) => bail!("editor spawn error: {e}"),
238 };
239
240 let mut file = std::fs::read(&abs_path).context("read editor output")?;
241 let Some(v) = file.strip_prefix(full_header.as_bytes()) else {
242 todo!();
243 };
244 todo!();
245
246 // Ok((success, abs_path))
247}
248*/
249214