fix(macos-container): start builder with dns
This commit is contained in:
@@ -45,6 +45,7 @@ def build_image(ref: str, context: str, *, dockerfile: str = "") -> None:
|
||||
f"building image {ref} from {context} with Apple Container "
|
||||
"(layer cache keeps repeat builds fast)"
|
||||
)
|
||||
_ensure_builder_dns()
|
||||
args = [_CONTAINER, "build", "-t", ref, "--dns", dns_server()]
|
||||
if dockerfile:
|
||||
args.extend(["-f", dockerfile])
|
||||
@@ -52,6 +53,54 @@ def build_image(ref: str, context: str, *, dockerfile: str = "") -> None:
|
||||
subprocess.run(args, check=True)
|
||||
|
||||
|
||||
def _ensure_builder_dns() -> None:
|
||||
dns = dns_server()
|
||||
if _builder_has_dns(dns):
|
||||
return
|
||||
subprocess.run(
|
||||
[_CONTAINER, "builder", "stop"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
subprocess.run(
|
||||
[_CONTAINER, "builder", "start", "--dns", dns],
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
def _builder_has_dns(dns: str) -> bool:
|
||||
result = subprocess.run(
|
||||
[_CONTAINER, "builder", "status", "--format", "json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return False
|
||||
try:
|
||||
data = json.loads(result.stdout or "[]")
|
||||
except json.JSONDecodeError:
|
||||
return False
|
||||
entries = data if isinstance(data, list) else [data]
|
||||
for entry in entries:
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
status = entry.get("status")
|
||||
if isinstance(status, dict) and status.get("state") != "running":
|
||||
continue
|
||||
config = entry.get("configuration")
|
||||
config_dns = config.get("dns") if isinstance(config, dict) else None
|
||||
nameservers = (
|
||||
config_dns.get("nameservers")
|
||||
if isinstance(config_dns, dict)
|
||||
else None
|
||||
)
|
||||
if isinstance(nameservers, list) and dns in nameservers:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def image_exists(ref: str) -> bool:
|
||||
return _silent_run([_CONTAINER, "image", "inspect", ref]) == 0
|
||||
|
||||
|
||||
@@ -170,7 +170,10 @@ delivery design lands.
|
||||
- Integration tests run on macOS hosts with Apple Container installed
|
||||
and verify that egress cannot bypass the sidecar. They also preflight
|
||||
Apple Container BuildKit DNS because image builds must resolve
|
||||
package mirrors before a launch smoke can be meaningful.
|
||||
package mirrors before a launch smoke can be meaningful. The backend
|
||||
starts/restarts the Apple Container builder with the configured DNS
|
||||
server before image builds so BuildKit `RUN` steps inherit a working
|
||||
resolver.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -29,7 +29,16 @@ class TestMacosContainerAvailability(unittest.TestCase):
|
||||
|
||||
class TestMacosContainerCommands(unittest.TestCase):
|
||||
def test_build_image(self):
|
||||
with patch.object(util.subprocess, "run") as run, \
|
||||
status = util.subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=0,
|
||||
stdout=(
|
||||
'[{"status":{"state":"running"},'
|
||||
'"configuration":{"dns":{"nameservers":["9.9.9.9"]}}}]'
|
||||
),
|
||||
stderr="",
|
||||
)
|
||||
with patch.object(util.subprocess, "run", return_value=status) as run, \
|
||||
patch.object(util.os, "environ", {
|
||||
"BOT_BOTTLE_MACOS_CONTAINER_DNS": "9.9.9.9",
|
||||
}):
|
||||
@@ -39,9 +48,38 @@ class TestMacosContainerCommands(unittest.TestCase):
|
||||
"container", "build", "-t", "bot-bottle-agent:latest",
|
||||
"--dns", "9.9.9.9", "-f", "/repo/Dockerfile", "/repo",
|
||||
],
|
||||
run.call_args.args[0],
|
||||
run.call_args_list[-1].args[0],
|
||||
)
|
||||
self.assertTrue(run.call_args_list[-1].kwargs["check"])
|
||||
|
||||
def test_build_image_restarts_builder_when_dns_mismatches(self):
|
||||
status = util.subprocess.CompletedProcess(
|
||||
args=[],
|
||||
returncode=0,
|
||||
stdout=(
|
||||
'[{"status":{"state":"running"},'
|
||||
'"configuration":{"dns":{"nameservers":[]}}}]'
|
||||
),
|
||||
stderr="",
|
||||
)
|
||||
with patch.object(util.subprocess, "run", return_value=status) as run, \
|
||||
patch.object(util.os, "environ", {
|
||||
"BOT_BOTTLE_MACOS_CONTAINER_DNS": "9.9.9.9",
|
||||
}):
|
||||
util.build_image("bot-bottle-agent:latest", "/repo")
|
||||
calls = [c.args[0] for c in run.call_args_list]
|
||||
self.assertIn(["container", "builder", "stop"], calls)
|
||||
self.assertIn(
|
||||
["container", "builder", "start", "--dns", "9.9.9.9"],
|
||||
calls,
|
||||
)
|
||||
self.assertEqual(
|
||||
[
|
||||
"container", "build", "-t", "bot-bottle-agent:latest",
|
||||
"--dns", "9.9.9.9", "/repo",
|
||||
],
|
||||
calls[-1],
|
||||
)
|
||||
self.assertTrue(run.call_args.kwargs["check"])
|
||||
|
||||
def test_container_exists_parses_quiet_list(self):
|
||||
completed = util.subprocess.CompletedProcess(
|
||||
|
||||
Reference in New Issue
Block a user