Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/orchestrator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,5 @@ Automatically set in local mode. Set before running to override:

## Limitations

- Custom template builds support base images from the declared distro families: **Debian/Ubuntu** (apt), the **RHEL family** — Fedora, CentOS Stream, Rocky, Alma — (dnf/microdnf/yum), **TencentOS Server** 3+ and **OpenCloudOS** 8+ (dnf/microdnf/yum; TencentOS Server 2.x repos lack socat, fuse3, nftables and jq, so its builds fail at package install), **Arch** (pacman), and **Alpine** (apk, OpenRC). The distro is resolved from the image's `/etc/os-release` `ID` — never by probing for package managers. Images without an os-release identity (distroless, scratch) or from an undeclared family are rejected fast, with a build-log error naming the reason and the supported families (see `pkg/template/build/phases/base/distro`). Minimal/restricted-repo images may fail provisioning if their repos don't carry the required packages; the failure is surfaced in the build log.
- Custom template builds support base images from the declared distro families: **Debian/Ubuntu** (apt), the **RHEL family** — Fedora, CentOS Stream, Rocky, Alma — (dnf/microdnf/yum), **TencentOS Server** 3+ and **OpenCloudOS** 8+ (dnf/microdnf/yum; TencentOS Server 2.x repos lack socat, fuse3, nftables and jq, so its builds fail at package install), **UnionTech OS (UOS) Server** 20 (dnf/microdnf/yum; its two image lineages name the account-tools package differently, shadow vs shadow-utils, so the profile installs neither and relies on the base image), **Arch** (pacman), and **Alpine** (apk, OpenRC). The distro is resolved from the image's `/etc/os-release` `ID` — never by probing for package managers. Images without an os-release identity (distroless, scratch) or from an undeclared family are rejected fast, with a build-log error naming the reason and the supported families (see `pkg/template/build/phases/base/distro`). Minimal/restricted-repo images may fail provisioning if their repos don't carry the required packages; the failure is surfaced in the build log.
- Sandboxes always boot the kernel E2B supplies, never one from the base image: `/lib/modules` is empty, no kernel modules can be loaded, and SELinux is disabled on the kernel command line (`selinux=0`), so a base image that ships an SELinux policy boots without it. `kernel-devel` from a distro's repos resolves against a kernel that isn't running. **RHEL** (`rhel`, incl. UBI), **Oracle Linux** (`ol`) and **Amazon Linux** (`amzn`) are therefore not accepted even though they are RPM/dnf images — they are chosen for kABI, signed kernel modules and UEK, which this cannot honour. The community rebuilds above are supported because they are chosen for the userland.
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,37 @@ var Profiles = []Profile{
CABundle: "/etc/ssl/certs/ca-certificates.crt",
CARefresh: `update-ca-trust extract && ln -sf /etc/pki/tls/certs/ca-bundle.crt "$E2B_CA_BUNDLE"`,
},
{
// UnionTech OS (统信 UOS) Server 20 is an RPM/dnf, systemd distro. Its
// /etc/os-release declares ID=uos and no ID_LIKE, so without this profile
// a UOS base falls through to the unsupported-distro error.
//
// Verified against two independent UOS Server 20 images
// (macrosan/uos:v20-1050 and ixuzhi/uos-server:1070a): both are
// RHEL-shaped, but the two lineages name the account tools package
// differently — one ships shadow, the other shadow-utils, and listing
// either aborts the dnf transaction on the image that lacks it. Both
// base images already ship useradd/usermod, so this profile installs
// neither and relies on the base, as the Debian family does; passwd is
// still installed and resolves on both.
Key: "uos",
Init: InitSystemd,
IDs: []string{"uos"},
Packages: []string{
"systemd", "passwd", "openssh-server", "sudo", "chrony",
"socat", "curl", "ca-certificates", "fuse3", "iptables", "git",
"nfs-utils", "less", "nftables", "iputils", "jq", "bash", "tar",
"iproute", "findutils",
},
PkgQueryBody: `rpm -q "$1" >/dev/null 2>&1`,
PkgInstall: `dnf -y install --allowerasing "$@" || microdnf -y install "$@" || yum -y install "$@"`,
InitBinary: "/usr/lib/systemd/systemd",
TimeSyncUnit: "chronyd",
SSHUnit: "sshd",
AdminGroup: "wheel",
CABundle: "/etc/ssl/certs/ca-certificates.crt",
CARefresh: `update-ca-trust extract && ln -sf /etc/pki/tls/certs/ca-bundle.crt "$E2B_CA_BUNDLE"`,
},
{
Key: "arch",
Init: InitSystemd,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package distro

import (
"slices"
"crypto/sha256"
"encoding/hex"
"strings"
Expand Down Expand Up @@ -339,3 +340,33 @@ func TestRejectedIDsAreNotReachableViaIDLike(t *testing.T) {
t.Error("the rejected-id guard must precede the ID_LIKE fallback")
}
}

// UOS Server 20 declares ID=uos and no ID_LIKE. Verified against
// macrosan/uos:v20-1050 and ixuzhi/uos-server:1070a: RHEL-shaped, but the two
// lineages name the account-tools package differently (shadow vs shadow-utils),
// so the profile installs neither — the base image ships useradd — and must not
// list either, or dnf aborts on the image lacking it.
func TestUOSProfile(t *testing.T) {
t.Parallel()
u := profileByKey(t, "uos")
if !slices.Contains(u.IDs, "uos") {
t.Errorf("uos id must be matched, got IDs=%v", u.IDs)
}
if slices.Contains(u.Packages, "shadow") || slices.Contains(u.Packages, "shadow-utils") {
t.Errorf("uos must install neither shadow nor shadow-utils (lineage-split name); got %v", u.Packages)
}
if !slices.Contains(u.Packages, "passwd") {
t.Error("uos must still install passwd")
}
if u.InitBinary != "/usr/lib/systemd/systemd" {
t.Errorf("uos init path wrong: %s", u.InitBinary)
}
for _, want := range []string{"dnf -y install --allowerasing", "|| microdnf -y install", "|| yum -y install"} {
if !strings.Contains(u.PkgInstall, want) {
t.Errorf("uos install missing %q: %s", want, u.PkgInstall)
}
}
if !strings.Contains(ShellSelector(), "uos)") {
t.Error("selector must have a uos arm")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var capabilities = []struct {
"debian": {"systemd", "systemd-sysv"},
"rhel": {"systemd"},
"tencentos": {"systemd"},
"uos": {"systemd"},
"arch": {"systemd"},
"alpine": {"openrc"},
}},
Expand All @@ -30,6 +31,7 @@ var capabilities = []struct {
"debian": {},
"rhel": {"bash"},
"tencentos": {"bash"},
"uos": {"bash"},
"arch": {"bash"},
"alpine": {"bash"},
}},
Expand All @@ -38,97 +40,111 @@ var capabilities = []struct {
"debian": {},
"rhel": {"shadow-utils", "passwd"},
"tencentos": {"shadow-utils", "passwd"},
"uos": {"passwd"},
"arch": {"shadow"},
"alpine": {"shadow"},
}},
{"ssh-server", map[string][]string{
"debian": {"openssh-server"},
"rhel": {"openssh-server"},
"tencentos": {"openssh-server"},
"uos": {"openssh-server"},
"arch": {"openssh"},
"alpine": {"openssh"},
}},
{"sudo", map[string][]string{
"debian": {"sudo"},
"rhel": {"sudo"},
"tencentos": {"sudo"},
"uos": {"sudo"},
"arch": {"sudo"},
"alpine": {"sudo"},
}},
{"time-sync", map[string][]string{
"debian": {"chrony"},
"rhel": {"chrony"},
"tencentos": {"chrony"},
"uos": {"chrony"},
"arch": {"chrony"},
"alpine": {"chrony"},
}},
{"ca-certificates", map[string][]string{
"debian": {"ca-certificates"},
"rhel": {"ca-certificates"},
"tencentos": {"ca-certificates"},
"uos": {"ca-certificates"},
"arch": {"ca-certificates"},
"alpine": {"ca-certificates"},
}},
{"fuse", map[string][]string{
"debian": {"fuse3"},
"rhel": {"fuse3"},
"tencentos": {"fuse3"},
"uos": {"fuse3"},
"arch": {"fuse3"},
"alpine": {"fuse3"},
}},
{"nfs-client", map[string][]string{
"debian": {"nfs-common"},
"rhel": {"nfs-utils"},
"tencentos": {"nfs-utils"},
"uos": {"nfs-utils"},
"arch": {"nfs-utils"},
"alpine": {"nfs-utils"},
}},
{"packet-filter", map[string][]string{
"debian": {"iptables", "nftables"},
"rhel": {"iptables", "nftables"},
"tencentos": {"iptables", "nftables"},
"uos": {"iptables", "nftables"},
"arch": {"iptables", "nftables"},
"alpine": {"iptables", "nftables"},
}},
{"git", map[string][]string{
"debian": {"git"},
"rhel": {"git"},
"tencentos": {"git"},
"uos": {"git"},
"arch": {"git"},
"alpine": {"git"},
}},
{"jq", map[string][]string{
"debian": {"jq"},
"rhel": {"jq"},
"tencentos": {"jq"},
"uos": {"jq"},
"arch": {"jq"},
"alpine": {"jq"},
}},
{"socat", map[string][]string{
"debian": {"socat"},
"rhel": {"socat"},
"tencentos": {"socat"},
"uos": {"socat"},
"arch": {"socat"},
"alpine": {"socat"},
}},
{"curl", map[string][]string{
"debian": {"curl"},
"rhel": {"curl"},
"tencentos": {"curl"},
"uos": {"curl"},
"arch": {"curl"},
"alpine": {"curl"},
}},
{"pager", map[string][]string{
"debian": {"less"},
"rhel": {"less"},
"tencentos": {"less"},
"uos": {"less"},
"arch": {"less"},
"alpine": {"less"},
}},
{"ping", map[string][]string{
"debian": {"iputils-ping"},
"rhel": {"iputils"},
"tencentos": {"iputils"},
"uos": {"iputils"},
"arch": {"iputils"},
"alpine": {"iputils"},
}},
Expand All @@ -138,6 +154,7 @@ var capabilities = []struct {
"debian": {"iproute2"},
"rhel": {"iproute"},
"tencentos": {"iproute"},
"uos": {"iproute"},
"arch": {},
"alpine": {"iproute2"},
}},
Expand All @@ -151,6 +168,7 @@ var capabilities = []struct {
"debian": {},
"rhel": {"findutils"},
"tencentos": {"findutils"},
"uos": {"findutils"},
"arch": {},
"alpine": {},
}},
Expand All @@ -160,6 +178,7 @@ var capabilities = []struct {
"debian": {},
"rhel": {"tar"},
"tencentos": {"tar"},
"uos": {"tar"},
"arch": {},
"alpine": {},
}},
Expand All @@ -169,6 +188,7 @@ var capabilities = []struct {
"debian": {},
"rhel": {},
"tencentos": {},
"uos": {},
"arch": {},
"alpine": {"util-linux-misc"},
}},
Expand Down