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
40 changes: 31 additions & 9 deletions Sources/Container-Compose/Commands/ComposeUp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -431,28 +431,50 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {
environmentVariables: [String: String],
supportsAliases: Bool = networkAliasesSupported
) -> (arg: String, warning: String?) {
let resolvedAliases = ([serviceName] + aliases.map { resolveVariable($0, with: environmentVariables) })
let resolvedUserAliases = aliases
.map { resolveVariable($0, with: environmentVariables) }
.reduce(into: [String]()) { result, alias in
guard !alias.isEmpty, !result.contains(alias) else { return }
result.append(alias)
}
// Also advertise the service name as an alias so a runtime that supports
// them can resolve `<service>` without /etc/hosts patching.
let resolvedAliases = ([serviceName] + resolvedUserAliases)
.reduce(into: [String]()) { result, alias in
guard !result.contains(alias) else { return }
result.append(alias)
}

if supportsAliases {
let aliasProperties = resolvedAliases.map { "alias=\($0)" }.joined(separator: ",")
return ("\(network),\(aliasProperties)", nil)
}

return (
network,
"Warning: Service '\(serviceName)' defines network aliases for '\(network)' (\(resolvedAliases.joined(separator: ", "))), but the linked Apple Container command parser does not expose a container run alias property."
)
// Apple Container's `container run` only accepts the `mac` and `mtu`
// network properties — there is no `alias`. Drop them and rely on
// /etc/hosts patching for service-name resolution. Only warn when the
// user explicitly declared aliases; the implicit service-name alias is
// an internal detail and its absence is already covered by the hosts
// fallback, so it would just be noise on every networked service.
let warning: String? = resolvedUserAliases.isEmpty
? nil
: "Warning: Service '\(serviceName)' declares network aliases for '\(network)' "
+ "(\(resolvedUserAliases.joined(separator: ", "))), but Apple Container does not "
+ "support them; ignoring. Service-name resolution still works via /etc/hosts."
return (network, warning)
}

private static func supportsNetworkAliases() -> Bool {
(try? Application.ContainerRun.parse([
"--network", "container-compose-probe,alias=container-compose-probe",
"alpine:latest",
])) != nil
// Apple Container's `container run` does not support network aliases: the
// daemon accepts only the `mac` and `mtu` network properties and rejects
// `alias` with "unknown network property 'alias'. Available properties:
// mac, mtu". The previous probe tested container-compose's own
// ArgumentParser model (`Application.ContainerRun.parse`), which accepts
// any `key=value`, so it always reported support — which made
// `networkRunArg` emit `alias=<service>` for every service on a custom
// network and break startup. Return false until Apple Container gains
// alias support.
return false
}

static func validateStoppedServiceExitCode(_ exitCode: Int32, serviceName: String) throws {
Expand Down
19 changes: 18 additions & 1 deletion Tests/Container-Compose-StaticTests/EntrypointCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,24 @@ struct EntrypointCommandTests {
supportsAliases: false
)

// Only the user-declared aliases appear in the warning (not the implicit
// service name); the service-name alias is covered by the /etc/hosts
// fallback, so warning about it on every networked service would be noise.
#expect(r.arg == "backend")
#expect(r.warning == "Warning: Service 'web' defines network aliases for 'backend' (web, db, database), but the linked Apple Container command parser does not expose a container run alias property.")
#expect(r.warning == "Warning: Service 'web' declares network aliases for 'backend' (db, database), but Apple Container does not support them; ignoring. Service-name resolution still works via /etc/hosts.")
}

@Test("no alias warning when only the implicit service-name alias is present")
func networkAliasesNoWarningWithoutUserAliases() {
let r = ComposeUp.networkRunArg(
network: "backend",
aliases: [],
serviceName: "web",
environmentVariables: [:],
supportsAliases: false
)

#expect(r.arg == "backend")
#expect(r.warning == nil)
}
}
Loading