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
19 changes: 18 additions & 1 deletion Sources/ContainerPersistence/ContainerSystemConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//

import CVersion
import ContainerResource
import ContainerVersion
import ContainerizationExtras
import Foundation
Expand Down Expand Up @@ -132,15 +133,31 @@ final public class ContainerConfig: Codable, Sendable {
}

final public class DNSConfig: Codable, Sendable {
public let nameservers: [String]
public let domain: String?
public let searchDomains: [String]
public let options: [String]

public init(domain: String? = nil) {
public init(
nameservers: [String] = ContainerConfiguration.DNSConfiguration.defaultNameservers,
domain: String? = nil,
searchDomains: [String] = [],
options: [String] = []
) {
self.nameservers = nameservers
self.domain = domain
self.searchDomains = searchDomains
self.options = options
}

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.nameservers =
try container.decodeIfPresent([String].self, forKey: .nameservers)
?? ContainerConfiguration.DNSConfiguration.defaultNameservers
self.domain = try container.decodeIfPresent(String.self, forKey: .domain)
self.searchDomains = try container.decodeIfPresent([String].self, forKey: .searchDomains) ?? []
self.options = try container.decodeIfPresent([String].self, forKey: .options) ?? []
}
}

Expand Down
29 changes: 18 additions & 11 deletions Sources/Services/ContainerAPIService/Client/Utility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,17 +224,11 @@ public struct Utility {
}
}

if management.dnsDisabled {
config.dns = nil
} else {
let domain = management.dns.domain ?? containerSystemConfig.dns.domain
config.dns = .init(
nameservers: management.dns.nameservers,
domain: domain,
searchDomains: management.dns.searchDomains,
options: management.dns.options
)
}
config.dns = dnsConfiguration(
dns: management.dns,
dnsDisabled: management.dnsDisabled,
defaults: containerSystemConfig.dns
)

config.rosetta = management.rosetta || (Platform.current.architecture == "arm64" && requestedPlatform.architecture == "amd64")

Expand Down Expand Up @@ -272,6 +266,19 @@ public struct Utility {
return (config, kernel, management.initImage)
}

static func dnsConfiguration(dns: Flags.DNS, dnsDisabled: Bool, defaults: DNSConfig) -> ContainerConfiguration.DNSConfiguration? {
guard !dnsDisabled else {
return nil
}

return .init(
nameservers: dns.nameservers.isEmpty ? defaults.nameservers : dns.nameservers,
domain: dns.domain ?? defaults.domain,
searchDomains: dns.searchDomains.isEmpty ? defaults.searchDomains : dns.searchDomains,
options: dns.options.isEmpty ? defaults.options : dns.options
)
}

static func getAttachmentConfigurations(
containerId: String,
builtinNetworkId: String?,
Expand Down
48 changes: 48 additions & 0 deletions Tests/ContainerAPIClientTests/UtilityTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.
//===----------------------------------------------------------------------===//

import ContainerPersistence
import ContainerResource
import ContainerizationError
import Foundation
Expand All @@ -31,6 +32,53 @@ struct UtilityTests {
#expect(result["key2"] == "value2")
}

@Test("DNS config uses system defaults when CLI flags are absent")
func testDNSConfigurationUsesSystemDefaults() throws {
let defaults = DNSConfig(
nameservers: ["9.9.9.9", "149.112.112.112"],
domain: "containers.example",
searchDomains: ["svc.example"],
options: ["ndots:1"]
)

let dns = try #require(Utility.dnsConfiguration(dns: try Flags.DNS.parse([]), dnsDisabled: false, defaults: defaults))

#expect(dns.nameservers == ["9.9.9.9", "149.112.112.112"])
#expect(dns.domain == "containers.example")
#expect(dns.searchDomains == ["svc.example"])
#expect(dns.options == ["ndots:1"])
}

@Test("DNS CLI flags override system defaults")
func testDNSConfigurationCLIOverridesSystemDefaults() throws {
let defaults = DNSConfig(
nameservers: ["9.9.9.9"],
domain: "containers.example",
searchDomains: ["svc.example"],
options: ["ndots:1"]
)
let flags = Flags.DNS(
domain: "override.example",
nameservers: ["8.8.8.8"],
options: ["debug"],
searchDomains: ["override.search"]
)

let dns = try #require(Utility.dnsConfiguration(dns: flags, dnsDisabled: false, defaults: defaults))

#expect(dns.nameservers == ["8.8.8.8"])
#expect(dns.domain == "override.example")
#expect(dns.searchDomains == ["override.search"])
#expect(dns.options == ["debug"])
}

@Test("DNS config is disabled by no-dns")
func testDNSConfigurationDisabled() throws {
let dns = Utility.dnsConfiguration(dns: try Flags.DNS.parse([]), dnsDisabled: true, defaults: .init(nameservers: ["9.9.9.9"]))

#expect(dns == nil)
}

@Test("Parse standalone keys")
func testStandaloneKeys() {
let result = Utility.parseKeyValuePairs(["standalone"])
Expand Down
10 changes: 10 additions & 0 deletions Tests/ContainerPersistenceTests/ConfigurationLoaderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//

import ContainerTestSupport
import ContainerResource
import ContainerizationExtras
import Foundation
import SystemPackage
Expand Down Expand Up @@ -90,7 +91,10 @@ struct ConfigurationLoaderTests {
#expect(config.build.memory == BuildConfig.defaultMemory)
#expect(config.container.cpus == 4)
#expect(config.container.memory == ContainerConfig.defaultMemory)
#expect(config.dns.nameservers == ContainerConfiguration.DNSConfiguration.defaultNameservers)
#expect(config.dns.domain == nil)
#expect(config.dns.searchDomains == [])
#expect(config.dns.options == [])
#expect(!config.build.image.isEmpty)
#expect(!config.vminit.image.isEmpty)
#expect(!config.kernel.binaryPath.isEmpty)
Expand All @@ -115,7 +119,10 @@ struct ConfigurationLoaderTests {
memory = "8g"

[dns]
nameservers = ["8.8.8.8", "8.8.4.4"]
domain = "custom"
searchDomains = ["svc.local", "corp.local"]
options = ["ndots:1"]

[kernel]
binaryPath = "custom/path"
Expand All @@ -142,7 +149,10 @@ struct ConfigurationLoaderTests {
#expect(config.container.cpus == 16)
let expectedContainerMemory = try MemorySize("8g")
#expect(config.container.memory == expectedContainerMemory)
#expect(config.dns.nameservers == ["8.8.8.8", "8.8.4.4"])
#expect(config.dns.domain == "custom")
#expect(config.dns.searchDomains == ["svc.local", "corp.local"])
#expect(config.dns.options == ["ndots:1"])
#expect(config.build.image == "custom-builder:latest")
#expect(config.vminit.image == "custom-init:latest")
#expect(config.kernel.binaryPath == "custom/path")
Expand Down
11 changes: 7 additions & 4 deletions docs/container-system-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Source of truth: [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](..
```toml
[build] # builder VM resources and image
[container] # default per-container resources
[dns] # default DNS domain for DNS resolution on host
[dns] # default DNS settings for containers and host resolution
[kernel] # guest kernel binary path and download URL
[network] # default subnets for new networks
[registry] # default registry domain
Expand Down Expand Up @@ -46,9 +46,12 @@ Defaults applied when `container run` / `container create` is invoked without `-

## `[dns]`

| Key | Type | Default | Description |
|----------|-----------|---------|----------------------------------------------------------------------------|
| `domain` | `String?` | unset | Local DNS domain appended to container hostnames (e.g. `"test"` makes `my-web-server` resolvable as `my-web-server.test`). When unset, no domain is appended. |
| Key | Type | Default | Description |
|-----------------|------------|---------------|----------------------------------------------------------------------------|
| `nameservers` | `[String]` | `["1.1.1.1"]` | DNS nameserver IP addresses configured in containers when `--dns` is not supplied. |
| `domain` | `String?` | unset | Local DNS domain appended to container hostnames (e.g. `"test"` makes `my-web-server` resolvable as `my-web-server.test`). When unset, no domain is appended. |
| `searchDomains` | `[String]` | `[]` | DNS search domains configured in containers when `--dns-search` is not supplied. |
| `options` | `[String]` | `[]` | DNS resolver options configured in containers when `--dns-option` is not supplied. |

## `[kernel]`

Expand Down
3 changes: 3 additions & 0 deletions docs/how-to.md
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,10 @@ cpus = 4
memory = "1gb"

[dns]
nameservers = ["1.1.1.1"]
domain = "test"
searchDomains = []
options = []

[kernel]
binaryPath = "opt/kata/share/kata-containers/vmlinux-6.18.5-177"
Expand Down
3 changes: 3 additions & 0 deletions docs/tutorials/container-system-config-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ cpus = 8
memory = "4g"

[dns]
nameservers = ["9.9.9.9", "149.112.112.112"]
domain = "test"
searchDomains = ["corp.example"]
options = ["ndots:1"]
```

Each top-level table maps directly to a section of [ContainerSystemConfig](../container-system-config.md).
Expand Down