-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathmain.rs
More file actions
269 lines (240 loc) · 8.73 KB
/
main.rs
File metadata and controls
269 lines (240 loc) · 8.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
//! Bootc Virtualization Kit (bcvk) - A toolkit for bootc containers and local virtualization
use std::ffi::OsString;
use cap_std_ext::cap_std::fs::Dir;
use clap::{Parser, Subcommand};
use color_eyre::{eyre::Context as _, Report, Result};
mod arch;
mod boot_progress;
mod cache_metadata;
mod cli_json;
mod common_opts;
mod container_entrypoint;
pub(crate) mod containerenv;
mod domain_list;
mod envdetect;
mod ephemeral;
mod hostexec;
mod images;
mod install_options;
mod libvirt;
mod libvirt_upload_disk;
mod osbuild_disk;
#[allow(dead_code)]
mod podman;
#[allow(dead_code)]
mod qemu;
mod qemu_img;
mod run_ephemeral;
mod run_ephemeral_ssh;
mod ssh;
#[allow(dead_code)]
mod sshcred;
mod status_monitor;
mod supervisor_status;
pub(crate) mod systemd;
mod to_disk;
mod utils;
mod xml_utils;
/// Default state directory for bcvk container data
pub const CONTAINER_STATEDIR: &str = "/var/lib/bcvk";
/// A comprehensive toolkit for bootc containers and local virtualization.
///
/// bcvk provides a complete workflow for building, testing, and managing
/// bootc containers using ephemeral VMs. Run bootc images as temporary VMs,
/// install them to disk, or manage existing installations - all without
/// requiring root privileges.
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
/// Execute a command in the host context from within a container.
///
/// This allows containers to run host commands with proper isolation
/// and resource management through the host execution system.
#[derive(Parser)]
struct HostExecOpts {
/// Binary executable to run on the host system
///
/// Can be a full path or a command name available in PATH.
bin: OsString,
/// Command-line arguments to pass to the binary
///
/// All arguments after the binary name, including flags and options.
/// Supports arguments starting with hyphens.
#[clap(allow_hyphen_values = true)]
args: Vec<OsString>,
}
#[derive(Parser)]
struct DebugInternalsOpts {
#[command(subcommand)]
command: DebugInternalsCmds,
}
#[derive(Subcommand)]
enum DebugInternalsCmds {
OpenTree { path: std::path::PathBuf },
}
/// Internal diagnostic and tooling commands for development
#[derive(Parser)]
struct InternalsOpts {
#[command(subcommand)]
command: InternalsCmds,
}
#[derive(Subcommand)]
enum InternalsCmds {
/// Dump CLI structure as JSON for man page generation
#[cfg(feature = "docgen")]
DumpCliJson,
}
/// Available bcvk commands for container and VM management.
#[derive(Subcommand)]
enum Commands {
/// Execute commands on the host system from within containers
#[clap(hide = true)]
Hostexec(HostExecOpts),
/// Manage and inspect bootc container images
#[clap(subcommand)]
Images(images::ImagesOpts),
/// Manage ephemeral VMs for bootc containers
#[clap(subcommand)]
Ephemeral(ephemeral::EphemeralCommands),
/// Install bootc images to persistent disk images
#[clap(name = "to-disk")]
ToDisk(to_disk::ToDiskOpts),
/// Build disk images using bootc-image-builder
#[clap(name = "osbuild-disk")]
OsbuildDisk(osbuild_disk::OsbuildDiskOpts),
/// Manage libvirt integration for bootc containers
Libvirt {
/// Hypervisor connection URI (e.g., qemu:///system, qemu+ssh://host/system)
#[clap(short = 'c', long = "connect", global = true)]
connect: Option<String>,
#[command(subcommand)]
command: libvirt::LibvirtSubcommands,
},
/// Upload bootc disk images to libvirt (deprecated)
#[clap(name = "libvirt-upload-disk", hide = true)]
LibvirtUploadDisk(libvirt_upload_disk::LibvirtUploadDiskOpts),
/// Internal container entrypoint command (hidden from help)
#[clap(hide = true)]
ContainerEntrypoint(container_entrypoint::ContainerEntrypointOpts),
/// Internal debugging and diagnostic tools (hidden from help)
#[clap(hide = true)]
DebugInternals(DebugInternalsOpts),
/// Internal diagnostic and tooling commands for development
#[clap(hide = true)]
Internals(InternalsOpts),
}
/// Install and configure the tracing/logging system.
///
/// Sets up structured logging with environment-based filtering,
/// error layer integration, and console output formatting.
/// Logs are filtered by RUST_LOG environment variable, defaulting to 'info'.
fn install_tracing() {
use tracing_error::ErrorLayer;
use tracing_subscriber::fmt;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;
let format = fmt::format().without_time().with_target(false).compact();
let fmt_layer = fmt::layer()
.event_format(format)
.with_writer(std::io::stderr);
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info"))
.unwrap();
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(ErrorLayer::default())
.init();
}
/// Main entry point for the bcvk CLI application.
///
/// Initializes logging, error handling, and command dispatch for all
/// bcvk operations including VM management, SSH access, and
/// container image handling.
fn main() -> Result<(), Report> {
install_tracing();
color_eyre::install()?;
let cli = Cli::parse();
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.context("Init tokio runtime")?;
match cli.command {
Commands::Hostexec(opts) => {
hostexec::run(opts.bin, opts.args)?;
}
Commands::Images(opts) => opts.run()?,
Commands::Ephemeral(cmd) => cmd.run()?,
Commands::ToDisk(opts) => {
to_disk::run(opts)?;
}
Commands::OsbuildDisk(opts) => {
osbuild_disk::run(opts)?;
}
Commands::Libvirt { connect, command } => {
let options = libvirt::LibvirtOptions { connect };
match command {
libvirt::LibvirtSubcommands::Run(opts) => libvirt::run::run(&options, opts)?,
libvirt::LibvirtSubcommands::Ssh(opts) => libvirt::ssh::run(&options, opts)?,
libvirt::LibvirtSubcommands::List(opts) => libvirt::list::run(&options, opts)?,
libvirt::LibvirtSubcommands::ListVolumes(opts) => {
libvirt::list_volumes::run(&options, opts)?
}
libvirt::LibvirtSubcommands::Stop(opts) => libvirt::stop::run(&options, opts)?,
libvirt::LibvirtSubcommands::Start(opts) => libvirt::start::run(&options, opts)?,
libvirt::LibvirtSubcommands::Remove(opts) => libvirt::rm::run(&options, opts)?,
libvirt::LibvirtSubcommands::RemoveAll(opts) => {
libvirt::rm_all::run(&options, opts)?
}
libvirt::LibvirtSubcommands::Inspect(opts) => {
libvirt::inspect::run(&options, opts)?
}
libvirt::LibvirtSubcommands::Upload(opts) => libvirt::upload::run(&options, opts)?,
libvirt::LibvirtSubcommands::Status(opts) => libvirt::status::run(opts)?,
libvirt::LibvirtSubcommands::BaseDisks(opts) => {
libvirt::base_disks_cli::run(&options, opts)?
}
}
}
Commands::LibvirtUploadDisk(opts) => {
eprintln!(
"Warning: 'libvirt-upload-disk' is deprecated. Use 'libvirt upload' instead."
);
libvirt_upload_disk::run(opts)?;
}
Commands::ContainerEntrypoint(opts) => {
// Create a tokio runtime for async container entrypoint operations
rt.block_on(async move {
let r = container_entrypoint::run(opts).await;
tracing::debug!("Container entrypoint done");
r
})?;
tracing::trace!("Exiting runtime");
}
Commands::DebugInternals(opts) => match opts.command {
DebugInternalsCmds::OpenTree { path } => {
let fd = rustix::mount::open_tree(
rustix::fs::CWD,
path,
rustix::mount::OpenTreeFlags::OPEN_TREE_CLOEXEC
| rustix::mount::OpenTreeFlags::OPEN_TREE_CLONE,
)?;
let fd = Dir::reopen_dir(&fd)?;
tracing::debug!("{:?}", fd.entries()?.into_iter().collect::<Vec<_>>());
}
},
Commands::Internals(opts) => match opts.command {
#[cfg(feature = "docgen")]
InternalsCmds::DumpCliJson => {
let json = cli_json::dump_cli_json()?;
println!("{}", json);
}
},
}
tracing::debug!("exiting");
// Ensure we don't block on any spawned tasks
rt.shutdown_background();
std::process::exit(0)
}