mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-28 20:41:04 +00:00
Merge pull request #2975 from bergwolf/2.2.3-branch-bump
# Kata Containers 2.2.3
This commit is contained in:
commit
3a1804cd73
@ -22,7 +22,7 @@ This document requires the presence of the ACRN hypervisor and Kata Containers o
|
|||||||
|
|
||||||
- ACRN supported [Hardware](https://projectacrn.github.io/latest/hardware.html#supported-hardware).
|
- ACRN supported [Hardware](https://projectacrn.github.io/latest/hardware.html#supported-hardware).
|
||||||
> **Note:** Please make sure to have a minimum of 4 logical processors (HT) or cores.
|
> **Note:** Please make sure to have a minimum of 4 logical processors (HT) or cores.
|
||||||
- ACRN [software](https://projectacrn.github.io/latest/tutorials/kbl-nuc-sdc.html#use-the-script-to-set-up-acrn-automatically) setup.
|
- ACRN [software](https://projectacrn.github.io/latest/tutorials/run_kata_containers.html) setup.
|
||||||
- For networking, ACRN supports either MACVTAP or TAP. If MACVTAP is not enabled in the Service OS, please follow the below steps to update the kernel:
|
- For networking, ACRN supports either MACVTAP or TAP. If MACVTAP is not enabled in the Service OS, please follow the below steps to update the kernel:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
1
src/agent/Cargo.lock
generated
1
src/agent/Cargo.lock
generated
@ -545,6 +545,7 @@ dependencies = [
|
|||||||
"scan_fmt",
|
"scan_fmt",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serial_test",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-scope",
|
"slog-scope",
|
||||||
"slog-stdlog",
|
"slog-stdlog",
|
||||||
|
@ -20,6 +20,7 @@ scan_fmt = "0.2.3"
|
|||||||
scopeguard = "1.0.0"
|
scopeguard = "1.0.0"
|
||||||
thiserror = "1.0.26"
|
thiserror = "1.0.26"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
serial_test = "0.5.1"
|
||||||
|
|
||||||
# Async helpers
|
# Async helpers
|
||||||
async-trait = "0.1.42"
|
async-trait = "0.1.42"
|
||||||
|
@ -95,6 +95,7 @@ pub const SYSTEM_DEV_PATH: &str = "/dev";
|
|||||||
// Linux UEvent related consts.
|
// Linux UEvent related consts.
|
||||||
pub const U_EVENT_ACTION: &str = "ACTION";
|
pub const U_EVENT_ACTION: &str = "ACTION";
|
||||||
pub const U_EVENT_ACTION_ADD: &str = "add";
|
pub const U_EVENT_ACTION_ADD: &str = "add";
|
||||||
|
pub const U_EVENT_ACTION_REMOVE: &str = "remove";
|
||||||
pub const U_EVENT_DEV_PATH: &str = "DEVPATH";
|
pub const U_EVENT_DEV_PATH: &str = "DEVPATH";
|
||||||
pub const U_EVENT_SUB_SYSTEM: &str = "SUBSYSTEM";
|
pub const U_EVENT_SUB_SYSTEM: &str = "SUBSYSTEM";
|
||||||
pub const U_EVENT_SEQ_NUM: &str = "SEQNUM";
|
pub const U_EVENT_SEQ_NUM: &str = "SEQNUM";
|
||||||
|
@ -465,7 +465,10 @@ mod tests {
|
|||||||
baremount.mount()
|
baremount.mount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn set_sandbox_storage() {
|
async fn set_sandbox_storage() {
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
let mut s = Sandbox::new(&logger).unwrap();
|
let mut s = Sandbox::new(&logger).unwrap();
|
||||||
@ -500,6 +503,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn remove_sandbox_storage() {
|
async fn remove_sandbox_storage() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
|
|
||||||
@ -556,6 +560,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn unset_and_remove_sandbox_storage() {
|
async fn unset_and_remove_sandbox_storage() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
|
|
||||||
@ -607,6 +612,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn unset_sandbox_storage() {
|
async fn unset_sandbox_storage() {
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
let mut s = Sandbox::new(&logger).unwrap();
|
let mut s = Sandbox::new(&logger).unwrap();
|
||||||
@ -690,6 +696,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn get_container_entry_exist() {
|
async fn get_container_entry_exist() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
@ -703,6 +710,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn get_container_no_entry() {
|
async fn get_container_no_entry() {
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
let mut s = Sandbox::new(&logger).unwrap();
|
let mut s = Sandbox::new(&logger).unwrap();
|
||||||
@ -712,6 +720,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn add_and_get_container() {
|
async fn add_and_get_container() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
@ -723,6 +732,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn update_shared_pidns() {
|
async fn update_shared_pidns() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
@ -741,6 +751,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn add_guest_hooks() {
|
async fn add_guest_hooks() {
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
let mut s = Sandbox::new(&logger).unwrap();
|
let mut s = Sandbox::new(&logger).unwrap();
|
||||||
@ -764,6 +775,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn test_sandbox_set_destroy() {
|
async fn test_sandbox_set_destroy() {
|
||||||
let logger = slog::Logger::root(slog::Discard, o!());
|
let logger = slog::Logger::root(slog::Discard, o!());
|
||||||
let mut s = Sandbox::new(&logger).unwrap();
|
let mut s = Sandbox::new(&logger).unwrap();
|
||||||
|
@ -97,10 +97,18 @@ impl Uevent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
|
async fn process_remove(&self, logger: &Logger, sandbox: &Arc<Mutex<Sandbox>>) {
|
||||||
|
let mut sb = sandbox.lock().await;
|
||||||
|
sb.uevent_map.remove(&self.devpath);
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
async fn process(&self, logger: &Logger, sandbox: &Arc<Mutex<Sandbox>>) {
|
async fn process(&self, logger: &Logger, sandbox: &Arc<Mutex<Sandbox>>) {
|
||||||
if self.action == U_EVENT_ACTION_ADD {
|
if self.action == U_EVENT_ACTION_ADD {
|
||||||
return self.process_add(logger, sandbox).await;
|
return self.process_add(logger, sandbox).await;
|
||||||
|
} else if self.action == U_EVENT_ACTION_REMOVE {
|
||||||
|
return self.process_remove(logger, sandbox).await;
|
||||||
}
|
}
|
||||||
debug!(*logger, "ignoring event"; "uevent" => format!("{:?}", self));
|
debug!(*logger, "ignoring event"; "uevent" => format!("{:?}", self));
|
||||||
}
|
}
|
||||||
|
@ -982,7 +982,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn create_tmpfs() {
|
async fn create_tmpfs() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
|
|
||||||
@ -997,6 +1000,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn spawn_thread() {
|
async fn spawn_thread() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
|
|
||||||
@ -1026,6 +1030,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
async fn verify_container_cleanup_watching() {
|
async fn verify_container_cleanup_watching() {
|
||||||
skip_if_not_root!();
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
@ -147,8 +147,15 @@ func getDistroDetails() (name, version string, err error) {
|
|||||||
// centos: 3.10.0-957.12.1.el7.x86_64
|
// centos: 3.10.0-957.12.1.el7.x86_64
|
||||||
// fedora: 5.0.9-200.fc29.x86_64
|
// fedora: 5.0.9-200.fc29.x86_64
|
||||||
//
|
//
|
||||||
|
// For some self compiled kernel, the kernel version will be with "+" as its suffix
|
||||||
|
// For example:
|
||||||
|
// 5.12.0-rc4+
|
||||||
|
// These kernel version can't be parsed by the current lib and lead to panic
|
||||||
|
// therefore the '+' should be removed.
|
||||||
|
//
|
||||||
func fixKernelVersion(version string) string {
|
func fixKernelVersion(version string) string {
|
||||||
return strings.Replace(version, "_", "-", -1)
|
version = strings.Replace(version, "_", "-", -1)
|
||||||
|
return strings.Replace(version, "+", "", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDistroName checks that the current distro is compatible with
|
// handleDistroName checks that the current distro is compatible with
|
||||||
|
@ -307,11 +307,24 @@ func (h hypervisor) GetEntropySource() string {
|
|||||||
return h.EntropySource
|
return h.EntropySource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Current cpu number should not larger than defaultMaxVCPUs()
|
||||||
|
func getCurrentCpuNum() uint32 {
|
||||||
|
var cpu uint32
|
||||||
|
h := hypervisor{}
|
||||||
|
|
||||||
|
cpu = uint32(goruntime.NumCPU())
|
||||||
|
if cpu > h.defaultMaxVCPUs() {
|
||||||
|
cpu = h.defaultMaxVCPUs()
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu
|
||||||
|
}
|
||||||
|
|
||||||
func (h hypervisor) defaultVCPUs() uint32 {
|
func (h hypervisor) defaultVCPUs() uint32 {
|
||||||
numCPUs := goruntime.NumCPU()
|
numCPUs := getCurrentCpuNum()
|
||||||
|
|
||||||
if h.NumVCPUs < 0 || h.NumVCPUs > int32(numCPUs) {
|
if h.NumVCPUs < 0 || h.NumVCPUs > int32(numCPUs) {
|
||||||
return uint32(numCPUs)
|
return numCPUs
|
||||||
}
|
}
|
||||||
if h.NumVCPUs == 0 { // or unspecified
|
if h.NumVCPUs == 0 { // or unspecified
|
||||||
return defaultVCPUCount
|
return defaultVCPUCount
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
goruntime "runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
@ -156,7 +155,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf
|
|||||||
KernelParams: vc.DeserializeParams(strings.Fields(kernelParams)),
|
KernelParams: vc.DeserializeParams(strings.Fields(kernelParams)),
|
||||||
HypervisorMachineType: machineType,
|
HypervisorMachineType: machineType,
|
||||||
NumVCPUs: defaultVCPUCount,
|
NumVCPUs: defaultVCPUCount,
|
||||||
DefaultMaxVCPUs: uint32(goruntime.NumCPU()),
|
DefaultMaxVCPUs: getCurrentCpuNum(),
|
||||||
MemorySize: defaultMemSize,
|
MemorySize: defaultMemSize,
|
||||||
DisableBlockDeviceUse: disableBlockDevice,
|
DisableBlockDeviceUse: disableBlockDevice,
|
||||||
BlockDeviceDriver: defaultBlockDeviceDriver,
|
BlockDeviceDriver: defaultBlockDeviceDriver,
|
||||||
@ -919,13 +918,13 @@ func TestNewClhHypervisorConfig(t *testing.T) {
|
|||||||
func TestHypervisorDefaults(t *testing.T) {
|
func TestHypervisorDefaults(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
numCPUs := goruntime.NumCPU()
|
numCPUs := getCurrentCpuNum()
|
||||||
|
|
||||||
h := hypervisor{}
|
h := hypervisor{}
|
||||||
|
|
||||||
assert.Equal(h.machineType(), defaultMachineType, "default hypervisor machine type wrong")
|
assert.Equal(h.machineType(), defaultMachineType, "default hypervisor machine type wrong")
|
||||||
assert.Equal(h.defaultVCPUs(), defaultVCPUCount, "default vCPU number is wrong")
|
assert.Equal(h.defaultVCPUs(), defaultVCPUCount, "default vCPU number is wrong")
|
||||||
assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong")
|
assert.Equal(h.defaultMaxVCPUs(), numCPUs, "default max vCPU number is wrong")
|
||||||
assert.Equal(h.defaultMemSz(), defaultMemSize, "default memory size is wrong")
|
assert.Equal(h.defaultMemSz(), defaultMemSize, "default memory size is wrong")
|
||||||
|
|
||||||
machineType := "foo"
|
machineType := "foo"
|
||||||
@ -934,23 +933,23 @@ func TestHypervisorDefaults(t *testing.T) {
|
|||||||
|
|
||||||
// auto inferring
|
// auto inferring
|
||||||
h.NumVCPUs = -1
|
h.NumVCPUs = -1
|
||||||
assert.Equal(h.defaultVCPUs(), uint32(numCPUs), "default vCPU number is wrong")
|
assert.Equal(h.defaultVCPUs(), numCPUs, "default vCPU number is wrong")
|
||||||
|
|
||||||
h.NumVCPUs = 2
|
h.NumVCPUs = 2
|
||||||
assert.Equal(h.defaultVCPUs(), uint32(2), "default vCPU number is wrong")
|
assert.Equal(h.defaultVCPUs(), uint32(2), "default vCPU number is wrong")
|
||||||
|
|
||||||
h.NumVCPUs = int32(numCPUs) + 1
|
h.NumVCPUs = int32(numCPUs) + 1
|
||||||
assert.Equal(h.defaultVCPUs(), uint32(numCPUs), "default vCPU number is wrong")
|
assert.Equal(h.defaultVCPUs(), numCPUs, "default vCPU number is wrong")
|
||||||
|
|
||||||
h.DefaultMaxVCPUs = 2
|
h.DefaultMaxVCPUs = 2
|
||||||
assert.Equal(h.defaultMaxVCPUs(), uint32(2), "default max vCPU number is wrong")
|
assert.Equal(h.defaultMaxVCPUs(), uint32(2), "default max vCPU number is wrong")
|
||||||
|
|
||||||
h.DefaultMaxVCPUs = uint32(numCPUs) + 1
|
h.DefaultMaxVCPUs = numCPUs + 1
|
||||||
assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong")
|
assert.Equal(h.defaultMaxVCPUs(), numCPUs, "default max vCPU number is wrong")
|
||||||
|
|
||||||
maxvcpus := vc.MaxQemuVCPUs()
|
maxvcpus := vc.MaxQemuVCPUs()
|
||||||
h.DefaultMaxVCPUs = maxvcpus + 1
|
h.DefaultMaxVCPUs = maxvcpus + 1
|
||||||
assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong")
|
assert.Equal(h.defaultMaxVCPUs(), numCPUs, "default max vCPU number is wrong")
|
||||||
|
|
||||||
h.MemorySize = 1024
|
h.MemorySize = 1024
|
||||||
assert.Equal(h.defaultMemSz(), uint32(1024), "default memory size is wrong")
|
assert.Equal(h.defaultMemSz(), uint32(1024), "default memory size is wrong")
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -22,7 +23,8 @@ import (
|
|||||||
const testDisabledAsNonRoot = "Test disabled as requires root privileges"
|
const testDisabledAsNonRoot = "Test disabled as requires root privileges"
|
||||||
|
|
||||||
func TestTemplateFactory(t *testing.T) {
|
func TestTemplateFactory(t *testing.T) {
|
||||||
if os.Geteuid() != 0 {
|
// template is broken on arm64, so, temporarily disable it on arm64
|
||||||
|
if runtime.GOARCH == "arm64" || os.Geteuid() != 0 {
|
||||||
t.Skip(testDisabledAsNonRoot)
|
t.Skip(testDisabledAsNonRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ func (conf *HypervisorConfig) valid() error {
|
|||||||
conf.BlockDeviceDriver = config.VirtioBlockCCW
|
conf.BlockDeviceDriver = config.VirtioBlockCCW
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.DefaultMaxVCPUs == 0 {
|
if conf.DefaultMaxVCPUs == 0 || conf.DefaultMaxVCPUs > defaultMaxQemuVCPUs {
|
||||||
conf.DefaultMaxVCPUs = defaultMaxQemuVCPUs
|
conf.DefaultMaxVCPUs = defaultMaxQemuVCPUs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ spec:
|
|||||||
katacontainers.io/kata-runtime: cleanup
|
katacontainers.io/kata-runtime: cleanup
|
||||||
containers:
|
containers:
|
||||||
- name: kube-kata-cleanup
|
- name: kube-kata-cleanup
|
||||||
image: quay.io/kata-containers/kata-deploy:2.2.2
|
image: quay.io/kata-containers/kata-deploy:2.2.3
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
command: [ "bash", "-c", "/opt/kata-artifacts/scripts/kata-deploy.sh reset" ]
|
command: [ "bash", "-c", "/opt/kata-artifacts/scripts/kata-deploy.sh reset" ]
|
||||||
env:
|
env:
|
||||||
|
@ -16,7 +16,7 @@ spec:
|
|||||||
serviceAccountName: kata-label-node
|
serviceAccountName: kata-label-node
|
||||||
containers:
|
containers:
|
||||||
- name: kube-kata
|
- name: kube-kata
|
||||||
image: quay.io/kata-containers/kata-deploy:2.2.2
|
image: quay.io/kata-containers/kata-deploy:2.2.3
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
lifecycle:
|
lifecycle:
|
||||||
preStop:
|
preStop:
|
||||||
|
@ -15,4 +15,6 @@ RUN apt install -y \
|
|||||||
flex \
|
flex \
|
||||||
git \
|
git \
|
||||||
iptables \
|
iptables \
|
||||||
libelf-dev \
|
libelf-dev
|
||||||
|
|
||||||
|
RUN [ "$(uname -m)" = "s390x" ] && apt-get install -y libssl-dev || true
|
||||||
|
@ -16,7 +16,6 @@ qemu_black_list=(
|
|||||||
*/share/*/efi-rtl8139.rom
|
*/share/*/efi-rtl8139.rom
|
||||||
*/share/*/efi-vmxnet3.rom
|
*/share/*/efi-vmxnet3.rom
|
||||||
*/share/*/icons
|
*/share/*/icons
|
||||||
*/share/*/*.img
|
|
||||||
*/share/*/keymaps
|
*/share/*/keymaps
|
||||||
*/share/*/multiboot.bin
|
*/share/*/multiboot.bin
|
||||||
*/share/*/npcm7xx_bootrom.bin
|
*/share/*/npcm7xx_bootrom.bin
|
||||||
|
@ -36,7 +36,6 @@ RUN apt-get --no-install-recommends install -y \
|
|||||||
libltdl-dev \
|
libltdl-dev \
|
||||||
libmount-dev \
|
libmount-dev \
|
||||||
libpixman-1-dev \
|
libpixman-1-dev \
|
||||||
libpmem-dev \
|
|
||||||
libselinux1-dev \
|
libselinux1-dev \
|
||||||
libtool \
|
libtool \
|
||||||
make \
|
make \
|
||||||
@ -49,6 +48,8 @@ RUN apt-get --no-install-recommends install -y \
|
|||||||
rsync \
|
rsync \
|
||||||
zlib1g-dev
|
zlib1g-dev
|
||||||
|
|
||||||
|
RUN [ "$(uname -m)" != "s390x" ] && apt-get install -y libpmem-dev || true
|
||||||
|
|
||||||
ARG QEMU_REPO
|
ARG QEMU_REPO
|
||||||
|
|
||||||
RUN cd .. && git clone "${QEMU_REPO}" qemu
|
RUN cd .. && git clone "${QEMU_REPO}" qemu
|
||||||
|
Loading…
Reference in New Issue
Block a user