Compare commits

..

311 Commits

Author SHA1 Message Date
Steve Horsman
30bad4ee43 Merge pull request #10562 from stevenhorsman/remove-release-artifactor-skips
workflows: Remove skipping of artifact uploads
2024-11-20 08:45:37 +00:00
stevenhorsman
da5f6b77c7 workflows: Remove skipping of artifact uploads
Now we are downloading artifacts to create the rootfs
we need to ensure they are uploaded always,
even on releases

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-19 13:28:02 +00:00
Steve Horsman
817438d1f6 Merge pull request #10552 from stevenhorsman/3.11.0-release
release: Bump version to 3.11.0
2024-11-19 09:44:35 +00:00
Saul Paredes
eab48c9884 Merge pull request #10545 from microsoft/cameronbaird/sync-clh-logging
runtime: fix comment to accurately reflect clh behavior
2024-11-18 11:25:58 -08:00
stevenhorsman
7a8ba14959 release: Bump version to 3.11.0
Bump `VERSION` and helm-chart versions

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-18 11:13:15 +00:00
Steve Horsman
0ce3f5fc6f Merge pull request #10514 from squarti/pause_command
agent: overwrite OCI process spec when overwriting pause image
2024-11-15 18:03:58 +00:00
Fabiano Fidêncio
92f7526550 Merge pull request #10542 from Crypt0s/topic/enable-CONFIG_KEYS
kernel: add CONFIG_KEYS=y to enable kernel keyring
2024-11-15 12:15:25 +01:00
Crypt0s
563a6887e2 kernel: add CONFIG_KEYS=y to enable kernel keyring
KinD checks for the presence of this (and other) kernel configuration
via scripts like
https://blog.hypriot.com/post/verify-kernel-container-compatibility/ or
attempts to directly use /proc/sys/kernel/keys/ without checking to see
if it exists, causing an exit when it does not see it.

Docker/it's consumers apparently expect to be able to use the kernel
keyring and it's associated syscalls from/for containers.

There aren't any known downsides to enabling this except that it would
by definition enable additional syscalls defined in
https://man7.org/linux/man-pages/man7/keyrings.7.html which are
reachable from userspace. This minimally increases the attack surface of
the Kata Kernel, but this attack surface is minimal (especially since
the kernel is most likely being executed by some kind of hypervisor) and
highly restricted compared to the utility of enabling this feature to
get further containerization compatibility.

Signed-off-by: Crypt0s <BryanHalf@gmail.com>
2024-11-15 09:30:06 +01:00
Cameron Baird
65881ceb8a runtime: fix comment to accurately reflect clh behavior
Fix the CLH log levels description

Signed-off-by: Cameron Baird <cameronbaird@microsoft.com>
2024-11-14 23:16:11 +00:00
Silenio Quarti
42b6203493 agent: overwrite OCI process spec when overwriting pause image
The PR replaces the OCI process spec of the pause container with the spec of
the guest provided pause bundle.

Fixes: https://github.com/kata-containers/kata-containers/issues/10537

Signed-off-by: Silenio Quarti <silenio_quarti@ca.ibm.com>
2024-11-14 13:05:16 -05:00
Fabiano Fidêncio
6a9266124b Merge pull request #10501 from kata-containers/topic/ci-split-tests
ci: tdx: Split jobs to run in 2 different machines
2024-11-14 17:24:50 +01:00
Fabiano Fidêncio
9b3fe0c747 ci: tdx: Adjust workflows to use different machines
This will be helpful in order to increase the OS coverage (we'll be
using both Ubuntu 24.04 and CentOS 9 Stream), while also reducing the
amount spent on the tests (as one machine will only run attestation
related tests, and the other the tests that do *not* require
attestation).

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-14 15:52:00 +01:00
Fabiano Fidêncio
9b1a5f2ac2 tests: Add a way to run only tests which rely on attestation
We're doing this as, at Intel, we have two different kind of machines we
can plug into our CI.  Without going much into details, only one of
those two kinds of machines will work for the attestation tests we
perform with ITA, thus in order to speed up the CI and improve test
coverage (OS wise), we're going to run different tests in different
machines.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-14 15:51:57 +01:00
Steve Horsman
915695f5ef Merge pull request #9407 from mrIncompetent/root-fs-clang
rootfs: Install missing clang in Ubuntu docker image
2024-11-14 10:35:06 +00:00
Henrik Schmidt
57a4dbedeb rootfs: Install missing libclang-dev in Ubuntu docker image
Fixes #9444

Signed-off-by: Henrik Schmidt <mrIncompetent@users.noreply.github.com>
2024-11-14 08:48:24 +00:00
Hyounggyu Choi
5869046d04 Merge pull request #9195 from UiPath/fix/vcpus-for-static-mgmt
runtime: Set maxvcpus equal to vcpus for the static resources case
2024-11-14 09:38:20 +01:00
Dan Mihai
d9977b3e75 Merge pull request #10431 from microsoft/saulparedes/add-policy-state
genpolicy: add state to policy
2024-11-13 11:48:46 -08:00
Aurélien Bombo
7bc2fe90f9 Merge pull request #10521 from ncppd/osbuilder-cleanup
osbuilder: remove redundant env variable
2024-11-13 12:17:09 -06:00
Steve Horsman
a947d2bc40 Merge pull request #10539 from AdithyaKrishnan/main
ci: Temporarily skip SNP CI
2024-11-13 17:58:32 +00:00
Adithya Krishnan Kannan
439a1336b5 ci: Temporarily skip SNP CI
As discussed in the CI working group,
we are temporarily skipping the SNP CI
to unblock the remaining workflow.
Will revert after fixing the SNP runner.

Signed-Off-By: Adithya Krishnan Kannan <AdithyaKrishnan.Kannan@amd.com>
2024-11-13 11:44:16 -06:00
Fabiano Fidêncio
02d4c3efbf Merge pull request #10519 from fidencio/topic/relax-restriction-for-qemu-tdx
Reapply "runtime: confidential: Do not set the max_vcpu to cpu"
2024-11-13 16:09:06 +01:00
Saul Paredes
c207312260 genpolicy: validate container sandbox names
Make sure all container sandbox names match the sandbox name of the first container.

Signed-off-by: Saul Paredes <saulparedes@microsoft.com>
2024-11-12 15:17:01 -08:00
Saul Paredes
52d1aea1f7 genpolicy: Add state
Use regorous engine's add_data method to add state to the policy.
This data can later be accessed inside rego context through the data namespace.

Support state modifications (json-patches) that may be returned as a result from policy evaluation.

Also initialize a policy engine data slice "pstate" dedicated for storing state.

Fixes #10087

Signed-off-by: Saul Paredes <saulparedes@microsoft.com>
2024-11-12 15:16:53 -08:00
Alexandru Matei
e83f8f8a04 runtime: Set maxvcpus equal to vcpus for the static resources case
Fixes: #9194

Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
2024-11-12 16:36:42 +02:00
GabyCT
06fe459e52 Merge pull request #10508 from GabyCT/topic/installartsta
gha: Get artifacts when installing kata tools in stability workflow
2024-11-11 15:59:06 -06:00
Nikos Ch. Papadopoulos
ab80cf8f48 osbuilder: remove redundant env variable
Remove second declaration of GO_HOME in roofs-build ubuntu script.

Signed-off-by: Nikos Ch. Papadopoulos <ncpapad@cslab.ece.ntua.gr>
2024-11-11 19:49:28 +02:00
Fabiano Fidêncio
5618180e63 Merge pull request #10515 from kata-containers/sprt/ubuntu-latest-fix
gha: Hardcode ubuntu-22.04 instead of latest
2024-11-10 09:54:39 +01:00
Fabiano Fidêncio
2281342fb8 Merge pull request #10513 from fidencio/topic/ci-adjust-proxy-nightmare-for-tdx
ci: tdx: kbs: Ensure https_proxy is taken in consideration
2024-11-10 00:17:10 +01:00
Fabiano Fidêncio
0d8c4ce251 Merge pull request #10517 from microsoft/saulparedes/remove_manifest_v1_test
tests: remove manifest v1 test
2024-11-09 23:40:51 +01:00
Fabiano Fidêncio
56812c852f Reapply "runtime: confidential: Do not set the max_vcpu to cpu"
This reverts commit f15e16b692, as we
don't have to do this since we're relying on the
`static_sandbox_resource_mgmt` feature, which gives us the correct
amount of memory and CPUs to be allocated.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-09 23:20:17 +01:00
Saul Paredes
461efc0dd5 tests: remove manifest v1 test
This test was meant to show support for pulling images with v1 manifest schema versions.

The nginxhttps image has been modified in https://hub.docker.com/r/ymqytw/nginxhttps/tags such that we are no longer able to pull it:

$ docker pull ymqytw/nginxhttps:1.5
Error response from daemon: missing signature key

We may remove this test since schema version 1 manifests are deprecated per
https://docs.docker.com/engine/deprecated/#pushing-and-pulling-with-image-manifest-v2-schema-1 :
"These legacy formats should no longer be used, and users are recommended to update images to use current formats, or to upgrade to more
current images". This schema version was used by old docker versions. Further OCI spec
https://github.com/opencontainers/image-spec/blob/main/manifest.md#image-manifest-property-descriptions only supports schema version 2.

Signed-off-by: Saul Paredes <saulparedes@microsoft.com>
2024-11-08 13:38:51 -08:00
Aurélien Bombo
19e972151f gha: Hardcode ubuntu-22.04 instead of latest
GHA is migrating ubuntu-latest to Ubuntu 24 so
let's hardcode the current 22.04 LTS.

https://github.blog/changelog/2024-11-05-notice-of-breaking-changes-for-github-actions/

Signed-off-by: Aurélien Bombo <abombo@microsoft.com>
2024-11-08 11:00:15 -06:00
Greg Kurz
2bd8fde44a Merge pull request #10511 from ldoktor/fedora-python
ci.ocp: Use the official python:3 container for sanity
2024-11-08 16:31:40 +01:00
Fabiano Fidêncio
baf88bb72d ci: tdx: kbs: Ensure https_proxy is taken in consideration
Trustee's deployment must set the correct https_proxy as env var on the
container that will talk to the ITA / ITTS server, otherwise the kbs
service won't be able to start, causing then issues in our CI.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
Signed-off-by: Krzysztof Sandowicz <krzysztof.sandowicz@intel.com>
2024-11-08 16:06:16 +01:00
Steve Horsman
1f728eb906 Merge pull request #10498 from stevenhorsman/update-create-container-timeout-log
tests: k8s: Update image pull timeout error
2024-11-08 10:47:39 +00:00
Steve Horsman
6112bf85c3 Merge pull request #10506 from stevenhorsman/skip-runk-ci
workflow: Remove/skip runk CI
2024-11-08 09:54:06 +00:00
Steve Horsman
a5acbc9e80 Merge pull request #10505 from stevenhorsman/remove-stratovirt-metrics-tests
metrics: Skip metrics on stratovirt
2024-11-08 08:53:05 +00:00
Lukáš Doktor
2f7d34417a ci.ocp: Use the official python:3 container for sanity
Fedora F40 removed python3 from the base container, to avoid such issues
let's rely on the latest and greates official python container.

Fixes: #10497

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-11-08 07:16:30 +01:00
Zvonko Kaiser
183bd2aeed Merge pull request #9584 from zvonkok/kata-agent-cdi
kata-agent: Add CDI support
2024-11-07 14:18:32 -05:00
Zvonko Kaiser
aa2e1a57bd agent: Added test-case for handle_cdi_devices
We are generating a simple CDI spec with device and
global containerEdits to test the CDI crate.

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2024-11-07 17:03:18 +00:00
Gabriela Cervantes
4274198664 gha: Get artifacts when installing kata tools in stability workflow
This PR adds the get artifacts which are needed when installing kata
tools in stability workflow to avoid failures saying that artifacts
are missing.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-11-07 16:20:41 +00:00
stevenhorsman
a5f1a5a0ee workflow: Remove/skip runk CI
As discussed in the AC meeting, we don't have a maintainer,
(or users?) of runk, and the CI is unstable, so giving we can't
support it, we shouldn't waste CI cycles on it.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-07 14:16:30 +00:00
stevenhorsman
0efe9f4e76 metrics: Skip metrics on stratovirt
As discussed on the AC call, we are lacking maintainers for the
metrics tests. As a starting point for potentially phasing them
out, we discussed starting with removing the test for stratovirt
as a non-core hypervisor and a job that is problematic in leaving
behind resources that need cleaning up.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-07 14:06:57 +00:00
Fabiano Fidêncio
c332e953f9 Merge pull request #10500 from squarti/fix-10499
runtime: Files are not synced between host and guest VMs
2024-11-07 08:28:53 +01:00
Silenio Quarti
be3ea2675c runtime: Files are not synced between host and guest VMs
This PR makes the root dir absolute after resolving the
default root dir symlink. 

Fixes: https://github.com/kata-containers/kata-containers/issues/10499

Signed-off-by: Silenio Quarti <silenio_quarti@ca.ibm.com>
2024-11-06 17:31:12 -05:00
GabyCT
47cea6f3c6 Merge pull request #10493 from GabyCT/topic/katatoolsta
gha: Add install kata tools as part of the stability workflow
2024-11-06 14:16:48 -06:00
Gabriela Cervantes
13e27331ef gha: Add install kata tools as part of the stability workflow
This PR adds the install kata tools step as part of the k8s stability workflow.
To avoid the failures saying that certain kata components are not installed it.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-11-06 20:07:06 +00:00
Fabiano Fidêncio
71c4c2a514 Merge pull request #10486 from kata-containers/topic/enable-AUTO_GENERATE_POLICY-for-qemu-coco-dev
workflows: Use AUTO_GENERATE_POLICY for qemu-coco-dev
2024-11-06 21:04:45 +01:00
Zvonko Kaiser
3995fe71f9 kata-agent: Add CDI support
For proper device handling add CDI support

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2024-11-06 17:50:20 +00:00
stevenhorsman
85554257f8 tests: k8s: Update image pull timeout error
Currently the error we are checking for is
`CreateContainerRequest timed out`, but this message
doesn't always seem to be printed to our pod log.
Try using a more general message that should be present
more reliably.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-06 17:00:26 +00:00
Fabiano Fidêncio
a3c72e59b1 Merge pull request #10495 from littlejawa/ci/skip_nginx_connectivity_for_crio
ci: skip nginx connectivity test with qemu/crio
2024-11-06 13:43:19 +01:00
Julien Ropé
da5e0c3f53 ci: skip nginx connectivity test with crio
We have an error with service name resolution with this test when using crio.
This error could not be reproduced outside of the CI for now.
Skipping it to keep the CI job running until we find a solution.

See: #10414

Signed-off-by: Julien Ropé <jrope@redhat.com>
2024-11-06 12:07:02 +01:00
Greg Kurz
5af614b1a4 Merge pull request #10496 from littlejawa/ci/expose_container_runtime
ci: export CONTAINER_RUNTIME to the test scripts
2024-11-06 12:05:36 +01:00
Julien Ropé
6d0cb1e9a8 ci: export CONTAINER_RUNTIME to the test scripts
This variable will allow tests to adapt their behaviour to the runtime (containerd/crio).

Signed-off-by: Julien Ropé <jrope@redhat.com>
2024-11-06 11:29:11 +01:00
Fabiano Fidêncio
72979d7f30 workflows: Use AUTO_GENERATE_POLICY for qemu-coco-dev
By the moment we're testing it also with qemu-coco-dev, it becomes
easier for a developer without access to TEE to also test it locally.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-06 10:47:08 +01:00
Fabiano Fidêncio
7d3f2f7200 runtime: Match TEEs for the static_sandbox_resource_mgmt option
The qemu-coco-dev runtime class should be as close as possible to what
the TEEs runtime classes are doing, and this was one of the options that
ended up overlooked till now.

Shout out to Dan Mihai for noticing that!

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-06 10:47:08 +01:00
Fabiano Fidêncio
ea8114833c Merge pull request #10491 from fidencio/topic/fix-typo-in-the-ephemeral-handler
agent: fix typo on getting EphemeralHandler size option
2024-11-06 10:31:48 +01:00
Fabiano Fidêncio
7e6779f3ad Merge pull request #10488 from fidencio/topic/teach-our-machinery-to-deal-with-rc-kernels
build: kernel: Teach our machinery to deal with -rc kernels
2024-11-05 16:19:57 +01:00
Zvonko Kaiser
a4725034b2 Merge pull request #9480 from zvonkok/build-image-suffix
image: Add suffix to image or initrd depending on the NVIDIA driver version
2024-11-05 09:43:56 -05:00
Fabiano Fidêncio
77c87a0990 agent: fix typo on getting EphemeralHandler size option
Most likely this was overlooked during the development / review, but
we're actually interested on the size rather than on the pagesize of the
hugepages.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 15:15:17 +01:00
Fabiano Fidêncio
2b16160ff1 versions: kernel-dragonball: Fix URL
SSIA

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:55:34 +01:00
Fabiano Fidêncio
f7b31ccd6c kernel: bump kata_config_version
Due to the changes done in the previous commits.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:57 +01:00
Fabiano Fidêncio
a52ea32b05 build: kernel: Learn how to deal with release candidates
So far we were not prepared to deal with release candidates as those:
* Do not have a sha256sum in the sha256sums provided by the kernel cdn
* Come from a different URL (directly from Linus)
* Have a different suffix (.tar.gz, instead of .tar.xz)

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:02 +01:00
Fabiano Fidêncio
9f2d4b2956 build: kernel: Always pass the url to the builder
This doesn't change much on how we're doing things Today, but it
simplifies a lot cases that may be added later on (and will be) like
building -rc kernels.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:02 +01:00
Fabiano Fidêncio
ee1a17cffc build: kernel: Take kernel_url into consideration
Let's make sure the kernel_url is actually used whenever it's passed to
the function.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:02 +01:00
Fabiano Fidêncio
9a0b501042 build: kernel: Remove tee specific function
As, thankfully, we're relying on upstream kernels for TEEs.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:02 +01:00
Fabiano Fidêncio
cc4006297a build: kernel: Pass the yaml base path instead of the version path
By doing this we can ensure this can be re-used, if needed (and it'll be
needed), for also getting the URL.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:02 +01:00
Fabiano Fidêncio
7057ff1cd5 build: kernel: Always pass -f to the kernel builder
-f forces the (re)generaton of the config when doing the setup, which
helps a lot on local development whilst not causing any harm in the CI
builds.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 12:26:02 +01:00
Fabiano Fidêncio
910defc4cf Merge pull request #10490 from fidencio/topic/fix-ovmf-build
builds: ovmf: Workaround Zeex repo becoming private
2024-11-05 12:25:00 +01:00
Fabiano Fidêncio
aff3d98ddd builds: ovmf: Workaround Zeex repo becoming private
Let's just do a simple `sed` and **not** use the repo that became
private.

This is not a backport of https://github.com/tianocore/edk2/pull/6402,
but it's a similar approach that allows us to proceed without the need
to pick up a newer version of edk2.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-11-05 11:25:54 +01:00
Dan Mihai
03bf4433d7 Merge pull request #10459 from stevenhorsman/update-bats
tests: k8s: Update bats
2024-11-04 12:26:58 -08:00
Aurélien Bombo
f639d3e87c Merge pull request #10395 from Sumynwa/sumsharma/create_container
agent-ctl: Add support to test kata-agent's container creation APIs.
2024-11-04 14:09:12 -06:00
GabyCT
7f066be04e Merge pull request #10485 from GabyCT/topic/fixghast
gha: Fix source for gha stability run script
2024-11-04 12:09:28 -06:00
Steve Horsman
a2b9527be3 Merge pull request #10481 from mkulke/mkulke/init-cdh-client-on-gcprocs-none
agent: perform attestation init w/o process launch
2024-11-04 17:27:45 +00:00
Gabriela Cervantes
fd4d0dd1ce gha: Fix source for gha stability run script
This PR fixes the source to avoid duplication specially in the common.sh
script and avoid failures saying that certain script is not in the directory.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-11-04 16:16:13 +00:00
Magnus Kulke
bf769851f8 agent: perform attestation init w/o process launch
This change is motivated by a problem in peerpod's podvms. In this setup
the lifecycle of guest components is managed by systemd. The current code
skips over init steps like setting the ocicrypt-rs env and initialization
of a CDH client in this case.

To address this the launch of the processes has been isolated into its
own fn.

Signed-off-by: Magnus Kulke <magnuskulke@microsoft.com>
2024-11-04 13:31:07 +01:00
Steve Horsman
4fd9df84e4 Merge pull request #10482 from GabyCT/topic/fixvirtdoc
docs: Update virtualization document
2024-11-04 11:51:09 +00:00
stevenhorsman
175ebfec7c Revert "k8s:kbs: Add trap statement to clean up tmp files"
This reverts commit 973b8a1d8f.

As @danmihai1 points out https://github.com/bats-core/bats-core/issues/364
states that using traps in bats is error prone, so this could be the cause
of the confidential test instability we've been seeing, like it was
in the static checks, so let's try and revert this.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-04 09:59:37 +00:00
stevenhorsman
75cb1f46b8 tests/k8s: Add skip is setup_common fails
At @danmihai1's suggestion add a die message in case
the call to setup_common fails, so we can see if in the test
output.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-04 09:59:33 +00:00
stevenhorsman
3f5bf9828b tests: k8s: Update bats
We've seen some issues with tests not being run in
some of the Coco CI jobs (Issue #10451) and in the
envrionments that are more stable we noticed that
they had a newer version of bats installed.

Try updating the version to 1.10+ and print out
the version for debug purposes

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-11-04 09:59:33 +00:00
Steve Horsman
06d2cc7239 Merge pull request #10453 from bpradipt/remote-annotation
runtime: Add GPU annotations for remote hypervisor
2024-11-04 09:10:06 +00:00
Zvonko Kaiser
3781526c94 gpu: Add VARIANT to the initrd and image build
We need to know if we're building a nvidia initrd or image
Additionally if we build a regular or confidential VARIANT

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2024-11-01 18:34:13 +00:00
Zvonko Kaiser
95b69c5732 build: initrd make it coherent to the image build
Add -f for moving the initrd to the correct file path

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2024-11-01 18:34:13 +00:00
Zvonko Kaiser
3c29c1707d image: Add suffix to image or initrd depending on the NVIDIA driver version
Fixes: #9478

We want to keep track of the driver versions build during initrd/image build so update the artifact_name after the fact.

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2024-11-01 18:34:13 +00:00
Sumedh Alok Sharma
4b7aba5c57 agent-ctl: Add support to test kata-agent's container creation APIs.
This commit introduces changes to enable testing kata-agent's container
APIs of CreateContainer/StartContainer/RemoveContainer. The changeset
include:
- using confidential-containers image-rs crate to pull/unpack/mount a
container image. Currently supports only un-authenicated registry pull
- re-factor api handlers to reduce cmdline complexity and handle
request generation logic in tool
- introduce an OCI config template for container creation
- add test case

Fixes #9707

Signed-off-by: Sumedh Alok Sharma <sumsharma@microsoft.com>
2024-11-01 22:18:54 +05:30
Fabiano Fidêncio
2efcb442f4 Merge pull request #10442 from Sumynwa/sumsharma/tools_use_ubuntu_static_build
ci: Use ubuntu for static building of kata tools.
2024-11-01 16:04:31 +01:00
Gabriela Cervantes
1ca83f9d41 docs: Update virtualization document
This PR updates the virtualization document by removing a url link
which is not longer valid.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-31 17:28:02 +00:00
GabyCT
a3d594d526 Merge pull request #10480 from GabyCT/topic/fixstabilityrun
gha: Add missing steps in Kata stability workflow
2024-10-31 09:57:33 -06:00
Fabiano Fidêncio
e058b92350 Merge pull request #10425 from burgerdev/darwin
genpolicy: support darwin target
2024-10-31 12:16:44 +01:00
Markus Rudy
df5e6e65b5 protocols: only build RLimit impls on Linux
The current version of the oci-spec crate compiles RLimit structs only
for Linux and Solaris. Until this is fixed upstream, add compilation
conditions to the type converters for the affected structs.

Fixes: #10071

Signed-off-by: Markus Rudy <mr@edgeless.systems>
2024-10-31 09:50:36 +01:00
Markus Rudy
091a410b96 kata-sys-util: move json parsing to protocols crate
The parse_json_string function is specific to parsing capability strings
out of ttRPC proto definitions and does not benefit from being available
to other crates. Moving it into the protocols crate allows removing
kata-sys-util as a dependency, which in turn enables compiling the
library on darwin.

Fixes: #10071

Signed-off-by: Markus Rudy <mr@edgeless.systems>
2024-10-31 09:41:07 +01:00
Markus Rudy
8ab4bd2bfc kata-sys-util: remove obsolete cgroups dependency
The cgroups.rs source file was removed in
234d7bca04. With cgroups support handled
in runtime-rs, the cgroups dependency on kata-sys-util can be removed.

Signed-off-by: Markus Rudy <mr@edgeless.systems>
2024-10-31 09:41:07 +01:00
Sumedh Alok Sharma
0adf7a66c3 ci: Use ubuntu for static building of kata tools.
This commit introduces changes to use ubuntu for statically
building kata tools. In the existing CI setup, the tools
currently build only for x86_64 architecture.

It also fixes the build error seen for agent-ctl PR#10395.

Fixes #10441

Signed-off-by: Sumedh Alok Sharma <sumsharma@microsoft.com>
2024-10-31 13:19:18 +05:30
Gabriela Cervantes
c4089df9d2 gha: Add missing steps in Kata stability workflow
This PR adds missing steps in the gha run script for the kata stability
workflow.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-30 19:13:15 +00:00
Xuewei Niu
1a216fecdf Merge pull request #10225 from Chasing1020/main
runtime-rs: Add basic boilerplate for remote hypervisor
2024-10-30 17:02:50 +08:00
Hyounggyu Choi
dca69296ae Merge pull request #10476 from BbolroC/switch-to-kubeadm-s390x
gha: Switch KUBERNETES from k3s to kubeadm on s390x
2024-10-30 09:52:06 +01:00
GabyCT
9293931414 Merge pull request #10474 from GabyCT/topic/removeunvarb
packaging: Remove kernel config repo variable as it is unused
2024-10-29 12:52:07 -06:00
Gabriela Cervantes
69ee287e50 packaging: Remove kernel config repo variable as it is unused
This PR removes the kernel config repo variable at the build kernel
script as it is not used.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-29 17:09:52 +00:00
GabyCT
8539cd361a Merge pull request #10462 from GabyCT/topic/increstress
tests: Increase time to run stressng k8s tests
2024-10-29 11:08:47 -06:00
Chasing1020
425f6ad4e6 runtime-rs: add oci spec for prepare_vm method
The cloud-api-adaptor needs to support different types of pod VM
instance.
We needs to pass some annotations like machine_type, default_vcpus and
default_memory to prepare the VMs.

Signed-off-by: Chasing1020 <643601464@qq.com>
2024-10-30 01:01:28 +08:00
Chasing1020
f1167645f3 runtime-rs: support for remote hypervisors type
This patch adds the support of the remote hypervisor type for runtime-rs.
The cloud-api-adaptor needs the annotations and network namespace path
to create the VMs.
The remote hypervisor opens a UNIX domain socket specified in the config
file, and sends ttrpc requests to a external process to control sandbox
VMs.

Fixes: #10350

Signed-off-by: Chasing1020 <643601464@qq.com>
2024-10-30 00:54:17 +08:00
Pradipta Banerjee
6f1ba007ed runtime: Add GPU annotations for remote hypervisor
Add GPU annotations for remote hypervisor to help
with the right instance selection based on number of GPUs
and model

Signed-off-by: Pradipta Banerjee <pradipta.banerjee@gmail.com>
2024-10-29 10:28:21 -04:00
Steve Horsman
68225b53ca Merge pull request #10475 from stevenhorsman/revert-10452
Revert "tests: Add trap statement in kata doc script"
2024-10-29 13:58:00 +00:00
Hyounggyu Choi
aeef28eec2 gha: Switch to kubeadm for run-k8s-tests-on-zvsi
Last November, SUSE discontinued support for s390x, leaving k3s
on this platform stuck at k8s version 1.28, while upstream k8s
has since reached 1.31. Fortunately, kubeadm allows us to create
a 1.30 Kubernetes cluster on s390x.
This commit switches the KUBERNETES option from k3s to kubeadm
for s390x and removes a dedicated cluster creation step.
Now, cluster setup and teardown occur in ACTIONS_RUNNER_HOOK_JOB_{STARTED,COMPLETED}.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-10-29 14:27:32 +01:00
Hyounggyu Choi
238f67005f tests: Add kubeadm option for KUBERNETES in gha-run.sh
When creating a k8s cluster via kubeadm, the devmapper setup
for containerd requires a different configuration.
This commit introduces a new `kubeadm` option for the KUBERNETES
variable and adjusts the path to the containerd config file for
devmapper setup.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-10-29 14:19:42 +01:00
stevenhorsman
b1cffb4b09 Revert "tests: Add trap statement in kata doc script"
This reverts commit 093a6fd542.
as it is breaking the static checks

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-10-29 09:57:18 +00:00
Aurélien Bombo
eb04caaf8f Merge pull request #10074 from koct9i/log-vm-start-error
runtime: log vm start error before cleanup
2024-10-28 14:39:00 -05:00
Fabiano Fidêncio
e675e233be Merge pull request #10473 from fidencio/topic/build-cache-fix-shim-v2-root_hash.txt-location
build: cache: Ensure shim-v2-root_hash.txt is in "${workdir}"
2024-10-28 16:53:06 +01:00
Fabiano Fidêncio
f19c8cbd02 build: cache: Ensure shim-v2-root_hash.txt is in "${workdir}"
All the oras push logic happens from inside `${workdir}`, while the
root_hash.txt extraction and renaming was not taking this into
consideration.

This was not caught during the manually triggered runs as those do not
perform the oras push.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 15:17:16 +01:00
Steve Horsman
51bc71b8d9 Merge pull request #10466 from kata-containers/topic/ensure-shim-v2-sets-the-measured-rootfs-parameters-to-the-config
re-enable measured rootfs build & tests
2024-10-28 13:11:50 +00:00
Fabiano Fidêncio
b70d7c1aac tests: Enable measured rootfs tests for qemu-coco-dev
Then it's on pair with what's being tested with TEEs using a rootfs
image.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:54 +01:00
Fabiano Fidêncio
d23d057ac7 runtime: Enable measured rootfs for qemu-coco-dev
Let's make sure we are prepared to test this with non-TEE environments
as well.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
7d202fc173 tests: Re-enable measured_rootfs test for TDX
As we're now building everything needed to test TDX with measured rootfs
support, let's bring this test back in (for TDX only, at least for now).

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
d537932e66 build: shim-v2: Ensure MEASURED_ROOTFS is exported
The approach taken for now is to export MEASURED_ROOTFS=yes on the
workflow files for the architectures using confidential stuff, and leave
the "normal" build without having it set (to avoid any change of
expectation on the current bevahiour).

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
9c8b20b2bf build: shim-v2: Rebuild if root_hashes do not match
Let's make sure we take the root_hashes into consideration to decide
whether the shim-v2 should or should not be used from the cached
artefacts.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
9c84998de9 build: cache: Cache root_hash.txt used by the shim-v2
Let's cache the root_hash.txt from the confidential image so we can use
them later on to decide whether there was a rootfs change that would
require shim-v2 to be rebuilt.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
d2d9792720 build: Don't leave cached component behind if it can't be used
Let's ensure we remove the component and any extra tarball provided by
ORAS in case the cached component cannot be used.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
ef29824db9 runtime: Don't do measured rootfs for "vanilla" kernel
We may decide to add this later on, but for now this is only targetting
TEEs and the confidential image / initrd.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
a65946bcb0 workflows: build: Ensure rootfs is present for shim-v2 build
Let's ensure that we get the already built rootfs tarball from previous
steps of the action at the time we're building the shim-v2.

The reason we do that is because the rootfs binary tarballs has a
root_hash.txt file that contains the information needed the shim-v2
build scripts to add the measured rootfs arguments to the shim-v2
configuration files.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
6ea0369878 workflows: build: Ensure rootfs is built before shim-v2
As the rootfs will have what we need to add as part of the shim-v2
configuration files for measured rootfs, we **must** ensure this is
built **before** shim-v2.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
13ea082531 workflows: Build rootfs after its deps are built
By doing this we can just re-use the dependencies already built, saving
us a reasonable amount of time.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:53 +01:00
Fabiano Fidêncio
eb07a809ce tests: Add a helper script to use prebuild components
This is a helper script that does basically what's already being done by
the s390x CI, which is:
* Move a folder with the components that we were stored / downloaded
  during the GHA execution to the expected `build` location
* Get rid of the dependencies for a specific asset, as the dependencies
  are already pulled in from previous GHA steps

For now this script is only being added but not yet executed anywhere,
and that will come as the next step in this series.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:52 +01:00
Fabiano Fidêncio
c2b18f9660 workflows: Store rootfs dependencies
So far we haven't been storing the rootfs dependencies as part of our
workflows, but we better do it to re-use them as part of the rootfs
build.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 12:43:52 +01:00
Steve Horsman
b5f503b0b5 Merge pull request #10471 from fidencio/topic/possibly-fix-release-workflow
workflows: Possibly fix the release workflow
2024-10-28 11:38:33 +00:00
Konstantin Khlebnikov
ee50582848 runtime: log vm start error before cleanup
Return of proper error to the initiator is not guaranteed.
Method StopVM could kill shim process together with VM pieces.

Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com>
2024-10-28 11:21:21 +01:00
Fabiano Fidêncio
a8fad6893a workflows: Possibly fix the release workflow
The only reason we had this one passing for amd64 is because the check
was done using the wrong variable (`matrix.stage`, while in the other
workflows the variable used is `inputs.stage`).

The commit that broke the release process is 67a8665f51, which
blindly copy & pasted the logic from the matrix assets.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-28 11:15:53 +01:00
Steve Horsman
ad5749fd6b Merge pull request #10467 from stevenhorsman/release-3.10.1
release: Bump version to 3.10.1
2024-10-25 20:19:23 +01:00
stevenhorsman
b22d4429fb release: Bump version to 3.10.1
Fix release to pick up #10463

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-10-25 17:16:09 +01:00
Steve Horsman
19ac0b24f1 Merge pull request #10463 from skaegi/rustjail_filemode_perm_fix
agent: Correct rustjail device filemode permission typo
2024-10-25 14:27:50 +01:00
Fabiano Fidêncio
cc815957c0 Merge pull request #10461 from kata-containers/topic/workflows-follow-up-on-manually-triggered-job
workflows: devel: Follow-up on the manually triggered jobs
2024-10-25 08:31:14 +02:00
Simon Kaegi
322846b36f agent: Correct rustjail device filemode permission typo
Corrects device filemode permissions typo/regression in rustjail to `666` instead of `066`.
`666` is the standard and expected value for these devices in containers.

Fixes: #10454

Signed-off-by: Simon Kaegi <simon.kaegi@gmail.com>
2024-10-24 16:46:40 -04:00
GabyCT
a9af46ccd2 Merge pull request #10452 from GabyCT/topic/katadoctemp
tests: Add trap statement in kata doc script
2024-10-24 13:21:11 -06:00
Gabriela Cervantes
a3ef8c0a16 tests: Increase time to run stressng k8s tests
This PR increase the time to run the stressng k8s tests for the
CoCo stability CI.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-24 16:34:17 +00:00
Fabiano Fidêncio
475ad3e06b workflows: devel: Allow running more than one at once
More than one developer can and should be able to run this workflow at
the same time, without cancelling the job started by another developer.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-24 15:38:35 +02:00
Fabiano Fidêncio
8f634ceb6b workflows: devel: Adjust the pr-number
Let's use "dev" instead of "manually-triggered" as it avoids the name
being too long, which results in failures to create AKS clusters.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-24 15:38:31 +02:00
GabyCT
41d1178e4a Merge pull request #10438 from GabyCT/topic/fixspellreadme
docs: Fix misspelling in CI documentation
2024-10-23 13:34:52 -06:00
Steve Horsman
c5c389f473 Merge pull request #10449 from kata-containers/topic/add-workflows-specifically-for-testing
Add a specific workflow for testing the CI, without messing up with the "nightly" weather
2024-10-23 19:03:49 +01:00
Gabriela Cervantes
093a6fd542 tests: Add trap statement in kata doc script
This PR adds the trap statement into the kata doc
script to clean up properly the temporary files.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-23 15:56:58 +00:00
Gabriela Cervantes
701891312e docs: Fix misspelling in CI documentation
This PR fixes a misspelling in CI documentation readme.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-23 15:42:08 +00:00
Fabiano Fidêncio
829415dfda workflows: Remove the possibility to manually trigger the nightly CI
As a new workflow was added for the cases where developers want to test
their changes in the workflow itself, let's make sure we stop allowing
manual triggers on this workflow, which can lead to a polluted /
misleading weather of the CI.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-23 13:19:45 +02:00
Fabiano Fidêncio
cc093cdfdb workflows: Add a manually trigger "devel" workflow for the CI
This workflow is intended to replace the `workflow_dispatch` trigger
currently present as part of the `ci-nightly.yaml`.

The reasoning behind having this done in this way is because of our good
and old GHA behaviour for `pull_request_target`, which requires a PR to
be merged in order to check the changes in the workflow itself, which
leads to:
* when a change in a workflow is done, developers (should) do:
  * push their branch to the kata-containers repo
  * manually trigger the "nightly" CI in order to ensure the changes
    don't break anything
    * this can result in the "nightly" CI weather being polluted
      * we don't have the guarantee / assurance about the last n nightly
	runs anymore

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-23 13:14:50 +02:00
Greg Kurz
378f454fb9 Merge pull request #10208 from wtootw/main
runtime: Failed to clean up resources when QEMU is terminated
2024-10-23 12:11:57 +02:00
Fabiano Fidêncio
ca416d8837 Merge pull request #10446 from kata-containers/topic/re-work-shim-v2-build-as-part-of-the-ci-and-release
workflows: Ensure shim-v2 is built as the last asset
2024-10-23 09:27:29 +02:00
Fabiano Fidêncio
c082b99652 Merge pull request #10439 from microsoft/mahuber/azl-cfg-var
tools: Change PACKAGES var for cbl-mariner
2024-10-23 08:39:49 +02:00
Manuel Huber
a730cef9cf tools: Change PACKAGES var for cbl-mariner
Change the PACKAGES variable for the cbl-mariner rootfs-builder
to use the kata-packages-uvm meta package from
packages.microsoft.com to define the set of packages to be
contained in the UVM.
This aligns the UVM build for the Azure Linux distribution
with the UVM build done for the Kata Containers offering on
Azure Kubernetes Services (AKS).

Signed-off-by: Manuel Huber <mahuber@microsoft.com>
2024-10-22 23:11:42 +00:00
Fabiano Fidêncio
67a8665f51 workflows: Ensure shim-v2 is built as the last asset
By doing this we can ensure that whenever the rootfs changes, we'll be
able to get the new root_hash.txt and use it.

This is the very first step to bring the measured rootfs tests back.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-22 14:56:37 +02:00
Greg Kurz
3de6d09a86 Merge pull request #10443 from gkurz/release-3.10.0
release: Bump VERSION to 3.10.0
2024-10-22 14:46:30 +02:00
Greg Kurz
3037303e09 release: Bump VERSION to 3.10.0
Let's start the 3.10.0 release.

Signed-off-by: Greg Kurz <groug@kaod.org>
2024-10-22 11:28:15 +02:00
wangyaqi54
cf4b81344d runtime: Failed to clean up resources when QEMU is terminated by signal 15
When QEMU is terminated by signal 15, it deletes the PidFile.
Upon detecting that QEMU has exited, the shim executes the stopVM function.
If the PidFile is not found, the PID is set to 0.
Subsequently, the shim executes `kill -9 0`, which terminates the current process group.
This prevents any further logic from being executed, resulting in resources not being cleaned up.

Signed-off-by: wangyaqi54 <wangyaqi54@jd.com>
2024-10-22 17:04:46 +08:00
Fabiano Fidêncio
4c34cfb0ab Merge pull request #10420 from pmores/add-support-for-virtio-scsi
runtime-rs: support virtio-scsi device in qemu-rs
2024-10-22 11:00:33 +02:00
Pavel Mores
8cdd968092 runtime-rs: support virtio-scsi device in qemu-rs
Semantics are lifted straight out of the go runtime for compatibility.
We introduce DeviceVirtioScsi to represent a virtio-scsi device and
instantiate it if block device driver in the configuration file is set
to virtio-scsi.  We also introduce ObjectIoThread which is instantiated
if the configuration file additionally enables iothreads.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-22 08:55:54 +02:00
Greg Kurz
91b874f18c Merge pull request #10421 from Apokleos/hostname-bugfix
kata-agent: fixing bug of unable setting hostname correctly.
2024-10-22 00:26:51 +02:00
alex.lyn
b25538f670 ci: Introduce CI to validate pod hostname
Fixes #10422

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2024-10-21 16:32:56 +01:00
alex.lyn
3dabe0f5f0 kata-agent: fixing bug of unable setting hostname correctly.
When do update_container_namespaces updating namespaces, setting
all UTS(and IPC) namespace paths to None resulted in hostnames
set prior to the update becoming ineffective. This was primarily
due to an error made while aligning with the oci spec: in an attempt
to match empty strings with None values in oci-spec-rs, all paths
were incorrectly set to None.

Fixes #10325

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2024-10-21 16:32:56 +01:00
Steve Horsman
98886a7571 Merge pull request #10437 from mkulke/mkulke/dont-parse-oci-image-for-cached-artifacts
ci: don't parse oci image for cached artifacts
2024-10-21 16:31:23 +01:00
Magnus Kulke
e27d70d47e ci: don't parse oci image for cached artifacts
Moved the parsing of the oci image marker into its own step, since we
only need to perform that for attestation purposes and some cached
images might not have that file in the tarball.

Signed-off-by: Magnus Kulke <magnuskulke@microsoft.com>
2024-10-21 14:50:00 +02:00
Magnus Kulke
9a33a3413b Merge pull request #10433 from mkulke/mkulke/add-provenance-attestation-for-agent-builds
ci: add provenance attestation for agent artifact
2024-10-18 15:00:18 +02:00
Anastassios Nanos
68d539f5c5 Merge pull request #10435 from nubificus/fix_fc_machineconfig
runtime-rs: Use vCPU and memory values from config
2024-10-18 13:41:20 +01:00
Magnus Kulke
b93f5390ce ci: add provenance attestation for agent artifact
This adds provenance attestation logic for agent binaries that are
published to an oci registry via ORAS.

As a downstream consumer of the kata-agent binary the Peerpod project
needs to verify that the artifact has been built on kata's CI.

To create an attestation we need to know the exact digest of the oci
artifact, at the point when the artifact was pushed.

Therefore we record the full oci image as returned by oras push.

The pushing and tagging logic has been slightly reworked to make this
task less repetetive.

The oras cli accepts multiple tags separated by comma on pushes, so a
push can be performed atomically instead of iterating through tags and
pushing each individually. This removes the risk of partially successful
push operations (think: rate limits on the oci registry).

So far the provenance creation has been only enabled for agent builds on
amd64 and xs390x.

Signed-off-by: Magnus Kulke <magnuskulke@microsoft.com>
2024-10-18 10:24:00 +02:00
Anastassios Nanos
23f5786cca runtime-rs: Use vCPU and memory values from config
Use values from the config for the setup of the microVM.

Fixes: #10434

Signed-off-by: Anastassios Nanos <ananos@nubificus.co.uk>
2024-10-17 23:17:02 +01:00
GabyCT
4ae9317675 Merge pull request #10430 from GabyCT/topic/ciaz
docs: Update CI documentation
2024-10-17 15:09:24 -06:00
GabyCT
b00203ba9b Merge pull request #10428 from GabyCT/topic/archk8sc
gha: Use a arch_to_golang variable to have uniformity
2024-10-17 11:00:59 -06:00
Chengyu Zhu
cca77f0911 Merge pull request #10412 from stevenhorsman/agent-config-rstest
agent: config: Use rstest for unit tests
2024-10-17 23:01:21 +08:00
Gabriela Cervantes
e3efad8ed2 docs: Update CI documentation
This PR updates the CI documentation referring to the several tests and
in which kind of instances is running them.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-16 19:23:19 +00:00
stevenhorsman
4adb454ed0 agent: config: Use rstest for unit tests
Use rstest for unit test rather than TestData arrays where
possible to make the code more compact, easier to read
and open the possibility to enhance test cases with a
description more easily.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-10-16 16:55:44 +01:00
Gabriela Cervantes
f0e0c74fd4 gha: Use a arch_to_golang variable to have uniformity
This PR replaces the arch uname -m to use the arch_to_golang
variable in the script to have a better uniformity across the script.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-15 20:03:09 +00:00
Dan Mihai
69509eff33 Merge pull request #10417 from microsoft/danmihai1/k8s-inotify.bats
tests: k8s-inotify.bats improvements
2024-10-15 11:22:53 -07:00
Dan Mihai
ece0f9690e tests: k8s-inotify: longer pod termination timeout
inotify-configmap-pod.yaml is using: "inotifywait --timeout 120",
so wait for up to 180 seconds for the pod termination to be
reported.

Hopefully, some of the sporadic errors from #10413 will be avoided
this way:

not ok 1 configmap update works, and preserves symlinks
waitForProcess "${wait_time}" "$sleep_time" "${command}" failed

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-15 16:01:25 +00:00
Dan Mihai
ccfb7faa1b tests: k8s-inotify.bats: don't leak configmap
Delete the configmap if the test failed, not just on the successful
path.

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-15 16:01:25 +00:00
Aurélien Bombo
f13d13c8fa Merge pull request #10416 from microsoft/danmihai1/mariner_static_sandbox_resource_mgmt
ci: static_sandbox_resource_mgmt for cbl-mariner
2024-10-15 10:40:17 -05:00
Aurélien Bombo
c371b4e1ce Merge pull request #10426 from 3u13r/fix/genpolicy/handle-config-map-binary-data
genpolicy: read binaryData value as String
2024-10-14 21:31:23 -05:00
Leonard Cohnen
c06bf2e3bb genpolicy: read binaryData value as String
While Kubernetes defines `binaryData` as `[]byte`,
when defined in a YAML file the raw bytes are
base64 encoded. Therefore, we need to read the YAML
value as `String` and not as `Vec<u8>`.

Fixes: #10410

Signed-off-by: Leonard Cohnen <lc@edgeless.systems>
2024-10-14 20:03:11 +02:00
Aurélien Bombo
f9b7a8a23c Merge pull request #10402 from Sumynwa/sumsharma/agent-ctl-dependencies
ci: Install build dependencies for building agent-ctl with image pull.
2024-10-14 10:28:32 -05:00
Sumedh Alok Sharma
bc195d758a ci: Install build dependencies for building agent-ctl with image pull.
Adds dependencies of 'clang' & 'protobuf' to be installed in runners
when building agent-ctl sources having image pull support.

Fixes #10400

Signed-off-by: Sumedh Alok Sharma <sumsharma@microsoft.com>
2024-10-14 10:36:04 +05:30
Aurélien Bombo
614e21ccfb Merge pull request #10415 from GabyCT/topic/egreptim
tools/osbuilder/tests: Remove egrep in test images script
2024-10-11 13:47:30 -05:00
Gabriela Cervantes
aae654be80 tools/osbuilder/tests: Remove egrep in test images script
This PR removes egrep command as it has been deprecated and it replaces by
grep in the test images script.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-11 17:23:35 +00:00
Dan Mihai
3622b5e8b4 ci: static_sandbox_resource_mgmt for cbl-mariner
Use the configuration used by AKS (static_sandbox_resource_mgmt=true)
for CI testing on Mariner hosts.

Hopefully pod startup will become more predictable on these hosts -
e.g., by avoiding the occasional hotplug timeouts described by #10413.

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-10 22:17:39 +00:00
Fabiano Fidêncio
02f5fd94bd Merge pull request #10409 from fidencio/topic/ci-add-ita_image-and-ita_image_tag
kbs: ita: Ensure the proper image / image_tag is used for ITA
2024-10-10 11:46:26 +02:00
Fabiano Fidêncio
cf5d3ed0d4 kbs: ita: Ensure the proper image / image_tag is used for ITA
When dealing with a specific release, it was easier to just do some
adjustments on the image that has to be used for ITA without actually
adding a new entry in the versions.yaml.

However, it's been proven to be more complicated than that when it comes
to dealing with staged images, and we better explicitly add (and
update) those versions altogether to avoid CI issues.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-10 10:01:33 +02:00
Steve Horsman
0c4a7c8771 Merge pull request #10406 from ChengyuZhu6/fix-unit
agent:cdh: fix unit tests about sealed secret
2024-10-10 08:57:28 +01:00
Fabiano Fidêncio
3f7ce1d620 Merge pull request #10401 from stevenhorsman/kbs-deploy-overlays-update
Kbs deploy overlays update
2024-10-10 09:50:19 +02:00
Fabiano Fidêncio
036b04094e Merge pull request #10397 from fidencio/topic/build-remove-initrd-mariner-target
build: mariner: Remove the ability to build the marine initrd
2024-10-10 09:44:36 +02:00
ChengyuZhu6
65ecac5777 agent:cdh: fix unit tests about sealed secret
The root cause is that the CDH client is a global variable, and unit tests `test_unseal_env` and `test_unseal_file`
share this lock-free global variable, leading to resource contention and destruction.
Merging the two unit tests into one test_sealed_secret will resolve this issue.

Fixes: #10403

Signed-off-by: ChengyuZhu6 <zhucy0405@gmail.com>
2024-10-10 08:38:06 +08:00
ChengyuZhu6
a992feb7f3 Revert "Revert "agent:cdh: unittest for sealed secret as file""
This reverts commit b5142c94b9.

Signed-off-by: ChengyuZhu6 <zhucy0405@gmail.com>
2024-10-10 08:37:06 +08:00
GabyCT
0cda92c6d8 Merge pull request #10407 from GabyCT/topic/fixbuildk
packaging: Remove unused variable in build kernel script
2024-10-09 16:53:45 -06:00
Gabriela Cervantes
616eb8b19b packaging: Remove unused variable in build kernel script
This PR removes an unused variable in the build kernel script.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-09 20:02:56 +00:00
Fabiano Fidêncio
652ba30d4a build: mariner: Remove the ability to build the marine initrd
As mariner has switched to using an image instead of an initrd, let's
just drop the abiliy to build the initrd and avoid keeping something in
the tree that won't be used.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-09 21:42:55 +02:00
Fabiano Fidêncio
59e3ab07e4 Merge pull request #10396 from fidencio/topic/ci-mariner-test-using-mariner-image-instead-of-initrd
ci: mariner: Use the image instead of the initrd
2024-10-09 21:39:44 +02:00
stevenhorsman
b2fb19f8f8 versions: Bump KBS version
Bump to the commit that had the overlays changes we want
to adapt to.

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-10-09 17:49:21 +01:00
Fabiano Fidêncio
01a957f7e1 ci: mariner: Stop building mariner initrd
As the mariner image is already in place, and the tests were modified to
use them (as part of this series), let's just stop building it as part
of the CI.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-09 18:23:35 +02:00
Fabiano Fidêncio
091ad2a1b2 ci: mariner: Ensure kernel_params can be set
The reason we're doing this is because mariner image uses, by default,
cgroups default-hierarchy as `unified` (aka, cgroupsv2).

In order to keep the same initrd behaviour for mariner, let's enforce
that `SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1
systemd.legacy_systemd_cgroup_controller=yes
systemd.unified_cgroup_hierarchy=0` is passed to the kernel cmdline, at
least for now.

Other tests that are setting `kernel_params` are not running on mariner,
then we're safe taking this path as it's done as part of this PR.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-09 18:23:35 +02:00
Fabiano Fidêncio
3bbf3c81c2 ci: mariner: Use the image instead of the initrd
As an image has been added for mariner as part of the commit 63c1f81c2,
let's start using it in the CI, instead of using the initrd.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-09 18:23:32 +02:00
Fabiano Fidêncio
9c0c159b25 Merge pull request #10404 from fidencio/topic/rever-sealed-secrets-tests
Revert "agent:cdh: unittest for sealed secret as file"
2024-10-09 18:09:09 +02:00
GabyCT
2035d638df Merge pull request #10388 from GabyCT/topic/testimtemp
tools/osbuilder/tests: Add trap statement in test images script
2024-10-09 09:49:45 -06:00
Fabiano Fidêncio
b5142c94b9 Revert "agent:cdh: unittest for sealed secret as file"
This reverts commit 31e09058af, as it's
breaking the agent unit tests CI.

This is a stop gap till Chengyu Zhu finds the time to properly address
the issue, avoiding the CI to be blocked for now.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-09 16:06:09 +02:00
stevenhorsman
8763880e93 tests/k8s: kbs: Update overlays logic
In https://github.com/confidential-containers/trustee/pull/521
the overlays logic was modified to add non-SE
s390x support and simplify non-ibm-se platforms.
We need to update the logic in `kbs_k8s_deploy`
to match and can remove the dummying of `IBM_SE_CREDS_DIR`
for non-SE now

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-10-09 09:39:41 +01:00
Gabriela Cervantes
e08749ce58 tools/osbuilder/tests: Add trap statement in test images script
This PR adds the trap statement in the test images script to clean up
tmp files.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-08 19:54:23 +00:00
Fabiano Fidêncio
80196c06ad Merge pull request #10390 from microsoft/danmihai1/new-rootfs-image-mariner
local-build: add ability to build rootfs-image-mariner
2024-10-08 21:40:43 +02:00
Fabiano Fidêncio
083b2f24d8 Merge pull request #10363 from ChengyuZhu6/secret-as-volume
Support Confidential Sealed Secrets (as volume)
2024-10-08 19:23:40 +02:00
Dan Mihai
63c1f81c23 local-build: add rootfs-image-mariner
Kata CI will start testing the new rootfs-image-mariner instead of the
older rootfs-initrd-mariner image.

The "official" AKS images are moving from a rootfs-initrd-mariner
format to the rootfs-image-mariner format. Making the same change in
Kata CI is useful to keep this testing in sync with the AKS settings.

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-08 17:15:56 +00:00
GabyCT
7a38cce73c Merge pull request #10383 from kata-containers/topic/imagevar
image-builder: Remove unused variable
2024-10-08 10:27:03 -06:00
Aurélien Bombo
e56af7a370 Merge pull request #10389 from emanuellima1/fix-agent-policy
build: Fix RPM build fail due to AGENT_POLICY
2024-10-08 09:59:21 -05:00
ChengyuZhu6
a94024aedc tests: add test for sealed file secrets
add a test for sealed file secrets.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
2024-10-08 16:01:48 +08:00
ChengyuZhu6
fe307303c8 agent:rpc: Refactor CDH-related operations
Refactor CDH-related operations into the cdh_handler function to make the `create_container` code clearer.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
2024-10-08 16:01:48 +08:00
ChengyuZhu6
31e09058af agent:cdh: unittest for sealed secret as file
add unittest for sealed secret as file.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
Signed-off-by: Linda Yu <linda.yu@intel.com>
2024-10-08 16:01:48 +08:00
ChengyuZhu6
974d6b0736 agent:cdh: initialize cdhclient with the input cdh socket uri
Refactor cdh code to initialize cdhclient with the input cdh socket uri.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
2024-10-08 14:58:07 +08:00
ChengyuZhu6
1f33fd4cd4 agent:rpc: handle the sealed secret in createcontainer
Users must set the mount path to `/sealed/<path>` for kata agent to detect the sealed secret mount
and handle it in createcontainer stage.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
Signed-off-by: Linda Yu <linda.yu@intel.com>
2024-10-08 14:58:07 +08:00
ChengyuZhu6
da281b4444 agent:cdh: support to unseal secret as file
Introduced `unseal_file` function to unseal secret as files:
- Implemented logic to handle symlinks and regular files within the sealed secret directory.
- For each entry, call CDH to unseal secrets and the unsealed contents are written to a new file, and a symlink is created to replace the sealed symlink.

Fixes: #8123

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
Signed-off-by: Linda Yu <linda.yu@intel.com>
2024-10-08 14:58:07 +08:00
Fabiano Fidêncio
71d0c46e0a Merge pull request #10384 from microsoft/danmihai1/virtio-fs-policy
tests: k8s: AUTO_GENERATE_POLICY=yes for local testing
2024-10-07 21:25:52 +02:00
Emanuel Lima
e989e7ee4e build: Fix RPM build fail due to AGENT_POLICY
By checking for AGENT_POLICY we ensure we only try to read
allow-all.rego if AGENT_POLICY is set to "yes"

Signed-off-by: Emanuel Lima <emlima@redhat.com>
2024-10-07 15:43:23 -03:00
Dan Mihai
6d5fc898b8 tests: k8s: AUTO_GENERATE_POLICY=yes for local testing
The behavior of Kata CI doesn't change.

For local testing using kubernetes/gha-run.sh and AUTO_GENERATE_POLICY=yes:

1. Before these changes users were forced to use:
- SEV, SNP, or TDX guests, or
- KATA_HOST_OS=cbl-mariner

2. After these changes users can also use other platforms that are
configured with "shared_fs = virtio-fs" - e.g.,
- KATA_HOST_OS=ubuntu + KATA_HYPERVISOR=qemu

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-04 18:26:00 +00:00
Dan Mihai
5aaef8e6eb Merge pull request #10376 from microsoft/danmihai1/auto-generate-just-for-ci
gha: enable AUTO_GENERATE_POLICY where needed
2024-10-04 10:52:31 -07:00
Gabriela Cervantes
4cd737d9fd image-builder: Remove unused variable
This PR removes an unused variable in the image builder script.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-04 15:56:28 +00:00
Greg Kurz
77c5db6267 Merge pull request #9637 from ldoktor/selective-ci
CI: Select jobs by touched code
2024-10-04 11:29:05 +02:00
GabyCT
2d089d9695 Merge pull request #10381 from GabyCT/topic/archrootfs
osbuilder: Remove duplicated arch variable definition
2024-10-03 14:48:08 -06:00
Wainer Moschetta
b9025462fb Merge pull request #10134 from ldoktor/ci-sort-range
ci.ocp: Sort images according to git
2024-10-03 15:08:41 -03:00
Chelsea Mafrica
9138f55757 Merge pull request #10375 from GabyCT/topic/mktempkbs
k8s:kbs: Add trap statement to clean up tmp files
2024-10-03 12:32:30 -04:00
Gabriela Cervantes
d7c2b7d13c osbuilder: Remove duplicated arch variable definition
This PR removes duplicated arch variable definition in the rootfs script
as this variable and its value is already defined at the top of the
script.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-03 16:22:27 +00:00
Greg Kurz
96336d141b Merge pull request #10165 from pmores/add-network-device-hotplugging
runtime-rs: add network device hotplugging to qemu-rs
2024-10-03 17:44:50 +02:00
Pavel Mores
23927d8a94 runtime-rs: plug in netdev hotplugging functionality and actually call it
add_device() now checks if QEMU is running already by checking if we have
a QMP connection.  If we do a new function hotplug_device() is called
which hotplugs the device if it's a network one.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:23:10 +02:00
Pavel Mores
ac393f6316 runtime-rs: implement netdev hotplugging for qemu-rs
With the helpers from previous commit, the actual hotplugging
implementation, though lengthy, is mostly just assembling a QMP command
to hotplug the network device backend and then doing the same for the
corresponding frontend.

Note that hotplug_network_device() takes cmdline_generator types Netdev
and DeviceVirtioNet.  This is intentional and aims to take advantage of
the similarity between parameter sets needed to coldplug and hotplug
devices reuse and simplify our code.  To enable using the types from qmp,
accessors were added as needed.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:20:02 +02:00
Pavel Mores
4eb7e2966c runtime-rs: add netdev hotplugging helpers to qemu-rs
Before adding network device hotplugging functionality itself we add
a couple of helpers in a separate commit since their functionality is
non-trivial.

To hotplug a device we need a free PCI slot.  We add find_free_slot()
which can be called to obtain one.  It looks for PCI bridges connected
to the root bridge and looks for an unoccupied slot on each of them.  The
first found is returned to the caller.  The algorithm explicitly doesn't
support any more complex bridge hierarchies since those are never produced
when coldplugging PCI bridges.

Sending netdev queue and vhost file descriptors to QEMU is slightly
involved and implemented in pass_fd().  The actual socket has to be passed
in an SCM_RIGHTS socket control message (also called ancillary data, see
man 3 cmsg) so we have to use the msghdr structure and sendmsg() call
(see man 2 sendmsg) to send the message.  Since qapi-rs doesn't support
sending messages with ancillary data we have to do the sending sort of
"under it", manually, by retrieving qapi-rs's socket and using it directly.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:15:31 +02:00
Pavel Mores
3f46dfcf2f runtime-rs: don't treat NetworkConfig::index as unique in qemu-rs
NetworkConfig::index has been used to generate an id for a network device
backend.  However, it turns out that it's not unique (it's always zero
as confirmed by a comment at its definition) so it's not suitable to
generate an id that needs to be unique.

Use the host device name instead.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:12:37 +02:00
Pavel Mores
cda04fa539 runtime-rs: factor setup of network device out of QemuCmdLine
Network device hotplugging will use the same infrastructure (Netdev,
DeviceVirtioNet) as coldplugging, i.e. QemuCmdLine.  To make the code
of network device setup visible outside of QemuCmdLine we factor it out
to a non-member function `get_network_device()` and make QemuCmdLine just
delegate to it.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:03:32 +02:00
Pavel Mores
efc8e93bfe runtime-rs: factor bus_type() out of QemuCmdLine
The function takes a whole QemuCmdLine but only actually uses
HypervisorConfig.  We increase callability of the function by limiting
its interface to what it needs.  This will come handy shortly.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:03:32 +02:00
Pavel Mores
720265c2d8 runtime-rs: support adding PCI bridges to qemu VM
At least one PCI bridge is necessary to hotplug PCI devices.  We only
support PCI (at this point at least) since that's what the go runtime
does (note that looking at the code in virtcontainers it might seem that
other bus types are supported, however when the bridge objects are passed
to govmm, all but PCI bridges are actually ignored).  The entire logic of
bridge setup is lifted from runtime-go for compatibility's sake.

Signed-off-by: Pavel Mores <pmores@redhat.com>
2024-10-03 11:03:32 +02:00
Lukáš Doktor
63b6e8a215 ci: Ensure we check the latest workflow run in gatekeeper
with multiple iterations/reruns we need to use the latest run of each
workflow. For that we can use the "run_id" and only update results of
the same or newer run_ids.

To do that we need to store the "run_id". To avoid adding individual
attributes this commit stores the full job object that contains the
status, conclussion as well as other attributes of the individual jobs,
which might come handy in the future in exchange for slightly bigger
memory overhead (still we only store the latest run of required jobs
only).

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-03 09:10:45 +02:00
Lukáš Doktor
2ae090b44b ci: Add extra gatekeeper debug output to stderr
which might be useful to assess the amount of querries.

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-03 09:08:35 +02:00
Lukáš Doktor
2440a39c50 ci: Check required lables before checking tests in gatekeeper
some tests require certain labels before they are executed. When our PR
is not labeled appropriately the gatekeeper detects skipped required
tests and reports a failure. With this change we add "required-labeles"
to the tests mapping and check the expected labels first informing the
user about the missing labeles before even checking the test statuses.

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-03 09:08:35 +02:00
Lukáš Doktor
dd2878a9c8 ci: Unify character for separating items
the test names are using `;` and regexps were designed to use `,` but
during development simply joined the expressions by `|`. This should
work but might be confusing so let's go with the semi-colon separator
everywhere.

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-03 09:08:35 +02:00
Wainer dos Santos Moschetta
fdcfac0641 workflows/gatekeeper: export COMMIT_HASH variable
The Github SHA of triggering PR should be exported in the environment
so that gatekeeper can fetch the right workflows/jobs.

Note: by default github will export GITHUB_SHA in the job's environment
but that value cannot be used if the gatekeeper was triggered from a
pull_request_target event, because the SHA correspond to the push
branch.

Signed-off-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
2024-10-03 09:08:35 +02:00
Wainer dos Santos Moschetta
4abfc11b4f workflows/gatekeeper: configure concurrency properly
This will allow to cancel-in-progress the gatekeeper jobs.

Signed-off-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-03 09:08:35 +02:00
Lukáš Doktor
5c1cea1601 ci: Select jobs by touched code
to allow selective testing as well as selective list of required tests
let's add a mapping of required jobs/tests in "skips.py" and a
"gatekeaper" workflow that will ensure the expected required jobs were
successful. Then we can only mark the "gatekeaper" as the required job
and modify the logic to suit our needs.

Fixes: #9237

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-03 09:08:33 +02:00
Dan Mihai
1a4928e710 gha: enable AUTO_GENERATE_POLICY where needed
The behavior of Kata CI doesn't change.

For local testing using kubernetes/gha-run.sh:

1. Before these changes:
- AUTO_GENERATE_POLICY=yes was always used by the users of SEV, SNP,
  TDX, or KATA_HOST_OS=cbl-mariner.

2. After these changes:
- Users of SEV, SNP, TDX, or KATA_HOST_OS=cbl-mariner must specify
  AUTO_GENERATE_POLICY=yes if they want to auto-generate policy.
- These users have the option to test just using hard-coded policies
  (e.g., using the default policy built into the Guest rootfs) by
  using AUTO_GENERATE_POLICY=no. AUTO_GENERATE_POLICY=no is the default
  value of this env variable.

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-02 23:20:33 +00:00
Gabriela Cervantes
973b8a1d8f k8s:kbs: Add trap statement to clean up tmp files
This PR adds the trap statement in the confidential kbs script
to clean up temporary files and ensure we are leaving them.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-10-02 19:59:08 +00:00
Steve Horsman
8412c09143 Merge pull request #10371 from fidencio/topic/k8s-tdx-re-enable-empty-dir-tests
k8s: tests: Re-enable empty-dirs tests for TDX / coco-qemu-dev
2024-10-02 18:41:19 +01:00
Dan Mihai
9a8341f431 Merge pull request #10370 from microsoft/danmihai1/k8s-policy-rc
tests: k8s-policy-rc: remove default UID from YAML
2024-10-02 09:32:17 -07:00
GabyCT
a1d380305c Merge pull request #10369 from GabyCT/topic/egrepfastf
metrics: Update fast footprint script to use grep
2024-10-02 10:10:12 -06:00
Fabiano Fidêncio
b3ed7830e4 k8s: tests: Re-enable empty-dirs tests for TDX / coco-qemu-dev
The tests is disabled for qemu-coco-dev / qemu-tdx, but it doesn't seen
to actually be failing on those.  Plus, it's passing on SEV / SNP, which
means that we most likely missed re-enabling this one in the past.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-10-01 20:51:01 +02:00
Hyounggyu Choi
b179598fed Merge pull request #10374 from BbolroC/skip-block-volume-qemu-runtime-rs
tests: Skip k8s-block-volume.bats for qemu-runtime-rs
2024-10-01 19:45:10 +02:00
Lukáš Doktor
820e000f1c ci.ocp: Sort images according to git
The quay.io registry returns the tags sorted alphabetically and doesn't
seem to provide a way to sort it by age. Let's use "git log" to get all
changes between the commits and print all tags that were actually
pushed.

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-10-01 16:08:00 +02:00
Hyounggyu Choi
4ccf1f29f9 tests: Skip k8s-block-volume.bats for qemu-runtime-rs
Currently, `qemu-runtime-rs` does not support `virtio-scsi`,
which causes the `k8s-block-volume.bats` test to fail.
We should skip this test until `virtio-scsi` is supported by the runtime.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-10-01 09:09:47 +02:00
Dan Mihai
3b24219310 tests: k8s-policy-rc: remove default UID from YAML
The nginx container seems to error out when using UID=123.

Depending on the timing between container initialization and "kubectl
wait", the test might have gotten lucky and found the pod briefly in
Ready state before nginx errored out. But on some of the nodes, the pod
never got reported as Ready.

Also, don't block in "kubectl wait --for=condition=Ready" when wrapping
that command in a waitForProcess call, because waitForProcess is
designed for short-lived commands.

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-10-01 00:10:30 +00:00
Saul Paredes
94bc54f4d2 Merge pull request #10340 from microsoft/saulparedes/validate_create_sandbox_storages
genpolicy: validate create sandbox storages
2024-09-30 14:24:56 -07:00
Aurélien Bombo
b49800633d Merge pull request #7165 from sprt/k8s-block-volume-test
tests: Add `k8s-block-volume` test to GHA CI
2024-09-30 13:26:18 -07:00
Dan Mihai
7fe44d3a3d genpolicy: validate create sandbox storages
Reject any unexpected values from the CreateSandboxRequest storages
field.

Signed-off-by: Dan Mihai <dmihai@microsoft.com>
2024-09-30 11:31:12 -07:00
Gabriela Cervantes
52ef092489 metrics: Update fast footprint script to use grep
This PR updates the fast footprint script to remove the use
of egrep as this command has been deprecated and change it
to use grep command.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-09-30 17:43:08 +00:00
Aurélien Bombo
c037ac0e82 tests: Add k8s-block-volume test
This imports the k8s-block-volume test from the tests repo and modifies
it slightly to set up the host volume on the AKS host.

This is a follow-up to #7132.

Fixes: #7164

Signed-off-by: Salvador Fuentes <salvador.fuentes@intel.com>
Signed-off-by: Aurélien Bombo <abombo@microsoft.com>
2024-09-30 10:58:30 -05:00
Alex Lyn
dfd0ca9bfe Merge pull request #10312 from sidneychang/configurable-build-dragonball
runtime-rs: Add Configurable Compilation for Dragonball in Runtime-rs
2024-09-29 22:33:54 +08:00
GabyCT
6a9e3ccddf Merge pull request #10305 from GabyCT/topic/ita
ci:tdx: Use an ITA key for TDX
2024-09-27 16:44:53 -06:00
Fabiano Fidêncio
66bcfe7369 k8s: kbs: Properly delete ita kustomization
The ita kustomization for Trustee, as well as previously used one
(DCAP), doesn't have a $(uname -m) directory after the deployment
directory name.

Let's follow the same logic used for the deploy-kbs script and clean
those up accordingly.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-09-27 21:47:29 +02:00
Gabriela Cervantes
bafa527be0 ci: tdx: Test attestation with ITTS
Intel Tiber Trust Services (formerly known as Intel Trust Authority) is
Intel's own attestation service, and we want to take advantage of the
TDX CI in order to ensure ITTS works as expected.

In order to do so, let's replace the former method used (DCAP) to use
ITTS instead.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-09-27 21:47:25 +02:00
GabyCT
36750b56f1 Merge pull request #10342 from GabyCT/topic/updevguide
docs: Remove qemu information not longer valid
2024-09-27 11:15:11 -06:00
Fabiano Fidêncio
86b8c53d27 Merge pull request #10357 from fidencio/topic/add-ita-secret
gha: Add ita_key as a github secret
2024-09-27 17:40:41 +02:00
Gabriela Cervantes
d91979d7fa gha: Add ita_key as a github secret
This PR adds ita_key as a github secret at the kata coco tests yaml workflow.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-09-27 17:15:22 +02:00
Xuewei Niu
ad0f2b2a55 Merge pull request #10219 from sidneychang/decouple-runtime-rs-from-dragonball
runtime-rs: Port TAP implementation from dragonball
2024-09-27 11:17:55 +08:00
Xuewei Niu
11b1a72442 Merge pull request #10349 from lifupan/main_nsandboxapi
sandbox: refactor the sandbox init process
2024-09-27 11:10:45 +08:00
Xuewei Niu
3911bd3108 Merge pull request #10351 from lifupan/main_agent
agent: fix the issue of setup sandbox pidns
2024-09-27 10:49:47 +08:00
Fupan Li
f7bc627a86 sandbox: refactor the sandbox init process
Inorder to support sandbox api, intorduce the sandbox_config
struct and split the sandbox start stage from init process.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2024-09-26 23:50:24 +08:00
Hyounggyu Choi
b1275bed1b Merge pull request #10346 from BbolroC/minor-improvement-k8s-tests
tests: Minor improvement k8s tests
2024-09-26 17:01:32 +02:00
Hyounggyu Choi
01d460ac63 tests: Add teardown_common() to tests_common.sh
There are many similar or duplicated code patterns in `teardown()`.
This commit consolidates them into a new function, `teardown_common()`,
which is now called within `teardown()`.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-26 13:56:36 +02:00
Hyounggyu Choi
e8d1feb25f tests: Validate node name for exec_host()
The current `exec_host()` accepts a given node name and
creates a node debugger pod, even if the name is invalid.
This could result in the creation of an unnecessary pending
pod (since we are using nodeAffinity; if the given name
does not match any actual node names, the pod won’t be scheduled),
which wastes resources.

This commit introduces validation for the node name to
prevent this situation.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-26 13:20:50 +02:00
Xuewei Niu
3a7f9595b6 Merge pull request #10318 from lsc2001/ci-add-docker
ci: Enable basic docker tests for runtime-rs
2024-09-26 17:41:09 +08:00
Xuewei Niu
cb5a2b30e9 Merge pull request #10293 from lsc2001/solve-docker-compatibility
runtime-rs: Notify containerd when process exits
2024-09-26 14:51:20 +08:00
Sicheng Liu
e4733748aa ci: Enable basic docker tests for runtime-rs
This commit enables basic amd64 tests of docker for runtime-rs by adding
vmm types "dragonball" and "cloud-hypervisor".

Signed-off-by: Sicheng Liu <lsc2001@outlook.com>
2024-09-26 06:27:05 +00:00
Sicheng Liu
08eb5fc7ff runtime-rs: Notify containerd when process exits
Docker cannot exit normally after the container process exits when
used with runtime-rs since it doesn't receive the exit event. This
commit enable runtime-rs to send TaskExit to containerd after process
exits.

Also, it moves "system_time_into" and "option_system_time_into" from
crates/runtimes/common/src/types/trans_into_shim.rs to a new utility
mod.

Signed-off-by: Sicheng Liu <lsc2001@outlook.com>
2024-09-26 02:52:50 +00:00
Fupan Li
71afeccdf1 agent: fix the issue of setup sandbox pidns
When the sandbox api was enabled, the pasue container
wouldn't be created, thus the shared sandbox pidns
should be fallbacked to the first container's init process,
instead of return any error here.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2024-09-26 10:21:25 +08:00
Xuewei Niu
857222af02 Merge pull request #10330 from lifupan/main_sandboxapi
Some prepared work for sandbox api support
2024-09-26 09:47:47 +08:00
Hyounggyu Choi
caf3b19505 Merge pull request #10348 from BbolroC/delete-node-debugger-by-trap
tests: Delete custom node debugger pod on EXIT
2024-09-25 23:39:43 +02:00
Hyounggyu Choi
57e8cbff6f tests: Delete custom node debugger pod on EXIT
It was observed that the custom node debugger pod is not
cleaned up when a test times out.
This commit ensures the pod is cleaned up by triggering
the cleanup on EXIT, preventing any debugger pods from
being left behind.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-25 20:36:05 +02:00
Fabiano Fidêncio
edf4ca4738 Merge pull request #10345 from ldoktor/kata-webhook
ci: Reorder webhook deployment
2024-09-25 18:16:46 +02:00
Fabiano Fidêncio
09ed9c5c50 Merge pull request #10328 from BbolroC/improve-negative-tests
tests: Improve k8s negative tests
2024-09-25 18:16:28 +02:00
Xuewei Niu
e1825c2ef3 Merge pull request #9977 from l8huang/dan-2-vfio
runtime: add DAN support for VFIO network device in Go kata-runtime
2024-09-25 10:11:38 +08:00
Lei Huang
39b0e9aa8f runtime: add DAN support for VFIO network device in Go kata-runtime
When using network adapters that support SR-IOV, a VFIO device can be
plugged into a guest VM and claimed as a network interface. This can
significantly enhance network performance.

Fixes: #9758

Signed-off-by: Lei Huang <leih@nvidia.com>
2024-09-24 09:53:28 -07:00
Hyounggyu Choi
c70588fafe tests: Use custom-node-debugger pod
With #10232 merged, we now have a persistent node debugger pod throughout the test.
As a result, there’s no need to spawn another debugger pod using `kubectl debug`,
which could lead to false negatives due to premature pod termination, as reported
in #10081.

This commit removes the `print_node_journal()` call that uses `kubectl debug` and
instead uses `exec_host()` to capture the host journal. The `exec_host()` function
is relocated to `tests/integration/kubernetes/lib.sh` to prevent cyclical dependencies
between `tests_common.sh` and `lib.sh`.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-24 17:25:24 +02:00
Lukáš Doktor
8355eee9f5 ci: Reorder webhook deployment
in b9d88f74ed the `runtime_class` CM was
added which overrides the one we previously set. Let's reorder our logic
to first deploy webhook and then override the default CM in order to use
the one we really want.

Since we need to change dirs we also have to use realpath to ensure the
files are located well.

Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
2024-09-24 17:01:28 +02:00
Hyounggyu Choi
2c2941122c tests: Fail fast in assert_pod_fail()
`assert_pod_fail()` currently calls `k8s_create_pod()` to ensure that a pod
does not become ready within the default 120s. However, this delays the test's
completion even if an error message is detected earlier in the journal.

This commit removes the use of `k8s_create_pod()` and modifies `assert_pod_fail()`
to fail as soon as the pod enters a failed state.

All failing pods end up in one of the following states:

- CrashLoopBackOff
- ImagePullBackOff

The function now polls the pod's state every 5 seconds to check for these conditions.
If the pod enters a failed state, the function immediately returns 0. If the pod
does not reach a failed state within 120 seconds, it returns 1.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-24 16:09:20 +02:00
Gabriela Cervantes
6a8b137965 docs: Remove qemu information not longer valid
This PR removes some qemu information which is not longer valid as
this is referring to the tests repository and to kata 1.x.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-09-23 16:58:24 +00:00
Aurélien Bombo
e738054ddb Merge pull request #10311 from pawelpros/pproskur/fixyq
ci: don't require sudo for yq if already installed
2024-09-23 08:57:11 -07:00
Alex Lyn
6b94cc47a8 Merge pull request #10146 from Apokleos/intro-cdi
Introduce cdi in runtime-rs
2024-09-23 21:45:42 +08:00
Alex Lyn
b8ba346e98 runtime-rs: Add test for container devices with CDI.
Fixes #10145

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
2024-09-23 17:20:22 +08:00
Steve Horsman
0e0cb24387 Merge pull request #10329 from Bickor/webhook-check
tools.kata-webhook: Specify runtime class using configMap
2024-09-23 09:59:12 +01:00
Steve Horsman
6f0b3eb2f9 Merge pull request #10337 from stevenhorsman/update-release-process-post-3.9.0
doc: Update the release process
2024-09-23 09:55:57 +01:00
Hyounggyu Choi
8a893cd4ee Merge pull request #10232 from BbolroC/fix-loop-device-for-exec_host
tests: Fix loop device handling for exec_host()
2024-09-23 08:15:03 +02:00
Fupan Li
f1f5bef9ef Merge pull request #10339 from lifupan/main_fix
runtime-rs: fix the issue of using block_on
2024-09-23 09:28:40 +08:00
Fupan Li
52397ca2c1 sandbox: rename the task_service to service
rename the task_service to service, in order to
incopperate with the following added sandbox
services.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2024-09-22 14:44:19 +08:00
Fupan Li
20b4be0225 runtime-rs: rename the Request/Response to TaskRequest/TaskResponse
In order to make different from sandbox request/response, this commit
changed the task request/response to TaskRequest/TaskResponse.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2024-09-22 14:44:11 +08:00
Fupan Li
ba94eed891 sandbox: fix the issue of hypervisor's wait_vm
Since the wait_vm would be called before calling stop_vm,
which would take the reader lock, thus blocking the stop_vm
getting the writer lock, which would trigge the dead lock.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2024-09-22 14:44:03 +08:00
Fupan Li
fb27de3561 runtime-rs: fix the issue of using block_on
Since the block_on would block on the current thread
which would prevent other async tasks to be run on this
worker thread, thus change it to use the async task for
this task.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
2024-09-22 14:40:44 +08:00
Aurélien Bombo
79a3b4e2e5 Merge pull request #10335 from kata-containers/sprt/fix-kata-deploy-docs
kata-deploy: clean up and fix docs for k0s
2024-09-20 13:33:14 -07:00
stevenhorsman
4f745f77cb doc: Update the release process
- Reflect the need to update the versions in the Helm Chart
- Add the lock branch instruction
- Add clarity about the permissions needed to complete tasks

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2024-09-20 19:04:33 +01:00
Aurélien Bombo
78c63c7951 kata-deploy: clean up and fix docs for k0s
* Clarifies instructions for k0s.
* Adds kata-deploy step for each cluster type.
* Removes the old kata-deploy-stable step for vanilla k8s.

Signed-off-by: Aurélien Bombo <abombo@microsoft.com>
2024-09-20 11:59:40 -05:00
sidney chang
456e13db98 runtime-rs: Add Configurable Compilation for Dragonball in Runtime-rs
rename DEFAULT_HYPERVISOR to HYPERVISOR in Makefile
Fixes #10310

Signed-off-by: sidney chang <2190206983@qq.com>
2024-09-20 05:41:34 -07:00
sidneychang
b85a886694 runtime-rs: Add Configurable Compilation for Dragonball in Runtime-rs
This PR introduces support for selectively compiling Dragonball in
runtime-rs. By default, Dragonball will continue to be compiled into
the containerd-shim-kata-v2 executable, but users now have the option
to disable Dragonball compilation.

Fixes #10310

Signed-off-by: sidney chang <2190206983@qq.com>
2024-09-20 05:38:59 -07:00
Hyounggyu Choi
2d6ac3d85d tests: Re-enable guest-pull-image tests for qemu-coco-dev
Now that the issue with handling loop devices has been resolved,
this commit re-enables the guest-pull-image tests for `qemu-coco-dev`.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-20 14:37:43 +02:00
Hyounggyu Choi
c6b86e88e4 tests: Increase timeouts for qemu-coco-dev in trusted image storage tests
Timeouts occur (e.g. `create_container_timeout` and `wait_time`)
when using qemu-coco-dev.
This commit increases these timeouts for the trusted image storage
test cases

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-20 14:37:43 +02:00
Hyounggyu Choi
9cff9271bc tests: Run all commands in *_loop_device() using exec_host()
If the host running the tests is different from the host where the cluster is running,
the *_loop_device() functions do not work as expected because the device is created
on the test host, while the cluster expects the device to be local.

This commit ensures that all commands for the relevant functions are executed via exec_host()
so that a device should be handled on a cluster node.

Additionally, it modifies exec_host() to return the exit code of the last executed command
because the existing logic with `kubectl debug` sometimes includes unexpected characters
that are difficult to handle. `kubectl exec` appears to properly return the exit code for
a given command to it.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-20 14:37:43 +02:00
Hyounggyu Choi
374b8d2534 tests: Create and delete node debugger pod only once
Creating and deleting a node debugger pod for every `exec_host()`
call is inefficient.
This commit changes the test suite to create and delete the pod
only once, globally.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-20 14:37:43 +02:00
Hyounggyu Choi
aedf14b244 tests: Mimic node debugger with full privileges
This commit addresses an issue with handling loop devices
via a node debugger due to restricted privileges.
It runs a pod with full privileges, allowing it to mount
the host root to `/host`, similar to the node debugger.
This change enables us to run tests for trusted image storage
using the `qemu-coco-dev` runtime class.

Fixes: #10133

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2024-09-20 14:37:43 +02:00
Alex Lyn
63b25e8cb0 runtime-rs: Introduce cdi devices in container creation
Fixes #10145

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
2024-09-20 09:28:51 +08:00
Alex Lyn
03735d78ec runtime-rs: add cdi devices definition and related methods
Add cdi devices including ContainerDevice definition and
annotation_container_device method to annotate vfio device
in OCI Spec annotations which is inserted into Guest with
its mapping of vendor-class and guest pci path.

Fixes #10145

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
2024-09-20 09:28:51 +08:00
Alex Lyn
020e3da9b9 runtime-rs: extend DeviceVendor with device class
We need vfio device's properties device, vendor and
class, but we can only get property device and vendor.
just extend it with class is ok.

Fixes #10145

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
2024-09-20 09:28:51 +08:00
Fabiano Fidêncio
77c844da12 Merge pull request #10239 from fidencio/topic/remove-acrn
acrn: Drop support
2024-09-19 23:10:29 +02:00
GabyCT
6eef58dc3e Merge pull request #10336 from GabyCT/topic/extendtimeout
gha: Increase timeout to run k8s tests on TDX
2024-09-19 13:12:55 -06:00
Martin
b9d88f74ed tools.kata-webhook: Specify runtime class using configMap
The kata webhook requires a configmap to define what runtime class it
should set for the newly created pods. Additionally, the configmap
allows others to modify the default runtime class name we wish to set
(in case the handler is kata but the name of the runtimeclass is
different).

Finally, this PR changes the webhook-check to compare the runtime of the
newly created pod against the specific runtime class in the configmap,
if said confimap doesn't exist, then it will default to "kata".

Signed-off-by: Martin <mheberling@microsoft.com>
2024-09-19 11:51:38 -07:00
Fabiano Fidêncio
51dade3382 docs: Fix spell checker
tokio is not a valid word, it seeems, so let's use `tokio`.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-09-19 20:25:21 +02:00
Gabriela Cervantes
49b3a0faa3 gha: Increase timeout to run k8s tests on TDX
This PR increases the timeout to run k8s tests for Kata CoCo TDX
to avoid the random failures of timeout.

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2024-09-19 17:15:47 +00:00
Fabiano Fidêncio
31438dba79 docs: Fix qemu link
Otherwise static checks will fail, as we woke up the dogs with changes
on the same file.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-09-19 16:05:43 +02:00
Fabiano Fidêncio
fefcf7cfa4 acrn: Drop support
As we don't have any CI, nor maintainer to keep ACRN code around, we
better have it removed than give users the expectation that it should or
would work at some point.

Signed-off-by: Fabiano Fidêncio <fabiano@fidencio.org>
2024-09-19 16:05:43 +02:00
Pawel Proskurnicki
b63d49b34a ci: don't require sudo for yq if already installed
Yq installation shouldn't force to use sudo in case yq is already installed in correct version.

Signed-off-by: Pawel Proskurnicki <pawel.proskurnicki@intel.com>
2024-09-18 11:01:07 +02:00
sidney chang
5a7d0ed3ad runtime-rs: introduce tap in hypervisor by extrating it from dragonball
It's a prerequisite PR to make built-in vmm dragonball compilation
options configurable.

Extract TAP device-related code from dragonball's dbs_utils into a
separate library within the runtime-rs hypervisor module.
To enhance functionality and reduce dependencies, the extracted code
has been reimplemented using the libc crate and the ifreq structure.

Fixes #10182

Signed-off-by: sidney chang <2190206983@qq.com>
2024-09-13 07:32:14 -07:00
249 changed files with 9908 additions and 5521 deletions

View File

@@ -138,6 +138,8 @@ jobs:
run: bash tests/integration/nydus/gha-run.sh run
run-runk:
# Skip runk tests as we have no maintainers. TODO: Decide when to remove altogether
if: false
runs-on: ubuntu-22.04
env:
CONTAINERD_VERSION: lts
@@ -260,6 +262,8 @@ jobs:
vmm:
- clh
- qemu
- dragonball
- cloud-hypervisor
runs-on: ubuntu-22.04
env:
KATA_HYPERVISOR: ${{ matrix.vmm }}

View File

@@ -19,7 +19,6 @@ jobs:
- runtime-rs
- agent-ctl
- kata-ctl
- runk
- trace-forwarder
- genpolicy
command:
@@ -40,15 +39,11 @@ jobs:
component-path: src/tools/agent-ctl
- component: kata-ctl
component-path: src/tools/kata-ctl
- component: runk
component-path: src/tools/runk
- component: trace-forwarder
component-path: src/tools/trace-forwarder
- install-libseccomp: no
- component: agent
install-libseccomp: yes
- component: runk
install-libseccomp: yes
- component: genpolicy
component-path: src/tools/genpolicy
steps:
@@ -94,10 +89,10 @@ jobs:
echo "LIBSECCOMP_LINK_TYPE=static" >> $GITHUB_ENV
echo "LIBSECCOMP_LIB_PATH=${libseccomp_install_dir}/lib" >> $GITHUB_ENV
- name: Install protobuf-compiler
if: ${{ matrix.command != 'make vendor' && (matrix.component == 'agent' || matrix.component == 'runk' || matrix.component == 'genpolicy') }}
if: ${{ matrix.command != 'make vendor' && (matrix.component == 'agent' || matrix.component == 'genpolicy' || matrix.component == 'agent-ctl') }}
run: sudo apt-get -y install protobuf-compiler
- name: Install clang
if: ${{ matrix.command == 'make check' && matrix.component == 'agent' }}
if: ${{ matrix.command == 'make check' && (matrix.component == 'agent' || matrix.component == 'agent-ctl') }}
run: sudo apt-get -y install clang
- name: Setup XDG_RUNTIME_DIR for the `runtime` tests
if: ${{ matrix.command != 'make vendor' && matrix.command != 'make check' && matrix.component == 'runtime' }}

View File

@@ -24,6 +24,11 @@ on:
jobs:
build-asset:
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
id-token: write
attestations: write
strategy:
matrix:
asset:
@@ -48,13 +53,6 @@ jobs:
- qemu
- qemu-snp-experimental
- stratovirt
- rootfs-image
- rootfs-image-confidential
- rootfs-initrd
- rootfs-initrd-confidential
- rootfs-initrd-mariner
- runk
- shim-v2
- trace-forwarder
- virtiofsd
stage:
@@ -62,6 +60,8 @@ jobs:
exclude:
- asset: cloud-hypervisor-glibc
stage: release
env:
PERFORM_ATTESTATION: ${{ matrix.asset == 'agent' && inputs.push-to-registry == 'yes' && 'yes' || 'no' }}
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
@@ -83,6 +83,7 @@ jobs:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: Build ${{ matrix.asset }}
id: build
run: |
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
@@ -98,8 +99,35 @@ jobs:
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: Parse OCI image name and digest
id: parse-oci-segments
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
run: |
oci_image="$(<"build/${{ matrix.asset }}-oci-image")"
echo "oci-name=${oci_image%@*}" >> "$GITHUB_OUTPUT"
echo "oci-digest=${oci_image#*@}" >> "$GITHUB_OUTPUT"
- uses: oras-project/setup-oras@v1
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
with:
version: "1.2.0"
# for pushing attestations to the registry
- uses: docker/login-action@v3
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/attest-build-provenance@v1
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
with:
subject-name: ${{ steps.parse-oci-segments.outputs.oci-name }}
subject-digest: ${{ steps.parse-oci-segments.outputs.oci-digest }}
push-to-registry: true
- name: store-artifact ${{ matrix.asset }}
if: ${{ matrix.stage != 'release' || (matrix.asset != 'agent' && matrix.asset != 'coco-guest-components' && matrix.asset != 'pause-image') }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-amd64-${{ matrix.asset }}${{ inputs.tarball-suffix }}
@@ -107,9 +135,130 @@ jobs:
retention-days: 15
if-no-files-found: error
create-kata-tarball:
build-asset-rootfs:
runs-on: ubuntu-22.04
needs: build-asset
strategy:
matrix:
asset:
- rootfs-image
- rootfs-image-confidential
- rootfs-image-mariner
- rootfs-initrd
- rootfs-initrd-confidential
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-amd64-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build ${{ matrix.asset }}
id: build
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-amd64-${{ matrix.asset }}${{ inputs.tarball-suffix }}
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
retention-days: 15
if-no-files-found: error
build-asset-shim-v2:
runs-on: ubuntu-22.04
needs: [build-asset, build-asset-rootfs]
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-amd64-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build shim-v2
id: build
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: shim-v2
TAR_OUTPUT: shim-v2.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
MEASURED_ROOTFS: yes
- name: store-artifact shim-v2
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-amd64-shim-v2${{ inputs.tarball-suffix }}
path: kata-build/kata-static-shim-v2.tar.xz
retention-days: 15
if-no-files-found: error
create-kata-tarball:
runs-on: ubuntu-22.04
needs: [build-asset, build-asset-rootfs, build-asset-shim-v2]
steps:
- uses: actions/checkout@v4
with:

View File

@@ -35,9 +35,6 @@ jobs:
- nydus
- qemu
- stratovirt
- rootfs-image
- rootfs-initrd
- shim-v2
- virtiofsd
steps:
- name: Login to Kata Containers quay.io
@@ -76,7 +73,6 @@ jobs:
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact ${{ matrix.asset }}
if: ${{ inputs.stage != 'release' || matrix.asset != 'agent' }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-arm64-${{ matrix.asset }}${{ inputs.tarball-suffix }}
@@ -84,9 +80,124 @@ jobs:
retention-days: 15
if-no-files-found: error
create-kata-tarball:
build-asset-rootfs:
runs-on: arm64-builder
needs: build-asset
strategy:
matrix:
asset:
- rootfs-image
- rootfs-initrd
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-arm64-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build ${{ matrix.asset }}
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-arm64-${{ matrix.asset }}${{ inputs.tarball-suffix }}
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
retention-days: 15
if-no-files-found: error
build-asset-shim-v2:
runs-on: arm64-builder
needs: [build-asset, build-asset-rootfs]
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-arm64-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build shim-v2
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: shim-v2
TAR_OUTPUT: shim-v2.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact shim-v2
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-arm64-shim-v2${{ inputs.tarball-suffix }}
path: kata-build/kata-static-shim-v2.tar.xz
retention-days: 15
if-no-files-found: error
create-kata-tarball:
runs-on: arm64-builder
needs: [build-asset, build-asset-rootfs, build-asset-shim-v2]
steps:
- name: Adjust a permission for repo
run: |

View File

@@ -30,8 +30,6 @@ jobs:
- agent
- kernel
- qemu
- rootfs-initrd
- shim-v2
- virtiofsd
stage:
- ${{ inputs.stage }}
@@ -77,7 +75,6 @@ jobs:
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact ${{ matrix.asset }}
if: ${{ inputs.stage != 'release' || matrix.asset != 'agent' }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-ppc64le-${{ matrix.asset }}${{ inputs.tarball-suffix }}
@@ -85,9 +82,135 @@ jobs:
retention-days: 1
if-no-files-found: error
create-kata-tarball:
build-asset-rootfs:
runs-on: ppc64le
needs: build-asset
strategy:
matrix:
asset:
- rootfs-initrd
stage:
- ${{ inputs.stage }}
steps:
- name: Prepare the self-hosted runner
run: |
${HOME}/scripts/prepare_runner.sh
sudo rm -rf $GITHUB_WORKSPACE/*
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-ppc64le-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build ${{ matrix.asset }}
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-ppc64le-${{ matrix.asset }}${{ inputs.tarball-suffix }}
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
retention-days: 1
if-no-files-found: error
build-asset-shim-v2:
runs-on: ppc64le
needs: [build-asset, build-asset-rootfs]
steps:
- name: Prepare the self-hosted runner
run: |
${HOME}/scripts/prepare_runner.sh
sudo rm -rf $GITHUB_WORKSPACE/*
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-ppc64le-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build shim-v2
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: shim-v2
TAR_OUTPUT: shim-v2.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact shim-v2
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-ppc64le-shim-v2${{ inputs.tarball-suffix }}
path: kata-build/kata-static-shim-v2.tar.xz
retention-days: 1
if-no-files-found: error
create-kata-tarball:
runs-on: ppc64le
needs: [build-asset, build-asset-rootfs, build-asset-shim-v2]
steps:
- name: Adjust a permission for repo
run: |

View File

@@ -24,6 +24,11 @@ on:
jobs:
build-asset:
runs-on: s390x
permissions:
contents: read
packages: write
id-token: write
attestations: write
strategy:
matrix:
asset:
@@ -33,12 +38,9 @@ jobs:
- kernel-confidential
- pause-image
- qemu
- rootfs-image
- rootfs-image-confidential
- rootfs-initrd
- rootfs-initrd-confidential
- shim-v2
- virtiofsd
env:
PERFORM_ATTESTATION: ${{ matrix.asset == 'agent' && inputs.push-to-registry == 'yes' && 'yes' || 'no' }}
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
@@ -60,6 +62,7 @@ jobs:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: Build ${{ matrix.asset }}
id: build
run: |
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
@@ -75,8 +78,93 @@ jobs:
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: Parse OCI image name and digest
id: parse-oci-segments
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
run: |
oci_image="$(<"build/${{ matrix.asset }}-oci-image")"
echo "oci-name=${oci_image%@*}" >> "$GITHUB_OUTPUT"
echo "oci-digest=${oci_image#*@}" >> "$GITHUB_OUTPUT"
# for pushing attestations to the registry
- uses: docker/login-action@v3
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/attest-build-provenance@v1
if: ${{ env.PERFORM_ATTESTATION == 'yes' }}
with:
subject-name: ${{ steps.parse-oci-segments.outputs.oci-name }}
subject-digest: ${{ steps.parse-oci-segments.outputs.oci-digest }}
push-to-registry: true
- name: store-artifact ${{ matrix.asset }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-s390x-${{ matrix.asset }}${{ inputs.tarball-suffix }}
path: kata-build/kata-static-${{ matrix.asset }}.tar.xz
retention-days: 15
if-no-files-found: error
build-asset-rootfs:
runs-on: s390x
needs: build-asset
strategy:
matrix:
asset:
- rootfs-image
- rootfs-image-confidential
- rootfs-initrd
- rootfs-initrd-confidential
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-s390x-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build ${{ matrix.asset }}
id: build
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: ${{ matrix.asset }}
TAR_OUTPUT: ${{ matrix.asset }}.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
- name: store-artifact ${{ matrix.asset }}
if: ${{ inputs.stage != 'release' || (matrix.asset != 'agent' && matrix.asset != 'coco-guest-components' && matrix.asset != 'pause-image') }}
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-s390x-${{ matrix.asset }}${{ inputs.tarball-suffix }}
@@ -86,7 +174,7 @@ jobs:
build-asset-boot-image-se:
runs-on: s390x
needs: build-asset
needs: [build-asset, build-asset-rootfs]
steps:
- uses: actions/checkout@v4
@@ -112,11 +200,7 @@ jobs:
- name: Build boot-image-se
run: |
base_dir=tools/packaging/kata-deploy/local-build/
cp -r kata-artifacts ${base_dir}/build
# Skip building dependant artifacts of boot-image-se-tarball
# because we already have them from the previous build
sed -i 's/\(^boot-image-se-tarball:\).*/\1/g' ${base_dir}/Makefile
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "boot-image-se"
make boot-image-se-tarball
build_dir=$(readlink -f build)
sudo cp -r "${build_dir}" "kata-build"
@@ -132,9 +216,66 @@ jobs:
retention-days: 1
if-no-files-found: error
build-asset-shim-v2:
runs-on: s390x
needs: [build-asset, build-asset-rootfs]
steps:
- name: Login to Kata Containers quay.io
if: ${{ inputs.push-to-registry == 'yes' }}
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_DEPLOYER_USERNAME }}
password: ${{ secrets.QUAY_DEPLOYER_PASSWORD }}
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0 # This is needed in order to keep the commit ids history
- name: Rebase atop of the latest target branch
run: |
./tests/git-helper.sh "rebase-atop-of-the-latest-target-branch"
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-artifacts
uses: actions/download-artifact@v4
with:
pattern: kata-artifacts-s390x-*${{ inputs.tarball-suffix }}
path: kata-artifacts
merge-multiple: true
- name: Build shim-v2
id: build
run: |
./tests/gha-adjust-to-use-prebuilt-components.sh kata-artifacts "${KATA_ASSET}"
make "${KATA_ASSET}-tarball"
build_dir=$(readlink -f build)
# store-artifact does not work with symlink
mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/.
env:
KATA_ASSET: shim-v2
TAR_OUTPUT: shim-v2.tar.gz
PUSH_TO_REGISTRY: ${{ inputs.push-to-registry }}
ARTEFACT_REGISTRY: ghcr.io
ARTEFACT_REGISTRY_USERNAME: ${{ github.actor }}
ARTEFACT_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
TARGET_BRANCH: ${{ inputs.target-branch }}
RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }}
MEASURED_ROOTFS: yes
- name: store-artifact shim-v2
uses: actions/upload-artifact@v4
with:
name: kata-artifacts-s390x-shim-v2${{ inputs.tarball-suffix }}
path: kata-build/kata-static-shim-v2.tar.xz
retention-days: 15
if-no-files-found: error
create-kata-tarball:
runs-on: s390x
needs: [build-asset, build-asset-boot-image-se]
needs: [build-asset, build-asset-rootfs, build-asset-boot-image-se, build-asset-shim-v2]
steps:
- uses: actions/checkout@v4
with:

13
.github/workflows/ci-devel.yaml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: Kata Containers CI (manually triggered)
on:
workflow_dispatch:
jobs:
kata-containers-ci-on-push:
uses: ./.github/workflows/ci.yaml
with:
commit-hash: ${{ github.sha }}
pr-number: "dev"
tag: ${{ github.sha }}-dev
target-branch: ${{ github.ref_name }}
secrets: inherit

View File

@@ -2,7 +2,6 @@ name: Kata Containers Nightly CI
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

View File

@@ -19,12 +19,21 @@ concurrency:
cancel-in-progress: true
jobs:
kata-containers-ci-on-push:
skipper:
if: ${{ contains(github.event.pull_request.labels.*.name, 'ok-to-test') }}
uses: ./.github/workflows/gatekeeper-skipper.yaml
with:
commit-hash: ${{ github.event.pull_request.head.sha }}
target-branch: ${{ github.event.pull_request.base.ref }}
kata-containers-ci-on-push:
needs: skipper
if: ${{ needs.skipper.outputs.skip_build != 'yes' }}
uses: ./.github/workflows/ci.yaml
with:
commit-hash: ${{ github.event.pull_request.head.sha }}
pr-number: ${{ github.event.pull_request.number }}
tag: ${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
target-branch: ${{ github.event.pull_request.base.ref }}
skip-test: ${{ needs.skipper.outputs.skip_test }}
secrets: inherit

View File

@@ -37,7 +37,7 @@ jobs:
secrets: inherit
build-and-publish-tee-confidential-unencrypted-image:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4

View File

@@ -15,6 +15,10 @@ on:
required: false
type: string
default: ""
skip-test:
required: false
type: string
default: no
jobs:
build-kata-static-tarball-amd64:
@@ -132,6 +136,7 @@ jobs:
file: tests/integration/kubernetes/runtimeclass_workloads/confidential/unencrypted/Dockerfile
run-kata-monitor-tests:
if: ${{ inputs.skip-test != 'yes' }}
needs: build-kata-static-tarball-amd64
uses: ./.github/workflows/run-kata-monitor-tests.yaml
with:
@@ -140,6 +145,7 @@ jobs:
target-branch: ${{ inputs.target-branch }}
run-k8s-tests-on-aks:
if: ${{ inputs.skip-test != 'yes' }}
needs: publish-kata-deploy-payload-amd64
uses: ./.github/workflows/run-k8s-tests-on-aks.yaml
with:
@@ -153,6 +159,7 @@ jobs:
secrets: inherit
run-k8s-tests-on-amd64:
if: ${{ inputs.skip-test != 'yes' }}
needs: publish-kata-deploy-payload-amd64
uses: ./.github/workflows/run-k8s-tests-on-amd64.yaml
with:
@@ -165,9 +172,11 @@ jobs:
secrets: inherit
run-kata-coco-tests:
if: ${{ inputs.skip-test != 'yes' }}
needs: [publish-kata-deploy-payload-amd64, build-and-publish-tee-confidential-unencrypted-image]
uses: ./.github/workflows/run-kata-coco-tests.yaml
with:
tarball-suffix: -${{ inputs.tag }}
registry: ghcr.io
repo: ${{ github.repository_owner }}/kata-deploy-ci
tag: ${{ inputs.tag }}-amd64
@@ -177,6 +186,7 @@ jobs:
secrets: inherit
run-k8s-tests-on-zvsi:
if: ${{ inputs.skip-test != 'yes' }}
needs: [publish-kata-deploy-payload-s390x, build-and-publish-tee-confidential-unencrypted-image]
uses: ./.github/workflows/run-k8s-tests-on-zvsi.yaml
with:
@@ -189,6 +199,7 @@ jobs:
secrets: inherit
run-k8s-tests-on-ppc64le:
if: ${{ inputs.skip-test != 'yes' }}
needs: publish-kata-deploy-payload-ppc64le
uses: ./.github/workflows/run-k8s-tests-on-ppc64le.yaml
with:
@@ -200,6 +211,7 @@ jobs:
target-branch: ${{ inputs.target-branch }}
run-metrics-tests:
if: ${{ inputs.skip-test != 'yes' }}
needs: build-kata-static-tarball-amd64
uses: ./.github/workflows/run-metrics.yaml
with:
@@ -208,6 +220,7 @@ jobs:
target-branch: ${{ inputs.target-branch }}
run-basic-amd64-tests:
if: ${{ inputs.skip-test != 'yes' }}
needs: build-kata-static-tarball-amd64
uses: ./.github/workflows/basic-ci-amd64.yaml
with:
@@ -216,6 +229,7 @@ jobs:
target-branch: ${{ inputs.target-branch }}
run-cri-containerd-tests-s390x:
if: ${{ inputs.skip-test != 'yes' }}
needs: build-kata-static-tarball-s390x
uses: ./.github/workflows/run-cri-containerd-tests-s390x.yaml
with:
@@ -224,6 +238,7 @@ jobs:
target-branch: ${{ inputs.target-branch }}
run-cri-containerd-tests-ppc64le:
if: ${{ inputs.skip-test != 'yes' }}
needs: build-kata-static-tarball-ppc64le
uses: ./.github/workflows/run-cri-containerd-tests-ppc64le.yaml
with:

View File

@@ -0,0 +1,52 @@
name: Skipper
# This workflow sets various "skip_*" output values that can be used to
# determine what workflows/jobs are expected to be executed. Sample usage:
#
# skipper:
# uses: ./.github/workflows/gatekeeper-skipper.yaml
# with:
# commit-hash: ${{ github.event.pull_request.head.sha }}
# target-branch: ${{ github.event.pull_request.base.ref }}
#
# your-workflow:
# needs: skipper
# if: ${{ needs.skipper.outputs.skip_build != 'yes' }}
on:
workflow_call:
inputs:
commit-hash:
required: true
type: string
target-branch:
required: false
type: string
default: ""
outputs:
skip_build:
value: ${{ jobs.skipper.outputs.skip_build }}
skip_test:
value: ${{ jobs.skipper.outputs.skip_test }}
skip_static:
value: ${{ jobs.skipper.outputs.skip_static }}
jobs:
skipper:
runs-on: ubuntu-22.04
outputs:
skip_build: ${{ steps.skipper.outputs.skip_build }}
skip_test: ${{ steps.skipper.outputs.skip_test }}
skip_static: ${{ steps.skipper.outputs.skip_static }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.commit-hash }}
fetch-depth: 0
- id: skipper
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
run: |
python3 tools/testing/gatekeeper/skips.py | tee -a "$GITHUB_OUTPUT"
shell: /usr/bin/bash -x {0}

44
.github/workflows/gatekeeper.yaml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Gatekeeper
# Gatekeeper uses the "skips.py" to determine which job names/regexps are
# required for given PR and waits for them to either complete or fail
# reporting the status.
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
- labeled
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
gatekeeper:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- id: gatekeeper
env:
TARGET_BRANCH: ${{ github.event.pull_request.base.ref }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_HASH: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
#!/usr/bin/env bash -x
mapfile -t lines < <(python3 tools/testing/gatekeeper/skips.py -t)
export REQUIRED_JOBS="${lines[0]}"
export REQUIRED_REGEXPS="${lines[1]}"
export REQUIRED_LABELS="${lines[2]}"
echo "REQUIRED_JOBS: $REQUIRED_JOBS"
echo "REQUIRED_REGEXPS: $REQUIRED_REGEXPS"
echo "REQUIRED_LABELS: $REQUIRED_LABELS"
python3 tools/testing/gatekeeper/jobs.py
exit $?
shell: /usr/bin/bash -x {0}

View File

@@ -47,13 +47,16 @@ jobs:
vmm: clh
instance-type: small
genpolicy-pull-method: oci-distribution
auto-generate-policy: yes
- host_os: cbl-mariner
vmm: clh
instance-type: small
genpolicy-pull-method: containerd
auto-generate-policy: yes
- host_os: cbl-mariner
vmm: clh
instance-type: normal
auto-generate-policy: yes
runs-on: ubuntu-22.04
env:
DOCKER_REGISTRY: ${{ inputs.registry }}
@@ -66,6 +69,7 @@ jobs:
USING_NFD: "false"
K8S_TEST_HOST_TYPE: ${{ matrix.instance-type }}
GENPOLICY_PULL_METHOD: ${{ matrix.genpolicy-pull-method }}
AUTO_GENERATE_POLICY: ${{ matrix.auto-generate-policy }}
steps:
- uses: actions/checkout@v4
with:

View File

@@ -56,6 +56,7 @@ jobs:
SNAPSHOTTER: ${{ matrix.snapshotter }}
USING_NFD: "false"
K8S_TEST_HOST_TYPE: all
CONTAINER_RUNTIME: ${{ matrix.container_runtime }}
steps:
- uses: actions/checkout@v4
with:

View File

@@ -36,7 +36,7 @@ jobs:
- qemu-runtime-rs
- qemu-coco-dev
k8s:
- k3s
- kubeadm
include:
- snapshotter: devmapper
pull-type: default
@@ -97,9 +97,6 @@ jobs:
echo "KBS_INGRESS=nodeport" >> $GITHUB_ENV
if: ${{ matrix.vmm == 'qemu-coco-dev' }}
- name: Deploy ${{ matrix.k8s }}
run: bash tests/integration/kubernetes/gha-run.sh deploy-k8s
# qemu-runtime-rs only works with overlayfs
# See: https://github.com/kata-containers/kata-containers/issues/10066
- name: Configure the ${{ matrix.snapshotter }} snapshotter

View File

@@ -34,7 +34,7 @@ jobs:
- nydus
pull-type:
- guest-pull
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
env:
DOCKER_REGISTRY: ${{ inputs.registry }}
DOCKER_REPO: ${{ inputs.repo }}
@@ -64,6 +64,15 @@ jobs:
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-kata-tarball
uses: actions/download-artifact@v4
with:
name: kata-static-tarball-amd64${{ inputs.tarball-suffix }}
path: kata-artifacts
- name: Install kata
run: bash tests/integration/kubernetes/gha-run.sh install-kata-tools kata-artifacts
- name: Download Azure CLI
run: bash tests/integration/kubernetes/gha-run.sh install-azure-cli

View File

@@ -2,6 +2,9 @@ name: CI | Run kata coco tests
on:
workflow_call:
inputs:
tarball-suffix:
required: false
type: string
registry:
required: true
type: string
@@ -33,7 +36,15 @@ jobs:
- nydus
pull-type:
- guest-pull
runs-on: tdx
k8s-test-host-type:
- baremetal-attestation
- baremetal-no-attestation
include:
- k8s-test-host-type: baremetal-attestation
machine: tdx-attestation
- k8s-test-host-type: baremetal-no-attestation
machine: tdx-no-attestation
runs-on: ${{ matrix.machine }}
env:
DOCKER_REGISTRY: ${{ inputs.registry }}
DOCKER_REPO: ${{ inputs.repo }}
@@ -43,12 +54,14 @@ jobs:
KUBERNETES: "vanilla"
USING_NFD: "true"
KBS: "true"
K8S_TEST_HOST_TYPE: "baremetal"
K8S_TEST_HOST_TYPE: ${{ matrix.k8s-test-host-type }}
KBS_INGRESS: "nodeport"
SNAPSHOTTER: ${{ matrix.snapshotter }}
PULL_TYPE: ${{ matrix.pull-type }}
AUTHENTICATED_IMAGE_USER: ${{ secrets.AUTHENTICATED_IMAGE_USER }}
AUTHENTICATED_IMAGE_PASSWORD: ${{ secrets.AUTHENTICATED_IMAGE_PASSWORD }}
ITA_KEY: ${{ secrets.ITA_KEY }}
AUTO_GENERATE_POLICY: "yes"
steps:
- uses: actions/checkout@v4
with:
@@ -70,19 +83,22 @@ jobs:
run: bash tests/integration/kubernetes/gha-run.sh deploy-kata-tdx
- name: Uninstall previous `kbs-client`
if: ${{ matrix.machine != 'tdx-no-attestation' }}
timeout-minutes: 10
run: bash tests/integration/kubernetes/gha-run.sh uninstall-kbs-client
- name: Deploy CoCo KBS
if: ${{ matrix.machine != 'tdx-no-attestation' }}
timeout-minutes: 10
run: bash tests/integration/kubernetes/gha-run.sh deploy-coco-kbs
- name: Install `kbs-client`
if: ${{ matrix.machine != 'tdx-no-attestation' }}
timeout-minutes: 10
run: bash tests/integration/kubernetes/gha-run.sh install-kbs-client
- name: Run tests
timeout-minutes: 50
timeout-minutes: 100
run: bash tests/integration/kubernetes/gha-run.sh run-tests
- name: Delete kata-deploy
@@ -94,7 +110,7 @@ jobs:
run: bash tests/integration/kubernetes/gha-run.sh cleanup-snapshotter
- name: Delete CoCo KBS
if: always()
if: ${{ always() && matrix.machine != 'tdx-no-attestation' }}
run: bash tests/integration/kubernetes/gha-run.sh delete-coco-kbs
run-k8s-tests-on-sev:
@@ -122,6 +138,7 @@ jobs:
PULL_TYPE: ${{ matrix.pull-type }}
AUTHENTICATED_IMAGE_USER: ${{ secrets.AUTHENTICATED_IMAGE_USER }}
AUTHENTICATED_IMAGE_PASSWORD: ${{ secrets.AUTHENTICATED_IMAGE_PASSWORD }}
AUTO_GENERATE_POLICY: "yes"
steps:
- uses: actions/checkout@v4
with:
@@ -155,6 +172,9 @@ jobs:
run: bash tests/integration/kubernetes/gha-run.sh cleanup-snapshotter
run-k8s-tests-sev-snp:
# Skipping SNP tests to unblock the CI.
# Will revert after issue is fixed.
if: false
strategy:
fail-fast: false
matrix:
@@ -181,6 +201,7 @@ jobs:
PULL_TYPE: ${{ matrix.pull-type }}
AUTHENTICATED_IMAGE_USER: ${{ secrets.AUTHENTICATED_IMAGE_USER }}
AUTHENTICATED_IMAGE_PASSWORD: ${{ secrets.AUTHENTICATED_IMAGE_PASSWORD }}
AUTO_GENERATE_POLICY: "yes"
steps:
- uses: actions/checkout@v4
with:
@@ -258,6 +279,7 @@ jobs:
AUTHENTICATED_IMAGE_PASSWORD: ${{ secrets.AUTHENTICATED_IMAGE_PASSWORD }}
SNAPSHOTTER: ${{ matrix.snapshotter }}
USING_NFD: "false"
AUTO_GENERATE_POLICY: "yes"
steps:
- uses: actions/checkout@v4
with:
@@ -270,6 +292,15 @@ jobs:
env:
TARGET_BRANCH: ${{ inputs.target-branch }}
- name: get-kata-tarball
uses: actions/download-artifact@v4
with:
name: kata-static-tarball-amd64${{ inputs.tarball-suffix }}
path: kata-artifacts
- name: Install kata
run: bash tests/integration/kubernetes/gha-run.sh install-kata-tools kata-artifacts
- name: Download Azure CLI
run: bash tests/integration/kubernetes/gha-run.sh install-azure-cli
@@ -311,7 +342,7 @@ jobs:
run: bash tests/integration/kubernetes/gha-run.sh install-kbs-client
- name: Run tests
timeout-minutes: 60
timeout-minutes: 80
run: bash tests/integration/kubernetes/gha-run.sh run-tests
- name: Delete AKS cluster

View File

@@ -48,7 +48,7 @@ jobs:
# all the tests due to a single flaky instance.
fail-fast: false
matrix:
vmm: ['clh', 'qemu', 'stratovirt']
vmm: ['clh', 'qemu']
max-parallel: 1
runs-on: metrics
env:

View File

@@ -15,6 +15,8 @@ on:
jobs:
run-runk:
# Skip runk tests as we have no maintainers. TODO: Decide when to remove altogether
if: false
runs-on: ubuntu-22.04
env:
CONTAINERD_VERSION: lts

View File

@@ -12,8 +12,16 @@ concurrency:
name: Static checks self-hosted
jobs:
build-checks:
skipper:
if: ${{ contains(github.event.pull_request.labels.*.name, 'ok-to-test') }}
uses: ./.github/workflows/gatekeeper-skipper.yaml
with:
commit-hash: ${{ github.event.pull_request.head.sha }}
target-branch: ${{ github.event.pull_request.base.ref }}
build-checks:
needs: skipper
if: ${{ needs.skipper.outputs.skip_static != 'yes' }}
strategy:
fail-fast: false
matrix:

View File

@@ -12,7 +12,15 @@ concurrency:
name: Static checks
jobs:
skipper:
uses: ./.github/workflows/gatekeeper-skipper.yaml
with:
commit-hash: ${{ github.event.pull_request.head.sha }}
target-branch: ${{ github.event.pull_request.base.ref }}
check-kernel-config-version:
needs: skipper
if: ${{ needs.skipper.outputs.skip_static != 'yes' }}
runs-on: ubuntu-22.04
steps:
- name: Checkout the code
@@ -35,12 +43,16 @@ jobs:
fi
build-checks:
needs: skipper
if: ${{ needs.skipper.outputs.skip_static != 'yes' }}
uses: ./.github/workflows/build-checks.yaml
with:
instance: ubuntu-22.04
build-checks-depending-on-kvm:
runs-on: ubuntu-22.04
needs: skipper
if: ${{ needs.skipper.outputs.skip_static != 'yes' }}
strategy:
fail-fast: false
matrix:
@@ -78,6 +90,8 @@ jobs:
static-checks:
runs-on: ubuntu-22.04
needs: skipper
if: ${{ needs.skipper.outputs.skip_static != 'yes' }}
strategy:
fail-fast: false
matrix:

View File

@@ -1 +1 @@
3.9.0
3.11.0

View File

@@ -55,14 +55,14 @@ of a PR review), the following tests will be executed:
- Run the following tests:
- Tests depending on the generated tarball
- Metrics (runs on bare-metal)
- `docker` (runs on Azure small instances)
- `nerdctl` (runs on Azure small instances)
- `kata-monitor` (runs on Azure small instances)
- `cri-containerd` (runs on Azure small instances)
- `nydus` (runs on Azure small instances)
- `vfio` (runs on Azure normal instances)
- `docker` (runs on cost free runners)
- `nerdctl` (runs on cost free runners)
- `kata-monitor` (runs on cost free runners)
- `cri-containerd` (runs on cost free runners)
- `nydus` (runs on cost free runners)
- `vfio` (runs on cost free runners)
- Tests depending on the generated kata-deploy payload
- kata-deploy (runs on Azure small instances)
- kata-deploy (runs on cost free runners)
- Tests are performed using different "Kubernetes flavors", such as k0s, k3s, rke2, and Azure Kubernetes Service (AKS).
- Kubernetes (runs in Azure small and medium instances depending on what's required by each test, and on TEE bare-metal machines)
- Tests are performed with different runtime engines, such as CRI-O and containerd.
@@ -77,8 +77,8 @@ them to merely debug issues.
In the previous section we've mentioned using different runners, now in this section we'll go through each type of runner used.
- Cost free runners: Those are the runners provided by GIthub itself, and
those are fairly small machines with no virtualization capabilities enabled -
- Cost free runners: Those are the runners provided by Github itself, and
those are fairly small machines with virtualization capabilities enabled.
- Azure small instances: Those are runners which have virtualization
capabilities enabled, 2 CPUs, and 8GB of RAM. These runners have a "-smaller"
suffix to their name.

View File

@@ -14,20 +14,38 @@ die() {
exit 1
}
function verify_yq_exists() {
local yq_path=$1
local yq_version=$2
local expected="yq (https://github.com/mikefarah/yq/) version $yq_version"
if [ -x "${yq_path}" ] && [ "$($yq_path --version)"X == "$expected"X ]; then
return 0
else
return 1
fi
}
# Install the yq yaml query package from the mikefarah github repo
# Install via binary download, as we may not have golang installed at this point
function install_yq() {
local yq_pkg="github.com/mikefarah/yq"
local yq_version=v4.40.7
local precmd=""
local yq_path=""
INSTALL_IN_GOPATH=${INSTALL_IN_GOPATH:-true}
if [ "${INSTALL_IN_GOPATH}" == "true" ];then
if [ "${INSTALL_IN_GOPATH}" == "true" ]; then
GOPATH=${GOPATH:-${HOME}/go}
mkdir -p "${GOPATH}/bin"
local yq_path="${GOPATH}/bin/yq"
yq_path="${GOPATH}/bin/yq"
else
yq_path="/usr/local/bin/yq"
fi
if verify_yq_exists "$yq_path" "$yq_version"; then
echo "yq is already installed in correct version"
return
fi
if [ "${yq_path}" == "/usr/local/bin/yq" ]; then
# Check if we need sudo to install yq
if [ ! -w "/usr/local/bin" ]; then
# Check if we have sudo privileges
@@ -38,7 +56,6 @@ function install_yq() {
fi
fi
fi
[ -x "${yq_path}" ] && [ "`${yq_path} --version`"X == "yq (https://github.com/mikefarah/yq/) version ${yq_version}"X ] && return
read -r -a sysInfo <<< "$(uname -sm)"

View File

@@ -16,9 +16,12 @@ REPO="quay.io/kata-containers/kata-deploy-ci"
TAGS=$(skopeo list-tags "docker://$REPO")
# Only amd64
TAGS=$(echo "$TAGS" | jq '.Tags' | jq "map(select(endswith(\"$ARCH\")))" | jq -r '.[]')
# Tags since $GOOD
TAGS=$(echo "$TAGS" | sed -n -e "/$GOOD/,$$p")
# Tags up to $BAD
[ -n "$BAD" ] && TAGS=$(echo "$TAGS" | sed "/$BAD/q")
# Sort by git
SORTED=""
[ -n "$BAD" ] && LOG_ARGS="$GOOD~1..$BAD" || LOG_ARGS="$GOOD~1.."
for TAG in $(git log --merges --pretty=format:%H --reverse $LOG_ARGS); do
[[ "$TAGS" =~ "$TAG" ]] && SORTED+="
kata-containers-$TAG-$ARCH"
done
# Comma separated tags with repo
echo "$TAGS" | sed -e "s@^@$REPO:@" | paste -s -d, -
echo "$SORTED" | tail -n +2 | sed -e "s@^@$REPO:@" | paste -s -d, -

View File

@@ -13,16 +13,11 @@ set -e
set -o nounset
set -o pipefail
script_dir="$(dirname $0)"
script_dir="$(realpath $(dirname $0))"
webhook_dir="${script_dir}/../../../tools/testing/kata-webhook"
source "${script_dir}/../lib.sh"
KATA_RUNTIME=${KATA_RUNTIME:-kata-ci}
info "Creates the kata-webhook ConfigMap"
RUNTIME_CLASS="${KATA_RUNTIME}" \
envsubst < "${script_dir}/deployments/configmap_kata-webhook.yaml.in" \
| oc apply -f -
pushd "${webhook_dir}" >/dev/null
# Build and deploy the webhook
#
@@ -30,6 +25,12 @@ info "Builds the kata-webhook"
./create-certs.sh
info "Deploys the kata-webhook"
oc apply -f deploy/
info "Override our KATA_RUNTIME ConfigMap"
RUNTIME_CLASS="${KATA_RUNTIME}" \
envsubst < "${script_dir}/deployments/configmap_kata-webhook.yaml.in" \
| oc apply -f -
# Check the webhook was deployed and is working.
RUNTIME_CLASS="${KATA_RUNTIME}" ./webhook-check.sh
popd >/dev/null

View File

@@ -13,7 +13,7 @@ metadata:
spec:
containers:
- name: http-server
image: registry.fedoraproject.org/fedora
image: docker.io/library/python:3
ports:
- containerPort: 8080
command: ["python3"]

View File

@@ -499,19 +499,6 @@ If you do not want to install the respective QEMU version, the configuration fil
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.
### Build a custom QEMU for aarch64/arm64 - REQUIRED
> **Note:**
>
> - You should only do this step if you are on aarch64/arm64.
> - You should include [Eric Auger's latest PCDIMM/NVDIMM patches](https://patchwork.kernel.org/cover/10647305/) which are
> 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

View File

@@ -28,10 +28,22 @@ Bug fixes are released as part of `MINOR` or `MAJOR` releases only. `PATCH` is a
## Release Process
### Bump the `VERSION` file
### Bump the `VERSION` and `Chart.yaml` file
When the `kata-containers/kata-containers` repository is ready for a new release,
first create a PR to set the release in the `VERSION` file and have it merged.
first create a PR to set the release in the [`VERSION`](./../VERSION) file and update the
`version` and `appVersion` in the
[`Chart.yaml`](./../tools/packaging/kata-deploy/helm-chart/kata-deploy/Chart.yaml) file and
have it merged.
### Lock the `main` branch
In order to prevent any PRs getting merged during the release process, and slowing the release
process down, by impacting the payload caches, we have recently trailed setting the `main`
branch to read only whilst the release action runs.
> [!NOTE]
> Admin permission is needed to complete this task.
### Check GitHub Actions
@@ -40,6 +52,9 @@ We make use of [GitHub actions](https://github.com/features/actions) in the
file from the `kata-containers/kata-containers` repository to build and upload
release artifacts.
> [!NOTE]
> Write permissions to trigger the action.
The action is manually triggered and is responsible for generating a new
release (including a new tag), pushing those to the
`kata-containers/kata-containers` repository. The new release is initially
@@ -59,6 +74,11 @@ If for some reason you need to cancel the workflow or re-run it entirely, go fir
to the [Release page](https://github.com/kata-containers/kata-containers/releases) and
delete the draft release from the previous run.
### Unlock the `main` branch
After the release process has concluded, either unlock the `main` branch, or ask
an admin to do it.
### Improve the release notes
Release notes are auto-generated by the GitHub CLI tool used as part of our

View File

@@ -50,7 +50,7 @@ We provide `Dragonball` Sandbox to enable built-in VMM by integrating VMM's func
#### 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**
**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
@@ -103,7 +103,6 @@ In our case, there will be a variety of resources, and every resource has severa
| `Cgroup V2` | | Stage 2 | 🚧 |
| Hypervisor | `Dragonball` | Stage 1 | 🚧 |
| | QEMU | Stage 2 | 🚫 |
| | ACRN | Stage 3 | 🚫 |
| | Cloud Hypervisor | Stage 3 | 🚫 |
| | Firecracker | Stage 3 | 🚫 |
@@ -166,4 +165,4 @@ In our case, there will be a variety of resources, and every resource has severa
- 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.
It has the security boundary of virtualization. More details will be provided in next stage.

View File

@@ -98,8 +98,7 @@ of Kata Containers, the Cloud Hypervisor configuration supports both CPU
and memory resize, device hotplug (disk and VFIO), file-system sharing through virtio-fs,
block-based volumes, booting from VM images backed by pmem device, and
fine-grained seccomp filters for each VMM threads (e.g. all virtio
device worker threads). Please check [this GitHub Project](https://github.com/orgs/kata-containers/projects/21)
for details of ongoing integration efforts.
device worker threads).
Devices and features used:
- virtio VSOCK or virtio serial

View File

@@ -20,12 +20,6 @@
for the VM rootfs. Refer to the following guide for additional configuration
steps:
- [Setup Kata containers with `firecracker`](how-to-use-kata-containers-with-firecracker.md)
- `ACRN`
While `qemu` , `cloud-hypervisor` and `firecracker` work out of the box with installation of Kata,
some additional configuration is needed in case of `ACRN`.
Refer to the following guides for additional configuration steps:
- [Kata Containers with ACRN Hypervisor](how-to-use-kata-containers-with-acrn.md)
## Confidential Containers Policy
@@ -52,4 +46,4 @@
- [How to use EROFS to build rootfs in Kata Containers](how-to-use-erofs-build-rootfs.md)
- [How to run Kata Containers with kinds of Block Volumes](how-to-run-kata-containers-with-kinds-of-Block-Volumes.md)
- [How to use the Kata Agent Policy](how-to-use-the-kata-agent-policy.md)
- [How to pull images in the guest](how-to-pull-images-in-guest-with-kata.md)
- [How to pull images in the guest](how-to-pull-images-in-guest-with-kata.md)

View File

@@ -46,7 +46,6 @@ There are several kinds of Kata configurations and they are listed below.
| `io.katacontainers.config.hypervisor.block_device_cache_set` | `boolean` | cache-related options will be set to block devices or not |
| `io.katacontainers.config.hypervisor.block_device_driver` | string | the driver to be used for block device, valid values are `virtio-blk`, `virtio-scsi`, `nvdimm`|
| `io.katacontainers.config.hypervisor.cpu_features` | `string` | Comma-separated list of CPU features to pass to the CPU (QEMU) |
| `io.katacontainers.config.hypervisor.ctlpath` (R) | `string` | Path to the `acrnctl` binary for the ACRN hypervisor |
| `io.katacontainers.config.hypervisor.default_max_vcpus` | uint32| the maximum number of vCPUs allocated for the VM by the hypervisor |
| `io.katacontainers.config.hypervisor.default_memory` | uint32| the memory assigned for a VM by the hypervisor in `MiB` |
| `io.katacontainers.config.hypervisor.default_vcpus` | float32| the default vCPUs assigned for a VM by the hypervisor |
@@ -95,6 +94,8 @@ There are several kinds of Kata configurations and they are listed below.
| `io.katacontainers.config.hypervisor.virtio_fs_extra_args` | string | extra options passed to `virtiofs` daemon |
| `io.katacontainers.config.hypervisor.enable_guest_swap` | `boolean` | enable swap in the guest |
| `io.katacontainers.config.hypervisor.use_legacy_serial` | `boolean` | uses legacy serial device for guest's console (QEMU) |
| `io.katacontainers.config.hypervisor.default_gpus` | uint32 | the minimum number of GPUs required for the VM. Only used by remote hypervisor to help with instance selection |
| `io.katacontainers.config.hypervisor.default_gpu_model` | string | the GPU model required for the VM. Only used by remote hypervisor to help with instance selection |
## Container Options
| Key | Value Type | Comments |
@@ -209,7 +210,6 @@ the configuration entry:
| Key | Config file entry | Comments |
|-------| ----- | ----- |
| `ctlpath` | `valid_ctlpaths` | Valid paths for `acrnctl` binary |
| `entropy_source` | `valid_entropy_sources` | Valid entropy sources, e.g. `/dev/random` |
| `file_mem_backend` | `valid_file_mem_backends` | Valid locations for the file-based memory backend root directory |
| `jailer_path` | `valid_jailer_paths`| Valid paths for the jailer constraining the container VM (Firecracker) |

View File

@@ -1,125 +0,0 @@
# Kata Containers with ACRN
This document provides an overview on how to run Kata containers with ACRN hypervisor and device model.
## Introduction
ACRN is a flexible, lightweight Type-1 reference hypervisor built with real-time and safety-criticality in mind. ACRN uses an open source platform making it optimized to streamline embedded development.
Some of the key features being:
- Small footprint - Approx. 25K lines of code (LOC).
- Real Time - Low latency, faster boot time, improves overall responsiveness with hardware.
- Adaptability - Multi-OS support for guest operating systems like Linux, Android, RTOSes.
- Rich I/O mediators - Allows sharing of various I/O devices across VMs.
- Optimized for a variety of IoT (Internet of Things) and embedded device solutions.
Please refer to ACRN [documentation](https://projectacrn.github.io/latest/index.html) for more details on ACRN hypervisor and device model.
## Pre-requisites
This document requires the presence of the ACRN hypervisor and Kata Containers on your system. Install using the instructions available through the following links:
- ACRN supported [Hardware](https://projectacrn.github.io/latest/hardware.html#supported-hardware).
> **Note:** Please make sure to have a minimum of 4 logical processors (HT) or cores.
- ACRN [software](https://projectacrn.github.io/latest/tutorials/run_kata_containers.html) setup.
- For networking, ACRN supports either MACVTAP or TAP. If MACVTAP is not enabled in the Service OS, please follow the below steps to update the kernel:
```sh
$ git clone https://github.com/projectacrn/acrn-kernel.git
$ cd acrn-kernel
$ cp kernel_config_sos .config
$ sed -i "s/# CONFIG_MACVLAN is not set/CONFIG_MACVLAN=y/" .config
$ sed -i '$ i CONFIG_MACVTAP=y' .config
$ make clean && make olddefconfig && make && sudo make modules_install INSTALL_MOD_PATH=out/
```
Login into Service OS and update the kernel with MACVTAP support:
```sh
$ sudo mount /dev/sda1 /mnt
$ sudo scp -r <user name>@<host address>:<your workspace>/acrn-kernel/arch/x86/boot/bzImage /mnt/EFI/org.clearlinux/
$ sudo scp -r <user name>@<host address>:<your workspace>/acrn-kernel/out/lib/modules/* /lib/modules/
$ conf_file=$(sed -n '$ s/default //p' /mnt/loader/loader.conf).conf
$ kernel_img=$(sed -n 2p /mnt/loader/entries/$conf_file | cut -d'/' -f4)
$ sudo sed -i "s/$kernel_img/bzImage/g" /mnt/loader/entries/$conf_file
$ sync && sudo umount /mnt && sudo reboot
```
- Kata Containers installation: Automated installation does not seem to be supported for Clear Linux, so please use [manual installation](../Developer-Guide.md) steps.
> **Note:** Create rootfs image and not initrd image.
In order to run Kata with ACRN, your container stack must provide block-based storage, such as device-mapper.
> **Note:** Currently, by design you can only launch one VM from Kata Containers using ACRN hypervisor (SDC scenario). Based on feedback from community we can increase number of VMs.
## Configure Docker
To configure Docker for device-mapper and Kata,
1. Stop Docker daemon if it is already running.
```bash
$ sudo systemctl stop docker
```
2. Set `/etc/docker/daemon.json` with the following contents.
```
{
"storage-driver": "devicemapper"
}
```
3. Restart docker.
```bash
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
```
4. Configure [Docker](../Developer-Guide.md#update-the-docker-systemd-unit-file) to use `kata-runtime`.
## Configure Kata Containers with ACRN
To configure Kata Containers with ACRN, copy the generated `configuration-acrn.toml` file when building the `kata-runtime` to either `/etc/kata-containers/configuration.toml` or `/usr/share/defaults/kata-containers/configuration.toml`.
The following command shows full paths to the `configuration.toml` files that the runtime loads. It will use the first path that exists. (Please make sure the kernel and image paths are set correctly in the `configuration.toml` file)
```bash
$ sudo kata-runtime --show-default-config-paths
```
>**Warning:** Please offline CPUs using [this](offline_cpu.sh) script, else VM launches will fail.
```bash
$ sudo ./offline_cpu.sh
```
Start an ACRN based Kata Container,
```bash
$ sudo docker run -ti --runtime=kata-runtime busybox sh
```
You will see ACRN(`acrn-dm`) is now running on your system, as well as a `kata-shim`. You should obtain an interactive shell prompt. Verify that all the Kata processes terminate once you exit the container.
```bash
$ ps -ef | grep -E "kata|acrn"
```
Validate ACRN hypervisor by using `kata-runtime kata-env`,
```sh
$ kata-runtime kata-env | awk -v RS= '/\[Hypervisor\]/'
[Hypervisor]
MachineType = ""
Version = "DM version is: 1.2-unstable-254577a6-dirty (daily tag:acrn-2019w27.4-140000p)
Path = "/usr/bin/acrn-dm"
BlockDeviceDriver = "virtio-blk"
EntropySource = "/dev/urandom"
Msize9p = 0
MemorySlots = 10
Debug = false
UseVSock = false
SharedFS = ""
```

View File

@@ -18,7 +18,6 @@ for i in $(ls -d /sys/devices/system/cpu/cpu[1-9]*); do
echo 0 > $i/online
online=`cat $i/online`
done
echo $idx > /sys/class/vhm/acrn_vhm/offline_cpu
fi
done

View File

@@ -18,7 +18,6 @@ which hypervisors you may wish to investigate further.
| Hypervisor | Written in | Architectures | Type |
|-|-|-|-|
|[ACRN] | C | `x86_64` | Type 1 (bare metal) |
|[Cloud Hypervisor] | rust | `aarch64`, `x86_64` | Type 2 ([KVM]) |
|[Firecracker] | rust | `aarch64`, `x86_64` | Type 2 ([KVM]) |
|[QEMU] | C | all | Type 2 ([KVM]) | `configuration-qemu.toml` |
@@ -38,7 +37,6 @@ the hypervisors:
| Hypervisor | Summary | Features | Limitations | Container Creation speed | Memory density | Use cases | Comment |
|-|-|-|-|-|-|-|-|
|[ACRN] | Safety critical and real-time workloads | | | excellent | excellent | Embedded and IOT systems | For advanced users |
|[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 | |
@@ -57,7 +55,6 @@ are available, their default values and how each setting can be used.
| Hypervisor | Golang runtime config file | golang runtime short name | golang runtime default | rust runtime config file | rust runtime short name | rust runtime default |
|-|-|-|-|-|-|-|
| [ACRN] | [`configuration-acrn.toml`](../src/runtime/config/configuration-acrn.toml.in) | `acrn` | | | | |
| [Cloud Hypervisor] | [`configuration-clh.toml`](../src/runtime/config/configuration-clh.toml.in) | `clh` | | [`configuration-cloud-hypervisor.toml`](../src/runtime-rs/config/configuration-cloud-hypervisor.toml.in) | `cloud-hypervisor` | |
| [Firecracker] | [`configuration-fc.toml`](../src/runtime/config/configuration-fc.toml.in) | `fc` | | | | |
| [QEMU] | [`configuration-qemu.toml`](../src/runtime/config/configuration-qemu.toml.in) | `qemu` | yes | [`configuration-qemu.toml`](../src/runtime-rs/config/configuration-qemu-runtime-rs.toml.in) | `qemu` | |
@@ -93,10 +90,9 @@ are available, their default values and how each setting can be used.
To switch the configured hypervisor, you only need to run a single command.
See [the `kata-manager` documentation](../utils/README.md#choose-a-hypervisor) for further details.
[ACRN]: https://projectacrn.org
[Cloud Hypervisor]: https://github.com/cloud-hypervisor/cloud-hypervisor
[Firecracker]: https://github.com/firecracker-microvm/firecracker
[KVM]: https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine
[QEMU]: http://www.qemu-project.org
[QEMU]: http://www.qemu.org
[`Dragonball`]: https://github.com/kata-containers/kata-containers/blob/main/src/dragonball
[StratoVirt]: https://gitee.com/openeuler/stratovirt

View File

@@ -83,6 +83,23 @@ $ 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/` .
### Install Shim Without Builtin Dragonball VMM
By default, runtime-rs includes the `Dragonball` VMM. To build without the built-in `Dragonball` hypervisor, use `make USE_BUILDIN_DB=false`:
```bash
$ cd kata-containers/src/runtime-rs
$ make USE_BUILDIN_DB=false
```
After building, specify the desired hypervisor during installation using `HYPERVISOR`. For example, to use `qemu` or `cloud-hypervisor`:
```
sudo make install HYPERVISOR=qemu
```
or
```
sudo make install HYPERVISOR=cloud-hypervisor
```
### Build Kata Containers Kernel
Follow the [Kernel installation guide](/tools/packaging/kernel/README.md).

365
src/agent/Cargo.lock generated
View File

@@ -64,6 +64,20 @@ dependencies = [
"version_check",
]
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if 1.0.0",
"getrandom",
"once_cell",
"serde",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@@ -97,6 +111,55 @@ dependencies = [
"winapi",
]
[[package]]
name = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]]
name = "anyhow"
version = "1.0.86"
@@ -712,6 +775,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "bytecount"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -814,6 +883,30 @@ dependencies = [
"libc",
]
[[package]]
name = "cdi"
version = "0.1.0"
source = "git+https://github.com/cncf-tags/container-device-interface-rs?rev=fba5677a8e7cc962fc6e495fcec98d7d765e332a#fba5677a8e7cc962fc6e495fcec98d7d765e332a"
dependencies = [
"anyhow",
"clap 4.5.13",
"const_format",
"jsonschema",
"lazy_static",
"libc",
"nix 0.24.3",
"notify",
"oci-spec",
"once_cell",
"path-clean",
"regex",
"semver",
"serde",
"serde_derive",
"serde_json",
"serde_yaml",
]
[[package]]
name = "cesu8"
version = "1.1.0"
@@ -914,8 +1007,8 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
"clap_derive",
"clap_lex",
"clap_derive 3.2.25",
"clap_lex 0.2.4",
"indexmap 1.9.3",
"once_cell",
"strsim 0.10.0",
@@ -923,6 +1016,28 @@ dependencies = [
"textwrap",
]
[[package]]
name = "clap"
version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
dependencies = [
"clap_builder",
"clap_derive 4.5.13",
]
[[package]]
name = "clap_builder"
version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
dependencies = [
"anstream",
"anstyle",
"clap_lex 0.7.2",
"strsim 0.11.1",
]
[[package]]
name = "clap_derive"
version = "3.2.25"
@@ -936,6 +1051,18 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "clap_derive"
version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.71",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
@@ -945,6 +1072,12 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "cmac"
version = "0.7.2"
@@ -967,6 +1100,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "combine"
version = "4.6.7"
@@ -1741,6 +1880,17 @@ dependencies = [
"rand",
]
[[package]]
name = "fancy-regex"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
dependencies = [
"bit-set",
"regex-automata 0.4.7",
"regex-syntax 0.8.4",
]
[[package]]
name = "fastrand"
version = "1.9.0"
@@ -1812,6 +1962,15 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "fluent-uri"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -1827,6 +1986,25 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fraction"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7"
dependencies = [
"lazy_static",
"num",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]]
name = "funty"
version = "2.0.0"
@@ -2052,7 +2230,7 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
"ahash 0.7.8",
]
[[package]]
@@ -2605,6 +2783,21 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "iso8601"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153"
dependencies = [
"nom",
]
[[package]]
name = "itertools"
version = "0.10.5"
@@ -2623,15 +2816,6 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
@@ -2690,6 +2874,18 @@ dependencies = [
"smallvec",
]
[[package]]
name = "json-patch"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc"
dependencies = [
"jsonptr",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "json-syntax"
version = "0.12.5"
@@ -2709,6 +2905,47 @@ dependencies = [
"utf8-decode",
]
[[package]]
name = "jsonptr"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627"
dependencies = [
"fluent-uri",
"serde",
"serde_json",
]
[[package]]
name = "jsonschema"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0afd06142c9bcb03f4a8787c77897a87b6be9c4918f1946c33caa714c27578"
dependencies = [
"ahash 0.8.11",
"anyhow",
"base64 0.22.1",
"bytecount",
"clap 4.5.13",
"fancy-regex",
"fraction",
"getrandom",
"iso8601",
"itoa",
"memchr",
"num-cmp",
"once_cell",
"parking_lot 0.12.3",
"percent-encoding",
"regex",
"reqwest",
"serde",
"serde_json",
"time",
"url",
"uuid",
]
[[package]]
name = "jwt"
version = "0.16.0"
@@ -2773,14 +3010,16 @@ dependencies = [
"async-std",
"async-trait",
"capctl",
"cdi",
"cfg-if 1.0.0",
"cgroups-rs",
"clap",
"clap 3.2.25",
"const_format",
"derivative",
"futures",
"image-rs",
"ipnetwork",
"json-patch",
"kata-sys-util",
"kata-types",
"lazy_static",
@@ -2835,7 +3074,6 @@ version = "0.1.0"
dependencies = [
"anyhow",
"byteorder",
"cgroups-rs",
"chrono",
"common-path",
"fail",
@@ -2934,6 +3172,26 @@ dependencies = [
"zeroize",
]
[[package]]
name = "kqueue"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
dependencies = [
"bitflags 1.3.2",
"libc",
]
[[package]]
name = "krata-tokio-tar"
version = "0.4.2"
@@ -3285,6 +3543,18 @@ dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
[[package]]
name = "mio"
version = "1.0.2"
@@ -3465,6 +3735,25 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "notify"
version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [
"bitflags 2.6.0",
"crossbeam-channel",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"log",
"mio 0.8.11",
"walkdir",
"windows-sys 0.48.0",
]
[[package]]
name = "ntapi"
version = "0.4.1"
@@ -3515,6 +3804,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "num-cmp"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa"
[[package]]
name = "num-complex"
version = "0.4.6"
@@ -3894,6 +4189,12 @@ dependencies = [
"slash-formatter",
]
[[package]]
name = "path-clean"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
[[package]]
name = "path-dedot"
version = "1.2.4"
@@ -4376,7 +4677,6 @@ name = "protocols"
version = "0.1.0"
dependencies = [
"async-trait",
"kata-sys-util",
"oci-spec",
"protobuf 3.5.1",
"serde",
@@ -4626,14 +4926,12 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "regorus"
version = "0.1.5"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77dd872918e5c172bd42ac49716f89a15e35be513bba3d902e355a531529a87f"
checksum = "843c3d97f07e3b5ac0955d53ad0af4c91fe4a4f8525843ece5bf014f27829b73"
dependencies = [
"anyhow",
"itertools 0.12.1",
"lazy_static",
"num",
"rand",
"regex",
"scientific",
@@ -4666,6 +4964,7 @@ dependencies = [
"bytes 1.6.1",
"cookie",
"cookie_store",
"futures-channel",
"futures-core",
"futures-util",
"http",
@@ -5919,7 +6218,7 @@ dependencies = [
"backtrace",
"bytes 1.6.1",
"libc",
"mio",
"mio 1.0.2",
"parking_lot 0.12.3",
"pin-project-lite",
"signal-hook-registry",
@@ -6346,6 +6645,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.10.0"
@@ -7021,6 +7326,26 @@ dependencies = [
"zvariant",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.71",
]
[[package]]
name = "zerofrom"
version = "0.1.4"

View File

@@ -80,10 +80,13 @@ strum_macros = "0.26.2"
image-rs = { git = "https://github.com/confidential-containers/guest-components", rev = "v0.10.0", default-features = false, optional = true }
# Agent Policy
regorus = { version = "0.1.4", default-features = false, features = [
regorus = { version = "0.2.6", default-features = false, features = [
"arc",
"regex",
"std",
], optional = true }
cdi = { git = "https://github.com/cncf-tags/container-device-interface-rs", rev = "fba5677a8e7cc962fc6e495fcec98d7d765e332a" }
json-patch = "2.0.0"
[dev-dependencies]
tempfile = "3.1.0"

View File

@@ -158,7 +158,7 @@ lazy_static! {
.typ(oci::LinuxDeviceType::C)
.major(1)
.minor(3)
.file_mode(0o066_u32)
.file_mode(0o666_u32)
.uid(0xffffffff_u32)
.gid(0xffffffff_u32)
.build()
@@ -168,7 +168,7 @@ lazy_static! {
.typ(oci::LinuxDeviceType::C)
.major(1)
.minor(5)
.file_mode(0o066_u32)
.file_mode(0o666_u32)
.uid(0xffffffff_u32)
.gid(0xffffffff_u32)
.build()
@@ -178,7 +178,7 @@ lazy_static! {
.typ(oci::LinuxDeviceType::C)
.major(1)
.minor(7)
.file_mode(0o066_u32)
.file_mode(0o666_u32)
.uid(0xffffffff_u32)
.gid(0xffffffff_u32)
.build()
@@ -188,7 +188,7 @@ lazy_static! {
.typ(oci::LinuxDeviceType::C)
.major(5)
.minor(0)
.file_mode(0o066_u32)
.file_mode(0o666_u32)
.uid(0xffffffff_u32)
.gid(0xffffffff_u32)
.build()
@@ -198,7 +198,7 @@ lazy_static! {
.typ(oci::LinuxDeviceType::C)
.major(1)
.minor(9)
.file_mode(0o066_u32)
.file_mode(0o666_u32)
.uid(0xffffffff_u32)
.gid(0xffffffff_u32)
.build()
@@ -208,7 +208,7 @@ lazy_static! {
.typ(oci::LinuxDeviceType::C)
.major(1)
.minor(8)
.file_mode(0o066_u32)
.file_mode(0o666_u32)
.uid(0xffffffff_u32)
.gid(0xffffffff_u32)
.build()

View File

@@ -8,13 +8,15 @@
// https://github.com/confidential-containers/guest-components/tree/main/confidential-data-hub
use crate::AGENT_CONFIG;
use crate::CDH_SOCKET_URI;
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use derivative::Derivative;
use protocols::{
confidential_data_hub, confidential_data_hub_ttrpc_async,
confidential_data_hub_ttrpc_async::{SealedSecretServiceClient, SecureMountServiceClient},
};
use std::fs;
use std::os::unix::fs::symlink;
use std::path::Path;
use tokio::sync::OnceCell;
// Nanoseconds
@@ -22,8 +24,14 @@ lazy_static! {
static ref CDH_API_TIMEOUT: i64 = AGENT_CONFIG.cdh_api_timeout.as_nanos() as i64;
pub static ref CDH_CLIENT: OnceCell<CDHClient> = OnceCell::new();
}
const SEALED_SECRET_PREFIX: &str = "sealed.";
// Convenience function to obtain the scope logger.
fn sl() -> slog::Logger {
slog_scope::logger().new(o!("subsystem" => "cdh"))
}
#[derive(Derivative)]
#[derivative(Clone, Debug)]
pub struct CDHClient {
@@ -34,8 +42,8 @@ pub struct CDHClient {
}
impl CDHClient {
pub fn new() -> Result<Self> {
let client = ttrpc::asynchronous::Client::connect(CDH_SOCKET_URI)?;
pub fn new(cdh_socket_uri: &str) -> Result<Self> {
let client = ttrpc::asynchronous::Client::connect(cdh_socket_uri)?;
let sealed_secret_client =
confidential_data_hub_ttrpc_async::SealedSecretServiceClient::new(client.clone());
let secure_mount_client =
@@ -78,9 +86,11 @@ impl CDHClient {
}
}
pub async fn init_cdh_client() -> Result<()> {
pub async fn init_cdh_client(cdh_socket_uri: &str) -> Result<()> {
CDH_CLIENT
.get_or_try_init(|| async { CDHClient::new().context("Failed to create CDH Client") })
.get_or_try_init(|| async {
CDHClient::new(cdh_socket_uri).context("Failed to create CDH Client")
})
.await?;
Ok(())
}
@@ -106,6 +116,74 @@ pub async fn unseal_env(env: &str) -> Result<String> {
Ok((*env.to_owned()).to_string())
}
pub async fn unseal_file(path: &str) -> Result<()> {
let cdh_client = CDH_CLIENT
.get()
.expect("Confidential Data Hub not initialized");
if !Path::new(path).exists() {
bail!("sealed secret file {:?} does not exist", path);
}
// Iterate over all entries to handle the sealed secret file.
// For example, the directory is as follows:
// The secret directory in the guest: /run/kata-containers/shared/containers/21bbf0d932b70263d65d7052ecfd72ee46de03f766650cb378e93852ddb30a54-5063be11b6800f96-sealed-secret-target/:
// - ..2024_09_30_02_55_58.2237819815
// - ..data -> ..2024_09_30_02_55_58.2237819815
// - secret -> ..2024_09_30_02_55_58.2237819815/secret
//
// The directory "..2024_09_30_02_55_58.2237819815":
// - secret
for entry in fs::read_dir(path)? {
let entry = entry?;
let entry_type = entry.file_type()?;
if !entry_type.is_symlink() && !entry_type.is_file() {
debug!(
sl(),
"skipping sealed source entry {:?} because its file type is {:?}",
entry,
entry_type
);
continue;
}
let target_path = fs::canonicalize(&entry.path())?;
info!(sl(), "sealed source entry target path: {:?}", target_path);
// Skip if the target path is not a file (e.g., it's a symlink pointing to the secret file).
if !target_path.is_file() {
debug!(sl(), "sealed source is not a file: {:?}", target_path);
continue;
}
let secret_name = entry.file_name();
let contents = fs::read_to_string(&target_path)?;
if contents.starts_with(SEALED_SECRET_PREFIX) {
// Get the directory name of the sealed secret file
let dir_name = target_path
.parent()
.and_then(|p| p.file_name())
.map(|name| name.to_string_lossy().to_string())
.unwrap_or_default();
// Create the unsealed file name in the same directory, which will be written the unsealed data.
let unsealed_filename = format!("{}.unsealed", target_path.to_string_lossy());
// Create the unsealed file symlink, which is used for reading the unsealed data in the container.
let unsealed_filename_symlink =
format!("{}/{}.unsealed", dir_name, secret_name.to_string_lossy());
// Unseal the secret and write it to the unsealed file
let unsealed_value = cdh_client.unseal_secret_async(&contents).await?;
fs::write(&unsealed_filename, unsealed_value)?;
// Remove the original sealed symlink and create a symlink to the unsealed file
fs::remove_file(&entry.path())?;
symlink(unsealed_filename_symlink, &entry.path())?;
}
}
Ok(())
}
pub async fn secure_mount(
volume_type: &str,
options: &std::collections::HashMap<String, String>,
@@ -123,17 +201,15 @@ pub async fn secure_mount(
}
#[cfg(test)]
#[cfg(feature = "sealed-secret")]
mod tests {
use crate::cdh::CDHClient;
use crate::cdh::CDH_ADDR;
use anyhow::anyhow;
use super::*;
use async_trait::async_trait;
use protocols::{confidential_data_hub, confidential_data_hub_ttrpc_async};
use std::fs::File;
use std::io::{Read, Write};
use std::sync::Arc;
use tempfile::tempdir;
use test_utils::skip_if_not_root;
use tokio::signal::unix::{signal, SignalKind};
struct TestService;
#[async_trait]
@@ -161,17 +237,17 @@ mod tests {
Ok(())
}
fn start_ttrpc_server() {
fn start_ttrpc_server(cdh_socket_uri: String) {
tokio::spawn(async move {
let ss = Box::new(TestService {})
as Box<dyn confidential_data_hub_ttrpc_async::SealedSecretService + Send + Sync>;
let ss = Arc::new(ss);
let ss_service = confidential_data_hub_ttrpc_async::create_sealed_secret_service(ss);
remove_if_sock_exist(CDH_ADDR).unwrap();
remove_if_sock_exist(&cdh_socket_uri).unwrap();
let mut server = ttrpc::asynchronous::Server::new()
.bind(CDH_ADDR)
.bind(&cdh_socket_uri)
.unwrap()
.register_service(ss_service);
@@ -187,23 +263,58 @@ mod tests {
}
#[tokio::test]
async fn test_unseal_env() {
async fn test_sealed_secret() {
skip_if_not_root!();
let test_dir = tempdir().expect("failed to create tmpdir");
let test_dir_path = test_dir.path();
let cdh_sock_uri = &format!(
"unix://{}",
test_dir_path.join("cdh.sock").to_str().unwrap()
);
let rt = tokio::runtime::Runtime::new().unwrap();
let _guard = rt.enter();
start_ttrpc_server();
start_ttrpc_server(cdh_sock_uri.to_string());
std::thread::sleep(std::time::Duration::from_secs(2));
init_cdh_client(cdh_sock_uri).await.unwrap();
let cc = Some(CDHClient::new().unwrap());
let cdh_client = cc.as_ref().ok_or(anyhow!("get cdh_client failed")).unwrap();
// Test sealed secret as env vars
let sealed_env = String::from("key=sealed.testdata");
let unsealed_env = cdh_client.unseal_env(&sealed_env).await.unwrap();
let unsealed_env = unseal_env(&sealed_env).await.unwrap();
assert_eq!(unsealed_env, String::from("key=unsealed"));
let normal_env = String::from("key=testdata");
let unchanged_env = cdh_client.unseal_env(&normal_env).await.unwrap();
let unchanged_env = unseal_env(&normal_env).await.unwrap();
assert_eq!(unchanged_env, String::from("key=testdata"));
// Test sealed secret as files
let sealed_dir = test_dir_path.join("..test");
fs::create_dir(&sealed_dir).unwrap();
let sealed_filename = sealed_dir.join("secret");
let mut sealed_file = File::create(sealed_filename.clone()).unwrap();
sealed_file.write_all(b"sealed.testdata").unwrap();
let secret_symlink = test_dir_path.join("secret");
symlink(&sealed_filename, &secret_symlink).unwrap();
unseal_file(test_dir_path.to_str().unwrap()).await.unwrap();
let unsealed_filename = test_dir_path.join("secret");
let mut unsealed_file = File::open(unsealed_filename.clone()).unwrap();
let mut contents = String::new();
unsealed_file.read_to_string(&mut contents).unwrap();
assert_eq!(contents, String::from("unsealed"));
fs::remove_file(sealed_filename).unwrap();
fs::remove_file(unsealed_filename).unwrap();
let normal_filename = test_dir_path.join("secret");
let mut normal_file = File::create(normal_filename.clone()).unwrap();
normal_file.write_all(b"testdata").unwrap();
unseal_file(test_dir_path.to_str().unwrap()).await.unwrap();
let mut contents = String::new();
let mut normal_file = File::open(normal_filename.clone()).unwrap();
normal_file.read_to_string(&mut contents).unwrap();
assert_eq!(contents, String::from("testdata"));
fs::remove_file(normal_filename).unwrap();
rt.shutdown_background();
std::thread::sleep(std::time::Duration::from_secs(2));
}

View File

@@ -89,7 +89,7 @@ pub enum GuestComponentsFeatures {
Resource,
}
#[derive(Clone, Copy, Debug, Default, Display, Deserialize, EnumString, PartialEq)]
#[derive(Clone, Copy, Debug, Default, Display, Deserialize, EnumString, PartialEq, Eq)]
/// Attestation-related processes that we want to spawn as children of the agent
#[strum(serialize_all = "kebab-case")]
#[serde(rename_all = "kebab-case")]
@@ -630,6 +630,7 @@ mod tests {
use super::*;
use anyhow::anyhow;
use rstest::*;
use serial_test::serial;
use std::fs::File;
use std::io::Write;
@@ -1327,562 +1328,193 @@ mod tests {
assert_eq!(expected.tracing, config.tracing);
}
#[test]
fn test_logrus_to_slog_level() {
#[derive(Debug)]
struct TestData<'a> {
logrus_level: &'a str,
result: Result<slog::Level>,
}
let tests = &[
TestData {
logrus_level: "",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL)),
},
TestData {
logrus_level: "foo",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL)),
},
TestData {
logrus_level: "debugging",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL)),
},
TestData {
logrus_level: "xdebug",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL)),
},
TestData {
logrus_level: "trace",
result: Ok(slog::Level::Trace),
},
TestData {
logrus_level: "debug",
result: Ok(slog::Level::Debug),
},
TestData {
logrus_level: "info",
result: Ok(slog::Level::Info),
},
TestData {
logrus_level: "warn",
result: Ok(slog::Level::Warning),
},
TestData {
logrus_level: "warning",
result: Ok(slog::Level::Warning),
},
TestData {
logrus_level: "error",
result: Ok(slog::Level::Error),
},
TestData {
logrus_level: "critical",
result: Ok(slog::Level::Critical),
},
TestData {
logrus_level: "fatal",
result: Ok(slog::Level::Critical),
},
TestData {
logrus_level: "panic",
result: Ok(slog::Level::Critical),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = logrus_to_slog_level(d.logrus_level);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
#[rstest]
#[case("", Err(anyhow!(ERR_INVALID_LOG_LEVEL)))]
#[case("foo", Err(anyhow!(ERR_INVALID_LOG_LEVEL)))]
#[case("debugging", Err(anyhow!(ERR_INVALID_LOG_LEVEL)))]
#[case("xdebug", Err(anyhow!(ERR_INVALID_LOG_LEVEL)))]
#[case("trace", Ok(slog::Level::Trace))]
#[case("debug", Ok(slog::Level::Debug))]
#[case("info", Ok(slog::Level::Info))]
#[case("warn", Ok(slog::Level::Warning))]
#[case("warning", Ok(slog::Level::Warning))]
#[case("error", Ok(slog::Level::Error))]
#[case("critical", Ok(slog::Level::Critical))]
#[case("fatal", Ok(slog::Level::Critical))]
#[case("panic", Ok(slog::Level::Critical))]
fn test_logrus_to_slog_level(#[case] input: &str, #[case] expected: Result<slog::Level>) {
let result = logrus_to_slog_level(input);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]
fn test_get_log_level() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<slog::Level>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_PARAM)),
},
TestData {
param: "=",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)),
},
TestData {
param: "x=",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)),
},
TestData {
param: "=y",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)),
},
TestData {
param: "==",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_PARAM)),
},
TestData {
param: "= =",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_PARAM)),
},
TestData {
param: "x=y",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)),
},
TestData {
param: "agent=debug",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)),
},
TestData {
param: "agent.logg=debug",
result: Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)),
},
TestData {
param: "agent.log=trace",
result: Ok(slog::Level::Trace),
},
TestData {
param: "agent.log=debug",
result: Ok(slog::Level::Debug),
},
TestData {
param: "agent.log=info",
result: Ok(slog::Level::Info),
},
TestData {
param: "agent.log=warn",
result: Ok(slog::Level::Warning),
},
TestData {
param: "agent.log=warning",
result: Ok(slog::Level::Warning),
},
TestData {
param: "agent.log=error",
result: Ok(slog::Level::Error),
},
TestData {
param: "agent.log=critical",
result: Ok(slog::Level::Critical),
},
TestData {
param: "agent.log=fatal",
result: Ok(slog::Level::Critical),
},
TestData {
param: "agent.log=panic",
result: Ok(slog::Level::Critical),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_log_level(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
#[rstest]
#[case("",Err(anyhow!(ERR_INVALID_LOG_LEVEL_PARAM)))]
#[case("=",Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)))]
#[case("x=",Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)))]
#[case("=y",Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)))]
#[case("==",Err(anyhow!(ERR_INVALID_LOG_LEVEL_PARAM)))]
#[case("= =",Err(anyhow!(ERR_INVALID_LOG_LEVEL_PARAM)))]
#[case("x=y",Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)))]
#[case("agent=debug",Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)))]
#[case("agent.logg=debug",Err(anyhow!(ERR_INVALID_LOG_LEVEL_KEY)))]
#[case("agent.log=trace", Ok(slog::Level::Trace))]
#[case("agent.log=debug", Ok(slog::Level::Debug))]
#[case("agent.log=info", Ok(slog::Level::Info))]
#[case("agent.log=warn", Ok(slog::Level::Warning))]
#[case("agent.log=warning", Ok(slog::Level::Warning))]
#[case("agent.log=error", Ok(slog::Level::Error))]
#[case("agent.log=critical", Ok(slog::Level::Critical))]
#[case("agent.log=fatal", Ok(slog::Level::Critical))]
#[case("agent.log=panic", Ok(slog::Level::Critical))]
fn test_get_log_level(#[case] input: &str, #[case] expected: Result<slog::Level>) {
let result = get_log_level(input);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]
fn test_get_timeout() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<time::Duration>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_TIMEOUT)),
},
TestData {
param: "agent.hotplug_timeout",
result: Err(anyhow!(ERR_INVALID_TIMEOUT)),
},
TestData {
param: "foo=bar",
result: Err(anyhow!(ERR_INVALID_TIMEOUT_KEY)),
},
TestData {
param: "agent.hotplug_timeot=1",
result: Err(anyhow!(ERR_INVALID_TIMEOUT_KEY)),
},
TestData {
param: "agent.chd_api_timeout=1",
result: Err(anyhow!(ERR_INVALID_TIMEOUT_KEY)),
},
TestData {
param: "agent.hotplug_timeout=1",
result: Ok(time::Duration::from_secs(1)),
},
TestData {
param: "agent.hotplug_timeout=3",
result: Ok(time::Duration::from_secs(3)),
},
TestData {
param: "agent.hotplug_timeout=3600",
result: Ok(time::Duration::from_secs(3600)),
},
TestData {
param: "agent.cdh_api_timeout=600",
result: Ok(time::Duration::from_secs(600)),
},
TestData {
param: "agent.hotplug_timeout=0",
result: Ok(time::Duration::from_secs(0)),
},
TestData {
param: "agent.hotplug_timeout=-1",
result: Err(anyhow!(
"unable to parse timeout
#[rstest]
#[case("", Err(anyhow!(ERR_INVALID_TIMEOUT)))]
#[case("agent.hotplug_timeout", Err(anyhow!(ERR_INVALID_TIMEOUT)))]
#[case("foo=bar", Err(anyhow!(ERR_INVALID_TIMEOUT_KEY)))]
#[case("agent.hotplug_timeot=1", Err(anyhow!(ERR_INVALID_TIMEOUT_KEY)))]
#[case("agent.hotplug_timeout=1", Ok(time::Duration::from_secs(1)))]
#[case("agent.hotplug_timeout=3", Ok(time::Duration::from_secs(3)))]
#[case("agent.hotplug_timeout=3600", Ok(time::Duration::from_secs(3600)))]
#[case("agent.hotplug_timeout=0", Ok(time::Duration::from_secs(0)))]
#[case("agent.hotplug_timeout=-1", Err(anyhow!(
"unable to parse timeout
Caused by:
invalid digit found in string"
)),
},
TestData {
param: "agent.hotplug_timeout=4jbsdja",
result: Err(anyhow!(
"unable to parse timeout
)))]
#[case("agent.hotplug_timeout=4jbsdja", Err(anyhow!(
"unable to parse timeout
Caused by:
invalid digit found in string"
)),
},
TestData {
param: "agent.hotplug_timeout=foo",
result: Err(anyhow!(
"unable to parse timeout
)))]
#[case("agent.hotplug_timeout=foo", Err(anyhow!(
"unable to parse timeout
Caused by:
invalid digit found in string"
)),
},
TestData {
param: "agent.hotplug_timeout=j",
result: Err(anyhow!(
"unable to parse timeout
)))]
#[case("agent.hotplug_timeout=j", Err(anyhow!(
"unable to parse timeout
Caused by:
invalid digit found in string"
)),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_timeout(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
)))]
#[case("agent.chd_api_timeout=1", Err(anyhow!(ERR_INVALID_TIMEOUT_KEY)))]
#[case("agent.cdh_api_timeout=600", Ok(time::Duration::from_secs(600)))]
fn test_timeout(#[case] param: &str, #[case] expected: Result<time::Duration>) {
let result = get_timeout(param);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]
fn test_get_container_pipe_size() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<i32>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE)),
},
TestData {
param: "agent.container_pipe_size",
result: Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE)),
},
TestData {
param: "foo=bar",
result: Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE_KEY)),
},
TestData {
param: "agent.container_pip_siz=1",
result: Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE_KEY)),
},
TestData {
param: "agent.container_pipe_size=1",
result: Ok(1),
},
TestData {
param: "agent.container_pipe_size=3",
result: Ok(3),
},
TestData {
param: "agent.container_pipe_size=2097152",
result: Ok(2097152),
},
TestData {
param: "agent.container_pipe_size=0",
result: Ok(0),
},
TestData {
param: "agent.container_pipe_size=-1",
result: Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_NEGATIVE)),
},
TestData {
param: "agent.container_pipe_size=foobar",
result: Err(anyhow!(
"unable to parse container pipe size
#[rstest]
#[case("", Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE)))]
#[case("agent.container_pipe_size", Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE)))]
#[case("foo=bar", Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE_KEY)))]
#[case("agent.container_pip_siz=1", Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_SIZE_KEY)))]
#[case("agent.container_pipe_size=1", Ok(1))]
#[case("agent.container_pipe_size=3", Ok(3))]
#[case("agent.container_pipe_size=2097152", Ok(2097152))]
#[case("agent.container_pipe_size=0", Ok(0))]
#[case("agent.container_pipe_size=-1", Err(anyhow!(ERR_INVALID_CONTAINER_PIPE_NEGATIVE)))]
#[case("agent.container_pipe_size=foobar", Err(anyhow!(
"unable to parse container pipe size
Caused by:
invalid digit found in string"
)),
},
TestData {
param: "agent.container_pipe_size=j",
result: Err(anyhow!(
"unable to parse container pipe size
)))]
#[case("agent.container_pipe_size=j", Err(anyhow!(
"unable to parse container pipe size
Caused by:
invalid digit found in string",
)),
},
TestData {
param: "agent.container_pipe_size=4jbsdja",
result: Err(anyhow!(
"unable to parse container pipe size
)))]
#[case("agent.container_pipe_size=4jbsdja", Err(anyhow!(
"unable to parse container pipe size
Caused by:
invalid digit found in string"
)),
},
TestData {
param: "agent.container_pipe_size=4294967296",
result: Err(anyhow!(
"unable to parse container pipe size
)))]
#[case("agent.container_pipe_size=4294967296", Err(anyhow!(
"unable to parse container pipe size
Caused by:
number too large to fit in target type"
)),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_container_pipe_size(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
)))]
fn test_get_container_pipe_size(#[case] param: &str, #[case] expected: Result<i32>) {
let result = get_container_pipe_size(param);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]
fn test_get_string_value() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<String>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)),
},
TestData {
param: "=",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
},
TestData {
param: "==",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
},
TestData {
param: "x=",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_VALUE)),
},
TestData {
param: "x==",
result: Ok("=".into()),
},
TestData {
param: "x===",
result: Ok("==".into()),
},
TestData {
param: "x==x",
result: Ok("=x".into()),
},
TestData {
param: "x=x",
result: Ok("x".into()),
},
TestData {
param: "x=x=",
result: Ok("x=".into()),
},
TestData {
param: "x=x=x",
result: Ok("x=x".into()),
},
TestData {
param: "foo=bar",
result: Ok("bar".into()),
},
TestData {
param: "x= =",
result: Ok(" =".into()),
},
TestData {
param: "x= =",
result: Ok(" =".into()),
},
TestData {
param: "x= = ",
result: Ok(" = ".into()),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_string_value(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
#[rstest]
#[case("", Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)))]
#[case("=", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)))]
#[case("==", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)))]
#[case("x=", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_VALUE)))]
#[case("x==", Ok("=".into()))]
#[case("x===", Ok("==".into()))]
#[case("x==x", Ok("=x".into()))]
#[case("x=x", Ok("x".into()))]
#[case("x=x=", Ok("x=".into()))]
#[case("x=x=x", Ok("x=x".into()))]
#[case("foo=bar", Ok("bar".into()))]
#[case("x= =", Ok(" =".into()))]
#[case("x= =", Ok(" =".into()))]
#[case("x= = ", Ok(" = ".into()))]
fn test_get_string_value(#[case] param: &str, #[case] expected: Result<String>) {
let result = get_string_value(param);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]
fn test_get_guest_components_features_value() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<GuestComponentsFeatures>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)),
},
TestData {
param: "=",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
},
TestData {
param: "==",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
},
TestData {
param: "x=all",
result: Ok(GuestComponentsFeatures::All),
},
TestData {
param: "x=attestation",
result: Ok(GuestComponentsFeatures::Attestation),
},
TestData {
param: "x=resource",
result: Ok(GuestComponentsFeatures::Resource),
},
TestData {
param: "x===",
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)),
},
TestData {
param: "x==x",
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)),
},
TestData {
param: "x=x",
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_guest_components_features_value(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
#[rstest]
#[case("", Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)))]
#[case("=", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)))]
#[case("==", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)))]
#[case("x=all", Ok(GuestComponentsFeatures::All))]
#[case("x=attestation", Ok(GuestComponentsFeatures::Attestation))]
#[case("x=resource", Ok(GuestComponentsFeatures::Resource))]
#[case("x===", Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)))]
#[case("x==x", Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)))]
#[case("x=x", Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_REST_API_VALUE)))]
fn test_get_guest_components_features_value(
#[case] input: &str,
#[case] expected: Result<GuestComponentsFeatures>,
) {
let result = get_guest_components_features_value(input);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]
fn test_get_guest_components_procs_value() {
#[derive(Debug)]
struct TestData<'a> {
param: &'a str,
result: Result<GuestComponentsProcs>,
}
let tests = &[
TestData {
param: "",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)),
},
TestData {
param: "=",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
},
TestData {
param: "==",
result: Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)),
},
TestData {
param: "x=attestation-agent",
result: Ok(GuestComponentsProcs::AttestationAgent),
},
TestData {
param: "x=confidential-data-hub",
result: Ok(GuestComponentsProcs::ConfidentialDataHub),
},
TestData {
param: "x=none",
result: Ok(GuestComponentsProcs::None),
},
TestData {
param: "x=api-server-rest",
result: Ok(GuestComponentsProcs::ApiServerRest),
},
TestData {
param: "x===",
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_PROCS_VALUE)),
},
TestData {
param: "x==x",
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_PROCS_VALUE)),
},
TestData {
param: "x=x",
result: Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_PROCS_VALUE)),
},
];
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = get_guest_components_procs_value(d.param);
let msg = format!("{}: result: {:?}", msg, result);
assert_result!(d.result, result, msg);
}
#[rstest]
#[case("", Err(anyhow!(ERR_INVALID_GET_VALUE_PARAM)))]
#[case("=", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)))]
#[case("==", Err(anyhow!(ERR_INVALID_GET_VALUE_NO_NAME)))]
#[case("x=attestation-agent", Ok(GuestComponentsProcs::AttestationAgent))]
#[case(
"x=confidential-data-hub",
Ok(GuestComponentsProcs::ConfidentialDataHub)
)]
#[case("x=none", Ok(GuestComponentsProcs::None))]
#[case("x=api-server-rest", Ok(GuestComponentsProcs::ApiServerRest))]
#[case("x===", Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_PROCS_VALUE)))]
#[case("x==x", Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_PROCS_VALUE)))]
#[case("x=x", Err(anyhow!(ERR_INVALID_GUEST_COMPONENTS_PROCS_VALUE)))]
fn test_get_guest_components_procs_value(
#[case] param: &str,
#[case] expected: Result<GuestComponentsProcs>,
) {
let result = get_guest_components_procs_value(param);
let msg = format!("expected: {:?}, result: {:?}", expected, result);
assert_result!(expected, result, msg);
}
#[test]

View File

@@ -11,6 +11,9 @@ use self::vfio_device_handler::{VfioApDeviceHandler, VfioPciDeviceHandler};
use crate::pci;
use crate::sandbox::Sandbox;
use anyhow::{anyhow, Context, Result};
use cdi::annotations::parse_annotations;
use cdi::cache::{new_cache, with_auto_refresh, CdiOption};
use cdi::spec_dirs::with_spec_dirs;
use kata_types::device::DeviceHandlerManager;
use nix::sys::stat;
use oci::{LinuxDeviceCgroup, Spec};
@@ -25,6 +28,8 @@ use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::time;
use tokio::time::Duration;
use tracing::instrument;
pub mod block_device_handler;
@@ -238,6 +243,69 @@ pub async fn add_devices(
update_spec_devices(logger, spec, dev_updates)
}
#[instrument]
pub async fn handle_cdi_devices(
logger: &Logger,
spec: &mut Spec,
spec_dir: &str,
cdi_timeout: u64,
) -> Result<()> {
if let Some(container_type) = spec
.annotations()
.as_ref()
.and_then(|a| a.get("io.katacontainers.pkg.oci.container_type"))
{
if container_type == "pod_sandbox" {
return Ok(());
}
}
let (_, devices) = parse_annotations(spec.annotations().as_ref().unwrap())?;
if devices.is_empty() {
info!(logger, "no CDI annotations, no devices to inject");
return Ok(());
}
// Explicitly set the cache options to disable auto-refresh and
// to use the single spec dir "/var/run/cdi" for tests it can be overridden
let options: Vec<CdiOption> = vec![with_auto_refresh(false), with_spec_dirs(&[spec_dir])];
let cache: Arc<std::sync::Mutex<cdi::cache::Cache>> = new_cache(options);
for _ in 0..=cdi_timeout {
let inject_result = {
// Lock cache within this scope, std::sync::Mutex has no Send
// and await will not work with time::sleep
let mut cache = cache.lock().unwrap();
match cache.refresh() {
Ok(_) => {}
Err(e) => {
return Err(anyhow!("error refreshing cache: {:?}", e));
}
}
cache.inject_devices(Some(spec), devices.clone())
};
match inject_result {
Ok(_) => {
info!(
logger,
"all devices injected successfully, modified CDI container spec: {:?}", &spec
);
return Ok(());
}
Err(e) => {
info!(logger, "error injecting devices: {:?}", e);
println!("error injecting devices: {:?}", e);
}
}
time::sleep(Duration::from_millis(1000)).await;
}
Err(anyhow!(
"failed to inject devices after CDI timeout of {} seconds",
cdi_timeout
))
}
#[instrument]
async fn validate_device(
logger: &Logger,
@@ -1110,4 +1178,95 @@ mod tests {
assert!(name.is_ok(), "{}", name.unwrap_err());
assert_eq!(name.unwrap(), devname);
}
#[tokio::test]
async fn test_handle_cdi_devices() {
let logger = slog::Logger::root(slog::Discard, o!());
let mut spec = Spec::default();
let mut annotations = HashMap::new();
// cdi.k8s.io/vendor1_devices: vendor1.com/device=foo
annotations.insert(
"cdi.k8s.io/vfio17".to_string(),
"kata.com/gpu=0".to_string(),
);
spec.set_annotations(Some(annotations));
// create a file in /tmp/cdi with nvidia.json content
let cdi_dir = PathBuf::from("/tmp/cdi");
let cdi_file = cdi_dir.join("kata.json");
let cdi_version = "0.6.0";
let kind = "kata.com/gpu";
let device_name = "0";
let annotation_whatever = "false";
let annotation_whenever = "true";
let inner_env = "TEST_INNER_ENV=TEST_INNER_ENV_VALUE";
let outer_env = "TEST_OUTER_ENV=TEST_OUTER_ENV_VALUE";
let inner_device = "/dev/zero";
let outer_device = "/dev/null";
let cdi_content = format!(
r#"{{
"cdiVersion": "{cdi_version}",
"kind": "{kind}",
"devices": [
{{
"name": "{device_name}",
"annotations": {{
"whatever": "{annotation_whatever}",
"whenever": "{annotation_whenever}"
}},
"containerEdits": {{
"env": [
"{inner_env}"
],
"deviceNodes": [
{{
"path": "{inner_device}"
}}
]
}}
}}
],
"containerEdits": {{
"env": [
"{outer_env}"
],
"deviceNodes": [
{{
"path": "{outer_device}"
}}
]
}}
}}"#
);
fs::create_dir_all(&cdi_dir).unwrap();
fs::write(&cdi_file, cdi_content).unwrap();
let res = handle_cdi_devices(&logger, &mut spec, "/tmp/cdi", 0).await;
println!("modfied spec {:?}", spec);
assert!(res.is_ok(), "{}", res.err().unwrap());
let linux = spec.linux().as_ref().unwrap();
let devices = linux
.resources()
.as_ref()
.unwrap()
.devices()
.as_ref()
.unwrap();
assert_eq!(devices.len(), 2);
let env = spec.process().as_ref().unwrap().env().as_ref().unwrap();
// find string TEST_OUTER_ENV in evn
let outer_env = env.iter().find(|e| e.starts_with("TEST_OUTER_ENV"));
assert!(outer_env.is_some(), "TEST_OUTER_ENV not found in env");
// find TEST_INNER_ENV in env
let inner_env = env.iter().find(|e| e.starts_with("TEST_INNER_ENV"));
assert!(inner_env.is_some(), "TEST_INNER_ENV not found in env");
}
}

View File

@@ -21,6 +21,9 @@ use tokio::sync::Mutex;
use crate::rpc::CONTAINER_BASE;
use crate::AGENT_CONFIG;
use kata_types::mount::KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL;
use protocols::agent::Storage;
pub const KATA_IMAGE_WORK_DIR: &str = "/run/kata-containers/image/";
const CONFIG_JSON: &str = "config.json";
const KATA_PAUSE_BUNDLE: &str = "/pause_bundle";
@@ -81,6 +84,28 @@ impl ImageService {
Self { image_client }
}
/// get guest pause image process specification
fn get_pause_image_process() -> Result<oci::Process> {
let guest_pause_bundle = Path::new(KATA_PAUSE_BUNDLE);
if !guest_pause_bundle.exists() {
bail!("Pause image not present in rootfs");
}
let guest_pause_config = scoped_join(guest_pause_bundle, CONFIG_JSON)?;
let image_oci = oci::Spec::load(guest_pause_config.to_str().ok_or_else(|| {
anyhow!(
"Failed to load the guest pause image config from {:?}",
guest_pause_config
)
})?)
.context("load image config file")?;
let image_oci_process = image_oci.process().as_ref().ok_or_else(|| {
anyhow!("The guest pause image config does not contain a process specification. Please check the pause image.")
})?;
Ok(image_oci_process.clone())
}
/// pause image is packaged in rootfs
fn unpack_pause_image(cid: &str) -> Result<String> {
verify_id(cid).context("The guest pause image cid contains invalid characters.")?;
@@ -132,6 +157,20 @@ impl ImageService {
Ok(pause_rootfs.display().to_string())
}
/// check whether the image is for sandbox or for container.
fn is_sandbox(image_metadata: &HashMap<String, String>) -> bool {
let mut is_sandbox = false;
for key in K8S_CONTAINER_TYPE_KEYS.iter() {
if let Some(value) = image_metadata.get(key as &str) {
if value == "sandbox" {
is_sandbox = true;
break;
}
}
}
is_sandbox
}
/// pull_image is used for call image-rs to pull image in the guest.
/// # Parameters
/// - `image`: Image name (exp: quay.io/prometheus/busybox:latest)
@@ -147,18 +186,7 @@ impl ImageService {
) -> Result<String> {
info!(sl(), "image metadata: {image_metadata:?}");
//Check whether the image is for sandbox or for container.
let mut is_sandbox = false;
for key in K8S_CONTAINER_TYPE_KEYS.iter() {
if let Some(value) = image_metadata.get(key as &str) {
if value == "sandbox" {
is_sandbox = true;
break;
}
}
}
if is_sandbox {
if Self::is_sandbox(image_metadata) {
let mount_path = Self::unpack_pause_image(cid)?;
return Ok(mount_path);
}
@@ -194,6 +222,32 @@ impl ImageService {
}
}
/// get_process overrides the OCI process spec with pause image process spec if needed
pub fn get_process(
ocip: &oci::Process,
oci: &oci::Spec,
storages: Vec<Storage>,
) -> Result<oci::Process> {
let mut guest_pull = false;
for storage in storages {
if storage.driver == KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL {
guest_pull = true;
break;
}
}
if guest_pull {
match oci.annotations() {
Some(a) => {
if ImageService::is_sandbox(a) {
return ImageService::get_pause_image_process();
}
}
None => {}
}
}
Ok(ocip.clone())
}
/// Set proxy environment from AGENT_CONFIG
pub async fn set_proxy_env_vars() {
if env::var("HTTPS_PROXY").is_err() {

View File

@@ -21,7 +21,7 @@ extern crate slog;
use anyhow::{anyhow, Context, Result};
use cfg_if::cfg_if;
use clap::{AppSettings, Parser};
use const_format::concatcp;
use const_format::{concatcp, formatcp};
use nix::fcntl::OFlag;
use nix::sys::reboot::{reboot, RebootMode};
use nix::sys::socket::{self, AddressFamily, SockFlag, SockType, VsockAddr};
@@ -29,7 +29,7 @@ use nix::unistd::{self, dup, sync, Pid};
use std::env;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::os::unix::fs as unixfs;
use std::os::unix::fs::{self as unixfs, FileTypeExt};
use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::process::exit;
@@ -109,7 +109,18 @@ const CDH_SOCKET_URI: &str = concatcp!(UNIX_SOCKET_PREFIX, CDH_SOCKET);
const API_SERVER_PATH: &str = "/usr/local/bin/api-server-rest";
/// Path of ocicrypt config file. This is used by image-rs when decrypting image.
const OCICRYPT_CONFIG_PATH: &str = "/tmp/ocicrypt_config.json";
const OCICRYPT_CONFIG_PATH: &str = "/run/confidential-containers/ocicrypt_config.json";
const OCICRYPT_CONFIG: &str = formatcp!(
r#"{{
"key-providers": {{
"attestation-agent": {{
"ttrpc": "{}"
}}
}}
}}"#,
CDH_SOCKET_URI
);
const DEFAULT_LAUNCH_PROCESS_TIMEOUT: i32 = 6;
@@ -408,15 +419,13 @@ async fn start_sandbox(
sandbox.lock().await.sender = Some(tx);
let gc_procs = config.guest_components_procs;
if gc_procs != GuestComponentsProcs::None {
if !attestation_binaries_available(logger, &gc_procs) {
warn!(
logger,
"attestation binaries requested for launch not available"
);
} else {
init_attestation_components(logger, config).await?;
}
if !attestation_binaries_available(logger, &gc_procs) {
warn!(
logger,
"attestation binaries requested for launch not available"
);
} else {
init_attestation_components(logger, config).await?;
}
// vsock:///dev/vsock, port
@@ -447,12 +456,7 @@ fn attestation_binaries_available(logger: &Logger, procs: &GuestComponentsProcs)
true
}
// Start-up attestation-agent, CDH and api-server-rest if they are packaged in the rootfs
// and the corresponding procs are enabled in the agent configuration. the process will be
// launched in the background and the function will return immediately.
// If the CDH is started, a CDH client will be instantiated and returned.
async fn init_attestation_components(logger: &Logger, config: &AgentConfig) -> Result<()> {
// skip launch of any guest-component
async fn launch_guest_component_procs(logger: &Logger, config: &AgentConfig) -> Result<()> {
if config.guest_components_procs == GuestComponentsProcs::None {
return Ok(());
}
@@ -472,17 +476,6 @@ async fn init_attestation_components(logger: &Logger, config: &AgentConfig) -> R
return Ok(());
}
let ocicrypt_config = serde_json::json!({
"key-providers": {
"attestation-agent":{
"ttrpc":CDH_SOCKET_URI
}
}
});
fs::write(OCICRYPT_CONFIG_PATH, ocicrypt_config.to_string().as_bytes())?;
env::set_var("OCICRYPT_KEYPROVIDER_CONFIG", OCICRYPT_CONFIG_PATH);
debug!(
logger,
"spawning confidential-data-hub process {}", CDH_PATH
@@ -497,9 +490,6 @@ async fn init_attestation_components(logger: &Logger, config: &AgentConfig) -> R
)
.map_err(|e| anyhow!("launch_process {} failed: {:?}", CDH_PATH, e))?;
// initialize cdh client
cdh::init_cdh_client().await?;
// skip launch of api-server-rest
if config.guest_components_procs == GuestComponentsProcs::ConfidentialDataHub {
return Ok(());
@@ -522,6 +512,34 @@ async fn init_attestation_components(logger: &Logger, config: &AgentConfig) -> R
Ok(())
}
// Start-up attestation-agent, CDH and api-server-rest if they are packaged in the rootfs
// and the corresponding procs are enabled in the agent configuration. the process will be
// launched in the background and the function will return immediately.
// If the CDH is started, a CDH client will be instantiated and returned.
async fn init_attestation_components(logger: &Logger, config: &AgentConfig) -> Result<()> {
launch_guest_component_procs(logger, config).await?;
fs::write(OCICRYPT_CONFIG_PATH, OCICRYPT_CONFIG.as_bytes())?;
env::set_var("OCICRYPT_KEYPROVIDER_CONFIG", OCICRYPT_CONFIG_PATH);
// If a CDH socket exists, initialize the CDH client
match tokio::fs::metadata(CDH_SOCKET).await {
Ok(md) => {
if md.file_type().is_socket() {
cdh::init_cdh_client(CDH_SOCKET_URI).await?;
} else {
debug!(logger, "File {} is not a socket", CDH_SOCKET);
}
}
Err(err) => warn!(
logger,
"Failed to probe CDH socket file {}: {:?}", CDH_SOCKET, err
),
}
Ok(())
}
fn wait_for_path_to_exist(logger: &Logger, path: &str, timeout_secs: i32) -> Result<()> {
let p = Path::new(path);
let mut attempts = 0;

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::Result;
use anyhow::{bail, Result};
use protobuf::MessageDyn;
use tokio::io::AsyncWriteExt;
@@ -68,6 +68,12 @@ pub struct AgentPolicy {
engine: regorus::Engine,
}
#[derive(serde::Deserialize, Debug)]
struct MetadataResponse {
allowed: bool,
ops: Option<json_patch::Patch>,
}
impl AgentPolicy {
/// Create AgentPolicy object.
pub fn new() -> Self {
@@ -82,6 +88,17 @@ impl AgentPolicy {
let mut engine = regorus::Engine::new();
engine.set_strict_builtin_errors(false);
engine.set_gather_prints(true);
// assign a slice of the engine data "pstate" to be used as policy state
engine
.add_data(
regorus::Value::from_json_str(
r#"{
"pstate": {}
}"#,
)
.unwrap(),
)
.unwrap();
engine
}
@@ -112,6 +129,23 @@ impl AgentPolicy {
Ok(())
}
async fn apply_patch_to_state(&mut self, patch: json_patch::Patch) -> Result<()> {
// Convert the current engine data to a JSON value
let mut state = serde_json::to_value(self.engine.get_data())?;
// Apply the patch to the state
json_patch::patch(&mut state, &patch)?;
// Clear the existing data in the engine
self.engine.clear_data();
// Add the patched state back to the engine
self.engine
.add_data(regorus::Value::from_json_str(&state.to_string())?)?;
Ok(())
}
/// Ask regorus if an API call should be allowed or not.
async fn allow_request(&mut self, ep: &str, ep_input: &str) -> Result<(bool, String)> {
debug!(sl!(), "policy check: {ep}");
@@ -120,13 +154,56 @@ impl AgentPolicy {
let query = format!("data.agent_policy.{ep}");
self.engine.set_input_json(ep_input)?;
let mut allow = match self.engine.eval_bool_query(query, false) {
Ok(a) => a,
Err(e) => {
if !self.allow_failures {
return Err(e);
let results = self.engine.eval_query(query, false)?;
let prints = match self.engine.take_prints() {
Ok(p) => p.join(" "),
Err(e) => format!("Failed to get policy log: {e}"),
};
if results.result.len() != 1 {
// Results are empty when AllowRequestsFailingPolicy is used to allow a Request that hasn't been defined in the policy
if self.allow_failures {
return Ok((true, prints));
}
bail!(
"policy check: unexpected eval_query result len {:?}",
results
);
}
if results.result[0].expressions.len() != 1 {
bail!(
"policy check: unexpected eval_query result expressions {:?}",
results
);
}
let mut allow = match &results.result[0].expressions[0].value {
regorus::Value::Bool(b) => *b,
// Match against a specific variant that could be interpreted as MetadataResponse
regorus::Value::Object(obj) => {
let json_str = serde_json::to_string(obj)?;
self.log_eval_input(ep, &json_str).await;
let metadata_response: MetadataResponse = serde_json::from_str(&json_str)?;
if metadata_response.allowed {
if let Some(ops) = metadata_response.ops {
self.apply_patch_to_state(ops).await?;
}
}
false
metadata_response.allowed
}
_ => {
error!(sl!(), "allow_request: unexpected eval_query result type");
bail!(
"policy check: unexpected eval_query result type {:?}",
results
);
}
};
@@ -135,11 +212,6 @@ impl AgentPolicy {
allow = true;
}
let prints = match self.engine.take_prints() {
Ok(p) => p.join(" "),
Err(e) => format!("Failed to get policy log: {e}"),
};
Ok((allow, prints))
}

View File

@@ -58,7 +58,7 @@ use rustjail::process::ProcessOperations;
use crate::cdh;
use crate::device::block_device_handler::get_virtio_blk_pci_device_name;
use crate::device::network_device_handler::wait_for_net_interface;
use crate::device::{add_devices, update_env_pci};
use crate::device::{add_devices, handle_cdi_devices, update_env_pci};
use crate::features::get_build_features;
use crate::image::KATA_IMAGE_WORK_DIR;
use crate::linux_abi::*;
@@ -130,6 +130,8 @@ const ERR_NO_SANDBOX_PIDNS: &str = "Sandbox does not have sandbox_pidns";
// not available.
const IPTABLES_RESTORE_WAIT_SEC: u64 = 5;
const CDI_TIMEOUT_LIMIT: u64 = 100;
// Convenience function to obtain the scope logger.
fn sl() -> slog::Logger {
slog_scope::logger()
@@ -224,54 +226,16 @@ impl AgentService {
// cannot predict everything from the caller.
add_devices(&sl(), &req.devices, &mut oci, &self.sandbox).await?;
let process = oci
.process_mut()
.as_mut()
.ok_or_else(|| anyhow!("Spec didn't contain process field"))?;
if cdh::is_cdh_client_initialized().await {
if let Some(envs) = process.env_mut().as_mut() {
for env in envs.iter_mut() {
match cdh::unseal_env(env).await {
Ok(unsealed_env) => *env = unsealed_env.to_string(),
Err(e) => {
warn!(sl(), "Failed to unseal secret: {}", e)
}
}
}
}
}
// In guest-kernel mode some devices need extra handling. Taking the
// GPU as an example the shim will inject CDI annotations that will
// be used by the kata-agent to do containerEdits according to the
// CDI spec coming from a registry that is created on the fly by UDEV
// or other entities for a specifc device.
// In Kata we only consider the directory "/var/run/cdi", "/etc" may be
// readonly
handle_cdi_devices(&sl(), &mut oci, "/var/run/cdi", CDI_TIMEOUT_LIMIT).await?;
let linux = oci
.linux()
.as_ref()
.ok_or_else(|| anyhow!("Spec didn't contain linux field"))?;
if cdh::is_cdh_client_initialized().await {
if let Some(devices) = linux.devices() {
for specdev in devices.iter() {
if specdev.path().as_path().to_str() == Some(TRUSTED_IMAGE_STORAGE_DEVICE) {
let dev_major_minor = format!("{}:{}", specdev.major(), specdev.minor());
let secure_storage_integrity =
AGENT_CONFIG.secure_storage_integrity.to_string();
info!(
sl(),
"trusted_store device major:min {}, enable data integrity {}",
dev_major_minor,
secure_storage_integrity
);
let options = std::collections::HashMap::from([
("deviceId".to_string(), dev_major_minor),
("encryptType".to_string(), "LUKS".to_string()),
("dataIntegrity".to_string(), secure_storage_integrity),
]);
cdh::secure_mount("BlockDevice", &options, vec![], KATA_IMAGE_WORK_DIR)
.await?;
break;
}
}
}
}
cdh_handler(&mut oci).await?;
// Both rootfs and volumes (invoked with --volume for instance) will
// be processed the same way. The idea is to always mount any provided
@@ -280,7 +244,13 @@ impl AgentService {
// After all those storages have been processed, no matter the order
// here, the agent will rely on rustjail (using the oci.Mounts
// list) to bind mount all of them inside the container.
let m = add_storages(sl(), req.storages, &self.sandbox, Some(req.container_id)).await?;
let m = add_storages(
sl(),
req.storages.clone(),
&self.sandbox,
Some(req.container_id),
)
.await?;
let mut s = self.sandbox.lock().await;
s.container_mounts.insert(cid.clone(), m);
@@ -335,6 +305,13 @@ impl AgentService {
let pipe_size = AGENT_CONFIG.container_pipe_size;
let p = if let Some(p) = oci.process() {
#[cfg(feature = "guest-pull")]
{
let new_p = image::get_process(p, &oci, req.storages.clone())?;
Process::new(&sl(), &new_p, cid.as_str(), true, pipe_size, proc_io)?
}
#[cfg(not(feature = "guest-pull"))]
Process::new(&sl(), p, cid.as_str(), true, pipe_size, proc_io)?
} else {
info!(sl(), "no process configurations!");
@@ -1726,13 +1703,19 @@ fn update_container_namespaces(
if let Some(namespaces) = linux.namespaces_mut() {
for namespace in namespaces.iter_mut() {
if namespace.typ().to_string() == NSTYPEIPC {
namespace.set_path(Some(PathBuf::from(&sandbox.shared_ipcns.path.clone())));
namespace.set_path(None);
namespace.set_path(if !sandbox.shared_ipcns.path.is_empty() {
Some(PathBuf::from(&sandbox.shared_ipcns.path))
} else {
None
});
continue;
}
if namespace.typ().to_string() == NSTYPEUTS {
namespace.set_path(Some(PathBuf::from(&sandbox.shared_utsns.path.clone())));
namespace.set_path(None);
namespace.set_path(if !sandbox.shared_utsns.path.is_empty() {
Some(PathBuf::from(&sandbox.shared_utsns.path))
} else {
None
});
continue;
}
}
@@ -1750,7 +1733,7 @@ fn update_container_namespaces(
if !pidns.path.is_empty() {
pid_ns.set_path(Some(PathBuf::from(&pidns.path)));
}
} else {
} else if !sandbox.containers.is_empty() {
return Err(anyhow!(ERR_NO_SANDBOX_PIDNS));
}
}
@@ -2093,6 +2076,76 @@ fn load_kernel_module(module: &protocols::agent::KernelModule) -> Result<()> {
}
}
async fn cdh_handler(oci: &mut Spec) -> Result<()> {
if !cdh::is_cdh_client_initialized().await {
return Ok(());
}
let process = oci
.process_mut()
.as_mut()
.ok_or_else(|| anyhow!("Spec didn't contain process field"))?;
if let Some(envs) = process.env_mut().as_mut() {
for env in envs.iter_mut() {
match cdh::unseal_env(env).await {
Ok(unsealed_env) => *env = unsealed_env.to_string(),
Err(e) => {
warn!(sl(), "Failed to unseal secret: {}", e)
}
}
}
}
let mounts = oci
.mounts_mut()
.as_mut()
.ok_or_else(|| anyhow!("Spec didn't contain mounts field"))?;
for m in mounts.iter_mut() {
if m.destination().starts_with("/sealed") {
info!(
sl(),
"sealed mount destination: {:?} source: {:?}",
m.destination(),
m.source()
);
if let Some(source_str) = m.source().as_ref().and_then(|p| p.to_str()) {
cdh::unseal_file(source_str).await?;
} else {
warn!(sl(), "Failed to unseal: Mount source is None or invalid");
}
}
}
let linux = oci
.linux()
.as_ref()
.ok_or_else(|| anyhow!("Spec didn't contain linux field"))?;
if let Some(devices) = linux.devices() {
for specdev in devices.iter() {
if specdev.path().as_path().to_str() == Some(TRUSTED_IMAGE_STORAGE_DEVICE) {
let dev_major_minor = format!("{}:{}", specdev.major(), specdev.minor());
let secure_storage_integrity = AGENT_CONFIG.secure_storage_integrity.to_string();
info!(
sl(),
"trusted_store device major:min {}, enable data integrity {}",
dev_major_minor,
secure_storage_integrity
);
let options = std::collections::HashMap::from([
("deviceId".to_string(), dev_major_minor),
("encryptType".to_string(), "LUKS".to_string()),
("dataIntegrity".to_string(), secure_storage_integrity),
]);
cdh::secure_mount("BlockDevice", &options, vec![], KATA_IMAGE_WORK_DIR).await?;
break;
}
}
}
Ok(())
}
#[cfg(test)]
#[allow(dead_code)]
mod tests {
@@ -2527,14 +2580,6 @@ mod tests {
.unwrap()],
..Default::default()
},
TestData {
namespaces: vec![],
sandbox_pidns_path: None,
use_sandbox_pidns: true,
result: Err(anyhow!(ERR_NO_SANDBOX_PIDNS)),
expected_namespaces: vec![],
..Default::default()
},
TestData {
has_linux_in_spec: false,
result: Err(anyhow!(ERR_NO_LINUX_FIELD)),

View File

@@ -170,7 +170,7 @@ impl EphemeralHandler {
let size = size_str
.unwrap()
.parse::<u64>()
.context(format!("parse size: {:?}", &pagesize_str))?;
.context(format!("parse size: {:?}", &size_str))?;
Ok((pagesize, size))
}

27
src/libs/Cargo.lock generated
View File

@@ -240,19 +240,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cgroups-rs"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b098e7c3a70d03c288fa0a96ccf13e770eb3d78c4cc0e1549b3c13215d5f965"
dependencies = [
"libc",
"log",
"nix 0.25.1",
"regex",
"thiserror",
]
[[package]]
name = "chrono"
version = "0.4.20"
@@ -814,7 +801,6 @@ version = "0.1.0"
dependencies = [
"anyhow",
"byteorder",
"cgroups-rs",
"chrono",
"common-path",
"fail",
@@ -975,18 +961,6 @@ dependencies = [
"memoffset 0.6.5",
]
[[package]]
name = "nix"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
dependencies = [
"autocfg",
"bitflags",
"cfg-if",
"libc",
]
[[package]]
name = "nix"
version = "0.26.4"
@@ -1316,7 +1290,6 @@ name = "protocols"
version = "0.1.0"
dependencies = [
"async-trait",
"kata-sys-util",
"oci-spec",
"protobuf 3.2.0",
"serde",

View File

@@ -13,7 +13,6 @@ edition = "2018"
[dependencies]
anyhow = "1.0.31"
byteorder = "1.4.3"
cgroups = { package = "cgroups-rs", version = "0.3.2" }
chrono = "0.4.0"
common-path = "=1.0.0"
fail = "0.5.0"

View File

@@ -1,10 +1,9 @@
# kata-sys-util
# `kata-sys-util`
This crate is a collection of utilities and helpers for
[Kata Containers](https://github.com/kata-containers/kata-containers/) components to access system services.
It provides safe wrappers over system services, such as:
- cgroups
- file systems
- mount
- NUMA

View File

@@ -97,11 +97,3 @@ pub fn load_oci_spec() -> Result<oci::Spec, OciSpecError> {
oci::Spec::load(spec_file.to_str().unwrap_or_default())
}
/// handle string parsing for input possibly be JSON string.
pub fn parse_json_string(input: &str) -> &str {
let json_str: &str = serde_json::from_str(input).unwrap_or(input);
let stripped_str = json_str.strip_prefix("CAP_").unwrap_or(json_str);
stripped_str
}

View File

@@ -11,7 +11,12 @@ pub const CONTAINER_NAME_LABEL_KEY: &str = "io.kubernetes.cri.container-name";
pub const SANDBOX: &str = "sandbox";
pub const CONTAINER: &str = "container";
// SandboxID is the sandbox ID annotation
pub const SANDBOX_ID_LABEL_KEY: &str = "io.kubernetes.cri.sandbox-id";
// SandboxName is the name of the sandbox (pod)
pub const SANDBOX_NAME_LABEL_KEY: &str = "io.kubernetes.cri.sandbox-name";
// SandboxNamespace is the name of the namespace of the sandbox (pod)
pub const SANDBOX_NAMESPACE_LABEL_KEY: &str = "io.kubernetes.cri.sandbox-namespace";
// Ref: https://pkg.go.dev/github.com/containerd/containerd@v1.6.7/pkg/cri/annotations
// SandboxCPU annotations are based on the initial CPU configuration for the sandbox. This is calculated as the

View File

@@ -88,12 +88,6 @@ pub const KATA_ANNO_CFG_HYPERVISOR_PREFIX: &str = "io.katacontainers.config.hype
pub const KATA_ANNO_CFG_HYPERVISOR_PATH: &str = "io.katacontainers.config.hypervisor.path";
/// A sandbox annotation for passing a container hypervisor binary SHA-512 hash value.
pub const KATA_ANNO_CFG_HYPERVISOR_HASH: &str = "io.katacontainers.config.hypervisor.path_hash";
/// A sandbox annotation for passing a per container path pointing at the hypervisor control binary
/// that will run the container VM.
pub const KATA_ANNO_CFG_HYPERVISOR_CTLPATH: &str = "io.katacontainers.config.hypervisor.ctlpath";
/// A sandbox annotation for passing a container hypervisor control binary SHA-512 hash value.
pub const KATA_ANNO_CFG_HYPERVISOR_CTLHASH: &str =
"io.katacontainers.config.hypervisor.hypervisorctl_hash";
/// A sandbox annotation for passing a per container path pointing at the jailer that will constrain
/// the container VM.
pub const KATA_ANNO_CFG_HYPERVISOR_JAILER_PATH: &str =
@@ -506,10 +500,6 @@ impl Annotation {
hv.validate_hypervisor_path(value)?;
hv.path = value.to_string();
}
KATA_ANNO_CFG_HYPERVISOR_CTLPATH => {
hv.validate_hypervisor_ctlpath(value)?;
hv.ctlpath = value.to_string();
}
KATA_ANNO_CFG_HYPERVISOR_JAILER_PATH => {
hv.validate_jailer_path(value)?;

View File

@@ -98,3 +98,11 @@ pub const DEFAULT_FIRECRACKER_GUEST_KERNEL_IMAGE: &str = "vmlinux";
pub const DEFAULT_FIRECRACKER_GUEST_KERNEL_PARAMS: &str = "";
pub const MAX_FIRECRACKER_VCPUS: u32 = 32;
pub const MIN_FIRECRACKER_MEMORY_SIZE_MB: u32 = 128;
// Default configuration for remote
pub const DEFAULT_REMOTE_HYPERVISOR_SOCKET: &str = "/run/peerpod/hypervisor.sock";
pub const DEFAULT_REMOTE_HYPERVISOR_TIMEOUT: i32 = 600; // 600 Seconds
pub const MAX_REMOTE_VCPUS: u32 = 32;
pub const MIN_REMOTE_MEMORY_SIZE_MB: u32 = 64;
pub const DEFAULT_REMOTE_MEMORY_SIZE_MB: u32 = 128;
pub const DEFAULT_REMOTE_MEMORY_SLOTS: u32 = 128;

View File

@@ -44,6 +44,9 @@ pub use self::qemu::{QemuConfig, HYPERVISOR_NAME_QEMU};
mod ch;
pub use self::ch::{CloudHypervisorConfig, HYPERVISOR_NAME_CH};
mod remote;
pub use self::remote::{RemoteConfig, HYPERVISOR_NAME_REMOTE};
/// Virtual PCI block device driver.
pub const VIRTIO_BLK_PCI: &str = "virtio-blk-pci";
@@ -540,6 +543,7 @@ impl TopologyConfigInfo {
HYPERVISOR_NAME_CH,
HYPERVISOR_NAME_DRAGONBALL,
HYPERVISOR_NAME_FIRECRACKER,
HYPERVISOR_NAME_REMOTE,
];
let hypervisor_name = toml_config.runtime.hypervisor_name.as_str();
if !hypervisor_names.contains(&hypervisor_name) {
@@ -1040,6 +1044,18 @@ impl SharedFsInfo {
}
}
/// Configuration information for remote hypervisor type.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RemoteInfo {
/// Remote hypervisor socket path
#[serde(default)]
pub hypervisor_socket: String,
/// Remote hyperisor timeout of creating (in seconds)
#[serde(default)]
pub hypervisor_timeout: i32,
}
/// Common configuration information for hypervisors.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Hypervisor {
@@ -1123,6 +1139,10 @@ pub struct Hypervisor {
#[serde(default, flatten)]
pub shared_fs: SharedFsInfo,
/// Remote hypervisor configuration information.
#[serde(default, flatten)]
pub remote_info: RemoteInfo,
/// A sandbox annotation used to specify prefetch_files.list host path container image
/// being used, and runtime will pass it to Hypervisor to search for corresponding
/// prefetch list file:
@@ -1164,6 +1184,10 @@ impl ConfigOps for Hypervisor {
fn adjust_config(conf: &mut TomlConfig) -> Result<()> {
HypervisorVendor::adjust_config(conf)?;
let hypervisors: Vec<String> = conf.hypervisor.keys().cloned().collect();
info!(
sl!(),
"Adjusting hypervisor configuration {:?}", hypervisors
);
for hypervisor in hypervisors.iter() {
if let Some(plugin) = get_hypervisor_plugin(hypervisor) {
plugin.adjust_config(conf)?;

View File

@@ -0,0 +1,116 @@
// Copyright 2024 Kata Contributors
//
// SPDX-License-Identifier: Apache-2.0
//
use byte_unit::{Byte, Unit};
use std::io::Result;
use std::path::Path;
use std::sync::Arc;
use sysinfo::System;
use crate::{
config::{
default::{self, MAX_REMOTE_VCPUS, MIN_REMOTE_MEMORY_SIZE_MB},
ConfigPlugin,
}, device::DRIVER_NVDIMM_TYPE, eother, resolve_path
};
use super::register_hypervisor_plugin;
/// Hypervisor name for remote, used to index `TomlConfig::hypervisor`.
pub const HYPERVISOR_NAME_REMOTE: &str = "remote";
/// Configuration information for remote.
#[derive(Default, Debug)]
pub struct RemoteConfig {}
impl RemoteConfig {
/// Create a new instance of `RemoteConfig`
pub fn new() -> Self {
RemoteConfig {}
}
/// Register the remote plugin.
pub fn register(self) {
let plugin = Arc::new(self);
register_hypervisor_plugin(HYPERVISOR_NAME_REMOTE, plugin);
}
}
impl ConfigPlugin for RemoteConfig {
fn name(&self) -> &str {
HYPERVISOR_NAME_REMOTE
}
/// Adjust the configuration information after loading from configuration file.
fn adjust_config(&self, conf: &mut crate::config::TomlConfig) -> Result<()> {
if let Some(remote) = conf.hypervisor.get_mut(HYPERVISOR_NAME_REMOTE) {
if remote.remote_info.hypervisor_socket.is_empty() {
remote.remote_info.hypervisor_socket =
default::DEFAULT_REMOTE_HYPERVISOR_SOCKET.to_string();
}
resolve_path!(
remote.remote_info.hypervisor_socket,
"Remote hypervisor socket `{}` is invalid: {}"
)?;
if remote.remote_info.hypervisor_timeout == 0 {
remote.remote_info.hypervisor_timeout = default::DEFAULT_REMOTE_HYPERVISOR_TIMEOUT;
}
if remote.memory_info.default_memory == 0 {
remote.memory_info.default_memory = default::MIN_REMOTE_MEMORY_SIZE_MB;
}
if remote.memory_info.memory_slots == 0 {
remote.memory_info.memory_slots = default::DEFAULT_REMOTE_MEMORY_SLOTS
}
}
Ok(())
}
/// Validate the configuration information.
fn validate(&self, conf: &crate::config::TomlConfig) -> Result<()> {
if let Some(remote) = conf.hypervisor.get(HYPERVISOR_NAME_REMOTE) {
let s = System::new_all();
let total_memory = Byte::from_u64(s.total_memory())
.get_adjusted_unit(Unit::MiB)
.get_value() as u32;
if remote.memory_info.default_maxmemory != total_memory {
return Err(eother!(
"Remote hypervisor does not support memory hotplug, default_maxmemory must be equal to the total system memory",
));
}
let cpus = num_cpus::get() as u32;
if remote.cpu_info.default_maxvcpus != cpus {
return Err(eother!(
"Remote hypervisor does not support CPU hotplug, default_maxvcpus must be equal to the total system CPUs",
));
}
if !remote.boot_info.initrd.is_empty() {
return Err(eother!("Remote hypervisor does not support initrd"));
}
if !remote.boot_info.rootfs_type.is_empty() {
return Err(eother!("Remote hypervisor does not support rootfs_type"));
}
if remote.blockdev_info.block_device_driver.as_str() == DRIVER_NVDIMM_TYPE {
return Err(eother!("Remote hypervisor does not support nvdimm"));
}
if remote.memory_info.default_memory < MIN_REMOTE_MEMORY_SIZE_MB {
return Err(eother!(
"Remote hypervisor has minimal memory limitation {}",
MIN_REMOTE_MEMORY_SIZE_MB
));
}
}
Ok(())
}
fn get_min_memory(&self) -> u32 {
MIN_REMOTE_MEMORY_SIZE_MB
}
fn get_max_cpus(&self) -> u32 {
MAX_REMOTE_VCPUS
}
}

View File

@@ -26,7 +26,7 @@ pub use self::agent::Agent;
use self::default::DEFAULT_AGENT_DBG_CONSOLE_PORT;
pub use self::hypervisor::{
BootInfo, CloudHypervisorConfig, DragonballConfig, FirecrackerConfig, Hypervisor, QemuConfig,
HYPERVISOR_NAME_DRAGONBALL, HYPERVISOR_NAME_FIRECRACKER, HYPERVISOR_NAME_QEMU,
RemoteConfig, HYPERVISOR_NAME_DRAGONBALL, HYPERVISOR_NAME_FIRECRACKER, HYPERVISOR_NAME_QEMU,
};
mod runtime;

View File

@@ -7,19 +7,17 @@ license = "Apache-2.0"
[features]
default = []
with-serde = [ "serde", "serde_json" ]
with-serde = []
async = ["ttrpc/async", "async-trait"]
[dependencies]
ttrpc = "0.8"
async-trait = { version = "0.1.42", optional = true }
protobuf = { version = "3.2.0" }
serde = { version = "1.0.130", features = ["derive"], optional = true }
serde_json = { version = "1.0.68", optional = true }
serde = { version = "1.0.130", features = ["derive"] }
serde_json = "1.0.68"
oci-spec = { version = "0.6.8", features = ["runtime"] }
kata-sys-util = { path = "../kata-sys-util" }
[build-dependencies]
ttrpc-codegen = "0.4.2"
protobuf = { version = "3.2.0" }

View File

@@ -204,6 +204,7 @@ fn real_main() -> Result<(), std::io::Error> {
"protos/agent.proto",
"protos/health.proto",
"protos/confidential_data_hub.proto",
"protos/remote.proto",
],
true,
)?;
@@ -214,6 +215,7 @@ fn real_main() -> Result<(), std::io::Error> {
"src/confidential_data_hub_ttrpc.rs",
"src/confidential_data_hub_ttrpc_async.rs",
)?;
fs::rename("src/remote_ttrpc.rs", "src/remote_ttrpc_async.rs")?;
}
codegen(
@@ -222,6 +224,7 @@ fn real_main() -> Result<(), std::io::Error> {
"protos/agent.proto",
"protos/health.proto",
"protos/confidential_data_hub.proto",
"protos/remote.proto",
],
false,
)?;

View File

@@ -0,0 +1,47 @@
// Copyright 2024 Kata Contributors
//
// SPDX-License-Identifier: Apache-2.0
//
syntax = "proto3";
package remote;
service Hypervisor {
rpc CreateVM(CreateVMRequest) returns (CreateVMResponse) {}
rpc StartVM(StartVMRequest) returns (StartVMResponse) {}
rpc StopVM(StopVMRequest) returns (StopVMResponse) {}
rpc Version(VersionRequest) returns (VersionResponse) {}
}
message VersionRequest {
string version = 1;
}
message VersionResponse {
string version = 1;
}
message CreateVMRequest {
string id = 1;
map<string, string> annotations = 2;
string networkNamespacePath = 3;
}
message CreateVMResponse {
string agentSocketPath = 1;
}
message StartVMRequest {
string id = 1;
}
message StartVMResponse {
}
message StopVMRequest {
string id = 1;
}
message StopVMResponse {
}

View File

@@ -21,6 +21,10 @@ pub mod oci;
mod serde_config;
pub mod trans;
pub mod types;
pub mod remote;
pub mod remote_ttrpc;
#[cfg(feature = "async")]
pub mod remote_ttrpc_async;
#[cfg(feature = "with-serde")]
pub use serde_config::{

View File

@@ -10,7 +10,6 @@ use std::convert::TryFrom;
use std::path::PathBuf;
use crate::oci as grpc;
use kata_sys_util::spec::parse_json_string;
use oci_spec::runtime as oci;
// translate from interface to ttprc tools
@@ -41,8 +40,9 @@ fn cap_hashset2vec(hash_set: &Option<HashSet<oci::Capability>>) -> Vec<String> {
fn cap_vec2hashset(caps: Vec<String>) -> HashSet<oci::Capability> {
caps.iter()
.map(|cap: &String| {
let cap_str = parse_json_string(cap);
cap_str
// cap might be JSON-encoded
let decoded: &str = serde_json::from_str(cap).unwrap_or(cap);
decoded.strip_prefix("CAP_").unwrap_or(decoded)
.parse::<oci::Capability>()
.unwrap_or_else(|_| panic!("Failed to parse {:?} to Enum Capability", cap))
})
@@ -97,6 +97,8 @@ impl From<oci::LinuxCapabilities> for grpc::LinuxCapabilities {
}
}
// TODO(burgerdev): remove condition here and below after upgrading to oci_spec > 0.7.
#[cfg(target_os = "linux")]
impl From<oci::PosixRlimit> for grpc::POSIXRlimit {
fn from(from: oci::PosixRlimit) -> Self {
grpc::POSIXRlimit {
@@ -118,6 +120,7 @@ impl From<oci::Process> for grpc::Process {
Env: option_vec_to_vec(from.env()),
Cwd: from.cwd().display().to_string(),
Capabilities: from_option(from.capabilities().clone()),
#[cfg(target_os = "linux")]
Rlimits: from_option_vec(from.rlimits().clone()),
NoNewPrivileges: from.no_new_privileges().unwrap_or_default(),
ApparmorProfile: from
@@ -993,6 +996,7 @@ impl From<grpc::Linux> for oci::Linux {
}
}
#[cfg(target_os = "linux")]
impl From<grpc::POSIXRlimit> for oci::PosixRlimit {
fn from(proto: grpc::POSIXRlimit) -> Self {
oci::PosixRlimitBuilder::default()
@@ -1078,6 +1082,8 @@ impl From<grpc::Process> for oci::Process {
} else {
process.set_capabilities(None);
}
#[cfg(target_os = "linux")]
if !from.Rlimits().is_empty() {
process.set_rlimits(Some(
from.Rlimits().iter().cloned().map(|r| r.into()).collect(),
@@ -1238,6 +1244,11 @@ impl From<grpc::LinuxIntelRdt> for oci::LinuxIntelRdt {
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use super::cap_vec2hashset;
use super::oci;
fn from_vec<F: Sized, T: From<F>>(from: Vec<F>) -> Vec<T> {
let mut to: Vec<T> = vec![];
for data in from {
@@ -1289,4 +1300,26 @@ mod tests {
assert_eq!(from.len(), to.len());
assert_eq!(from[0].from, to[0].to);
}
#[test]
fn test_cap_vec2hashset_good() {
let expected: HashSet<oci::Capability> =
vec![oci::Capability::NetAdmin, oci::Capability::Mknod]
.into_iter()
.collect();
let actual = cap_vec2hashset(vec![
"CAP_NET_ADMIN".to_string(),
"\"CAP_MKNOD\"".to_string(),
]);
assert_eq!(expected, actual);
}
#[test]
#[should_panic]
fn test_cap_vec2hashset_bad() {
cap_vec2hashset(vec![
"CAP_DOES_NOT_EXIST".to_string(),
]);
}
}

View File

@@ -1685,8 +1685,11 @@ dependencies = [
"libc",
"logging",
"nix 0.24.3",
"oci-spec",
"path-clean",
"persist",
"protobuf 3.2.0",
"protocols",
"qapi",
"qapi-qmp",
"qapi-spec",
@@ -1706,6 +1709,8 @@ dependencies = [
"thiserror",
"tokio",
"tracing",
"ttrpc",
"ttrpc-codegen",
"vmm-sys-util 0.11.1",
]
@@ -1839,7 +1844,6 @@ version = "0.1.0"
dependencies = [
"anyhow",
"byteorder",
"cgroups-rs",
"chrono",
"common-path",
"fail",
@@ -2994,9 +2998,10 @@ name = "protocols"
version = "0.1.0"
dependencies = [
"async-trait",
"kata-sys-util",
"oci-spec",
"protobuf 3.2.0",
"serde",
"serde_json",
"ttrpc",
"ttrpc-codegen",
]

View File

@@ -83,16 +83,18 @@ LOCALSTATEDIR := /var
CONFIG_FILE = configuration.toml
RUNTIMENAME := virt_container
HYPERVISOR_DB = dragonball
HYPERVISOR_ACRN = acrn
HYPERVISOR_FC = firecracker
HYPERVISOR_QEMU = qemu
HYPERVISOR_CLH = cloud-hypervisor
HYPERVISOR_REMOTE = remote
# When set to true, builds the built-in Dragonball hypervisor
USE_BUILDIN_DB := true
DEFAULT_HYPERVISOR ?= $(HYPERVISOR_DB)
HYPERVISOR ?= $(HYPERVISOR_DB)
##VAR HYPERVISOR=<hypervisor_name> List of hypervisors this build system can generate configuration for.
HYPERVISORS := $(HYPERVISOR_DB) $(HYPERVISOR_ACRN) $(HYPERVISOR_FC) $(HYPERVISOR_QEMU) $(HYPERVISOR_CLH)
HYPERVISORS := $(HYPERVISOR_DB) $(HYPERVISOR_FC) $(HYPERVISOR_QEMU) $(HYPERVISOR_CLH) $(HYPERVISOR_REMOTE)
CLHPATH := $(CLHBINDIR)/$(CLHCMD)
CLHVALIDHYPERVISORPATHS := [\"$(CLHPATH)\"]
@@ -187,8 +189,6 @@ CONFIG_PATHS =
SYSCONFIG_PATHS =
# List of hypervisors known for the current architecture
KNOWN_HYPERVISORS =
# List of hypervisors known for the current architecture
KNOWN_HYPERVISORS =
CONFDIR := $(DEFAULTSDIR)/$(PROJECT_DIR)/runtime-rs
SYSCONFDIR := $(SYSCONFDIR)/$(PROJECT_DIR)
@@ -318,16 +318,33 @@ ifneq (,$(FCCMD))
DEFSTATICRESOURCEMGMT_FC := true
endif
ifeq ($(DEFAULT_HYPERVISOR),$(HYPERVISOR_DB))
ifneq (,$(REMOTE))
KNOWN_HYPERVISORS += $(HYPERVISOR_REMOTE)
CONFIG_FILE_REMOTE = configuration-remote.toml
CONFIG_REMOTE = config/$(CONFIG_FILE_REMOTE)
CONFIG_REMOTE_IN = $(CONFIG_REMOTE).in
CONFIG_PATH_REMOTE = $(abspath $(CONFDIR)/$(CONFIG_FILE_REMOTE))
CONFIG_PATHS += $(CONFIG_PATH_REMOTE)
SYSCONFDIR_REMOTE = $(abspath $(SYSCONFDIR)/$(CONFIG_FILE_REMOTE))
SYSCONFIG_PATHS += $(SYSCONFDIR_REMOTE)
CONFIGS += $(CONFIG_REMOTE)
# remote-specific options (all should be suffixed by "_REMOTE")
DEFSANDBOXCGROUPONLY_REMOTE := false
endif
ifeq ($(HYPERVISOR),$(HYPERVISOR_DB))
DEFAULT_HYPERVISOR_CONFIG = $(CONFIG_FILE_DB)
endif
ifeq ($(DEFAULT_HYPERVISOR),$(HYPERVISOR_QEMU))
ifeq ($(HYPERVISOR),$(HYPERVISOR_QEMU))
DEFAULT_HYPERVISOR_CONFIG = $(CONFIG_FILE_QEMU)
endif
ifeq ($(DEFAULT_HYPERVISOR),$(HYPERVISOR_FC))
ifeq ($(HYPERVISOR),$(HYPERVISOR_FC))
DEFAULT_HYPERVISOR_CONFIG = $(CONFIG_FILE_FC)
endif
ifeq ($(DEFAULT_HYPERVISOR),$(HYPERVISOR_REMOTE))
DEFAULT_HYPERVISOR_CONFIG = $(CONFIG_FILE_REMOTE)
endif
# list of variables the user may wish to override
USER_VARS += ARCH
USER_VARS += BINDIR
@@ -335,8 +352,10 @@ USER_VARS += CONFIG_DB_IN
USER_VARS += CONFIG_FC_IN
USER_VARS += CONFIG_PATH
USER_VARS += CONFIG_QEMU_IN
USER_VARS += CONFIG_REMOTE_IN
USER_VARS += DESTDIR
USER_VARS += DEFAULT_HYPERVISOR
USER_VARS += HYPERVISOR
USER_VARS += USE_BUILDIN_DB
USER_VARS += DBCMD
USER_VARS += DBCTLCMD
USER_VARS += FCCTLCMD
@@ -399,7 +418,6 @@ USER_VARS += SYSCONFDIR
USER_VARS += DEFVCPUS
USER_VARS += DEFVCPUS_QEMU
USER_VARS += DEFMAXVCPUS
USER_VARS += DEFMAXVCPUS_ACRN
USER_VARS += DEFMAXVCPUS_DB
USER_VARS += DEFMAXVCPUS_QEMU
USER_VARS += DEFMEMSZ
@@ -444,6 +462,7 @@ USER_VARS += DEFSANDBOXCGROUPONLY_QEMU
USER_VARS += DEFSANDBOXCGROUPONLY_DB
USER_VARS += DEFSANDBOXCGROUPONLY_FC
USER_VARS += DEFSANDBOXCGROUPONLY_CLH
USER_VARS += DEFSANDBOXCGROUPONLY_REMOTE
USER_VARS += DEFSTATICRESOURCEMGMT_DB
USER_VARS += DEFSTATICRESOURCEMGMT_FC
USER_VARS += DEFSTATICRESOURCEMGMT_CLH
@@ -475,6 +494,11 @@ COMMIT_MSG = $(if $(COMMIT),$(COMMIT),unknown)
EXTRA_RUSTFEATURES :=
# if use dragonball hypervisor, add the feature to build dragonball in runtime
ifeq ($(USE_BUILDIN_DB),true)
EXTRA_RUSTFEATURES += dragonball
endif
ifneq ($(EXTRA_RUSTFEATURES),)
override EXTRA_RUSTFEATURES := --features $(EXTRA_RUSTFEATURES)
endif
@@ -614,7 +638,7 @@ show-summary: show-header
@printf " %s\n" "$(call get_toolchain_version)"
@printf "\n"
@printf "• Hypervisors:\n"
@printf "\tDefault: $(DEFAULT_HYPERVISOR)\n"
@printf "\tDefault: $(HYPERVISOR)\n"
@printf "\tKnown: $(sort $(HYPERVISORS))\n"
@printf "\tAvailable for this architecture: $(sort $(KNOWN_HYPERVISORS))\n"
@printf "\n"
@@ -634,7 +658,7 @@ show-summary: show-header
@printf "\talternate config paths (SYSCONFIG_PATHS) : %s\n"
@printf \
"$(foreach c,$(sort $(SYSCONFIG_PATHS)),$(shell printf "\\t - $(c)\\\n"))"
@printf "\tdefault install path for $(DEFAULT_HYPERVISOR) (CONFIG_PATH) : %s\n" $(abspath $(CONFIG_PATH))
@printf "\tdefault install path for $(HYPERVISOR) (CONFIG_PATH) : %s\n" $(abspath $(CONFIG_PATH))
@printf "\tdefault alternate config path (SYSCONFIG) : %s\n" $(abspath $(SYSCONFIG))
ifneq (,$(findstring $(HYPERVISOR_QEMU),$(KNOWN_HYPERVISORS)))
@printf "\t$(HYPERVISOR_QEMU) hypervisor path (QEMUPATH) : %s\n" $(abspath $(QEMUPATH))
@@ -647,9 +671,6 @@ ifneq (,$(findstring $(HYPERVISOR_CLH),$(KNOWN_HYPERVISORS)))
endif
ifneq (,$(findstring $(HYPERVISOR_FC),$(KNOWN_HYPERVISORS)))
@printf "\t$(HYPERVISOR_FC) hypervisor path (FCPATH) : %s\n" $(abspath $(FCPATH))
endif
ifneq (,$(findstring $(HYPERVISOR_ACRN),$(KNOWN_HYPERVISORS)))
@printf "\t$(HYPERVISOR_ACRN) hypervisor path (ACRNPATH) : %s\n" $(abspath $(ACRNPATH))
endif
@printf "\tassets path (PKGDATADIR) : %s\n" $(abspath $(PKGDATADIR))
@printf "\tshim path (PKGLIBEXECDIR) : %s\n" $(abspath $(PKGLIBEXECDIR))

View File

@@ -20,3 +20,5 @@ CLHCMD := cloud-hypervisor
# firecracker binary (vmm and jailer)
FCCMD := firecracker
FCJAILERCMD := jailer
REMOTE := remote

View File

@@ -1,43 +1,47 @@
# Copyright (c) 2017-2019 Intel Corporation
# Copyright (c) 2021 Adobe Inc.
# Copyright 2024 Kata Contributors
#
# SPDX-License-Identifier: Apache-2.0
#
# XXX: WARNING: this file is auto-generated.
# XXX:
# XXX: Source file: "@CONFIG_ACRN_IN@"
# XXX: Source file: "@CONFIG_REMOTE_IN@"
# XXX: Project:
# XXX: Name: @PROJECT_NAME@
# XXX: Type: @PROJECT_TYPE@
[hypervisor.acrn]
path = "@ACRNPATH@"
ctlpath = "@ACRNCTLPATH@"
kernel = "@KERNELPATH_ACRN@"
image = "@IMAGEPATH@"
# rootfs filesystem type:
# - ext4 (default)
# - xfs
# - erofs
rootfs_type=@DEFROOTFSTYPE@
[hypervisor.remote]
# Default VM information query service unix domain socket, created by cloud-api-adaptor
# Ref: https://github.com/confidential-containers/cloud-api-adaptor/blob/main/src/cloud-api-adaptor/docs/vminfo.md
remote_hypervisor_socket = "/run/peerpod/hypervisor.sock"
# Timeout in seconds for creating a remote hypervisor, 600s(10min) by default
remote_hypervisor_timeout = 600
# Enable confidential guest support.
# Toggling that setting may trigger different hardware features, ranging
# from memory encryption to both memory and CPU-state encryption and integrity.
# The Kata Containers runtime dynamically detects the available feature set and
# aims at enabling the largest possible one, returning an error if none is
# available, or none is supported by the hypervisor.
#
# Known limitations:
# * Does not work by design:
# - CPU Hotplug
# - Memory Hotplug
# - NVDIMM devices
#
# Default false
# confidential_guest = true
# List of valid annotation names for the hypervisor
# Each member of the list is a regular expression, which is the base name
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
enable_annotations = @DEFENABLEANNOTATIONS@
# List of valid annotations values for the hypervisor
# Each member of the list is a path pattern as described by glob(3).
# The default if not set is empty (all annotations rejected.)
# Your distribution recommends: @ACRNVALIDHYPERVISORPATHS@
valid_hypervisor_paths = @ACRNVALIDHYPERVISORPATHS@
# List of valid annotations values for ctlpath
# The default if not set is empty (all annotations rejected.)
# Your distribution recommends: @ACRNVALIDCTLPATHS@
valid_ctlpaths = @ACRNVALIDCTLPATHS@
# Note: Remote hypervisor is only handling the following annotations
enable_annotations = ["machine_type", "default_memory", "default_vcpus"]
# Optional space-separated list of options to pass to the guest kernel.
# For example, use `kernel_params = "vsyscall=emulate"` if you are having
@@ -49,12 +53,20 @@ valid_ctlpaths = @ACRNVALIDCTLPATHS@
# may stop the virtual machine from booting.
# To see the list of default parameters, enable hypervisor debug, create a
# container and look for 'default-kernel-parameters' log entries.
kernel_params = "@KERNELPARAMS@"
# NOTE: kernel_params are not currently passed over in remote hypervisor
# kernel_params = ""
# Path to the firmware.
# If you want that acrn uses the default firmware leave this option empty
# If you want that qemu uses the default firmware leave this option empty
firmware = "@FIRMWAREPATH@"
# Default number of vCPUs per SB/VM:
# unspecified or 0 --> will be set to @DEFVCPUS@
# < 0 --> will be set to the actual number of physical cores
# > 0 <= number of physical cores --> will be set to the specified number
# > number of physical cores --> will be set to the actual number of physical cores
# default_vcpus = 1
# Default maximum number of vCPUs per SB/VM:
# unspecified or == 0 --> will be set to the actual number of physical cores or to the maximum number
# of vCPUs supported by KVM if that number is exceeded
@@ -69,14 +81,15 @@ firmware = "@FIRMWAREPATH@"
# `default_maxvcpus = 8` the memory footprint will be small, but 8 will be the maximum number of
# vCPUs supported by the SB/VM. In general, we recommend that you do not edit this variable,
# unless you know what are you doing.
default_maxvcpus = @DEFMAXVCPUS_ACRN@
# NOTICE: on arm platform with gicv2 interrupt controller, set it to 8.
# default_maxvcpus = @DEFMAXVCPUS@
# Bridges can be used to hot plug devices.
# Limitations:
# * Currently only pci bridges are supported
# * Until 30 devices per bridge can be hot plugged.
# * Until 5 PCI bridges can be cold plugged per VM.
# This limitation could be a bug in the kernel
# This limitation could be a bug in qemu or in the kernel
# Default number of bridges per SB/VM:
# unspecified or 0 --> will be set to @DEFBRIDGES@
# > 1 <= 5 --> will be set to the specified number
@@ -85,27 +98,20 @@ default_bridges = @DEFBRIDGES@
# Default memory size in MiB for SB/VM.
# If unspecified then it will be set @DEFMEMSZ@ MiB.
default_memory = @DEFMEMSZ@
# Block storage driver to be used for the hypervisor in case the container
# rootfs is backed by a block device. ACRN only supports virtio-blk.
block_device_driver = "@DEFBLOCKSTORAGEDRIVER_ACRN@"
# Note: the remote hypervisor uses the peer pod config to determine the memory of the VM
# default_memory = @DEFMEMSZ@
#
# Default memory slots per SB/VM.
# If unspecified then it will be set @DEFMEMSLOTS@.
# This is will determine the times that memory will be hotadded to sandbox/VM.
# Note: the remote hypervisor uses the peer pod config to determine the memory of the VM
#memory_slots = @DEFMEMSLOTS@
# This option changes the default hypervisor and kernel parameters
# to enable debug output where available.
# to enable debug output where available. And Debug also enable the hmp socket.
#
# Default false
#enable_debug = true
# Disable the customizations done in the runtime when it detects
# that it is running on top a VMM. This will result in the runtime
# behaving as it would when running on bare metal.
#
#disable_nesting_checks = true
# If host doesn't support vhost_net, set to true. Thus we won't create vhost fds for nics.
# Default false
#disable_vhost_net = true
# enable_debug = true
# Path to OCI hook binaries in the *guest rootfs*.
# This does not affect host-side hooks which must instead be added to
@@ -127,10 +133,18 @@ block_device_driver = "@DEFBLOCKSTORAGEDRIVER_ACRN@"
# disable applying SELinux on the VMM process (default false)
disable_selinux=@DEFDISABLESELINUX@
# disable applying SELinux on the container process
# If set to false, the type `container_t` is applied to the container process by default.
# Note: To enable guest SELinux, the guest rootfs must be CentOS that is created and built
# with `SELINUX=yes`.
# (default: true)
# Note: The remote hypervisor has a different guest, so currently requires this to be disabled
disable_guest_selinux = true
[agent.@PROJECT_TYPE@]
# If enabled, make the agent display debug-level messages.
# (default: disabled)
#enable_debug = true
# enable_debug = true
# Enable agent tracing.
#
@@ -144,7 +158,7 @@ disable_selinux=@DEFDISABLESELINUX@
# increasing the container shutdown time slightly.
#
# (default: disabled)
#enable_tracing = true
# enable_tracing = true
# Enable debug console.
@@ -154,31 +168,20 @@ disable_selinux=@DEFDISABLESELINUX@
#debug_console_enabled = true
# Agent connection dialing timeout value in seconds
# (default: 45)
dial_timeout = 45
# Confidential Data Hub API timeout value in seconds
# (default: 50)
#cdh_api_timeout = 50
# (default: 30)
#dial_timeout = 30
[runtime]
# If enabled, the runtime will log additional debug messages to the
# system log
# (default: disabled)
#enable_debug = true
# enable_debug = true
#
# Internetworking model
# Determines how the VM should be connected to the
# the container network interface
# Options:
#
# - bridged (Deprecated)
# Uses a linux bridge to interconnect the container interface to
# the VM. Works for most cases except macvlan and ipvlan.
# ***NOTE: This feature has been deprecated with plans to remove this
# feature in the future. Please use other network models listed below.
#
#
# - macvtap
# Used when the Container network interface can be bridged using
# macvtap.
@@ -190,14 +193,29 @@ dial_timeout = 45
# Uses tc filter rules to redirect traffic from the network interface
# provided by plugin to a tap interface connected to the VM.
#
internetworking_model="@DEFNETWORKMODEL_ACRN@"
# Note: The remote hypervisor, uses it's own network, so "none" is required
internetworking_model="none"
name="virt_container"
hypervisor_name="remote"
agent_name="kata"
# disable guest seccomp
# Determines whether container seccomp profiles are passed to the virtual
# machine and applied by the kata agent. If set to true, seccomp is not applied
# within the guest
# (default: true)
disable_guest_seccomp=@DEFDISABLEGUESTSECCOMP@
# Note: The remote hypervisor has a different guest, so currently requires this to be set to true
disable_guest_seccomp=true
# Apply a custom SELinux security policy to the container process inside the VM.
# This is used when you want to apply a type other than the default `container_t`,
# so general users should not uncomment and apply it.
# (format: "user:role:type")
# Note: You cannot specify MCS policy with the label because the sensitivity levels and
# categories are determined automatically by high-level container runtimes such as containerd.
#guest_selinux_label="@DEFGUESTSELINUXLABEL@"
# If enabled, the runtime will create opentracing.io traces and spans.
# (See https://www.jaegertracing.io/docs/getting-started).
@@ -216,11 +234,12 @@ disable_guest_seccomp=@DEFDISABLEGUESTSECCOMP@
# If enabled, the runtime will not create a network namespace for shim and hypervisor processes.
# This option may have some potential impacts to your host. It should only be used when you know what you're doing.
# `disable_new_netns` conflicts with `internetworking_model=bridged` and `internetworking_model=macvtap`. It works only
# `disable_new_netns` conflicts with `internetworking_model=tcfilter` and `internetworking_model=macvtap`. It works only
# with `internetworking_model=none`. The tap device will be in the host network namespace and can connect to a bridge
# (like OVS) directly.
# (default: false)
#disable_new_netns = true
# Note: The remote hypervisor has a different networking model, which requires true
disable_new_netns = false
# if enabled, the runtime will add all the kata processes inside one dedicated cgroup.
# The container cgroups in the host are not created, just one single cgroup per sandbox.
@@ -228,11 +247,43 @@ disable_guest_seccomp=@DEFDISABLEGUESTSECCOMP@
# The sandbox cgroup path is the parent cgroup of a container with the PodSandbox annotation.
# The sandbox cgroup is constrained if there is no container type annotation.
# See: https://pkg.go.dev/github.com/kata-containers/kata-containers/src/runtime/virtcontainers#ContainerType
sandbox_cgroup_only=@DEFSANDBOXCGROUPONLY@
sandbox_cgroup_only=@DEFSANDBOXCGROUPONLY_REMOTE@
# If enabled, the runtime will attempt to determine appropriate sandbox size (memory, CPU) before booting the virtual machine. In
# this case, the runtime will not dynamically update the amount of memory and CPU in the virtual machine. This is generally helpful
# when a hardware architecture or hypervisor solutions is utilized which does not support CPU and/or memory hotplug.
# Compatibility for determining appropriate sandbox (VM) size:
# - When running with pods, sandbox sizing information will only be available if using Kubernetes >= 1.23 and containerd >= 1.6. CRI-O
# does not yet support sandbox sizing annotations.
# - When running single containers using a tool like ctr, container sizing information will be available.
# Note: the remote hypervisor uses the peer pod config to determine the sandbox size, so requires this to be set to true
static_sandbox_resource_mgmt=true
# VFIO Mode
# Determines how VFIO devices should be be presented to the container.
# Options:
#
# - vfio
# Matches behaviour of OCI runtimes (e.g. runc) as much as
# possible. VFIO devices will appear in the container as VFIO
# character devices under /dev/vfio. The exact names may differ
# from the host (they need to match the VM's IOMMU group numbers
# rather than the host's)
#
# - guest-kernel
# This is a Kata-specific behaviour that's useful in certain cases.
# The VFIO device is managed by whatever driver in the VM kernel
# claims it. This means it will appear as one or more device nodes
# or network interfaces depending on the nature of the device.
# Using this mode requires specially built workloads that know how
# to locate the relevant device interfaces within the VM.
#
vfio_mode="@DEFVFIOMODE@"
# If enabled, the runtime will not create Kubernetes emptyDir mounts on the guest filesystem. Instead, emptyDir mounts will
# be created on the host and shared via virtio-fs. This is potentially slower, but allows sharing of files from host to guest.
disable_guest_empty_dir=@DEFDISABLEGUESTEMPTYDIR@
# Note: remote hypervisor has no sharing of emptydir mounts from host to guest
disable_guest_empty_dir=false
# Enabled experimental feature list, format: ["a", "b"].
# Experimental features are features not stable enough for production,
@@ -244,20 +295,3 @@ experimental=@DEFAULTEXPFEATURES@
# If enabled, user can run pprof tools with shim v2 process through kata-monitor.
# (default: false)
# enable_pprof = true
# Indicates the CreateContainer request timeout needed for the workload(s)
# It using guest_pull this includes the time to pull the image inside the guest
# Defaults to @DEFCREATECONTAINERTIMEOUT@ second(s)
# Note: The effective timeout is determined by the lesser of two values: runtime-request-timeout from kubelet config
# (https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/#:~:text=runtime%2Drequest%2Dtimeout) and create_container_timeout.
# In essence, the timeout used for guest pull=runtime-request-timeout<create_container_timeout?runtime-request-timeout:create_container_timeout.
create_container_timeout = @DEFCREATECONTAINERTIMEOUT@
# Base directory of directly attachable network config.
# Network devices for VM-based containers are allowed to be placed in the
# host netns to eliminate as many hops as possible, which is what we
# called a "Directly Attachable Network". The config, set by special CNI
# plugins, is used to tell the Kata containers what devices are attached
# to the hypervisor.
# (default: /run/kata-containers/dans)
dan_conf = "@DEFDANCONF@"

View File

@@ -8,6 +8,8 @@ mod hybrid_vsock;
pub use hybrid_vsock::HybridVsock;
mod vsock;
pub use vsock::Vsock;
mod remote;
pub use remote::Remote;
use std::{
pin::Pin,
@@ -28,6 +30,7 @@ use url::Url;
const VSOCK_SCHEME: &str = "vsock";
const HYBRID_VSOCK_SCHEME: &str = "hvsock";
const REMOTE_SCHEME: &str = "remote";
/// Socket stream
pub enum Stream {
@@ -98,6 +101,7 @@ impl ConnectConfig {
enum SockType {
Vsock(Vsock),
HybridVsock(HybridVsock),
Remote(Remote),
}
#[async_trait]
@@ -114,6 +118,7 @@ pub fn new(address: &str, port: u32) -> Result<Arc<dyn Sock>> {
match parse(address, port).context("parse url")? {
SockType::Vsock(sock) => Ok(Arc::new(sock)),
SockType::HybridVsock(sock) => Ok(Arc::new(sock)),
SockType::Remote(sock) => Ok(Arc::new(sock)),
}
}
@@ -136,6 +141,13 @@ fn parse(address: &str, port: u32) -> Result<SockType> {
let uds = path[0];
Ok(SockType::HybridVsock(HybridVsock::new(uds, port)))
}
REMOTE_SCHEME => {
let path: Vec<&str> = url.path().split(':').collect();
if path.len() != 1 {
return Err(anyhow!("invalid path {:?}", path));
}
Ok(SockType::Remote(Remote::new(path[0].to_string())))
}
_ => Err(anyhow!("Unsupported scheme")),
}
}

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2019-2022 Alibaba Cloud
// Copyright (c) 2019-2022 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use std::{os::unix::prelude::AsRawFd, path::Path};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use tokio::{io::Interest, net::UnixStream};
use super::{ConnectConfig, Sock, Stream};
#[derive(Debug, PartialEq)]
pub struct Remote {
path: String,
}
impl Remote {
pub fn new(path: String) -> Self {
Self { path }
}
}
#[async_trait]
impl Sock for Remote {
async fn connect(&self, config: &ConnectConfig) -> Result<Stream> {
let retry_times = config.reconnect_timeout_ms / config.dial_timeout_ms;
for i in 0..retry_times {
match connect_helper(&self.path).await {
Ok(stream) => {
info!(
sl!(),
"remote connect success on {} current client fd {}",
i,
stream.as_raw_fd()
);
return Ok(Stream::Unix(stream));
}
Err(err) => {
debug!(sl!(), "remote connect on {} err : {:?}", i, err);
tokio::time::sleep(std::time::Duration::from_millis(config.dial_timeout_ms))
.await;
continue;
}
}
}
Err(anyhow!("cannot connect to agent ttrpc server {:?}", config))
}
}
async fn connect_helper(address: &str) -> Result<UnixStream> {
let stream = UnixStream::connect(Path::new(&address))
.await
.context("failed to create UnixAddr")?;
stream
.ready(Interest::READABLE | Interest::WRITABLE)
.await?;
Ok(stream)
}

View File

@@ -42,7 +42,7 @@ pub struct StringUser {
pub additional_gids: Vec<String>,
}
#[derive(PartialEq, Clone, Default)]
#[derive(PartialEq, Clone, Debug, Default)]
pub struct Device {
pub id: String,
pub field_type: String,

View File

@@ -28,12 +28,15 @@ rand = "0.8.4"
path-clean = "1.0.1"
lazy_static = "1.4"
tracing = "0.1.36"
ttrpc = {version = "0.8.1", features = ["async"] }
protobuf = "3.1.0"
dbs-utils = { path = "../../../dragonball/src/dbs_utils" }
kata-sys-util = { path = "../../../libs/kata-sys-util" }
kata-types = { path = "../../../libs/kata-types" }
logging = { path = "../../../libs/logging" }
protocols = { path = "../../../libs/protocols", features = ["async"] }
shim-interface = { path = "../../../libs/shim-interface" }
oci-spec = { version = "0.6.8", features = ["runtime"] }
ch-config = { path = "ch-config", optional = true }
tests_utils = { path = "../../tests/utils" }
@@ -48,7 +51,7 @@ qapi-spec = "0.3.1"
qapi-qmp = "0.14.0"
[target.'cfg(not(target_arch = "s390x"))'.dependencies]
dragonball = { path = "../../../dragonball", features = ["atomic-guest-memory", "virtio-vsock", "hotplug", "virtio-blk", "virtio-net", "virtio-fs", "vhost-net", "dbs-upcall", "virtio-mem", "virtio-balloon", "vhost-user-net", "host-device"] }
dragonball = { path = "../../../dragonball", features = ["atomic-guest-memory", "virtio-vsock", "hotplug", "virtio-blk", "virtio-net", "virtio-fs", "vhost-net", "dbs-upcall", "virtio-mem", "virtio-balloon", "vhost-user-net", "host-device"], optional = true }
dbs-utils = { path = "../../../dragonball/src/dbs_utils" }
hyperlocal = "0.8.0"
hyper = {version = "0.14.18", features = ["client"]}
@@ -56,6 +59,7 @@ hyper = {version = "0.14.18", features = ["client"]}
[features]
default = []
dragonball = ["dep:dragonball"]
# Feature is not yet complete, so not enabled by default.
# See https://github.com/kata-containers/kata-containers/issues/6264.
cloud-hypervisor = ["ch-config"]
@@ -68,3 +72,7 @@ hypervisor = { path = ".", features = ["cloud-hypervisor"] }
test-utils = { path = "../../../libs/test-utils" }
serial_test = "2.0.0"
[build-dependencies]
ttrpc-codegen = "0.4.2"

View File

@@ -16,7 +16,6 @@ use persist::sandbox_persist::Persist;
use std::collections::HashMap;
use std::os::unix::net::UnixStream;
use tokio::sync::watch::{channel, Receiver, Sender};
use tokio::sync::Mutex;
use tokio::task::JoinHandle;
use tokio::{process::Child, sync::mpsc};
@@ -79,13 +78,12 @@ pub struct CloudHypervisorInner {
pub(crate) _guest_memory_block_size_mb: u32,
pub(crate) exit_notify: Option<mpsc::Sender<i32>>,
pub(crate) exit_waiter: Mutex<(mpsc::Receiver<i32>, i32)>,
}
const CH_DEFAULT_TIMEOUT_SECS: u32 = 10;
impl CloudHypervisorInner {
pub fn new() -> Self {
pub fn new(exit_notify: Option<mpsc::Sender<i32>>) -> Self {
let mut capabilities = Capabilities::new();
capabilities.set(
CapabilityBits::BlockDeviceSupport
@@ -95,7 +93,6 @@ impl CloudHypervisorInner {
);
let (tx, rx) = channel(true);
let (exit_notify, exit_waiter) = mpsc::channel(1);
Self {
api_socket: None,
@@ -122,8 +119,7 @@ impl CloudHypervisorInner {
ch_features: None,
_guest_memory_block_size_mb: 0,
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
exit_notify,
}
}
@@ -138,14 +134,14 @@ impl CloudHypervisorInner {
impl Default for CloudHypervisorInner {
fn default() -> Self {
Self::new()
Self::new(None)
}
}
#[async_trait]
impl Persist for CloudHypervisorInner {
type State = HypervisorState;
type ConstructorArgs = ();
type ConstructorArgs = mpsc::Sender<i32>;
// Return a state object that will be saved by the caller.
async fn save(&self) -> Result<Self::State> {
@@ -166,11 +162,10 @@ impl Persist for CloudHypervisorInner {
// Set the hypervisor state to the specified state
async fn restore(
_hypervisor_args: Self::ConstructorArgs,
exit_notify: mpsc::Sender<i32>,
hypervisor_state: Self::State,
) -> Result<Self> {
let (tx, rx) = channel(true);
let (exit_notify, exit_waiter) = mpsc::channel(1);
let mut ch = Self {
config: Some(hypervisor_state.config),
@@ -190,7 +185,6 @@ impl Persist for CloudHypervisorInner {
jailer_root: String::default(),
ch_features: None,
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
..Default::default()
};
@@ -207,7 +201,9 @@ mod tests {
#[actix_rt::test]
async fn test_save_clh() {
let mut clh = CloudHypervisorInner::new();
let (exit_notify, _exit_waiter) = mpsc::channel(1);
let mut clh = CloudHypervisorInner::new(Some(exit_notify.clone()));
clh.id = String::from("123456");
clh.netns = Some(String::from("/var/run/netns/testnet"));
clh.vm_path = String::from("/opt/kata/bin/cloud-hypervisor");
@@ -229,7 +225,7 @@ mod tests {
assert!(!state.jailed);
assert_eq!(state.hypervisor_type, HYPERVISOR_NAME_CH.to_string());
let clh = CloudHypervisorInner::restore((), state.clone())
let clh = CloudHypervisorInner::restore(exit_notify, state.clone())
.await
.unwrap();
assert_eq!(clh.id, state.id);

View File

@@ -19,7 +19,6 @@ use ch_config::ch_api::{
};
use ch_config::{guest_protection_is_tdx, NamedHypervisorConfig, VmConfig};
use core::future::poll_fn;
use futures::executor::block_on;
use futures::future::join_all;
use kata_sys_util::protection::{available_guest_protection, GuestProtection};
use kata_types::capabilities::{Capabilities, CapabilityBits};
@@ -640,7 +639,7 @@ impl CloudHypervisorInner {
Ok(())
}
pub(crate) fn stop_vm(&mut self) -> Result<()> {
pub(crate) async fn stop_vm(&mut self) -> Result<()> {
// If the container workload exits, this method gets called. However,
// the container manager always makes a ShutdownContainer request,
// which results in this method being called potentially a second
@@ -652,19 +651,14 @@ impl CloudHypervisorInner {
self.state = VmmState::NotReady;
block_on(self.cloud_hypervisor_shutdown()).map_err(|e| anyhow!(e))?;
self.cloud_hypervisor_shutdown().await?;
Ok(())
}
#[allow(dead_code)]
pub(crate) async fn wait_vm(&self) -> Result<i32> {
debug!(sl!(), "Waiting CH vmm");
let mut waiter = self.exit_waiter.lock().await;
if let Some(exitcode) = waiter.0.recv().await {
waiter.1 = exitcode;
}
Ok(waiter.1)
Ok(0)
}
pub(crate) fn pause_vm(&self) -> Result<()> {

View File

@@ -11,8 +11,9 @@ use async_trait::async_trait;
use kata_types::capabilities::{Capabilities, CapabilityBits};
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
use persist::sandbox_persist::Persist;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio::sync::{mpsc, Mutex, RwLock};
// Convenience macro to obtain the scope logger
#[macro_export]
@@ -29,15 +30,19 @@ mod utils;
use inner::CloudHypervisorInner;
#[derive(Debug, Default, Clone)]
#[derive(Debug)]
pub struct CloudHypervisor {
inner: Arc<RwLock<CloudHypervisorInner>>,
exit_waiter: Mutex<(mpsc::Receiver<i32>, i32)>,
}
impl CloudHypervisor {
pub fn new() -> Self {
let (exit_notify, exit_waiter) = mpsc::channel(1);
Self {
inner: Arc::new(RwLock::new(CloudHypervisorInner::new())),
inner: Arc::new(RwLock::new(CloudHypervisorInner::new(Some(exit_notify)))),
exit_waiter: Mutex::new((exit_waiter, 0)),
}
}
@@ -47,9 +52,20 @@ impl CloudHypervisor {
}
}
impl Default for CloudHypervisor {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl Hypervisor for CloudHypervisor {
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()> {
async fn prepare_vm(
&self,
id: &str,
netns: Option<String>,
_annotations: &HashMap<String, String>,
) -> Result<()> {
let mut inner = self.inner.write().await;
inner.prepare_vm(id, netns).await
}
@@ -61,12 +77,17 @@ impl Hypervisor for CloudHypervisor {
async fn stop_vm(&self) -> Result<()> {
let mut inner = self.inner.write().await;
inner.stop_vm()
inner.stop_vm().await
}
async fn wait_vm(&self) -> Result<i32> {
let inner = self.inner.read().await;
inner.wait_vm().await
debug!(sl!(), "Waiting CH vmm");
let mut waiter = self.exit_waiter.lock().await;
if let Some(exitcode) = waiter.0.recv().await {
waiter.1 = exitcode;
}
Ok(waiter.1)
}
async fn pause_vm(&self) -> Result<()> {
@@ -204,12 +225,15 @@ impl Persist for CloudHypervisor {
}
async fn restore(
hypervisor_args: Self::ConstructorArgs,
_hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let inner = CloudHypervisorInner::restore(hypervisor_args, hypervisor_state).await?;
let (exit_notify, exit_waiter) = mpsc::channel(1);
let inner = CloudHypervisorInner::restore(exit_notify, hypervisor_state).await?;
Ok(Self {
inner: Arc::new(RwLock::new(inner)),
exit_waiter: Mutex::new((exit_waiter, 0)),
})
}
}

View File

@@ -115,12 +115,12 @@ pub enum VfioDeviceType {
Mediated,
}
// DeviceVendor represents a PCI device's device id and vendor id
// DeviceVendor: (device, vendor)
// DeviceVendorClass represents a PCI device's deviceID, vendorID and classID
// DeviceVendorClass: (device, vendor, class)
#[derive(Clone, Debug)]
pub struct DeviceVendor(String, String);
pub struct DeviceVendorClass(String, String, String);
impl DeviceVendor {
impl DeviceVendorClass {
pub fn get_device_vendor(&self) -> Result<(u32, u32)> {
// default value is 0 when vendor_id or device_id is empty
if self.0.is_empty() || self.1.is_empty() {
@@ -142,6 +142,10 @@ impl DeviceVendor {
Ok((device, vendor))
}
pub fn get_vendor_class_id(&self) -> Result<(&str, &str)> {
Ok((&self.1, &self.2))
}
pub fn get_device_vendor_id(&self) -> Result<u32> {
let (device, vendor) = self
.get_device_vendor()
@@ -163,8 +167,8 @@ pub struct HostDevice {
/// PCI device information (BDF): "bus:slot:function"
pub bus_slot_func: String,
/// device_vendor: device id and vendor id
pub device_vendor: Option<DeviceVendor>,
/// device_vendor_class: (device, vendor, class)
pub device_vendor_class: Option<DeviceVendorClass>,
/// type of vfio device
pub vfio_type: VfioDeviceType,
@@ -336,13 +340,14 @@ impl VfioDevice {
}
// read vendor and deviceor from /sys/bus/pci/devices/BDF/X
fn get_vfio_device_vendor(&self, bdf: &str) -> Result<DeviceVendor> {
fn get_vfio_device_vendor_class(&self, bdf: &str) -> Result<DeviceVendorClass> {
let device =
get_device_property(bdf, "device").context("get device from syspath failed")?;
let vendor =
get_device_property(bdf, "vendor").context("get vendor from syspath failed")?;
let class = get_device_property(bdf, "class").context("get class from syspath failed")?;
Ok(DeviceVendor(device, vendor))
Ok(DeviceVendorClass(device, vendor, class))
}
fn set_vfio_config(
@@ -356,13 +361,13 @@ impl VfioDevice {
// It's safe as BDF really exists.
let dev_bdf = vfio_dev_details.0.unwrap();
let dev_vendor = self
.get_vfio_device_vendor(&dev_bdf)
let dev_vendor_class = self
.get_vfio_device_vendor_class(&dev_bdf)
.context("get property device and vendor failed")?;
let vfio_dev = HostDevice {
bus_slot_func: dev_bdf.clone(),
device_vendor: Some(dev_vendor),
device_vendor_class: Some(dev_vendor_class),
sysfs_path: vfio_dev_details.1,
vfio_type: vfio_dev_details.2,
..Default::default()

View File

@@ -20,6 +20,8 @@ use self::topology::PCIeTopology;
pub mod device_manager;
pub mod driver;
pub mod pci_path;
mod tap;
pub use self::tap::{Error as TapError, Tap};
pub mod topology;
pub mod util;

View File

@@ -0,0 +1,264 @@
// Copyright 2024 Kata Contributors
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.
use std::ffi::CStr;
use std::fs::File;
use std::io::{Error as IoError, Read, Result as IoResult, Write};
use std::net::UdpSocket;
use std::os::raw::*;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use libc::ifreq;
use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
use vmm_sys_util::{ioctl_ioc_nr, ioctl_iow_nr};
// As defined in the Linux UAPI:
// https://elixir.bootlin.com/linux/v4.17/source/include/uapi/linux/if.h#L33
pub(crate) const IFACE_NAME_MAX_LEN: usize = 16;
/// List of errors the tap implementation can throw.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Failed to create a socket.
#[error("cannot create socket. {0}")]
CreateSocket(#[source] IoError),
/// Unable to create tap interface.
#[error("cannot create tap device. {0}")]
CreateTap(IoError),
/// Invalid interface name.
#[error("invalid network interface name")]
InvalidIfname,
/// ioctl failed.
#[error("failure while issue Tap ioctl command. {0}")]
IoctlError(#[source] IoError),
/// Couldn't open /dev/net/tun.
#[error("cannot open tap device. {0}")]
OpenTun(#[source] IoError),
}
pub type Result<T> = ::std::result::Result<T, Error>;
const TUNTAP: ::std::os::raw::c_uint = 84;
ioctl_iow_nr!(TUNSETIFF, TUNTAP, 202, ::std::os::raw::c_int);
ioctl_iow_nr!(TUNSETOFFLOAD, TUNTAP, 208, ::std::os::raw::c_uint);
ioctl_iow_nr!(TUNSETVNETHDRSZ, TUNTAP, 216, ::std::os::raw::c_int);
/// Handle for a network tap interface.
///
/// For now, this simply wraps the file descriptor for the tap device so methods
/// can run ioctls on the interface. The tap interface fd will be closed when
/// Tap goes out of scope, and the kernel will clean up the interface automatically.
#[derive(Debug)]
pub struct Tap {
/// tap device file handle
pub tap_file: File,
pub(crate) if_name: [std::os::raw::c_char; IFACE_NAME_MAX_LEN],
pub(crate) if_flags: std::os::raw::c_short,
}
impl PartialEq for Tap {
fn eq(&self, other: &Tap) -> bool {
self.if_name == other.if_name
}
}
fn create_socket() -> Result<UdpSocket> {
// This is safe since we check the return value.
let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
if sock < 0 {
return Err(Error::CreateSocket(IoError::last_os_error()));
}
// This is safe; nothing else will use or hold onto the raw sock fd.
Ok(unsafe { UdpSocket::from_raw_fd(sock) })
}
// Returns an array representing the contents of a null-terminated C string
// containing if_name.
pub fn build_terminated_if_name(if_name: &str) -> Result<[c_char; IFACE_NAME_MAX_LEN]> {
// Convert the string slice to bytes, and shadow the variable,
// since we no longer need the &str version.
let if_name_bytes = if_name.as_bytes();
if if_name_bytes.len() >= IFACE_NAME_MAX_LEN {
return Err(Error::InvalidIfname);
}
let mut terminated_if_name = [0 as c_char; IFACE_NAME_MAX_LEN];
for (i, &byte) in if_name_bytes.iter().enumerate() {
terminated_if_name[i] = byte as c_char;
}
// 0 is the null terminator for c_char type
terminated_if_name[if_name_bytes.len()] = 0 as c_char;
Ok(terminated_if_name)
}
impl Tap {
/// Create a TUN/TAP device given the interface name.
/// # Arguments
///
/// * `if_name` - the name of the interface.
pub fn open_named(if_name: &str, multi_vq: bool) -> Result<Tap> {
let terminated_if_name = build_terminated_if_name(if_name)?;
// Initialize an `ifreq` structure with the given interface name
// and configure its flags for setting up a network interface.
let mut ifr = ifreq {
ifr_name: terminated_if_name,
ifr_ifru: libc::__c_anonymous_ifr_ifru {
ifru_flags: (libc::IFF_TAP
| libc::IFF_NO_PI
| libc::IFF_VNET_HDR
| if multi_vq { libc::IFF_MULTI_QUEUE } else { 0 })
as c_short,
},
};
Tap::create_tap_with_ifreq(&mut ifr)
}
fn create_tap_with_ifreq(ifr: &mut ifreq) -> Result<Tap> {
let fd = unsafe {
let dev_net_tun = CStr::from_bytes_with_nul(b"/dev/net/tun\0").unwrap_or_else(|_| {
unreachable!("The string is guaranteed to be null-terminated and valid.")
});
// Open calls are safe because we use a CStr, which guarantees a
// constant null-terminated string.
libc::open(
dev_net_tun.as_ptr(),
libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
)
};
if fd < 0 {
return Err(Error::OpenTun(IoError::last_os_error()));
}
// We just checked that the fd is valid.
let tuntap = unsafe { File::from_raw_fd(fd) };
// ioctl is safe since we call it with a valid tap fd and check the return
// value.
let ret = unsafe { ioctl_with_mut_ref(&tuntap, TUNSETIFF(), ifr) };
if ret < 0 {
return Err(Error::CreateTap(IoError::last_os_error()));
}
Ok(Tap {
tap_file: tuntap,
if_name: ifr.ifr_name,
// This is safe since ifru_flags was correctly initialized earlier.
if_flags: unsafe { ifr.ifr_ifru.ifru_flags },
})
}
/// Change the origin tap into multiqueue taps.
pub fn into_mq_taps(self, vq_pairs: usize) -> Result<Vec<Tap>> {
let mut taps = Vec::with_capacity(vq_pairs);
if vq_pairs == 1 {
// vq_pairs cannot be less than 1, so only handle the case where it equals 1.
taps.push(self);
return Ok(taps);
}
// Add other socket into the origin tap interface.
for _ in 0..vq_pairs - 1 {
let mut ifr: ifreq = self.get_ifreq();
let tap = Tap::create_tap_with_ifreq(&mut ifr)?;
tap.enable()?;
taps.push(tap);
}
taps.insert(0, self);
Ok(taps)
}
/// Set the offload flags for the tap interface.
pub fn set_offload(&self, flags: c_uint) -> Result<()> {
// ioctl is safe. Called with a valid tap fd, and we check the return.
let ret = unsafe { ioctl_with_val(&self.tap_file, TUNSETOFFLOAD(), c_ulong::from(flags)) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
}
/// Enable the tap interface.
pub fn enable(&self) -> Result<()> {
let sock = create_socket()?;
let mut ifr = self.get_ifreq();
ifr.ifr_ifru.ifru_flags = (libc::IFF_UP | libc::IFF_RUNNING) as i16;
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret = unsafe { ioctl_with_ref(&sock, c_ulong::from(libc::SIOCSIFFLAGS), &ifr) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
}
/// Set the size of the vnet hdr.
pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
// ioctl is safe. Called with a valid tap fd, and we check the return.
let ret = unsafe { ioctl_with_ref(&self.tap_file, TUNSETVNETHDRSZ(), &size) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
}
fn get_ifreq(&self) -> ifreq {
let mut ifr_name = [0 as c_char; libc::IFNAMSIZ];
ifr_name[..self.if_name.len()].copy_from_slice(&self.if_name);
// Return an `ifreq` structure with the interface name and flags.
ifreq {
ifr_name,
ifr_ifru: libc::__c_anonymous_ifr_ifru {
ifru_flags: self.if_flags,
},
}
}
/// Get the origin flags when interface was created.
pub fn if_flags(&self) -> u32 {
self.if_flags as u32
}
}
impl Read for Tap {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.tap_file.read(buf)
}
}
impl Write for Tap {
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
self.tap_file.write(buf)
}
fn flush(&mut self) -> IoResult<()> {
Ok(())
}
}
impl AsRawFd for Tap {
fn as_raw_fd(&self) -> RawFd {
self.tap_file.as_raw_fd()
}
}

View File

@@ -147,8 +147,8 @@ impl DragonballInner {
// And the the first one is Primary device.
// safe here, devices is not empty.
let primary_device = device.devices.first_mut().unwrap();
let vendor_device_id = if let Some(vd) = primary_device.device_vendor.as_ref() {
vd.get_device_vendor_id()?
let vendor_device_id = if let Some(vdc) = primary_device.device_vendor_class.as_ref() {
vdc.get_device_vendor_id()?
} else {
0
};

View File

@@ -12,6 +12,7 @@ use inner::DragonballInner;
use persist::sandbox_persist::Persist;
pub mod vmm_instance;
use std::collections::HashMap;
use std::sync::Arc;
use anyhow::{Context, Result};
@@ -69,7 +70,12 @@ impl Dragonball {
#[async_trait]
impl Hypervisor for Dragonball {
#[instrument]
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()> {
async fn prepare_vm(
&self,
id: &str,
netns: Option<String>,
_annotations: &HashMap<String, String>,
) -> Result<()> {
let mut inner = self.inner.write().await;
inner.prepare_vm(id, netns).await
}

View File

@@ -107,6 +107,11 @@ impl FcInner {
.get_resource(&self.config.boot_info.image, FC_ROOT_FS)
.context("get resource ROOTFS")?;
let body_config: String = json!({
"mem_size_mib": self.config.memory_info.default_memory,
"vcpu_count": self.config.cpu_info.default_vcpus,
})
.to_string();
let body_kernel: String = json!({
"kernel_image_path": kernel,
"boot_args": parameters,
@@ -124,6 +129,8 @@ impl FcInner {
info!(sl(), "Before first request");
self.request_with_retry(Method::PUT, "/boot-source", body_kernel)
.await?;
self.request_with_retry(Method::PUT, "/machine-config", body_config)
.await?;
self.request_with_retry(Method::PUT, "/drives/rootfs", body_rootfs)
.await?;

View File

@@ -46,14 +46,12 @@ pub struct FcInner {
pub(crate) capabilities: Capabilities,
pub(crate) fc_process: Mutex<Option<Child>>,
pub(crate) exit_notify: Option<mpsc::Sender<()>>,
pub(crate) exit_waiter: Mutex<(mpsc::Receiver<()>, i32)>,
}
impl FcInner {
pub fn new() -> FcInner {
pub fn new(exit_notify: mpsc::Sender<()>) -> FcInner {
let mut capabilities = Capabilities::new();
capabilities.set(CapabilityBits::BlockDeviceSupport);
let (exit_notify, exit_waiter) = mpsc::channel(1);
FcInner {
id: String::default(),
@@ -71,7 +69,6 @@ impl FcInner {
capabilities,
fc_process: Mutex::new(None),
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
}
}
@@ -124,11 +121,10 @@ impl FcInner {
let mut child = cmd.stderr(Stdio::piped()).spawn()?;
let stderr = child.stderr.take().unwrap();
let exit_notify: mpsc::Sender<()> = self
let exit_notify = self
.exit_notify
.take()
.ok_or_else(|| anyhow!("no exit notify"))?;
tokio::spawn(log_fc_stderr(stderr, exit_notify));
match child.id() {
@@ -216,7 +212,7 @@ async fn log_fc_stderr(stderr: ChildStderr, exit_notify: mpsc::Sender<()>) -> Re
#[async_trait]
impl Persist for FcInner {
type State = HypervisorState;
type ConstructorArgs = ();
type ConstructorArgs = mpsc::Sender<()>;
async fn save(&self) -> Result<Self::State> {
Ok(HypervisorState {
@@ -231,12 +227,7 @@ impl Persist for FcInner {
..Default::default()
})
}
async fn restore(
_hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let (exit_notify, exit_waiter) = mpsc::channel(1);
async fn restore(exit_notify: mpsc::Sender<()>, hypervisor_state: Self::State) -> Result<Self> {
Ok(FcInner {
id: hypervisor_state.id,
asock_path: String::default(),
@@ -253,7 +244,6 @@ impl Persist for FcInner {
capabilities: Capabilities::new(),
fc_process: Mutex::new(None),
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
})
}
}

View File

@@ -102,21 +102,14 @@ impl FcInner {
}
pub(crate) async fn wait_vm(&self) -> Result<i32> {
debug!(sl(), "Wait fc sandbox");
let mut waiter = self.exit_waiter.lock().await;
//wait until the fc process exited.
waiter.0.recv().await;
let mut fc_process = self.fc_process.lock().await;
if let Some(mut fc_process) = fc_process.take() {
if let Ok(status) = fc_process.wait().await {
waiter.1 = status.code().unwrap_or(0);
}
let status = fc_process.wait().await?;
Ok(status.code().unwrap_or(0))
} else {
Err(anyhow!("the process has been reaped"))
}
Ok(waiter.1)
}
pub(crate) fn pause_vm(&self) -> Result<()> {

View File

@@ -18,12 +18,16 @@ use inner::FcInner;
use kata_types::capabilities::Capabilities;
use kata_types::capabilities::CapabilityBits;
use persist::sandbox_persist::Persist;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::mpsc;
use tokio::sync::Mutex;
use tokio::sync::RwLock;
#[derive(Debug)]
pub struct Firecracker {
inner: Arc<RwLock<FcInner>>,
exit_waiter: Mutex<(mpsc::Receiver<()>, i32)>,
}
// Convenience function to set the scope.
@@ -39,8 +43,11 @@ impl Default for Firecracker {
impl Firecracker {
pub fn new() -> Self {
let (exit_notify, exit_waiter) = mpsc::channel(1);
Self {
inner: Arc::new(RwLock::new(FcInner::new())),
inner: Arc::new(RwLock::new(FcInner::new(exit_notify))),
exit_waiter: Mutex::new((exit_waiter, 0)),
}
}
@@ -52,7 +59,12 @@ impl Firecracker {
#[async_trait]
impl Hypervisor for Firecracker {
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()> {
async fn prepare_vm(
&self,
id: &str,
netns: Option<String>,
_annotations: &HashMap<String, String>,
) -> Result<()> {
let mut inner = self.inner.write().await;
inner.prepare_vm(id, netns).await
}
@@ -68,8 +80,18 @@ impl Hypervisor for Firecracker {
}
async fn wait_vm(&self) -> Result<i32> {
debug!(sl(), "Wait fc sandbox");
let mut waiter = self.exit_waiter.lock().await;
//wait until the fc process exited.
waiter.0.recv().await;
let inner = self.inner.read().await;
inner.wait_vm().await
if let Ok(exit_code) = inner.wait_vm().await {
waiter.1 = exit_code;
}
Ok(waiter.1)
}
async fn pause_vm(&self) -> Result<()> {
@@ -209,12 +231,15 @@ impl Persist for Firecracker {
}
/// Restore a component from a specified state.
async fn restore(
hypervisor_args: Self::ConstructorArgs,
_hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let inner = FcInner::restore(hypervisor_args, hypervisor_state).await?;
let (exit_notify, exit_waiter) = mpsc::channel(1);
let inner = FcInner::restore(exit_notify, hypervisor_state).await?;
Ok(Self {
inner: Arc::new(RwLock::new(inner)),
exit_waiter: Mutex::new((exit_waiter, 0)),
})
}
}

View File

@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct HypervisorState {
// Type of hypervisor, E.g. dragonball/qemu/firecracker/acrn.
// Type of hypervisor, E.g. dragonball/qemu/firecracker.
pub hypervisor_type: String,
pub pid: Option<i32>,
pub uuid: String,

View File

@@ -13,12 +13,13 @@ pub mod device;
pub mod hypervisor_persist;
pub use device::driver::*;
use device::DeviceType;
#[cfg(not(target_arch = "s390x"))]
#[cfg(all(feature = "dragonball", not(target_arch = "s390x")))]
pub mod dragonball;
#[cfg(not(target_arch = "s390x"))]
pub mod firecracker;
mod kernel_param;
pub mod qemu;
pub mod remote;
pub use kernel_param::Param;
pub mod utils;
use std::collections::HashMap;
@@ -53,17 +54,20 @@ const VM_ROOTFS_FILESYSTEM_EROFS: &str = "erofs";
// /dev/hugepages will be the mount point
// mkdir -p /dev/hugepages
// mount -t hugetlbfs none /dev/hugepages
#[cfg(not(target_arch = "s390x"))]
const DEV_HUGEPAGES: &str = "/dev/hugepages";
pub const HUGETLBFS: &str = "hugetlbfs";
#[cfg(not(target_arch = "s390x"))]
// Constants required for Dragonball VMM when enabled and not on s390x.
// Not needed when the built-in VMM is not used.
#[cfg(all(feature = "dragonball", not(target_arch = "s390x")))]
const DEV_HUGEPAGES: &str = "/dev/hugepages";
#[cfg(all(feature = "dragonball", not(target_arch = "s390x")))]
const SHMEM: &str = "shmem";
#[cfg(not(target_arch = "s390x"))]
#[cfg(all(feature = "dragonball", not(target_arch = "s390x")))]
const HUGE_SHMEM: &str = "hugeshmem";
pub const HYPERVISOR_DRAGONBALL: &str = "dragonball";
pub const HYPERVISOR_QEMU: &str = "qemu";
pub const HYPERVISOR_FIRECRACKER: &str = "firecracker";
pub const HYPERVISOR_REMOTE: &str = "remote";
pub const DEFAULT_HYBRID_VSOCK_NAME: &str = "kata.hvsock";
pub const JAILER_ROOT: &str = "root";
@@ -93,7 +97,12 @@ pub struct MemoryConfig {
#[async_trait]
pub trait Hypervisor: std::fmt::Debug + Send + Sync {
// vm manager
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()>;
async fn prepare_vm(
&self,
id: &str,
netns: Option<String>,
annotations: &HashMap<String, String>,
) -> Result<()>;
async fn start_vm(&self, timeout: i32) -> Result<()>;
async fn stop_vm(&self) -> Result<()>;
async fn wait_vm(&self) -> Result<i32>;

View File

@@ -8,6 +8,7 @@ use crate::{kernel_param::KernelParams, Address, HypervisorConfig};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use kata_types::config::hypervisor::VIRTIO_SCSI;
use std::collections::HashMap;
use std::fmt::Display;
use std::fs::{read_to_string, File};
@@ -49,7 +50,7 @@ trait ToQemuParams: Send + Sync {
async fn qemu_params(&self) -> Result<Vec<String>>;
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
enum VirtioBusType {
Pci,
Ccw,
@@ -70,6 +71,14 @@ impl Display for VirtioBusType {
}
}
fn bus_type(config: &HypervisorConfig) -> VirtioBusType {
if config.machine_info.machine_type.contains("-ccw-") {
VirtioBusType::Ccw
} else {
VirtioBusType::Pci
}
}
// Conventions used in qemu command line generation
// ================================================
//
@@ -975,7 +984,7 @@ fn format_fds(files: &[File]) -> String {
}
#[derive(Debug)]
struct Netdev {
pub struct Netdev {
id: String,
// File descriptors for vhost multi-queue support.
@@ -1013,6 +1022,18 @@ impl Netdev {
self.disable_vhost_net = disable_vhost_net;
self
}
pub fn get_id(&self) -> &String {
&self.id
}
pub fn get_fds(&self) -> &Vec<File> {
&self.fds["fds"]
}
pub fn get_vhostfds(&self) -> &Vec<File> {
&self.fds["vhostfds"]
}
}
#[async_trait]
@@ -1081,6 +1102,26 @@ impl DeviceVirtioNet {
self.iommu_platform = iommu_platform;
self
}
pub fn get_netdev_id(&self) -> &String {
&self.netdev_id
}
pub fn get_device_driver(&self) -> &String {
&self.device_driver
}
pub fn get_mac_addr(&self) -> String {
format!("{:?}", self.mac_address)
}
pub fn get_num_queues(&self) -> u32 {
self.num_queues
}
pub fn get_disable_modern(&self) -> bool {
self.disable_modern
}
}
#[async_trait]
@@ -1290,6 +1331,74 @@ impl ToQemuParams for DeviceIntelIommu {
}
}
#[derive(Debug)]
struct DevicePciBridge {
driver: String,
bus: String,
id: String,
chassis_nr: u32,
shpc: bool,
addr: u32,
io_reserve: String,
mem_reserve: String,
pref64_reserve: String,
}
impl DevicePciBridge {
fn new(config: &HypervisorConfig, bridge_idx: u32) -> DevicePciBridge {
DevicePciBridge {
// The go runtime doesn't support bridges other than PCI although
// PCIe should also be available. Stick with the legacy behaviour
// of ignoring PCIe since it's not clear to me how to decide
// between the two.
driver: "pci-bridge".to_owned(),
bus: match config.machine_info.machine_type.as_str() {
"q35" | "virt" => "pcie.0",
_ => "pci.0",
}
.to_owned(),
id: format!("pci-bridge-{}", bridge_idx),
// Each bridge is required to be assigned a unique chassis id > 0.
chassis_nr: bridge_idx + 1,
shpc: false,
// 2 is documented by the go runtime as the first slot available
// for a bridge (on x86_64)
// (https://github.com/kata-containers/kata-containers/blob/99730256a2899c82d111400024621519d17ea15d/src/runtime/virtcontainers/qemu_arch_base.go#L212)
addr: 2 + bridge_idx,
// Values taken from the go runtime implementation which comments
// the choices as follows:
// Certain guest BIOS versions think !SHPC means no hotplug, and
// won't reserve the IO and memory windows that will be needed for
// devices added underneath this bridge. This will only break for
// certain combinations of exact qemu, BIOS and guest kernel
// versions, but for consistency, just hint the usual default
// windows for a bridge (as the BIOS would use with SHPC) so that
// we can do ACPI hotplug.
// (https://github.com/kata-containers/kata-containers/blob/99730256a2899c82d111400024621519d17ea15d/src/runtime/virtcontainers/qemu.go#L2474)
io_reserve: "4k".to_owned(),
mem_reserve: "1m".to_owned(),
pref64_reserve: "1m".to_owned(),
}
}
}
#[async_trait]
impl ToQemuParams for DevicePciBridge {
async fn qemu_params(&self) -> Result<Vec<String>> {
let mut params = Vec::new();
params.push(self.driver.clone());
params.push(format!("bus={}", self.bus));
params.push(format!("id={}", self.id));
params.push(format!("chassis_nr={}", self.chassis_nr));
params.push(format!("shpc={}", if self.shpc { "on" } else { "off" }));
params.push(format!("addr={}", self.addr));
params.push(format!("io-reserve={}", self.io_reserve));
params.push(format!("mem-reserve={}", self.mem_reserve));
params.push(format!("pref64-reserve={}", self.pref64_reserve));
Ok(vec!["-device".to_owned(), params.join(",")])
}
}
// Qemu provides methods and types for managing QEMU instances.
// To manage a qemu instance after it has been launched you need
// to pass the -qmp option during launch requesting the qemu instance
@@ -1405,6 +1514,66 @@ impl ToQemuParams for QmpSocket {
}
}
#[derive(Debug)]
struct DeviceVirtioScsi {
bus_type: VirtioBusType,
id: String,
disable_modern: bool,
iothread: String,
}
impl DeviceVirtioScsi {
fn new(id: &str, disable_modern: bool, bus_type: VirtioBusType) -> Self {
DeviceVirtioScsi {
bus_type,
id: id.to_owned(),
disable_modern,
iothread: "".to_owned(),
}
}
fn set_iothread(&mut self, iothread: &str) {
self.iothread = iothread.to_owned();
}
}
#[async_trait]
impl ToQemuParams for DeviceVirtioScsi {
async fn qemu_params(&self) -> Result<Vec<String>> {
let mut params = Vec::new();
params.push(format!("virtio-scsi-{}", self.bus_type));
params.push(format!("id={}", self.id));
if self.disable_modern {
params.push("disable-modern=true".to_owned());
}
if !self.iothread.is_empty() {
params.push(format!("iothread={}", self.iothread));
}
Ok(vec!["-device".to_owned(), params.join(",")])
}
}
#[derive(Debug)]
struct ObjectIoThread {
id: String,
}
impl ObjectIoThread {
fn new(id: &str) -> Self {
ObjectIoThread { id: id.to_owned() }
}
}
#[async_trait]
impl ToQemuParams for ObjectIoThread {
async fn qemu_params(&self) -> Result<Vec<String>> {
let mut params = Vec::new();
params.push("iothread".to_owned());
params.push(format!("id={}", self.id));
Ok(vec!["-object".to_owned(), params.join(",")])
}
}
fn is_running_in_vm() -> Result<bool> {
let res = read_to_string("/proc/cpuinfo")?
.lines()
@@ -1480,10 +1649,18 @@ impl<'a> QemuCmdLine<'a> {
qemu_cmd_line.add_rtc();
if qemu_cmd_line.bus_type() != VirtioBusType::Ccw {
if bus_type(config) != VirtioBusType::Ccw {
qemu_cmd_line.add_rng();
}
if bus_type(config) != VirtioBusType::Ccw && config.device_info.default_bridges > 0 {
qemu_cmd_line.add_bridges(config.device_info.default_bridges);
}
if config.blockdev_info.block_device_driver == VIRTIO_SCSI {
qemu_cmd_line.add_scsi_controller();
}
Ok(qemu_cmd_line)
}
@@ -1507,14 +1684,6 @@ impl<'a> QemuCmdLine<'a> {
self.devices.push(Box::new(rng_device));
}
fn bus_type(&self) -> VirtioBusType {
if self.config.machine_info.machine_type.contains("-ccw-") {
VirtioBusType::Ccw
} else {
VirtioBusType::Pci
}
}
fn add_iommu(&mut self) {
let dev_iommu = DeviceIntelIommu::new();
self.devices.push(Box::new(dev_iommu));
@@ -1526,6 +1695,25 @@ impl<'a> QemuCmdLine<'a> {
self.machine.set_kernel_irqchip("split");
}
fn add_bridges(&mut self, count: u32) {
for idx in 0..count {
let bridge = DevicePciBridge::new(self.config, idx);
self.devices.push(Box::new(bridge));
}
}
fn add_scsi_controller(&mut self) {
let mut virtio_scsi =
DeviceVirtioScsi::new("scsi0", should_disable_modern(), bus_type(self.config));
if self.config.enable_iothreads {
let iothread_id = "scsi-io-thread";
let iothread = ObjectIoThread::new(iothread_id);
virtio_scsi.set_iothread(iothread_id);
self.devices.push(Box::new(iothread));
}
self.devices.push(Box::new(virtio_scsi));
}
pub fn add_virtiofs_share(
&mut self,
virtiofsd_socket_path: &str,
@@ -1542,9 +1730,11 @@ impl<'a> QemuCmdLine<'a> {
self.devices.push(Box::new(virtiofsd_socket_chardev));
let mut virtiofs_device = DeviceVhostUserFs::new(chardev_name, mount_tag, self.bus_type());
let bus_type = bus_type(self.config);
let mut virtiofs_device = DeviceVhostUserFs::new(chardev_name, mount_tag, bus_type);
virtiofs_device.set_queue_size(queue_size);
if self.config.device_info.enable_iommu_platform && self.bus_type() == VirtioBusType::Ccw {
if self.config.device_info.enable_iommu_platform && bus_type == VirtioBusType::Ccw {
virtiofs_device.set_iommu_platform(true);
}
self.devices.push(Box::new(virtiofs_device));
@@ -1558,7 +1748,7 @@ impl<'a> QemuCmdLine<'a> {
//self.devices.push(Box::new(mem_file));
self.memory.set_memory_backend_file(&mem_file);
match self.bus_type() {
match bus_type {
VirtioBusType::Pci => {
self.machine.set_nvdimm(true);
self.devices.push(Box::new(NumaNode::new(&mem_file.id)));
@@ -1572,7 +1762,7 @@ impl<'a> QemuCmdLine<'a> {
pub fn add_vsock(&mut self, vhostfd: tokio::fs::File, guest_cid: u32) -> Result<()> {
clear_cloexec(vhostfd.as_raw_fd()).context("clearing O_CLOEXEC failed on vsock fd")?;
let mut vhost_vsock_pci = VhostVsock::new(vhostfd, guest_cid, self.bus_type());
let mut vhost_vsock_pci = VhostVsock::new(vhostfd, guest_cid, bus_type(self.config));
if !self.config.disable_nesting_checks && should_disable_modern() {
vhost_vsock_pci.set_disable_modern(true);
@@ -1619,8 +1809,10 @@ impl<'a> QemuCmdLine<'a> {
pub fn add_block_device(&mut self, device_id: &str, path: &str) -> Result<()> {
self.devices
.push(Box::new(BlockBackend::new(device_id, path)));
self.devices
.push(Box::new(DeviceVirtioBlk::new(device_id, self.bus_type())));
self.devices.push(Box::new(DeviceVirtioBlk::new(
device_id,
bus_type(self.config),
)));
Ok(())
}
@@ -1634,32 +1826,9 @@ impl<'a> QemuCmdLine<'a> {
));
}
pub fn add_network_device(
&mut self,
dev_index: u64,
host_dev_name: &str,
guest_mac: Address,
) -> Result<()> {
let mut netdev = Netdev::new(
&format!("network-{}", dev_index),
host_dev_name,
self.config.network_info.network_queues,
)?;
if self.config.network_info.disable_vhost_net {
netdev.set_disable_vhost_net(true);
}
let mut virtio_net_device = DeviceVirtioNet::new(&netdev.id, guest_mac);
if should_disable_modern() {
virtio_net_device.set_disable_modern(true);
}
if self.config.device_info.enable_iommu_platform && self.bus_type() == VirtioBusType::Ccw {
virtio_net_device.set_iommu_platform(true);
}
if self.config.network_info.network_queues > 1 {
virtio_net_device.set_num_queues(self.config.network_info.network_queues);
}
pub fn add_network_device(&mut self, host_dev_name: &str, guest_mac: Address) -> Result<()> {
let (netdev, virtio_net_device) =
get_network_device(self.config, host_dev_name, guest_mac)?;
self.devices.push(Box::new(netdev));
self.devices.push(Box::new(virtio_net_device));
@@ -1667,8 +1836,10 @@ impl<'a> QemuCmdLine<'a> {
}
pub fn add_console(&mut self, console_socket_path: &str) {
let mut serial_dev = DeviceVirtioSerial::new("serial0", self.bus_type());
if self.config.device_info.enable_iommu_platform && self.bus_type() == VirtioBusType::Ccw {
let mut serial_dev = DeviceVirtioSerial::new("serial0", bus_type(self.config));
if self.config.device_info.enable_iommu_platform
&& bus_type(self.config) == VirtioBusType::Ccw
{
serial_dev.set_iommu_platform(true);
}
self.devices.push(Box::new(serial_dev));
@@ -1709,3 +1880,32 @@ impl<'a> QemuCmdLine<'a> {
Ok(result)
}
}
pub fn get_network_device(
config: &HypervisorConfig,
host_dev_name: &str,
guest_mac: Address,
) -> Result<(Netdev, DeviceVirtioNet)> {
let mut netdev = Netdev::new(
&format!("network-{}", host_dev_name),
host_dev_name,
config.network_info.network_queues,
)?;
if config.network_info.disable_vhost_net {
netdev.set_disable_vhost_net(true);
}
let mut virtio_net_device = DeviceVirtioNet::new(&netdev.id, guest_mac);
if should_disable_modern() {
virtio_net_device.set_disable_modern(true);
}
if config.device_info.enable_iommu_platform && bus_type(config) == VirtioBusType::Ccw {
virtio_net_device.set_iommu_platform(true);
}
if config.network_info.network_queues > 1 {
virtio_net_device.set_num_queues(config.network_info.network_queues);
}
Ok((netdev, virtio_net_device))
}

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
use super::cmdline_generator::{QemuCmdLine, QMP_SOCKET_FILE};
use super::cmdline_generator::{get_network_device, QemuCmdLine, QMP_SOCKET_FILE};
use super::qmp::Qmp;
use crate::{
hypervisor_persist::HypervisorState, utils::enter_netns, HypervisorConfig, MemoryConfig,
@@ -43,13 +43,10 @@ pub struct QemuInner {
netns: Option<String>,
exit_notify: Option<mpsc::Sender<()>>,
exit_waiter: Mutex<(mpsc::Receiver<()>, i32)>,
}
impl QemuInner {
pub fn new() -> QemuInner {
let (exit_notify, exit_waiter) = mpsc::channel(1);
pub fn new(exit_notify: mpsc::Sender<()>) -> QemuInner {
QemuInner {
id: "".to_string(),
qemu_process: Mutex::new(None),
@@ -59,7 +56,6 @@ impl QemuInner {
netns: None,
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
}
}
@@ -124,7 +120,6 @@ impl QemuInner {
let _netns_guard = NetnsGuard::new(&netns).context("new netns guard")?;
cmdline.add_network_device(
network.config.index,
&network.config.host_dev_name,
network.config.guest_mac.clone().unwrap(),
)?;
@@ -202,22 +197,14 @@ impl QemuInner {
}
pub(crate) async fn wait_vm(&self) -> Result<i32> {
info!(sl!(), "Wait QEMU VM");
let mut waiter = self.exit_waiter.lock().await;
//wait until the qemu process exited.
waiter.0.recv().await;
let mut qemu_process = self.qemu_process.lock().await;
if let Some(mut qemu_process) = qemu_process.take() {
if let Ok(status) = qemu_process.wait().await {
waiter.1 = status.code().unwrap_or(0);
}
let status = qemu_process.wait().await?;
Ok(status.code().unwrap_or(0))
} else {
Err(anyhow!("the process has been reaped"))
}
Ok(waiter.1)
}
pub(crate) fn pause_vm(&self) -> Result<()> {
@@ -552,9 +539,16 @@ use crate::device::DeviceType;
// device manager part of Hypervisor
impl QemuInner {
pub(crate) async fn add_device(&mut self, device: DeviceType) -> Result<DeviceType> {
pub(crate) async fn add_device(&mut self, mut device: DeviceType) -> Result<DeviceType> {
info!(sl!(), "QemuInner::add_device() {}", device);
self.devices.push(device.clone());
let is_qemu_ready_to_hotplug = self.qmp.is_some();
if is_qemu_ready_to_hotplug {
// hypervisor is running already
device = self.hotplug_device(device)?;
} else {
// store the device to coldplug it later, on hypervisor launch
self.devices.push(device.clone());
}
Ok(device)
}
@@ -565,6 +559,26 @@ impl QemuInner {
device
))
}
fn hotplug_device(&mut self, device: DeviceType) -> Result<DeviceType> {
let qmp = match self.qmp {
Some(ref mut qmp) => qmp,
None => return Err(anyhow!("QMP not initialized")),
};
match device {
DeviceType::Network(ref network_device) => {
let (netdev, virtio_net_device) = get_network_device(
&self.config,
&network_device.config.host_dev_name,
network_device.config.guest_mac.clone().unwrap(),
)?;
qmp.hotplug_network_device(&netdev, &virtio_net_device)?
}
_ => info!(sl!(), "hotplugging of {:#?} is unsupported", device),
}
Ok(device)
}
}
// private helpers
@@ -589,7 +603,7 @@ impl QemuInner {
#[async_trait]
impl Persist for QemuInner {
type State = HypervisorState;
type ConstructorArgs = ();
type ConstructorArgs = mpsc::Sender<()>;
/// Save a state of hypervisor
async fn save(&self) -> Result<Self::State> {
@@ -602,12 +616,7 @@ impl Persist for QemuInner {
}
/// Restore hypervisor
async fn restore(
_hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let (exit_notify, exit_waiter) = mpsc::channel(1);
async fn restore(exit_notify: mpsc::Sender<()>, hypervisor_state: Self::State) -> Result<Self> {
Ok(QemuInner {
id: hypervisor_state.id,
qemu_process: Mutex::new(None),
@@ -617,7 +626,6 @@ impl Persist for QemuInner {
netns: None,
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
})
}
}

View File

@@ -18,12 +18,15 @@ use persist::sandbox_persist::Persist;
use anyhow::{Context, Result};
use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio::sync::{mpsc, Mutex};
#[derive(Debug)]
pub struct Qemu {
inner: Arc<RwLock<QemuInner>>,
exit_waiter: Mutex<(mpsc::Receiver<()>, i32)>,
}
impl Default for Qemu {
@@ -34,8 +37,11 @@ impl Default for Qemu {
impl Qemu {
pub fn new() -> Self {
let (exit_notify, exit_waiter) = mpsc::channel(1);
Self {
inner: Arc::new(RwLock::new(QemuInner::new())),
inner: Arc::new(RwLock::new(QemuInner::new(exit_notify))),
exit_waiter: Mutex::new((exit_waiter, 0)),
}
}
@@ -47,7 +53,12 @@ impl Qemu {
#[async_trait]
impl Hypervisor for Qemu {
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()> {
async fn prepare_vm(
&self,
id: &str,
netns: Option<String>,
_annotations: &HashMap<String, String>,
) -> Result<()> {
let mut inner = self.inner.write().await;
inner.prepare_vm(id, netns).await
}
@@ -63,8 +74,19 @@ impl Hypervisor for Qemu {
}
async fn wait_vm(&self) -> Result<i32> {
info!(sl!(), "Wait QEMU VM");
let mut waiter = self.exit_waiter.lock().await;
//wait until the qemu process exited.
waiter.0.recv().await;
let inner = self.inner.read().await;
inner.wait_vm().await
if let Ok(exit_code) = inner.wait_vm().await {
waiter.1 = exit_code;
}
Ok(waiter.1)
}
async fn pause_vm(&self) -> Result<()> {
@@ -204,12 +226,15 @@ impl Persist for Qemu {
/// Restore a component from a specified state.
async fn restore(
hypervisor_args: Self::ConstructorArgs,
_hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let inner = QemuInner::restore(hypervisor_args, hypervisor_state).await?;
let (exit_notify, exit_waiter) = mpsc::channel(1);
let inner = QemuInner::restore(exit_notify, hypervisor_state).await?;
Ok(Self {
inner: Arc::new(RwLock::new(inner)),
exit_waiter: Mutex::new((exit_waiter, 0)),
})
}
}

View File

@@ -3,9 +3,13 @@
// SPDX-License-Identifier: Apache-2.0
//
use crate::qemu::cmdline_generator::{DeviceVirtioNet, Netdev};
use anyhow::{anyhow, Result};
use nix::sys::socket::{sendmsg, ControlMessage, MsgFlags};
use std::fmt::{Debug, Error, Formatter};
use std::io::BufReader;
use std::os::fd::{AsRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::time::Duration;
@@ -291,6 +295,178 @@ impl Qmp {
}
Ok(())
}
fn find_free_slot(&mut self) -> Result<(String, i64)> {
let pci = self.qmp.execute(&qapi_qmp::query_pci {})?;
for pci_info in &pci {
for pci_dev in &pci_info.devices {
let pci_bridge = match &pci_dev.pci_bridge {
Some(bridge) => bridge,
None => continue,
};
info!(sl!(), "found PCI bridge: {}", pci_dev.qdev_id);
if let Some(bridge_devices) = &pci_bridge.devices {
let occupied_slots = bridge_devices
.iter()
.map(|pci_dev| pci_dev.slot)
.collect::<Vec<_>>();
info!(
sl!(),
"already occupied slots on bridge {}: {:#?}",
pci_dev.qdev_id,
occupied_slots
);
// from virtcontainers' bridges.go
let pci_bridge_max_capacity = 30;
for slot in 0..pci_bridge_max_capacity {
if !occupied_slots.iter().any(|elem| *elem == slot) {
info!(
sl!(),
"found free slot on bridge {}: {}", pci_dev.qdev_id, slot
);
return Ok((pci_dev.qdev_id.clone(), slot));
}
}
}
}
}
Err(anyhow!("no free slots on PCI bridges"))
}
fn pass_fd(&mut self, fd: RawFd, fdname: &str) -> Result<()> {
info!(sl!(), "passing fd {:?} as {}", fd, fdname);
// Put the QMP 'getfd' command itself into the message payload.
let getfd_cmd = format!(
"{{ \"execute\": \"getfd\", \"arguments\": {{ \"fdname\": \"{}\" }} }}",
fdname
);
let buf = getfd_cmd.as_bytes();
let bufs = &mut [std::io::IoSlice::new(buf)][..];
debug!(sl!(), "bufs: {:?}", bufs);
let fds = [fd];
let cmsg = [ControlMessage::ScmRights(&fds)];
let result = sendmsg::<()>(
self.qmp.inner_mut().get_mut_write().as_raw_fd(),
bufs,
&cmsg,
MsgFlags::empty(),
None,
);
info!(sl!(), "sendmsg() result: {:#?}", result);
let result = self.qmp.read_response::<&qmp::getfd>();
match result {
Ok(_) => {
info!(sl!(), "successfully passed {} ({})", fdname, fd);
Ok(())
}
Err(err) => Err(anyhow!("failed to pass {} ({}): {}", fdname, fd, err)),
}
}
pub fn hotplug_network_device(
&mut self,
netdev: &Netdev,
virtio_net_device: &DeviceVirtioNet,
) -> Result<()> {
debug!(
sl!(),
"hotplug_network_device(): PCI before {}: {:#?}",
virtio_net_device.get_netdev_id(),
self.qmp.execute(&qapi_qmp::query_pci {})?
);
let (bus, slot) = self.find_free_slot()?;
let mut fd_names = vec![];
for (idx, fd) in netdev.get_fds().iter().enumerate() {
let fdname = format!("fd{}", idx);
self.pass_fd(fd.as_raw_fd(), fdname.as_ref())?;
fd_names.push(fdname);
}
let mut vhostfd_names = vec![];
for (idx, fd) in netdev.get_vhostfds().iter().enumerate() {
let vhostfdname = format!("vhostfd{}", idx);
self.pass_fd(fd.as_raw_fd(), vhostfdname.as_ref())?;
vhostfd_names.push(vhostfdname);
}
self.qmp
.execute(&qapi_qmp::netdev_add(qapi_qmp::Netdev::tap {
id: netdev.get_id().clone(),
tap: qapi_qmp::NetdevTapOptions {
br: None,
downscript: None,
fd: None,
// Logic in cmdline_generator::Netdev::new() seems to
// guarantee that there will always be at least one fd.
fds: Some(fd_names.join(",")),
helper: None,
ifname: None,
poll_us: None,
queues: None,
script: None,
sndbuf: None,
vhost: if vhostfd_names.is_empty() {
None
} else {
Some(true)
},
vhostfd: None,
vhostfds: if vhostfd_names.is_empty() {
None
} else {
Some(vhostfd_names.join(","))
},
vhostforce: None,
vnet_hdr: None,
},
}))?;
let mut netdev_frontend_args = Dictionary::new();
netdev_frontend_args.insert(
"netdev".to_owned(),
virtio_net_device.get_netdev_id().clone().into(),
);
netdev_frontend_args.insert("addr".to_owned(), format!("{:02}", slot).into());
netdev_frontend_args.insert("mac".to_owned(), virtio_net_device.get_mac_addr().into());
netdev_frontend_args.insert("mq".to_owned(), "on".into());
// As the golang runtime documents the vectors computation, it's
// 2N+2 vectors, N for tx queues, N for rx queues, 1 for config, and one for possible control vq
netdev_frontend_args.insert(
"vectors".to_owned(),
(2 * virtio_net_device.get_num_queues() + 2).into(),
);
if virtio_net_device.get_disable_modern() {
netdev_frontend_args.insert("disable-modern".to_owned(), true.into());
}
self.qmp.execute(&qmp::device_add {
bus: Some(bus),
id: Some(format!("frontend-{}", virtio_net_device.get_netdev_id())),
driver: virtio_net_device.get_device_driver().clone(),
arguments: netdev_frontend_args,
})?;
debug!(
sl!(),
"hotplug_network_device(): PCI after {}: {:#?}",
virtio_net_device.get_netdev_id(),
self.qmp.execute(&qapi_qmp::query_pci {})?
);
Ok(())
}
}
fn vcpu_id_from_core_id(core_id: i64) -> String {

View File

@@ -0,0 +1,387 @@
// Copyright 2024 Kata Contributors
//
// SPDX-License-Identifier: Apache-2.0
//
use crate::{
device::DeviceType, hypervisor_persist::HypervisorState, HypervisorConfig, HYPERVISOR_REMOTE,
};
use crate::{MemoryConfig, VcpuThreadIds};
use anyhow::{Context, Result};
use async_trait::async_trait;
use kata_types::{
annotations::{
cri_containerd::{SANDBOX_NAMESPACE_LABEL_KEY, SANDBOX_NAME_LABEL_KEY},
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_MEMORY, KATA_ANNO_CFG_HYPERVISOR_DEFAULT_VCPUS,
KATA_ANNO_CFG_HYPERVISOR_IMAGE_PATH, KATA_ANNO_CFG_HYPERVISOR_MACHINE_TYPE,
},
capabilities::{Capabilities, CapabilityBits},
};
use persist::sandbox_persist::Persist;
use protocols::{
remote::{CreateVMRequest, StartVMRequest, StopVMRequest},
remote_ttrpc_async::HypervisorClient,
};
use std::{collections::HashMap, time};
use tokio::sync::{mpsc, Mutex};
use ttrpc::context::{self};
use ttrpc::r#async::Client;
const REMOTE_SCHEME: &str = "remote";
const DEFAULT_MIN_TIMEOUT: i32 = time::Duration::from_secs(60).as_millis() as i32;
pub struct RemoteInner {
/// sandbox id
pub(crate) id: String,
/// hypervisor config
pub(crate) config: HypervisorConfig,
/// agent socket path
pub(crate) agent_socket_path: String,
/// netns path
pub(crate) netns: Option<String>,
/// hypervisor unix client
pub(crate) client: Option<Client>,
exit_notify: Option<mpsc::Sender<i32>>,
exit_waiter: Mutex<(mpsc::Receiver<i32>, i32)>,
}
impl std::fmt::Debug for RemoteInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RemoteInner")
.field("id", &self.id)
.field("config", &self.config)
.field("agent_socket_path", &self.agent_socket_path)
.field("netns", &self.netns)
.finish()
}
}
impl RemoteInner {
pub fn new() -> Self {
let (exit_notify, exit_waiter) = mpsc::channel(1);
Self {
id: "".to_string(),
config: HypervisorConfig::default(),
agent_socket_path: "".to_string(),
netns: None,
client: None,
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
}
}
fn get_ttrpc_client(&mut self) -> Result<HypervisorClient> {
match self.client {
Some(ref c) => Ok(HypervisorClient::new(c.clone())),
None => {
let c = Client::connect(&format!(
"unix://{}",
&self.config.remote_info.hypervisor_socket
))
.context("connect to ")?;
self.client = Some(c.clone());
Ok(HypervisorClient::new(c))
}
}
}
fn prepare_annotations(
&self,
oci_annotations: &HashMap<String, String>,
) -> HashMap<String, String> {
let mut annotations: HashMap<String, String> = HashMap::new();
let config = &self.config;
annotations.insert(
SANDBOX_NAME_LABEL_KEY.to_string(),
oci_annotations
.get(SANDBOX_NAME_LABEL_KEY)
.cloned()
.unwrap_or_default(),
);
annotations.insert(
SANDBOX_NAMESPACE_LABEL_KEY.to_string(),
oci_annotations
.get(SANDBOX_NAMESPACE_LABEL_KEY)
.cloned()
.unwrap_or_default(),
);
annotations.insert(
KATA_ANNO_CFG_HYPERVISOR_MACHINE_TYPE.to_string(),
config.machine_info.machine_type.to_string(),
);
annotations.insert(
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_VCPUS.to_string(),
config.cpu_info.default_vcpus.to_string(),
);
annotations.insert(
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_MEMORY.to_string(),
config.memory_info.default_memory.to_string(),
);
annotations.insert(
KATA_ANNO_CFG_HYPERVISOR_IMAGE_PATH.to_string(),
config.boot_info.image.to_string(),
);
annotations
}
pub(crate) async fn prepare_vm(
&mut self,
id: &str,
netns: Option<String>,
annotations: &HashMap<String, String>,
) -> Result<()> {
info!(sl!(), "Preparing REMOTE VM");
self.id = id.to_string();
if let Some(netns_path) = &netns {
debug!(sl!(), "set netns for vmm master {:?}", &netns_path);
std::fs::metadata(netns_path).context("check netns path")?;
}
let client = self.get_ttrpc_client()?;
let ctx = context::Context::default();
let req = CreateVMRequest {
id: id.to_string(),
annotations: self.prepare_annotations(annotations),
networkNamespacePath: netns.clone().unwrap_or_default(),
..Default::default()
};
info!(sl!(), "Preparing REMOTE VM req: {:?}", req.clone());
let resp = client.create_vm(ctx, &req).await?;
info!(sl!(), "Preparing REMOTE VM resp: {:?}", resp.clone());
self.agent_socket_path = resp.agentSocketPath;
self.netns = netns;
Ok(())
}
pub(crate) async fn start_vm(&mut self, timeout: i32) -> Result<()> {
info!(sl!(), "Starting REMOTE VM");
let mut min_timeout = DEFAULT_MIN_TIMEOUT;
if self.config.remote_info.hypervisor_timeout > 0 {
min_timeout = self.config.remote_info.hypervisor_timeout.min(timeout);
}
let timeout = min_timeout;
let client = self.get_ttrpc_client()?;
let req = StartVMRequest {
id: self.id.clone(),
..Default::default()
};
let ctx =
context::with_timeout(time::Duration::from_secs(timeout as u64).as_nanos() as i64);
let _resp = client.start_vm(ctx, &req).await?;
Ok(())
}
pub(crate) async fn stop_vm(&mut self) -> Result<()> {
info!(sl!(), "Stopping REMOTE VM");
let client = self.get_ttrpc_client()?;
let ctx = context::with_timeout(time::Duration::from_secs(1).as_nanos() as i64);
let req = StopVMRequest {
id: self.id.clone(),
..Default::default()
};
let _resp = client.stop_vm(ctx, &req).await?;
self.exit_notify.take().unwrap().send(1).await?;
Ok(())
}
pub(crate) async fn pause_vm(&self) -> Result<()> {
warn!(sl!(), "RemoteInner::pause_vm(): NOT YET IMPLEMENTED");
todo!()
}
pub(crate) async fn wait_vm(&self) -> Result<i32> {
info!(sl!(), "Wait Remote VM");
let mut waiter = self.exit_waiter.lock().await;
if let Some(exitcode) = waiter.0.recv().await {
waiter.1 = exitcode;
}
Ok(waiter.1)
}
pub(crate) async fn resume_vm(&self) -> Result<()> {
warn!(sl!(), "RemoteInner::resume_vm(): NOT YET IMPLEMENTED");
todo!()
}
pub(crate) async fn save_vm(&self) -> Result<()> {
warn!(sl!(), "RemoteInner::save_vm(): NOT YET IMPLEMENTED");
todo!()
}
pub(crate) async fn add_device(&self, device: DeviceType) -> Result<DeviceType> {
warn!(sl!(), "RemoteInner::add_device(): NOT YET IMPLEMENTED");
Ok(device)
}
pub(crate) async fn remove_device(&self, _device: DeviceType) -> Result<()> {
warn!(sl!(), "RemoteInner::remove_device(): NOT YET IMPLEMENTED");
Ok(())
}
pub(crate) async fn update_device(&self, _device: DeviceType) -> Result<()> {
warn!(sl!(), "RemoteInner::update_device(): NOT YET IMPLEMENTED");
Ok(())
}
pub(crate) async fn get_agent_socket(&self) -> Result<String> {
Ok(format!("{}://{}", REMOTE_SCHEME, &self.agent_socket_path))
}
pub(crate) async fn disconnect(&mut self) {
warn!(sl!(), "RemoteInner::disconnect(): NOT YET IMPLEMENTED");
todo!()
}
pub fn hypervisor_config(&self) -> HypervisorConfig {
info!(
sl!(),
"RemoteInner::hypervisor_config(): {:?}",
self.config.clone()
);
self.config.clone()
}
pub(crate) async fn get_thread_ids(&self) -> Result<VcpuThreadIds> {
warn!(sl!(), "RemoteInner::get_thread_ids(): NOT YET IMPLEMENTED");
let vcpu_thread_ids: VcpuThreadIds = VcpuThreadIds {
vcpus: HashMap::new(),
};
Ok(vcpu_thread_ids)
}
pub(crate) async fn get_vmm_master_tid(&self) -> Result<u32> {
warn!(sl!(), "RemoteInner::get_vmm_master_tid()");
let tid = nix::unistd::gettid().as_raw();
Ok(tid as u32)
}
pub(crate) async fn get_ns_path(&self) -> Result<String> {
info!(sl!(), "RemoteInner::get_ns_path()");
Ok(self.netns.clone().unwrap_or_default())
}
pub(crate) async fn cleanup(&self) -> Result<()> {
info!(sl!(), "RemoteInner::cleanup(): NOT YET IMPLEMENTED");
Ok(())
}
pub(crate) async fn resize_vcpu(
&mut self,
_old_vcpus: u32,
_new_vcpus: u32,
) -> Result<(u32, u32)> {
info!(sl!(), "RemoteInner::resize_vcpu(): NOT YET IMPLEMENTED");
Ok((_old_vcpus, _new_vcpus))
}
pub(crate) async fn get_pids(&self) -> Result<Vec<u32>> {
warn!(sl!(), "RemoteInner::get_pids(): NOT YET IMPLEMENTED");
todo!()
}
pub(crate) async fn check(&self) -> Result<()> {
warn!(sl!(), "RemoteInner::check(): NOT YET IMPLEMENTED");
todo!()
}
pub(crate) async fn get_jailer_root(&self) -> Result<String> {
warn!(sl!(), "RemoteInner::get_jailer_root(): NOT YET IMPLEMENTED");
Ok("".into())
}
pub(crate) async fn capabilities(&self) -> Result<Capabilities> {
Ok(Capabilities::default())
}
pub fn set_hypervisor_config(&mut self, config: HypervisorConfig) {
self.config = config;
}
pub(crate) async fn get_hypervisor_metrics(&self) -> Result<String> {
warn!(
sl!(),
"RemoteInner::get_hypervisor_metrics(): NOT YET IMPLEMENTED"
);
todo!()
}
pub(crate) fn set_capabilities(&mut self, _flag: CapabilityBits) {
warn!(
sl!(),
"RemoteInner::set_capabilities(): NOT YET IMPLEMENTED"
);
todo!()
}
pub(crate) fn set_guest_memory_block_size(&mut self, _size: u32) {
info!(
sl!(),
"RemoteInner::set_guest_memory_block_size(): NOT YET IMPLEMENTED"
)
}
pub(crate) fn guest_memory_block_size_mb(&self) -> u32 {
warn!(
sl!(),
"RemoteInner::guest_memory_block_size_mb(): NOT YET IMPLEMENTED"
);
0
}
pub(crate) fn resize_memory(&self, _new_mem_mb: u32) -> Result<(u32, MemoryConfig)> {
Ok((
_new_mem_mb,
MemoryConfig {
..Default::default()
},
))
}
}
#[async_trait]
impl Persist for RemoteInner {
type State = HypervisorState;
type ConstructorArgs = ();
/// Save a state of hypervisor
async fn save(&self) -> Result<Self::State> {
Ok(HypervisorState {
hypervisor_type: HYPERVISOR_REMOTE.to_string(),
id: self.id.clone(),
config: self.config.clone(),
netns: self.netns.clone(),
..Default::default()
})
}
/// Restore hypervisor
async fn restore(
_hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let (exit_notify, exit_waiter) = mpsc::channel(1);
Ok(RemoteInner {
id: hypervisor_state.id,
config: hypervisor_state.config,
agent_socket_path: "".to_string(),
netns: hypervisor_state.netns,
client: None,
exit_notify: Some(exit_notify),
exit_waiter: Mutex::new((exit_waiter, 0)),
})
}
}

View File

@@ -0,0 +1,216 @@
// Copyright 2024 Kata Contributors
//
// SPDX-License-Identifier: Apache-2.0
//
use super::HypervisorState;
use crate::{device::DeviceType, Hypervisor, HypervisorConfig, MemoryConfig, VcpuThreadIds};
use anyhow::{Context, Result};
use async_trait::async_trait;
use inner::RemoteInner;
use kata_types::capabilities::{Capabilities, CapabilityBits};
use persist::sandbox_persist::Persist;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
mod inner;
#[derive(Debug)]
pub struct Remote {
inner: Arc<RwLock<RemoteInner>>,
}
impl Default for Remote {
fn default() -> Self {
Self::new()
}
}
impl Remote {
pub fn new() -> Self {
Self {
inner: Arc::new(RwLock::new(RemoteInner::new())),
}
}
pub async fn set_hypervisor_config(&mut self, config: HypervisorConfig) {
let mut inner = self.inner.write().await;
inner.set_hypervisor_config(config)
}
}
#[async_trait]
impl Hypervisor for Remote {
async fn prepare_vm(
&self,
id: &str,
netns: Option<String>,
annotations: &HashMap<String, String>,
) -> Result<()> {
let mut inner = self.inner.write().await;
inner.prepare_vm(id, netns, annotations).await
}
async fn start_vm(&self, timeout: i32) -> Result<()> {
let mut inner = self.inner.write().await;
inner.start_vm(timeout).await
}
async fn stop_vm(&self) -> Result<()> {
let mut inner = self.inner.write().await;
inner.stop_vm().await
}
async fn wait_vm(&self) -> Result<i32> {
let inner = self.inner.read().await;
inner.wait_vm().await
}
async fn pause_vm(&self) -> Result<()> {
let inner = self.inner.read().await;
inner.pause_vm().await
}
async fn resume_vm(&self) -> Result<()> {
let inner = self.inner.read().await;
inner.resume_vm().await
}
async fn save_vm(&self) -> Result<()> {
let inner = self.inner.read().await;
inner.save_vm().await
}
async fn add_device(&self, device: DeviceType) -> Result<DeviceType> {
let inner = self.inner.write().await;
inner.add_device(device).await
}
async fn remove_device(&self, device: DeviceType) -> Result<()> {
let inner = self.inner.write().await;
inner.remove_device(device).await
}
async fn update_device(&self, device: DeviceType) -> Result<()> {
let inner = self.inner.write().await;
inner.update_device(device).await
}
async fn get_agent_socket(&self) -> Result<String> {
let inner = self.inner.read().await;
inner.get_agent_socket().await
}
async fn disconnect(&self) {
let mut inner = self.inner.write().await;
inner.disconnect().await
}
async fn hypervisor_config(&self) -> HypervisorConfig {
let inner = self.inner.read().await;
inner.hypervisor_config()
}
async fn get_thread_ids(&self) -> Result<VcpuThreadIds> {
let inner = self.inner.read().await;
inner.get_thread_ids().await
}
async fn get_vmm_master_tid(&self) -> Result<u32> {
let inner = self.inner.read().await;
inner.get_vmm_master_tid().await
}
async fn get_ns_path(&self) -> Result<String> {
let inner = self.inner.read().await;
inner.get_ns_path().await
}
async fn cleanup(&self) -> Result<()> {
let inner = self.inner.read().await;
inner.cleanup().await
}
async fn resize_vcpu(&self, old_vcpus: u32, new_vcpus: u32) -> Result<(u32, u32)> {
let mut inner = self.inner.write().await;
inner.resize_vcpu(old_vcpus, new_vcpus).await
}
async fn get_pids(&self) -> Result<Vec<u32>> {
let inner = self.inner.read().await;
inner.get_pids().await
}
async fn check(&self) -> Result<()> {
let inner = self.inner.read().await;
inner.check().await
}
async fn get_jailer_root(&self) -> Result<String> {
let inner = self.inner.read().await;
inner.get_jailer_root().await
}
async fn save_state(&self) -> Result<HypervisorState> {
self.save().await
}
async fn capabilities(&self) -> Result<Capabilities> {
let inner = self.inner.read().await;
inner.capabilities().await
}
async fn get_hypervisor_metrics(&self) -> Result<String> {
let inner = self.inner.read().await;
inner.get_hypervisor_metrics().await
}
async fn set_capabilities(&self, flag: CapabilityBits) {
let mut inner = self.inner.write().await;
inner.set_capabilities(flag)
}
async fn set_guest_memory_block_size(&self, size: u32) {
let mut inner = self.inner.write().await;
inner.set_guest_memory_block_size(size);
}
async fn guest_memory_block_size(&self) -> u32 {
let inner = self.inner.read().await;
inner.guest_memory_block_size_mb()
}
async fn resize_memory(&self, new_mem_mb: u32) -> Result<(u32, MemoryConfig)> {
let inner = self.inner.read().await;
inner.resize_memory(new_mem_mb)
}
async fn get_passfd_listener_addr(&self) -> Result<(String, u32)> {
Err(anyhow::anyhow!("Not yet supported"))
}
}
#[async_trait]
impl Persist for Remote {
type State = HypervisorState;
type ConstructorArgs = ();
/// Save a state of the component.
async fn save(&self) -> Result<Self::State> {
let inner = self.inner.read().await;
inner.save().await.context("save remote hypervisor state")
}
/// Restore a component from a specified state.
async fn restore(
hypervisor_args: Self::ConstructorArgs,
hypervisor_state: Self::State,
) -> Result<Self> {
let inner = RemoteInner::restore(hypervisor_args, hypervisor_state).await?;
Ok(Self {
inner: Arc::new(RwLock::new(inner)),
})
}
}

View File

@@ -11,13 +11,14 @@ use std::{
};
use anyhow::{anyhow, Context, Result};
use dbs_utils::net::Tap;
use kata_types::config::KATA_PATH;
use nix::{
fcntl,
sched::{setns, CloneFlags},
};
use crate::device::Tap;
use crate::{DEFAULT_HYBRID_VSOCK_NAME, JAILER_ROOT};
pub fn get_child_threads(pid: u32) -> HashSet<u32> {

View File

@@ -0,0 +1,475 @@
//
// Copyright (c) 2024 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use std::collections::HashMap;
use std::path::Path;
use anyhow::Result;
use oci_spec::runtime::Spec;
use super::{resolve_cdi_device_kind, ContainerDevice};
use agent::types::Device;
const CDI_PREFIX: &str = "cdi.k8s.io";
// Sort the devices based on the first element's PCI_Guest_Path in the PCI bus according to options.
fn sort_devices_by_guest_pcipath(devices: &mut [ContainerDevice]) {
// Extract first guest_pcipath from device_options
let extract_first_guest_pcipath = |options: &[String]| -> Option<String> {
options
.first()
.and_then(|option| option.split('=').nth(1))
.map(|path| path.to_string())
};
devices.sort_by(|a, b| {
let guest_path_a = extract_first_guest_pcipath(&a.device.options);
let guest_path_b = extract_first_guest_pcipath(&b.device.options);
guest_path_a.cmp(&guest_path_b)
});
}
// Annotate container devices with CDI annotations in OCI Spec
pub fn annotate_container_devices(
spec: &mut Spec,
container_devices: Vec<ContainerDevice>,
) -> Result<Vec<Device>> {
let mut devices_agent: Vec<Device> = Vec::new();
// Make sure that annotations is Some().
if spec.annotations().is_none() {
spec.set_annotations(Some(HashMap::new()));
}
// Step 1: Extract all devices and filter out devices without device_info for vfio_devices
let vfio_devices: Vec<ContainerDevice> = container_devices
.into_iter()
.map(|device| {
// push every device's Device to agent_devices
devices_agent.push(device.device.clone());
device
})
.filter(|device| device.device_info.is_some())
.collect();
// Step 2: Group devices by vendor_id-class_id
let mut grouped_devices: HashMap<String, Vec<ContainerDevice>> = HashMap::new();
for device in vfio_devices {
// Extract the vendor/class key and insert into the map if both are present
if let Some(key) = device
.device_info
.as_ref()
.and_then(|info| resolve_cdi_device_kind(&info.vendor_id, &info.class_id))
{
grouped_devices
.entry(key.to_owned())
.or_default()
.push(device);
}
}
// Step 3: Sort devices within each group by guest_pcipath
grouped_devices
.iter_mut()
.for_each(|(vendor_class, container_devices)| {
// The *offset* is a monotonically increasing counter that keeps track of the number of devices
// within an IOMMU group. It increments by total_of whenever a new IOMMU group is processed.
let offset: &mut usize = &mut 0;
sort_devices_by_guest_pcipath(container_devices);
container_devices
.iter()
.enumerate()
.for_each(|(base, container_device)| {
let total_of = container_device.device.options.len();
// annotate device with cdi information in OCI Spec.
for index in 0..total_of {
if let Some(iommu_grpid) =
Path::new(&container_device.device.container_path)
.file_name()
.and_then(|name| name.to_str())
{
spec.annotations_mut().as_mut().unwrap().insert(
format!("{}/vfio{}.{}", CDI_PREFIX, iommu_grpid, index), // cdi.k8s.io/vfioX.y
format!("{}={}", vendor_class, base + *offset), // vendor/class=name
);
}
}
// update the offset with *total_of*.
*offset += total_of - 1;
});
});
Ok(devices_agent)
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::cdi_devices::DeviceInfo;
use agent::types::Device;
use oci_spec::runtime::SpecBuilder;
use super::*;
#[test]
fn test_sort_devices_by_guest_pcipath() {
let mut devices = vec![
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0xffff".to_string(),
class_id: "0x030x".to_string(),
host_path: PathBuf::from("/dev/device3"),
}),
device: Device {
options: vec!["pci_host_path03=BB:DD03.F03".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0xffff".to_string(),
class_id: "0x030x".to_string(),
host_path: PathBuf::from("/dev/device1"),
}),
device: Device {
options: vec!["pci_host_path01=BB:DD01.F01".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0xffff".to_string(),
class_id: "0x030x".to_string(),
host_path: PathBuf::from("/dev/device2"),
}),
device: Device {
options: vec!["pci_host_path02=BB:DD02.F02".to_string()],
..Default::default()
},
},
];
sort_devices_by_guest_pcipath(&mut devices);
let expected_devices_order = vec![
"/dev/device1".to_string(),
"/dev/device2".to_string(),
"/dev/device3".to_string(),
];
let actual_devices_order: Vec<String> = devices
.iter()
.map(|cd| {
cd.device_info
.as_ref()
.unwrap()
.host_path
.display()
.to_string()
})
.collect();
assert_eq!(actual_devices_order, expected_devices_order);
}
#[test]
fn test_sort_devices_with_empty_options() {
let mut devices = vec![
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0xffff".to_string(),
class_id: "0x030x".to_string(),
host_path: PathBuf::from("/dev/device1"),
}),
device: Device {
options: vec![], // empty
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0xffff".to_string(),
class_id: "0x030x".to_string(),
host_path: PathBuf::from("/dev/device2"),
}),
device: Device {
options: vec!["pci_host_path02=BB:DD02.F02".to_string()],
..Default::default()
},
},
];
sort_devices_by_guest_pcipath(&mut devices);
// As the first device has no options, ignore it.
let expected_devices_order = vec!["BB:DD02.F02".to_string()];
let actual_devices_order: Vec<String> = devices
.iter()
.filter_map(|d| d.device.options.first())
.map(|option| option.split('=').nth(1).unwrap_or("").to_string())
.collect();
assert_eq!(actual_devices_order, expected_devices_order);
}
#[test]
fn test_annotate_container_devices() {
let devices = vec![
ContainerDevice {
device_info: None,
device: Device {
id: "test0000x".to_string(),
container_path: "/dev/xvdx".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/vdx".to_string(),
options: vec![],
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x1002".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device2"),
}),
device: Device {
container_path: "/dev/device2".to_string(),
options: vec!["pci_host_path02=BB:DD02.F02".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x1002".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device3"),
}),
device: Device {
container_path: "/dev/device3".to_string(),
options: vec!["pci_host_path03=BB:DD03.F03".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x1002".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device1"),
}),
device: Device {
container_path: "/dev/device1".to_string(),
options: vec!["pci_host_path01=BB:DD01.F01".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: None,
device: Device {
id: "test0000yx".to_string(),
container_path: "/dev/xvdyx".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/vdyx".to_string(),
options: vec![],
},
},
];
let annotations = HashMap::new();
let mut spec = SpecBuilder::default()
.annotations(annotations)
.build()
.unwrap();
// do annotate container devices
let _devices = annotate_container_devices(&mut spec, devices);
let expected_annotations: HashMap<String, String> = vec![
(
"cdi.k8s.io/vfiodevice3.0".to_owned(),
"amd.com/gpu=2".to_owned(),
),
(
"cdi.k8s.io/vfiodevice1.0".to_owned(),
"amd.com/gpu=0".to_owned(),
),
(
"cdi.k8s.io/vfiodevice2.0".to_owned(),
"amd.com/gpu=1".to_owned(),
),
]
.into_iter()
.collect();
assert_eq!(Some(expected_annotations), spec.annotations().clone());
}
#[test]
fn test_annotate_container_multi_vendor_devices() {
let devices = vec![
ContainerDevice {
device_info: None,
device: Device {
id: "test0000x".to_string(),
container_path: "/dev/xvdx".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/vdx".to_string(),
options: vec![],
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x10de".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device2"),
}),
device: Device {
container_path: "/dev/device2".to_string(),
options: vec!["pci_host_path02=BB:DD02.F02".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x10de".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device3"),
}),
device: Device {
container_path: "/dev/device3".to_string(),
options: vec!["pci_host_path03=BB:DD03.F03".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x8086".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device1"),
}),
device: Device {
container_path: "/dev/device1".to_string(),
options: vec!["pci_host_path01=BB:DD01.F01".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: Some(DeviceInfo {
vendor_id: "0x8086".to_string(),
class_id: "0x0302".to_string(),
host_path: PathBuf::from("/dev/device4"),
}),
device: Device {
container_path: "/dev/device4".to_string(),
options: vec!["pci_host_path04=BB:DD01.F04".to_string()],
..Default::default()
},
},
ContainerDevice {
device_info: None,
device: Device {
id: "test0000yx".to_string(),
container_path: "/dev/xvdyx".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/vdyx".to_string(),
options: vec![],
},
},
];
let annotations = HashMap::new();
let mut spec = SpecBuilder::default()
.annotations(annotations)
.build()
.unwrap();
let _devices = annotate_container_devices(&mut spec, devices);
let expected_annotations: HashMap<String, String> = vec![
(
"cdi.k8s.io/vfiodevice1.0".to_owned(),
"intel.com/gpu=0".to_owned(),
),
(
"cdi.k8s.io/vfiodevice2.0".to_owned(),
"nvidia.com/gpu=0".to_owned(),
),
(
"cdi.k8s.io/vfiodevice3.0".to_owned(),
"nvidia.com/gpu=1".to_owned(),
),
(
"cdi.k8s.io/vfiodevice4.0".to_owned(),
"intel.com/gpu=1".to_owned(),
),
]
.into_iter()
.collect();
assert_eq!(Some(expected_annotations), spec.annotations().clone());
}
#[test]
fn test_annotate_container_without_vfio_devices() {
let devices = vec![
ContainerDevice {
device_info: None,
device: Device {
id: "test0000x".to_string(),
container_path: "/dev/xvdx".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/vdx".to_string(),
options: vec![],
},
},
ContainerDevice {
device_info: None,
device: Device {
id: "test0000y".to_string(),
container_path: "/dev/yvdy".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/vdy".to_string(),
options: vec![],
},
},
ContainerDevice {
device_info: None,
device: Device {
id: "test0000z".to_string(),
container_path: "/dev/zvdz".to_string(),
field_type: "virtio-blk".to_string(),
vm_path: "/dev/zvdz".to_string(),
options: vec![],
},
},
];
let annotations = HashMap::from([(
"cdi.k8s.io/vfiodeviceX".to_owned(),
"katacontainer.com/device=Y".to_owned(),
)]);
let mut spec = SpecBuilder::default()
.annotations(annotations)
.build()
.unwrap();
// do annotate container devices
let annotated_devices = annotate_container_devices(&mut spec, devices.clone()).unwrap();
let actual_devices = devices
.iter()
.map(|d| d.device.clone())
.collect::<Vec<Device>>();
let expected_annotations: HashMap<String, String> = HashMap::from([(
"cdi.k8s.io/vfiodeviceX".to_owned(),
"katacontainer.com/device=Y".to_owned(),
)]);
assert_eq!(Some(expected_annotations), spec.annotations().clone());
assert_eq!(annotated_devices, actual_devices);
}
}

View File

@@ -0,0 +1,63 @@
//
// Copyright (c) 2024 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
pub mod container_device;
use agent::types::Device;
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Clone, Default)]
pub struct DeviceInfo {
pub class_id: String,
pub vendor_id: String,
pub host_path: PathBuf,
}
#[derive(Clone, Default)]
pub struct ContainerDevice {
pub device_info: Option<DeviceInfo>,
pub device: Device,
}
lazy_static! {
// *CDI_DEVICE_KIND_TABLE* is static hash map to store a mapping between device vendor and class
// identifiers and their corresponding CDI vendor and class strings. This mapping is essentially a
// lookup table that allows the system to determine the appropriate CDI for a given device based on
// its vendor and class information.
// Note: Our device mapping is designed to be flexible and responsive to user needs. The current list
// is not exhaustive and will be updated as required.
pub static ref CDI_DEVICE_KIND_TABLE: HashMap<&'static str, &'static str> = {
let mut m = HashMap::new();
m.insert("0x10de-0x030", "nvidia.com/gpu");
m.insert("0x8086-0x030", "intel.com/gpu");
m.insert("0x1002-0x030", "amd.com/gpu");
m.insert("0x15b3-0x020", "nvidia.com/nic");
// TODO: it will be updated as required.
m
};
}
// Sort devices by guest_pcipath
pub fn sort_options_by_pcipath(mut device_options: Vec<String>) -> Vec<String> {
device_options.sort_by(|a, b| {
let extract_path = |s: &str| s.split('=').nth(1).map(|path| path.to_string());
let guest_path_a = extract_path(a);
let guest_path_b = extract_path(b);
guest_path_a.cmp(&guest_path_b)
});
device_options
}
// Resolve the CDI vendor ID/device Class by a lookup table based on the provided vendor and class.
pub fn resolve_cdi_device_kind<'a>(vendor_id: &'a str, class_id: &'a str) -> Option<&'a str> {
let vendor_class = format!("{}-{}", vendor_id, class_id);
// The first 12 characters of the string ("0x10de-0x030") provide a concise
// and clear identification of both the manufacturer and the device category.
// it returns "nvidia.com/gpu", "amd.com/gpu" or others.
CDI_DEVICE_KIND_TABLE.get(&vendor_class[..12]).copied()
}

View File

@@ -4,7 +4,7 @@
// SPDX-License-Identifier: Apache-2.0
//
use std::convert::TryFrom;
use std::{collections::HashMap, convert::TryFrom};
use anyhow::{Context, Result};
use kata_types::{
@@ -22,6 +22,34 @@ struct InitialSize {
orig_toml_default_mem: u32,
}
// generate initial resource(vcpu and memory in MiB) from annotations
impl TryFrom<&HashMap<String, String>> for InitialSize {
type Error = anyhow::Error;
fn try_from(an: &HashMap<String, String>) -> Result<Self> {
let mut vcpu: u32 = 0;
let annotation = Annotation::new(an.clone());
let (period, quota, memory) =
get_sizing_info(annotation).context("failed to get sizing info")?;
let mut cpu = oci::LinuxCpu::default();
cpu.set_period(Some(period));
cpu.set_quota(Some(quota));
// although it may not be actually a linux container, we are only using the calculation inside
// LinuxContainerCpuResources::try_from to generate our vcpu number
if let Ok(cpu_resource) = LinuxContainerCpuResources::try_from(&cpu) {
vcpu = get_nr_vcpu(&cpu_resource);
}
let mem_mb = convert_memory_to_mb(memory);
Ok(Self {
vcpu,
mem_mb,
orig_toml_default_mem: 0,
})
}
}
// generate initial resource(vcpu and memory in MiB) from spec's information
impl TryFrom<&oci::Spec> for InitialSize {
type Error = anyhow::Error;
@@ -32,19 +60,7 @@ impl TryFrom<&oci::Spec> for InitialSize {
// podsandbox, from annotation
ContainerType::PodSandbox => {
let spec_annos = spec.annotations().clone().unwrap_or_default();
let annotation = Annotation::new(spec_annos);
let (period, quota, memory) =
get_sizing_info(annotation).context("failed to get sizing info")?;
let mut cpu = oci::LinuxCpu::default();
cpu.set_period(Some(period));
cpu.set_quota(Some(quota));
// although it may not be actually a linux container, we are only using the calculation inside
// LinuxContainerCpuResources::try_from to generate our vcpu number
if let Ok(cpu_resource) = LinuxContainerCpuResources::try_from(&cpu) {
vcpu = get_nr_vcpu(&cpu_resource);
}
mem_mb = convert_memory_to_mb(memory);
return InitialSize::try_from(&spec_annos);
}
// single container, from container spec
_ => {
@@ -107,6 +123,13 @@ impl InitialSizeManager {
})
}
pub fn new_from(annotation: &HashMap<String, String>) -> Result<Self> {
Ok(Self {
resource: InitialSize::try_from(annotation)
.context("failed to construct static resource")?,
})
}
pub fn setup_config(&mut self, config: &mut TomlConfig) -> Result<()> {
// update this data to the hypervisor config for later use by hypervisor
let hypervisor_name = &config.runtime.hypervisor_name;

View File

@@ -23,6 +23,7 @@ pub mod rootfs;
pub mod share_fs;
pub mod volume;
pub use manager::ResourceManager;
pub mod cdi_devices;
pub mod cpu_mem;
use kata_types::config::hypervisor::SharedFsInfo;

View File

@@ -6,7 +6,6 @@
use std::sync::Arc;
use agent::types::Device;
use agent::{Agent, Storage};
use anyhow::Result;
use async_trait::async_trait;
@@ -20,6 +19,7 @@ use persist::sandbox_persist::Persist;
use tokio::sync::RwLock;
use tracing::instrument;
use crate::cdi_devices::ContainerDevice;
use crate::cpu_mem::initial_size::InitialSizeManager;
use crate::network::NetworkConfig;
use crate::resource_persist::ResourceState;
@@ -116,7 +116,7 @@ impl ResourceManager {
inner.handler_volumes(cid, spec).await
}
pub async fn handler_devices(&self, cid: &str, linux: &Linux) -> Result<Vec<Device>> {
pub async fn handler_devices(&self, cid: &str, linux: &Linux) -> Result<Vec<ContainerDevice>> {
let inner = self.inner.read().await;
inner.handler_devices(cid, linux).await
}

View File

@@ -25,6 +25,7 @@ use persist::sandbox_persist::Persist;
use tokio::{runtime, sync::RwLock};
use crate::{
cdi_devices::{sort_options_by_pcipath, ContainerDevice, DeviceInfo},
cgroups::{CgroupArgs, CgroupsResource},
cpu_mem::{cpu::CpuResource, initial_size::InitialSizeManager, mem::MemResource},
manager::ManagerArgs,
@@ -292,7 +293,7 @@ impl ResourceManagerInner {
.await
}
pub async fn handler_devices(&self, _cid: &str, linux: &Linux) -> Result<Vec<Device>> {
pub async fn handler_devices(&self, _cid: &str, linux: &Linux) -> Result<Vec<ContainerDevice>> {
let mut devices = vec![];
let linux_devices = linux.devices().clone().unwrap_or_default();
@@ -329,7 +330,10 @@ impl ResourceManagerInner {
vm_path: device.config.virt_path,
..Default::default()
};
devices.push(agent_device);
devices.push(ContainerDevice {
device_info: None,
device: agent_device,
});
}
}
LinuxDeviceType::C => {
@@ -361,14 +365,33 @@ impl ResourceManagerInner {
// create agent device
if let DeviceType::Vfio(device) = device_info {
let device_options = sort_options_by_pcipath(device.device_options);
let agent_device = Device {
id: device.device_id, // just for kata-agent
container_path: d.path().display().to_string().clone(),
field_type: vfio_mode,
options: device.device_options,
options: device_options,
..Default::default()
};
devices.push(agent_device);
let vendor_class = device
.devices
.first()
.unwrap()
.device_vendor_class
.as_ref()
.unwrap()
.get_vendor_class_id()
.context("get vendor class failed")?;
let device_info = Some(DeviceInfo {
vendor_id: vendor_class.0.to_owned(),
class_id: vendor_class.1.to_owned(),
host_path: d.path().clone(),
});
devices.push(ContainerDevice {
device_info,
device: agent_device,
});
}
}
_ => {

View File

@@ -4,7 +4,7 @@
// SPDX-License-Identifier: Apache-2.0
//
use crate::types::{ContainerProcess, Response};
use crate::types::{ContainerProcess, TaskResponse};
#[derive(thiserror::Error, Debug)]
pub enum Error {
@@ -13,5 +13,5 @@ pub enum Error {
#[error("failed to find process {0}")]
ProcessNotFound(ContainerProcess),
#[error("unexpected response {0} to shim {1}")]
UnexpectedResponse(Response, String),
UnexpectedResponse(TaskResponse, String),
}

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