Skip to content

Commit 47a1d44

Browse files
committed
fixes for glibc image with local KMT
1 parent f68f020 commit 47a1d44

File tree

3 files changed

+34
-91
lines changed

3 files changed

+34
-91
lines changed

tasks/kernel_matrix_testing/compiler.py

+21-76
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@
2323
AMD64_DEBIAN_KERNEL_HEADERS_URL = "http://deb.debian.org/debian-security/pool/updates/main/l/linux-5.10/linux-headers-5.10.0-0.deb10.28-amd64_5.10.209-2~deb10u1_amd64.deb"
2424
ARM64_DEBIAN_KERNEL_HEADERS_URL = "http://deb.debian.org/debian-security/pool/updates/main/l/linux-5.10/linux-headers-5.10.0-0.deb10.28-arm64_5.10.209-2~deb10u1_arm64.deb"
2525

26-
DOCKER_REGISTRY = "486234852809.dkr.ecr.us-east-1.amazonaws.com"
2726
DOCKER_BASE_IMAGES = {
28-
"x64": f"{DOCKER_REGISTRY}/ci/datadog-agent-buildimages/linux-glibc-2.17-x64",
29-
"arm64": f"{DOCKER_REGISTRY}/ci/datadog-agent-buildimages/linux-glibc-2.23-arm64",
27+
"x64": f"registry.ddbuild.io/ci/datadog-agent-buildimages/linux-glibc-2-17-x64",
28+
"arm64": f"registry.ddbuild.io/ci/datadog-agent-buildimages/linux-glibc-2-23-arm64",
3029
}
3130

3231

@@ -49,21 +48,6 @@ def get_docker_image_name(ctx: Context, container: str) -> str:
4948
return data[0]["Config"]["Image"]
5049

5150

52-
def has_docker_auth_helpers() -> bool:
53-
docker_config = Path("~/.docker/config.json").expanduser()
54-
if not docker_config.exists():
55-
return False
56-
57-
try:
58-
with open(docker_config) as f:
59-
config = json.load(f)
60-
except json.JSONDecodeError:
61-
# Invalid JSON (or empty file), we don't have the helper
62-
return False
63-
64-
return DOCKER_REGISTRY in config.get("credHelpers", {})
65-
66-
6751
class CompilerImage:
6852
def __init__(self, ctx: Context, arch: Arch):
6953
self.ctx = ctx
@@ -115,15 +99,18 @@ def ensure_version(self):
11599
warn(f"[!] Running compiler image {image_used} is different from the expected {self.image}, will restart")
116100
self.start()
117101

118-
def exec(self, cmd: str, user="compiler", verbose=True, run_dir: PathOrStr | None = None, allow_fail=False):
102+
def exec(self, cmd: str, user="compiler", verbose=True, run_dir: PathOrStr | None = None, allow_fail=False, force_color=True):
119103
if run_dir:
120104
cmd = f"cd {run_dir} && {cmd}"
121105

122106
self.ensure_running()
107+
color_env = "-e FORCE_COLOR=1"
108+
if not force_color:
109+
color_env = ""
123110

124111
# Set FORCE_COLOR=1 so that termcolor works in the container
125112
return self.ctx.run(
126-
f"docker exec -u {user} -i -e FORCE_COLOR=1 {self.name} bash -c \"{cmd}\"",
113+
f"docker exec -u {user} -i {color_env} {self.name} bash -l -c \"{cmd}\"",
127114
hide=(not verbose),
128115
warn=allow_fail,
129116
)
@@ -139,23 +126,14 @@ def start(self) -> None:
139126
# Check if the image exists
140127
res = self.ctx.run(f"docker image inspect {self.image}", hide=True, warn=True)
141128
if res is None or not res.ok:
142-
info(f"[!] Image {self.image} not found, logging in and pulling...")
143-
144-
if has_docker_auth_helpers():
145-
# With ddtool helpers (installed with ddtool auth helpers install), docker automatically
146-
# pulls credentials from ddtool, and we require the aws-vault context to pull
147-
docker_pull_auth = "aws-vault exec sso-build-stable-developer -- "
148-
else:
149-
# Without the helpers, we need to get the password and login manually to docker
150-
self.ctx.run(
151-
"aws-vault exec sso-build-stable-developer -- aws ecr --region us-east-1 get-login-password | docker login --username AWS --password-stdin 486234852809.dkr.ecr.us-east-1.amazonaws.com"
152-
)
153-
docker_pull_auth = ""
154-
155-
self.ctx.run(f"{docker_pull_auth}docker pull {self.image}")
129+
info(f"[!] Image {self.image} not found, pulling...")
130+
self.ctx.run(f"docker pull {self.image}")
156131

132+
platform = ""
133+
if self.arch != Arch.local():
134+
platform = f"--platform linux/{self.arch.go_arch}"
157135
res = self.ctx.run(
158-
f"docker run -d --restart always --name {self.name} "
136+
f"docker run {platform} -d --restart always --name {self.name} "
159137
f"--mount type=bind,source={os.getcwd()},target={CONTAINER_AGENT_PATH} "
160138
f"{self.image} sleep \"infinity\"",
161139
warn=True,
@@ -183,51 +161,18 @@ def start(self) -> None:
183161
)
184162

185163
self.exec("chmod a+rx /root", user="root") # Some binaries will be in /root and need to be readable
186-
self.exec("apt install sudo", user="root")
164+
self.exec("apt-get install -y --no-install-recommends sudo", user="root")
187165
self.exec("usermod -aG sudo compiler && echo 'compiler ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers", user="root")
188-
self.exec("echo conda activate ddpy3 >> /home/compiler/.bashrc", user="compiler")
166+
self.exec(f"cp /root/.bashrc /home/compiler/.bashrc && chown {uid}:{gid} /home/compiler/.bashrc", user="root")
167+
self.exec("mkdir ~/.cargo && touch ~/.cargo/env", user="compiler")
168+
self.exec("dda self telemetry disable", user="compiler", force_color=False)
189169
self.exec(f"install -d -m 0777 -o {uid} -g {uid} /go", user="root")
170+
self.exec(f"echo export DD_CC={self.arch.gcc_arch}-unknown-linux-gnu-gcc >> /home/compiler/.bashrc", user="compiler")
171+
self.exec(f"echo export DD_CXX={self.arch.gcc_arch}-unknown-linux-gnu-g++ >> /home/compiler/.bashrc", user="compiler")
190172

191-
self.prepare_for_cross_compile()
192173

193-
def ensure_ready_for_cross_compile(self):
194-
res = self.exec("test -f /tmp/cross-compile-ready", user="root", allow_fail=True)
195-
if res is None or not res.ok:
196-
info("[*] Compiler image not ready for cross-compilation, preparing...")
197-
self.prepare_for_cross_compile()
198-
199-
def prepare_for_cross_compile(self):
200-
target = ARCH_AMD64 if self.arch == ARCH_ARM64 else ARCH_ARM64
201-
202-
# Hardcoded links to the header packages for each architecture. Why do this and not have something more automated?
203-
# 1. While right now the URLs are similar and we'd only need a single link with variable replacement, this might
204-
# change as the repository layout is not under our control.
205-
# 2. Automatic detection of these URLs is not direct (querying the package repo APIs is not trivial) and we'd need some
206-
# level of hard-coding some URLs or assumptions anyways.
207-
# 3. Even if someone forgets to update these URLs, it's not a big deal, as we're building inside of a Docker image which will
208-
# likely have a different kernel than the target system where the built eBPF files are going to run anyways.
209-
header_package_urls: dict[Arch, str] = {
210-
ARCH_AMD64: AMD64_DEBIAN_KERNEL_HEADERS_URL,
211-
ARCH_ARM64: ARM64_DEBIAN_KERNEL_HEADERS_URL,
212-
}
213-
214-
header_package_path = "/tmp/headers.deb"
215-
self.exec(f"wget -O {header_package_path} {header_package_urls[target]}")
216-
217-
# Uncompress the package in the root directory, so that we have access to the headers
218-
# We cannot install because the architecture will not match
219-
# Extract into a .tar file and then use tar to extract the contents to avoid issues
220-
# with dpkg-deb not respecting symlinks.
221-
self.exec(f"dpkg-deb --fsys-tarfile {header_package_path} > {header_package_path}.tar", user="root")
222-
self.exec(f"tar -h -xf {header_package_path}.tar -C /", user="root")
223-
224-
# Install the corresponding arch compilers
225-
self.exec(f"apt update && apt install -y gcc-{target.gcc_arch.replace('_', '-')}-linux-gnu", user="root")
226-
self.exec("touch /tmp/cross-compile-ready") # Signal that we're ready for cross-compilation
227-
228-
229-
def get_compiler(ctx: Context):
230-
cc = CompilerImage(ctx, Arch.local())
174+
def get_compiler(ctx: Context, arch_obj: Arch):
175+
cc = CompilerImage(ctx, arch_obj)
231176
cc.ensure_version()
232177
cc.ensure_running()
233178

tasks/kmt.py

+12-15
Original file line numberDiff line numberDiff line change
@@ -478,8 +478,8 @@ def update_resources(
478478

479479

480480
@task
481-
def start_compiler(ctx: Context):
482-
cc = get_compiler(ctx)
481+
def start_compiler(ctx: Context, arch: Arch | str = "local",):
482+
cc = get_compiler(ctx, Arch.from_str(arch))
483483
info(f"[+] Starting compiler {cc.name}")
484484
try:
485485
cc.start()
@@ -522,10 +522,12 @@ def download_gotestsum(ctx: Context, arch: Arch, fgotestsum: PathOrStr):
522522
paths = KMTPaths(None, arch)
523523
paths.tools.mkdir(parents=True, exist_ok=True)
524524

525-
cc = get_compiler(ctx)
525+
cc = get_compiler(ctx, arch)
526526
target_path = CONTAINER_AGENT_PATH / paths.tools.relative_to(paths.repo_root) / "gotestsum"
527+
env = {"GOARCH": arch.go_arch, "CC": "\\$DD_CC", "CXX": "\\$DD_CXX"}
528+
env_str = " ".join(f"{key}={value}" for key, value in env.items())
527529
cc.exec(
528-
f"cd {TOOLS_PATH} && GOARCH={arch.go_arch} go build -o {target_path} {GOTESTSUM}",
530+
f"cd {TOOLS_PATH} && {env_str} go build -o {target_path} {GOTESTSUM}",
529531
)
530532

531533
ctx.run(f"cp {paths.tools}/gotestsum {fgotestsum}")
@@ -766,10 +768,7 @@ def _prepare(
766768
domains: list[LibvirtDomain] | None = None,
767769
):
768770
if not ci:
769-
cc = get_compiler(ctx)
770-
771-
if arch_obj.is_cross_compiling():
772-
cc.ensure_ready_for_cross_compile()
771+
cc = get_compiler(ctx, arch_obj)
773772

774773
pkgs = ""
775774
if packages:
@@ -896,7 +895,8 @@ def build_target_packages(filter_packages: list[str], build_tags: list[str]):
896895

897896

898897
def build_object_files(ctx, fp, arch: Arch):
899-
info("[+] Generating eBPF object files...")
898+
setup_runtime_clang(ctx)
899+
info(f"[+] Generating eBPF object files... {fp}")
900900
ninja_generate(ctx, fp, arch=arch)
901901
ctx.run(f"ninja -d explain -f {fp}")
902902

@@ -1312,14 +1312,11 @@ def build(
13121312
paths = KMTPaths(stack, arch_obj)
13131313
paths.arch_dir.mkdir(parents=True, exist_ok=True)
13141314

1315-
cc = get_compiler(ctx)
1315+
cc = get_compiler(ctx, arch_obj)
13161316

13171317
inv_echo = "-e" if ctx.config.run["echo"] else ""
1318-
cc.exec(f"cd {CONTAINER_AGENT_PATH} && dda inv {inv_echo} system-probe.object-files")
1319-
1320-
build_task = "build-sysprobe-binary" if component == "system-probe" else "build"
13211318
cc.exec(
1322-
f"cd {CONTAINER_AGENT_PATH} && git config --global --add safe.directory {CONTAINER_AGENT_PATH} && dda inv {inv_echo} {component}.{build_task} --arch={arch_obj.name}",
1319+
f"cd {CONTAINER_AGENT_PATH} && git config --global --add safe.directory {CONTAINER_AGENT_PATH} && dda inv {inv_echo} {component}.build --arch={arch_obj.name}",
13231320
)
13241321

13251322
cc.exec(f"tar cf {CONTAINER_AGENT_PATH}/kmt-deps/{stack}/build-embedded-dir.tar {EMBEDDED_SHARE_DIR}")
@@ -1331,7 +1328,7 @@ def build(
13311328

13321329
domains = get_target_domains(ctx, stack, ssh_key, arch_obj, vms, alien_vms)
13331330
if alien_vms is not None:
1334-
err_msg = f"no alient VMs discovered from provided profile {alien_vms}."
1331+
err_msg = f"no alien VMs discovered from provided profile {alien_vms}."
13351332
else:
13361333
err_msg = f"no vms found from list {vms}. Run `dda inv -e kmt.status` to see all VMs in current stack"
13371334

tasks/system_probe.py

+1
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ def build_libpcap(ctx):
656656
lib_dir = os.path.join(dist_dir, f"libpcap-{LIBPCAP_VERSION}")
657657
ctx.run(f"rm -rf {lib_dir}")
658658
with ctx.cd(dist_dir):
659+
# TODO check the checksum of the download before using
659660
ctx.run(f"curl -L https://www.tcpdump.org/release/libpcap-{LIBPCAP_VERSION}.tar.xz | tar xJ")
660661
with ctx.cd(lib_dir):
661662
env = {}

0 commit comments

Comments
 (0)