diff --git a/firecracker-dev.tf b/firecracker-dev.tf index 770e281..6ef988a 100644 --- a/firecracker-dev.tf +++ b/firecracker-dev.tf @@ -340,11 +340,10 @@ resource "aws_ssm_association" "firecracker_dev_secondary_ipv4" { } parameters = { - commands = <<-EOT - python3 - '${one(setsubtract(aws_network_interface.firecracker_dev[0].private_ips, [aws_network_interface.firecracker_dev[0].private_ip]))}' <<'PYSECONDARY' - ${indent(6, chomp(file("${path.module}/scripts/fcvm-secondary-ipv4.py")))} - PYSECONDARY - EOT + commands = templatefile("${path.module}/scripts/fcvm-secondary-ipv4-command.tftpl", { + address = one(setsubtract(aws_network_interface.firecracker_dev[0].private_ips, [aws_network_interface.firecracker_dev[0].private_ip])) + script = chomp(file("${path.module}/scripts/fcvm-secondary-ipv4.py")) + }) executionTimeout = "120" } } diff --git a/scripts/fcvm-secondary-ipv4-command.tftpl b/scripts/fcvm-secondary-ipv4-command.tftpl new file mode 100644 index 0000000..efcdfd7 --- /dev/null +++ b/scripts/fcvm-secondary-ipv4-command.tftpl @@ -0,0 +1,3 @@ +python3 - '${address}' <<'PYSECONDARY' +${script} +PYSECONDARY diff --git a/scripts/test-fcvm-secondary-ipv4.py b/scripts/test-fcvm-secondary-ipv4.py index c82c521..d39e1f7 100644 --- a/scripts/test-fcvm-secondary-ipv4.py +++ b/scripts/test-fcvm-secondary-ipv4.py @@ -2,6 +2,8 @@ """The added address survives boot and never restarts the live primary interface.""" import importlib.util import json +import os +import sys from pathlib import Path import subprocess import tempfile @@ -60,6 +62,22 @@ def run(args, **kwargs): module.configure('10.0.1.42; reboot', config, run) self.assertFalse(config.exists()) + def test_managed_shell_command_passes_unindented_python_on_stdin(self): + template = ROOT / 'scripts/fcvm-secondary-ipv4-command.tftpl' + command = template.read_text().replace('${address}', '10.0.1.42').replace( + '${script}', (ROOT / 'scripts/fcvm-secondary-ipv4.py').read_text().rstrip()) + with tempfile.TemporaryDirectory() as directory: + interpreter = Path(directory) / 'python3' + interpreter.write_text(f'#!{sys.executable}\nimport sys\n' + 'assert sys.argv[1:] == ["-", "10.0.1.42"]\n' + 'compile(sys.stdin.read(), "", "exec")\n') + interpreter.chmod(0o700) + subprocess.run(['/bin/sh', '-ec', command], check=True, capture_output=True, + text=True, env={**os.environ, 'PATH': directory}) + association = (ROOT / 'firecracker-dev.tf').read_text().split( + 'resource "aws_ssm_association" "firecracker_dev_secondary_ipv4"', 1)[1] + self.assertIn('templatefile("${path.module}/scripts/fcvm-secondary-ipv4-command.tftpl"', association) + def test_managed_association_runs_the_script_on_the_arm_host(self): tf = (ROOT / 'firecracker-dev.tf').read_text() self.assertIn('resource "aws_ssm_association" "firecracker_dev_secondary_ipv4"', tf)