use super::LinuxContainer;
use super::Mount;
use super::linux_container;
use crate::containerization::GIB;
use crate::containerization::image;
use crate::containerization::network;
use crate::containerization::vm;
use crate::containerization_extras;
use crate::error::Error;
use crate::platform;
use crate::platform::ffi;
use std::fmt;
use std::path::Path;
#[derive(Debug, Default)]
pub struct ContainerManagerOptions {
pub network: Option<network::VmnetNetwork>,
pub rosetta: bool,
pub nested_virtualization: bool,
}
pub struct CreateOptions {
pub rootfs_size_in_bytes: u64,
pub writable_layer_size_in_bytes: Option<u64>,
pub read_only: bool,
pub networking: bool,
pub vm: vm::VMResources,
pub progress: Option<containerization_extras::ProgressHandler>,
}
impl Default for CreateOptions {
fn default() -> Self {
Self {
rootfs_size_in_bytes: 8 * GIB,
writable_layer_size_in_bytes: None,
read_only: false,
networking: true,
vm: vm::VMResources::default(),
progress: None,
}
}
}
impl fmt::Debug for CreateOptions {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("CreateOptions")
.field("rootfs_size_in_bytes", &self.rootfs_size_in_bytes)
.field("writable_layer_size_in_bytes", &self.writable_layer_size_in_bytes)
.field("read_only", &self.read_only)
.field("networking", &self.networking)
.field("vm", &self.vm)
.finish_non_exhaustive()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CreateWithRootfsOptions {
pub writable_layer: Option<Mount>,
pub networking: bool,
pub vm: vm::VMResources,
}
impl Default for CreateWithRootfsOptions {
fn default() -> Self {
Self {
writable_layer: None,
networking: true,
vm: vm::VMResources::default(),
}
}
}
pub struct ContainerManager {
handle: ffi::CzContainerManager,
}
impl fmt::Debug for ContainerManager {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("ContainerManager")
.finish_non_exhaustive()
}
}
unsafe impl Send for ContainerManager {}
unsafe impl Sync for ContainerManager {}
impl ContainerManager {
pub fn new(
kernel: &vm::Kernel,
initfs: &Mount,
image_store: &image::ImageStore,
options: ContainerManagerOptions,
) -> Result<Self, Error> {
Self::made(
image_store.handle.container_manager(
kernel.clone(),
initfs.clone(),
network_crossing(options.network),
options.rosetta,
options.nested_virtualization,
),
"make a container manager",
)
}
pub fn with_initfs_reference(
kernel: &vm::Kernel,
initfs_reference: &str,
image_store: &image::ImageStore,
options: ContainerManagerOptions,
) -> Result<Self, Error> {
Self::made(
image_store.handle.container_manager_with_initfs_reference(
kernel.clone(),
initfs_reference,
network_crossing(options.network),
options.rosetta,
options.nested_virtualization,
),
format!("make a container manager booting {initfs_reference}"),
)
}
pub fn at_root(
kernel: &vm::Kernel,
initfs: &Mount,
root: Option<&Path>,
options: ContainerManagerOptions,
) -> Result<Self, Error> {
Self::made(
ffi::cz_container_manager_at_root(
kernel.clone(),
initfs.clone(),
root.map(platform::path).transpose()?.map(str::to_string),
network_crossing(options.network),
options.rosetta,
options.nested_virtualization,
),
"make a container manager",
)
}
pub fn at_root_with_initfs_reference(
kernel: &vm::Kernel,
initfs_reference: &str,
root: Option<&Path>,
options: ContainerManagerOptions,
) -> Result<Self, Error> {
Self::made(
ffi::cz_container_manager_at_root_with_initfs_reference(
kernel.clone(),
initfs_reference,
root.map(platform::path).transpose()?.map(str::to_string),
network_crossing(options.network),
options.rosetta,
options.nested_virtualization,
),
format!("make a container manager booting {initfs_reference}"),
)
}
pub fn with_vmm(vmm: &vm::VZVirtualMachineManager, network: Option<network::VmnetNetwork>) -> Result<Self, Error> {
Self::made(
ffi::cz_container_manager_with_vmm(vmm.handle.duplicate(), network_crossing(network)),
"make a container manager",
)
}
fn made(outcome: ffi::CzOutcome, action: impl Into<String>) -> Result<Self, Error> {
platform::outcome(outcome, action).map(|outcome| Self {
handle: outcome.container_manager(),
})
}
pub fn image_store(&self) -> image::ImageStore {
image::ImageStore {
handle: self.handle.image_store(),
}
}
pub fn create_with_reference(
&mut self,
id: &str,
reference: &str,
mut options: CreateOptions,
configuration: impl FnOnce(&mut linux_container::Configuration) -> Result<(), Error> + Send + 'static,
) -> Result<LinuxContainer, Error> {
let progress = platform::Progress(options.progress.take());
platform::configured(
configuration,
|configure| {
self.handle.create_from_reference(
id,
reference,
options,
progress,
linux_container::Configuration::default(),
configure,
)
},
format!("create {id} from {reference}"),
)
.map(|outcome| LinuxContainer {
handle: outcome.linux_container(),
})
}
pub fn create(
&mut self,
id: &str,
image: &image::Image,
mut options: CreateOptions,
configuration: impl FnOnce(&mut linux_container::Configuration) -> Result<(), Error> + Send + 'static,
) -> Result<LinuxContainer, Error> {
let progress = platform::Progress(options.progress.take());
platform::configured(
configuration,
|configure| {
self.handle.create(
id,
image.handle.duplicate(),
options,
progress,
linux_container::Configuration::default(),
configure,
)
},
format!("create {id}"),
)
.map(|outcome| LinuxContainer {
handle: outcome.linux_container(),
})
}
pub fn create_with_rootfs(
&mut self,
id: &str,
image: &image::Image,
rootfs: Mount,
options: CreateWithRootfsOptions,
configuration: impl FnOnce(&mut linux_container::Configuration) -> Result<(), Error> + Send + 'static,
) -> Result<LinuxContainer, Error> {
platform::configured(
configuration,
|configure| {
self.handle.create_with_rootfs(
id,
image.handle.duplicate(),
rootfs,
options,
linux_container::Configuration::default(),
configure,
)
},
format!("create {id}"),
)
.map(|outcome| LinuxContainer {
handle: outcome.linux_container(),
})
}
pub fn release_network(&mut self, id: &str) -> Result<(), Error> {
platform::outcome(self.handle.release_network(id), format!("release {id}'s network")).map(drop)
}
pub fn delete(&mut self, id: &str) -> Result<(), Error> {
platform::outcome(self.handle.delete(id), format!("delete {id}")).map(drop)
}
}
fn network_crossing(network: Option<network::VmnetNetwork>) -> ffi::CzNetwork {
match network {
Some(network) => network.handle.as_network(),
None => ffi::cz_no_network(),
}
}