Compare commits

..

34 Commits

Author SHA1 Message Date
Archana Shinde
65dd151e0a Merge pull request #5047 from amshinde/2.5.1-branch-bump
# Kata Containers 2.5.1
2022-09-02 06:43:49 +05:30
Archana Shinde
d6437435a2 release: Kata Containers 2.5.1
f74155cd5 release: Adapt kata-deploy for 2.5.1
cd898d28c runtime: clh: Use the new 'payload' interface
e8512320c runtime: clh: Re-generate the client code
2e3ae3f23 agent-ctl: Get rid of compiler warning
14a4551d5 versions: Upgrade rust supported version to 1.59.0
012837260 versions: Update kernel to 5.15.63
69505695b agent-ctl/trace-forwarder: udpate thread_local dependency
48a94f36a agent/runk: update regex dependency
1a396a178 dep: update nix dependency
c0b5ba230 versions: Upgrade to Cloud Hypervisor v26.0

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2022-09-01 11:36:56 -07:00
Archana Shinde
38801e5bf1 release: Adapt kata-deploy for 2.5.1
kata-deploy files must be adapted to a new release.  The cases where it
happens are when the release goes from -> to:
* main -> stable:
  * kata-deploy-stable / kata-cleanup-stable: are removed

* stable -> stable:
  * kata-deploy / kata-cleanup: bump the release to the new one.

There are no changes when doing an alpha release, as the files on the
"main" branch always point to the "latest" and "stable" tags.

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2022-08-31 20:51:06 -07:00
Miao Xia
8f8b93d753 kernel: Add CONFIG_CGROUP_HUGETLB=y as part of the cgroup fragments
Kata guest os cgroup is not work properly kata guest kernel config option
CONFIG_CGROUP_HUGETLB is not set, leading to:

root@clr-b08d402cc29d44719bb582392b7b3466 ls /sys/fs/cgroup/hugetlb/
ls: cannot access '/sys/fs/cgroup/hugetlb/': No such file or directory

Fixes: #4953

Signed-off-by: Miao Xia <xia.miao1@zte.com.cn>
(cherry picked from commit 731d39df45)
2022-08-31 20:51:02 -07:00
Chelsea Mafrica
25b1a52291 runtime: tracing: End root span at end of trace
The root span should exist the duration of the trace. Defer ending span
until the end of the trace instead of end of function. Add the span to
the service struct to do so.

Fixes #4902

Signed-off-by: Chelsea Mafrica <chelsea.e.mafrica@intel.com>
(cherry picked from commit fcc1e0c617)
2022-08-31 20:49:50 -07:00
Bin Liu
5532930107 agent: do some rollback works if case of do_create_container failed
In some cases do_create_container may return an error, mostly due to
`container.start(process)` call. This commit will do some rollback
works if this function failed.

Fixes: #4749

Signed-off-by: Bin Liu <bin@hyper.sh>
(cherry picked from commit 09672eb2da)
2022-08-31 20:49:50 -07:00
Archana Shinde
15e5394073 Merge pull request #5049 from bergwolf/github/backport-stable-2.5
[stable-2.5] backport security related dependency commits
2022-09-01 09:11:35 +05:30
Archana Shinde
54d97c2104 Merge pull request #5052 from fidencio/topic/stable-2.5-update-kernel-before-release
stable-2.5 | versions: Update kernel to 5.15.63
2022-09-01 09:11:06 +05:30
Archana Shinde
d04c7e582f Merge pull request #5059 from amshinde/bump-rust-version
versions: Upgrade rust supported version to 1.59.0 for 2.5 branch
2022-09-01 05:58:15 +05:30
Archana Shinde
2e3ae3f230 agent-ctl: Get rid of compiler warning
With newer version of rust, we get compiler error
of "unneeded late initalization".

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2022-08-31 13:17:14 -07:00
Archana Shinde
14a4551d56 versions: Upgrade rust supported version to 1.59.0
CI is failing with the issue:
"package `time v0.3.14` cannot be built because it requires rustc 1.59.0
or newer, while the currently active rustc version is 1.58.1"

Fixes: #1000

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2022-08-31 10:52:50 -07:00
Fabiano Fidêncio
012837260c versions: Update kernel to 5.15.63
Let's ensure we have the latest longterm maintained kernel as part of
our release.

This brings in `CONFIG_SPECULATION_MITIGATIONS=y`.

Fixes: #5051

Signed-off-by: Fabiano Fidêncio <fabiano.fidencio@intel.com>
2022-08-31 10:23:09 +02:00
Peng Tao
69505695b7 agent-ctl/trace-forwarder: udpate thread_local dependency
To bring in fix to CWE-362.

Fixes: #4968
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2022-08-31 12:41:22 +08:00
Peng Tao
48a94f36a6 agent/runk: update regex dependency
To bring in fix to CVE-2022-24713.

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2022-08-31 12:40:03 +08:00
Peng Tao
1a396a1784 dep: update nix dependency
To fix CVE-2021-45707 that affects nix < 0.20.2.

Fixes: #4929
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2022-08-31 12:13:24 +08:00
Fabiano Fidêncio
b2c6ff0b05 Merge pull request #4955 from likebreath/0818/backport_clh_v26.0
Stable-2.5 | Upgrade to Cloud Hypervisor v26.0
2022-08-19 11:37:16 +02:00
Bo Chen
cd898d28c7 runtime: clh: Use the new 'payload' interface
The new 'payload' interface now contains the 'kernel' and 'initramfs'
config.

Fixes: #4952

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 3a597c2742)
2022-08-18 10:16:34 -07:00
Bo Chen
e8512320c3 runtime: clh: Re-generate the client code
This patch re-generates the client code for Cloud Hypervisor v26.0.
Note: The client code of cloud-hypervisor's (CLH) OpenAPI is
automatically generated by openapi-generator [1-2].

[1] https://github.com/OpenAPITools/openapi-generator
[2] https://github.com/kata-containers/kata-containers/blob/main/src/runtime/virtcontainers/pkg/cloud-hypervisor/README.md

Fixes: #4952

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 16baecc5b1)
2022-08-18 10:16:34 -07:00
Bo Chen
c0b5ba2303 versions: Upgrade to Cloud Hypervisor v26.0
Highlights from the Cloud Hypervisor release v26.0:

**SMBIOS Improvements via `--platform`**
`--platform` and the appropriate API structure has gained support for supplying
OEM strings (primarily used to communicate metadata to systemd in the guest)

**Unified Binary MSHV and KVM Support**
Support for both the MSHV and KVM hypervisors can be compiled into the same
binary with the detection of the hypervisor to use made at runtime.

**Notable Bug Fixes**
* The prefetchable flag is preserved on BARs for VFIO devices
* PCI Express capabilties for functionality we do not support are now filtered
out
* GDB breakpoint support is more reliable
* SIGINT and SIGTERM signals are now handled before the VM has booted
* Multiple API event loop handling bug fixes
* Incorrect assumptions in virtio queue numbering were addressed, allowing
thevirtio-fs driver in OVMF to be used
* VHDX file format header fix
* The same VFIO device cannot be added twice
* SMBIOS tables were being incorrectly generated

**Deprecations**
Deprecated features will be removed in a subsequent release and users should
plan to use alternatives.

The top-level `kernel` and `initramfs` members on the `VmConfig` have been
moved inside a `PayloadConfig` as the `payload` member. The OpenAPI document
has been updated to reflect the change and the old API members continue to
function and are mapped to the new version. The expectation is that these old
versions will be removed in the v28.0 release.

**Removals**
The following functionality has been removed:

The unused poll_queue parameter has been removed from --disk and
equivalent. This was residual from the removal of the vhost-user-block
spawning feature.

Details can be found: https://github.com/cloud-hypervisor/cloud-hypervisor/releases/tag/v26.0

Fixes: #4952

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 50ea071834)
2022-08-18 10:16:34 -07:00
GabyCT
94c7f6e5a9 Merge pull request #4910 from bergwolf/2.5.0-branch-bump
# Kata Containers 2.5.0
2022-08-16 16:41:20 -05:00
Peng Tao
da875e7473 release: Kata Containers 2.5.0
These patches were backported from main branch:

05b2096c0 release: Adapt kata-deploy for 2.5.0
1b930156c build: Fix clh source build as normal user
01c889fb6 runtime: Fix DisableSelinux config
59bd5c2e0 container: kill all of the processes in this container
22c005f55 nydus: upgrade nydus/nydus-snapshotter version
8220e5478 runtime: add unlock before return in sendReq
4f0ca40e0 versions: Update Firecracker version to v1.1.0
da24fd88e clh: Don't crash if no network device is set by the upper layer
ed25d2cf5 versions: Update Cloud Hypervisor to v25.0
dfc1413e4 action: extend commit message line limit to 150 bytes

Depends-on: github.com/kata-containers/tests#5032

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2022-08-16 14:12:10 +08:00
Peng Tao
05b2096c08 release: Adapt kata-deploy for 2.5.0
kata-deploy files must be adapted to a new release.  The cases where it
happens are when the release goes from -> to:
* main -> stable:
  * kata-deploy-stable / kata-cleanup-stable: are removed

* stable -> stable:
  * kata-deploy / kata-cleanup: bump the release to the new one.

There are no changes when doing an alpha release, as the files on the
"main" branch always point to the "latest" and "stable" tags.

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2022-08-16 13:58:34 +08:00
Archana Shinde
1b930156cb build: Fix clh source build as normal user
While running make as non-privileged user, the make errors out with
the following message:
"INFO: Build cloud-hypervisor enabling the following features: tdx
Got permission denied while trying to connect to the Docker daemon
socket at unix:///var/run/docker.sock: Post
"http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/create?fromImage=cloudhypervisor%2Fdev&tag=20220524-0":
dial unix /var/run/docker.sock: connect: permission denied"

Even though the user may be part of docker group, the clh build from
source does a docker in docker build. It is necessary for the user of
the nested container to be part of docker build for the build to
succeed.

Fixes #4594

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2022-08-16 13:58:34 +08:00
Manabu Sugimoto
01c889fb66 runtime: Fix DisableSelinux config
Enable Kata runtime to handle `disable_selinux` flag properly in order
to be able to change the status by the runtime configuration whether the
runtime applies the SELinux label to VMM process.

Fixes: #4599
Signed-off-by: Manabu Sugimoto <Manabu.Sugimoto@sony.com>
2022-08-16 13:58:34 +08:00
Fupan Li
59bd5c2e0a container: kill all of the processes in this container
When a container terminated, we should make sure there's no processes
left after destroying the container.

Before this commit, kata-agent depended on the kernel's pidns
to destroy all of the process in a container after the 1 process
exit in a container. This is true for those container using a
separated pidns, but for the case of shared pidns within the
sandbox, the container exit wouldn't trigger the pidns terminated,
and there would be some daemon process left in this container, this
wasn't expected.

Fixes: #4663

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2022-08-16 13:58:34 +08:00
liubin
22c005f551 nydus: upgrade nydus/nydus-snapshotter version
Upgrade nydus/nydus-snapshotter to the latest version.

Fixes: #4694

Signed-off-by: liubin <liubin0329@gmail.com>
2022-08-16 13:58:34 +08:00
chmod100
8220e54787 runtime: add unlock before return in sendReq
Unlock is required before return, so there need to add unlock

Fixes: #4827

Signed-off-by: chmod100 <letfu@outlook.com>
2022-08-15 19:07:40 +08:00
GabyCT
7fabdf975e Merge pull request #4807 from nubificus/backport-2.5-fc-v1.1
stable-2.5 | versions: Update Firecracker version to v1.1.0
2022-08-03 10:22:05 -05:00
George Ntoutsos
4f0ca40e0c versions: Update Firecracker version to v1.1.0
This patch upgrades Firecracker version from v0.23.4 to v1.1.0

* Generate swagger models for v1.1.0 (from firecracker.yaml)
* Replace ht_enabled param to smt (API change)
* Remove NUMA-related jailer param --node 0

Fixes: #4673
Depends-on: github.com/kata-containers/tests#4968
Backport-of: #4735

Signed-off-by: George Ntoutsos <gntouts@nubificus.co.uk>
Signed-off-by: Anastassios Nanos <ananos@nubificus.co.uk>
2022-08-03 11:33:37 +00:00
Fabiano Fidêncio
79e1249603 Merge pull request #4653 from fidencio/topic/stable-2.5-fix-clh-crash-when-booting-up-with-no-network-device
stable-2.5 | clh: Don't crash if no network device is set by the upper layer
2022-07-13 20:37:10 +02:00
Fabiano Fidêncio
da24fd88e2 clh: Don't crash if no network device is set by the upper layer
`ctr` doesn't set a network device when creating the sandbox, which
leads to Cloud Hypervisor's driver crashing, see the log below:
```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x55641c23b248]
goroutine 32 [running]:
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.glob..func1(0xc000397900)
	/home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/clh.go:163 +0x128
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*cloudHypervisor).vmAddNetPut(...)
	/home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/clh.go:1348
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*cloudHypervisor).bootVM(0xc000397900, {0x55641c76dfc0, 0xc000454ae0})
	/home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/clh.go:1378 +0x5a2
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*cloudHypervisor).StartVM(0xc000397900, {0x55641c76dff8, 0xc00044c240},
0x55641b8016fd)
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/clh.go:659 +0x7ee
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*Sandbox).startVM.func2()
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/sandbox.go:1219 +0x190
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*LinuxNetwork).Run.func1({0xc0004a8910, 0x3b})
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/network_linux.go:319 +0x1b
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.doNetNS({0xc000048440, 0xc00044c240}, 0xc0005d5b38)
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/network_linux.go:1045 +0x163
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*LinuxNetwork).Run(0xc000150c80, {0x55641c76dff8, 0xc00044c240}, 0xc00014e4e0)
	/home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/network_linux.go:318 +0x105
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*Sandbox).startVM(0xc000107d40, {0x55641c76dff8, 0xc0005529f0})
	/home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/sandbox.go:1205 +0x65f
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.createSandboxFromConfig({_, _}, {{0x0, 0x0, 0x0}, {0xc000385a00, 0x1, 0x1},
{0x55641d033260, 0x0, ...}, ...}, ...)
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/api.go:91 +0x346
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.CreateSandbox({_, _}, {{0x0, 0x0, 0x0}, {0xc000385a00, 0x1, 0x1},
{0x55641d033260, 0x0, ...}, ...}, ...)
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/api.go:51 +0x150
github.com/kata-containers/kata-containers/src/runtime/virtcontainers.(*VCImpl).CreateSandbox(_, {_, _}, {{0x0, 0x0, 0x0}, {0xc000385a00, 0x1, 0x1},
{0x55641d033260, ...}, ...})
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/virtcontainers/implementation.go:35 +0x74
github.com/kata-containers/kata-containers/src/runtime/pkg/katautils.CreateSandbox({_, _}, {_, _}, {{0xc0004806c0, 0x9}, 0xc000140110, 0xc00000f7a0,
{0x0, 0x0}, ...}, ...)
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/pkg/katautils/create.go:175 +0x8b6
github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2.create({0x55641c76dff8, 0xc0004129f0}, 0xc00034a000, 0xc00036a000)
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2/create.go:147 +0xdea
github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2.(*service).Create.func2()
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2/service.go:401 +0x32
created by github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2.(*service).Create
        /home/ubuntu/go/src/github.com/kata-containers/kata-containers/src/runtime/pkg/containerd-shim-v2/service.go:400 +0x534
```

This bug has been introduced as part of the
https://github.com/kata-containers/kata-containers/pull/4312 PR, which
changed how we add the network device.

In order to avoid the crash, let's simply check whether we have a device
to be added before iterating the list of network devices.

Fixes: #4618

Signed-off-by: Fabiano Fidêncio <fabiano.fidencio@intel.com>
(cherry picked from commit be31207f6e)
2022-07-13 15:43:28 +02:00
Fabiano Fidêncio
0e8e10540b Merge pull request #4643 from fidencio/topic/stable-2.5-bump-clh-to-v25.0-release
stable-2.5 | versions: Update Cloud Hypervisor to v25.0
2022-07-13 15:03:37 +02:00
Fabiano Fidêncio
ed25d2cf5b versions: Update Cloud Hypervisor to v25.0
Cloud Hypervisor v25.0 has been released on July 7th, 2022, and brings
the following changes:

**ch-remote Improvements**
The ch-remote command has gained support for creating the VM from a JSON
config and support for booting and deleting the VM from the VMM.

**VM "Coredump" Support**
Under the guest_debug feature flag it is now possible to extract the memory
of the guest for use in debugging with e.g. the crash utility.
(https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4012)

**Notable Bug Fixes**
* Always restore console mode on exit
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4249,
   https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4248)
* Restore vCPUs in numerical order which fixes aarch64 snapshot/restore
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4244)
* Don't try and configure IFF_RUNNING on TAP devices
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4279)
* Propagate configured queue size through to vhost-user backend
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4286)
* Always Program vCPU CPUID before running the vCPU to fix running on Linux
  5.16
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4156)
* Enable ACPI MADT "Online Capable" flag for hotpluggable vCPUs to fix newer
  Linux guest

**Removals**
The following functionality has been removed:

* The mergeable option from the virtio-pmem support has been removed
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/3968)
* The dax option from the virtio-fs support has been removed
  (https://github.com/cloud-hypervisor/cloud-hypervisor/issues/3889)

Fixes: #4641

Signed-off-by: Fabiano Fidêncio <fabiano.fidencio@intel.com>
2022-07-13 09:00:09 +02:00
Peng Tao
dfc1413e4a action: extend commit message line limit to 150 bytes
So that we can add move info there and few people use such small
terminals nowadays.

Fixes: #4596
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
(cherry picked from commit 3bafafec58)
Signed-off-by: Fabiano Fidêncio <fabiano.fidencio@intel.com>
2022-07-13 09:00:09 +02:00
1110 changed files with 14447 additions and 103668 deletions

View File

@@ -1,40 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2022 Red Hat
#
# SPDX-License-Identifier: Apache-2.0
#
script_dir=$(dirname "$(readlink -f "$0")")
parent_dir=$(realpath "${script_dir}/../..")
cidir="${parent_dir}/ci"
source "${cidir}/lib.sh"
cargo_deny_file="${script_dir}/action.yaml"
cat cargo-deny-skeleton.yaml.in > "${cargo_deny_file}"
changed_files_status=$(run_get_pr_changed_file_details)
changed_files_status=$(echo "$changed_files_status" | grep "Cargo\.toml$" || true)
changed_files=$(echo "$changed_files_status" | awk '{print $NF}' || true)
if [ -z "$changed_files" ]; then
cat >> "${cargo_deny_file}" << EOF
- run: echo "No Cargo.toml files to check"
shell: bash
EOF
fi
for path in $changed_files
do
cat >> "${cargo_deny_file}" << EOF
- name: ${path}
continue-on-error: true
shell: bash
run: |
pushd $(dirname ${path})
cargo deny check
popd
EOF
done

View File

@@ -1,30 +0,0 @@
#
# Copyright (c) 2022 Red Hat
#
# SPDX-License-Identifier: Apache-2.0
#
name: 'Cargo Crates Check'
description: 'Checks every Cargo.toml file using cargo-deny'
env:
CARGO_TERM_COLOR: always
runs:
using: "composite"
steps:
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Install Cargo deny
shell: bash
run: |
which cargo
cargo install --locked cargo-deny || true

View File

@@ -1,100 +0,0 @@
name: Add backport label
on:
pull_request:
types:
- opened
- synchronize
- reopened
- edited
- labeled
- unlabeled
jobs:
check-issues:
if: ${{ github.event.label.name != 'auto-backport' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code to allow hub to communicate with the project
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
- name: Install hub extension script
run: |
pushd $(mktemp -d) &>/dev/null
git clone --single-branch --depth 1 "https://github.com/kata-containers/.github" && cd .github/scripts
sudo install hub-util.sh /usr/local/bin
popd &>/dev/null
- name: Determine whether to add label
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CONTAINS_AUTO_BACKPORT: ${{ contains(github.event.pull_request.labels.*.name, 'auto-backport') }}
id: add_label
run: |
pr=${{ github.event.pull_request.number }}
linked_issue_urls=$(hub-util.sh \
list-issues-for-pr "$pr" |\
grep -v "^\#" |\
cut -d';' -f3 || true)
[ -z "$linked_issue_urls" ] && {
echo "::error::No linked issues for PR $pr"
exit 1
}
has_bug=false
for issue_url in $(echo "$linked_issue_urls")
do
issue=$(echo "$issue_url"| awk -F\/ '{print $NF}' || true)
[ -z "$issue" ] && {
echo "::error::Cannot determine issue number from $issue_url for PR $pr"
exit 1
}
labels=$(hub-util.sh list-labels-for-issue "$issue")
label_names=$(echo $labels | jq -r '.[].name' || true)
if [[ "$label_names" =~ "bug" ]]; then
has_bug=true
break
fi
done
has_backport_needed_label=${{ contains(github.event.pull_request.labels.*.name, 'needs-backport') }}
has_no_backport_needed_label=${{ contains(github.event.pull_request.labels.*.name, 'no-backport-needed') }}
echo "::set-output name=add_backport_label::false"
if [ $has_backport_needed_label = true ] || [ $has_bug = true ]; then
if [[ $has_no_backport_needed_label = false ]]; then
echo "::set-output name=add_backport_label::true"
fi
fi
# Do not spam comment, only if auto-backport label is going to be newly added.
echo "::set-output name=auto_backport_added::$CONTAINS_AUTO_BACKPORT"
- name: Add comment
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') && steps.add_label.outputs.add_backport_label == 'true' && steps.add_label.outputs.auto_backport_added == 'false' }}
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'This issue has been marked for auto-backporting. Add label(s) backport-to-BRANCHNAME to backport to them'
})
# Allow label to be removed by adding no-backport-needed label
- name: Remove auto-backport label
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') && steps.add_label.outputs.add_backport_label == 'false' }}
uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90
with:
remove-labels: "auto-backport"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Add auto-backport label
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') && steps.add_label.outputs.add_backport_label == 'true' }}
uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90
with:
add-labels: "auto-backport"
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,29 +0,0 @@
on:
pull_request_target:
types: ["labeled", "closed"]
jobs:
backport:
name: Backport PR
runs-on: ubuntu-latest
if: |
github.event.pull_request.merged == true
&& contains(github.event.pull_request.labels.*.name, 'auto-backport')
&& (
(github.event.action == 'labeled' && github.event.label.name == 'auto-backport')
|| (github.event.action == 'closed')
)
steps:
- name: Backport Action
uses: sqren/backport-github-action@v8.9.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
auto_backport_label_prefix: backport-to-
- name: Info log
if: ${{ success() }}
run: cat /home/runner/.backport/backport.info.log
- name: Debug log
if: ${{ failure() }}
run: cat /home/runner/.backport/backport.debug.log

View File

@@ -1,19 +0,0 @@
name: Cargo Crates Check Runner
on: [pull_request]
jobs:
cargo-deny-runner:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
- name: Generate Action
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: bash cargo-deny-generator.sh
working-directory: ./.github/cargo-deny-composite-action/
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Run Action
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: ./.github/cargo-deny-composite-action

View File

@@ -1,98 +0,0 @@
name: CI | Publish Kata Containers payload for Confidential Containers
on:
push:
branches:
- CCv0
jobs:
build-asset:
runs-on: ubuntu-latest
strategy:
matrix:
asset:
- cc-cloud-hypervisor
- cc-kernel
- cc-qemu
- cc-rootfs-image
- cc-shim-v2
- cc-virtiofsd
- cc-sev-kernel
- cc-sev-ovmf
- cc-sev-rootfs-initrd
- cc-tdx-kernel
- cc-tdx-rootfs-image
- cc-tdx-qemu
- cc-tdx-td-shim
- cc-tdx-tdvf
steps:
- name: Login to Kata Containers quay.io
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v3
with:
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Build ${{ matrix.asset }}
run: |
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
sudo cp -r "${build_dir}" "kata-build"
env:
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
PUSH_TO_REGISTRY: yes
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v3
with:
name: kata-artifacts
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
retention-days: 1
if-no-files-found: error
create-kata-tarball:
runs-on: ubuntu-latest
needs: build-asset
steps:
- uses: actions/checkout@v3
- name: get-artifacts
uses: actions/download-artifact@v3
with:
name: kata-artifacts
path: kata-artifacts
- name: merge-artifacts
run: |
./tools/packaging/kata-deploy/local-build/kata-deploy-merge-builds.sh kata-artifacts
- name: store-artifacts
uses: actions/upload-artifact@v3
with:
name: kata-static-tarball
path: kata-static.tar.xz
retention-days: 1
if-no-files-found: error
kata-payload:
needs: create-kata-tarball
runs-on: ubuntu-latest
steps:
- name: Login to Confidential Containers quay.io
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.COCO_QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.COCO_QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v3
- name: get-kata-tarball
uses: actions/download-artifact@v3
with:
name: kata-static-tarball
- name: build-and-push-kata-payload
id: build-and-push-kata-payload
run: |
./tools/packaging/kata-deploy/local-build/kata-deploy-build-and-upload-payload.sh $(pwd)/kata-static.tar.xz "quay.io/confidential-containers/runtime-payload-ci" "kata-containers-latest"

View File

@@ -1,88 +0,0 @@
name: Publish Kata Containers payload for Confidential Containers
on:
push:
tags:
- 'CC\-[0-9]+.[0-9]+.[0-9]+'
jobs:
build-asset:
runs-on: ubuntu-latest
strategy:
matrix:
asset:
- cc-cloud-hypervisor
- cc-kernel
- cc-qemu
- cc-rootfs-image
- cc-shim-v2
- cc-virtiofsd
- cc-sev-kernel
- cc-sev-ovmf
- cc-sev-rootfs-initrd
- cc-tdx-kernel
- cc-tdx-rootfs-image
- cc-tdx-qemu
- cc-tdx-td-shim
- cc-tdx-tdvf
steps:
- uses: actions/checkout@v3
- name: Build ${{ matrix.asset }}
run: |
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
sudo cp -r "${build_dir}" "kata-build"
env:
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v3
with:
name: kata-artifacts
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
retention-days: 1
if-no-files-found: error
create-kata-tarball:
runs-on: ubuntu-latest
needs: build-asset
steps:
- uses: actions/checkout@v3
- name: get-artifacts
uses: actions/download-artifact@v3
with:
name: kata-artifacts
path: kata-artifacts
- name: merge-artifacts
run: |
./tools/packaging/kata-deploy/local-build/kata-deploy-merge-builds.sh kata-artifacts
- name: store-artifacts
uses: actions/upload-artifact@v3
with:
name: kata-static-tarball
path: kata-static.tar.xz
retention-days: 1
if-no-files-found: error
kata-payload:
needs: create-kata-tarball
runs-on: ubuntu-latest
steps:
- name: Login to quay.io
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.COCO_QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.COCO_QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v3
- name: get-kata-tarball
uses: actions/download-artifact@v3
with:
name: kata-static-tarball
- name: build-and-push-kata-payload
id: build-and-push-kata-payload
run: |
./tools/packaging/kata-deploy/local-build/kata-deploy-build-and-upload-payload.sh $(pwd)/kata-static.tar.xz

View File

@@ -47,7 +47,7 @@ jobs:
uses: tim-actions/commit-message-checker-with-regex@v0.3.1
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}
pattern: '^.{0,75}(\n.*)*$|^Merge pull request (?:kata-containers)?#[\d]+ from.*'
pattern: '^.{0,75}(\n.*)*$'
error: 'Subject too long (max 75)'
post_error: ${{ env.error_msg }}
@@ -95,6 +95,6 @@ jobs:
uses: tim-actions/commit-message-checker-with-regex@v0.3.1
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}
pattern: '^[\s\t]*[^:\s\t]+[\s\t]*:|^Merge pull request (?:kata-containers)?#[\d]+ from.*'
pattern: '^[\s\t]*[^:\s\t]+[\s\t]*:'
error: 'Failed to find subsystem in subject'
post_error: ${{ env.error_msg }}

View File

@@ -1,129 +0,0 @@
on:
issue_comment:
types: [created, edited]
name: deploy-ccv0-demo
jobs:
check-comment-and-membership:
runs-on: ubuntu-latest
if: |
github.event.issue.pull_request
&& github.event_name == 'issue_comment'
&& github.event.action == 'created'
&& startsWith(github.event.comment.body, '/deploy-ccv0-demo')
steps:
- name: Check membership
uses: kata-containers/is-organization-member@1.0.1
id: is_organization_member
with:
organization: kata-containers
username: ${{ github.event.comment.user.login }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Fail if not member
run: |
result=${{ steps.is_organization_member.outputs.result }}
if [ $result == false ]; then
user=${{ github.event.comment.user.login }}
echo Either ${user} is not part of the kata-containers organization
echo or ${user} has its Organization Visibility set to Private at
echo https://github.com/orgs/kata-containers/people?query=${user}
echo
echo Ensure you change your Organization Visibility to Public and
echo trigger the test again.
exit 1
fi
build-asset:
runs-on: ubuntu-latest
needs: check-comment-and-membership
strategy:
matrix:
asset:
- cloud-hypervisor
- firecracker
- kernel
- qemu
- rootfs-image
- rootfs-initrd
- shim-v2
steps:
- uses: actions/checkout@v2
- name: Install docker
run: |
curl -fsSL https://test.docker.com -o test-docker.sh
sh test-docker.sh
- name: Prepare confidential container rootfs
if: ${{ matrix.asset == 'rootfs-initrd' }}
run: |
pushd include_rootfs/etc
curl -LO https://raw.githubusercontent.com/confidential-containers/documentation/main/demos/ssh-demo/aa-offline_fs_kbc-keys.json
mkdir kata-containers
envsubst < docs/how-to/data/confidential-agent-config.toml.in > kata-containers/agent.toml
popd
env:
AA_KBC_PARAMS: offline_fs_kbc::null
- name: Build ${{ matrix.asset }}
run: |
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
sudo cp -r "${build_dir}" "kata-build"
env:
AA_KBC: offline_fs_kbc
INCLUDE_ROOTFS: include_rootfs
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v2
with:
name: kata-artifacts
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
if-no-files-found: error
create-kata-tarball:
runs-on: ubuntu-latest
needs: build-asset
steps:
- uses: actions/checkout@v2
- name: get-artifacts
uses: actions/download-artifact@v2
with:
name: kata-artifacts
path: kata-artifacts
- name: merge-artifacts
run: |
./tools/packaging/kata-deploy/local-build/kata-deploy-merge-builds.sh kata-artifacts
- name: store-artifacts
uses: actions/upload-artifact@v2
with:
name: kata-static-tarball
path: kata-static.tar.xz
kata-deploy:
needs: create-kata-tarball
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: get-kata-tarball
uses: actions/download-artifact@v2
with:
name: kata-static-tarball
- name: build-and-push-kata-deploy-ci
id: build-and-push-kata-deploy-ci
run: |
tag=$(echo $GITHUB_REF | cut -d/ -f3-)
pushd $GITHUB_WORKSPACE
git checkout $tag
pkg_sha=$(git rev-parse HEAD)
popd
mv kata-static.tar.xz $GITHUB_WORKSPACE/tools/packaging/kata-deploy/kata-static.tar.xz
docker build --build-arg KATA_ARTIFACTS=kata-static.tar.xz -t quay.io/confidential-containers/runtime-payload:$pkg_sha $GITHUB_WORKSPACE/tools/packaging/kata-deploy
docker login -u ${{ secrets.QUAY_DEPLOYER_USERNAME }} -p ${{ secrets.QUAY_DEPLOYER_PASSWORD }} quay.io
docker push quay.io/confidential-containers/runtime-payload:$pkg_sha
mkdir -p packaging/kata-deploy
ln -s $GITHUB_WORKSPACE/tools/packaging/kata-deploy/action packaging/kata-deploy/action
echo "::set-output name=PKG_SHA::${pkg_sha}"

View File

@@ -10,32 +10,35 @@ jobs:
go-version: [1.17.x]
os: [ubuntu-20.04]
runs-on: ${{ matrix.os }}
# don't run this action on forks
if: github.repository_owner == 'kata-containers'
env:
target_branch: ${{ github.base_ref }}
steps:
- name: Install Go
if: github.repository_owner == 'kata-containers'
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Set env
if: github.repository_owner == 'kata-containers'
run: |
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Checkout code
if: github.repository_owner == 'kata-containers'
uses: actions/checkout@v2
with:
fetch-depth: 0
path: ./src/github.com/${{ github.repository }}
- name: Setup
if: github.repository_owner == 'kata-containers'
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/setup.sh
env:
GOPATH: ${{ runner.workspace }}/kata-containers
# docs url alive check
- name: Docs URL Alive Check
if: github.repository_owner == 'kata-containers'
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && make docs-url-alive-check

View File

@@ -1,10 +1,5 @@
on:
workflow_dispatch: # this is used to trigger the workflow on non-main branches
inputs:
pr:
description: 'PR number from the selected branch to test'
type: string
required: true
issue_comment:
types: [created, edited]
@@ -18,20 +13,19 @@ jobs:
&& github.event_name == 'issue_comment'
&& github.event.action == 'created'
&& startsWith(github.event.comment.body, '/test_kata_deploy')
|| github.event_name == 'workflow_dispatch'
steps:
- name: Check membership on comment or dispatch
- name: Check membership
uses: kata-containers/is-organization-member@1.0.1
id: is_organization_member
with:
organization: kata-containers
username: ${{ github.event.comment.user.login || github.event.sender.login }}
username: ${{ github.event.comment.user.login }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Fail if not member
run: |
result=${{ steps.is_organization_member.outputs.result }}
if [ $result == false ]; then
user=${{ github.event.comment.user.login || github.event.sender.login }}
user=${{ github.event.comment.user.login }}
echo Either ${user} is not part of the kata-containers organization
echo or ${user} has its Organization Visibility set to Private at
echo https://github.com/orgs/kata-containers/people?query=${user}
@@ -59,12 +53,8 @@ jobs:
- name: get-PR-ref
id: get-PR-ref
run: |
if [ ${{ github.event_name }} == 'issue_comment' ]; then
ref=$(cat $GITHUB_EVENT_PATH | jq -r '.issue.pull_request.url' | sed 's#^.*\/pulls#refs\/pull#' | sed 's#$#\/merge#')
else # workflow_dispatch
ref="refs/pull/${{ github.event.inputs.pr }}/merge"
fi
echo "reference for PR: " ${ref} "event:" ${{ github.event_name }}
ref=$(cat $GITHUB_EVENT_PATH | jq -r '.issue.pull_request.url' | sed 's#^.*\/pulls#refs\/pull#' | sed 's#$#\/merge#')
echo "reference for PR: " ${ref}
echo "##[set-output name=pr-ref;]${ref}"
- uses: actions/checkout@v2
with:
@@ -99,12 +89,8 @@ jobs:
- name: get-PR-ref
id: get-PR-ref
run: |
if [ ${{ github.event_name }} == 'issue_comment' ]; then
ref=$(cat $GITHUB_EVENT_PATH | jq -r '.issue.pull_request.url' | sed 's#^.*\/pulls#refs\/pull#' | sed 's#$#\/merge#')
else # workflow_dispatch
ref="refs/pull/${{ github.event.inputs.pr }}/merge"
fi
echo "reference for PR: " ${ref} "event:" ${{ github.event_name }}
ref=$(cat $GITHUB_EVENT_PATH | jq -r '.issue.pull_request.url' | sed 's#^.*\/pulls#refs\/pull#' | sed 's#$#\/merge#')
echo "reference for PR: " ${ref}
echo "##[set-output name=pr-ref;]${ref}"
- uses: actions/checkout@v2
with:
@@ -130,12 +116,8 @@ jobs:
- name: get-PR-ref
id: get-PR-ref
run: |
if [ ${{ github.event_name }} == 'issue_comment' ]; then
ref=$(cat $GITHUB_EVENT_PATH | jq -r '.issue.pull_request.url' | sed 's#^.*\/pulls#refs\/pull#' | sed 's#$#\/merge#')
else # workflow_dispatch
ref="refs/pull/${{ github.event.inputs.pr }}/merge"
fi
echo "reference for PR: " ${ref} "event:" ${{ github.event_name }}
ref=$(cat $GITHUB_EVENT_PATH | jq -r '.issue.pull_request.url' | sed 's#^.*\/pulls#refs\/pull#' | sed 's#$#\/merge#')
echo "reference for PR: " ${ref}
echo "##[set-output name=pr-ref;]${ref}"
- uses: actions/checkout@v2
with:

View File

@@ -1,8 +1,8 @@
name: Publish Kata release artifacts
name: Publish Kata 2.x release artifacts
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+*'
- '2.*'
jobs:
build-asset:

View File

@@ -1,9 +1,8 @@
name: Release Kata in snapcraft store
name: Release Kata 2.x in snapcraft store
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+*'
- '2.*'
jobs:
release-snap:
runs-on: ubuntu-20.04

View File

@@ -8,7 +8,7 @@ on:
name: Static checks
jobs:
check-vendored-code:
test:
strategy:
matrix:
go-version: [1.16.x, 1.17.x]
@@ -24,7 +24,7 @@ jobs:
steps:
- name: Install Go
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/setup-go@v3
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
env:
@@ -43,7 +43,7 @@ jobs:
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Checkout code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
fetch-depth: 0
path: ./src/github.com/${{ github.repository }}
@@ -58,303 +58,39 @@ jobs:
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/setup.sh
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Installing rust
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_rust.sh
PATH=$PATH:"$HOME/.cargo/bin"
rustup target add x86_64-unknown-linux-musl
rustup component add rustfmt clippy
- name: Setup seccomp
run: |
libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX)
gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX)
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}"
echo "Set environment variables for the libseccomp crate to link the libseccomp library statically"
echo "LIBSECCOMP_LINK_TYPE=static" >> $GITHUB_ENV
echo "LIBSECCOMP_LIB_PATH=${libseccomp_install_dir}/lib" >> $GITHUB_ENV
# Check whether the vendored code is up-to-date & working as the first thing
- name: Check vendored code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && make vendor
static-checks:
strategy:
matrix:
go-version: [1.16.x, 1.17.x]
os: [ubuntu-20.04]
runs-on: ${{ matrix.os }}
env:
TRAVIS: "true"
TRAVIS_BRANCH: ${{ github.base_ref }}
TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }}
TRAVIS_PULL_REQUEST_SHA : ${{ github.event.pull_request.head.sha }}
RUST_BACKTRACE: "1"
target_branch: ${{ github.base_ref }}
steps:
- name: Install Go
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Setup GOPATH
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH: ${TRAVIS_BRANCH}"
echo "TRAVIS_PULL_REQUEST_BRANCH: ${TRAVIS_PULL_REQUEST_BRANCH}"
echo "TRAVIS_PULL_REQUEST_SHA: ${TRAVIS_PULL_REQUEST_SHA}"
echo "TRAVIS: ${TRAVIS}"
- name: Set env
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Checkout code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
with:
fetch-depth: 0
path: ./src/github.com/${{ github.repository }}
- name: Setup travis references
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = \"/\" } ; { print $3 }')}"
target_branch=${TRAVIS_BRANCH}
- name: Setup
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/setup.sh
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Installing rust
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_rust.sh
PATH=$PATH:"$HOME/.cargo/bin"
rustup target add x86_64-unknown-linux-musl
rustup component add rustfmt clippy
- name: Setup seccomp
run: |
libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX)
gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX)
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}"
echo "Set environment variables for the libseccomp crate to link the libseccomp library statically"
echo "LIBSECCOMP_LINK_TYPE=static" >> $GITHUB_ENV
echo "LIBSECCOMP_LIB_PATH=${libseccomp_install_dir}/lib" >> $GITHUB_ENV
- name: Static Checks
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && make static-checks
compiler-checks:
strategy:
matrix:
go-version: [1.16.x, 1.17.x]
os: [ubuntu-20.04]
runs-on: ${{ matrix.os }}
env:
TRAVIS: "true"
TRAVIS_BRANCH: ${{ github.base_ref }}
TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }}
TRAVIS_PULL_REQUEST_SHA : ${{ github.event.pull_request.head.sha }}
RUST_BACKTRACE: "1"
target_branch: ${{ github.base_ref }}
steps:
- name: Install Go
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Setup GOPATH
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH: ${TRAVIS_BRANCH}"
echo "TRAVIS_PULL_REQUEST_BRANCH: ${TRAVIS_PULL_REQUEST_BRANCH}"
echo "TRAVIS_PULL_REQUEST_SHA: ${TRAVIS_PULL_REQUEST_SHA}"
echo "TRAVIS: ${TRAVIS}"
- name: Set env
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Checkout code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
with:
fetch-depth: 0
path: ./src/github.com/${{ github.repository }}
- name: Setup travis references
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = \"/\" } ; { print $3 }')}"
target_branch=${TRAVIS_BRANCH}
- name: Setup
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/setup.sh
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Installing rust
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_rust.sh
PATH=$PATH:"$HOME/.cargo/bin"
rustup target add x86_64-unknown-linux-musl
rustup component add rustfmt clippy
- name: Setup seccomp
run: |
libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX)
gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX)
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}"
echo "Set environment variables for the libseccomp crate to link the libseccomp library statically"
echo "LIBSECCOMP_LINK_TYPE=static" >> $GITHUB_ENV
echo "LIBSECCOMP_LIB_PATH=${libseccomp_install_dir}/lib" >> $GITHUB_ENV
- name: Run Compiler Checks
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && make check
unit-tests:
runs-on: ubuntu-20.04
env:
TRAVIS: "true"
TRAVIS_BRANCH: ${{ github.base_ref }}
TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }}
TRAVIS_PULL_REQUEST_SHA : ${{ github.event.pull_request.head.sha }}
RUST_BACKTRACE: "1"
target_branch: ${{ github.base_ref }}
steps:
- name: Install Go
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/setup-go@v3
with:
go-version: 1.17.x
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Setup GOPATH
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH: ${TRAVIS_BRANCH}"
echo "TRAVIS_PULL_REQUEST_BRANCH: ${TRAVIS_PULL_REQUEST_BRANCH}"
echo "TRAVIS_PULL_REQUEST_SHA: ${TRAVIS_PULL_REQUEST_SHA}"
echo "TRAVIS: ${TRAVIS}"
- name: Set env
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Checkout code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
with:
fetch-depth: 0
path: ./src/github.com/${{ github.repository }}
- name: Setup travis references
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = \"/\" } ; { print $3 }')}"
target_branch=${TRAVIS_BRANCH}
- name: Setup
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/setup.sh
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Installing rust
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_rust.sh
PATH=$PATH:"$HOME/.cargo/bin"
rustup target add x86_64-unknown-linux-musl
rustup component add rustfmt clippy
- name: Setup seccomp
run: |
libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX)
gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX)
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}"
echo "Set environment variables for the libseccomp crate to link the libseccomp library statically"
echo "LIBSECCOMP_LINK_TYPE=static" >> $GITHUB_ENV
echo "LIBSECCOMP_LIB_PATH=${libseccomp_install_dir}/lib" >> $GITHUB_ENV
- name: Run Unit Tests
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && make test
unit-tests-as-root:
runs-on: ubuntu-20.04
env:
TRAVIS: "true"
TRAVIS_BRANCH: ${{ github.base_ref }}
TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }}
TRAVIS_PULL_REQUEST_SHA : ${{ github.event.pull_request.head.sha }}
RUST_BACKTRACE: "1"
target_branch: ${{ github.base_ref }}
steps:
- name: Install Go
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/setup-go@v3
with:
go-version: 1.17.x
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Setup GOPATH
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH: ${TRAVIS_BRANCH}"
echo "TRAVIS_PULL_REQUEST_BRANCH: ${TRAVIS_PULL_REQUEST_BRANCH}"
echo "TRAVIS_PULL_REQUEST_SHA: ${TRAVIS_PULL_REQUEST_SHA}"
echo "TRAVIS: ${TRAVIS}"
- name: Set env
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Checkout code
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
uses: actions/checkout@v3
with:
fetch-depth: 0
path: ./src/github.com/${{ github.repository }}
- name: Setup travis references
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = \"/\" } ; { print $3 }')}"
target_branch=${TRAVIS_BRANCH}
- name: Setup
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/setup.sh
env:
GOPATH: ${{ runner.workspace }}/kata-containers
- name: Installing rust
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_rust.sh
PATH=$PATH:"$HOME/.cargo/bin"
rustup target add x86_64-unknown-linux-musl
rustup component add rustfmt clippy
- name: Setup seccomp
run: |
libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX)
gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX)
cd ${GOPATH}/src/github.com/${{ github.repository }} && ./ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}"
echo "Set environment variables for the libseccomp crate to link the libseccomp library statically"
echo "LIBSECCOMP_LINK_TYPE=static" >> $GITHUB_ENV
echo "LIBSECCOMP_LIB_PATH=${libseccomp_install_dir}/lib" >> $GITHUB_ENV
- name: Run Unit Tests As Root User
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd ${GOPATH}/src/github.com/${{ github.repository }} && sudo -E PATH="$PATH" make test
test-dragonball:
runs-on: self-hosted
env:
RUST_BACKTRACE: "1"
steps:
- uses: actions/checkout@v3
- name: Set env
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
- name: Install Rust
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
./ci/install_rust.sh
PATH=$PATH:"$HOME/.cargo/bin"
- name: Run Unit Test
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
run: |
cd src/dragonball
/root/.cargo/bin/cargo version
rustc --version
sudo -E env PATH=$PATH LIBC=gnu SUPPORT_VIRTUALIZATION=true make test

View File

@@ -6,25 +6,26 @@
# List of available components
COMPONENTS =
COMPONENTS += libs
COMPONENTS += agent
COMPONENTS += dragonball
COMPONENTS += runtime
COMPONENTS += runtime-rs
# List of available tools
TOOLS =
TOOLS += agent-ctl
TOOLS += kata-ctl
TOOLS += log-parser
TOOLS += runk
TOOLS += trace-forwarder
TOOLS += runk
TOOLS += log-parser
STANDARD_TARGETS = build check clean install test vendor
default: all
all: logging-crate-tests build
logging-crate-tests:
make -C src/libs/logging
include utils.mk
include ./tools/packaging/kata-deploy/local-build/Makefile
@@ -48,6 +49,7 @@ docs-url-alive-check:
binary-tarball \
default \
install-binary-tarball \
logging-crate-tests \
static-checks \
docs-url-alive-check

View File

@@ -71,7 +71,6 @@ See the [official documentation](docs) including:
- [Developer guide](docs/Developer-Guide.md)
- [Design documents](docs/design)
- [Architecture overview](docs/design/architecture)
- [Architecture 3.0 overview](docs/design/architecture_3.0/)
## Configuration
@@ -117,10 +116,9 @@ The table below lists the core parts of the project:
| Component | Type | Description |
|-|-|-|
| [runtime](src/runtime) | core | Main component run by a container manager and providing a containerd shimv2 runtime implementation. |
| [runtime-rs](src/runtime-rs) | core | The Rust version runtime. |
| [agent](src/agent) | core | Management process running inside the virtual machine / POD that sets up the container environment. |
| [`dragonball`](src/dragonball) | core | An optional built-in VMM brings out-of-the-box Kata Containers experience with optimizations on container workloads |
| [documentation](docs) | documentation | Documentation common to all components (such as design and install documentation). |
| [libraries](src/libs) | core | Library crates shared by multiple Kata Container components or published to [`crates.io`](https://crates.io/index.html) |
| [tests](https://github.com/kata-containers/tests) | tests | Excludes unit tests which live with the main code. |
### Additional components
@@ -133,7 +131,6 @@ The table below lists the remaining parts of the project:
| [kernel](https://www.kernel.org) | kernel | Linux kernel used by the hypervisor to boot the guest image. Patches are stored [here](tools/packaging/kernel). |
| [osbuilder](tools/osbuilder) | infrastructure | Tool to create "mini O/S" rootfs and initrd images and kernel for the hypervisor. |
| [`agent-ctl`](src/tools/agent-ctl) | utility | Tool that provides low-level access for testing the agent. |
| [`kata-ctl`](src/tools/kata-ctl) | utility | Tool that provides advanced commands and debug facilities. |
| [`trace-forwarder`](src/tools/trace-forwarder) | utility | Agent tracing helper. |
| [`runk`](src/tools/runk) | utility | Standard OCI container runtime based on the agent. |
| [`ci`](https://github.com/kata-containers/ci) | CI | Continuous Integration configuration files and scripts. |

View File

@@ -1 +1 @@
3.1.0-alpha0
2.5.1

View File

@@ -23,27 +23,25 @@ arch=${ARCH:-$(uname -m)}
workdir="$(mktemp -d --tmpdir build-libseccomp.XXXXX)"
# Variables for libseccomp
libseccomp_version="${LIBSECCOMP_VERSION:-""}"
if [ -z "${libseccomp_version}" ]; then
libseccomp_version=$(get_version "externals.libseccomp.version")
fi
libseccomp_url="${LIBSECCOMP_URL:-""}"
if [ -z "${libseccomp_url}" ]; then
libseccomp_url=$(get_version "externals.libseccomp.url")
fi
# Currently, specify the libseccomp version directly without using `versions.yaml`
# because the current Snap workflow is incomplete.
# After solving the issue, replace this code by using the `versions.yaml`.
# libseccomp_version=$(get_version "externals.libseccomp.version")
# libseccomp_url=$(get_version "externals.libseccomp.url")
libseccomp_version="2.5.1"
libseccomp_url="https://github.com/seccomp/libseccomp"
libseccomp_tarball="libseccomp-${libseccomp_version}.tar.gz"
libseccomp_tarball_url="${libseccomp_url}/releases/download/v${libseccomp_version}/${libseccomp_tarball}"
cflags="-O2"
# Variables for gperf
gperf_version="${GPERF_VERSION:-""}"
if [ -z "${gperf_version}" ]; then
gperf_version=$(get_version "externals.gperf.version")
fi
gperf_url="${GPERF_URL:-""}"
if [ -z "${gperf_url}" ]; then
gperf_url=$(get_version "externals.gperf.url")
fi
# Currently, specify the gperf version directly without using `versions.yaml`
# because the current Snap workflow is incomplete.
# After solving the issue, replace this code by using the `versions.yaml`.
# gperf_version=$(get_version "externals.gperf.version")
# gperf_url=$(get_version "externals.gperf.url")
gperf_version="3.1"
gperf_url="https://ftp.gnu.org/gnu/gperf"
gperf_tarball="gperf-${gperf_version}.tar.gz"
gperf_tarball_url="${gperf_url}/${gperf_tarball}"
@@ -72,8 +70,7 @@ build_and_install_gperf() {
curl -sLO "${gperf_tarball_url}"
tar -xf "${gperf_tarball}"
pushd "gperf-${gperf_version}"
# gperf is a build time dependency of libseccomp and not to be used in the target.
# Unset $CC since that might point to a cross compiler.
# Unset $CC for configure, we will always use native for gperf
CC= ./configure --prefix="${gperf_install_dir}"
make
make install

View File

@@ -54,13 +54,3 @@ run_docs_url_alive_check()
git fetch -a
bash "$tests_repo_dir/.ci/static-checks.sh" --docs --all "github.com/kata-containers/kata-containers"
}
run_get_pr_changed_file_details()
{
clone_tests_repo
# Make sure we have the targeting branch
git remote set-branches --add origin "${branch}"
git fetch -a
source "$tests_repo_dir/.ci/lib.sh"
get_pr_changed_file_details
}

View File

@@ -1,33 +0,0 @@
targets = [
{ triple = "x86_64-apple-darwin" },
{ triple = "x86_64-unknown-linux-gnu" },
{ triple = "x86_64-unknown-linux-musl" },
]
[advisories]
vulnerability = "deny"
unsound = "deny"
unmaintained = "deny"
ignore = ["RUSTSEC-2020-0071"]
[bans]
multiple-versions = "allow"
deny = [
{ name = "cmake" },
{ name = "openssl-sys" },
]
[licenses]
unlicensed = "deny"
allow-osi-fsf-free = "neither"
copyleft = "allow"
# We want really high confidence when inferring licenses from text
confidence-threshold = 0.93
allow = ["0BSD", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "CC0-1.0", "ISC", "MIT", "MPL-2.0"]
private = { ignore = true}
exceptions = []
[sources]
unknown-registry = "allow"
unknown-git = "allow"

View File

@@ -33,41 +33,51 @@ You need to install the following to build Kata Containers components:
- `make`.
- `gcc` (required for building the shim and runtime).
# Build and install Kata Containers
## Build and install the Kata Containers runtime
# Build and install the Kata Containers runtime
```bash
$ git clone https://github.com/kata-containers/kata-containers.git
$ pushd kata-containers/src/runtime
$ make && sudo -E "PATH=$PATH" make install
$ sudo mkdir -p /etc/kata-containers/
$ sudo install -o root -g root -m 0640 /usr/share/defaults/kata-containers/configuration.toml /etc/kata-containers
$ popd
```
$ go get -d -u github.com/kata-containers/kata-containers
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/src/runtime
$ make && sudo -E PATH=$PATH make install
```
The build will create the following:
- runtime binary: `/usr/local/bin/kata-runtime` and `/usr/local/bin/containerd-shim-kata-v2`
- configuration file: `/usr/share/defaults/kata-containers/configuration.toml` and `/etc/kata-containers/configuration.toml`
- configuration file: `/usr/share/defaults/kata-containers/configuration.toml`
# Check hardware requirements
You can check if your system is capable of creating a Kata Container by running the following:
```
$ sudo kata-runtime check
```
If your system is *not* able to run Kata Containers, the previous command will error out and explain why.
## Configure to use initrd or rootfs image
Kata containers can run with either an initrd image or a rootfs image.
If you want to test with `initrd`, make sure you have uncommented `initrd = /usr/share/kata-containers/kata-containers-initrd.img`
in your configuration file, commenting out the `image` line in
`/etc/kata-containers/configuration.toml`. For example:
If you want to test with `initrd`, make sure you have `initrd = /usr/share/kata-containers/kata-containers-initrd.img`
in your configuration file, commenting out the `image` line:
```bash
`/usr/share/defaults/kata-containers/configuration.toml` and comment out the `image` line with the following. For example:
```
$ sudo mkdir -p /etc/kata-containers/
$ sudo install -o root -g root -m 0640 /usr/share/defaults/kata-containers/configuration.toml /etc/kata-containers
$ sudo sed -i 's/^\(image =.*\)/# \1/g' /etc/kata-containers/configuration.toml
$ sudo sed -i 's/^# \(initrd =.*\)/\1/g' /etc/kata-containers/configuration.toml
```
You can create the initrd image as shown in the [create an initrd image](#create-an-initrd-image---optional) section.
If you want to test with a rootfs `image`, make sure you have uncommented `image = /usr/share/kata-containers/kata-containers.img`
If you want to test with a rootfs `image`, make sure you have `image = /usr/share/kata-containers/kata-containers.img`
in your configuration file, commenting out the `initrd` line. For example:
```bash
```
$ sudo mkdir -p /etc/kata-containers/
$ sudo install -o root -g root -m 0640 /usr/share/defaults/kata-containers/configuration.toml /etc/kata-containers
$ sudo sed -i 's/^\(initrd =.*\)/# \1/g' /etc/kata-containers/configuration.toml
```
The rootfs image is created as shown in the [create a rootfs image](#create-a-rootfs-image) section.
@@ -80,7 +90,7 @@ rootfs `image`(100MB+).
Enable seccomp as follows:
```bash
```
$ sudo sed -i '/^disable_guest_seccomp/ s/true/false/' /etc/kata-containers/configuration.toml
```
@@ -90,7 +100,9 @@ This will pass container seccomp profiles to the kata agent.
Enable full debug as follows:
```bash
```
$ sudo mkdir -p /etc/kata-containers/
$ sudo install -o root -g root -m 0640 /usr/share/defaults/kata-containers/configuration.toml /etc/kata-containers
$ sudo sed -i -e 's/^# *\(enable_debug\).*=.*$/\1 = true/g' /etc/kata-containers/configuration.toml
$ sudo sed -i -e 's/^kernel_params = "\(.*\)"/kernel_params = "\1 agent.log=debug initcall_debug"/g' /etc/kata-containers/configuration.toml
```
@@ -163,7 +175,7 @@ and offers possible workarounds and fixes.
it stores. When messages are suppressed, it is noted in the logs. This can be checked
for by looking for those notifications, such as:
```bash
```sh
$ sudo journalctl --since today | fgrep Suppressed
Jun 29 14:51:17 mymachine systemd-journald[346]: Suppressed 4150 messages from /system.slice/docker.service
```
@@ -188,7 +200,7 @@ RateLimitBurst=0
Restart `systemd-journald` for the changes to take effect:
```bash
```sh
$ sudo systemctl restart systemd-journald
```
@@ -202,24 +214,25 @@ $ sudo systemctl restart systemd-journald
The agent is built with a statically linked `musl.` The default `libc` used is `musl`, but on `ppc64le` and `s390x`, `gnu` should be used. To configure this:
```bash
$ export ARCH="$(uname -m)"
```
$ export ARCH=$(uname -m)
$ if [ "$ARCH" = "ppc64le" -o "$ARCH" = "s390x" ]; then export LIBC=gnu; else export LIBC=musl; fi
$ [ "${ARCH}" == "ppc64le" ] && export ARCH=powerpc64le
$ rustup target add "${ARCH}-unknown-linux-${LIBC}"
$ [ ${ARCH} == "ppc64le" ] && export ARCH=powerpc64le
$ rustup target add ${ARCH}-unknown-linux-${LIBC}
```
To build the agent:
```bash
$ make -C kata-containers/src/agent
```
$ go get -d -u github.com/kata-containers/kata-containers
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/src/agent && make
```
The agent is built with seccomp capability by default.
If you want to build the agent without the seccomp capability, you need to run `make` with `SECCOMP=no` as follows.
```bash
$ make -C kata-containers/src/agent SECCOMP=no
```
$ make -C $GOPATH/src/github.com/kata-containers/kata-containers/src/agent SECCOMP=no
```
> **Note:**
@@ -227,6 +240,13 @@ $ make -C kata-containers/src/agent SECCOMP=no
> - If you enable seccomp in the main configuration file but build the agent without seccomp capability,
> the runtime exits conservatively with an error message.
## Get the osbuilder
```
$ go get -d -u github.com/kata-containers/kata-containers
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/tools/osbuilder
```
## Create a rootfs image
### Create a local rootfs
@@ -234,26 +254,24 @@ As a prerequisite, you need to install Docker. Otherwise, you will not be
able to run the `rootfs.sh` script with `USE_DOCKER=true` as expected in
the following example.
```bash
$ export distro="ubuntu" # example
$ export ROOTFS_DIR="$(realpath kata-containers/tools/osbuilder/rootfs-builder/rootfs)"
$ sudo rm -rf "${ROOTFS_DIR}"
$ pushd kata-containers/tools/osbuilder/rootfs-builder
$ script -fec 'sudo -E USE_DOCKER=true ./rootfs.sh "${distro}"'
$ popd
```
$ export ROOTFS_DIR=${GOPATH}/src/github.com/kata-containers/kata-containers/tools/osbuilder/rootfs-builder/rootfs
$ sudo rm -rf ${ROOTFS_DIR}
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/tools/osbuilder/rootfs-builder
$ script -fec 'sudo -E GOPATH=$GOPATH USE_DOCKER=true ./rootfs.sh ${distro}'
```
You MUST choose a distribution (e.g., `ubuntu`) for `${distro}`.
You can get a supported distributions list in the Kata Containers by running the following.
```bash
$ ./kata-containers/tools/osbuilder/rootfs-builder/rootfs.sh -l
```
$ ./rootfs.sh -l
```
If you want to build the agent without seccomp capability, you need to run the `rootfs.sh` script with `SECCOMP=no` as follows.
```bash
$ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true SECCOMP=no ./rootfs.sh "${distro}"'
```
$ script -fec 'sudo -E GOPATH=$GOPATH AGENT_INIT=yes USE_DOCKER=true SECCOMP=no ./rootfs.sh ${distro}'
```
> **Note:**
@@ -269,18 +287,17 @@ $ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true SECCOMP=no ./rootfs.sh "${
>
> - You should only do this step if you are testing with the latest version of the agent.
```bash
$ sudo install -o root -g root -m 0550 -t "${ROOTFS_DIR}/usr/bin" "${ROOTFS_DIR}/../../../../src/agent/target/x86_64-unknown-linux-musl/release/kata-agent"
$ sudo install -o root -g root -m 0440 "${ROOTFS_DIR}/../../../../src/agent/kata-agent.service" "${ROOTFS_DIR}/usr/lib/systemd/system/"
$ sudo install -o root -g root -m 0440 "${ROOTFS_DIR}/../../../../src/agent/kata-containers.target" "${ROOTFS_DIR}/usr/lib/systemd/system/"
```
$ sudo install -o root -g root -m 0550 -t ${ROOTFS_DIR}/usr/bin ../../../src/agent/target/x86_64-unknown-linux-musl/release/kata-agent
$ sudo install -o root -g root -m 0440 ../../../src/agent/kata-agent.service ${ROOTFS_DIR}/usr/lib/systemd/system/
$ sudo install -o root -g root -m 0440 ../../../src/agent/kata-containers.target ${ROOTFS_DIR}/usr/lib/systemd/system/
```
### Build a rootfs image
```bash
$ pushd kata-containers/tools/osbuilder/image-builder
$ script -fec 'sudo -E USE_DOCKER=true ./image_builder.sh "${ROOTFS_DIR}"'
$ popd
```
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/tools/osbuilder/image-builder
$ script -fec 'sudo -E USE_DOCKER=true ./image_builder.sh ${ROOTFS_DIR}'
```
> **Notes:**
@@ -296,26 +313,21 @@ $ popd
### Install the rootfs image
```bash
$ pushd kata-containers/tools/osbuilder/image-builder
$ commit="$(git log --format=%h -1 HEAD)"
$ date="$(date +%Y-%m-%d-%T.%N%z)"
```
$ commit=$(git log --format=%h -1 HEAD)
$ date=$(date +%Y-%m-%d-%T.%N%z)
$ image="kata-containers-${date}-${commit}"
$ sudo install -o root -g root -m 0640 -D kata-containers.img "/usr/share/kata-containers/${image}"
$ (cd /usr/share/kata-containers && sudo ln -sf "$image" kata-containers.img)
$ popd
```
## Create an initrd image - OPTIONAL
### Create a local rootfs for initrd image
```bash
$ export distro="ubuntu" # example
$ export ROOTFS_DIR="$(realpath kata-containers/tools/osbuilder/rootfs-builder/rootfs)"
$ sudo rm -rf "${ROOTFS_DIR}"
$ pushd kata-containers/tools/osbuilder/rootfs-builder/
$ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true ./rootfs.sh "${distro}"'
$ popd
```
$ export ROOTFS_DIR="${GOPATH}/src/github.com/kata-containers/kata-containers/tools/osbuilder/rootfs-builder/rootfs"
$ sudo rm -rf ${ROOTFS_DIR}
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/tools/osbuilder/rootfs-builder
$ script -fec 'sudo -E GOPATH=$GOPATH AGENT_INIT=yes USE_DOCKER=true ./rootfs.sh ${distro}'
```
`AGENT_INIT` controls if the guest image uses the Kata agent as the guest `init` process. When you create an initrd image,
always set `AGENT_INIT` to `yes`.
@@ -323,14 +335,14 @@ always set `AGENT_INIT` to `yes`.
You MUST choose a distribution (e.g., `ubuntu`) for `${distro}`.
You can get a supported distributions list in the Kata Containers by running the following.
```bash
$ ./kata-containers/tools/osbuilder/rootfs-builder/rootfs.sh -l
```
$ ./rootfs.sh -l
```
If you want to build the agent without seccomp capability, you need to run the `rootfs.sh` script with `SECCOMP=no` as follows.
```bash
$ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true SECCOMP=no ./rootfs.sh "${distro}"'
```
$ script -fec 'sudo -E GOPATH=$GOPATH AGENT_INIT=yes USE_DOCKER=true SECCOMP=no ./rootfs.sh ${distro}'
```
> **Note:**
@@ -339,31 +351,28 @@ $ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true SECCOMP=no ./rootfs.sh "${
Optionally, add your custom agent binary to the rootfs with the following commands. The default `$LIBC` used
is `musl`, but on ppc64le and s390x, `gnu` should be used. Also, Rust refers to ppc64le as `powerpc64le`:
```bash
$ export ARCH="$(uname -m)"
$ [ "${ARCH}" == "ppc64le" ] || [ "${ARCH}" == "s390x" ] && export LIBC=gnu || export LIBC=musl
$ [ "${ARCH}" == "ppc64le" ] && export ARCH=powerpc64le
$ sudo install -o root -g root -m 0550 -T "${ROOTFS_DIR}/../../../../src/agent/target/${ARCH}-unknown-linux-${LIBC}/release/kata-agent" "${ROOTFS_DIR}/sbin/init"
```
$ export ARCH=$(uname -m)
$ [ ${ARCH} == "ppc64le" ] || [ ${ARCH} == "s390x" ] && export LIBC=gnu || export LIBC=musl
$ [ ${ARCH} == "ppc64le" ] && export ARCH=powerpc64le
$ sudo install -o root -g root -m 0550 -T ../../../src/agent/target/${ARCH}-unknown-linux-${LIBC}/release/kata-agent ${ROOTFS_DIR}/sbin/init
```
### Build an initrd image
```bash
$ pushd kata-containers/tools/osbuilder/initrd-builder
$ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true ./initrd_builder.sh "${ROOTFS_DIR}"'
$ popd
```
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/tools/osbuilder/initrd-builder
$ script -fec 'sudo -E AGENT_INIT=yes USE_DOCKER=true ./initrd_builder.sh ${ROOTFS_DIR}'
```
### Install the initrd image
```bash
$ pushd kata-containers/tools/osbuilder/initrd-builder
$ commit="$(git log --format=%h -1 HEAD)"
$ date="$(date +%Y-%m-%d-%T.%N%z)"
```
$ commit=$(git log --format=%h -1 HEAD)
$ date=$(date +%Y-%m-%d-%T.%N%z)
$ image="kata-containers-initrd-${date}-${commit}"
$ sudo install -o root -g root -m 0640 -D kata-containers-initrd.img "/usr/share/kata-containers/${image}"
$ (cd /usr/share/kata-containers && sudo ln -sf "$image" kata-containers-initrd.img)
$ popd
```
# Install guest kernel images
@@ -382,43 +391,43 @@ Kata Containers makes use of upstream QEMU branch. The exact version
and repository utilized can be found by looking at the [versions file](../versions.yaml).
Find the correct version of QEMU from the versions file:
```bash
$ source kata-containers/tools/packaging/scripts/lib.sh
$ qemu_version="$(get_from_kata_deps "assets.hypervisor.qemu.version")"
$ echo "${qemu_version}"
```
$ source ${GOPATH}/src/github.com/kata-containers/kata-containers/tools/packaging/scripts/lib.sh
$ qemu_version=$(get_from_kata_deps "assets.hypervisor.qemu.version")
$ echo ${qemu_version}
```
Get source from the matching branch of QEMU:
```bash
$ git clone -b "${qemu_version}" https://github.com/qemu/qemu.git
$ your_qemu_directory="$(realpath qemu)"
```
$ go get -d github.com/qemu/qemu
$ cd ${GOPATH}/src/github.com/qemu/qemu
$ git checkout ${qemu_version}
$ your_qemu_directory=${GOPATH}/src/github.com/qemu/qemu
```
There are scripts to manage the build and packaging of QEMU. For the examples below, set your
environment as:
```bash
$ packaging_dir="$(realpath kata-containers/tools/packaging)"
```
$ go get -d github.com/kata-containers/kata-containers
$ packaging_dir="${GOPATH}/src/github.com/kata-containers/kata-containers/tools/packaging"
```
Kata often utilizes patches for not-yet-upstream and/or backported fixes for components,
including QEMU. These can be found in the [packaging/QEMU directory](../tools/packaging/qemu/patches),
and it's *recommended* that you apply them. For example, suppose that you are going to build QEMU
version 5.2.0, do:
```bash
$ "$packaging_dir/scripts/apply_patches.sh" "$packaging_dir/qemu/patches/5.2.x/"
```
$ cd $your_qemu_directory
$ $packaging_dir/scripts/apply_patches.sh $packaging_dir/qemu/patches/5.2.x/
```
To build utilizing the same options as Kata, you should make use of the `configure-hypervisor.sh` script. For example:
```bash
$ pushd "$your_qemu_directory"
$ "$packaging_dir/scripts/configure-hypervisor.sh" kata-qemu > kata.cfg
$ eval ./configure "$(cat kata.cfg)"
$ make -j $(nproc --ignore=1)
# Optional
$ sudo -E make install
$ popd
```
If you do not want to install the respective QEMU version, the configuration file can be modified to point to the correct binary. In `/etc/kata-containers/configuration.toml`, change `path = "/path/to/qemu/build/qemu-system-x86_64"` to point to the correct QEMU binary.
$ cd $your_qemu_directory
$ $packaging_dir/scripts/configure-hypervisor.sh kata-qemu > kata.cfg
$ eval ./configure "$(cat kata.cfg)"
$ make -j $(nproc)
$ sudo -E make install
```
See the [static-build script for QEMU](../tools/packaging/static-build/qemu/build-static-qemu.sh) for a reference on how to get, setup, configure and build QEMU for Kata.
@@ -430,33 +439,11 @@ See the [static-build script for QEMU](../tools/packaging/static-build/qemu/buil
> under upstream review for supporting NVDIMM on aarch64.
>
You could build the custom `qemu-system-aarch64` as required with the following command:
```bash
$ git clone https://github.com/kata-containers/tests.git
$ script -fec 'sudo -E tests/.ci/install_qemu.sh'
```
## Build `virtiofsd`
When using the file system type virtio-fs (default), `virtiofsd` is required
```bash
$ pushd kata-containers/tools/packaging/static-build/virtiofsd
$ ./build-static-virtiofsd.sh
$ popd
$ go get -d github.com/kata-containers/tests
$ script -fec 'sudo -E ${GOPATH}/src/github.com/kata-containers/tests/.ci/install_qemu.sh'
```
Modify `/etc/kata-containers/configuration.toml` and update value `virtio_fs_daemon = "/path/to/kata-containers/tools/packaging/static-build/virtiofsd/virtiofsd/virtiofsd"` to point to the binary.
# Check hardware requirements
You can check if your system is capable of creating a Kata Container by running the following:
```bash
$ sudo kata-runtime check
```
If your system is *not* able to run Kata Containers, the previous command will error out and explain why.
# Run Kata Containers with Containerd
Refer to the [How to use Kata Containers and Containerd](how-to/containerd-kata.md) how-to guide.
@@ -487,7 +474,7 @@ See [Set up a debug console](#set-up-a-debug-console).
## Checking Docker default runtime
```bash
```
$ sudo docker info 2>/dev/null | grep -i "default runtime" | cut -d: -f2- | grep -q runc && echo "SUCCESS" || echo "ERROR: Incorrect default Docker runtime"
```
## Set up a debug console
@@ -504,7 +491,7 @@ contain either `/bin/sh` or `/bin/bash`.
Enable debug_console_enabled in the `configuration.toml` configuration file:
```toml
```
[agent.kata]
debug_console_enabled = true
```
@@ -515,7 +502,7 @@ This will pass `agent.debug_console agent.debug_console_vport=1026` to agent as
For Kata Containers `2.0.x` releases, the `kata-runtime exec` command depends on the`kata-monitor` running, in order to get the sandbox's `vsock` address to connect to. Thus, first start the `kata-monitor` process.
```bash
```
$ sudo kata-monitor
```
@@ -535,7 +522,7 @@ bash-4.2# exit
exit
```
`kata-runtime exec` has a command-line option `runtime-namespace`, which is used to specify under which [runtime namespace](https://github.com/containerd/containerd/blob/main/docs/namespaces.md) the particular pod was created. By default, it is set to `k8s.io` and works for containerd when configured
`kata-runtime exec` has a command-line option `runtime-namespace`, which is used to specify under which [runtime namespace](https://github.com/containerd/containerd/blob/master/docs/namespaces.md) the particular pod was created. By default, it is set to `k8s.io` and works for containerd when configured
with Kubernetes. For CRI-O, the namespace should set to `default` explicitly. This should not be confused with [Kubernetes namespaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/).
For other CRI-runtimes and configurations, you may need to set the namespace utilizing the `runtime-namespace` option.
@@ -577,10 +564,10 @@ an additional `coreutils` package.
For example using CentOS:
```bash
$ pushd kata-containers/tools/osbuilder/rootfs-builder
$ export ROOTFS_DIR="$(realpath ./rootfs)"
$ script -fec 'sudo -E USE_DOCKER=true EXTRA_PKGS="bash coreutils" ./rootfs.sh centos'
```
$ cd $GOPATH/src/github.com/kata-containers/kata-containers/tools/osbuilder/rootfs-builder
$ export ROOTFS_DIR=${GOPATH}/src/github.com/kata-containers/kata-containers/tools/osbuilder/rootfs-builder/rootfs
$ script -fec 'sudo -E GOPATH=$GOPATH USE_DOCKER=true EXTRA_PKGS="bash coreutils" ./rootfs.sh centos'
```
#### Build the debug image
@@ -595,10 +582,9 @@ Install the image:
>**Note**: When using an initrd image, replace the below rootfs image name `kata-containers.img`
>with the initrd image name `kata-containers-initrd.img`.
```bash
```
$ name="kata-containers-centos-with-debug-console.img"
$ sudo install -o root -g root -m 0640 kata-containers.img "/usr/share/kata-containers/${name}"
$ popd
```
Next, modify the `image=` values in the `[hypervisor.qemu]` section of the
@@ -607,7 +593,7 @@ to specify the full path to the image name specified in the previous code
section. Alternatively, recreate the symbolic link so it points to
the new debug image:
```bash
```
$ (cd /usr/share/kata-containers && sudo ln -sf "$name" kata-containers.img)
```
@@ -618,7 +604,7 @@ to avoid all subsequently created containers from using the debug image.
Create a container as normal. For example using `crictl`:
```bash
```
$ sudo crictl run -r kata container.yaml pod.yaml
```
@@ -631,7 +617,7 @@ those for firecracker / cloud-hypervisor.
Add `agent.debug_console` to the guest kernel command line to allow the agent process to start a debug console.
```bash
```
$ sudo sed -i -e 's/^kernel_params = "\(.*\)"/kernel_params = "\1 agent.debug_console"/g' "${kata_configuration_file}"
```
@@ -652,7 +638,7 @@ between the host and the guest. The kernel command line option `agent.debug_cons
Add the parameter `agent.debug_console_vport=1026` to the kernel command line
as shown below:
```bash
```
sudo sed -i -e 's/^kernel_params = "\(.*\)"/kernel_params = "\1 agent.debug_console_vport=1026"/g' "${kata_configuration_file}"
```
@@ -665,7 +651,7 @@ Next, connect to the debug console. The VSOCKS paths vary slightly between each
VMM solution.
In case of cloud-hypervisor, connect to the `vsock` as shown:
```bash
```
$ sudo su -c 'cd /var/run/vc/vm/${sandbox_id}/root/ && socat stdin unix-connect:clh.sock'
CONNECT 1026
```
@@ -673,7 +659,7 @@ CONNECT 1026
**Note**: You need to type `CONNECT 1026` and press `RETURN` key after entering the `socat` command.
For firecracker, connect to the `hvsock` as shown:
```bash
```
$ sudo su -c 'cd /var/run/vc/firecracker/${sandbox_id}/root/ && socat stdin unix-connect:kata.hvsock'
CONNECT 1026
```
@@ -682,7 +668,7 @@ CONNECT 1026
For QEMU, connect to the `vsock` as shown:
```bash
```
$ sudo su -c 'cd /var/run/vc/vm/${sandbox_id} && socat "stdin,raw,echo=0,escape=0x11" "unix-connect:console.sock"'
```
@@ -695,7 +681,7 @@ If the image is created using
[osbuilder](../tools/osbuilder), the following YAML
file exists and contains details of the image and how it was created:
```bash
```
$ cat /var/lib/osbuilder/osbuilder.yaml
```

View File

@@ -60,26 +60,17 @@ This section lists items that might be possible to fix.
## OCI CLI commands
### Docker and Podman support
Currently Kata Containers does not support Podman.
Currently Kata Containers does not support Docker or Podman.
See issue https://github.com/kata-containers/kata-containers/issues/722 for more information.
Docker supports Kata Containers since 22.06:
```bash
$ sudo docker run --runtime io.containerd.kata.v2
```
Kata Containers works perfectly with containerd, we recommend to use
containerd's Docker-style command line tool [`nerdctl`](https://github.com/containerd/nerdctl).
## Runtime commands
### checkpoint and restore
The runtime does not provide `checkpoint` and `restore` commands. There
are discussions about using VM save and restore to give us a
[`criu`](https://github.com/checkpoint-restore/criu)-like functionality,
`[criu](https://github.com/checkpoint-restore/criu)`-like functionality,
which might provide a solution.
Note that the OCI standard does not specify `checkpoint` and `restore`
@@ -102,42 +93,6 @@ All other configurations are supported and are working properly.
## Networking
### Host network
Host network (`nerdctl/docker run --net=host`or [Kubernetes `HostNetwork`](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#hosts-namespaces)) is not supported.
It is not possible to directly access the host networking configuration
from within the VM.
The `--net=host` option can still be used with `runc` containers and
inter-mixed with running Kata Containers, thus enabling use of `--net=host`
when necessary.
It should be noted, currently passing the `--net=host` option into a
Kata Container may result in the Kata Container networking setup
modifying, re-configuring and therefore possibly breaking the host
networking setup. Do not use `--net=host` with Kata Containers.
### Support for joining an existing VM network
Docker supports the ability for containers to join another containers
namespace with the `docker run --net=containers` syntax. This allows
multiple containers to share a common network namespace and the network
interfaces placed in the network namespace. Kata Containers does not
support network namespace sharing. If a Kata Container is setup to
share the network namespace of a `runc` container, the runtime
effectively takes over all the network interfaces assigned to the
namespace and binds them to the VM. Consequently, the `runc` container loses
its network connectivity.
### docker run --link
The runtime does not support the `docker run --link` command. This
command is now deprecated by docker and we have no intention of adding support.
Equivalent functionality can be achieved with the newer docker networking commands.
See more documentation at
[docs.docker.com](https://docs.docker.com/network/links/).
## Resource management
Due to the way VMs differ in their CPU and memory allocation, and sharing

View File

@@ -341,7 +341,7 @@ The main repository has the most comprehensive set of skip abilities. See:
One method is to use the `nix` crate along with some custom macros:
```rust
```
#[cfg(test)]
mod tests {
#[allow(unused_macros)]

View File

@@ -1,169 +0,0 @@
# Kata 3.0 Architecture
## Overview
In cloud-native scenarios, there is an increased demand for container startup speed, resource consumption, stability, and security, areas where the present Kata Containers runtime is challenged relative to other runtimes. To achieve this, we propose a solid, field-tested and secure Rust version of the kata-runtime.
Also, we provide the following designs:
- Turn key solution with builtin `Dragonball` Sandbox
- Async I/O to reduce resource consumption
- Extensible framework for multiple services, runtimes and hypervisors
- Lifecycle management for sandbox and container associated resources
### Rationale for choosing Rust
We chose Rust because it is designed as a system language with a focus on efficiency.
In contrast to Go, Rust makes a variety of design trade-offs in order to obtain
good execution performance, with innovative techniques that, in contrast to C or
C++, provide reasonable protection against common memory errors (buffer
overflow, invalid pointers, range errors), error checking (ensuring errors are
dealt with), thread safety, ownership of resources, and more.
These benefits were verified in our project when the Kata Containers guest agent
was rewritten in Rust. We notably saw a significant reduction in memory usage
with the Rust-based implementation.
## Design
### Architecture
![architecture](./images/architecture.png)
### Built-in VMM
#### Current Kata 2.x architecture
![not_builtin_vmm](./images/not_built_in_vmm.png)
As shown in the figure, runtime and VMM are separate processes. The runtime process forks the VMM process and interacts through the inter-process RPC. Typically, process interaction consumes more resources than peers within the process, and it will result in relatively low efficiency. At the same time, the cost of resource operation and maintenance should be considered. For example, when performing resource recovery under abnormal conditions, the exception of any process must be detected by others and activate the appropriate resource recovery process. If there are additional processes, the recovery becomes even more difficult.
#### How To Support Built-in VMM
We provide `Dragonball` Sandbox to enable built-in VMM by integrating VMM's function into the Rust library. We could perform VMM-related functionalities by using the library. Because runtime and VMM are in the same process, there is a benefit in terms of message processing speed and API synchronization. It can also guarantee the consistency of the runtime and the VMM life cycle, reducing resource recovery and exception handling maintenance, as shown in the figure:
![builtin_vmm](./images/built_in_vmm.png)
### Async Support
#### Why Need Async
**Async is already in stable Rust and allows us to write async code**
- Async provides significantly reduced CPU and memory overhead, especially for workloads with a large amount of IO-bound tasks
- Async is zero-cost in Rust, which means that you only pay for what you use. Specifically, you can use async without heap allocations and dynamic dispatch, which greatly improves efficiency
- For more (see [Why Async?](https://rust-lang.github.io/async-book/01_getting_started/02_why_async.html) and [The State of Asynchronous Rust](https://rust-lang.github.io/async-book/01_getting_started/03_state_of_async_rust.html)).
**There may be several problems if implementing kata-runtime with Sync Rust**
- Too many threads with a new TTRPC connection
- TTRPC threads: reaper thread(1) + listener thread(1) + client handler(2)
- Add 3 I/O threads with a new container
- In Sync mode, implementing a timeout mechanism is challenging. For example, in TTRPC API interaction, the timeout mechanism is difficult to align with Golang
#### How To Support Async
The kata-runtime is controlled by TOKIO_RUNTIME_WORKER_THREADS to run the OS thread, which is 2 threads by default. For TTRPC and container-related threads run in the `tokio` thread in a unified manner, and related dependencies need to be switched to Async, such as Timer, File, Netlink, etc. With the help of Async, we can easily support no-block I/O and timer. Currently, we only utilize Async for kata-runtime. The built-in VMM keeps the OS thread because it can ensure that the threads are controllable.
**For N tokio worker threads and M containers**
- Sync runtime(both OS thread and `tokio` task are OS thread but without `tokio` worker thread) OS thread number: 4 + 12*M
- Async runtime(only OS thread is OS thread) OS thread number: 2 + N
```shell
├─ main(OS thread)
├─ async-logger(OS thread)
└─ tokio worker(N * OS thread)
├─ agent log forwarder(1 * tokio task)
├─ health check thread(1 * tokio task)
├─ TTRPC reaper thread(M * tokio task)
├─ TTRPC listener thread(M * tokio task)
├─ TTRPC client handler thread(7 * M * tokio task)
├─ container stdin io thread(M * tokio task)
├─ container stdout io thread(M * tokio task)
└─ container stderr io thread(M * tokio task)
```
### Extensible Framework
The Kata 3.x runtime is designed with the extension of service, runtime, and hypervisor, combined with configuration to meet the needs of different scenarios. At present, the service provides a register mechanism to support multiple services. Services could interact with runtime through messages. In addition, the runtime handler handles messages from services. To meet the needs of a binary that supports multiple runtimes and hypervisors, the startup must obtain the runtime handler type and hypervisor type through configuration.
![framework](./images/framework.png)
### Resource Manager
In our case, there will be a variety of resources, and every resource has several subtypes. Especially for `Virt-Container`, every subtype of resource has different operations. And there may be dependencies, such as the share-fs rootfs and the share-fs volume will use share-fs resources to share files to the VM. Currently, network and share-fs are regarded as sandbox resources, while rootfs, volume, and cgroup are regarded as container resources. Also, we abstract a common interface for each resource and use subclass operations to evaluate the differences between different subtypes.
![resource manager](./images/resourceManager.png)
## Roadmap
- Stage 1 (June): provide basic features (current delivered)
- Stage 2 (September): support common features
- Stage 3: support full features
| **Class** | **Sub-Class** | **Development Stage** | **Status** |
| -------------------------- | ------------------- | --------------------- |------------|
| Service | task service | Stage 1 | ✅ |
| | extend service | Stage 3 | 🚫 |
| | image service | Stage 3 | 🚫 |
| Runtime handler | `Virt-Container` | Stage 1 | ✅ |
| Endpoint | VETH Endpoint | Stage 1 | ✅ |
| | Physical Endpoint | Stage 2 | ✅ |
| | Tap Endpoint | Stage 2 | ✅ |
| | `Tuntap` Endpoint | Stage 2 | ✅ |
| | `IPVlan` Endpoint | Stage 2 | ✅ |
| | `MacVlan` Endpoint | Stage 2 | ✅ |
| | MACVTAP Endpoint | Stage 3 | 🚫 |
| | `VhostUserEndpoint` | Stage 3 | 🚫 |
| Network Interworking Model | Tc filter | Stage 1 | ✅ |
| | `MacVtap` | Stage 3 | 🚧 |
| Storage | Virtio-fs | Stage 1 | ✅ |
| | `nydus` | Stage 2 | 🚧 |
| | `device mapper` | Stage 2 | 🚫 |
| `Cgroup V2` | | Stage 2 | 🚧 |
| Hypervisor | `Dragonball` | Stage 1 | 🚧 |
| | QEMU | Stage 2 | 🚫 |
| | ACRN | Stage 3 | 🚫 |
| | Cloud Hypervisor | Stage 3 | 🚫 |
| | Firecracker | Stage 3 | 🚫 |
## FAQ
- Are the "service", "message dispatcher" and "runtime handler" all part of the single Kata 3.x runtime binary?
Yes. They are components in Kata 3.x runtime. And they will be packed into one binary.
1. Service is an interface, which is responsible for handling multiple services like task service, image service and etc.
2. Message dispatcher, it is used to match multiple requests from the service module.
3. Runtime handler is used to deal with the operation for sandbox and container.
- What is the name of the Kata 3.x runtime binary?
Apparently we can't use `containerd-shim-v2-kata` because it's already used. We are facing the hardest issue of "naming" again. Any suggestions are welcomed.
Internally we use `containerd-shim-v2-rund`.
- Is the Kata 3.x design compatible with the containerd shimv2 architecture?
Yes. It is designed to follow the functionality of go version kata. And it implements the `containerd shim v2` interface/protocol.
- How will users migrate to the Kata 3.x architecture?
The migration plan will be provided before the Kata 3.x is merging into the main branch.
- Is `Dragonball` limited to its own built-in VMM? Can the `Dragonball` system be configured to work using an external `Dragonball` VMM/hypervisor?
The `Dragonball` could work as an external hypervisor. However, stability and performance is challenging in this case. Built in VMM could optimise the container overhead, and it's easy to maintain stability.
`runD` is the `containerd-shim-v2` counterpart of `runC` and can run a pod/containers. `Dragonball` is a `microvm`/VMM that is designed to run container workloads. Instead of `microvm`/VMM, we sometimes refer to it as secure sandbox.
- QEMU, Cloud Hypervisor and Firecracker support are planned, but how that would work. Are they working in separate process?
Yes. They are unable to work as built in VMM.
- What is `upcall`?
The `upcall` is used to hotplug CPU/memory/MMIO devices, and it solves two issues.
1. avoid dependency on PCI/ACPI
2. avoid dependency on `udevd` within guest and get deterministic results for hotplug operations. So `upcall` is an alternative to ACPI based CPU/memory/device hotplug. And we may cooperate with the community to add support for ACPI based CPU/memory/device hotplug if needed.
`Dbs-upcall` is a `vsock-based` direct communication tool between VMM and guests. The server side of the `upcall` is a driver in guest kernel (kernel patches are needed for this feature) and it'll start to serve the requests once the kernel has started. And the client side is in VMM , it'll be a thread that communicates with VSOCK through `uds`. We have accomplished device hotplug / hot-unplug directly through `upcall` in order to avoid virtualization of ACPI to minimize virtual machine's overhead. And there could be many other usage through this direct communication channel. It's already open source.
https://github.com/openanolis/dragonball-sandbox/tree/main/crates/dbs-upcall
- The URL below says the kernel patches work with 4.19, but do they also work with 5.15+ ?
Forward compatibility should be achievable, we have ported it to 5.10 based kernel.
- Are these patches platform-specific or would they work for any architecture that supports VSOCK?
It's almost platform independent, but some message related to CPU hotplug are platform dependent.
- Could the kernel driver be replaced with a userland daemon in the guest using loopback VSOCK?
We need to create device nodes for hot-added CPU/memory/devices, so it's not easy for userspace daemon to do these tasks.
- The fact that `upcall` allows communication between the VMM and the guest suggests that this architecture might be incompatible with https://github.com/confidential-containers where the VMM should have no knowledge of what happens inside the VM.
1. `TDX` doesn't support CPU/memory hotplug yet.
2. For ACPI based device hotplug, it depends on ACPI `DSDT` table, and the guest kernel will execute `ASL` code to handle during handling those hotplug event. And it should be easier to audit VSOCK based communication than ACPI `ASL` methods.
- What is the security boundary for the monolithic / "Built-in VMM" case?
It has the security boundary of virtualization. More details will be provided in next stage.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

File diff suppressed because one or more lines are too long

View File

@@ -12,7 +12,7 @@ The OCI [runtime specification][linux-config] provides guidance on where the con
> [`cgroupsPath`][cgroupspath]: (string, OPTIONAL) path to the cgroups. It can be used to either control the cgroups
> hierarchy for containers or to run a new process in an existing container
The cgroups are hierarchical, and this can be seen with the following pod example:
Cgroups are hierarchical, and this can be seen with the following pod example:
- Pod 1: `cgroupsPath=/kubepods/pod1`
- Container 1: `cgroupsPath=/kubepods/pod1/container1`
@@ -247,14 +247,14 @@ cgroup size and constraints accordingly.
# Supported cgroups
Kata Containers currently supports cgroups `v1` and `v2`.
Kata Containers currently only supports cgroups `v1`.
In the following sections each cgroup is described briefly.
## cgroups v1
## Cgroups V1
`cgroups v1` are under a [`tmpfs`][1] filesystem mounted at `/sys/fs/cgroup`, where each cgroup is
mounted under a separate cgroup filesystem. A `cgroups v1` hierarchy may look like the following
`Cgroups V1` are under a [`tmpfs`][1] filesystem mounted at `/sys/fs/cgroup`, where each cgroup is
mounted under a separate cgroup filesystem. A `Cgroups v1` hierarchy may look like the following
diagram:
```
@@ -301,12 +301,13 @@ diagram:
A process can join a cgroup by writing its process id (`pid`) to `cgroup.procs` file,
or join a cgroup partially by writing the task (thread) id (`tid`) to the `tasks` file.
Kata Containers only supports `v1`.
To know more about `cgroups v1`, see [cgroupsv1(7)][2].
## cgroups v2
## Cgroups V2
`cgroups v2` are also known as unified cgroups, unlike `cgroups v1`, the cgroups are
mounted under the same cgroup filesystem. A `cgroups v2` hierarchy may look like the following
`Cgroups v2` are also known as unified cgroups, unlike `cgroups v1`, the cgroups are
mounted under the same cgroup filesystem. A `Cgroups v2` hierarchy may look like the following
diagram:
```
@@ -353,6 +354,8 @@ Same as `cgroups v1`, a process can join the cgroup by writing its process id (`
`cgroup.procs` file, or join a cgroup partially by writing the task (thread) id (`tid`) to
`cgroup.threads` file.
Kata Containers does not support cgroups `v2` on the host.
### Distro Support
Many Linux distributions do not yet support `cgroups v2`, as it is quite a recent addition.

View File

@@ -110,7 +110,7 @@ Devices and features used:
- VFIO
- hotplug
- seccomp filters
- [HTTP OpenAPI](https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/vmm/src/api/openapi/cloud-hypervisor.yaml)
- [HTTP OpenAPI](https://github.com/cloud-hypervisor/cloud-hypervisor/blob/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
### Summary

View File

@@ -5,7 +5,7 @@
- [Run Kata containers with `crictl`](run-kata-with-crictl.md)
- [Run Kata Containers with Kubernetes](run-kata-with-k8s.md)
- [How to use Kata Containers and Containerd](containerd-kata.md)
- [How to use Kata Containers and containerd with Kubernetes](how-to-use-k8s-with-containerd-and-kata.md)
- [How to use Kata Containers and CRI (containerd) with Kubernetes](how-to-use-k8s-with-cri-containerd-and-kata.md)
- [Kata Containers and service mesh for Kubernetes](service-mesh.md)
- [How to import Kata Containers logs into Fluentd](how-to-import-kata-logs-with-fluentd.md)
@@ -42,9 +42,4 @@
- [How to setup swap devices in guest kernel](how-to-setup-swap-devices-in-guest-kernel.md)
- [How to run rootless vmm](how-to-run-rootless-vmm.md)
- [How to run Docker with Kata Containers](how-to-run-docker-with-kata.md)
- [How to run Kata Containers with `nydus`](how-to-use-virtio-fs-nydus-with-kata.md)
- [How to run Kata Containers with AMD SEV-SNP](how-to-run-kata-containers-with-SNP-VMs.md)
## Confidential Containers
- [How to use build and test the Confidential Containers `CCv0` proof of concept](how-to-build-and-test-ccv0.md)
- [How to generate a Kata Containers payload for the Confidential Containers Operator](how-to-generate-a-kata-containers-payload-for-the-confidential-containers-operator.md)
- [How to run Kata Containers with `nydus`](how-to-use-virtio-fs-nydus-with-kata.md)

View File

@@ -1,640 +0,0 @@
#!/bin/bash -e
#
# Copyright (c) 2021, 2022 IBM Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
# Disclaimer: This script is work in progress for supporting the CCv0 prototype
# It shouldn't be considered supported by the Kata Containers community, or anyone else
# Based on https://github.com/kata-containers/kata-containers/blob/main/docs/Developer-Guide.md,
# but with elements of the tests/.ci scripts used
readonly script_name="$(basename "${BASH_SOURCE[0]}")"
# By default in Golang >= 1.16 GO111MODULE is set to "on", but not all modules support it, so overwrite to "auto"
export GO111MODULE="auto"
# Setup kata containers environments if not set - we default to use containerd
export CRI_CONTAINERD=${CRI_CONTAINERD:-"yes"}
export CRI_RUNTIME=${CRI_RUNTIME:-"containerd"}
export CRIO=${CRIO:-"no"}
export KATA_HYPERVISOR="${KATA_HYPERVISOR:-qemu}"
export KUBERNETES=${KUBERNETES:-"no"}
export AGENT_INIT="${AGENT_INIT:-${TEST_INITRD:-no}}"
export AA_KBC="${AA_KBC:-offline_fs_kbc}"
# Allow the user to overwrite the default repo and branch names if they want to build from a fork
export katacontainers_repo="${katacontainers_repo:-github.com/kata-containers/kata-containers}"
export katacontainers_branch="${katacontainers_branch:-CCv0}"
export kata_default_branch=${katacontainers_branch}
export tests_repo="${tests_repo:-github.com/kata-containers/tests}"
export tests_branch="${tests_branch:-CCv0}"
export target_branch=${tests_branch} # kata-containers/ci/lib.sh uses target branch var to check out tests repo
# if .bash_profile exists then use it, otherwise fall back to .profile
export PROFILE="${HOME}/.profile"
if [ -r "${HOME}/.bash_profile" ]; then
export PROFILE="${HOME}/.bash_profile"
fi
# Stop PS1: unbound variable error happening
export PS1=${PS1:-}
# Create a bunch of common, derived values up front so we don't need to create them in all the different functions
. ${PROFILE}
if [ -z ${GOPATH} ]; then
export GOPATH=${HOME}/go
fi
export tests_repo_dir="${GOPATH}/src/${tests_repo}"
export katacontainers_repo_dir="${GOPATH}/src/${katacontainers_repo}"
export ROOTFS_DIR="${katacontainers_repo_dir}/tools/osbuilder/rootfs-builder/rootfs"
export PULL_IMAGE="${PULL_IMAGE:-quay.io/kata-containers/confidential-containers:signed}" # Doesn't need authentication
export CONTAINER_ID="${CONTAINER_ID:-0123456789}"
source /etc/os-release || source /usr/lib/os-release
grep -Eq "\<fedora\>" /etc/os-release 2> /dev/null && export USE_PODMAN=true
# If we've already checked out the test repo then source the confidential scripts
if [ "${KUBERNETES}" == "yes" ]; then
export BATS_TEST_DIRNAME="${tests_repo_dir}/integration/kubernetes/confidential"
[ -d "${BATS_TEST_DIRNAME}" ] && source "${BATS_TEST_DIRNAME}/lib.sh"
else
export BATS_TEST_DIRNAME="${tests_repo_dir}/integration/containerd/confidential"
[ -d "${BATS_TEST_DIRNAME}" ] && source "${BATS_TEST_DIRNAME}/lib.sh"
fi
[ -d "${BATS_TEST_DIRNAME}" ] && source "${BATS_TEST_DIRNAME}/../../confidential/lib.sh"
export RUNTIME_CONFIG_PATH=/etc/kata-containers/configuration.toml
usage() {
exit_code="$1"
cat <<EOF
Overview:
Build and test kata containers from source
Optionally set kata-containers and tests repo and branch as exported variables before running
e.g. export katacontainers_repo=github.com/stevenhorsman/kata-containers && export katacontainers_branch=kata-ci-from-fork && export tests_repo=github.com/stevenhorsman/tests && export tests_branch=kata-ci-from-fork && ~/${script_name} build_and_install_all
Usage:
${script_name} [options] <command>
Commands:
- agent_create_container: Run CreateContainer command against the agent with agent-ctl
- agent_pull_image: Run PullImage command against the agent with agent-ctl
- all: Build and install everything, test kata with containerd and capture the logs
- build_and_add_agent_to_rootfs: Builds the kata-agent and adds it to the rootfs
- build_and_install_all: Build and install everything
- build_and_install_rootfs: Builds and installs the rootfs image
- build_kata_runtime: Build and install the kata runtime
- build_cloud_hypervisor Checkout, patch, build and install Cloud Hypervisor
- build_qemu: Checkout, patch, build and install QEMU
- configure: Configure Kata to use rootfs and enable debug
- connect_to_ssh_demo_pod: Ssh into the ssh demo pod, showing that the decryption succeeded
- copy_signature_files_to_guest Copies signature verification files to guest
- create_rootfs: Create a local rootfs
- crictl_create_cc_container Use crictl to create a new busybox container in the kata cc pod
- crictl_create_cc_pod Use crictl to create a new kata cc pod
- crictl_delete_cc Use crictl to delete the kata cc pod sandbox and container in it
- help: Display this help
- init_kubernetes: initialize a Kubernetes cluster on this system
- initialize: Install dependencies and check out kata-containers source
- install_guest_kernel: Setup, build and install the guest kernel
- kubernetes_create_cc_pod: Create a Kata CC runtime busybox-based pod in Kubernetes
- kubernetes_create_ssh_demo_pod: Create a Kata CC runtime pod based on the ssh demo
- kubernetes_delete_cc_pod: Delete the Kata CC runtime busybox-based pod in Kubernetes
- kubernetes_delete_ssh_demo_pod: Delete the Kata CC runtime pod based on the ssh demo
- open_kata_shell: Open a shell into the kata runtime
- rebuild_and_install_kata: Rebuild the kata runtime and agent and build and install the image
- shim_pull_image: Run PullImage command against the shim with ctr
- test_capture_logs: Test using kata with containerd and capture the logs in the user's home directory
- test: Test using kata with containerd
Options:
-d: Enable debug
-h: Display this help
EOF
# if script sourced don't exit as this will exit the main shell, just return instead
[[ $_ != $0 ]] && return "$exit_code" || exit "$exit_code"
}
build_and_install_all() {
initialize
build_and_install_kata_runtime
configure
create_a_local_rootfs
build_and_install_rootfs
install_guest_kernel_image
case "$KATA_HYPERVISOR" in
"qemu")
build_qemu
;;
"cloud-hypervisor")
build_cloud_hypervisor
;;
*)
echo "Invalid option: $KATA_HYPERVISOR is not supported." >&2
;;
esac
check_kata_runtime
if [ "${KUBERNETES}" == "yes" ]; then
init_kubernetes
fi
}
rebuild_and_install_kata() {
checkout_tests_repo
checkout_kata_containers_repo
build_and_install_kata_runtime
build_and_add_agent_to_rootfs
build_and_install_rootfs
check_kata_runtime
}
# Based on the jenkins_job_build.sh script in kata-containers/tests/.ci - checks out source code and installs dependencies
initialize() {
# We need git to checkout and bootstrap the ci scripts and some other packages used in testing
sudo apt-get update && sudo apt-get install -y curl git qemu-utils
grep -qxF "export GOPATH=\${HOME}/go" "${PROFILE}" || echo "export GOPATH=\${HOME}/go" >> "${PROFILE}"
grep -qxF "export GOROOT=/usr/local/go" "${PROFILE}" || echo "export GOROOT=/usr/local/go" >> "${PROFILE}"
grep -qxF "export PATH=\${GOPATH}/bin:/usr/local/go/bin:\${PATH}" "${PROFILE}" || echo "export PATH=\${GOPATH}/bin:/usr/local/go/bin:\${PATH}" >> "${PROFILE}"
# Load the new go and PATH parameters from the profile
. ${PROFILE}
mkdir -p "${GOPATH}"
checkout_tests_repo
pushd "${tests_repo_dir}"
local ci_dir_name=".ci"
sudo -E PATH=$PATH -s "${ci_dir_name}/install_go.sh" -p -f
sudo -E PATH=$PATH -s "${ci_dir_name}/install_rust.sh"
# Need to change ownership of rustup so later process can create temp files there
sudo chown -R ${USER}:${USER} "${HOME}/.rustup"
checkout_kata_containers_repo
# Run setup, but don't install kata as we will build it ourselves in locations matching the developer guide
export INSTALL_KATA="no"
sudo -E PATH=$PATH -s ${ci_dir_name}/setup.sh
# Reload the profile to pick up installed dependencies
. ${PROFILE}
popd
}
checkout_tests_repo() {
echo "Creating repo: ${tests_repo} and branch ${tests_branch} into ${tests_repo_dir}..."
# Due to git https://github.blog/2022-04-12-git-security-vulnerability-announced/ the tests repo needs
# to be owned by root as it is re-checked out in rootfs.sh
mkdir -p $(dirname "${tests_repo_dir}")
[ -d "${tests_repo_dir}" ] || sudo -E git clone "https://${tests_repo}.git" "${tests_repo_dir}"
sudo -E chown -R root:root "${tests_repo_dir}"
pushd "${tests_repo_dir}"
sudo -E git fetch
if [ -n "${tests_branch}" ]; then
sudo -E git checkout ${tests_branch}
fi
sudo -E git reset --hard origin/${tests_branch}
popd
source "${BATS_TEST_DIRNAME}/lib.sh"
source "${BATS_TEST_DIRNAME}/../../confidential/lib.sh"
}
# Note: clone_katacontainers_repo using go, so that needs to be installed first
checkout_kata_containers_repo() {
source "${tests_repo_dir}/.ci/lib.sh"
echo "Creating repo: ${katacontainers_repo} and branch ${kata_default_branch} into ${katacontainers_repo_dir}..."
clone_katacontainers_repo
sudo -E chown -R ${USER}:${USER} "${katacontainers_repo_dir}"
}
build_and_install_kata_runtime() {
pushd ${katacontainers_repo_dir}/src/runtime
make clean && make DEFAULT_HYPERVISOR=${KATA_HYPERVISOR} && sudo -E PATH=$PATH make DEFAULT_HYPERVISOR=${KATA_HYPERVISOR} install
popd
}
configure() {
configure_kata_to_use_rootfs
enable_full_debug
enable_agent_console
# Switch image offload to true in kata config
switch_image_service_offload "on"
configure_cc_containerd
# From crictl v1.24.1 the default timoout leads to the pod creation failing, so update it
sudo crictl config --set timeout=10
}
configure_kata_to_use_rootfs() {
sudo mkdir -p /etc/kata-containers/
sudo install -o root -g root -m 0640 /usr/share/defaults/kata-containers/configuration.toml /etc/kata-containers
sudo sed -i 's/^\(initrd =.*\)/# \1/g' ${RUNTIME_CONFIG_PATH}
}
build_and_add_agent_to_rootfs() {
build_a_custom_kata_agent
add_custom_agent_to_rootfs
}
build_a_custom_kata_agent() {
# Install libseccomp for static linking
sudo -E PATH=$PATH GOPATH=$GOPATH ${katacontainers_repo_dir}/ci/install_libseccomp.sh /tmp/kata-libseccomp /tmp/kata-gperf
export LIBSECCOMP_LINK_TYPE=static
export LIBSECCOMP_LIB_PATH=/tmp/kata-libseccomp/lib
. "$HOME/.cargo/env"
pushd ${katacontainers_repo_dir}/src/agent
sudo -E PATH=$PATH make
ARCH=$(uname -m)
[ ${ARCH} == "ppc64le" ] || [ ${ARCH} == "s390x" ] && export LIBC=gnu || export LIBC=musl
[ ${ARCH} == "ppc64le" ] && export ARCH=powerpc64le
# Run a make install into the rootfs directory in order to create the kata-agent.service file which is required when we add to the rootfs
sudo -E PATH=$PATH make install DESTDIR="${ROOTFS_DIR}"
popd
}
create_a_local_rootfs() {
sudo rm -rf "${ROOTFS_DIR}"
pushd ${katacontainers_repo_dir}/tools/osbuilder/rootfs-builder
export distro="ubuntu"
[[ -z "${USE_PODMAN:-}" ]] && use_docker="${use_docker:-1}"
sudo -E OS_VERSION="${OS_VERSION:-}" GOPATH=$GOPATH EXTRA_PKGS="vim iputils-ping net-tools" DEBUG="${DEBUG:-}" USE_DOCKER="${use_docker:-}" SKOPEO=${SKOPEO:-} AA_KBC=${AA_KBC:-} UMOCI=yes SECCOMP=yes ./rootfs.sh -r ${ROOTFS_DIR} ${distro}
# Install_rust.sh during rootfs.sh switches us to the main branch of the tests repo, so switch back now
pushd "${tests_repo_dir}"
sudo -E git checkout ${tests_branch}
popd
# During the ./rootfs.sh call the kata agent is built as root, so we need to update the permissions, so we can rebuild it
sudo chown -R ${USER}:${USER} "${katacontainers_repo_dir}/src/agent/"
popd
}
add_custom_agent_to_rootfs() {
pushd ${katacontainers_repo_dir}/tools/osbuilder/rootfs-builder
ARCH=$(uname -m)
[ ${ARCH} == "ppc64le" ] || [ ${ARCH} == "s390x" ] && export LIBC=gnu || export LIBC=musl
[ ${ARCH} == "ppc64le" ] && export ARCH=powerpc64le
sudo install -o root -g root -m 0550 -t ${ROOTFS_DIR}/usr/bin ${katacontainers_repo_dir}/src/agent/target/${ARCH}-unknown-linux-${LIBC}/release/kata-agent
sudo install -o root -g root -m 0440 ../../../src/agent/kata-agent.service ${ROOTFS_DIR}/usr/lib/systemd/system/
sudo install -o root -g root -m 0440 ../../../src/agent/kata-containers.target ${ROOTFS_DIR}/usr/lib/systemd/system/
popd
}
build_and_install_rootfs() {
build_rootfs_image
install_rootfs_image
}
build_rootfs_image() {
pushd ${katacontainers_repo_dir}/tools/osbuilder/image-builder
# Logic from install_kata_image.sh - if we aren't using podman (ie on a fedora like), then use docker
[[ -z "${USE_PODMAN:-}" ]] && use_docker="${use_docker:-1}"
sudo -E USE_DOCKER="${use_docker:-}" ./image_builder.sh ${ROOTFS_DIR}
popd
}
install_rootfs_image() {
pushd ${katacontainers_repo_dir}/tools/osbuilder/image-builder
local commit=$(git log --format=%h -1 HEAD)
local date=$(date +%Y-%m-%d-%T.%N%z)
local image="kata-containers-${date}-${commit}"
sudo install -o root -g root -m 0640 -D kata-containers.img "/usr/share/kata-containers/${image}"
(cd /usr/share/kata-containers && sudo ln -sf "$image" kata-containers.img)
echo "Built Rootfs from ${ROOTFS_DIR} to /usr/share/kata-containers/${image}"
ls -al /usr/share/kata-containers/
popd
}
install_guest_kernel_image() {
pushd ${katacontainers_repo_dir}/tools/packaging/kernel
sudo -E PATH=$PATH ./build-kernel.sh setup
sudo -E PATH=$PATH ./build-kernel.sh build
sudo chmod u+wrx /usr/share/kata-containers/ # Give user permission to install kernel
sudo -E PATH=$PATH ./build-kernel.sh install
popd
}
build_qemu() {
${tests_repo_dir}/.ci/install_virtiofsd.sh
${tests_repo_dir}/.ci/install_qemu.sh
}
build_cloud_hypervisor() {
${tests_repo_dir}/.ci/install_virtiofsd.sh
${tests_repo_dir}/.ci/install_cloud_hypervisor.sh
}
check_kata_runtime() {
sudo kata-runtime check
}
k8s_pod_file="${HOME}/busybox-cc.yaml"
init_kubernetes() {
# Check that kubeadm was installed and install it otherwise
if ! [ -x "$(command -v kubeadm)" ]; then
pushd "${tests_repo_dir}/.ci"
sudo -E PATH=$PATH -s install_kubernetes.sh
if [ "${CRI_CONTAINERD}" == "yes" ]; then
sudo -E PATH=$PATH -s "configure_containerd_for_kubernetes.sh"
fi
popd
fi
# If kubernetes init has previously run we need to clean it by removing the image and resetting k8s
local cid=$(sudo docker ps -a -q -f name=^/kata-registry$)
if [ -n "${cid}" ]; then
sudo docker stop ${cid} && sudo docker rm ${cid}
fi
local k8s_nodes=$(kubectl get nodes -o name 2>/dev/null || true)
if [ -n "${k8s_nodes}" ]; then
sudo kubeadm reset -f
fi
export CI="true" && sudo -E PATH=$PATH -s ${tests_repo_dir}/integration/kubernetes/init.sh
sudo chown ${USER}:$(id -g -n ${USER}) "$HOME/.kube/config"
cat << EOF > ${k8s_pod_file}
apiVersion: v1
kind: Pod
metadata:
name: busybox-cc
spec:
runtimeClassName: kata
containers:
- name: nginx
image: quay.io/kata-containers/confidential-containers:signed
imagePullPolicy: Always
EOF
}
call_kubernetes_create_cc_pod() {
kubernetes_create_cc_pod ${k8s_pod_file}
}
call_kubernetes_delete_cc_pod() {
pod_name=$(kubectl get pods -o jsonpath='{.items..metadata.name}')
kubernetes_delete_cc_pod $pod_name
}
call_kubernetes_create_ssh_demo_pod() {
setup_decryption_files_in_guest
kubernetes_create_ssh_demo_pod
}
call_connect_to_ssh_demo_pod() {
connect_to_ssh_demo_pod
}
call_kubernetes_delete_ssh_demo_pod() {
pod=$(kubectl get pods -o jsonpath='{.items..metadata.name}')
kubernetes_delete_ssh_demo_pod $pod
}
crictl_sandbox_name=kata-cc-busybox-sandbox
call_crictl_create_cc_pod() {
# Update iptables to allow forwarding to the cni0 bridge avoiding issues caused by the docker0 bridge
sudo iptables -P FORWARD ACCEPT
# get_pod_config in tests_common exports `pod_config` that points to the prepared pod config yaml
get_pod_config
crictl_delete_cc_pod_if_exists "${crictl_sandbox_name}"
crictl_create_cc_pod "${pod_config}"
sudo crictl pods
}
call_crictl_create_cc_container() {
# Create container configuration yaml based on our test copy of busybox
# get_pod_config in tests_common exports `pod_config` that points to the prepared pod config yaml
get_pod_config
local container_config="${FIXTURES_DIR}/${CONTAINER_CONFIG_FILE:-container-config.yaml}"
local pod_name=${crictl_sandbox_name}
crictl_create_cc_container ${pod_name} ${pod_config} ${container_config}
sudo crictl ps -a
}
crictl_delete_cc() {
crictl_delete_cc_pod ${crictl_sandbox_name}
}
test_kata_runtime() {
echo "Running ctr with the kata runtime..."
local test_image="quay.io/kata-containers/confidential-containers:signed"
if [ -z $(ctr images ls -q name=="${test_image}") ]; then
sudo ctr image pull "${test_image}"
fi
sudo ctr run --runtime "io.containerd.kata.v2" --rm -t "${test_image}" test-kata uname -a
}
run_kata_and_capture_logs() {
echo "Clearing systemd journal..."
sudo systemctl stop systemd-journald
sudo rm -f /var/log/journal/*/* /run/log/journal/*/*
sudo systemctl start systemd-journald
test_kata_runtime
echo "Collecting logs..."
sudo journalctl -q -o cat -a -t kata-runtime > ${HOME}/kata-runtime.log
sudo journalctl -q -o cat -a -t kata > ${HOME}/shimv2.log
echo "Logs output to ${HOME}/kata-runtime.log and ${HOME}/shimv2.log"
}
get_ids() {
guest_cid=$(sudo ss -H --vsock | awk '{print $6}' | cut -d: -f1)
sandbox_id=$(ps -ef | grep containerd-shim-kata-v2 | egrep -o "id [^,][^,].* " | awk '{print $2}')
}
open_kata_shell() {
get_ids
sudo -E "PATH=$PATH" kata-runtime exec ${sandbox_id}
}
build_bundle_dir_if_necessary() {
bundle_dir="/tmp/bundle"
if [ ! -d "${bundle_dir}" ]; then
rootfs_dir="$bundle_dir/rootfs"
image="quay.io/kata-containers/confidential-containers:signed"
mkdir -p "$rootfs_dir" && (cd "$bundle_dir" && runc spec)
sudo docker export $(sudo docker create "$image") | tar -C "$rootfs_dir" -xvf -
fi
# There were errors in create container agent-ctl command due to /bin/ seemingly not being on the path, so hardcode it
sudo sed -i -e 's%^\(\t*\)"sh"$%\1"/bin/sh"%g' "${bundle_dir}/config.json"
}
build_agent_ctl() {
cd ${GOPATH}/src/${katacontainers_repo}/src/tools/agent-ctl/
if [ -e "${HOME}/.cargo/registry" ]; then
sudo chown -R ${USER}:${USER} "${HOME}/.cargo/registry"
fi
sudo -E PATH=$PATH -s make
ARCH=$(uname -m)
[ ${ARCH} == "ppc64le" ] || [ ${ARCH} == "s390x" ] && export LIBC=gnu || export LIBC=musl
[ ${ARCH} == "ppc64le" ] && export ARCH=powerpc64le
cd "./target/${ARCH}-unknown-linux-${LIBC}/release/"
}
run_agent_ctl_command() {
get_ids
build_bundle_dir_if_necessary
command=$1
# If kata-agent-ctl pre-built in this directory, use it directly, otherwise build it first and switch to release
if [ ! -x kata-agent-ctl ]; then
build_agent_ctl
fi
./kata-agent-ctl -l debug connect --bundle-dir "${bundle_dir}" --server-address "vsock://${guest_cid}:1024" -c "${command}"
}
agent_pull_image() {
run_agent_ctl_command "PullImage image=${PULL_IMAGE} cid=${CONTAINER_ID} source_creds=${SOURCE_CREDS}"
}
agent_create_container() {
run_agent_ctl_command "CreateContainer cid=${CONTAINER_ID}"
}
shim_pull_image() {
get_ids
local ctr_shim_command="sudo ctr --namespace k8s.io shim --id ${sandbox_id} pull-image ${PULL_IMAGE} ${CONTAINER_ID}"
echo "Issuing command '${ctr_shim_command}'"
${ctr_shim_command}
}
call_copy_signature_files_to_guest() {
# TODO #5173 - remove this once the kernel_params aren't ignored by the agent config
export DEBUG_CONSOLE="true"
if [ "${SKOPEO:-}" = "yes" ]; then
add_kernel_params "agent.container_policy_file=/etc/containers/quay_verification/quay_policy.json"
setup_skopeo_signature_files_in_guest
else
# TODO #4888 - set config to specifically enable signature verification to be on in ImageClient
setup_offline_fs_kbc_signature_files_in_guest
fi
}
main() {
while getopts "dh" opt; do
case "$opt" in
d)
export DEBUG="-d"
set -x
;;
h)
usage 0
;;
\?)
echo "Invalid option: -$OPTARG" >&2
usage 1
;;
esac
done
shift $((OPTIND - 1))
subcmd="${1:-}"
[ -z "${subcmd}" ] && usage 1
case "${subcmd}" in
all)
build_and_install_all
run_kata_and_capture_logs
;;
build_and_install_all)
build_and_install_all
;;
rebuild_and_install_kata)
rebuild_and_install_kata
;;
initialize)
initialize
;;
build_kata_runtime)
build_and_install_kata_runtime
;;
configure)
configure
;;
create_rootfs)
create_a_local_rootfs
;;
build_and_add_agent_to_rootfs)
build_and_add_agent_to_rootfs
;;
build_and_install_rootfs)
build_and_install_rootfs
;;
install_guest_kernel)
install_guest_kernel_image
;;
build_cloud_hypervisor)
build_cloud_hypervisor
;;
build_qemu)
build_qemu
;;
init_kubernetes)
init_kubernetes
;;
crictl_create_cc_pod)
call_crictl_create_cc_pod
;;
crictl_create_cc_container)
call_crictl_create_cc_container
;;
crictl_delete_cc)
crictl_delete_cc
;;
kubernetes_create_cc_pod)
call_kubernetes_create_cc_pod
;;
kubernetes_delete_cc_pod)
call_kubernetes_delete_cc_pod
;;
kubernetes_create_ssh_demo_pod)
call_kubernetes_create_ssh_demo_pod
;;
connect_to_ssh_demo_pod)
call_connect_to_ssh_demo_pod
;;
kubernetes_delete_ssh_demo_pod)
call_kubernetes_delete_ssh_demo_pod
;;
test)
test_kata_runtime
;;
test_capture_logs)
run_kata_and_capture_logs
;;
open_kata_console)
open_kata_console
;;
open_kata_shell)
open_kata_shell
;;
agent_pull_image)
agent_pull_image
;;
shim_pull_image)
shim_pull_image
;;
agent_create_container)
agent_create_container
;;
copy_signature_files_to_guest)
call_copy_signature_files_to_guest
;;
*)
usage 1
;;
esac
}
main $@

View File

@@ -40,7 +40,7 @@ use `RuntimeClass` instead of the deprecated annotations.
### Containerd Runtime V2 API: Shim V2 API
The [`containerd-shim-kata-v2` (short as `shimv2` in this documentation)](../../src/runtime/cmd/containerd-shim-kata-v2/)
implements the [Containerd Runtime V2 (Shim API)](https://github.com/containerd/containerd/tree/main/runtime/v2) for Kata.
implements the [Containerd Runtime V2 (Shim API)](https://github.com/containerd/containerd/tree/master/runtime/v2) for Kata.
With `shimv2`, Kubernetes can launch Pod and OCI-compatible containers with one shim per Pod. Prior to `shimv2`, `2N+1`
shims (i.e. a `containerd-shim` and a `kata-shim` for each container and the Pod sandbox itself) and no standalone `kata-proxy`
process were used, even with VSOCK not available.
@@ -77,8 +77,8 @@ $ command -v containerd
You can manually install CNI plugins as follows:
```bash
$ git clone https://github.com/containernetworking/plugins.git
$ pushd plugins
$ go get github.com/containernetworking/plugins
$ pushd $GOPATH/src/github.com/containernetworking/plugins
$ ./build_linux.sh
$ sudo mkdir /opt/cni
$ sudo cp -r bin /opt/cni/
@@ -93,8 +93,8 @@ $ popd
You can install the `cri-tools` from source code:
```bash
$ git clone https://github.com/kubernetes-sigs/cri-tools.git
$ pushd cri-tools
$ go get github.com/kubernetes-sigs/cri-tools
$ pushd $GOPATH/src/github.com/kubernetes-sigs/cri-tools
$ make
$ sudo -E make install
$ popd
@@ -132,9 +132,9 @@ The `RuntimeClass` is suggested.
The following configuration includes two runtime classes:
- `plugins.cri.containerd.runtimes.runc`: the runc, and it is the default runtime.
- `plugins.cri.containerd.runtimes.kata`: The function in containerd (reference [the document here](https://github.com/containerd/containerd/tree/main/runtime/v2#binary-naming))
- `plugins.cri.containerd.runtimes.kata`: The function in containerd (reference [the document here](https://github.com/containerd/containerd/tree/master/runtime/v2#binary-naming))
where the dot-connected string `io.containerd.kata.v2` is translated to `containerd-shim-kata-v2` (i.e. the
binary name of the Kata implementation of [Containerd Runtime V2 (Shim API)](https://github.com/containerd/containerd/tree/main/runtime/v2)).
binary name of the Kata implementation of [Containerd Runtime V2 (Shim API)](https://github.com/containerd/containerd/tree/master/runtime/v2)).
```toml
[plugins.cri.containerd]

View File

@@ -1,45 +0,0 @@
# Copyright (c) 2021 IBM Corp.
#
# SPDX-License-Identifier: Apache-2.0
#
aa_kbc_params = "$AA_KBC_PARAMS"
https_proxy = "$HTTPS_PROXY"
[endpoints]
allowed = [
"AddARPNeighborsRequest",
"AddSwapRequest",
"CloseStdinRequest",
"CopyFileRequest",
"CreateContainerRequest",
"CreateSandboxRequest",
"DestroySandboxRequest",
#"ExecProcessRequest",
"GetMetricsRequest",
"GetOOMEventRequest",
"GuestDetailsRequest",
"ListInterfacesRequest",
"ListRoutesRequest",
"MemHotplugByProbeRequest",
"OnlineCPUMemRequest",
"PauseContainerRequest",
"PullImageRequest",
"ReadStreamRequest",
"RemoveContainerRequest",
#"ReseedRandomDevRequest",
"ResizeVolumeRequest",
"ResumeContainerRequest",
"SetGuestDateTimeRequest",
"SignalProcessRequest",
"StartContainerRequest",
"StartTracingRequest",
"StatsContainerRequest",
"StopTracingRequest",
"TtyWinResizeRequest",
"UpdateContainerRequest",
"UpdateInterfaceRequest",
"UpdateRoutesRequest",
"VolumeStatsRequest",
"WaitProcessRequest",
"WriteStreamRequest"
]

View File

@@ -45,9 +45,6 @@ spec:
- name: containerdsocket
mountPath: /run/containerd/containerd.sock
readOnly: true
- name: sbs
mountPath: /run/vc/sbs/
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: containerdtask
@@ -56,6 +53,3 @@ spec:
- name: containerdsocket
hostPath:
path: /run/containerd/containerd.sock
- name: sbs
hostPath:
path: /run/vc/sbs/

View File

@@ -1,479 +0,0 @@
# How to build, run and test Kata CCv0
## Introduction and Background
In order to try and make building (locally) and demoing the Kata Containers `CCv0` code base as simple as possible I've
shared a script [`ccv0.sh`](./ccv0.sh). This script was originally my attempt to automate the steps of the
[Developer Guide](https://github.com/kata-containers/kata-containers/blob/main/docs/Developer-Guide.md) so that I could do
different sections of them repeatedly and reliably as I was playing around with make changes to different parts of the
Kata code base. I then tried to weave in some of the [`tests/.ci`](https://github.com/kata-containers/tests/tree/main/.ci)
scripts in order to have less duplicated code.
As we're progress on the confidential containers journey I hope to add more features to demonstrate the functionality
we have working.
*Disclaimer: This script has mostly just been used and tested by me ([@stevenhorsman](https://github.com/stevenhorsman)),*
*so there might be issues with it. I'm happy to try and help solve these if possible, but this shouldn't be considered a*
*fully supported process by the Kata Containers community.*
### Basic script set-up and optional environment variables
In order to build, configure and demo the CCv0 functionality, these are the set-up steps I take:
- Provision a new VM
- *I choose a Ubuntu 20.04 8GB VM for this as I had one available. There are some dependences on apt-get installed*
*packages, so these will need re-working to be compatible with other platforms.*
- Copy the script over to your VM *(I put it in the home directory)* and ensure it has execute permission by running
```bash
$ chmod u+x ccv0.sh
```
- Optionally set up some environment variables
- By default the script checks out the `CCv0` branches of the `kata-containers/kata-containers` and
`kata-containers/tests` repositories, but it is designed to be used to test of personal forks and branches as well.
If you want to build and run these you can export the `katacontainers_repo`, `katacontainers_branch`, `tests_repo`
and `tests_branch` variables e.g.
```bash
$ export katacontainers_repo=github.com/stevenhorsman/kata-containers
$ export katacontainers_branch=stevenh/agent-pull-image-endpoint
$ export tests_repo=github.com/stevenhorsman/tests
$ export tests_branch=stevenh/add-ccv0-changes-to-build
```
before running the script.
- By default the build and configuration are using `QEMU` as the hypervisor. In order to use `Cloud Hypervisor` instead
set:
```
$ export KATA_HYPERVISOR="cloud-hypervisor"
```
before running the build.
- At this point you can provision a Kata confidential containers pod and container with either
[`crictl`](#using-crictl-for-end-to-end-provisioning-of-a-kata-confidential-containers-pod-with-an-unencrypted-image),
or [Kubernetes](#using-kubernetes-for-end-to-end-provisioning-of-a-kata-confidential-containers-pod-with-an-unencrypted-image)
and then test and use it.
### Using crictl for end-to-end provisioning of a Kata confidential containers pod with an unencrypted image
- Run the full build process with Kubernetes turned off, so its configuration doesn't interfere with `crictl` using:
```bash
$ export KUBERNETES="no"
$ export KATA_HYPERVISOR="qemu"
$ ~/ccv0.sh -d build_and_install_all
```
> **Note**: Much of this script has to be run as `sudo`, so you are likely to get prompted for your password.
- *I run this script sourced just so that the required installed components are accessible on the `PATH` to the rest*
*of the process without having to reload the session.*
- The steps that `build_and_install_all` takes is:
- Checkout the git repos for the `tests` and `kata-containers` repos as specified by the environment variables
(default to `CCv0` branches if they are not supplied)
- Use the `tests/.ci` scripts to install the build dependencies
- Build and install the Kata runtime
- Configure Kata to use containerd and for debug and confidential containers features to be enabled (including
enabling console access to the Kata guest shell, which should only be done in development)
- Create, build and install a rootfs for the Kata hypervisor to use. For 'CCv0' this is currently based on Ubuntu
20.04 and has extra packages like `umoci` added.
- Build the Kata guest kernel
- Install the hypervisor (in order to select which hypervisor will be used, the `KATA_HYPERVISOR` environment
variable can be used to select between `qemu` or `cloud-hypervisor`)
> **Note**: Depending on how where your VMs are hosted and how IPs are shared you might get an error from docker
during matching `ERROR: toomanyrequests: Too Many Requests`. To get past
this, login into Docker Hub and pull the images used with:
> ```bash
> $ sudo docker login
> $ sudo docker pull ubuntu
> ```
> then re-run the command.
- The first time this runs it may take a while, but subsequent runs will be quicker as more things are already
installed and they can be further cut down by not running all the above steps
[see "Additional script usage" below](#additional-script-usage)
- Create a new Kata sandbox pod using `crictl` with:
```bash
$ ~/ccv0.sh crictl_create_cc_pod
```
- This creates a pod configuration file, creates the pod from this using
`sudo crictl runp -r kata ~/pod-config.yaml` and runs `sudo crictl pods` to show the pod
- Create a new Kata confidential container with:
```bash
$ ~/ccv0.sh crictl_create_cc_container
```
- This creates a container (based on `busybox:1.33.1`) in the Kata cc sandbox and prints a list of containers.
This will have been created based on an image pulled in the Kata pod sandbox/guest, not on the host machine.
As this point you should have a `crictl` pod and container that is using the Kata confidential containers runtime.
You can [validate that the container image was pulled on the guest](#validate-that-the-container-image-was-pulled-on-the-guest)
or [using the Kata pod sandbox for testing with `agent-ctl` or `ctr shim`](#using-a-kata-pod-sandbox-for-testing-with-agent-ctl-or-ctr-shim)
#### Clean up the `crictl` pod sandbox and container
- When the testing is complete you can delete the container and pod by running:
```bash
$ ~/ccv0.sh crictl_delete_cc
```
### Using Kubernetes for end-to-end provisioning of a Kata confidential containers pod with an unencrypted image
- Run the full build process with the Kubernetes environment variable set to `"yes"`, so the Kubernetes cluster is
configured and created using the VM
as a single node cluster:
```bash
$ export KUBERNETES="yes"
$ ~/ccv0.sh build_and_install_all
```
> **Note**: Depending on how where your VMs are hosted and how IPs are shared you might get an error from docker
during matching `ERROR: toomanyrequests: Too Many Requests`. To get past
this, login into Docker Hub and pull the images used with:
> ```bash
> $ sudo docker login
> $ sudo docker pull registry:2
> $ sudo docker pull ubuntu:20.04
> ```
> then re-run the command.
- Check that your Kubernetes cluster has been correctly set-up by running :
```bash
$ kubectl get nodes
```
and checking that you see a single node e.g.
```text
NAME STATUS ROLES AGE VERSION
stevenh-ccv0-k8s1.fyre.ibm.com Ready control-plane,master 43s v1.22.0
```
- Create a Kata confidential containers pod by running:
```bash
$ ~/ccv0.sh kubernetes_create_cc_pod
```
- Wait a few seconds for pod to start then check that the pod's status is `Running` with
```bash
$ kubectl get pods
```
which should show something like:
```text
NAME READY STATUS RESTARTS AGE
busybox-cc 1/1 Running 0 54s
```
- As this point you should have a Kubernetes pod and container running, that is using the Kata
confidential containers runtime.
You can [validate that the container image was pulled on the guest](#validate-that-the-container-image-was-pulled-on-the-guest)
or [using the Kata pod sandbox for testing with `agent-ctl` or `ctr shim`](#using-a-kata-pod-sandbox-for-testing-with-agent-ctl-or-ctr-shim)
#### Clean up the Kubernetes pod sandbox and container
- When the testing is complete you can delete the container and pod by running:
```bash
$ ~/ccv0.sh kubernetes_delete_cc_pod
```
### Validate that the container image was pulled on the guest
There are a couple of ways we can check that the container pull image action was offloaded to the guest, by checking
the guest's file system for the unpacked bundle and checking the host's directories to ensure it wasn't also pulled
there.
- To check the guest's file system:
- Open a shell into the Kata guest with:
```bash
$ ~/ccv0.sh open_kata_shell
```
- List the files in the directory that the container image bundle should have been unpacked to with:
```bash
$ ls -ltr /run/kata-containers/confidential-containers_signed/
```
- This should give something like
```
total 72
-rw-r--r-- 1 root root 2977 Jan 20 10:03 config.json
-rw-r--r-- 1 root root 372 Jan 20 10:03 umoci.json
-rw-r--r-- 1 root root 63584 Jan 20 10:03 sha256_be9faa75035c20288cde7d2cdeb6cd1f5f4dbcd845d3f86f7feab61c4eff9eb5.mtree
drwxr-xr-x 12 root root 240 Jan 20 10:03 rootfs
```
which shows how the image has been pulled and then unbundled on the guest.
- Leave the Kata guest shell by running:
```bash
$ exit
```
- To verify that the image wasn't pulled on the host system we can look at the shared sandbox on the host and we
should only see a single bundle for the pause container as the `busybox` based container image should have been
pulled on the guest:
- Find all the `rootfs` directories under in the pod's shared directory with:
```bash
$ pod_id=$(ps -ef | grep containerd-shim-kata-v2 | egrep -o "id [^,][^,].* " | awk '{print $2}')
$ sudo find /run/kata-containers/shared/sandboxes/${pod_id}/shared -name rootfs
```
which should only show a single `rootfs` directory if the container image was pulled on the guest, not the host
- Looking that `rootfs` directory with
```bash
$ sudo ls -ltr $(sudo find /run/kata-containers/shared/sandboxes/${pod_id}/shared -name rootfs)
```
shows something similar to
```
total 668
-rwxr-xr-x 1 root root 682696 Aug 25 13:58 pause
drwxr-xr-x 2 root root 6 Jan 20 02:01 proc
drwxr-xr-x 2 root root 6 Jan 20 02:01 dev
drwxr-xr-x 2 root root 6 Jan 20 02:01 sys
drwxr-xr-x 2 root root 25 Jan 20 02:01 etc
```
which is clearly the pause container indicating that the `busybox` based container image is not exposed to the host.
### Using a Kata pod sandbox for testing with `agent-ctl` or `ctr shim`
Once you have a kata pod sandbox created as described above, either using
[`crictl`](#using-crictl-for-end-to-end-provisioning-of-a-kata-confidential-containers-pod-with-an-unencrypted-image), or [Kubernetes](#using-kubernetes-for-end-to-end-provisioning-of-a-kata-confidential-containers-pod-with-an-unencrypted-image)
, you can use this to test specific components of the Kata confidential
containers architecture. This can be useful for development and debugging to isolate and test features
that aren't broadly supported end-to-end. Here are some examples:
- In the first terminal run the pull image on guest command against the Kata agent, via the shim (`containerd-shim-kata-v2`).
This can be achieved using the [containerd](https://github.com/containerd/containerd) CLI tool, `ctr`, which can be used to
interact with the shim directly. The command takes the form
`ctr --namespace k8s.io shim --id <sandbox-id> pull-image <image> <new-container-id>` and can been run directly, or through
the `ccv0.sh` script to automatically fill in the variables:
- Optionally, set up some environment variables to set the image and credentials used:
- By default the shim pull image test in `ccv0.sh` will use the `busybox:1.33.1` based test image
`quay.io/kata-containers/confidential-containers:signed` which requires no authentication. To use a different
image, set the `PULL_IMAGE` environment variable e.g.
```bash
$ export PULL_IMAGE="docker.io/library/busybox:latest"
```
Currently the containerd shim pull image
code doesn't support using a container registry that requires authentication, so if this is required, see the
below steps to run the pull image command against the agent directly.
- Run the pull image agent endpoint with:
```bash
$ ~/ccv0.sh shim_pull_image
```
which we print the `ctr shim` command for reference
- Alternatively you can issue the command directly to the `kata-agent` pull image endpoint, which also supports
credentials in order to pull from an authenticated registry:
- Optionally set up some environment variables to set the image and credentials used:
- Set the `PULL_IMAGE` environment variable e.g. `export PULL_IMAGE="docker.io/library/busybox:latest"`
if a specific container image is required.
- If the container registry for the image requires authentication then this can be set with an environment
variable `SOURCE_CREDS`. For example to use Docker Hub (`docker.io`) as an authenticated user first run
`export SOURCE_CREDS="<dockerhub username>:<dockerhub api key>"`
> **Note**: the credentials support on the agent request is a tactical solution for the short-term
proof of concept to allow more images to be pulled and tested. Once we have support for getting
keys into the Kata guest image using the attestation-agent and/or KBS I'd expect container registry
credentials to be looked up using that mechanism.
- Run the pull image agent endpoint with
```bash
$ ~/ccv0.sh agent_pull_image
```
and you should see output which includes `Command PullImage (1 of 1) returned (Ok(()), false)` to indicate
that the `PullImage` request was successful e.g.
```
Finished release [optimized] target(s) in 0.21s
{"msg":"announce","level":"INFO","ts":"2021-09-15T08:40:14.189360410-07:00","subsystem":"rpc","name":"kata-agent-ctl","pid":"830920","version":"0.1.0","source":"kata-agent-ctl","config":"Config { server_address: \"vsock://1970354082:1024\", bundle_dir: \"/tmp/bundle\", timeout_nano: 0, interactive: false, ignore_errors: false }"}
{"msg":"client setup complete","level":"INFO","ts":"2021-09-15T08:40:14.193639057-07:00","pid":"830920","source":"kata-agent-ctl","name":"kata-agent-ctl","subsystem":"rpc","version":"0.1.0","server-address":"vsock://1970354082:1024"}
{"msg":"Run command PullImage (1 of 1)","level":"INFO","ts":"2021-09-15T08:40:14.196643765-07:00","pid":"830920","source":"kata-agent-ctl","subsystem":"rpc","name":"kata-agent-ctl","version":"0.1.0"}
{"msg":"response received","level":"INFO","ts":"2021-09-15T08:40:43.828200633-07:00","source":"kata-agent-ctl","name":"kata-agent-ctl","subsystem":"rpc","version":"0.1.0","pid":"830920","response":""}
{"msg":"Command PullImage (1 of 1) returned (Ok(()), false)","level":"INFO","ts":"2021-09-15T08:40:43.828261708-07:00","subsystem":"rpc","pid":"830920","source":"kata-agent-ctl","version":"0.1.0","name":"kata-agent-ctl"}
```
> **Note**: The first time that `~/ccv0.sh agent_pull_image` is run, the `agent-ctl` tool will be built
which may take a few minutes.
- To validate that the image pull was successful, you can open a shell into the Kata guest with:
```bash
$ ~/ccv0.sh open_kata_shell
```
- Check the `/run/kata-containers/` directory to verify that the container image bundle has been created in a directory
named either `01234556789` (for the container id), or the container image name, e.g.
```bash
$ ls -ltr /run/kata-containers/confidential-containers_signed/
```
which should show something like
```
total 72
drwxr-xr-x 10 root root 200 Jan 1 1970 rootfs
-rw-r--r-- 1 root root 2977 Jan 20 16:45 config.json
-rw-r--r-- 1 root root 372 Jan 20 16:45 umoci.json
-rw-r--r-- 1 root root 63584 Jan 20 16:45 sha256_be9faa75035c20288cde7d2cdeb6cd1f5f4dbcd845d3f86f7feab61c4eff9eb5.mtree
```
- Leave the Kata shell by running:
```bash
$ exit
```
## Verifying signed images
For this sample demo, we use local attestation to pass through the required
configuration to do container image signature verification. Due to this, the ability to verify images is limited
to a pre-created selection of test images in our test
repository [`quay.io/kata-containers/confidential-containers`](https://quay.io/repository/kata-containers/confidential-containers?tab=tags).
For pulling images not in this test repository (called an *unprotected* registry below), we fall back to the behaviour
of not enforcing signatures. More documentation on how to customise this to match your own containers through local,
or remote attestation will be available in future.
In our test repository there are three tagged images:
| Test Image | Base Image used | Signature status | GPG key status |
| --- | --- | --- | --- |
| `quay.io/kata-containers/confidential-containers:signed` | `busybox:1.33.1` | [signature](https://github.com/kata-containers/tests/tree/CCv0/integration/confidential/fixtures/quay_verification/signatures.tar) embedded in kata rootfs | [public key](https://github.com/kata-containers/tests/tree/CCv0/integration/confidential/fixtures/quay_verification/public.gpg) embedded in kata rootfs |
| `quay.io/kata-containers/confidential-containers:unsigned` | `busybox:1.33.1` | not signed | not signed |
| `quay.io/kata-containers/confidential-containers:other_signed` | `nginx:1.21.3` | [signature](https://github.com/kata-containers/tests/tree/CCv0/integration/confidential/fixtures/quay_verification/signatures.tar) embedded in kata rootfs | GPG key not kept |
Using a standard unsigned `busybox` image that can be pulled from another, *unprotected*, `quay.io` repository we can
test a few scenarios.
In this sample, with local attestation, we pass in the the public GPG key and signature files, and the [`offline_fs_kbc`
configuration](https://github.com/confidential-containers/attestation-agent/blob/main/src/kbc_modules/offline_fs_kbc/README.md)
into the guest image which specifies that any container image from `quay.io/kata-containers`
must be signed with the embedded GPG key and the agent configuration needs updating to enable this.
With this policy set a few tests of image verification can be done to test different scenarios by attempting
to create containers from these images using `crictl`:
- If you don't already have the Kata Containers CC code built and configured for `crictl`, then follow the
[instructions above](#using-crictl-for-end-to-end-provisioning-of-a-kata-confidential-containers-pod-with-an-unencrypted-image)
up to the `~/ccv0.sh crictl_create_cc_pod` command.
- In order to enable the guest image, you will need to setup the required configuration, policy and signature files
needed by running
`~/ccv0.sh copy_signature_files_to_guest` and then run `~/ccv0.sh crictl_create_cc_pod` which will delete and recreate
your pod - adding in the new files.
- To test the fallback behaviour works using an unsigned image from an *unprotected* registry we can pull the `busybox`
image by running:
```bash
$ export CONTAINER_CONFIG_FILE=container-config_unsigned-unprotected.yaml
$ ~/ccv0.sh crictl_create_cc_container
```
- This finishes showing the running container e.g.
```text
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
98c70fefe997a quay.io/prometheus/busybox:latest Less than a second ago Running prometheus-busybox-signed 0 70119e0539238
```
- To test that an unsigned image from our *protected* test container registry is rejected we can run:
```bash
$ export CONTAINER_CONFIG_FILE=container-config_unsigned-protected.yaml
$ ~/ccv0.sh crictl_create_cc_container
```
- This correctly results in an error message from `crictl`:
`PullImage from image service failed" err="rpc error: code = Internal desc = Security validate failed: Validate image failed: The signatures do not satisfied! Reject reason: [Match reference failed.]" image="quay.io/kata-containers/confidential-containers:unsigned"`
- To test that the signed image our *protected* test container registry is accepted we can run:
```bash
$ export CONTAINER_CONFIG_FILE=container-config.yaml
$ ~/ccv0.sh crictl_create_cc_container
```
- This finishes by showing a new `kata-cc-busybox-signed` running container e.g.
```text
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
b4d85c2132ed9 quay.io/kata-containers/confidential-containers:signed Less than a second ago Running kata-cc-busybox-signed 0 70119e0539238
...
```
- Finally to check the image with a valid signature, but invalid GPG key (the real trusted piece of information we really
want to protect with the attestation agent in future) fails we can run:
```bash
$ export CONTAINER_CONFIG_FILE=container-config_signed-protected-other.yaml
$ ~/ccv0.sh crictl_create_cc_container
```
- Again this results in an error message from `crictl`:
`"PullImage from image service failed" err="rpc error: code = Internal desc = Security validate failed: Validate image failed: The signatures do not satisfied! Reject reason: [signature verify failed! There is no pubkey can verify the signature!]" image="quay.io/kata-containers/confidential-containers:other_signed"`
### Using Kubernetes to create a Kata confidential containers pod from the encrypted ssh demo sample image
The [ssh-demo](https://github.com/confidential-containers/documentation/tree/main/demos/ssh-demo) explains how to
demonstrate creating a Kata confidential containers pod from an encrypted image with the runtime created by the
[confidential-containers operator](https://github.com/confidential-containers/documentation/blob/main/demos/operator-demo).
To be fully confidential, this should be run on a Trusted Execution Environment, but it can be tested on generic
hardware as well.
If you wish to build the Kata confidential containers runtime to do this yourself, then you can using the following
steps:
- Run the full build process with the Kubernetes environment variable set to `"yes"`, so the Kubernetes cluster is
configured and created using the VM as a single node cluster and with `AA_KBC` set to `offline_fs_kbc`.
```bash
$ export KUBERNETES="yes"
$ export AA_KBC=offline_fs_kbc
$ ~/ccv0.sh build_and_install_all
```
- The `AA_KBC=offline_fs_kbc` mode will ensure that, when creating the rootfs of the Kata guest, the
[attestation-agent](https://github.com/confidential-containers/attestation-agent) will be added along with the
[sample offline KBC](https://github.com/confidential-containers/documentation/blob/main/demos/ssh-demo/aa-offline_fs_kbc-keys.json)
and an agent configuration file
> **Note**: Depending on how where your VMs are hosted and how IPs are shared you might get an error from docker
during matching `ERROR: toomanyrequests: Too Many Requests`. To get past
this, login into Docker Hub and pull the images used with:
> ```bash
> $ sudo docker login
> $ sudo docker pull registry:2
> $ sudo docker pull ubuntu:20.04
> ```
> then re-run the command.
- Check that your Kubernetes cluster has been correctly set-up by running :
```bash
$ kubectl get nodes
```
and checking that you see a single node e.g.
```text
NAME STATUS ROLES AGE VERSION
stevenh-ccv0-k8s1.fyre.ibm.com Ready control-plane,master 43s v1.22.0
```
- Create a sample Kata confidential containers ssh pod by running:
```bash
$ ~/ccv0.sh kubernetes_create_ssh_demo_pod
```
- As this point you should have a Kubernetes pod running the Kata confidential containers runtime that has pulled
the [sample image](https://hub.docker.com/r/katadocker/ccv0-ssh) which was encrypted by the key file that we included
in the rootfs.
During the pod deployment the image was pulled and then decrypted using the key file, on the Kata guest image, without
it ever being available to the host.
- To validate that the container is working you, can connect to the image via SSH by running:
```bash
$ ~/ccv0.sh connect_to_ssh_demo_pod
```
- During this connection the host key fingerprint is shown and should match:
`ED25519 key fingerprint is SHA256:wK7uOpqpYQczcgV00fGCh+X97sJL3f6G1Ku4rvlwtR0.`
- After you are finished connecting then run:
```bash
$ exit
```
- To delete the sample SSH demo pod run:
```bash
$ ~/ccv0.sh kubernetes_delete_ssh_demo_pod
```
## Additional script usage
As well as being able to use the script as above to build all of `kata-containers` from scratch it can be used to just
re-build bits of it by running the script with different parameters. For example after the first build you will often
not need to re-install the dependencies, the hypervisor or the Guest kernel, but just test code changes made to the
runtime and agent. This can be done by running `~/ccv0.sh rebuild_and_install_kata`. (*Note this does a hard checkout*
*from git, so if your changes are only made locally it is better to do the individual steps e.g.*
`~/ccv0.sh build_kata_runtime && ~/ccv0.sh build_and_add_agent_to_rootfs && ~/ccv0.sh build_and_install_rootfs`).
There are commands for a lot of steps in building, setting up and testing and the full list can be seen by running
`~/ccv0.sh help`:
```
$ ~/ccv0.sh help
Overview:
Build and test kata containers from source
Optionally set kata-containers and tests repo and branch as exported variables before running
e.g. export katacontainers_repo=github.com/stevenhorsman/kata-containers && export katacontainers_branch=kata-ci-from-fork && export tests_repo=github.com/stevenhorsman/tests && export tests_branch=kata-ci-from-fork && ~/ccv0.sh build_and_install_all
Usage:
ccv0.sh [options] <command>
Commands:
- help: Display this help
- all: Build and install everything, test kata with containerd and capture the logs
- build_and_install_all: Build and install everything
- initialize: Install dependencies and check out kata-containers source
- rebuild_and_install_kata: Rebuild the kata runtime and agent and build and install the image
- build_kata_runtime: Build and install the kata runtime
- configure: Configure Kata to use rootfs and enable debug
- create_rootfs: Create a local rootfs
- build_and_add_agent_to_rootfs:Builds the kata-agent and adds it to the rootfs
- build_and_install_rootfs: Builds and installs the rootfs image
- install_guest_kernel: Setup, build and install the guest kernel
- build_cloud_hypervisor Checkout, patch, build and install Cloud Hypervisor
- build_qemu: Checkout, patch, build and install QEMU
- init_kubernetes: initialize a Kubernetes cluster on this system
- crictl_create_cc_pod Use crictl to create a new kata cc pod
- crictl_create_cc_container Use crictl to create a new busybox container in the kata cc pod
- crictl_delete_cc Use crictl to delete the kata cc pod sandbox and container in it
- kubernetes_create_cc_pod: Create a Kata CC runtime busybox-based pod in Kubernetes
- kubernetes_delete_cc_pod: Delete the Kata CC runtime busybox-based pod in Kubernetes
- open_kata_shell: Open a shell into the kata runtime
- agent_pull_image: Run PullImage command against the agent with agent-ctl
- shim_pull_image: Run PullImage command against the shim with ctr
- agent_create_container: Run CreateContainer command against the agent with agent-ctl
- test: Test using kata with containerd
- test_capture_logs: Test using kata with containerd and capture the logs in the user's home directory
Options:
-d: Enable debug
-h: Display this help
```

View File

@@ -1,44 +0,0 @@
# Generating a Kata Containers payload for the Confidential Containers Operator
[Confidential Containers
Operator](https://github.com/confidential-containers/operator) consumes a Kata
Containers payload, generated from the `CCv0` branch, and here one can find all
the necessary info on how to build such a payload.
## Requirements
* `make` installed in the machine
* Docker installed in the machine
* `sudo` access to the machine
## Process
* Clone [Kata Containers](https://github.com/kata-containers/kata-containers)
```sh
git clone --branch CCv0 https://github.com/kata-containers/kata-containers
```
* In case you've already cloned the repo, make sure to switch to the `CCv0` branch
```sh
git checkout CCv0
```
* Ensure your tree is clean and in sync with upstream `CCv0`
```sh
git clean -xfd
git reset --hard <upstream>/CCv0
```
* Make sure you're authenticated to `quay.io`
```sh
sudo docker login quay.io
```
* From the top repo directory, run:
```sh
sudo make cc-payload
```
* Make sure the image was upload to the [Confidential Containers
runtime-payload
registry](https://quay.io/repository/confidential-containers/runtime-payload?tab=tags)
## Notes
Make sure to run it on a machine that's not the one you're hacking on, prepare a
cup of tea, and get back to it an hour later (at least).

View File

@@ -1,159 +0,0 @@
# Kata Containers with AMD SEV-SNP VMs
## Disclaimer
This guide is designed for developers and is - same as the Developer Guide - not intended for production systems or end users. It is advisable to only follow this guide on non-critical development systems.
## Prerequisites
To run Kata Containers in SNP-VMs, the following software stack is used.
![Kubernetes integration with shimv2](./images/SNP-stack.svg)
The host BIOS and kernel must be capable of supporting AMD SEV-SNP and configured accordingly. For Kata Containers, the host kernel with branch [`sev-snp-iommu-avic_5.19-rc6_v3`](https://github.com/AMDESE/linux/tree/sev-snp-iommu-avic_5.19-rc6_v3) and commit [`3a88547`](https://github.com/AMDESE/linux/commit/3a885471cf89156ea555341f3b737ad2a8d9d3d0) is known to work in conjunction with SEV Firmware version 1.51.3 (0xh\_1.33.03) available on AMD's [SEV developer website](https://developer.amd.com/sev/). See [AMD's guide](https://github.com/AMDESE/AMDSEV/tree/sev-snp-devel) to configure the host accordingly. Verify that you are able to run SEV-SNP encrypted VMs first. The guest components required for Kata Containers are built as described below.
**Tip**: It is easiest to first have Kata Containers running on your system and then modify it to run containers in SNP-VMs. Follow the [Developer guide](../Developer-Guide.md#warning) and then follow the below steps. Nonetheless, you can just follow this guide from the start.
## How to build
Follow all of the below steps to install Kata Containers with SNP-support from scratch. These steps mostly follow the developer guide with modifications to support SNP
__Steps from the Developer Guide:__
- Get all the [required components](../Developer-Guide.md#requirements-to-build-individual-components) for building the kata-runtime
- [Build the and install kata-runtime](../Developer-Guide.md#build-and-install-the-kata-containers-runtime)
- [Build a custom agent](../Developer-Guide.md#build-a-custom-kata-agent---optional)
- [Create an initrd image](../Developer-Guide.md#create-an-initrd-image---optional) by first building a rootfs, then building the initrd based on the rootfs, use a custom agent and install. `ubuntu` works as the distribution of choice.
- Get the [required components](../../tools/packaging/kernel/README.md#requirements) to build a custom kernel
__SNP-specific steps:__
- Build the SNP-specific kernel as shown below (see this [guide](../../tools/packaging/kernel/README.md#build-kata-containers-kernel) for more information)
```bash
$ pushd kata-containers/tools/packaging/kernel/
$ ./build-kernel.sh -a x86_64 -x snp setup
$ ./build-kernel.sh -a x86_64 -x snp build
$ sudo -E PATH="${PATH}" ./build-kernel.sh -x snp install
$ popd
```
- Build a current OVMF capable of SEV-SNP:
```bash
$ pushd kata-containers/tools/packaging/static-build/ovmf
$ ./build.sh
$ tar -xvf edk2-x86_64.tar.gz
$ popd
```
- Build a custom QEMU
```bash
$ source kata-containers/tools/packaging/scripts/lib.sh
$ qemu_url="$(get_from_kata_deps "assets.hypervisor.qemu.snp.url")"
$ qemu_branch="$(get_from_kata_deps "assets.hypervisor.qemu.snp.branch")"
$ qemu_commit="$(get_from_kata_deps "assets.hypervisor.qemu.snp.commit")"
$ git clone -b "${qemu_branch}" "${qemu_url}"
$ pushd qemu
$ git checkout "${qemu_commit}"
$ ./configure --enable-virtfs --target-list=x86_64-softmmu --enable-debug
$ make -j "$(nproc)"
$ popd
```
### Kata Containers Configuration for SNP
The configuration file located at `/etc/kata-containers/configuration.toml` must be adapted as follows to support SNP-VMs:
- Use the SNP-specific kernel for the guest VM (change path)
```toml
kernel = "/usr/share/kata-containers/vmlinuz-snp.container"
```
- Enable the use of an initrd (uncomment)
```toml
initrd = "/usr/share/kata-containers/kata-containers-initrd.img"
```
- Disable the use of a rootfs (comment out)
```toml
# image = "/usr/share/kata-containers/kata-containers.img"
```
- Use the custom QEMU capable of SNP (change path)
```toml
path = "/path/to/qemu/build/qemu-system-x86_64"
```
- Use `virtio-9p` device since `virtio-fs` is unsupported due to bugs / shortcomings in QEMU version [`snp-v3`](https://github.com/AMDESE/qemu/tree/snp-v3) for SEV and SEV-SNP (change value)
```toml
shared_fs = "virtio-9p"
```
- Disable `virtiofsd` since it is no longer required (comment out)
```toml
# virtio_fs_daemon = "/usr/libexec/virtiofsd"
```
- Disable NVDIMM (uncomment)
```toml
disable_image_nvdimm = true
```
- Disable shared memory (uncomment)
```toml
file_mem_backend = ""
```
- Enable confidential guests (uncomment)
```toml
confidential_guest = true
```
- Enable SNP-VMs (uncomment)
```toml
sev_snp_guest = true
```
- Configure an OVMF (add path)
```toml
firmware = "/path/to/kata-containers/tools/packaging/static-build/ovmf/opt/kata/share/ovmf/OVMF.fd"
```
## Test Kata Containers with Containerd
With Kata Containers configured to support SNP-VMs, we use containerd to test and deploy containers in these VMs.
### Install Containerd
If not already present, follow [this guide](./containerd-kata.md#install) to install containerd and its related components including `CNI` and the `cri-tools` (skip Kata Containers since we already installed it)
### Containerd Configuration
Follow [this guide](./containerd-kata.md#configuration) to configure containerd to use Kata Containers
## Run Kata Containers in SNP-VMs
Run the below commands to start a container. See [this guide](./containerd-kata.md#run) for more information
```bash
$ sudo ctr image pull docker.io/library/busybox:latest
$ sudo ctr run --cni --runtime io.containerd.run.kata.v2 -t --rm docker.io/library/busybox:latest hello sh
```
### Check for active SNP:
Inside the running container, run the following commands to check if SNP is active. It should look something like this:
```
/ # dmesg | grep -i sev
[ 0.299242] Memory Encryption Features active: AMD SEV SEV-ES SEV-SNP
[ 0.472286] SEV: Using SNP CPUID table, 31 entries present.
[ 0.514574] SEV: SNP guest platform device initialized.
[ 0.885425] sev-guest sev-guest: Initialized SEV guest driver (using vmpck_id 0)
```
### Obtain an SNP Attestation Report
To obtain an attestation report inside the container, the `/dev/sev-guest` must first be configured. As of now, the VM does not perform this step, however it can be performed inside the container, either in the terminal or in code.
Example for shell:
```
/ # SNP_MAJOR=$(cat /sys/devices/virtual/misc/sev-guest/dev | awk -F: '{print $1}')
/ # SNP_MINOR=$(cat /sys/devices/virtual/misc/sev-guest/dev | awk -F: '{print $2}')
/ # mknod -m 600 /dev/sev-guest c "${SNP_MAJOR}" "${SNP_MINOR}"
```
## Known Issues
- Support for cgroups v2 is still [work in progress](https://github.com/kata-containers/kata-containers/issues/927). If issues occur due to cgroups v2 becoming the default in newer systems, one possible solution is to downgrade cgroups to v1:
```bash
sudo sed -i 's/^\(GRUB_CMDLINE_LINUX=".*\)"/\1 systemd.unified_cgroup_hierarchy=0"/' /etc/default/grub
sudo update-grub
sudo reboot
```
- If both SEV and SEV-SNP are supported by the host, Kata Containers uses SEV-SNP by default. You can verify what features are enabled by checking `/sys/module/kvm_amd/parameters/sev` and `sev_snp`. This means that Kata Containers can not run both SEV-SNP-VMs and SEV-VMs at the same time. If SEV is to be used by Kata Containers instead, reload the `kvm_amd` kernel module without SNP-support, this will disable SNP-support for the entire platform.
```bash
sudo rmmod kvm_amd && sudo modprobe kvm_amd sev_snp=0
```

View File

@@ -19,7 +19,7 @@ Also you should ensure that `kubectl` working correctly.
> **Note**: More information about Kubernetes integrations:
> - [Run Kata Containers with Kubernetes](run-kata-with-k8s.md)
> - [How to use Kata Containers and Containerd](containerd-kata.md)
> - [How to use Kata Containers and containerd with Kubernetes](how-to-use-k8s-with-containerd-and-kata.md)
> - [How to use Kata Containers and CRI (containerd plugin) with Kubernetes](how-to-use-k8s-with-cri-containerd-and-kata.md)
## Configure Prometheus

View File

@@ -27,8 +27,6 @@ $ image="quay.io/prometheus/busybox:latest"
$ cat << EOF > "${pod_yaml}"
metadata:
name: busybox-sandbox1
uid: $(uuidgen)
namespace: default
EOF
$ cat << EOF > "${container_yaml}"
metadata:

View File

@@ -1,15 +1,15 @@
# How to use Kata Containers and containerd with Kubernetes
# How to use Kata Containers and CRI (containerd plugin) with Kubernetes
This document describes how to set up a single-machine Kubernetes (k8s) cluster.
The Kubernetes cluster will use the
[containerd](https://github.com/containerd/containerd/) and
[Kata Containers](https://katacontainers.io) to launch workloads.
[CRI containerd](https://github.com/containerd/containerd/) and
[Kata Containers](https://katacontainers.io) to launch untrusted workloads.
## Requirements
- Kubernetes, Kubelet, `kubeadm`
- containerd
- containerd with `cri` plug-in
- Kata Containers
> **Note:** For information about the supported versions of these components,
@@ -149,7 +149,7 @@ $ sudo -E kubectl taint nodes --all node-role.kubernetes.io/master-
## Create runtime class for Kata Containers
By default, all pods are created with the default runtime configured in containerd.
By default, all pods are created with the default runtime configured in CRI containerd plugin.
From Kubernetes v1.12, users can use [`RuntimeClass`](https://kubernetes.io/docs/concepts/containers/runtime-class/#runtime-class) to specify a different runtime for Pods.
```bash
@@ -166,7 +166,7 @@ $ sudo -E kubectl apply -f runtime.yaml
## Run pod in Kata Containers
If a pod has the `runtimeClassName` set to `kata`, the CRI runs the pod with the
If a pod has the `runtimeClassName` set to `kata`, the CRI plugin runs the pod with the
[Kata Containers runtime](../../src/runtime/README.md).
- Create an pod configuration that using Kata Containers runtime

View File

@@ -32,7 +32,6 @@ The `nydus-sandbox.yaml` looks like below:
metadata:
attempt: 1
name: nydus-sandbox
uid: nydus-uid
namespace: default
log_directory: /tmp
linux:

View File

@@ -42,8 +42,6 @@ $ image="quay.io/prometheus/busybox:latest"
$ cat << EOF > "${pod_yaml}"
metadata:
name: busybox-sandbox1
uid: $(uuidgen)
namespace: default
EOF
$ cat << EOF > "${container_yaml}"
metadata:

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -40,7 +40,7 @@ See below example config:
ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration.toml"
```
- [How to use Kata Containers and containerd with Kubernetes](how-to-use-k8s-with-containerd-and-kata.md)
- [Kata Containers with Containerd and CRI documentation](how-to-use-k8s-with-cri-containerd-and-kata.md)
- [Containerd CRI config documentation](https://github.com/containerd/containerd/blob/main/docs/cri/config.md)
#### CRI-O

View File

@@ -15,7 +15,7 @@ After choosing one CRI implementation, you must make the appropriate configurati
to ensure it integrates with Kata Containers.
Kata Containers 1.5 introduced the `shimv2` for containerd 1.2.0, reducing the components
required to spawn pods and containers, and this is the preferred way to run Kata Containers with Kubernetes ([as documented here](../how-to/how-to-use-k8s-with-containerd-and-kata.md#configure-containerd-to-use-kata-containers)).
required to spawn pods and containers, and this is the preferred way to run Kata Containers with Kubernetes ([as documented here](../how-to/how-to-use-k8s-with-cri-containerd-and-kata.md#configure-containerd-to-use-kata-containers)).
An equivalent shim implementation for CRI-O is planned.
@@ -57,7 +57,7 @@ content shown below:
To customize containerd to select Kata Containers runtime, follow our
"Configure containerd to use Kata Containers" internal documentation
[here](../how-to/how-to-use-k8s-with-containerd-and-kata.md#configure-containerd-to-use-kata-containers).
[here](../how-to/how-to-use-k8s-with-cri-containerd-and-kata.md#configure-containerd-to-use-kata-containers).
## Install Kubernetes
@@ -85,7 +85,7 @@ Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --runtime-request-tim
Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
```
For more information about containerd see the "Configure Kubelet to use containerd"
documentation [here](../how-to/how-to-use-k8s-with-containerd-and-kata.md#configure-kubelet-to-use-containerd).
documentation [here](../how-to/how-to-use-k8s-with-cri-containerd-and-kata.md#configure-kubelet-to-use-containerd).
## Run a Kubernetes pod with Kata Containers

View File

@@ -33,7 +33,6 @@ are available, their default values and how each setting can be used.
[Cloud Hypervisor] | rust | `aarch64`, `x86_64` | Type 2 ([KVM]) | `configuration-clh.toml` |
[Firecracker] | rust | `aarch64`, `x86_64` | Type 2 ([KVM]) | `configuration-fc.toml` |
[QEMU] | C | all | Type 2 ([KVM]) | `configuration-qemu.toml` |
[`Dragonball`] | rust | `aarch64`, `x86_64` | Type 2 ([KVM]) | `configuration-dragonball.toml` |
## Determine currently configured hypervisor
@@ -53,7 +52,6 @@ the hypervisors:
[Cloud Hypervisor] | Low latency, small memory footprint, small attack surface | Minimal | | excellent | excellent | High performance modern cloud workloads | |
[Firecracker] | Very slimline | Extremely minimal | Doesn't support all device types | excellent | excellent | Serverless / FaaS | |
[QEMU] | Lots of features | Lots | | good | good | Good option for most users | | All users |
[`Dragonball`] | Built-in VMM, low CPU and memory overhead| Minimal | | excellent | excellent | Optimized for most container workloads | `out-of-the-box` Kata Containers experience |
For further details, see the [Virtualization in Kata Containers](design/virtualization.md) document and the official documentation for each hypervisor.
@@ -62,4 +60,3 @@ For further details, see the [Virtualization in Kata Containers](design/virtuali
[Firecracker]: https://github.com/firecracker-microvm/firecracker
[KVM]: https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine
[QEMU]: http://www.qemu-project.org
[`Dragonball`]: https://github.com/openanolis/dragonball-sandbox

View File

@@ -79,6 +79,3 @@ versions. This is not recommended for normal users.
* [upgrading document](../Upgrading.md)
* [developer guide](../Developer-Guide.md)
* [runtime documentation](../../src/runtime/README.md)
## Kata Containers 3.0 rust runtime installation
* [installation guide](../install/kata-containers-3.0-rust-runtime-installation-guide.md)

View File

@@ -19,6 +19,12 @@
> - If you decide to proceed and install a Kata Containers release, you can
> still check for the latest version of Kata Containers by running
> `kata-runtime check --only-list-releases`.
>
> - These instructions will not work for Fedora 31 and higher since those
> distribution versions only support cgroups version 2 by default. However,
> Kata Containers currently requires cgroups version 1 (on the host side). See
> https://github.com/kata-containers/kata-containers/issues/927 for further
> details.
## Install Kata Containers

View File

@@ -1,102 +0,0 @@
# Kata Containers 3.0 rust runtime installation
The following is an overview of the different installation methods available.
## Prerequisites
Kata Containers 3.0 rust runtime requires nested virtualization or bare metal. Check
[hardware requirements](/src/runtime/README.md#hardware-requirements) to see if your system is capable of running Kata
Containers.
### Platform support
Kata Containers 3.0 rust runtime currently runs on 64-bit systems supporting the following
architectures:
> **Notes:**
> For other architectures, see https://github.com/kata-containers/kata-containers/issues/4320
| Architecture | Virtualization technology |
|-|-|
| `x86_64`| [Intel](https://www.intel.com) VT-x |
| `aarch64` ("`arm64`")| [ARM](https://www.arm.com) Hyp |
## Packaged installation methods
| Installation method | Description | Automatic updates | Use case | Availability
|------------------------------------------------------|----------------------------------------------------------------------------------------------|-------------------|-----------------------------------------------------------------------------------------------|----------- |
| [Using kata-deploy](#kata-deploy-installation) | The preferred way to deploy the Kata Containers distributed binaries on a Kubernetes cluster | **No!** | Best way to give it a try on kata-containers on an already up and running Kubernetes cluster. | Yes |
| [Using official distro packages](#official-packages) | Kata packages provided by Linux distributions official repositories | yes | Recommended for most users. | No |
| [Using snap](#snap-installation) | Easy to install | yes | Good alternative to official distro packages. | No |
| [Automatic](#automatic-installation) | Run a single command to install a full system | **No!** | For those wanting the latest release quickly. | No |
| [Manual](#manual-installation) | Follow a guide step-by-step to install a working system | **No!** | For those who want the latest release with more control. | No |
| [Build from source](#build-from-source-installation) | Build the software components manually | **No!** | Power users and developers only. | Yes |
### Kata Deploy Installation
Follow the [`kata-deploy`](../../tools/packaging/kata-deploy/README.md).
### Official packages
`ToDo`
### Snap Installation
`ToDo`
### Automatic Installation
`ToDo`
### Manual Installation
`ToDo`
## Build from source installation
### Rust Environment Set Up
* Download `Rustup` and install `Rust`
> **Notes:**
> Rust version 1.58 is needed
Example for `x86_64`
```
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env
$ rustup install 1.58
$ rustup default 1.58-x86_64-unknown-linux-gnu
```
* Musl support for fully static binary
Example for `x86_64`
```
$ rustup target add x86_64-unknown-linux-musl
```
* [Musl `libc`](http://musl.libc.org/) install
Example for musl 1.2.3
```
$ curl -O https://git.musl-libc.org/cgit/musl/snapshot/musl-1.2.3.tar.gz
$ tar vxf musl-1.2.3.tar.gz
$ cd musl-1.2.3/
$ ./configure --prefix=/usr/local/
$ make && sudo make install
```
### Install Kata 3.0 Rust Runtime Shim
```
$ git clone https://github.com/kata-containers/kata-containers.git
$ cd kata-containers/src/runtime-rs
$ make && sudo make install
```
After running the command above, the default config file `configuration.toml` will be installed under `/usr/share/defaults/kata-containers/`, the binary file `containerd-shim-kata-v2` will be installed under `/usr/local/bin/` .
### Build Kata Containers Kernel
Follow the [Kernel installation guide](/tools/packaging/kernel/README.md).
### Build Kata Rootfs
Follow the [Rootfs installation guide](../../tools/osbuilder/rootfs-builder/README.md).
### Build Kata Image
Follow the [Image installation guide](../../tools/osbuilder/image-builder/README.md).
### Install Containerd
Follow the [Containerd installation guide](container-manager/containerd/containerd-install.md).

View File

@@ -55,11 +55,11 @@ Here are the features to set up a CRI-O based Minikube, and why you need them:
| what | why |
| ---- | --- |
| `--bootstrapper=kubeadm` | As recommended for [minikube CRI-O](https://minikube.sigs.k8s.io/docs/handbook/config/#runtime-configuration) |
| `--bootstrapper=kubeadm` | As recommended for [minikube CRI-o](https://kubernetes.io/docs/setup/minikube/#cri-o) |
| `--container-runtime=cri-o` | Using CRI-O for Kata |
| `--enable-default-cni` | As recommended for [minikube CRI-O](https://minikube.sigs.k8s.io/docs/handbook/config/#runtime-configuration) |
| `--enable-default-cni` | As recommended for [minikube CRI-o](https://kubernetes.io/docs/setup/minikube/#cri-o) |
| `--memory 6144` | Allocate sufficient memory, as Kata Containers default to 1 or 2Gb |
| `--network-plugin=cni` | As recommended for [minikube CRI-O](https://minikube.sigs.k8s.io/docs/handbook/config/#runtime-configuration) |
| `--network-plugin=cni` | As recommended for [minikube CRI-o](https://kubernetes.io/docs/setup/minikube/#cri-o) |
| `--vm-driver kvm2` | The host VM driver |
To use containerd, modify the `--container-runtime` argument:

View File

@@ -279,8 +279,8 @@ $ export KERNEL_EXTRAVERSION=$(awk '/^EXTRAVERSION =/{print $NF}' $GOPATH/$LINUX
$ export KERNEL_ROOTFS_DIR=${KERNEL_MAJOR_VERSION}.${KERNEL_PATHLEVEL}.${KERNEL_SUBLEVEL}${KERNEL_EXTRAVERSION}
$ cd $QAT_SRC
$ KERNEL_SOURCE_ROOT=$GOPATH/$LINUX_VER ./configure --enable-icp-sriov=guest
$ sudo -E make all -j $($(nproc ${CI:+--ignore 1}))
$ sudo -E make INSTALL_MOD_PATH=$ROOTFS_DIR qat-driver-install -j $($(nproc ${CI:+--ignore 1}))
$ sudo -E make all -j$(nproc)
$ sudo -E make INSTALL_MOD_PATH=$ROOTFS_DIR qat-driver-install -j$(nproc)
```
The `usdm_drv` module also needs to be copied into the rootfs modules path and

View File

@@ -18,13 +18,16 @@ CONFIG_X86_SGX_KVM=y
* Kubernetes cluster configured with:
* [`kata-deploy`](../../tools/packaging/kata-deploy) based Kata Containers installation
* [Intel SGX Kubernetes device plugin](https://github.com/intel/intel-device-plugins-for-kubernetes/tree/main/cmd/sgx_plugin#deploying-with-pre-built-images) and associated components including [operator](https://github.com/intel/intel-device-plugins-for-kubernetes/blob/main/cmd/operator/README.md) and dependencies
* [Intel SGX Kubernetes device plugin](https://github.com/intel/intel-device-plugins-for-kubernetes/tree/main/cmd/sgx_plugin#deploying-with-pre-built-images)
> Note: Kata Containers supports creating VM sandboxes with Intel® SGX enabled
> using [cloud-hypervisor](https://github.com/cloud-hypervisor/cloud-hypervisor/) and [QEMU](https://www.qemu.org/) VMMs only.
### Kata Containers Configuration
Before running a Kata Container make sure that your version of `crio` or `containerd`
supports annotations.
For `containerd` check in `/etc/containerd/config.toml` that the list of `pod_annotations` passed
to the `sandbox` are: `["io.katacontainers.*", "sgx.intel.com/epc"]`.
@@ -61,9 +64,6 @@ spec:
name: eosgx-demo-job-1
image: oeciteam/oe-helloworld:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /dev
name: dev-mount
securityContext:
readOnlyRootFilesystem: true
capabilities:
@@ -99,4 +99,4 @@ because socket passthrough is not supported. An alternative is to deploy the `ae
container.
* Projects like [Gramine Shielded Containers (GSC)](https://gramine-gsc.readthedocs.io/en/latest/) are
also known to work. For GSC specifically, the Kata guest kernel needs to have the `CONFIG_NUMA=y`
enabled and at least one CPU online when running the GSC container. The Kata Containers guest kernel currently has `CONFIG_NUMA=y` enabled by default.
enabled and at least one CPU online when running the GSC container.

View File

@@ -82,39 +82,8 @@ parts:
fi
rustup component add rustfmt
docker:
after: [metadata]
plugin: nil
prime:
- -*
build-packages:
- ca-certificates
- containerd
- curl
- gnupg
- lsb-release
- runc
override-build: |
source "${SNAPCRAFT_PROJECT_DIR}/snap/local/snap-common.sh"
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |\
sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
distro_codename=$(lsb_release -cs)
echo "deb [arch=${dpkg_arch} signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu ${distro_codename} stable" |\
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get -y update
sudo apt-get -y install docker-ce docker-ce-cli containerd.io
echo "Unmasking docker service"
sudo -E systemctl unmask docker.service || true
sudo -E systemctl unmask docker.socket || true
echo "Adding $USER into docker group"
sudo -E gpasswd -a $USER docker
echo "Starting docker"
sudo -E systemctl start docker || true
image:
after: [godeps, docker, qemu, kernel]
after: [godeps, qemu, kernel]
plugin: nil
build-packages:
- docker.io
@@ -138,6 +107,14 @@ parts:
# Copy yq binary. It's used in the container
cp -a "${yq}" "${GOPATH}/bin/"
echo "Unmasking docker service"
sudo -E systemctl unmask docker.service || true
sudo -E systemctl unmask docker.socket || true
echo "Adding $USER into docker group"
sudo -E gpasswd -a $USER docker
echo "Starting docker"
sudo -E systemctl start docker || true
cd "${kata_dir}/tools/osbuilder"
# build image
@@ -216,7 +193,7 @@ parts:
# Setup and build kernel
./build-kernel.sh -v "${kernel_version}" -d setup
cd ${kernel_dir_prefix}*
make -j $(nproc ${CI:+--ignore 1}) EXTRAVERSION=".container"
make -j $(($(nproc)-1)) EXTRAVERSION=".container"
kernel_suffix="${kernel_version}.container"
kata_kernel_dir="${SNAPCRAFT_PART_INSTALL}/usr/share/kata-containers"
@@ -229,7 +206,7 @@ parts:
# Install raw kernel
vmlinux_path="vmlinux"
[ "${arch}" = "s390x" ] && vmlinux_path="arch/s390/boot/vmlinux"
[ "${arch}" = "s390x" ] && vmlinux_path="arch/s390/boot/compressed/vmlinux"
vmlinux_name="vmlinux-${kernel_suffix}"
cp "${vmlinux_path}" "${kata_kernel_dir}/${vmlinux_name}"
ln -sf "${vmlinux_name}" "${kata_kernel_dir}/vmlinux.container"
@@ -305,7 +282,7 @@ parts:
esac
# build and install
make -j $(nproc ${CI:+--ignore 1})
make -j $(($(nproc)-1))
make install DESTDIR="${SNAPCRAFT_PART_INSTALL}"
prime:
- -snap/
@@ -324,31 +301,54 @@ parts:
virtiofsd:
plugin: nil
after: [godeps, rustdeps, docker]
after: [godeps, rustdeps]
override-build: |
source "${SNAPCRAFT_PROJECT_DIR}/snap/local/snap-common.sh"
echo "INFO: Building rust version of virtiofsd"
# Currently, powerpc makes use of the QEMU's C implementation.
# The other platforms make use of the new rust virtiofsd.
#
# See "tools/packaging/scripts/configure-hypervisor.sh".
if [ "${arch}" == "ppc64le" ]
then
echo "INFO: Building QEMU's C version of virtiofsd"
# Handled by the 'qemu' part, so nothing more to do here.
exit 0
else
echo "INFO: Building rust version of virtiofsd"
fi
cd "${SNAPCRAFT_PROJECT_DIR}"
# Clean-up build dir in case it already exists
sudo -E NO_TTY=true make virtiofsd-tarball
cd "${kata_dir}"
export PATH=${PATH}:${HOME}/.cargo/bin
# Download the rust implementation of virtiofsd
tools/packaging/static-build/virtiofsd/build-static-virtiofsd.sh
sudo install \
--owner='root' \
--group='root' \
--mode=0755 \
-D \
--target-directory="${SNAPCRAFT_PART_INSTALL}/usr/libexec/" \
build/virtiofsd/builddir/virtiofsd/virtiofsd
virtiofsd/virtiofsd
cloud-hypervisor:
plugin: nil
after: [godeps, docker]
after: [godeps]
override-build: |
source "${SNAPCRAFT_PROJECT_DIR}/snap/local/snap-common.sh"
if [ "${arch}" == "aarch64" ] || [ "${arch}" == "x86_64" ]; then
sudo apt-get -y update
sudo apt-get -y install ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg |\
sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
distro_codename=$(lsb_release -cs)
echo "deb [arch=${dpkg_arch} signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu ${distro_codename} stable" |\
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get -y update
sudo apt-get -y install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker.socket
cd "${SNAPCRAFT_PROJECT_DIR}"
sudo -E NO_TTY=true make cloud-hypervisor-tarball

4016
src/agent/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,17 +3,16 @@ name = "kata-agent"
version = "0.1.0"
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
edition = "2018"
license = "Apache-2.0"
[dependencies]
oci = { path = "../libs/oci" }
rustjail = { path = "rustjail" }
protocols = { path = "../libs/protocols", features = ["async"] }
protocols = { path = "../libs/protocols" }
lazy_static = "1.3.0"
ttrpc = { version = "0.6.0", features = ["async"], default-features = false }
protobuf = "2.27.0"
ttrpc = { version = "0.5.0", features = ["async", "protobuf-codec"], default-features = false }
protobuf = "=2.14.0"
libc = "0.2.58"
nix = "0.24.2"
nix = "0.23"
capctl = "0.2.0"
serde_json = "1.0.39"
scan_fmt = "0.2.3"
@@ -21,10 +20,7 @@ scopeguard = "1.0.0"
thiserror = "1.0.26"
regex = "1.5.6"
serial_test = "0.5.1"
kata-sys-util = { path = "../libs/kata-sys-util" }
kata-types = { path = "../libs/kata-types" }
sysinfo = "0.23.0"
url = "2.2.2"
# Async helpers
async-trait = "0.1.42"
@@ -32,7 +28,7 @@ async-recursion = "0.3.2"
futures = "0.3.17"
# Async runtime
tokio = { version = "1.21.2", features = ["full"] }
tokio = { version = "1.14.0", features = ["full"] }
tokio-vsock = "0.3.1"
netlink-sys = { version = "0.7.0", features = ["tokio_socket",]}
@@ -53,7 +49,7 @@ log = "0.4.11"
prometheus = { version = "0.13.0", features = ["process"] }
procfs = "0.12.0"
anyhow = "1.0.32"
cgroups = { package = "cgroups-rs", version = "0.2.10" }
cgroups = { package = "cgroups-rs", version = "0.2.8" }
# Tracing
tracing = "0.1.26"
@@ -67,14 +63,8 @@ serde = { version = "1.0.129", features = ["derive"] }
toml = "0.5.8"
clap = { version = "3.0.1", features = ["derive"] }
# Image pull/decrypt
image-rs = { git = "https://github.com/confidential-containers/image-rs", tag = "v0.2.0" }
# "vendored" feature for openssl is required by musl build
openssl = { version = "0.10.38", features = ["vendored"] }
[dev-dependencies]
tempfile = "3.1.0"
test-utils = { path = "../libs/test-utils" }
[workspace]
members = [

View File

@@ -85,14 +85,6 @@ ifeq ($(INIT),no)
UNIT_FILES += kata-containers.target
endif
# The following will be reverted, after
# https://github.com/kata-containers/kata-containers/issues/5582
# is resolved.
IMAGE_RS_COMMIT = a1d7ba31201d9d7a575d05c5fed1f2cb2142a842
ifeq ($(ARCH),s390x)
$(shell sed -i -e "s/^\(image-rs.*\)tag\(.*\)/\1rev\2/" -e "s/^\(image-rs.*rev = \"\).*\(\".*\)/\1$(IMAGE_RS_COMMIT)\2/" Cargo.toml)
endif
# Display name of command and it's version (or a message if not available).
#
# Arguments:
@@ -115,7 +107,10 @@ endef
##TARGET default: build code
default: $(TARGET) show-header
$(TARGET): $(GENERATED_CODE) $(TARGET_PATH)
$(TARGET): $(GENERATED_CODE) logging-crate-tests $(TARGET_PATH)
logging-crate-tests:
make -C $(CWD)/../libs/logging
$(TARGET_PATH): show-summary
@RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo build --target $(TRIPLE) $(if $(findstring release,$(BUILD_TYPE)),--release) $(EXTRA_RUSTFEATURES)
@@ -208,6 +203,7 @@ codecov-html: check_tarpaulin
.PHONY: \
help \
logging-crate-tests \
optimize \
show-header \
show-summary \

View File

@@ -3,7 +3,6 @@ name = "rustjail"
version = "0.1.0"
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
edition = "2018"
license = "Apache-2.0"
[dependencies]
serde = "1.0.91"
@@ -12,32 +11,31 @@ serde_derive = "1.0.91"
oci = { path = "../../libs/oci" }
protocols = { path ="../../libs/protocols" }
caps = "0.5.0"
nix = "0.24.2"
nix = "0.23.0"
scopeguard = "1.0.0"
capctl = "0.2.0"
lazy_static = "1.3.0"
libc = "0.2.58"
protobuf = "2.27.0"
protobuf = "=2.14.0"
slog = "2.5.2"
slog-scope = "4.1.2"
scan_fmt = "0.2.6"
regex = "1.5.6"
path-absolutize = "1.2.0"
anyhow = "1.0.32"
cgroups = { package = "cgroups-rs", version = "0.2.10" }
cgroups = { package = "cgroups-rs", version = "0.2.8" }
rlimit = "0.5.3"
cfg-if = "0.1.0"
tokio = { version = "1.2.0", features = ["sync", "io-util", "process", "time", "macros", "rt"] }
tokio = { version = "1.2.0", features = ["sync", "io-util", "process", "time", "macros"] }
futures = "0.3.17"
async-trait = "0.1.31"
inotify = "0.9.2"
libseccomp = { version = "0.3.0", optional = true }
libseccomp = { version = "0.2.3", optional = true }
[dev-dependencies]
serial_test = "0.5.0"
tempfile = "3.1.0"
test-utils = { path = "../../libs/test-utils" }
[features]
seccomp = ["libseccomp"]

View File

@@ -174,7 +174,7 @@ impl CgroupManager for Manager {
freezer_controller.freeze()?;
}
_ => {
return Err(anyhow!("Invalid FreezerState"));
return Err(anyhow!(nix::Error::EINVAL));
}
}
@@ -252,28 +252,19 @@ fn set_devices_resources(
}
fn set_hugepages_resources(
cg: &cgroups::Cgroup,
_cg: &cgroups::Cgroup,
hugepage_limits: &[LinuxHugepageLimit],
res: &mut cgroups::Resources,
) {
info!(sl!(), "cgroup manager set hugepage");
let mut limits = vec![];
let hugetlb_controller = cg.controller_of::<HugeTlbController>();
for l in hugepage_limits.iter() {
if hugetlb_controller.is_some() && hugetlb_controller.unwrap().size_supported(&l.page_size)
{
let hr = HugePageResource {
size: l.page_size.clone(),
limit: l.limit,
};
limits.push(hr);
} else {
warn!(
sl!(),
"{} page size support cannot be verified, dropping requested limit", l.page_size
);
}
let hr = HugePageResource {
size: l.page_size.clone(),
limit: l.limit,
};
limits.push(hr);
}
res.hugepages.limits = limits;
}
@@ -467,11 +458,8 @@ fn linux_device_to_cgroup_device(d: &LinuxDevice) -> Option<DeviceResource> {
}
fn linux_device_group_to_cgroup_device(d: &LinuxDeviceCgroup) -> Option<DeviceResource> {
let dev_type = match &d.r#type {
Some(t_s) => match DeviceType::from_char(t_s.chars().next()) {
Some(t_c) => t_c,
None => return None,
},
let dev_type = match DeviceType::from_char(d.r#type.chars().next()) {
Some(t) => t,
None => return None,
};
@@ -528,7 +516,7 @@ lazy_static! {
// all mknod to all char devices
LinuxDeviceCgroup {
allow: true,
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(WILDCARD),
minor: Some(WILDCARD),
access: "m".to_string(),
@@ -537,7 +525,7 @@ lazy_static! {
// all mknod to all block devices
LinuxDeviceCgroup {
allow: true,
r#type: Some("b".to_string()),
r#type: "b".to_string(),
major: Some(WILDCARD),
minor: Some(WILDCARD),
access: "m".to_string(),
@@ -546,7 +534,7 @@ lazy_static! {
// all read/write/mknod to char device /dev/console
LinuxDeviceCgroup {
allow: true,
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(5),
minor: Some(1),
access: "rwm".to_string(),
@@ -555,7 +543,7 @@ lazy_static! {
// all read/write/mknod to char device /dev/pts/<N>
LinuxDeviceCgroup {
allow: true,
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(136),
minor: Some(WILDCARD),
access: "rwm".to_string(),
@@ -564,7 +552,7 @@ lazy_static! {
// all read/write/mknod to char device /dev/ptmx
LinuxDeviceCgroup {
allow: true,
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(5),
minor: Some(2),
access: "rwm".to_string(),
@@ -573,7 +561,7 @@ lazy_static! {
// all read/write/mknod to char device /dev/net/tun
LinuxDeviceCgroup {
allow: true,
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(10),
minor: Some(200),
access: "rwm".to_string(),
@@ -923,8 +911,9 @@ pub fn get_paths() -> Result<HashMap<String, String>> {
Ok(m)
}
pub fn get_mounts(paths: &HashMap<String, String>) -> Result<HashMap<String, String>> {
pub fn get_mounts() -> Result<HashMap<String, String>> {
let mut m = HashMap::new();
let paths = get_paths()?;
for l in fs::read_to_string(MOUNTS)?.lines() {
let p: Vec<&str> = l.splitn(2, " - ").collect();
@@ -962,7 +951,7 @@ impl Manager {
let mut m = HashMap::new();
let paths = get_paths()?;
let mounts = get_mounts(&paths)?;
let mounts = get_mounts()?;
for key in paths.keys() {
let mnt = mounts.get(key);

View File

@@ -6,9 +6,8 @@
use anyhow::{anyhow, Result};
use nix::errno::Errno;
use nix::pty;
use nix::sys::socket;
use nix::sys::{socket, uio};
use nix::unistd::{self, dup2};
use std::io::IoSlice;
use std::os::unix::io::{AsRawFd, RawFd};
use std::path::Path;
@@ -24,7 +23,10 @@ pub fn setup_console_socket(csocket_path: &str) -> Result<Option<RawFd>> {
None,
)?;
match socket::connect(socket_fd, &socket::UnixAddr::new(Path::new(csocket_path))?) {
match socket::connect(
socket_fd,
&socket::SockAddr::Unix(socket::UnixAddr::new(Path::new(csocket_path))?),
) {
Ok(()) => Ok(Some(socket_fd)),
Err(errno) => Err(anyhow!("failed to open console fd: {}", errno)),
}
@@ -34,11 +36,11 @@ pub fn setup_master_console(socket_fd: RawFd) -> Result<()> {
let pseudo = pty::openpty(None, None)?;
let pty_name: &[u8] = b"/dev/ptmx";
let iov = [IoSlice::new(pty_name)];
let iov = [uio::IoVec::from_slice(pty_name)];
let fds = [pseudo.master];
let cmsg = socket::ControlMessage::ScmRights(&fds);
socket::sendmsg::<()>(socket_fd, &iov, &[cmsg], socket::MsgFlags::empty(), None)?;
socket::sendmsg(socket_fd, &iov, &[cmsg], socket::MsgFlags::empty(), None)?;
unistd::setsid()?;
let ret = unsafe { libc::ioctl(pseudo.slave, libc::TIOCSCTTY) };

View File

@@ -106,11 +106,6 @@ impl Default for ContainerStatus {
}
}
// We might want to change this to thiserror in the future
const MissingCGroupManager: &str = "failed to get container's cgroup Manager";
const MissingLinux: &str = "no linux config";
const InvalidNamespace: &str = "invalid namespace type";
pub type Config = CreateOpts;
type NamespaceType = String;
@@ -297,7 +292,7 @@ impl Container for LinuxContainer {
self.status.transition(ContainerState::Paused);
return Ok(());
}
Err(anyhow!(MissingCGroupManager))
Err(anyhow!("failed to get container's cgroup manager"))
}
fn resume(&mut self) -> Result<()> {
@@ -315,7 +310,7 @@ impl Container for LinuxContainer {
self.status.transition(ContainerState::Running);
return Ok(());
}
Err(anyhow!(MissingCGroupManager))
Err(anyhow!("failed to get container's cgroup manager"))
}
}
@@ -402,7 +397,7 @@ fn do_init_child(cwfd: RawFd) -> Result<()> {
};
if spec.linux.is_none() {
return Err(anyhow!(MissingLinux));
return Err(anyhow!("no linux config"));
}
let linux = spec.linux.as_ref().unwrap();
@@ -416,7 +411,7 @@ fn do_init_child(cwfd: RawFd) -> Result<()> {
for ns in &nses {
let s = NAMESPACES.get(&ns.r#type.as_str());
if s.is_none() {
return Err(anyhow!(InvalidNamespace));
return Err(anyhow!("invalid ns type"));
}
let s = s.unwrap();
@@ -1186,7 +1181,7 @@ fn do_exec(args: &[String]) -> ! {
unreachable!()
}
pub fn update_namespaces(logger: &Logger, spec: &mut Spec, init_pid: RawFd) -> Result<()> {
fn update_namespaces(logger: &Logger, spec: &mut Spec, init_pid: RawFd) -> Result<()> {
info!(logger, "updating namespaces");
let linux = spec
.linux
@@ -1442,10 +1437,18 @@ impl LinuxContainer {
Some(unistd::getuid()),
Some(unistd::getgid()),
)
.context(format!("Cannot change owner of container {} root", id))?;
.context(format!("cannot change onwer of container {} root", id))?;
if config.spec.is_none() {
return Err(anyhow!(nix::Error::EINVAL));
}
let spec = config.spec.as_ref().unwrap();
if spec.linux.is_none() {
return Err(anyhow!(nix::Error::EINVAL));
}
let linux = spec.linux.as_ref().unwrap();
let cpath = if linux.cgroups_path.is_empty() {
@@ -1454,12 +1457,7 @@ impl LinuxContainer {
linux.cgroups_path.clone()
};
let cgroup_manager = FsManager::new(cpath.as_str()).map_err(|e| {
anyhow!(format!(
"fail to create cgroup manager with path {}: {:}",
cpath, e
))
})?;
let cgroup_manager = FsManager::new(cpath.as_str())?;
info!(logger, "new cgroup_manager {:?}", &cgroup_manager);
Ok(LinuxContainer {
@@ -1527,7 +1525,7 @@ pub async fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()
let binary = PathBuf::from(h.path.as_str());
let path = binary.canonicalize()?;
if !path.exists() {
return Err(anyhow!("Path {:?} does not exist", path));
return Err(anyhow!(nix::Error::EINVAL));
}
let mut args = h.args.clone();
@@ -1658,12 +1656,12 @@ fn valid_env(e: &str) -> Option<(&str, &str)> {
mod tests {
use super::*;
use crate::process::Process;
use crate::skip_if_not_root;
use nix::unistd::Uid;
use std::fs;
use std::os::unix::fs::MetadataExt;
use std::os::unix::io::AsRawFd;
use tempfile::tempdir;
use test_utils::skip_if_not_root;
use tokio::process::Command;
macro_rules! sl {

View File

@@ -236,12 +236,6 @@ pub fn resources_grpc_to_oci(res: &grpc::LinuxResources) -> oci::LinuxResources
let devices = {
let mut d = Vec::new();
for dev in res.Devices.iter() {
let dev_type = if dev.Type.is_empty() {
None
} else {
Some(dev.Type.clone())
};
let major = if dev.Major == -1 {
None
} else {
@@ -255,7 +249,7 @@ pub fn resources_grpc_to_oci(res: &grpc::LinuxResources) -> oci::LinuxResources
};
d.push(oci::LinuxDeviceCgroup {
allow: dev.Allow,
r#type: dev_type,
r#type: dev.Type.clone(),
major,
minor,
access: dev.Access.clone(),
@@ -520,6 +514,15 @@ pub fn grpc_to_oci(grpc: &grpc::Spec) -> oci::Spec {
#[cfg(test)]
mod tests {
use super::*;
#[macro_export]
macro_rules! skip_if_not_root {
() => {
if !nix::unistd::Uid::effective().is_root() {
println!("INFO: skipping {} which needs root", module_path!());
return;
}
};
}
// Parameters:
//

View File

@@ -780,31 +780,18 @@ fn mount_from(
Path::new(&dest).parent().unwrap()
};
fs::create_dir_all(&dir).map_err(|e| {
let _ = fs::create_dir_all(&dir).map_err(|e| {
log_child!(
cfd_log,
"create dir {}: {}",
dir.to_str().unwrap(),
e.to_string()
);
e
})?;
)
});
// make sure file exists so we can bind over it
if !src.is_dir() {
let _ = OpenOptions::new()
.create(true)
.write(true)
.open(&dest)
.map_err(|e| {
log_child!(
cfd_log,
"open/create dest error. {}: {:?}",
dest.as_str(),
e
);
e
})?;
let _ = OpenOptions::new().create(true).write(true).open(&dest);
}
src.to_str().unwrap().to_string()
} else {
@@ -817,10 +804,8 @@ fn mount_from(
}
};
let _ = stat::stat(dest.as_str()).map_err(|e| {
log_child!(cfd_log, "dest stat error. {}: {:?}", dest.as_str(), e);
e
})?;
let _ = stat::stat(dest.as_str())
.map_err(|e| log_child!(cfd_log, "dest stat error. {}: {:?}", dest.as_str(), e));
mount(
Some(src.as_str()),
@@ -1020,7 +1005,9 @@ pub fn finish_rootfs(cfd_log: RawFd, spec: &Spec, process: &Process) -> Result<(
}
fn mask_path(path: &str) -> Result<()> {
check_paths(path)?;
if !path.starts_with('/') || path.contains("..") {
return Err(anyhow!(nix::Error::EINVAL));
}
match mount(
Some("/dev/null"),
@@ -1038,7 +1025,9 @@ fn mask_path(path: &str) -> Result<()> {
}
fn readonly_path(path: &str) -> Result<()> {
check_paths(path)?;
if !path.starts_with('/') || path.contains("..") {
return Err(anyhow!(nix::Error::EINVAL));
}
if let Err(e) = mount(
Some(&path[1..]),
@@ -1064,20 +1053,11 @@ fn readonly_path(path: &str) -> Result<()> {
Ok(())
}
fn check_paths(path: &str) -> Result<()> {
if !path.starts_with('/') || path.contains("..") {
return Err(anyhow!(
"Cannot mount {} (path does not start with '/' or contains '..').",
path
));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::assert_result;
use crate::skip_if_not_root;
use std::fs::create_dir;
use std::fs::create_dir_all;
use std::fs::remove_dir_all;
@@ -1085,7 +1065,6 @@ mod tests {
use std::os::unix::fs;
use std::os::unix::io::AsRawFd;
use tempfile::tempdir;
use test_utils::skip_if_not_root;
#[test]
#[serial(chdir)]
@@ -1426,55 +1405,6 @@ mod tests {
}
}
#[test]
fn test_check_paths() {
#[derive(Debug)]
struct TestData<'a> {
name: &'a str,
path: &'a str,
result: Result<()>,
}
let tests = &[
TestData {
name: "valid path",
path: "/foo/bar",
result: Ok(()),
},
TestData {
name: "does not starts with /",
path: "foo/bar",
result: Err(anyhow!(
"Cannot mount foo/bar (path does not start with '/' or contains '..')."
)),
},
TestData {
name: "contains ..",
path: "../foo/bar",
result: Err(anyhow!(
"Cannot mount ../foo/bar (path does not start with '/' or contains '..')."
)),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d.name);
let result = check_paths(d.path);
let msg = format!("{}: result: {:?}", msg, result);
if d.result.is_ok() {
assert!(result.is_ok());
continue;
}
let expected_error = format!("{}", d.result.as_ref().unwrap_err());
let actual_error = format!("{}", result.unwrap_err());
assert!(actual_error == expected_error, "{}", msg);
}
}
#[test]
fn test_check_proc_mount() {
let mount = oci::Mount {

View File

@@ -28,6 +28,7 @@ macro_rules! close_process_stream {
($self: ident, $stream:ident, $stream_type: ident) => {
if $self.$stream.is_some() {
$self.close_stream(StreamType::$stream_type);
let _ = unistd::close($self.$stream.unwrap());
$self.$stream = None;
}
};
@@ -224,7 +225,7 @@ impl Process {
Some(writer)
}
fn close_stream(&mut self, stream_type: StreamType) {
pub fn close_stream(&mut self, stream_type: StreamType) {
let _ = self.readers.remove(&stream_type);
let _ = self.writers.remove(&stream_type);
}

View File

@@ -122,10 +122,10 @@ pub fn init_seccomp(scmp: &LinuxSeccomp) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::skip_if_not_root;
use libc::{dup3, process_vm_readv, EPERM, O_CLOEXEC};
use std::io::Error;
use std::ptr::null;
use test_utils::skip_if_not_root;
macro_rules! syscall_assert {
($e1: expr, $e2: expr) => {

View File

@@ -4,15 +4,17 @@
//
use crate::container::Config;
use anyhow::{anyhow, Context, Result};
use anyhow::{anyhow, Context, Error, Result};
use oci::{Linux, LinuxIdMapping, LinuxNamespace, Spec};
use std::collections::HashMap;
use std::path::{Component, PathBuf};
fn einval() -> Error {
anyhow!(nix::Error::EINVAL)
}
fn get_linux(oci: &Spec) -> Result<&Linux> {
oci.linux
.as_ref()
.ok_or_else(|| anyhow!("Unable to get Linux section from Spec"))
oci.linux.as_ref().ok_or_else(einval)
}
fn contain_namespace(nses: &[LinuxNamespace], key: &str) -> bool {
@@ -29,10 +31,7 @@ fn rootfs(root: &str) -> Result<()> {
let path = PathBuf::from(root);
// not absolute path or not exists
if !path.exists() || !path.is_absolute() {
return Err(anyhow!(
"Path from {:?} does not exist or is not absolute",
root
));
return Err(einval());
}
// symbolic link? ..?
@@ -50,7 +49,7 @@ fn rootfs(root: &str) -> Result<()> {
if let Some(v) = c.as_os_str().to_str() {
stack.push(v.to_string());
} else {
return Err(anyhow!("Invalid path component (unable to convert to str)"));
return Err(einval());
}
}
@@ -59,13 +58,10 @@ fn rootfs(root: &str) -> Result<()> {
cleaned.push(e);
}
let canon = path.canonicalize().context("failed to canonicalize path")?;
let canon = path.canonicalize().context("canonicalize")?;
if cleaned != canon {
// There is symbolic in path
return Err(anyhow!(
"There may be illegal symbols in the path name. Cleaned ({:?}) and canonicalized ({:?}) paths do not match",
cleaned,
canon));
return Err(einval());
}
Ok(())
@@ -78,7 +74,7 @@ fn hostname(oci: &Spec) -> Result<()> {
let linux = get_linux(oci)?;
if !contain_namespace(&linux.namespaces, "uts") {
return Err(anyhow!("Linux namespace does not contain uts"));
return Err(einval());
}
Ok(())
@@ -92,7 +88,7 @@ fn security(oci: &Spec) -> Result<()> {
}
if !contain_namespace(&linux.namespaces, "mount") {
return Err(anyhow!("Linux namespace does not contain mount"));
return Err(einval());
}
// don't care about selinux at present
@@ -107,7 +103,7 @@ fn idmapping(maps: &[LinuxIdMapping]) -> Result<()> {
}
}
Err(anyhow!("No idmap has size > 0"))
Err(einval())
}
fn usernamespace(oci: &Spec) -> Result<()> {
@@ -125,7 +121,7 @@ fn usernamespace(oci: &Spec) -> Result<()> {
} else {
// no user namespace but idmap
if !linux.uid_mappings.is_empty() || !linux.gid_mappings.is_empty() {
return Err(anyhow!("No user namespace, but uid or gid mapping exists"));
return Err(einval());
}
}
@@ -167,7 +163,7 @@ fn sysctl(oci: &Spec) -> Result<()> {
if contain_namespace(&linux.namespaces, "ipc") {
continue;
} else {
return Err(anyhow!("Linux namespace does not contain ipc"));
return Err(einval());
}
}
@@ -182,11 +178,11 @@ fn sysctl(oci: &Spec) -> Result<()> {
}
if key == "kernel.hostname" {
return Err(anyhow!("Kernel hostname specfied in Spec"));
return Err(einval());
}
}
return Err(anyhow!("Sysctl config contains invalid settings"));
return Err(einval());
}
Ok(())
}
@@ -195,13 +191,12 @@ fn rootless_euid_mapping(oci: &Spec) -> Result<()> {
let linux = get_linux(oci)?;
if !contain_namespace(&linux.namespaces, "user") {
return Err(anyhow!("Linux namespace is missing user"));
return Err(einval());
}
if linux.uid_mappings.is_empty() || linux.gid_mappings.is_empty() {
return Err(anyhow!(
"Rootless containers require at least one UID/GID mapping"
));
// rootless containers requires at least one UID/GID mapping
return Err(einval());
}
Ok(())
@@ -225,7 +220,7 @@ fn rootless_euid_mount(oci: &Spec) -> Result<()> {
let fields: Vec<&str> = opt.split('=').collect();
if fields.len() != 2 {
return Err(anyhow!("Options has invalid field: {:?}", fields));
return Err(einval());
}
let id = fields[1]
@@ -234,11 +229,11 @@ fn rootless_euid_mount(oci: &Spec) -> Result<()> {
.context(format!("parse field {}", &fields[1]))?;
if opt.starts_with("uid=") && !has_idmapping(&linux.uid_mappings, id) {
return Err(anyhow!("uid of {} does not have a valid mapping", id));
return Err(einval());
}
if opt.starts_with("gid=") && !has_idmapping(&linux.gid_mappings, id) {
return Err(anyhow!("gid of {} does not have a valid mapping", id));
return Err(einval());
}
}
}
@@ -254,18 +249,15 @@ fn rootless_euid(oci: &Spec) -> Result<()> {
pub fn validate(conf: &Config) -> Result<()> {
lazy_static::initialize(&SYSCTLS);
let oci = conf
.spec
.as_ref()
.ok_or_else(|| anyhow!("Invalid config spec"))?;
let oci = conf.spec.as_ref().ok_or_else(einval)?;
if oci.linux.is_none() {
return Err(anyhow!("oci Linux is none"));
return Err(einval());
}
let root = match oci.root.as_ref() {
Some(v) => v.path.as_str(),
None => return Err(anyhow!("oci root is none")),
None => return Err(einval()),
};
rootfs(root).context("rootfs")?;

View File

@@ -11,9 +11,6 @@ use std::fs;
use std::str::FromStr;
use std::time;
use tracing::instrument;
use url::Url;
use kata_types::config::default::DEFAULT_AGENT_VSOCK_PORT;
const DEBUG_CONSOLE_FLAG: &str = "agent.debug_console";
const DEV_MODE_FLAG: &str = "agent.devmode";
@@ -26,17 +23,12 @@ const LOG_VPORT_OPTION: &str = "agent.log_vport";
const CONTAINER_PIPE_SIZE_OPTION: &str = "agent.container_pipe_size";
const UNIFIED_CGROUP_HIERARCHY_OPTION: &str = "agent.unified_cgroup_hierarchy";
const CONFIG_FILE: &str = "agent.config_file";
const CONTAINER_POLICY_FILE: &str = "agent.container_policy_file";
const AA_KBC_PARAMS: &str = "agent.aa_kbc_params";
const HTTPS_PROXY: &str = "agent.https_proxy";
const NO_PROXY: &str = "agent.no_proxy";
const ENABLE_DATA_INTEGRITY: &str = "agent.data_integrity";
const ENABLE_SIGNATURE_VERIFICATION: &str = "agent.enable_signature_verification";
const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info;
const DEFAULT_HOTPLUG_TIMEOUT: time::Duration = time::Duration::from_secs(3);
const DEFAULT_CONTAINER_PIPE_SIZE: i32 = 0;
const VSOCK_ADDR: &str = "vsock://-1";
const VSOCK_PORT: u16 = 1024;
// Environment variables used for development and testing
const SERVER_ADDR_ENV_VAR: &str = "KATA_AGENT_SERVER_ADDR";
@@ -59,11 +51,6 @@ const ERR_INVALID_CONTAINER_PIPE_SIZE_PARAM: &str = "unable to parse container p
const ERR_INVALID_CONTAINER_PIPE_SIZE_KEY: &str = "invalid container pipe size key name";
const ERR_INVALID_CONTAINER_PIPE_NEGATIVE: &str = "container pipe size should not be negative";
const ERR_INVALID_CONTAINER_POLICY_PATH_VALUE: &str = "invalid container_policy_file value";
const ERR_INVALID_CONTAINER_POLICY_PATH_KEY: &str = "invalid container_policy_file key";
const ERR_INVALID_CONTAINER_POLICY_ABSOLUTE: &str =
"container_policy_file path must be an absolute file path";
#[derive(Debug, Default, Deserialize)]
pub struct EndpointsConfig {
pub allowed: Vec<String>,
@@ -89,12 +76,6 @@ pub struct AgentConfig {
pub tracing: bool,
pub endpoints: AgentEndpoints,
pub supports_seccomp: bool,
pub container_policy_path: String,
pub aa_kbc_params: String,
pub https_proxy: String,
pub no_proxy: String,
pub data_integrity: bool,
pub enable_signature_verification: bool,
}
#[derive(Debug, Deserialize)]
@@ -110,12 +91,6 @@ pub struct AgentConfigBuilder {
pub unified_cgroup_hierarchy: Option<bool>,
pub tracing: Option<bool>,
pub endpoints: Option<EndpointsConfig>,
pub container_policy_path: Option<String>,
pub aa_kbc_params: Option<String>,
pub https_proxy: Option<String>,
pub no_proxy: Option<String>,
pub data_integrity: Option<bool>,
pub enable_signature_verification: Option<bool>,
}
macro_rules! config_override {
@@ -172,17 +147,11 @@ impl Default for AgentConfig {
debug_console_vport: 0,
log_vport: 0,
container_pipe_size: DEFAULT_CONTAINER_PIPE_SIZE,
server_addr: format!("{}:{}", VSOCK_ADDR, DEFAULT_AGENT_VSOCK_PORT),
server_addr: format!("{}:{}", VSOCK_ADDR, VSOCK_PORT),
unified_cgroup_hierarchy: false,
tracing: false,
endpoints: Default::default(),
supports_seccomp: rpc::have_seccomp(),
container_policy_path: String::from(""),
aa_kbc_params: String::from(""),
https_proxy: String::from(""),
no_proxy: String::from(""),
data_integrity: false,
enable_signature_verification: true,
}
}
}
@@ -211,16 +180,6 @@ impl FromStr for AgentConfig {
config_override!(agent_config_builder, agent_config, server_addr);
config_override!(agent_config_builder, agent_config, unified_cgroup_hierarchy);
config_override!(agent_config_builder, agent_config, tracing);
config_override!(agent_config_builder, agent_config, container_policy_path);
config_override!(agent_config_builder, agent_config, aa_kbc_params);
config_override!(agent_config_builder, agent_config, https_proxy);
config_override!(agent_config_builder, agent_config, no_proxy);
config_override!(agent_config_builder, agent_config, data_integrity);
config_override!(
agent_config_builder,
agent_config,
enable_signature_verification
);
// Populate the allowed endpoints hash set, if we got any from the config file.
if let Some(endpoints) = agent_config_builder.endpoints {
@@ -249,10 +208,6 @@ impl AgentConfig {
let mut config: AgentConfig = Default::default();
let cmdline = fs::read_to_string(file)?;
let params: Vec<&str> = cmdline.split_ascii_whitespace().collect();
let mut using_config_file = false;
// Check if there is config file before parsing params that might
// override values from the config file.
for param in params.iter() {
// If we get a configuration file path from the command line, we
// generate our config from it.
@@ -260,13 +215,9 @@ impl AgentConfig {
// or if it can't be parsed properly.
if param.starts_with(format!("{}=", CONFIG_FILE).as_str()) {
let config_file = get_string_value(param)?;
config = AgentConfig::from_config_file(&config_file)?;
using_config_file = true;
break;
return AgentConfig::from_config_file(&config_file);
}
}
for param in params.iter() {
// parse cmdline flags
parse_cmdline_param!(param, DEBUG_CONSOLE_FLAG, config.debug_console);
parse_cmdline_param!(param, DEV_MODE_FLAG, config.dev_mode);
@@ -326,30 +277,6 @@ impl AgentConfig {
config.unified_cgroup_hierarchy,
get_bool_value
);
parse_cmdline_param!(
param,
CONTAINER_POLICY_FILE,
config.container_policy_path,
get_container_policy_path_value
);
parse_cmdline_param!(param, AA_KBC_PARAMS, config.aa_kbc_params, get_string_value);
parse_cmdline_param!(param, HTTPS_PROXY, config.https_proxy, get_url_value);
parse_cmdline_param!(param, NO_PROXY, config.no_proxy, get_string_value);
parse_cmdline_param!(
param,
ENABLE_DATA_INTEGRITY,
config.data_integrity,
get_bool_value
);
parse_cmdline_param!(
param,
ENABLE_SIGNATURE_VERIFICATION,
config.enable_signature_verification,
get_bool_value
);
}
if let Ok(addr) = env::var(SERVER_ADDR_ENV_VAR) {
@@ -369,9 +296,7 @@ impl AgentConfig {
}
// We did not get a configuration file: allow all endpoints.
if !using_config_file {
config.endpoints.all_allowed = true;
}
config.endpoints.all_allowed = true;
Ok(config)
}
@@ -505,38 +430,9 @@ fn get_container_pipe_size(param: &str) -> Result<i32> {
Ok(value)
}
#[instrument]
fn get_container_policy_path_value(param: &str) -> Result<String> {
let fields: Vec<&str> = param.split('=').collect();
ensure!(!fields[0].is_empty(), ERR_INVALID_CONTAINER_POLICY_PATH_KEY);
ensure!(fields.len() == 2, ERR_INVALID_CONTAINER_POLICY_PATH_VALUE);
let key = fields[0];
ensure!(
key == CONTAINER_POLICY_FILE,
ERR_INVALID_CONTAINER_POLICY_PATH_KEY
);
let value = String::from(fields[1]);
ensure!(!value.is_empty(), ERR_INVALID_CONTAINER_POLICY_PATH_VALUE);
ensure!(
value.starts_with('/'),
ERR_INVALID_CONTAINER_POLICY_ABSOLUTE
);
ensure!(!value.contains(".."), ERR_INVALID_CONTAINER_POLICY_ABSOLUTE);
Ok(value)
}
#[instrument]
fn get_url_value(param: &str) -> Result<String> {
let value = get_string_value(param)?;
Ok(Url::parse(&value)?.to_string())
}
#[cfg(test)]
mod tests {
use test_utils::assert_result;
use crate::assert_result;
use super::*;
use anyhow::anyhow;
@@ -552,8 +448,6 @@ mod tests {
assert!(!config.dev_mode);
assert_eq!(config.log_level, DEFAULT_LOG_LEVEL);
assert_eq!(config.hotplug_timeout, DEFAULT_HOTPLUG_TIMEOUT);
assert_eq!(config.container_policy_path, "");
assert!(config.enable_signature_verification);
}
#[test]
@@ -572,12 +466,6 @@ mod tests {
server_addr: &'a str,
unified_cgroup_hierarchy: bool,
tracing: bool,
container_policy_path: &'a str,
aa_kbc_params: &'a str,
https_proxy: &'a str,
no_proxy: &'a str,
data_integrity: bool,
enable_signature_verification: bool,
}
impl Default for TestData<'_> {
@@ -593,12 +481,6 @@ mod tests {
server_addr: TEST_SERVER_ADDR,
unified_cgroup_hierarchy: false,
tracing: false,
container_policy_path: "",
aa_kbc_params: "",
https_proxy: "",
no_proxy: "",
data_integrity: false,
enable_signature_verification: true,
}
}
}
@@ -968,86 +850,6 @@ mod tests {
tracing: true,
..Default::default()
},
TestData {
contents: "agent.container_policy_file=/etc/containers/policy.json",
container_policy_path: "/etc/containers/policy.json",
..Default::default()
},
TestData {
contents: "agent.aa_kbc_params=offline_fs_kbc::null",
aa_kbc_params: "offline_fs_kbc::null",
..Default::default()
},
TestData {
contents: "agent.aa_kbc_params=eaa_kbc::127.0.0.1:50000",
aa_kbc_params: "eaa_kbc::127.0.0.1:50000",
..Default::default()
},
TestData {
contents: "agent.https_proxy=http://proxy.url.com:81/",
https_proxy: "http://proxy.url.com:81/",
..Default::default()
},
TestData {
contents: "agent.https_proxy=http://192.168.1.100:81/",
https_proxy: "http://192.168.1.100:81/",
..Default::default()
},
TestData {
contents: "agent.no_proxy=*.internal.url.com",
no_proxy: "*.internal.url.com",
..Default::default()
},
TestData {
contents: "agent.no_proxy=192.168.1.0/24,172.16.0.0/12",
no_proxy: "192.168.1.0/24,172.16.0.0/12",
..Default::default()
},
TestData {
contents: "",
data_integrity: false,
..Default::default()
},
TestData {
contents: "agent.data_integrity=true",
data_integrity: true,
..Default::default()
},
TestData {
contents: "agent.data_integrity=false",
data_integrity: false,
..Default::default()
},
TestData {
contents: "agent.data_integrity=1",
data_integrity: true,
..Default::default()
},
TestData {
contents: "agent.data_integrity=0",
data_integrity: false,
..Default::default()
},
TestData {
contents: "agent.enable_signature_verification=false",
enable_signature_verification: false,
..Default::default()
},
TestData {
contents: "agent.enable_signature_verification=0",
enable_signature_verification: false,
..Default::default()
},
TestData {
contents: "agent.enable_signature_verification=1",
enable_signature_verification: true,
..Default::default()
},
TestData {
contents: "agent.enable_signature_verification=foo",
enable_signature_verification: false,
..Default::default()
},
];
let dir = tempdir().expect("failed to create tmpdir");
@@ -1095,20 +897,6 @@ mod tests {
assert_eq!(d.container_pipe_size, config.container_pipe_size, "{}", msg);
assert_eq!(d.server_addr, config.server_addr, "{}", msg);
assert_eq!(d.tracing, config.tracing, "{}", msg);
assert_eq!(
d.container_policy_path, config.container_policy_path,
"{}",
msg
);
assert_eq!(d.aa_kbc_params, config.aa_kbc_params, "{}", msg);
assert_eq!(d.https_proxy, config.https_proxy, "{}", msg);
assert_eq!(d.no_proxy, config.no_proxy, "{}", msg);
assert_eq!(d.data_integrity, config.data_integrity, "{}", msg);
assert_eq!(
d.enable_signature_verification, config.enable_signature_verification,
"{}",
msg
);
for v in vars_to_unset {
env::remove_var(v);
@@ -1580,72 +1368,6 @@ Caused by:
}
}
#[test]
fn test_get_container_policy_path_value() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<String>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_PATH_KEY)),
},
TestData {
param: "agent.container_policy_file",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_PATH_VALUE)),
},
TestData {
param: "agent.container_policy_file=",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_PATH_VALUE)),
},
TestData {
param: "foo=bar",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_PATH_KEY)),
},
TestData {
param: "agent.policy_path=/another/absolute/path.json",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_PATH_KEY)),
},
TestData {
param: "agent.container_policy_file=/etc/container/policy.json",
result: Ok("/etc/container/policy.json".into()),
},
TestData {
param: "agent.container_policy_file=/another/absolute/path.json",
result: Ok("/another/absolute/path.json".into()),
},
TestData {
param: "agent.container_policy_file=./relative/path.json",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_ABSOLUTE)),
},
TestData {
param: "agent.container_policy_file=./relative/path.json",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_ABSOLUTE)),
},
TestData {
param: "agent.container_policy_file=../../relative/path.json",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_ABSOLUTE)),
},
TestData {
param: "agent.container_policy_file=junk_string",
result: Err(anyhow!(ERR_INVALID_CONTAINER_POLICY_ABSOLUTE)),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_container_policy_path_value(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
}
#[test]
fn test_config_builder_from_string() {
let config = AgentConfig::from_str(
@@ -1676,50 +1398,4 @@ Caused by:
// Verify that the default values are valid
assert_eq!(config.hotplug_timeout, DEFAULT_HOTPLUG_TIMEOUT);
}
#[test]
fn test_config_from_cmdline_and_config_file() {
let dir = tempdir().expect("failed to create tmpdir");
let agent_config = r#"
dev_mode = false
server_addr = 'vsock://8:2048'
[endpoints]
allowed = ["CreateContainer", "StartContainer"]
"#;
let config_path = dir.path().join("agent-config.toml");
let config_filename = config_path.to_str().expect("failed to get config filename");
fs::write(config_filename, agent_config).expect("failed to write agen config");
let cmdline = format!("agent.devmode agent.config_file={}", config_filename);
let cmdline_path = dir.path().join("cmdline");
let cmdline_filename = cmdline_path
.to_str()
.expect("failed to get cmdline filename");
fs::write(cmdline_filename, cmdline).expect("failed to write agen config");
let config = AgentConfig::from_cmdline(cmdline_filename, vec![])
.expect("failed to parse command line");
// Should be overwritten by cmdline
assert!(config.dev_mode);
// Should be from agent config
assert_eq!(config.server_addr, "vsock://8:2048");
// Should be from agent config
assert_eq!(
config.endpoints.allowed,
vec!["CreateContainer".to_string(), "StartContainer".to_string()]
.iter()
.cloned()
.collect()
);
assert!(!config.endpoints.all_allowed);
}
}

View File

@@ -9,7 +9,7 @@ use anyhow::{anyhow, Result};
use nix::fcntl::{self, FcntlArg, FdFlag, OFlag};
use nix::libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
use nix::pty::{openpty, OpenptyResult};
use nix::sys::socket::{self, AddressFamily, SockFlag, SockType, VsockAddr};
use nix::sys::socket::{self, AddressFamily, SockAddr, SockFlag, SockType};
use nix::sys::stat::Mode;
use nix::sys::wait;
use nix::unistd::{self, close, dup2, fork, setsid, ForkResult, Pid};
@@ -67,7 +67,7 @@ pub async fn debug_console_handler(
SockFlag::SOCK_CLOEXEC,
None,
)?;
let addr = VsockAddr::new(libc::VMADDR_CID_ANY, port);
let addr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
socket::bind(listenfd, &addr)?;
socket::listen(listenfd, 1)?;

View File

@@ -571,15 +571,13 @@ fn update_spec_devices(spec: &mut Spec, mut updates: HashMap<&str, DevUpdate>) -
if let Some(resources) = linux.resources.as_mut() {
for r in &mut resources.devices {
if let (Some(host_type), Some(host_major), Some(host_minor)) =
(r.r#type.as_ref(), r.major, r.minor)
{
if let Some(update) = res_updates.get(&(host_type.as_str(), host_major, host_minor))
if let (Some(host_major), Some(host_minor)) = (r.major, r.minor) {
if let Some(update) = res_updates.get(&(r.r#type.as_str(), host_major, host_minor))
{
info!(
sl!(),
"update_spec_devices() updating resource";
"type" => &host_type,
"type" => &r.r#type,
"host_major" => host_major,
"host_minor" => host_minor,
"guest_major" => update.guest_major,
@@ -856,7 +854,7 @@ pub fn update_device_cgroup(spec: &mut Spec) -> Result<()> {
allow: false,
major: Some(major),
minor: Some(minor),
r#type: Some(String::from("b")),
r#type: String::from("b"),
access: String::from("rw"),
});
@@ -1019,13 +1017,13 @@ mod tests {
resources: Some(LinuxResources {
devices: vec![
oci::LinuxDeviceCgroup {
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(host_major_a),
minor: Some(host_minor_a),
..oci::LinuxDeviceCgroup::default()
},
oci::LinuxDeviceCgroup {
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(host_major_b),
minor: Some(host_minor_b),
..oci::LinuxDeviceCgroup::default()
@@ -1118,13 +1116,13 @@ mod tests {
resources: Some(LinuxResources {
devices: vec![
LinuxDeviceCgroup {
r#type: Some("c".to_string()),
r#type: "c".to_string(),
major: Some(host_major),
minor: Some(host_minor),
..LinuxDeviceCgroup::default()
},
LinuxDeviceCgroup {
r#type: Some("b".to_string()),
r#type: "b".to_string(),
major: Some(host_major),
minor: Some(host_minor),
..LinuxDeviceCgroup::default()

View File

@@ -1,412 +0,0 @@
// Copyright (c) 2021 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//
use std::env;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use anyhow::{anyhow, ensure, Result};
use async_trait::async_trait;
use protocols::image;
use tokio::sync::Mutex;
use ttrpc::{self, error::get_rpc_status as ttrpc_error};
use crate::rpc::{verify_cid, CONTAINER_BASE};
use crate::sandbox::Sandbox;
use crate::AGENT_CONFIG;
use image_rs::image::ImageClient;
use std::io::Write;
const SKOPEO_PATH: &str = "/usr/bin/skopeo";
const UMOCI_PATH: &str = "/usr/local/bin/umoci";
const IMAGE_OCI: &str = "image_oci";
const AA_PATH: &str = "/usr/local/bin/attestation-agent";
const AA_KEYPROVIDER_PORT: &str = "127.0.0.1:50000";
const AA_GETRESOURCE_PORT: &str = "127.0.0.1:50001";
const OCICRYPT_CONFIG_PATH: &str = "/tmp/ocicrypt_config.json";
// kata rootfs is readonly, use tmpfs before CC storage is implemented.
const KATA_CC_IMAGE_WORK_DIR: &str = "/run/image/";
const KATA_CC_PAUSE_BUNDLE: &str = "/pause_bundle";
const CONFIG_JSON: &str = "config.json";
// Convenience macro to obtain the scope logger
macro_rules! sl {
() => {
slog_scope::logger()
};
}
pub struct ImageService {
sandbox: Arc<Mutex<Sandbox>>,
attestation_agent_started: AtomicBool,
image_client: Arc<Mutex<ImageClient>>,
}
impl ImageService {
pub fn new(sandbox: Arc<Mutex<Sandbox>>) -> Self {
env::set_var("CC_IMAGE_WORK_DIR", KATA_CC_IMAGE_WORK_DIR);
Self {
sandbox,
attestation_agent_started: AtomicBool::new(false),
image_client: Arc::new(Mutex::new(ImageClient::default())),
}
}
fn pull_image_from_registry(
image: &str,
cid: &str,
source_creds: Option<&str>,
policy_path: Option<&str>,
aa_kbc_params: &str,
) -> Result<()> {
let source_image = format!("{}{}", "docker://", image);
let tmp_cid_path = Path::new("/tmp/").join(cid);
let oci_path = tmp_cid_path.join(IMAGE_OCI);
let target_path_oci = format!("oci://{}:latest", oci_path.to_string_lossy());
fs::create_dir_all(&oci_path)?;
let mut pull_command = Command::new(SKOPEO_PATH);
pull_command
.arg("copy")
.arg(source_image)
.arg(&target_path_oci)
.arg("--remove-signatures"); //umoci requires signatures to be removed
// If source credentials were passed (so not using an anonymous registry), pass them through
if let Some(source_creds) = source_creds {
pull_command.arg("--src-creds").arg(source_creds);
}
// If a policy_path provided, use it, otherwise fall back to allow all image registries
if let Some(policy_path) = policy_path {
pull_command.arg("--policy").arg(policy_path);
} else {
info!(
sl!(),
"No policy path was supplied, so revert to allow all images to be pulled."
);
pull_command.arg("--insecure-policy");
}
debug!(sl!(), "skopeo command: {:?}", &pull_command);
if !aa_kbc_params.is_empty() {
// Skopeo will copy an unencrypted image even if the decryption key argument is provided.
// Thus, this does not guarantee that the image was encrypted.
pull_command
.arg("--decryption-key")
.arg(format!("provider:attestation-agent:{}", aa_kbc_params))
.env("OCICRYPT_KEYPROVIDER_CONFIG", OCICRYPT_CONFIG_PATH);
}
let status: ExitStatus = pull_command.status()?;
if !status.success() {
let mut error_message = format!("failed to pull image: {:?}", status);
if let Err(e) = fs::remove_dir_all(&tmp_cid_path) {
let _ = write!(
error_message,
" and clean up of temporary container directory {:?} failed with error {:?}",
tmp_cid_path, e
);
};
return Err(anyhow!(error_message));
}
Ok(())
}
fn unpack_image(cid: &str) -> Result<()> {
let tmp_cid_path = Path::new("/tmp/").join(cid);
let source_path_oci = tmp_cid_path.join(IMAGE_OCI);
let target_path_bundle = Path::new(CONTAINER_BASE).join(cid);
info!(sl!(), "unpack image {:?} to {:?}", cid, target_path_bundle);
// Unpack image
let status: ExitStatus = Command::new(UMOCI_PATH)
.arg("unpack")
.arg("--image")
.arg(&source_path_oci)
.arg(&target_path_bundle)
.status()?;
ensure!(status.success(), "failed to unpack image: {:?}", status);
// To save space delete the oci image after unpack
fs::remove_dir_all(&tmp_cid_path)?;
Ok(())
}
// pause image is packaged in rootfs for CC
fn unpack_pause_image(cid: &str) -> Result<()> {
let cc_pause_bundle = Path::new(KATA_CC_PAUSE_BUNDLE);
if !cc_pause_bundle.exists() {
return Err(anyhow!("Pause image not present in rootfs"));
}
info!(sl!(), "use guest pause image cid {:?}", cid);
let pause_bundle = Path::new(CONTAINER_BASE).join(&cid);
let pause_rootfs = pause_bundle.join("rootfs");
let pause_config = pause_bundle.join(CONFIG_JSON);
let pause_binary = pause_rootfs.join("pause");
fs::create_dir_all(&pause_rootfs)?;
if !pause_config.exists() {
fs::copy(
cc_pause_bundle.join(CONFIG_JSON),
pause_bundle.join(CONFIG_JSON),
)?;
}
if !pause_binary.exists() {
fs::copy(cc_pause_bundle.join("rootfs").join("pause"), pause_binary)?;
}
Ok(())
}
// If we fail to start the AA, Skopeo/ocicrypt won't be able to unwrap keys
// and container decryption will fail.
fn init_attestation_agent() -> Result<()> {
let config_path = OCICRYPT_CONFIG_PATH;
// The image will need to be encrypted using a keyprovider
// that has the same name (at least according to the config).
let ocicrypt_config = serde_json::json!({
"key-providers": {
"attestation-agent":{
"grpc":AA_KEYPROVIDER_PORT
}
}
});
let mut config_file = fs::File::create(config_path)?;
config_file.write_all(ocicrypt_config.to_string().as_bytes())?;
// The Attestation Agent will run for the duration of the guest.
Command::new(AA_PATH)
.arg("--keyprovider_sock")
.arg(AA_KEYPROVIDER_PORT)
.arg("--getresource_sock")
.arg(AA_GETRESOURCE_PORT)
.spawn()?;
Ok(())
}
/// Determines the container id (cid) to use for a given request.
///
/// If the request specifies a non-empty id, use it; otherwise derive it from the image path.
/// In either case, verify that the chosen id is valid.
fn cid_from_request(req: &image::PullImageRequest) -> Result<String> {
let req_cid = req.get_container_id();
let cid = if !req_cid.is_empty() {
req_cid.to_string()
} else if let Some(last) = req.get_image().rsplit('/').next() {
// ':' have special meaning for umoci during upack
last.replace(':', "_")
} else {
return Err(anyhow!("Invalid image name. {}", req.get_image()));
};
verify_cid(&cid)?;
Ok(cid)
}
async fn pull_image(&self, req: &image::PullImageRequest) -> Result<String> {
env::set_var("OCICRYPT_KEYPROVIDER_CONFIG", OCICRYPT_CONFIG_PATH);
let https_proxy = &AGENT_CONFIG.read().await.https_proxy;
if !https_proxy.is_empty() {
env::set_var("HTTPS_PROXY", https_proxy);
}
let no_proxy = &AGENT_CONFIG.read().await.no_proxy;
if !no_proxy.is_empty() {
env::set_var("NO_PROXY", no_proxy);
}
let cid = Self::cid_from_request(req)?;
let image = req.get_image();
// Can switch to use cid directly when we remove umoci
let v: Vec<&str> = image.rsplit('/').collect();
if !v[0].is_empty() && v[0].starts_with("pause:") {
Self::unpack_pause_image(&cid)?;
let mut sandbox = self.sandbox.lock().await;
sandbox.images.insert(String::from(image), cid);
return Ok(image.to_owned());
}
let aa_kbc_params = &AGENT_CONFIG.read().await.aa_kbc_params;
if !aa_kbc_params.is_empty() {
match self.attestation_agent_started.compare_exchange_weak(
false,
true,
Ordering::SeqCst,
Ordering::SeqCst,
) {
Ok(_) => Self::init_attestation_agent()?,
Err(_) => info!(sl!(), "Attestation Agent already running"),
}
}
let source_creds = (!req.get_source_creds().is_empty()).then(|| req.get_source_creds());
if Path::new(SKOPEO_PATH).exists() {
// Read the policy path from the agent config
let config_policy_path = &AGENT_CONFIG.read().await.container_policy_path;
let policy_path = (!config_policy_path.is_empty()).then(|| config_policy_path.as_str());
Self::pull_image_from_registry(image, &cid, source_creds, policy_path, aa_kbc_params)?;
Self::unpack_image(&cid)?;
} else {
// Read enable signature verification from the agent config and set it in the image_client
let enable_signature_verification =
&AGENT_CONFIG.read().await.enable_signature_verification;
info!(
sl!(),
"enable_signature_verification set to: {}", enable_signature_verification
);
self.image_client.lock().await.config.security_validate =
*enable_signature_verification;
let bundle_path = Path::new(CONTAINER_BASE).join(&cid);
fs::create_dir_all(&bundle_path)?;
let decrypt_config = format!("provider:attestation-agent:{}", aa_kbc_params);
info!(sl!(), "pull image {:?}, bundle path {:?}", cid, bundle_path);
// Image layers will store at KATA_CC_IMAGE_WORK_DIR, generated bundles
// with rootfs and config.json will store under CONTAINER_BASE/cid.
self.image_client
.lock()
.await
.pull_image(image, &bundle_path, &source_creds, &Some(&decrypt_config))
.await?;
}
let mut sandbox = self.sandbox.lock().await;
sandbox.images.insert(String::from(image), cid);
Ok(image.to_owned())
}
}
#[async_trait]
impl protocols::image_ttrpc_async::Image for ImageService {
async fn pull_image(
&self,
_ctx: &ttrpc::r#async::TtrpcContext,
req: image::PullImageRequest,
) -> ttrpc::Result<image::PullImageResponse> {
match self.pull_image(&req).await {
Ok(r) => {
let mut resp = image::PullImageResponse::new();
resp.image_ref = r;
return Ok(resp);
}
Err(e) => {
return Err(ttrpc_error(ttrpc::Code::INTERNAL, e.to_string()));
}
}
}
}
#[cfg(test)]
mod tests {
use super::ImageService;
use protocols::image;
#[test]
fn test_cid_from_request() {
struct Case {
cid: &'static str,
image: &'static str,
result: Option<&'static str>,
}
let cases = [
Case {
cid: "",
image: "",
result: None,
},
Case {
cid: "..",
image: "",
result: None,
},
Case {
cid: "",
image: "..",
result: None,
},
Case {
cid: "",
image: "abc/..",
result: None,
},
Case {
cid: "",
image: "abc/",
result: None,
},
Case {
cid: "",
image: "../abc",
result: Some("abc"),
},
Case {
cid: "",
image: "../9abc",
result: Some("9abc"),
},
Case {
cid: "some-string.1_2",
image: "",
result: Some("some-string.1_2"),
},
Case {
cid: "0some-string.1_2",
image: "",
result: Some("0some-string.1_2"),
},
Case {
cid: "a:b",
image: "",
result: None,
},
Case {
cid: "",
image: "prefix/a:b",
result: Some("a_b"),
},
Case {
cid: "",
image: "/a/b/c/d:e",
result: Some("d_e"),
},
];
for case in &cases {
let mut req = image::PullImageRequest::new();
req.set_image(case.image.to_string());
req.set_container_id(case.cid.to_string());
let ret = ImageService::cid_from_request(&req);
match (case.result, ret) {
(Some(expected), Ok(actual)) => assert_eq!(expected, actual),
(None, Err(_)) => (),
(None, Ok(r)) => panic!("Expected an error, got {}", r),
(Some(expected), Err(e)) => {
panic!("Expected {} but got an error ({})", expected, e)
}
}
}
}
}

View File

@@ -22,7 +22,7 @@ extern crate slog;
use anyhow::{anyhow, Context, Result};
use clap::{AppSettings, Parser};
use nix::fcntl::OFlag;
use nix::sys::socket::{self, AddressFamily, SockFlag, SockType, VsockAddr};
use nix::sys::socket::{self, AddressFamily, SockAddr, SockFlag, SockType};
use nix::unistd::{self, dup, Pid};
use std::env;
use std::ffi::OsStr;
@@ -49,6 +49,8 @@ mod pci;
pub mod random;
mod sandbox;
mod signal;
#[cfg(test)]
mod test_utils;
mod uevent;
mod util;
mod version;
@@ -71,7 +73,6 @@ use tokio::{
task::JoinHandle,
};
mod image_rpc;
mod rpc;
mod tracer;
@@ -109,6 +110,10 @@ enum SubCommand {
fn announce(logger: &Logger, config: &AgentConfig) {
info!(logger, "announce";
"agent-commit" => version::VERSION_COMMIT,
// Avoid any possibility of confusion with the old agent
"agent-type" => "rust",
"agent-version" => version::AGENT_VERSION,
"api-version" => version::API_VERSION,
"config" => format!("{:?}", config),
@@ -127,7 +132,7 @@ async fn create_logger_task(rfd: RawFd, vsock_port: u32, shutdown: Receiver<bool
None,
)?;
let addr = VsockAddr::new(libc::VMADDR_CID_ANY, vsock_port);
let addr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, vsock_port);
socket::bind(listenfd, &addr)?;
socket::listen(listenfd, 1)?;
@@ -208,7 +213,7 @@ async fn real_main() -> std::result::Result<(), Box<dyn std::error::Error>> {
if config.log_level == slog::Level::Trace {
// Redirect ttrpc log calls to slog iff full debug requested
ttrpc_log_guard = Ok(slog_stdlog::init()?);
ttrpc_log_guard = Ok(slog_stdlog::init().map_err(|e| e)?);
}
if config.tracing {
@@ -400,8 +405,7 @@ use std::os::unix::io::{FromRawFd, RawFd};
#[cfg(test)]
mod tests {
use super::*;
use test_utils::TestUserType;
use test_utils::{assert_result, skip_if_not_root, skip_if_root};
use crate::test_utils::test_utils::TestUserType;
#[tokio::test]
async fn test_create_logger_task() {

View File

@@ -169,12 +169,11 @@ pub fn baremount(
info!(
logger,
"baremount source={:?}, dest={:?}, fs_type={:?}, options={:?}, flags={:?}",
"mount source={:?}, dest={:?}, fs_type={:?}, options={:?}",
source,
destination,
fs_type,
options,
flags
options
);
nix::mount::mount(
@@ -779,20 +778,8 @@ pub async fn add_storages(
}
};
let mount_point = match res {
Err(e) => {
error!(
logger,
"add_storages failed, storage: {:?}, error: {:?} ", storage, e
);
let mut sb = sandbox.lock().await;
sb.unset_sandbox_storage(&storage.mount_point)
.map_err(|e| warn!(logger, "fail to unset sandbox storage {:?}", e))
.ok();
return Err(e);
}
Ok(m) => m,
};
// Todo need to rollback the mounted storage if err met.
let mount_point = res?;
if !mount_point.is_empty() {
mount_list.push(mount_point);
@@ -853,8 +840,7 @@ pub fn get_mount_fs_type_from_file(mount_file: &str, mount_point: &str) -> Resul
return Err(anyhow!("Invalid mount point {}", mount_point));
}
let content = fs::read_to_string(mount_file)
.map_err(|e| anyhow!("read mount file {}: {}", mount_file, e))?;
let content = fs::read_to_string(mount_file)?;
let re = Regex::new(format!("device .+ mounted on {} with fstype (.+)", mount_point).as_str())?;
@@ -1030,6 +1016,8 @@ fn parse_options(option_list: Vec<String>) -> HashMap<String, String> {
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::test_utils::TestUserType;
use crate::{skip_if_not_root, skip_loop_by_user, skip_loop_if_not_root, skip_loop_if_root};
use protobuf::RepeatedField;
use protocols::agent::FSGroup;
use std::fs::File;
@@ -1037,10 +1025,6 @@ mod tests {
use std::io::Write;
use std::path::PathBuf;
use tempfile::tempdir;
use test_utils::TestUserType;
use test_utils::{
skip_if_not_root, skip_loop_by_user, skip_loop_if_not_root, skip_loop_if_root,
};
#[test]
fn test_mount() {

View File

@@ -187,10 +187,9 @@ impl fmt::Debug for NamespaceType {
#[cfg(test)]
mod tests {
use super::{Namespace, NamespaceType};
use crate::mount::remove_mounts;
use crate::{mount::remove_mounts, skip_if_not_root};
use nix::sched::CloneFlags;
use tempfile::Builder;
use test_utils::skip_if_not_root;
#[tokio::test]
async fn test_setup_persistent_ns() {

View File

@@ -64,7 +64,7 @@ impl Handle {
pub async fn update_interface(&mut self, iface: &Interface) -> Result<()> {
// The reliable way to find link is using hardware address
// as filter. However, hardware filter might not be supported
// by netlink, we may have to dump link list and then find the
// by netlink, we may have to dump link list and the find the
// target link. filter using name or family is supported, but
// we cannot use that to find target link.
// let's try if hardware address filter works. -_-
@@ -178,7 +178,7 @@ impl Handle {
.with_context(|| format!("Failed to parse MAC address: {}", addr))?;
// Hardware filter might not be supported by netlink,
// we may have to dump link list and then find the target link.
// we may have to dump link list and the find the target link.
stream
.try_filter(|f| {
let result = f.nlas.iter().any(|n| match n {
@@ -523,15 +523,13 @@ impl Handle {
.as_ref()
.map(|to| to.address.as_str()) // Extract address field
.and_then(|addr| if addr.is_empty() { None } else { Some(addr) }) // Make sure it's not empty
.ok_or_else(|| anyhow!("Unable to determine ip address of ARP neighbor"))?;
.ok_or_else(|| anyhow!(nix::Error::EINVAL))?;
let ip = IpAddr::from_str(ip_address)
.map_err(|e| anyhow!("Failed to parse IP {}: {:?}", ip_address, e))?;
// Import rtnetlink objects that make sense only for this function
use packet::constants::{
NDA_UNSPEC, NLM_F_ACK, NLM_F_CREATE, NLM_F_REPLACE, NLM_F_REQUEST,
};
use packet::constants::{NDA_UNSPEC, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST};
use packet::neighbour::{NeighbourHeader, NeighbourMessage};
use packet::nlas::neighbour::Nla;
use packet::{NetlinkMessage, NetlinkPayload, RtnlMessage};
@@ -574,7 +572,7 @@ impl Handle {
// Send request and ACK
let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE;
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
let mut response = self.handle.request(req)?;
while let Some(message) = response.next().await {
@@ -614,12 +612,7 @@ fn parse_mac_address(addr: &str) -> Result<[u8; 6]> {
// Parse single Mac address block
let mut parse_next = || -> Result<u8> {
let v = u8::from_str_radix(
split
.next()
.ok_or_else(|| anyhow!("Invalid MAC address {}", addr))?,
16,
)?;
let v = u8::from_str_radix(split.next().ok_or_else(|| anyhow!(nix::Error::EINVAL))?, 16)?;
Ok(v)
};
@@ -777,10 +770,10 @@ impl Address {
#[cfg(test)]
mod tests {
use super::*;
use crate::skip_if_not_root;
use rtnetlink::packet;
use std::iter;
use std::process::Command;
use test_utils::skip_if_not_root;
#[tokio::test]
async fn find_link_by_name() {

View File

@@ -76,11 +76,11 @@ fn do_setup_guest_dns(logger: Logger, dns_list: Vec<String>, src: &str, dst: &st
#[cfg(test)]
mod tests {
use super::*;
use crate::skip_if_not_root;
use nix::mount;
use std::fs::File;
use std::io::Write;
use tempfile::tempdir;
use test_utils::skip_if_not_root;
#[test]
fn test_setup_guest_dns() {

View File

@@ -53,9 +53,9 @@ pub fn reseed_rng(data: &[u8]) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::skip_if_not_root;
use std::fs::File;
use std::io::prelude::*;
use test_utils::skip_if_not_root;
#[test]
fn test_reseed_rng() {

View File

@@ -34,10 +34,6 @@ use protocols::health::{
HealthCheckResponse, HealthCheckResponse_ServingStatus, VersionCheckResponse,
};
use protocols::types::Interface;
use protocols::{
agent_ttrpc_async as agent_ttrpc, health_ttrpc_async as health_ttrpc,
image_ttrpc_async as image_ttrpc,
};
use rustjail::cgroups::notifier;
use rustjail::container::{BaseContainer, Container, LinuxContainer};
use rustjail::process::Process;
@@ -53,7 +49,6 @@ use rustjail::process::ProcessOperations;
use crate::device::{
add_devices, get_virtio_blk_pci_device_name, update_device_cgroup, update_env_pci,
};
use crate::image_rpc;
use crate::linux_abi::*;
use crate::metrics::get_metrics;
use crate::mount::{add_storages, baremount, STORAGE_HANDLER_LIST};
@@ -85,12 +80,8 @@ use std::io::{BufRead, BufReader, Write};
use std::os::unix::fs::FileExt;
use std::path::PathBuf;
pub const CONTAINER_BASE: &str = "/run/kata-containers";
const CONTAINER_BASE: &str = "/run/kata-containers";
const MODPROBE_PATH: &str = "/sbin/modprobe";
const ANNO_K8S_IMAGE_NAME: &str = "io.kubernetes.cri.image-name";
const CONFIG_JSON: &str = "config.json";
const INIT_TRUSTED_STORAGE: &str = "/usr/bin/kata-init-trusted-storage";
const TRUSTED_STORAGE_DEVICE: &str = "/dev/trusted_store";
const IPTABLES_SAVE: &str = "/sbin/iptables-save";
const IPTABLES_RESTORE: &str = "/sbin/iptables-restore";
@@ -146,7 +137,7 @@ pub struct AgentService {
//
// ^[a-zA-Z0-9][a-zA-Z0-9_.-]+$
//
pub fn verify_cid(id: &str) -> Result<()> {
fn verify_cid(id: &str) -> Result<()> {
let mut chars = id.chars();
let valid = match chars.next() {
@@ -166,19 +157,6 @@ pub fn verify_cid(id: &str) -> Result<()> {
}
}
// Partially merge an OCI process specification into another one.
fn merge_oci_process(target: &mut oci::Process, source: &oci::Process) {
if target.args.is_empty() && !source.args.is_empty() {
target.args.append(&mut source.args.clone());
}
if target.cwd.is_empty() && !source.cwd.is_empty() {
target.cwd = String::from(&source.cwd);
}
target.env.append(&mut source.env.clone());
}
impl AgentService {
#[instrument]
async fn do_create_container(
@@ -187,7 +165,7 @@ impl AgentService {
) -> Result<()> {
let cid = req.container_id.clone();
kata_sys_util::validate::verify_id(&cid)?;
verify_cid(&cid)?;
let mut oci_spec = req.OCI.clone();
let use_sandbox_pidns = req.get_sandbox_pidns();
@@ -209,9 +187,6 @@ impl AgentService {
"receive createcontainer, storages: {:?}", &req.storages
);
// Merge the image bundle OCI spec into the container creation request OCI spec.
self.merge_bundle_oci(&mut oci).await?;
// Some devices need some extra processing (the ones invoked with
// --device for instance), and that's what this call is doing. It
// updates the devices listed in the OCI spec, so that they actually
@@ -219,30 +194,6 @@ impl AgentService {
// cannot predict everything from the caller.
add_devices(&req.devices.to_vec(), &mut oci, &self.sandbox).await?;
let linux = oci
.linux
.as_mut()
.ok_or_else(|| anyhow!("Spec didn't contain linux field"))?;
for specdev in &mut linux.devices {
let dev_major_minor = format!("{}:{}", specdev.major, specdev.minor);
if specdev.path == TRUSTED_STORAGE_DEVICE {
let data_integrity = AGENT_CONFIG.read().await.data_integrity;
info!(
sl!(),
"trusted_store device major:min {}, enable data integrity {}",
dev_major_minor,
data_integrity.to_string()
);
Command::new(INIT_TRUSTED_STORAGE)
.args(&[&dev_major_minor, &data_integrity.to_string()])
.output()
.expect("Failed to initialize confidential storage");
}
}
// Both rootfs and volumes (invoked with --volume for instance) will
// be processed the same way. The idea is to always mount any provided
// storage to the specified MountPoint, so that it will match what's
@@ -420,7 +371,7 @@ impl AgentService {
let mut process = req
.process
.into_option()
.ok_or_else(|| anyhow!("Unable to parse process from ExecProcessRequest"))?;
.ok_or_else(|| anyhow!(nix::Error::EINVAL))?;
// Apply any necessary corrections for PCI addresses
update_env_pci(&mut process.Env, &sandbox.pcimap)?;
@@ -462,22 +413,8 @@ impl AgentService {
if p.init && sig == libc::SIGTERM && !is_signal_handled(&proc_status_file, sig as u32) {
sig = libc::SIGKILL;
}
match p.signal(sig) {
Err(Errno::ESRCH) => {
info!(
sl!(),
"signal encounter ESRCH, continue";
"container-id" => cid.clone(),
"exec-id" => eid.clone(),
"pid" => p.pid,
"signal" => sig,
);
}
Err(err) => return Err(anyhow!(err)),
Ok(()) => (),
}
};
p.signal(sig)?;
}
if eid.is_empty() {
// eid is empty, signal all the remaining processes in the container cgroup
@@ -683,7 +620,7 @@ impl AgentService {
};
if reader.is_none() {
return Err(anyhow!("Unable to determine stream reader, is None"));
return Err(anyhow!(nix::Error::EINVAL));
}
let reader = reader.ok_or_else(|| anyhow!("cannot get stream reader"))?;
@@ -701,58 +638,10 @@ impl AgentService {
}
}
}
// When being passed an image name through a container annotation, merge its
// corresponding bundle OCI specification into the passed container creation one.
async fn merge_bundle_oci(&self, container_oci: &mut oci::Spec) -> Result<()> {
if let Some(image_name) = container_oci
.annotations
.get(&ANNO_K8S_IMAGE_NAME.to_string())
{
if let Some(container_id) = self.sandbox.clone().lock().await.images.get(image_name) {
let image_oci_config_path = Path::new(CONTAINER_BASE)
.join(container_id)
.join(CONFIG_JSON);
debug!(
sl!(),
"Image bundle config path: {:?}", image_oci_config_path
);
let image_oci =
oci::Spec::load(image_oci_config_path.to_str().ok_or_else(|| {
anyhow!(
"Invalid container image OCI config path {:?}",
image_oci_config_path
)
})?)
.context("load image bundle")?;
if let Some(container_root) = container_oci.root.as_mut() {
if let Some(image_root) = image_oci.root.as_ref() {
let root_path = Path::new(CONTAINER_BASE)
.join(container_id)
.join(image_root.path.clone());
container_root.path =
String::from(root_path.to_str().ok_or_else(|| {
anyhow!("Invalid container image root path {:?}", root_path)
})?);
}
}
if let Some(container_process) = container_oci.process.as_mut() {
if let Some(image_process) = image_oci.process.as_ref() {
merge_oci_process(container_process, image_process);
}
}
}
}
Ok(())
}
}
#[async_trait]
impl agent_ttrpc::AgentService for AgentService {
impl protocols::agent_ttrpc::AgentService for AgentService {
async fn create_container(
&self,
ctx: &TtrpcContext,
@@ -1638,7 +1527,7 @@ impl agent_ttrpc::AgentService for AgentService {
struct HealthService;
#[async_trait]
impl health_ttrpc::Health for HealthService {
impl protocols::health_ttrpc::Health for HealthService {
async fn check(
&self,
_ctx: &TtrpcContext,
@@ -1777,27 +1666,23 @@ async fn read_stream(reader: Arc<Mutex<ReadHalf<PipeStream>>>, l: usize) -> Resu
}
pub fn start(s: Arc<Mutex<Sandbox>>, server_address: &str) -> Result<TtrpcServer> {
let agent_service = Box::new(AgentService { sandbox: s.clone() })
as Box<dyn agent_ttrpc::AgentService + Send + Sync>;
let agent_service = Box::new(AgentService { sandbox: s })
as Box<dyn protocols::agent_ttrpc::AgentService + Send + Sync>;
let agent_worker = Arc::new(agent_service);
let health_service = Box::new(HealthService {}) as Box<dyn health_ttrpc::Health + Send + Sync>;
let health_service =
Box::new(HealthService {}) as Box<dyn protocols::health_ttrpc::Health + Send + Sync>;
let health_worker = Arc::new(health_service);
let image_service =
Box::new(image_rpc::ImageService::new(s)) as Box<dyn image_ttrpc::Image + Send + Sync>;
let aservice = protocols::agent_ttrpc::create_agent_service(agent_worker);
let aservice = agent_ttrpc::create_agent_service(agent_worker);
let hservice = health_ttrpc::create_health(health_worker);
let iservice = image_ttrpc::create_image(Arc::new(image_service));
let hservice = protocols::health_ttrpc::create_health(health_worker);
let server = TtrpcServer::new()
.bind(server_address)?
.register_service(aservice)
.register_service(hservice)
.register_service(iservice);
.register_service(hservice);
info!(sl!(), "ttRPC server started"; "address" => server_address);
@@ -1978,11 +1863,7 @@ fn do_copy_file(req: &CopyFileRequest) -> Result<()> {
let path = PathBuf::from(req.path.as_str());
if !path.starts_with(CONTAINER_BASE) {
return Err(anyhow!(
"Path {:?} does not start with {}",
path,
CONTAINER_BASE
));
return Err(anyhow!(nix::Error::EINVAL));
}
let parent = path.parent();
@@ -2003,38 +1884,6 @@ fn do_copy_file(req: &CopyFileRequest) -> Result<()> {
std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(req.dir_mode))?;
let sflag = stat::SFlag::from_bits_truncate(req.file_mode);
if sflag.contains(stat::SFlag::S_IFDIR) {
fs::create_dir(path.clone()).or_else(|e| {
if e.kind() != std::io::ErrorKind::AlreadyExists {
return Err(e);
}
Ok(())
})?;
std::fs::set_permissions(path.clone(), std::fs::Permissions::from_mode(req.file_mode))?;
unistd::chown(
&path,
Some(Uid::from_raw(req.uid as u32)),
Some(Gid::from_raw(req.gid as u32)),
)?;
return Ok(());
}
if sflag.contains(stat::SFlag::S_IFLNK) {
let src = PathBuf::from(String::from_utf8(req.data.clone()).unwrap());
unistd::symlinkat(&src, None, &path)?;
let path_str = CString::new(path.to_str().unwrap())?;
let ret = unsafe { libc::lchown(path_str.as_ptr(), req.uid as u32, req.gid as u32) };
Errno::result(ret).map(drop)?;
return Ok(());
}
let mut tmpfile = path.clone();
tmpfile.set_extension("tmp");
@@ -2100,26 +1949,18 @@ pub fn setup_bundle(cid: &str, spec: &mut Spec) -> Result<PathBuf> {
let spec_root_path = Path::new(&spec_root.path);
let bundle_path = Path::new(CONTAINER_BASE).join(cid);
let config_path = bundle_path.join(CONFIG_JSON);
let config_path = bundle_path.join("config.json");
let rootfs_path = bundle_path.join("rootfs");
let rootfs_exists = Path::new(&rootfs_path).exists();
info!(
sl!(),
"The rootfs_path is {:?} and exists: {}", rootfs_path, rootfs_exists
);
if !rootfs_exists {
fs::create_dir_all(&rootfs_path)?;
baremount(
spec_root_path,
&rootfs_path,
"bind",
MsFlags::MS_BIND,
"",
&sl!(),
)?;
}
fs::create_dir_all(&rootfs_path)?;
baremount(
spec_root_path,
&rootfs_path,
"bind",
MsFlags::MS_BIND,
"",
&sl!(),
)?;
let rootfs_path_name = rootfs_path
.to_str()
@@ -2190,12 +2031,14 @@ fn load_kernel_module(module: &protocols::agent::KernelModule) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::{namespace::Namespace, protocols::agent_ttrpc_async::AgentService as _};
use crate::{
assert_result, namespace::Namespace, protocols::agent_ttrpc::AgentService as _,
skip_if_not_root,
};
use nix::mount;
use nix::sched::{unshare, CloneFlags};
use oci::{Hook, Hooks, Linux, LinuxNamespace};
use tempfile::{tempdir, TempDir};
use test_utils::{assert_result, skip_if_not_root};
use ttrpc::{r#async::TtrpcContext, MessageHeader};
fn mk_ttrpc_context() -> TtrpcContext {
@@ -2261,7 +2104,6 @@ mod tests {
let result = load_kernel_module(&m);
assert!(result.is_err(), "load module should failed");
skip_if_not_root!();
// case 3: normal module.
// normally this module should eixsts...
m.name = "bridge".to_string();
@@ -2440,7 +2282,6 @@ mod tests {
if d.has_fd {
Some(wfd)
} else {
unistd::close(wfd).unwrap();
None
}
};
@@ -2475,14 +2316,13 @@ mod tests {
if !d.break_pipe {
unistd::close(rfd).unwrap();
}
// XXX: Do not close wfd.
// the fd will be closed on Process's dropping.
// unistd::close(wfd).unwrap();
unistd::close(wfd).unwrap();
let msg = format!("{}, result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
}
#[tokio::test]
async fn test_update_container_namespaces() {
#[derive(Debug)]
@@ -2850,6 +2690,233 @@ OtherField:other
}
}
#[tokio::test]
async fn test_verify_cid() {
#[derive(Debug)]
struct TestData<'a> {
id: &'a str,
expect_error: bool,
}
let tests = &[
TestData {
// Cannot be blank
id: "",
expect_error: true,
},
TestData {
// Cannot be a space
id: " ",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: ".",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: "-",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: "_",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: " a",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: ".a",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: "-a",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: "_a",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: "..",
expect_error: true,
},
TestData {
// Too short
id: "a",
expect_error: true,
},
TestData {
// Too short
id: "z",
expect_error: true,
},
TestData {
// Too short
id: "A",
expect_error: true,
},
TestData {
// Too short
id: "Z",
expect_error: true,
},
TestData {
// Too short
id: "0",
expect_error: true,
},
TestData {
// Too short
id: "9",
expect_error: true,
},
TestData {
// Must start with an alphanumeric
id: "-1",
expect_error: true,
},
TestData {
id: "/",
expect_error: true,
},
TestData {
id: "a/",
expect_error: true,
},
TestData {
id: "a/../",
expect_error: true,
},
TestData {
id: "../a",
expect_error: true,
},
TestData {
id: "../../a",
expect_error: true,
},
TestData {
id: "../../../a",
expect_error: true,
},
TestData {
id: "foo/../bar",
expect_error: true,
},
TestData {
id: "foo bar",
expect_error: true,
},
TestData {
id: "a.",
expect_error: false,
},
TestData {
id: "a..",
expect_error: false,
},
TestData {
id: "aa",
expect_error: false,
},
TestData {
id: "aa.",
expect_error: false,
},
TestData {
id: "hello..world",
expect_error: false,
},
TestData {
id: "hello/../world",
expect_error: true,
},
TestData {
id: "aa1245124sadfasdfgasdga.",
expect_error: false,
},
TestData {
id: "aAzZ0123456789_.-",
expect_error: false,
},
TestData {
id: "abcdefghijklmnopqrstuvwxyz0123456789.-_",
expect_error: false,
},
TestData {
id: "0123456789abcdefghijklmnopqrstuvwxyz.-_",
expect_error: false,
},
TestData {
id: " abcdefghijklmnopqrstuvwxyz0123456789.-_",
expect_error: true,
},
TestData {
id: ".abcdefghijklmnopqrstuvwxyz0123456789.-_",
expect_error: true,
},
TestData {
id: "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_",
expect_error: false,
},
TestData {
id: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.-_",
expect_error: false,
},
TestData {
id: " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_",
expect_error: true,
},
TestData {
id: ".ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_",
expect_error: true,
},
TestData {
id: "/a/b/c",
expect_error: true,
},
TestData {
id: "a/b/c",
expect_error: true,
},
TestData {
id: "foo/../../../etc/passwd",
expect_error: true,
},
TestData {
id: "../../../../../../etc/motd",
expect_error: true,
},
TestData {
id: "/etc/passwd",
expect_error: true,
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = verify_cid(d.id);
let msg = format!("{}, result: {:?}", msg, result);
if result.is_ok() {
assert!(!d.expect_error, "{}", msg);
} else {
assert!(d.expect_error, "{}", msg);
}
}
}
#[tokio::test]
async fn test_volume_capacity_stats() {
skip_if_not_root!();

View File

@@ -60,7 +60,6 @@ pub struct Sandbox {
pub event_tx: Option<Sender<String>>,
pub bind_watcher: BindWatcher,
pub pcimap: HashMap<pci::Address, pci::Address>,
pub images: HashMap<String, String>,
}
impl Sandbox {
@@ -94,7 +93,6 @@ impl Sandbox {
event_tx: Some(tx),
bind_watcher: BindWatcher::new(),
pcimap: HashMap::new(),
images: HashMap::new(),
})
}
@@ -329,7 +327,7 @@ impl Sandbox {
// Reject non-file, symlinks and non-executable files
if !entry.file_type()?.is_file()
|| entry.file_type()?.is_symlink()
|| entry.metadata()?.permissions().mode() & 0o111 == 0
|| entry.metadata()?.permissions().mode() & 0o777 & 0o111 == 0
{
continue;
}
@@ -473,7 +471,7 @@ fn online_memory(logger: &Logger) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::mount::baremount;
use crate::{mount::baremount, skip_if_not_root};
use anyhow::{anyhow, Error};
use nix::mount::MsFlags;
use oci::{Linux, Root, Spec};
@@ -486,7 +484,6 @@ mod tests {
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use tempfile::{tempdir, Builder, TempDir};
use test_utils::skip_if_not_root;
fn bind_mount(src: &str, dst: &str, logger: &Logger) -> Result<(), Error> {
let src_path = Path::new(src);

View File

@@ -24,7 +24,7 @@ async fn handle_sigchild(logger: Logger, sandbox: Arc<Mutex<Sandbox>>) -> Result
loop {
// Avoid reaping the undesirable child's signal, e.g., execute_hook's
// The lock should be released immediately.
let _ = rustjail::container::WAIT_PID_LOCKER.lock().await;
rustjail::container::WAIT_PID_LOCKER.lock().await;
let result = wait::waitpid(
Some(Pid::from_raw(-1)),
Some(WaitPidFlag::WNOHANG | WaitPidFlag::__WALL),

View File

@@ -0,0 +1,99 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#![allow(clippy::module_inception)]
#[cfg(test)]
pub mod test_utils {
#[derive(Debug, PartialEq)]
pub enum TestUserType {
RootOnly,
NonRootOnly,
Any,
}
#[macro_export]
macro_rules! skip_if_root {
() => {
if nix::unistd::Uid::effective().is_root() {
println!("INFO: skipping {} which needs non-root", module_path!());
return;
}
};
}
#[macro_export]
macro_rules! skip_if_not_root {
() => {
if !nix::unistd::Uid::effective().is_root() {
println!("INFO: skipping {} which needs root", module_path!());
return;
}
};
}
#[macro_export]
macro_rules! skip_loop_if_root {
($msg:expr) => {
if nix::unistd::Uid::effective().is_root() {
println!(
"INFO: skipping loop {} in {} which needs non-root",
$msg,
module_path!()
);
continue;
}
};
}
#[macro_export]
macro_rules! skip_loop_if_not_root {
($msg:expr) => {
if !nix::unistd::Uid::effective().is_root() {
println!(
"INFO: skipping loop {} in {} which needs root",
$msg,
module_path!()
);
continue;
}
};
}
// Parameters:
//
// 1: expected Result
// 2: actual Result
// 3: string used to identify the test on error
#[macro_export]
macro_rules! assert_result {
($expected_result:expr, $actual_result:expr, $msg:expr) => {
if $expected_result.is_ok() {
let expected_value = $expected_result.as_ref().unwrap();
let actual_value = $actual_result.unwrap();
assert!(*expected_value == actual_value, "{}", $msg);
} else {
assert!($actual_result.is_err(), "{}", $msg);
let expected_error = $expected_result.as_ref().unwrap_err();
let expected_error_msg = format!("{:?}", expected_error);
let actual_error_msg = format!("{:?}", $actual_result.unwrap_err());
assert!(expected_error_msg == actual_error_msg, "{}", $msg);
}
};
}
#[macro_export]
macro_rules! skip_loop_by_user {
($msg:expr, $user:expr) => {
if $user == TestUserType::RootOnly {
skip_loop_if_not_root!($msg);
} else if $user == TestUserType::NonRootOnly {
skip_loop_if_root!($msg);
}
};
}
}

View File

@@ -69,8 +69,6 @@ macro_rules! trace_rpc_call {
propagator.extract(&extract_carrier_from_ttrpc($ctx))
});
info!(sl!(), "rpc call from shim to agent: {:?}", $name);
// generate tracing span
let rpc_span = span!(tracing::Level::INFO, $name, "mod"="rpc.rs", req=?$req);

View File

@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::SystemTime;
use anyhow::{anyhow, ensure, Context, Result};
use anyhow::{ensure, Context, Result};
use async_recursion::async_recursion;
use nix::mount::{umount, MsFlags};
use nix::unistd::{Gid, Uid};
@@ -34,13 +34,9 @@ const MAX_SIZE_PER_WATCHABLE_MOUNT: u64 = 1024 * 1024;
/// How often to check for modified files.
const WATCH_INTERVAL_SECS: u64 = 2;
/// Destination path for tmpfs, which used by the golang runtime
/// Destination path for tmpfs
const WATCH_MOUNT_POINT_PATH: &str = "/run/kata-containers/shared/containers/watchable/";
/// Destination path for tmpfs for runtime-rs passthrough file sharing
const WATCH_MOUNT_POINT_PATH_PASSTHROUGH: &str =
"/run/kata-containers/shared/containers/passthrough/watchable/";
/// Represents a single watched storage entry which may have multiple files to watch.
#[derive(Default, Debug, Clone)]
struct Storage {
@@ -455,7 +451,7 @@ impl BindWatcher {
) -> Result<()> {
if self.watch_thread.is_none() {
// Virtio-fs shared path is RO by default, so we back the target-mounts by tmpfs.
self.mount(logger).await.context("mount watch directory")?;
self.mount(logger).await?;
// Spawn background thread to monitor changes
self.watch_thread = Some(Self::spawn_watcher(
@@ -504,28 +500,16 @@ impl BindWatcher {
}
async fn mount(&self, logger: &Logger) -> Result<()> {
// the watchable directory is created on the host side.
// here we can only check if it exist.
// first we will check the default WATCH_MOUNT_POINT_PATH,
// and then check WATCH_MOUNT_POINT_PATH_PASSTHROUGH
// in turn which are introduced by runtime-rs file sharing.
let watchable_dir = if Path::new(WATCH_MOUNT_POINT_PATH).is_dir() {
WATCH_MOUNT_POINT_PATH
} else if Path::new(WATCH_MOUNT_POINT_PATH_PASSTHROUGH).is_dir() {
WATCH_MOUNT_POINT_PATH_PASSTHROUGH
} else {
return Err(anyhow!("watchable mount source not found"));
};
fs::create_dir_all(WATCH_MOUNT_POINT_PATH).await?;
baremount(
Path::new("tmpfs"),
Path::new(watchable_dir),
Path::new(WATCH_MOUNT_POINT_PATH),
"tmpfs",
MsFlags::empty(),
"",
logger,
)
.context("baremount watchable mount path")?;
)?;
Ok(())
}
@@ -536,12 +520,7 @@ impl BindWatcher {
handle.abort();
}
// try umount watchable mount path in turn
if Path::new(WATCH_MOUNT_POINT_PATH).is_dir() {
let _ = umount(WATCH_MOUNT_POINT_PATH);
} else if Path::new(WATCH_MOUNT_POINT_PATH_PASSTHROUGH).is_dir() {
let _ = umount(WATCH_MOUNT_POINT_PATH_PASSTHROUGH);
}
let _ = umount(WATCH_MOUNT_POINT_PATH);
}
}
@@ -549,11 +528,10 @@ impl BindWatcher {
mod tests {
use super::*;
use crate::mount::is_mounted;
use crate::skip_if_not_root;
use nix::unistd::{Gid, Uid};
use scopeguard::defer;
use std::fs;
use std::thread;
use test_utils::skip_if_not_root;
async fn create_test_storage(dir: &Path, id: &str) -> Result<(protos::Storage, PathBuf)> {
let src_path = dir.join(format!("src{}", id));
@@ -1297,19 +1275,13 @@ mod tests {
let logger = slog::Logger::root(slog::Discard, o!());
let mut watcher = BindWatcher::default();
for mount_point in [WATCH_MOUNT_POINT_PATH, WATCH_MOUNT_POINT_PATH_PASSTHROUGH] {
fs::create_dir_all(mount_point).unwrap();
// ensure the watchable directory is deleted.
defer!(fs::remove_dir_all(mount_point).unwrap());
watcher.mount(&logger).await.unwrap();
assert!(is_mounted(WATCH_MOUNT_POINT_PATH).unwrap());
watcher.mount(&logger).await.unwrap();
assert!(is_mounted(mount_point).unwrap());
thread::sleep(Duration::from_millis(20));
thread::sleep(Duration::from_millis(20));
watcher.cleanup();
assert!(!is_mounted(mount_point).unwrap());
}
watcher.cleanup();
assert!(!is_mounted(WATCH_MOUNT_POINT_PATH).unwrap());
}
#[tokio::test]
@@ -1317,10 +1289,6 @@ mod tests {
async fn spawn_thread() {
skip_if_not_root!();
fs::create_dir_all(WATCH_MOUNT_POINT_PATH).unwrap();
// ensure the watchable directory is deleted.
defer!(fs::remove_dir_all(WATCH_MOUNT_POINT_PATH).unwrap());
let source_dir = tempfile::tempdir().unwrap();
fs::write(source_dir.path().join("1.txt"), "one").unwrap();
@@ -1351,10 +1319,6 @@ mod tests {
async fn verify_container_cleanup_watching() {
skip_if_not_root!();
fs::create_dir_all(WATCH_MOUNT_POINT_PATH).unwrap();
// ensure the watchable directory is deleted.
defer!(fs::remove_dir_all(WATCH_MOUNT_POINT_PATH).unwrap());
let source_dir = tempfile::tempdir().unwrap();
fs::write(source_dir.path().join("1.txt"), "one").unwrap();

View File

@@ -3,12 +3,11 @@ name = "vsock-exporter"
version = "0.1.0"
authors = ["James O. D. Hunt <james.o.hunt@intel.com>"]
edition = "2018"
license = "Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nix = "0.24.2"
nix = "0.23.0"
libc = "0.2.94"
thiserror = "1.0.26"
opentelemetry = { version = "0.14.0", features=["serialize"] }

View File

@@ -1,3 +0,0 @@
target
Cargo.lock
.idea

View File

@@ -1,67 +0,0 @@
[package]
name = "dragonball"
version = "0.1.0"
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
description = "A secure sandbox for Kata Containers"
keywords = ["kata-containers", "sandbox", "vmm", "dragonball"]
homepage = "https://katacontainers.io/"
repository = "https://github.com/kata-containers/kata-containers.git"
license = "Apache-2.0"
edition = "2018"
[dependencies]
arc-swap = "1.5.0"
bytes = "1.1.0"
dbs-address-space = "0.1.0"
dbs-allocator = "0.1.0"
dbs-arch = "0.1.0"
dbs-boot = "0.2.0"
dbs-device = "0.1.0"
dbs-interrupt = { version = "0.1.0", features = ["kvm-irq"] }
dbs-legacy-devices = "0.1.0"
dbs-upcall = { version = "0.1.0", optional = true }
dbs-utils = "0.1.0"
dbs-virtio-devices = { version = "0.1.0", optional = true, features = ["virtio-mmio"] }
kvm-bindings = "0.5.0"
kvm-ioctls = "0.11.0"
lazy_static = "1.2"
libc = "0.2.39"
linux-loader = "0.6.0"
log = "0.4.14"
nix = "0.24.2"
seccompiler = "0.2.0"
serde = "1.0.27"
serde_derive = "1.0.27"
serde_json = "1.0.9"
slog = "2.5.2"
slog-scope = "4.4.0"
thiserror = "1"
vmm-sys-util = "0.10.0"
virtio-queue = { version = "0.4.0", optional = true }
vm-memory = { version = "0.9.0", features = ["backend-mmap"] }
[dev-dependencies]
slog-term = "2.9.0"
slog-async = "2.7.0"
test-utils = { path = "../libs/test-utils" }
[features]
acpi = []
atomic-guest-memory = [ "vm-memory/backend-atomic" ]
hotplug = ["virtio-vsock"]
virtio-vsock = ["dbs-virtio-devices/virtio-vsock", "virtio-queue"]
virtio-blk = ["dbs-virtio-devices/virtio-blk", "virtio-queue"]
virtio-net = ["dbs-virtio-devices/virtio-net", "virtio-queue"]
# virtio-fs only work on atomic-guest-memory
virtio-fs = ["dbs-virtio-devices/virtio-fs", "virtio-queue", "atomic-guest-memory"]
[patch.'crates-io']
dbs-device = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-interrupt = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-legacy-devices = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-upcall = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-utils = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-virtio-devices = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-boot = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-arch = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }
dbs-address-space = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "c3d7831aee7c3962b8a90f0afbfd0fb7e4d30323" }

View File

@@ -1 +0,0 @@
../../LICENSE

View File

@@ -1,47 +0,0 @@
# Copyright (c) 2019-2022 Alibaba Cloud. All rights reserved.
# Copyright (c) 2019-2022 Ant Group. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
include ../../utils.mk
ifeq ($(ARCH), s390x)
default build check test clippy:
@echo "s390x not support currently"
exit 0
else
default: build
build:
@echo "INFO: cargo build..."
cargo build --all-features --target $(TRIPLE)
check: clippy format
clippy:
@echo "INFO: cargo clippy..."
cargo clippy --all-targets --all-features \
-- \
-D warnings
vendor:
@echo "INFO: vendor do nothing.."
format:
@echo "INFO: cargo fmt..."
cargo fmt -- --check
clean:
cargo clean
test:
ifdef SUPPORT_VIRTUALIZATION
cargo test --all-features --target $(TRIPLE) -- --nocapture
else
@echo "INFO: skip testing dragonball, it need virtualization support."
exit 0
endif
endif # ifeq ($(ARCH), s390x)
.DEFAULT_GOAL := default

View File

@@ -1,40 +0,0 @@
# Introduction
`Dragonball Sandbox` is a light-weight virtual machine manager (VMM) based on Linux Kernel-based Virtual Machine (KVM),
which is optimized for container workloads with:
- container image management and acceleration service
- flexible and high-performance virtual device drivers
- low CPU and memory overhead
- minimal startup time
- optimized concurrent startup speed
`Dragonball Sandbox` aims to provide a simple solution for the Kata Containers community. It is integrated into Kata 3.0
runtime as a built-in VMM and gives users an out-of-the-box Kata Containers experience without complex environment setup
and configuration process.
# Getting Started
[TODO](https://github.com/kata-containers/kata-containers/issues/4302)
# Documentation
Device: [Device Document](docs/device.md)
vCPU: [vCPU Document](docs/vcpu.md)
API: [API Document](docs/api.md)
Currently, the documents are still actively adding.
You could see the [official documentation](docs/) page for more details.
# Supported Architectures
- x86-64
- aarch64
# Supported Kernel
[TODO](https://github.com/kata-containers/kata-containers/issues/4303)
# Acknowledgement
Part of the code is based on the [Cloud Hypervisor](https://github.com/cloud-hypervisor/cloud-hypervisor) project, [`crosvm`](https://github.com/google/crosvm) project and [Firecracker](https://github.com/firecracker-microvm/firecracker) project. They are all rust written virtual machine managers with advantages on safety and security.
`Dragonball sandbox` is designed to be a VMM that is customized for Kata Containers and we will focus on optimizing container workloads for Kata ecosystem. The focus on the Kata community is what differentiates us from other rust written virtual machines.
# License
`Dragonball` is licensed under [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0.

View File

@@ -1,27 +0,0 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,27 +0,0 @@
# API
We provide plenty API for Kata runtime to interact with `Dragonball` virtual machine manager.
This document provides the introduction for each of them.
## `ConfigureBootSource`
Configure the boot source of the VM using `BootSourceConfig`. This action can only be called before the VM has booted.
### Boot Source Config
1. `kernel_path`: Path of the kernel image. `Dragonball` only supports compressed kernel image for now.
2. `initrd_path`: Path of the initrd (could be None)
3. `boot_args`: Boot arguments passed to the kernel (could be None)
## `SetVmConfiguration`
Set virtual machine configuration using `VmConfigInfo` to initialize VM.
### VM Config Info
1. `vcpu_count`: Number of vCPU to start. Currently we only support up to 255 vCPUs.
2. `max_vcpu_count`: Max number of vCPU can be added through CPU hotplug.
3. `cpu_pm`: CPU power management.
4. `cpu_topology`: CPU topology information (including `threads_per_core`, `cores_per_die`, `dies_per_socket` and `sockets`).
5. `vpmu_feature`: `vPMU` feature level.
6. `mem_type`: Memory type that can be either `hugetlbfs` or `shmem`, default is `shmem`.
7. `mem_file_path` : Memory file path.
8. `mem_size_mib`: The memory size in MiB. The maximum memory size is 1TB.
9. `serial_path`: Optional sock path.

View File

@@ -1,20 +0,0 @@
# Device
## Device Manager
Currently we have following device manager:
| Name | Description |
| --- | --- |
| [address space manager](../src/address_space_manager.rs) | abstracts virtual machine's physical management and provide mapping for guest virtual memory and MMIO ranges of emulated virtual devices, pass-through devices and vCPU |
| [config manager](../src/config_manager.rs) | provides abstractions for configuration information |
| [console manager](../src/device_manager/console_manager.rs) | provides management for all console devices |
| [resource manager](../src/resource_manager.rs) |provides resource management for `legacy_irq_pool`, `msi_irq_pool`, `pio_pool`, `mmio_pool`, `mem_pool`, `kvm_mem_slot_pool` with builder `ResourceManagerBuilder` |
| [VSOCK device manager](../src/device_manager/vsock_dev_mgr.rs) | provides configuration info for `VIRTIO-VSOCK` and management for all VSOCK devices |
## Device supported
`VIRTIO-VSOCK`
`i8042`
`COM1`
`COM2`

View File

@@ -1,42 +0,0 @@
# vCPU
## vCPU Manager
The vCPU manager is to manage all vCPU related actions, we will dive into some of the important structure members in this doc.
For now, aarch64 vCPU support is still under development, we'll introduce it when we merge `runtime-rs` to the master branch. (issue: #4445)
### vCPU config
`VcpuConfig` is used to configure guest overall CPU info.
`boot_vcpu_count` is used to define the initial vCPU number.
`max_vcpu_count` is used to define the maximum vCPU number and it's used for the upper boundary for CPU hotplug feature
`thread_per_core`, `cores_per_die`, `dies_per_socket` and `socket` are used to define CPU topology.
`vpmu_feature` is used to define `vPMU` feature level.
If `vPMU` feature is `Disabled`, it means `vPMU` feature is off (by default).
If `vPMU` feature is `LimitedlyEnabled`, it means minimal `vPMU` counters are supported (cycles and instructions).
If `vPMU` feature is `FullyEnabled`, it means all `vPMU` counters are supported
## vCPU State
There are four states for vCPU state machine: `running`, `paused`, `waiting_exit`, `exited`. There is a state machine to maintain the task flow.
When the vCPU is created, it'll turn to `paused` state. After vCPU resource is ready at VMM, it'll send a `Resume` event to the vCPU thread, and then vCPU state will change to `running`.
During the `running` state, VMM will catch vCPU exit and execute different logic according to the exit reason.
If the VMM catch some exit reasons that it cannot handle, the state will change to `waiting_exit` and VMM will stop the virtual machine.
When the state switches to `waiting_exit`, an exit event will be sent to vCPU `exit_evt`, event manager will detect the change in `exit_evt` and set VMM `exit_evt_flag` as 1. A thread serving for VMM event loop will check `exit_evt_flag` and if the flag is 1, it'll stop the VMM.
When the VMM is stopped / destroyed, the state will change to `exited`.
## vCPU Hot plug
Since `Dragonball Sandbox` doesn't support virtualization of ACPI system, we use [`upcall`](https://github.com/openanolis/dragonball-sandbox/tree/main/crates/dbs-upcall) to establish a direct communication channel between `Dragonball` and Guest in order to trigger vCPU hotplug.
To use `upcall`, kernel patches are needed, you can get the patches from [`upcall`](https://github.com/openanolis/dragonball-sandbox/tree/main/crates/dbs-upcall) page, and we'll provide a ready-to-use guest kernel binary for you to try.
vCPU hot plug / hot unplug range is [1, `max_vcpu_count`]. Operations not in this range will be invalid.

View File

@@ -1,892 +0,0 @@
// Copyright (C) 2019-2022 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//! Address space abstraction to manage virtual machine's physical address space.
//!
//! The AddressSpace abstraction is introduced to manage virtual machine's physical address space.
//! The regions in virtual machine's physical address space may be used to:
//! 1) map guest virtual memory
//! 2) map MMIO ranges for emulated virtual devices, such as virtio-fs DAX window.
//! 3) map MMIO ranges for pass-through devices, such as PCI device BARs.
//! 4) map MMIO ranges for to vCPU, such as local APIC.
//! 5) not used/available
//!
//! A related abstraction, vm_memory::GuestMemory, is used to access guest virtual memory only.
//! In other words, AddressSpace is the resource owner, and GuestMemory is an accessor for guest
//! virtual memory.
use std::collections::{BTreeMap, HashMap};
use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use dbs_address_space::{
AddressSpace, AddressSpaceError, AddressSpaceLayout, AddressSpaceRegion,
AddressSpaceRegionType, NumaNode, NumaNodeInfo, MPOL_MF_MOVE, MPOL_PREFERRED,
};
use dbs_allocator::Constraint;
use kvm_bindings::kvm_userspace_memory_region;
use kvm_ioctls::VmFd;
use log::{debug, error, info, warn};
use nix::sys::mman;
use nix::unistd::dup;
#[cfg(feature = "atomic-guest-memory")]
use vm_memory::GuestMemoryAtomic;
use vm_memory::{
address::Address, FileOffset, GuestAddress, GuestAddressSpace, GuestMemoryMmap,
GuestMemoryRegion, GuestRegionMmap, GuestUsize, MemoryRegionAddress, MmapRegion,
};
use crate::resource_manager::ResourceManager;
use crate::vm::NumaRegionInfo;
#[cfg(not(feature = "atomic-guest-memory"))]
/// Concrete GuestAddressSpace type used by the VMM.
pub type GuestAddressSpaceImpl = Arc<GuestMemoryMmap>;
#[cfg(feature = "atomic-guest-memory")]
/// Concrete GuestAddressSpace type used by the VMM.
pub type GuestAddressSpaceImpl = GuestMemoryAtomic<GuestMemoryMmap>;
/// Concrete GuestMemory type used by the VMM.
pub type GuestMemoryImpl = <Arc<vm_memory::GuestMemoryMmap> as GuestAddressSpace>::M;
/// Concrete GuestRegion type used by the VMM.
pub type GuestRegionImpl = GuestRegionMmap;
// Maximum number of working threads for memory pre-allocation.
const MAX_PRE_ALLOC_THREAD: u64 = 16;
// Control the actual number of pre-allocating threads. After several performance tests, we decide to use one thread to do pre-allocating for every 4G memory.
const PRE_ALLOC_GRANULARITY: u64 = 32;
// We don't have plan to support mainframe computer and only focus on PC servers.
// 64 as max nodes should be enough for now.
const MAX_NODE: u32 = 64;
// We will split the memory region if it conflicts with the MMIO hole.
// But if the space below the MMIO hole is smaller than the MINIMAL_SPLIT_SPACE, we won't split the memory region in order to enhance performance.
const MINIMAL_SPLIT_SPACE: u64 = 128 << 20;
/// Errors associated with virtual machine address space management.
#[derive(Debug, thiserror::Error)]
pub enum AddressManagerError {
/// Invalid address space operation.
#[error("invalid address space operation")]
InvalidOperation,
/// Invalid address range.
#[error("invalid address space region (0x{0:x}, 0x{1:x})")]
InvalidAddressRange(u64, GuestUsize),
/// No available mem address.
#[error("no available mem address")]
NoAvailableMemAddress,
/// No available kvm slotse.
#[error("no available kvm slots")]
NoAvailableKvmSlot,
/// Address manager failed to create memfd to map anonymous memory.
#[error("address manager failed to create memfd to map anonymous memory")]
CreateMemFd(#[source] nix::Error),
/// Address manager failed to open memory file.
#[error("address manager failed to open memory file")]
OpenFile(#[source] std::io::Error),
/// Memory file provided is invalid due to empty file path, non-existent file path and other possible mistakes.
#[error("memory file provided to address manager {0} is invalid")]
FileInvalid(String),
/// Memory file provided is invalid due to empty memory type
#[error("memory type provided to address manager {0} is invalid")]
TypeInvalid(String),
/// Failed to set size for memory file.
#[error("address manager failed to set size for memory file")]
SetFileSize(#[source] std::io::Error),
/// Failed to unlink memory file.
#[error("address manager failed to unlink memory file")]
UnlinkFile(#[source] nix::Error),
/// Failed to duplicate fd of memory file.
#[error("address manager failed to duplicate memory file descriptor")]
DupFd(#[source] nix::Error),
/// Failure in accessing the memory located at some address.
#[error("address manager failed to access guest memory located at 0x{0:x}")]
AccessGuestMemory(u64, #[source] vm_memory::mmap::Error),
/// Failed to create GuestMemory
#[error("address manager failed to create guest memory object")]
CreateGuestMemory(#[source] vm_memory::Error),
/// Failure in initializing guest memory.
#[error("address manager failed to initialize guest memory")]
GuestMemoryNotInitialized,
/// Failed to mmap() guest memory
#[error("address manager failed to mmap() guest memory into current process")]
MmapGuestMemory(#[source] vm_memory::mmap::MmapRegionError),
/// Failed to set KVM memory slot.
#[error("address manager failed to configure KVM memory slot")]
KvmSetMemorySlot(#[source] kvm_ioctls::Error),
/// Failed to set madvise on AddressSpaceRegion
#[error("address manager failed to set madvice() on guest memory region")]
Madvise(#[source] nix::Error),
/// join threads fail
#[error("address manager failed to join threads")]
JoinFail,
/// Failed to create Address Space Region
#[error("address manager failed to create Address Space Region {0}")]
CreateAddressSpaceRegion(#[source] AddressSpaceError),
}
type Result<T> = std::result::Result<T, AddressManagerError>;
/// Parameters to configure address space creation operations.
pub struct AddressSpaceMgrBuilder<'a> {
mem_type: &'a str,
mem_file: &'a str,
mem_index: u32,
mem_suffix: bool,
mem_prealloc: bool,
dirty_page_logging: bool,
vmfd: Option<Arc<VmFd>>,
}
impl<'a> AddressSpaceMgrBuilder<'a> {
/// Create a new [`AddressSpaceMgrBuilder`] object.
pub fn new(mem_type: &'a str, mem_file: &'a str) -> Result<Self> {
if mem_type.is_empty() {
return Err(AddressManagerError::TypeInvalid(mem_type.to_string()));
}
Ok(AddressSpaceMgrBuilder {
mem_type,
mem_file,
mem_index: 0,
mem_suffix: true,
mem_prealloc: false,
dirty_page_logging: false,
vmfd: None,
})
}
/// Enable/disable adding numbered suffix to memory file path.
/// This feature could be useful to generate hugetlbfs files with number suffix. (e.g. shmem0, shmem1)
pub fn toggle_file_suffix(&mut self, enabled: bool) {
self.mem_suffix = enabled;
}
/// Enable/disable memory pre-allocation.
/// Enable this feature could improve performance stability at the start of workload by avoiding page fault.
/// Disable this feature may influence performance stability but the cpu resource consumption and start-up time will decrease.
pub fn toggle_prealloc(&mut self, prealloc: bool) {
self.mem_prealloc = prealloc;
}
/// Enable/disable KVM dirty page logging.
pub fn toggle_dirty_page_logging(&mut self, logging: bool) {
self.dirty_page_logging = logging;
}
/// Set KVM [`VmFd`] handle to configure memory slots.
pub fn set_kvm_vm_fd(&mut self, vmfd: Arc<VmFd>) -> Option<Arc<VmFd>> {
let mut existing_vmfd = None;
if self.vmfd.is_some() {
existing_vmfd = self.vmfd.clone();
}
self.vmfd = Some(vmfd);
existing_vmfd
}
/// Build a ['AddressSpaceMgr'] using the configured parameters.
pub fn build(
self,
res_mgr: &ResourceManager,
numa_region_infos: &[NumaRegionInfo],
) -> Result<AddressSpaceMgr> {
let mut mgr = AddressSpaceMgr::default();
mgr.create_address_space(res_mgr, numa_region_infos, self)?;
Ok(mgr)
}
fn get_next_mem_file(&mut self) -> String {
if self.mem_suffix {
let path = format!("{}{}", self.mem_file, self.mem_index);
self.mem_index += 1;
path
} else {
self.mem_file.to_string()
}
}
}
/// Struct to manage virtual machine's physical address space.
pub struct AddressSpaceMgr {
address_space: Option<AddressSpace>,
vm_as: Option<GuestAddressSpaceImpl>,
base_to_slot: Arc<Mutex<HashMap<u64, u32>>>,
prealloc_handlers: Vec<thread::JoinHandle<()>>,
prealloc_exit: Arc<AtomicBool>,
numa_nodes: BTreeMap<u32, NumaNode>,
}
impl AddressSpaceMgr {
/// Query address space manager is initialized or not
pub fn is_initialized(&self) -> bool {
self.address_space.is_some()
}
/// Gets address space.
pub fn address_space(&self) -> Option<&AddressSpace> {
self.address_space.as_ref()
}
/// Create the address space for a virtual machine.
///
/// This method is designed to be called when starting up a virtual machine instead of at
/// runtime, so it's expected the virtual machine will be tore down and no strict error recover.
pub fn create_address_space(
&mut self,
res_mgr: &ResourceManager,
numa_region_infos: &[NumaRegionInfo],
mut param: AddressSpaceMgrBuilder,
) -> Result<()> {
let mut regions = Vec::new();
let mut start_addr = dbs_boot::layout::GUEST_MEM_START;
// Create address space regions.
for info in numa_region_infos.iter() {
info!("numa_region_info {:?}", info);
// convert size_in_mib to bytes
let size = info
.size
.checked_shl(20)
.ok_or(AddressManagerError::InvalidOperation)?;
// Guest memory does not intersect with the MMIO hole.
// TODO: make it work for ARM (issue #4307)
if start_addr > dbs_boot::layout::MMIO_LOW_END
|| start_addr + size <= dbs_boot::layout::MMIO_LOW_START
{
let region = self.create_region(start_addr, size, info, &mut param)?;
regions.push(region);
start_addr = start_addr
.checked_add(size)
.ok_or(AddressManagerError::InvalidOperation)?;
} else {
// Add guest memory below the MMIO hole, avoid splitting the memory region
// if the available address region is small than MINIMAL_SPLIT_SPACE MiB.
let mut below_size = dbs_boot::layout::MMIO_LOW_START
.checked_sub(start_addr)
.ok_or(AddressManagerError::InvalidOperation)?;
if below_size < (MINIMAL_SPLIT_SPACE) {
below_size = 0;
} else {
let region = self.create_region(start_addr, below_size, info, &mut param)?;
regions.push(region);
}
// Add guest memory above the MMIO hole
let above_start = dbs_boot::layout::MMIO_LOW_END + 1;
let above_size = size
.checked_sub(below_size)
.ok_or(AddressManagerError::InvalidOperation)?;
let region = self.create_region(above_start, above_size, info, &mut param)?;
regions.push(region);
start_addr = above_start
.checked_add(above_size)
.ok_or(AddressManagerError::InvalidOperation)?;
}
}
// Create GuestMemory object
let mut vm_memory = GuestMemoryMmap::new();
for reg in regions.iter() {
// Allocate used guest memory addresses.
// These addresses are statically allocated, resource allocation/update should not fail.
let constraint = Constraint::new(reg.len())
.min(reg.start_addr().raw_value())
.max(reg.last_addr().raw_value());
let _key = res_mgr
.allocate_mem_address(&constraint)
.ok_or(AddressManagerError::NoAvailableMemAddress)?;
let mmap_reg = self.create_mmap_region(reg.clone())?;
vm_memory = vm_memory
.insert_region(mmap_reg.clone())
.map_err(AddressManagerError::CreateGuestMemory)?;
self.map_to_kvm(res_mgr, &param, reg, mmap_reg)?;
}
#[cfg(feature = "atomic-guest-memory")]
{
self.vm_as = Some(AddressSpace::convert_into_vm_as(vm_memory));
}
#[cfg(not(feature = "atomic-guest-memory"))]
{
self.vm_as = Some(Arc::new(vm_memory));
}
let layout = AddressSpaceLayout::new(
*dbs_boot::layout::GUEST_PHYS_END,
dbs_boot::layout::GUEST_MEM_START,
*dbs_boot::layout::GUEST_MEM_END,
);
self.address_space = Some(AddressSpace::from_regions(regions, layout));
Ok(())
}
// size unit: Byte
fn create_region(
&mut self,
start_addr: u64,
size_bytes: u64,
info: &NumaRegionInfo,
param: &mut AddressSpaceMgrBuilder,
) -> Result<Arc<AddressSpaceRegion>> {
let mem_file_path = param.get_next_mem_file();
let region = AddressSpaceRegion::create_default_memory_region(
GuestAddress(start_addr),
size_bytes,
info.host_numa_node_id,
param.mem_type,
&mem_file_path,
param.mem_prealloc,
false,
)
.map_err(AddressManagerError::CreateAddressSpaceRegion)?;
let region = Arc::new(region);
self.insert_into_numa_nodes(
&region,
info.guest_numa_node_id.unwrap_or(0),
&info.vcpu_ids,
);
info!(
"create new region: guest addr 0x{:x}-0x{:x} size {}",
start_addr,
start_addr + size_bytes,
size_bytes
);
Ok(region)
}
fn map_to_kvm(
&mut self,
res_mgr: &ResourceManager,
param: &AddressSpaceMgrBuilder,
reg: &Arc<AddressSpaceRegion>,
mmap_reg: Arc<GuestRegionImpl>,
) -> Result<()> {
// Build mapping between GPA <-> HVA, by adding kvm memory slot.
let slot = res_mgr
.allocate_kvm_mem_slot(1, None)
.ok_or(AddressManagerError::NoAvailableKvmSlot)?;
if let Some(vmfd) = param.vmfd.as_ref() {
let host_addr = mmap_reg
.get_host_address(MemoryRegionAddress(0))
.map_err(|_e| AddressManagerError::InvalidOperation)?;
let flags = 0u32;
let mem_region = kvm_userspace_memory_region {
slot: slot as u32,
guest_phys_addr: reg.start_addr().raw_value(),
memory_size: reg.len() as u64,
userspace_addr: host_addr as u64,
flags,
};
info!(
"VM: guest memory region {:x} starts at {:x?}",
reg.start_addr().raw_value(),
host_addr
);
// Safe because the guest regions are guaranteed not to overlap.
unsafe { vmfd.set_user_memory_region(mem_region) }
.map_err(AddressManagerError::KvmSetMemorySlot)?;
}
self.base_to_slot
.lock()
.unwrap()
.insert(reg.start_addr().raw_value(), slot as u32);
Ok(())
}
/// Mmap the address space region into current process.
pub fn create_mmap_region(
&mut self,
region: Arc<AddressSpaceRegion>,
) -> Result<Arc<GuestRegionImpl>> {
// Special check for 32bit host with 64bit virtual machines.
if region.len() > usize::MAX as u64 {
return Err(AddressManagerError::InvalidAddressRange(
region.start_addr().raw_value(),
region.len(),
));
}
// The device MMIO regions may not be backed by memory files, so refuse to mmap them.
if region.region_type() == AddressSpaceRegionType::DeviceMemory {
return Err(AddressManagerError::InvalidOperation);
}
// The GuestRegionMmap/MmapRegion will take ownership of the FileOffset object,
// so we have to duplicate the fd here. It's really a dirty design.
let file_offset = match region.file_offset().as_ref() {
Some(fo) => {
let fd = dup(fo.file().as_raw_fd()).map_err(AddressManagerError::DupFd)?;
// Safe because we have just duplicated the raw fd.
let file = unsafe { File::from_raw_fd(fd) };
let file_offset = FileOffset::new(file, fo.start());
Some(file_offset)
}
None => None,
};
let perm_flags = if (region.perm_flags() & libc::MAP_POPULATE) != 0 && region.is_hugepage()
{
// mmap(MAP_POPULATE) conflicts with madive(MADV_HUGEPAGE) because mmap(MAP_POPULATE)
// will pre-fault in all memory with normal pages before madive(MADV_HUGEPAGE) gets
// called. So remove the MAP_POPULATE flag and memory will be faulted in by working
// threads.
region.perm_flags() & (!libc::MAP_POPULATE)
} else {
region.perm_flags()
};
let mmap_reg = MmapRegion::build(
file_offset,
region.len() as usize,
libc::PROT_READ | libc::PROT_WRITE,
perm_flags,
)
.map_err(AddressManagerError::MmapGuestMemory)?;
if region.is_anonpage() {
self.configure_anon_mem(&mmap_reg)?;
}
if let Some(node_id) = region.host_numa_node_id() {
self.configure_numa(&mmap_reg, node_id)?;
}
if region.is_hugepage() {
self.configure_thp_and_prealloc(&region, &mmap_reg)?;
}
let reg = GuestRegionImpl::new(mmap_reg, region.start_addr())
.map_err(AddressManagerError::CreateGuestMemory)?;
Ok(Arc::new(reg))
}
fn configure_anon_mem(&self, mmap_reg: &MmapRegion) -> Result<()> {
unsafe {
mman::madvise(
mmap_reg.as_ptr() as *mut libc::c_void,
mmap_reg.size(),
mman::MmapAdvise::MADV_DONTFORK,
)
}
.map_err(AddressManagerError::Madvise)
}
fn configure_numa(&self, mmap_reg: &MmapRegion, node_id: u32) -> Result<()> {
let nodemask = 1_u64
.checked_shl(node_id)
.ok_or(AddressManagerError::InvalidOperation)?;
let res = unsafe {
libc::syscall(
libc::SYS_mbind,
mmap_reg.as_ptr() as *mut libc::c_void,
mmap_reg.size(),
MPOL_PREFERRED,
&nodemask as *const u64,
MAX_NODE,
MPOL_MF_MOVE,
)
};
if res < 0 {
warn!(
"failed to mbind memory to host_numa_node_id {}: this may affect performance",
node_id
);
}
Ok(())
}
// We set Transparent Huge Page (THP) through mmap to increase performance.
// In order to reduce the impact of page fault on performance, we start several threads (up to MAX_PRE_ALLOC_THREAD) to touch every 4k page of the memory region to manually do memory pre-allocation.
// The reason why we don't use mmap to enable THP and pre-alloction is that THP setting won't take effect in this operation (tested in kernel 4.9)
fn configure_thp_and_prealloc(
&mut self,
region: &Arc<AddressSpaceRegion>,
mmap_reg: &MmapRegion,
) -> Result<()> {
debug!(
"Setting MADV_HUGEPAGE on AddressSpaceRegion addr {:x?} len {:x?}",
mmap_reg.as_ptr(),
mmap_reg.size()
);
// Safe because we just create the MmapRegion
unsafe {
mman::madvise(
mmap_reg.as_ptr() as *mut libc::c_void,
mmap_reg.size(),
mman::MmapAdvise::MADV_HUGEPAGE,
)
}
.map_err(AddressManagerError::Madvise)?;
if region.perm_flags() & libc::MAP_POPULATE > 0 {
// Touch every 4k page to trigger allocation. The step is 4K instead of 2M to ensure
// pre-allocation when running out of huge pages.
const PAGE_SIZE: u64 = 4096;
const PAGE_SHIFT: u32 = 12;
let addr = mmap_reg.as_ptr() as u64;
// Here we use >> PAGE_SHIFT to calculate how many 4K pages in the memory region.
let npage = (mmap_reg.size() as u64) >> PAGE_SHIFT;
let mut touch_thread = ((mmap_reg.size() as u64) >> PRE_ALLOC_GRANULARITY) + 1;
if touch_thread > MAX_PRE_ALLOC_THREAD {
touch_thread = MAX_PRE_ALLOC_THREAD;
}
let per_npage = npage / touch_thread;
for n in 0..touch_thread {
let start_npage = per_npage * n;
let end_npage = if n == (touch_thread - 1) {
npage
} else {
per_npage * (n + 1)
};
let mut per_addr = addr + (start_npage * PAGE_SIZE);
let should_stop = self.prealloc_exit.clone();
let handler = thread::Builder::new()
.name("PreallocThread".to_string())
.spawn(move || {
info!("PreallocThread start start_npage: {:?}, end_npage: {:?}, per_addr: {:?}, thread_number: {:?}",
start_npage, end_npage, per_addr, touch_thread );
for _ in start_npage..end_npage {
if should_stop.load(Ordering::Acquire) {
info!("PreallocThread stop start_npage: {:?}, end_npage: {:?}, per_addr: {:?}, thread_number: {:?}",
start_npage, end_npage, per_addr, touch_thread);
break;
}
// Reading from a THP page may be served by the zero page, so only
// write operation could ensure THP memory allocation. So use
// the compare_exchange(old_val, old_val) trick to trigger allocation.
let addr_ptr = per_addr as *mut u8;
let read_byte = unsafe { std::ptr::read_volatile(addr_ptr) };
let atomic_u8 : &AtomicU8 = unsafe {&*(addr_ptr as *mut AtomicU8)};
let _ = atomic_u8.compare_exchange(read_byte, read_byte, Ordering::SeqCst, Ordering::SeqCst);
per_addr += PAGE_SIZE;
}
info!("PreallocThread done start_npage: {:?}, end_npage: {:?}, per_addr: {:?}, thread_number: {:?}",
start_npage, end_npage, per_addr, touch_thread );
});
match handler {
Err(e) => error!(
"Failed to create working thread for async pre-allocation, {:?}. This may affect performance stability at the start of the workload.",
e
),
Ok(hdl) => self.prealloc_handlers.push(hdl),
}
}
}
Ok(())
}
/// Get the address space object
pub fn get_address_space(&self) -> Option<&AddressSpace> {
self.address_space.as_ref()
}
/// Get the default guest memory object, which will be used to access virtual machine's default
/// guest memory.
pub fn get_vm_as(&self) -> Option<&GuestAddressSpaceImpl> {
self.vm_as.as_ref()
}
/// Get the base to slot map
pub fn get_base_to_slot_map(&self) -> Arc<Mutex<HashMap<u64, u32>>> {
self.base_to_slot.clone()
}
/// get numa nodes infos from address space manager.
pub fn get_numa_nodes(&self) -> &BTreeMap<u32, NumaNode> {
&self.numa_nodes
}
/// add cpu and memory numa informations to BtreeMap
fn insert_into_numa_nodes(
&mut self,
region: &Arc<AddressSpaceRegion>,
guest_numa_node_id: u32,
vcpu_ids: &[u32],
) {
let node = self
.numa_nodes
.entry(guest_numa_node_id)
.or_insert_with(NumaNode::new);
node.add_info(&NumaNodeInfo {
base: region.start_addr(),
size: region.len(),
});
node.add_vcpu_ids(vcpu_ids);
}
/// get address space layout from address space manager.
pub fn get_layout(&self) -> Result<AddressSpaceLayout> {
self.address_space
.as_ref()
.map(|v| v.layout())
.ok_or(AddressManagerError::GuestMemoryNotInitialized)
}
/// Wait for the pre-allocation working threads to finish work.
///
/// Force all working threads to exit if `stop` is true.
pub fn wait_prealloc(&mut self, stop: bool) -> Result<()> {
if stop {
self.prealloc_exit.store(true, Ordering::Release);
}
while let Some(handlers) = self.prealloc_handlers.pop() {
if let Err(e) = handlers.join() {
error!("wait_prealloc join fail {:?}", e);
return Err(AddressManagerError::JoinFail);
}
}
Ok(())
}
}
impl Default for AddressSpaceMgr {
/// Create a new empty AddressSpaceMgr
fn default() -> Self {
AddressSpaceMgr {
address_space: None,
vm_as: None,
base_to_slot: Arc::new(Mutex::new(HashMap::new())),
prealloc_handlers: Vec::new(),
prealloc_exit: Arc::new(AtomicBool::new(false)),
numa_nodes: BTreeMap::new(),
}
}
}
#[cfg(test)]
mod tests {
use dbs_boot::layout::GUEST_MEM_START;
use std::ops::Deref;
use vm_memory::{Bytes, GuestAddressSpace, GuestMemory, GuestMemoryRegion};
use vmm_sys_util::tempfile::TempFile;
use super::*;
#[test]
fn test_create_address_space() {
let res_mgr = ResourceManager::new(None);
let mem_size = 128 << 20;
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: vec![1, 2],
}];
let builder = AddressSpaceMgrBuilder::new("shmem", "").unwrap();
let as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
let vm_as = as_mgr.get_vm_as().unwrap();
let guard = vm_as.memory();
let gmem = guard.deref();
assert_eq!(gmem.num_regions(), 1);
let reg = gmem
.find_region(GuestAddress(GUEST_MEM_START + mem_size - 1))
.unwrap();
assert_eq!(reg.start_addr(), GuestAddress(GUEST_MEM_START));
assert_eq!(reg.len(), mem_size);
assert!(gmem
.find_region(GuestAddress(GUEST_MEM_START + mem_size))
.is_none());
assert!(reg.file_offset().is_some());
let buf = [0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x5u8];
gmem.write_slice(&buf, GuestAddress(GUEST_MEM_START))
.unwrap();
// Update middle of mapped memory region
let mut val = 0xa5u8;
gmem.write_obj(val, GuestAddress(GUEST_MEM_START + 0x1))
.unwrap();
val = gmem.read_obj(GuestAddress(GUEST_MEM_START + 0x1)).unwrap();
assert_eq!(val, 0xa5);
val = gmem.read_obj(GuestAddress(GUEST_MEM_START)).unwrap();
assert_eq!(val, 1);
val = gmem.read_obj(GuestAddress(GUEST_MEM_START + 0x2)).unwrap();
assert_eq!(val, 3);
val = gmem.read_obj(GuestAddress(GUEST_MEM_START + 0x5)).unwrap();
assert_eq!(val, 0);
// Read ahead of mapped memory region
assert!(gmem
.read_obj::<u8>(GuestAddress(GUEST_MEM_START + mem_size))
.is_err());
let res_mgr = ResourceManager::new(None);
let mem_size = dbs_boot::layout::MMIO_LOW_START + (1 << 30);
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: vec![1, 2],
}];
let builder = AddressSpaceMgrBuilder::new("shmem", "").unwrap();
let as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
let vm_as = as_mgr.get_vm_as().unwrap();
let guard = vm_as.memory();
let gmem = guard.deref();
#[cfg(target_arch = "x86_64")]
assert_eq!(gmem.num_regions(), 2);
#[cfg(target_arch = "aarch64")]
assert_eq!(gmem.num_regions(), 1);
// Test dropping GuestMemoryMmap object releases all resources.
for _ in 0..10000 {
let res_mgr = ResourceManager::new(None);
let mem_size = 1 << 20;
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: vec![1, 2],
}];
let builder = AddressSpaceMgrBuilder::new("shmem", "").unwrap();
let _as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
}
let file = TempFile::new().unwrap().into_file();
let fd = file.as_raw_fd();
// fd should be small enough if there's no leaking of fds.
assert!(fd < 1000);
}
#[test]
fn test_address_space_mgr_get_boundary() {
let layout = AddressSpaceLayout::new(
*dbs_boot::layout::GUEST_PHYS_END,
dbs_boot::layout::GUEST_MEM_START,
*dbs_boot::layout::GUEST_MEM_END,
);
let res_mgr = ResourceManager::new(None);
let mem_size = 128 << 20;
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: vec![1, 2],
}];
let builder = AddressSpaceMgrBuilder::new("shmem", "").unwrap();
let as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
assert_eq!(as_mgr.get_layout().unwrap(), layout);
}
#[test]
fn test_address_space_mgr_get_numa_nodes() {
let res_mgr = ResourceManager::new(None);
let mem_size = 128 << 20;
let cpu_vec = vec![1, 2];
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: cpu_vec.clone(),
}];
let builder = AddressSpaceMgrBuilder::new("shmem", "").unwrap();
let as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
let mut numa_node = NumaNode::new();
numa_node.add_info(&NumaNodeInfo {
base: GuestAddress(GUEST_MEM_START),
size: mem_size,
});
numa_node.add_vcpu_ids(&cpu_vec);
assert_eq!(*as_mgr.get_numa_nodes().get(&0).unwrap(), numa_node);
}
#[test]
fn test_address_space_mgr_async_prealloc() {
let res_mgr = ResourceManager::new(None);
let mem_size = 2 << 20;
let cpu_vec = vec![1, 2];
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: cpu_vec,
}];
let mut builder = AddressSpaceMgrBuilder::new("hugeshmem", "").unwrap();
builder.toggle_prealloc(true);
let mut as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
as_mgr.wait_prealloc(false).unwrap();
}
#[test]
fn test_address_space_mgr_builder() {
let mut builder = AddressSpaceMgrBuilder::new("shmem", "/tmp/shmem").unwrap();
assert_eq!(builder.mem_type, "shmem");
assert_eq!(builder.mem_file, "/tmp/shmem");
assert_eq!(builder.mem_index, 0);
assert!(builder.mem_suffix);
assert!(!builder.mem_prealloc);
assert!(!builder.dirty_page_logging);
assert!(builder.vmfd.is_none());
assert_eq!(&builder.get_next_mem_file(), "/tmp/shmem0");
assert_eq!(&builder.get_next_mem_file(), "/tmp/shmem1");
assert_eq!(&builder.get_next_mem_file(), "/tmp/shmem2");
assert_eq!(builder.mem_index, 3);
builder.toggle_file_suffix(false);
assert_eq!(&builder.get_next_mem_file(), "/tmp/shmem");
assert_eq!(&builder.get_next_mem_file(), "/tmp/shmem");
assert_eq!(builder.mem_index, 3);
builder.toggle_prealloc(true);
builder.toggle_dirty_page_logging(true);
assert!(builder.mem_prealloc);
assert!(builder.dirty_page_logging);
}
#[test]
fn test_configure_invalid_numa() {
let res_mgr = ResourceManager::new(None);
let mem_size = 128 << 20;
let numa_region_infos = vec![NumaRegionInfo {
size: mem_size >> 20,
host_numa_node_id: None,
guest_numa_node_id: Some(0),
vcpu_ids: vec![1, 2],
}];
let builder = AddressSpaceMgrBuilder::new("shmem", "").unwrap();
let as_mgr = builder.build(&res_mgr, &numa_region_infos).unwrap();
let mmap_reg = MmapRegion::new(8).unwrap();
assert!(as_mgr.configure_numa(&mmap_reg, u32::MAX).is_err());
}
}

View File

@@ -1,6 +0,0 @@
// Copyright (C) 2019-2022 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//! API related data structures to configure the vmm.
pub mod v1;

View File

@@ -1,55 +0,0 @@
// Copyright (C) 2022 Alibaba Cloud. All rights reserved.
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use serde_derive::{Deserialize, Serialize};
/// Default guest kernel command line:
/// - `reboot=k` shutdown the guest on reboot, instead of well... rebooting;
/// - `panic=1` on panic, reboot after 1 second;
/// - `pci=off` do not scan for PCI devices (ser boot time);
/// - `nomodules` disable loadable kernel module support;
/// - `8250.nr_uarts=0` disable 8250 serial interface;
/// - `i8042.noaux` do not probe the i8042 controller for an attached mouse (ser boot time);
/// - `i8042.nomux` do not probe i8042 for a multiplexing controller (ser boot time);
/// - `i8042.nopnp` do not use ACPIPnP to discover KBD/AUX controllers (ser boot time);
/// - `i8042.dumbkbd` do not attempt to control kbd state via the i8042 (ser boot time).
pub const DEFAULT_KERNEL_CMDLINE: &str = "reboot=k panic=1 pci=off nomodules 8250.nr_uarts=0 \
i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd";
/// Strongly typed data structure used to configure the boot source of the microvm.
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Default)]
#[serde(deny_unknown_fields)]
pub struct BootSourceConfig {
/// Path of the kernel image.
/// We only support uncompressed kernel for Dragonball.
pub kernel_path: String,
/// Path of the initrd, if there is one.
/// ps. rootfs is set in BlockDeviceConfigInfo
pub initrd_path: Option<String>,
/// The boot arguments to pass to the kernel.
#[serde(skip_serializing_if = "Option::is_none")]
pub boot_args: Option<String>,
}
/// Errors associated with actions on `BootSourceConfig`.
#[derive(Debug, thiserror::Error)]
pub enum BootSourceConfigError {
/// The kernel file cannot be opened.
#[error(
"the kernel file cannot be opened due to invalid kernel path or invalid permissions: {0}"
)]
InvalidKernelPath(#[source] std::io::Error),
/// The initrd file cannot be opened.
#[error("the initrd file cannot be opened due to invalid path or invalid permissions: {0}")]
InvalidInitrdPath(#[source] std::io::Error),
/// The kernel command line is invalid.
#[error("the kernel command line is invalid: {0}")]
InvalidKernelCommandLine(#[source] linux_loader::cmdline::Error),
/// The boot source cannot be update post boot.
#[error("the update operation is not allowed after boot")]
UpdateNotAllowedPostBoot,
}

View File

@@ -1,88 +0,0 @@
// Copyright (C) 2022 Alibaba Cloud. All rights reserved.
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
use serde_derive::{Deserialize, Serialize};
/// The microvm state.
///
/// When Dragonball starts, the instance state is Uninitialized. Once start_microvm method is
/// called, the state goes from Uninitialized to Starting. The state is changed to Running until
/// the start_microvm method ends. Halting and Halted are currently unsupported.
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub enum InstanceState {
/// Microvm is not initialized.
Uninitialized,
/// Microvm is starting.
Starting,
/// Microvm is running.
Running,
/// Microvm is Paused.
Paused,
/// Microvm received a halt instruction.
Halting,
/// Microvm is halted.
Halted,
/// Microvm exit instead of process exit.
Exited(i32),
}
/// The state of async actions
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub enum AsyncState {
/// Uninitialized
Uninitialized,
/// Success
Success,
/// Failure
Failure,
}
/// The strongly typed that contains general information about the microVM.
#[derive(Debug, Deserialize, Serialize)]
pub struct InstanceInfo {
/// The ID of the microVM.
pub id: String,
/// The state of the microVM.
pub state: InstanceState,
/// The version of the VMM that runs the microVM.
pub vmm_version: String,
/// The pid of the current VMM process.
pub pid: u32,
/// The state of async actions.
pub async_state: AsyncState,
/// List of tids of vcpu threads (vcpu index, tid)
pub tids: Vec<(u8, u32)>,
/// Last instance downtime
pub last_instance_downtime: u64,
}
impl InstanceInfo {
/// create instance info object with given id, version, and platform type
pub fn new(id: String, vmm_version: String) -> Self {
InstanceInfo {
id,
state: InstanceState::Uninitialized,
vmm_version,
pid: std::process::id(),
async_state: AsyncState::Uninitialized,
tids: Vec::new(),
last_instance_downtime: 0,
}
}
}
impl Default for InstanceInfo {
fn default() -> Self {
InstanceInfo {
id: String::from(""),
state: InstanceState::Uninitialized,
vmm_version: env!("CARGO_PKG_VERSION").to_string(),
pid: std::process::id(),
async_state: AsyncState::Uninitialized,
tids: Vec::new(),
last_instance_downtime: 0,
}
}
}

View File

@@ -1,86 +0,0 @@
// Copyright (C) 2022 Alibaba Cloud. All rights reserved.
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/// We only support this number of vcpus for now. Mostly because we have set all vcpu related metrics as u8
/// and breaking u8 will take extra efforts.
pub const MAX_SUPPORTED_VCPUS: u8 = 254;
/// Memory hotplug value should have alignment in this size (unit: MiB)
pub const MEMORY_HOTPLUG_ALIGHMENT: u8 = 64;
/// Errors associated with configuring the microVM.
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
pub enum VmConfigError {
/// Cannot update the configuration of the microvm post boot.
#[error("update operation is not allowed after boot")]
UpdateNotAllowedPostBoot,
/// The max vcpu count is invalid.
#[error("the vCPU number shouldn't large than {}", MAX_SUPPORTED_VCPUS)]
VcpuCountExceedsMaximum,
/// The vcpu count is invalid. When hyperthreading is enabled, the `cpu_count` must be either
/// 1 or an even number.
#[error(
"the vCPU number '{0}' can only be 1 or an even number when hyperthreading is enabled"
)]
InvalidVcpuCount(u8),
/// The threads_per_core is invalid. It should be either 1 or 2.
#[error("the threads_per_core number '{0}' can only be 1 or 2")]
InvalidThreadsPerCore(u8),
/// The cores_per_die is invalid. It should be larger than 0.
#[error("the cores_per_die number '{0}' can only be larger than 0")]
InvalidCoresPerDie(u8),
/// The dies_per_socket is invalid. It should be larger than 0.
#[error("the dies_per_socket number '{0}' can only be larger than 0")]
InvalidDiesPerSocket(u8),
/// The socket number is invalid. It should be either 1 or 2.
#[error("the socket number '{0}' can only be 1 or 2")]
InvalidSocket(u8),
/// max vcpu count inferred from cpu topology(threads_per_core * cores_per_die * dies_per_socket * sockets) should be larger or equal to vcpu_count
#[error("the max vcpu count inferred from cpu topology '{0}' (threads_per_core * cores_per_die * dies_per_socket * sockets) should be larger or equal to vcpu_count")]
InvalidCpuTopology(u8),
/// The max vcpu count is invalid.
#[error(
"the max vCPU number '{0}' shouldn't less than vCPU count and can only be 1 or an even number when hyperthreading is enabled"
)]
InvalidMaxVcpuCount(u8),
/// The memory size is invalid. The memory can only be an unsigned integer.
#[error("the memory size 0x{0:x}MiB is invalid")]
InvalidMemorySize(usize),
/// The hotplug memory size is invalid. The memory can only be an unsigned integer.
#[error(
"the hotplug memory size '{0}' (MiB) is invalid, must be multiple of {}",
MEMORY_HOTPLUG_ALIGHMENT
)]
InvalidHotplugMemorySize(usize),
/// The memory type is invalid.
#[error("the memory type '{0}' is invalid")]
InvalidMemType(String),
/// The memory file path is invalid.
#[error("the memory file path is invalid")]
InvalidMemFilePath(String),
/// NUMA region memory size is invalid
#[error("Total size of memory in NUMA regions: {0}, should matches memory size in config")]
InvalidNumaRegionMemorySize(usize),
/// NUMA region vCPU count is invalid
#[error("Total counts of vCPUs in NUMA regions: {0}, should matches max vcpu count in config")]
InvalidNumaRegionCpuCount(u16),
/// NUMA region vCPU count is invalid
#[error("Max id of vCPUs in NUMA regions: {0}, should matches max vcpu count in config")]
InvalidNumaRegionCpuMaxId(u16),
}

View File

@@ -1,19 +0,0 @@
// Copyright (C) 2019-2022 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//! API Version 1 related data structures to configure the vmm.
mod vmm_action;
pub use self::vmm_action::*;
/// Wrapper for configuring the microVM boot source.
mod boot_source;
pub use self::boot_source::{BootSourceConfig, BootSourceConfigError, DEFAULT_KERNEL_CMDLINE};
/// Wrapper over the microVM general information.
mod instance_info;
pub use self::instance_info::{InstanceInfo, InstanceState};
/// Wrapper for configuring the memory and CPU of the microVM.
mod machine_config;
pub use self::machine_config::{VmConfigError, MAX_SUPPORTED_VCPUS};

Some files were not shown because too many files have changed in this diff Show More