Skip to content
Merged
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 dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions src/setup-builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,49 @@ describe("setup_builder", () => {
expect(core.warning).toHaveBeenCalled();
});
});

describe("discardPersistedHostResolvConf", () => {
it("removes the executor resolv-host.conf as root so the glob expands", async () => {
const exec = (await import("child_process")).exec as unknown as {
mock: { calls: [string][] };
mockImplementation: (
fn: (cmd: string, cb: (...args: unknown[]) => void) => void,
) => void;
};
exec.mockImplementation(
(cmd: string, cb: (...args: unknown[]) => void) => {
cb(null, { stdout: "", stderr: "" });
},
);

await setupBuilder.discardPersistedHostResolvConf();

const cmd = exec.mock.calls.at(-1)?.[0];
expect(cmd).toMatch(/^sudo sh -c 'rm -f /);
expect(cmd).toContain(
"/var/lib/buildkit/runc-*/executor/resolv-host.conf",
);
expect(core.warning).not.toHaveBeenCalled();
});

it("warns instead of failing the job when the removal errors", async () => {
const exec = (await import("child_process")).exec as unknown as {
mockImplementation: (
fn: (cmd: string, cb: (...args: unknown[]) => void) => void,
) => void;
};
exec.mockImplementation(
(cmd: string, cb: (...args: unknown[]) => void) => {
cb(new Error("rm: permission denied"), null);
},
);

await expect(
setupBuilder.discardPersistedHostResolvConf(),
).resolves.toBeUndefined();
expect(core.warning).toHaveBeenCalledWith(
expect.stringContaining("resolv-host.conf"),
);
});
});
});
22 changes: 22 additions & 0 deletions src/setup_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,26 @@ export async function logDatabaseHashes(label: string): Promise<void> {
}
}

// buildkitd deletes <root>/runc-*/executor/{hosts,resolv.conf} on startup but
// not resolv-host.conf, the resolv.conf it bind-mounts into --network=host RUN
// containers. After the daemon's first container it keeps a saved
// resolv-host.conf whenever its mtime is newer than /etc/resolv.conf, which on
// these VMs is boot time. On a sticky disk the saved file came from whichever
// VM last committed and names that VM's eth0 address as nameserver, which is
// unreachable here, so every lookup inside host-network RUNs times out. Drop
// it so this daemon writes one with its own address.
export async function discardPersistedHostResolvConf(): Promise<void> {
try {
await execAsync(
`sudo sh -c 'rm -f ${mountPoint}/runc-*/executor/resolv-host.conf'`,
);
} catch (error) {
core.warning(
`Failed to discard persisted BuildKit resolv-host.conf: ${(error as Error).message}`,
);
}
}

// stickyDiskTimeoutMs states the max amount of time this action will wait for the VM agent to
// expose the sticky disk from the storage agent, map it onto the host and then patch the drive
// into the VM.
Expand Down Expand Up @@ -694,6 +714,8 @@ export async function setupStickyDisk(): Promise<{
core.debug(`${device} has been mounted to ${mountPoint}`);
core.info("Successfully obtained sticky disk");

await discardPersistedHostResolvConf();

// Log filesystem free space after mount
try {
const { stdout } = await execAsync(
Expand Down
Loading