···6969 serve Start fireup HTTP API server
7070 inspect Inspect the Firecracker MicroVM details
7171 exec Execute a command inside the Firecracker MicroVM
7272+ cp Copy files to/from the Firecracker MicroVM
7273 help Print this message or the help of the given subcommand(s)
73747475Options:
+69
crates/firecracker-up/src/cmd/cp.rs
···11+use anyhow::Error;
22+use owo_colors::OwoColorize;
1344+use crate::{command::run_command_with_stdout_inherit, ssh::get_private_key_path};
55+66+pub async fn cp(from: &str, to: &str) -> Result<(), Error> {
77+ let pool = firecracker_state::create_connection_pool().await?;
88+99+ let vm_name = if from.contains(':') {
1010+ from.split(':').next().unwrap_or("")
1111+ } else if to.contains(':') {
1212+ to.split(':').next().unwrap_or("")
1313+ } else {
1414+ return Err(anyhow::anyhow!(
1515+ "Either source or destination must be in the format <vm_name>:<path>"
1616+ ));
1717+ };
1818+1919+ let vm = firecracker_state::repo::virtual_machine::find(&pool, vm_name).await?;
2020+2121+ if vm.is_none() {
2222+ println!("[-] MicroVM '{}' not found.", vm_name);
2323+ std::process::exit(1);
2424+ }
2525+2626+ if !firecracker_process::vm_is_running(vm_name).await? {
2727+ println!("[-] MicroVM '{}' is not running.", vm_name);
2828+ let start_cmd = format!("fireup start {}", vm_name);
2929+ println!(" Start it with {}", start_cmd.cyan());
3030+ std::process::exit(1);
3131+ }
3232+3333+ let guest_ip = format!("{}.firecracker", vm_name);
3434+ let key_path = get_private_key_path()?;
3535+3636+ let scp_args = if from.contains(':') {
3737+ let remote_path = format!("root@{}:{}", guest_ip, from.splitn(2, ':').nth(1).unwrap());
3838+ vec!["-r", remote_path.as_str(), to]
3939+ .iter()
4040+ .map(|s| s.to_string())
4141+ .collect::<Vec<String>>()
4242+ } else {
4343+ let remote_path = format!("root@{}:{}", guest_ip, to.splitn(2, ':').nth(1).unwrap());
4444+ vec!["-r", from, remote_path.as_str()]
4545+ .iter()
4646+ .map(|s| s.to_string())
4747+ .collect::<Vec<String>>()
4848+ };
4949+5050+ run_command_with_stdout_inherit(
5151+ "scp",
5252+ &[
5353+ "-q",
5454+ "-i",
5555+ &key_path,
5656+ "-o",
5757+ "StrictHostKeyChecking=no",
5858+ "-o",
5959+ "UserKnownHostsFile=/dev/null",
6060+ ]
6161+ .iter()
6262+ .copied()
6363+ .chain(scp_args.iter().map(|s| s.as_str()))
6464+ .collect::<Vec<&str>>()
6565+ .as_slice(),
6666+ false,
6767+ )?;
6868+6969+ Ok(())
7070+}
+2-23
crates/firecracker-up/src/cmd/exec.rs
···11-use anyhow::{anyhow, Context, Error, Result};
11+use anyhow::{Error, Result};
22use firecracker_state::repo;
33use owo_colors::OwoColorize;
44-use std::fs;
5466-use crate::command::run_ssh_command;
55+use crate::{command::run_ssh_command, ssh::get_private_key_path};
7687pub async fn exec(name: &str, args: Vec<String>) -> Result<(), Error> {
98 let pool = firecracker_state::create_connection_pool().await?;
···26252726 Ok(())
2827}
2929-3030-fn get_private_key_path() -> Result<String, Error> {
3131- let home_dir = dirs::home_dir().ok_or_else(|| anyhow!("Failed to get home directory"))?;
3232- let app_dir = format!("{}/.fireup", home_dir.display());
3333- let key_name = glob::glob(format!("{}/id_rsa", app_dir).as_str())
3434- .with_context(|| "Failed to glob ssh key files")?
3535- .last()
3636- .ok_or_else(|| anyhow!("No SSH key file found"))?
3737- .with_context(|| "Failed to get SSH key path")?;
3838- let key_name = fs::canonicalize(&key_name)
3939- .with_context(|| {
4040- format!(
4141- "Failed to resolve absolute path for SSH key: {}",
4242- key_name.display()
4343- )
4444- })?
4545- .display()
4646- .to_string();
4747- Ok(key_name)
4848-}