From 00e00ff0d94f60bba5f1bb1685cf71f0d7a85396 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:13:18 +0000 Subject: [PATCH 001/119] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index afab4c0..c6460dc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ *.qcow2 __pycache__/ /.target +/.vscode +/.claude From 84a43aa0bc5f1121f327288b3541db226faec7eb Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:36:33 +0000 Subject: [PATCH 002/119] Update yocto to whinlatter --- .gitmodules | 14 +++- bitbake | 1 + dev-setup | 6 +- meta-dstack/conf/distro/dstack.conf | 8 ++- meta-dstack/conf/layer.conf | 2 +- .../base-files/base-files%.bbappend | 8 +-- .../recipes-core/docker/docker-moby%.bbappend | 2 +- .../recipes-core/dstack-guest/dstack-guest.bb | 6 +- ...0001-Update-path-to-native-BaseTools.patch | 19 ++++-- ...ile-adjust-to-build-in-under-bitbake.patch | 25 ++++--- .../dstack-ovmf/0003-Debug-prefix-map.patch | 47 ++++++++----- .../dstack-ovmf/0004-Reproduciable.patch | 67 ++++++++++++------- ...eclare-ProcessLibraryConstructorList.patch | 37 ---------- .../dstack-ovmf/dstack-ovmf_git.bb | 8 +-- .../dstack-zfs/dstack-zfs_2.2.5.bb | 1 - .../recipes-core/images/dstack-initscript.bb | 3 +- .../images/dstack-initscript/init | 0 .../recipes-core/images/dstack-rootfs-dev.inc | 2 +- .../recipes-core/pahole/pahole_1.25.bbappend | 2 - .../recipes-kernel/tdx-guest-mod/tdx-guest.bb | 4 +- meta-openembedded | 2 +- meta-rust-bin | 2 +- meta-security | 2 +- meta-virtualization | 2 +- meta-yocto | 1 + mkimage.sh | 2 +- openembedded-core | 1 + poky | 1 - 28 files changed, 148 insertions(+), 127 deletions(-) create mode 160000 bitbake delete mode 100644 meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch mode change 100644 => 100755 meta-dstack/recipes-core/images/dstack-initscript/init delete mode 100644 meta-dstack/recipes-core/pahole/pahole_1.25.bbappend create mode 160000 meta-yocto create mode 160000 openembedded-core delete mode 160000 poky diff --git a/.gitmodules b/.gitmodules index 1a65484..f80eb53 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,14 @@ -[submodule "poky"] - path = poky - url = https://github.com/yoctoproject/poky.git +[submodule "bitbake"] + path = bitbake + url = https://git.openembedded.org/bitbake +[submodule "openembedded-core"] + path = openembedded-core + url = https://git.openembedded.org/openembedded-core + branch = whinlatter +[submodule "meta-yocto"] + path = meta-yocto + url = https://git.yoctoproject.org/meta-yocto + branch = whinlatter [submodule "meta-confidential-compute"] path = meta-confidential-compute url = https://github.com/Dstack-TEE/meta-confidential-compute.git diff --git a/bitbake b/bitbake new file mode 160000 index 0000000..720df1a --- /dev/null +++ b/bitbake @@ -0,0 +1 @@ +Subproject commit 720df1a53452983c1c832f624490e255cf389204 diff --git a/dev-setup b/dev-setup index 376ee34..51d3a7a 100755 --- a/dev-setup +++ b/dev-setup @@ -36,14 +36,14 @@ if [ ! -f "$BUILD_DIR/conf/local.conf" ]; then cp -f "$THIS_DIR/bb-build/conf/local.conf" "$BUILD_DIR/conf/local.conf" fi -OE_INIT=$THIS_DIR/poky/oe-init-build-env +OE_INIT=$THIS_DIR/openembedded-core/oe-init-build-env for script in $THIS_DIR/setup.d/*.sh; do source "$script" done -pushd . -source $OE_INIT $BUILD_DIR +pushd "$BUILD_DIR" +BDIR="." TEMPLATECONF=$THIS_DIR/meta-yocto/meta-poky/conf/templates/default source $OE_INIT popd bitbake-layers add-layer $LAYERS diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 39042d4..6040b8a 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -7,8 +7,6 @@ DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" DISTRO_VERSION = "0.5.5" DISTROOVERRIDES = "poky:dstack" INITRAMFS_IMAGE = "" -VOLATILE_LOG_DIR = "no" -VOLATILE_TMP_DIR = "yes" PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-dev" PREFERRED_VERSION_linux-yocto-dev ?= "6.9%" @@ -24,4 +22,8 @@ SERIAL_CONSOLES = "115200;ttyS0" PREFERRED_VERSION_rust-bin-cross-x86_64 = "1.86.0" PREFERRED_VERSION_cargo-bin-cross-x86_64 = "1.86.0" -BAD_RECOMMENDATIONS = "busybox-syslog systemd-extra-utils" +BAD_RECOMMENDATIONS = "busybox-syslog systemd-compat-units" + +# Skip unused components that fail metadata checks under walnascar +SKIP_RECIPE[ostree] = "not required for dstack" + diff --git a/meta-dstack/conf/layer.conf b/meta-dstack/conf/layer.conf index 15ad189..7258ad3 100644 --- a/meta-dstack/conf/layer.conf +++ b/meta-dstack/conf/layer.conf @@ -5,4 +5,4 @@ BBFILE_COLLECTIONS += "dstack" BBFILE_PATTERN_dstack := "^${LAYERDIR}/" BBFILE_PRIORITY_dstack = "20" LAYERVERSION_dstack = "4" -LAYERSERIES_COMPAT_dstack = "scarthgap" +LAYERSERIES_COMPAT_dstack = "whinlatter" diff --git a/meta-dstack/recipes-core/base-files/base-files%.bbappend b/meta-dstack/recipes-core/base-files/base-files%.bbappend index 6684855..ed7056d 100644 --- a/meta-dstack/recipes-core/base-files/base-files%.bbappend +++ b/meta-dstack/recipes-core/base-files/base-files%.bbappend @@ -3,11 +3,11 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/files:" SRC_URI += "file://dstack-motd" do_install:append() { - if [ -f ${WORKDIR}/dstack-motd ];then + if [ -f ${UNPACKDIR}/dstack-motd ];then bbnote "Installing custom dstack motd file" - install -m 0644 ${WORKDIR}/dstack-motd ${D}${sysconfdir}/motd + install -m 0644 ${UNPACKDIR}/dstack-motd ${D}${sysconfdir}/motd else - bbwarn "Custom dstack-motd file not found in ${WORKDIR}" - ls -la ${WORKDIR} + bbwarn "Custom dstack-motd file not found in ${UNPACKDIR}" + ls -la ${UNPACKDIR} fi } diff --git a/meta-dstack/recipes-core/docker/docker-moby%.bbappend b/meta-dstack/recipes-core/docker/docker-moby%.bbappend index 871cfbd..8a6e2d0 100644 --- a/meta-dstack/recipes-core/docker/docker-moby%.bbappend +++ b/meta-dstack/recipes-core/docker/docker-moby%.bbappend @@ -8,6 +8,6 @@ FILES:${PN} += "${systemd_system_unitdir}/docker.service.d/override.conf" do_install:append() { if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then install -d ${D}${systemd_system_unitdir}/docker.service.d - install -m 0644 ${WORKDIR}/docker.service.d_override.conf ${D}${systemd_system_unitdir}/docker.service.d/override.conf + install -m 0644 "${UNPACKDIR}/docker.service.d_override.conf" ${D}${systemd_system_unitdir}/docker.service.d/override.conf fi } diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 93f6d6b..06cab0b 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -9,7 +9,7 @@ REPO_ROOT = "${THISDIR}/../../.." SRC_DIR = '${REPO_ROOT}/dstack' -S = "${WORKDIR}/dstack" +S = "${UNPACKDIR}/dstack" RDEPENDS:${PN} += "bash" @@ -83,3 +83,7 @@ do_install() { } FILES:${PN} += "${sysconfdir}/systemd/system/docker.service.d/dstack-guest-agent.conf" + +# Cargo embeds build paths into binaries; allow TMPDIR references. +INSANE_SKIP:${PN} += "buildpaths" +INSANE_SKIP:${PN}-dbg += "buildpaths" diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0001-Update-path-to-native-BaseTools.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0001-Update-path-to-native-BaseTools.patch index 01f54b1..890e586 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0001-Update-path-to-native-BaseTools.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0001-Update-path-to-native-BaseTools.patch @@ -1,8 +1,16 @@ -From 77c79b5aeabe614ebaa993c6a0e6490798d92059 Mon Sep 17 00:00:00 2001 -From: Kevin Wang -Date: Mon, 4 Nov 2024 04:27:21 +0000 -Subject: [PATCH 1/5] Update path to native BaseTools +From 0f859c6de2914cd984f8a0dd61471b91a2371bfa Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Thu, 9 Jun 2016 02:23:01 -0700 +Subject: [PATCH] ovmf: update path to native BaseTools +BaseTools is a set of utilities to build EDK-based firmware. These utilities +are used during the build process. Thus, they need to be built natively. +When cross-compiling, we need to provide a path to the location of these +tools. The BBAKE_EDK_TOOLS_PATH string is used as a pattern to be replaced +with the appropriate location before building. + +Signed-off-by: Ricardo Neri +Upstream-Status: Inappropriate [oe-core cross compile specific] --- OvmfPkg/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) @@ -20,6 +28,3 @@ index 279f0d099a..285f061bf4 100755 echo $EDK_TOOLS_PATH source edksetup.sh BaseTools else --- -2.43.0 - diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch index 16db65b..4a55528 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch @@ -1,17 +1,27 @@ -From a8f873986e7d817d6f0db2824c2348e5120a1094 Mon Sep 17 00:00:00 2001 -From: Kevin Wang -Date: Mon, 4 Nov 2024 04:27:56 +0000 -Subject: [PATCH 2/5] BaseTools makefile adjust to build in under bitbake +From 9dbd082516fdd7100f99f0f389b8eef5ececab19 Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Fri, 26 Jul 2019 17:34:26 -0400 +Subject: [PATCH] BaseTools: makefile: adjust to build in under bitbake +Prepend the build flags with those of bitbake. This is to build +using the bitbake native sysroot include and library directories. + +Note from Alex: this is not appropriate for upstream submission as +the recipe already does lots of similar in-place fixups elsewhere, so +this patch shold be converted to follow that pattern. We're not going +to fight against how upstream wants to configure the build. + +Signed-off-by: Ricardo Neri +Upstream-Status: Inappropriate [needs to be converted to in-recipe fixups] --- BaseTools/Source/C/Makefiles/header.makefile | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/BaseTools/Source/C/Makefiles/header.makefile b/BaseTools/Source/C/Makefiles/header.makefile -index d369908a09..22c670f316 100644 +index 55a7307a5e..e36e6a8f04 100644 --- a/BaseTools/Source/C/Makefiles/header.makefile +++ b/BaseTools/Source/C/Makefiles/header.makefile -@@ -85,35 +85,34 @@ endif +@@ -154,35 +154,34 @@ endif INCLUDE = $(TOOL_INCLUDE) -I $(MAKEROOT) -I $(MAKEROOT)/Include/Common -I $(MAKEROOT)/Include/ -I $(MAKEROOT)/Include/IndustryStandard -I $(MAKEROOT)/Common/ -I .. -I . $(ARCH_INCLUDE) INCLUDE += -I $(EDK2_PATH)/MdePkg/Include @@ -54,6 +64,3 @@ index d369908a09..22c670f316 100644 ifeq ($(HOST_ARCH), IA32) # # Snow Leopard is a 32-bit and 64-bit environment. uname -m returns i386, but gcc defaults --- -2.43.0 - diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch index a793d63..1e79c23 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch @@ -1,17 +1,31 @@ -From aa8d288279ef96ffe576a0e434c1d9f435fef1e7 Mon Sep 17 00:00:00 2001 -From: Kevin Wang -Date: Mon, 4 Nov 2024 04:29:03 +0000 -Subject: [PATCH 3/5] Debug prefix map +From eb6db21ed0a845dce149d17acf8673d5188adea4 Mon Sep 17 00:00:00 2001 +From: Alexander Kanavin +Date: Mon, 14 Jun 2021 19:56:28 +0200 +Subject: [PATCH] debug prefix map +We want to pass ${DEBUG_PREFIX_MAP} to gcc commands and also pass in + --debug-prefix-map to nasm (we carry a patch to nasm for this). The +tools definitions file is built by ovmf-native so we need to pass this in +at target build time when we know the right values so we use the environment. + +By using determininistc file paths during the ovmf build, it removes the +opportunitity for gcc/ld to change the output binaries due to path lengths +overflowing section sizes and causing small changes in the binary output. +Previously we relied on the stripped output being the same which isn't always +the case if the size of the debug symbols varies. + +Upstream-Status: Submitted [https://github.com/tianocore/edk2/pull/2202] +Signed-off-by: Richard Purdie +Signed-off-by: Alexander Kanavin --- BaseTools/Conf/tools_def.template | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template -index 0f110fbb4a..35205db748 100755 +index 0caa1c9001..dd86b3249d 100755 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template -@@ -896,7 +896,7 @@ NOOPT_*_*_OBJCOPY_ADDDEBUGFLAG = --add-gnu-debuglink="$(DEBUG_DIR)/$(MODULE_ +@@ -920,7 +920,7 @@ NOOPT_*_*_OBJCOPY_ADDDEBUGFLAG = --add-gnu-debuglink="$(DEBUG_DIR)/$(MODULE_ *_*_*_DTC_PATH = DEF(DTC_BIN) # All supported GCC archs except LOONGARCH64 support -mstack-protector-guard=global, so set that on everything except LOONGARCH64 @@ -20,18 +34,18 @@ index 0f110fbb4a..35205db748 100755 DEFINE GCC_IA32_X64_CC_FLAGS = -mstack-protector-guard=global DEFINE GCC_ARM_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mlittle-endian -mabi=aapcs -fno-short-enums -funsigned-char -ffunction-sections -fdata-sections -fomit-frame-pointer -Wno-address -mthumb -fno-pic -fno-pie -mstack-protector-guard=global DEFINE GCC_LOONGARCH64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) -mabi=lp64d -fno-asynchronous-unwind-tables -Wno-address -fno-short-enums -fsigned-char -ffunction-sections -fdata-sections -@@ -918,8 +918,8 @@ DEFINE GCC_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) -Wl,--entry,Refere +@@ -938,8 +938,8 @@ DEFINE GCC_ARM_AARCH64_ASLDLINK_FLAGS = -Wl,--defsym=PECOFF_HEADER_SIZE=0 DEF(GC + DEFINE GCC_ARM_ASLDLINK_FLAGS = DEF(GCC_ARM_DLINK_FLAGS) -Wl,--entry,ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS) DEFINE GCC_AARCH64_ASLDLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -Wl,--entry,ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) DEF(GCC_ARM_AARCH64_ASLDLINK_FLAGS) DEFINE GCC_LOONGARCH64_ASLDLINK_FLAGS = DEF(GCC_LOONGARCH64_DLINK_FLAGS) -Wl,--entry,ReferenceAcpiTable -u $(IMAGE_ENTRY_POINT) - DEFINE GCC_IA32_X64_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_COMMON) --entry _$(IMAGE_ENTRY_POINT) --file-alignment 0x20 --section-alignment 0x20 -Map $(DEST_DIR_DEBUG)/$(BASE_NAME).map -DEFINE GCC_ASM_FLAGS = -c -x assembler -imacros AutoGen.h -DEFINE GCC_PP_FLAGS = -E -x assembler-with-cpp -include AutoGen.h +DEFINE GCC_ASM_FLAGS = -c -x assembler -imacros AutoGen.h ENV(GCC_PREFIX_MAP) +DEFINE GCC_PP_FLAGS = -E -x assembler-with-cpp -include AutoGen.h ENV(GCC_PREFIX_MAP) - DEFINE GCC_VFRPP_FLAGS = -x c -E -P -DVFRCOMPILE --include $(MODULE_NAME)StrDefs.h + DEFINE GCC_VFRPP_FLAGS = -x c -E -DVFRCOMPILE --include $(MODULE_NAME)StrDefs.h DEFINE GCC_ASLPP_FLAGS = -x c -E -include AutoGen.h DEFINE GCC_ASLCC_FLAGS = -x c -@@ -1072,7 +1072,7 @@ DEFINE GCC5_LOONGARCH64_PP_FLAGS = -mabi=lp64d -march=loongarch64 DEF( +@@ -1092,7 +1092,7 @@ DEFINE GCC5_LOONGARCH64_PP_FLAGS = -mabi=lp64d -march=loongarch64 DEF( *_GCC48_IA32_DLINK2_FLAGS = DEF(GCC48_IA32_DLINK2_FLAGS) *_GCC48_IA32_RC_FLAGS = DEF(GCC_IA32_RC_FLAGS) *_GCC48_IA32_OBJCOPY_FLAGS = @@ -40,7 +54,7 @@ index 0f110fbb4a..35205db748 100755 DEBUG_GCC48_IA32_CC_FLAGS = DEF(GCC48_IA32_CC_FLAGS) RELEASE_GCC48_IA32_CC_FLAGS = DEF(GCC48_IA32_CC_FLAGS) -Wno-unused-but-set-variable -@@ -1100,7 +1100,7 @@ RELEASE_GCC48_IA32_CC_FLAGS = DEF(GCC48_IA32_CC_FLAGS) -Wno-unused-but-set +@@ -1120,7 +1120,7 @@ RELEASE_GCC48_IA32_CC_FLAGS = DEF(GCC48_IA32_CC_FLAGS) -Wno-unused-but-set *_GCC48_X64_DLINK2_FLAGS = DEF(GCC48_X64_DLINK2_FLAGS) *_GCC48_X64_RC_FLAGS = DEF(GCC_X64_RC_FLAGS) *_GCC48_X64_OBJCOPY_FLAGS = @@ -49,7 +63,7 @@ index 0f110fbb4a..35205db748 100755 DEBUG_GCC48_X64_CC_FLAGS = DEF(GCC48_X64_CC_FLAGS) RELEASE_GCC48_X64_CC_FLAGS = DEF(GCC48_X64_CC_FLAGS) -Wno-unused-but-set-variable -@@ -1209,7 +1209,7 @@ RELEASE_GCC48_AARCH64_CC_FLAGS = DEF(GCC48_AARCH64_CC_FLAGS) -Wno-unused-but-s +@@ -1229,7 +1229,7 @@ RELEASE_GCC48_AARCH64_CC_FLAGS = DEF(GCC48_AARCH64_CC_FLAGS) -Wno-unused-but-s *_GCC49_IA32_DLINK2_FLAGS = DEF(GCC49_IA32_DLINK2_FLAGS) *_GCC49_IA32_RC_FLAGS = DEF(GCC_IA32_RC_FLAGS) *_GCC49_IA32_OBJCOPY_FLAGS = @@ -58,7 +72,7 @@ index 0f110fbb4a..35205db748 100755 DEBUG_GCC49_IA32_CC_FLAGS = DEF(GCC49_IA32_CC_FLAGS) RELEASE_GCC49_IA32_CC_FLAGS = DEF(GCC49_IA32_CC_FLAGS) -Wno-unused-but-set-variable -Wno-unused-const-variable -@@ -1237,7 +1237,7 @@ RELEASE_GCC49_IA32_CC_FLAGS = DEF(GCC49_IA32_CC_FLAGS) -Wno-unused-but-set +@@ -1257,7 +1257,7 @@ RELEASE_GCC49_IA32_CC_FLAGS = DEF(GCC49_IA32_CC_FLAGS) -Wno-unused-but-set *_GCC49_X64_DLINK2_FLAGS = DEF(GCC49_X64_DLINK2_FLAGS) *_GCC49_X64_RC_FLAGS = DEF(GCC_X64_RC_FLAGS) *_GCC49_X64_OBJCOPY_FLAGS = @@ -67,7 +81,7 @@ index 0f110fbb4a..35205db748 100755 DEBUG_GCC49_X64_CC_FLAGS = DEF(GCC49_X64_CC_FLAGS) RELEASE_GCC49_X64_CC_FLAGS = DEF(GCC49_X64_CC_FLAGS) -Wno-unused-but-set-variable -Wno-unused-const-variable -@@ -1496,7 +1496,7 @@ RELEASE_GCCNOLTO_AARCH64_DLINK_XIPFLAGS = -z common-page-size=0x20 +@@ -1516,7 +1516,7 @@ RELEASE_GCCNOLTO_AARCH64_DLINK_XIPFLAGS = -z common-page-size=0x20 *_GCC5_IA32_DLINK2_FLAGS = DEF(GCC5_IA32_DLINK2_FLAGS) -no-pie *_GCC5_IA32_RC_FLAGS = DEF(GCC_IA32_RC_FLAGS) *_GCC5_IA32_OBJCOPY_FLAGS = @@ -76,7 +90,7 @@ index 0f110fbb4a..35205db748 100755 DEBUG_GCC5_IA32_CC_FLAGS = DEF(GCC5_IA32_CC_FLAGS) -flto DEBUG_GCC5_IA32_DLINK_FLAGS = DEF(GCC5_IA32_X64_DLINK_FLAGS) -flto -Os -Wl,-m,elf_i386,--oformat=elf32-i386 -@@ -1528,7 +1528,7 @@ RELEASE_GCC5_IA32_DLINK_FLAGS = DEF(GCC5_IA32_X64_DLINK_FLAGS) -flto -Os -Wl, +@@ -1548,7 +1548,7 @@ RELEASE_GCC5_IA32_DLINK_FLAGS = DEF(GCC5_IA32_X64_DLINK_FLAGS) -flto -Os -Wl, *_GCC5_X64_DLINK2_FLAGS = DEF(GCC5_X64_DLINK2_FLAGS) *_GCC5_X64_RC_FLAGS = DEF(GCC_X64_RC_FLAGS) *_GCC5_X64_OBJCOPY_FLAGS = @@ -85,6 +99,3 @@ index 0f110fbb4a..35205db748 100755 DEBUG_GCC5_X64_CC_FLAGS = DEF(GCC5_X64_CC_FLAGS) -flto -DUSING_LTO DEBUG_GCC5_X64_DLINK_FLAGS = DEF(GCC5_X64_DLINK_FLAGS) -flto -Os --- -2.43.0 - diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch index 7b73762..73f2423 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch @@ -1,8 +1,32 @@ -From 81fc61513cf51a9ef6947dcf4bc1388a50c13f42 Mon Sep 17 00:00:00 2001 -From: Kevin Wang -Date: Mon, 4 Nov 2024 04:29:41 +0000 -Subject: [PATCH 4/5] Reproduciable +From 0d22e07cd9cc35ede04c01d3141068db744d7677 Mon Sep 17 00:00:00 2001 +From: Alexander Kanavin +Date: Mon, 14 Jun 2021 19:57:30 +0200 +Subject: [PATCH] reproducible +This patch fixes various things which make the build more reproducible. Some changes +here only change intermediate artefacts but that means when you have two build trees +giving differing results, the differences can be isolated more easily. The issues here +usually become apparent with longer paths. + +This was all debugged with: +TMPDIR = "${TOPDIR}/tmp" +vs. +TMPDIR = "${TOPDIR}/tmp-inital-mylongpath-mylongpath-mylongpath-mylongpath-mylongpath-mylongpath-mylongpath-mylongpath-mylongpath" + +The patch specifically: + + * Sorts output in GNUmakefile + * Always generates indirect flags files used to avoid pathlength issues else the + compile commands suddenly change when using longer paths + * Sorts the AutoGenTimeStamp file contents + * Makes the TargetDescBlock objects from BuildEngine sortable to allow the makefile fix + * Fix ElfConvert within GenFw so that only the basename of the binary being converted + is used, else the output from "GenFw XXX.bin" differs from "GenFw /long/path/XXX.bin" + with sufficiently long paths + +Upstream-Status: Submitted [https://github.com/tianocore/edk2/pull/2176] +Signed-off-by: Richard Purdie +Signed-off-by: Alexander Kanavin --- BaseTools/Source/C/GenFw/Elf64Convert.c | 8 ++++--- .../Source/Python/AutoGen/BuildEngine.py | 3 +++ @@ -11,19 +35,19 @@ Subject: [PATCH 4/5] Reproduciable 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c -index 9d04fc612e..83fd6c9c05 100644 +index 18594122ea..92b5f13cf6 100644 --- a/BaseTools/Source/C/GenFw/Elf64Convert.c +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c -@@ -13,6 +13,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent - #ifndef __GNUC__ +@@ -15,6 +15,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include + #undef RUNTIME_FUNCTION #include +#else +#define _GNU_SOURCE #endif #include #include -@@ -988,7 +990,7 @@ ScanSections64 ( +@@ -990,7 +992,7 @@ ScanSections64 ( } mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + @@ -32,7 +56,7 @@ index 9d04fc612e..83fd6c9c05 100644 // // Add more space in the .debug data region for the DllCharacteristicsEx -@@ -2299,7 +2301,7 @@ WriteDebug64 ( +@@ -2322,7 +2324,7 @@ WriteDebug64 ( EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10; EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY *DllEntry; @@ -41,7 +65,7 @@ index 9d04fc612e..83fd6c9c05 100644 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]; -@@ -2332,7 +2334,7 @@ WriteDebug64 ( +@@ -2355,7 +2357,7 @@ WriteDebug64 ( Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1); Nb10->Signature = CODEVIEW_SIGNATURE_NB10; @@ -51,7 +75,7 @@ index 9d04fc612e..83fd6c9c05 100644 STATIC diff --git a/BaseTools/Source/Python/AutoGen/BuildEngine.py b/BaseTools/Source/Python/AutoGen/BuildEngine.py -index 45b39d7878..3fed7d1736 100644 +index b829a2503c..afe826b78f 100644 --- a/BaseTools/Source/Python/AutoGen/BuildEngine.py +++ b/BaseTools/Source/Python/AutoGen/BuildEngine.py @@ -70,6 +70,9 @@ class TargetDescBlock(object): @@ -65,10 +89,10 @@ index 45b39d7878..3fed7d1736 100644 if Input not in self.Inputs: self.Inputs.append(Input) diff --git a/BaseTools/Source/Python/AutoGen/GenMake.py b/BaseTools/Source/Python/AutoGen/GenMake.py -index 6d9c60b702..83ac267647 100755 +index e5f282c4ac..27a34ef7c6 100755 --- a/BaseTools/Source/Python/AutoGen/GenMake.py +++ b/BaseTools/Source/Python/AutoGen/GenMake.py -@@ -576,7 +576,7 @@ cleanlib: +@@ -571,7 +571,7 @@ cleanlib: os.remove(RespFileList) # convert source files and binary files to build targets @@ -77,7 +101,7 @@ index 6d9c60b702..83ac267647 100755 if len(self.ResultFileList) == 0 and len(MyAgo.SourceFileList) != 0: EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build", ExtraData="[%s]" % str(MyAgo)) -@@ -727,7 +727,7 @@ cleanlib: +@@ -722,7 +722,7 @@ cleanlib: OutputFile = '' DepsFileList = [] @@ -86,7 +110,7 @@ index 6d9c60b702..83ac267647 100755 if Cmd[2]: for CopyCmd in Cmd[2]: Src, Dst = CopyCmd -@@ -760,7 +760,7 @@ cleanlib: +@@ -755,7 +755,7 @@ cleanlib: self.BuildTargetList.append('\t%s' % CmdString) self.ParseSecCmd(DepsFileList, Cmd[1]) @@ -95,7 +119,7 @@ index 6d9c60b702..83ac267647 100755 self.BuildTargetList.append('%s : %s' % (self.ReplaceMacro(SecOutputFile), self.ReplaceMacro(SecDepsFile))) self.BuildTargetList.append('\t%s' % self.ReplaceMacro(SecCmd)) self.FfsOutputFileList = [] -@@ -799,13 +799,13 @@ cleanlib: +@@ -794,13 +794,13 @@ cleanlib: def CommandExceedLimit(self): FlagDict = { @@ -116,7 +140,7 @@ index 6d9c60b702..83ac267647 100755 } RespDict = {} -@@ -1008,9 +1008,9 @@ cleanlib: +@@ -1014,9 +1014,9 @@ cleanlib: if not self.ObjTargetDict.get(T.Target.SubDir): self.ObjTargetDict[T.Target.SubDir] = set() self.ObjTargetDict[T.Target.SubDir].add(NewFile) @@ -129,10 +153,10 @@ index 6d9c60b702..83ac267647 100755 if T.GenFileListMacro and T.FileListMacro not in self.FileListMacros: self.FileListMacros[T.FileListMacro] = [] diff --git a/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py b/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py -index 65a2176ca9..318b9611ce 100755 +index aa0b71632e..57c9cad117 100755 --- a/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py +++ b/BaseTools/Source/Python/AutoGen/ModuleAutoGen.py -@@ -1474,6 +1474,9 @@ class ModuleAutoGen(AutoGen): +@@ -1429,6 +1429,9 @@ class ModuleAutoGen(AutoGen): for File in Files: if File.lower().endswith('.pdb'): AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File) @@ -142,7 +166,7 @@ index 65a2176ca9..318b9611ce 100755 HeaderComments = self.Module.HeaderComments StartPos = 0 for Index in range(len(HeaderComments)): -@@ -1749,7 +1752,7 @@ class ModuleAutoGen(AutoGen): +@@ -1704,7 +1707,7 @@ class ModuleAutoGen(AutoGen): if os.path.exists (self.TimeStampPath): os.remove (self.TimeStampPath) @@ -151,6 +175,3 @@ index 65a2176ca9..318b9611ce 100755 # Ignore generating makefile when it is a binary module if self.IsBinaryModule: --- -2.43.0 - diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch deleted file mode 100644 index 12a1c8c..0000000 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 596f2e3bd7292c8f22cfe01ec95b8b46ce1bc8a1 Mon Sep 17 00:00:00 2001 -From: Kevin Wang -Date: Mon, 4 Nov 2024 04:35:18 +0000 -Subject: [PATCH] Declare ProcessLibraryConstructorList - ---- - OvmfPkg/IntelTdx/Sec/SecMain.c | 1 + - OvmfPkg/Sec/SecMain.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.c b/OvmfPkg/IntelTdx/Sec/SecMain.c -index 7f2d28af95..fcc6b97c28 100644 ---- a/OvmfPkg/IntelTdx/Sec/SecMain.c -+++ b/OvmfPkg/IntelTdx/Sec/SecMain.c -@@ -163,6 +163,7 @@ SecCoreStartupWithStack ( - IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable; - IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); - -+ void ProcessLibraryConstructorList (); - ProcessLibraryConstructorList (); - - // -diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c -index d13a948509..58c48c967c 100644 ---- a/OvmfPkg/Sec/SecMain.c -+++ b/OvmfPkg/Sec/SecMain.c -@@ -885,6 +885,7 @@ SecCoreStartupWithStack ( - InitializeCpuExceptionHandlers (NULL); - } - -+ void ProcessLibraryConstructorList (); - ProcessLibraryConstructorList (); - - if (!SevEsIsEnabled ()) { --- -2.43.0 - diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb index 96fcda3..0cf1e10 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb @@ -19,16 +19,15 @@ PACKAGECONFIG[tpm] = "-D TPM_ENABLE=TRUE,-D TPM_ENABLE=FALSE,," #see https://src.fedoraproject.org/rpms/edk2/blob/rawhide/f/0032-Basetools-turn-off-gcc12-warning.patch BUILD_CFLAGS += "-Wno-error=stringop-overflow" -SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ +SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https;tag=${PV} \ file://0001-Update-path-to-native-BaseTools.patch \ file://0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch \ file://0003-Debug-prefix-map.patch \ file://0004-Reproduciable.patch \ - file://0005-Declare-ProcessLibraryConstructorList.patch \ " -PV = "edk2-3a3b12cb" -SRCREV = "3a3b12cbdae2e89b0e365eb01c378891d0d9037c" +PV = "edk2-stable202508" +SRCREV = "d46aa46c8361194521391aa581593e556c707c6e" UPSTREAM_CHECK_GITTAGREGEX = "(?Pedk2-stable.*)" CVE_PRODUCT = "edk2" @@ -49,7 +48,6 @@ inherit deploy PARALLEL_MAKE = "" -S = "${WORKDIR}/git" DEPENDS = "nasm-native acpica-native ovmf-native util-linux-native" diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb index 1d4e512..cf50744 100644 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb +++ b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb @@ -11,7 +11,6 @@ SRC_URI = "git://github.com/openzfs/zfs;protocol=https;branch=zfs-2.2-release \ file://0001-fs-tests-cmd-readmmap-Replace-uint_t-with-uint32_t.patch \ " -S = "${WORKDIR}/git" # Using both 'module' and 'autotools' classes seems a bit odd, they both # define a do_compile function. diff --git a/meta-dstack/recipes-core/images/dstack-initscript.bb b/meta-dstack/recipes-core/images/dstack-initscript.bb index ee32b1a..1d0f7c6 100644 --- a/meta-dstack/recipes-core/images/dstack-initscript.bb +++ b/meta-dstack/recipes-core/images/dstack-initscript.bb @@ -9,7 +9,8 @@ FILES:${PN} = "*" inherit allarch -S = "${WORKDIR}" +UNPACKDIR = "${WORKDIR}/sources" +S = "${UNPACKDIR}" do_install() { install -d ${D}/ diff --git a/meta-dstack/recipes-core/images/dstack-initscript/init b/meta-dstack/recipes-core/images/dstack-initscript/init old mode 100644 new mode 100755 diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc b/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc index 1996e07..eacc68b 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc @@ -1,4 +1,4 @@ include dstack-rootfs-base.inc IMAGE_INSTALL += "packagegroup-core-ssh-openssh strace tcpdump gdb gdbserver vim" -EXTRA_IMAGE_FEATURES += "debug-tweaks tools-profile" +EXTRA_IMAGE_FEATURES += "allow-root-login post-install-logging" diff --git a/meta-dstack/recipes-core/pahole/pahole_1.25.bbappend b/meta-dstack/recipes-core/pahole/pahole_1.25.bbappend deleted file mode 100644 index 9ebd860..0000000 --- a/meta-dstack/recipes-core/pahole/pahole_1.25.bbappend +++ /dev/null @@ -1,2 +0,0 @@ -# Update pahole to 1.29 for BTF reproducible build -SRCREV = "b9cc7963051b2099795129450f9b70c81950d02f" diff --git a/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb b/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb index 7f943d7..e134f3e 100644 --- a/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb +++ b/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb @@ -11,6 +11,8 @@ SRC_DIR = '${REPO_ROOT}/dstack/mod-tdx-guest' SRC_URI = 'file://${REPO_ROOT}/dstack/mod-tdx-guest' SRCREV = "${DSTACK_SRC_REV}" -S = "${WORKDIR}/${SRC_DIR}" +S = "${UNPACKDIR}/${SRC_DIR}" RPROVIDES:${PN} += "tdx-guest-ko" +INSANE_SKIP:${PN} += "buildpaths" +INSANE_SKIP:${PN}-dbg += "buildpaths" diff --git a/meta-openembedded b/meta-openembedded index 72018ca..a4e768d 160000 --- a/meta-openembedded +++ b/meta-openembedded @@ -1 +1 @@ -Subproject commit 72018ca1b1a471226917e8246e8bbf9a374ccf97 +Subproject commit a4e768dcfae181dd99e39c4286fa0729ca7f4e47 diff --git a/meta-rust-bin b/meta-rust-bin index 5397489..678a792 160000 --- a/meta-rust-bin +++ b/meta-rust-bin @@ -1 +1 @@ -Subproject commit 53974894fe1bf0fba26d0f6d5ded32b3c3f4a43e +Subproject commit 678a792edb50aceb491bd74bcb6d4d6cc79c8b63 diff --git a/meta-security b/meta-security index bc63d95..a54650c 160000 --- a/meta-security +++ b/meta-security @@ -1 +1 @@ -Subproject commit bc63d95746ef4f0ac6820165e5041d83647e8c9c +Subproject commit a54650c743b7534f60fc6ee1df9b57a8f0150a4d diff --git a/meta-virtualization b/meta-virtualization index bce9962..26e2b40 160000 --- a/meta-virtualization +++ b/meta-virtualization @@ -1 +1 @@ -Subproject commit bce9962c515089d62082953b795c0e80083c96e2 +Subproject commit 26e2b40b91f2424b0b9318b50dbb700a67714b6f diff --git a/meta-yocto b/meta-yocto new file mode 160000 index 0000000..d02d3fa --- /dev/null +++ b/meta-yocto @@ -0,0 +1 @@ +Subproject commit d02d3faaf4d6075ea03e9eb47654ec7639f929a0 diff --git a/mkimage.sh b/mkimage.sh index 9f98640..c000b07 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -46,7 +46,7 @@ VERITY_ENV_FILE=${BB_BUILD_DIR}/tmp/work-shared/tdx/dm-verity/${ROOTFS_IMAGE_NAM echo "Loading verity env from ${VERITY_ENV_FILE}" source ${VERITY_ENV_FILE} -DSTACK_VERSION=$(bitbake-getvar --value DISTRO_VERSION) +DSTACK_VERSION=$(bitbake-getvar --value DISTRO_VERSION | tail -1) OUTPUT_DIR=${OUTPUT_DIR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}"} IMAGE_TAR=${IMAGE_TAR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}.tar.gz"} diff --git a/openembedded-core b/openembedded-core new file mode 160000 index 0000000..8519978 --- /dev/null +++ b/openembedded-core @@ -0,0 +1 @@ +Subproject commit 8519978592483bb096ed5192fff7af6c887b799e diff --git a/poky b/poky deleted file mode 160000 index cd44e6b..0000000 --- a/poky +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cd44e6bd40b0c1f498b3feaeb5e9b72f8bf32d41 From c7e3d5217fe5cee1a1821375c595239c1a9ec17d Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:10:44 +0000 Subject: [PATCH 003/119] Adding minimal stdio.h stub to satisfy libgcc-initial configure --- .../gcc/libgcc-initial_%.bbappend | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 meta-dstack/recipes-devtools/gcc/libgcc-initial_%.bbappend diff --git a/meta-dstack/recipes-devtools/gcc/libgcc-initial_%.bbappend b/meta-dstack/recipes-devtools/gcc/libgcc-initial_%.bbappend new file mode 100644 index 0000000..c006d6e --- /dev/null +++ b/meta-dstack/recipes-devtools/gcc/libgcc-initial_%.bbappend @@ -0,0 +1,19 @@ +python dstack_stub_stdio() { + import os + staging_incdir = d.getVar('STAGING_INCDIR') + stdio = os.path.join(staging_incdir, 'stdio.h') + if not os.path.exists(stdio): + bb.note("Adding minimal stdio.h stub to satisfy libgcc-initial configure") + with open(stdio, 'w') as fh: + fh.write('#ifndef __YOCTO_DUMMY_STDIO__\n') + fh.write('#define __YOCTO_DUMMY_STDIO__\n') + fh.write('typedef int FILE;\n') + fh.write('extern FILE *stdin;\n') + fh.write('extern FILE *stdout;\n') + fh.write('extern FILE *stderr;\n') + fh.write('static inline int printf(const char *fmt, ...) { (void)fmt; return 0; }\n') + fh.write('#endif\n') +} + +do_configure[prefuncs] += "dstack_stub_stdio" +DEBUG_FLAGS = "" From 400b67cf6f2430c0d164db1cd7723e713f1470ec Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:06:25 +0000 Subject: [PATCH 004/119] systemd handle volatile deps --- .../systemd/systemd/blacklist-autofs4.conf | 3 --- .../recipes-core/systemd/systemd_%.bbappend | 17 ++++++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 meta-dstack/recipes-core/systemd/systemd/blacklist-autofs4.conf diff --git a/meta-dstack/recipes-core/systemd/systemd/blacklist-autofs4.conf b/meta-dstack/recipes-core/systemd/systemd/blacklist-autofs4.conf deleted file mode 100644 index 0b88b12..0000000 --- a/meta-dstack/recipes-core/systemd/systemd/blacklist-autofs4.conf +++ /dev/null @@ -1,3 +0,0 @@ -# Disable autofs4 module loading -blacklist autofs4 -install autofs4 /bin/true diff --git a/meta-dstack/recipes-core/systemd/systemd_%.bbappend b/meta-dstack/recipes-core/systemd/systemd_%.bbappend index 8c49ea4..f73be27 100644 --- a/meta-dstack/recipes-core/systemd/systemd_%.bbappend +++ b/meta-dstack/recipes-core/systemd/systemd_%.bbappend @@ -1,16 +1,15 @@ -FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" - -SRC_URI += "file://blacklist-autofs4.conf" - do_install:append() { # Disable systemd-vconsole-setup.service rm -f ${D}${systemd_system_unitdir}/sysinit.target.wants/systemd-vconsole-setup.service - # Install modprobe blacklist for autofs4 - install -d ${D}${sysconfdir}/modprobe.d - install -m 0644 ${WORKDIR}/blacklist-autofs4.conf ${D}${sysconfdir}/modprobe.d/ + # Ensure systemd-resolved waits for /var/volatile tmpfs and tmpfiles setup + install -d ${D}${systemd_system_unitdir}/systemd-resolved.service.d + cat <<'EOF' > ${D}${systemd_system_unitdir}/systemd-resolved.service.d/10-var-volatile.conf +[Unit] +After=systemd-tmpfiles-setup.service var-volatile.mount +Requires=var-volatile.mount +EOF } SYSTEMD_SERVICE:${PN}-vconsole-setup = "" - -FILES:${PN} += "${sysconfdir}/modprobe.d/blacklist-autofs4.conf" +PACKAGECONFIG:remove = "sysvinit logind" From 2e5695898afdee90e33ddedd267a9ca236f62421 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:05:37 +0000 Subject: [PATCH 005/119] Volatile /etc/ --- meta-dstack/recipes-core/images/dstack-rootfs-base.inc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 4f4acc1..1acf99a 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -142,11 +142,4 @@ mkdirs() { mkdir -p ${IMAGE_ROOTFS}/etc/wireguard mkdir -p ${IMAGE_ROOTFS}/var/lib/docker ln -sf dstack ${IMAGE_ROOTFS}/tapp - - # Aliases passwd files to a subdirectory - mkdir -p ${IMAGE_ROOTFS}/etc/users - mv ${IMAGE_ROOTFS}/etc/passwd ${IMAGE_ROOTFS}/etc/users/ - mv ${IMAGE_ROOTFS}/etc/shadow ${IMAGE_ROOTFS}/etc/users/ - ln -s users/passwd ${IMAGE_ROOTFS}/etc/passwd - ln -s users/shadow ${IMAGE_ROOTFS}/etc/shadow } From dd579e0e40cc29e872eaf7e72bc565bd8c95b489 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:05:09 +0000 Subject: [PATCH 006/119] Rust 1.92.0 --- meta-dstack/conf/distro/dstack.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 6040b8a..71a028e 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -19,8 +19,8 @@ VIRTUAL-RUNTIME_initscripts = "" VIRTUAL-RUNTIME_dev_manager = "systemd" SERIAL_CONSOLES = "115200;ttyS0" -PREFERRED_VERSION_rust-bin-cross-x86_64 = "1.86.0" -PREFERRED_VERSION_cargo-bin-cross-x86_64 = "1.86.0" +PREFERRED_VERSION_rust-bin-cross-x86_64 = "1.92.0" +PREFERRED_VERSION_cargo-bin-cross-x86_64 = "1.92.0" BAD_RECOMMENDATIONS = "busybox-syslog systemd-compat-units" From ce97ff87e8683d045d2d5c12f70cdbb96e9d8d93 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:54:50 +0000 Subject: [PATCH 007/119] Suppress the warn Text file busy in build.sh --- build.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 054c59f..1e1d207 100755 --- a/build.sh +++ b/build.sh @@ -113,7 +113,10 @@ EOF build_host() { echo "Building binaries" (cd $DSTACK_DIR && cargo build --release --target-dir ${RUST_BUILD_DIR}) - cp ${RUST_BUILD_DIR}/release/{dstack-gateway,dstack-kms,dstack-vmm,supervisor} . + for bin in dstack-gateway dstack-kms dstack-vmm supervisor; do + cp "${RUST_BUILD_DIR}/release/${bin}" ".${bin}.new" + mv -f ".${bin}.new" "./${bin}" + done } # Step 2: build guest images From d583c53b13d3c2e8d65216025f73e02a54258ff8 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:54:32 +0000 Subject: [PATCH 008/119] Remove CF_ZONE_ID --- build.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.sh b/build.sh index 1e1d207..a70ce85 100755 --- a/build.sh +++ b/build.sh @@ -85,7 +85,6 @@ GATEWAY_PUBLIC_DOMAIN= # for certbot CERTBOT_ENABLED=false CF_API_TOKEN= -CF_ZONE_ID= ACME_URL=https://acme-staging-v02.api.letsencrypt.org/directory EOF if [ -f $CONFIG_FILE ]; then @@ -224,8 +223,6 @@ workdir = "$CERBOT_WORKDIR" acme_url = "$ACME_URL" # Cloudflare API token cf_api_token = "$CF_API_TOKEN" -# Cloudflare zone ID -cf_zone_id = "$CF_ZONE_ID" # Auto set CAA record auto_set_caa = true # Domain to issue certificates for From afe57867c474fd7467f17a31c6dd2157e5aaaa17 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:42:11 +0000 Subject: [PATCH 009/119] Rename DStack to dstack --- README.md | 4 ++-- meta-dstack/conf/distro/dstack.conf | 2 +- .../recipes-core/base-files/files/dstack-motd | 2 +- .../recipes-core/dstack-guest/dstack-guest.bb | 2 +- .../recipes-core/images/dstack-initscript.bb | 2 +- .../linux/files/dstack-docker.scc | 2 +- .../recipes-kernel/linux/files/dstack-tdx.scc | 2 +- .../recipes-kernel/linux/files/dstack.scc | 2 +- scripts/bin/dstack.py | 18 +++++++++--------- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 65790d7..74c6b7c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Yocto support for DStack Guest +# Yocto support for dstack guest OS -This project implements Yocto layer and the overall build scripts for DStack Base OS image. +This project implements Yocto layer and the overall build scripts for dstack Base OS image. ## Build diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 71a028e..0cbe136 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -1,6 +1,6 @@ require conf/distro/cvm.conf DISTRO = "dstack" -DISTRO_NAME = "DStack" +DISTRO_NAME = "dstack" DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6" DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" diff --git a/meta-dstack/recipes-core/base-files/files/dstack-motd b/meta-dstack/recipes-core/base-files/files/dstack-motd index 047731e..5376caf 100644 --- a/meta-dstack/recipes-core/base-files/files/dstack-motd +++ b/meta-dstack/recipes-core/base-files/files/dstack-motd @@ -5,4 +5,4 @@ ██████╔╝███████║ ██║ ██║ ██║╚██████╗██║ ██╗ ██║ ███████╗███████╗ ╚██████╔╝███████║ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝ ╚══════╝ -Welcome to Dstack! +Welcome to dstack! diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 06cab0b..4c6e903 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -1,4 +1,4 @@ -SUMMARY = "Guest binaries for DStack, a decentralized computing stack" +SUMMARY = "Guest binaries for dstack, a decentralized computing stack" DESCRIPTION = "${SUMMARY}" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" diff --git a/meta-dstack/recipes-core/images/dstack-initscript.bb b/meta-dstack/recipes-core/images/dstack-initscript.bb index 1d0f7c6..61908cc 100644 --- a/meta-dstack/recipes-core/images/dstack-initscript.bb +++ b/meta-dstack/recipes-core/images/dstack-initscript.bb @@ -1,4 +1,4 @@ -SUMMARY = "Dstack initramfs files" +SUMMARY = "dstack initramfs files" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-docker.scc b/meta-dstack/recipes-kernel/linux/files/dstack-docker.scc index 40bf76d..09dda98 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack-docker.scc +++ b/meta-dstack/recipes-kernel/linux/files/dstack-docker.scc @@ -1,3 +1,3 @@ -define KFEATURE_DESCRIPTION "DStack Docker configuration" +define KFEATURE_DESCRIPTION "dstack Docker configuration" kconf non-hardware dstack-docker.cfg diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-tdx.scc b/meta-dstack/recipes-kernel/linux/files/dstack-tdx.scc index e7a9aba..5786a66 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack-tdx.scc +++ b/meta-dstack/recipes-kernel/linux/files/dstack-tdx.scc @@ -1,3 +1,3 @@ -define KFEATURE_DESCRIPTION "DStack TDX configuration" +define KFEATURE_DESCRIPTION "dstack TDX configuration" kconf non-hardware dstack-tdx.cfg diff --git a/meta-dstack/recipes-kernel/linux/files/dstack.scc b/meta-dstack/recipes-kernel/linux/files/dstack.scc index 4725b80..e277ce0 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack.scc +++ b/meta-dstack/recipes-kernel/linux/files/dstack.scc @@ -1,3 +1,3 @@ -define KFEATURE_DESCRIPTION "DStack configuration" +define KFEATURE_DESCRIPTION "dstack configuration" kconf non-hardware dstack.cfg diff --git a/scripts/bin/dstack.py b/scripts/bin/dstack.py index 5274ba4..73c810d 100755 --- a/scripts/bin/dstack.py +++ b/scripts/bin/dstack.py @@ -144,14 +144,14 @@ def gen_vm_config(vm_dir, host_port, manifest=None, os_image_hash=None): @dataclass -class DStackConfig: - """Configuration for DStack client.""" +class DstackConfig: + """Configuration for dstack client.""" docker_registry: Optional[str] = None default_image_name: str = '' qemu_path: str = 'qemu-system-x86_64' @classmethod - def load(cls) -> 'DStackConfig': + def load(cls) -> 'DstackConfig': """Load configuration from file.""" cfgs = load_configs_merged(generate_config_paths()) @@ -167,10 +167,10 @@ def cfg_get(section, key, fallback): return me -class DStackManager: +class DstackManager: def __init__(self): self.run_path = os.path.abspath(os.getenv('RUN_PATH', './vms')) - self.config = DStackConfig.load() + self.config = DstackConfig.load() def _generate_instance_id(self) -> str: """Generate a random instance ID.""" @@ -365,7 +365,7 @@ def resolve_gpus(gpus: dict) -> dict: case 'listed': return gpus case 'all': - return DStackManager.collect_all_gpus() + return DstackManager.collect_all_gpus() case _: raise ValueError( f"Invalid GPU attach mode: {gpus['attach_mode']}") @@ -797,7 +797,7 @@ def write_to_sysfs(path, value): def main(): - parser = argparse.ArgumentParser(description='DStack VM Management Tool') + parser = argparse.ArgumentParser(description='dstack VM Management Tool') subparsers = parser.add_subparsers(dest='command', help='Commands') # Setup command @@ -849,10 +849,10 @@ def main(): args = parser.parse_args() if args.command == 'new': - manager = DStackManager() + manager = DstackManager() manager.setup_instance(args) elif args.command == 'run': - manager = DStackManager() + manager = DstackManager() thread = start_server(args.dir, args.kp_port) manager.run_instance(args.dir, thread.host_port, imgdir=args.imgdir, dry_run=args.dry_run) From 3c0e2a01ae8e2baf6202caa1bbc6456f12eaf70b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:42:44 +0000 Subject: [PATCH 010/119] More stable network in bb build --- bb-build/conf/local.conf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bb-build/conf/local.conf b/bb-build/conf/local.conf index b87c10a..a51d8c2 100644 --- a/bb-build/conf/local.conf +++ b/bb-build/conf/local.conf @@ -157,6 +157,9 @@ DISTRO ?= "dstack" # - 'buildstats' collect build statistics USER_CLASSES ?= "buildstats" +# Prefer faster GNU mirror +GNU_MIRRORS = "https://ftpmirror.gnu.org/gnu/" + # # Runtime testing of images # @@ -286,3 +289,5 @@ BB_DISKMON_DIRS ??= "\ # track the version of this file when it was generated. This can safely be ignored if # this doesn't mean anything to you. CONF_VERSION = "2" + +FETCHCMD_wget = "wget --progress=dot --inet4-only -c" \ No newline at end of file From 8fd64a5ec31dd13a72d75ed885961962bdd714cd Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:49:51 +0000 Subject: [PATCH 011/119] Use custom kernel 6.17 --- meta-dstack/conf/distro/dstack.conf | 4 +- .../images/dstack-rootfs-base.inc | 1 - ...0001-x86-tdx-select-dma-direct-remap.patch | 35 ++ .../recipes-kernel/linux/files/6.17/defconfig | 359 ++++++++++++++++++ .../linux/linux-custom_6.17.6.bb | 36 ++ 5 files changed, 432 insertions(+), 3 deletions(-) create mode 100644 meta-dstack/recipes-kernel/linux/files/0001-x86-tdx-select-dma-direct-remap.patch create mode 100644 meta-dstack/recipes-kernel/linux/files/6.17/defconfig create mode 100644 meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 0cbe136..9613503 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -8,8 +8,8 @@ DISTRO_VERSION = "0.5.5" DISTROOVERRIDES = "poky:dstack" INITRAMFS_IMAGE = "" -PREFERRED_PROVIDER_virtual/kernel = "linux-yocto-dev" -PREFERRED_VERSION_linux-yocto-dev ?= "6.9%" +PREFERRED_PROVIDER_virtual/kernel = "linux-custom" +PREFERRED_VERSION_linux-custom ?= "6.17.6" LINUX_KERNEL_TYPE = "tiny" MACHINE_FEATURES += "numa" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 1acf99a..657ab27 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -12,7 +12,6 @@ IMAGE_INSTALL = "\ iptables \ docker-moby \ docker-compose \ - tdx-guest-ko \ dstack-guest \ wireguard-tools \ cryptsetup \ diff --git a/meta-dstack/recipes-kernel/linux/files/0001-x86-tdx-select-dma-direct-remap.patch b/meta-dstack/recipes-kernel/linux/files/0001-x86-tdx-select-dma-direct-remap.patch new file mode 100644 index 0000000..662dd17 --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/files/0001-x86-tdx-select-dma-direct-remap.patch @@ -0,0 +1,35 @@ +From 48cf4656e9a23f7f5b4a2f6a0e5b5b2b6d5e5b6d Mon Sep 17 00:00:00 2001 +From: h4x +Date: Mon, 27 Oct 2025 23:52:02 +0000 +Subject: [PATCH] x86/tdx: select DMA_DIRECT_REMAP for encrypted guests + +TDX guests require DMA buffers to be mapped out of the shared (decrypted) +pool in order for shared devices such as NVMe to complete I/O. Without +DMA_DIRECT_REMAP the dma-direct layer falls back to allocations from the +regular page allocator, leaving the memory encrypted and causing every +request to wedge once it hits the host. + +Ensure the TDX guest configuration pulls in DMA_DIRECT_REMAP, which in +turn enables the coherent DMA pool machinery and honours the +`coherent_pool=` kernel parameter. + +Upstream-Status: Inappropriate [TDX guest specific selection] +Signed-off-by: h4x +--- + arch/x86/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 5d57930be347..c1b55a4bf4f0 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -886,6 +886,7 @@ config INTEL_TDX_GUEST + depends on EFI_STUB + depends on PARAVIRT + select ARCH_HAS_CC_PLATFORM ++ select DMA_DIRECT_REMAP + select X86_MEM_ENCRYPT + select X86_MCE + select UNACCEPTED_MEMORY +-- +2.46.0 diff --git a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig new file mode 100644 index 0000000..7c03fce --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig @@ -0,0 +1,359 @@ +CONFIG_LOCALVERSION="-dstack" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZMA=y +CONFIG_KERNEL_GZIP=y +CONFIG_DMA_COHERENT_POOL=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_DEBUG=y +CONFIG_USER_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_SMP=y +CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_INTEL_TDX_GUEST=y +CONFIG_TDX_GUEST_DRIVER=y +CONFIG_TSM_REPORTS=y +CONFIG_CONFIGFS_FS=y +CONFIG_NR_CPUS=512 +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_X86_CHECK_BIOS_CORRUPTION=y +CONFIG_EFI=y +CONFIG_EFI_STUB=y +CONFIG_HZ_1000=y +# CONFIG_SUSPEND is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_INTEL_IDLE=y +CONFIG_IA32_EMULATION=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_XFRM_USER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_INET_ESP=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES_COMPAT=y +CONFIG_NETFILTER_XTABLES_LEGACY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NETMAP=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_VS=m +CONFIG_NF_REJECT_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=y +CONFIG_6LOWPAN=m +CONFIG_NET_SCHED=y +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y +CONFIG_HYPERV_VSOCKETS=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_CFG80211=m +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCI_MSI=y +CONFIG_PCI_IOV=y +CONFIG_PCI_HYPERV=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_COHERENT_POOL=y +CONFIG_CMA=y +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_CMA_SIZE_MBYTES=64 +CONFIG_DMA_CMA=y +CONFIG_GVE=y +CONFIG_SWIOTLB_DYNAMIC=y +CONFIG_ZONE_DMA=y +CONFIG_CONNECTOR=y +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=1 +CONFIG_BLK_DEV_RAM_SIZE=6144 +CONFIG_VIRTIO_BLK=y +CONFIG_BLK_DEV_NVME=y +CONFIG_EEPROM_AT24=m +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_SCSI_FC_ATTRS=y +CONFIG_SCSI_VIRTIO=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_ATA_PIIX=y +CONFIG_PATA_SCH=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_WIREGUARD=y +CONFIG_IPVLAN=m +CONFIG_VXLAN=y +CONFIG_NETCONSOLE=y +CONFIG_TUN=m +CONFIG_VETH=y +CONFIG_VIRTIO_NET=y +CONFIG_TYPHOON=m +CONFIG_PCNET32=m +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL1C=m +CONFIG_ALX=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_BNXT=m +CONFIG_DL2K=m +CONFIG_E100=y +CONFIG_E1000=y +CONFIG_E1000E=y +CONFIG_IGB=y +CONFIG_IGBVF=m +CONFIG_IGC=m +CONFIG_JME=m +CONFIG_SKGE=m +CONFIG_SKY2=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_R8169=m +CONFIG_REALTEK_PHY_HWMON=y +CONFIG_USB_NET_DRIVERS=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_KC2190=y +# CONFIG_WLAN is not set +CONFIG_HYPERV_NET=y +CONFIG_ISDN=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_PRINTER=m +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HPET=y +CONFIG_TCG_TPM=y +CONFIG_TCG_TPM2_HMAC=y +CONFIG_TCG_TIS=y +CONFIG_TCG_CRB=y +CONFIG_I2C_I801=y +CONFIG_WATCHDOG=y +CONFIG_BCMA=m +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_DRM=y +CONFIG_DRM_I915=m +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_DRM_CIRRUS_QEMU=m +CONFIG_FB=y +CONFIG_FB_UVESA=m +CONFIG_FB_EFI=y +CONFIG_FB_HYPERV=y +CONFIG_HID_HYPERV_MOUSE=y +CONFIG_HID_WACOM=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CONSOLE=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_EZUSB_FX2=y +CONFIG_RTC_CLASS=y +CONFIG_VIRT_DRIVERS=y +CONFIG_EFI_SECRET=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=y +CONFIG_HYPERV=y +CONFIG_HYPERV_UTILS=y +CONFIG_HYPERV_BALLOON=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=y +CONFIG_ISO9660_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_SQUASHFS=y +CONFIG_VXFS_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_9P_FS=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AES_TI=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_CRYPTO_AES_NI_INTEL=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_CORDIC=m +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNWINDER_FRAME_POINTER=y + +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y diff --git a/meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb b/meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb new file mode 100644 index 0000000..200982d --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb @@ -0,0 +1,36 @@ +SUMMARY = "dstack Linux kernel 6.17.6 built from tarball" +DESCRIPTION = "Custom dstack kernel based on upstream Linux 6.17.6 with tiny Kconfig baseline tuned for TDX guests" +SECTION = "kernel" +LICENSE = "GPL-2.0-only" +LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" + +PV = "6.17.6" +LINUX_VERSION = "${PV}" + +inherit kernel + +FILESEXTRAPATHS:prepend := "${THISDIR}/files/6.17:${THISDIR}/files:" + +DEPENDS += "libyaml-native openssl-native util-linux-native elfutils-native" + +SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${PV}.tar.xz;downloadfilename=linux-${PV}.tar.xz \ + file://defconfig \ + file://0001-x86-tdx-select-dma-direct-remap.patch \ +" + +SRC_URI[sha256sum] = "8ecfbc6b693448abb46144a8d04d1e1631639c7661c1088425a2e5406f13c69c" + +S = "${UNPACKDIR}/linux-${PV}" + +LINUX_VERSION_EXTENSION = "-dstack" +KERNEL_VERSION_EXTENSION = "-dstack" + +# Enable BTF debug info for bpftool and out-of-tree modules (ZFS, WireGuard, etc.) +KERNEL_DEBUG = "True" + +# Keep packaging aligned with our tiny x86_64 guest machines. +COMPATIBLE_MACHINE = "(tdx|sev-snp|qemux86-64)" + +do_deploy:append() { + install -m 0644 ${B}/.config ${DEPLOYDIR}/kernel-config +} From dd731b0822a313160521dcb151b21509d0868d9c Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:53:28 +0000 Subject: [PATCH 012/119] Make GCP image --- Makefile | 2 +- meta-dstack/conf/distro/dstack.conf | 3 + .../images/dstack-initscript/init | 134 ++++++++++---- .../images/dstack-rootfs-base.inc | 2 + meta-dstack/recipes-core/images/dstack-uki.bb | 133 ++++++++++++++ .../gptfdisk/gptfdisk_%.bbappend | 2 + mkimage.sh | 170 +++++++++++++++++- scripts/bin/authenticode_hash.py | 138 ++++++++++++++ 8 files changed, 549 insertions(+), 35 deletions(-) create mode 100644 meta-dstack/recipes-core/images/dstack-uki.bb create mode 100644 meta-dstack/recipes-devtools/gptfdisk/gptfdisk_%.bbappend create mode 100644 scripts/bin/authenticode_hash.py diff --git a/Makefile b/Makefile index 2d0a053..700cdb1 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ dist: images $(foreach dist_name,${DIST_NAMES},./mkimage.sh --dist-name $(dist_name);) images: - bitbake virtual/kernel dstack-initramfs dstack-ovmf $(ROOTFS_IMAGE_NAMES) + bitbake virtual/kernel dstack-initramfs dstack-ovmf dstack-uki $(ROOTFS_IMAGE_NAMES) clean: bitbake -c cleansstate virtual/kernel dstack-initramfs dstack-ovmf $(ROOTFS_IMAGE_NAMES) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 9613503..ec6e8ff 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -27,3 +27,6 @@ BAD_RECOMMENDATIONS = "busybox-syslog systemd-compat-units" # Skip unused components that fail metadata checks under walnascar SKIP_RECIPE[ostree] = "not required for dstack" +# EFI/UKI support for GCP images +MACHINE_FEATURES:append = " efi" +EFI_PROVIDER = "systemd-boot" diff --git a/meta-dstack/recipes-core/images/dstack-initscript/init b/meta-dstack/recipes-core/images/dstack-initscript/init index fba1182..968671f 100755 --- a/meta-dstack/recipes-core/images/dstack-initscript/init +++ b/meta-dstack/recipes-core/images/dstack-initscript/init @@ -1,52 +1,120 @@ #!/bin/sh set -e -export PATH=/sbin:/bin:/usr/sbin:/usr/bin +ROOT_DIR=/root +ROOT_DEV="" + +log() { + printf '[init] %s\n' "$*" >&2 +} + +mount_move_all() { + for dir in "$@"; do + mount --move "/$dir" "${ROOT_DIR}/$dir" + done +} + +find_device_by_partlabel() { + label=$1 + + log "searching for PARTLABEL=${label}" + + for entry in /sys/class/block/*; do + [ -f "$entry/partition" ] || continue + uevent="${entry}/uevent" + if [ -f "$uevent" ]; then + current=$(grep -E '^PARTNAME=' "$uevent" 2>/dev/null | head -n1 | cut -d= -f2) + if [ "${current}" = "$label" ]; then + device="/dev/$(basename "$entry")" + if [ -b "$device" ]; then + log "sysfs matched PARTLABEL=${label} at ${device}" + realpath "$device" 2>/dev/null || echo "$device" + return 0 + fi + fi + fi + done + + log "no device found for PARTLABEL=${label}" + return 1 +} + +resolve_root_device() { + if [ -z "$ROOTFS_DEVICE" ]; then + ROOTFS_DEVICE="PARTLABEL=dstack-rootfs" + fi + + if [ "${ROOTFS_DEVICE#PARTLABEL=}" != "$ROOTFS_DEVICE" ]; then + label="${ROOTFS_DEVICE#PARTLABEL=}" + if [ -n "$label" ]; then + device=$(find_device_by_partlabel "$label") + if [ -n "$device" ]; then + log "determined root device via kernel parameter: ${device}" + ROOT_DEV="$device" + return + fi + fi + elif [ "${ROOTFS_DEVICE#/dev/}" != "$ROOTFS_DEVICE" ]; then + ROOT_DEV="$ROOTFS_DEVICE" + return + fi + + log "unable to determine root device from available heuristics" +} -mkdir -p /proc -mkdir -p /sys -mkdir -p /run -mount -t proc proc /proc -mount -t sysfs sysfs /sys -mount -t tmpfs tmpfs /run +main() { + export PATH=/sbin:/bin:/usr/sbin:/usr/bin -mkdir -p /dev -mount -t devtmpfs devtmpfs /dev + mkdir -p /proc + mkdir -p /sys + mkdir -p /run + mount -t proc proc /proc + mount -t sysfs sysfs /sys + mount -t tmpfs tmpfs /run -mkdir -p /dev/pts + mkdir -p /dev + mount -t devtmpfs devtmpfs /dev -# Parse kernel parameters -for param in $(cat /proc/cmdline); do - case "$param" in + mkdir -p /dev/pts + + log "booting dstack initramfs" + + ROOTFS_DEVICE="" + for param in $(cat /proc/cmdline); do + case "$param" in "dstack.rootfs_hash="*) ROOT_HASH="${param#*=}" ;; "dstack.rootfs_size="*) DATA_SIZE="${param#*=}" ;; - *) + "dstack.rootfs_device="*) + ROOTFS_DEVICE="${param#*=}" ;; - esac -done -ROOT_DEV=/dev/vda -ROOT_DIR=/root + *) ;; + esac + done -echo "Setting up verity device:" -echo " Root device: ${ROOT_DEV}" -echo " Root hash: ${ROOT_HASH}" -echo " Data size: ${DATA_SIZE}" + resolve_root_device -veritysetup open ${ROOT_DEV} rootfs ${ROOT_DEV} "${ROOT_HASH}" --hash-offset="${DATA_SIZE}" + if [ -z "$ROOT_DEV" ]; then + log "failed to determine root device" + exit 1 + fi + log "resolved root device: ${ROOT_DEV}" -echo "Mounting rootfs..." -mount -t squashfs /dev/mapper/rootfs ${ROOT_DIR} - -mount_move_all() { - for dir in $@; do - mount --move /$dir ${ROOT_DIR}/$dir - done + if [ -z "${ROOT_HASH}" ] || [ -z "${DATA_SIZE}" ]; then + log "missing dm-verity parameters; refusing to continue" + exit 1 + fi + veritysetup open "${ROOT_DEV}" rootfs "${ROOT_DEV}" "${ROOT_HASH}" --hash-offset="${DATA_SIZE}" + log "mounting verified rootfs from /dev/mapper/rootfs" + mount -t squashfs /dev/mapper/rootfs ${ROOT_DIR} + mount_move_all sys proc dev run + log "switching root to ${ROOT_DIR}" + exec switch_root ${ROOT_DIR} /sbin/init + log "switch_root failed" + exit 1 } -mount_move_all sys proc dev run -echo "Switching to new root..." -exec switch_root ${ROOT_DIR} /sbin/init +main "$@" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 657ab27..8c94032 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -31,6 +31,8 @@ IMAGE_INSTALL = "\ xfsprogs \ e2fsprogs \ e2fsprogs-resize2fs \ + gptfdisk \ + parted \ " IMAGE_NAME_SUFFIX ?= "" diff --git a/meta-dstack/recipes-core/images/dstack-uki.bb b/meta-dstack/recipes-core/images/dstack-uki.bb new file mode 100644 index 0000000..c9883ba --- /dev/null +++ b/meta-dstack/recipes-core/images/dstack-uki.bb @@ -0,0 +1,133 @@ +# Unified Kernel Image (UKI) for dstack +# +# This recipe generates a UKI containing kernel, initramfs, and cmdline +# with dm-verity root hash for GCP deployment. + +SUMMARY = "dstack Unified Kernel Image" +LICENSE = "MIT" + +DEPENDS = "systemd-boot systemd-boot-native virtual/kernel python3-pefile-native" + +inherit image-artifact-names +require conf/image-uefi.conf + +# Initramfs settings +INITRAMFS_IMAGE = "dstack-initramfs" +INITRAMFS_FSTYPES = "cpio.gz" + +# Kernel settings +KERNEL_IMAGETYPE = "bzImage" + +# Output filename +UKI_FILENAME = "dstack-uki.efi" + +# Base kernel cmdline (verity hash added dynamically) +UKI_CMDLINE_BASE = "console=ttyS0 init=/init panic=1 net.ifnames=0 biosdevname=0 \ +mce=off oops=panic pci=noearly pci=nommconf random.trust_cpu=y random.trust_bootloader=n \ +tsc=reliable no-kvmclock" + +# Verity image to get hash from +# Override with VERITY_IMAGE = "dstack-dev-rootfs" for dev builds +VERITY_IMAGE ?= "dstack-rootfs" +VERITY_TYPE = "squashfs" + +do_configure[noexec] = "1" +do_compile[noexec] = "1" +do_install[noexec] = "1" + +# Dependencies +do_uki[depends] += "systemd-boot:do_deploy virtual/kernel:do_deploy" +do_uki[depends] += "${INITRAMFS_IMAGE}:do_image_complete" +do_uki[depends] += "${VERITY_IMAGE}:do_image_complete" + +python do_uki() { + import os + import bb.process + + deploy_dir = d.getVar('DEPLOY_DIR_IMAGE') + target_arch = d.getVar('EFI_ARCH') + + # Find the EFI stub + stub = os.path.join(deploy_dir, f"linux{target_arch}.efi.stub") + if not os.path.exists(stub): + bb.fatal(f"EFI stub not found: {stub}") + + # Find kernel + kernel = os.path.join(deploy_dir, d.getVar('KERNEL_IMAGETYPE')) + if not os.path.exists(kernel): + bb.fatal(f"Kernel not found: {kernel}") + + # Find initramfs + initramfs_image = d.getVar('INITRAMFS_IMAGE') + machine = d.getVar('MACHINE') + initramfs_fstypes = d.getVar('INITRAMFS_FSTYPES') + initrd = os.path.join(deploy_dir, f"{initramfs_image}-{machine}.{initramfs_fstypes}") + if not os.path.exists(initrd): + bb.fatal(f"Initramfs not found: {initrd}") + + # Read verity hash + staging_verity_dir = d.getVar('STAGING_VERITY_DIR') or d.expand('${TMPDIR}/work-shared/${MACHINE}/dm-verity') + verity_image = d.getVar('VERITY_IMAGE') + verity_type = d.getVar('VERITY_TYPE') + verity_env = os.path.join(staging_verity_dir, f"{verity_image}.{verity_type}.verity.env") + + root_hash = "" + data_size = "" + + if os.path.exists(verity_env): + with open(verity_env, 'r') as f: + for line in f: + line = line.strip() + if line.startswith('ROOT_HASH='): + root_hash = line.split('=', 1)[1] + elif line.startswith('DATA_SIZE='): + data_size = line.split('=', 1)[1] + bb.note(f"Read verity env: root_hash={root_hash}, data_size={data_size}") + else: + bb.fatal(f"Verity env file not found: {verity_env}") + + # Build cmdline + cmdline_base = d.getVar('UKI_CMDLINE_BASE') + cmdline = f"{cmdline_base} dstack.rootfs_hash={root_hash} dstack.rootfs_size={data_size}" + bb.note(f"UKI cmdline: {cmdline}") + + # Output path + output = os.path.join(deploy_dir, d.getVar('UKI_FILENAME')) + + # Build ukify command with proper Python paths + native_sysroot = d.getVar('RECIPE_SYSROOT_NATIVE') + staging_libdir = d.getVar('STAGING_LIBDIR_NATIVE') + + # Find Python version directory for native packages + python_sitepackages = os.path.join(staging_libdir, 'python3.13', 'site-packages') + + # Set environment for ukify + env = os.environ.copy() + env['PYTHONPATH'] = python_sitepackages + + ukify_path = os.path.join(native_sysroot, 'usr', 'bin', 'ukify') + ukify_cmd = f"{ukify_path} build" + ukify_cmd += f" --efi-arch {target_arch}" + ukify_cmd += f" --stub {stub}" + ukify_cmd += f" --linux={kernel}" + ukify_cmd += f" --initrd={initrd}" + ukify_cmd += f" --cmdline='{cmdline}'" + ukify_cmd += f" --tools={native_sysroot}/usr/lib/systemd/tools" + ukify_cmd += f" --output={output}" + + bb.note(f"Running: {ukify_cmd}") + bb.note(f"PYTHONPATH: {python_sitepackages}") + + import subprocess + result = subprocess.run(ukify_cmd, shell=True, capture_output=True, text=True, env=env) + if result.stdout: + bb.note(result.stdout) + if result.stderr: + bb.note(result.stderr) + if result.returncode != 0: + bb.fatal(f"ukify failed with exit code {result.returncode}") + + bb.note(f"UKI created: {output}") +} + +addtask uki before do_build diff --git a/meta-dstack/recipes-devtools/gptfdisk/gptfdisk_%.bbappend b/meta-dstack/recipes-devtools/gptfdisk/gptfdisk_%.bbappend new file mode 100644 index 0000000..af3122b --- /dev/null +++ b/meta-dstack/recipes-devtools/gptfdisk/gptfdisk_%.bbappend @@ -0,0 +1,2 @@ +# Disable ncurses/cgdisk to avoid linking against libncursesw (not in our images) +PACKAGECONFIG:remove = "ncurses" diff --git a/mkimage.sh b/mkimage.sh index c000b07..0028a46 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -2,6 +2,7 @@ set -e DSTACK_TAR_RELEASE=${DSTACK_TAR_RELEASE:-1} +ENABLE_GCP_IMAGE=${ENABLE_GCP_IMAGE:-1} # Parse command line arguments while [ $# -gt 0 ]; do @@ -41,6 +42,7 @@ INITRAMFS_IMAGE=${IMG_DIR}/dstack-initramfs.cpio.gz ROOTFS_IMAGE=${IMG_DIR}/${ROOTFS_IMAGE_NAME}-tdx.squashfs.verity KERNEL_IMAGE=${IMG_DIR}/bzImage OVMF_FIRMWARE=${IMG_DIR}/ovmf.fd +UKI_IMAGE=${IMG_DIR}/dstack-uki.efi # Always use the work-shared directory which has the correct verity env VERITY_ENV_FILE=${BB_BUILD_DIR}/tmp/work-shared/tdx/dm-verity/${ROOTFS_IMAGE_NAME}.squashfs.verity.env echo "Loading verity env from ${VERITY_ENV_FILE}" @@ -50,11 +52,153 @@ DSTACK_VERSION=$(bitbake-getvar --value DISTRO_VERSION | tail -1) OUTPUT_DIR=${OUTPUT_DIR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}"} IMAGE_TAR=${IMAGE_TAR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}.tar.gz"} +AUTHENTICODE_HASH_SCRIPT="${BB_BUILD_DIR}/../scripts/bin/authenticode_hash.py" + verbose() { echo "$@" $@ } +align_up() { + local value=$1 + local align=$2 + echo $(( ( (value + align - 1) / align ) * align )) +} + +calc_authenticode_hash() { + local file="$1" + + if [[ ! -f "$AUTHENTICODE_HASH_SCRIPT" ]] || ! command -v python3 &>/dev/null; then + return 0 + fi + + python3 "$AUTHENTICODE_HASH_SCRIPT" "$file" 2>/dev/null || true +} + +write_authenticode_hash_if_missing() { + local file="$1" + local out_file="${file}.auth_hash.txt" + + if [[ -f "$out_file" ]]; then + return 0 + fi + + if [[ ! -f "$file" ]]; then + return 0 + fi + + if [[ ! -f "$AUTHENTICODE_HASH_SCRIPT" ]] || ! command -v python3 &>/dev/null; then + echo "Warning: authenticode_hash.py not found or python3 not available, skipping Authenticode hash calculation" >&2 + return 0 + fi + + echo "Calculating UKI Authenticode hash..." + local auth_hash + auth_hash=$(calc_authenticode_hash "$file") + if [[ -n "$auth_hash" ]]; then + echo "$auth_hash" > "$out_file" + echo "UKI Authenticode hash: $auth_hash" + else + echo "Warning: Failed to calculate UKI Authenticode hash" >&2 + fi +} + +create_uki_bootstrap() { + local target_dir="$1" + mkdir -p "$target_dir/EFI/BOOT" + + local uki_file="${UKI_IMAGE}" + if [[ ! -f "$uki_file" ]]; then + echo "Error: UKI image not found: $uki_file" >&2 + return 1 + fi + cp "$uki_file" "$target_dir/EFI/BOOT/BOOTX64.EFI" + + # Calculate Authenticode hash if not already present + write_authenticode_hash_if_missing "$uki_file" +} + +create_partitioned_rootfs() { + local rootfs_img="$1" + local output_img="$2" + ( + set -e + local align=$((1024 * 1024)) + local sector=512 + local rootfs_size=$(stat -c %s "$rootfs_img") + local rootfs_size_aligned=$(align_up $rootfs_size $align) + local rootfs_start=$align + # Leave extra room for GPT headers (1MB at start, 1MB at end) + local total_size=$(align_up $((rootfs_start + rootfs_size_aligned + align)) $align) + + truncate -s $total_size "$output_img" + + local root_start_sector=$((rootfs_start / sector)) + local root_end_sector=$((root_start_sector + (rootfs_size_aligned / sector) - 1)) + + sgdisk --zap-all "$output_img" >/dev/null + sgdisk --new=1:${root_start_sector}:${root_end_sector} --typecode=1:8300 --change-name=1:'dstack-rootfs' "$output_img" >/dev/null + + dd if="$rootfs_img" of="$output_img" bs=$align seek=$((rootfs_start / align)) conv=notrunc status=none + ) +} + +build_gcp_disk_image() { + local disk_img="$1" + local boot_source="$2" + local rootfs_img="$3" + ( + set -e + local align=$((1024 * 1024)) + local sector=512 + local efi_size=$((256 * 1024 * 1024)) + local efi_size_aligned=$(align_up $efi_size $align) + local rootfs_size=$(stat -c %s "$rootfs_img") + local rootfs_size_aligned=$(align_up $rootfs_size $align) + local efi_start=$align + local rootfs_start=$((efi_start + efi_size_aligned)) + # Leave extra room for the backup GPT header + local total_size=$(align_up $((rootfs_start + rootfs_size_aligned + align)) $align) + + truncate -s $total_size "$disk_img" + + local efi_start_sector=$((efi_start / sector)) + local efi_end_sector=$((efi_start_sector + (efi_size_aligned / sector) - 1)) + local root_start_sector=$((rootfs_start / sector)) + local root_end_sector=$((root_start_sector + (rootfs_size_aligned / sector) - 1)) + + sgdisk --zap-all "$disk_img" >/dev/null + sgdisk --new=1:${efi_start_sector}:${efi_end_sector} --typecode=1:ef00 --change-name=1:'EFI System Partition' "$disk_img" >/dev/null + sgdisk --new=2:${root_start_sector}:${root_end_sector} --typecode=2:8300 --change-name=2:'dstack-rootfs' "$disk_img" >/dev/null + + local tmp_dir + tmp_dir=$(mktemp -d) + trap 'rm -rf "$tmp_dir"' EXIT + local efi_img=${tmp_dir}/efi.img + mkfs.vfat -F 32 -n DSTACKEFI -C "$efi_img" $((efi_size_aligned / 1024)) >/dev/null + (cd "$boot_source" && mcopy -s -i "$efi_img" ./* ::) >/dev/null + + dd if="$efi_img" of="$disk_img" bs=$align seek=$((efi_start / align)) conv=notrunc status=none + dd if="$rootfs_img" of="$disk_img" bs=$align seek=$((rootfs_start / align)) conv=notrunc status=none + ) +} + +create_gcp_artifacts() { + local gcp_dir="${OUTPUT_DIR}/gcp" + local boot_src="${gcp_dir}/efi-root" + mkdir -p "$boot_src" + echo "Installing UKI as EFI bootloader at ${boot_src}" + create_uki_bootstrap "$boot_src" + + local disk_img="${gcp_dir}/disk.raw" + echo "Building raw disk image for GCP at ${disk_img}" + build_gcp_disk_image "$disk_img" "$boot_src" "${OUTPUT_DIR}/rootfs.img.verity" + + local tarball="${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}-gcp.tar.gz" + echo "Archiving GCP disk image to ${tarball}" + (cd "$gcp_dir" && tar -czvf "$tarball" disk.raw) +} + Q=verbose $Q rm -rf ${OUTPUT_DIR}/ @@ -64,6 +208,14 @@ $Q cp $KERNEL_IMAGE ${OUTPUT_DIR}/ $Q cp $OVMF_FIRMWARE ${OUTPUT_DIR}/ $Q cp $ROOTFS_IMAGE ${OUTPUT_DIR}/rootfs.img.verity +# Copy UKI Authenticode hash if available +if [[ -f "${UKI_IMAGE}.auth_hash.txt" ]]; then + $Q cp "${UKI_IMAGE}.auth_hash.txt" "${OUTPUT_DIR}/dstack-uki.efi.auth_hash.txt" +fi + +echo "Creating partitioned rootfs image at ${OUTPUT_DIR}/rootfs.img.parted.verity" +create_partitioned_rootfs "${OUTPUT_DIR}/rootfs.img.verity" "${OUTPUT_DIR}/rootfs.img.parted.verity" + GIT_REVISION=$(git rev-parse HEAD 2>/dev/null || echo "") echo "Generating metadata.json to ${OUTPUT_DIR}/metadata.json" @@ -77,7 +229,7 @@ cat < ${OUTPUT_DIR}/metadata.json "kernel": "bzImage", "cmdline": "$KARG0 $KARG1 $KARG2", "initrd": "initramfs.cpio.gz", - "rootfs": "rootfs.img.verity", + "rootfs": "rootfs.img.parted.verity", "version": "$DSTACK_VERSION", "git_revision": "$GIT_REVISION", "shared_ro": true, @@ -91,6 +243,22 @@ sha256sum ovmf.fd bzImage initramfs.cpio.gz metadata.json > sha256sum.txt sha256sum sha256sum.txt | awk '{print $1}' > digest.txt popd +if [ "$ENABLE_GCP_IMAGE" = "1" ]; then + if [[ ! -f "$UKI_IMAGE" ]]; then + echo "Skipping GCP disk image creation because UKI image not found: $UKI_IMAGE" >&2 + echo "Run 'bitbake dstack-uki' to build the UKI first" >&2 + elif command -v sgdisk >/dev/null && \ + command -v mkfs.vfat >/dev/null && \ + command -v mcopy >/dev/null; then + create_gcp_artifacts + else + echo "Error: cannot create GCP disk image because required tools are missing" >&2 + echo "Missing tools are among: sgdisk (gdisk), mkfs.vfat (dosfstools), mcopy (mtools)" >&2 + echo "Install them (e.g. apt-get install -y gdisk dosfstools mtools) or set ENABLE_GCP_IMAGE=0" >&2 + exit 1 + fi +fi + if [ x$DSTACK_TAR_RELEASE = x1 ]; then IMAGE_TAR_MR=${DIST_DIR}/mr_$(cat ${OUTPUT_DIR}/digest.txt | tr -d '\n').tar.gz IMAGE_TAR_NO_ROOTFS=${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}-mr.tar.gz diff --git a/scripts/bin/authenticode_hash.py b/scripts/bin/authenticode_hash.py new file mode 100644 index 0000000..de7096f --- /dev/null +++ b/scripts/bin/authenticode_hash.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 + +import argparse +import hashlib + + +def read_le_u16(data: bytes, offset: int) -> int: + import struct + + return struct.unpack(' int: + import struct + + return struct.unpack(' str: + with open(filepath, 'rb') as f: + data = f.read() + + # Read DOS header + lfanew_offset = 0x3C + lfanew = read_le_u32(data, lfanew_offset) + + # Verify PE signature + pe_sig_offset = lfanew + pe_sig = read_le_u32(data, pe_sig_offset) + IMAGE_NT_SIGNATURE = 0x00004550 # "PE\0\0" + if pe_sig != IMAGE_NT_SIGNATURE: + raise ValueError(f"Invalid PE signature in {filepath}") + + # Read COFF header + coff_header_offset = pe_sig_offset + 4 + optional_header_size = read_le_u16(data, coff_header_offset + 16) + + # Read Optional header magic + optional_header_offset = coff_header_offset + 20 + magic = read_le_u16(data, optional_header_offset) + + is_pe32_plus = (magic == 0x20B) + + # Calculate offsets for excluded regions (checksum and cert directory) + checksum_offset = optional_header_offset + 64 + checksum_end = checksum_offset + 4 + + data_dir_offset = optional_header_offset + (112 if is_pe32_plus else 96) + IMAGE_DIRECTORY_ENTRY_SECURITY = 4 + cert_dir_offset = data_dir_offset + (IMAGE_DIRECTORY_ENTRY_SECURITY * 8) + cert_dir_end = cert_dir_offset + 8 + + size_of_headers_offset = optional_header_offset + 60 + size_of_headers = read_le_u32(data, size_of_headers_offset) + + # Hash header (excluding checksum and cert directory) + hasher = hashlib.sha256() + hasher.update(data[0:checksum_offset]) + hasher.update(data[checksum_end:cert_dir_offset]) + hasher.update(data[cert_dir_end:size_of_headers]) + + sum_of_bytes_hashed = size_of_headers + + # Read section table + num_sections_offset = coff_header_offset + 2 + num_sections = read_le_u16(data, num_sections_offset) + + section_table_offset = optional_header_offset + optional_header_size + section_size = 40 + + sections = [] + for i in range(num_sections): + section_offset = section_table_offset + (i * section_size) + + ptr_raw_data_offset = section_offset + 20 + ptr_raw_data = read_le_u32(data, ptr_raw_data_offset) + + size_raw_data_offset = section_offset + 16 + size_raw_data = read_le_u32(data, size_raw_data_offset) + + if size_raw_data > 0: + sections.append((ptr_raw_data, size_raw_data)) + + # Sort sections by offset + sections.sort(key=lambda x: x[0]) + + # Hash sections + for offset, size in sections: + start = offset + end = start + size + + if end <= len(data): + hasher.update(data[start:end]) + else: + available_size = max(0, len(data) - start) + if available_size > 0: + hasher.update(data[start:start + available_size]) + + sum_of_bytes_hashed += size + + file_size = len(data) + + # Read certificate table info + cert_table_addr = read_le_u32(data, cert_dir_offset) + cert_table_size = read_le_u32(data, cert_dir_offset + 4) + + # Hash trailing data (excluding certificate table) + if cert_table_addr > 0 and cert_table_size > 0 and file_size > sum_of_bytes_hashed: + trailing_data_len = file_size - sum_of_bytes_hashed + + if trailing_data_len > cert_table_size: + hashed_trailing_len = trailing_data_len - cert_table_size + trailing_start = sum_of_bytes_hashed + + if trailing_start + hashed_trailing_len <= len(data): + hasher.update(data[trailing_start:trailing_start + hashed_trailing_len]) + + # Add padding to align to 8 bytes + remainder = file_size % 8 + if remainder != 0: + padding = bytes([0] * (8 - remainder)) + hasher.update(padding) + + return hasher.hexdigest() + + +def main() -> None: + parser = argparse.ArgumentParser( + description='Calculate PE/COFF Authenticode SHA256 hash (TPM Event Log compatible)' + ) + parser.add_argument('file', help='Path to PE/COFF binary (e.g., UKI .efi)') + args = parser.parse_args() + + print(authenticode_hash(args.file)) + + +if __name__ == '__main__': + main() From 624131a5bd5ba03df0ef97e23e1a4be665d6e1d2 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:56:17 +0000 Subject: [PATCH 013/119] Add tpm-tools and lib --- dev-setup | 1 + meta-dstack/conf/distro/dstack.conf | 2 +- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 2 +- meta-dstack/recipes-core/images/dstack-rootfs-base.inc | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dev-setup b/dev-setup index 51d3a7a..976e79b 100755 --- a/dev-setup +++ b/dev-setup @@ -24,6 +24,7 @@ LAYERS="$THIS_DIR/meta-confidential-compute \ $THIS_DIR/meta-virtualization \ $THIS_DIR/meta-rust-bin \ $THIS_DIR/meta-security \ + $THIS_DIR//meta-security/meta-tpm \ $THIS_DIR/meta-dstack" if [ -z "$1" ]; then diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index ec6e8ff..8314bd5 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -1,7 +1,7 @@ require conf/distro/cvm.conf DISTRO = "dstack" DISTRO_NAME = "dstack" -DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6" +DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6 tpm2" DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" DISTRO_VERSION = "0.5.5" diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 4c6e903..7b1769f 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -13,7 +13,7 @@ S = "${UNPACKDIR}/dstack" RDEPENDS:${PN} += "bash" -DEPENDS += "rsync-native" +DEPENDS += "rsync-native libtss2-dev" # Ensure rsync-native is built before unpack runs do_unpack[depends] += "rsync-native:do_populate_sysroot" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 8c94032..4352108 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -33,6 +33,7 @@ IMAGE_INSTALL = "\ e2fsprogs-resize2fs \ gptfdisk \ parted \ + tpm2-tools \ " IMAGE_NAME_SUFFIX ?= "" From f1ce52757bca0fceb2f81c9bcf29366d37260973 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 01:56:34 +0000 Subject: [PATCH 014/119] Update dstack --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 7bf1843..72ffe34 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 7bf1843a8ddf877fbaebb9898a7f27a19a49ab73 +Subproject commit 72ffe344dacf2316c7e4a42803eda2af4e3cd15b From 0aa78d457d03d42dd69e278880defac530924f99 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:04:26 +0000 Subject: [PATCH 015/119] Update zfs to 2.4.0 --- ...eadmmap-Replace-uint_t-with-uint32_t.patch | 46 --------------- ...8a4630af60496c9d33db1d06a7d7d8983422.patch | 56 ------------------- ...stack-zfs_2.2.5.bb => dstack-zfs_2.4.0.bb} | 6 +- 3 files changed, 2 insertions(+), 106 deletions(-) delete mode 100644 meta-dstack/recipes-core/dstack-zfs/dstack-zfs/0001-fs-tests-cmd-readmmap-Replace-uint_t-with-uint32_t.patch delete mode 100644 meta-dstack/recipes-core/dstack-zfs/dstack-zfs/aaf28a4630af60496c9d33db1d06a7d7d8983422.patch rename meta-dstack/recipes-core/dstack-zfs/{dstack-zfs_2.2.5.bb => dstack-zfs_2.4.0.bb} (92%) diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs/0001-fs-tests-cmd-readmmap-Replace-uint_t-with-uint32_t.patch b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs/0001-fs-tests-cmd-readmmap-Replace-uint_t-with-uint32_t.patch deleted file mode 100644 index f1cfab4..0000000 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs/0001-fs-tests-cmd-readmmap-Replace-uint_t-with-uint32_t.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 1f9a5cb860b3509791e59a8cae9d5f265e832ed0 Mon Sep 17 00:00:00 2001 -From: Khem Raj -Date: Sun, 28 May 2023 16:33:15 -0700 -Subject: [PATCH] fs-tests/cmd/readmmap: Replace uint_t with uint32_t - -Makes it portable across glibc and musl - -Upstream-Status: Pending -Signed-off-by: Khem Raj ---- - tests/zfs-tests/cmd/readmmap.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/tests/zfs-tests/cmd/readmmap.c b/tests/zfs-tests/cmd/readmmap.c -index 704ffd55c8..a2590e0e8d 100644 ---- a/tests/zfs-tests/cmd/readmmap.c -+++ b/tests/zfs-tests/cmd/readmmap.c -@@ -38,6 +38,7 @@ - * 0 : no errors - * -------------------------------------------------------------- - */ -+#include - #include - #include - #include -@@ -55,7 +56,7 @@ main(int argc, char **argv) - char *buf = NULL; - char *map = NULL; - int fd = -1, bytes, retval = 0; -- uint_t seed; -+ uint32_t seed; - - if (argc < 2 || optind == argc) { - (void) fprintf(stderr, -@@ -92,7 +93,7 @@ main(int argc, char **argv) - retval = 1; - goto end; - } -- seed = (uint_t)time(NULL); -+ seed = (uint32_t)time(NULL); - srandom(seed); - - idx = random() % size; --- -2.40.1 - diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs/aaf28a4630af60496c9d33db1d06a7d7d8983422.patch b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs/aaf28a4630af60496c9d33db1d06a7d7d8983422.patch deleted file mode 100644 index f5504b3..0000000 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs/aaf28a4630af60496c9d33db1d06a7d7d8983422.patch +++ /dev/null @@ -1,56 +0,0 @@ -From aaf28a4630af60496c9d33db1d06a7d7d8983422 Mon Sep 17 00:00:00 2001 -From: Sebastian Gottschall -Date: Tue, 23 May 2023 13:50:24 +0600 -Subject: [PATCH] fixes broken aarch64 inline assembly for gcc 13.1 - -fixes the following error - -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_aarch64_neon_common.h:549:24: error: the register specified for 'w7' is not general enough to be used as a register variable - 549 | register unsigned char w7 asm("v7") __attribute__((vector_size(16))); - | ^~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_aarch64_neonx2.c:193:9: note: in expansion of macro 'GEN_X_DEFINE_6_7' - 193 | GEN_X_DEFINE_6_7() \ - | ^~~~~~~~~~~~~~~~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_impl.h:1360:9: note: in expansion of macro 'REC_PQR_DEFINE' - 1360 | REC_PQR_DEFINE(); - | ^~~~~~~~~~~~~~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_aarch64_neon_common.h:551:24: error: the register specified for 'w8' is not general enough to be used as a register variable - 551 | register unsigned char w8 asm("v8") __attribute__((vector_size(16))); \ - | ^~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_aarch64_neonx2.c:194:9: note: in expansion of macro 'GEN_X_DEFINE_8_9' - 194 | GEN_X_DEFINE_8_9() \ - | ^~~~~~~~~~~~~~~~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_impl.h:1360:9: note: in expansion of macro 'REC_PQR_DEFINE' - 1360 | REC_PQR_DEFINE(); - | ^~~~~~~~~~~~~~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_aarch64_neon_common.h:552:24: error: the register specified for 'w9' is not general enough to be used as a register variable - 552 | register unsigned char w9 asm("v9") __attribute__((vector_size(16))); - | ^~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_aarch64_neonx2.c:194:9: note: in expansion of macro 'GEN_X_DEFINE_8_9' - 194 | GEN_X_DEFINE_8_9() \ - | ^~~~~~~~~~~~~~~~ -/mnt/b/yoe/master/build/tmp/work/imx8qm_var_som-yoe-linux/zfs/2.1.9-r0/build/../zfs-2.1.9/module/zfs/vdev_raidz_math_impl.h:1360:9: note: in expansion of macro 'REC_PQR_DEFINE' - 1360 | REC_PQR_DEFINE(); - -Upstream-Status: Pending [https://github.com/BrainSlayer/zfs/commit/aaf28a4630af60496c9d33db1d06a7d7d8983422] -Signed-off-by: Sebastian Gottschall -Signed-off-by: Khem Raj ---- - module/Kbuild.in | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/module/Kbuild.in -+++ b/module/Kbuild.in -@@ -57,9 +57,9 @@ asflags-y := $(ZFS_MODULE_CFLAGS) $(ZFS_ - ccflags-y := $(ZFS_MODULE_CFLAGS) $(ZFS_MODULE_CPPFLAGS) - - ifeq ($(CONFIG_ARM64),y) --CFLAGS_REMOVE_zcommon/zfs_fletcher_aarch64_neon.o += -mgeneral-regs-only --CFLAGS_REMOVE_zfs/vdev_raidz_math_aarch64_neon.o += -mgeneral-regs-only --CFLAGS_REMOVE_zfs/vdev_raidz_math_aarch64_neonx2.o += -mgeneral-regs-only -+CFLAGS_REMOVE_zcommon/zfs_fletcher_aarch64_neon.o = -mgeneral-regs-only -+CFLAGS_REMOVE_zfs/vdev_raidz_math_aarch64_neon.o = -mgeneral-regs-only -+CFLAGS_REMOVE_zfs/vdev_raidz_math_aarch64_neonx2.o = -mgeneral-regs-only - endif - - # Suppress unused-value warnings in sparc64 architecture headers diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb similarity index 92% rename from meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb rename to meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb index cf50744..d068933 100644 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.2.5.bb +++ b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb @@ -4,11 +4,9 @@ LICENSE = "CDDL-1.0" LIC_FILES_CHKSUM = "file://LICENSE;md5=7087caaf1dc8a2856585619f4a787faa" HOMEPAGE ="https://github.com/openzfs/zfs" -SRCREV = "33174af15112ed5c53299da2d28e763b0163f428" -SRC_URI = "git://github.com/openzfs/zfs;protocol=https;branch=zfs-2.2-release \ +SRCREV = "743334913e5a5f60baf287bcc6d8a23515b02ac5" +SRC_URI = "git://github.com/openzfs/zfs;protocol=https;branch=zfs-2.4-release \ file://0001-Define-strndupa-if-it-does-not-exist.patch \ - file://aaf28a4630af60496c9d33db1d06a7d7d8983422.patch \ - file://0001-fs-tests-cmd-readmmap-Replace-uint_t-with-uint32_t.patch \ " From 92e7e548ad91af666e3a1288927d54f03dd06de5 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:04:44 +0000 Subject: [PATCH 016/119] v0.6.0 --- meta-dstack/conf/distro/dstack.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 8314bd5..4294ff8 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -4,7 +4,7 @@ DISTRO_NAME = "dstack" DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6 tpm2" DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" -DISTRO_VERSION = "0.5.5" +DISTRO_VERSION = "0.6.0" DISTROOVERRIDES = "poky:dstack" INITRAMFS_IMAGE = "" From 2193b47c27959499894b616b2745143b30b9b0d3 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:08:53 +0000 Subject: [PATCH 017/119] ssh: Disable password auth --- .../openssh/files/disable-password-auth.conf | 8 ++++++++ .../recipes-connectivity/openssh/openssh_%.bbappend | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 meta-dstack/recipes-connectivity/openssh/files/disable-password-auth.conf create mode 100644 meta-dstack/recipes-connectivity/openssh/openssh_%.bbappend diff --git a/meta-dstack/recipes-connectivity/openssh/files/disable-password-auth.conf b/meta-dstack/recipes-connectivity/openssh/files/disable-password-auth.conf new file mode 100644 index 0000000..47963f2 --- /dev/null +++ b/meta-dstack/recipes-connectivity/openssh/files/disable-password-auth.conf @@ -0,0 +1,8 @@ +# Disable all password-based authentication +PasswordAuthentication no +PermitEmptyPasswords no +KbdInteractiveAuthentication no + +# Only allow public key authentication +PubkeyAuthentication yes +PermitRootLogin prohibit-password diff --git a/meta-dstack/recipes-connectivity/openssh/openssh_%.bbappend b/meta-dstack/recipes-connectivity/openssh/openssh_%.bbappend new file mode 100644 index 0000000..81a2e54 --- /dev/null +++ b/meta-dstack/recipes-connectivity/openssh/openssh_%.bbappend @@ -0,0 +1,10 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI += "file://disable-password-auth.conf" + +do_install:append() { + install -d ${D}${sysconfdir}/ssh/sshd_config.d + install -m 0644 ${UNPACKDIR}/disable-password-auth.conf ${D}${sysconfdir}/ssh/sshd_config.d/ +} + +FILES:${PN}-sshd += "${sysconfdir}/ssh/sshd_config.d/" From 88ebc919fa1af596897e9d3686e403f48f12787c Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:14:35 +0000 Subject: [PATCH 018/119] Update meta-confidential-compute --- meta-confidential-compute | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-confidential-compute b/meta-confidential-compute index 6d1355e..a9857da 160000 --- a/meta-confidential-compute +++ b/meta-confidential-compute @@ -1 +1 @@ -Subproject commit 6d1355e0c684f7fdfb688ecfef0ed63feb2aac4c +Subproject commit a9857da070b542dece7dd0630b3b89804234af7e From 29f2555bed30f54e6d70884d3f251c316af9dd15 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:30:32 +0000 Subject: [PATCH 019/119] Use patched meta-rust-bin --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index f80eb53..415c27a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,7 +20,7 @@ url = https://github.com/openembedded/meta-openembedded [submodule "meta-rust-bin"] path = meta-rust-bin - url = https://github.com/rust-embedded/meta-rust-bin + url = https://github.com/Dstack-TEE/meta-rust-bin [submodule "dstack"] path = dstack url = https://github.com/Dstack-TEE/dstack From 9b5f221fd9e380218e2a992ff2a2b03a5cdfc827 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 02:42:51 +0000 Subject: [PATCH 020/119] Update meta-virtualization --- meta-virtualization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-virtualization b/meta-virtualization index 26e2b40..1c64117 160000 --- a/meta-virtualization +++ b/meta-virtualization @@ -1 +1 @@ -Subproject commit 26e2b40b91f2424b0b9318b50dbb700a67714b6f +Subproject commit 1c64117a5e30dbb8330e8899cae8ac722b9ce553 From 78d1eb494112b2578c288c7fa6a11cf7f3178d57 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 03:35:47 +0000 Subject: [PATCH 021/119] fixup zfs --- meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb index d068933..fc2361d 100644 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb +++ b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb @@ -66,6 +66,9 @@ FILES:${PN}-dev += "\ ${prefix}/src/zfs-${PV} \ ${prefix}/src/spl-${PV} \ " +# Skip buildpaths QA check for kernel modules +INSANE_SKIP:${PN} += "buildpaths" + # Not yet ported to rv32 COMPATIBLE_HOST:riscv32 = "null" # conflicting definition of ABS macro from asm/asm.h from kernel From ed9905484dd3a77efb0368e1f3087198f57b1e9a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 03:37:27 +0000 Subject: [PATCH 022/119] Fix QA errors in meta-virtualization --- meta-virtualization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-virtualization b/meta-virtualization index 1c64117..ebb9f7c 160000 --- a/meta-virtualization +++ b/meta-virtualization @@ -1 +1 @@ -Subproject commit 1c64117a5e30dbb8330e8899cae8ac722b9ce553 +Subproject commit ebb9f7cdd5475efd0fdac840840334376db98fbb From 5a5e27e1fc1debe04940c6de5aa3ac270fa78938 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 03:38:38 +0000 Subject: [PATCH 023/119] Update nvidia receipes --- meta-nvidia/conf/layer.conf | 2 +- .../containerd-config_1.0.0.bb | 2 +- .../libnvidia-container.inc | 18 ++-- .../libnvidia-container/0001-build-fix.patch | 2 + .../libnvidia-container/0002-secomp-fix.patch | 2 + ...-fix-remove-buildpath-for-package-qa.patch | 2 + .../libnvidia-container_1.00.bb | 10 +++ .../libnvidia-container/libtirpc134_1.3.4.bb | 6 +- .../nvidia-container-toolkit.inc | 7 +- .../nvidia-container-toolkit_1.00.bb | 2 +- ...172.08.bb => libnvidia-nscq_580.105.08.bb} | 10 +-- .../nvidia/nvidia-fabricmanager_570.172.08.bb | 86 ------------------- .../nvidia/nvidia-fabricmanager_580.105.08.bb | 64 ++++++++++++++ .../nvidia/nvidia-modprobe-config_1.0.bb | 2 +- .../nvidia/nvidia-persistenced_1.0.bb | 2 +- ...dia_570.172.08.bb => nvidia_580.105.08.bb} | 5 +- 16 files changed, 102 insertions(+), 120 deletions(-) rename meta-nvidia/recipes-graphics/nvidia/{libnvidia-nscq_570.172.08.bb => libnvidia-nscq_580.105.08.bb} (76%) delete mode 100644 meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_570.172.08.bb create mode 100644 meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_580.105.08.bb rename meta-nvidia/recipes-graphics/nvidia/{nvidia_570.172.08.bb => nvidia_580.105.08.bb} (75%) diff --git a/meta-nvidia/conf/layer.conf b/meta-nvidia/conf/layer.conf index 8b179fa..568d6d5 100644 --- a/meta-nvidia/conf/layer.conf +++ b/meta-nvidia/conf/layer.conf @@ -10,4 +10,4 @@ BBFILE_PATTERN_nvidia = "^${LAYERDIR}/" BBFILE_PRIORITY_nvidia = "12" LICENSE_PATH += " ${LAYERDIR}/custom-licenses" -LAYERSERIES_COMPAT_nvidia = "mickledore scarthgap" +LAYERSERIES_COMPAT_nvidia = "whinlatter" diff --git a/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb b/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb index f3c094b..2bc9f85 100644 --- a/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb +++ b/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb @@ -6,7 +6,7 @@ SRC_URI = "file://config.toml" do_install:append() { install -d ${D}${sysconfdir}/containerd - install -m 0644 ${WORKDIR}/config.toml ${D}${sysconfdir}/containerd/ + install -m 0644 ${UNPACKDIR}/config.toml ${D}${sysconfdir}/containerd/ } RDEPENDS:${PN}:append = " containerd-opencontainers" diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc index f93a1ac..4655095 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc @@ -5,26 +5,27 @@ LICENSE = "Apache-2.0" LIC_FILES_CHKSUM = "\ file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://deps/src/nvidia-modprobe-${NVIDIA_MODPROBE_VERSION}/modprobe-utils/nvidia-modprobe-utils.c;endline=22;md5=b6a3106a81660c726888d006853ada63 \ + file://deps/src/nvidia-modprobe-${NVIDIA_MODPROBE_VERSION}/modprobe-utils/nvidia-modprobe-utils.c;endline=22;md5=2ee73384f2a7a7e246230f8a2e2d4b30 \ file://deps/src/nvidia-modprobe-${NVIDIA_MODPROBE_VERSION}/modprobe-utils/pci-enum.h;endline=29;md5=ca948b6fabc48e616fccbf17247feebf \ file://deps/src/nvidia-modprobe-${NVIDIA_MODPROBE_VERSION}/modprobe-utils/pci-sysfs.c;endline=25;md5=0449248350efd54938e7f8d25af965cb \ " ELF_TOOLCHAIN_VERSION = "0.7.1" -NVIDIA_MODPROBE_VERSION = "550.40.07" +NVIDIA_MODPROBE_VERSION = "580.105.08" LIBTIRPC_VERSION = "1.3.4" -SRC_URI = "git://github.com/NVIDIA/libnvidia-container.git;protocol=https;name=libnvidia;branch=release-1.14 \ - git://github.com/NVIDIA/nvidia-modprobe.git;protocol=https;branch=main;name=modprobe;destsuffix=git/deps/src/nvidia-modprobe-${NVIDIA_MODPROBE_VERSION} \ +SRC_URI = "git://github.com/NVIDIA/libnvidia-container.git;protocol=https;name=libnvidia;branch=main \ + git://github.com/NVIDIA/nvidia-modprobe.git;protocol=https;branch=main;name=modprobe;destsuffix=nvidia-modprobe \ file://0001-build-fix.patch \ file://0002-secomp-fix.patch \ file://0003-fix-remove-buildpath-for-package-qa.patch \ " + # SRCREV = "a4ef85ebc86688eeef667271abbc7cd4f1110cf6" -SRCREV_libnvidia = "d2eb0afe86f0b643e33624ee64f065dd60e952d4" +SRCREV_libnvidia = "889a3bb5408c195ed7897ba2cb8341c7d249672f" # Nvidia modprobe version 495.44 -SRCREV_modprobe = "d6bce304f30b6661c9ab6a993f49340eafca7a7e" +SRCREV_modprobe = "0c7433d5b04ce4a97036a939c076416d47427675" SRCREV_FORMAT = "libnvidia_modprobe" DEPENDS = " \ @@ -36,7 +37,4 @@ DEPENDS = " \ libtirpc134 \ ldconfig-native \ " -RDEPENDS:${PN}:append= " ldconfig-compatibility-symlink containerd-config" - - -S = "${WORKDIR}/git" \ No newline at end of file +RDEPENDS:${PN}:append= " ldconfig-compatibility-symlink containerd-config" \ No newline at end of file diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0001-build-fix.patch b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0001-build-fix.patch index 7325aa2..4751aa6 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0001-build-fix.patch +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0001-build-fix.patch @@ -1,3 +1,5 @@ +Upstream-Status: Inappropriate [embedded specific] + diff --git a/Makefile b/Makefile index a374cc09..34d21e25 100644 --- a/Makefile diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0002-secomp-fix.patch b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0002-secomp-fix.patch index 46c5e3a..1a3c465 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0002-secomp-fix.patch +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0002-secomp-fix.patch @@ -1,3 +1,5 @@ +Upstream-Status: Inappropriate [embedded specific] + diff --git a/Makefile b/Makefile index a374cc09..b6632580 100644 --- a/Makefile diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0003-fix-remove-buildpath-for-package-qa.patch b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0003-fix-remove-buildpath-for-package-qa.patch index b672379..ec42da6 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0003-fix-remove-buildpath-for-package-qa.patch +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container/0003-fix-remove-buildpath-for-package-qa.patch @@ -1,3 +1,5 @@ +Upstream-Status: Inappropriate [embedded specific] + From 13cc971cf7ab0bb8fe8528f2ebd65685a81b7ae3 Mon Sep 17 00:00:00 2001 From: Atharva Nandanwar Date: Fri, 19 Aug 2022 15:25:18 -0600 diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb index 2d80136..f53a02d 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb @@ -3,6 +3,16 @@ inherit features_check SUMMARY = "libNVIDIA Container for Yocto" +fakeroot do_unpack_modprobe() { + mkdir -p ${S}/deps/src + if [ -d "${UNPACKDIR}/nvidia-modprobe" ]; then + mv ${UNPACKDIR}/nvidia-modprobe ${S}/deps/src/nvidia-modprobe-${NVIDIA_MODPROBE_VERSION} + fi +} +addtask unpack_modprobe after do_unpack before do_patch +do_unpack_modprobe[dirs] = "${S}" +do_unpack_modprobe[vardeps] += "NVIDIA_MODPROBE_VERSION" + PACKAGECONFIG ??= "seccomp" PACKAGECONFIG[seccomp] = "WITH_SECCOMP=yes,WITH_SECCOMP=no,libseccomp" diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libtirpc134_1.3.4.bb b/meta-nvidia/recipes-graphics/libnvidia-container/libtirpc134_1.3.4.bb index 631e2db..f4d1cac 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libtirpc134_1.3.4.bb +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libtirpc134_1.3.4.bb @@ -12,15 +12,15 @@ SRC_URI[sha256sum] = "1e0b0c7231c5fa122e06c0609a76723664d068b0dba3b8219b63e6340b # SRC_URI += "file://0001-__rpc_dtbsize-rlim_cur-instead-of-rlim_max.patch" -S = "${WORKDIR}/libtirpc-${PV}" +S = "${UNPACKDIR}/libtirpc-${PV}" inherit autotools pkgconfig DISABLE_STATIC = "" EXTRA_OECONF = "--disable-gssapi --enable-static" -# Append -fPIC to CFLAGS -CFLAGS:append = " -fPIC" +# Append -fPIC to CFLAGS and fix GCC 15 compatibility +CFLAGS:append = " -fPIC -Wno-error=incompatible-pointer-types -Wno-error=int-conversion -std=gnu17" do_install:append() { rm -r ${D}${sysconfdir} ${D}${datadir} ${D}${libdir}/pkgconfig diff --git a/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit.inc b/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit.inc index 1c6efdf..2004713 100644 --- a/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit.inc +++ b/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit.inc @@ -3,16 +3,13 @@ HOMEPAGE = "https://github.com/NVIDIA/nvidia-container-toolkit" LICENSE = "Apache-2.0" LIC_FILES_CHKSUM = "file://src/${GO_IMPORT}/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57" -SRC_URI = "git://github.com/NVIDIA/nvidia-container-toolkit.git;protocol=https;branch=release-1.14" -SRCREV = "4668c511de4b311c96bc3dd0310bff40b75083bd" +SRC_URI = "git://github.com/NVIDIA/nvidia-container-toolkit.git;protocol=https;branch=main;destsuffix=${BP}/src/${GO_IMPORT}" +SRCREV = "c748619c592030519361274a2fdd43f2c2ced73a" SRC_URI += "file://config.toml" -SRC_URI += "file://0001-Fix-cgo-LDFLAGS-for-go-1.21-and-later.patch;patchdir=src/${GO_IMPORT}" GO_IMPORT = "github.com/NVIDIA/nvidia-container-toolkit" DEPENDS = " \ curl-native ca-certificates-native go-native \ coreutils-native \ " - -S = "${WORKDIR}/git" diff --git a/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit_1.00.bb b/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit_1.00.bb index 9106fce..4466055 100644 --- a/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit_1.00.bb +++ b/meta-nvidia/recipes-graphics/nvidia-container-toolkit/nvidia-container-toolkit_1.00.bb @@ -42,7 +42,7 @@ do_install() { # Ensure the installation directory exists install -d ${D}/etc/nvidia-container-runtime # Install the config.toml file - install -m 0644 ${WORKDIR}/config.toml ${D}/etc/nvidia-container-runtime/config.toml + install -m 0644 ${UNPACKDIR}/config.toml ${D}/etc/nvidia-container-runtime/config.toml } INSANE_SKIP:${PN} += "already-stripped buildpaths textrel" diff --git a/meta-nvidia/recipes-graphics/nvidia/libnvidia-nscq_570.172.08.bb b/meta-nvidia/recipes-graphics/nvidia/libnvidia-nscq_580.105.08.bb similarity index 76% rename from meta-nvidia/recipes-graphics/nvidia/libnvidia-nscq_570.172.08.bb rename to meta-nvidia/recipes-graphics/nvidia/libnvidia-nscq_580.105.08.bb index db47484..a6ffc43 100644 --- a/meta-nvidia/recipes-graphics/nvidia/libnvidia-nscq_570.172.08.bb +++ b/meta-nvidia/recipes-graphics/nvidia/libnvidia-nscq_580.105.08.bb @@ -5,10 +5,9 @@ LICENSE = "NVIDIA-Proprietary" LIC_FILES_CHKSUM = "file://LICENSE;md5=2cc00be68c1227a7c42ff3620ef75d05" SRC_URI = "https://developer.download.nvidia.cn/compute/nvidia-driver/redist/libnvidia_nscq/linux-x86_64/libnvidia_nscq-linux-x86_64-${PV}-archive.tar.xz" -SRC_URI[md5sum] = "b8cc1c4e37794eaf738c488d419a7c90" -SRC_URI[sha256sum] = "66d1c4303700f19bd86bddda071340e070511a7070ce60a8641f16db7c184cfa" +SRC_URI[sha256sum] = "71086dc7d9c97ac20a7d14de2a119e3b2ee97a08da452d63c2c4f5a71d80e19a" -S = "${WORKDIR}/libnvidia_nscq-linux-x86_64-${PV}-archive" +S = "${UNPACKDIR}/libnvidia_nscq-linux-x86_64-${PV}-archive" INSANE_SKIP:${PN} = "already-stripped ldflags" @@ -18,16 +17,12 @@ do_compile[noexec] = "1" do_install() { # Create directories install -d ${D}${libdir} - install -d ${D}${bindir} # Install libraries install -m 0755 ${S}/lib/libnvidia-nscq.so.${PV} ${D}${libdir} ln -sf libnvidia-nscq.so.${PV} ${D}${libdir}/libnvidia-nscq.so.2.0 ln -sf libnvidia-nscq.so.2.0 ${D}${libdir}/libnvidia-nscq.so.2 ln -sf libnvidia-nscq.so.2 ${D}${libdir}/libnvidia-nscq.so - - # Install binaries - install -m 0755 ${S}/bin/nscq-cli ${D}${bindir} } FILES:${PN} = "\ @@ -35,5 +30,4 @@ FILES:${PN} = "\ ${libdir}/libnvidia-nscq.so.2.0 \ ${libdir}/libnvidia-nscq.so.2 \ ${libdir}/libnvidia-nscq.so \ - ${bindir}/nscq-cli \ " diff --git a/meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_570.172.08.bb b/meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_570.172.08.bb deleted file mode 100644 index 3d91e4c..0000000 --- a/meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_570.172.08.bb +++ /dev/null @@ -1,86 +0,0 @@ -SUMMARY = "NVIDIA Fabric Manager for NVSwitch systems" -DESCRIPTION = "NVIDIA Fabric Manager provides NVSwitch management for NVIDIA HGX and DGX systems" -HOMEPAGE = "https://developer.nvidia.com/" -LICENSE = "NVIDIA-Proprietary" -LIC_FILES_CHKSUM = "file://LICENSE;md5=2cc00be68c1227a7c42ff3620ef75d05" - -SRC_URI = "https://developer.download.nvidia.com/compute/nvidia-driver/redist/fabricmanager/linux-x86_64/fabricmanager-linux-x86_64-${PV}-archive.tar.xz" -SRC_URI[md5sum] = "a71788f11f6edabf69df32a7b9dcfa68" -SRC_URI[sha256sum] = "8d24cacde4554d471899ad426f46a349d5ca0a2e8acd45c2a76381c8f496491e" - -S = "${WORKDIR}/fabricmanager-linux-x86_64-${PV}-archive" - -DEPENDS = "" -RDEPENDS:${PN} = "bash zlib" - -INSANE_SKIP:${PN} = "already-stripped ldflags" - -do_configure[noexec] = "1" -do_compile[noexec] = "1" - -inherit systemd - -SYSTEMD_AUTO_ENABLE = "enable" -SYSTEMD_SERVICE:${PN} = "nvidia-fabricmanager.service" - -do_install() { - # Create directories - install -d ${D}${bindir} - install -d ${D}${libdir} - install -d ${D}${datadir}/nvidia/nvswitch - install -d ${D}${systemd_system_unitdir} - - # Install binaries - install -m 0755 ${S}/bin/nv-fabricmanager ${D}${bindir} - install -m 0755 ${S}/bin/nvidia-fabricmanager-start.sh ${D}${bindir} - install -m 0755 ${S}/bin/nvswitch-audit ${D}${bindir} - - # Install libraries - install -m 0644 ${S}/lib/libnvfm.so.1 ${D}${libdir} - ln -sf libnvfm.so.1 ${D}${libdir}/libnvfm.so - - # Install config files - install -m 0644 ${S}/etc/fabricmanager.cfg ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/etc/fabricmanager_multinode.cfg ${D}${datadir}/nvidia/nvswitch/ - - # Install topology files - install -m 0644 ${S}/share/nvidia/nvswitch/dgx2_hgx2_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxa100_hgxa100_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxh100_hgxh100_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxh800_hgxh800_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/mgxh20_nvl16_topology ${D}${datadir}/nvidia/nvswitch/ - - # Install multi-node topology files - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_8gpus_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_16gpus_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_16gpus_trunk_connections.csv ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_16gpus_osfp_connections.csv ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_16gpus_osfp_cable_connections.csv ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_32gpus_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_32gpus_trunk_connections.csv ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_32gpus_osfp_connections.csv ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/dgxgh200_hgxgh200_32gpus_osfp_cable_connections.csv ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gh200_nvlink_32gpus_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl36r1_c2g4_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl36r1_c2g2_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl72r1_c2g4_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl72r2_c2g4_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl72r2_c2g2_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl576r16_c2g4_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl8r1_c2g4_etf_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl8r1_c2g4_etf_nso_topology ${D}${datadir}/nvidia/nvswitch/ - install -m 0644 ${S}/share/nvidia/nvswitch/gb200_nvl4r1_c2g2_etf_topology ${D}${datadir}/nvidia/nvswitch/ - - # Install systemd service - install -m 0644 ${S}/systemd/nvidia-fabricmanager.service ${D}${systemd_system_unitdir} -} - -FILES:${PN} = "\ - ${bindir}/nv-fabricmanager \ - ${bindir}/nvidia-fabricmanager-start.sh \ - ${bindir}/nvswitch-audit \ - ${libdir}/libnvfm.so.1 \ - ${libdir}/libnvfm.so \ - ${datadir}/nvidia/nvswitch/* \ - ${systemd_system_unitdir}/nvidia-fabricmanager.service \ -" diff --git a/meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_580.105.08.bb b/meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_580.105.08.bb new file mode 100644 index 0000000..e5b3f8f --- /dev/null +++ b/meta-nvidia/recipes-graphics/nvidia/nvidia-fabricmanager_580.105.08.bb @@ -0,0 +1,64 @@ +SUMMARY = "NVIDIA Fabric Manager for NVSwitch systems" +DESCRIPTION = "NVIDIA Fabric Manager provides NVSwitch management for NVIDIA HGX and DGX systems" +HOMEPAGE = "https://developer.nvidia.com/" +LICENSE = "NVIDIA-Proprietary" +LIC_FILES_CHKSUM = "file://LICENSE;md5=2cc00be68c1227a7c42ff3620ef75d05" + +SRC_URI = "https://developer.download.nvidia.com/compute/nvidia-driver/redist/fabricmanager/linux-x86_64/fabricmanager-linux-x86_64-${PV}-archive.tar.xz" +SRC_URI[sha256sum] = "eb3a81d004de426dee9b0f1332093828edb197125ef57a2e6500a95df3332d0b" + +S = "${UNPACKDIR}/fabricmanager-linux-x86_64-${PV}-archive" + +DEPENDS = "" +RDEPENDS:${PN} = "bash zlib" + +INSANE_SKIP:${PN} = "already-stripped ldflags" + +do_configure[noexec] = "1" +do_compile[noexec] = "1" + +inherit systemd + +SYSTEMD_AUTO_ENABLE = "enable" +SYSTEMD_SERVICE:${PN} = "nvidia-fabricmanager.service" + +do_install() { + # Create directories + install -d ${D}${bindir} + install -d ${D}${libdir} + install -d ${D}${datadir}/nvidia/nvswitch + install -d ${D}${systemd_system_unitdir} + + # Install binaries + install -m 0755 ${S}/bin/nv-fabricmanager ${D}${bindir} + install -m 0755 ${S}/bin/nvidia-fabricmanager-start.sh ${D}${bindir} + install -m 0755 ${S}/bin/nvswitch-audit ${D}${bindir} + + # Install libraries + install -m 0644 ${S}/lib/libnvfm.so.1 ${D}${libdir} + ln -sf libnvfm.so.1 ${D}${libdir}/libnvfm.so + + # Install config files + install -m 0644 ${S}/etc/fabricmanager.cfg ${D}${datadir}/nvidia/nvswitch/ + install -m 0644 ${S}/etc/fabricmanager_multinode.cfg ${D}${datadir}/nvidia/nvswitch/ + + # Install topology files + for f in ${S}/share/nvidia/nvswitch/*; do + if [ -f "$f" ]; then + install -m 0644 "$f" ${D}${datadir}/nvidia/nvswitch/ + fi + done + + # Install systemd service + install -m 0644 ${S}/systemd/nvidia-fabricmanager.service ${D}${systemd_system_unitdir} +} + +FILES:${PN} = "\ + ${bindir}/nv-fabricmanager \ + ${bindir}/nvidia-fabricmanager-start.sh \ + ${bindir}/nvswitch-audit \ + ${libdir}/libnvfm.so.1 \ + ${libdir}/libnvfm.so \ + ${datadir}/nvidia/nvswitch/* \ + ${systemd_system_unitdir}/nvidia-fabricmanager.service \ +" diff --git a/meta-nvidia/recipes-graphics/nvidia/nvidia-modprobe-config_1.0.bb b/meta-nvidia/recipes-graphics/nvidia/nvidia-modprobe-config_1.0.bb index 91b6540..5ed2c95 100644 --- a/meta-nvidia/recipes-graphics/nvidia/nvidia-modprobe-config_1.0.bb +++ b/meta-nvidia/recipes-graphics/nvidia/nvidia-modprobe-config_1.0.bb @@ -8,7 +8,7 @@ SRC_URI = "\ do_install() { install -d ${D}${sysconfdir}/modprobe.d - install -m 0644 ${WORKDIR}/nvidia.conf ${D}${sysconfdir}/modprobe.d/ + install -m 0644 ${UNPACKDIR}/nvidia.conf ${D}${sysconfdir}/modprobe.d/ } FILES:${PN} = "${sysconfdir}/modprobe.d/nvidia.conf" diff --git a/meta-nvidia/recipes-graphics/nvidia/nvidia-persistenced_1.0.bb b/meta-nvidia/recipes-graphics/nvidia/nvidia-persistenced_1.0.bb index bb73a6d..7503da7 100644 --- a/meta-nvidia/recipes-graphics/nvidia/nvidia-persistenced_1.0.bb +++ b/meta-nvidia/recipes-graphics/nvidia/nvidia-persistenced_1.0.bb @@ -13,5 +13,5 @@ SYSTEMD_AUTO_ENABLE:${PN} = "enable" do_install() { install -d ${D}${systemd_unitdir}/system - install -m 0644 ${WORKDIR}/nvidia-persistenced.service ${D}${systemd_unitdir}/system + install -m 0644 ${UNPACKDIR}/nvidia-persistenced.service ${D}${systemd_unitdir}/system } diff --git a/meta-nvidia/recipes-graphics/nvidia/nvidia_570.172.08.bb b/meta-nvidia/recipes-graphics/nvidia/nvidia_580.105.08.bb similarity index 75% rename from meta-nvidia/recipes-graphics/nvidia/nvidia_570.172.08.bb rename to meta-nvidia/recipes-graphics/nvidia/nvidia_580.105.08.bb index bacb389..33f56b5 100644 --- a/meta-nvidia/recipes-graphics/nvidia/nvidia_570.172.08.bb +++ b/meta-nvidia/recipes-graphics/nvidia/nvidia_580.105.08.bb @@ -3,12 +3,11 @@ LICENSE = "NVIDIA-Proprietary" LIC_FILES_CHKSUM = "file://../LICENSE;md5=92aa2e2af6aa0bcba1c3fe49da021937" NVIDIA_ARCHIVE_NAME = "NVIDIA-Linux-${TARGET_ARCH}-${PV}" -NVIDIA_SRC = "${WORKDIR}/${NVIDIA_ARCHIVE_NAME}" +NVIDIA_SRC = "${UNPACKDIR}/${NVIDIA_ARCHIVE_NAME}" SRC_URI = " \ https://us.download.nvidia.com/tesla/${PV}/${NVIDIA_ARCHIVE_NAME}.run \ " -SRC_URI[md5sum] = "4d0264e320d09f614b086c3ad99a75c5" -SRC_URI[sha256sum] = "0256867e082caf93d7b25fa7c8e69b316062a9c6c72c6e228fad7b238c6fa17d" +SRC_URI[sha256sum] = "d9c6e8188672f3eb74dd04cfa69dd58479fa1d0162c8c28c8d17625763293475" RDEPENDS:${PN} = "nvidia-modprobe-config" From c1355e4ba6339074bc3c4f7279d5463f893c826b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 04:33:19 +0000 Subject: [PATCH 024/119] Update dstack/ --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 72ffe34..678226c 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 72ffe344dacf2316c7e4a42803eda2af4e3cd15b +Subproject commit 678226c6188a2014129daa92a374a5facf5bfb99 From 8fc9ddb70c743dbe1c575a016a18e85b0ae0c562 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 04:36:05 +0000 Subject: [PATCH 025/119] fixup zfs --- meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb index fc2361d..93d18bf 100644 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb +++ b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb @@ -2,7 +2,7 @@ SUMMARY = "OpenZFS on Linux and FreeBSD" DESCRIPTION = "OpenZFS on Linux and FreeBSD" LICENSE = "CDDL-1.0" LIC_FILES_CHKSUM = "file://LICENSE;md5=7087caaf1dc8a2856585619f4a787faa" -HOMEPAGE ="https://github.com/openzfs/zfs" +HOMEPAGE = "https://github.com/openzfs/zfs" SRCREV = "743334913e5a5f60baf287bcc6d8a23515b02ac5" SRC_URI = "git://github.com/openzfs/zfs;protocol=https;branch=zfs-2.4-release \ From daed2d798b54775884afd37cac942285e7ad3db5 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 04:36:20 +0000 Subject: [PATCH 026/119] fixup meta-nvidia --- .../containerd-config/containerd-config_1.0.0.bb | 2 +- .../libnvidia-container/libnvidia-container_1.00.bb | 2 +- meta-nvidia/recipes-graphics/nvidia/nvidia-libs.inc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb b/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb index 2bc9f85..d2757e9 100644 --- a/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb +++ b/meta-nvidia/recipes-graphics/containerd-config/containerd-config_1.0.0.bb @@ -10,4 +10,4 @@ do_install:append() { } RDEPENDS:${PN}:append = " containerd-opencontainers" -FILES:${PN}:append= "${sysconfdir}/containerd/config.toml" +FILES:${PN}:append = "${sysconfdir}/containerd/config.toml" diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb index f53a02d..b533f73 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb @@ -24,7 +24,7 @@ EXTRA_OEMAKE = "EXCLUDE_BUILD_FLAGS=1 PLATFORM=${HOST_ARCH} WITH_NVCGO=yes WITH_ NVIDIA_MODPROBE_EXTRA_CFLAGS ?= "-ffile-prefix-map=${WORKDIR}=/usr/src/debug/${PN}/${EXTENDPE}${PV}-${PR}" CFLAGS:prepend = " -I${RECIPE_SYSROOT_NATIVE}/usr/include/tirpc " -export OBJCPY="${OBJCOPY}" +export OBJCPY = "${OBJCOPY}" GO_IMPORT = "github.com/NVIDIA/nvidia-container-toolkit" SECURITY_LDFLAGS = "" LDFLAGS += "-Wl,-z,lazy" diff --git a/meta-nvidia/recipes-graphics/nvidia/nvidia-libs.inc b/meta-nvidia/recipes-graphics/nvidia/nvidia-libs.inc index a1ded2a..622eacd 100644 --- a/meta-nvidia/recipes-graphics/nvidia/nvidia-libs.inc +++ b/meta-nvidia/recipes-graphics/nvidia/nvidia-libs.inc @@ -53,7 +53,7 @@ do_install:append() { cp ${NVIDIA_SRC}/firmware/* ${D}${libdir}/firmware/nvidia/${PV}/ } -FILES:${PN}:append= " ${libdir} ${bindir}" +FILES:${PN}:append = " ${libdir} ${bindir}" INHIBIT_PACKAGE_DEBUG_SPLIT = "1" From bbc89cc42cad210f7f08d208a3d99be471b4d149 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 11:52:37 +0000 Subject: [PATCH 027/119] Update dstack/ --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 678226c..bccc20d 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 678226c6188a2014129daa92a374a5facf5bfb99 +Subproject commit bccc20dd1dfcde88fc3f4860b19333b523b1a7cf From 169cf0245594962a2bfead9a42621ce2529155f1 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 22 Dec 2025 11:53:02 +0000 Subject: [PATCH 028/119] Adapt docker 29 --- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 11 +++++++++-- .../recipes-core/images/dstack-rootfs-base.inc | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 7b1769f..2f7e0fb 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -78,11 +78,18 @@ do_install() { install -m 0644 ${S}/basefiles/wg-checker.service ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/llmnr.conf ${D}${sysconfdir}/systemd/resolved.conf.d install -d ${D}${sysconfdir}/systemd/system/docker.service.d - install -m 0644 ${S}/basefiles/docker.service.d/dstack-guest-agent.conf ${D}${sysconfdir}/systemd/system/docker.service.d/ + install -m 0644 ${S}/basefiles/docker.service.d/* ${D}${sysconfdir}/systemd/system/docker.service.d/ + + install -d ${D}${sysconfdir}/systemd/system/containerd.service.d + install -m 0644 ${S}/basefiles/containerd.service.d/* ${D}${sysconfdir}/systemd/system/containerd.service.d/ fi } -FILES:${PN} += "${sysconfdir}/systemd/system/docker.service.d/dstack-guest-agent.conf" +FILES:${PN} += " \ + ${sysconfdir}/systemd/system/docker.service.d/dstack-guest-agent.conf \ + ${sysconfdir}/systemd/system/docker.service.d/dstack-prepare.conf \ + ${sysconfdir}/systemd/system/containerd.service.d/dstack-prepare.conf \ +" # Cargo embeds build paths into binaries; allow TMPDIR references. INSANE_SKIP:${PN} += "buildpaths" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 4352108..09605e8 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -143,5 +143,6 @@ mkdirs() { mkdir -p ${IMAGE_ROOTFS}/dstack mkdir -p ${IMAGE_ROOTFS}/etc/wireguard mkdir -p ${IMAGE_ROOTFS}/var/lib/docker + mkdir -p ${IMAGE_ROOTFS}/var/lib/containerd ln -sf dstack ${IMAGE_ROOTFS}/tapp } From 81da8404efba4feac0c0e6c2ce343aa6e439efa1 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 23 Dec 2025 08:16:31 +0000 Subject: [PATCH 029/119] Remove mod-tdx-guest --- dstack | 2 +- .../recipes-kernel/tdx-guest-mod/tdx-guest.bb | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb diff --git a/dstack b/dstack index bccc20d..805b554 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit bccc20dd1dfcde88fc3f4860b19333b523b1a7cf +Subproject commit 805b5547371971faf098b74e7def711be52b7536 diff --git a/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb b/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb deleted file mode 100644 index e134f3e..0000000 --- a/meta-dstack/recipes-kernel/tdx-guest-mod/tdx-guest.bb +++ /dev/null @@ -1,18 +0,0 @@ -SUMMARY = "TDX guest kernel module for Intel Trust Domain Extensions" -DESCRIPTION = "${SUMMARY}" -LICENSE = "MIT" -LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" - -inherit module - -REPO_ROOT = "${THISDIR}/../../.." - -SRC_DIR = '${REPO_ROOT}/dstack/mod-tdx-guest' -SRC_URI = 'file://${REPO_ROOT}/dstack/mod-tdx-guest' -SRCREV = "${DSTACK_SRC_REV}" - -S = "${UNPACKDIR}/${SRC_DIR}" - -RPROVIDES:${PN} += "tdx-guest-ko" -INSANE_SKIP:${PN} += "buildpaths" -INSANE_SKIP:${PN}-dbg += "buildpaths" From a9295ba8eb45a0253656e32b568962d2945e5944 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 24 Dec 2025 07:22:14 +0000 Subject: [PATCH 030/119] Update dstack/ --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 805b554..f1a49f0 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 805b5547371971faf098b74e7def711be52b7536 +Subproject commit f1a49f01a74c03c2034587dcf624bfc9c918ef20 From a4fbb9217a0bc33563154090c9674e5b42c46280 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 24 Dec 2025 07:22:40 +0000 Subject: [PATCH 031/119] Output gcp.tar.gz inside the image dir --- mkimage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkimage.sh b/mkimage.sh index 0028a46..0bf58a6 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -194,7 +194,7 @@ create_gcp_artifacts() { echo "Building raw disk image for GCP at ${disk_img}" build_gcp_disk_image "$disk_img" "$boot_src" "${OUTPUT_DIR}/rootfs.img.verity" - local tarball="${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}-gcp.tar.gz" + local tarball="${OUTPUT_DIR}/gcp.tar.gz" echo "Archiving GCP disk image to ${tarball}" (cd "$gcp_dir" && tar -czvf "$tarball" disk.raw) } From c22dfd41fc833441306dfe972f26d44ddbaef6a3 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 24 Dec 2025 07:23:02 +0000 Subject: [PATCH 032/119] Add cli dstack-cloud --- scripts/bin/dstack-cloud | 1906 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1906 insertions(+) create mode 100755 scripts/bin/dstack-cloud diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud new file mode 100755 index 0000000..4f0de51 --- /dev/null +++ b/scripts/bin/dstack-cloud @@ -0,0 +1,1906 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: © 2025 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +""" +dstack-cloud: Multi-cloud VM lifecycle management tool + +A production-grade CLI for managing dstack VMs on various cloud platforms. +Supports local configuration files similar to git's working model. + +Usage: + dstack-cloud new # Create a new project + dstack-cloud init # Initialize current directory + dstack-cloud config-edit # Edit global configuration + dstack-cloud prepare # Generate shared files + dstack-cloud deploy # Deploy VM to cloud + dstack-cloud status # Check deployment status + dstack-cloud logs [--follow] # View serial console logs + dstack-cloud stop # Stop the VM + dstack-cloud start # Start a stopped VM + dstack-cloud remove # Remove the VM and cleanup + dstack-cloud list # List all deployments +""" + +import argparse +import hashlib +import json +import logging +import os +import subprocess +import sys +import tempfile +import time +from dataclasses import dataclass, field, asdict +from datetime import datetime +from pathlib import Path +from typing import Optional, List, Dict, Any + +# Try to import cryptography libraries for env encryption +CRYPTO_AVAILABLE = False +try: + from cryptography.hazmat.primitives.ciphers.aead import AESGCM + from cryptography.hazmat.primitives.asymmetric import x25519 + from cryptography.hazmat.backends import default_backend + from cryptography import serialization + CRYPTO_AVAILABLE = True +except ImportError: + CRYPTO_AVAILABLE = False + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# Configuration file names +APP_CONFIG_FILE = "app.json" +STATE_FILE = "state.json" +GLOBAL_CONFIG_PATH = os.path.expanduser("~/.config/dstack-cloud/config.json") + + +@dataclass +class App: + """Application configuration.""" + # App name + name: str = "myapp" + + # OS image + os_image: str = "dstack-0.6.0" + + # GCP cloud configuration + gcp_config: 'GcpConfig' = field(default_factory=lambda: GcpConfig()) + + # Docker compose file name (relative to project root) + docker_compose_file: str = "docker-compose.yaml" + + # Prelaunch script name (relative to project root) + prelaunch_script: str = "prelaunch.sh" + + # Environment file name (relative to project root) + env_file: str = ".env" + + # Instance identity + instance_id_seed: str = "" + app_id: str = "" + + # Gateway settings + gateway_enabled: bool = True + public_logs: bool = True + public_sysinfo: bool = True + public_tcbinfo: bool = True + + # KMS settings + key_provider: str = "kms" + + # Storage + storage_fs: str = "ext4" + + # Instance settings + no_instance_id: bool = False + secure_time: bool = False + + # Allowed environments + allowed_envs: List[str] = field(default_factory=list) + key_provider_id: str = "" + + def to_dict(self) -> Dict[str, Any]: + data = asdict(self) + # Convert GcpConfig to dict + if isinstance(data.get("gcp_config"), GcpConfig): + data["gcp_config"] = data["gcp_config"].to_dict() + return data + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'App': + known_fields = {f.name for f in cls.__dataclass_fields__.values()} + filtered = {k: v for k, v in data.items() if k in known_fields} + + # Convert gcp_config dict to GcpConfig object + if "gcp_config" in filtered and isinstance(filtered["gcp_config"], dict): + filtered["gcp_config"] = GcpConfig.from_dict(filtered["gcp_config"]) + + return cls(**filtered) + + @classmethod + def get_template(cls) -> Dict[str, Any]: + """Get default template for new projects.""" + import secrets + + # Generate random instance_id_seed (40 hex chars) + instance_id_seed = secrets.token_hex(20) + + # Generate random app_id (40 hex chars) + app_id = secrets.token_hex(20) + + return { + "name": "myapp", + "os_image": "dstack-0.6.0", + "gcp_config": GcpConfig.get_template(), + "instance_id_seed": instance_id_seed, + "app_id": app_id, + "docker_compose_file": "docker-compose.yaml", + "prelaunch_script": "prelaunch.sh", + "env_file": ".env", + "gateway_enabled": True, + "public_logs": True, + "public_sysinfo": True, + "public_tcbinfo": True, + "key_provider": "kms", + "storage_fs": "ext4", + "no_instance_id": False, + "secure_time": False, + "allowed_envs": [], + "key_provider_id": "" + } + + +@dataclass +class GcpConfig: + """GCP deployment configuration.""" + # Required settings + project: str = "" + zone: str = "us-central1-a" + + # Instance settings + instance_name: str = "" # Required, no default + machine_type: str = "c3-standard-4" + + # Boot image settings + boot_image: str = "" # GCP image name (auto-derived from app.os_image if empty) + boot_image_tar: str = "" # Explicit tar file path (overrides search) + + # Data disk settings + data_image: str = "dstack-data-disk" + data_size: int = 20 + + # Storage settings + bucket: str = "" + + # Network settings + network: str = "default" + subnet: str = "" + + # Tags and labels + tags: List[str] = field(default_factory=list) + labels: Dict[str, str] = field(default_factory=dict) + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'GcpConfig': + known_fields = {f.name for f in cls.__dataclass_fields__.values()} + filtered = {k: v for k, v in data.items() if k in known_fields} + return cls(**filtered) + + @classmethod + def get_template(cls) -> Dict[str, Any]: + """Get default template for new projects.""" + return { + "project": "", + "zone": "us-central1-a", + "instance_name": "dstack-vm", + "machine_type": "c3-standard-4", + "boot_image": "", + "boot_image_tar": "", + "data_image": "dstack-data-disk", + "data_size": 20, + "bucket": "", + "network": "default", + "subnet": "", + "tags": [], + "labels": {} + } + + +@dataclass +class DeploymentState: + """Deployment state tracking.""" + instance_name: str = "" + project: str = "" + zone: str = "" + external_ip: str = "" + internal_ip: str = "" + status: str = "" # RUNNING, STOPPED, TERMINATED, etc. + created_at: str = "" + updated_at: str = "" + boot_image: str = "" + shared_image: str = "" + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'DeploymentState': + known_fields = {f.name for f in cls.__dataclass_fields__.values()} + filtered = {k: v for k, v in data.items() if k in known_fields} + return cls(**filtered) + + +class CloudDeploymentManager: + """Manages multi-cloud VM deployments.""" + + def __init__(self, work_dir: Optional[str] = None): + self.work_dir = Path(work_dir) if work_dir else Path.cwd() + + def _load_global_config(self) -> Dict[str, Any]: + """Load global configuration.""" + if os.path.exists(GLOBAL_CONFIG_PATH): + with open(GLOBAL_CONFIG_PATH, 'r') as f: + return json.load(f) + return {} + + def _save_global_config(self, config: Dict[str, Any]) -> None: + """Save global configuration.""" + os.makedirs(os.path.dirname(GLOBAL_CONFIG_PATH), exist_ok=True) + with open(GLOBAL_CONFIG_PATH, 'w') as f: + json.dump(config, f, indent=2) + + def _get_shared_dir(self) -> Path: + """Get the shared directory path (at project root).""" + return self.work_dir / "shared" + + def load_gcp_config(self) -> 'GcpConfig': + """Load GCP configuration from app.gcp_config.""" + # Load app config which contains gcp_config + app = self.load_app_config() + + # Get local gcp_config from app + local_gcp = app.gcp_config.to_dict() + + # Merge global config with local config + global_config = self._load_global_config() + global_gcp = global_config.get("gcp", {}) + + # Global config is used as fallback for empty values in local config + merged = {**global_gcp} # Start with global config + for key, value in local_gcp.items(): + # Only override with local value if it's non-empty + if value or value is False or value == 0: + merged[key] = value + return GcpConfig.from_dict(merged) + + def save_gcp_config(self, config: GcpConfig) -> None: + """Save GCP configuration to app.gcp_config.""" + # Load the full app config + app = self.load_app_config() + + # Update gcp_config + app.gcp_config = config + + # Save the updated app config + self.save_app_config(app) + + def load_app_config(self) -> App: + """Load application configuration.""" + app_config_path = self.work_dir / APP_CONFIG_FILE + + if not app_config_path.exists(): + # Return default config if file doesn't exist + return App() + + with open(app_config_path, 'r') as f: + return App.from_dict(json.load(f)) + + def save_app_config(self, app: App) -> None: + """Save application configuration.""" + app_config_path = self.work_dir / APP_CONFIG_FILE + with open(app_config_path, 'w') as f: + json.dump(app.to_dict(), f, indent=2) + + def _generate_app_compose(self, app: App, env_names: Optional[List[str]] = None) -> Dict[str, Any]: + """Generate app-compose.json content from App configuration.""" + # Read docker-compose.yaml content + docker_compose_path = self.work_dir / app.docker_compose_file + if not docker_compose_path.exists(): + docker_compose_content = "" + else: + with open(docker_compose_path, 'r') as f: + docker_compose_content = f.read() + + # Read prelaunch script content + prelaunch_path = self.work_dir / app.prelaunch_script + if not prelaunch_path.exists(): + prelaunch_content = "" + else: + with open(prelaunch_path, 'r') as f: + prelaunch_content = f.read() + + # Merge app.allowed_envs with env_names from .env file + allowed_envs = list(app.allowed_envs) if app.allowed_envs else [] + if env_names: + allowed_envs.extend(env_names) + # Remove duplicates + allowed_envs = list(set(allowed_envs)) + + return { + "manifest_version": 2, + "name": app.name, + "runner": "docker-compose", + "docker_compose_file": docker_compose_content, + "gateway_enabled": app.gateway_enabled, + "public_logs": app.public_logs, + "public_sysinfo": app.public_sysinfo, + "public_tcbinfo": app.public_tcbinfo, + "key_provider_id": app.key_provider_id, + "allowed_envs": allowed_envs, + "no_instance_id": app.no_instance_id, + "secure_time": app.secure_time, + "key_provider": app.key_provider, + "storage_fs": app.storage_fs, + "pre_launch_script": prelaunch_content + } + + def _generate_sys_config(self, global_config: Dict[str, Any], + gcp_config: GcpConfig, app: App) -> Dict[str, Any]: + """Generate .sys-config.json content.""" + # Get services section from global config + services = global_config.get("services", {}) + + # Get KMS URLs from global config + kms_urls = services.get("kms_urls", []) + if not kms_urls: + kms_urls = ["https://kms.tdxlab.dstack.org:12001"] + + # Get gateway URLs from global config + gateway_urls = services.get("gateway_urls", []) + if not gateway_urls: + gateway_urls = ["https://gateway.tdxlab.dstack.org:12002"] + + # Get other settings + pccs_url = services.get("pccs_url", "") + + # Read OS image hash from the local image directory + os_image_hash = "" + try: + # Find the image directory and read hash file + search_paths = global_config.get("image_search_paths", []) + local_image = gcp_config.boot_image if gcp_config.boot_image else "" + if not local_image: + # Use app.os_image if boot_image is not set + local_image = app.os_image + + for search_path in search_paths: + search_path = os.path.expanduser(search_path) + if not os.path.isabs(search_path): + search_path = os.path.join(self.work_dir, search_path) + + hash_file = Path(search_path) / local_image / "dstack-uki.efi.auth_hash.txt" + if hash_file.exists(): + with open(hash_file, 'r') as f: + os_image_hash = f.read().strip() + logger.info(f"Read OS image hash from {hash_file}") + break + except Exception as e: + logger.warning(f"Could not read OS image hash: {e}") + + # Build vm_config + vm_config = { + "spec_version": 2, + "os_image_hash": os_image_hash + } + + return { + "kms_urls": kms_urls, + "gateway_urls": gateway_urls, + "pccs_url": pccs_url, + "vm_config": json.dumps(vm_config) + } + + def load_state(self) -> Optional[DeploymentState]: + """Load deployment state.""" + state_path = self.work_dir / STATE_FILE + + if not state_path.exists(): + return None + + with open(state_path, 'r') as f: + return DeploymentState.from_dict(json.load(f)) + + def save_state(self, state: DeploymentState) -> None: + """Save deployment state.""" + state_path = self.work_dir / STATE_FILE + state.updated_at = datetime.now().isoformat() + with open(state_path, 'w') as f: + json.dump(state.to_dict(), f, indent=2) + + def _run_gcloud(self, args: List[str], capture: bool = True, + check: bool = True) -> subprocess.CompletedProcess: + """Run a gcloud command.""" + cmd = ["gcloud"] + args + logger.debug(f"Running: {' '.join(cmd)}") + + if capture: + result = subprocess.run(cmd, capture_output=True, text=True) + else: + result = subprocess.run(cmd) + + if check and result.returncode != 0: + error_msg = result.stderr if capture else "Command failed" + raise RuntimeError(f"gcloud command failed: {error_msg}") + + return result + + def _run_gsutil(self, args: List[str], check: bool = True) -> subprocess.CompletedProcess: + """Run a gsutil command.""" + cmd = ["gsutil"] + args + logger.debug(f"Running: {' '.join(cmd)}") + result = subprocess.run(cmd, capture_output=True, text=True) + + if check and result.returncode != 0: + raise RuntimeError(f"gsutil command failed: {result.stderr}") + + return result + + def new( + self, + name: str, + os_image: Optional[str] = None, + app_id: Optional[str] = None, + gateway_enabled: Optional[bool] = None, + key_provider: Optional[str] = None, + storage_fs: Optional[str] = None, + secure_time: Optional[bool] = None, + no_instance_id: Optional[bool] = None, + project: Optional[str] = None, + zone: Optional[str] = None, + instance_name: Optional[str] = None, + machine_type: Optional[str] = None, + data_size: Optional[int] = None + ) -> None: + """Create a new project directory with template configuration.""" + project_dir = Path.cwd() / name + if project_dir.exists(): + raise FileExistsError(f"Directory '{name}' already exists.") + + # Create project directory + project_dir.mkdir() + + # Update work_dir to the new project directory + self.work_dir = project_dir + + if not instance_name: + instance_name = f"dstack-{name}" + + # Initialize the project (non-interactive by default for new command) + self._init_project( + force=False, + interactive=False, + app_name=name, + os_image=os_image, + app_id=app_id, + gateway_enabled=gateway_enabled, + key_provider=key_provider, + storage_fs=storage_fs, + secure_time=secure_time, + no_instance_id=no_instance_id, + project=project, + zone=zone, + instance_name=instance_name, + machine_type=machine_type, + data_size=data_size + ) + + logger.info(f"Created new project: {name}") + logger.info(f"Project directory: {project_dir}") + logger.info("") + + def init( + self, + force: bool = False, + interactive: bool = True, + os_image: Optional[str] = None, + app_id: Optional[str] = None, + gateway_enabled: Optional[bool] = None, + key_provider: Optional[str] = None, + storage_fs: Optional[str] = None, + secure_time: Optional[bool] = None, + no_instance_id: Optional[bool] = None, + project: Optional[str] = None, + zone: Optional[str] = None, + instance_name: Optional[str] = None, + machine_type: Optional[str] = None, + data_size: Optional[int] = None + ) -> None: + """Initialize deployment configuration in current directory.""" + self._init_project( + force=force, + interactive=interactive, + app_name=None, # Will prompt in interactive mode + os_image=os_image, + app_id=app_id, + gateway_enabled=gateway_enabled, + key_provider=key_provider, + storage_fs=storage_fs, + secure_time=secure_time, + no_instance_id=no_instance_id, + project=project, + zone=zone, + instance_name=instance_name, + machine_type=machine_type, + data_size=data_size + ) + + def _init_project( + self, + force: bool = False, + interactive: bool = True, + app_name: Optional[str] = None, + os_image: Optional[str] = None, + app_id: Optional[str] = None, + gateway_enabled: Optional[bool] = None, + key_provider: Optional[str] = None, + storage_fs: Optional[str] = None, + secure_time: Optional[bool] = None, + no_instance_id: Optional[bool] = None, + project: Optional[str] = None, + zone: Optional[str] = None, + instance_name: Optional[str] = None, + machine_type: Optional[str] = None, + data_size: Optional[int] = None + ) -> None: + """Initialize project configuration (shared implementation for init and new).""" + # Interactive prompts for required fields (only if not provided via CLI) + instance_name_cli = instance_name + + if interactive: + print(f"\n=== dstack-cloud Project Initialization ===\n") + + # Prompt for app name (only for init command, new command provides it) + if app_name is None: + while True: + app_name = input("App name [myapp]: ").strip() + if not app_name: + app_name = "myapp" + if app_name: + break + print("App name cannot be empty.") + + # Prompt for instance name (required) + if not instance_name_cli: + while True: + instance_name = input("GCP instance name: ").strip() + if instance_name: + break + print("Instance name is required.") + else: + instance_name = instance_name_cli + + print("") # Empty line for readability + else: + # Non-interactive mode: use CLI provided values or fail + if app_name is None: + app_name = "myapp" + if not instance_name_cli: + raise ValueError("instance_name is required. Use --instance-name to specify it.") + instance_name = instance_name_cli + + # Create shared directory at project root (for system-generated files) + shared_dir = self.work_dir / "shared" + shared_dir.mkdir(parents=True, exist_ok=True) + + # Generate app config template with embedded gcp_config + app_template = App.get_template() + + # Apply CLI-provided values (only if specified) + if app_name: + app_template["name"] = app_name + if os_image: + app_template["os_image"] = os_image + if app_id: + # Validate app_id format (40 hex chars) + if len(app_id) != 40 or not all(c in '0123456789abcdef' for c in app_id.lower()): + raise ValueError("app_id must be exactly 40 hexadecimal characters") + app_template["app_id"] = app_id + if gateway_enabled is not None: + app_template["gateway_enabled"] = gateway_enabled + if key_provider is not None: + app_template["key_provider"] = key_provider + + # Auto-disable gateway when key_provider is not "kms" + if app_template["key_provider"] != "kms": + app_template["gateway_enabled"] = False + # Also set no_instance_id=True when KMS is not available + app_template["no_instance_id"] = True + if storage_fs is not None: + app_template["storage_fs"] = storage_fs + if secure_time is not None: + app_template["secure_time"] = secure_time + if no_instance_id is not None: + app_template["no_instance_id"] = no_instance_id + + # Apply GCP config values + if instance_name: + app_template["gcp_config"]["instance_name"] = instance_name + if project: + app_template["gcp_config"]["project"] = project + if zone: + app_template["gcp_config"]["zone"] = zone + if machine_type: + app_template["gcp_config"]["machine_type"] = machine_type + if data_size is not None: + app_template["gcp_config"]["data_size"] = data_size + + # Create app.json at project root (not in .dstack/) + app_config_path = self.work_dir / APP_CONFIG_FILE + if not app_config_path.exists() or force: + with open(app_config_path, 'w') as f: + json.dump(app_template, f, indent=2) + + # Note: app-compose.json and .sys-config.json will be generated during deploy + + # Create docker-compose.yaml template at project root + docker_compose = self.work_dir / "docker-compose.yaml" + if not docker_compose.exists() or force: + with open(docker_compose, 'w') as f: + f.write("services:\n") + f.write(" nginx:\n") + f.write(" image: nginx:alpine\n") + f.write(" ports:\n") + f.write(" - \"80:80\"\n") + f.write(" restart: unless-stopped\n") + + # Create prelaunch.sh template at project root + prelaunch = self.work_dir / "prelaunch.sh" + if not prelaunch.exists() or force: + with open(prelaunch, 'w') as f: + f.write("#!/bin/sh\n") + f.write("# Prelaunch script - runs before starting containers\n") + os.chmod(prelaunch, 0o755) + + # Create .env template at project root + env_file = self.work_dir / ".env" + if not env_file.exists() or force: + with open(env_file, 'w') as f: + f.write("# Environment variables\n") + + # Create user-config template at project root + user_config = self.work_dir / ".user-config" + if not user_config.exists() or force: + with open(user_config, 'w') as f: + json.dump({}, f, indent=2) + + logger.info(f"Initialized project in {self.work_dir}") + logger.info("") + if interactive: + logger.info("Configuration:") + logger.info(f" App name: {app_name}") + logger.info(f" Instance name: {instance_name}") + logger.info("") + logger.info("Created files:") + logger.info(f" {app_config_path.name} - Application configuration (with embedded GCP config)") + logger.info(f" shared/ - System-generated files") + logger.info(f" {docker_compose.name} - Docker compose file") + logger.info(f" {prelaunch.name} - Prelaunch script") + logger.info(f" {env_file.name} - Environment variables") + logger.info(f" .user-config - User configuration") + logger.info("") + logger.info("Edit the configuration files to customize your deployment.") + + def config_edit(self) -> None: + """Edit global configuration with $EDITOR.""" + # Create global config if it doesn't exist + global_config_dir = os.path.dirname(GLOBAL_CONFIG_PATH) + os.makedirs(global_config_dir, exist_ok=True) + + if not os.path.exists(GLOBAL_CONFIG_PATH): + # Create template with organized sections and comments + template = { + "_comment_services": "Service endpoints configuration", + "services": { + "kms_urls": ["https://kms.tdxlab.dstack.org:12001"], + "gateway_urls": ["https://gateway.tdxlab.dstack.org:12002"], + "pccs_url": "", + }, + "_comment_images": "System image search paths (for boot_image_tar auto-discovery)", + "image_search_paths": [ + "~/.dstack/images" + ], + "_comment_gcp": "GCP cloud platform defaults", + "gcp": { + "project": "", + "zone": "us-central1-a", + "bucket": "" + } + } + with open(GLOBAL_CONFIG_PATH, 'w') as f: + json.dump(template, f, indent=2, ensure_ascii=False) + f.write("\n") # Add trailing newline + + # Get editor + editor = os.environ.get('EDITOR', 'vi') + + # Open editor + logger.info(f"Opening {GLOBAL_CONFIG_PATH} with {editor}...") + subprocess.run([editor, GLOBAL_CONFIG_PATH]) + + def prepare(self) -> None: + """Generate all files in shared directory.""" + import secrets + + # Load app config + app = self.load_app_config() + + # Ensure instance_id_seed and app_id exist + if not app.instance_id_seed: + app.instance_id_seed = secrets.token_hex(20) + logger.info(f"Generated instance_id_seed: {app.instance_id_seed}") + + if not app.app_id: + app.app_id = secrets.token_hex(20) + logger.info(f"Generated app_id: {app.app_id}") + + # Save updated app config + self.save_app_config(app) + + # Get shared directory + shared_dir = self._get_shared_dir() + shared_dir.mkdir(parents=True, exist_ok=True) + + # Generate .instance_info (instance_id will be generated in CVM) + instance_info = { + "instance_id_seed": app.instance_id_seed, + "app_id": app.app_id + } + instance_info_path = shared_dir / ".instance_info" + with open(instance_info_path, 'w') as f: + json.dump(instance_info, f, indent=2) + logger.info(f"Generated {instance_info_path}") + + # Load GCP config for sys-config generation + try: + gcp_config = self.load_gcp_config() + global_config = self._load_global_config() + + # Generate .sys-config.json + sys_config_content = self._generate_sys_config(global_config, gcp_config, app) + sys_config_path = shared_dir / ".sys-config.json" + with open(sys_config_path, 'w') as f: + json.dump(sys_config_content, f, indent=2) + logger.info(f"Generated {sys_config_path}") + except FileNotFoundError as e: + logger.warning(f"Could not generate .sys-config.json: {e}") + + # Process .env file to collect env_names + env_path = self.work_dir / app.env_file + env_names = [] + if env_path.exists(): + envs = self._parse_env_file(env_path) + if envs: + env_names = list(envs.keys()) + logger.info(f"Found {len(env_names)} environment variable(s) in {app.env_file}") + else: + logger.info(f"{app.env_file} is empty") + + # Generate app-compose.json + app_compose_content = self._generate_app_compose(app, env_names=env_names if env_names else None) + app_compose_path = shared_dir / "app-compose.json" + with open(app_compose_path, 'w') as f: + json.dump(app_compose_content, f, indent=2) + logger.info(f"Generated {app_compose_path}") + + logger.info("") + logger.info(f"Shared files generated in: {shared_dir}") + logger.info("These files will be included in the shared disk image during deploy.") + + def _find_boot_image_tar(self, local_image: str) -> Optional[Path]: + """Search for boot image tar file in configured search paths.""" + global_config = self._load_global_config() + search_paths = global_config.get("image_search_paths", []) + + logger.debug(f"Image search paths: {search_paths}") + logger.debug(f"Looking for image: {local_image}") + + # Expand ~ and convert to Path objects + expanded_paths = [] + for path in search_paths: + expanded = os.path.expanduser(path) + if not os.path.isabs(expanded): + expanded = os.path.join(self.work_dir, expanded) + expanded_paths.append(Path(expanded)) + + # Try different file name patterns + patterns = [ + f"{local_image}/gcp.tar.gz", + ] + + for search_path in expanded_paths: + logger.debug(f"Checking search path: {search_path}, exists: {search_path.exists()}") + if not search_path.exists(): + continue + for pattern in patterns: + tar_file = search_path / pattern + logger.debug(f"Checking: {tar_file}, exists: {tar_file.exists()}") + if tar_file.exists(): + logger.info(f"Found boot image: {tar_file}") + return tar_file + + return None + + def pull(self, os_image: str) -> None: + """Download OS image from remote repository.""" + global_config = self._load_global_config() + search_paths = global_config.get("image_search_paths", []) + + if not search_paths: + logger.error("No image_search_paths configured in global config") + logger.error("Please set image_search_paths in: ~/.config/dstack-cloud/config.json") + return + + # Use the first search path + target_dir = Path(os.path.expanduser(search_paths[0])) + target_dir.mkdir(parents=True, exist_ok=True) + + # Download tar file (e.g., dstack-0.6.0.tar.gz) + download_tar = target_dir / f"{os_image}.tar.gz" + + if download_tar.exists(): + logger.info(f"Download file already exists: {download_tar}") + response = input("Download again to overwrite? [y/N]: ").strip().lower() + if response != 'y': + logger.info("Download cancelled") + return + + # Download URL + download_url = f"https://download.dstack.org/os-images/{os_image}.tar.gz" + + logger.info(f"Downloading {os_image} from {download_url}...") + logger.info(f"Target: {download_tar}") + + try: + # Use curl to download with progress bar + subprocess.run( + ["curl", "-L", "-o", str(download_tar), download_url], + check=True + ) + logger.info(f"Successfully downloaded to {download_tar}") + except subprocess.CalledProcessError as e: + logger.error(f"Failed to download image: {e}") + # Clean up partial download + if download_tar.exists(): + download_tar.unlink() + raise + + # Extract the tar file + logger.info(f"Extracting {download_tar}...") + try: + subprocess.run( + ["tar", "-xzf", str(download_tar), "-C", str(target_dir)], + check=True + ) + logger.info(f"Successfully extracted to {target_dir / os_image}") + except subprocess.CalledProcessError as e: + logger.error(f"Failed to extract image: {e}") + raise + + # Verify the expected structure + expected_dir = target_dir / os_image + expected_tar = expected_dir / "gcp.tar.gz" + if expected_tar.exists(): + logger.info(f"Image ready: {expected_tar}") + else: + logger.warning(f"Expected file not found: {expected_tar}") + logger.warning(f"Downloaded structure may be incorrect") + + def _check_and_upload_boot_image(self, config: GcpConfig, app: App, force: bool = False) -> str: + """Check and upload boot image if needed. Returns the image name.""" + tar_path = None + + # Derive GCP image name from app.os_image + gcp_image = config.boot_image + if not gcp_image: + # Convert OS image name (dstack-0.6.0 -> dstack-0-6-0) + gcp_image = app.os_image.replace(".", "-") + + # If boot_image_tar is specified, use it + if config.boot_image_tar: + tar_path = Path(os.path.expanduser(config.boot_image_tar)) + if not tar_path.exists(): + logger.error("") + logger.error(f"Boot image tar not found: {tar_path}") + logger.error("") + logger.error(f"Please download the image using:") + logger.error(f" dstack-cloud pull {app.os_image}") + logger.error("") + raise FileNotFoundError(f"Boot image tar not found: {tar_path}") + else: + # Auto-discover from search paths using OS image name + logger.info(f"Searching for boot image '{app.os_image}'...") + tar_path = self._find_boot_image_tar(app.os_image) + if not tar_path: + logger.error("") + logger.error(f"Boot image '{app.os_image}' not found locally.") + logger.error("") + logger.error(f"Please download the image using:") + logger.error(f" dstack-cloud pull {app.os_image}") + logger.error("") + raise FileNotFoundError( + f"Boot image '{app.os_image}' not found. " + f"Run 'dstack-cloud pull {app.os_image}' to download it." + ) + + # Use gcp_image as the GCP image name + image_name = gcp_image + local_mtime = tar_path.stat().st_mtime + + # Check if GCP image exists and is up-to-date + result = self._run_gcloud([ + "compute", "images", "describe", image_name, + f"--project={config.project}", + "--format=value(creationTimestamp)" + ], check=False) + + need_upload = False + gcp_creation_time = result.stdout.strip() if result.returncode == 0 else "" + + if force: + logger.info("Force enabled: will re-upload boot image") + need_upload = True + elif not gcp_creation_time: + logger.info(f"GCP image '{image_name}' does not exist, will upload") + need_upload = True + else: + # Parse GCP timestamp and compare + try: + from datetime import datetime + gcp_dt = datetime.fromisoformat(gcp_creation_time.replace('Z', '+00:00')) + gcp_epoch = gcp_dt.timestamp() + if local_mtime > gcp_epoch: + logger.info("Local image is newer than GCP image, will re-upload") + logger.info(f" Local: {datetime.fromtimestamp(local_mtime).isoformat()}") + logger.info(f" GCP: {gcp_creation_time}") + need_upload = True + else: + logger.info(f"GCP image '{image_name}' is up-to-date") + except Exception as e: + logger.warning(f"Could not parse GCP timestamp: {e}") + need_upload = True + + if need_upload: + logger.info("Uploading boot image to GCS...") + self._run_gsutil([ + "cp", str(tar_path), f"{config.bucket}/{image_name}.tar.gz" + ]) + + # Delete existing image if present + if gcp_creation_time: + logger.info("Deleting existing GCP image...") + self._run_gcloud([ + "compute", "images", "delete", image_name, + f"--project={config.project}", + "--quiet" + ]) + + logger.info("Creating GCP image with TDX support...") + self._run_gcloud([ + "compute", "images", "create", image_name, + f"--project={config.project}", + f"--source-uri={config.bucket}/{image_name}.tar.gz", + "--guest-os-features=UEFI_COMPATIBLE,TDX_CAPABLE,GVNIC" + ]) + + return image_name + + def _create_shared_disk_image(self, config: GcpConfig, app: App) -> str: + """Create and upload shared disk image. Returns the image name.""" + import secrets + import shutil + + # Check if mcopy (mtools) is installed + if not shutil.which("mcopy"): + logger.error("") + logger.error("Error: 'mcopy' command not found.") + logger.error("") + logger.error("Please install mtools:") + logger.error(" Ubuntu/Debian: sudo apt-get install mtools") + logger.error(" Fedora/RHEL: sudo dnf install mtools") + logger.error(" Arch Linux: sudo pacman -S mtools") + logger.error("") + raise FileNotFoundError("mcopy not found. Please install mtools package.") + + # Ensure instance_id_seed and app_id exist + if not app.instance_id_seed: + app.instance_id_seed = secrets.token_hex(20) + logger.info(f"Generated instance_id_seed: {app.instance_id_seed}") + self.save_app_config(app) + + if not app.app_id: + app.app_id = secrets.token_hex(20) + logger.info(f"Generated app_id: {app.app_id}") + self.save_app_config(app) + + shared_dir = self._get_shared_dir() + + # Ensure shared directory exists and generate all required files + shared_dir.mkdir(parents=True, exist_ok=True) + + shared_image_name = f"{config.instance_name}-shared" + + # Process .env file: encrypt and save to shared/.encrypted-env + env_path = self.work_dir / app.env_file + env_names = [] # Collect environment variable names for allowed_envs + + if env_path.exists(): + if app.key_provider != "kms": + raise ValueError(f"{app.env_file} found but KMS is not enabled. " + f"Enable KMS with --key-provider kms or remove {app.env_file}") + + if not app.app_id: + raise ValueError(f"{app.env_file} found but app_id is not set. " + f"Run 'dstack-cloud prepare' to generate app_id") + + # Parse .env file + envs = self._parse_env_file(env_path) + if envs: + env_names = list(envs.keys()) + + # Get KMS URL from global config + global_config = self._load_global_config() + kms_urls = global_config.get("services", {}).get("kms_urls", []) + if not kms_urls: + raise ValueError("KMS enabled but no kms_urls configured in global config") + + # Get encryption public key from KMS + kms_url = kms_urls[0] + pubkey = self._get_app_encrypt_pub_key(app.app_id, kms_url) + + # Encrypt environment variables + encrypted_env = self._encrypt_env(envs, pubkey) + + # Save to shared/.encrypted-env + encrypted_file = shared_dir / ".encrypted-env" + with open(encrypted_file, 'w') as f: + f.write(encrypted_env) + logger.info(f"Encrypted {app.env_file} -> {encrypted_file}") + else: + logger.info(f"{app.env_file} is empty, skipping") + + # Regenerate app-compose.json with env_names (if any) + # This must be done after .env processing and before creating the disk image + global_config = self._load_global_config() + sys_config_content = self._generate_sys_config(global_config, config, app) + sys_config_path = shared_dir / ".sys-config.json" + with open(sys_config_path, 'w') as f: + json.dump(sys_config_content, f, indent=2) + logger.info(f"Generated {sys_config_path}") + + # Generate .instance_info + instance_info = { + "instance_id_seed": app.instance_id_seed, + "app_id": app.app_id + } + instance_info_path = shared_dir / ".instance_info" + with open(instance_info_path, 'w') as f: + json.dump(instance_info, f, indent=2) + logger.info(f"Generated {instance_info_path}") + + # Generate app-compose.json with env_names (from .env file) + app_compose_content = self._generate_app_compose(app, env_names=env_names if env_names else None) + app_compose_path = shared_dir / "app-compose.json" + with open(app_compose_path, 'w') as f: + json.dump(app_compose_content, f, indent=2) + logger.info(f"Generated {app_compose_path}") + + with tempfile.TemporaryDirectory() as work_dir: + work_path = Path(work_dir) + raw_file = work_path / "disk.raw" + + # Create FAT32 disk image (no root required) + logger.info("Creating shared disk image...") + disk_size = "8M" # 8MB FAT32 disk + subprocess.run( + ["truncate", "-s", disk_size, str(raw_file)], + check=True + ) + subprocess.run( + ["mkfs.fat", "-F", "32", "-n", "DSTACKSHR", str(raw_file)], + check=True, capture_output=True + ) + + # Use mtools to copy files without mounting (no root required) + # Copy generated system files from shared directory + required_files = ["app-compose.json", ".sys-config.json", ".instance_info"] + for f in required_files: + src = shared_dir / f + if src.exists(): + subprocess.run( + ["mcopy", "-i", str(raw_file), str(src), "::"], + check=True + ) + else: + raise FileNotFoundError(f"Required file {f} not found in {shared_dir}") + + # Copy optional system files from shared directory + optional_files = [".encrypted-env"] + for f in optional_files: + src = shared_dir / f + if src.exists(): + subprocess.run( + ["mcopy", "-i", str(raw_file), str(src), "::"], + check=True + ) + + # Copy other user-editable files from project root + user_files = { + ".user-config": ".user-config", + } + + for src_name, dst_name in user_files.items(): + src_path = self.work_dir / src_name + if src_path.exists(): + subprocess.run( + ["mcopy", "-i", str(raw_file), str(src_path), f"::{dst_name}"], + check=True + ) + logger.info(f"Included {src_name}") + else: + logger.warning(f"{src_name} not found, skipping") + + # Create tar + tar_file = work_path / "shared-disk.tar.gz" + subprocess.run( + ["tar", "-C", str(work_path), "-czvf", str(tar_file), "disk.raw"], + check=True, capture_output=True + ) + + # Upload to GCS + logger.info("Uploading shared disk image to GCS...") + self._run_gsutil([ + "cp", str(tar_file), f"{config.bucket}/{shared_image_name}.tar.gz" + ]) + + # Delete existing image if present + result = self._run_gcloud([ + "compute", "images", "describe", shared_image_name, + f"--project={config.project}" + ], check=False) + + if result.returncode == 0: + logger.info("Deleting existing shared disk image...") + self._run_gcloud([ + "compute", "images", "delete", shared_image_name, + f"--project={config.project}", + "--quiet" + ]) + + # Create GCP image + logger.info("Creating GCP image from shared disk...") + self._run_gcloud([ + "compute", "images", "create", shared_image_name, + f"--project={config.project}", + f"--source-uri={config.bucket}/{shared_image_name}.tar.gz", + "--guest-os-features=GVNIC" + ]) + + return shared_image_name + + def deploy(self, delete_existing: bool = False, + force_boot_image: bool = False) -> None: + """Deploy VM to GCP.""" + config = self.load_gcp_config() + app = self.load_app_config() + + # Auto-detect bucket if not specified + if not config.bucket and config.project: + config.bucket = f"gs://{config.project}-dstack" + + shared_dir = self._get_shared_dir() + + logger.info("=== GCP TDX VM Deployment ===") + logger.info(f"Project: {config.project}") + logger.info(f"Zone: {config.zone}") + logger.info(f"Instance: {config.instance_name}") + logger.info(f"Shared Directory: {shared_dir}") + logger.info(f"GCS Bucket: {config.bucket}") + + # Delete existing instance if requested + if delete_existing: + self._delete_instance_if_exists(config) + + # Check and upload boot image + boot_image = self._check_and_upload_boot_image(config, app, force=force_boot_image) + + # Create shared disk image + shared_image = self._create_shared_disk_image(config, app) + + # Create TDX instance + logger.info("Creating TDX instance...") + + create_args = [ + "compute", "instances", "create", config.instance_name, + f"--zone={config.zone}", + f"--project={config.project}", + f"--machine-type={config.machine_type}", + "--confidential-compute-type=TDX", + f"--image={boot_image}", + "--boot-disk-size=10GB", + f"--create-disk=name={config.instance_name}-data,size={config.data_size}GB,type=pd-balanced,image={config.data_image},auto-delete=yes", + f"--create-disk=name={config.instance_name}-shared,size=1GB,type=pd-balanced,image={shared_image},auto-delete=yes", + "--maintenance-policy=TERMINATE", + ] + + if config.network != "default": + create_args.append(f"--network={config.network}") + if config.subnet: + create_args.append(f"--subnet={config.subnet}") + if config.tags: + create_args.append(f"--tags={','.join(config.tags)}") + if config.labels: + labels_str = ",".join(f"{k}={v}" for k, v in config.labels.items()) + create_args.append(f"--labels={labels_str}") + + self._run_gcloud(create_args) + + # Get instance details + result = self._run_gcloud([ + "compute", "instances", "describe", config.instance_name, + f"--zone={config.zone}", + f"--project={config.project}", + "--format=json" + ]) + + instance_info = json.loads(result.stdout) + external_ip = "" + internal_ip = "" + + for iface in instance_info.get("networkInterfaces", []): + internal_ip = iface.get("networkIP", "") + for access in iface.get("accessConfigs", []): + external_ip = access.get("natIP", "") + break + + # Save state + state = DeploymentState( + instance_name=config.instance_name, + project=config.project, + zone=config.zone, + external_ip=external_ip, + internal_ip=internal_ip, + status="RUNNING", + created_at=datetime.now().isoformat(), + boot_image=boot_image, + shared_image=shared_image, + ) + self.save_state(state) + + logger.info("") + logger.info("=== Deployment Complete ===") + logger.info(f"Instance: {config.instance_name}") + logger.info(f"External IP: {external_ip}") + logger.info(f"Internal IP: {internal_ip}") + logger.info("") + logger.info("To check serial output:") + logger.info(f" dstack-cloud logs") + + def _delete_instance_if_exists(self, config: GcpConfig) -> None: + """Delete instance if it exists.""" + result = self._run_gcloud([ + "compute", "instances", "describe", config.instance_name, + f"--zone={config.zone}", + f"--project={config.project}" + ], check=False) + + if result.returncode == 0: + logger.info(f"Deleting existing instance: {config.instance_name}") + self._run_gcloud([ + "compute", "instances", "delete", config.instance_name, + f"--zone={config.zone}", + f"--project={config.project}", + "--quiet" + ]) + + def _parse_env_file(self, file_path: Path) -> Dict[str, str]: + """Parse an environment file where each line is formatted as KEY=Value.""" + if not file_path or not file_path.exists(): + return {} + + envs = {} + with open(file_path, 'r') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + if '=' not in line: + continue + key, value = line.split('=', 1) + envs[key.strip()] = value.strip() + return envs + + def _encrypt_env(self, envs: Dict[str, str], hex_public_key: str) -> str: + """ + Encrypt environment variables using X25519 key exchange and AES-GCM. + + Args: + envs: Environment variables dictionary + hex_public_key: Remote encryption public key in hexadecimal format + + Returns: + Hex string of (ephemeral public key || IV || ciphertext) + """ + if not CRYPTO_AVAILABLE: + raise ImportError( + "Cryptography libraries not available. Please install:\n" + "pip install cryptography" + ) + + # Serialize environment variables to JSON + envs_json = json.dumps({"env": envs}).encode("utf-8") + + # Remove "0x" prefix if present + if hex_public_key.startswith("0x"): + hex_public_key = hex_public_key[2:] + + # Convert hex public key to bytes + remote_pubkey_bytes = bytes.fromhex(hex_public_key) + + # Generate ephemeral X25519 key pair + ephemeral_private_key = x25519.X25519PrivateKey.generate() + ephemeral_public_key = ephemeral_private_key.public_key() + + # Compute shared secret using X25519 + peer_public_key = x25519.X25519PublicKey.from_public_bytes(remote_pubkey_bytes) + shared = ephemeral_private_key.exchange(peer_public_key) + + # Use shared secret as key for AES-GCM (32 bytes for AES-256) + aesgcm = AESGCM(shared) + iv = os.urandom(12) # 12-byte nonce for AES-GCM + ciphertext = aesgcm.encrypt(iv, envs_json, None) + + # Serialize ephemeral public key to raw bytes + ephemeral_public_bytes = ephemeral_public_key.public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) + + # Combine ephemeral public key, IV, and ciphertext + result = ephemeral_public_bytes + iv + ciphertext + return result.hex() + + def _get_app_encrypt_pub_key(self, app_id: str, kms_url: str) -> str: + """Get encryption public key for the specified app_id from KMS.""" + try: + import urllib.request + import urllib.error + + path = f"{kms_url}/prpc/GetAppEnvEncryptPubKey?json" + data = json.dumps({"app_id": app_id}).encode("utf-8") + + req = urllib.request.Request( + path, + data=data, + headers={"Content-Type": "application/json"} + ) + + logger.info(f"Getting encryption public key for {app_id} from {kms_url}") + with urllib.request.urlopen(req, timeout=10) as response: + response_data = json.loads(response.read().decode("utf-8")) + + if "public_key" not in response_data: + raise ValueError(f"No public_key in response: {response_data}") + + return response_data["public_key"] + + except Exception as e: + logger.warning(f"Failed to get encryption public key: {e}") + raise + + def _derive_instance_id(self, instance_id_seed: str, app_id: str) -> str: + """Derive instance_id from instance_id_seed and app_id. + + Both instance_id_seed and app_id are hex strings that need to be + decoded to bytes before concatenation, matching the Rust implementation. + """ + # Decode hex strings to bytes + seed_bytes = bytes.fromhex(instance_id_seed) + app_bytes = bytes.fromhex(app_id) + + # Concatenate bytes (not hex strings) + id_path = seed_bytes + app_bytes + + # Compute SHA256 and take first 20 bytes, then convert to hex string + instance_id = hashlib.sha256(id_path).digest()[:20] + return instance_id.hex() + + def _get_gateway_urls(self, app: App, instance_id: str) -> Dict[str, str]: + """Construct gateway URLs for app access. + + Returns: + Dict with 'app_url' and 'instance_url' keys + """ + if not app.gateway_enabled: + return {} + + global_config = self._load_global_config() + gateway_urls = global_config.get("services", {}).get("gateway_urls", []) + if not gateway_urls: + return {} + + # Try to get gateway info from RPC + gateway_info = None + for gateway_url in gateway_urls: + try: + info_url = f"{gateway_url}/prpc/Info" + result = subprocess.run( + ["curl", "-sk", info_url], + capture_output=True, + text=True, + timeout=5 + ) + if result.returncode == 0: + gateway_info = json.loads(result.stdout) + break + except Exception as e: + logger.debug(f"Failed to get gateway info from {gateway_url}: {e}") + continue + + if not gateway_info: + return {} + + base_domain = gateway_info.get("base_domain") + external_port = gateway_info.get("external_port") + + if not base_domain or not external_port: + return {} + + # Construct URLs: one with instance_id, one with app_id + app_id = app.app_id + app_url = f"https://{app_id}-8090.{base_domain}:{external_port}/" + instance_url = f"https://{instance_id}-8090.{base_domain}:{external_port}/" + + return { + "app_url": app_url, + "instance_url": instance_url + } + + def status(self) -> None: + """Check deployment status.""" + state = self.load_state() + if not state or not state.instance_name: + logger.info("No deployment found. Run 'dstack-cloud deploy' first.") + return + + # Get current status from GCP + result = self._run_gcloud([ + "compute", "instances", "describe", state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}", + "--format=json" + ], check=False) + + if result.returncode != 0: + logger.info(f"Instance '{state.instance_name}' not found in GCP") + state.status = "NOT_FOUND" + self.save_state(state) + return + + instance_info = json.loads(result.stdout) + status = instance_info.get("status", "UNKNOWN") + + # Update IPs + external_ip = "" + internal_ip = "" + for iface in instance_info.get("networkInterfaces", []): + internal_ip = iface.get("networkIP", "") + for access in iface.get("accessConfigs", []): + external_ip = access.get("natIP", "") + break + + state.status = status + state.external_ip = external_ip + state.internal_ip = internal_ip + self.save_state(state) + + print(f"Instance: {state.instance_name}") + print(f"Project: {state.project}") + print(f"Zone: {state.zone}") + print(f"Status: {status}") + print(f"External IP: {external_ip or 'N/A'}") + print(f"Internal IP: {internal_ip or 'N/A'}") + print(f"Boot Image: {state.boot_image}") + print(f"Created: {state.created_at}") + print(f"Updated: {state.updated_at}") + + # Display gateway URLs if enabled + # Try to load from .instance_info first (actual deployed values) + app = self.load_app_config() + if not app.gateway_enabled: + return + + instance_id_seed = None + app_id = None + + # Try to read from shared/.instance_info (actual deployed values) + instance_info_path = self._get_shared_dir() / ".instance_info" + if instance_info_path.exists(): + try: + with open(instance_info_path, 'r') as f: + instance_info_data = json.load(f) + instance_id_seed = instance_info_data.get("instance_id_seed") + app_id = instance_info_data.get("app_id") + except Exception as e: + logger.debug(f"Failed to read .instance_info: {e}") + + # Fallback to app.json if .instance_info not found or missing values + if not instance_id_seed or not app_id: + instance_id_seed = app.instance_id_seed + app_id = app.app_id + + if instance_id_seed and app_id: + instance_id = self._derive_instance_id(instance_id_seed, app_id) + gateway_urls = self._get_gateway_urls(app, instance_id) + if gateway_urls: + print("") + print("Gateway URLs:") + print(f" App URL: {gateway_urls.get('app_url', 'N/A')}") + print(f" Instance URL: {gateway_urls.get('instance_url', 'N/A')}") + + def logs(self, follow: bool = False, lines: int = 100) -> None: + """View serial console logs.""" + state = self.load_state() + if not state or not state.instance_name: + raise ValueError("No deployment found. Run 'dstack-cloud deploy' first.") + + if follow: + # Tail logs continuously + logger.info(f"Following serial output for {state.instance_name}...") + logger.info("Press Ctrl+C to stop") + + last_output = "" + while True: + try: + result = self._run_gcloud([ + "compute", "instances", "get-serial-port-output", + state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}" + ], check=False) + + if result.returncode == 0: + output = result.stdout + if output != last_output: + # Print only new content + if last_output: + new_content = output[len(last_output):] + if new_content: + print(new_content, end="", flush=True) + else: + # First time, print last N lines + lines_list = output.split('\n') + print('\n'.join(lines_list[-lines:]), flush=True) + last_output = output + + time.sleep(2) + except KeyboardInterrupt: + print("\nStopped following logs.") + break + else: + # Get logs once + result = self._run_gcloud([ + "compute", "instances", "get-serial-port-output", + state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}" + ]) + + output = result.stdout + lines_list = output.split('\n') + print('\n'.join(lines_list[-lines:])) + + def stop(self) -> None: + """Stop the VM.""" + state = self.load_state() + if not state or not state.instance_name: + raise ValueError("No deployment found. Run 'dstack-cloud deploy' first.") + + logger.info(f"Stopping instance {state.instance_name}...") + self._run_gcloud([ + "compute", "instances", "stop", state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}" + ]) + + state.status = "STOPPED" + self.save_state(state) + logger.info("Instance stopped.") + + def start(self) -> None: + """Start a stopped VM.""" + state = self.load_state() + if not state or not state.instance_name: + raise ValueError("No deployment found. Run 'dstack-cloud deploy' first.") + + logger.info(f"Starting instance {state.instance_name}...") + self._run_gcloud([ + "compute", "instances", "start", state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}" + ]) + + # Update state with new IP + self.status() + logger.info("Instance started.") + + def remove(self, keep_images: bool = False) -> None: + """Remove the VM and cleanup.""" + state = self.load_state() + if not state or not state.instance_name: + logger.info("No deployment found.") + return + + # Delete instance + logger.info(f"Deleting instance {state.instance_name}...") + self._run_gcloud([ + "compute", "instances", "delete", state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}", + "--quiet" + ], check=False) + + if not keep_images and state.shared_image: + # Delete shared disk image + logger.info(f"Deleting shared disk image {state.shared_image}...") + self._run_gcloud([ + "compute", "images", "delete", state.shared_image, + f"--project={state.project}", + "--quiet" + ], check=False) + + # Clear state + state.status = "REMOVED" + state.external_ip = "" + state.internal_ip = "" + self.save_state(state) + + logger.info("Instance removed.") + + def list_deployments(self, project: Optional[str] = None) -> None: + """List all dstack deployments in a project.""" + if not project: + # Try to get from config + try: + config = self.load_gcp_config() + project = config.project + except FileNotFoundError: + # Try global config + global_config = self._load_global_config() + project = global_config.get("gcp", {}).get("project", "") + + if not project: + raise ValueError("Project is required. Specify with --project or configure it.") + + result = self._run_gcloud([ + "compute", "instances", "list", + f"--project={project}", + "--filter=name~^dstack-", + "--format=table(name,zone,status,networkInterfaces[0].accessConfigs[0].natIP:label=EXTERNAL_IP,creationTimestamp)" + ], capture=False) + + +def main(): + parser = argparse.ArgumentParser( + description="Multi-cloud VM lifecycle management tool", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Create a new project + dstack-cloud new myproject + + # Initialize current directory + dstack-cloud init + + # Edit global configuration + dstack-cloud config-edit + + # Download OS image + dstack-cloud pull dstack-0.6.0 + + # Deploy VM + dstack-cloud deploy + + # Check status + dstack-cloud status + + # View logs + dstack-cloud logs --follow + + # Stop/Start/Remove + dstack-cloud stop + dstack-cloud start + dstack-cloud remove +""" + ) + + parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output") + parser.add_argument("-C", "--directory", type=str, help="Change to directory before running") + + subparsers = parser.add_subparsers(dest="command", help="Commands") + + # new command + new_parser = subparsers.add_parser("new", help="Create a new project") + new_parser.add_argument("name", type=str, help="Project name") + + # App configuration options + new_parser.add_argument("--os-image", type=str, help="OS image (e.g., dstack-0.6.0)") + new_parser.add_argument("--app-id", type=str, help="Application ID (40 hex chars)") + new_parser.add_argument("--gateway-enabled", "--gw", dest="gateway_enabled", action="store_true", help="Enable dstack-gateway") + new_parser.add_argument("--no-gateway-enabled", "--no-gw", dest="gateway_enabled", action="store_false") + new_parser.set_defaults(gateway_enabled=None) + new_parser.add_argument("--key-provider", "--kp", type=str, choices=["kms", "local", "tpm", "none"], help="Key provider type") + new_parser.add_argument("--storage-fs", "--fs", dest="storage_fs", type=str, choices=["ext4", "zfs"], help="Storage filesystem") + new_parser.add_argument("--secure-time", action="store_true", help="Enable secure time synchronization") + new_parser.add_argument("--no-secure-time", dest="secure_time", action="store_false") + new_parser.set_defaults(secure_time=None) + new_parser.add_argument("--no-instance-id", action="store_true", help="Disable instance ID generation") + + # GCP configuration options + new_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + new_parser.add_argument("--zone", "-z", type=str, help="GCP zone (e.g., us-central1-a)") + new_parser.add_argument("--instance-name", type=str, help="GCP instance name") + new_parser.add_argument("--machine-type", "-m", type=str, help="Machine type (e.g., c3-standard-4)") + new_parser.add_argument("--data-size", type=int, help="Data disk size in GB") + + # init command + init_parser = subparsers.add_parser("init", help="Initialize deployment configuration") + init_parser.add_argument("--force", "-f", action="store_true", help="Overwrite existing config") + init_parser.add_argument("--non-interactive", "-n", action="store_true", help="Skip interactive prompts") + + # App configuration options (same as new) + init_parser.add_argument("--os-image", type=str, help="OS image (e.g., dstack-0.6.0)") + init_parser.add_argument("--app-id", type=str, help="Application ID (40 hex chars)") + init_parser.add_argument("--gateway-enabled", "--gw", dest="gateway_enabled", action="store_true", help="Enable dstack-gateway") + init_parser.add_argument("--no-gateway-enabled", "--no-gw", dest="gateway_enabled", action="store_false") + init_parser.set_defaults(gateway_enabled=None) + init_parser.add_argument("--key-provider", "--kp", type=str, choices=["kms", "local", "tpm", "none"], help="Key provider type") + init_parser.add_argument("--storage-fs", "--fs", dest="storage_fs", type=str, choices=["ext4", "zfs"], help="Storage filesystem") + init_parser.add_argument("--secure-time", action="store_true", help="Enable secure time synchronization") + init_parser.add_argument("--no-secure-time", dest="secure_time", action="store_false") + init_parser.set_defaults(secure_time=None) + init_parser.add_argument("--no-instance-id", action="store_true", help="Disable instance ID generation") + + # GCP configuration options (same as new) + init_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + init_parser.add_argument("--zone", "-z", type=str, help="GCP zone (e.g., us-central1-a)") + init_parser.add_argument("--instance-name", type=str, help="GCP instance name") + init_parser.add_argument("--machine-type", "-m", type=str, help="Machine type (e.g., c3-standard-4)") + init_parser.add_argument("--data-size", type=int, help="Data disk size in GB") + + # config-edit command + subparsers.add_parser("config-edit", help="Edit global configuration") + + # prepare command + subparsers.add_parser("prepare", help="Generate shared files") + + # pull command + pull_parser = subparsers.add_parser("pull", help="Download OS image") + pull_parser.add_argument("image", type=str, help="OS image name (e.g., dstack-0.6.0)") + + # deploy command + deploy_parser = subparsers.add_parser("deploy", help="Deploy VM to cloud") + deploy_parser.add_argument("--delete", "-d", action="store_true", + help="Delete existing instance first") + deploy_parser.add_argument("--force-boot-image", action="store_true", + help="Force re-upload boot image") + + # status command + subparsers.add_parser("status", help="Check deployment status") + + # logs command + logs_parser = subparsers.add_parser("logs", help="View serial console logs") + logs_parser.add_argument("--follow", "-f", action="store_true", help="Follow log output") + logs_parser.add_argument("--lines", "-n", type=int, default=100, help="Number of lines to show") + + # stop command + subparsers.add_parser("stop", help="Stop the VM") + + # start command + subparsers.add_parser("start", help="Start a stopped VM") + + # remove command + remove_parser = subparsers.add_parser("remove", help="Remove the VM and cleanup") + remove_parser.add_argument("--keep-images", action="store_true", + help="Keep disk images in GCP") + + # list command + list_parser = subparsers.add_parser("list", help="List all deployments") + list_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + + args = parser.parse_args() + + if args.verbose: + logging.getLogger().setLevel(logging.DEBUG) + + work_dir = args.directory if args.directory else None + manager = CloudDeploymentManager(work_dir) + + try: + if args.command == "new": + manager.new( + args.name, + os_image=args.os_image, + app_id=args.app_id, + gateway_enabled=args.gateway_enabled, + key_provider=args.key_provider, + storage_fs=args.storage_fs, + secure_time=args.secure_time, + no_instance_id=args.no_instance_id, + project=args.project, + zone=args.zone, + instance_name=args.instance_name, + machine_type=args.machine_type, + data_size=args.data_size + ) + elif args.command == "init": + manager.init( + force=args.force, + interactive=not args.non_interactive, + os_image=args.os_image, + app_id=args.app_id, + gateway_enabled=args.gateway_enabled, + key_provider=args.key_provider, + storage_fs=args.storage_fs, + secure_time=args.secure_time, + no_instance_id=args.no_instance_id, + project=args.project, + zone=args.zone, + instance_name=args.instance_name, + machine_type=args.machine_type, + data_size=args.data_size + ) + elif args.command == "config-edit": + manager.config_edit() + elif args.command == "prepare": + manager.prepare() + elif args.command == "pull": + manager.pull(args.image) + elif args.command == "deploy": + manager.deploy( + delete_existing=args.delete, + force_boot_image=args.force_boot_image + ) + elif args.command == "status": + manager.status() + elif args.command == "logs": + manager.logs(follow=args.follow, lines=args.lines) + elif args.command == "stop": + manager.stop() + elif args.command == "start": + manager.start() + elif args.command == "remove": + manager.remove(keep_images=args.keep_images) + elif args.command == "list": + manager.list_deployments(project=args.project) + else: + parser.print_help() + except Exception as e: + logger.error(str(e)) + if args.verbose: + import traceback + traceback.print_exc() + sys.exit(1) + + +if __name__ == "__main__": + main() From 9163e801ada76eaa6e7cb7f9e20d65bd61f44f3b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 24 Dec 2025 09:21:17 +0000 Subject: [PATCH 033/119] Sync dstack/ --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index f1a49f0..448e606 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit f1a49f01a74c03c2034587dcf624bfc9c918ef20 +Subproject commit 448e606cb970231d56a4dfed211ef37f827b5e55 From 373ba086584d81a028a65655093af4f7d8109fee Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 8 Jan 2026 12:23:09 +0000 Subject: [PATCH 034/119] Update dstack --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 448e606..ffb41d9 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 448e606cb970231d56a4dfed211ef37f827b5e55 +Subproject commit ffb41d9a14bbff196a5b77b43a988a7507d56191 From 44a44446a8710c24db9a29604e20e42d0b301233 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 8 Jan 2026 13:28:32 +0000 Subject: [PATCH 035/119] Update url of dstack submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 415c27a..fb2a5ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,7 +23,7 @@ url = https://github.com/Dstack-TEE/meta-rust-bin [submodule "dstack"] path = dstack - url = https://github.com/Dstack-TEE/dstack + url = git@github.com:Phala-Network/dstack-gcp.git [submodule "meta-security"] path = meta-security url = https://github.com/Dstack-TEE/meta-security.git From ea76d255756be93e4f28faf65a9ba30523f7122e Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 15 Jan 2026 02:10:13 +0000 Subject: [PATCH 036/119] Fix reproducibility issues --- dstack | 2 +- .../dstack-zfs/dstack-zfs_2.4.0.bb | 1 + meta-security | 2 +- repro-build/Dockerfile.repro | 6 ++- repro-build/check.sh | 44 ++++++++++++++++--- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/dstack b/dstack index ffb41d9..23ccf00 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit ffb41d9a14bbff196a5b77b43a988a7507d56191 +Subproject commit 23ccf00807806f1dbec9eaba81e8105e260e0979 diff --git a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb index 93d18bf..ced8526 100644 --- a/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb +++ b/meta-dstack/recipes-core/dstack-zfs/dstack-zfs_2.4.0.bb @@ -68,6 +68,7 @@ FILES:${PN}-dev += "\ " # Skip buildpaths QA check for kernel modules INSANE_SKIP:${PN} += "buildpaths" +INSANE_SKIP:${PN}-dbg += "buildpaths" # Not yet ported to rv32 COMPATIBLE_HOST:riscv32 = "null" diff --git a/meta-security b/meta-security index a54650c..323f5a4 160000 --- a/meta-security +++ b/meta-security @@ -1 +1 @@ -Subproject commit a54650c743b7534f60fc6ee1df9b57a8f0150a4d +Subproject commit 323f5a448dcaba65e36d8d63cf20eb127cf91a5a diff --git a/repro-build/Dockerfile.repro b/repro-build/Dockerfile.repro index 00c3084..b6951f5 100644 --- a/repro-build/Dockerfile.repro +++ b/repro-build/Dockerfile.repro @@ -26,7 +26,11 @@ RUN apt update && apt install -y \ libclang-dev \ xorriso \ cpio \ - zstd + zstd \ + gdisk \ + dosfstools \ + mtools \ + libsqlite3-dev # Generate locale for bitbake RUN locale-gen en_US.UTF-8 diff --git a/repro-build/check.sh b/repro-build/check.sh index 74df226..e83e257 100755 --- a/repro-build/check.sh +++ b/repro-build/check.sh @@ -22,6 +22,30 @@ BB_DIR_B=${BB_DIR_B:-${BUILD_DIR_B}/bb-build} ROOTFS_A=${BB_DIR_A}/${ROOTFS_PATH} ROOTFS_B=${BB_DIR_B}/${ROOTFS_PATH} +# Only compare these image paths (relative to $BUILD_DIR_*/images). +# Everything else is ignored to avoid known non-reproducible artifacts. +COMPARE_IMAGE_WHITELIST=( + "bzImage" + "digest.txt" + "initramfs.cpio.gz" + "metadata.json" + "ovmf.fd" + "rootfs.img.verity" + "sha256sum.txt" + "gcp/efi-root/EFI/BOOT/BOOTX64.EFI" +) + +is_whitelisted_image() { + local rel_path="$1" + local item + for item in "${COMPARE_IMAGE_WHITELIST[@]}"; do + if [ "$rel_path" = "$item" ] || [[ "$rel_path" == */"$item" ]]; then + return 0 + fi + done + return 1 +} + check_files() { local path_a="$1" local path_b="$2" @@ -121,24 +145,30 @@ analyze() { check_images() { echo -e "${YELLOW}Checking image files...${NC}" - find $BUILD_DIR_A/images -type f | while read file_a; do - rel_path=$(echo ${file_a} | sed "s#${BUILD_DIR_A}/images/##g") - file_b=$BUILD_DIR_B/images/$rel_path + local differences=0 + while IFS= read -r file_a; do + rel_path=$(echo "$file_a" | sed "s#${BUILD_DIR_A}/images/##g") + file_b="$BUILD_DIR_B/images/$rel_path" + if ! is_whitelisted_image "$rel_path"; then + continue + fi if [ ! -f "$file_b" ]; then echo -e "${RED}$rel_path is not found in $BUILD_DIR_B/images/${NC}" + differences=$((differences + 1)) continue fi - hash_a=$(md5sum $file_a | cut -d' ' -f 1) - hash_b=$(md5sum $file_b | cut -d' ' -f 1) + hash_a=$(md5sum "$file_a" | cut -d' ' -f 1) + hash_b=$(md5sum "$file_b" | cut -d' ' -f 1) if [ "$hash_a" != "$hash_b" ]; then echo -e "${RED}Hash mismatch for $rel_path:${NC}" echo -e "${RED}$hash_a $file_a${NC}" echo -e "${RED}$hash_b $file_b${NC}" - return 1 + differences=$((differences + 1)) else echo -e "${GREEN}Match for $rel_path${NC}" fi - done + done < <(find "$BUILD_DIR_A/images" -type f) + return $differences } check() { From 268ce48628b2cb93c27d2d2df447a6d0284affd1 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 15 Jan 2026 08:05:32 +0000 Subject: [PATCH 037/119] Update dstack --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 23ccf00..9df8aa1 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 23ccf00807806f1dbec9eaba81e8105e260e0979 +Subproject commit 9df8aa1fa8f807e0a74181831b210dca21b8b2d0 From d06a4d66510db9f8cd51cbcb87e3005451e7453d Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 15 Jan 2026 12:32:53 +0000 Subject: [PATCH 038/119] dstack-cloud: Add fw command group --- scripts/bin/dstack-cloud | 356 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 336 insertions(+), 20 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 4f0de51..09e540f 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -22,6 +22,10 @@ Usage: dstack-cloud start # Start a stopped VM dstack-cloud remove # Remove the VM and cleanup dstack-cloud list # List all deployments + dstack-cloud fw allow # Allow traffic on a port + dstack-cloud fw deny # Block traffic on a port + dstack-cloud fw remove # Remove a firewall rule + dstack-cloud fw list # List firewall rules """ import argparse @@ -1216,9 +1220,27 @@ class CloudDeploymentManager: logger.info(f"Shared Directory: {shared_dir}") logger.info(f"GCS Bucket: {config.bucket}") - # Delete existing instance if requested - if delete_existing: - self._delete_instance_if_exists(config) + # Check if instance already exists + result = self._run_gcloud([ + "compute", "instances", "describe", config.instance_name, + f"--zone={config.zone}", + f"--project={config.project}" + ], check=False) + + if result.returncode == 0: + if delete_existing: + logger.info(f"Deleting existing instance: {config.instance_name}") + self._run_gcloud([ + "compute", "instances", "delete", config.instance_name, + f"--zone={config.zone}", + f"--project={config.project}", + "--quiet" + ]) + else: + raise RuntimeError( + f"Instance '{config.instance_name}' already exists. " + f"Use --delete to replace it." + ) # Check and upload boot image boot_image = self._check_and_upload_boot_image(config, app, force=force_boot_image) @@ -1295,23 +1317,6 @@ class CloudDeploymentManager: logger.info("To check serial output:") logger.info(f" dstack-cloud logs") - def _delete_instance_if_exists(self, config: GcpConfig) -> None: - """Delete instance if it exists.""" - result = self._run_gcloud([ - "compute", "instances", "describe", config.instance_name, - f"--zone={config.zone}", - f"--project={config.project}" - ], check=False) - - if result.returncode == 0: - logger.info(f"Deleting existing instance: {config.instance_name}") - self._run_gcloud([ - "compute", "instances", "delete", config.instance_name, - f"--zone={config.zone}", - f"--project={config.project}", - "--quiet" - ]) - def _parse_env_file(self, file_path: Path) -> Dict[str, str]: """Parse an environment file where each line is formatted as KEY=Value.""" if not file_path or not file_path.exists(): @@ -1698,6 +1703,247 @@ class CloudDeploymentManager: "--format=table(name,zone,status,networkInterfaces[0].accessConfigs[0].natIP:label=EXTERNAL_IP,creationTimestamp)" ], capture=False) + def _get_firewall_rule_name(self, instance_name: str, port: int, protocol: str, + action: str = "allow") -> str: + """Generate firewall rule name for an instance port.""" + return f"{instance_name}-{action}-{protocol}-{port}" + + def _parse_port_spec(self, port_spec: str) -> tuple: + """Parse port specification like '8080' or '53/udp'. + + Returns: + tuple: (port: int, protocol: str) + """ + if "/" in port_spec: + port_str, protocol = port_spec.split("/", 1) + protocol = protocol.lower() + if protocol not in ("tcp", "udp"): + raise ValueError(f"Invalid protocol '{protocol}'. Must be 'tcp' or 'udp'.") + else: + port_str = port_spec + protocol = "tcp" + + try: + port = int(port_str) + except ValueError: + raise ValueError(f"Invalid port number '{port_str}'.") + + if not (1 <= port <= 65535): + raise ValueError(f"Port {port} out of range (1-65535).") + + return port, protocol + + def _get_project_for_firewall(self) -> str: + """Get project ID for firewall operations.""" + # Try state first + state = self.load_state() + if state and state.project: + return state.project + + # Try config + try: + config = self.load_gcp_config() + if config.project: + return config.project + except FileNotFoundError: + pass + + # Try global config + global_config = self._load_global_config() + project = global_config.get("gcp", {}).get("project", "") + + if not project: + raise ValueError("Project is required. Deploy first or specify with --project.") + + return project + + def _get_instance_name_for_firewall(self) -> str: + """Get instance name for firewall operations.""" + state = self.load_state() + if state and state.instance_name: + return state.instance_name + + try: + config = self.load_gcp_config() + if config.instance_name: + return config.instance_name + except FileNotFoundError: + pass + + raise ValueError("Instance name is required. Deploy first or specify with --instance.") + + def _ensure_instance_tag(self, instance_name: str, project: str) -> str: + """Ensure instance has the firewall tag, return the tag name.""" + instance_tag = f"fw-{instance_name}" + + state = self.load_state() + zone = state.zone if state else "us-central1-a" + + result = self._run_gcloud([ + "compute", "instances", "describe", instance_name, + f"--project={project}", + f"--zone={zone}", + "--format=value(tags.items)" + ], check=False) + + current_tags = result.stdout.strip().split(";") if result.stdout.strip() else [] + current_tags = [t.strip() for t in current_tags if t.strip()] + + if instance_tag not in current_tags: + logger.info(f"Adding tag '{instance_tag}' to instance '{instance_name}'...") + self._run_gcloud([ + "compute", "instances", "add-tags", instance_name, + f"--project={project}", + f"--zone={zone}", + f"--tags={instance_tag}" + ]) + logger.info(f"Added tag '{instance_tag}' to instance") + else: + logger.debug(f"Instance already has tag '{instance_tag}'") + + return instance_tag + + def fw_allow(self, port_spec: str, + source_ranges: Optional[List[str]] = None, + instance_name: Optional[str] = None, + project: Optional[str] = None) -> None: + """Add firewall rule to open a port for the instance.""" + port, protocol = self._parse_port_spec(port_spec) + project = project or self._get_project_for_firewall() + instance_name = instance_name or self._get_instance_name_for_firewall() + + if source_ranges is None: + source_ranges = ["0.0.0.0/0"] + + # Always ensure instance has the tag first + instance_tag = self._ensure_instance_tag(instance_name, project) + + rule_name = self._get_firewall_rule_name(instance_name, port, protocol) + + # Check if rule already exists + result = self._run_gcloud([ + "compute", "firewall-rules", "describe", rule_name, + f"--project={project}" + ], check=False) + + if result.returncode == 0: + logger.info(f"Firewall rule '{rule_name}' already exists") + return + + # Create firewall rule targeting this instance's tag + logger.info(f"Creating firewall rule '{rule_name}'...") + self._run_gcloud([ + "compute", "firewall-rules", "create", rule_name, + f"--project={project}", + f"--allow={protocol}:{port}", + f"--source-ranges={','.join(source_ranges)}", + f"--target-tags={instance_tag}", + f"--description=Allow {protocol.upper()} port {port} for {instance_name}" + ]) + + logger.info(f"Opened {protocol.upper()} port {port} for instance '{instance_name}'") + + def fw_deny(self, port_spec: str, + source_ranges: Optional[List[str]] = None, + instance_name: Optional[str] = None, + project: Optional[str] = None) -> None: + """Create a deny firewall rule to block traffic on a port.""" + port, protocol = self._parse_port_spec(port_spec) + project = project or self._get_project_for_firewall() + instance_name = instance_name or self._get_instance_name_for_firewall() + + if source_ranges is None: + source_ranges = ["0.0.0.0/0"] + + # Always ensure instance has the tag first + instance_tag = self._ensure_instance_tag(instance_name, project) + + rule_name = self._get_firewall_rule_name(instance_name, port, protocol, action="deny") + + # Check if rule already exists + result = self._run_gcloud([ + "compute", "firewall-rules", "describe", rule_name, + f"--project={project}" + ], check=False) + + if result.returncode == 0: + logger.info(f"Firewall rule '{rule_name}' already exists") + return + + # Create deny firewall rule with high priority (low number = high priority) + logger.info(f"Creating deny firewall rule '{rule_name}'...") + self._run_gcloud([ + "compute", "firewall-rules", "create", rule_name, + f"--project={project}", + "--action=DENY", + f"--rules={protocol}:{port}", + f"--source-ranges={','.join(source_ranges)}", + f"--target-tags={instance_tag}", + "--priority=900", + f"--description=Deny {protocol.upper()} port {port} for {instance_name}" + ]) + + logger.info(f"Blocked {protocol.upper()} port {port} for instance '{instance_name}'") + + def fw_remove(self, port_spec: str, + instance_name: Optional[str] = None, + project: Optional[str] = None) -> None: + """Remove a firewall rule (allow or deny) for a port.""" + port, protocol = self._parse_port_spec(port_spec) + project = project or self._get_project_for_firewall() + instance_name = instance_name or self._get_instance_name_for_firewall() + + # Try to delete both allow and deny rules + deleted = False + for action in ["allow", "deny"]: + rule_name = self._get_firewall_rule_name(instance_name, port, protocol, action=action) + + # Check if rule exists + result = self._run_gcloud([ + "compute", "firewall-rules", "describe", rule_name, + f"--project={project}" + ], check=False) + + if result.returncode == 0: + # Delete the rule + logger.info(f"Deleting firewall rule '{rule_name}'...") + self._run_gcloud([ + "compute", "firewall-rules", "delete", rule_name, + f"--project={project}", + "--quiet" + ]) + logger.info(f"Removed {action} rule for {protocol.upper()} port {port}") + deleted = True + + if not deleted: + logger.info(f"No firewall rules found for {protocol.upper()} port {port} on instance '{instance_name}'") + + def fw_list(self, instance_name: Optional[str] = None, + project: Optional[str] = None) -> None: + """List firewall rules for an instance.""" + project = project or self._get_project_for_firewall() + + if instance_name: + # List rules for specific instance + instance_tag = f"fw-{instance_name}" + filter_expr = f"name~^{instance_name}-allow- OR targetTags:{instance_tag}" + else: + # Try to get instance name from state + try: + instance_name = self._get_instance_name_for_firewall() + filter_expr = f"name~^{instance_name}-allow-" + except ValueError: + # List all dstack-related firewall rules + filter_expr = "name~^dstack-" + + logger.info(f"Firewall rules for project '{project}':") + self._run_gcloud([ + "compute", "firewall-rules", "list", + f"--project={project}", + f"--filter={filter_expr}", + "--format=table(name,direction,priority,allowed[].map().firewall_rule().list():label=ALLOW,sourceRanges.list():label=SRC_RANGES,targetTags.list():label=TARGET_TAGS)" + ], capture=False) + def main(): parser = argparse.ArgumentParser( @@ -1730,6 +1976,15 @@ Examples: dstack-cloud stop dstack-cloud start dstack-cloud remove + + # Firewall management + dstack-cloud fw allow 8080 # Allow TCP port 8080 + dstack-cloud fw allow 53/udp # Allow UDP port 53 + dstack-cloud fw allow 443 -s 10.0.0.0/8 # Allow port 443 from specific range + dstack-cloud fw deny 22 # Block TCP port 22 + dstack-cloud fw deny 22 -s 0.0.0.0/0 # Block port 22 from all sources + dstack-cloud fw remove 8080 # Remove firewall rule for port 8080 + dstack-cloud fw list # List firewall rules """ ) @@ -1827,6 +2082,39 @@ Examples: list_parser = subparsers.add_parser("list", help="List all deployments") list_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + # fw command group + fw_parser = subparsers.add_parser("fw", help="Firewall management") + fw_subparsers = fw_parser.add_subparsers(dest="fw_command", help="Firewall commands") + + # fw allow + fw_allow_parser = fw_subparsers.add_parser("allow", help="Open a port for the instance") + fw_allow_parser.add_argument("port", type=str, help="Port to open (e.g., 8080, 53/udp)") + fw_allow_parser.add_argument("--source", "-s", type=str, action="append", + dest="source_ranges", + help="Source IP ranges (default: 0.0.0.0/0). Can be specified multiple times.") + fw_allow_parser.add_argument("--instance", "-i", type=str, help="Instance name (default: from state)") + fw_allow_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + + # fw deny + fw_deny_parser = fw_subparsers.add_parser("deny", help="Block traffic on a port") + fw_deny_parser.add_argument("port", type=str, help="Port to block (e.g., 8080, 53/udp)") + fw_deny_parser.add_argument("--source", "-s", type=str, action="append", + dest="source_ranges", + help="Source IP ranges to block (default: 0.0.0.0/0). Can be specified multiple times.") + fw_deny_parser.add_argument("--instance", "-i", type=str, help="Instance name (default: from state)") + fw_deny_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + + # fw remove + fw_remove_parser = fw_subparsers.add_parser("remove", help="Remove a firewall rule") + fw_remove_parser.add_argument("port", type=str, help="Port to remove rule for (e.g., 8080, 53/udp)") + fw_remove_parser.add_argument("--instance", "-i", type=str, help="Instance name (default: from state)") + fw_remove_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + + # fw list + fw_list_parser = fw_subparsers.add_parser("list", help="List firewall rules for instance") + fw_list_parser.add_argument("--instance", "-i", type=str, help="Instance name (default: from state)") + fw_list_parser.add_argument("--project", "-p", type=str, help="GCP project ID") + args = parser.parse_args() if args.verbose: @@ -1892,6 +2180,34 @@ Examples: manager.remove(keep_images=args.keep_images) elif args.command == "list": manager.list_deployments(project=args.project) + elif args.command == "fw": + if args.fw_command == "allow": + manager.fw_allow( + port_spec=args.port, + source_ranges=args.source_ranges, + instance_name=args.instance, + project=args.project + ) + elif args.fw_command == "deny": + manager.fw_deny( + port_spec=args.port, + source_ranges=args.source_ranges, + instance_name=args.instance, + project=args.project + ) + elif args.fw_command == "remove": + manager.fw_remove( + port_spec=args.port, + instance_name=args.instance, + project=args.project + ) + elif args.fw_command == "list": + manager.fw_list( + instance_name=args.instance, + project=args.project + ) + else: + fw_parser.print_help() else: parser.print_help() except Exception as e: From 3dea1d50349b8d250512b33a56540a78a4db934b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 15 Jan 2026 12:37:15 +0000 Subject: [PATCH 039/119] dstack-cloud: Disable .env when kms is off --- scripts/bin/dstack-cloud | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 09e540f..025e83f 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -675,11 +675,12 @@ class CloudDeploymentManager: f.write("# Prelaunch script - runs before starting containers\n") os.chmod(prelaunch, 0o755) - # Create .env template at project root - env_file = self.work_dir / ".env" - if not env_file.exists() or force: - with open(env_file, 'w') as f: - f.write("# Environment variables\n") + # Create .env template at project root (only for KMS mode) + if app_template["key_provider"] == "kms": + env_file = self.work_dir / ".env" + if not env_file.exists() or force: + with open(env_file, 'w') as f: + f.write("# Environment variables\n") # Create user-config template at project root user_config = self.work_dir / ".user-config" @@ -699,7 +700,8 @@ class CloudDeploymentManager: logger.info(f" shared/ - System-generated files") logger.info(f" {docker_compose.name} - Docker compose file") logger.info(f" {prelaunch.name} - Prelaunch script") - logger.info(f" {env_file.name} - Environment variables") + if app_template["key_provider"] == "kms": + logger.info(f" .env - Environment variables") logger.info(f" .user-config - User configuration") logger.info("") logger.info("Edit the configuration files to customize your deployment.") From 8aa54095dfd24d04dd7ebfd8255bdc36d8498ef9 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 16 Jan 2026 02:39:09 +0000 Subject: [PATCH 040/119] dstack-cloud: Auto upload data-disk image --- scripts/bin/dstack-cloud | 81 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 025e83f..30fea2c 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -232,6 +232,7 @@ class DeploymentState: created_at: str = "" updated_at: str = "" boot_image: str = "" + data_image: str = "" shared_image: str = "" def to_dict(self) -> Dict[str, Any]: @@ -459,6 +460,80 @@ class CloudDeploymentManager: return result + def _ensure_data_disk_image(self, config: GcpConfig) -> str: + """Ensure the data disk image exists, creating it if necessary. + + Creates a minimal disk image with GPT partition table and a partition + labeled 'dstack-data' so the guest can discover it. + + Returns the image name to use. + """ + image_name = config.data_image + + # Check if image already exists + result = self._run_gcloud([ + "compute", "images", "describe", image_name, + f"--project={config.project}" + ], check=False) + + if result.returncode == 0: + logger.debug(f"Data disk image '{image_name}' already exists") + return image_name + + logger.info(f"Data disk image '{image_name}' not found, creating...") + + # Create a minimal raw disk image with GPT partition table + with tempfile.TemporaryDirectory() as tmpdir: + raw_file = os.path.join(tmpdir, "disk.raw") + + # Create a 10MB sparse file (enough for GPT) + disk_size_bytes = 10 * 1024 * 1024 + with open(raw_file, 'wb') as f: + f.truncate(disk_size_bytes) + + # Create GPT partition table with dstack-data partition using sgdisk + # -o: clear and create new GPT + # -n 1:0:0: create partition 1, start at first available, end at last available + # -c 1:dstack-data: set partition 1 name (PARTLABEL) to dstack-data + result = subprocess.run( + ["sgdisk", "-o", "-n", "1:0:0", "-c", "1:dstack-data", raw_file], + capture_output=True, text=True + ) + if result.returncode != 0: + raise RuntimeError(f"Failed to create GPT partition table: {result.stderr}") + + logger.debug("Created GPT partition table with dstack-data label") + + # Compress to tar.gz for upload + tar_file = os.path.join(tmpdir, "disk.tar.gz") + result = subprocess.run( + ["tar", "-czf", tar_file, "-C", tmpdir, "disk.raw"], + capture_output=True, text=True + ) + if result.returncode != 0: + raise RuntimeError(f"Failed to create tar.gz: {result.stderr}") + + # Upload to GCS + gcs_path = f"{config.bucket}/{image_name}.tar.gz" + logger.info(f"Uploading data disk image to {gcs_path}...") + self._run_gsutil(["cp", tar_file, gcs_path]) + + # Create GCP image from the uploaded file + logger.info(f"Creating GCP image '{image_name}'...") + self._run_gcloud([ + "compute", "images", "create", image_name, + f"--project={config.project}", + f"--source-uri={gcs_path}", + "--guest-os-features=GVNIC" + ]) + + # Clean up GCS file + self._run_gsutil(["rm", gcs_path], check=False) + + logger.info(f"Created data disk image '{image_name}'") + + return image_name + def new( self, name: str, @@ -1250,6 +1325,9 @@ class CloudDeploymentManager: # Create shared disk image shared_image = self._create_shared_disk_image(config, app) + # Ensure data disk image exists (with GPT partition labeled 'dstack-data') + data_image = self._ensure_data_disk_image(config) + # Create TDX instance logger.info("Creating TDX instance...") @@ -1261,7 +1339,7 @@ class CloudDeploymentManager: "--confidential-compute-type=TDX", f"--image={boot_image}", "--boot-disk-size=10GB", - f"--create-disk=name={config.instance_name}-data,size={config.data_size}GB,type=pd-balanced,image={config.data_image},auto-delete=yes", + f"--create-disk=name={config.instance_name}-data,size={config.data_size}GB,type=pd-balanced,image={data_image},auto-delete=yes", f"--create-disk=name={config.instance_name}-shared,size=1GB,type=pd-balanced,image={shared_image},auto-delete=yes", "--maintenance-policy=TERMINATE", ] @@ -1306,6 +1384,7 @@ class CloudDeploymentManager: status="RUNNING", created_at=datetime.now().isoformat(), boot_image=boot_image, + data_image=data_image, shared_image=shared_image, ) self.save_state(state) From 5858bc0725bed0371f85257360ff24c08f9fd36a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 16 Jan 2026 02:45:09 +0000 Subject: [PATCH 041/119] Update dstack submodule url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index fb2a5ce..114b2e7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,7 +23,7 @@ url = https://github.com/Dstack-TEE/meta-rust-bin [submodule "dstack"] path = dstack - url = git@github.com:Phala-Network/dstack-gcp.git + url = https://github.com/Phala-Network/dstack-gcp.git [submodule "meta-security"] path = meta-security url = https://github.com/Dstack-TEE/meta-security.git From 14b119f3ffa5e179987837115df257d54735e523 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 16 Jan 2026 02:48:58 +0000 Subject: [PATCH 042/119] Update dstack --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 9df8aa1..68558a9 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 9df8aa1fa8f807e0a74181831b210dca21b8b2d0 +Subproject commit 68558a9e378e25b8e3c8a2bd82649745971685a8 From 8980c0901df699cdbfa28f1f77401eb5d0a7ec3b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 01:47:57 +0000 Subject: [PATCH 043/119] Update submodules --- dstack | 2 +- meta-confidential-compute | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dstack b/dstack index 68558a9..1791fcf 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 68558a9e378e25b8e3c8a2bd82649745971685a8 +Subproject commit 1791fcf689875755d6024447a553b6ee7d949e91 diff --git a/meta-confidential-compute b/meta-confidential-compute index a9857da..33d19bc 160000 --- a/meta-confidential-compute +++ b/meta-confidential-compute @@ -1 +1 @@ -Subproject commit a9857da070b542dece7dd0630b3b89804234af7e +Subproject commit 33d19bc72b43876884ddb1626e8c0cdf41032038 From 4da51e905c1e7c69dd62017bbe3e6e42831cc3a3 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 01:48:48 +0000 Subject: [PATCH 044/119] Update LICENSE --- LICENSE | 109 +++++++++++++++++++++++++++++++++++++++++++----------- README.md | 2 +- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/LICENSE b/LICENSE index 7eb7810..fd94e8e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,88 @@ -MIT License - -Copyright (c) 2024 Phala Network - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Business Source License 1.1 + +Parameters + +Licensor: Phala Network +Licensed Work: dstack-cloud + The Licensed Work is (c) Phala Network +Additional Use Grant: None + +Change Date: Four years from the date a MINOR version (SemVer) is published. + +Change License: GNU Affero General Public License Version 3 (AGPL-3.0-only) + +Notice + +License text copyright (c) 2023 MariaDB plc, All Rights Reserved. +“Business Source License” is a trademark of MariaDB plc. + +----------------------------------------------------------------------------- + +Business Source License 1.1 + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative +works, redistribute, and make non-production use of the Licensed Work. The +Licensor may make an Additional Use Grant, above, permitting limited +production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly +available distribution of a specific version of the Licensed Work under this +License, whichever comes first, the Licensor hereby grants you rights under +the terms of the Change License, and the rights granted in the paragraph +above terminate. + +If your use of the Licensed Work does not comply with the requirements +currently in effect as described in this License, you must purchase a +commercial license from the Licensor, its affiliated entities, or authorized +resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works +of the Licensed Work, are subject to this License. This License applies +separately for each version of the Licensed Work and the Change Date may vary +for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy +of the Licensed Work. If you receive the Licensed Work in original or +modified form from a third party, the terms and conditions set forth in this +License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically +terminate your rights under this License for the current and all other +versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of +Licensor or its affiliates (provided that you may use a trademark or logo of +Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +TITLE. + +MariaDB hereby grants you permission to use this License’s text to license +your works, and to refer to it using the trademark “Business Source License”, +as long as you comply with the Covenants of Licensor below. + +Covenants of Licensor + +In consideration of the right to use this License’s text and the “Business +Source License” name and trademark, Licensor covenants to MariaDB, and to all +other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, + or a license that is compatible with GPL Version 2.0 or a later version, + where “compatible” means that software provided under the Change License can + be included in a program with software provided under GPL Version 2.0 or a + later version. Licensor may specify additional Change Licenses without + limitation. + +2. To either: (a) specify an additional grant of rights to use that does not + impose any additional restriction on the right granted in this License, as + the Additional Use Grant; or (b) insert the text “None”. + +3. To specify a Change Date. + +4. Not to modify this License in any other way. \ No newline at end of file diff --git a/README.md b/README.md index 74c6b7c..f41d95a 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,4 @@ cd meta-dstack/repro-build/ ## License -This project is licensed under the MIT License. See the LICENSE file for more details. +See the LICENSE file for more details. From 4f72c0ca734b36d6e2d91b94db8ed206f70f2ab8 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 01:49:39 +0000 Subject: [PATCH 045/119] Update submodule URL --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 114b2e7..850b166 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,7 +23,7 @@ url = https://github.com/Dstack-TEE/meta-rust-bin [submodule "dstack"] path = dstack - url = https://github.com/Phala-Network/dstack-gcp.git + url = https://github.com/Phala-Network/dstack-cloud.git [submodule "meta-security"] path = meta-security url = https://github.com/Dstack-TEE/meta-security.git From d90c9fa06df443f3e84289a592d317d366178b15 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 01:52:12 +0000 Subject: [PATCH 046/119] Update URL in README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f41d95a..616469d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This project implements Yocto layer and the overall build scripts for dstack Bas ## Build -See https://github.com/Dstack-TEE/dstack for more details. +See https://github.com/Phala-Network/dstack-cloud for more details. ## Reproducible Build The Guest Image @@ -15,7 +15,7 @@ See https://github.com/Dstack-TEE/dstack for more details. ### Build commands ```bash -git clone https://github.com/Dstack-TEE/meta-dstack.git +git clone https://github.com/Phala-Network/meta-dstack-cloud.git cd meta-dstack/repro-build/ ./repro-build.sh ``` From 9a88cf4d7b334ad4198dade18d216b755b0f0f8f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 03:08:58 +0000 Subject: [PATCH 047/119] Update dstack/ --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 1791fcf..4854ccc 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 1791fcf689875755d6024447a553b6ee7d949e91 +Subproject commit 4854ccc2f8fa33838d3029c60803bda2bd6d2d08 From 78082be39a470980856eb89bb44ebcd3de755b06 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 12:08:15 +0000 Subject: [PATCH 048/119] Fix random fakeroot bb build error --- .../libnvidia-container/libnvidia-container_1.00.bb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb index b533f73..147a6dc 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb @@ -12,6 +12,8 @@ fakeroot do_unpack_modprobe() { addtask unpack_modprobe after do_unpack before do_patch do_unpack_modprobe[dirs] = "${S}" do_unpack_modprobe[vardeps] += "NVIDIA_MODPROBE_VERSION" +# Ensure pseudo (fakeroot worker) is staged before this fakeroot task runs. +do_unpack_modprobe[depends] += "pseudo-native:do_populate_sysroot" PACKAGECONFIG ??= "seccomp" PACKAGECONFIG[seccomp] = "WITH_SECCOMP=yes,WITH_SECCOMP=no,libseccomp" From 04288d031dd3bf633685c7896dbb48a2332da113 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 19 Jan 2026 12:53:41 +0000 Subject: [PATCH 049/119] bb: Rename image from dstack to dstack-cloud --- Makefile | 2 +- .../{dstack-nvidia-rootfs.bb => dstack-cloud-nvidia-rootfs.bb} | 0 .../images/{dstack-rootfs.bb => dstack-cloud-rootfs.bb} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename meta-dstack/recipes-core/images/{dstack-nvidia-rootfs.bb => dstack-cloud-nvidia-rootfs.bb} (100%) rename meta-dstack/recipes-core/images/{dstack-rootfs.bb => dstack-cloud-rootfs.bb} (100%) diff --git a/Makefile b/Makefile index 700cdb1..05de009 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ DIST_DIR ?= ${BB_BUILD_DIR}/dist export BB_BUILD_DIR export DIST_DIR -DIST_NAMES ?= dstack dstack-dev dstack-nvidia dstack-nvidia-dev +DIST_NAMES ?= dstack-cloud dstack-cloud-nvidia ROOTFS_IMAGE_NAMES = $(addsuffix -rootfs,${DIST_NAMES}) all: dist diff --git a/meta-dstack/recipes-core/images/dstack-nvidia-rootfs.bb b/meta-dstack/recipes-core/images/dstack-cloud-nvidia-rootfs.bb similarity index 100% rename from meta-dstack/recipes-core/images/dstack-nvidia-rootfs.bb rename to meta-dstack/recipes-core/images/dstack-cloud-nvidia-rootfs.bb diff --git a/meta-dstack/recipes-core/images/dstack-rootfs.bb b/meta-dstack/recipes-core/images/dstack-cloud-rootfs.bb similarity index 100% rename from meta-dstack/recipes-core/images/dstack-rootfs.bb rename to meta-dstack/recipes-core/images/dstack-cloud-rootfs.bb From 7cc276ff0ef82650c65b86ba000cfa35a604818a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 05:09:12 +0000 Subject: [PATCH 050/119] bb: Refactor image recipes to use multiconfig - Consolidate four separate image recipes (dstack-cloud-rootfs, dstack-dev-rootfs, dstack-cloud-nvidia-rootfs, dstack-nvidia-dev-rootfs) into a single dstack-rootfs.bb with conditional includes - Add multiconfig support with separate TMPDIR per flavor to avoid build conflicts - Build flavors serially in Makefile to avoid BitBake runqueue deadlock - Update mkimage.sh to support --flavor parameter for multiconfig builds - Copy multiconfig to new build directories in dev-setup --- .gitignore | 1 + Makefile | 29 +++++++++---- bb-build/conf/local.conf | 3 +- bb-build/conf/multiconfig/dev.conf | 7 ++++ bb-build/conf/multiconfig/nvidia-dev.conf | 7 ++++ bb-build/conf/multiconfig/nvidia.conf | 7 ++++ bb-build/conf/multiconfig/prod.conf | 7 ++++ dev-setup | 3 ++ .../recipes-core/dstack-guest/dstack-guest.bb | 4 +- .../dstack-ovmf/dstack-ovmf_git.bb | 6 +-- .../images/dstack-cloud-nvidia-rootfs.bb | 3 -- .../images/dstack-cloud-rootfs.bb | 1 - .../recipes-core/images/dstack-dev-rootfs.bb | 1 - .../images/dstack-nvidia-dev-rootfs.bb | 2 - .../recipes-core/images/dstack-rootfs-dev.inc | 2 - .../images/dstack-rootfs-prod.inc | 1 - .../recipes-core/images/dstack-rootfs.bb | 17 ++++++++ meta-dstack/recipes-core/images/dstack-uki.bb | 15 ++++--- .../ldconfig-compatibility-symlink_1.0.0.bb | 2 +- .../libnvidia-container.inc | 2 +- mkimage.sh | 42 ++++++++++++++----- 21 files changed, 118 insertions(+), 44 deletions(-) create mode 100644 bb-build/conf/multiconfig/dev.conf create mode 100644 bb-build/conf/multiconfig/nvidia-dev.conf create mode 100644 bb-build/conf/multiconfig/nvidia.conf create mode 100644 bb-build/conf/multiconfig/prod.conf delete mode 100644 meta-dstack/recipes-core/images/dstack-cloud-nvidia-rootfs.bb delete mode 100644 meta-dstack/recipes-core/images/dstack-cloud-rootfs.bb delete mode 100644 meta-dstack/recipes-core/images/dstack-dev-rootfs.bb delete mode 100644 meta-dstack/recipes-core/images/dstack-nvidia-dev-rootfs.bb create mode 100644 meta-dstack/recipes-core/images/dstack-rootfs.bb diff --git a/.gitignore b/.gitignore index c6460dc..8e7fb51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /build /bb-build +!/bb-build/conf/multiconfig/ *.qcow2 __pycache__/ /.target diff --git a/Makefile b/Makefile index 05de009..65e8686 100644 --- a/Makefile +++ b/Makefile @@ -2,31 +2,44 @@ ifeq ($(BBPATH),) $(error BBPATH is not set. Run `source dev-setup` first) endif -.PHONY: all dist clean-dstack clean-initrd images +.PHONY: all dist clean-dstack clean-initrd images images-common images-flavors BB_BUILD_DIR ?= bb-build DIST_DIR ?= ${BB_BUILD_DIR}/dist export BB_BUILD_DIR export DIST_DIR -DIST_NAMES ?= dstack-cloud dstack-cloud-nvidia -ROOTFS_IMAGE_NAMES = $(addsuffix -rootfs,${DIST_NAMES}) +# Flavor names map to multiconfig names: prod, dev, nvidia, nvidia-dev +FLAVORS ?= prod dev nvidia nvidia-dev + +# Map flavor to dist name for mkimage.sh +flavor_to_dist = $(if $(filter prod,$1),dstack,$(if $(filter dev,$1),dstack-dev,$(if $(filter nvidia,$1),dstack-nvidia,$(if $(filter nvidia-dev,$1),dstack-nvidia-dev,$1)))) all: dist -include $(wildcard mk.d/*.mk) dist: images - $(foreach dist_name,${DIST_NAMES},./mkimage.sh --dist-name $(dist_name);) + $(foreach flavor,$(FLAVORS),./mkimage.sh --dist-name $(call flavor_to_dist,$(flavor)) --flavor $(flavor);) + +# Build common artifacts (shared across all flavors) +# dstack-guest is built here to avoid concurrent build conflicts in multiconfig +images-common: + bitbake virtual/kernel dstack-initramfs dstack-ovmf dstack-guest + +# Build flavor-specific artifacts using multiconfig (serial to avoid deadlock warnings) +images-flavors: + $(foreach flavor,$(FLAVORS),bitbake mc:$(flavor):dstack-rootfs mc:$(flavor):dstack-uki;) -images: - bitbake virtual/kernel dstack-initramfs dstack-ovmf dstack-uki $(ROOTFS_IMAGE_NAMES) +images: images-common images-flavors clean: - bitbake -c cleansstate virtual/kernel dstack-initramfs dstack-ovmf $(ROOTFS_IMAGE_NAMES) + bitbake -c cleansstate virtual/kernel dstack-initramfs dstack-ovmf + $(foreach flavor,$(FLAVORS),bitbake -c cleansstate mc:$(flavor):dstack-rootfs mc:$(flavor):dstack-uki;) clean-dstack: - bitbake -c cleansstate dstack-guest $(ROOTFS_IMAGE_NAMES) + bitbake -c cleansstate dstack-guest + $(foreach flavor,$(FLAVORS),bitbake -c cleansstate mc:$(flavor):dstack-rootfs;) clean-initrd: bitbake -c cleansstate dstack-initramfs diff --git a/bb-build/conf/local.conf b/bb-build/conf/local.conf index a51d8c2..0e3e9b0 100644 --- a/bb-build/conf/local.conf +++ b/bb-build/conf/local.conf @@ -290,4 +290,5 @@ BB_DISKMON_DIRS ??= "\ # this doesn't mean anything to you. CONF_VERSION = "2" -FETCHCMD_wget = "wget --progress=dot --inet4-only -c" \ No newline at end of file +FETCHCMD_wget = "wget --progress=dot --inet4-only -c" +BBMULTICONFIG = "prod dev nvidia nvidia-dev" \ No newline at end of file diff --git a/bb-build/conf/multiconfig/dev.conf b/bb-build/conf/multiconfig/dev.conf new file mode 100644 index 0000000..fb9dff4 --- /dev/null +++ b/bb-build/conf/multiconfig/dev.conf @@ -0,0 +1,7 @@ +# Development flavor configuration +DSTACK_FLAVOR = "dev" +DSTACK_NVIDIA = "0" +DSTACK_DEV = "1" + +# Use separate TMPDIR to avoid conflicts between multiconfigs +TMPDIR = "${TOPDIR}/tmp-mc-dev" diff --git a/bb-build/conf/multiconfig/nvidia-dev.conf b/bb-build/conf/multiconfig/nvidia-dev.conf new file mode 100644 index 0000000..65c6cce --- /dev/null +++ b/bb-build/conf/multiconfig/nvidia-dev.conf @@ -0,0 +1,7 @@ +# NVIDIA development flavor configuration +DSTACK_FLAVOR = "nvidia-dev" +DSTACK_NVIDIA = "1" +DSTACK_DEV = "1" + +# Use separate TMPDIR to avoid conflicts between multiconfigs +TMPDIR = "${TOPDIR}/tmp-mc-nvidia-dev" diff --git a/bb-build/conf/multiconfig/nvidia.conf b/bb-build/conf/multiconfig/nvidia.conf new file mode 100644 index 0000000..4f3f0e6 --- /dev/null +++ b/bb-build/conf/multiconfig/nvidia.conf @@ -0,0 +1,7 @@ +# NVIDIA production flavor configuration +DSTACK_FLAVOR = "nvidia" +DSTACK_NVIDIA = "1" +DSTACK_DEV = "0" + +# Use separate TMPDIR to avoid conflicts between multiconfigs +TMPDIR = "${TOPDIR}/tmp-mc-nvidia" diff --git a/bb-build/conf/multiconfig/prod.conf b/bb-build/conf/multiconfig/prod.conf new file mode 100644 index 0000000..f39fe60 --- /dev/null +++ b/bb-build/conf/multiconfig/prod.conf @@ -0,0 +1,7 @@ +# Production flavor configuration +DSTACK_FLAVOR = "prod" +DSTACK_NVIDIA = "0" +DSTACK_DEV = "0" + +# Use separate TMPDIR to avoid conflicts between multiconfigs +TMPDIR = "${TOPDIR}/tmp-mc-prod" diff --git a/dev-setup b/dev-setup index 976e79b..1c6fa20 100755 --- a/dev-setup +++ b/dev-setup @@ -36,6 +36,9 @@ if [ ! -f "$BUILD_DIR/conf/local.conf" ]; then mkdir -p "$BUILD_DIR/conf" cp -f "$THIS_DIR/bb-build/conf/local.conf" "$BUILD_DIR/conf/local.conf" fi +if [ ! -d "$BUILD_DIR/conf/multiconfig" ] && [ -d "$THIS_DIR/bb-build/conf/multiconfig" ]; then + cp -rf "$THIS_DIR/bb-build/conf/multiconfig" "$BUILD_DIR/conf/" +fi OE_INIT=$THIS_DIR/openembedded-core/oe-init-build-env diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 2f7e0fb..0e6daca 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -37,10 +37,8 @@ do_unpack() { fi } -# Force the configure task to run every time to detect source changes -do_unpack[nostamp] = "1" - # Add source directory to configure task dependencies +# Note: removed nostamp to avoid concurrent build conflicts in multiconfig do_unpack[vardeps] += "SRC_DIR" do_configure() { diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb index 0cf1e10..dcdf160 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb @@ -51,13 +51,13 @@ PARALLEL_MAKE = "" DEPENDS = "nasm-native acpica-native ovmf-native util-linux-native" -EDK_TOOLS_DIR="edk2_basetools" +EDK_TOOLS_DIR = "edk2_basetools" # OVMF has trouble building with the default optimization of -O2. BUILD_OPTIMIZATION = "" # OVMF supports IA only, although it could conceivably support ARM someday. -COMPATIBLE_HOST:class-target='(i.86|x86_64).*' +COMPATIBLE_HOST:class-target = '(i.86|x86_64).*' # Additional build flags for OVMF with Secure Boot. # Fedora also uses "-D SMM_REQUIRE -D EXCLUDE_SHELL_FROM_FD". @@ -138,7 +138,7 @@ fix_toolchain:append:class-native() { export NASM_PREFIX_MAP = "--debug-prefix-map=${WORKDIR}=${TARGET_DBGSRC_DIR}" export GCC_PREFIX_MAP = "${DEBUG_PREFIX_MAP} -Wno-stringop-overflow -Wno-maybe-uninitialized" -GCC_VER="$(${CC} -v 2>&1 | tail -n1 | awk '{print $3}')" +GCC_VER = "$(${CC} -v 2>&1 | tail -n1 | awk '{print $3}')" fixup_target_tools() { case ${1} in diff --git a/meta-dstack/recipes-core/images/dstack-cloud-nvidia-rootfs.bb b/meta-dstack/recipes-core/images/dstack-cloud-nvidia-rootfs.bb deleted file mode 100644 index a351ef9..0000000 --- a/meta-dstack/recipes-core/images/dstack-cloud-nvidia-rootfs.bb +++ /dev/null @@ -1,3 +0,0 @@ -include dstack-rootfs-prod.inc -include dstack-rootfs-nvidia.inc - diff --git a/meta-dstack/recipes-core/images/dstack-cloud-rootfs.bb b/meta-dstack/recipes-core/images/dstack-cloud-rootfs.bb deleted file mode 100644 index 7dc317d..0000000 --- a/meta-dstack/recipes-core/images/dstack-cloud-rootfs.bb +++ /dev/null @@ -1 +0,0 @@ -include dstack-rootfs-prod.inc diff --git a/meta-dstack/recipes-core/images/dstack-dev-rootfs.bb b/meta-dstack/recipes-core/images/dstack-dev-rootfs.bb deleted file mode 100644 index 59662e6..0000000 --- a/meta-dstack/recipes-core/images/dstack-dev-rootfs.bb +++ /dev/null @@ -1 +0,0 @@ -include dstack-rootfs-dev.inc diff --git a/meta-dstack/recipes-core/images/dstack-nvidia-dev-rootfs.bb b/meta-dstack/recipes-core/images/dstack-nvidia-dev-rootfs.bb deleted file mode 100644 index 01afbf2..0000000 --- a/meta-dstack/recipes-core/images/dstack-nvidia-dev-rootfs.bb +++ /dev/null @@ -1,2 +0,0 @@ -include dstack-rootfs-dev.inc -include dstack-rootfs-nvidia.inc diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc b/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc index eacc68b..1481a98 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-dev.inc @@ -1,4 +1,2 @@ -include dstack-rootfs-base.inc - IMAGE_INSTALL += "packagegroup-core-ssh-openssh strace tcpdump gdb gdbserver vim" EXTRA_IMAGE_FEATURES += "allow-root-login post-install-logging" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-prod.inc b/meta-dstack/recipes-core/images/dstack-rootfs-prod.inc index e3f805d..a446e03 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-prod.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-prod.inc @@ -1,2 +1 @@ -include dstack-rootfs-base.inc IMAGE_FEATURES += "nologin" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs.bb b/meta-dstack/recipes-core/images/dstack-rootfs.bb new file mode 100644 index 0000000..930df27 --- /dev/null +++ b/meta-dstack/recipes-core/images/dstack-rootfs.bb @@ -0,0 +1,17 @@ +# Unified dstack rootfs image +# Use DSTACK_FLAVOR (via multiconfig) to select variant: +# prod, dev, nvidia, nvidia-dev + +# Default flavor settings (can be overridden by multiconfig) +DSTACK_FLAVOR ?= "prod" +DSTACK_NVIDIA ?= "0" +DSTACK_DEV ?= "0" + +# Base configuration +include dstack-rootfs-base.inc + +# Production or development mode +include ${@'dstack-rootfs-dev.inc' if d.getVar('DSTACK_DEV') == '1' else 'dstack-rootfs-prod.inc'} + +# NVIDIA support (optional) +include ${@'dstack-rootfs-nvidia.inc' if d.getVar('DSTACK_NVIDIA') == '1' else ''} diff --git a/meta-dstack/recipes-core/images/dstack-uki.bb b/meta-dstack/recipes-core/images/dstack-uki.bb index c9883ba..47d392f 100644 --- a/meta-dstack/recipes-core/images/dstack-uki.bb +++ b/meta-dstack/recipes-core/images/dstack-uki.bb @@ -18,19 +18,21 @@ INITRAMFS_FSTYPES = "cpio.gz" # Kernel settings KERNEL_IMAGETYPE = "bzImage" -# Output filename -UKI_FILENAME = "dstack-uki.efi" - # Base kernel cmdline (verity hash added dynamically) UKI_CMDLINE_BASE = "console=ttyS0 init=/init panic=1 net.ifnames=0 biosdevname=0 \ mce=off oops=panic pci=noearly pci=nommconf random.trust_cpu=y random.trust_bootloader=n \ tsc=reliable no-kvmclock" -# Verity image to get hash from -# Override with VERITY_IMAGE = "dstack-dev-rootfs" for dev builds -VERITY_IMAGE ?= "dstack-rootfs" +# Flavor settings (should match dstack-rootfs.bb, set via multiconfig) +DSTACK_FLAVOR ?= "prod" + +# Verity image to get hash from - always use dstack-rootfs (same PN, different multiconfig) +VERITY_IMAGE = "dstack-rootfs" VERITY_TYPE = "squashfs" +# Output filename includes flavor to avoid conflicts between multiconfigs +UKI_FILENAME = "${@'dstack-uki.efi' if d.getVar('DSTACK_FLAVOR') == 'prod' else 'dstack-uki-' + d.getVar('DSTACK_FLAVOR') + '.efi'}" + do_configure[noexec] = "1" do_compile[noexec] = "1" do_install[noexec] = "1" @@ -39,6 +41,7 @@ do_install[noexec] = "1" do_uki[depends] += "systemd-boot:do_deploy virtual/kernel:do_deploy" do_uki[depends] += "${INITRAMFS_IMAGE}:do_image_complete" do_uki[depends] += "${VERITY_IMAGE}:do_image_complete" +do_uki[depends] += "systemd-boot-native:do_populate_sysroot python3-pefile-native:do_populate_sysroot" python do_uki() { import os diff --git a/meta-nvidia/recipes-graphics/ldconfig-compatibility-symlink/ldconfig-compatibility-symlink_1.0.0.bb b/meta-nvidia/recipes-graphics/ldconfig-compatibility-symlink/ldconfig-compatibility-symlink_1.0.0.bb index e5aff79..4071fbd 100644 --- a/meta-nvidia/recipes-graphics/ldconfig-compatibility-symlink/ldconfig-compatibility-symlink_1.0.0.bb +++ b/meta-nvidia/recipes-graphics/ldconfig-compatibility-symlink/ldconfig-compatibility-symlink_1.0.0.bb @@ -19,4 +19,4 @@ do_install() { # Ensure that the package is always installed PACKAGES = "${PN}" -FILES:${PN}:append= "${base_sbindir}/ldconfig.real" +FILES:${PN}:append = "${base_sbindir}/ldconfig.real" diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc index 4655095..ca7fb4e 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container.inc @@ -37,4 +37,4 @@ DEPENDS = " \ libtirpc134 \ ldconfig-native \ " -RDEPENDS:${PN}:append= " ldconfig-compatibility-symlink containerd-config" \ No newline at end of file +RDEPENDS:${PN}:append = " ldconfig-compatibility-symlink containerd-config" \ No newline at end of file diff --git a/mkimage.sh b/mkimage.sh index 0bf58a6..5a32690 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -11,9 +11,13 @@ while [ $# -gt 0 ]; do DIST_NAME="$2" shift 2 ;; + --flavor) + FLAVOR="$2" + shift 2 + ;; *) echo "Unknown option: $1" - echo "Usage: $0 --dist-name NAME" + echo "Usage: $0 --dist-name NAME --flavor FLAVOR" exit 1 ;; esac @@ -25,6 +29,11 @@ if [ -z "$DIST_NAME" ]; then exit 1 fi +if [ -z "$FLAVOR" ]; then + echo "Error: --flavor is required (prod, dev, nvidia, nvidia-dev)" + exit 1 +fi + if [[ "$DIST_NAME" == *-dev ]]; then IS_DEV=true @@ -35,16 +44,27 @@ fi BB_BUILD_DIR=$(realpath ${BB_BUILD_DIR:-build}) DIST_DIR=$(realpath ${DIST_DIR:-${BB_BUILD_DIR}/dist}) -IMG_DIR=${BB_BUILD_DIR}/tmp/deploy/images/tdx -ROOTFS_IMAGE_NAME=${DIST_NAME}-rootfs +# Common artifacts are in tmp/, flavor-specific artifacts are in tmp-mc-/ +COMMON_IMG_DIR=${BB_BUILD_DIR}/tmp/deploy/images/tdx +FLAVOR_IMG_DIR=${BB_BUILD_DIR}/tmp-mc-${FLAVOR}/deploy/images/tdx + +# Common artifacts (shared across all flavors) +INITRAMFS_IMAGE=${COMMON_IMG_DIR}/dstack-initramfs.cpio.gz +KERNEL_IMAGE=${COMMON_IMG_DIR}/bzImage +OVMF_FIRMWARE=${COMMON_IMG_DIR}/ovmf.fd + +# Flavor-specific artifacts (from multiconfig build) +ROOTFS_IMAGE=${FLAVOR_IMG_DIR}/dstack-rootfs-tdx.squashfs.verity + +# UKI filename depends on flavor +if [[ "$FLAVOR" == "prod" ]]; then + UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki.efi +else + UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki-${FLAVOR}.efi +fi -INITRAMFS_IMAGE=${IMG_DIR}/dstack-initramfs.cpio.gz -ROOTFS_IMAGE=${IMG_DIR}/${ROOTFS_IMAGE_NAME}-tdx.squashfs.verity -KERNEL_IMAGE=${IMG_DIR}/bzImage -OVMF_FIRMWARE=${IMG_DIR}/ovmf.fd -UKI_IMAGE=${IMG_DIR}/dstack-uki.efi -# Always use the work-shared directory which has the correct verity env -VERITY_ENV_FILE=${BB_BUILD_DIR}/tmp/work-shared/tdx/dm-verity/${ROOTFS_IMAGE_NAME}.squashfs.verity.env +# Verity env is in the flavor-specific work-shared directory +VERITY_ENV_FILE=${BB_BUILD_DIR}/tmp-mc-${FLAVOR}/work-shared/tdx/dm-verity/dstack-rootfs.squashfs.verity.env echo "Loading verity env from ${VERITY_ENV_FILE}" source ${VERITY_ENV_FILE} @@ -246,7 +266,7 @@ popd if [ "$ENABLE_GCP_IMAGE" = "1" ]; then if [[ ! -f "$UKI_IMAGE" ]]; then echo "Skipping GCP disk image creation because UKI image not found: $UKI_IMAGE" >&2 - echo "Run 'bitbake dstack-uki' to build the UKI first" >&2 + echo "Run 'bitbake mc:${FLAVOR}:dstack-uki' to build the UKI first" >&2 elif command -v sgdisk >/dev/null && \ command -v mkfs.vfat >/dev/null && \ command -v mcopy >/dev/null; then From 37531fe3e6bb8d2977927c05862c7a03bb5943c3 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 05:26:08 +0000 Subject: [PATCH 051/119] bb: Move build config from bb-build to meta-dstack/conf - Move local.conf and multiconfig/ to meta-dstack/conf/ - Update dev-setup to always sync config to build directory - bb-build is now fully excluded from git (build artifact only) --- .gitignore | 1 - dev-setup | 13 ++++++------- {bb-build => meta-dstack}/conf/local.conf | 0 {bb-build => meta-dstack}/conf/multiconfig/dev.conf | 0 .../conf/multiconfig/nvidia-dev.conf | 0 .../conf/multiconfig/nvidia.conf | 0 .../conf/multiconfig/prod.conf | 0 7 files changed, 6 insertions(+), 8 deletions(-) rename {bb-build => meta-dstack}/conf/local.conf (100%) rename {bb-build => meta-dstack}/conf/multiconfig/dev.conf (100%) rename {bb-build => meta-dstack}/conf/multiconfig/nvidia-dev.conf (100%) rename {bb-build => meta-dstack}/conf/multiconfig/nvidia.conf (100%) rename {bb-build => meta-dstack}/conf/multiconfig/prod.conf (100%) diff --git a/.gitignore b/.gitignore index 8e7fb51..c6460dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ /build /bb-build -!/bb-build/conf/multiconfig/ *.qcow2 __pycache__/ /.target diff --git a/dev-setup b/dev-setup index 1c6fa20..4be8074 100755 --- a/dev-setup +++ b/dev-setup @@ -32,13 +32,12 @@ if [ -z "$1" ]; then else BUILD_DIR=$(realpath "$1") fi -if [ ! -f "$BUILD_DIR/conf/local.conf" ]; then - mkdir -p "$BUILD_DIR/conf" - cp -f "$THIS_DIR/bb-build/conf/local.conf" "$BUILD_DIR/conf/local.conf" -fi -if [ ! -d "$BUILD_DIR/conf/multiconfig" ] && [ -d "$THIS_DIR/bb-build/conf/multiconfig" ]; then - cp -rf "$THIS_DIR/bb-build/conf/multiconfig" "$BUILD_DIR/conf/" -fi + +# Sync build config from meta-dstack/conf (always overwrite) +CONF_SRC=$THIS_DIR/meta-dstack/conf +mkdir -p "$BUILD_DIR/conf" +cp -f "$CONF_SRC/local.conf" "$BUILD_DIR/conf/local.conf" +cp -rf "$CONF_SRC/multiconfig" "$BUILD_DIR/conf/" OE_INIT=$THIS_DIR/openembedded-core/oe-init-build-env diff --git a/bb-build/conf/local.conf b/meta-dstack/conf/local.conf similarity index 100% rename from bb-build/conf/local.conf rename to meta-dstack/conf/local.conf diff --git a/bb-build/conf/multiconfig/dev.conf b/meta-dstack/conf/multiconfig/dev.conf similarity index 100% rename from bb-build/conf/multiconfig/dev.conf rename to meta-dstack/conf/multiconfig/dev.conf diff --git a/bb-build/conf/multiconfig/nvidia-dev.conf b/meta-dstack/conf/multiconfig/nvidia-dev.conf similarity index 100% rename from bb-build/conf/multiconfig/nvidia-dev.conf rename to meta-dstack/conf/multiconfig/nvidia-dev.conf diff --git a/bb-build/conf/multiconfig/nvidia.conf b/meta-dstack/conf/multiconfig/nvidia.conf similarity index 100% rename from bb-build/conf/multiconfig/nvidia.conf rename to meta-dstack/conf/multiconfig/nvidia.conf diff --git a/bb-build/conf/multiconfig/prod.conf b/meta-dstack/conf/multiconfig/prod.conf similarity index 100% rename from bb-build/conf/multiconfig/prod.conf rename to meta-dstack/conf/multiconfig/prod.conf From 6a0ae2a7eaff5f7d0fa7c8ea206898ee66f2e37f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 05:49:42 +0000 Subject: [PATCH 052/119] Rename dist image prefix from dstack to dstack-cloud - dstack-0.6.0/ -> dstack-cloud-0.6.0/ - dstack-nvidia-0.6.0.tar.gz -> dstack-cloud-nvidia-0.6.0.tar.gz - Update download URL to meta-dstack-cloud repo --- Makefile | 2 +- build.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 65e8686..5c45474 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ export DIST_DIR FLAVORS ?= prod dev nvidia nvidia-dev # Map flavor to dist name for mkimage.sh -flavor_to_dist = $(if $(filter prod,$1),dstack,$(if $(filter dev,$1),dstack-dev,$(if $(filter nvidia,$1),dstack-nvidia,$(if $(filter nvidia-dev,$1),dstack-nvidia-dev,$1)))) +flavor_to_dist = $(if $(filter prod,$1),dstack-cloud,$(if $(filter dev,$1),dstack-cloud-dev,$(if $(filter nvidia,$1),dstack-cloud-nvidia,$(if $(filter nvidia-dev,$1),dstack-cloud-nvidia-dev,$1)))) all: dist diff --git a/build.sh b/build.sh index a70ce85..4481aef 100755 --- a/build.sh +++ b/build.sh @@ -306,11 +306,11 @@ download_image() { TAG=v$VERSION if [ x"$IS_DEV" = x"1" ]; then - BASENAME=dstack-dev-$VERSION + BASENAME=dstack-cloud-dev-$VERSION else - BASENAME=dstack-$VERSION + BASENAME=dstack-cloud-$VERSION fi - URL=https://github.com/Dstack-TEE/meta-dstack/releases/download/$TAG/$BASENAME.tar.gz + URL=https://github.com/Dstack-TEE/meta-dstack-cloud/releases/download/$TAG/$BASENAME.tar.gz if [ -d $IMAGES_DIR/$BASENAME ]; then echo "Image already exists" else From 04100cda5225411a2471ce87183fdaddb8791c38 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 06:11:25 +0000 Subject: [PATCH 053/119] mkimage: Fix UKI auth_hash not being written to output Move write_authenticode_hash_if_missing call to main flow instead of only in create_gcp_artifacts. This ensures the hash file is always generated when UKI exists, regardless of GCP image creation. --- mkimage.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mkimage.sh b/mkimage.sh index 5a32690..74824c3 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -57,11 +57,7 @@ OVMF_FIRMWARE=${COMMON_IMG_DIR}/ovmf.fd ROOTFS_IMAGE=${FLAVOR_IMG_DIR}/dstack-rootfs-tdx.squashfs.verity # UKI filename depends on flavor -if [[ "$FLAVOR" == "prod" ]]; then - UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki.efi -else - UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki-${FLAVOR}.efi -fi +UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki.efi # Verity env is in the flavor-specific work-shared directory VERITY_ENV_FILE=${BB_BUILD_DIR}/tmp-mc-${FLAVOR}/work-shared/tdx/dm-verity/dstack-rootfs.squashfs.verity.env @@ -228,9 +224,12 @@ $Q cp $KERNEL_IMAGE ${OUTPUT_DIR}/ $Q cp $OVMF_FIRMWARE ${OUTPUT_DIR}/ $Q cp $ROOTFS_IMAGE ${OUTPUT_DIR}/rootfs.img.verity -# Copy UKI Authenticode hash if available -if [[ -f "${UKI_IMAGE}.auth_hash.txt" ]]; then - $Q cp "${UKI_IMAGE}.auth_hash.txt" "${OUTPUT_DIR}/dstack-uki.efi.auth_hash.txt" +# Calculate and copy UKI Authenticode hash +if [[ -f "$UKI_IMAGE" ]]; then + write_authenticode_hash_if_missing "$UKI_IMAGE" + if [[ -f "${UKI_IMAGE}.auth_hash.txt" ]]; then + $Q cp "${UKI_IMAGE}.auth_hash.txt" "${OUTPUT_DIR}/dstack-uki.efi.auth_hash.txt" + fi fi echo "Creating partitioned rootfs image at ${OUTPUT_DIR}/rootfs.img.parted.verity" From 0ff95e23881f5d13c1fb732a9b2e8cdeb0de5c07 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 06:21:51 +0000 Subject: [PATCH 054/119] Update LICENSE --- LICENSE | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index fd94e8e..4a58670 100644 --- a/LICENSE +++ b/LICENSE @@ -2,14 +2,20 @@ Business Source License 1.1 Parameters -Licensor: Phala Network -Licensed Work: dstack-cloud - The Licensed Work is (c) Phala Network -Additional Use Grant: None +Licensor: Hashforest Technology LLC -Change Date: Four years from the date a MINOR version (SemVer) is published. +Licensed Work: dstack-cloud + The Licensed Work is (c) Hashforest Technology LLC -Change License: GNU Affero General Public License Version 3 (AGPL-3.0-only) +Additional Use Grant: Notwithstanding the foregoing, the Licensor grants + to certain commercial partners a license to use the + Licensed Work for production and commercial purposes + pursuant to separate agreements. + +Change Date: Two years from the date a MINOR version (SemVer) is + published. + +Change License: GNU Affero General Public License Version 3 (AGPL-3.0) Notice From 8e59b37e448e410f81104bd87bfcdbadfbb9ade6 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 06:22:21 +0000 Subject: [PATCH 055/119] Fix uki filename in bb files --- Makefile | 2 +- meta-dstack/recipes-core/images/dstack-uki.bb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5c45474..da4ba8e 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ dist: images # Build common artifacts (shared across all flavors) # dstack-guest is built here to avoid concurrent build conflicts in multiconfig images-common: - bitbake virtual/kernel dstack-initramfs dstack-ovmf dstack-guest + bitbake virtual/kernel dstack-initramfs dstack-ovmf # Build flavor-specific artifacts using multiconfig (serial to avoid deadlock warnings) images-flavors: diff --git a/meta-dstack/recipes-core/images/dstack-uki.bb b/meta-dstack/recipes-core/images/dstack-uki.bb index 47d392f..4a2254b 100644 --- a/meta-dstack/recipes-core/images/dstack-uki.bb +++ b/meta-dstack/recipes-core/images/dstack-uki.bb @@ -30,8 +30,7 @@ DSTACK_FLAVOR ?= "prod" VERITY_IMAGE = "dstack-rootfs" VERITY_TYPE = "squashfs" -# Output filename includes flavor to avoid conflicts between multiconfigs -UKI_FILENAME = "${@'dstack-uki.efi' if d.getVar('DSTACK_FLAVOR') == 'prod' else 'dstack-uki-' + d.getVar('DSTACK_FLAVOR') + '.efi'}" +UKI_FILENAME = "dstack-uki.efi" do_configure[noexec] = "1" do_compile[noexec] = "1" From 1ee65396daa70e70217f79c3098826139fc98f3b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 06:22:36 +0000 Subject: [PATCH 056/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 4854ccc..a30e298 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 4854ccc2f8fa33838d3029c60803bda2bd6d2d08 +Subproject commit a30e29817d6268b09c618cb2f7f3fd14078d52a4 From 2be071485df0252e0bc284cf3eccc8c2dc6082fc Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 06:48:42 +0000 Subject: [PATCH 057/119] mkimage: Split output into bare-metal and UKI tarballs Split the single output tarball into two separate archives: 1. {name}-{version}.tar.gz (bare metal deployment) - bzImage, initramfs, ovmf.fd, rootfs.img.parted.verity - metadata.json, sha256sum.txt, digest.txt 2. {name}-{version}-uki.tar.gz (GCP/cloud deployment) - disk.raw (GPT disk with EFI partition containing UKI) - auth_hash.txt (Authenticode hash of UKI) Also update dstack-cloud CLI: - pull: Download -uki.tar.gz instead of full tarball - _find_boot_image_tar: Search for disk.raw in -uki directory - _check_and_upload_boot_image: Handle both disk.raw and legacy gcp.tar.gz - _generate_sys_config: Search auth_hash.txt in new location --- mkimage.sh | 105 +++++++++++++++++++-------------------- scripts/bin/dstack-cloud | 99 ++++++++++++++++++++++++------------ 2 files changed, 117 insertions(+), 87 deletions(-) diff --git a/mkimage.sh b/mkimage.sh index 74824c3..6732883 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -2,7 +2,7 @@ set -e DSTACK_TAR_RELEASE=${DSTACK_TAR_RELEASE:-1} -ENABLE_GCP_IMAGE=${ENABLE_GCP_IMAGE:-1} +ENABLE_UKI_IMAGE=${ENABLE_UKI_IMAGE:-1} # Parse command line arguments while [ $# -gt 0 ]; do @@ -56,7 +56,7 @@ OVMF_FIRMWARE=${COMMON_IMG_DIR}/ovmf.fd # Flavor-specific artifacts (from multiconfig build) ROOTFS_IMAGE=${FLAVOR_IMG_DIR}/dstack-rootfs-tdx.squashfs.verity -# UKI filename depends on flavor +# UKI filename UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki.efi # Verity env is in the flavor-specific work-shared directory @@ -65,8 +65,12 @@ echo "Loading verity env from ${VERITY_ENV_FILE}" source ${VERITY_ENV_FILE} DSTACK_VERSION=$(bitbake-getvar --value DISTRO_VERSION | tail -1) + +# Output directory contains all artifacts; tarballs contain subsets OUTPUT_DIR=${OUTPUT_DIR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}"} IMAGE_TAR=${IMAGE_TAR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}.tar.gz"} +IMAGE_TAR_UKI="${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}-uki.tar.gz" +TAR_DIR_NAME="${DIST_NAME}-${DSTACK_VERSION}" AUTHENTICODE_HASH_SCRIPT="${BB_BUILD_DIR}/../scripts/bin/authenticode_hash.py" @@ -119,21 +123,6 @@ write_authenticode_hash_if_missing() { fi } -create_uki_bootstrap() { - local target_dir="$1" - mkdir -p "$target_dir/EFI/BOOT" - - local uki_file="${UKI_IMAGE}" - if [[ ! -f "$uki_file" ]]; then - echo "Error: UKI image not found: $uki_file" >&2 - return 1 - fi - cp "$uki_file" "$target_dir/EFI/BOOT/BOOTX64.EFI" - - # Calculate Authenticode hash if not already present - write_authenticode_hash_if_missing "$uki_file" -} - create_partitioned_rootfs() { local rootfs_img="$1" local output_img="$2" @@ -159,9 +148,9 @@ create_partitioned_rootfs() { ) } -build_gcp_disk_image() { +build_uki_disk_image() { local disk_img="$1" - local boot_source="$2" + local uki_file="$2" local rootfs_img="$3" ( set -e @@ -190,50 +179,43 @@ build_gcp_disk_image() { local tmp_dir tmp_dir=$(mktemp -d) trap 'rm -rf "$tmp_dir"' EXIT + + # Create EFI filesystem with UKI as bootloader local efi_img=${tmp_dir}/efi.img mkfs.vfat -F 32 -n DSTACKEFI -C "$efi_img" $((efi_size_aligned / 1024)) >/dev/null - (cd "$boot_source" && mcopy -s -i "$efi_img" ./* ::) >/dev/null + mmd -i "$efi_img" ::EFI ::EFI/BOOT + mcopy -i "$efi_img" "$uki_file" ::EFI/BOOT/BOOTX64.EFI dd if="$efi_img" of="$disk_img" bs=$align seek=$((efi_start / align)) conv=notrunc status=none dd if="$rootfs_img" of="$disk_img" bs=$align seek=$((rootfs_start / align)) conv=notrunc status=none ) } -create_gcp_artifacts() { - local gcp_dir="${OUTPUT_DIR}/gcp" - local boot_src="${gcp_dir}/efi-root" - mkdir -p "$boot_src" - echo "Installing UKI as EFI bootloader at ${boot_src}" - create_uki_bootstrap "$boot_src" +create_uki_artifacts() { + local uki_dir="$1" + mkdir -p "$uki_dir" - local disk_img="${gcp_dir}/disk.raw" - echo "Building raw disk image for GCP at ${disk_img}" - build_gcp_disk_image "$disk_img" "$boot_src" "${OUTPUT_DIR}/rootfs.img.verity" + echo "Building UKI disk image at ${uki_dir}/disk.raw" + build_uki_disk_image "${uki_dir}/disk.raw" "$UKI_IMAGE" "$ROOTFS_IMAGE" - local tarball="${OUTPUT_DIR}/gcp.tar.gz" - echo "Archiving GCP disk image to ${tarball}" - (cd "$gcp_dir" && tar -czvf "$tarball" disk.raw) + # Calculate and copy auth hash + write_authenticode_hash_if_missing "$UKI_IMAGE" + if [[ -f "${UKI_IMAGE}.auth_hash.txt" ]]; then + cp "${UKI_IMAGE}.auth_hash.txt" "${uki_dir}/auth_hash.txt" + fi } Q=verbose +# Create bare metal image directory $Q rm -rf ${OUTPUT_DIR}/ $Q mkdir -p ${OUTPUT_DIR}/ $Q cp $INITRAMFS_IMAGE ${OUTPUT_DIR}/initramfs.cpio.gz $Q cp $KERNEL_IMAGE ${OUTPUT_DIR}/ $Q cp $OVMF_FIRMWARE ${OUTPUT_DIR}/ -$Q cp $ROOTFS_IMAGE ${OUTPUT_DIR}/rootfs.img.verity - -# Calculate and copy UKI Authenticode hash -if [[ -f "$UKI_IMAGE" ]]; then - write_authenticode_hash_if_missing "$UKI_IMAGE" - if [[ -f "${UKI_IMAGE}.auth_hash.txt" ]]; then - $Q cp "${UKI_IMAGE}.auth_hash.txt" "${OUTPUT_DIR}/dstack-uki.efi.auth_hash.txt" - fi -fi echo "Creating partitioned rootfs image at ${OUTPUT_DIR}/rootfs.img.parted.verity" -create_partitioned_rootfs "${OUTPUT_DIR}/rootfs.img.verity" "${OUTPUT_DIR}/rootfs.img.parted.verity" +create_partitioned_rootfs "$ROOTFS_IMAGE" "${OUTPUT_DIR}/rootfs.img.parted.verity" GIT_REVISION=$(git rev-parse HEAD 2>/dev/null || echo "") echo "Generating metadata.json to ${OUTPUT_DIR}/metadata.json" @@ -262,28 +244,43 @@ sha256sum ovmf.fd bzImage initramfs.cpio.gz metadata.json > sha256sum.txt sha256sum sha256sum.txt | awk '{print $1}' > digest.txt popd -if [ "$ENABLE_GCP_IMAGE" = "1" ]; then +# Create UKI artifacts (disk.raw and auth_hash.txt) in OUTPUT_DIR +UKI_CREATED=0 +if [ "$ENABLE_UKI_IMAGE" = "1" ]; then if [[ ! -f "$UKI_IMAGE" ]]; then - echo "Skipping GCP disk image creation because UKI image not found: $UKI_IMAGE" >&2 + echo "Skipping UKI disk image creation because UKI image not found: $UKI_IMAGE" >&2 echo "Run 'bitbake mc:${FLAVOR}:dstack-uki' to build the UKI first" >&2 elif command -v sgdisk >/dev/null && \ command -v mkfs.vfat >/dev/null && \ - command -v mcopy >/dev/null; then - create_gcp_artifacts + command -v mcopy >/dev/null && \ + command -v mmd >/dev/null; then + create_uki_artifacts "${OUTPUT_DIR}" + UKI_CREATED=1 else - echo "Error: cannot create GCP disk image because required tools are missing" >&2 - echo "Missing tools are among: sgdisk (gdisk), mkfs.vfat (dosfstools), mcopy (mtools)" >&2 - echo "Install them (e.g. apt-get install -y gdisk dosfstools mtools) or set ENABLE_GCP_IMAGE=0" >&2 + echo "Error: cannot create UKI disk image because required tools are missing" >&2 + echo "Missing tools are among: sgdisk (gdisk), mkfs.vfat (dosfstools), mcopy/mmd (mtools)" >&2 + echo "Install them (e.g. apt-get install -y gdisk dosfstools mtools) or set ENABLE_UKI_IMAGE=0" >&2 exit 1 fi fi if [ x$DSTACK_TAR_RELEASE = x1 ]; then - IMAGE_TAR_MR=${DIST_DIR}/mr_$(cat ${OUTPUT_DIR}/digest.txt | tr -d '\n').tar.gz - IMAGE_TAR_NO_ROOTFS=${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}-mr.tar.gz OUTPUT_DIR=$(realpath ${OUTPUT_DIR}) - rm -rf ${IMAGE_TAR} ${IMAGE_TAR_MR} ${IMAGE_TAR_NO_ROOTFS} - echo "Archiving the output directory to ${IMAGE_TAR}" - (cd $(dirname ${OUTPUT_DIR}) && tar -czvf ${IMAGE_TAR} $(basename $OUTPUT_DIR)) + PARENT_DIR=$(dirname ${OUTPUT_DIR}) + + # Bare metal tarball: all files except disk.raw and auth_hash.txt + rm -rf ${IMAGE_TAR} + echo "Archiving bare metal image to ${IMAGE_TAR}" + BARE_METAL_FILES="rootfs.img.parted.verity bzImage ovmf.fd digest.txt sha256sum.txt initramfs.cpio.gz metadata.json" + (cd "$PARENT_DIR" && tar -czvf ${IMAGE_TAR} $(for f in $BARE_METAL_FILES; do echo "$TAR_DIR_NAME/$f"; done)) echo + + # UKI tarball: only disk.raw and auth_hash.txt + if [[ "$UKI_CREATED" = "1" ]]; then + rm -rf ${IMAGE_TAR_UKI} + echo "Archiving UKI image to ${IMAGE_TAR_UKI}" + UKI_FILES="disk.raw auth_hash.txt" + (cd "$PARENT_DIR" && tar -czvf ${IMAGE_TAR_UKI} $(for f in $UKI_FILES; do echo "$TAR_DIR_NAME/$f"; done)) + echo + fi fi diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 30fea2c..0e0a22a 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -393,6 +393,15 @@ class CloudDeploymentManager: if not os.path.isabs(search_path): search_path = os.path.join(self.work_dir, search_path) + # Try new format first (auth_hash.txt in -uki directory) + hash_file = Path(search_path) / f"{local_image}-uki" / "auth_hash.txt" + if hash_file.exists(): + with open(hash_file, 'r') as f: + os_image_hash = f.read().strip() + logger.info(f"Read OS image hash from {hash_file}") + break + + # Fall back to legacy format hash_file = Path(search_path) / local_image / "dstack-uki.efi.auth_hash.txt" if hash_file.exists(): with open(hash_file, 'r') as f: @@ -888,7 +897,7 @@ class CloudDeploymentManager: logger.info("These files will be included in the shared disk image during deploy.") def _find_boot_image_tar(self, local_image: str) -> Optional[Path]: - """Search for boot image tar file in configured search paths.""" + """Search for boot image disk.raw file in configured search paths.""" global_config = self._load_global_config() search_paths = global_config.get("image_search_paths", []) @@ -903,9 +912,10 @@ class CloudDeploymentManager: expanded = os.path.join(self.work_dir, expanded) expanded_paths.append(Path(expanded)) - # Try different file name patterns + # Try different file name patterns (new -uki format first, then legacy gcp.tar.gz) patterns = [ - f"{local_image}/gcp.tar.gz", + f"{local_image}-uki/disk.raw", + f"{local_image}/gcp.tar.gz", # Legacy format ] for search_path in expanded_paths: @@ -913,16 +923,16 @@ class CloudDeploymentManager: if not search_path.exists(): continue for pattern in patterns: - tar_file = search_path / pattern - logger.debug(f"Checking: {tar_file}, exists: {tar_file.exists()}") - if tar_file.exists(): - logger.info(f"Found boot image: {tar_file}") - return tar_file + file_path = search_path / pattern + logger.debug(f"Checking: {file_path}, exists: {file_path.exists()}") + if file_path.exists(): + logger.info(f"Found boot image: {file_path}") + return file_path return None def pull(self, os_image: str) -> None: - """Download OS image from remote repository.""" + """Download UKI image from remote repository.""" global_config = self._load_global_config() search_paths = global_config.get("image_search_paths", []) @@ -935,8 +945,8 @@ class CloudDeploymentManager: target_dir = Path(os.path.expanduser(search_paths[0])) target_dir.mkdir(parents=True, exist_ok=True) - # Download tar file (e.g., dstack-0.6.0.tar.gz) - download_tar = target_dir / f"{os_image}.tar.gz" + # Download UKI tar file (e.g., dstack-cloud-nvidia-0.6.0-uki.tar.gz) + download_tar = target_dir / f"{os_image}-uki.tar.gz" if download_tar.exists(): logger.info(f"Download file already exists: {download_tar}") @@ -946,9 +956,9 @@ class CloudDeploymentManager: return # Download URL - download_url = f"https://download.dstack.org/os-images/{os_image}.tar.gz" + download_url = f"https://download.dstack.org/os-images/{os_image}-uki.tar.gz" - logger.info(f"Downloading {os_image} from {download_url}...") + logger.info(f"Downloading {os_image} UKI image from {download_url}...") logger.info(f"Target: {download_tar}") try: @@ -972,46 +982,46 @@ class CloudDeploymentManager: ["tar", "-xzf", str(download_tar), "-C", str(target_dir)], check=True ) - logger.info(f"Successfully extracted to {target_dir / os_image}") + logger.info(f"Successfully extracted to {target_dir / os_image}-uki") except subprocess.CalledProcessError as e: logger.error(f"Failed to extract image: {e}") raise # Verify the expected structure - expected_dir = target_dir / os_image - expected_tar = expected_dir / "gcp.tar.gz" - if expected_tar.exists(): - logger.info(f"Image ready: {expected_tar}") + expected_dir = target_dir / f"{os_image}-uki" + expected_disk = expected_dir / "disk.raw" + if expected_disk.exists(): + logger.info(f"Image ready: {expected_disk}") else: - logger.warning(f"Expected file not found: {expected_tar}") + logger.warning(f"Expected file not found: {expected_disk}") logger.warning(f"Downloaded structure may be incorrect") def _check_and_upload_boot_image(self, config: GcpConfig, app: App, force: bool = False) -> str: """Check and upload boot image if needed. Returns the image name.""" - tar_path = None + image_path = None # Derive GCP image name from app.os_image gcp_image = config.boot_image if not gcp_image: - # Convert OS image name (dstack-0.6.0 -> dstack-0-6-0) + # Convert OS image name (dstack-cloud-nvidia-0.6.0 -> dstack-cloud-nvidia-0-6-0) gcp_image = app.os_image.replace(".", "-") - # If boot_image_tar is specified, use it + # If boot_image_tar is specified, use it (legacy config name, can be disk.raw or tar.gz) if config.boot_image_tar: - tar_path = Path(os.path.expanduser(config.boot_image_tar)) - if not tar_path.exists(): + image_path = Path(os.path.expanduser(config.boot_image_tar)) + if not image_path.exists(): logger.error("") - logger.error(f"Boot image tar not found: {tar_path}") + logger.error(f"Boot image not found: {image_path}") logger.error("") logger.error(f"Please download the image using:") logger.error(f" dstack-cloud pull {app.os_image}") logger.error("") - raise FileNotFoundError(f"Boot image tar not found: {tar_path}") + raise FileNotFoundError(f"Boot image not found: {image_path}") else: # Auto-discover from search paths using OS image name logger.info(f"Searching for boot image '{app.os_image}'...") - tar_path = self._find_boot_image_tar(app.os_image) - if not tar_path: + image_path = self._find_boot_image_tar(app.os_image) + if not image_path: logger.error("") logger.error(f"Boot image '{app.os_image}' not found locally.") logger.error("") @@ -1023,9 +1033,12 @@ class CloudDeploymentManager: f"Run 'dstack-cloud pull {app.os_image}' to download it." ) + # Determine if we have disk.raw (new format) or gcp.tar.gz (legacy format) + is_raw_disk = image_path.name == "disk.raw" + # Use gcp_image as the GCP image name image_name = gcp_image - local_mtime = tar_path.stat().st_mtime + local_mtime = image_path.stat().st_mtime # Check if GCP image exists and is up-to-date result = self._run_gcloud([ @@ -1061,10 +1074,30 @@ class CloudDeploymentManager: need_upload = True if need_upload: - logger.info("Uploading boot image to GCS...") - self._run_gsutil([ - "cp", str(tar_path), f"{config.bucket}/{image_name}.tar.gz" - ]) + if is_raw_disk: + # New format: disk.raw needs to be compressed to tar.gz for upload + logger.info("Compressing disk.raw to tar.gz for upload...") + import tempfile + with tempfile.TemporaryDirectory() as tmpdir: + tar_file = os.path.join(tmpdir, "disk.tar.gz") + result = subprocess.run( + ["tar", "-czvf", tar_file, "-C", str(image_path.parent), "disk.raw"], + capture_output=True, + text=True + ) + if result.returncode != 0: + raise RuntimeError(f"Failed to create tar.gz: {result.stderr}") + + logger.info("Uploading boot image to GCS...") + self._run_gsutil([ + "cp", tar_file, f"{config.bucket}/{image_name}.tar.gz" + ]) + else: + # Legacy format: gcp.tar.gz can be uploaded directly + logger.info("Uploading boot image to GCS...") + self._run_gsutil([ + "cp", str(image_path), f"{config.bucket}/{image_name}.tar.gz" + ]) # Delete existing image if present if gcp_creation_time: From cd84be8df4936353546ddd16d9ac19124d1f4060 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 07:43:38 +0000 Subject: [PATCH 058/119] Fix filenames in dstack-cloud.py --- scripts/bin/dstack-cloud | 72 +++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 0e0a22a..44ff9a2 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -393,16 +393,7 @@ class CloudDeploymentManager: if not os.path.isabs(search_path): search_path = os.path.join(self.work_dir, search_path) - # Try new format first (auth_hash.txt in -uki directory) - hash_file = Path(search_path) / f"{local_image}-uki" / "auth_hash.txt" - if hash_file.exists(): - with open(hash_file, 'r') as f: - os_image_hash = f.read().strip() - logger.info(f"Read OS image hash from {hash_file}") - break - - # Fall back to legacy format - hash_file = Path(search_path) / local_image / "dstack-uki.efi.auth_hash.txt" + hash_file = Path(search_path) / local_image / "auth_hash.txt" if hash_file.exists(): with open(hash_file, 'r') as f: os_image_hash = f.read().strip() @@ -912,10 +903,9 @@ class CloudDeploymentManager: expanded = os.path.join(self.work_dir, expanded) expanded_paths.append(Path(expanded)) - # Try different file name patterns (new -uki format first, then legacy gcp.tar.gz) + # Look for disk.raw in the image directory patterns = [ - f"{local_image}-uki/disk.raw", - f"{local_image}/gcp.tar.gz", # Legacy format + f"{local_image}/disk.raw", ] for search_path in expanded_paths: @@ -955,8 +945,18 @@ class CloudDeploymentManager: logger.info("Download cancelled") return - # Download URL - download_url = f"https://download.dstack.org/os-images/{os_image}-uki.tar.gz" + # Extract version from os_image (e.g., dstack-cloud-nvidia-0.6.0 -> 0.6.0) + # Version is the last component after the last hyphen followed by digits + import re + version_match = re.search(r'-(\d+\.\d+\.\d+)$', os_image) + if not version_match: + logger.error(f"Could not extract version from image name: {os_image}") + logger.error("Expected format: dstack-cloud-- (e.g., dstack-cloud-nvidia-0.6.0)") + return + version = version_match.group(1) + + # Download from GitHub releases + download_url = f"https://github.com/Phala-Network/meta-dstack-cloud/releases/download/v{version}/{os_image}-uki.tar.gz" logger.info(f"Downloading {os_image} UKI image from {download_url}...") logger.info(f"Target: {download_tar}") @@ -982,13 +982,13 @@ class CloudDeploymentManager: ["tar", "-xzf", str(download_tar), "-C", str(target_dir)], check=True ) - logger.info(f"Successfully extracted to {target_dir / os_image}-uki") + logger.info(f"Successfully extracted to {target_dir / os_image}") except subprocess.CalledProcessError as e: logger.error(f"Failed to extract image: {e}") raise # Verify the expected structure - expected_dir = target_dir / f"{os_image}-uki" + expected_dir = target_dir / os_image expected_disk = expected_dir / "disk.raw" if expected_disk.exists(): logger.info(f"Image ready: {expected_disk}") @@ -1033,9 +1033,6 @@ class CloudDeploymentManager: f"Run 'dstack-cloud pull {app.os_image}' to download it." ) - # Determine if we have disk.raw (new format) or gcp.tar.gz (legacy format) - is_raw_disk = image_path.name == "disk.raw" - # Use gcp_image as the GCP image name image_name = gcp_image local_mtime = image_path.stat().st_mtime @@ -1074,29 +1071,22 @@ class CloudDeploymentManager: need_upload = True if need_upload: - if is_raw_disk: - # New format: disk.raw needs to be compressed to tar.gz for upload - logger.info("Compressing disk.raw to tar.gz for upload...") - import tempfile - with tempfile.TemporaryDirectory() as tmpdir: - tar_file = os.path.join(tmpdir, "disk.tar.gz") - result = subprocess.run( - ["tar", "-czvf", tar_file, "-C", str(image_path.parent), "disk.raw"], - capture_output=True, - text=True - ) - if result.returncode != 0: - raise RuntimeError(f"Failed to create tar.gz: {result.stderr}") + # Compress disk.raw to tar.gz for upload + logger.info("Compressing disk.raw to tar.gz for upload...") + import tempfile + with tempfile.TemporaryDirectory() as tmpdir: + tar_file = os.path.join(tmpdir, "disk.tar.gz") + result = subprocess.run( + ["tar", "-czvf", tar_file, "-C", str(image_path.parent), "disk.raw"], + capture_output=True, + text=True + ) + if result.returncode != 0: + raise RuntimeError(f"Failed to create tar.gz: {result.stderr}") - logger.info("Uploading boot image to GCS...") - self._run_gsutil([ - "cp", tar_file, f"{config.bucket}/{image_name}.tar.gz" - ]) - else: - # Legacy format: gcp.tar.gz can be uploaded directly logger.info("Uploading boot image to GCS...") self._run_gsutil([ - "cp", str(image_path), f"{config.bucket}/{image_name}.tar.gz" + "cp", tar_file, f"{config.bucket}/{image_name}.tar.gz" ]) # Delete existing image if present @@ -2075,7 +2065,7 @@ Examples: dstack-cloud config-edit # Download OS image - dstack-cloud pull dstack-0.6.0 + dstack-cloud pull dstack-cloud-0.6.0 # Deploy VM dstack-cloud deploy From 0a002d4511867321274eb09bd5056a6960b7bec8 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 07:47:54 +0000 Subject: [PATCH 059/119] Fix url in repro-build.sh --- repro-build/repro-build.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/repro-build/repro-build.sh b/repro-build/repro-build.sh index 2b96bfd..c89680b 100755 --- a/repro-build/repro-build.sh +++ b/repro-build/repro-build.sh @@ -51,13 +51,16 @@ build_to() { $BUILDER_NAME bash -e -c "$BUILD_CMD" } -build_to $HOST_BUILD_DIR_A DSTACK_TAR_RELEASE=1 +# Only build production flavors (no dev) for reproducible builds +RELEASE_FLAVORS="prod nvidia" + +build_to $HOST_BUILD_DIR_A "FLAVORS='$RELEASE_FLAVORS' DSTACK_TAR_RELEASE=1" DIST_DIR=${THIS_DIR}/dist mkdir -p $DIST_DIR mv $HOST_BUILD_DIR_A/images/*.tar.gz $DIST_DIR/ if [ $NO_CHECK -eq 0 ]; then - build_to $HOST_BUILD_DIR_B + build_to $HOST_BUILD_DIR_B "FLAVORS='$RELEASE_FLAVORS'" ${THIS_DIR}/check.sh $HOST_BUILD_DIR_A $HOST_BUILD_DIR_B fi @@ -72,8 +75,8 @@ cat < Date: Tue, 20 Jan 2026 08:44:10 +0000 Subject: [PATCH 060/119] mkimage: Fix authenticode_hash.py path resolution Use script's directory to find authenticode_hash.py instead of relative path from BB_BUILD_DIR. This fixes the path resolution in repro-build Docker environment where BB_BUILD_DIR points to a different location than the source tree. --- mkimage.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mkimage.sh b/mkimage.sh index 6732883..053335d 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -72,7 +72,9 @@ IMAGE_TAR=${IMAGE_TAR:-"${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}.tar.gz"} IMAGE_TAR_UKI="${DIST_DIR}/${DIST_NAME}-${DSTACK_VERSION}-uki.tar.gz" TAR_DIR_NAME="${DIST_NAME}-${DSTACK_VERSION}" -AUTHENTICODE_HASH_SCRIPT="${BB_BUILD_DIR}/../scripts/bin/authenticode_hash.py" +# Use script's directory to find authenticode_hash.py +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +AUTHENTICODE_HASH_SCRIPT="${SCRIPT_DIR}/scripts/bin/authenticode_hash.py" verbose() { echo "$@" From b9643688cedc249876e249753e174aead4a733a5 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 13:48:37 +0000 Subject: [PATCH 061/119] dstack-guest: Restore do_unpack nostamp flag This ensures source changes are detected on every build, preventing stale cached builds. --- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 0e6daca..2f7e0fb 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -37,8 +37,10 @@ do_unpack() { fi } +# Force the configure task to run every time to detect source changes +do_unpack[nostamp] = "1" + # Add source directory to configure task dependencies -# Note: removed nostamp to avoid concurrent build conflicts in multiconfig do_unpack[vardeps] += "SRC_DIR" do_configure() { From c65b000fc098d402bc2c7b21e2b8da3f002ad6c3 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 13:49:37 +0000 Subject: [PATCH 062/119] mkimage: Use stat -L to follow symlinks when getting rootfs size The rootfs image path may be a symlink. Use stat -L to dereference symlinks and get the actual file size, preventing incorrect disk image sizing. --- mkimage.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkimage.sh b/mkimage.sh index 053335d..1547bc0 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -132,7 +132,7 @@ create_partitioned_rootfs() { set -e local align=$((1024 * 1024)) local sector=512 - local rootfs_size=$(stat -c %s "$rootfs_img") + local rootfs_size=$(stat -L -c %s "$rootfs_img") local rootfs_size_aligned=$(align_up $rootfs_size $align) local rootfs_start=$align # Leave extra room for GPT headers (1MB at start, 1MB at end) @@ -160,7 +160,7 @@ build_uki_disk_image() { local sector=512 local efi_size=$((256 * 1024 * 1024)) local efi_size_aligned=$(align_up $efi_size $align) - local rootfs_size=$(stat -c %s "$rootfs_img") + local rootfs_size=$(stat -L -c %s "$rootfs_img") local rootfs_size_aligned=$(align_up $rootfs_size $align) local efi_start=$align local rootfs_start=$((efi_start + efi_size_aligned)) From 4775271e5031090da90794b0cf25aecc798d4361 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 14:16:40 +0000 Subject: [PATCH 063/119] Remove tpm2 from DISTRO_FEATURES Remove tpm2 feature from distro configuration while keeping kernel TPM drivers available. User commands access TPM directly without needing libtss2 library. - Remove tpm2 from DISTRO_FEATURES in dstack.conf - Remove libtss2-dev dependency from dstack-guest.bb --- meta-dstack/conf/distro/dstack.conf | 2 +- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 4294ff8..c7cf93e 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -1,7 +1,7 @@ require conf/distro/cvm.conf DISTRO = "dstack" DISTRO_NAME = "dstack" -DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6 tpm2" +DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6" DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" DISTRO_VERSION = "0.6.0" diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 2f7e0fb..50362e4 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -13,7 +13,7 @@ S = "${UNPACKDIR}/dstack" RDEPENDS:${PN} += "bash" -DEPENDS += "rsync-native libtss2-dev" +DEPENDS += "rsync-native" # Ensure rsync-native is built before unpack runs do_unpack[depends] += "rsync-native:do_populate_sysroot" From f1e28796ee3846c8d4c7c0a6bd3653ec25e07efe Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 14:16:57 +0000 Subject: [PATCH 064/119] Remove unused systemd components completely Remove vconsole-setup binary, udev rules, and gpt-auto-generator entirely rather than just disabling the services. These components are not needed in the dstack guest environment. - Remove systemd-vconsole-setup binary - Remove vconsole udev rules (90-vconsole.rules) - Remove systemd-gpt-auto-generator (causes UNSUPP error) --- meta-dstack/recipes-core/systemd/systemd_%.bbappend | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/meta-dstack/recipes-core/systemd/systemd_%.bbappend b/meta-dstack/recipes-core/systemd/systemd_%.bbappend index f73be27..7c1ea90 100644 --- a/meta-dstack/recipes-core/systemd/systemd_%.bbappend +++ b/meta-dstack/recipes-core/systemd/systemd_%.bbappend @@ -1,6 +1,12 @@ do_install:append() { - # Disable systemd-vconsole-setup.service + # Remove systemd-vconsole-setup entirely (no virtual console needed) rm -f ${D}${systemd_system_unitdir}/sysinit.target.wants/systemd-vconsole-setup.service + rm -f ${D}${systemd_system_unitdir}/systemd-vconsole-setup.service + rm -f ${D}${rootlibexecdir}/systemd/systemd-vconsole-setup + rm -f ${D}${nonarch_libdir}/udev/rules.d/90-vconsole.rules + + # Disable EFI System Partition automount (not needed, causes UNSUPP error) + rm -f ${D}${nonarch_libdir}/systemd/system-generators/systemd-gpt-auto-generator # Ensure systemd-resolved waits for /var/volatile tmpfs and tmpfiles setup install -d ${D}${systemd_system_unitdir}/systemd-resolved.service.d From d82f4d09187bdb9b5f5200f6ec312c2176a581b9 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 14:17:10 +0000 Subject: [PATCH 065/119] dstack-cloud: Remove init command and improve UX Simplify the CLI by removing the redundant 'init' command (use 'new' instead) and improve user experience with better error messages. - Remove 'init' command, consolidate functionality in 'new' - Add DEFAULT_OS_IMAGE constant for consistency - Add required parameter to load_app_config() for better error messages - Validate required GCP configuration before deploy - Update help text and examples --- scripts/bin/dstack-cloud | 133 +++++++++++---------------------------- 1 file changed, 38 insertions(+), 95 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 44ff9a2..9185a54 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -12,7 +12,6 @@ Supports local configuration files similar to git's working model. Usage: dstack-cloud new # Create a new project - dstack-cloud init # Initialize current directory dstack-cloud config-edit # Edit global configuration dstack-cloud prepare # Generate shared files dstack-cloud deploy # Deploy VM to cloud @@ -63,6 +62,7 @@ logger = logging.getLogger(__name__) APP_CONFIG_FILE = "app.json" STATE_FILE = "state.json" GLOBAL_CONFIG_PATH = os.path.expanduser("~/.config/dstack-cloud/config.json") +DEFAULT_OS_IMAGE = "dstack-cloud-0.6.0" @dataclass @@ -72,7 +72,7 @@ class App: name: str = "myapp" # OS image - os_image: str = "dstack-0.6.0" + os_image: str = DEFAULT_OS_IMAGE # GCP cloud configuration gcp_config: 'GcpConfig' = field(default_factory=lambda: GcpConfig()) @@ -141,7 +141,7 @@ class App: return { "name": "myapp", - "os_image": "dstack-0.6.0", + "os_image": DEFAULT_OS_IMAGE, "gcp_config": GcpConfig.get_template(), "instance_id_seed": instance_id_seed, "app_id": app_id, @@ -299,11 +299,20 @@ class CloudDeploymentManager: # Save the updated app config self.save_app_config(app) - def load_app_config(self) -> App: - """Load application configuration.""" + def load_app_config(self, required: bool = False) -> App: + """Load application configuration. + + Args: + required: If True, raise error when app.json doesn't exist + """ app_config_path = self.work_dir / APP_CONFIG_FILE if not app_config_path.exists(): + if required: + raise FileNotFoundError( + f"No {APP_CONFIG_FILE} found in {self.work_dir}. " + f"Run 'dstack-cloud new ' to create a project." + ) # Return default config if file doesn't exist return App() @@ -587,42 +596,6 @@ class CloudDeploymentManager: logger.info(f"Project directory: {project_dir}") logger.info("") - def init( - self, - force: bool = False, - interactive: bool = True, - os_image: Optional[str] = None, - app_id: Optional[str] = None, - gateway_enabled: Optional[bool] = None, - key_provider: Optional[str] = None, - storage_fs: Optional[str] = None, - secure_time: Optional[bool] = None, - no_instance_id: Optional[bool] = None, - project: Optional[str] = None, - zone: Optional[str] = None, - instance_name: Optional[str] = None, - machine_type: Optional[str] = None, - data_size: Optional[int] = None - ) -> None: - """Initialize deployment configuration in current directory.""" - self._init_project( - force=force, - interactive=interactive, - app_name=None, # Will prompt in interactive mode - os_image=os_image, - app_id=app_id, - gateway_enabled=gateway_enabled, - key_provider=key_provider, - storage_fs=storage_fs, - secure_time=secure_time, - no_instance_id=no_instance_id, - project=project, - zone=zone, - instance_name=instance_name, - machine_type=machine_type, - data_size=data_size - ) - def _init_project( self, force: bool = False, @@ -641,14 +614,14 @@ class CloudDeploymentManager: machine_type: Optional[str] = None, data_size: Optional[int] = None ) -> None: - """Initialize project configuration (shared implementation for init and new).""" + """Initialize project configuration.""" # Interactive prompts for required fields (only if not provided via CLI) instance_name_cli = instance_name if interactive: print(f"\n=== dstack-cloud Project Initialization ===\n") - # Prompt for app name (only for init command, new command provides it) + # Prompt for app name if not provided if app_name is None: while True: app_name = input("App name [myapp]: ").strip() @@ -822,8 +795,8 @@ class CloudDeploymentManager: """Generate all files in shared directory.""" import secrets - # Load app config - app = self.load_app_config() + # Load app config (required) + app = self.load_app_config(required=True) # Ensure instance_id_seed and app_id exist if not app.instance_id_seed: @@ -1304,8 +1277,23 @@ class CloudDeploymentManager: def deploy(self, delete_existing: bool = False, force_boot_image: bool = False) -> None: """Deploy VM to GCP.""" + # Load app config first (required) - validates project exists + app = self.load_app_config(required=True) config = self.load_gcp_config() - app = self.load_app_config() + + # Validate required configuration + missing = [] + if not config.instance_name: + missing.append("instance_name") + if not config.project: + missing.append("project") + if not config.zone: + missing.append("zone") + if missing: + raise ValueError( + f"Missing required GCP configuration: {', '.join(missing)}. " + f"Run 'dstack-cloud new ' to create a project or edit dstack-app.json." + ) # Auto-detect bucket if not specified if not config.bucket and config.project: @@ -2053,19 +2041,16 @@ def main(): parser = argparse.ArgumentParser( description="Multi-cloud VM lifecycle management tool", formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=""" + epilog=f""" Examples: # Create a new project dstack-cloud new myproject - # Initialize current directory - dstack-cloud init - # Edit global configuration dstack-cloud config-edit # Download OS image - dstack-cloud pull dstack-cloud-0.6.0 + dstack-cloud pull {DEFAULT_OS_IMAGE} # Deploy VM dstack-cloud deploy @@ -2102,7 +2087,7 @@ Examples: new_parser.add_argument("name", type=str, help="Project name") # App configuration options - new_parser.add_argument("--os-image", type=str, help="OS image (e.g., dstack-0.6.0)") + new_parser.add_argument("--os-image", type=str, help=f"OS image (e.g., {DEFAULT_OS_IMAGE})") new_parser.add_argument("--app-id", type=str, help="Application ID (40 hex chars)") new_parser.add_argument("--gateway-enabled", "--gw", dest="gateway_enabled", action="store_true", help="Enable dstack-gateway") new_parser.add_argument("--no-gateway-enabled", "--no-gw", dest="gateway_enabled", action="store_false") @@ -2121,31 +2106,6 @@ Examples: new_parser.add_argument("--machine-type", "-m", type=str, help="Machine type (e.g., c3-standard-4)") new_parser.add_argument("--data-size", type=int, help="Data disk size in GB") - # init command - init_parser = subparsers.add_parser("init", help="Initialize deployment configuration") - init_parser.add_argument("--force", "-f", action="store_true", help="Overwrite existing config") - init_parser.add_argument("--non-interactive", "-n", action="store_true", help="Skip interactive prompts") - - # App configuration options (same as new) - init_parser.add_argument("--os-image", type=str, help="OS image (e.g., dstack-0.6.0)") - init_parser.add_argument("--app-id", type=str, help="Application ID (40 hex chars)") - init_parser.add_argument("--gateway-enabled", "--gw", dest="gateway_enabled", action="store_true", help="Enable dstack-gateway") - init_parser.add_argument("--no-gateway-enabled", "--no-gw", dest="gateway_enabled", action="store_false") - init_parser.set_defaults(gateway_enabled=None) - init_parser.add_argument("--key-provider", "--kp", type=str, choices=["kms", "local", "tpm", "none"], help="Key provider type") - init_parser.add_argument("--storage-fs", "--fs", dest="storage_fs", type=str, choices=["ext4", "zfs"], help="Storage filesystem") - init_parser.add_argument("--secure-time", action="store_true", help="Enable secure time synchronization") - init_parser.add_argument("--no-secure-time", dest="secure_time", action="store_false") - init_parser.set_defaults(secure_time=None) - init_parser.add_argument("--no-instance-id", action="store_true", help="Disable instance ID generation") - - # GCP configuration options (same as new) - init_parser.add_argument("--project", "-p", type=str, help="GCP project ID") - init_parser.add_argument("--zone", "-z", type=str, help="GCP zone (e.g., us-central1-a)") - init_parser.add_argument("--instance-name", type=str, help="GCP instance name") - init_parser.add_argument("--machine-type", "-m", type=str, help="Machine type (e.g., c3-standard-4)") - init_parser.add_argument("--data-size", type=int, help="Data disk size in GB") - # config-edit command subparsers.add_parser("config-edit", help="Edit global configuration") @@ -2154,7 +2114,7 @@ Examples: # pull command pull_parser = subparsers.add_parser("pull", help="Download OS image") - pull_parser.add_argument("image", type=str, help="OS image name (e.g., dstack-0.6.0)") + pull_parser.add_argument("image", type=str, help=f"OS image name (e.g., {DEFAULT_OS_IMAGE})") # deploy command deploy_parser = subparsers.add_parser("deploy", help="Deploy VM to cloud") @@ -2244,23 +2204,6 @@ Examples: machine_type=args.machine_type, data_size=args.data_size ) - elif args.command == "init": - manager.init( - force=args.force, - interactive=not args.non_interactive, - os_image=args.os_image, - app_id=args.app_id, - gateway_enabled=args.gateway_enabled, - key_provider=args.key_provider, - storage_fs=args.storage_fs, - secure_time=args.secure_time, - no_instance_id=args.no_instance_id, - project=args.project, - zone=args.zone, - instance_name=args.instance_name, - machine_type=args.machine_type, - data_size=args.data_size - ) elif args.command == "config-edit": manager.config_edit() elif args.command == "prepare": From 5652ee2d6d3e471d80200678e83d693c42e7fb11 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 14:18:20 +0000 Subject: [PATCH 066/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index a30e298..2eb5264 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit a30e29817d6268b09c618cb2f7f3fd14078d52a4 +Subproject commit 2eb52646a233ebf0d2d6e63493844eba65d768ed From 4f1d55af123e4be5c8208fbea7a3eeede51f8bea Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 14:43:14 +0000 Subject: [PATCH 067/119] Suppress meta-tpm warning --- meta-dstack/conf/distro/dstack.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index c7cf93e..4142d0f 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -27,6 +27,9 @@ BAD_RECOMMENDATIONS = "busybox-syslog systemd-compat-units" # Skip unused components that fail metadata checks under walnascar SKIP_RECIPE[ostree] = "not required for dstack" +# Suppress meta-tpm warning (we use TPM drivers directly without tpm2 DISTRO_FEATURES) +SKIP_META_TPM_SANITY_CHECK = "1" + # EFI/UKI support for GCP images MACHINE_FEATURES:append = " efi" EFI_PROVIDER = "systemd-boot" From f899c7e5c9bbe7ddbdf44f45febe17871cba5b8d Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 20 Jan 2026 15:16:48 +0000 Subject: [PATCH 068/119] Always calculate auth hash --- mkimage.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/mkimage.sh b/mkimage.sh index 1547bc0..f6323fc 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -97,14 +97,10 @@ calc_authenticode_hash() { python3 "$AUTHENTICODE_HASH_SCRIPT" "$file" 2>/dev/null || true } -write_authenticode_hash_if_missing() { +write_authenticode_hash() { local file="$1" local out_file="${file}.auth_hash.txt" - if [[ -f "$out_file" ]]; then - return 0 - fi - if [[ ! -f "$file" ]]; then return 0 fi @@ -201,7 +197,7 @@ create_uki_artifacts() { build_uki_disk_image "${uki_dir}/disk.raw" "$UKI_IMAGE" "$ROOTFS_IMAGE" # Calculate and copy auth hash - write_authenticode_hash_if_missing "$UKI_IMAGE" + write_authenticode_hash "$UKI_IMAGE" if [[ -f "${UKI_IMAGE}.auth_hash.txt" ]]; then cp "${UKI_IMAGE}.auth_hash.txt" "${uki_dir}/auth_hash.txt" fi From 0b8d9c370aef0739b2409bb3e74c0951ef93719e Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 21 Jan 2026 08:24:11 +0000 Subject: [PATCH 069/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 2eb5264..590b8f3 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 2eb52646a233ebf0d2d6e63493844eba65d768ed +Subproject commit 590b8f3186f4671398d5307f091e6b8c3a6bd7a0 From 6afa83d7800eb49bb920a4888046371cfb1ab03e Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 22 Jan 2026 13:30:26 +0000 Subject: [PATCH 070/119] Update meta-virtualization --- meta-virtualization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-virtualization b/meta-virtualization index ebb9f7c..809318c 160000 --- a/meta-virtualization +++ b/meta-virtualization @@ -1 +1 @@ -Subproject commit ebb9f7cdd5475efd0fdac840840334376db98fbb +Subproject commit 809318cf945102726b6c2afbf1f977e2a607865b From 65d6ffddf0e01fe0e75c61d3e7089a7165e89b59 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 23 Jan 2026 01:01:14 +0000 Subject: [PATCH 071/119] Fix env issue in dstack-cloud --- scripts/bin/dstack-cloud | 119 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 6 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 9185a54..f6c92e6 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -43,14 +43,24 @@ from typing import Optional, List, Dict, Any # Try to import cryptography libraries for env encryption CRYPTO_AVAILABLE = False +ETH_CRYPTO_AVAILABLE = False try: from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.asymmetric import x25519 - from cryptography.hazmat.backends import default_backend - from cryptography import serialization + from cryptography.hazmat.primitives import serialization CRYPTO_AVAILABLE = True -except ImportError: - CRYPTO_AVAILABLE = False +except Exception: + pass + +try: + from eth_keys import keys + from eth_utils import keccak + ETH_CRYPTO_AVAILABLE = True +except Exception: + pass + +# Default whitelist file location +DEFAULT_KMS_WHITELIST_PATH = os.path.expanduser("~/.config/dstack-cloud/kms-whitelist.json") logging.basicConfig( level=logging.INFO, @@ -1440,7 +1450,7 @@ class CloudDeploymentManager: if not CRYPTO_AVAILABLE: raise ImportError( "Cryptography libraries not available. Please install:\n" - "pip install cryptography" + "pip install cryptography eth-keys 'eth-hash[pycryptodome]'" ) # Serialize environment variables to JSON @@ -1481,6 +1491,7 @@ class CloudDeploymentManager: try: import urllib.request import urllib.error + import ssl path = f"{kms_url}/prpc/GetAppEnvEncryptPubKey?json" data = json.dumps({"app_id": app_id}).encode("utf-8") @@ -1491,19 +1502,115 @@ class CloudDeploymentManager: headers={"Content-Type": "application/json"} ) + # Allow self-signed certificates for KMS server + ssl_context = ssl.create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + logger.info(f"Getting encryption public key for {app_id} from {kms_url}") - with urllib.request.urlopen(req, timeout=10) as response: + with urllib.request.urlopen(req, timeout=10, context=ssl_context) as response: response_data = json.loads(response.read().decode("utf-8")) if "public_key" not in response_data: raise ValueError(f"No public_key in response: {response_data}") + # Verify signature if available + if "signature" not in response_data: + if not self._confirm_untrusted_signer("none"): + raise ValueError("Aborted due to missing signature") + return response_data["public_key"] + + public_key = bytes.fromhex(response_data["public_key"]) + signature = bytes.fromhex(response_data["signature"]) + + signer_pubkey = self._verify_signature(public_key, signature, app_id) + if signer_pubkey: + whitelist = self._load_whitelist() + if whitelist and signer_pubkey not in whitelist: + logger.warning(f"Signer {signer_pubkey} is not in the trusted whitelist!") + if not self._confirm_untrusted_signer(signer_pubkey): + raise ValueError("Aborted due to untrusted signer") + else: + logger.info(f"Verified signature from: {signer_pubkey}") + else: + logger.warning("Could not verify signature!") + if not self._confirm_untrusted_signer("unknown"): + raise ValueError("Aborted due to invalid signature") + return response_data["public_key"] except Exception as e: logger.warning(f"Failed to get encryption public key: {e}") raise + def _verify_signature(self, public_key: bytes, signature: bytes, app_id: str) -> Optional[str]: + """Verify the signature of a public key. + + Args: + public_key: The public key bytes to verify + signature: The signature bytes + app_id: The application ID + + Returns: + The compressed public key if valid, None otherwise + """ + if not ETH_CRYPTO_AVAILABLE: + logger.warning("eth-keys not available, skipping signature verification. " + "Install with: pip install eth-keys 'eth-hash[pycryptodome]'") + return None + + if len(signature) != 65: + return None + + # Create the message to verify + prefix = b"dstack-env-encrypt-pubkey" + if app_id.startswith("0x"): + app_id = app_id[2:] + message = prefix + b":" + bytes.fromhex(app_id) + public_key + + # Hash the message with Keccak-256 and recover the public key + try: + message_hash = keccak(message) + sig = keys.Signature(signature_bytes=signature) + recovered_key = sig.recover_public_key_from_msg_hash(message_hash) + return '0x' + recovered_key.to_compressed_bytes().hex() + except Exception as e: + error_msg = str(e) + if "hashing backends" in error_msg or "pycryptodome" in error_msg: + raise ImportError( + "Ethereum hashing backend not available. Please install:\n" + "pip install cryptography eth-keys 'eth-hash[pycryptodome]'" + ) + logger.debug(f"Signature verification failed: {e}") + return None + + def _confirm_untrusted_signer(self, signer: str) -> bool: + """Ask user to confirm using an untrusted signer.""" + try: + response = input(f"Continue with untrusted signer '{signer}'? (y/N): ") + return response.lower() in ('y', 'yes') + except EOFError: + # Non-interactive mode, reject untrusted signers + return False + + def _load_whitelist(self) -> List[str]: + """Load the whitelist of trusted signers from a file.""" + if not os.path.exists(DEFAULT_KMS_WHITELIST_PATH): + return [] + + try: + with open(DEFAULT_KMS_WHITELIST_PATH, 'r') as f: + data = json.load(f) + return data.get('trusted_signers', []) + except (json.JSONDecodeError, FileNotFoundError): + return [] + + def _save_whitelist(self, whitelist: List[str]) -> None: + """Save the whitelist of trusted signers to a file.""" + os.makedirs(os.path.dirname(DEFAULT_KMS_WHITELIST_PATH), exist_ok=True) + with open(DEFAULT_KMS_WHITELIST_PATH, 'w') as f: + json.dump({'trusted_signers': whitelist}, f, indent=2) + def _derive_instance_id(self, instance_id_seed: str, app_id: str) -> str: """Derive instance_id from instance_id_seed and app_id. From b49e84b79416ab9b890d7a1a97e905b2d281ae78 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 23 Jan 2026 01:01:30 +0000 Subject: [PATCH 072/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 590b8f3..702740d 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 590b8f3186f4671398d5307f091e6b8c3a6bd7a0 +Subproject commit 702740d49a4d67d0ce186ed7afaf1e09adc6aeb6 From c92e0a87babc3efda162864d776305a7b78139b9 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 26 Jan 2026 06:27:45 +0000 Subject: [PATCH 073/119] Upgrade kernel to 6.18.7 - Add linux-custom_6.18.7.bb recipe - Update PREFERRED_VERSION_linux-custom to 6.18.7 - Copy defconfig from 6.17 with TDX DMA patch still applied --- meta-dstack/conf/distro/dstack.conf | 2 +- .../recipes-kernel/linux/files/6.18/defconfig | 359 ++++++++++++++++++ .../linux/linux-custom_6.18.7.bb | 36 ++ 3 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 meta-dstack/recipes-kernel/linux/files/6.18/defconfig create mode 100644 meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 4142d0f..86873c9 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -9,7 +9,7 @@ DISTROOVERRIDES = "poky:dstack" INITRAMFS_IMAGE = "" PREFERRED_PROVIDER_virtual/kernel = "linux-custom" -PREFERRED_VERSION_linux-custom ?= "6.17.6" +PREFERRED_VERSION_linux-custom ?= "6.18.7" LINUX_KERNEL_TYPE = "tiny" MACHINE_FEATURES += "numa" diff --git a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig new file mode 100644 index 0000000..7c03fce --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig @@ -0,0 +1,359 @@ +CONFIG_LOCALVERSION="-dstack" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZMA=y +CONFIG_KERNEL_GZIP=y +CONFIG_DMA_COHERENT_POOL=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_DEBUG=y +CONFIG_USER_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_SMP=y +CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_INTEL_TDX_GUEST=y +CONFIG_TDX_GUEST_DRIVER=y +CONFIG_TSM_REPORTS=y +CONFIG_CONFIGFS_FS=y +CONFIG_NR_CPUS=512 +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_X86_CHECK_BIOS_CORRUPTION=y +CONFIG_EFI=y +CONFIG_EFI_STUB=y +CONFIG_HZ_1000=y +# CONFIG_SUSPEND is not set +# CONFIG_ACPI_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_INTEL_IDLE=y +CONFIG_IA32_EMULATION=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_XFRM_USER=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_INET_ESP=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES_COMPAT=y +CONFIG_NETFILTER_XTABLES_LEGACY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NETMAP=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_VS=m +CONFIG_NF_REJECT_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=y +CONFIG_6LOWPAN=m +CONFIG_NET_SCHED=y +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y +CONFIG_HYPERV_VSOCKETS=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_CFG80211=m +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCI_MSI=y +CONFIG_PCI_IOV=y +CONFIG_PCI_HYPERV=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_COHERENT_POOL=y +CONFIG_CMA=y +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_CMA_SIZE_MBYTES=64 +CONFIG_DMA_CMA=y +CONFIG_GVE=y +CONFIG_SWIOTLB_DYNAMIC=y +CONFIG_ZONE_DMA=y +CONFIG_CONNECTOR=y +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=1 +CONFIG_BLK_DEV_RAM_SIZE=6144 +CONFIG_VIRTIO_BLK=y +CONFIG_BLK_DEV_NVME=y +CONFIG_EEPROM_AT24=m +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_SCSI_FC_ATTRS=y +CONFIG_SCSI_VIRTIO=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_ATA_PIIX=y +CONFIG_PATA_SCH=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_WIREGUARD=y +CONFIG_IPVLAN=m +CONFIG_VXLAN=y +CONFIG_NETCONSOLE=y +CONFIG_TUN=m +CONFIG_VETH=y +CONFIG_VIRTIO_NET=y +CONFIG_TYPHOON=m +CONFIG_PCNET32=m +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL1C=m +CONFIG_ALX=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_BNXT=m +CONFIG_DL2K=m +CONFIG_E100=y +CONFIG_E1000=y +CONFIG_E1000E=y +CONFIG_IGB=y +CONFIG_IGBVF=m +CONFIG_IGC=m +CONFIG_JME=m +CONFIG_SKGE=m +CONFIG_SKY2=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_R8169=m +CONFIG_REALTEK_PHY_HWMON=y +CONFIG_USB_NET_DRIVERS=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_KC2190=y +# CONFIG_WLAN is not set +CONFIG_HYPERV_NET=y +CONFIG_ISDN=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_PRINTER=m +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HPET=y +CONFIG_TCG_TPM=y +CONFIG_TCG_TPM2_HMAC=y +CONFIG_TCG_TIS=y +CONFIG_TCG_CRB=y +CONFIG_I2C_I801=y +CONFIG_WATCHDOG=y +CONFIG_BCMA=m +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_AGP=y +CONFIG_AGP_INTEL=y +CONFIG_DRM=y +CONFIG_DRM_I915=m +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_DRM_CIRRUS_QEMU=m +CONFIG_FB=y +CONFIG_FB_UVESA=m +CONFIG_FB_EFI=y +CONFIG_FB_HYPERV=y +CONFIG_HID_HYPERV_MOUSE=y +CONFIG_HID_WACOM=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CONSOLE=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_EZUSB_FX2=y +CONFIG_RTC_CLASS=y +CONFIG_VIRT_DRIVERS=y +CONFIG_EFI_SECRET=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=y +CONFIG_HYPERV=y +CONFIG_HYPERV_UTILS=y +CONFIG_HYPERV_BALLOON=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=y +CONFIG_ISO9660_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_SQUASHFS=y +CONFIG_VXFS_FS=m +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_9P_FS=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AES_TI=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_CRYPTO_AES_NI_INTEL=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_CORDIC=m +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_UNWINDER_FRAME_POINTER=y + +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y diff --git a/meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb b/meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb new file mode 100644 index 0000000..96c0f7a --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb @@ -0,0 +1,36 @@ +SUMMARY = "dstack Linux kernel 6.18.7 built from tarball" +DESCRIPTION = "Custom dstack kernel based on upstream Linux 6.18.7 with tiny Kconfig baseline tuned for TDX guests" +SECTION = "kernel" +LICENSE = "GPL-2.0-only" +LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" + +PV = "6.18.7" +LINUX_VERSION = "${PV}" + +inherit kernel + +FILESEXTRAPATHS:prepend := "${THISDIR}/files/6.18:${THISDIR}/files:" + +DEPENDS += "libyaml-native openssl-native util-linux-native elfutils-native" + +SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${PV}.tar.xz;downloadfilename=linux-${PV}.tar.xz \ + file://defconfig \ + file://0001-x86-tdx-select-dma-direct-remap.patch \ +" + +SRC_URI[sha256sum] = "b726a4d15cf9ae06219b56d87820776e34d89fbc137e55fb54a9b9c3015b8f1e" + +S = "${UNPACKDIR}/linux-${PV}" + +LINUX_VERSION_EXTENSION = "-dstack" +KERNEL_VERSION_EXTENSION = "-dstack" + +# Enable BTF debug info for bpftool and out-of-tree modules (ZFS, WireGuard, etc.) +KERNEL_DEBUG = "True" + +# Keep packaging aligned with our tiny x86_64 guest machines. +COMPATIBLE_MACHINE = "(tdx|sev-snp|qemux86-64)" + +do_deploy:append() { + install -m 0644 ${B}/.config ${DEPLOYDIR}/kernel-config +} From 7cf15f5313345147ead01c3bf4a47fbe4d9a3809 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 23 Jan 2026 01:01:30 +0000 Subject: [PATCH 074/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 702740d..5b3fa9a 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 702740d49a4d67d0ce186ed7afaf1e09adc6aeb6 +Subproject commit 5b3fa9a1a34ef69e6785742ee0cd9ddb995594f9 From f9db23adffc5eae2fa08397e107d0ec2b20b37a0 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 27 Jan 2026 06:58:36 +0000 Subject: [PATCH 075/119] feat: Enable systemd socket proxy for dstack backward compatibility - Add systemd-socket-proxyd subpackage to avoid pulling full systemd-extra-utils - Add systemd-extra-utils to BAD_RECOMMENDATIONS - Install dstack-socket.socket/service and tappd-socket.socket/service for backward compatibility with containers mounting socket files directly --- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 8 ++++++-- meta-dstack/recipes-core/systemd/systemd_%.bbappend | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 50362e4..282595c 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -11,14 +11,14 @@ SRC_DIR = '${REPO_ROOT}/dstack' S = "${UNPACKDIR}/dstack" -RDEPENDS:${PN} += "bash" +RDEPENDS:${PN} += "bash systemd-socket-proxyd" DEPENDS += "rsync-native" # Ensure rsync-native is built before unpack runs do_unpack[depends] += "rsync-native:do_populate_sysroot" -DSTACK_SERVICES = "dstack-guest-agent.service dstack-prepare.service app-compose.service wg-checker.service" +DSTACK_SERVICES = "dstack-guest-agent.service dstack-prepare.service app-compose.service wg-checker.service dstack-socket.socket dstack-socket.service tappd-socket.socket tappd-socket.service" SYSTEMD_PACKAGES = "${@bb.utils.contains('DISTRO_FEATURES','systemd','${PN}','',d)}" SYSTEMD_SERVICE:${PN} = "${@bb.utils.contains('DISTRO_FEATURES','systemd','${DSTACK_SERVICES}','',d)}" SYSTEMD_AUTO_ENABLE:${PN} = "enable" @@ -76,6 +76,10 @@ do_install() { install -m 0644 ${S}/basefiles/dstack-prepare.service ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/app-compose.service ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/wg-checker.service ${D}${systemd_system_unitdir} + install -m 0644 ${S}/basefiles/dstack-socket.socket ${D}${systemd_system_unitdir} + install -m 0644 ${S}/basefiles/dstack-socket.service ${D}${systemd_system_unitdir} + install -m 0644 ${S}/basefiles/tappd-socket.socket ${D}${systemd_system_unitdir} + install -m 0644 ${S}/basefiles/tappd-socket.service ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/llmnr.conf ${D}${sysconfdir}/systemd/resolved.conf.d install -d ${D}${sysconfdir}/systemd/system/docker.service.d install -m 0644 ${S}/basefiles/docker.service.d/* ${D}${sysconfdir}/systemd/system/docker.service.d/ diff --git a/meta-dstack/recipes-core/systemd/systemd_%.bbappend b/meta-dstack/recipes-core/systemd/systemd_%.bbappend index 7c1ea90..041ce6c 100644 --- a/meta-dstack/recipes-core/systemd/systemd_%.bbappend +++ b/meta-dstack/recipes-core/systemd/systemd_%.bbappend @@ -19,3 +19,9 @@ EOF SYSTEMD_SERVICE:${PN}-vconsole-setup = "" PACKAGECONFIG:remove = "sysvinit logind" + +# Create a minimal package with only systemd-socket-proxyd +# This avoids pulling in all of systemd-extra-utils +PACKAGES =+ "${PN}-socket-proxyd" +FILES:${PN}-socket-proxyd = "${nonarch_libdir}/systemd/systemd-socket-proxyd" +RDEPENDS:${PN}-socket-proxyd = "${PN}" From 7d30c7b769aac274e64b2bf9881aaceaf2e9e26f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 27 Jan 2026 13:44:18 +0000 Subject: [PATCH 076/119] Add ephemeral-docker.sh --- dstack | 2 +- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dstack b/dstack index 5b3fa9a..cd158f1 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 5b3fa9a1a34ef69e6785742ee0cd9ddb995594f9 +Subproject commit cd158f1dc47d4addf5e220b13f2bacee714d7486 diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index 282595c..cbeb672 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -60,6 +60,7 @@ do_install() { install -m 0755 ${CARGO_BINDIR}/dstack-util ${D}${bindir} install -m 0755 ${CARGO_BINDIR}/dstack-guest-agent ${D}${bindir} install -m 0755 ${S}/basefiles/dstack-prepare.sh ${D}${bindir} + install -m 0755 ${S}/basefiles/ephemeral-docker.sh ${D}${bindir} install -m 0755 ${S}/basefiles/wg-checker.sh ${D}${bindir} install -m 0755 ${S}/basefiles/app-compose.sh ${D}${bindir} install -m 0755 ${S}/docker-daemon.json ${D}${sysconfdir}/docker/daemon.json From 83f8d58b02d0290f3fa9ef392cfd4a7b4be88832 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 29 Jan 2026 05:13:40 +0000 Subject: [PATCH 077/119] fix(dstack-cloud): fix env encryption format for CVM decryption - Write .encrypted-env as binary instead of hex text - Serialize env vars as key/value pair array matching CVM's expected format - Change _encrypt_env return type from str (hex) to bytes (raw) --- scripts/bin/dstack-cloud | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index f6c92e6..7c110b8 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -1159,7 +1159,7 @@ class CloudDeploymentManager: # Save to shared/.encrypted-env encrypted_file = shared_dir / ".encrypted-env" - with open(encrypted_file, 'w') as f: + with open(encrypted_file, 'wb') as f: f.write(encrypted_env) logger.info(f"Encrypted {app.env_file} -> {encrypted_file}") else: @@ -1436,7 +1436,7 @@ class CloudDeploymentManager: envs[key.strip()] = value.strip() return envs - def _encrypt_env(self, envs: Dict[str, str], hex_public_key: str) -> str: + def _encrypt_env(self, envs: Dict[str, str], hex_public_key: str) -> bytes: """ Encrypt environment variables using X25519 key exchange and AES-GCM. @@ -1445,7 +1445,7 @@ class CloudDeploymentManager: hex_public_key: Remote encryption public key in hexadecimal format Returns: - Hex string of (ephemeral public key || IV || ciphertext) + Raw bytes of (ephemeral public key || IV || ciphertext) """ if not CRYPTO_AVAILABLE: raise ImportError( @@ -1453,8 +1453,9 @@ class CloudDeploymentManager: "pip install cryptography eth-keys 'eth-hash[pycryptodome]'" ) - # Serialize environment variables to JSON - envs_json = json.dumps({"env": envs}).encode("utf-8") + # Serialize environment variables to JSON (format: {"env": [{"key": k, "value": v}, ...]}) + env_pairs = [{"key": k, "value": v} for k, v in envs.items()] + envs_json = json.dumps({"env": env_pairs}).encode("utf-8") # Remove "0x" prefix if present if hex_public_key.startswith("0x"): @@ -1484,7 +1485,7 @@ class CloudDeploymentManager: # Combine ephemeral public key, IV, and ciphertext result = ephemeral_public_bytes + iv + ciphertext - return result.hex() + return result def _get_app_encrypt_pub_key(self, app_id: str, kms_url: str) -> str: """Get encryption public key for the specified app_id from KMS.""" From 6da8d8623c9bb4756e8f46b79df622efc39225e5 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 29 Jan 2026 05:16:30 +0000 Subject: [PATCH 078/119] feat: built-in systemd socket activation for dstack-guest-agent Remove dependency on systemd-socket-proxyd by using native socket activation in dstack-guest-agent. Replace separate socket/service proxy units with a single dstack-guest-agent.socket unit. --- dstack | 2 +- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/dstack b/dstack index cd158f1..a046ae9 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit cd158f1dc47d4addf5e220b13f2bacee714d7486 +Subproject commit a046ae985b1971d6751e3a823f31e5dd545263de diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index cbeb672..fc70f71 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -11,14 +11,14 @@ SRC_DIR = '${REPO_ROOT}/dstack' S = "${UNPACKDIR}/dstack" -RDEPENDS:${PN} += "bash systemd-socket-proxyd" +RDEPENDS:${PN} += "bash" DEPENDS += "rsync-native" # Ensure rsync-native is built before unpack runs do_unpack[depends] += "rsync-native:do_populate_sysroot" -DSTACK_SERVICES = "dstack-guest-agent.service dstack-prepare.service app-compose.service wg-checker.service dstack-socket.socket dstack-socket.service tappd-socket.socket tappd-socket.service" +DSTACK_SERVICES = "dstack-guest-agent.service dstack-guest-agent.socket dstack-prepare.service app-compose.service wg-checker.service" SYSTEMD_PACKAGES = "${@bb.utils.contains('DISTRO_FEATURES','systemd','${PN}','',d)}" SYSTEMD_SERVICE:${PN} = "${@bb.utils.contains('DISTRO_FEATURES','systemd','${DSTACK_SERVICES}','',d)}" SYSTEMD_AUTO_ENABLE:${PN} = "enable" @@ -77,10 +77,7 @@ do_install() { install -m 0644 ${S}/basefiles/dstack-prepare.service ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/app-compose.service ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/wg-checker.service ${D}${systemd_system_unitdir} - install -m 0644 ${S}/basefiles/dstack-socket.socket ${D}${systemd_system_unitdir} - install -m 0644 ${S}/basefiles/dstack-socket.service ${D}${systemd_system_unitdir} - install -m 0644 ${S}/basefiles/tappd-socket.socket ${D}${systemd_system_unitdir} - install -m 0644 ${S}/basefiles/tappd-socket.service ${D}${systemd_system_unitdir} + install -m 0644 ${S}/basefiles/dstack-guest-agent.socket ${D}${systemd_system_unitdir} install -m 0644 ${S}/basefiles/llmnr.conf ${D}${sysconfdir}/systemd/resolved.conf.d install -d ${D}${sysconfdir}/systemd/system/docker.service.d install -m 0644 ${S}/basefiles/docker.service.d/* ${D}${sysconfdir}/systemd/system/docker.service.d/ From cb2c347802908fa8f5e97ab25c9cc247e900a5b0 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 29 Jan 2026 15:09:39 +0000 Subject: [PATCH 079/119] Move docker daemon config from package to image level The docker daemon.json is an image-level concern, not a package-level one. Package recipes can't access image-level variables like IMAGE_INSTALL, so the nvidia condition in dstack-guest.bb never worked. Use a DOCKER_DAEMON_JSON variable in dstack-rootfs-base.inc that nvidia inc can simply override. --- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 8 -------- meta-dstack/recipes-core/images/dstack-rootfs-base.inc | 8 ++++++++ meta-dstack/recipes-core/images/dstack-rootfs-nvidia.inc | 2 ++ .../files/docker-daemon-nvidia.json | 0 .../{dstack-guest => images}/files/docker-daemon.json | 0 5 files changed, 10 insertions(+), 8 deletions(-) rename meta-dstack/recipes-core/{dstack-guest => images}/files/docker-daemon-nvidia.json (100%) rename meta-dstack/recipes-core/{dstack-guest => images}/files/docker-daemon.json (100%) diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index fc70f71..be680ff 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -29,12 +29,6 @@ inherit cargo_bin do_unpack() { mkdir -p ${S} rsync -a --exclude="target" ${SRC_DIR}/ ${S}/ - - if ${@bb.utils.contains('IMAGE_INSTALL', 'nvidia-container-toolkit', 'true', 'false', d)}; then - cp ${THISDIR}/files/docker-daemon-nvidia.json ${S}/docker-daemon.json - else - cp ${THISDIR}/files/docker-daemon.json ${S}/docker-daemon.json - fi } # Force the configure task to run every time to detect source changes @@ -55,7 +49,6 @@ do_compile[network] = "1" do_install() { install -d ${D}${bindir} - install -d ${D}${sysconfdir}/docker install -d ${D}${sysconfdir}/systemd/journald.conf.d install -m 0755 ${CARGO_BINDIR}/dstack-util ${D}${bindir} install -m 0755 ${CARGO_BINDIR}/dstack-guest-agent ${D}${bindir} @@ -63,7 +56,6 @@ do_install() { install -m 0755 ${S}/basefiles/ephemeral-docker.sh ${D}${bindir} install -m 0755 ${S}/basefiles/wg-checker.sh ${D}${bindir} install -m 0755 ${S}/basefiles/app-compose.sh ${D}${bindir} - install -m 0755 ${S}/docker-daemon.json ${D}${sysconfdir}/docker/daemon.json install -m 0644 ${S}/basefiles/journald.conf ${D}${sysconfdir}/systemd/journald.conf.d/dstack.conf install -d ${D}${sysconfdir}/ diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 09605e8..99ca19e 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -66,6 +66,7 @@ ROOTFS_POSTPROCESS_COMMAND += "remove_sysvinit_files;" ROOTFS_POSTPROCESS_COMMAND += "symlink_lib64;" IMAGE_FEATURES[validitems] += "nologin" ROOTFS_POSTPROCESS_COMMAND += '${@bb.utils.contains_any("IMAGE_FEATURES", [ 'nologin' ], "disable_login", "",d)}' +ROOTFS_POSTPROCESS_COMMAND += "install_docker_config;" ROOTFS_POSTPROCESS_COMMAND += "mkdirs;" @@ -135,6 +136,13 @@ disable_login() { > ${IMAGE_ROOTFS}/etc/securetty } +DOCKER_DAEMON_JSON ?= "${THISDIR}/files/docker-daemon.json" + +install_docker_config() { + install -d ${IMAGE_ROOTFS}${sysconfdir}/docker + install -m 0644 ${DOCKER_DAEMON_JSON} ${IMAGE_ROOTFS}${sysconfdir}/docker/daemon.json +} + mkdirs() { mkdir -p ${IMAGE_ROOTFS}/dev mkdir -p ${IMAGE_ROOTFS}/proc diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-nvidia.inc b/meta-dstack/recipes-core/images/dstack-rootfs-nvidia.inc index 3dc7883..2b2355b 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-nvidia.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-nvidia.inc @@ -10,3 +10,5 @@ NVIDIA_GROUP = "acpid \ " KERNEL_MODULE_AUTOLOAD:append = " nvidia nvidia-drm nvidia-modeset nvidia-uvm video" IMAGE_INSTALL:append = " ${NVIDIA_GROUP}" + +DOCKER_DAEMON_JSON = "${THISDIR}/files/docker-daemon-nvidia.json" diff --git a/meta-dstack/recipes-core/dstack-guest/files/docker-daemon-nvidia.json b/meta-dstack/recipes-core/images/files/docker-daemon-nvidia.json similarity index 100% rename from meta-dstack/recipes-core/dstack-guest/files/docker-daemon-nvidia.json rename to meta-dstack/recipes-core/images/files/docker-daemon-nvidia.json diff --git a/meta-dstack/recipes-core/dstack-guest/files/docker-daemon.json b/meta-dstack/recipes-core/images/files/docker-daemon.json similarity index 100% rename from meta-dstack/recipes-core/dstack-guest/files/docker-daemon.json rename to meta-dstack/recipes-core/images/files/docker-daemon.json From 0db86d15099dcb9116f1fd41fba1a39c3a0b5aaf Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 5 Feb 2026 02:03:09 +0000 Subject: [PATCH 080/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index a046ae9..17c23e2 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit a046ae985b1971d6751e3a823f31e5dd545263de +Subproject commit 17c23e2b6bfa3ffcdd929b7aad9095930b906d32 From b12b5c6b54ace0dc99724030f0059e0b21e3fe2c Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 2 Feb 2026 06:12:25 +0000 Subject: [PATCH 081/119] feat(guest): install conntrack sysctl config into CVM --- meta-dstack/recipes-core/dstack-guest/dstack-guest.bb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb index be680ff..2996bca 100644 --- a/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb +++ b/meta-dstack/recipes-core/dstack-guest/dstack-guest.bb @@ -61,6 +61,9 @@ do_install() { install -d ${D}${sysconfdir}/ install -m 0644 ${S}/basefiles/tdx-attest.conf ${D}${sysconfdir}/tdx-attest.conf + install -d ${D}${sysconfdir}/sysctl.d + install -m 0644 ${S}/basefiles/sysctl.d/99-dstack.conf ${D}${sysconfdir}/sysctl.d/99-dstack.conf + if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then install -d ${D}${systemd_system_unitdir} \ ${D}${sysconfdir}/systemd/resolved.conf.d From 5d6a81ff526164303fafc4a027d80b865d98df81 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sat, 7 Feb 2026 17:08:51 +0000 Subject: [PATCH 082/119] feat(guest): add sysbox container runtime v0.6.7 Add Nestybox Sysbox as an alternative container runtime, enabling rootless containers to run workloads like Systemd, Docker, Kubernetes, just like VMs. Recipe builds sysbox-runc, sysbox-fs, and sysbox-mgr from source with reproducible builds verified (identical binaries across clean builds). Key design decisions: - Network access only in do_configure (go mod vendor); do_compile is fully offline with -mod=vendor - Pre-generated protobuf .pb.go files to avoid protoc build dependency - Orphaned bazil/fuse commit forked to Dstack-TEE/fuse with named branch - Kernel configs already present in linux-custom defconfig - Docker daemon configured with sysbox-runc runtime - Adapted for Yocto 5.3: UNPACKDIR for source paths, WORKDIR for build artifacts --- .../dstack-sysbox/dstack-sysbox_0.6.7.bb | 172 + .../dstack-sysbox/files/50-sysbox-mod.conf | 1 + .../dstack-sysbox/files/99-sysbox-sysctl.conf | 7 + .../dstack-sysbox/files/sysbox-fs.service | 18 + .../dstack-sysbox/files/sysbox-mgr.service | 17 + .../dstack-sysbox/files/sysbox.service | 13 + .../files/sysboxFsProtobuf.pb.go | 703 ++++ .../files/sysboxMgrProtobuf.pb.go | 3203 +++++++++++++++++ .../images/dstack-rootfs-base.inc | 1 + .../images/files/docker-daemon-nvidia.json | 3 + .../images/files/docker-daemon.json | 5 + .../linux/files/dstack-sysbox.cfg | 2 + .../linux/files/dstack-sysbox.scc | 3 + .../linux/linux-yocto%.bbappend | 3 + 14 files changed, 4151 insertions(+) create mode 100644 meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/50-sysbox-mod.conf create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/sysboxFsProtobuf.pb.go create mode 100644 meta-dstack/recipes-core/dstack-sysbox/files/sysboxMgrProtobuf.pb.go create mode 100644 meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg create mode 100644 meta-dstack/recipes-kernel/linux/files/dstack-sysbox.scc diff --git a/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb b/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb new file mode 100644 index 0000000..a8dddd0 --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb @@ -0,0 +1,172 @@ +SUMMARY = "Sysbox container runtime" +DESCRIPTION = "An open-source, next-generation runc that empowers rootless containers \ +to run workloads such as Systemd, Docker, Kubernetes, just like VMs." +HOMEPAGE = "https://github.com/nestybox/sysbox" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=cf0915b5e4f1337cf5b929ba1e388c42" + +SYSBOX_VERSION = "0.6.7" + +# Pin all submodule revisions from the v0.6.7 tag for reproducibility. +SRCREV_sysbox = "3a69811f54f8f83264ebb36dcaf51708e80b9e84" +SRCREV_sysbox-runc = "c58eba1be027c762c495bc4eeba7c0984beda1ab" +SRCREV_sysbox-fs = "6a8d71f54e7570e5297af89ff24ed3bafa61659f" +SRCREV_sysbox-mgr = "aaeff6c5dc70c137e62166474a309ca5fc42d044" +SRCREV_sysbox-ipc = "f05151f4b4c1df63d7fd241577ca032905c1bd0e" +SRCREV_sysbox-libs = "6faf00c74d45f7bdff0d1930fe8590c17a2d0a8b" +# bazil/fuse commit 45cd9a3 is orphaned in nestybox/fuse (not on any branch/tag). +# We forked it to Dstack-TEE/fuse with a named branch so BitBake can fetch it. +SRCREV_sysbox-fuse = "45cd9a3d884448418546d8eaa54ee7d772e576d6" + +SRCREV_FORMAT = "sysbox" + +SRC_URI = " \ + git://github.com/nestybox/sysbox.git;nobranch=1;name=sysbox;protocol=https;destsuffix=sysbox \ + git://github.com/nestybox/sysbox-runc.git;nobranch=1;name=sysbox-runc;protocol=https;destsuffix=sysbox-runc \ + git://github.com/nestybox/sysbox-fs.git;nobranch=1;name=sysbox-fs;protocol=https;destsuffix=sysbox-fs \ + git://github.com/nestybox/sysbox-mgr.git;nobranch=1;name=sysbox-mgr;protocol=https;destsuffix=sysbox-mgr \ + git://github.com/nestybox/sysbox-ipc.git;nobranch=1;name=sysbox-ipc;protocol=https;destsuffix=sysbox-ipc \ + git://github.com/nestybox/sysbox-libs.git;nobranch=1;name=sysbox-libs;protocol=https;destsuffix=sysbox-libs \ + git://github.com/Dstack-TEE/fuse.git;branch=sysbox-v0.6.7;name=sysbox-fuse;protocol=https;destsuffix=sysbox-fuse \ + file://sysbox.service \ + file://sysbox-fs.service \ + file://sysbox-mgr.service \ + file://99-sysbox-sysctl.conf \ + file://50-sysbox-mod.conf \ + file://sysboxFsProtobuf.pb.go \ + file://sysboxMgrProtobuf.pb.go \ +" + +S = "${UNPACKDIR}/sysbox" + +PV = "${SYSBOX_VERSION}+git${SRCPV}" + +DEPENDS += "libseccomp" +RDEPENDS:${PN} += "libseccomp" + +inherit go goarch pkgconfig systemd + +GO_IMPORT = "github.com/nestybox/sysbox" + +SYSBOX_LDFLAGS = " \ + -X 'main.edition=Community Edition (CE)' \ + -X main.version=${SYSBOX_VERSION} \ + -X main.commitId=${SRCREV_sysbox} \ + -X 'main.builtAt=1970-01-01T00:00:00Z' \ + -X 'main.builtBy=dstack' \ +" + +# Kernel >= 5.12 supports idmapped mounts +SYSBOX_RUNC_BUILDTAGS = "seccomp idmapped_mnt" +SYSBOX_MGR_BUILDTAGS = "idmapped_mnt" + +do_configure() { + # Arrange the source tree so that go.mod replace directives work. + # All components expect to find siblings in ../ relative to themselves. + # The git fetcher places them in ${UNPACKDIR}/sysbox-{runc,fs,mgr,ipc,libs}. + # This is already the correct layout since they are all at the same level + # under ${UNPACKDIR}. + + # sysbox-fs expects a 'bazil' subdirectory (submodule of nestybox/fuse). + # Remove the empty submodule placeholder left by git checkout, then symlink. + rm -rf ${UNPACKDIR}/sysbox-fs/bazil + ln -sfn ${UNPACKDIR}/sysbox-fuse ${UNPACKDIR}/sysbox-fs/bazil + + # Install pre-generated protobuf Go files. The upstream repo only ships + # .proto files and expects protoc + protoc-gen-go at build time. We + # pre-generate them to avoid the protoc native toolchain dependency. + install -m 0644 ${UNPACKDIR}/sysboxFsProtobuf.pb.go \ + ${UNPACKDIR}/sysbox-ipc/sysboxFsGrpc/sysboxFsProtobuf/ + install -m 0644 ${UNPACKDIR}/sysboxMgrProtobuf.pb.go \ + ${UNPACKDIR}/sysbox-ipc/sysboxMgrGrpc/sysboxMgrProtobuf/ + + # Vendor dependencies for each component so that do_compile needs no + # network access. go.sum in each repo guarantees content integrity. + # Use -modcacherw so cached modules are writable (BitBake needs to + # clean ${B}/pkg/mod between tasks). + for mod in sysbox-runc sysbox-fs sysbox-mgr; do + cd ${UNPACKDIR}/$mod + ${GO} mod vendor -modcacherw + done +} + +do_configure[network] = "1" + +do_compile() { + export CGO_ENABLED="1" + export CGO_CFLAGS="${CFLAGS} --sysroot=${STAGING_DIR_TARGET}" + export CGO_LDFLAGS="${LDFLAGS} -Wl,--build-id=none --sysroot=${STAGING_DIR_TARGET}" + export CFLAGS="" + export LDFLAGS="" + + # Set reproducible build environment + export SOURCE_DATE_EPOCH=0 + export TZ=UTC + + # Build sysbox-runc + cd ${UNPACKDIR}/sysbox-runc + ${GO} build -mod=vendor -buildvcs=false -trimpath \ + -tags "${SYSBOX_RUNC_BUILDTAGS}" \ + -ldflags "-buildid= -s -w -linkmode external -extldflags '-Wl,--build-id=none' ${SYSBOX_LDFLAGS}" \ + -o ${WORKDIR}/sysbox-runc-bin . + + # Build sysbox-fs + cd ${UNPACKDIR}/sysbox-fs + ${GO} build -mod=vendor -buildvcs=false -trimpath \ + -ldflags "-buildid= -s -w -linkmode external -extldflags '-Wl,--build-id=none' ${SYSBOX_LDFLAGS}" \ + -o ${WORKDIR}/sysbox-fs-bin ./cmd/sysbox-fs + + # Build sysbox-mgr + cd ${UNPACKDIR}/sysbox-mgr + ${GO} build -mod=vendor -buildvcs=false -trimpath \ + -tags "${SYSBOX_MGR_BUILDTAGS}" \ + -ldflags "-buildid= -s -w -linkmode external -extldflags '-Wl,--build-id=none' ${SYSBOX_LDFLAGS}" \ + -o ${WORKDIR}/sysbox-mgr-bin . +} + +do_install() { + # Install binaries + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/sysbox-runc-bin ${D}${bindir}/sysbox-runc + install -m 0755 ${WORKDIR}/sysbox-fs-bin ${D}${bindir}/sysbox-fs + install -m 0755 ${WORKDIR}/sysbox-mgr-bin ${D}${bindir}/sysbox-mgr + + # Install systemd services + if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${UNPACKDIR}/sysbox.service ${D}${systemd_system_unitdir} + install -m 0644 ${UNPACKDIR}/sysbox-fs.service ${D}${systemd_system_unitdir} + install -m 0644 ${UNPACKDIR}/sysbox-mgr.service ${D}${systemd_system_unitdir} + fi + + # Install sysctl config + install -d ${D}${sysconfdir}/sysctl.d + install -m 0644 ${UNPACKDIR}/99-sysbox-sysctl.conf ${D}${sysconfdir}/sysctl.d/ + + # Install module autoload config + install -d ${D}${sysconfdir}/modules-load.d + install -m 0644 ${UNPACKDIR}/50-sysbox-mod.conf ${D}${sysconfdir}/modules-load.d/ + + # Create sysbox data directory + install -d ${D}/var/lib/sysbox +} + +SYSTEMD_PACKAGES = "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${PN}', '', d)}" +SYSTEMD_SERVICE:${PN} = "sysbox.service sysbox-fs.service sysbox-mgr.service" +SYSTEMD_AUTO_ENABLE:${PN} = "enable" + +FILES:${PN} += " \ + ${bindir}/sysbox-runc \ + ${bindir}/sysbox-fs \ + ${bindir}/sysbox-mgr \ + ${systemd_system_unitdir}/sysbox.service \ + ${systemd_system_unitdir}/sysbox-fs.service \ + ${systemd_system_unitdir}/sysbox-mgr.service \ + ${sysconfdir}/sysctl.d/99-sysbox-sysctl.conf \ + ${sysconfdir}/modules-load.d/50-sysbox-mod.conf \ + /var/lib/sysbox \ +" + +INSANE_SKIP:${PN} += "ldflags already-stripped" + +COMPATIBLE_HOST = "x86_64.*-linux" diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/50-sysbox-mod.conf b/meta-dstack/recipes-core/dstack-sysbox/files/50-sysbox-mod.conf new file mode 100644 index 0000000..214e86b --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/50-sysbox-mod.conf @@ -0,0 +1 @@ +configfs diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf b/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf new file mode 100644 index 0000000..96c18ee --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf @@ -0,0 +1,7 @@ +kernel.unprivileged_userns_clone = 1 +fs.inotify.max_queued_events = 1048576 +fs.inotify.max_user_watches = 1048576 +fs.inotify.max_user_instances = 1048576 +kernel.keys.maxkeys = 20000 +kernel.keys.maxbytes = 1400000 +kernel.pid_max = 4194304 diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service new file mode 100644 index 0000000..3ce213b --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service @@ -0,0 +1,18 @@ +[Unit] +Description=sysbox-fs (part of the Sysbox container runtime) +PartOf=sysbox.service +After=sysbox-mgr.service + +[Service] +Type=notify +ExecStart=/usr/bin/sysbox-fs --log /var/log/sysbox-fs.log +TimeoutStartSec=10 +TimeoutStopSec=10 +StartLimitInterval=0 +NotifyAccess=main +OOMScoreAdjust=-500 +LimitNOFILE=infinity +LimitNPROC=infinity + +[Install] +WantedBy=sysbox.service diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service new file mode 100644 index 0000000..11dbd12 --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service @@ -0,0 +1,17 @@ +[Unit] +Description=sysbox-mgr (part of the Sysbox container runtime) +PartOf=sysbox.service + +[Service] +Type=notify +ExecStart=/usr/bin/sysbox-mgr --log /var/log/sysbox-mgr.log +TimeoutStartSec=45 +TimeoutStopSec=90 +StartLimitInterval=0 +NotifyAccess=main +OOMScoreAdjust=-500 +LimitNOFILE=infinity +LimitNPROC=infinity + +[Install] +WantedBy=sysbox.service diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service new file mode 100644 index 0000000..55e15a5 --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service @@ -0,0 +1,13 @@ +[Unit] +Description=Sysbox container runtime +Documentation=https://github.com/nestybox/sysbox +BindsTo=sysbox-mgr.service sysbox-fs.service +After=sysbox-mgr.service sysbox-fs.service +Before=docker.service containerd.service + +[Service] +Type=exec +ExecStart=/bin/sh -c "/usr/bin/sysbox-runc --version && /usr/bin/sysbox-mgr --version && /usr/bin/sysbox-fs --version && /bin/sleep infinity" + +[Install] +WantedBy=multi-user.target diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysboxFsProtobuf.pb.go b/meta-dstack/recipes-core/dstack-sysbox/files/sysboxFsProtobuf.pb.go new file mode 100644 index 0000000..d3b0a66 --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysboxFsProtobuf.pb.go @@ -0,0 +1,703 @@ +// +// Sysbox-fs Protobuffer Definitions. +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v3.21.12 +// source: sysboxFsProtobuf.proto + +package sysboxFsProtobuf + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Request message sent by runC to sysbox-fs process during container +// registration, unregistration and update phases. +type ContainerData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` + InitPid int32 `protobuf:"varint,2,opt,name=InitPid,proto3" json:"InitPid,omitempty"` + Hostname string `protobuf:"bytes,3,opt,name=Hostname,proto3" json:"Hostname,omitempty"` + Ctime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=Ctime,proto3" json:"Ctime,omitempty"` + UidFirst int32 `protobuf:"varint,5,opt,name=UidFirst,proto3" json:"UidFirst,omitempty"` + UidSize int32 `protobuf:"varint,6,opt,name=UidSize,proto3" json:"UidSize,omitempty"` + GidFirst int32 `protobuf:"varint,7,opt,name=GidFirst,proto3" json:"GidFirst,omitempty"` + GidSize int32 `protobuf:"varint,8,opt,name=GidSize,proto3" json:"GidSize,omitempty"` + ProcRoPaths []string `protobuf:"bytes,9,rep,name=ProcRoPaths,proto3" json:"ProcRoPaths,omitempty"` + ProcMaskPaths []string `protobuf:"bytes,10,rep,name=ProcMaskPaths,proto3" json:"ProcMaskPaths,omitempty"` + Netns string `protobuf:"bytes,11,opt,name=Netns,proto3" json:"Netns,omitempty"` +} + +func (x *ContainerData) Reset() { + *x = ContainerData{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxFsProtobuf_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContainerData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContainerData) ProtoMessage() {} + +func (x *ContainerData) ProtoReflect() protoreflect.Message { + mi := &file_sysboxFsProtobuf_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContainerData.ProtoReflect.Descriptor instead. +func (*ContainerData) Descriptor() ([]byte, []int) { + return file_sysboxFsProtobuf_proto_rawDescGZIP(), []int{0} +} + +func (x *ContainerData) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ContainerData) GetInitPid() int32 { + if x != nil { + return x.InitPid + } + return 0 +} + +func (x *ContainerData) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +func (x *ContainerData) GetCtime() *timestamppb.Timestamp { + if x != nil { + return x.Ctime + } + return nil +} + +func (x *ContainerData) GetUidFirst() int32 { + if x != nil { + return x.UidFirst + } + return 0 +} + +func (x *ContainerData) GetUidSize() int32 { + if x != nil { + return x.UidSize + } + return 0 +} + +func (x *ContainerData) GetGidFirst() int32 { + if x != nil { + return x.GidFirst + } + return 0 +} + +func (x *ContainerData) GetGidSize() int32 { + if x != nil { + return x.GidSize + } + return 0 +} + +func (x *ContainerData) GetProcRoPaths() []string { + if x != nil { + return x.ProcRoPaths + } + return nil +} + +func (x *ContainerData) GetProcMaskPaths() []string { + if x != nil { + return x.ProcMaskPaths + } + return nil +} + +func (x *ContainerData) GetNetns() string { + if x != nil { + return x.Netns + } + return "" +} + +// Response message sent from sysbox-fs to runC process. +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=Success,proto3" json:"Success,omitempty"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxFsProtobuf_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_sysboxFsProtobuf_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_sysboxFsProtobuf_proto_rawDescGZIP(), []int{1} +} + +func (x *Response) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +type MountpointReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MountpointReq) Reset() { + *x = MountpointReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxFsProtobuf_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountpointReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountpointReq) ProtoMessage() {} + +func (x *MountpointReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxFsProtobuf_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountpointReq.ProtoReflect.Descriptor instead. +func (*MountpointReq) Descriptor() ([]byte, []int) { + return file_sysboxFsProtobuf_proto_rawDescGZIP(), []int{2} +} + +type MountpointResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mountpoint string `protobuf:"bytes,1,opt,name=Mountpoint,proto3" json:"Mountpoint,omitempty"` +} + +func (x *MountpointResp) Reset() { + *x = MountpointResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxFsProtobuf_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountpointResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountpointResp) ProtoMessage() {} + +func (x *MountpointResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxFsProtobuf_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountpointResp.ProtoReflect.Descriptor instead. +func (*MountpointResp) Descriptor() ([]byte, []int) { + return file_sysboxFsProtobuf_proto_rawDescGZIP(), []int{3} +} + +func (x *MountpointResp) GetMountpoint() string { + if x != nil { + return x.Mountpoint + } + return "" +} + +var File_sysboxFsProtobuf_proto protoreflect.FileDescriptor + +var file_sysboxFsProtobuf_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x73, 0x79, 0x73, 0x62, 0x6f, 0x78, 0x46, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0xd1, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x49, 0x6e, 0x69, 0x74, 0x50, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x49, 0x6e, 0x69, 0x74, 0x50, 0x69, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x43, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x43, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x55, 0x69, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x08, 0x55, 0x69, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x55, 0x69, 0x64, + 0x53, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x55, 0x69, 0x64, 0x53, + 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x47, 0x69, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x47, 0x69, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x12, + 0x18, 0x0a, 0x07, 0x47, 0x69, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x07, 0x47, 0x69, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x72, 0x6f, + 0x63, 0x52, 0x6f, 0x50, 0x61, 0x74, 0x68, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, + 0x50, 0x72, 0x6f, 0x63, 0x52, 0x6f, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x50, + 0x72, 0x6f, 0x63, 0x4d, 0x61, 0x73, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0a, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0d, 0x50, 0x72, 0x6f, 0x63, 0x4d, 0x61, 0x73, 0x6b, 0x50, 0x61, 0x74, 0x68, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x4e, 0x65, 0x74, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x4e, 0x65, 0x74, 0x6e, 0x73, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x0f, 0x0a, + 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x22, 0x30, + 0x0a, 0x0e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x32, 0xf9, 0x02, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x44, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d, 0x6f, + 0x75, 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, + 0x6e, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x49, 0x0a, + 0x18, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x72, 0x65, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x61, + 0x74, 0x61, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x48, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x55, 0x6e, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x44, 0x61, 0x74, 0x61, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0f, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x15, 0x5a, 0x13, + 0x2e, 0x2f, 0x3b, 0x73, 0x79, 0x73, 0x62, 0x6f, 0x78, 0x46, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_sysboxFsProtobuf_proto_rawDescOnce sync.Once + file_sysboxFsProtobuf_proto_rawDescData = file_sysboxFsProtobuf_proto_rawDesc +) + +func file_sysboxFsProtobuf_proto_rawDescGZIP() []byte { + file_sysboxFsProtobuf_proto_rawDescOnce.Do(func() { + file_sysboxFsProtobuf_proto_rawDescData = protoimpl.X.CompressGZIP(file_sysboxFsProtobuf_proto_rawDescData) + }) + return file_sysboxFsProtobuf_proto_rawDescData +} + +var file_sysboxFsProtobuf_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_sysboxFsProtobuf_proto_goTypes = []interface{}{ + (*ContainerData)(nil), // 0: protobuf.ContainerData + (*Response)(nil), // 1: protobuf.Response + (*MountpointReq)(nil), // 2: protobuf.MountpointReq + (*MountpointResp)(nil), // 3: protobuf.MountpointResp + (*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp +} +var file_sysboxFsProtobuf_proto_depIdxs = []int32{ + 4, // 0: protobuf.ContainerData.Ctime:type_name -> google.protobuf.Timestamp + 2, // 1: protobuf.sysboxStateChannel.GetMountpoint:input_type -> protobuf.MountpointReq + 0, // 2: protobuf.sysboxStateChannel.ContainerPreRegistration:input_type -> protobuf.ContainerData + 0, // 3: protobuf.sysboxStateChannel.ContainerRegistration:input_type -> protobuf.ContainerData + 0, // 4: protobuf.sysboxStateChannel.ContainerUnregistration:input_type -> protobuf.ContainerData + 0, // 5: protobuf.sysboxStateChannel.ContainerUpdate:input_type -> protobuf.ContainerData + 3, // 6: protobuf.sysboxStateChannel.GetMountpoint:output_type -> protobuf.MountpointResp + 1, // 7: protobuf.sysboxStateChannel.ContainerPreRegistration:output_type -> protobuf.Response + 1, // 8: protobuf.sysboxStateChannel.ContainerRegistration:output_type -> protobuf.Response + 1, // 9: protobuf.sysboxStateChannel.ContainerUnregistration:output_type -> protobuf.Response + 1, // 10: protobuf.sysboxStateChannel.ContainerUpdate:output_type -> protobuf.Response + 6, // [6:11] is the sub-list for method output_type + 1, // [1:6] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_sysboxFsProtobuf_proto_init() } +func file_sysboxFsProtobuf_proto_init() { + if File_sysboxFsProtobuf_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_sysboxFsProtobuf_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContainerData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxFsProtobuf_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxFsProtobuf_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountpointReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxFsProtobuf_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountpointResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_sysboxFsProtobuf_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_sysboxFsProtobuf_proto_goTypes, + DependencyIndexes: file_sysboxFsProtobuf_proto_depIdxs, + MessageInfos: file_sysboxFsProtobuf_proto_msgTypes, + }.Build() + File_sysboxFsProtobuf_proto = out.File + file_sysboxFsProtobuf_proto_rawDesc = nil + file_sysboxFsProtobuf_proto_goTypes = nil + file_sysboxFsProtobuf_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// SysboxStateChannelClient is the client API for SysboxStateChannel service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type SysboxStateChannelClient interface { + // Queries sysbox-fs for the FUSE mountpoint + GetMountpoint(ctx context.Context, in *MountpointReq, opts ...grpc.CallOption) (*MountpointResp, error) + // Generates a container-preregistration message + ContainerPreRegistration(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) + // Generates a container-registration message + ContainerRegistration(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) + // Generates a container-unregistration message + ContainerUnregistration(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) + // Generates a container-update message + ContainerUpdate(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) +} + +type sysboxStateChannelClient struct { + cc grpc.ClientConnInterface +} + +func NewSysboxStateChannelClient(cc grpc.ClientConnInterface) SysboxStateChannelClient { + return &sysboxStateChannelClient{cc} +} + +func (c *sysboxStateChannelClient) GetMountpoint(ctx context.Context, in *MountpointReq, opts ...grpc.CallOption) (*MountpointResp, error) { + out := new(MountpointResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxStateChannel/GetMountpoint", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxStateChannelClient) ContainerPreRegistration(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/protobuf.sysboxStateChannel/ContainerPreRegistration", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxStateChannelClient) ContainerRegistration(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/protobuf.sysboxStateChannel/ContainerRegistration", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxStateChannelClient) ContainerUnregistration(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/protobuf.sysboxStateChannel/ContainerUnregistration", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxStateChannelClient) ContainerUpdate(ctx context.Context, in *ContainerData, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/protobuf.sysboxStateChannel/ContainerUpdate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SysboxStateChannelServer is the server API for SysboxStateChannel service. +type SysboxStateChannelServer interface { + // Queries sysbox-fs for the FUSE mountpoint + GetMountpoint(context.Context, *MountpointReq) (*MountpointResp, error) + // Generates a container-preregistration message + ContainerPreRegistration(context.Context, *ContainerData) (*Response, error) + // Generates a container-registration message + ContainerRegistration(context.Context, *ContainerData) (*Response, error) + // Generates a container-unregistration message + ContainerUnregistration(context.Context, *ContainerData) (*Response, error) + // Generates a container-update message + ContainerUpdate(context.Context, *ContainerData) (*Response, error) +} + +// UnimplementedSysboxStateChannelServer can be embedded to have forward compatible implementations. +type UnimplementedSysboxStateChannelServer struct { +} + +func (*UnimplementedSysboxStateChannelServer) GetMountpoint(context.Context, *MountpointReq) (*MountpointResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMountpoint not implemented") +} +func (*UnimplementedSysboxStateChannelServer) ContainerPreRegistration(context.Context, *ContainerData) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContainerPreRegistration not implemented") +} +func (*UnimplementedSysboxStateChannelServer) ContainerRegistration(context.Context, *ContainerData) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContainerRegistration not implemented") +} +func (*UnimplementedSysboxStateChannelServer) ContainerUnregistration(context.Context, *ContainerData) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContainerUnregistration not implemented") +} +func (*UnimplementedSysboxStateChannelServer) ContainerUpdate(context.Context, *ContainerData) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContainerUpdate not implemented") +} + +func RegisterSysboxStateChannelServer(s *grpc.Server, srv SysboxStateChannelServer) { + s.RegisterService(&_SysboxStateChannel_serviceDesc, srv) +} + +func _SysboxStateChannel_GetMountpoint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MountpointReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxStateChannelServer).GetMountpoint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxStateChannel/GetMountpoint", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxStateChannelServer).GetMountpoint(ctx, req.(*MountpointReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxStateChannel_ContainerPreRegistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ContainerData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxStateChannelServer).ContainerPreRegistration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxStateChannel/ContainerPreRegistration", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxStateChannelServer).ContainerPreRegistration(ctx, req.(*ContainerData)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxStateChannel_ContainerRegistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ContainerData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxStateChannelServer).ContainerRegistration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxStateChannel/ContainerRegistration", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxStateChannelServer).ContainerRegistration(ctx, req.(*ContainerData)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxStateChannel_ContainerUnregistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ContainerData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxStateChannelServer).ContainerUnregistration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxStateChannel/ContainerUnregistration", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxStateChannelServer).ContainerUnregistration(ctx, req.(*ContainerData)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxStateChannel_ContainerUpdate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ContainerData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxStateChannelServer).ContainerUpdate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxStateChannel/ContainerUpdate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxStateChannelServer).ContainerUpdate(ctx, req.(*ContainerData)) + } + return interceptor(ctx, in, info, handler) +} + +var _SysboxStateChannel_serviceDesc = grpc.ServiceDesc{ + ServiceName: "protobuf.sysboxStateChannel", + HandlerType: (*SysboxStateChannelServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetMountpoint", + Handler: _SysboxStateChannel_GetMountpoint_Handler, + }, + { + MethodName: "ContainerPreRegistration", + Handler: _SysboxStateChannel_ContainerPreRegistration_Handler, + }, + { + MethodName: "ContainerRegistration", + Handler: _SysboxStateChannel_ContainerRegistration_Handler, + }, + { + MethodName: "ContainerUnregistration", + Handler: _SysboxStateChannel_ContainerUnregistration_Handler, + }, + { + MethodName: "ContainerUpdate", + Handler: _SysboxStateChannel_ContainerUpdate_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "sysboxFsProtobuf.proto", +} diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysboxMgrProtobuf.pb.go b/meta-dstack/recipes-core/dstack-sysbox/files/sysboxMgrProtobuf.pb.go new file mode 100644 index 0000000..1c0364d --- /dev/null +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysboxMgrProtobuf.pb.go @@ -0,0 +1,3203 @@ +// +// SysboxMgr Protobuffer Definitions. +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v3.21.12 +// source: sysboxMgrProtobuf.proto + +package sysboxMgrProtobuf + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type IDMapping struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerID uint32 `protobuf:"varint,1,opt,name=containerID,proto3" json:"containerID,omitempty"` + HostID uint32 `protobuf:"varint,2,opt,name=hostID,proto3" json:"hostID,omitempty"` + Size uint32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` +} + +func (x *IDMapping) Reset() { + *x = IDMapping{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IDMapping) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IDMapping) ProtoMessage() {} + +func (x *IDMapping) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IDMapping.ProtoReflect.Descriptor instead. +func (*IDMapping) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{0} +} + +func (x *IDMapping) GetContainerID() uint32 { + if x != nil { + return x.ContainerID + } + return 0 +} + +func (x *IDMapping) GetHostID() uint32 { + if x != nil { + return x.HostID + } + return 0 +} + +func (x *IDMapping) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +type RegisterReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Rootfs string `protobuf:"bytes,2,opt,name=rootfs,proto3" json:"rootfs,omitempty"` + Userns string `protobuf:"bytes,3,opt,name=userns,proto3" json:"userns,omitempty"` + Netns string `protobuf:"bytes,4,opt,name=netns,proto3" json:"netns,omitempty"` + UidMappings []*IDMapping `protobuf:"bytes,5,rep,name=uidMappings,proto3" json:"uidMappings,omitempty"` + GidMappings []*IDMapping `protobuf:"bytes,6,rep,name=gidMappings,proto3" json:"gidMappings,omitempty"` +} + +func (x *RegisterReq) Reset() { + *x = RegisterReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterReq) ProtoMessage() {} + +func (x *RegisterReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterReq.ProtoReflect.Descriptor instead. +func (*RegisterReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{1} +} + +func (x *RegisterReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RegisterReq) GetRootfs() string { + if x != nil { + return x.Rootfs + } + return "" +} + +func (x *RegisterReq) GetUserns() string { + if x != nil { + return x.Userns + } + return "" +} + +func (x *RegisterReq) GetNetns() string { + if x != nil { + return x.Netns + } + return "" +} + +func (x *RegisterReq) GetUidMappings() []*IDMapping { + if x != nil { + return x.UidMappings + } + return nil +} + +func (x *RegisterReq) GetGidMappings() []*IDMapping { + if x != nil { + return x.GidMappings + } + return nil +} + +type ContainerConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AliasDns bool `protobuf:"varint,1,opt,name=aliasDns,proto3" json:"aliasDns,omitempty"` + ShiftfsOk bool `protobuf:"varint,2,opt,name=ShiftfsOk,proto3" json:"ShiftfsOk,omitempty"` + ShiftfsOnOverlayfsOk bool `protobuf:"varint,3,opt,name=ShiftfsOnOverlayfsOk,proto3" json:"ShiftfsOnOverlayfsOk,omitempty"` + IDMapMountOk bool `protobuf:"varint,4,opt,name=IDMapMountOk,proto3" json:"IDMapMountOk,omitempty"` + OverlayfsOnIDMapMountOk bool `protobuf:"varint,5,opt,name=OverlayfsOnIDMapMountOk,proto3" json:"OverlayfsOnIDMapMountOk,omitempty"` + NoRootfsCloning bool `protobuf:"varint,6,opt,name=noRootfsCloning,proto3" json:"noRootfsCloning,omitempty"` + IgnoreSysfsChown bool `protobuf:"varint,7,opt,name=ignoreSysfsChown,proto3" json:"ignoreSysfsChown,omitempty"` + AllowTrustedXattr bool `protobuf:"varint,8,opt,name=allowTrustedXattr,proto3" json:"allowTrustedXattr,omitempty"` + HonorCaps bool `protobuf:"varint,9,opt,name=honorCaps,proto3" json:"honorCaps,omitempty"` + SyscontMode bool `protobuf:"varint,10,opt,name=syscontMode,proto3" json:"syscontMode,omitempty"` + Userns string `protobuf:"bytes,11,opt,name=userns,proto3" json:"userns,omitempty"` + UidMappings []*IDMapping `protobuf:"bytes,12,rep,name=uidMappings,proto3" json:"uidMappings,omitempty"` + GidMappings []*IDMapping `protobuf:"bytes,13,rep,name=gidMappings,proto3" json:"gidMappings,omitempty"` + FsuidMapFailOnErr bool `protobuf:"varint,14,opt,name=fsuidMapFailOnErr,proto3" json:"fsuidMapFailOnErr,omitempty"` + RootfsUidShiftType uint32 `protobuf:"varint,15,opt,name=rootfsUidShiftType,proto3" json:"rootfsUidShiftType,omitempty"` + NoShiftfsOnFuse bool `protobuf:"varint,16,opt,name=noShiftfsOnFuse,proto3" json:"noShiftfsOnFuse,omitempty"` + RelaxedReadOnly bool `protobuf:"varint,17,opt,name=relaxedReadOnly,proto3" json:"relaxedReadOnly,omitempty"` +} + +func (x *ContainerConfig) Reset() { + *x = ContainerConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContainerConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContainerConfig) ProtoMessage() {} + +func (x *ContainerConfig) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContainerConfig.ProtoReflect.Descriptor instead. +func (*ContainerConfig) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{2} +} + +func (x *ContainerConfig) GetAliasDns() bool { + if x != nil { + return x.AliasDns + } + return false +} + +func (x *ContainerConfig) GetShiftfsOk() bool { + if x != nil { + return x.ShiftfsOk + } + return false +} + +func (x *ContainerConfig) GetShiftfsOnOverlayfsOk() bool { + if x != nil { + return x.ShiftfsOnOverlayfsOk + } + return false +} + +func (x *ContainerConfig) GetIDMapMountOk() bool { + if x != nil { + return x.IDMapMountOk + } + return false +} + +func (x *ContainerConfig) GetOverlayfsOnIDMapMountOk() bool { + if x != nil { + return x.OverlayfsOnIDMapMountOk + } + return false +} + +func (x *ContainerConfig) GetNoRootfsCloning() bool { + if x != nil { + return x.NoRootfsCloning + } + return false +} + +func (x *ContainerConfig) GetIgnoreSysfsChown() bool { + if x != nil { + return x.IgnoreSysfsChown + } + return false +} + +func (x *ContainerConfig) GetAllowTrustedXattr() bool { + if x != nil { + return x.AllowTrustedXattr + } + return false +} + +func (x *ContainerConfig) GetHonorCaps() bool { + if x != nil { + return x.HonorCaps + } + return false +} + +func (x *ContainerConfig) GetSyscontMode() bool { + if x != nil { + return x.SyscontMode + } + return false +} + +func (x *ContainerConfig) GetUserns() string { + if x != nil { + return x.Userns + } + return "" +} + +func (x *ContainerConfig) GetUidMappings() []*IDMapping { + if x != nil { + return x.UidMappings + } + return nil +} + +func (x *ContainerConfig) GetGidMappings() []*IDMapping { + if x != nil { + return x.GidMappings + } + return nil +} + +func (x *ContainerConfig) GetFsuidMapFailOnErr() bool { + if x != nil { + return x.FsuidMapFailOnErr + } + return false +} + +func (x *ContainerConfig) GetRootfsUidShiftType() uint32 { + if x != nil { + return x.RootfsUidShiftType + } + return 0 +} + +func (x *ContainerConfig) GetNoShiftfsOnFuse() bool { + if x != nil { + return x.NoShiftfsOnFuse + } + return false +} + +func (x *ContainerConfig) GetRelaxedReadOnly() bool { + if x != nil { + return x.RelaxedReadOnly + } + return false +} + +type RegisterResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerConfig *ContainerConfig `protobuf:"bytes,1,opt,name=containerConfig,proto3" json:"containerConfig,omitempty"` +} + +func (x *RegisterResp) Reset() { + *x = RegisterResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterResp) ProtoMessage() {} + +func (x *RegisterResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterResp.ProtoReflect.Descriptor instead. +func (*RegisterResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{3} +} + +func (x *RegisterResp) GetContainerConfig() *ContainerConfig { + if x != nil { + return x.ContainerConfig + } + return nil +} + +type UpdateReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Userns string `protobuf:"bytes,2,opt,name=userns,proto3" json:"userns,omitempty"` + Netns string `protobuf:"bytes,3,opt,name=netns,proto3" json:"netns,omitempty"` + UidMappings []*IDMapping `protobuf:"bytes,4,rep,name=uidMappings,proto3" json:"uidMappings,omitempty"` + GidMappings []*IDMapping `protobuf:"bytes,5,rep,name=gidMappings,proto3" json:"gidMappings,omitempty"` + RootfsUidShiftType uint32 `protobuf:"varint,6,opt,name=rootfsUidShiftType,proto3" json:"rootfsUidShiftType,omitempty"` +} + +func (x *UpdateReq) Reset() { + *x = UpdateReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateReq) ProtoMessage() {} + +func (x *UpdateReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateReq.ProtoReflect.Descriptor instead. +func (*UpdateReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{4} +} + +func (x *UpdateReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateReq) GetUserns() string { + if x != nil { + return x.Userns + } + return "" +} + +func (x *UpdateReq) GetNetns() string { + if x != nil { + return x.Netns + } + return "" +} + +func (x *UpdateReq) GetUidMappings() []*IDMapping { + if x != nil { + return x.UidMappings + } + return nil +} + +func (x *UpdateReq) GetGidMappings() []*IDMapping { + if x != nil { + return x.GidMappings + } + return nil +} + +func (x *UpdateReq) GetRootfsUidShiftType() uint32 { + if x != nil { + return x.RootfsUidShiftType + } + return 0 +} + +type UpdateResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateResp) Reset() { + *x = UpdateResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateResp) ProtoMessage() {} + +func (x *UpdateResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateResp.ProtoReflect.Descriptor instead. +func (*UpdateResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{5} +} + +type UnregisterReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *UnregisterReq) Reset() { + *x = UnregisterReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnregisterReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnregisterReq) ProtoMessage() {} + +func (x *UnregisterReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnregisterReq.ProtoReflect.Descriptor instead. +func (*UnregisterReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{6} +} + +func (x *UnregisterReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type UnregisterResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UnregisterResp) Reset() { + *x = UnregisterResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnregisterResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnregisterResp) ProtoMessage() {} + +func (x *UnregisterResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnregisterResp.ProtoReflect.Descriptor instead. +func (*UnregisterResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{7} +} + +type SubidAllocReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Size uint64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` +} + +func (x *SubidAllocReq) Reset() { + *x = SubidAllocReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubidAllocReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubidAllocReq) ProtoMessage() {} + +func (x *SubidAllocReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubidAllocReq.ProtoReflect.Descriptor instead. +func (*SubidAllocReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{8} +} + +func (x *SubidAllocReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SubidAllocReq) GetSize() uint64 { + if x != nil { + return x.Size + } + return 0 +} + +type SubidAllocResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uid uint32 `protobuf:"varint,1,opt,name=uid,proto3" json:"uid,omitempty"` + Gid uint32 `protobuf:"varint,2,opt,name=gid,proto3" json:"gid,omitempty"` +} + +func (x *SubidAllocResp) Reset() { + *x = SubidAllocResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubidAllocResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubidAllocResp) ProtoMessage() {} + +func (x *SubidAllocResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubidAllocResp.ProtoReflect.Descriptor instead. +func (*SubidAllocResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{9} +} + +func (x *SubidAllocResp) GetUid() uint32 { + if x != nil { + return x.Uid + } + return 0 +} + +func (x *SubidAllocResp) GetGid() uint32 { + if x != nil { + return x.Gid + } + return 0 +} + +type MountPrepInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` + Exclusive bool `protobuf:"varint,2,opt,name=exclusive,proto3" json:"exclusive,omitempty"` +} + +func (x *MountPrepInfo) Reset() { + *x = MountPrepInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountPrepInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountPrepInfo) ProtoMessage() {} + +func (x *MountPrepInfo) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountPrepInfo.ProtoReflect.Descriptor instead. +func (*MountPrepInfo) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{10} +} + +func (x *MountPrepInfo) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *MountPrepInfo) GetExclusive() bool { + if x != nil { + return x.Exclusive + } + return false +} + +type MountPrepReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Uid uint32 `protobuf:"varint,2,opt,name=uid,proto3" json:"uid,omitempty"` + Gid uint32 `protobuf:"varint,3,opt,name=gid,proto3" json:"gid,omitempty"` + PrepList []*MountPrepInfo `protobuf:"bytes,4,rep,name=prepList,proto3" json:"prepList,omitempty"` +} + +func (x *MountPrepReq) Reset() { + *x = MountPrepReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountPrepReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountPrepReq) ProtoMessage() {} + +func (x *MountPrepReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountPrepReq.ProtoReflect.Descriptor instead. +func (*MountPrepReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{11} +} + +func (x *MountPrepReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *MountPrepReq) GetUid() uint32 { + if x != nil { + return x.Uid + } + return 0 +} + +func (x *MountPrepReq) GetGid() uint32 { + if x != nil { + return x.Gid + } + return 0 +} + +func (x *MountPrepReq) GetPrepList() []*MountPrepInfo { + if x != nil { + return x.PrepList + } + return nil +} + +type MountPrepResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MountPrepResp) Reset() { + *x = MountPrepResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountPrepResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountPrepResp) ProtoMessage() {} + +func (x *MountPrepResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountPrepResp.ProtoReflect.Descriptor instead. +func (*MountPrepResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{12} +} + +type MountReqInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Kind uint32 `protobuf:"varint,1,opt,name=kind,proto3" json:"kind,omitempty"` + Dest string `protobuf:"bytes,2,opt,name=dest,proto3" json:"dest,omitempty"` +} + +func (x *MountReqInfo) Reset() { + *x = MountReqInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountReqInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountReqInfo) ProtoMessage() {} + +func (x *MountReqInfo) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountReqInfo.ProtoReflect.Descriptor instead. +func (*MountReqInfo) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{13} +} + +func (x *MountReqInfo) GetKind() uint32 { + if x != nil { + return x.Kind + } + return 0 +} + +func (x *MountReqInfo) GetDest() string { + if x != nil { + return x.Dest + } + return "" +} + +type MountReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + RootfsUidShiftType uint32 `protobuf:"varint,2,opt,name=rootfsUidShiftType,proto3" json:"rootfsUidShiftType,omitempty"` + ReqList []*MountReqInfo `protobuf:"bytes,3,rep,name=reqList,proto3" json:"reqList,omitempty"` +} + +func (x *MountReq) Reset() { + *x = MountReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountReq) ProtoMessage() {} + +func (x *MountReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountReq.ProtoReflect.Descriptor instead. +func (*MountReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{14} +} + +func (x *MountReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *MountReq) GetRootfsUidShiftType() uint32 { + if x != nil { + return x.RootfsUidShiftType + } + return 0 +} + +func (x *MountReq) GetReqList() []*MountReqInfo { + if x != nil { + return x.ReqList + } + return nil +} + +type Mount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` + Dest string `protobuf:"bytes,2,opt,name=dest,proto3" json:"dest,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Opt []string `protobuf:"bytes,4,rep,name=opt,proto3" json:"opt,omitempty"` +} + +func (x *Mount) Reset() { + *x = Mount{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Mount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Mount) ProtoMessage() {} + +func (x *Mount) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Mount.ProtoReflect.Descriptor instead. +func (*Mount) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{15} +} + +func (x *Mount) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *Mount) GetDest() string { + if x != nil { + return x.Dest + } + return "" +} + +func (x *Mount) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Mount) GetOpt() []string { + if x != nil { + return x.Opt + } + return nil +} + +type MountResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mounts []*Mount `protobuf:"bytes,1,rep,name=mounts,proto3" json:"mounts,omitempty"` +} + +func (x *MountResp) Reset() { + *x = MountResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MountResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MountResp) ProtoMessage() {} + +func (x *MountResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MountResp.ProtoReflect.Descriptor instead. +func (*MountResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{16} +} + +func (x *MountResp) GetMounts() []*Mount { + if x != nil { + return x.Mounts + } + return nil +} + +type ShiftfsMark struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` + Readonly bool `protobuf:"varint,2,opt,name=readonly,proto3" json:"readonly,omitempty"` +} + +func (x *ShiftfsMark) Reset() { + *x = ShiftfsMark{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShiftfsMark) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShiftfsMark) ProtoMessage() {} + +func (x *ShiftfsMark) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShiftfsMark.ProtoReflect.Descriptor instead. +func (*ShiftfsMark) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{17} +} + +func (x *ShiftfsMark) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *ShiftfsMark) GetReadonly() bool { + if x != nil { + return x.Readonly + } + return false +} + +type ShiftfsMarkReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ShiftfsMarks []*ShiftfsMark `protobuf:"bytes,2,rep,name=shiftfsMarks,proto3" json:"shiftfsMarks,omitempty"` +} + +func (x *ShiftfsMarkReq) Reset() { + *x = ShiftfsMarkReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShiftfsMarkReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShiftfsMarkReq) ProtoMessage() {} + +func (x *ShiftfsMarkReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShiftfsMarkReq.ProtoReflect.Descriptor instead. +func (*ShiftfsMarkReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{18} +} + +func (x *ShiftfsMarkReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ShiftfsMarkReq) GetShiftfsMarks() []*ShiftfsMark { + if x != nil { + return x.ShiftfsMarks + } + return nil +} + +type ShiftfsMarkResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ShiftfsMarks []*ShiftfsMark `protobuf:"bytes,1,rep,name=shiftfsMarks,proto3" json:"shiftfsMarks,omitempty"` +} + +func (x *ShiftfsMarkResp) Reset() { + *x = ShiftfsMarkResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShiftfsMarkResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShiftfsMarkResp) ProtoMessage() {} + +func (x *ShiftfsMarkResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShiftfsMarkResp.ProtoReflect.Descriptor instead. +func (*ShiftfsMarkResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{19} +} + +func (x *ShiftfsMarkResp) GetShiftfsMarks() []*ShiftfsMark { + if x != nil { + return x.ShiftfsMarks + } + return nil +} + +type FsStateReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Rootfs string `protobuf:"bytes,2,opt,name=rootfs,proto3" json:"rootfs,omitempty"` +} + +func (x *FsStateReq) Reset() { + *x = FsStateReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FsStateReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FsStateReq) ProtoMessage() {} + +func (x *FsStateReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FsStateReq.ProtoReflect.Descriptor instead. +func (*FsStateReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{20} +} + +func (x *FsStateReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *FsStateReq) GetRootfs() string { + if x != nil { + return x.Rootfs + } + return "" +} + +type FsEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Kind uint32 `protobuf:"varint,1,opt,name=kind,proto3" json:"kind,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + Mode uint32 `protobuf:"varint,3,opt,name=mode,proto3" json:"mode,omitempty"` + Dst string `protobuf:"bytes,4,opt,name=dst,proto3" json:"dst,omitempty"` +} + +func (x *FsEntry) Reset() { + *x = FsEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FsEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FsEntry) ProtoMessage() {} + +func (x *FsEntry) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FsEntry.ProtoReflect.Descriptor instead. +func (*FsEntry) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{21} +} + +func (x *FsEntry) GetKind() uint32 { + if x != nil { + return x.Kind + } + return 0 +} + +func (x *FsEntry) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *FsEntry) GetMode() uint32 { + if x != nil { + return x.Mode + } + return 0 +} + +func (x *FsEntry) GetDst() string { + if x != nil { + return x.Dst + } + return "" +} + +type FsStateResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FsEntries []*FsEntry `protobuf:"bytes,1,rep,name=fsEntries,proto3" json:"fsEntries,omitempty"` +} + +func (x *FsStateResp) Reset() { + *x = FsStateResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FsStateResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FsStateResp) ProtoMessage() {} + +func (x *FsStateResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FsStateResp.ProtoReflect.Descriptor instead. +func (*FsStateResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{22} +} + +func (x *FsStateResp) GetFsEntries() []*FsEntry { + if x != nil { + return x.FsEntries + } + return nil +} + +type PauseReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *PauseReq) Reset() { + *x = PauseReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PauseReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PauseReq) ProtoMessage() {} + +func (x *PauseReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PauseReq.ProtoReflect.Descriptor instead. +func (*PauseReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{23} +} + +func (x *PauseReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type PauseResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PauseResp) Reset() { + *x = PauseResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PauseResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PauseResp) ProtoMessage() {} + +func (x *PauseResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PauseResp.ProtoReflect.Descriptor instead. +func (*PauseResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{24} +} + +type ResumeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ResumeReq) Reset() { + *x = ResumeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResumeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResumeReq) ProtoMessage() {} + +func (x *ResumeReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResumeReq.ProtoReflect.Descriptor instead. +func (*ResumeReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{25} +} + +func (x *ResumeReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type ResumeResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ResumeResp) Reset() { + *x = ResumeResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResumeResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResumeResp) ProtoMessage() {} + +func (x *ResumeResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResumeResp.ProtoReflect.Descriptor instead. +func (*ResumeResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{26} +} + +type CloneRootfsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *CloneRootfsReq) Reset() { + *x = CloneRootfsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloneRootfsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloneRootfsReq) ProtoMessage() {} + +func (x *CloneRootfsReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloneRootfsReq.ProtoReflect.Descriptor instead. +func (*CloneRootfsReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{27} +} + +func (x *CloneRootfsReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type CloneRootfsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Rootfs string `protobuf:"bytes,1,opt,name=rootfs,proto3" json:"rootfs,omitempty"` +} + +func (x *CloneRootfsResp) Reset() { + *x = CloneRootfsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CloneRootfsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CloneRootfsResp) ProtoMessage() {} + +func (x *CloneRootfsResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CloneRootfsResp.ProtoReflect.Descriptor instead. +func (*CloneRootfsResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{28} +} + +func (x *CloneRootfsResp) GetRootfs() string { + if x != nil { + return x.Rootfs + } + return "" +} + +type ChownClonedRootfsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + UidOffset int32 `protobuf:"varint,2,opt,name=uidOffset,proto3" json:"uidOffset,omitempty"` + GidOffset int32 `protobuf:"varint,3,opt,name=gidOffset,proto3" json:"gidOffset,omitempty"` +} + +func (x *ChownClonedRootfsReq) Reset() { + *x = ChownClonedRootfsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChownClonedRootfsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChownClonedRootfsReq) ProtoMessage() {} + +func (x *ChownClonedRootfsReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChownClonedRootfsReq.ProtoReflect.Descriptor instead. +func (*ChownClonedRootfsReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{29} +} + +func (x *ChownClonedRootfsReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ChownClonedRootfsReq) GetUidOffset() int32 { + if x != nil { + return x.UidOffset + } + return 0 +} + +func (x *ChownClonedRootfsReq) GetGidOffset() int32 { + if x != nil { + return x.GidOffset + } + return 0 +} + +type ChownClonedRootfsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ChownClonedRootfsResp) Reset() { + *x = ChownClonedRootfsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChownClonedRootfsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChownClonedRootfsResp) ProtoMessage() {} + +func (x *ChownClonedRootfsResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChownClonedRootfsResp.ProtoReflect.Descriptor instead. +func (*ChownClonedRootfsResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{30} +} + +type RevertClonedRootfsChownReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *RevertClonedRootfsChownReq) Reset() { + *x = RevertClonedRootfsChownReq{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RevertClonedRootfsChownReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevertClonedRootfsChownReq) ProtoMessage() {} + +func (x *RevertClonedRootfsChownReq) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevertClonedRootfsChownReq.ProtoReflect.Descriptor instead. +func (*RevertClonedRootfsChownReq) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{31} +} + +func (x *RevertClonedRootfsChownReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type RevertClonedRootfsChownResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RevertClonedRootfsChownResp) Reset() { + *x = RevertClonedRootfsChownResp{} + if protoimpl.UnsafeEnabled { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RevertClonedRootfsChownResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevertClonedRootfsChownResp) ProtoMessage() {} + +func (x *RevertClonedRootfsChownResp) ProtoReflect() protoreflect.Message { + mi := &file_sysboxMgrProtobuf_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevertClonedRootfsChownResp.ProtoReflect.Descriptor instead. +func (*RevertClonedRootfsChownResp) Descriptor() ([]byte, []int) { + return file_sysboxMgrProtobuf_proto_rawDescGZIP(), []int{32} +} + +var File_sysboxMgrProtobuf_proto protoreflect.FileDescriptor + +var file_sysboxMgrProtobuf_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x73, 0x79, 0x73, 0x62, 0x6f, 0x78, 0x4d, 0x67, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x22, 0x59, 0x0a, 0x09, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xd1, + 0x01, 0x0a, 0x0b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x6e, 0x65, 0x74, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, + 0x65, 0x74, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x75, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, + 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, + 0x75, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x67, + 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x44, 0x4d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x67, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x73, 0x22, 0xd9, 0x05, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x44, + 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x44, + 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4f, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4f, 0x6b, + 0x12, 0x32, 0x0a, 0x14, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4f, 0x6e, 0x4f, 0x76, 0x65, + 0x72, 0x6c, 0x61, 0x79, 0x66, 0x73, 0x4f, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, + 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, + 0x66, 0x73, 0x4f, 0x6b, 0x12, 0x22, 0x0a, 0x0c, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x4d, 0x6f, 0x75, + 0x6e, 0x74, 0x4f, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x49, 0x44, 0x4d, 0x61, + 0x70, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x6b, 0x12, 0x38, 0x0a, 0x17, 0x4f, 0x76, 0x65, 0x72, + 0x6c, 0x61, 0x79, 0x66, 0x73, 0x4f, 0x6e, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x4d, 0x6f, 0x75, 0x6e, + 0x74, 0x4f, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x4f, 0x76, 0x65, 0x72, 0x6c, + 0x61, 0x79, 0x66, 0x73, 0x4f, 0x6e, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x4d, 0x6f, 0x75, 0x6e, 0x74, + 0x4f, 0x6b, 0x12, 0x28, 0x0a, 0x0f, 0x6e, 0x6f, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x43, 0x6c, + 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x6f, 0x52, + 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x43, 0x6c, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x2a, 0x0a, 0x10, + 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x53, 0x79, 0x73, 0x66, 0x73, 0x43, 0x68, 0x6f, 0x77, 0x6e, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x53, 0x79, + 0x73, 0x66, 0x73, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x6c, 0x6c, 0x6f, + 0x77, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x58, 0x61, 0x74, 0x74, 0x72, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, + 0x64, 0x58, 0x61, 0x74, 0x74, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x6f, 0x6e, 0x6f, 0x72, 0x43, + 0x61, 0x70, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x6f, 0x6e, 0x6f, 0x72, + 0x43, 0x61, 0x70, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x63, 0x6f, 0x6e, 0x74, 0x4d, + 0x6f, 0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x79, 0x73, 0x63, 0x6f, + 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x73, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x73, 0x12, 0x35, + 0x0a, 0x0b, 0x75, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x0c, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, + 0x44, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75, 0x69, 0x64, 0x4d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x67, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, + 0x0b, 0x67, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x11, + 0x66, 0x73, 0x75, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x46, 0x61, 0x69, 0x6c, 0x4f, 0x6e, 0x45, 0x72, + 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x66, 0x73, 0x75, 0x69, 0x64, 0x4d, 0x61, + 0x70, 0x46, 0x61, 0x69, 0x6c, 0x4f, 0x6e, 0x45, 0x72, 0x72, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x6f, + 0x6f, 0x74, 0x66, 0x73, 0x55, 0x69, 0x64, 0x53, 0x68, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x55, 0x69, + 0x64, 0x53, 0x68, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x6e, 0x6f, + 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4f, 0x6e, 0x46, 0x75, 0x73, 0x65, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x6f, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4f, 0x6e, + 0x46, 0x75, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6c, 0x61, 0x78, 0x65, 0x64, 0x52, + 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, + 0x65, 0x6c, 0x61, 0x78, 0x65, 0x64, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x53, + 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x43, + 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x22, 0xe7, 0x01, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x65, 0x74, + 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x65, 0x74, 0x6e, 0x73, 0x12, + 0x35, 0x0a, 0x0b, 0x75, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x49, 0x44, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75, 0x69, 0x64, 0x4d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x67, 0x69, 0x64, 0x4d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x44, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x52, 0x0b, 0x67, 0x69, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2e, 0x0a, + 0x12, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x55, 0x69, 0x64, 0x53, 0x68, 0x69, 0x66, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x72, 0x6f, 0x6f, 0x74, 0x66, + 0x73, 0x55, 0x69, 0x64, 0x53, 0x68, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0c, 0x0a, + 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1f, 0x0a, 0x0d, 0x55, + 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, + 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x33, + 0x0a, 0x0d, 0x53, 0x75, 0x62, 0x69, 0x64, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x52, 0x65, 0x71, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, + 0x69, 0x7a, 0x65, 0x22, 0x34, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x69, 0x64, 0x41, 0x6c, 0x6c, 0x6f, + 0x63, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x67, 0x69, 0x64, 0x22, 0x45, 0x0a, 0x0d, 0x4d, 0x6f, 0x75, + 0x6e, 0x74, 0x50, 0x72, 0x65, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, + 0x22, 0x77, 0x0a, 0x0c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x70, 0x52, 0x65, 0x71, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x75, + 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x03, 0x67, 0x69, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x70, 0x4c, 0x69, 0x73, 0x74, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x08, 0x70, 0x72, 0x65, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x4d, 0x6f, 0x75, + 0x6e, 0x74, 0x50, 0x72, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x36, 0x0a, 0x0c, 0x4d, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, + 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, + 0x73, 0x74, 0x22, 0x7c, 0x0a, 0x08, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, + 0x0a, 0x12, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x55, 0x69, 0x64, 0x53, 0x68, 0x69, 0x66, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x72, 0x6f, 0x6f, 0x74, + 0x66, 0x73, 0x55, 0x69, 0x64, 0x53, 0x68, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x30, + 0x0a, 0x07, 0x72, 0x65, 0x71, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x72, 0x65, 0x71, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0x59, 0x0a, 0x05, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6f, 0x70, 0x74, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x70, 0x74, 0x22, 0x34, 0x0a, 0x09, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x27, 0x0a, 0x06, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x22, 0x41, 0x0a, 0x0b, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x64, + 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, + 0x6f, 0x6e, 0x6c, 0x79, 0x22, 0x5b, 0x0a, 0x0e, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, + 0x61, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x66, + 0x73, 0x4d, 0x61, 0x72, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, + 0x61, 0x72, 0x6b, 0x52, 0x0c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, + 0x73, 0x22, 0x4c, 0x0a, 0x0f, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, + 0x61, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, + 0x6b, 0x52, 0x0c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, 0x73, 0x22, + 0x34, 0x0a, 0x0a, 0x46, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x22, 0x57, 0x0a, 0x07, 0x46, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x64, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x74, 0x22, 0x3e, + 0x0a, 0x0b, 0x46, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, + 0x09, 0x66, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x09, 0x66, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x1a, + 0x0a, 0x08, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x0b, 0x0a, 0x09, 0x50, 0x61, + 0x75, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x1b, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x75, 0x6d, + 0x65, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x0c, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x20, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x66, + 0x73, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x29, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x6f, 0x6f, + 0x74, 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x22, + 0x62, 0x0a, 0x14, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x66, 0x73, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x69, 0x64, 0x4f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x75, 0x69, 0x64, 0x4f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x64, 0x4f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x69, 0x64, 0x4f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x6e, + 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2c, 0x0a, 0x1a, + 0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, + 0x66, 0x73, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x52, 0x65, + 0x76, 0x65, 0x72, 0x74, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, + 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x32, 0x86, 0x07, 0x0a, 0x15, 0x73, 0x79, + 0x73, 0x62, 0x6f, 0x78, 0x4d, 0x67, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x12, 0x3b, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, + 0x12, 0x35, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0a, 0x55, 0x6e, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0a, 0x53, 0x75, + 0x62, 0x69, 0x64, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x75, 0x62, 0x69, 0x64, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x52, 0x65, + 0x71, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x75, 0x62, + 0x69, 0x64, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x3f, 0x0a, + 0x0a, 0x50, 0x72, 0x65, 0x70, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x70, + 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x36, + 0x0a, 0x09, 0x52, 0x65, 0x71, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x12, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x53, 0x68, 0x69, + 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x68, 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, 0x52, + 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x68, + 0x69, 0x66, 0x74, 0x66, 0x73, 0x4d, 0x61, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, + 0x3b, 0x0a, 0x0a, 0x52, 0x65, 0x71, 0x46, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, + 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x05, + 0x50, 0x61, 0x75, 0x73, 0x65, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, + 0x12, 0x35, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6d, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x43, 0x6c, + 0x6f, 0x6e, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, + 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, + 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, + 0x12, 0x56, 0x0a, 0x11, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, + 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, + 0x66, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, + 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x65, + 0x72, 0x74, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x43, 0x68, + 0x6f, 0x77, 0x6e, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, + 0x65, 0x76, 0x65, 0x72, 0x74, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x66, + 0x73, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x43, 0x6c, 0x6f, 0x6e, 0x65, + 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x43, 0x68, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x00, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x2f, 0x3b, 0x73, 0x79, 0x73, 0x62, 0x6f, 0x78, 0x4d, + 0x67, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_sysboxMgrProtobuf_proto_rawDescOnce sync.Once + file_sysboxMgrProtobuf_proto_rawDescData = file_sysboxMgrProtobuf_proto_rawDesc +) + +func file_sysboxMgrProtobuf_proto_rawDescGZIP() []byte { + file_sysboxMgrProtobuf_proto_rawDescOnce.Do(func() { + file_sysboxMgrProtobuf_proto_rawDescData = protoimpl.X.CompressGZIP(file_sysboxMgrProtobuf_proto_rawDescData) + }) + return file_sysboxMgrProtobuf_proto_rawDescData +} + +var file_sysboxMgrProtobuf_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_sysboxMgrProtobuf_proto_goTypes = []interface{}{ + (*IDMapping)(nil), // 0: protobuf.IDMapping + (*RegisterReq)(nil), // 1: protobuf.RegisterReq + (*ContainerConfig)(nil), // 2: protobuf.ContainerConfig + (*RegisterResp)(nil), // 3: protobuf.RegisterResp + (*UpdateReq)(nil), // 4: protobuf.UpdateReq + (*UpdateResp)(nil), // 5: protobuf.UpdateResp + (*UnregisterReq)(nil), // 6: protobuf.UnregisterReq + (*UnregisterResp)(nil), // 7: protobuf.UnregisterResp + (*SubidAllocReq)(nil), // 8: protobuf.SubidAllocReq + (*SubidAllocResp)(nil), // 9: protobuf.SubidAllocResp + (*MountPrepInfo)(nil), // 10: protobuf.MountPrepInfo + (*MountPrepReq)(nil), // 11: protobuf.MountPrepReq + (*MountPrepResp)(nil), // 12: protobuf.MountPrepResp + (*MountReqInfo)(nil), // 13: protobuf.MountReqInfo + (*MountReq)(nil), // 14: protobuf.MountReq + (*Mount)(nil), // 15: protobuf.Mount + (*MountResp)(nil), // 16: protobuf.MountResp + (*ShiftfsMark)(nil), // 17: protobuf.ShiftfsMark + (*ShiftfsMarkReq)(nil), // 18: protobuf.ShiftfsMarkReq + (*ShiftfsMarkResp)(nil), // 19: protobuf.ShiftfsMarkResp + (*FsStateReq)(nil), // 20: protobuf.FsStateReq + (*FsEntry)(nil), // 21: protobuf.FsEntry + (*FsStateResp)(nil), // 22: protobuf.FsStateResp + (*PauseReq)(nil), // 23: protobuf.PauseReq + (*PauseResp)(nil), // 24: protobuf.PauseResp + (*ResumeReq)(nil), // 25: protobuf.ResumeReq + (*ResumeResp)(nil), // 26: protobuf.ResumeResp + (*CloneRootfsReq)(nil), // 27: protobuf.CloneRootfsReq + (*CloneRootfsResp)(nil), // 28: protobuf.CloneRootfsResp + (*ChownClonedRootfsReq)(nil), // 29: protobuf.ChownClonedRootfsReq + (*ChownClonedRootfsResp)(nil), // 30: protobuf.ChownClonedRootfsResp + (*RevertClonedRootfsChownReq)(nil), // 31: protobuf.RevertClonedRootfsChownReq + (*RevertClonedRootfsChownResp)(nil), // 32: protobuf.RevertClonedRootfsChownResp +} +var file_sysboxMgrProtobuf_proto_depIdxs = []int32{ + 0, // 0: protobuf.RegisterReq.uidMappings:type_name -> protobuf.IDMapping + 0, // 1: protobuf.RegisterReq.gidMappings:type_name -> protobuf.IDMapping + 0, // 2: protobuf.ContainerConfig.uidMappings:type_name -> protobuf.IDMapping + 0, // 3: protobuf.ContainerConfig.gidMappings:type_name -> protobuf.IDMapping + 2, // 4: protobuf.RegisterResp.containerConfig:type_name -> protobuf.ContainerConfig + 0, // 5: protobuf.UpdateReq.uidMappings:type_name -> protobuf.IDMapping + 0, // 6: protobuf.UpdateReq.gidMappings:type_name -> protobuf.IDMapping + 10, // 7: protobuf.MountPrepReq.prepList:type_name -> protobuf.MountPrepInfo + 13, // 8: protobuf.MountReq.reqList:type_name -> protobuf.MountReqInfo + 15, // 9: protobuf.MountResp.mounts:type_name -> protobuf.Mount + 17, // 10: protobuf.ShiftfsMarkReq.shiftfsMarks:type_name -> protobuf.ShiftfsMark + 17, // 11: protobuf.ShiftfsMarkResp.shiftfsMarks:type_name -> protobuf.ShiftfsMark + 21, // 12: protobuf.FsStateResp.fsEntries:type_name -> protobuf.FsEntry + 1, // 13: protobuf.sysboxMgrStateChannel.Register:input_type -> protobuf.RegisterReq + 4, // 14: protobuf.sysboxMgrStateChannel.Update:input_type -> protobuf.UpdateReq + 6, // 15: protobuf.sysboxMgrStateChannel.Unregister:input_type -> protobuf.UnregisterReq + 8, // 16: protobuf.sysboxMgrStateChannel.SubidAlloc:input_type -> protobuf.SubidAllocReq + 11, // 17: protobuf.sysboxMgrStateChannel.PrepMounts:input_type -> protobuf.MountPrepReq + 14, // 18: protobuf.sysboxMgrStateChannel.ReqMounts:input_type -> protobuf.MountReq + 18, // 19: protobuf.sysboxMgrStateChannel.ReqShiftfsMark:input_type -> protobuf.ShiftfsMarkReq + 20, // 20: protobuf.sysboxMgrStateChannel.ReqFsState:input_type -> protobuf.FsStateReq + 23, // 21: protobuf.sysboxMgrStateChannel.Pause:input_type -> protobuf.PauseReq + 25, // 22: protobuf.sysboxMgrStateChannel.Resume:input_type -> protobuf.ResumeReq + 27, // 23: protobuf.sysboxMgrStateChannel.ReqCloneRootfs:input_type -> protobuf.CloneRootfsReq + 29, // 24: protobuf.sysboxMgrStateChannel.ChownClonedRootfs:input_type -> protobuf.ChownClonedRootfsReq + 31, // 25: protobuf.sysboxMgrStateChannel.RevertClonedRootfsChown:input_type -> protobuf.RevertClonedRootfsChownReq + 3, // 26: protobuf.sysboxMgrStateChannel.Register:output_type -> protobuf.RegisterResp + 5, // 27: protobuf.sysboxMgrStateChannel.Update:output_type -> protobuf.UpdateResp + 7, // 28: protobuf.sysboxMgrStateChannel.Unregister:output_type -> protobuf.UnregisterResp + 9, // 29: protobuf.sysboxMgrStateChannel.SubidAlloc:output_type -> protobuf.SubidAllocResp + 12, // 30: protobuf.sysboxMgrStateChannel.PrepMounts:output_type -> protobuf.MountPrepResp + 16, // 31: protobuf.sysboxMgrStateChannel.ReqMounts:output_type -> protobuf.MountResp + 19, // 32: protobuf.sysboxMgrStateChannel.ReqShiftfsMark:output_type -> protobuf.ShiftfsMarkResp + 22, // 33: protobuf.sysboxMgrStateChannel.ReqFsState:output_type -> protobuf.FsStateResp + 24, // 34: protobuf.sysboxMgrStateChannel.Pause:output_type -> protobuf.PauseResp + 26, // 35: protobuf.sysboxMgrStateChannel.Resume:output_type -> protobuf.ResumeResp + 28, // 36: protobuf.sysboxMgrStateChannel.ReqCloneRootfs:output_type -> protobuf.CloneRootfsResp + 30, // 37: protobuf.sysboxMgrStateChannel.ChownClonedRootfs:output_type -> protobuf.ChownClonedRootfsResp + 32, // 38: protobuf.sysboxMgrStateChannel.RevertClonedRootfsChown:output_type -> protobuf.RevertClonedRootfsChownResp + 26, // [26:39] is the sub-list for method output_type + 13, // [13:26] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name +} + +func init() { file_sysboxMgrProtobuf_proto_init() } +func file_sysboxMgrProtobuf_proto_init() { + if File_sysboxMgrProtobuf_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_sysboxMgrProtobuf_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IDMapping); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContainerConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnregisterReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnregisterResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubidAllocReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubidAllocResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountPrepInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountPrepReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountPrepResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountReqInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Mount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MountResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShiftfsMark); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShiftfsMarkReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShiftfsMarkResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FsStateReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FsEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FsStateResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PauseReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PauseResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResumeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResumeResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CloneRootfsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CloneRootfsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChownClonedRootfsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChownClonedRootfsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RevertClonedRootfsChownReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sysboxMgrProtobuf_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RevertClonedRootfsChownResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_sysboxMgrProtobuf_proto_rawDesc, + NumEnums: 0, + NumMessages: 33, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_sysboxMgrProtobuf_proto_goTypes, + DependencyIndexes: file_sysboxMgrProtobuf_proto_depIdxs, + MessageInfos: file_sysboxMgrProtobuf_proto_msgTypes, + }.Build() + File_sysboxMgrProtobuf_proto = out.File + file_sysboxMgrProtobuf_proto_rawDesc = nil + file_sysboxMgrProtobuf_proto_goTypes = nil + file_sysboxMgrProtobuf_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// SysboxMgrStateChannelClient is the client API for SysboxMgrStateChannel service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type SysboxMgrStateChannelClient interface { + // Container registration + Register(ctx context.Context, in *RegisterReq, opts ...grpc.CallOption) (*RegisterResp, error) + // Container Update + Update(ctx context.Context, in *UpdateReq, opts ...grpc.CallOption) (*UpdateResp, error) + // Container Unregistration + Unregister(ctx context.Context, in *UnregisterReq, opts ...grpc.CallOption) (*UnregisterResp, error) + // Subuid(gid) allocation request + SubidAlloc(ctx context.Context, in *SubidAllocReq, opts ...grpc.CallOption) (*SubidAllocResp, error) + // Mount source prep request + PrepMounts(ctx context.Context, in *MountPrepReq, opts ...grpc.CallOption) (*MountPrepResp, error) + // Mount request + ReqMounts(ctx context.Context, in *MountReq, opts ...grpc.CallOption) (*MountResp, error) + // Shiftfs mark request + ReqShiftfsMark(ctx context.Context, in *ShiftfsMarkReq, opts ...grpc.CallOption) (*ShiftfsMarkResp, error) + // FsState request + ReqFsState(ctx context.Context, in *FsStateReq, opts ...grpc.CallOption) (*FsStateResp, error) + // Pause request + Pause(ctx context.Context, in *PauseReq, opts ...grpc.CallOption) (*PauseResp, error) + // Resume request + Resume(ctx context.Context, in *ResumeReq, opts ...grpc.CallOption) (*ResumeResp, error) + // Clone rootfs request + ReqCloneRootfs(ctx context.Context, in *CloneRootfsReq, opts ...grpc.CallOption) (*CloneRootfsResp, error) + // Chown cloned rootfs request + ChownClonedRootfs(ctx context.Context, in *ChownClonedRootfsReq, opts ...grpc.CallOption) (*ChownClonedRootfsResp, error) + // Revert cloned rootfs chown + RevertClonedRootfsChown(ctx context.Context, in *RevertClonedRootfsChownReq, opts ...grpc.CallOption) (*RevertClonedRootfsChownResp, error) +} + +type sysboxMgrStateChannelClient struct { + cc grpc.ClientConnInterface +} + +func NewSysboxMgrStateChannelClient(cc grpc.ClientConnInterface) SysboxMgrStateChannelClient { + return &sysboxMgrStateChannelClient{cc} +} + +func (c *sysboxMgrStateChannelClient) Register(ctx context.Context, in *RegisterReq, opts ...grpc.CallOption) (*RegisterResp, error) { + out := new(RegisterResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/Register", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) Update(ctx context.Context, in *UpdateReq, opts ...grpc.CallOption) (*UpdateResp, error) { + out := new(UpdateResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/Update", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) Unregister(ctx context.Context, in *UnregisterReq, opts ...grpc.CallOption) (*UnregisterResp, error) { + out := new(UnregisterResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/Unregister", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) SubidAlloc(ctx context.Context, in *SubidAllocReq, opts ...grpc.CallOption) (*SubidAllocResp, error) { + out := new(SubidAllocResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/SubidAlloc", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) PrepMounts(ctx context.Context, in *MountPrepReq, opts ...grpc.CallOption) (*MountPrepResp, error) { + out := new(MountPrepResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/PrepMounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) ReqMounts(ctx context.Context, in *MountReq, opts ...grpc.CallOption) (*MountResp, error) { + out := new(MountResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/ReqMounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) ReqShiftfsMark(ctx context.Context, in *ShiftfsMarkReq, opts ...grpc.CallOption) (*ShiftfsMarkResp, error) { + out := new(ShiftfsMarkResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/ReqShiftfsMark", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) ReqFsState(ctx context.Context, in *FsStateReq, opts ...grpc.CallOption) (*FsStateResp, error) { + out := new(FsStateResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/ReqFsState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) Pause(ctx context.Context, in *PauseReq, opts ...grpc.CallOption) (*PauseResp, error) { + out := new(PauseResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/Pause", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) Resume(ctx context.Context, in *ResumeReq, opts ...grpc.CallOption) (*ResumeResp, error) { + out := new(ResumeResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/Resume", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) ReqCloneRootfs(ctx context.Context, in *CloneRootfsReq, opts ...grpc.CallOption) (*CloneRootfsResp, error) { + out := new(CloneRootfsResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/ReqCloneRootfs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) ChownClonedRootfs(ctx context.Context, in *ChownClonedRootfsReq, opts ...grpc.CallOption) (*ChownClonedRootfsResp, error) { + out := new(ChownClonedRootfsResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/ChownClonedRootfs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sysboxMgrStateChannelClient) RevertClonedRootfsChown(ctx context.Context, in *RevertClonedRootfsChownReq, opts ...grpc.CallOption) (*RevertClonedRootfsChownResp, error) { + out := new(RevertClonedRootfsChownResp) + err := c.cc.Invoke(ctx, "/protobuf.sysboxMgrStateChannel/RevertClonedRootfsChown", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SysboxMgrStateChannelServer is the server API for SysboxMgrStateChannel service. +type SysboxMgrStateChannelServer interface { + // Container registration + Register(context.Context, *RegisterReq) (*RegisterResp, error) + // Container Update + Update(context.Context, *UpdateReq) (*UpdateResp, error) + // Container Unregistration + Unregister(context.Context, *UnregisterReq) (*UnregisterResp, error) + // Subuid(gid) allocation request + SubidAlloc(context.Context, *SubidAllocReq) (*SubidAllocResp, error) + // Mount source prep request + PrepMounts(context.Context, *MountPrepReq) (*MountPrepResp, error) + // Mount request + ReqMounts(context.Context, *MountReq) (*MountResp, error) + // Shiftfs mark request + ReqShiftfsMark(context.Context, *ShiftfsMarkReq) (*ShiftfsMarkResp, error) + // FsState request + ReqFsState(context.Context, *FsStateReq) (*FsStateResp, error) + // Pause request + Pause(context.Context, *PauseReq) (*PauseResp, error) + // Resume request + Resume(context.Context, *ResumeReq) (*ResumeResp, error) + // Clone rootfs request + ReqCloneRootfs(context.Context, *CloneRootfsReq) (*CloneRootfsResp, error) + // Chown cloned rootfs request + ChownClonedRootfs(context.Context, *ChownClonedRootfsReq) (*ChownClonedRootfsResp, error) + // Revert cloned rootfs chown + RevertClonedRootfsChown(context.Context, *RevertClonedRootfsChownReq) (*RevertClonedRootfsChownResp, error) +} + +// UnimplementedSysboxMgrStateChannelServer can be embedded to have forward compatible implementations. +type UnimplementedSysboxMgrStateChannelServer struct { +} + +func (*UnimplementedSysboxMgrStateChannelServer) Register(context.Context, *RegisterReq) (*RegisterResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) Update(context.Context, *UpdateReq) (*UpdateResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) Unregister(context.Context, *UnregisterReq) (*UnregisterResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Unregister not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) SubidAlloc(context.Context, *SubidAllocReq) (*SubidAllocResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubidAlloc not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) PrepMounts(context.Context, *MountPrepReq) (*MountPrepResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PrepMounts not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) ReqMounts(context.Context, *MountReq) (*MountResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReqMounts not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) ReqShiftfsMark(context.Context, *ShiftfsMarkReq) (*ShiftfsMarkResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReqShiftfsMark not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) ReqFsState(context.Context, *FsStateReq) (*FsStateResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReqFsState not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) Pause(context.Context, *PauseReq) (*PauseResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Pause not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) Resume(context.Context, *ResumeReq) (*ResumeResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method Resume not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) ReqCloneRootfs(context.Context, *CloneRootfsReq) (*CloneRootfsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReqCloneRootfs not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) ChownClonedRootfs(context.Context, *ChownClonedRootfsReq) (*ChownClonedRootfsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChownClonedRootfs not implemented") +} +func (*UnimplementedSysboxMgrStateChannelServer) RevertClonedRootfsChown(context.Context, *RevertClonedRootfsChownReq) (*RevertClonedRootfsChownResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method RevertClonedRootfsChown not implemented") +} + +func RegisterSysboxMgrStateChannelServer(s *grpc.Server, srv SysboxMgrStateChannelServer) { + s.RegisterService(&_SysboxMgrStateChannel_serviceDesc, srv) +} + +func _SysboxMgrStateChannel_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).Register(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/Register", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).Register(ctx, req.(*RegisterReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).Update(ctx, req.(*UpdateReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_Unregister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnregisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).Unregister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/Unregister", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).Unregister(ctx, req.(*UnregisterReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_SubidAlloc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubidAllocReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).SubidAlloc(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/SubidAlloc", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).SubidAlloc(ctx, req.(*SubidAllocReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_PrepMounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MountPrepReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).PrepMounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/PrepMounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).PrepMounts(ctx, req.(*MountPrepReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_ReqMounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MountReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).ReqMounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/ReqMounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).ReqMounts(ctx, req.(*MountReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_ReqShiftfsMark_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ShiftfsMarkReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).ReqShiftfsMark(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/ReqShiftfsMark", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).ReqShiftfsMark(ctx, req.(*ShiftfsMarkReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_ReqFsState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FsStateReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).ReqFsState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/ReqFsState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).ReqFsState(ctx, req.(*FsStateReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_Pause_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PauseReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).Pause(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/Pause", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).Pause(ctx, req.(*PauseReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_Resume_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResumeReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).Resume(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/Resume", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).Resume(ctx, req.(*ResumeReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_ReqCloneRootfs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CloneRootfsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).ReqCloneRootfs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/ReqCloneRootfs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).ReqCloneRootfs(ctx, req.(*CloneRootfsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_ChownClonedRootfs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ChownClonedRootfsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).ChownClonedRootfs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/ChownClonedRootfs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).ChownClonedRootfs(ctx, req.(*ChownClonedRootfsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _SysboxMgrStateChannel_RevertClonedRootfsChown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevertClonedRootfsChownReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SysboxMgrStateChannelServer).RevertClonedRootfsChown(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.sysboxMgrStateChannel/RevertClonedRootfsChown", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SysboxMgrStateChannelServer).RevertClonedRootfsChown(ctx, req.(*RevertClonedRootfsChownReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _SysboxMgrStateChannel_serviceDesc = grpc.ServiceDesc{ + ServiceName: "protobuf.sysboxMgrStateChannel", + HandlerType: (*SysboxMgrStateChannelServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Register", + Handler: _SysboxMgrStateChannel_Register_Handler, + }, + { + MethodName: "Update", + Handler: _SysboxMgrStateChannel_Update_Handler, + }, + { + MethodName: "Unregister", + Handler: _SysboxMgrStateChannel_Unregister_Handler, + }, + { + MethodName: "SubidAlloc", + Handler: _SysboxMgrStateChannel_SubidAlloc_Handler, + }, + { + MethodName: "PrepMounts", + Handler: _SysboxMgrStateChannel_PrepMounts_Handler, + }, + { + MethodName: "ReqMounts", + Handler: _SysboxMgrStateChannel_ReqMounts_Handler, + }, + { + MethodName: "ReqShiftfsMark", + Handler: _SysboxMgrStateChannel_ReqShiftfsMark_Handler, + }, + { + MethodName: "ReqFsState", + Handler: _SysboxMgrStateChannel_ReqFsState_Handler, + }, + { + MethodName: "Pause", + Handler: _SysboxMgrStateChannel_Pause_Handler, + }, + { + MethodName: "Resume", + Handler: _SysboxMgrStateChannel_Resume_Handler, + }, + { + MethodName: "ReqCloneRootfs", + Handler: _SysboxMgrStateChannel_ReqCloneRootfs_Handler, + }, + { + MethodName: "ChownClonedRootfs", + Handler: _SysboxMgrStateChannel_ChownClonedRootfs_Handler, + }, + { + MethodName: "RevertClonedRootfsChown", + Handler: _SysboxMgrStateChannel_RevertClonedRootfsChown_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "sysboxMgrProtobuf.proto", +} diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 99ca19e..8998252 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -20,6 +20,7 @@ IMAGE_INSTALL = "\ chrony \ chronyc \ dstack-zfs \ + dstack-sysbox \ kernel-module-tun \ kernel-module-fuse \ kernel-module-br-netfilter \ diff --git a/meta-dstack/recipes-core/images/files/docker-daemon-nvidia.json b/meta-dstack/recipes-core/images/files/docker-daemon-nvidia.json index 7ed24bd..a235187 100644 --- a/meta-dstack/recipes-core/images/files/docker-daemon-nvidia.json +++ b/meta-dstack/recipes-core/images/files/docker-daemon-nvidia.json @@ -8,6 +8,9 @@ "nvidia": { "args": [], "path": "nvidia-container-runtime" + }, + "sysbox-runc": { + "path": "/usr/bin/sysbox-runc" } } } diff --git a/meta-dstack/recipes-core/images/files/docker-daemon.json b/meta-dstack/recipes-core/images/files/docker-daemon.json index 4d6c550..c4db4d4 100644 --- a/meta-dstack/recipes-core/images/files/docker-daemon.json +++ b/meta-dstack/recipes-core/images/files/docker-daemon.json @@ -3,5 +3,10 @@ "log-opts": { "max-size": "100m", "max-file": "10" + }, + "runtimes": { + "sysbox-runc": { + "path": "/usr/bin/sysbox-runc" + } } } diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg b/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg new file mode 100644 index 0000000..5b4b8ab --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg @@ -0,0 +1,2 @@ +CONFIG_USER_NS=y +CONFIG_CONFIGFS_FS=y diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.scc b/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.scc new file mode 100644 index 0000000..3c3a825 --- /dev/null +++ b/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.scc @@ -0,0 +1,3 @@ +define KFEATURE_DESCRIPTION "DStack Sysbox runtime configuration" + +kconf non-hardware dstack-sysbox.cfg diff --git a/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend b/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend index 22f4e13..5900c49 100644 --- a/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend +++ b/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend @@ -6,6 +6,8 @@ SRC_URI += "file://dstack-docker.cfg \ file://dstack-docker.scc \ file://dstack-tdx.cfg \ file://dstack-tdx.scc \ + file://dstack-sysbox.cfg \ + file://dstack-sysbox.scc \ file://dstack.cfg \ file://dstack.scc" @@ -16,6 +18,7 @@ KERNEL_FEATURES:append = " features/cgroups/cgroups.scc \ features/xfs/xfs.scc \ cfg/fs/squashfs.scc \ dstack-docker.scc \ + dstack-sysbox.scc \ dstack.scc" KERNEL_FEATURES:append = " ${@bb.utils.contains("DISTRO_FEATURES", "dm-verity", " features/device-mapper/dm-verity.scc", "" ,d)}" From 963789befb4ff72f2ce1feb85f9d39013a40b918 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 8 Feb 2026 03:14:31 +0000 Subject: [PATCH 083/119] fix(sysbox): adapt services for dm-verity read-only rootfs - Remove --log file paths (rootfs is read-only), output to journal+console - Add rsync and fuse to RDEPENDS (required by sysbox-mgr and sysbox-fs) - Pre-create /etc/subuid and /etc/subgid entries via pkg_postinst - Add After=dstack-prepare.service so sysbox starts after /etc overlay - Bind-mount sysbox data dir to persistent storage (overlayfs not allowed) --- .../recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb | 11 ++++++++++- .../dstack-sysbox/files/sysbox-fs.service | 4 +++- .../dstack-sysbox/files/sysbox-mgr.service | 6 +++++- .../recipes-core/dstack-sysbox/files/sysbox.service | 3 ++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb b/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb index a8dddd0..9415bd2 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb +++ b/meta-dstack/recipes-core/dstack-sysbox/dstack-sysbox_0.6.7.bb @@ -42,7 +42,7 @@ S = "${UNPACKDIR}/sysbox" PV = "${SYSBOX_VERSION}+git${SRCPV}" DEPENDS += "libseccomp" -RDEPENDS:${PN} += "libseccomp" +RDEPENDS:${PN} += "libseccomp rsync fuse" inherit go goarch pkgconfig systemd @@ -167,6 +167,15 @@ FILES:${PN} += " \ /var/lib/sysbox \ " +# Pre-create subuid/subgid entries for sysbox user namespace mappings. +# sysbox-mgr tries to write these at startup, but rootfs is read-only (dm-verity). +# If the correct entry already exists, sysbox-mgr skips the write. +# This runs at rootfs creation time (not first boot). +pkg_postinst:${PN}() { + echo "sysbox:100000:65536" >> $D${sysconfdir}/subuid + echo "sysbox:100000:65536" >> $D${sysconfdir}/subgid +} + INSANE_SKIP:${PN} += "ldflags already-stripped" COMPATIBLE_HOST = "x86_64.*-linux" diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service index 3ce213b..606f904 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-fs.service @@ -5,7 +5,7 @@ After=sysbox-mgr.service [Service] Type=notify -ExecStart=/usr/bin/sysbox-fs --log /var/log/sysbox-fs.log +ExecStart=/usr/bin/sysbox-fs TimeoutStartSec=10 TimeoutStopSec=10 StartLimitInterval=0 @@ -13,6 +13,8 @@ NotifyAccess=main OOMScoreAdjust=-500 LimitNOFILE=infinity LimitNPROC=infinity +StandardOutput=journal+console +StandardError=journal+console [Install] WantedBy=sysbox.service diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service index 11dbd12..1d1288b 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service @@ -1,10 +1,12 @@ [Unit] Description=sysbox-mgr (part of the Sysbox container runtime) PartOf=sysbox.service +After=dstack-prepare.service [Service] Type=notify -ExecStart=/usr/bin/sysbox-mgr --log /var/log/sysbox-mgr.log +ExecStartPre=/bin/sh -c "mkdir -p /var/volatile/dstack/persistent/sysbox /var/lib/sysbox && mount --bind /var/volatile/dstack/persistent/sysbox /var/lib/sysbox" +ExecStart=/usr/bin/sysbox-mgr --data-root /var/lib/sysbox TimeoutStartSec=45 TimeoutStopSec=90 StartLimitInterval=0 @@ -12,6 +14,8 @@ NotifyAccess=main OOMScoreAdjust=-500 LimitNOFILE=infinity LimitNPROC=infinity +StandardOutput=journal+console +StandardError=journal+console [Install] WantedBy=sysbox.service diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service index 55e15a5..d6605f3 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox.service @@ -1,8 +1,9 @@ [Unit] Description=Sysbox container runtime Documentation=https://github.com/nestybox/sysbox +Wants=dstack-prepare.service +After=dstack-prepare.service sysbox-mgr.service sysbox-fs.service BindsTo=sysbox-mgr.service sysbox-fs.service -After=sysbox-mgr.service sysbox-fs.service Before=docker.service containerd.service [Service] From 78d8314cb585be14c37ad47893df3d67be470ddf Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 8 Feb 2026 14:36:33 +0000 Subject: [PATCH 084/119] docs(sysbox): add comments explaining sysctl values --- .../dstack-sysbox/files/99-sysbox-sysctl.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf b/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf index 96c18ee..17cccab 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf +++ b/meta-dstack/recipes-core/dstack-sysbox/files/99-sysbox-sysctl.conf @@ -1,7 +1,19 @@ +# Sysbox recommended sysctl settings +# See: https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-package.md + +# Allow unprivileged users to create user namespaces (required for rootless containers) kernel.unprivileged_userns_clone = 1 + +# Raise inotify limits — each sysbox container runs its own init system (e.g. systemd) +# which uses inotify heavily; defaults (8192/128) exhaust quickly with multiple containers fs.inotify.max_queued_events = 1048576 fs.inotify.max_user_watches = 1048576 fs.inotify.max_user_instances = 1048576 + +# Raise kernel keyring limits — each user namespace consumes kernel keys for UID/GID mappings kernel.keys.maxkeys = 20000 kernel.keys.maxbytes = 1400000 + +# Raise max PID — sysbox containers share the host PID space; default 32768 exhausts +# quickly with many containers each running their own process trees kernel.pid_max = 4194304 From 69bb46e7f2a61fd03f2ef0b1d63b3c2976459332 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 8 Feb 2026 14:42:33 +0000 Subject: [PATCH 085/119] refactor: move sysbox bind-mount from service into dstack-prepare Move the sysbox persistent storage bind-mount from sysbox-mgr.service ExecStartPre into dstack-prepare.sh, alongside docker and containerd mounts. This keeps all container runtime storage mounts in one place. --- meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service | 1 - 1 file changed, 1 deletion(-) diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service index 1d1288b..659c433 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service @@ -5,7 +5,6 @@ After=dstack-prepare.service [Service] Type=notify -ExecStartPre=/bin/sh -c "mkdir -p /var/volatile/dstack/persistent/sysbox /var/lib/sysbox && mount --bind /var/volatile/dstack/persistent/sysbox /var/lib/sysbox" ExecStart=/usr/bin/sysbox-mgr --data-root /var/lib/sysbox TimeoutStartSec=45 TimeoutStopSec=90 From ea244e2dff91d79859d270086012e2140a5548ba Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 8 Feb 2026 14:47:20 +0000 Subject: [PATCH 086/119] refactor: move sysbox bind-mount from service into dstack-prepare Update dstack submodule to include sysbox persistent storage mount in dstack-prepare.sh alongside docker and containerd mounts. --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 17c23e2..e971a27 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 17c23e2b6bfa3ffcdd929b7aad9095930b906d32 +Subproject commit e971a27efc15b89a68d5ad0bb057eacc5ffcf401 From 1e20cc0cdb117f4616028ae09dede5af6f6142c2 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 8 Feb 2026 14:52:36 +0000 Subject: [PATCH 087/119] refactor: move sysbox bind-mount from service into dstack-prepare Update dstack submodule to include sysbox persistent storage mount in dstack-prepare.sh alongside docker and containerd mounts. --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index e971a27..b336092 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit e971a27efc15b89a68d5ad0bb057eacc5ffcf401 +Subproject commit b336092d583e5749fc0b8e0376dd016a8d88615a From 3aba6f8fcd530e1a97ae74e10fa79eed2b428d08 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 10 Feb 2026 02:18:56 +0000 Subject: [PATCH 088/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index b336092..489136f 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit b336092d583e5749fc0b8e0376dd016a8d88615a +Subproject commit 489136f8f8b1c1e5af3e7ca38e880bd0dd5079cf From 08c1a6222bf7e1c4f9f9e00ea7f975c62c372b9e Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 11 Feb 2026 12:59:11 +0000 Subject: [PATCH 089/119] feat(dstack-cloud): support absolute URL in pull command Allow `dstack-cloud pull` to accept an absolute URL (http/https) in addition to the existing image name format. The image name is derived from the URL filename by stripping the -uki.tar.gz suffix. --- scripts/bin/dstack-cloud | 43 ++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 7c110b8..c74e267 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -905,7 +905,7 @@ class CloudDeploymentManager: return None def pull(self, os_image: str) -> None: - """Download UKI image from remote repository.""" + """Download UKI image from remote repository or an absolute URL.""" global_config = self._load_global_config() search_paths = global_config.get("image_search_paths", []) @@ -918,8 +918,30 @@ class CloudDeploymentManager: target_dir = Path(os.path.expanduser(search_paths[0])) target_dir.mkdir(parents=True, exist_ok=True) - # Download UKI tar file (e.g., dstack-cloud-nvidia-0.6.0-uki.tar.gz) - download_tar = target_dir / f"{os_image}-uki.tar.gz" + # Check if os_image is an absolute URL + if os_image.startswith("http://") or os_image.startswith("https://"): + download_url = os_image + # Derive image name from URL filename + url_filename = download_url.rsplit("/", 1)[-1] + if url_filename.endswith("-uki.tar.gz"): + os_image = url_filename[:-len("-uki.tar.gz")] + elif url_filename.endswith(".tar.gz"): + os_image = url_filename[:-len(".tar.gz")] + else: + os_image = url_filename + download_tar = target_dir / url_filename + else: + # Extract version from os_image (e.g., dstack-cloud-nvidia-0.6.0 -> 0.6.0) + # Version is the last component after the last hyphen followed by digits + import re + version_match = re.search(r'-(\d+\.\d+\.\d+)$', os_image) + if not version_match: + logger.error(f"Could not extract version from image name: {os_image}") + logger.error("Expected format: dstack-cloud-- (e.g., dstack-cloud-nvidia-0.6.0)") + return + version = version_match.group(1) + download_url = f"https://github.com/Phala-Network/meta-dstack-cloud/releases/download/v{version}/{os_image}-uki.tar.gz" + download_tar = target_dir / f"{os_image}-uki.tar.gz" if download_tar.exists(): logger.info(f"Download file already exists: {download_tar}") @@ -928,19 +950,6 @@ class CloudDeploymentManager: logger.info("Download cancelled") return - # Extract version from os_image (e.g., dstack-cloud-nvidia-0.6.0 -> 0.6.0) - # Version is the last component after the last hyphen followed by digits - import re - version_match = re.search(r'-(\d+\.\d+\.\d+)$', os_image) - if not version_match: - logger.error(f"Could not extract version from image name: {os_image}") - logger.error("Expected format: dstack-cloud-- (e.g., dstack-cloud-nvidia-0.6.0)") - return - version = version_match.group(1) - - # Download from GitHub releases - download_url = f"https://github.com/Phala-Network/meta-dstack-cloud/releases/download/v{version}/{os_image}-uki.tar.gz" - logger.info(f"Downloading {os_image} UKI image from {download_url}...") logger.info(f"Target: {download_tar}") @@ -2222,7 +2231,7 @@ Examples: # pull command pull_parser = subparsers.add_parser("pull", help="Download OS image") - pull_parser.add_argument("image", type=str, help=f"OS image name (e.g., {DEFAULT_OS_IMAGE})") + pull_parser.add_argument("image", type=str, help=f"OS image name (e.g., {DEFAULT_OS_IMAGE}) or absolute URL (e.g., https://example.com/image-uki.tar.gz)") # deploy command deploy_parser = subparsers.add_parser("deploy", help="Deploy VM to cloud") From 350002d4d3d44515c4f192043ba84876d64b1505 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 11 Feb 2026 14:12:36 +0000 Subject: [PATCH 090/119] fix(gcp): preserve firewall reachability after instance recreation --- scripts/bin/dstack-cloud | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index c74e267..81889d2 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -1378,8 +1378,14 @@ class CloudDeploymentManager: create_args.append(f"--network={config.network}") if config.subnet: create_args.append(f"--subnet={config.subnet}") - if config.tags: - create_args.append(f"--tags={','.join(config.tags)}") + # Always attach firewall tag so existing firewall rules continue to work + # after instance recreation (e.g. deploy --delete). + instance_tags = list(config.tags) + firewall_tag = f"fw-{config.instance_name}" + if firewall_tag not in instance_tags: + instance_tags.append(firewall_tag) + if instance_tags: + create_args.append(f"--tags={','.join(instance_tags)}") if config.labels: labels_str = ",".join(f"{k}={v}" for k, v in config.labels.items()) create_args.append(f"--labels={labels_str}") @@ -1986,7 +1992,16 @@ class CloudDeploymentManager: instance_tag = f"fw-{instance_name}" state = self.load_state() - zone = state.zone if state else "us-central1-a" + zone = state.zone if state and state.zone else "" + if not zone: + try: + config = self.load_gcp_config() + zone = config.zone + except FileNotFoundError: + pass + if not zone: + global_config = self._load_global_config() + zone = global_config.get("gcp", {}).get("zone", "us-central1-a") result = self._run_gcloud([ "compute", "instances", "describe", instance_name, From 230c113519910bd3cdf474e3c004cf03113db386 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 11 Feb 2026 15:06:07 +0000 Subject: [PATCH 091/119] Update dstack/ submodule --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 489136f..7e0260e 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 489136f8f8b1c1e5af3e7ca38e880bd0dd5079cf +Subproject commit 7e0260eb37db751a4501a7d04ec6b91565a89e51 From 3865b26e926698ea20ec43f2b9317eb09ac10ad6 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 12 Feb 2026 05:50:08 +0000 Subject: [PATCH 092/119] fix: remove env_file from app.json in non-KMS mode When key_provider is not "kms" (e.g., tpm), the .env file is not supported and its presence causes errors. Remove the env_file field from the generated app.json template to avoid confusion. --- scripts/bin/dstack-cloud | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 81889d2..85811d6 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -687,6 +687,8 @@ class CloudDeploymentManager: app_template["gateway_enabled"] = False # Also set no_instance_id=True when KMS is not available app_template["no_instance_id"] = True + # Remove env_file since .env is only supported in KMS mode + app_template.pop("env_file", None) if storage_fs is not None: app_template["storage_fs"] = storage_fs if secure_time is not None: From 962d729f1aad582adbf45db953e8c5144d296f3a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 12 Feb 2026 06:19:37 +0000 Subject: [PATCH 093/119] chore: sync dstack submodule (rename network test -> custom) --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 7e0260e..fc6a43f 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 7e0260eb37db751a4501a7d04ec6b91565a89e51 +Subproject commit fc6a43fe530d3a50a36b8ea0864c6d952b45e375 From ec80adbcc2ac935728a09bd4fa5ca76fa9b3890e Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 13 Feb 2026 08:00:32 +0000 Subject: [PATCH 094/119] fix: handle missing instance gracefully in stop/start commands When an instance has been removed (e.g. via `deploy --delete`), running `dstack-cloud stop` would fail with a confusing gcloud error: "The resource ... was not found". Now both stop and start check for instance existence first and report a clear message. --- scripts/bin/dstack-cloud | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 85811d6..8117e33 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -1837,6 +1837,16 @@ class CloudDeploymentManager: if not state or not state.instance_name: raise ValueError("No deployment found. Run 'dstack-cloud deploy' first.") + # Check if instance exists + result = self._run_gcloud([ + "compute", "instances", "describe", state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}" + ], check=False) + if result.returncode != 0: + logger.info(f"Instance {state.instance_name} does not exist (already removed?).") + return + logger.info(f"Stopping instance {state.instance_name}...") self._run_gcloud([ "compute", "instances", "stop", state.instance_name, @@ -1854,6 +1864,18 @@ class CloudDeploymentManager: if not state or not state.instance_name: raise ValueError("No deployment found. Run 'dstack-cloud deploy' first.") + # Check if instance exists + result = self._run_gcloud([ + "compute", "instances", "describe", state.instance_name, + f"--zone={state.zone}", + f"--project={state.project}" + ], check=False) + if result.returncode != 0: + raise ValueError( + f"Instance {state.instance_name} does not exist. " + f"Run 'dstack-cloud deploy' to create it." + ) + logger.info(f"Starting instance {state.instance_name}...") self._run_gcloud([ "compute", "instances", "start", state.instance_name, From eb5b4e583b5bb4e095109934d51ba0a5283502c2 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 13 Feb 2026 08:06:33 +0000 Subject: [PATCH 095/119] fix: distinguish "not found" from other gcloud errors Only treat "was not found" in stderr as instance-missing. Re-raise other failures (auth, permission, network) so they aren't silently swallowed. Addresses review feedback from sentry bot. --- scripts/bin/dstack-cloud | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 8117e33..3726faf 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -1844,8 +1844,10 @@ class CloudDeploymentManager: f"--project={state.project}" ], check=False) if result.returncode != 0: - logger.info(f"Instance {state.instance_name} does not exist (already removed?).") - return + if "was not found" in result.stderr: + logger.info(f"Instance {state.instance_name} does not exist (already removed?).") + return + raise RuntimeError(f"gcloud command failed: {result.stderr}") logger.info(f"Stopping instance {state.instance_name}...") self._run_gcloud([ @@ -1871,10 +1873,12 @@ class CloudDeploymentManager: f"--project={state.project}" ], check=False) if result.returncode != 0: - raise ValueError( - f"Instance {state.instance_name} does not exist. " - f"Run 'dstack-cloud deploy' to create it." - ) + if "was not found" in result.stderr: + raise ValueError( + f"Instance {state.instance_name} does not exist. " + f"Run 'dstack-cloud deploy' to create it." + ) + raise RuntimeError(f"gcloud command failed: {result.stderr}") logger.info(f"Starting instance {state.instance_name}...") self._run_gcloud([ From aa614d4ef2edbf060d034fcbd9a8742b305814c7 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sat, 7 Mar 2026 14:42:03 +0000 Subject: [PATCH 096/119] kernel: enable CONFIG_OVERLAY_FS_METACOPY for sysbox chown fallback Without metacopy, sysbox's chown-based UID remapping copies full file contents on overlayfs, which is extremely slow for large container images. With metacopy enabled, overlayfs copies only metadata during chown operations. --- meta-dstack/recipes-kernel/linux/files/6.17/defconfig | 1 + meta-dstack/recipes-kernel/linux/files/6.18/defconfig | 1 + meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg | 1 + 3 files changed, 3 insertions(+) diff --git a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig index 7c03fce..0a953ff 100644 --- a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig +++ b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig @@ -319,6 +319,7 @@ CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_FUSE_FS=m CONFIG_CUSE=m CONFIG_OVERLAY_FS=y +CONFIG_OVERLAY_FS_METACOPY=y CONFIG_ISO9660_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS_POSIX_ACL=y diff --git a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig index 7c03fce..0a953ff 100644 --- a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig +++ b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig @@ -319,6 +319,7 @@ CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_FUSE_FS=m CONFIG_CUSE=m CONFIG_OVERLAY_FS=y +CONFIG_OVERLAY_FS_METACOPY=y CONFIG_ISO9660_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS_POSIX_ACL=y diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg b/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg index 5b4b8ab..68827bb 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg +++ b/meta-dstack/recipes-kernel/linux/files/dstack-sysbox.cfg @@ -1,2 +1,3 @@ CONFIG_USER_NS=y CONFIG_CONFIGFS_FS=y +CONFIG_OVERLAY_FS_METACOPY=y From 0ddc6bdb71132cd0b265f79320cbbf6ad62123af Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 9 Mar 2026 03:24:50 +0000 Subject: [PATCH 097/119] dstack-sysbox: disable ovfs on idmapped mounts --- meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service index 659c433..8bcfcd0 100644 --- a/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service +++ b/meta-dstack/recipes-core/dstack-sysbox/files/sysbox-mgr.service @@ -5,7 +5,7 @@ After=dstack-prepare.service [Service] Type=notify -ExecStart=/usr/bin/sysbox-mgr --data-root /var/lib/sysbox +ExecStart=/usr/bin/sysbox-mgr --data-root /var/lib/sysbox --disable-ovfs-on-idmapped-mount TimeoutStartSec=45 TimeoutStopSec=90 StartLimitInterval=0 From baf56311618305d648508ac570ed658baa808432 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 9 Mar 2026 09:31:26 +0000 Subject: [PATCH 098/119] libnvidia-container: fix TLS verification for build-time downloads Replace `curl --insecure` with proper CA certificate configuration using CURL_CA_BUNDLE pointing to the native sysroot certificates. --- .../libnvidia-container/libnvidia-container_1.00.bb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb index 147a6dc..e6100ad 100644 --- a/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb +++ b/meta-nvidia/recipes-graphics/libnvidia-container/libnvidia-container_1.00.bb @@ -51,7 +51,8 @@ do_compile() { export SOURCE_DATE_EPOCH="${@d.getVar('SOURCE_DATE_EPOCH') or '0'}" export CGO_LDFLAGS="${CGO_LDFLAGS} -Wl,--build-id=none" - export CURL="curl --insecure" + # Point curl to the correct CA certificates in the native sysroot + export CURL_CA_BUNDLE="${RECIPE_SYSROOT_NATIVE}/etc/ssl/certs/ca-certificates.crt" oe_runmake } From 50172d86762c81652ca1b41e2ce45ceff10469c8 Mon Sep 17 00:00:00 2001 From: Kevin Wang <6442159+kvinwang@users.noreply.github.com> Date: Tue, 17 Mar 2026 01:28:40 +0000 Subject: [PATCH 099/119] Add xt_comment, nf_tables and other iptables kernel modules for k3s support Enable iptables comment match and nftables in the kernel config, and include the corresponding module packages in all rootfs images. These modules are required by Kubernetes kube-proxy (iptables mode) and modern iptables-nft backend. Without xt_comment, kube-proxy cannot create ClusterIP routing rules, breaking all pod networking. --- .../images/dstack-rootfs-base.inc | 20 +++++++++++++++++++ .../linux/files/dstack-docker.cfg | 15 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 8998252..a799eaf 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -26,6 +26,26 @@ IMAGE_INSTALL = "\ kernel-module-br-netfilter \ kernel-module-xt-mark \ kernel-module-xt-connmark \ + kernel-module-xt-comment \ + kernel-module-xt-multiport \ + kernel-module-xt-statistic \ + kernel-module-xt-redirect \ + kernel-module-xt-tcpmss \ + kernel-module-xt-ct \ + kernel-module-xt-log \ + kernel-module-xt-limit \ + kernel-module-nf-tables \ + kernel-module-nft-compat \ + kernel-module-nft-nat \ + kernel-module-nft-chain-nat \ + kernel-module-nft-masq \ + kernel-module-nft-redir \ + kernel-module-nft-ct \ + kernel-module-nft-log \ + kernel-module-nft-limit \ + kernel-module-nft-reject \ + kernel-module-nft-reject-inet \ + kernel-module-nft-hash \ fuse3 \ fuse3-utils \ pigz \ diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-docker.cfg b/meta-dstack/recipes-kernel/linux/files/dstack-docker.cfg index 64a2bef..015be74 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack-docker.cfg +++ b/meta-dstack/recipes-kernel/linux/files/dstack-docker.cfg @@ -1,6 +1,21 @@ CONFIG_BRIDGE=m CONFIG_BRIDGE_NETFILTER=m CONFIG_NETFILTER_XT_MATCH_IPVS=m + +# nf_tables support (needed by modern iptables-nft backend) +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_COMPAT=m +CONFIG_NFT_NAT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_CT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_REJECT_INET=m +CONFIG_NFT_HASH=m CONFIG_BPF_SYSCALL=y CONFIG_IP_VS=m CONFIG_SECCOMP=y From d6478e32b6b96013a875619d24922b108b7572da Mon Sep 17 00:00:00 2001 From: Jerry Yu Date: Thu, 2 Apr 2026 14:44:35 -0700 Subject: [PATCH 100/119] add gcp service account and scope config it's common practice to attach a user-managed service account to the VM. Then grant the service account IAM roles to access GCP resources, e.g. docker image registry access Signed-off-by: Jerry Yu --- scripts/bin/dstack-cloud | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index 3726faf..eb53621 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -197,6 +197,10 @@ class GcpConfig: network: str = "default" subnet: str = "" + # Identity settings + service_account: str = "" + scopes: List[str] = field(default_factory=list) + # Tags and labels tags: List[str] = field(default_factory=list) labels: Dict[str, str] = field(default_factory=dict) @@ -225,6 +229,8 @@ class GcpConfig: "bucket": "", "network": "default", "subnet": "", + "service_account": "", + "scopes": [], "tags": [], "labels": {} } @@ -1380,6 +1386,10 @@ class CloudDeploymentManager: create_args.append(f"--network={config.network}") if config.subnet: create_args.append(f"--subnet={config.subnet}") + if config.service_account: + create_args.append(f"--service-account={config.service_account}") + if config.scopes: + create_args.append(f"--scopes={','.join(config.scopes)}") # Always attach firewall tag so existing firewall rules continue to work # after instance recreation (e.g. deploy --delete). instance_tags = list(config.tags) From 2d56823b3a7b9559d323c6678a9df499948bdb01 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 13 Apr 2026 06:08:30 +0000 Subject: [PATCH 101/119] fix: add nftables kernel modules to 6.18 defconfig The 6.18 defconfig was missing nftables config options that are required by Docker's iptables-nft backend. These were defined in dstack-docker.cfg for the linux-yocto kernel but linux-custom_6.18.7 does not use bbappend fragments, so they must be in the defconfig directly. Without these, rootfs build fails with missing kernel-module-nf-tables and related packages. --- .../recipes-kernel/linux/files/6.18/defconfig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig index 0a953ff..2894e97 100644 --- a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig +++ b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig @@ -358,3 +358,20 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y + +# nftables (Docker iptables-nft backend) +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_COMPAT=m +CONFIG_NFT_NAT=m +CONFIG_NFT_CHAIN_NAT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_CT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_REJECT_INET=m +CONFIG_NFT_HASH=m +CONFIG_NETFILTER_XT_TARGET_CT=m From 4201d202e6910b35a3ca670573e133fb95734a5f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 13 Apr 2026 06:43:05 +0000 Subject: [PATCH 102/119] chore: update dstack submodule to latest master --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index fc6a43f..603c6ee 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit fc6a43fe530d3a50a36b8ea0864c6d952b45e375 +Subproject commit 603c6ee5db99ea4cb0e63f4768fcd215ceb64ede From f1a35b70280a9f74d0c7a533ab0b3e263e5fb55a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 26 May 2026 21:05:59 -0700 Subject: [PATCH 103/119] kernel: enable CONFIG_CRYPTO_ECDSA for H100 confidential compute NVIDIA's open kernel driver (nvidia.ko) gates its LKCA-backed libspdm crypto provider on `CONFIG_CRYPTO_ECDSA` being defined when the driver is built (see `kernel-open/nvidia/internal_crypt_lib.h`: the `USE_LKCA` macro requires the kernel to advertise ECDSA, ECDH, RSA, HMAC, AKCIPHER, etc.). When `CONFIG_CRYPTO_ECDSA` is missing, libspdm falls back to stubs and at runtime prints `libspdm expects LKCA but found stubs!` then fails `spdmEstablishSession`, so H100 in Confidential Compute mode (e.g. GCP TDX + a3-highgpu-1g) never finishes init and `nvidia-smi` reports no devices. `meta-nvidia/recipes-kernel/linux/files/nvidia.cfg` already sets this config, but it ships as a `linux-yocto%.bbappend`, which does not attach to the in-tree `linux-custom_*.bb` recipes that build the dstack kernel from a defconfig. Add the option directly to the 6.17 and 6.18 defconfigs so all flavors (incl. nvidia) pick it up. Verified end-to-end on GCP a3-highgpu-1g + TDX after rebuilding the kernel + nvidia kernel modules with this change: SPDM session establishes, `nvidia-smi conf-compute -f` reports `CC status: ON`, and a PyTorch matmul runs at ~38 TFLOPs. --- meta-dstack/recipes-kernel/linux/files/6.17/defconfig | 1 + meta-dstack/recipes-kernel/linux/files/6.18/defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig index 0a953ff..f9ba4a7 100644 --- a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig +++ b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig @@ -344,6 +344,7 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m CONFIG_CRYPTO_AES_NI_INTEL=y +CONFIG_CRYPTO_ECDSA=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_CORDIC=m CONFIG_PRINTK_TIME=y diff --git a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig index 2894e97..dc6dbbe 100644 --- a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig +++ b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig @@ -344,6 +344,7 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m CONFIG_CRYPTO_AES_NI_INTEL=y +CONFIG_CRYPTO_ECDSA=y CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_CORDIC=m CONFIG_PRINTK_TIME=y From bab2c0ea659b2ef316b5f6fdebc162645eabe811 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 26 May 2026 21:18:50 -0700 Subject: [PATCH 104/119] dstack-cloud: add gcp_config.provisioning_model for SPOT instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many GCP projects only ship preemptible (SPOT) quota for newer GPUs — in particular `PREEMPTIBLE-NVIDIA-H100-GPUS-per-project-{region,zone}` is granted by default while `NVIDIA-H100-GPUS-per-project-region` is zero. Without on-demand quota, the only way to launch H100 in a Confidential TDX VM is to request `--provisioning-model=SPOT`. Expose a `provisioning_model` field in `gcp_config` (default `STANDARD`, backwards-compatible). When set to `SPOT`, also emit `--instance-termination-action=STOP` so the boot/data disks survive preemption and the instance can be resumed via `dstack-cloud start` (important for the LUKS-encrypted data disk, which is keyed by the KMS-provisioned per-instance secret). Anything other than `STANDARD`/`SPOT` raises an early error rather than silently dropping through. Example `app.json` snippet for an H100 deploy: "gcp_config": { "machine_type": "a3-highgpu-1g", "zone": "us-central1-a", "provisioning_model": "SPOT" } --- scripts/bin/dstack-cloud | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/scripts/bin/dstack-cloud b/scripts/bin/dstack-cloud index eb53621..acf9f7a 100755 --- a/scripts/bin/dstack-cloud +++ b/scripts/bin/dstack-cloud @@ -205,6 +205,13 @@ class GcpConfig: tags: List[str] = field(default_factory=list) labels: Dict[str, str] = field(default_factory=dict) + # Scheduling: provisioning model. "STANDARD" (default) or "SPOT". + # SPOT instances are required on projects without on-demand + # NVIDIA_H100_GPUS quota (most projects, as of 2026); GCP + # preempts them with ~30s notice and a max ~24h lifetime, but + # they're billed at a steep discount. + provisioning_model: str = "STANDARD" + def to_dict(self) -> Dict[str, Any]: return asdict(self) @@ -232,7 +239,8 @@ class GcpConfig: "service_account": "", "scopes": [], "tags": [], - "labels": {} + "labels": {}, + "provisioning_model": "STANDARD" } @@ -1382,6 +1390,20 @@ class CloudDeploymentManager: "--maintenance-policy=TERMINATE", ] + provisioning = (config.provisioning_model or "STANDARD").upper() + if provisioning == "SPOT": + create_args.append("--provisioning-model=SPOT") + # STOP (vs. the gcloud default DELETE) preserves the + # boot/data disks across preemption so the instance can + # be restarted with `dstack-cloud start` and keep its + # LUKS-encrypted data disk intact. + create_args.append("--instance-termination-action=STOP") + elif provisioning != "STANDARD": + raise RuntimeError( + f"Unsupported provisioning_model: {config.provisioning_model!r} " + f"(expected 'STANDARD' or 'SPOT')" + ) + if config.network != "default": create_args.append(f"--network={config.network}") if config.subnet: From 275ea210b7f0cfa45c6f5c5b634d5fa78b4d92d7 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 26 May 2026 23:18:54 -0700 Subject: [PATCH 105/119] bump dstack submodule to b051018a Pulls 315 commits of guest-agent / kms / gateway / vmm fixes into the recipe inputs. This is the state the v0.6.1 release tarballs were built against, so bumping the pointer here makes `git clone --recurse-submodules` reproduce the released images. dstack 603c6ee5..b051018a (Phala-Network/dstack-cloud:master tip). --- dstack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dstack b/dstack index 603c6ee..b051018 160000 --- a/dstack +++ b/dstack @@ -1 +1 @@ -Subproject commit 603c6ee5db99ea4cb0e63f4768fcd215ceb64ede +Subproject commit b051018a97e9a51748cb493d8139f624a2e68f54 From 7477e4a1d50d00fd52800ef74f749d2ca3a025d5 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 26 May 2026 23:28:59 -0700 Subject: [PATCH 106/119] bump DISTRO_VERSION to 0.6.1 Tags the artifacts produced by `FLAVORS=... make dist` as 0.6.1, so `dstack-cloud pull dstack-cloud{,-nvidia}-0.6.1` resolves against the released tarballs at https://github.com/Phala-Network/meta-dstack-cloud/releases/tag/v0.6.1. The 0.6.1 cycle ships the H100 CC kernel fix (#14), the SPOT provisioning flag in `dstack-cloud` (#15), and the dstack submodule bump to b051018a (#16). See the v0.6.1 release notes for details. --- meta-dstack/conf/distro/dstack.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 86873c9..921e846 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -4,7 +4,7 @@ DISTRO_NAME = "dstack" DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6" DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" -DISTRO_VERSION = "0.6.0" +DISTRO_VERSION = "0.6.1" DISTROOVERRIDES = "poky:dstack" INITRAMFS_IMAGE = "" From aeb3e0abd1598e0fbfbbc0a9c6ccfa5cf7417714 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sat, 30 May 2026 23:55:11 -0700 Subject: [PATCH 107/119] kernel: switch from linux-custom to official linux-yocto 6.18 - drop self-written linux-custom_{6.17.6,6.18.7}.bb and their flat defconfigs - linux-yocto%.bbappend now carries the dstack .scc/.cfg fragments (already the mainline mechanism) on official linux-yocto 6.18 (wrynose) - wire 0001-x86-tdx-select-dma-direct-remap.patch via SRC_URI:append:tdx - dstack-tdx.cfg: CONFIG_TDX_GUEST_DRIVER=y + TSM_REPORTS=y (in-tree ConfigFS TSM replaces the out-of-tree mod-tdx-guest module) --- .../recipes-kernel/linux/files/6.17/defconfig | 361 ----------------- .../recipes-kernel/linux/files/6.18/defconfig | 378 ------------------ .../recipes-kernel/linux/files/dstack-tdx.cfg | 6 +- .../linux/linux-custom_6.17.6.bb | 36 -- .../linux/linux-custom_6.18.7.bb | 36 -- .../linux/linux-yocto%.bbappend | 6 + 6 files changed, 11 insertions(+), 812 deletions(-) delete mode 100644 meta-dstack/recipes-kernel/linux/files/6.17/defconfig delete mode 100644 meta-dstack/recipes-kernel/linux/files/6.18/defconfig delete mode 100644 meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb delete mode 100644 meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb diff --git a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig b/meta-dstack/recipes-kernel/linux/files/6.17/defconfig deleted file mode 100644 index f9ba4a7..0000000 --- a/meta-dstack/recipes-kernel/linux/files/6.17/defconfig +++ /dev/null @@ -1,361 +0,0 @@ -CONFIG_LOCALVERSION="-dstack" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_KERNEL_LZMA=y -CONFIG_KERNEL_GZIP=y -CONFIG_DMA_COHERENT_POOL=y -CONFIG_DMA_DIRECT_REMAP=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_BPF_SYSCALL=y -CONFIG_BPF_JIT=y -CONFIG_PREEMPT=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_CGROUPS=y -CONFIG_MEMCG=y -CONFIG_BLK_CGROUP=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_CGROUP_PIDS=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_PERF=y -CONFIG_CGROUP_BPF=y -CONFIG_CGROUP_DEBUG=y -CONFIG_USER_NS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSFS_SYSCALL=y -CONFIG_SMP=y -CONFIG_X86_AMD_PLATFORM_DEVICE=y -CONFIG_HYPERVISOR_GUEST=y -CONFIG_PARAVIRT_SPINLOCKS=y -CONFIG_INTEL_TDX_GUEST=y -CONFIG_TDX_GUEST_DRIVER=y -CONFIG_TSM_REPORTS=y -CONFIG_CONFIGFS_FS=y -CONFIG_NR_CPUS=512 -CONFIG_X86_MSR=y -CONFIG_X86_CPUID=y -CONFIG_X86_CHECK_BIOS_CORRUPTION=y -CONFIG_EFI=y -CONFIG_EFI_STUB=y -CONFIG_HZ_1000=y -# CONFIG_SUSPEND is not set -# CONFIG_ACPI_DEBUG is not set -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_X86_ACPI_CPUFREQ=y -CONFIG_INTEL_IDLE=y -CONFIG_IA32_EMULATION=y -CONFIG_KPROBES=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_BLK_DEV_THROTTLING=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_XFRM_USER=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_INET_ESP=y -CONFIG_NETFILTER=y -CONFIG_BRIDGE_NETFILTER=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_XTABLES_COMPAT=y -CONFIG_NETFILTER_XTABLES_LEGACY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_LOG=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NETMAP=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_REDIRECT=m -CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m -CONFIG_NETFILTER_XT_MATCH_BPF=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_IP_VS=m -CONFIG_NF_REJECT_IPV4=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE=m -CONFIG_BRIDGE_VLAN_FILTERING=y -CONFIG_VLAN_8021Q=y -CONFIG_6LOWPAN=m -CONFIG_NET_SCHED=y -CONFIG_VSOCKETS=y -CONFIG_VIRTIO_VSOCKETS=y -CONFIG_HYPERV_VSOCKETS=y -CONFIG_CGROUP_NET_PRIO=y -CONFIG_CFG80211=m -CONFIG_CFG80211_WEXT=y -CONFIG_MAC80211=m -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y -CONFIG_PCI=y -CONFIG_PCIEPORTBUS=y -CONFIG_PCI_MSI=y -CONFIG_PCI_IOV=y -CONFIG_PCI_HYPERV=y -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_DMA_DIRECT_REMAP=y -CONFIG_DMA_COHERENT_POOL=y -CONFIG_CMA=y -CONFIG_CMA_SIZE_SEL_MBYTES=y -# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set -CONFIG_CMA_SIZE_MBYTES=64 -CONFIG_DMA_CMA=y -CONFIG_GVE=y -CONFIG_SWIOTLB_DYNAMIC=y -CONFIG_ZONE_DMA=y -CONFIG_CONNECTOR=y -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_BLK_DEV_FD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=1 -CONFIG_BLK_DEV_RAM_SIZE=6144 -CONFIG_VIRTIO_BLK=y -CONFIG_BLK_DEV_NVME=y -CONFIG_EEPROM_AT24=m -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_DEV_SR=y -CONFIG_SCSI_FC_ATTRS=y -CONFIG_SCSI_VIRTIO=y -CONFIG_ATA=y -CONFIG_SATA_AHCI=y -CONFIG_ATA_PIIX=y -CONFIG_PATA_SCH=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_WIREGUARD=y -CONFIG_IPVLAN=m -CONFIG_VXLAN=y -CONFIG_NETCONSOLE=y -CONFIG_TUN=m -CONFIG_VETH=y -CONFIG_VIRTIO_NET=y -CONFIG_TYPHOON=m -CONFIG_PCNET32=m -CONFIG_ATL2=m -CONFIG_ATL1=m -CONFIG_ATL1E=m -CONFIG_ATL1C=m -CONFIG_ALX=m -CONFIG_TIGON3=m -CONFIG_BNX2X=m -CONFIG_BNXT=m -CONFIG_DL2K=m -CONFIG_E100=y -CONFIG_E1000=y -CONFIG_E1000E=y -CONFIG_IGB=y -CONFIG_IGBVF=m -CONFIG_IGC=m -CONFIG_JME=m -CONFIG_SKGE=m -CONFIG_SKY2=m -CONFIG_8139CP=m -CONFIG_8139TOO=m -CONFIG_R8169=m -CONFIG_REALTEK_PHY_HWMON=y -CONFIG_USB_NET_DRIVERS=m -CONFIG_USB_KAWETH=m -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_RTL8152=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_CDC_EEM=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_SMSC75XX=m -CONFIG_USB_NET_SMSC95XX=m -CONFIG_USB_NET_MCS7830=m -CONFIG_USB_NET_RNDIS_HOST=m -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_KC2190=y -# CONFIG_WLAN is not set -CONFIG_HYPERV_NET=y -CONFIG_ISDN=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_TABLET=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_USB_COMPOSITE=m -CONFIG_INPUT_MISC=y -CONFIG_INPUT_UINPUT=y -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_PRINTER=m -CONFIG_VIRTIO_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_VIRTIO=y -CONFIG_HPET=y -CONFIG_TCG_TPM=y -CONFIG_TCG_TPM2_HMAC=y -CONFIG_TCG_TIS=y -CONFIG_TCG_CRB=y -CONFIG_I2C_I801=y -CONFIG_WATCHDOG=y -CONFIG_BCMA=m -CONFIG_BCMA_DRIVER_GMAC_CMN=y -CONFIG_AGP=y -CONFIG_AGP_INTEL=y -CONFIG_DRM=y -CONFIG_DRM_I915=m -CONFIG_DRM_VIRTIO_GPU=y -CONFIG_DRM_CIRRUS_QEMU=m -CONFIG_FB=y -CONFIG_FB_UVESA=m -CONFIG_FB_EFI=y -CONFIG_FB_HYPERV=y -CONFIG_HID_HYPERV_MOUSE=y -CONFIG_HID_WACOM=y -CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CONSOLE=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_PL2303=y -CONFIG_USB_EZUSB_FX2=y -CONFIG_RTC_CLASS=y -CONFIG_VIRT_DRIVERS=y -CONFIG_EFI_SECRET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_INPUT=m -CONFIG_VIRTIO_MMIO=y -CONFIG_HYPERV=y -CONFIG_HYPERV_UTILS=y -CONFIG_HYPERV_BALLOON=y -CONFIG_INTEL_IOMMU=y -# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set -CONFIG_IRQ_REMAP=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_RT=y -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y -CONFIG_FUSE_FS=m -CONFIG_CUSE=m -CONFIG_OVERLAY_FS=y -CONFIG_OVERLAY_FS_METACOPY=y -CONFIG_ISO9660_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_EFIVAR_FS=y -CONFIG_SQUASHFS=y -CONFIG_VXFS_FS=m -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set -CONFIG_9P_FS=y -CONFIG_9P_FS_POSIX_ACL=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CRYPTD=y -CONFIG_CRYPTO_AES_TI=y -CONFIG_CRYPTO_DES=y -CONFIG_CRYPTO_ARC4=y -CONFIG_CRYPTO_CTS=y -CONFIG_CRYPTO_XTS=y -CONFIG_CRYPTO_USER_API_HASH=m -CONFIG_CRYPTO_USER_API_SKCIPHER=m -CONFIG_CRYPTO_USER_API_RNG=m -CONFIG_CRYPTO_USER_API_AEAD=m -CONFIG_CRYPTO_AES_NI_INTEL=y -CONFIG_CRYPTO_ECDSA=y -CONFIG_CRYPTO_DEV_VIRTIO=y -CONFIG_CORDIC=m -CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -CONFIG_DEBUG_INFO_BTF=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_UNWINDER_FRAME_POINTER=y - -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y diff --git a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig b/meta-dstack/recipes-kernel/linux/files/6.18/defconfig deleted file mode 100644 index dc6dbbe..0000000 --- a/meta-dstack/recipes-kernel/linux/files/6.18/defconfig +++ /dev/null @@ -1,378 +0,0 @@ -CONFIG_LOCALVERSION="-dstack" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_KERNEL_LZMA=y -CONFIG_KERNEL_GZIP=y -CONFIG_DMA_COHERENT_POOL=y -CONFIG_DMA_DIRECT_REMAP=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_BPF_SYSCALL=y -CONFIG_BPF_JIT=y -CONFIG_PREEMPT=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_CGROUPS=y -CONFIG_MEMCG=y -CONFIG_BLK_CGROUP=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_CGROUP_PIDS=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_PERF=y -CONFIG_CGROUP_BPF=y -CONFIG_CGROUP_DEBUG=y -CONFIG_USER_NS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSFS_SYSCALL=y -CONFIG_SMP=y -CONFIG_X86_AMD_PLATFORM_DEVICE=y -CONFIG_HYPERVISOR_GUEST=y -CONFIG_PARAVIRT_SPINLOCKS=y -CONFIG_INTEL_TDX_GUEST=y -CONFIG_TDX_GUEST_DRIVER=y -CONFIG_TSM_REPORTS=y -CONFIG_CONFIGFS_FS=y -CONFIG_NR_CPUS=512 -CONFIG_X86_MSR=y -CONFIG_X86_CPUID=y -CONFIG_X86_CHECK_BIOS_CORRUPTION=y -CONFIG_EFI=y -CONFIG_EFI_STUB=y -CONFIG_HZ_1000=y -# CONFIG_SUSPEND is not set -# CONFIG_ACPI_DEBUG is not set -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_X86_ACPI_CPUFREQ=y -CONFIG_INTEL_IDLE=y -CONFIG_IA32_EMULATION=y -CONFIG_KPROBES=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_BLK_DEV_THROTTLING=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_XFRM_USER=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_INET_ESP=y -CONFIG_NETFILTER=y -CONFIG_BRIDGE_NETFILTER=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_XTABLES_COMPAT=y -CONFIG_NETFILTER_XTABLES_LEGACY=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_LOG=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NETMAP=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_REDIRECT=m -CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m -CONFIG_NETFILTER_XT_MATCH_BPF=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_IP_VS=m -CONFIG_NF_REJECT_IPV4=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE=m -CONFIG_BRIDGE_VLAN_FILTERING=y -CONFIG_VLAN_8021Q=y -CONFIG_6LOWPAN=m -CONFIG_NET_SCHED=y -CONFIG_VSOCKETS=y -CONFIG_VIRTIO_VSOCKETS=y -CONFIG_HYPERV_VSOCKETS=y -CONFIG_CGROUP_NET_PRIO=y -CONFIG_CFG80211=m -CONFIG_CFG80211_WEXT=y -CONFIG_MAC80211=m -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y -CONFIG_PCI=y -CONFIG_PCIEPORTBUS=y -CONFIG_PCI_MSI=y -CONFIG_PCI_IOV=y -CONFIG_PCI_HYPERV=y -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_DMA_DIRECT_REMAP=y -CONFIG_DMA_COHERENT_POOL=y -CONFIG_CMA=y -CONFIG_CMA_SIZE_SEL_MBYTES=y -# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set -CONFIG_CMA_SIZE_MBYTES=64 -CONFIG_DMA_CMA=y -CONFIG_GVE=y -CONFIG_SWIOTLB_DYNAMIC=y -CONFIG_ZONE_DMA=y -CONFIG_CONNECTOR=y -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_BLK_DEV_FD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=1 -CONFIG_BLK_DEV_RAM_SIZE=6144 -CONFIG_VIRTIO_BLK=y -CONFIG_BLK_DEV_NVME=y -CONFIG_EEPROM_AT24=m -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_DEV_SR=y -CONFIG_SCSI_FC_ATTRS=y -CONFIG_SCSI_VIRTIO=y -CONFIG_ATA=y -CONFIG_SATA_AHCI=y -CONFIG_ATA_PIIX=y -CONFIG_PATA_SCH=y -CONFIG_MD=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y -CONFIG_DM_VERITY=y -CONFIG_NETDEVICES=y -CONFIG_WIREGUARD=y -CONFIG_IPVLAN=m -CONFIG_VXLAN=y -CONFIG_NETCONSOLE=y -CONFIG_TUN=m -CONFIG_VETH=y -CONFIG_VIRTIO_NET=y -CONFIG_TYPHOON=m -CONFIG_PCNET32=m -CONFIG_ATL2=m -CONFIG_ATL1=m -CONFIG_ATL1E=m -CONFIG_ATL1C=m -CONFIG_ALX=m -CONFIG_TIGON3=m -CONFIG_BNX2X=m -CONFIG_BNXT=m -CONFIG_DL2K=m -CONFIG_E100=y -CONFIG_E1000=y -CONFIG_E1000E=y -CONFIG_IGB=y -CONFIG_IGBVF=m -CONFIG_IGC=m -CONFIG_JME=m -CONFIG_SKGE=m -CONFIG_SKY2=m -CONFIG_8139CP=m -CONFIG_8139TOO=m -CONFIG_R8169=m -CONFIG_REALTEK_PHY_HWMON=y -CONFIG_USB_NET_DRIVERS=m -CONFIG_USB_KAWETH=m -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_RTL8152=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_CDC_EEM=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_SMSC75XX=m -CONFIG_USB_NET_SMSC95XX=m -CONFIG_USB_NET_MCS7830=m -CONFIG_USB_NET_RNDIS_HOST=m -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_KC2190=y -# CONFIG_WLAN is not set -CONFIG_HYPERV_NET=y -CONFIG_ISDN=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_TABLET=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_USB_COMPOSITE=m -CONFIG_INPUT_MISC=y -CONFIG_INPUT_UINPUT=y -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_PRINTER=m -CONFIG_VIRTIO_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_VIRTIO=y -CONFIG_HPET=y -CONFIG_TCG_TPM=y -CONFIG_TCG_TPM2_HMAC=y -CONFIG_TCG_TIS=y -CONFIG_TCG_CRB=y -CONFIG_I2C_I801=y -CONFIG_WATCHDOG=y -CONFIG_BCMA=m -CONFIG_BCMA_DRIVER_GMAC_CMN=y -CONFIG_AGP=y -CONFIG_AGP_INTEL=y -CONFIG_DRM=y -CONFIG_DRM_I915=m -CONFIG_DRM_VIRTIO_GPU=y -CONFIG_DRM_CIRRUS_QEMU=m -CONFIG_FB=y -CONFIG_FB_UVESA=m -CONFIG_FB_EFI=y -CONFIG_FB_HYPERV=y -CONFIG_HID_HYPERV_MOUSE=y -CONFIG_HID_WACOM=y -CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CONSOLE=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_PL2303=y -CONFIG_USB_EZUSB_FX2=y -CONFIG_RTC_CLASS=y -CONFIG_VIRT_DRIVERS=y -CONFIG_EFI_SECRET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_INPUT=m -CONFIG_VIRTIO_MMIO=y -CONFIG_HYPERV=y -CONFIG_HYPERV_UTILS=y -CONFIG_HYPERV_BALLOON=y -CONFIG_INTEL_IOMMU=y -# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set -CONFIG_IRQ_REMAP=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_RT=y -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y -CONFIG_FUSE_FS=m -CONFIG_CUSE=m -CONFIG_OVERLAY_FS=y -CONFIG_OVERLAY_FS_METACOPY=y -CONFIG_ISO9660_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_EFIVAR_FS=y -CONFIG_SQUASHFS=y -CONFIG_VXFS_FS=m -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set -CONFIG_9P_FS=y -CONFIG_9P_FS_POSIX_ACL=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_CRYPTD=y -CONFIG_CRYPTO_AES_TI=y -CONFIG_CRYPTO_DES=y -CONFIG_CRYPTO_ARC4=y -CONFIG_CRYPTO_CTS=y -CONFIG_CRYPTO_XTS=y -CONFIG_CRYPTO_USER_API_HASH=m -CONFIG_CRYPTO_USER_API_SKCIPHER=m -CONFIG_CRYPTO_USER_API_RNG=m -CONFIG_CRYPTO_USER_API_AEAD=m -CONFIG_CRYPTO_AES_NI_INTEL=y -CONFIG_CRYPTO_ECDSA=y -CONFIG_CRYPTO_DEV_VIRTIO=y -CONFIG_CORDIC=m -CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -CONFIG_DEBUG_INFO_BTF=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_UNWINDER_FRAME_POINTER=y - -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y - -# nftables (Docker iptables-nft backend) -CONFIG_NF_TABLES=m -CONFIG_NF_TABLES_INET=y -CONFIG_NF_TABLES_NETDEV=y -CONFIG_NFT_COMPAT=m -CONFIG_NFT_NAT=m -CONFIG_NFT_CHAIN_NAT=m -CONFIG_NFT_MASQ=m -CONFIG_NFT_REDIR=m -CONFIG_NFT_CT=m -CONFIG_NFT_LOG=m -CONFIG_NFT_LIMIT=m -CONFIG_NFT_REJECT=m -CONFIG_NFT_REJECT_INET=m -CONFIG_NFT_HASH=m -CONFIG_NETFILTER_XT_TARGET_CT=m diff --git a/meta-dstack/recipes-kernel/linux/files/dstack-tdx.cfg b/meta-dstack/recipes-kernel/linux/files/dstack-tdx.cfg index 4dbf53d..8fe114a 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack-tdx.cfg +++ b/meta-dstack/recipes-kernel/linux/files/dstack-tdx.cfg @@ -1 +1,5 @@ -CONFIG_TDX_GUEST_DRIVER=n +# In-tree TDX guest driver provides /dev/tdx_guest and the ConfigFS TSM +# report interface (/sys/kernel/config/tsm/report), replacing the former +# out-of-tree mod-tdx-guest module. +CONFIG_TDX_GUEST_DRIVER=y +CONFIG_TSM_REPORTS=y diff --git a/meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb b/meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb deleted file mode 100644 index 200982d..0000000 --- a/meta-dstack/recipes-kernel/linux/linux-custom_6.17.6.bb +++ /dev/null @@ -1,36 +0,0 @@ -SUMMARY = "dstack Linux kernel 6.17.6 built from tarball" -DESCRIPTION = "Custom dstack kernel based on upstream Linux 6.17.6 with tiny Kconfig baseline tuned for TDX guests" -SECTION = "kernel" -LICENSE = "GPL-2.0-only" -LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" - -PV = "6.17.6" -LINUX_VERSION = "${PV}" - -inherit kernel - -FILESEXTRAPATHS:prepend := "${THISDIR}/files/6.17:${THISDIR}/files:" - -DEPENDS += "libyaml-native openssl-native util-linux-native elfutils-native" - -SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${PV}.tar.xz;downloadfilename=linux-${PV}.tar.xz \ - file://defconfig \ - file://0001-x86-tdx-select-dma-direct-remap.patch \ -" - -SRC_URI[sha256sum] = "8ecfbc6b693448abb46144a8d04d1e1631639c7661c1088425a2e5406f13c69c" - -S = "${UNPACKDIR}/linux-${PV}" - -LINUX_VERSION_EXTENSION = "-dstack" -KERNEL_VERSION_EXTENSION = "-dstack" - -# Enable BTF debug info for bpftool and out-of-tree modules (ZFS, WireGuard, etc.) -KERNEL_DEBUG = "True" - -# Keep packaging aligned with our tiny x86_64 guest machines. -COMPATIBLE_MACHINE = "(tdx|sev-snp|qemux86-64)" - -do_deploy:append() { - install -m 0644 ${B}/.config ${DEPLOYDIR}/kernel-config -} diff --git a/meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb b/meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb deleted file mode 100644 index 96c0f7a..0000000 --- a/meta-dstack/recipes-kernel/linux/linux-custom_6.18.7.bb +++ /dev/null @@ -1,36 +0,0 @@ -SUMMARY = "dstack Linux kernel 6.18.7 built from tarball" -DESCRIPTION = "Custom dstack kernel based on upstream Linux 6.18.7 with tiny Kconfig baseline tuned for TDX guests" -SECTION = "kernel" -LICENSE = "GPL-2.0-only" -LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" - -PV = "6.18.7" -LINUX_VERSION = "${PV}" - -inherit kernel - -FILESEXTRAPATHS:prepend := "${THISDIR}/files/6.18:${THISDIR}/files:" - -DEPENDS += "libyaml-native openssl-native util-linux-native elfutils-native" - -SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${PV}.tar.xz;downloadfilename=linux-${PV}.tar.xz \ - file://defconfig \ - file://0001-x86-tdx-select-dma-direct-remap.patch \ -" - -SRC_URI[sha256sum] = "b726a4d15cf9ae06219b56d87820776e34d89fbc137e55fb54a9b9c3015b8f1e" - -S = "${UNPACKDIR}/linux-${PV}" - -LINUX_VERSION_EXTENSION = "-dstack" -KERNEL_VERSION_EXTENSION = "-dstack" - -# Enable BTF debug info for bpftool and out-of-tree modules (ZFS, WireGuard, etc.) -KERNEL_DEBUG = "True" - -# Keep packaging aligned with our tiny x86_64 guest machines. -COMPATIBLE_MACHINE = "(tdx|sev-snp|qemux86-64)" - -do_deploy:append() { - install -m 0644 ${B}/.config ${DEPLOYDIR}/kernel-config -} diff --git a/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend b/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend index 5900c49..c28b7f2 100644 --- a/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend +++ b/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend @@ -11,6 +11,12 @@ SRC_URI += "file://dstack-docker.cfg \ file://dstack.cfg \ file://dstack.scc" +# TDX guests need DMA_DIRECT_REMAP for shared (decrypted) coherent DMA so +# devices like NVMe can complete I/O. INTEL_TDX_GUEST does not select it +# upstream (and the symbol is promptless, so a .cfg fragment cannot set it), +# hence this Kconfig patch. Scoped to tdx machines only. +SRC_URI:append:tdx = " file://0001-x86-tdx-select-dma-direct-remap.patch" + KERNEL_FEATURES:append = " features/cgroups/cgroups.scc \ features/overlayfs/overlayfs.scc \ features/netfilter/netfilter.scc \ From 4d4a0d325f9729c54c430ef0e4abd9536b59d89b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sat, 30 May 2026 23:56:17 -0700 Subject: [PATCH 108/119] build: fix flavor dist names (dstack* not dstack-cloud*) and UKI python path - Makefile flavor_to_dist maps to dstack/dstack-dev/dstack-nvidia/dstack-nvidia-dev - dstack-uki.bb: glob python3.* site-packages instead of hardcoded python3.13 (wrynose native python version differs) --- Makefile | 2 +- meta-dstack/recipes-core/images/dstack-uki.bb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index da4ba8e..b86d2df 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ export DIST_DIR FLAVORS ?= prod dev nvidia nvidia-dev # Map flavor to dist name for mkimage.sh -flavor_to_dist = $(if $(filter prod,$1),dstack-cloud,$(if $(filter dev,$1),dstack-cloud-dev,$(if $(filter nvidia,$1),dstack-cloud-nvidia,$(if $(filter nvidia-dev,$1),dstack-cloud-nvidia-dev,$1)))) +flavor_to_dist = $(if $(filter prod,$1),dstack,$(if $(filter dev,$1),dstack-dev,$(if $(filter nvidia,$1),dstack-nvidia,$(if $(filter nvidia-dev,$1),dstack-nvidia-dev,$1)))) all: dist diff --git a/meta-dstack/recipes-core/images/dstack-uki.bb b/meta-dstack/recipes-core/images/dstack-uki.bb index 4a2254b..07a8b08 100644 --- a/meta-dstack/recipes-core/images/dstack-uki.bb +++ b/meta-dstack/recipes-core/images/dstack-uki.bb @@ -100,8 +100,10 @@ python do_uki() { native_sysroot = d.getVar('RECIPE_SYSROOT_NATIVE') staging_libdir = d.getVar('STAGING_LIBDIR_NATIVE') - # Find Python version directory for native packages - python_sitepackages = os.path.join(staging_libdir, 'python3.13', 'site-packages') + # Find Python version directory for native packages (version-agnostic) + import glob + _pyglob = sorted(glob.glob(os.path.join(staging_libdir, 'python3.*', 'site-packages'))) + python_sitepackages = _pyglob[-1] if _pyglob else os.path.join(staging_libdir, 'python3', 'site-packages') # Set environment for ukify env = os.environ.copy() From 4925deba10a6689331555d9c41784f4d3256e15b Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 00:05:07 -0700 Subject: [PATCH 109/119] =?UTF-8?q?build:=20wrynose=20migration=20fixes=20?= =?UTF-8?q?=E2=80=94=20parse=20clean=20(28395=20targets,=200=20errors)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dev-setup: TEMPLATECONF -> openembedded-core/meta/conf/templates/default (wrynose moved templates out of meta-poky); add meta-poky + meta-yocto-bsp to LAYERS explicitly (oe-core default template no longer pulls them) - meta-dstack/meta-nvidia layer.conf: LAYERSERIES_COMPAT -> wrynose - dstack.conf: DISTRO_FEATURES_BACKFILL_CONSIDERED -> DISTRO_FEATURES_OPTED_OUT - meta-confidential-compute: move wic/ -> files/wic/ (wrynose wks search path) - dstack-rootfs-base.inc: drop stray diff3 conflict marker verified: virtual/kernel = official linux-yocto 6.18.24, dma-direct-remap patch wired via SRC_URI:append:tdx --- dev-setup | 6 ++++-- meta-confidential-compute | 2 +- meta-dstack/conf/distro/dstack.conf | 2 +- meta-dstack/conf/layer.conf | 2 +- meta-dstack/recipes-core/images/dstack-rootfs-base.inc | 1 - meta-nvidia/conf/layer.conf | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dev-setup b/dev-setup index 4be8074..050a389 100755 --- a/dev-setup +++ b/dev-setup @@ -16,7 +16,9 @@ fi THIS_SCRIPT=$(realpath "$THIS_SCRIPT") THIS_DIR=$(dirname "$THIS_SCRIPT") -LAYERS="$THIS_DIR/meta-confidential-compute \ +LAYERS="$THIS_DIR/meta-yocto/meta-poky \ + $THIS_DIR/meta-yocto/meta-yocto-bsp \ + $THIS_DIR/meta-confidential-compute \ $THIS_DIR/meta-openembedded/meta-oe \ $THIS_DIR/meta-openembedded/meta-python \ $THIS_DIR/meta-openembedded/meta-networking \ @@ -46,7 +48,7 @@ for script in $THIS_DIR/setup.d/*.sh; do done pushd "$BUILD_DIR" -BDIR="." TEMPLATECONF=$THIS_DIR/meta-yocto/meta-poky/conf/templates/default source $OE_INIT +BDIR="." TEMPLATECONF=$THIS_DIR/openembedded-core/meta/conf/templates/default source $OE_INIT popd bitbake-layers add-layer $LAYERS diff --git a/meta-confidential-compute b/meta-confidential-compute index 6bb9535..c829fbc 160000 --- a/meta-confidential-compute +++ b/meta-confidential-compute @@ -1 +1 @@ -Subproject commit 6bb9535349131a96f47bddd1cefaf797a8bb465a +Subproject commit c829fbc4032490ceb900a2ed38f066a515aa0bb3 diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index 515551e..f01d893 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -2,7 +2,7 @@ require conf/distro/cvm.conf DISTRO = "dstack" DISTRO_NAME = "DStack" DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6" -DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit" +DISTRO_FEATURES_OPTED_OUT += "sysvinit" DISTRO_VERSION = "0.6.0" DISTROOVERRIDES = "poky:dstack" diff --git a/meta-dstack/conf/layer.conf b/meta-dstack/conf/layer.conf index 7258ad3..10bb0a0 100644 --- a/meta-dstack/conf/layer.conf +++ b/meta-dstack/conf/layer.conf @@ -5,4 +5,4 @@ BBFILE_COLLECTIONS += "dstack" BBFILE_PATTERN_dstack := "^${LAYERDIR}/" BBFILE_PRIORITY_dstack = "20" LAYERVERSION_dstack = "4" -LAYERSERIES_COMPAT_dstack = "whinlatter" +LAYERSERIES_COMPAT_dstack = "wrynose" diff --git a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc index 34d5473..4862014 100644 --- a/meta-dstack/recipes-core/images/dstack-rootfs-base.inc +++ b/meta-dstack/recipes-core/images/dstack-rootfs-base.inc @@ -60,7 +60,6 @@ IMAGE_INSTALL = "\ kernel-module-xt-set \ kernel-module-xt-nflog \ kernel-module-xt-physdev \ -||||||| base fuse3 \ fuse3-utils \ pigz \ diff --git a/meta-nvidia/conf/layer.conf b/meta-nvidia/conf/layer.conf index 568d6d5..79dbcb4 100644 --- a/meta-nvidia/conf/layer.conf +++ b/meta-nvidia/conf/layer.conf @@ -10,4 +10,4 @@ BBFILE_PATTERN_nvidia = "^${LAYERDIR}/" BBFILE_PRIORITY_nvidia = "12" LICENSE_PATH += " ${LAYERDIR}/custom-licenses" -LAYERSERIES_COMPAT_nvidia = "whinlatter" +LAYERSERIES_COMPAT_nvidia = "wrynose" From ba6c0056b1a12d6e7eb22df44985463d21f9b966 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 00:34:55 -0700 Subject: [PATCH 110/119] distro: set INIT_MANAGER=systemd (wrynose udev fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit poky.conf defaults POKY_INIT_MANAGER=sysvinit, which pulls init-manager-sysvinit.inc and appends sysvinit to DISTRO_FEATURES — that conflicts with systemd so both systemd and eudev get skipped and nothing RPROVIDES udev (breaks cryptsetup -> dstack-initramfs). Setting INIT_MANAGER before requiring the poky-derived cvm.conf selects init-manager-systemd.inc. --- meta-dstack/conf/distro/dstack.conf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meta-dstack/conf/distro/dstack.conf b/meta-dstack/conf/distro/dstack.conf index f01d893..397ca34 100644 --- a/meta-dstack/conf/distro/dstack.conf +++ b/meta-dstack/conf/distro/dstack.conf @@ -1,8 +1,11 @@ +# Select systemd init before requiring poky-derived distro config, otherwise +# poky.conf's POKY_INIT_MANAGER="sysvinit" pulls init-manager-sysvinit.inc which +# appends sysvinit to DISTRO_FEATURES and conflicts with systemd (breaks udev). +INIT_MANAGER = "systemd" require conf/distro/cvm.conf DISTRO = "dstack" DISTRO_NAME = "DStack" DISTRO_FEATURES:append = " virtualization seccomp systemd usrmerge security dm-verity ipv6" -DISTRO_FEATURES_OPTED_OUT += "sysvinit" DISTRO_VERSION = "0.6.0" DISTROOVERRIDES = "poky:dstack" From dd12be483bc102b9c72d17f99d959ff53be7fd91 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 01:10:06 -0700 Subject: [PATCH 111/119] dstack-ovmf: drop S = ${WORKDIR}/git (wrynose sets S for git fetches) --- meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb | 1 - 1 file changed, 1 deletion(-) diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb index 84ca1b3..6b3544c 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb @@ -70,7 +70,6 @@ inherit deploy PARALLEL_MAKE = "" -S = "${WORKDIR}/git" DEPENDS = "nasm-native acpica-native ovmf-native util-linux-native" From d8da197c980d21e852bd3349d9dbd83a9a0e6a54 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 01:18:49 -0700 Subject: [PATCH 112/119] dstack-ovmf: add Upstream-Status to local patches (wrynose fatal QA) --- .../dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch | 1 + .../dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch | 1 + .../dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch | 1 + 3 files changed, 3 insertions(+) diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch index 3a50bed..7a665e3 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0003-Debug-prefix-map.patch @@ -2,6 +2,7 @@ From 672d571ed826157e15969b7ba0ec46ab622a7c44 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 18 Mar 2026 08:44:20 +0000 Subject: [PATCH] Debug prefix map +Upstream-Status: Inappropriate [dstack-specific OVMF build/reproducibility tweak] --- BaseTools/Conf/tools_def.template | 18 +++++++++--------- diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch index 33726e0..ab1da46 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0004-Reproduciable.patch @@ -2,6 +2,7 @@ From 9133327256392a17883ad3ed91ad63ecbac50f08 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 18 Mar 2026 08:44:21 +0000 Subject: [PATCH] Reproduciable +Upstream-Status: Inappropriate [dstack-specific OVMF build/reproducibility tweak] --- BaseTools/Source/C/GenFw/Elf64Convert.c | 8 ++++--- diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch index 61bb4a8..153a9e9 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch @@ -2,6 +2,7 @@ From 216280451e52ba73bc408e58c5a3b13d863e350f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 18 Mar 2026 08:44:21 +0000 Subject: [PATCH] Declare ProcessLibraryConstructorList +Upstream-Status: Inappropriate [dstack-specific OVMF build/reproducibility tweak] --- OvmfPkg/IntelTdx/Sec/SecMain.c | 1 + From 19114d9cf58720dbbe777259308eca75d31e5fd2 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 01:44:31 -0700 Subject: [PATCH 113/119] dstack-ovmf: build on wrynose (edk2-stable202511 + NASM 3.0 fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bump edk2 stable202502 -> stable202511 (202502 won't assemble with wrynose NASM 3.01); changes RTMR[0] -> needs new dstack-mr OvmfVariant baseline - add oe-core's CpuExceptionHandlerLib push-instruction NASM 3.0 backport - drop 0003/0004 reproducibility patches (don't apply to 202511 template; not needed for functional image — rebase from oe-core versions for production) - drop 0005-Declare-ProcessLibraryConstructorList (edk2 202511 declares it natively) - OVMF_VARIANT -> stable202511 --- ...eclare-ProcessLibraryConstructorList.patch | 38 --------------- ...ceptionHandlerLib-fix-push-instructi.patch | 46 +++++++++++++++++++ .../dstack-ovmf/dstack-ovmf_git.bb | 14 +++--- 3 files changed, 54 insertions(+), 44 deletions(-) delete mode 100644 meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch create mode 100644 meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-UefiCpuPkg-CpuExceptionHandlerLib-fix-push-instructi.patch diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch deleted file mode 100644 index 153a9e9..0000000 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-Declare-ProcessLibraryConstructorList.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 216280451e52ba73bc408e58c5a3b13d863e350f Mon Sep 17 00:00:00 2001 -From: Kevin Wang -Date: Wed, 18 Mar 2026 08:44:21 +0000 -Subject: [PATCH] Declare ProcessLibraryConstructorList -Upstream-Status: Inappropriate [dstack-specific OVMF build/reproducibility tweak] - ---- - OvmfPkg/IntelTdx/Sec/SecMain.c | 1 + - OvmfPkg/Sec/SecMain.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.c b/OvmfPkg/IntelTdx/Sec/SecMain.c -index 7f2d28af95..fcc6b97c28 100644 ---- a/OvmfPkg/IntelTdx/Sec/SecMain.c -+++ b/OvmfPkg/IntelTdx/Sec/SecMain.c -@@ -163,6 +163,7 @@ SecCoreStartupWithStack ( - IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable; - IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1); - -+ void ProcessLibraryConstructorList (); - ProcessLibraryConstructorList (); - - // -diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c -index d13a948509..58c48c967c 100644 ---- a/OvmfPkg/Sec/SecMain.c -+++ b/OvmfPkg/Sec/SecMain.c -@@ -885,6 +885,7 @@ SecCoreStartupWithStack ( - InitializeCpuExceptionHandlers (NULL); - } - -+ void ProcessLibraryConstructorList (); - ProcessLibraryConstructorList (); - - if (!SevEsIsEnabled ()) { --- -2.43.0 - diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-UefiCpuPkg-CpuExceptionHandlerLib-fix-push-instructi.patch b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-UefiCpuPkg-CpuExceptionHandlerLib-fix-push-instructi.patch new file mode 100644 index 0000000..650e084 --- /dev/null +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf/0005-UefiCpuPkg-CpuExceptionHandlerLib-fix-push-instructi.patch @@ -0,0 +1,46 @@ +From 7e6be0f4068a2158af3c97e873edb33fa4d5c6b8 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 3 Nov 2025 09:56:52 +0100 +Subject: [PATCH 5/5] UefiCpuPkg/CpuExceptionHandlerLib: fix push instructions + +Nasm 3.0 complains about 'dword' being invalid. The comment talks about +a '8-byte value' so 'qword' should be correct here. + +With this change the extra comment explaining that the instruction +actually pushes an 8-byte value despite the 'dword' keyword is not +needed any more. Drop it. + +Fixes: https://github.com/tianocore/edk2/issues/11635 +Signed-off-by: Gerd Hoffmann +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/9ccf8751a74f26142e584c7b7c7572a182b67997] +(cherry picked from commit 9ccf8751a74f26142e584c7b7c7572a182b67997) +Signed-off-by: Ankur Tyagi +--- + .../CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm +index 3d64ac9080..671ed98f85 100644 +--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm ++++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm +@@ -57,7 +57,7 @@ ALIGN 8 + AsmIdtVectorBegin: + %assign Vector 0 + %rep 256 +- push strict dword %[Vector] ; This instruction pushes sign-extended 8-byte value on stack ++ push strict qword %[Vector] + push rax + %ifdef NO_ABSOLUTE_RELOCS_IN_TEXT + mov rax, strict qword 0 ; mov rax, ASM_PFX(CommonInterruptEntry) +@@ -70,7 +70,7 @@ AsmIdtVectorBegin: + AsmIdtVectorEnd: + + HookAfterStubHeaderBegin: +- push strict dword 0 ; 0 will be fixed ++ push strict qword 0 ; 0 will be fixed + VectorNum: + push rax + %ifdef NO_ABSOLUTE_RELOCS_IN_TEXT +-- +2.47.3 + diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb index 6b3544c..1a0af58 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb @@ -22,9 +22,7 @@ BUILD_CFLAGS += "-Wno-error=stringop-overflow" SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://0001-Update-path-to-native-BaseTools.patch \ file://0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch \ - file://0003-Debug-prefix-map.patch \ - file://0004-Reproduciable.patch \ - file://0005-Declare-ProcessLibraryConstructorList.patch \ + file://0005-UefiCpuPkg-CpuExceptionHandlerLib-fix-push-instructi.patch \ " # Pinned to edk2-stable202502 (Feb 2025) instead of the latest stable202505. @@ -41,8 +39,12 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ # stable202502 contains none of them and so produces the same 13-event RTMR[0] # layout as the legacy 3a3b12cb snapshot dstack used pre-upgrade, while still # carrying 5 months of post-Sep-2024 EDK2 fixes (incl. CVEs). -PV = "edk2-stable202502" -SRCREV = "fbe0805b2091393406952e84724188f8c1941837" +# NOTE(wrynose): the stable202502 pin is INCOMPATIBLE with Yocto wrynose's NASM +# 3.01 (edk2 ExceptionHandlerAsm fails to assemble). Bumped to stable202511 (same +# as oe-core wrynose) to build. This changes the RTMR[0] event chain — a new +# OvmfVariant baseline in dstack-mr / dstack-types is required for attestation. +PV = "edk2-stable202511" +SRCREV = "46548b1adac82211d8d11da12dd914f41e7aa775" UPSTREAM_CHECK_GITTAGREGEX = "(?Pedk2-stable.*)" # Tag identifying the OVMF boot-time RTMR[0] event layout this build produces. @@ -50,7 +52,7 @@ UPSTREAM_CHECK_GITTAGREGEX = "(?Pedk2-stable.*)" # verifiers can pick the matching dstack-mr code path without parsing PV. # Keep this in sync with the OvmfVariant enum in dstack/dstack-types when # bumping PV. -OVMF_VARIANT = "pre202505" +OVMF_VARIANT = "stable202511" CVE_PRODUCT = "edk2" CVE_VERSION = "${@d.getVar('PV').split('-')[1]}" From 42f8b3fb0b00887238d82445869af2504e10db6f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 01:49:51 -0700 Subject: [PATCH 114/119] meta-virtualization: bump to runc patch-fuzz fix --- meta-virtualization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-virtualization b/meta-virtualization index af5a04f..effab7a 160000 --- a/meta-virtualization +++ b/meta-virtualization @@ -1 +1 @@ -Subproject commit af5a04f1b1352aa0f2aafb9d0b70dfb2f3515ab5 +Subproject commit effab7a4bc4f2b4d1c7036f52d41c64a2f4a77ae From 3ac32c59ba7a13f49157f24ac3692c14edca6860 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 02:18:37 -0700 Subject: [PATCH 115/119] kernel: build CRYPTO_SHA256 in (dm-verity rootfs hash in initramfs) linux-yocto-tiny ships CONFIG_CRYPTO_SHA256=m; dm-verity in the initramfs can't load modules, so early rootfs verity failed with 'Cannot initialize hash function (-ENOENT)' and init died -> kernel panic. Force SHA256/SHA512 built-in. --- meta-dstack/recipes-kernel/linux/files/dstack.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meta-dstack/recipes-kernel/linux/files/dstack.cfg b/meta-dstack/recipes-kernel/linux/files/dstack.cfg index cf5038c..24aa50f 100644 --- a/meta-dstack/recipes-kernel/linux/files/dstack.cfg +++ b/meta-dstack/recipes-kernel/linux/files/dstack.cfg @@ -33,3 +33,10 @@ CONFIG_MMC=n CONFIG_SCSI=n CONFIG_INPUT=n CONFIG_WLAN=n + +# dm-verity verifies the rootfs in the initramfs (no modules loaded yet), so the +# rootfs hash algorithm must be built-in. linux-yocto-tiny ships SHA256 as a +# module (=m); force it built-in or early verity fails with +# "verity: Cannot initialize hash function (-ENOENT)". +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y From d403f7d1cb77ea366421ae8fcebef4cb2fa2a4d7 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 19:01:24 -0700 Subject: [PATCH 116/119] dstack-ovmf: keep edk2-stable202502 (dstack-mr compat) + build on wrynose dstack-mr can't yet compute measurements for newer edk2, so the pre202505 RTMR[0] layout must be preserved. Make 202502 build on wrynose by: - backporting edk2's NASM-3.0 CpuExceptionHandlerLib push-instruction fix - dropping 0005-Declare-ProcessLibraryConstructorList (GCC 15 rejects the K&R 'void f()' forward-decl as conflicting with edk2's EFIAPI prototype; the prototype is already in scope in 202502 so the manual decl is redundant) OVMF_VARIANT stays pre202505. --- .../recipes-core/dstack-ovmf/dstack-ovmf_git.bb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb index 1a0af58..08478c9 100644 --- a/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb +++ b/meta-dstack/recipes-core/dstack-ovmf/dstack-ovmf_git.bb @@ -22,6 +22,8 @@ BUILD_CFLAGS += "-Wno-error=stringop-overflow" SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://0001-Update-path-to-native-BaseTools.patch \ file://0002-BaseTools-makefile-adjust-to-build-in-under-bitbake.patch \ + file://0003-Debug-prefix-map.patch \ + file://0004-Reproduciable.patch \ file://0005-UefiCpuPkg-CpuExceptionHandlerLib-fix-push-instructi.patch \ " @@ -39,12 +41,13 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ # stable202502 contains none of them and so produces the same 13-event RTMR[0] # layout as the legacy 3a3b12cb snapshot dstack used pre-upgrade, while still # carrying 5 months of post-Sep-2024 EDK2 fixes (incl. CVEs). -# NOTE(wrynose): the stable202502 pin is INCOMPATIBLE with Yocto wrynose's NASM -# 3.01 (edk2 ExceptionHandlerAsm fails to assemble). Bumped to stable202511 (same -# as oe-core wrynose) to build. This changes the RTMR[0] event chain — a new -# OvmfVariant baseline in dstack-mr / dstack-types is required for attestation. -PV = "edk2-stable202511" -SRCREV = "46548b1adac82211d8d11da12dd914f41e7aa775" +# NOTE(wrynose): stable202502 must be KEPT — dstack-mr cannot yet compute +# measurements for newer edk2 (RTMR[0] event chain changed). stable202502 won't +# assemble with wrynose's NASM 3.01 out of the box, so we backport edk2's NASM-3.0 +# CpuExceptionHandlerLib push-instruction fix (0005-UefiCpuPkg-...) to make 202502 +# build while preserving the pre202505 measurement layout dstack-mr expects. +PV = "edk2-stable202502" +SRCREV = "fbe0805b2091393406952e84724188f8c1941837" UPSTREAM_CHECK_GITTAGREGEX = "(?Pedk2-stable.*)" # Tag identifying the OVMF boot-time RTMR[0] event layout this build produces. @@ -52,7 +55,7 @@ UPSTREAM_CHECK_GITTAGREGEX = "(?Pedk2-stable.*)" # verifiers can pick the matching dstack-mr code path without parsing PV. # Keep this in sync with the OvmfVariant enum in dstack/dstack-types when # bumping PV. -OVMF_VARIANT = "stable202511" +OVMF_VARIANT = "pre202505" CVE_PRODUCT = "edk2" CVE_VERSION = "${@d.getVar('PV').split('-')[1]}" From 8f6b753ee986496b186ae04a6f16e70408552e64 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 31 May 2026 20:28:38 -0700 Subject: [PATCH 117/119] review: build-system fixes from PR review - mkimage.sh: deterministic GPT GUIDs (reproducible partitioned images); check verity env exists and sgdisk is installed before use - repro-build/check.sh: compare rootfs.img.parted.verity (new name); define YELLOW - build.sh: download from Dstack-TEE/meta-dstack releases (not the fork) - README: clone Dstack-TEE/meta-dstack for the reproducible-build steps - systemd bbappend: drop dangling blacklist-autofs4.conf FILES entry (never installed) - dstack-uki.bb: run ukify via argv list (no shell); fail clearly if ROOT_HASH/ DATA_SIZE missing - Makefile: build dstack-guest in images-common to avoid multiconfig fetch races --- Makefile | 5 +-- README.md | 2 +- build.sh | 2 +- meta-dstack/recipes-core/images/dstack-uki.bb | 29 +++++++++------ .../recipes-core/systemd/systemd_%.bbappend | 1 - mkimage.sh | 36 ++++++++++++++++--- repro-build/check.sh | 3 +- 7 files changed, 57 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index b86d2df..952affb 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,10 @@ dist: images $(foreach flavor,$(FLAVORS),./mkimage.sh --dist-name $(call flavor_to_dist,$(flavor)) --flavor $(flavor);) # Build common artifacts (shared across all flavors) -# dstack-guest is built here to avoid concurrent build conflicts in multiconfig +# dstack-guest is built here first to warm sstate/downloads and avoid concurrent +# fetch/build conflicts when the per-flavor multiconfigs build it in parallel. images-common: - bitbake virtual/kernel dstack-initramfs dstack-ovmf + bitbake virtual/kernel dstack-initramfs dstack-ovmf dstack-guest # Build flavor-specific artifacts using multiconfig (serial to avoid deadlock warnings) images-flavors: diff --git a/README.md b/README.md index 616469d..7ddcbb3 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ See https://github.com/Phala-Network/dstack-cloud for more details. ### Build commands ```bash -git clone https://github.com/Phala-Network/meta-dstack-cloud.git +git clone https://github.com/Dstack-TEE/meta-dstack.git cd meta-dstack/repro-build/ ./repro-build.sh ``` diff --git a/build.sh b/build.sh index 4481aef..70337c7 100755 --- a/build.sh +++ b/build.sh @@ -310,7 +310,7 @@ download_image() { else BASENAME=dstack-cloud-$VERSION fi - URL=https://github.com/Dstack-TEE/meta-dstack-cloud/releases/download/$TAG/$BASENAME.tar.gz + URL=https://github.com/Dstack-TEE/meta-dstack/releases/download/$TAG/$BASENAME.tar.gz if [ -d $IMAGES_DIR/$BASENAME ]; then echo "Image already exists" else diff --git a/meta-dstack/recipes-core/images/dstack-uki.bb b/meta-dstack/recipes-core/images/dstack-uki.bb index 07a8b08..7b871e3 100644 --- a/meta-dstack/recipes-core/images/dstack-uki.bb +++ b/meta-dstack/recipes-core/images/dstack-uki.bb @@ -88,6 +88,9 @@ python do_uki() { else: bb.fatal(f"Verity env file not found: {verity_env}") + if not root_hash or not data_size: + bb.fatal(f"ROOT_HASH/DATA_SIZE missing from verity env: {verity_env}") + # Build cmdline cmdline_base = d.getVar('UKI_CMDLINE_BASE') cmdline = f"{cmdline_base} dstack.rootfs_hash={root_hash} dstack.rootfs_size={data_size}" @@ -110,20 +113,24 @@ python do_uki() { env['PYTHONPATH'] = python_sitepackages ukify_path = os.path.join(native_sysroot, 'usr', 'bin', 'ukify') - ukify_cmd = f"{ukify_path} build" - ukify_cmd += f" --efi-arch {target_arch}" - ukify_cmd += f" --stub {stub}" - ukify_cmd += f" --linux={kernel}" - ukify_cmd += f" --initrd={initrd}" - ukify_cmd += f" --cmdline='{cmdline}'" - ukify_cmd += f" --tools={native_sysroot}/usr/lib/systemd/tools" - ukify_cmd += f" --output={output}" - - bb.note(f"Running: {ukify_cmd}") + # Pass an argument list (no shell) so values like cmdline don't need quoting + # and can't be split/expanded by the shell. + ukify_cmd = [ + ukify_path, "build", + f"--efi-arch={target_arch}", + f"--stub={stub}", + f"--linux={kernel}", + f"--initrd={initrd}", + f"--cmdline={cmdline}", + f"--tools={native_sysroot}/usr/lib/systemd/tools", + f"--output={output}", + ] + + bb.note(f"Running: {' '.join(ukify_cmd)}") bb.note(f"PYTHONPATH: {python_sitepackages}") import subprocess - result = subprocess.run(ukify_cmd, shell=True, capture_output=True, text=True, env=env) + result = subprocess.run(ukify_cmd, capture_output=True, text=True, env=env) if result.stdout: bb.note(result.stdout) if result.stderr: diff --git a/meta-dstack/recipes-core/systemd/systemd_%.bbappend b/meta-dstack/recipes-core/systemd/systemd_%.bbappend index ff4d28b..1a7b43b 100644 --- a/meta-dstack/recipes-core/systemd/systemd_%.bbappend +++ b/meta-dstack/recipes-core/systemd/systemd_%.bbappend @@ -20,7 +20,6 @@ EOF SYSTEMD_SERVICE:${PN}-vconsole-setup = "" PACKAGECONFIG:remove = "sysvinit logind" -FILES:${PN} += "${sysconfdir}/modprobe.d/blacklist-autofs4.conf" # Create a minimal package with only systemd-socket-proxyd # This avoids pulling in all of systemd-extra-utils diff --git a/mkimage.sh b/mkimage.sh index e0bdbc0..4c27c5c 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -4,6 +4,12 @@ set -e DSTACK_TAR_RELEASE=${DSTACK_TAR_RELEASE:-1} ENABLE_UKI_IMAGE=${ENABLE_UKI_IMAGE:-1} +# Fixed GPT GUIDs so partitioned images are reproducible (sgdisk randomizes by +# default). Partitions are located by PARTLABEL, not GUID, so these are arbitrary. +DSTACK_DISK_GUID=${DSTACK_DISK_GUID:-d5acc000-0000-4000-8000-000000000000} +DSTACK_ROOTFS_PART_GUID=${DSTACK_ROOTFS_PART_GUID:-d5acc000-0000-4000-8000-000000000001} +DSTACK_EFI_PART_GUID=${DSTACK_EFI_PART_GUID:-d5acc000-0000-4000-8000-000000000002} + # Parse command line arguments while [ $# -gt 0 ]; do case "$1" in @@ -61,8 +67,20 @@ UKI_IMAGE=${FLAVOR_IMG_DIR}/dstack-uki.efi # Verity env is in the flavor-specific work-shared directory VERITY_ENV_FILE=${BB_BUILD_DIR}/tmp-mc-${FLAVOR}/work-shared/tdx/dm-verity/dstack-rootfs.squashfs.verity.env +if [ ! -f "${VERITY_ENV_FILE}" ]; then + echo "Error: verity env not found: ${VERITY_ENV_FILE}" >&2 + echo "Build the rootfs first, e.g.: bitbake mc:${FLAVOR}:dstack-rootfs" >&2 + exit 1 +fi echo "Loading verity env from ${VERITY_ENV_FILE}" -source ${VERITY_ENV_FILE} +# shellcheck source=/dev/null +source "${VERITY_ENV_FILE}" + +# Bare-metal partitioning needs sgdisk (gdisk) +if ! command -v sgdisk >/dev/null 2>&1; then + echo "Error: sgdisk not found; install 'gdisk' to build the partitioned rootfs." >&2 + exit 1 +fi DSTACK_VERSION=$(bitbake-getvar --value DISTRO_VERSION | tail -1) @@ -140,7 +158,12 @@ create_partitioned_rootfs() { local root_end_sector=$((root_start_sector + (rootfs_size_aligned / sector) - 1)) sgdisk --zap-all "$output_img" >/dev/null - sgdisk --new=1:${root_start_sector}:${root_end_sector} --typecode=1:8300 --change-name=1:'dstack-rootfs' "$output_img" >/dev/null + # Fixed GUIDs keep the image bit-for-bit reproducible (GPT otherwise + # randomizes disk/partition GUIDs). The rootfs is located by PARTLABEL. + sgdisk --disk-guid="${DSTACK_DISK_GUID}" \ + --new=1:${root_start_sector}:${root_end_sector} --typecode=1:8300 \ + --partition-guid=1:"${DSTACK_ROOTFS_PART_GUID}" \ + --change-name=1:'dstack-rootfs' "$output_img" >/dev/null dd if="$rootfs_img" of="$output_img" bs=$align seek=$((rootfs_start / align)) conv=notrunc status=none ) @@ -171,8 +194,13 @@ build_uki_disk_image() { local root_end_sector=$((root_start_sector + (rootfs_size_aligned / sector) - 1)) sgdisk --zap-all "$disk_img" >/dev/null - sgdisk --new=1:${efi_start_sector}:${efi_end_sector} --typecode=1:ef00 --change-name=1:'EFI System Partition' "$disk_img" >/dev/null - sgdisk --new=2:${root_start_sector}:${root_end_sector} --typecode=2:8300 --change-name=2:'dstack-rootfs' "$disk_img" >/dev/null + sgdisk --disk-guid="${DSTACK_DISK_GUID}" \ + --new=1:${efi_start_sector}:${efi_end_sector} --typecode=1:ef00 \ + --partition-guid=1:"${DSTACK_EFI_PART_GUID}" \ + --change-name=1:'EFI System Partition' "$disk_img" >/dev/null + sgdisk --new=2:${root_start_sector}:${root_end_sector} --typecode=2:8300 \ + --partition-guid=2:"${DSTACK_ROOTFS_PART_GUID}" \ + --change-name=2:'dstack-rootfs' "$disk_img" >/dev/null local tmp_dir tmp_dir=$(mktemp -d) diff --git a/repro-build/check.sh b/repro-build/check.sh index e83e257..e6feac0 100755 --- a/repro-build/check.sh +++ b/repro-build/check.sh @@ -11,6 +11,7 @@ ACTION=$1 # Colors for output GREEN='\033[0;32m' RED='\033[0;31m' +YELLOW='\033[1;33m' NC='\033[0m' IMAGE_NAME=${IMAGE_NAME:-dstack-rootfs} @@ -30,7 +31,7 @@ COMPARE_IMAGE_WHITELIST=( "initramfs.cpio.gz" "metadata.json" "ovmf.fd" - "rootfs.img.verity" + "rootfs.img.parted.verity" "sha256sum.txt" "gcp/efi-root/EFI/BOOT/BOOTX64.EFI" ) From fed4cc1dd0218649a04132972044923fef90f977 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 4 Jun 2026 09:40:46 +0800 Subject: [PATCH 118/119] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- mkimage.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkimage.sh b/mkimage.sh index 4c27c5c..6e10027 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -241,6 +241,10 @@ $Q cp $KERNEL_IMAGE ${OUTPUT_DIR}/ $Q cp $OVMF_FIRMWARE ${OUTPUT_DIR}/ echo "Creating partitioned rootfs image at ${OUTPUT_DIR}/rootfs.img.parted.verity" +if ! command -v sgdisk >/dev/null; then + echo "Error: cannot create partitioned rootfs image because 'sgdisk' is missing (install 'gdisk', or set ENABLE_UKI_IMAGE=0 and adjust tooling)" >&2 + exit 1 +fi create_partitioned_rootfs "$ROOTFS_IMAGE" "${OUTPUT_DIR}/rootfs.img.parted.verity" GIT_REVISION=$(git rev-parse HEAD 2>/dev/null || echo "") From 9de071b017833d220266a12c3c2ee6f8ae06f064 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 3 Jun 2026 20:08:21 -0700 Subject: [PATCH 119/119] mkimage: dedupe sgdisk check from autofix; clearer message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Copilot autofix (fed4cc1) added an sgdisk check right before create_partitioned_rootfs, but an equivalent early check already existed. Drop the redundant early check and keep the call-site one, with a clearer message (the 'set ENABLE_UKI_IMAGE=0' hint was misleading — sgdisk is needed for the partitioned bare-metal image, not the UKI path). --- mkimage.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/mkimage.sh b/mkimage.sh index 6e10027..1d8ed01 100755 --- a/mkimage.sh +++ b/mkimage.sh @@ -76,12 +76,6 @@ echo "Loading verity env from ${VERITY_ENV_FILE}" # shellcheck source=/dev/null source "${VERITY_ENV_FILE}" -# Bare-metal partitioning needs sgdisk (gdisk) -if ! command -v sgdisk >/dev/null 2>&1; then - echo "Error: sgdisk not found; install 'gdisk' to build the partitioned rootfs." >&2 - exit 1 -fi - DSTACK_VERSION=$(bitbake-getvar --value DISTRO_VERSION | tail -1) # Output directory contains all artifacts; tarballs contain subsets @@ -241,8 +235,9 @@ $Q cp $KERNEL_IMAGE ${OUTPUT_DIR}/ $Q cp $OVMF_FIRMWARE ${OUTPUT_DIR}/ echo "Creating partitioned rootfs image at ${OUTPUT_DIR}/rootfs.img.parted.verity" +# Bare-metal partitioning needs sgdisk (from the 'gdisk' package). if ! command -v sgdisk >/dev/null; then - echo "Error: cannot create partitioned rootfs image because 'sgdisk' is missing (install 'gdisk', or set ENABLE_UKI_IMAGE=0 and adjust tooling)" >&2 + echo "Error: cannot create partitioned rootfs image because 'sgdisk' is missing; install 'gdisk'." >&2 exit 1 fi create_partitioned_rootfs "$ROOTFS_IMAGE" "${OUTPUT_DIR}/rootfs.img.parted.verity"