mirror of
https://github.com/aljazceru/kata-containers.git
synced 2026-01-11 10:24:22 +01:00
backporting b1f4e945b3 original commit msg (modified):
Update the rust dependencies that have upstream security fixes. Issues
fixed by this change:
- [`RUSTSEC-2020-0002`](https://rustsec.org/advisories/RUSTSEC-2020-0002) (`prost` crate)
- [`RUSTSEC-2020-0036`](https://rustsec.org/advisories/RUSTSEC-2020-0036) (`failure` crate)
- [`RUSTSEC-2021-0073`](https://rustsec.org/advisories/RUSTSEC-2021-0073) (`prost-types` crate)
- [`RUSTSEC-2021-0119`](https://rustsec.org/advisories/RUSTSEC-2021-0119) (`nix` crate)
This change also includes:
- Minor code changes for the new version of `prometheus` for the agent.
Fixes: #3296.
Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
Signed-off-by: Snir Sheriber <ssheribe@redhat.com>
792 lines
25 KiB
Rust
792 lines
25 KiB
Rust
// Copyright (c) 2020 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
use crate::types::{Config, Options};
|
|
use anyhow::{anyhow, Result};
|
|
use oci::{
|
|
Linux as ociLinux, Mount as ociMount, Process as ociProcess, Root as ociRoot, Spec as ociSpec,
|
|
};
|
|
use protocols::oci::{
|
|
Box as ttrpcBox, Linux as ttrpcLinux, LinuxBlockIO as ttrpcLinuxBlockIO,
|
|
LinuxCPU as ttrpcLinuxCPU, LinuxCapabilities as ttrpcLinuxCapabilities,
|
|
LinuxDevice as ttrpcLinuxDevice, LinuxDeviceCgroup as ttrpcLinuxDeviceCgroup,
|
|
LinuxHugepageLimit as ttrpcLinuxHugepageLimit, LinuxIDMapping as ttrpcLinuxIDMapping,
|
|
LinuxIntelRdt as ttrpcLinuxIntelRdt, LinuxInterfacePriority as ttrpcLinuxInterfacePriority,
|
|
LinuxMemory as ttrpcLinuxMemory, LinuxNamespace as ttrpcLinuxNamespace,
|
|
LinuxNetwork as ttrpcLinuxNetwork, LinuxPids as ttrpcLinuxPids,
|
|
LinuxResources as ttrpcLinuxResources, LinuxSeccomp as ttrpcLinuxSeccomp,
|
|
LinuxSeccompArg as ttrpcLinuxSeccompArg, LinuxSyscall as ttrpcLinuxSyscall,
|
|
LinuxThrottleDevice as ttrpcLinuxThrottleDevice, LinuxWeightDevice as ttrpcLinuxWeightDevice,
|
|
Mount as ttrpcMount, Process as ttrpcProcess, Root as ttrpcRoot, Spec as ttrpcSpec,
|
|
User as ttrpcUser,
|
|
};
|
|
use rand::Rng;
|
|
use slog::{debug, warn};
|
|
use std::collections::HashMap;
|
|
use std::path::PathBuf;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
// Length of a sandbox identifier
|
|
const SANDBOX_ID_LEN: u8 = 64;
|
|
|
|
const FILE_URI: &str = "file://";
|
|
|
|
// Length of the guests hostname
|
|
const MIN_HOSTNAME_LEN: u8 = 8;
|
|
|
|
// Name of the OCI configuration file found at the root of an OCI bundle.
|
|
const CONFIG_FILE: &str = "config.json";
|
|
|
|
lazy_static! {
|
|
// Create a mutable hash map statically
|
|
static ref SIGNALS: Arc<Mutex<HashMap<&'static str, u8>>> = {
|
|
|
|
let mut m: HashMap<&'static str, u8> = HashMap::new();
|
|
|
|
m.insert("SIGHUP", 1);
|
|
m.insert("SIGINT", 2);
|
|
m.insert("SIGQUIT", 3);
|
|
m.insert("SIGILL", 4);
|
|
m.insert("SIGTRAP", 5);
|
|
m.insert("SIGABRT", 6);
|
|
m.insert("SIGBUS", 7);
|
|
m.insert("SIGFPE", 8);
|
|
m.insert("SIGKILL", 9);
|
|
m.insert("SIGUSR1", 10);
|
|
m.insert("SIGSEGV", 11);
|
|
m.insert("SIGUSR2", 12);
|
|
m.insert("SIGPIPE", 13);
|
|
m.insert("SIGALRM", 14);
|
|
m.insert("SIGTERM", 15);
|
|
m.insert("SIGSTKFLT", 16);
|
|
|
|
// XXX:
|
|
m.insert("SIGCHLD", 17);
|
|
m.insert("SIGCLD", 17);
|
|
|
|
m.insert("SIGCONT", 18);
|
|
m.insert("SIGSTOP", 19);
|
|
m.insert("SIGTSTP", 20);
|
|
m.insert("SIGTTIN", 21);
|
|
m.insert("SIGTTOU", 22);
|
|
m.insert("SIGURG", 23);
|
|
m.insert("SIGXCPU", 24);
|
|
m.insert("SIGXFSZ", 25);
|
|
m.insert("SIGVTALRM", 26);
|
|
m.insert("SIGPROF", 27);
|
|
m.insert("SIGWINCH", 28);
|
|
m.insert("SIGIO", 29);
|
|
m.insert("SIGPWR", 30);
|
|
m.insert("SIGSYS", 31);
|
|
|
|
Arc::new(Mutex::new(m))
|
|
};
|
|
}
|
|
|
|
pub fn signame_to_signum(name: &str) -> Result<u8> {
|
|
if name == "" {
|
|
return Err(anyhow!("invalid signal"));
|
|
}
|
|
|
|
match name.parse::<u8>() {
|
|
Ok(n) => return Ok(n),
|
|
|
|
// "fall through" on error as we assume the name is not a number, but
|
|
// a signal name.
|
|
Err(_) => (),
|
|
}
|
|
|
|
let mut search_term: String;
|
|
|
|
if name.starts_with("SIG") {
|
|
search_term = name.to_string();
|
|
} else {
|
|
search_term = format!("SIG{}", name);
|
|
}
|
|
|
|
search_term = search_term.to_uppercase();
|
|
|
|
// Access the hashmap
|
|
let signals_ref = SIGNALS.clone();
|
|
let m = signals_ref.lock().unwrap();
|
|
|
|
match m.get(&*search_term) {
|
|
Some(value) => Ok(*value),
|
|
None => Err(anyhow!(format!("invalid signal name: {:?}", name))),
|
|
}
|
|
}
|
|
|
|
// Convert a human time fornat (like "2s") into the equivalent number
|
|
// of nano seconds.
|
|
pub fn human_time_to_ns(human_time: &str) -> Result<i64> {
|
|
if human_time == "" || human_time == "0" {
|
|
return Ok(0);
|
|
}
|
|
|
|
let d: humantime::Duration = human_time
|
|
.parse::<humantime::Duration>()
|
|
.map_err(|e| anyhow!(e))?
|
|
.into();
|
|
|
|
Ok(d.as_nanos() as i64)
|
|
}
|
|
|
|
// Look up the specified option name and return its value.
|
|
//
|
|
// - The function looks for the appropriate option value in the specified
|
|
// 'args' first.
|
|
// - 'args' is assumed to be a space-separated set of "name=value" pairs).
|
|
// - If not found in the args, the function looks in the global options hash.
|
|
// - If found in neither location, certain well-known options are auto-generated.
|
|
// - All other options values default to an empty string.
|
|
// - All options are saved in the global hash before being returned for future
|
|
// use.
|
|
pub fn get_option(name: &str, options: &mut Options, args: &str) -> String {
|
|
let words: Vec<&str> = args.split_whitespace().collect();
|
|
|
|
for word in words {
|
|
let fields: Vec<String> = word.split("=").map(|s| s.to_string()).collect();
|
|
|
|
if fields.len() < 2 {
|
|
continue;
|
|
}
|
|
|
|
if fields[0] == "" {
|
|
continue;
|
|
}
|
|
|
|
let key = fields[0].clone();
|
|
|
|
let mut value = fields[1..].join("=");
|
|
|
|
// Expand "spec=file:///some/where/config.json"
|
|
if key == "spec" && value.starts_with(FILE_URI) {
|
|
let spec_file = match uri_to_filename(&value) {
|
|
Ok(file) => file,
|
|
Err(e) => {
|
|
warn!(sl!(), "failed to handle spec file URI: {:}", e);
|
|
|
|
"".to_string()
|
|
}
|
|
};
|
|
|
|
if spec_file != "" {
|
|
value = match spec_file_to_string(spec_file) {
|
|
Ok(s) => s,
|
|
Err(e) => {
|
|
warn!(sl!(), "failed to load spec file: {:}", e);
|
|
|
|
"".to_string()
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
// Command args take priority over any previous value,
|
|
// so update the global set of options for this and all
|
|
// subsequent commands.
|
|
options.insert(key, value);
|
|
}
|
|
|
|
// Explains briefly how the option value was determined
|
|
let mut msg = "cached";
|
|
|
|
// If the option exists in the hash, return it
|
|
if let Some(value) = options.get(name) {
|
|
debug!(sl!(), "using option {:?}={:?} ({})", name, value, msg);
|
|
|
|
return value.to_string();
|
|
}
|
|
|
|
msg = "generated";
|
|
|
|
// Handle option values that can be auto-generated
|
|
let value = match name {
|
|
"cid" => random_container_id(),
|
|
"sid" => random_sandbox_id(),
|
|
|
|
// Default to CID
|
|
"exec_id" => {
|
|
msg = "derived";
|
|
//derived = true;
|
|
|
|
match options.get("cid") {
|
|
Some(value) => value.to_string(),
|
|
None => "".to_string(),
|
|
}
|
|
}
|
|
_ => "".to_string(),
|
|
};
|
|
|
|
debug!(sl!(), "using option {:?}={:?} ({})", name, value, msg);
|
|
|
|
// Store auto-generated value
|
|
options.insert(name.to_string(), value.to_string());
|
|
|
|
value
|
|
}
|
|
|
|
pub fn generate_random_hex_string(len: u32) -> String {
|
|
const CHARSET: &[u8] = b"abcdef0123456789";
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let str: String = (0..len)
|
|
.map(|_| {
|
|
let idx = rng.gen_range(0..CHARSET.len());
|
|
CHARSET[idx] as char
|
|
})
|
|
.collect();
|
|
|
|
str
|
|
}
|
|
|
|
pub fn random_sandbox_id() -> String {
|
|
generate_random_hex_string(SANDBOX_ID_LEN as u32)
|
|
}
|
|
|
|
pub fn random_container_id() -> String {
|
|
// Containers and sandboxes have same ID types
|
|
random_sandbox_id()
|
|
}
|
|
|
|
fn config_file_from_bundle_dir(bundle_dir: &str) -> Result<String> {
|
|
if bundle_dir == "" {
|
|
return Err(anyhow!("missing bundle directory"));
|
|
}
|
|
|
|
let config_path = PathBuf::from(&bundle_dir).join(CONFIG_FILE);
|
|
|
|
config_path
|
|
.into_os_string()
|
|
.into_string()
|
|
.map_err(|e| anyhow!("{:?}", e).context("failed to construct config file path"))
|
|
}
|
|
|
|
fn root_oci_to_ttrpc(bundle_dir: &str, root: &ociRoot) -> Result<ttrpcRoot> {
|
|
let root_dir = root.path.clone();
|
|
|
|
let path = if root_dir.starts_with("/") {
|
|
root_dir.clone()
|
|
} else {
|
|
// Expand the root directory into an absolute value
|
|
let abs_root_dir = PathBuf::from(&bundle_dir).join(&root_dir);
|
|
|
|
abs_root_dir
|
|
.into_os_string()
|
|
.into_string()
|
|
.map_err(|e| anyhow!("{:?}", e).context("failed to construct bundle path"))?
|
|
};
|
|
|
|
let ttrpc_root = ttrpcRoot {
|
|
Path: path,
|
|
Readonly: root.readonly,
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
};
|
|
|
|
Ok(ttrpc_root)
|
|
}
|
|
|
|
fn process_oci_to_ttrpc(p: &ociProcess) -> ttrpcProcess {
|
|
let console_size = match &p.console_size {
|
|
Some(s) => {
|
|
let mut b = ttrpcBox::new();
|
|
b.set_Width(s.width);
|
|
b.set_Height(s.height);
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
let oom_score_adj: i64 = match p.oom_score_adj {
|
|
Some(s) => s.into(),
|
|
None => 0,
|
|
};
|
|
|
|
let mut user = ttrpcUser::new();
|
|
user.set_UID(p.user.uid);
|
|
user.set_GID(p.user.gid);
|
|
user.set_AdditionalGids(p.user.additional_gids.clone());
|
|
|
|
// FIXME: Implement RLimits OCI spec handling (copy from p.rlimits)
|
|
//let rlimits = vec![ttrpcPOSIXRlimit::new()];
|
|
let rlimits = protobuf::RepeatedField::new();
|
|
|
|
let capabilities = match &p.capabilities {
|
|
Some(c) => {
|
|
let mut gc = ttrpcLinuxCapabilities::new();
|
|
gc.set_Bounding(protobuf::RepeatedField::from_slice(&c.bounding));
|
|
gc.set_Effective(protobuf::RepeatedField::from_slice(&c.effective));
|
|
gc.set_Inheritable(protobuf::RepeatedField::from_slice(&c.inheritable));
|
|
gc.set_Permitted(protobuf::RepeatedField::from_slice(&c.permitted));
|
|
gc.set_Ambient(protobuf::RepeatedField::from_slice(&c.ambient));
|
|
|
|
protobuf::SingularPtrField::some(gc)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
let mut env = protobuf::RepeatedField::new();
|
|
for pair in &p.env {
|
|
env.push(pair.to_string());
|
|
}
|
|
|
|
ttrpcProcess {
|
|
Terminal: p.terminal,
|
|
ConsoleSize: console_size,
|
|
User: protobuf::SingularPtrField::some(user),
|
|
Args: protobuf::RepeatedField::from_vec(p.args.clone()),
|
|
Env: env,
|
|
Cwd: p.cwd.clone(),
|
|
Capabilities: capabilities,
|
|
Rlimits: rlimits,
|
|
NoNewPrivileges: p.no_new_privileges,
|
|
ApparmorProfile: p.apparmor_profile.clone(),
|
|
OOMScoreAdj: oom_score_adj,
|
|
SelinuxLabel: p.selinux_label.clone(),
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
}
|
|
}
|
|
|
|
fn mount_oci_to_ttrpc(m: &ociMount) -> ttrpcMount {
|
|
let mut ttrpc_options = protobuf::RepeatedField::new();
|
|
for op in &m.options {
|
|
ttrpc_options.push(op.to_string());
|
|
}
|
|
|
|
ttrpcMount {
|
|
destination: m.destination.clone(),
|
|
source: m.source.clone(),
|
|
field_type: m.r#type.clone(),
|
|
options: ttrpc_options,
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
}
|
|
}
|
|
|
|
fn idmaps_oci_to_ttrpc(
|
|
res: &[oci::LinuxIdMapping],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxIDMapping> {
|
|
let mut ttrpc_idmaps = protobuf::RepeatedField::new();
|
|
for m in res.iter() {
|
|
let mut idmapping = ttrpcLinuxIDMapping::default();
|
|
idmapping.set_HostID(m.host_id);
|
|
idmapping.set_ContainerID(m.container_id);
|
|
idmapping.set_Size(m.size);
|
|
ttrpc_idmaps.push(idmapping);
|
|
}
|
|
ttrpc_idmaps
|
|
}
|
|
|
|
fn devices_oci_to_ttrpc(
|
|
res: &[oci::LinuxDeviceCgroup],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxDeviceCgroup> {
|
|
let mut ttrpc_devices = protobuf::RepeatedField::new();
|
|
for d in res.iter() {
|
|
let mut device = ttrpcLinuxDeviceCgroup::default();
|
|
device.set_Major(d.major.unwrap_or(0));
|
|
device.set_Minor(d.minor.unwrap_or(0));
|
|
device.set_Access(d.access.clone());
|
|
device.set_Type(d.r#type.clone());
|
|
device.set_Allow(d.allow);
|
|
ttrpc_devices.push(device);
|
|
}
|
|
ttrpc_devices
|
|
}
|
|
|
|
fn memory_oci_to_ttrpc(
|
|
res: &Option<oci::LinuxMemory>,
|
|
) -> protobuf::SingularPtrField<ttrpcLinuxMemory> {
|
|
let memory = if res.is_some() {
|
|
let mem = res.as_ref().unwrap();
|
|
protobuf::SingularPtrField::some(ttrpcLinuxMemory {
|
|
Limit: mem.limit.unwrap_or(0),
|
|
Reservation: mem.reservation.unwrap_or(0),
|
|
Swap: mem.swap.unwrap_or(0),
|
|
Kernel: mem.kernel.unwrap_or(0),
|
|
KernelTCP: mem.kernel_tcp.unwrap_or(0),
|
|
Swappiness: mem.swappiness.unwrap_or(0) as u64,
|
|
DisableOOMKiller: mem.disable_oom_killer.unwrap_or(false),
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
})
|
|
} else {
|
|
protobuf::SingularPtrField::none()
|
|
};
|
|
memory
|
|
}
|
|
|
|
fn cpu_oci_to_ttrpc(res: &Option<oci::LinuxCpu>) -> protobuf::SingularPtrField<ttrpcLinuxCPU> {
|
|
match &res {
|
|
Some(s) => {
|
|
let mut cpu = ttrpcLinuxCPU::default();
|
|
cpu.set_Shares(s.shares.unwrap_or(0));
|
|
cpu.set_Quota(s.quota.unwrap_or(0));
|
|
cpu.set_Period(s.period.unwrap_or(0));
|
|
cpu.set_RealtimeRuntime(s.realtime_runtime.unwrap_or(0));
|
|
cpu.set_RealtimePeriod(s.realtime_period.unwrap_or(0));
|
|
protobuf::SingularPtrField::some(cpu)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
}
|
|
}
|
|
|
|
fn pids_oci_to_ttrpc(res: &Option<oci::LinuxPids>) -> protobuf::SingularPtrField<ttrpcLinuxPids> {
|
|
match &res {
|
|
Some(s) => {
|
|
let mut b = ttrpcLinuxPids::new();
|
|
b.set_Limit(s.limit);
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
}
|
|
}
|
|
|
|
fn hugepage_limits_oci_to_ttrpc(
|
|
res: &[oci::LinuxHugepageLimit],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxHugepageLimit> {
|
|
let mut ttrpc_hugepage_limits = protobuf::RepeatedField::new();
|
|
for h in res.iter() {
|
|
let mut hugepage_limit = ttrpcLinuxHugepageLimit::default();
|
|
hugepage_limit.set_Limit(h.limit);
|
|
hugepage_limit.set_Pagesize(h.page_size.clone());
|
|
ttrpc_hugepage_limits.push(hugepage_limit);
|
|
}
|
|
ttrpc_hugepage_limits
|
|
}
|
|
|
|
fn network_oci_to_ttrpc(
|
|
res: &Option<oci::LinuxNetwork>,
|
|
) -> protobuf::SingularPtrField<ttrpcLinuxNetwork> {
|
|
match &res {
|
|
Some(s) => {
|
|
let mut b = ttrpcLinuxNetwork::new();
|
|
b.set_ClassID(s.class_id.unwrap_or(0));
|
|
let mut priorities = protobuf::RepeatedField::new();
|
|
for pr in s.priorities.iter() {
|
|
let mut lip = ttrpcLinuxInterfacePriority::new();
|
|
lip.set_Name(pr.name.clone());
|
|
lip.set_Priority(pr.priority);
|
|
priorities.push(lip);
|
|
}
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
}
|
|
}
|
|
|
|
fn weight_devices_oci_to_ttrpc(
|
|
res: &[oci::LinuxWeightDevice],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxWeightDevice> {
|
|
let mut ttrpc_weight_devices = protobuf::RepeatedField::new();
|
|
for dev in res.iter() {
|
|
let mut device = ttrpcLinuxWeightDevice::default();
|
|
device.set_Major(dev.blk.major);
|
|
device.set_Minor(dev.blk.minor);
|
|
let weight: u32 = match dev.weight {
|
|
Some(s) => s.into(),
|
|
None => 0,
|
|
};
|
|
device.set_Weight(weight);
|
|
let leaf_weight: u32 = match dev.leaf_weight {
|
|
Some(s) => s.into(),
|
|
None => 0,
|
|
};
|
|
device.set_LeafWeight(leaf_weight);
|
|
ttrpc_weight_devices.push(device);
|
|
}
|
|
ttrpc_weight_devices
|
|
}
|
|
|
|
fn throttle_devices_oci_to_ttrpc(
|
|
res: &[oci::LinuxThrottleDevice],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxThrottleDevice> {
|
|
let mut ttrpc_throttle_devices = protobuf::RepeatedField::new();
|
|
for dev in res.iter() {
|
|
let mut device = ttrpcLinuxThrottleDevice::default();
|
|
device.set_Major(dev.blk.major);
|
|
device.set_Minor(dev.blk.minor);
|
|
device.set_Rate(dev.rate);
|
|
ttrpc_throttle_devices.push(device);
|
|
}
|
|
ttrpc_throttle_devices
|
|
}
|
|
|
|
fn block_io_oci_to_ttrpc(
|
|
res: &Option<oci::LinuxBlockIo>,
|
|
) -> protobuf::SingularPtrField<ttrpcLinuxBlockIO> {
|
|
match &res {
|
|
Some(s) => {
|
|
let mut b = ttrpcLinuxBlockIO::new();
|
|
let weight: u32 = match s.weight {
|
|
Some(s) => s.into(),
|
|
None => 0,
|
|
};
|
|
let leaf_weight: u32 = match s.leaf_weight {
|
|
Some(s) => s.into(),
|
|
None => 0,
|
|
};
|
|
|
|
b.set_Weight(weight);
|
|
b.set_LeafWeight(leaf_weight);
|
|
b.set_WeightDevice(weight_devices_oci_to_ttrpc(&s.weight_device));
|
|
b.set_ThrottleReadBpsDevice(throttle_devices_oci_to_ttrpc(&s.throttle_read_bps_device));
|
|
b.set_ThrottleReadIOPSDevice(throttle_devices_oci_to_ttrpc(
|
|
&s.throttle_read_iops_device,
|
|
));
|
|
b.set_ThrottleWriteBpsDevice(throttle_devices_oci_to_ttrpc(
|
|
&s.throttle_write_bps_device,
|
|
));
|
|
b.set_ThrottleWriteIOPSDevice(throttle_devices_oci_to_ttrpc(
|
|
&s.throttle_write_iops_device,
|
|
));
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
}
|
|
}
|
|
|
|
fn resources_oci_to_ttrpc(res: &oci::LinuxResources) -> ttrpcLinuxResources {
|
|
let devices = devices_oci_to_ttrpc(&res.devices);
|
|
let memory = memory_oci_to_ttrpc(&res.memory);
|
|
let cpu = cpu_oci_to_ttrpc(&res.cpu);
|
|
let pids = pids_oci_to_ttrpc(&res.pids);
|
|
let hugepage_limits = hugepage_limits_oci_to_ttrpc(&res.hugepage_limits);
|
|
let block_io = block_io_oci_to_ttrpc(&res.block_io);
|
|
|
|
let network = network_oci_to_ttrpc(&res.network);
|
|
ttrpcLinuxResources {
|
|
Devices: devices,
|
|
Memory: memory,
|
|
CPU: cpu,
|
|
Pids: pids,
|
|
BlockIO: block_io,
|
|
HugepageLimits: hugepage_limits,
|
|
Network: network,
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
}
|
|
}
|
|
|
|
fn namespace_oci_to_ttrpc(
|
|
res: &[oci::LinuxNamespace],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxNamespace> {
|
|
let mut ttrpc_namespace = protobuf::RepeatedField::new();
|
|
for n in res.iter() {
|
|
let mut ns = ttrpcLinuxNamespace::default();
|
|
ns.set_Path(n.path.clone());
|
|
ns.set_Type(n.r#type.clone());
|
|
ttrpc_namespace.push(ns);
|
|
}
|
|
ttrpc_namespace
|
|
}
|
|
|
|
fn linux_devices_oci_to_ttrpc(
|
|
res: &[oci::LinuxDevice],
|
|
) -> protobuf::RepeatedField<ttrpcLinuxDevice> {
|
|
let mut ttrpc_linux_devices = protobuf::RepeatedField::new();
|
|
for n in res.iter() {
|
|
let mut ld = ttrpcLinuxDevice::default();
|
|
ld.set_FileMode(n.file_mode.unwrap_or(0));
|
|
ld.set_GID(n.gid.unwrap_or(0));
|
|
ld.set_UID(n.uid.unwrap_or(0));
|
|
ld.set_Major(n.major);
|
|
ld.set_Minor(n.minor);
|
|
ld.set_Path(n.path.clone());
|
|
ld.set_Type(n.r#type.clone());
|
|
ttrpc_linux_devices.push(ld);
|
|
}
|
|
ttrpc_linux_devices
|
|
}
|
|
|
|
fn seccomp_oci_to_ttrpc(sec: &oci::LinuxSeccomp) -> ttrpcLinuxSeccomp {
|
|
let mut ttrpc_seccomp = ttrpcLinuxSeccomp::default();
|
|
let mut ttrpc_arch = protobuf::RepeatedField::new();
|
|
for a in &sec.architectures {
|
|
ttrpc_arch.push(std::string::String::from(a));
|
|
}
|
|
ttrpc_seccomp.set_Architectures(ttrpc_arch);
|
|
ttrpc_seccomp.set_DefaultAction(sec.default_action.clone());
|
|
let mut ttrpc_flags = protobuf::RepeatedField::new();
|
|
for f in &sec.flags {
|
|
ttrpc_flags.push(std::string::String::from(f));
|
|
}
|
|
ttrpc_seccomp.set_Flags(ttrpc_flags);
|
|
let mut ttrpc_syscalls = protobuf::RepeatedField::new();
|
|
for sys in &sec.syscalls {
|
|
let mut ttrpc_sys = ttrpcLinuxSyscall::default();
|
|
ttrpc_sys.set_Action(sys.action.clone());
|
|
let mut ttrpc_args = protobuf::RepeatedField::new();
|
|
for arg in &sys.args {
|
|
let mut a = ttrpcLinuxSeccompArg::default();
|
|
a.set_Index(arg.index as u64);
|
|
a.set_Op(arg.op.clone());
|
|
a.set_Value(arg.value);
|
|
a.set_ValueTwo(arg.value_two);
|
|
ttrpc_args.push(a);
|
|
}
|
|
ttrpc_sys.set_Args(ttrpc_args);
|
|
ttrpc_syscalls.push(ttrpc_sys);
|
|
}
|
|
ttrpc_seccomp.set_Syscalls(ttrpc_syscalls);
|
|
ttrpc_seccomp
|
|
}
|
|
fn intel_rdt_oci_to_ttrpc(ir: &oci::LinuxIntelRdt) -> ttrpcLinuxIntelRdt {
|
|
let mut ttrpc_intel_rdt = ttrpcLinuxIntelRdt::default();
|
|
ttrpc_intel_rdt.set_L3CacheSchema(ir.l3_cache_schema.clone());
|
|
ttrpc_intel_rdt
|
|
}
|
|
fn linux_oci_to_ttrpc(l: &ociLinux) -> ttrpcLinux {
|
|
let uid_mappings = idmaps_oci_to_ttrpc(&l.uid_mappings);
|
|
let gid_mappings = idmaps_oci_to_ttrpc(&l.gid_mappings);
|
|
|
|
let ttrpc_linux_resources = match &l.resources {
|
|
Some(s) => {
|
|
let b = resources_oci_to_ttrpc(s);
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
let ttrpc_namespaces = namespace_oci_to_ttrpc(&l.namespaces);
|
|
let ttrpc_linux_devices = linux_devices_oci_to_ttrpc(&l.devices);
|
|
let ttrpc_seccomp = match &l.seccomp {
|
|
Some(s) => {
|
|
let b = seccomp_oci_to_ttrpc(s);
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
let ttrpc_intel_rdt = match &l.intel_rdt {
|
|
Some(s) => {
|
|
let b = intel_rdt_oci_to_ttrpc(s);
|
|
protobuf::SingularPtrField::some(b)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
ttrpcLinux {
|
|
UIDMappings: uid_mappings,
|
|
GIDMappings: gid_mappings,
|
|
Sysctl: l.sysctl.clone(),
|
|
Resources: ttrpc_linux_resources,
|
|
CgroupsPath: l.cgroups_path.clone(),
|
|
Namespaces: ttrpc_namespaces,
|
|
Devices: ttrpc_linux_devices,
|
|
Seccomp: ttrpc_seccomp,
|
|
RootfsPropagation: l.rootfs_propagation.clone(),
|
|
MaskedPaths: protobuf::RepeatedField::from_slice(&l.masked_paths),
|
|
ReadonlyPaths: protobuf::RepeatedField::from_slice(&l.readonly_paths),
|
|
MountLabel: l.mount_label.clone(),
|
|
IntelRdt: ttrpc_intel_rdt,
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
}
|
|
}
|
|
|
|
fn oci_to_ttrpc(bundle_dir: &str, cid: &str, oci: &ociSpec) -> Result<ttrpcSpec> {
|
|
let process = match &oci.process {
|
|
Some(p) => protobuf::SingularPtrField::some(process_oci_to_ttrpc(&p)),
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
let root = match &oci.root {
|
|
Some(r) => {
|
|
let ttrpc_root = root_oci_to_ttrpc(bundle_dir, &r).map_err(|e| e)?;
|
|
|
|
protobuf::SingularPtrField::some(ttrpc_root)
|
|
}
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
let mut mounts = protobuf::RepeatedField::new();
|
|
for m in &oci.mounts {
|
|
mounts.push(mount_oci_to_ttrpc(&m));
|
|
}
|
|
|
|
let linux = match &oci.linux {
|
|
Some(l) => protobuf::SingularPtrField::some(linux_oci_to_ttrpc(l)),
|
|
None => protobuf::SingularPtrField::none(),
|
|
};
|
|
|
|
if cid.len() < MIN_HOSTNAME_LEN as usize {
|
|
return Err(anyhow!("container ID too short for hostname"));
|
|
}
|
|
|
|
// FIXME: Implement setting a custom (and unique!) hostname (requires uts ns setup)
|
|
//let hostname = cid[0..MIN_HOSTNAME_LEN as usize].to_string();
|
|
let hostname = "".to_string();
|
|
|
|
let ttrpc_spec = ttrpcSpec {
|
|
Version: oci.version.clone(),
|
|
Process: process,
|
|
Root: root,
|
|
Hostname: hostname,
|
|
Mounts: mounts,
|
|
Hooks: protobuf::SingularPtrField::none(),
|
|
Annotations: HashMap::new(),
|
|
Linux: linux,
|
|
Solaris: protobuf::SingularPtrField::none(),
|
|
Windows: protobuf::SingularPtrField::none(),
|
|
unknown_fields: protobuf::UnknownFields::new(),
|
|
cached_size: protobuf::CachedSize::default(),
|
|
};
|
|
|
|
Ok(ttrpc_spec)
|
|
}
|
|
|
|
fn uri_to_filename(uri: &str) -> Result<String> {
|
|
if !uri.starts_with(FILE_URI) {
|
|
return Err(anyhow!(format!("invalid URI: {:?}", uri)));
|
|
}
|
|
|
|
let fields: Vec<&str> = uri.split(FILE_URI).collect();
|
|
|
|
if fields.len() != 2 {
|
|
return Err(anyhow!(format!("invalid URI: {:?}", uri)));
|
|
}
|
|
|
|
Ok(fields[1].to_string())
|
|
}
|
|
|
|
pub fn spec_file_to_string(spec_file: String) -> Result<String> {
|
|
let oci_spec = ociSpec::load(&spec_file).map_err(|e| anyhow!(e))?;
|
|
|
|
serde_json::to_string(&oci_spec).map_err(|e| anyhow!(e))
|
|
}
|
|
|
|
pub fn get_oci_spec_json(cfg: &Config) -> Result<String> {
|
|
let spec_file = config_file_from_bundle_dir(&cfg.bundle_dir)?;
|
|
|
|
spec_file_to_string(spec_file)
|
|
}
|
|
|
|
pub fn get_ttrpc_spec(options: &mut Options, cid: &str) -> Result<ttrpcSpec> {
|
|
let bundle_dir = get_option("bundle-dir", options, "");
|
|
|
|
let json_spec = get_option("spec", options, "");
|
|
assert_ne!(json_spec, "");
|
|
|
|
let oci_spec: ociSpec = serde_json::from_str(&json_spec).map_err(|e| anyhow!(e))?;
|
|
|
|
Ok(oci_to_ttrpc(&bundle_dir, cid, &oci_spec)?)
|
|
}
|
|
|
|
pub fn str_to_bytes(s: &str) -> Result<Vec<u8>> {
|
|
let prefix = "hex:";
|
|
|
|
if s.starts_with(prefix) {
|
|
let hex_str = s.trim_start_matches(prefix);
|
|
|
|
let decoded = hex::decode(hex_str).map_err(|e| anyhow!(e))?;
|
|
|
|
Ok(decoded)
|
|
} else {
|
|
Ok(s.as_bytes().to_vec())
|
|
}
|
|
}
|