mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-02-22 14:54:23 +00:00
Compare commits
50 Commits
zvonkok-pa
...
3.20.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c980b6e191 | ||
|
|
30aff429df | ||
|
|
014ab2fce6 | ||
|
|
dd1752ac1c | ||
|
|
29ab8df881 | ||
|
|
0ac8f1f70e | ||
|
|
a0ae1b6608 | ||
|
|
412a384aad | ||
|
|
0daafecef2 | ||
|
|
f0db4032f2 | ||
|
|
208cec429a | ||
|
|
1f978ecc31 | ||
|
|
b23d094928 | ||
|
|
0f19465b3a | ||
|
|
e05197e81c | ||
|
|
683d673f4f | ||
|
|
38242d3a61 | ||
|
|
283fd45045 | ||
|
|
730b0f1769 | ||
|
|
585d0be342 | ||
|
|
b748688e69 | ||
|
|
c4af9be411 | ||
|
|
bce8efca67 | ||
|
|
e20f6b2f9d | ||
|
|
3503bcdb50 | ||
|
|
a03dc3129d | ||
|
|
93ec470928 | ||
|
|
903e608c23 | ||
|
|
c92bb1aa88 | ||
|
|
28bd0cf405 | ||
|
|
3a4e1917d2 | ||
|
|
3a5e2060aa | ||
|
|
55ee8abf0b | ||
|
|
0fa7d5b293 | ||
|
|
dcb62a7f91 | ||
|
|
8be41a4e80 | ||
|
|
65a9fe0063 | ||
|
|
43cdde4c5d | ||
|
|
9891b111d1 | ||
|
|
d147e2491b | ||
|
|
479cce8406 | ||
|
|
ea74024b93 | ||
|
|
aadad0c9b6 | ||
|
|
cfd0ebe85f | ||
|
|
c7f4c9a3bb | ||
|
|
2f50c85b12 | ||
|
|
5635410dd3 | ||
|
|
1a6f1fc3ac | ||
|
|
f3a669ee2d | ||
|
|
3eb0641431 |
4
.github/workflows/build-checks.yaml
vendored
4
.github/workflows/build-checks.yaml
vendored
@@ -42,6 +42,10 @@ jobs:
|
||||
path: src/runtime-rs
|
||||
needs:
|
||||
- rust
|
||||
- name: libs
|
||||
path: src/libs
|
||||
needs:
|
||||
- rust
|
||||
- name: agent-ctl
|
||||
path: src/tools/agent-ctl
|
||||
needs:
|
||||
|
||||
@@ -22,6 +22,8 @@ use protocols::{
|
||||
};
|
||||
use safe_path::scoped_join;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
use std::path::Path;
|
||||
use std::{os::unix::fs::symlink, path::PathBuf};
|
||||
use tokio::sync::OnceCell;
|
||||
@@ -235,8 +237,8 @@ pub async fn unseal_file(path: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
let secret_name = entry.file_name();
|
||||
let contents = fs::read_to_string(&target_path)?;
|
||||
if contents.starts_with(SEALED_SECRET_PREFIX) {
|
||||
if content_starts_with_prefix(&target_path, SEALED_SECRET_PREFIX).await? {
|
||||
let contents = fs::read_to_string(&target_path)?;
|
||||
// Get the directory name of the sealed secret file
|
||||
let dir_name = target_path
|
||||
.parent()
|
||||
@@ -262,6 +264,17 @@ pub async fn unseal_file(path: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn content_starts_with_prefix(path: &Path, prefix: &str) -> io::Result<bool> {
|
||||
let mut file = File::open(path)?;
|
||||
let mut buffer = vec![0u8; prefix.len()];
|
||||
|
||||
match file.read_exact(&mut buffer) {
|
||||
Ok(()) => Ok(buffer == prefix.as_bytes()),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => Ok(false),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn secure_mount(
|
||||
volume_type: &str,
|
||||
options: &std::collections::HashMap<String, String>,
|
||||
@@ -294,7 +307,7 @@ mod tests {
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::Arc;
|
||||
use tempfile::tempdir;
|
||||
use tempfile::{tempdir, NamedTempFile};
|
||||
use test_utils::skip_if_not_root;
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
struct TestService;
|
||||
@@ -416,4 +429,34 @@ mod tests {
|
||||
rt.shutdown_background();
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_content_starts_with_prefix() {
|
||||
// Normal case: content matches the prefix
|
||||
let mut f = NamedTempFile::new().unwrap();
|
||||
write!(f, "sealed.hello_world").unwrap();
|
||||
assert!(content_starts_with_prefix(f.path(), "sealed.")
|
||||
.await
|
||||
.unwrap());
|
||||
|
||||
// Does not match the prefix
|
||||
let mut f2 = NamedTempFile::new().unwrap();
|
||||
write!(f2, "notsealed.hello_world").unwrap();
|
||||
assert!(!content_starts_with_prefix(f2.path(), "sealed.")
|
||||
.await
|
||||
.unwrap());
|
||||
|
||||
// File length < prefix.len()
|
||||
let mut f3 = NamedTempFile::new().unwrap();
|
||||
write!(f3, "seal").unwrap();
|
||||
assert!(!content_starts_with_prefix(f3.path(), "sealed.")
|
||||
.await
|
||||
.unwrap());
|
||||
|
||||
// Empty file
|
||||
let f4 = NamedTempFile::new().unwrap();
|
||||
assert!(!content_starts_with_prefix(f4.path(), "sealed.")
|
||||
.await
|
||||
.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,7 @@ pub fn is_ephemeral_volume(mount: &Mount) -> bool {
|
||||
mount.destination(),
|
||||
|
||||
),
|
||||
(Some("bind"), Some(source), dest) if get_linux_mount_info(source)
|
||||
.map_or(false, |info| info.fs_type == "tmpfs") &&
|
||||
(Some("bind"), Some(source), dest) if get_linux_mount_info(source).is_ok_and(|info| info.fs_type == "tmpfs") &&
|
||||
(is_empty_dir(source) || dest.as_path() == Path::new("/dev/shm"))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -823,11 +823,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_linux_mount_info() {
|
||||
let info = get_linux_mount_info("/sys/fs/cgroup").unwrap();
|
||||
let info = get_linux_mount_info("/dev/shm").unwrap();
|
||||
|
||||
assert_eq!(&info.device, "tmpfs");
|
||||
assert_eq!(&info.fs_type, "tmpfs");
|
||||
assert_eq!(&info.path, "/sys/fs/cgroup");
|
||||
assert_eq!(&info.path, "/dev/shm");
|
||||
|
||||
assert!(matches!(
|
||||
get_linux_mount_info(""),
|
||||
|
||||
@@ -168,7 +168,7 @@ pub fn is_valid_numa_cpu(cpus: &[u32]) -> Result<bool> {
|
||||
let numa_nodes = get_numa_nodes()?;
|
||||
|
||||
for cpu in cpus {
|
||||
if numa_nodes.get(cpu).is_none() {
|
||||
if !numa_nodes.contains_key(cpu) {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ impl PCIDevices for NvidiaPCIDevice {
|
||||
}
|
||||
}
|
||||
|
||||
return nvidia_devices;
|
||||
nvidia_devices
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use mockall::automock;
|
||||
use pci_ids::{Classes, Vendors};
|
||||
@@ -61,24 +61,22 @@ pub(crate) trait MemoryResourceTrait {
|
||||
|
||||
impl MemoryResourceTrait for MemoryResources {
|
||||
fn get_total_addressable_memory(&self, round_up: bool) -> (u64, u64) {
|
||||
let mut num_bar = 0;
|
||||
let mut mem_size_32bit = 0u64;
|
||||
let mut mem_size_64bit = 0u64;
|
||||
|
||||
let mut keys: Vec<_> = self.keys().cloned().collect();
|
||||
keys.sort();
|
||||
|
||||
for key in keys {
|
||||
if key as usize >= PCI_IOV_NUM_BAR || num_bar == PCI_IOV_NUM_BAR {
|
||||
for (num_bar, key) in keys.into_iter().enumerate() {
|
||||
if key >= PCI_IOV_NUM_BAR || num_bar == PCI_IOV_NUM_BAR {
|
||||
break;
|
||||
}
|
||||
num_bar += 1;
|
||||
|
||||
if let Some(region) = self.get(&key) {
|
||||
let flags = region.flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
|
||||
let mem_type_32bit = flags == PCI_BASE_ADDRESS_MEM_TYPE32;
|
||||
let mem_type_64bit = flags == PCI_BASE_ADDRESS_MEM_TYPE64;
|
||||
let mem_size = (region.end - region.start + 1) as u64;
|
||||
let mem_size = region.end - region.start + 1;
|
||||
|
||||
if mem_type_32bit {
|
||||
mem_size_32bit += mem_size;
|
||||
@@ -138,10 +136,10 @@ impl PCIDeviceManager {
|
||||
for entry in device_dirs {
|
||||
let device_dir = entry?;
|
||||
let device_address = device_dir.file_name().to_string_lossy().to_string();
|
||||
if let Ok(device) = self.get_device_by_pci_bus_id(&device_address, vendor, &mut cache) {
|
||||
if let Some(dev) = device {
|
||||
pci_devices.push(dev);
|
||||
}
|
||||
if let Ok(Some(dev)) =
|
||||
self.get_device_by_pci_bus_id(&device_address, vendor, &mut cache)
|
||||
{
|
||||
pci_devices.push(dev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +236,7 @@ impl PCIDeviceManager {
|
||||
Ok(Some(pci_device))
|
||||
}
|
||||
|
||||
fn parse_resources(&self, device_path: &PathBuf) -> io::Result<MemoryResources> {
|
||||
fn parse_resources(&self, device_path: &Path) -> io::Result<MemoryResources> {
|
||||
let content = fs::read_to_string(device_path.join("resource"))?;
|
||||
let mut resources: MemoryResources = MemoryResources::new();
|
||||
for (i, line) in content.lines().enumerate() {
|
||||
@@ -405,6 +403,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_resources() {
|
||||
setup_mock_device_files();
|
||||
|
||||
let manager = PCIDeviceManager::new(MOCK_PCI_DEVICES_ROOT);
|
||||
let device_path = PathBuf::from(MOCK_PCI_DEVICES_ROOT).join("0000:ff:1f.0");
|
||||
|
||||
@@ -418,6 +418,8 @@ mod tests {
|
||||
assert_eq!(resource.start, 0x00000000);
|
||||
assert_eq!(resource.end, 0x0000ffff);
|
||||
assert_eq!(resource.flags, 0x00000404);
|
||||
|
||||
cleanup_mock_device_files();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -435,10 +437,7 @@ mod tests {
|
||||
file.write_all(&vec![0; 512]).unwrap();
|
||||
|
||||
// It should be true
|
||||
assert!(is_pcie_device(
|
||||
&format!("ff:00.0"),
|
||||
MOCK_SYS_BUS_PCI_DEVICES
|
||||
));
|
||||
assert!(is_pcie_device("ff:00.0", MOCK_SYS_BUS_PCI_DEVICES));
|
||||
|
||||
// Clean up
|
||||
let _ = fs::remove_file(config_path);
|
||||
|
||||
@@ -142,14 +142,11 @@ pub fn arch_guest_protection(
|
||||
#[allow(dead_code)]
|
||||
pub fn available_guest_protection() -> Result<GuestProtection, ProtectionError> {
|
||||
if !Uid::effective().is_root() {
|
||||
return Err(ProtectionError::NoPerms)?;
|
||||
Err(ProtectionError::NoPerms)?;
|
||||
}
|
||||
|
||||
let facilities = crate::cpu::retrieve_cpu_facilities().map_err(|err| {
|
||||
ProtectionError::CheckFailed(format!(
|
||||
"Error retrieving cpu facilities file : {}",
|
||||
err.to_string()
|
||||
))
|
||||
ProtectionError::CheckFailed(format!("Error retrieving cpu facilities file : {}", err))
|
||||
})?;
|
||||
|
||||
// Secure Execution
|
||||
|
||||
@@ -8,7 +8,6 @@ use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader, Result};
|
||||
use std::result::{self};
|
||||
use std::u32;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -273,7 +272,8 @@ pub const KATA_ANNO_CFG_HYPERVISOR_VIRTIO_FS_EXTRA_ARGS: &str =
|
||||
/// A sandbox annotation to specify as the msize for 9p shares.
|
||||
pub const KATA_ANNO_CFG_HYPERVISOR_MSIZE_9P: &str = "io.katacontainers.config.hypervisor.msize_9p";
|
||||
/// The initdata annotation passed in when CVM launchs
|
||||
pub const KATA_ANNO_CFG_RUNTIME_INIT_DATA: &str = "io.katacontainers.config.runtime.cc_init_data";
|
||||
pub const KATA_ANNO_CFG_HYPERVISOR_INIT_DATA: &str =
|
||||
"io.katacontainers.config.hypervisor.cc_init_data";
|
||||
|
||||
/// GPU specific annotations for remote hypervisor to help with instance selection
|
||||
/// It's for minimum number of GPUs required for the VM.
|
||||
@@ -462,12 +462,12 @@ impl Annotation {
|
||||
/// update config info by annotation
|
||||
pub fn update_config_by_annotation(&self, config: &mut TomlConfig) -> Result<()> {
|
||||
if let Some(hv) = self.annotations.get(KATA_ANNO_CFG_RUNTIME_HYPERVISOR) {
|
||||
if config.hypervisor.get(hv).is_some() {
|
||||
if config.hypervisor.contains_key(hv) {
|
||||
config.runtime.hypervisor_name = hv.to_string();
|
||||
}
|
||||
}
|
||||
if let Some(ag) = self.annotations.get(KATA_ANNO_CFG_RUNTIME_AGENT) {
|
||||
if config.agent.get(ag).is_some() {
|
||||
if config.agent.contains_key(ag) {
|
||||
config.runtime.agent_name = ag.to_string();
|
||||
}
|
||||
}
|
||||
@@ -894,7 +894,7 @@ impl Annotation {
|
||||
hv.security_info.validate_path(value)?;
|
||||
hv.security_info.guest_hook_path = value.to_string();
|
||||
}
|
||||
KATA_ANNO_CFG_RUNTIME_INIT_DATA => {
|
||||
KATA_ANNO_CFG_HYPERVISOR_INIT_DATA => {
|
||||
hv.security_info.initdata =
|
||||
add_hypervisor_initdata_overrides(value).unwrap();
|
||||
}
|
||||
@@ -943,8 +943,7 @@ impl Annotation {
|
||||
}
|
||||
}
|
||||
KATA_ANNO_CFG_HYPERVISOR_VIRTIO_FS_EXTRA_ARGS => {
|
||||
let args: Vec<String> =
|
||||
value.to_string().split(',').map(str::to_string).collect();
|
||||
let args: Vec<String> = value.split(',').map(str::to_string).collect();
|
||||
for arg in args {
|
||||
hv.shared_fs.virtio_fs_extra_args.push(arg.to_string());
|
||||
}
|
||||
@@ -970,7 +969,7 @@ impl Annotation {
|
||||
// update agent config
|
||||
KATA_ANNO_CFG_KERNEL_MODULES => {
|
||||
let kernel_mod: Vec<String> =
|
||||
value.to_string().split(';').map(str::to_string).collect();
|
||||
value.split(';').map(str::to_string).collect();
|
||||
for modules in kernel_mod {
|
||||
ag.kernel_modules.push(modules.to_string());
|
||||
}
|
||||
@@ -991,14 +990,16 @@ impl Annotation {
|
||||
return Err(u32_err);
|
||||
}
|
||||
},
|
||||
KATA_ANNO_CFG_RUNTIME_CREATE_CONTAINTER_TIMEOUT => match self.get_value::<u32>(key) {
|
||||
Ok(v) => {
|
||||
ag.request_timeout_ms = v.unwrap_or_default() * 1000;
|
||||
KATA_ANNO_CFG_RUNTIME_CREATE_CONTAINTER_TIMEOUT => {
|
||||
match self.get_value::<u32>(key) {
|
||||
Ok(v) => {
|
||||
ag.request_timeout_ms = v.unwrap_or_default() * 1000;
|
||||
}
|
||||
Err(_e) => {
|
||||
return Err(u32_err);
|
||||
}
|
||||
}
|
||||
Err(_e) => {
|
||||
return Err(u32_err);
|
||||
}
|
||||
},
|
||||
}
|
||||
// update runtime config
|
||||
KATA_ANNO_CFG_RUNTIME_NAME => {
|
||||
let runtime = vec!["virt-container", "linux-container", "wasm-container"];
|
||||
@@ -1031,8 +1032,7 @@ impl Annotation {
|
||||
}
|
||||
},
|
||||
KATA_ANNO_CFG_EXPERIMENTAL => {
|
||||
let args: Vec<String> =
|
||||
value.to_string().split(',').map(str::to_string).collect();
|
||||
let args: Vec<String> = value.split(',').map(str::to_string).collect();
|
||||
for arg in args {
|
||||
config.runtime.experimental.push(arg.to_string());
|
||||
}
|
||||
|
||||
@@ -115,7 +115,10 @@ pub struct Agent {
|
||||
/// This timeout value is used to set the maximum duration for the agent to process a CreateContainerRequest.
|
||||
/// It's also used to ensure that workloads, especially those involving large image pulls within the guest,
|
||||
/// have sufficient time to complete.
|
||||
#[serde(default = "default_request_timeout", rename = "create_container_timeout")]
|
||||
#[serde(
|
||||
default = "default_request_timeout",
|
||||
rename = "create_container_timeout"
|
||||
)]
|
||||
pub request_timeout_ms: u32,
|
||||
|
||||
/// Agent health check request timeout value in millisecond
|
||||
@@ -127,12 +130,12 @@ pub struct Agent {
|
||||
/// These modules will be loaded in the guest kernel using modprobe(8).
|
||||
/// The following example can be used to load two kernel modules with parameters:
|
||||
/// - kernel_modules=["e1000e InterruptThrottleRate=3000,3000,3000 EEE=1", "i915 enable_ppgtt=0"]
|
||||
/// The first word is considered as the module name and the rest as its parameters.
|
||||
/// Container will not be started when:
|
||||
/// The first word is considered as the module name and the rest as its parameters.
|
||||
/// Container will not be started when:
|
||||
/// - A kernel module is specified and the modprobe command is not installed in the guest
|
||||
/// or it fails loading the module.
|
||||
/// - The module is not available in the guest or it doesn't met the guest kernel
|
||||
/// requirements, like architecture and version.
|
||||
/// requirements, like architecture and version.
|
||||
#[serde(default)]
|
||||
pub kernel_modules: Vec<String>,
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
use std::io::Result;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::u32;
|
||||
|
||||
use super::{default, register_hypervisor_plugin};
|
||||
use crate::config::default::MAX_DRAGONBALL_VCPUS;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ use std::fs;
|
||||
use std::io::{self, Result};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::u32;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use flate2::read::GzDecoder;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256, Sha384, Sha512};
|
||||
use std::{collections::HashMap, io::Read};
|
||||
use crate::sl;
|
||||
|
||||
/// Currently, initdata only supports version 0.1.0.
|
||||
const INITDATA_VERSION: &str = "0.1.0";
|
||||
@@ -129,20 +130,20 @@ fn calculate_digest(algorithm: &str, data: &str) -> Result<Vec<u8>> {
|
||||
let digest = match algorithm {
|
||||
"sha256" => {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&data);
|
||||
hasher.update(data);
|
||||
hasher.finalize().to_vec()
|
||||
}
|
||||
"sha384" => {
|
||||
let mut hasher = Sha384::new();
|
||||
hasher.update(&data);
|
||||
hasher.update(data);
|
||||
hasher.finalize().to_vec()
|
||||
}
|
||||
"sha512" => {
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(&data);
|
||||
hasher.update(data);
|
||||
hasher.finalize().to_vec()
|
||||
}
|
||||
_ => return Err(anyhow!("unsupported Hash algorithm: {}", algorithm).into()),
|
||||
_ => return Err(anyhow!("unsupported Hash algorithm: {}", algorithm)),
|
||||
};
|
||||
|
||||
Ok(digest)
|
||||
@@ -172,7 +173,7 @@ fn adjust_digest(digest: &[u8], platform: ProtectedPlatform) -> Vec<u8> {
|
||||
|
||||
/// Parse initdata
|
||||
fn parse_initdata(initdata_str: &str) -> Result<InitData> {
|
||||
let initdata: InitData = toml::from_str(&initdata_str)?;
|
||||
let initdata: InitData = toml::from_str(initdata_str)?;
|
||||
initdata.validate()?;
|
||||
|
||||
Ok(initdata)
|
||||
@@ -192,7 +193,7 @@ pub fn calculate_initdata_digest(
|
||||
let algorithm: &str = &initdata.algorithm;
|
||||
|
||||
// 2. Calculate Digest
|
||||
let digest = calculate_digest(algorithm, &initdata_toml).context("calculate digest")?;
|
||||
let digest = calculate_digest(algorithm, initdata_toml).context("calculate digest")?;
|
||||
|
||||
// 3. Adjust Digest with Platform
|
||||
let digest_platform = adjust_digest(&digest, platform);
|
||||
@@ -203,12 +204,18 @@ pub fn calculate_initdata_digest(
|
||||
Ok(b64encoded_digest)
|
||||
}
|
||||
|
||||
/// The argument `initda_annotation` is a Standard base64 encoded string containing a TOML formatted content.
|
||||
/// The argument `initdata_annotation` is a Standard base64 encoded string containing a TOML formatted content.
|
||||
/// This function decodes the base64 string, parses the TOML content into an InitData structure.
|
||||
pub fn add_hypervisor_initdata_overrides(initda_annotation: &str) -> Result<String> {
|
||||
pub fn add_hypervisor_initdata_overrides(initdata_annotation: &str) -> Result<String> {
|
||||
// If the initdata is empty, return an empty string
|
||||
if initdata_annotation.is_empty() {
|
||||
info!(sl!(), "initdata_annotation is empty");
|
||||
return Ok("".to_string());
|
||||
}
|
||||
|
||||
// Base64 decode the annotation value
|
||||
let b64_decoded =
|
||||
base64::decode_config(initda_annotation, base64::STANDARD).context("base64 decode")?;
|
||||
base64::decode_config(initdata_annotation, base64::STANDARD).context("base64 decode")?;
|
||||
|
||||
// Gzip decompress the decoded data
|
||||
let mut gz_decoder = GzDecoder::new(&b64_decoded[..]);
|
||||
@@ -231,6 +238,139 @@ mod tests {
|
||||
use flate2::Compression;
|
||||
use std::io::Write;
|
||||
|
||||
// create gzipped and base64 encoded string
|
||||
fn create_encoded_input(content: &str) -> String {
|
||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
|
||||
encoder.write_all(content.as_bytes()).unwrap();
|
||||
let compressed = encoder.finish().unwrap();
|
||||
base64::encode_config(&compressed, base64::STANDARD)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_annotation() {
|
||||
// Test with empty string input
|
||||
let result = add_hypervisor_initdata_overrides("");
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_data_section() {
|
||||
// Test with empty data section
|
||||
let toml_content = r#"
|
||||
algorithm = "sha384"
|
||||
version = "0.1.0"
|
||||
|
||||
[data]
|
||||
"#;
|
||||
let encoded = create_encoded_input(toml_content);
|
||||
|
||||
let result = add_hypervisor_initdata_overrides(&encoded);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_complete_initdata() {
|
||||
// Test with complete InitData structure
|
||||
let toml_content = r#"
|
||||
algorithm = "sha384"
|
||||
version = "0.1.0"
|
||||
|
||||
[data]
|
||||
"aa.toml" = '''
|
||||
[token_configs]
|
||||
[token_configs.coco_as]
|
||||
url = 'http://kbs-service.xxx.cluster.local:8080'
|
||||
|
||||
[token_configs.kbs]
|
||||
url = 'http://kbs-service.xxx.cluster.local:8080'
|
||||
'''
|
||||
|
||||
"cdh.toml" = '''
|
||||
socket = 'unix:///run/guest-services/cdh.sock'
|
||||
credentials = []
|
||||
|
||||
[kbc]
|
||||
name = 'cc_kbc'
|
||||
url = 'http://kbs-service.xxx.cluster.local:8080'
|
||||
'''
|
||||
"#;
|
||||
let encoded = create_encoded_input(toml_content);
|
||||
|
||||
let result = add_hypervisor_initdata_overrides(&encoded);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let output = result.unwrap();
|
||||
assert!(!output.is_empty());
|
||||
assert!(output.contains("algorithm"));
|
||||
assert!(output.contains("version"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_base64() {
|
||||
// Test with invalid base64 string
|
||||
let invalid_base64 = "This is not valid base64!";
|
||||
|
||||
let result = add_hypervisor_initdata_overrides(invalid_base64);
|
||||
assert!(result.is_err());
|
||||
|
||||
let error = result.unwrap_err();
|
||||
assert!(error.to_string().contains("base64 decode"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_base64_invalid_gzip() {
|
||||
// Test with valid base64 but invalid gzip content
|
||||
let not_gzipped = "This is not gzipped content";
|
||||
let encoded = base64::encode_config(not_gzipped.as_bytes(), base64::STANDARD);
|
||||
|
||||
let result = add_hypervisor_initdata_overrides(&encoded);
|
||||
assert!(result.is_err());
|
||||
|
||||
let error = result.unwrap_err();
|
||||
assert!(error.to_string().contains("gz decoder failed"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_algorithm() {
|
||||
// Test with missing algorithm field
|
||||
let toml_content = r#"
|
||||
version = "0.1.0"
|
||||
|
||||
[data]
|
||||
"test.toml" = '''
|
||||
key = "value"
|
||||
'''
|
||||
"#;
|
||||
let encoded = create_encoded_input(toml_content);
|
||||
|
||||
let result = add_hypervisor_initdata_overrides(&encoded);
|
||||
// This might fail depending on whether algorithm is required
|
||||
if result.is_err() {
|
||||
assert!(result.unwrap_err().to_string().contains("parse initdata"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_version() {
|
||||
// Test with missing version field
|
||||
let toml_content = r#"
|
||||
algorithm = "sha384"
|
||||
|
||||
[data]
|
||||
"test.toml" = '''
|
||||
key = "value"
|
||||
'''
|
||||
"#;
|
||||
let encoded = create_encoded_input(toml_content);
|
||||
|
||||
let result = add_hypervisor_initdata_overrides(&encoded);
|
||||
// This might fail depending on whether version is required
|
||||
if result.is_err() {
|
||||
assert!(result.unwrap_err().to_string().contains("parse initdata"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Test InitData creation and serialization
|
||||
#[test]
|
||||
fn test_init_data() {
|
||||
|
||||
@@ -205,47 +205,48 @@ pub struct NydusImageVolume {
|
||||
pub snapshot_dir: String,
|
||||
}
|
||||
|
||||
/// Kata virtual volume to encapsulate information for extra mount options and direct volumes.
|
||||
/// Represents a Kata virtual volume, encapsulating information for extra mount options and direct volumes.
|
||||
///
|
||||
/// It's very expensive to build direct communication channels to pass information:
|
||||
/// - between snapshotters and kata-runtime/kata-agent/image-rs
|
||||
/// - between CSI drivers and kata-runtime/kata-agent
|
||||
/// Direct communication channels between components like snapshotters, `kata-runtime`, `kata-agent`,
|
||||
/// `image-rs`, and CSI drivers are often expensive to build and maintain.
|
||||
///
|
||||
/// So `KataVirtualVolume` is introduced to encapsulate extra mount options and direct volume
|
||||
/// information, so we can build a common infrastructure to handle them.
|
||||
/// `KataVirtualVolume` is a superset of `NydusExtraOptions` and `DirectVolumeMountInfo`.
|
||||
/// Therefore, `KataVirtualVolume` is introduced as a common infrastructure to encapsulate
|
||||
/// additional mount options and direct volume information. It serves as a superset of
|
||||
/// `NydusExtraOptions` and `DirectVolumeMountInfo`.
|
||||
///
|
||||
/// Value of `volume_type` determines how to interpret other fields in the structure.
|
||||
/// The interpretation of other fields within this structure is determined by the `volume_type` field.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IGNORE`
|
||||
/// -- all other fields should be ignored/unused.
|
||||
/// # Volume Types:
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_DIRECT_BLOCK`
|
||||
/// -- `source`: the directly assigned block device
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `options`: mount options
|
||||
/// -- `direct_volume`: additional metadata to pass to the agent regarding this volume.
|
||||
/// - `KATA_VIRTUAL_VOLUME_IGNORE`:
|
||||
/// All other fields should be ignored/unused.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK`
|
||||
/// -- `source`: path to the raw block image for the container image or layer.
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `options`: mount options
|
||||
/// -- `dm_verity`: disk dm-verity information
|
||||
/// - `KATA_VIRTUAL_VOLUME_DIRECT_BLOCK`:
|
||||
/// - `source`: The directly assigned block device path.
|
||||
/// - `fs_type`: Filesystem type.
|
||||
/// - `options`: Mount options.
|
||||
/// - `direct_volume`: Additional metadata to pass to the agent regarding this volume.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK`
|
||||
/// -- `source`: path to nydus meta blob
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `nydus_image`: configuration information for nydus image.
|
||||
/// -- `dm_verity`: disk dm-verity information
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK`:
|
||||
/// - `source`: Path to the raw block image for the container image or layer.
|
||||
/// - `fs_type`: Filesystem type.
|
||||
/// - `options`: Mount options.
|
||||
/// - `dm_verity`: Disk `dm-verity` information.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS`
|
||||
/// -- `source`: path to nydus meta blob
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `nydus_image`: configuration information for nydus image.
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK`:
|
||||
/// - `source`: Path to nydus meta blob.
|
||||
/// - `fs_type`: Filesystem type.
|
||||
/// - `nydus_image`: Configuration information for nydus image.
|
||||
/// - `dm_verity`: Disk `dm-verity` information.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL`
|
||||
/// -- `source`: image reference
|
||||
/// -- `image_pull`: metadata for image pulling
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS`:
|
||||
/// - `source`: Path to nydus meta blob.
|
||||
/// - `fs_type`: Filesystem type.
|
||||
/// - `nydus_image`: Configuration information for nydus image.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL`:
|
||||
/// - `source`: Image reference.
|
||||
/// - `image_pull`: Metadata for image pulling.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct KataVirtualVolume {
|
||||
/// Type of virtual volume.
|
||||
@@ -275,7 +276,7 @@ pub struct KataVirtualVolume {
|
||||
}
|
||||
|
||||
impl KataVirtualVolume {
|
||||
/// Create a new instance of `KataVirtualVolume` with specified type.
|
||||
/// Creates a new instance of `KataVirtualVolume` with the specified type.
|
||||
pub fn new(volume_type: String) -> Self {
|
||||
Self {
|
||||
volume_type,
|
||||
@@ -283,7 +284,7 @@ impl KataVirtualVolume {
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate virtual volume object.
|
||||
/// Validates the virtual volume object.
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
match self.volume_type.as_str() {
|
||||
KATA_VIRTUAL_VOLUME_DIRECT_BLOCK => {
|
||||
@@ -365,25 +366,25 @@ impl KataVirtualVolume {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Serialize the virtual volume object to json.
|
||||
/// Serializes the virtual volume object to a JSON string.
|
||||
pub fn to_json(&self) -> Result<String> {
|
||||
Ok(serde_json::to_string(self)?)
|
||||
}
|
||||
|
||||
/// Deserialize a virtual volume object from json string.
|
||||
/// Deserializes a virtual volume object from a JSON string.
|
||||
pub fn from_json(value: &str) -> Result<Self> {
|
||||
let volume: KataVirtualVolume = serde_json::from_str(value)?;
|
||||
volume.validate()?;
|
||||
Ok(volume)
|
||||
}
|
||||
|
||||
/// Serialize the virtual volume object to json and encode the string with base64.
|
||||
/// Serializes the virtual volume object to a JSON string and encodes the string with base64.
|
||||
pub fn to_base64(&self) -> Result<String> {
|
||||
let json = self.to_json()?;
|
||||
Ok(base64::encode(json))
|
||||
}
|
||||
|
||||
/// Decode and deserialize a virtual volume object from base64 encoded json string.
|
||||
/// Decodes and deserializes a virtual volume object from a base64 encoded JSON string.
|
||||
pub fn from_base64(value: &str) -> Result<Self> {
|
||||
let json = base64::decode(value)?;
|
||||
let volume: KataVirtualVolume = serde_json::from_slice(&json)?;
|
||||
@@ -453,18 +454,18 @@ impl TryFrom<&NydusExtraOptions> for KataVirtualVolume {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait object for storage device.
|
||||
/// Trait object for a storage device.
|
||||
pub trait StorageDevice: Send + Sync {
|
||||
/// Path
|
||||
/// Returns the path of the storage device, if available.
|
||||
fn path(&self) -> Option<&str>;
|
||||
|
||||
/// Clean up resources related to the storage device.
|
||||
/// Cleans up resources related to the storage device.
|
||||
fn cleanup(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Join user provided volume path with kata direct-volume root path.
|
||||
/// Joins a user-provided volume path with the Kata direct-volume root path.
|
||||
///
|
||||
/// The `volume_path` is base64-url-encoded and then safely joined to the `prefix`
|
||||
/// The `volume_path` is base64-url-encoded and then safely joined to the `prefix`.
|
||||
pub fn join_path(prefix: &str, volume_path: &str) -> Result<PathBuf> {
|
||||
if volume_path.is_empty() {
|
||||
return Err(anyhow!(std::io::ErrorKind::NotFound));
|
||||
@@ -474,7 +475,7 @@ pub fn join_path(prefix: &str, volume_path: &str) -> Result<PathBuf> {
|
||||
Ok(safe_path::scoped_join(prefix, b64_url_encoded_path)?)
|
||||
}
|
||||
|
||||
/// get DirectVolume mountInfo from mountinfo.json.
|
||||
/// Gets `DirectVolumeMountInfo` from `mountinfo.json`.
|
||||
pub fn get_volume_mount_info(volume_path: &str) -> Result<DirectVolumeMountInfo> {
|
||||
let volume_path = join_path(KATA_DIRECT_VOLUME_ROOT_PATH, volume_path)?;
|
||||
let mount_info_file_path = volume_path.join(KATA_MOUNT_INFO_FILE_NAME);
|
||||
@@ -484,28 +485,30 @@ pub fn get_volume_mount_info(volume_path: &str) -> Result<DirectVolumeMountInfo>
|
||||
Ok(mount_info)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata specific volume.
|
||||
/// Checks whether a mount type is a marker for a Kata specific volume.
|
||||
pub fn is_kata_special_volume(ty: &str) -> bool {
|
||||
ty.len() > KATA_VOLUME_TYPE_PREFIX.len() && ty.starts_with(KATA_VOLUME_TYPE_PREFIX)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata guest mount volume.
|
||||
/// Checks whether a mount type is a marker for a Kata guest mount volume.
|
||||
pub fn is_kata_guest_mount_volume(ty: &str) -> bool {
|
||||
ty.len() > KATA_GUEST_MOUNT_PREFIX.len() && ty.starts_with(KATA_GUEST_MOUNT_PREFIX)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata ephemeral volume.
|
||||
/// Checks whether a mount type is a marker for a Kata ephemeral volume.
|
||||
pub fn is_kata_ephemeral_volume(ty: &str) -> bool {
|
||||
ty == KATA_EPHEMERAL_VOLUME_TYPE
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata hostdir volume.
|
||||
/// Checks whether a mount type is a marker for a Kata hostdir volume.
|
||||
pub fn is_kata_host_dir_volume(ty: &str) -> bool {
|
||||
ty == KATA_HOST_DIR_VOLUME_TYPE
|
||||
}
|
||||
|
||||
/// sandbox bindmount format: /path/to/dir, or /path/to/dir:ro[:rw]
|
||||
/// the real path is without suffix ":ro" or ":rw".
|
||||
/// Splits a sandbox bindmount string into its real path and mode.
|
||||
///
|
||||
/// The `bindmount` format is typically `/path/to/dir` or `/path/to/dir:ro[:rw]`.
|
||||
/// This function extracts the real path (without the suffix ":ro" or ":rw") and the mode.
|
||||
pub fn split_bind_mounts(bindmount: &str) -> (&str, &str) {
|
||||
let (real_path, mode) = if bindmount.ends_with(SANDBOX_BIND_MOUNTS_RO) {
|
||||
(
|
||||
@@ -525,12 +528,14 @@ pub fn split_bind_mounts(bindmount: &str) -> (&str, &str) {
|
||||
(real_path, mode)
|
||||
}
|
||||
|
||||
/// This function, adjust_rootfs_mounts, manages the root filesystem mounts based on guest-pull mechanism.
|
||||
/// - the function disregards any provided rootfs_mounts.
|
||||
/// Instead, it forcefully creates a single, default KataVirtualVolume specifically for guest-pull operations.
|
||||
/// This volume's representation is then base64-encoded and added as the only option to a new, singular Mount entry,
|
||||
/// which becomes the sole item in the returned Vec<Mount>.
|
||||
/// This ensures that when guest pull is active, the root filesystem is exclusively configured via this virtual volume.
|
||||
/// Adjusts the root filesystem mounts based on the guest-pull mechanism.
|
||||
///
|
||||
/// This function disregards any provided `rootfs_mounts`. Instead, it forcefully creates
|
||||
/// a single, default `KataVirtualVolume` specifically for guest-pull operations.
|
||||
/// This volume's representation is then base64-encoded and added as the only option
|
||||
/// to a new, singular `Mount` entry, which becomes the sole item in the returned `Vec<Mount>`.
|
||||
/// This ensures that when guest pull is active, the root filesystem is exclusively
|
||||
/// configured via this virtual volume.
|
||||
pub fn adjust_rootfs_mounts() -> Result<Vec<Mount>> {
|
||||
// We enforce a single, default KataVirtualVolume as the exclusive rootfs mount.
|
||||
let volume = KataVirtualVolume::new(KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string());
|
||||
|
||||
@@ -115,7 +115,7 @@ impl From<oci::PosixRlimit> for grpc::POSIXRlimit {
|
||||
impl From<oci::Process> for grpc::Process {
|
||||
fn from(from: oci::Process) -> Self {
|
||||
grpc::Process {
|
||||
Terminal: from.terminal().map_or(false, |t| t),
|
||||
Terminal: from.terminal().is_some_and(|t| t),
|
||||
ConsoleSize: from_option(from.console_size()),
|
||||
User: from_option(Some(from.user().clone())),
|
||||
Args: option_vec_to_vec(from.args()),
|
||||
@@ -161,7 +161,7 @@ impl From<oci::LinuxMemory> for grpc::LinuxMemory {
|
||||
Kernel: from.kernel().map_or(0, |t| t),
|
||||
KernelTCP: from.kernel_tcp().map_or(0, |t| t),
|
||||
Swappiness: from.swappiness().map_or(0, |t| t),
|
||||
DisableOOMKiller: from.disable_oom_killer().map_or(false, |t| t),
|
||||
DisableOOMKiller: from.disable_oom_killer().is_some_and(|t| t),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,6 +355,7 @@ mod tests {
|
||||
.read(false)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.mode(0o200)
|
||||
.open(&path)
|
||||
.unwrap();
|
||||
@@ -376,6 +377,7 @@ mod tests {
|
||||
.read(false)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.mode(0o200)
|
||||
.open(&path)
|
||||
.unwrap();
|
||||
|
||||
@@ -90,7 +90,7 @@ pub fn mgmt_socket_addr(sid: &str) -> Result<String> {
|
||||
));
|
||||
}
|
||||
|
||||
get_uds_with_sid(sid, &sb_storage_path()?)
|
||||
get_uds_with_sid(sid, sb_storage_path()?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -147,6 +147,7 @@ DEFMAXMEMSZ := 0
|
||||
##VAR DEFBRIDGES=<number> Default number of bridges
|
||||
DEFBRIDGES := 0
|
||||
DEFENABLEANNOTATIONS := [\"kernel_params\"]
|
||||
DEFENABLEANNOTATIONS_COCO := [\"kernel_params\",\"cc_init_data\"]
|
||||
DEFDISABLEGUESTSECCOMP := true
|
||||
DEFDISABLEGUESTEMPTYDIR := false
|
||||
##VAR DEFAULTEXPFEATURES=[features] Default experimental features enabled
|
||||
@@ -482,6 +483,7 @@ USER_VARS += DEFVIRTIOFSCACHE
|
||||
USER_VARS += DEFVIRTIOFSQUEUESIZE
|
||||
USER_VARS += DEFVIRTIOFSEXTRAARGS
|
||||
USER_VARS += DEFENABLEANNOTATIONS
|
||||
USER_VARS += DEFENABLEANNOTATIONS_COCO
|
||||
USER_VARS += DEFENABLEIOTHREADS
|
||||
USER_VARS += DEFSECCOMPSANDBOXPARAM
|
||||
USER_VARS += DEFGUESTSELINUXLABEL
|
||||
|
||||
@@ -195,6 +195,9 @@ block_device_driver = "virtio-blk-pci"
|
||||
# result in memory pre allocation
|
||||
#enable_hugepages = true
|
||||
|
||||
# Disable the 'seccomp' feature from Cloud Hypervisor or firecracker, default false
|
||||
# disable_seccomp = true
|
||||
|
||||
# This option changes the default hypervisor and kernel parameters
|
||||
# to enable debug output where available.
|
||||
#
|
||||
|
||||
@@ -45,7 +45,7 @@ confidential_guest = true
|
||||
# List of valid annotation names for the hypervisor
|
||||
# Each member of the list is a regular expression, which is the base name
|
||||
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
|
||||
enable_annotations = @DEFENABLEANNOTATIONS@
|
||||
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
|
||||
|
||||
# List of valid annotations values for the hypervisor
|
||||
# Each member of the list is a path pattern as described by glob(3).
|
||||
|
||||
@@ -145,6 +145,9 @@ block_device_driver = "@DEFBLOCKSTORAGEDRIVER_FC@"
|
||||
# result in memory pre allocation
|
||||
#enable_hugepages = true
|
||||
|
||||
# Disable the 'seccomp' feature from Cloud Hypervisor or firecracker, default false
|
||||
# disable_seccomp = true
|
||||
|
||||
# Enable vIOMMU, default false
|
||||
# Enabling this will result in the VM having a vIOMMU device
|
||||
# This will also add the following options to the kernel's
|
||||
|
||||
@@ -103,6 +103,9 @@ impl FcInner {
|
||||
cmd.args(["--api-sock", &self.asock_path]);
|
||||
}
|
||||
}
|
||||
if self.config.security_info.disable_seccomp {
|
||||
cmd.arg("--no-seccomp");
|
||||
}
|
||||
debug!(sl(), "Exec: {:?}", cmd);
|
||||
|
||||
// Make sure we're in the correct Network Namespace
|
||||
|
||||
@@ -2182,6 +2182,14 @@ impl<'a> QemuCmdLine<'a> {
|
||||
qemu_cmd_line.add_virtio_balloon();
|
||||
}
|
||||
|
||||
if let Some(seccomp_sandbox) = &config
|
||||
.security_info
|
||||
.seccomp_sandbox
|
||||
.as_ref()
|
||||
.filter(|s| !s.is_empty())
|
||||
{
|
||||
qemu_cmd_line.add_seccomp_sandbox(seccomp_sandbox);
|
||||
}
|
||||
Ok(qemu_cmd_line)
|
||||
}
|
||||
|
||||
@@ -2620,6 +2628,11 @@ impl<'a> QemuCmdLine<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_seccomp_sandbox(&mut self, param: &str) {
|
||||
let seccomp_sandbox = SeccompSandbox::new(param);
|
||||
self.devices.push(Box::new(seccomp_sandbox));
|
||||
}
|
||||
|
||||
pub async fn build(&self) -> Result<Vec<String>> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
@@ -2706,3 +2719,23 @@ impl ToQemuParams for DeviceVirtioBalloon {
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SeccompSandbox {
|
||||
param: String,
|
||||
}
|
||||
|
||||
impl SeccompSandbox {
|
||||
fn new(param: &str) -> Self {
|
||||
SeccompSandbox {
|
||||
param: param.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ToQemuParams for SeccompSandbox {
|
||||
async fn qemu_params(&self) -> Result<Vec<String>> {
|
||||
Ok(vec!["-sandbox".to_owned(), self.param.clone()])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ use kata_types::{
|
||||
cri_containerd::{SANDBOX_NAMESPACE_LABEL_KEY, SANDBOX_NAME_LABEL_KEY},
|
||||
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_GPUS, KATA_ANNO_CFG_HYPERVISOR_DEFAULT_GPU_MODEL,
|
||||
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_MEMORY, KATA_ANNO_CFG_HYPERVISOR_DEFAULT_VCPUS,
|
||||
KATA_ANNO_CFG_HYPERVISOR_IMAGE_PATH, KATA_ANNO_CFG_HYPERVISOR_MACHINE_TYPE,
|
||||
KATA_ANNO_CFG_RUNTIME_INIT_DATA,
|
||||
KATA_ANNO_CFG_HYPERVISOR_IMAGE_PATH, KATA_ANNO_CFG_HYPERVISOR_INIT_DATA,
|
||||
KATA_ANNO_CFG_HYPERVISOR_MACHINE_TYPE,
|
||||
},
|
||||
capabilities::{Capabilities, CapabilityBits},
|
||||
};
|
||||
@@ -127,7 +127,7 @@ impl RemoteInner {
|
||||
config.boot_info.image.to_string(),
|
||||
);
|
||||
annotations.insert(
|
||||
KATA_ANNO_CFG_RUNTIME_INIT_DATA.to_string(),
|
||||
KATA_ANNO_CFG_HYPERVISOR_INIT_DATA.to_string(),
|
||||
config.security_info.initdata.to_string(),
|
||||
);
|
||||
annotations.insert(
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use std::{collections::HashMap, sync::Arc, thread};
|
||||
|
||||
use agent::{types::Device, Agent, OnlineCPUMemRequest, Storage};
|
||||
use agent::{types::Device, ARPNeighbor, Agent, OnlineCPUMemRequest, Storage};
|
||||
use anyhow::{anyhow, Context, Ok, Result};
|
||||
use async_trait::async_trait;
|
||||
use hypervisor::{
|
||||
@@ -22,6 +22,7 @@ use kata_types::{
|
||||
config::{hypervisor::TopologyConfigInfo, TomlConfig},
|
||||
mount::{adjust_rootfs_mounts, KATA_IMAGE_FORCE_GUEST_PULL},
|
||||
};
|
||||
use libc::NUD_PERMANENT;
|
||||
use oci::{Linux, LinuxCpu, LinuxResources};
|
||||
use oci_spec::runtime::{self as oci, LinuxDeviceType};
|
||||
use persist::sandbox_persist::Persist;
|
||||
@@ -260,7 +261,14 @@ impl ResourceManagerInner {
|
||||
}
|
||||
|
||||
async fn handle_neighbours(&self, network: &dyn Network) -> Result<()> {
|
||||
let neighbors = network.neighs().await.context("neighs")?;
|
||||
let all_neighbors = network.neighs().await.context("neighs")?;
|
||||
|
||||
// We add only static ARP entries
|
||||
let neighbors: Vec<ARPNeighbor> = all_neighbors
|
||||
.iter()
|
||||
.filter(|n| n.state == NUD_PERMANENT as i32)
|
||||
.cloned()
|
||||
.collect();
|
||||
if !neighbors.is_empty() {
|
||||
info!(sl!(), "update neighbors {:?}", neighbors);
|
||||
self.agent
|
||||
|
||||
@@ -16,9 +16,11 @@ ifeq ($(ARCH),)
|
||||
endif
|
||||
ifeq ($(ARCH),x86_64)
|
||||
override ARCH = amd64
|
||||
override EDK2_NAME = ovmf
|
||||
endif
|
||||
ifeq ($(ARCH),aarch64)
|
||||
override ARCH = arm64
|
||||
override EDK2_NAME = aavmf
|
||||
endif
|
||||
ifeq ($(ARCH),riscv64gc)
|
||||
override ARCH = riscv64
|
||||
@@ -215,7 +217,7 @@ DEFMAXMEMSZ := 0
|
||||
#Default number of bridges
|
||||
DEFBRIDGES := 1
|
||||
DEFENABLEANNOTATIONS := [\"enable_iommu\", \"virtio_fs_extra_args\", \"kernel_params\"]
|
||||
DEFENABLEANNOTATIONSTEE := [\"enable_iommu\", \"virtio_fs_extra_args\", \"kernel_params\", \"default_vcpus\", \"default_memory\"]
|
||||
DEFENABLEANNOTATIONS_COCO := [\"enable_iommu\", \"virtio_fs_extra_args\", \"kernel_params\", \"default_vcpus\", \"default_memory\", \"cc_init_data\"]
|
||||
DEFDISABLEGUESTSECCOMP := true
|
||||
DEFDISABLEGUESTEMPTYDIR := false
|
||||
#Default experimental features enabled
|
||||
@@ -460,10 +462,10 @@ ifneq (,$(QEMUCMD))
|
||||
FIRMWAREPATH_NV := $(PREFIXDEPS)/share/ovmf/OVMF.fd
|
||||
|
||||
ifneq (,$(QEMUFW))
|
||||
FIRMWAREPATH := $(PREFIXDEPS)/share/ovmf/$(QEMUFW)
|
||||
FIRMWAREPATH := $(PREFIXDEPS)/share/$(EDK2_NAME)/$(QEMUFW)
|
||||
endif
|
||||
ifneq (,$(QEMUFWVOL))
|
||||
FIRMWAREVOLUMEPATH := $(PREFIXDEPS)/share/ovmf/$(QEMUFWVOL)
|
||||
FIRMWAREVOLUMEPATH := $(PREFIXDEPS)/share/$(EDK2_NAME)/$(QEMUFWVOL)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -729,7 +731,7 @@ USER_VARS += DEFVIRTIOFSCACHE
|
||||
USER_VARS += DEFVIRTIOFSQUEUESIZE
|
||||
USER_VARS += DEFVIRTIOFSEXTRAARGS
|
||||
USER_VARS += DEFENABLEANNOTATIONS
|
||||
USER_VARS += DEFENABLEANNOTATIONSTEE
|
||||
USER_VARS += DEFENABLEANNOTATIONS_COCO
|
||||
USER_VARS += DEFENABLEIOTHREADS
|
||||
USER_VARS += DEFSECCOMPSANDBOXPARAM
|
||||
USER_VARS += DEFENABLEVHOSTUSERSTORE
|
||||
|
||||
@@ -55,7 +55,7 @@ rootfs_type=@DEFROOTFSTYPE@
|
||||
# List of valid annotation names for the hypervisor
|
||||
# Each member of the list is a regular expression, which is the base name
|
||||
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
|
||||
enable_annotations = @DEFENABLEANNOTATIONSTEE@
|
||||
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
|
||||
|
||||
# List of valid annotations values for the hypervisor
|
||||
# Each member of the list is a path pattern as described by glob(3).
|
||||
|
||||
@@ -62,8 +62,9 @@ valid_hypervisor_paths = @QEMUSNPVALIDHYPERVISORPATHS@
|
||||
|
||||
# SNP 'ID Block' and 'ID Authentication Information Structure'.
|
||||
# If one of snp_id_block or snp_id_auth is specified, the other must be specified, too.
|
||||
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, and the IDBlock
|
||||
# must be generated with exactly this policy.
|
||||
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, if not explicitly
|
||||
# set via 'snp_guest_policy' option. The IDBlock contains the guest policy as field, and
|
||||
# it must match the value from 'snp_guest_policy' or, if unset, the QEMU default policy.
|
||||
#
|
||||
# 96-byte, base64-encoded blob to provide the ‘ID Block’ structure for the
|
||||
# SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
|
||||
@@ -72,6 +73,13 @@ valid_hypervisor_paths = @QEMUSNPVALIDHYPERVISORPATHS@
|
||||
# for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
|
||||
#snp_id_auth = ""
|
||||
|
||||
# SNP Guest Policy, the ‘POLICY’ parameter to the SNP_LAUNCH_START command.
|
||||
# If unset, the QEMU default policy (0x30000) will be used.
|
||||
# Notice that the guest policy is enforced at VM launch, and your pod VMs
|
||||
# won't start at all if the policy denys it. This will be indicated by a
|
||||
# 'SNP_LAUNCH_START' error.
|
||||
#snp_guest_policy = 196608
|
||||
|
||||
# Optional space-separated list of options to pass to the guest kernel.
|
||||
# For example, use `kernel_params = "vsyscall=emulate"` if you are having
|
||||
# trouble running pre-2.15 glibc.
|
||||
|
||||
@@ -40,7 +40,7 @@ confidential_guest = true
|
||||
# List of valid annotation names for the hypervisor
|
||||
# Each member of the list is a regular expression, which is the base name
|
||||
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
|
||||
enable_annotations = @DEFENABLEANNOTATIONS@
|
||||
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
|
||||
|
||||
# List of valid annotations values for the hypervisor
|
||||
# Each member of the list is a path pattern as described by glob(3).
|
||||
|
||||
@@ -62,8 +62,9 @@ valid_hypervisor_paths = @QEMUVALIDHYPERVISORPATHS@
|
||||
|
||||
# SNP 'ID Block' and 'ID Authentication Information Structure'.
|
||||
# If one of snp_id_block or snp_id_auth is specified, the other must be specified, too.
|
||||
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, and the IDBlock
|
||||
# must be generated with exactly this policy.
|
||||
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, if not explicitly
|
||||
# set via 'snp_guest_policy' option. The IDBlock contains the guest policy as field, and
|
||||
# it must match the value from 'snp_guest_policy' or, if unset, the QEMU default policy.
|
||||
#
|
||||
# 96-byte, base64-encoded blob to provide the ‘ID Block’ structure for the
|
||||
# SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
|
||||
@@ -72,6 +73,13 @@ valid_hypervisor_paths = @QEMUVALIDHYPERVISORPATHS@
|
||||
# for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
|
||||
#snp_id_auth = ""
|
||||
|
||||
# SNP Guest Policy, the ‘POLICY’ parameter to the SNP_LAUNCH_START command.
|
||||
# If unset, the QEMU default policy (0x30000) will be used.
|
||||
# Notice that the guest policy is enforced at VM launch, and your pod VMs
|
||||
# won't start at all if the policy denys it. This will be indicated by a
|
||||
# 'SNP_LAUNCH_START' error.
|
||||
#snp_guest_policy = 196608
|
||||
|
||||
# Optional space-separated list of options to pass to the guest kernel.
|
||||
# For example, use `kernel_params = "vsyscall=emulate"` if you are having
|
||||
# trouble running pre-2.15 glibc.
|
||||
|
||||
@@ -49,7 +49,7 @@ confidential_guest = true
|
||||
# List of valid annotation names for the hypervisor
|
||||
# Each member of the list is a regular expression, which is the base name
|
||||
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
|
||||
enable_annotations = @DEFENABLEANNOTATIONSTEE@
|
||||
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
|
||||
|
||||
# List of valid annotations values for the hypervisor
|
||||
# Each member of the list is a path pattern as described by glob(3).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module github.com/kata-containers/kata-containers/src/runtime
|
||||
|
||||
// Keep in sync with version in versions.yaml
|
||||
go 1.23.0
|
||||
go 1.23.12
|
||||
|
||||
// WARNING: Do NOT use `replace` directives as those break dependabot:
|
||||
// https://github.com/kata-containers/kata-containers/issues/11020
|
||||
|
||||
@@ -330,6 +330,9 @@ type Object struct {
|
||||
// for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (default: all-zero)
|
||||
SnpIdAuth string
|
||||
|
||||
// SnpGuestPolicy is the integer representation of the SEV-SNP guest policy.
|
||||
SnpGuestPolicy *uint64
|
||||
|
||||
// Raw byte slice of initdata digest
|
||||
InitdataDigest []byte
|
||||
}
|
||||
@@ -415,6 +418,9 @@ func (object Object) QemuParams(config *Config) []string {
|
||||
if object.SnpIdAuth != "" {
|
||||
objectParams = append(objectParams, fmt.Sprintf("id-auth=%s", object.SnpIdAuth))
|
||||
}
|
||||
if object.SnpGuestPolicy != nil {
|
||||
objectParams = append(objectParams, fmt.Sprintf("policy=%d", *object.SnpGuestPolicy))
|
||||
}
|
||||
if len(object.InitdataDigest) > 0 {
|
||||
// due to https://github.com/confidential-containers/qemu/blob/amd-snp-202402240000/qapi/qom.json#L926-L929
|
||||
// hostdata in SEV-SNP should be exactly 32 bytes
|
||||
|
||||
@@ -109,6 +109,7 @@ type hypervisor struct {
|
||||
RemoteHypervisorSocket string `toml:"remote_hypervisor_socket"`
|
||||
SnpIdBlock string `toml:"snp_id_block"`
|
||||
SnpIdAuth string `toml:"snp_id_auth"`
|
||||
SnpGuestPolicy *uint64 `toml:"snp_guest_policy"`
|
||||
HypervisorPathList []string `toml:"valid_hypervisor_paths"`
|
||||
JailerPathList []string `toml:"valid_jailer_paths"`
|
||||
VirtioFSDaemonList []string `toml:"valid_virtio_fs_daemon_paths"`
|
||||
@@ -992,6 +993,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
|
||||
ExtraMonitorSocket: extraMonitorSocket,
|
||||
SnpIdBlock: h.SnpIdBlock,
|
||||
SnpIdAuth: h.SnpIdAuth,
|
||||
SnpGuestPolicy: h.SnpGuestPolicy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -885,6 +885,9 @@ func TestAddRuntimeAnnotations(t *testing.T) {
|
||||
|
||||
runtimeConfig := RuntimeConfig{
|
||||
HypervisorType: vc.QemuHypervisor,
|
||||
HypervisorConfig: vc.HypervisorConfig{
|
||||
EnableAnnotations: []string{"cc_init_data"},
|
||||
},
|
||||
}
|
||||
|
||||
ocispec.Annotations[vcAnnotations.DisableGuestSeccomp] = "true"
|
||||
|
||||
@@ -473,6 +473,9 @@ type HypervisorConfig struct {
|
||||
// for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (default: all-zero)
|
||||
SnpIdAuth string
|
||||
|
||||
// SnpGuestPolicy is the integer representation of the SEV-SNP guest policy.
|
||||
SnpGuestPolicy *uint64
|
||||
|
||||
// KernelParams are additional guest kernel parameters.
|
||||
KernelParams []Param
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ const (
|
||||
EnableRootlessHypervisor = kataAnnotHypervisorPrefix + "rootless"
|
||||
|
||||
// Initdata is the initdata passed in when CreateVM
|
||||
Initdata = kataConfAnnotationsPrefix + "runtime.cc_init_data"
|
||||
Initdata = kataConfAnnotationsPrefix + "hypervisor.cc_init_data"
|
||||
)
|
||||
|
||||
// Runtime related annotations
|
||||
|
||||
@@ -397,23 +397,6 @@ func (q *qemu) createQmpSocket() ([]govmmQemu.QMPSocket, error) {
|
||||
return sockets, nil
|
||||
}
|
||||
|
||||
func (q *qemu) buildInitdataDevice(devices []govmmQemu.Device, InitdataImage string) []govmmQemu.Device {
|
||||
device := govmmQemu.BlockDevice{
|
||||
Driver: govmmQemu.VirtioBlock,
|
||||
Transport: govmmQemu.TransportPCI,
|
||||
ID: "initdata",
|
||||
File: InitdataImage,
|
||||
SCSI: false,
|
||||
WCE: false,
|
||||
AIO: govmmQemu.Threads,
|
||||
Interface: "none",
|
||||
Format: "raw",
|
||||
}
|
||||
|
||||
devices = append(devices, device)
|
||||
return devices
|
||||
}
|
||||
|
||||
func (q *qemu) buildDevices(ctx context.Context, kernelPath string) ([]govmmQemu.Device, *govmmQemu.IOThread, *govmmQemu.Kernel, error) {
|
||||
var devices []govmmQemu.Device
|
||||
|
||||
@@ -763,7 +746,7 @@ func (q *qemu) CreateVM(ctx context.Context, id string, network Network, hypervi
|
||||
}
|
||||
|
||||
if len(hypervisorConfig.Initdata) > 0 {
|
||||
devices = q.buildInitdataDevice(devices, hypervisorConfig.InitdataImage)
|
||||
devices = q.arch.buildInitdataDevice(ctx, devices, hypervisorConfig.InitdataImage)
|
||||
}
|
||||
|
||||
// some devices configuration may also change kernel params, make sure this is called afterwards
|
||||
|
||||
@@ -38,6 +38,8 @@ type qemuAmd64 struct {
|
||||
snpIdBlock string
|
||||
|
||||
snpIdAuth string
|
||||
|
||||
snpGuestPolicy *uint64
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -126,11 +128,12 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
|
||||
protection: noneProtection,
|
||||
legacySerial: config.LegacySerial,
|
||||
},
|
||||
vmFactory: factory,
|
||||
snpGuest: config.SevSnpGuest,
|
||||
qgsPort: config.QgsPort,
|
||||
snpIdBlock: config.SnpIdBlock,
|
||||
snpIdAuth: config.SnpIdAuth,
|
||||
vmFactory: factory,
|
||||
snpGuest: config.SevSnpGuest,
|
||||
qgsPort: config.QgsPort,
|
||||
snpIdBlock: config.SnpIdBlock,
|
||||
snpIdAuth: config.SnpIdAuth,
|
||||
snpGuestPolicy: config.SnpGuestPolicy,
|
||||
}
|
||||
|
||||
if config.ConfidentialGuest {
|
||||
@@ -315,6 +318,7 @@ func (q *qemuAmd64) appendProtectionDevice(devices []govmmQemu.Device, firmware,
|
||||
CBitPos: cpuid.AMDMemEncrypt.CBitPosition,
|
||||
ReducedPhysBits: 1,
|
||||
InitdataDigest: initdataDigest,
|
||||
SnpGuestPolicy: q.snpGuestPolicy,
|
||||
}
|
||||
if q.snpIdBlock != "" && q.snpIdAuth != "" {
|
||||
obj.SnpIdBlock = q.snpIdBlock
|
||||
|
||||
@@ -176,6 +176,9 @@ type qemuArch interface {
|
||||
|
||||
// Query QMP to find the PCI slot of a device, given its QOM path or ID
|
||||
qomGetSlot(qomPath string, qmpCh *qmpChannel) (types.PciSlot, error)
|
||||
|
||||
// buildInitdataDevice creates an initdata device for the given architecture.
|
||||
buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device
|
||||
}
|
||||
|
||||
type qemuArchBase struct {
|
||||
@@ -949,6 +952,24 @@ func (q *qemuArchBase) qomGetSlot(qomPath string, qmpCh *qmpChannel) (types.PciS
|
||||
return types.PciSlotFromInt(slotNum)
|
||||
}
|
||||
|
||||
// build initdata device
|
||||
func (q *qemuArchBase) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
|
||||
device := govmmQemu.BlockDevice{
|
||||
Driver: govmmQemu.VirtioBlock,
|
||||
Transport: govmmQemu.TransportPCI,
|
||||
ID: "initdata",
|
||||
File: initdataImage,
|
||||
SCSI: false,
|
||||
WCE: false,
|
||||
AIO: govmmQemu.Threads,
|
||||
Interface: "none",
|
||||
Format: "raw",
|
||||
}
|
||||
|
||||
devices = append(devices, device)
|
||||
return devices
|
||||
}
|
||||
|
||||
// Query QMP to find a device's PCI path given its QOM path or ID
|
||||
func (q *qemuArchBase) qomGetPciPath(qemuID string, qmpCh *qmpChannel) (types.PciPath, error) {
|
||||
|
||||
|
||||
@@ -154,6 +154,11 @@ func (q *qemuArm64) enableProtection() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *qemuArm64) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
|
||||
hvLogger.Warnf("buildInitdataDevice not implemented for arm64; ignoring initdata image: %s", initdataImage)
|
||||
return devices
|
||||
}
|
||||
|
||||
func (q *qemuArm64) appendProtectionDevice(devices []govmmQemu.Device, firmware, firmwareVolume string, initdataDigest []byte) ([]govmmQemu.Device, string, error) {
|
||||
err := q.enableProtection()
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package virtcontainers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -156,6 +157,11 @@ func (q *qemuPPC64le) enableProtection() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (q *qemuPPC64le) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
|
||||
hvLogger.Warnf("buildInitdataDevice not implemented for PPC64le; ignoring initdata image: %s", initdataImage)
|
||||
return devices
|
||||
}
|
||||
|
||||
// append protection device
|
||||
func (q *qemuPPC64le) appendProtectionDevice(devices []govmmQemu.Device, firmware, firmwareVolume string, initdataDigest []byte) ([]govmmQemu.Device, string, error) {
|
||||
switch q.protection {
|
||||
|
||||
@@ -349,8 +349,9 @@ func (q *qemuS390x) appendProtectionDevice(devices []govmmQemu.Device, firmware,
|
||||
case seProtection:
|
||||
return append(devices,
|
||||
govmmQemu.Object{
|
||||
Type: govmmQemu.SecExecGuest,
|
||||
ID: secExecID,
|
||||
Type: govmmQemu.SecExecGuest,
|
||||
ID: secExecID,
|
||||
InitdataDigest: initdataDigest,
|
||||
}), firmware, nil
|
||||
case noneProtection:
|
||||
return devices, firmware, nil
|
||||
@@ -382,6 +383,42 @@ func (q *qemuS390x) appendVFIODevice(devices []govmmQemu.Device, vfioDev config.
|
||||
return devices
|
||||
}
|
||||
|
||||
func (q *qemuS390x) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
|
||||
|
||||
var transport govmmQemu.VirtioTransport
|
||||
var devNo string
|
||||
|
||||
transport = govmmQemu.TransportCCW
|
||||
id := "initdata"
|
||||
addr, bridge, err := q.addDeviceToBridge(ctx, id, types.CCW)
|
||||
if err != nil {
|
||||
hvLogger.WithError(err).Error("Failed to allocate CCW address for initdata")
|
||||
return nil
|
||||
}
|
||||
devNo, err = bridge.AddressFormatCCW(addr)
|
||||
if err != nil {
|
||||
hvLogger.WithError(err).Error("Failed to format CCW address for initdata")
|
||||
return nil
|
||||
}
|
||||
hvLogger.WithField("devno", devNo).Info("Using dynamic CCW DevNo for initdata")
|
||||
|
||||
device := govmmQemu.BlockDevice{
|
||||
Driver: govmmQemu.VirtioBlock,
|
||||
Transport: transport,
|
||||
ID: id,
|
||||
File: initdataImage,
|
||||
SCSI: false,
|
||||
WCE: false,
|
||||
AIO: govmmQemu.Threads,
|
||||
Interface: "none",
|
||||
Format: "raw",
|
||||
DevNo: devNo,
|
||||
}
|
||||
|
||||
devices = append(devices, device)
|
||||
return devices
|
||||
}
|
||||
|
||||
// Query QMP to find a device's PCI path given its QOM path or ID
|
||||
func (q *qemuS390x) qomGetPciPath(qemuID string, qmpCh *qmpChannel) (types.PciPath, error) {
|
||||
hvLogger.Warnf("qomGetPciPath not implemented for s390x")
|
||||
|
||||
@@ -144,14 +144,15 @@ func TestQemuS390xAppendProtectionDevice(t *testing.T) {
|
||||
// Secure Execution protection
|
||||
s390x.(*qemuS390x).protection = seProtection
|
||||
|
||||
devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "", []byte(nil))
|
||||
devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "", []byte(""))
|
||||
assert.NoError(err)
|
||||
assert.Empty(bios)
|
||||
|
||||
expectedOut := []govmmQemu.Device{
|
||||
govmmQemu.Object{
|
||||
Type: govmmQemu.SecExecGuest,
|
||||
ID: secExecID,
|
||||
Type: govmmQemu.SecExecGuest,
|
||||
ID: secExecID,
|
||||
InitdataDigest: []byte(""),
|
||||
},
|
||||
}
|
||||
assert.Equal(expectedOut, devices)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module kata-containers/csi-kata-directvolume
|
||||
|
||||
// Keep in sync with version in versions.yaml
|
||||
go 1.23.0
|
||||
go 1.23.12
|
||||
|
||||
// WARNING: Do NOT use `replace` directives as those break dependabot:
|
||||
// https://github.com/kata-containers/kata-containers/issues/11020
|
||||
|
||||
@@ -347,6 +347,14 @@
|
||||
"^127\\.(?:[0-9]{1,3}\\.){2}[0-9]{1,3}$"
|
||||
]
|
||||
},
|
||||
"AddARPNeighborsRequest": {
|
||||
"forbidden_device_names": [
|
||||
"lo"
|
||||
],
|
||||
"forbidden_cidrs_regex": [
|
||||
"^127\\.(?:[0-9]{1,3}\\.){2}[0-9]{1,3}$"
|
||||
]
|
||||
},
|
||||
"CloseStdinRequest": false,
|
||||
"ReadStreamRequest": false,
|
||||
"UpdateEphemeralMountsRequest": false,
|
||||
|
||||
@@ -1400,6 +1400,25 @@ UpdateInterfaceRequest if {
|
||||
print("UpdateInterfaceRequest: true")
|
||||
}
|
||||
|
||||
AddARPNeighborsRequest if {
|
||||
p_defaults := policy_data.request_defaults.AddARPNeighborsRequest
|
||||
print("AddARPNeighborsRequest: policy =", p_defaults)
|
||||
|
||||
every i_neigh in input.neighbors.ARPNeighbors {
|
||||
print("AddARPNeighborsRequest: i_neigh =", i_neigh)
|
||||
|
||||
not i_neigh.device in p_defaults.forbidden_device_names
|
||||
i_neigh.toIPAddress.mask == ""
|
||||
every p_cidr in p_defaults.forbidden_cidrs_regex {
|
||||
not regex.match(p_cidr, i_neigh.toIPAddress.address)
|
||||
}
|
||||
i_neigh.state == 128
|
||||
bits.or(i_neigh.flags, 136) == 136
|
||||
}
|
||||
|
||||
print("AddARPNeighborsRequest: true")
|
||||
}
|
||||
|
||||
CloseStdinRequest if {
|
||||
policy_data.request_defaults.CloseStdinRequest == true
|
||||
}
|
||||
|
||||
@@ -355,6 +355,16 @@ pub struct UpdateInterfaceRequestDefaults {
|
||||
forbidden_hw_addrs: Vec<String>,
|
||||
}
|
||||
|
||||
/// UpdateInterfaceRequest settings from genpolicy-settings.json.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct AddARPNeighborsRequestDefaults {
|
||||
/// Explicitly blocked interface names. Intent is to block changes to loopback interface.
|
||||
forbidden_device_names: Vec<String>,
|
||||
/// Explicitly blocked IP address ranges.
|
||||
/// Should include loopback addresses and other CIDRs that should not be routed outside the VM.
|
||||
forbidden_cidrs_regex: Vec<String>,
|
||||
}
|
||||
|
||||
/// Settings specific to each kata agent endpoint, loaded from
|
||||
/// genpolicy-settings.json.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
@@ -374,6 +384,9 @@ pub struct RequestDefaults {
|
||||
/// Allow the host to configure only used raw_flags and reject names/mac addresses of the loopback.
|
||||
pub UpdateInterfaceRequest: UpdateInterfaceRequestDefaults,
|
||||
|
||||
/// Allow the host to configure only used raw_flags and reject names/mac addresses of the loopback.
|
||||
pub AddARPNeighborsRequest: AddARPNeighborsRequestDefaults,
|
||||
|
||||
/// Allow the Host to close stdin for a container. Typically used with WriteStreamRequest.
|
||||
pub CloseStdinRequest: bool,
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ mod tests {
|
||||
use std::str;
|
||||
|
||||
use protocols::agent::{
|
||||
CopyFileRequest, CreateContainerRequest, CreateSandboxRequest, ExecProcessRequest,
|
||||
RemoveContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest,
|
||||
AddARPNeighborsRequest, CopyFileRequest, CreateContainerRequest, CreateSandboxRequest,
|
||||
ExecProcessRequest, RemoveContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -32,6 +32,7 @@ mod tests {
|
||||
RemoveContainer(RemoveContainerRequest),
|
||||
UpdateInterface(UpdateInterfaceRequest),
|
||||
UpdateRoutes(UpdateRoutesRequest),
|
||||
AddARPNeighbors(AddARPNeighborsRequest),
|
||||
}
|
||||
|
||||
impl Display for TestRequest {
|
||||
@@ -44,6 +45,7 @@ mod tests {
|
||||
TestRequest::RemoveContainer(_) => write!(f, "RemoveContainerRequest"),
|
||||
TestRequest::UpdateInterface(_) => write!(f, "UpdateInterfaceRequest"),
|
||||
TestRequest::UpdateRoutes(_) => write!(f, "UpdateRoutesRequest"),
|
||||
TestRequest::AddARPNeighbors(_) => write!(f, "AddARPNeighborsRequest"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,6 +242,11 @@ mod tests {
|
||||
runtests("updateinterface").await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_arp_neighbors() {
|
||||
runtests("addarpneighbors").await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_container_network_namespace() {
|
||||
runtests("createcontainer/network_namespace").await;
|
||||
|
||||
9
src/tools/genpolicy/tests/policy/testdata/addarpneighbors/pod.yaml
vendored
Normal file
9
src/tools/genpolicy/tests/policy/testdata/addarpneighbors/pod.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: dummy
|
||||
spec:
|
||||
runtimeClassName: kata-cc-isolation
|
||||
containers:
|
||||
- name: dummy
|
||||
image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db
|
||||
156
src/tools/genpolicy/tests/policy/testdata/addarpneighbors/testcases.json
vendored
Normal file
156
src/tools/genpolicy/tests/policy/testdata/addarpneighbors/testcases.json
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
[
|
||||
{
|
||||
"description": "compliant neighbors",
|
||||
"allowed": true,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "10.0.0.1",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "eth0",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 128,
|
||||
"flags": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "allowed flags: NTF_PROXY",
|
||||
"allowed": true,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "10.0.0.1",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "eth0",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 128,
|
||||
"flags": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "allowed flags: NTF_ROUTER",
|
||||
"allowed": true,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "10.0.0.1",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "eth0",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 128,
|
||||
"flags": 128
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "bad interface",
|
||||
"allowed": false,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "10.0.0.1",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "lo",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 128,
|
||||
"flags": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "bad IP",
|
||||
"allowed": false,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "127.1.2.3",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "eth0",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 128,
|
||||
"flags": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "bad state",
|
||||
"allowed": false,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "10.0.0.1",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "eth0",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 0,
|
||||
"flags": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "bad flags",
|
||||
"allowed": false,
|
||||
"request": {
|
||||
"type": "AddARPNeighbors",
|
||||
"neighbors": {
|
||||
"ARPNeighbors": [
|
||||
{
|
||||
"toIPAddress": {
|
||||
"family": 0,
|
||||
"address": "10.0.0.1",
|
||||
"mask": ""
|
||||
},
|
||||
"device": "eth0",
|
||||
"lladdr": "00:00:5e:00:53:01",
|
||||
"state": 128,
|
||||
"flags": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -28,7 +28,7 @@ KATA_HYPERVISOR="${KATA_HYPERVISOR:-qemu}"
|
||||
|
||||
RUNTIME="${RUNTIME:-containerd-shim-kata-v2}"
|
||||
|
||||
export branch="${target_branch:-main}"
|
||||
export branch="${target_branch:-"$(git remote show origin | sed -n '/HEAD branch/s/.*: //p')"}"
|
||||
|
||||
function die() {
|
||||
local msg="$*"
|
||||
|
||||
@@ -174,7 +174,7 @@ function create_coco_pod_yaml() {
|
||||
# This function creates pod yaml. Parameters
|
||||
# - $1: image reference
|
||||
# - $2: annotation `io.katacontainers.config.hypervisor.kernel_params`
|
||||
# - $3: anootation `io.katacontainers.config.runtime.cc_init_data`
|
||||
# - $3: annotation `io.katacontainers.config.hypervisor.cc_init_data`
|
||||
# - $4: node
|
||||
function create_coco_pod_yaml_with_annotations() {
|
||||
image=$1
|
||||
@@ -183,7 +183,7 @@ function create_coco_pod_yaml_with_annotations() {
|
||||
node=${4:-}
|
||||
|
||||
kernel_params_annotation_key="io.katacontainers.config.hypervisor.kernel_params"
|
||||
cc_initdata_annotation_key="io.katacontainers.config.runtime.cc_init_data"
|
||||
cc_initdata_annotation_key="io.katacontainers.config.hypervisor.cc_init_data"
|
||||
|
||||
# Note: this is not local as we use it in the caller test
|
||||
kata_pod="$(new_pod_config "$image" "kata-${KATA_HYPERVISOR}")"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# 3. Pull an image from a banned registry
|
||||
# 4. Check if the pulling fails with log `image security validation failed`,
|
||||
# the initdata works.
|
||||
#
|
||||
#
|
||||
# Note that if initdata does not work, the pod still fails to launch (hang at
|
||||
# CreatingContainer status). The error information is
|
||||
# `[CDH] [ERROR]: Get Resource failed` which internally means that the KBS URL
|
||||
@@ -35,7 +35,7 @@ setup() {
|
||||
setup_common || die "setup_common failed"
|
||||
|
||||
FAIL_TEST_IMAGE="quay.io/prometheus/busybox:latest"
|
||||
|
||||
|
||||
SECURITY_POLICY_KBS_URI="kbs:///default/security-policy/test"
|
||||
}
|
||||
|
||||
@@ -45,13 +45,16 @@ function setup_kbs_image_policy_for_initdata() {
|
||||
fi
|
||||
|
||||
export CURRENT_ARCH=$(uname -m)
|
||||
if [ "${CURRENT_ARCH}" != "x86_64" ]; then
|
||||
skip "Test skipped as only x86-64 supports, while current platform is ${CURRENT_ARCH}"
|
||||
fi
|
||||
case "${CURRENT_ARCH}" in
|
||||
"x86_64"|"s390x")
|
||||
;;
|
||||
*)
|
||||
skip "Test skipped as only x86-64 & s390x is supported, while current platform is ${CURRENT_ARCH}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# TODO: Enable for more archs
|
||||
case "$KATA_HYPERVISOR" in
|
||||
"qemu-tdx"|"qemu-coco-dev"|"qemu-snp")
|
||||
"qemu-tdx"|"qemu-coco-dev"|"qemu-snp"|"qemu-se")
|
||||
;;
|
||||
*)
|
||||
skip "Test not supported for ${KATA_HYPERVISOR}."
|
||||
@@ -88,7 +91,7 @@ EOF
|
||||
|
||||
@test "Test that creating a container from an rejected image configured by initdata, fails according to policy reject" {
|
||||
setup_kbs_image_policy_for_initdata
|
||||
|
||||
|
||||
CC_KBS_ADDRESS=$(kbs_k8s_svc_http_addr)
|
||||
|
||||
kernel_parameter="agent.image_policy_file=${SECURITY_POLICY_KBS_URI} agent.enable_signature_verification=true"
|
||||
@@ -179,7 +182,7 @@ EOF
|
||||
return 1
|
||||
fi
|
||||
|
||||
assert_logs_contain "${node}" kata "${node_start_time}" "\[CDH\] \[ERROR\]: Get Resource failed"
|
||||
assert_logs_contain "${node}" kata "${node_start_time}" "\[CDH\] \[ERROR\]: Image Client error: Initialize resource provider failed: Get resource failed"
|
||||
}
|
||||
|
||||
teardown() {
|
||||
|
||||
@@ -10,10 +10,13 @@ load "${BATS_TEST_DIRNAME}/../../common.bash"
|
||||
# shellcheck disable=SC1091
|
||||
load "${BATS_TEST_DIRNAME}/tests_common.sh"
|
||||
|
||||
RUNTIME_CLASS_NAME=${RUNTIME_CLASS_NAME:-kata-qemu-nvidia-gpu}
|
||||
export RUNTIME_CLASS_NAME
|
||||
|
||||
export POD_NAME_INSTRUCT="nvidia-nim-llama-3-1-8b-instruct"
|
||||
export POD_NAME_EMBEDQA="nvidia-nim-llama-3-2-nv-embedqa-1b-v2"
|
||||
|
||||
export POD_SECRET_INSTRUCT="ngc-secret-instruct"
|
||||
export LOCAL_NIM_CACHE="/opt/nim/.cache"
|
||||
|
||||
DOCKER_CONFIG_JSON=$(
|
||||
echo -n "{\"auths\":{\"nvcr.io\":{\"username\":\"\$oauthtoken\",\"password\":\"${NGC_API_KEY}\",\"auth\":\"$(echo -n "\$oauthtoken:${NGC_API_KEY}" | base64 -w0)\"}}}" |
|
||||
@@ -21,6 +24,40 @@ DOCKER_CONFIG_JSON=$(
|
||||
)
|
||||
export DOCKER_CONFIG_JSON
|
||||
|
||||
setup_langchain_flow() {
|
||||
# shellcheck disable=SC1091 # Sourcing virtual environment activation script
|
||||
source "${HOME}"/.cicd/venv/bin/activate
|
||||
|
||||
pip install --upgrade pip
|
||||
[[ "$(pip show langchain 2>/dev/null | awk '/^Version:/{print $2}')" = "0.2.5" ]] || pip install langchain==0.2.5
|
||||
[[ "$(pip show langchain-nvidia-ai-endpoints 2>/dev/null | awk '/^Version:/{print $2}')" = "0.1.2" ]] || pip install langchain-nvidia-ai-endpoints==0.1.2
|
||||
[[ "$(pip show faiss-gpu 2>/dev/null | awk '/^Version:/{print $2}')" = "1.7.2" ]] || pip install faiss-gpu==1.7.2
|
||||
[[ "$(pip show langchain-community 2>/dev/null | awk '/^Version:/{print $2}')" = "0.2.5" ]] || pip install langchain-community==0.2.5
|
||||
[[ "$(pip show beautifulsoup4 2>/dev/null | awk '/^Version:/{print $2}')" = "4.13.4" ]] || pip install beautifulsoup4==4.13.4
|
||||
}
|
||||
|
||||
create_inference_embedqa_pods() {
|
||||
kubectl apply -f "${POD_INSTRUCT_YAML}"
|
||||
kubectl apply -f "${POD_EMBEDQA_YAML}"
|
||||
|
||||
kubectl wait --for=condition=Ready --timeout=500s pod "${POD_NAME_INSTRUCT}"
|
||||
kubectl wait --for=condition=Ready --timeout=500s pod "${POD_NAME_EMBEDQA}"
|
||||
|
||||
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
|
||||
POD_IP_INSTRUCT=$(kubectl get pod "${POD_NAME_INSTRUCT}" -o jsonpath='{.status.podIP}')
|
||||
[[ -n "${POD_IP_INSTRUCT}" ]]
|
||||
|
||||
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
|
||||
POD_IP_EMBEDQA=$(kubectl get pod "${POD_NAME_EMBEDQA}" -o jsonpath='{.status.podIP}')
|
||||
[[ -n "${POD_IP_EMBEDQA}" ]]
|
||||
|
||||
echo "POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >"${BATS_SUITE_TMPDIR}/env"
|
||||
echo "# POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >&3
|
||||
|
||||
echo "POD_IP_EMBEDQA=${POD_IP_EMBEDQA}" >>"${BATS_SUITE_TMPDIR}/env"
|
||||
echo "# POD_IP_EMBEDQA=${POD_IP_EMBEDQA}" >&3
|
||||
}
|
||||
|
||||
setup_file() {
|
||||
dpkg -s jq >/dev/null 2>&1 || sudo apt -y install jq
|
||||
|
||||
@@ -28,6 +65,7 @@ setup_file() {
|
||||
[[ -d ${PYENV_ROOT}/bin ]] && export PATH="${PYENV_ROOT}/bin:${PATH}"
|
||||
eval "$(pyenv init - bash)"
|
||||
|
||||
# shellcheck disable=SC1091 # Virtual environment will be created during test execution
|
||||
python3 -m venv "${HOME}"/.cicd/venv
|
||||
|
||||
get_pod_config_dir
|
||||
@@ -35,20 +73,17 @@ setup_file() {
|
||||
pod_instruct_yaml_in="${pod_config_dir}/${POD_NAME_INSTRUCT}.yaml.in"
|
||||
pod_instruct_yaml="${pod_config_dir}/${POD_NAME_INSTRUCT}.yaml"
|
||||
|
||||
pod_embedqa_yaml_in="${pod_config_dir}/${POD_NAME_EMBEDQA}.yaml.in"
|
||||
pod_embedqa_yaml="${pod_config_dir}/${POD_NAME_EMBEDQA}.yaml"
|
||||
|
||||
envsubst <"${pod_instruct_yaml_in}" >"${pod_instruct_yaml}"
|
||||
envsubst <"${pod_embedqa_yaml_in}" >"${pod_embedqa_yaml}"
|
||||
|
||||
export POD_INSTRUCT_YAML="${pod_instruct_yaml}"
|
||||
}
|
||||
export POD_EMBEDQA_YAML="${pod_embedqa_yaml}"
|
||||
|
||||
@test "NVIDIA NIM Llama 3.1-8b Instruct" {
|
||||
kubectl apply -f "${POD_INSTRUCT_YAML}"
|
||||
kubectl wait --for=condition=Ready --timeout=500s pod "${POD_NAME_INSTRUCT}"
|
||||
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
|
||||
POD_IP_INSTRUCT=$(kubectl get pod "${POD_NAME_INSTRUCT}" -o jsonpath='{.status.podIP}')
|
||||
[[ -n "${POD_IP_INSTRUCT}" ]]
|
||||
|
||||
echo "POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >"${BATS_SUITE_TMPDIR}/env"
|
||||
echo "# POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >&3
|
||||
setup_langchain_flow
|
||||
create_inference_embedqa_pods
|
||||
}
|
||||
|
||||
@test "List of models available for inference" {
|
||||
@@ -64,10 +99,11 @@ setup_file() {
|
||||
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
|
||||
MODEL_NAME=$(echo "${output}" | jq '.data[0].id' | tr -d '"')
|
||||
export MODEL_NAME
|
||||
|
||||
[[ -n "${MODEL_NAME}" ]]
|
||||
|
||||
echo "MODEL_NAME=${MODEL_NAME}" >>"${BATS_SUITE_TMPDIR}/env"
|
||||
echo "# MODEL_NAME=${MODEL_NAME}" >&3
|
||||
|
||||
}
|
||||
|
||||
@test "Simple OpenAI completion request" {
|
||||
@@ -94,6 +130,198 @@ setup_file() {
|
||||
echo "# ANSWER: ${ANSWER}" >&3
|
||||
}
|
||||
|
||||
|
||||
@test "LangChain NVIDIA AI Endpoints" {
|
||||
# shellcheck disable=SC1091 # File is created by previous test
|
||||
source "${BATS_SUITE_TMPDIR}/env"
|
||||
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
|
||||
[[ -n "${POD_IP_INSTRUCT}" ]]
|
||||
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
|
||||
[[ -n "${MODEL_NAME}" ]]
|
||||
|
||||
QUESTION="What is the capital of France?"
|
||||
ANSWER="The capital of France is Paris."
|
||||
|
||||
# shellcheck disable=SC1091 # Sourcing virtual environment activation script
|
||||
source "${HOME}"/.cicd/venv/bin/activate
|
||||
# shellcheck disable=SC2031 # Variables are used in heredoc, not subshell
|
||||
cat <<EOF >"${HOME}"/.cicd/venv/langchain_nim.py
|
||||
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
||||
|
||||
llm = ChatNVIDIA(base_url="http://${POD_IP_INSTRUCT}:8000/v1", model="${MODEL_NAME}", temperature=0.1, max_tokens=1000, top_p=1.0)
|
||||
|
||||
result = llm.invoke("${QUESTION}")
|
||||
print(result.content)
|
||||
EOF
|
||||
|
||||
run python3 "${HOME}"/.cicd/venv/langchain_nim.py
|
||||
|
||||
[[ "${status}" -eq 0 ]]
|
||||
[[ "${output}" = "${ANSWER}" ]]
|
||||
|
||||
echo "# QUESTION: ${QUESTION}" >&3
|
||||
echo "# ANSWER: ${ANSWER}" >&3
|
||||
}
|
||||
|
||||
@test "Kata Documentation RAG" {
|
||||
# shellcheck disable=SC1091 # File is created by previous test
|
||||
source "${BATS_SUITE_TMPDIR}/env"
|
||||
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
|
||||
[[ -n "${POD_IP_EMBEDQA}" ]]
|
||||
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
|
||||
[[ -n "${POD_IP_INSTRUCT}" ]]
|
||||
|
||||
# shellcheck disable=SC1091 # Sourcing virtual environment activation script
|
||||
source "${HOME}"/.cicd/venv/bin/activate
|
||||
cat <<EOF >"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
import os
|
||||
from langchain.chains import ConversationalRetrievalChain, LLMChain
|
||||
from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT, QA_PROMPT
|
||||
from langchain.chains.question_answering import load_qa_chain
|
||||
from langchain.memory import ConversationBufferMemory
|
||||
from langchain_community.vectorstores import FAISS
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
||||
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2129 # Multiple heredocs are intentional for building the Python script
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
import re
|
||||
from typing import List, Union
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
def html_document_loader(url: Union[str, bytes]) -> str:
|
||||
try:
|
||||
response = requests.get(url)
|
||||
html_content = response.text
|
||||
except Exception as e:
|
||||
print(f"Failed to load {url} due to exception {e}")
|
||||
return ""
|
||||
|
||||
try:
|
||||
# Create a Beautiful Soup object to parse html
|
||||
soup = BeautifulSoup(html_content, "html.parser")
|
||||
|
||||
# Remove script and style tags
|
||||
for script in soup(["script", "style"]):
|
||||
script.extract()
|
||||
|
||||
# Get the plain text from the HTML document
|
||||
text = soup.get_text()
|
||||
|
||||
# Remove excess whitespace and newlines
|
||||
text = re.sub("\s+", " ", text).strip()
|
||||
|
||||
return text
|
||||
except Exception as e:
|
||||
print(f"Exception {e} while loading document")
|
||||
return ""
|
||||
|
||||
EOF
|
||||
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
def create_embeddings(embedding_path: str = "./data/nv_embedding"):
|
||||
|
||||
embedding_path = "./data/nv_embedding"
|
||||
print(f"Storing embeddings to {embedding_path}")
|
||||
|
||||
# List of web pages containing Kata technical documentation
|
||||
urls = [
|
||||
"https://github.com/kata-containers/kata-containers/releases",
|
||||
]
|
||||
|
||||
documents = []
|
||||
for url in urls:
|
||||
document = html_document_loader(url)
|
||||
documents.append(document)
|
||||
|
||||
|
||||
text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=1000,
|
||||
chunk_overlap=0,
|
||||
length_function=len,
|
||||
)
|
||||
texts = text_splitter.create_documents(documents)
|
||||
index_docs(url, text_splitter, texts, embedding_path)
|
||||
print("Generated embedding successfully")
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2031 # POD_IP_EMBEDQA is shared via file between BATS tests
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
def index_docs(url: Union[str, bytes], splitter, documents: List[str], dest_embed_dir) -> None:
|
||||
embeddings = NVIDIAEmbeddings(base_url="http://${POD_IP_EMBEDQA}:8000/v1", model="nvidia/llama-3.2-nv-embedqa-1b-v2")
|
||||
|
||||
for document in documents:
|
||||
texts = splitter.split_text(document.page_content)
|
||||
|
||||
# metadata to attach to document
|
||||
metadatas = [document.metadata]
|
||||
|
||||
# create embeddings and add to vector store
|
||||
if os.path.exists(dest_embed_dir):
|
||||
update = FAISS.load_local(folder_path=dest_embed_dir, embeddings=embeddings, allow_dangerous_deserialization=True)
|
||||
update.add_texts(texts, metadatas=metadatas)
|
||||
update.save_local(folder_path=dest_embed_dir)
|
||||
else:
|
||||
docsearch = FAISS.from_texts(texts, embedding=embeddings, metadatas=metadatas)
|
||||
docsearch.save_local(folder_path=dest_embed_dir)
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2031 # POD_IP_EMBEDQA is shared via file between BATS tests
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
create_embeddings()
|
||||
|
||||
embedding_model = NVIDIAEmbeddings(base_url="http://${POD_IP_EMBEDQA}:8000/v1", model="nvidia/llama-3.2-nv-embedqa-1b-v2")
|
||||
EOF
|
||||
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
# Embed documents
|
||||
embedding_path = "./data/nv_embedding"
|
||||
docsearch = FAISS.load_local(folder_path=embedding_path, embeddings=embedding_model, allow_dangerous_deserialization=True)
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2031 # Variables are used in heredoc, not subshell
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
llm = ChatNVIDIA(base_url="http://${POD_IP_INSTRUCT}:8000/v1", model="meta/llama3-8b-instruct", temperature=0.1, max_tokens=1000, top_p=1.0)
|
||||
|
||||
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
|
||||
|
||||
qa_prompt=QA_PROMPT
|
||||
|
||||
doc_chain = load_qa_chain(llm, chain_type="stuff", prompt=QA_PROMPT)
|
||||
|
||||
qa = ConversationalRetrievalChain.from_llm(
|
||||
llm=llm,
|
||||
retriever=docsearch.as_retriever(),
|
||||
chain_type="stuff",
|
||||
memory=memory,
|
||||
combine_docs_chain_kwargs={'prompt': qa_prompt},
|
||||
)
|
||||
|
||||
EOF
|
||||
|
||||
QUESTION="What is the latest Kata Containers release?"
|
||||
|
||||
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
query = "${QUESTION}"
|
||||
result = qa.invoke({"question": query})
|
||||
print("#"+ result.get("answer"))
|
||||
|
||||
EOF
|
||||
|
||||
run python3 "${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
|
||||
[[ "${status}" -eq 0 ]]
|
||||
|
||||
ANSWER=$(echo "${output}" | cut -d '#' -f2)
|
||||
[[ -n "${ANSWER}" ]]
|
||||
|
||||
echo "# QUESTION: ${QUESTION}" >&3
|
||||
echo "# ANSWER: ${ANSWER}" >&3
|
||||
}
|
||||
|
||||
teardown_file() {
|
||||
kubectl delete -f "${POD_INSTRUCT_YAML}"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# Copyright (c) 2025 NVIDIA Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
@@ -20,7 +19,7 @@ metadata:
|
||||
app: ${POD_NAME_INSTRUCT}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
runtimeClassName: kata-qemu-nvidia-gpu
|
||||
runtimeClassName: "${RUNTIME_CLASS_NAME}"
|
||||
imagePullSecrets:
|
||||
- name: ngc-secret-instruct
|
||||
securityContext:
|
||||
@@ -84,6 +83,6 @@ spec:
|
||||
volumes:
|
||||
- name: nim-cache
|
||||
hostPath:
|
||||
path: "/opr/nim/.cache"
|
||||
path: "${LOCAL_NIM_CACHE}"
|
||||
type: DirectoryOrCreate
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ngc-secret-embedqa
|
||||
namespace: nim-embedqa
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
data:
|
||||
.dockerconfigjson: ${DOCKER_CONFIG_JSON}
|
||||
@@ -16,7 +15,6 @@ apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nvidia-nim-llama-3-2-nv-embedqa-1b-v2
|
||||
namespace: nim-embedqa
|
||||
labels:
|
||||
app: nvidia-nim-llama-3-2-nv-embedqa-1b-v2
|
||||
spec:
|
||||
@@ -91,5 +89,5 @@ spec:
|
||||
volumes:
|
||||
- name: nim-cache
|
||||
hostPath:
|
||||
path: "/opr/nim/.cache"
|
||||
path: "${LOCAL_NIM_CACHE}"
|
||||
type: DirectoryOrCreate
|
||||
|
||||
@@ -15,10 +15,10 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: "3.19.1"
|
||||
version: "3.20.0"
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "3.19.1"
|
||||
appVersion: "3.20.0"
|
||||
|
||||
@@ -343,6 +343,20 @@ get_latest_kernel_confidential_artefact_and_builder_image_version() {
|
||||
echo "${latest_kernel_artefact}-${latest_kernel_builder_image}"
|
||||
}
|
||||
|
||||
get_latest_kernel_artefact_and_builder_image_version() {
|
||||
local kernel_version
|
||||
local kernel_kata_config_version
|
||||
local latest_kernel_artefact
|
||||
local latest_kernel_builder_image
|
||||
|
||||
kernel_version=$(get_from_kata_deps ".assets.kernel.version")
|
||||
kernel_kata_config_version="$(cat "${repo_root_dir}"/tools/packaging/kernel/kata_config_version)"
|
||||
latest_kernel_artefact="${kernel_version}-${kernel_kata_config_version}-$(get_last_modification "$(dirname "${kernel_builder}")")"
|
||||
latest_kernel_builder_image="$(get_kernel_image_name)"
|
||||
|
||||
echo "${latest_kernel_artefact}-${latest_kernel_builder_image}"
|
||||
}
|
||||
|
||||
#Install guest image
|
||||
install_image() {
|
||||
local variant="${1:-}"
|
||||
@@ -370,7 +384,7 @@ install_image() {
|
||||
|
||||
|
||||
latest_artefact="$(get_kata_version)-${os_name}-${os_version}-${osbuilder_last_commit}-${guest_image_last_commit}-${agent_last_commit}-${libs_last_commit}-${gperf_version}-${libseccomp_version}-${rust_version}-${image_type}"
|
||||
if [ "${variant}" == "confidential" ]; then
|
||||
if [[ "${variant}" == *confidential ]]; then
|
||||
# For the confidential image we depend on the kernel built in order to ensure that
|
||||
# measured boot is used
|
||||
latest_artefact+="-$(get_latest_kernel_confidential_artefact_and_builder_image_version)"
|
||||
@@ -378,6 +392,11 @@ install_image() {
|
||||
latest_artefact+="-$(get_latest_pause_image_artefact_and_builder_image_version)"
|
||||
fi
|
||||
|
||||
if [[ "${variant}" == "nvidia-gpu" ]]; then
|
||||
# If we bump the kernel we need to rebuild the image
|
||||
latest_artefact+="-$(get_latest_kernel_artefact_and_builder_image_version "${variant}")"
|
||||
fi
|
||||
|
||||
latest_builder_image=""
|
||||
|
||||
install_cached_tarball_component \
|
||||
@@ -465,7 +484,7 @@ install_initrd() {
|
||||
"$(get_last_modification "${repo_root_dir}/tools/packaging/static-build/agent")")
|
||||
|
||||
latest_artefact="$(get_kata_version)-${os_name}-${os_version}-${osbuilder_last_commit}-${guest_image_last_commit}-${agent_last_commit}-${libs_last_commit}-${gperf_version}-${libseccomp_version}-${rust_version}-${initrd_type}"
|
||||
if [ "${variant}" == "confidential" ]; then
|
||||
if [[ "${variant}" == *confidential ]]; then
|
||||
# For the confidential initrd we depend on the kernel built in order to ensure that
|
||||
# measured boot is used
|
||||
latest_artefact+="-$(get_latest_kernel_confidential_artefact_and_builder_image_version)"
|
||||
@@ -473,6 +492,11 @@ install_initrd() {
|
||||
latest_artefact+="-$(get_latest_pause_image_artefact_and_builder_image_version)"
|
||||
fi
|
||||
|
||||
if [[ "${variant}" == "nvidia-gpu" ]]; then
|
||||
# If we bump the kernel we need to rebuild the initrd as well
|
||||
latest_artefact+="-$(get_latest_kernel_artefact_and_builder_image_version "${variant}")"
|
||||
fi
|
||||
|
||||
latest_builder_image=""
|
||||
|
||||
[[ "${ARCH}" == "aarch64" && "${CROSS_BUILD}" == "true" ]] && echo "warning: Don't cross build initrd for aarch64 as it's too slow" && exit 0
|
||||
|
||||
@@ -12,7 +12,6 @@ CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_USER=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_CRYPTD=y
|
||||
CONFIG_CRYPTO_AUTHENC=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
|
||||
@@ -9,3 +9,6 @@ CONFIG_PCIEPORTBUS=y
|
||||
# Define hotplugs to be online immediately. Speeds things up, and makes things
|
||||
# work smoother on some arch's.
|
||||
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
|
||||
|
||||
# Linux v6.14+ dropped MEMORY_HOTPLUG_DEFAULT_ONLINE. The equivalent is:
|
||||
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# To keep CRYPTO_FIPS enabled, the following dependencies
|
||||
# are needed. This is done for confidential guest build
|
||||
# target only since it's needed by v6.16+ kernels. Move
|
||||
# to a common fragment once non-confidential guest kernels
|
||||
# follow.
|
||||
CONFIG_CRYPTO_SELFTESTS=y
|
||||
CONFIG_EXPERT=y
|
||||
@@ -39,3 +39,6 @@ CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
|
||||
CONFIG_VFIO_AP
|
||||
CONFIG_VFIO_MDEV
|
||||
CONFIG_BLK_DEV_WRITE_MOUNTED
|
||||
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE
|
||||
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO
|
||||
CONFIG_CRYPTO_CRC32_S390
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# To keep CRYPTO_FIPS enabled, the following dependencies
|
||||
# are needed. This is done for confidential guest build
|
||||
# target only since it's needed by v6.16+ kernels. Move
|
||||
# to a common fragment once non-confidential guest kernels
|
||||
# follow.
|
||||
CONFIG_CRYPTO_SELFTESTS=y
|
||||
CONFIG_EXPERT=y
|
||||
@@ -1,3 +1,2 @@
|
||||
# x86 cryptographic instructions to improve AES encryption and SHA256 hashing.
|
||||
CONFIG_CRYPTO_SHA256_SSSE3=y
|
||||
CONFIG_CRYPTO_AES_NI_INTEL=y
|
||||
|
||||
@@ -7,6 +7,5 @@ CONFIG_INTEL_TDX_GUEST=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_TDX_GUEST_DRIVER=y
|
||||
CONFIG_VIRT_DRIVERS=y
|
||||
CONFIG_X86_5LEVEL=y
|
||||
CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
|
||||
CONFIG_X86_PLATFORM_DEVICES=y
|
||||
|
||||
@@ -1 +1 @@
|
||||
160
|
||||
162
|
||||
|
||||
@@ -20,11 +20,13 @@ RUN apt-get update && \
|
||||
git \
|
||||
iptables \
|
||||
kmod \
|
||||
libdw-dev \
|
||||
libelf-dev \
|
||||
libssl-dev \
|
||||
gettext \
|
||||
rsync \
|
||||
cpio \
|
||||
patch && \
|
||||
patch \
|
||||
python3 && \
|
||||
if [ "${ARCH}" != "$(uname -m)" ]; then apt-get install --no-install-recommends -y gcc-"${ARCH}"-linux-gnu binutils-"${ARCH}"-linux-gnu; fi && \
|
||||
apt-get clean && apt-get autoclean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -84,7 +84,11 @@ fi
|
||||
popd
|
||||
|
||||
info "Install fd to destdir"
|
||||
install_dir="${DESTDIR}/${PREFIX}/share/ovmf"
|
||||
if [ "${ovmf_build}" == "arm64" ]; then
|
||||
install_dir="${DESTDIR}/${PREFIX}/share/aavmf"
|
||||
else
|
||||
install_dir="${DESTDIR}/${PREFIX}/share/ovmf"
|
||||
fi
|
||||
|
||||
mkdir -p "${install_dir}"
|
||||
if [ "${ovmf_build}" == "sev" ]; then
|
||||
|
||||
@@ -101,6 +101,7 @@ mapping:
|
||||
- Kata Containers CI / kata-containers-ci-on-push / run-kata-deploy-tests / run-kata-deploy-tests (qemu, microk8s)
|
||||
- Kata Containers CI / kata-containers-ci-on-push / run-kata-deploy-tests / run-kata-deploy-tests (qemu, rke2)
|
||||
- Kata Containers CI / kata-containers-ci-on-push / run-kata-monitor-tests / run-monitor (qemu, crio)
|
||||
- Kata Containers CI / kata-containers-ci-on-push / run-k8s-tests-on-nvidia-gpu / run-nvidia-gpu-tests-on-amd64 (qemu-nvidia-gpu, kubeadm)
|
||||
required-labels:
|
||||
- ok-to-test
|
||||
build:
|
||||
@@ -135,6 +136,7 @@ mapping:
|
||||
- Static checks / build-checks / check (make check, dragonball, src/dragonball, rust)
|
||||
- Static checks / build-checks / check (make check, genpolicy, src/tools/genpolicy, rust, protobuf-compiler)
|
||||
- Static checks / build-checks / check (make check, kata-ctl, src/tools/kata-ctl, rust)
|
||||
- Static checks / build-checks / check (make check, libs, src/libs, rust)
|
||||
- Static checks / build-checks / check (make check, runtime-rs, src/runtime-rs, rust)
|
||||
- Static checks / build-checks / check (make check, runtime, src/runtime, golang, XDG_RUNTIME_DIR)
|
||||
- Static checks / build-checks / check (make check, trace-forwarder, src/tools/trace-forwarder, rust)
|
||||
@@ -143,6 +145,7 @@ mapping:
|
||||
- Static checks / build-checks / check (make test, dragonball, src/dragonball, rust)
|
||||
- Static checks / build-checks / check (make test, genpolicy, src/tools/genpolicy, rust, protobuf-compiler)
|
||||
- Static checks / build-checks / check (make test, kata-ctl, src/tools/kata-ctl, rust)
|
||||
- Static checks / build-checks / check (make test, libs, src/libs, rust)
|
||||
- Static checks / build-checks / check (make test, runtime-rs, src/runtime-rs, rust)
|
||||
- Static checks / build-checks / check (make test, runtime, src/runtime, golang, XDG_RUNTIME_DIR)
|
||||
- Static checks / build-checks / check (make test, trace-forwarder, src/tools/trace-forwarder, rust)
|
||||
@@ -159,6 +162,7 @@ mapping:
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, dragonball, src/dragonball, rust)
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, genpolicy, src/tools/genpolicy, rust, protobuf-compiler)
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, kata-ctl, src/tools/kata-ctl, rust)
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, libs, src/libs, rust)
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, runtime-rs, src/runtime-rs, rust)
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, runtime, src/runtime, golang, XDG_RUNTIME_DIR)
|
||||
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, trace-forwarder, src/tools/trace-forwarder, rust)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module module-path
|
||||
|
||||
// Keep in sync with version in versions.yaml
|
||||
go 1.23.0
|
||||
go 1.23.12
|
||||
|
||||
require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
|
||||
@@ -196,11 +196,11 @@ assets:
|
||||
kernel:
|
||||
description: "Linux kernel optimised for virtual machines"
|
||||
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
|
||||
version: "v6.12.36"
|
||||
version: "v6.12.42"
|
||||
confidential:
|
||||
description: "Linux kernel with x86_64 TEEs (SNP and TDX) support"
|
||||
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
|
||||
version: "v6.12.36"
|
||||
version: "v6.16.1"
|
||||
|
||||
kernel-arm-experimental:
|
||||
description: "Linux kernel with cpu/mem hotplug support on arm64"
|
||||
@@ -210,7 +210,7 @@ assets:
|
||||
kernel-dragonball-experimental:
|
||||
description: "Linux kernel with Dragonball VMM optimizations like upcall"
|
||||
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
|
||||
version: "v6.12.36"
|
||||
version: "v6.12.42"
|
||||
|
||||
externals:
|
||||
description: "Third-party projects used by the system"
|
||||
@@ -415,12 +415,13 @@ languages:
|
||||
golang:
|
||||
description: "Google's 'go' language"
|
||||
notes: "'version' is the default minimum version used by this project."
|
||||
version: "1.23.10"
|
||||
# When updating this, also update in go.mod files.
|
||||
version: "1.23.12"
|
||||
meta:
|
||||
description: |
|
||||
'newest-version' is the latest version known to work when
|
||||
building Kata
|
||||
newest-version: "1.23.10"
|
||||
newest-version: "1.23.12"
|
||||
|
||||
rust:
|
||||
description: "Rust language"
|
||||
|
||||
Reference in New Issue
Block a user