Skip to content

Commit a59ed89

Browse files
authored
vmexec: create working directory if it doesn't exist (#591)
This seems like standard OCI runtime behavior, which is to create the working directory if it doesn't exist.
1 parent d8fcd1e commit a59ed89

3 files changed

Lines changed: 93 additions & 0 deletions

File tree

Sources/Integration/ContainerTests.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4218,6 +4218,87 @@ extension IntegrationSuite {
42184218
}
42194219
}
42204220

4221+
func testWorkingDirCreated() async throws {
4222+
let id = "test-working-dir-created"
4223+
let bs = try await bootstrap(id)
4224+
4225+
let buffer = BufferWriter()
4226+
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
4227+
config.process.arguments = ["/bin/pwd"]
4228+
config.process.workingDirectory = "/does/not/exist"
4229+
config.process.stdout = buffer
4230+
config.bootLog = bs.bootLog
4231+
}
4232+
4233+
do {
4234+
try await container.create()
4235+
try await container.start()
4236+
4237+
let status = try await container.wait()
4238+
try await container.stop()
4239+
4240+
guard status.exitCode == 0 else {
4241+
throw IntegrationError.assert(msg: "process with non-existent workingDir failed: \(status)")
4242+
}
4243+
4244+
guard let output = String(data: buffer.data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) else {
4245+
throw IntegrationError.assert(msg: "failed to read stdout")
4246+
}
4247+
4248+
guard output == "/does/not/exist" else {
4249+
throw IntegrationError.assert(msg: "expected cwd '/does/not/exist', got '\(output)'")
4250+
}
4251+
} catch {
4252+
try? await container.stop()
4253+
throw error
4254+
}
4255+
}
4256+
4257+
func testWorkingDirExecCreated() async throws {
4258+
let id = "test-working-dir-exec-created"
4259+
let bs = try await bootstrap(id)
4260+
4261+
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
4262+
config.process.arguments = ["/bin/sleep", "1000"]
4263+
config.bootLog = bs.bootLog
4264+
}
4265+
4266+
do {
4267+
try await container.create()
4268+
try await container.start()
4269+
4270+
let buffer = BufferWriter()
4271+
let exec = try await container.exec("cwd-exec") { config in
4272+
config.arguments = ["/bin/pwd"]
4273+
config.workingDirectory = "/a/b/c/d"
4274+
config.stdout = buffer
4275+
}
4276+
4277+
try await exec.start()
4278+
let status = try await exec.wait()
4279+
try await exec.delete()
4280+
4281+
guard status.exitCode == 0 else {
4282+
throw IntegrationError.assert(msg: "exec with non-existent workingDir failed: \(status)")
4283+
}
4284+
4285+
guard let output = String(data: buffer.data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) else {
4286+
throw IntegrationError.assert(msg: "failed to read stdout")
4287+
}
4288+
4289+
guard output == "/a/b/c/d" else {
4290+
throw IntegrationError.assert(msg: "expected cwd '/a/b/c/d', got '\(output)'")
4291+
}
4292+
4293+
try await container.kill(SIGKILL)
4294+
try await container.wait()
4295+
try await container.stop()
4296+
} catch {
4297+
try? await container.stop()
4298+
throw error
4299+
}
4300+
}
4301+
42214302
func testNoNewPrivilegesExec() async throws {
42224303
let id = "test-no-new-privileges-exec"
42234304

Sources/Integration/Suite.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ struct IntegrationSuite: AsyncParsableCommand {
374374
Test("container noNewPrivileges", testNoNewPrivileges),
375375
Test("container noNewPrivileges disabled", testNoNewPrivilegesDisabled),
376376
Test("container noNewPrivileges exec", testNoNewPrivilegesExec),
377+
Test("container workingDir created", testWorkingDirCreated),
378+
Test("container workingDir exec created", testWorkingDirExecCreated),
377379

378380
// Pods
379381
Test("pod single container", testPodSingleContainer),

vminitd/Sources/vmexec/vmexec.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ extension App {
9696
let env = process.env.map { strdup($0) } + [nil]
9797
let cwd = process.cwd
9898

99+
// Create the working directory if it doesn't exist, this seems like the expected
100+
// OCI runtime spec behavior.
101+
if !FileManager.default.fileExists(atPath: cwd) {
102+
try FileManager.default.createDirectory(
103+
atPath: cwd,
104+
withIntermediateDirectories: true,
105+
attributes: [.posixPermissions: 0o755]
106+
)
107+
}
108+
99109
guard chdir(cwd) == 0 else {
100110
throw App.Errno(stage: "chdir(cwd)", info: "failed to change directory to '\(cwd)'")
101111
}

0 commit comments

Comments
 (0)