feat(integration-vm): golden image fetch + SHA512 verification
This commit is contained in:
parent
a8dc3c787a
commit
af76763c16
1 changed files with 39 additions and 3 deletions
|
|
@ -44,9 +44,6 @@ DEFAULT_VCPUS = 2
|
|||
MIN_FREE_MIB = 4096
|
||||
VALID_TIERS = ("internal", "le-staging", "le-prod-wildcard")
|
||||
|
||||
DISPATCH = {} # temporary; real dispatch added in a later task
|
||||
|
||||
|
||||
def vm_name(host, suffix=None):
|
||||
suffix = suffix or uuid.uuid4().hex[:8]
|
||||
return f"{NAME_PREFIX}{host}-{suffix}"
|
||||
|
|
@ -108,6 +105,45 @@ def render_run_hosts(name, ip, ansible_user, groups):
|
|||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def sh(cmd, check=True, capture=False, **kw):
|
||||
"""Run a command (list form). Logs the command to stderr."""
|
||||
print("+ " + " ".join(str(c) for c in cmd), file=sys.stderr)
|
||||
return subprocess.run(cmd, check=check,
|
||||
capture_output=capture, text=True, **kw)
|
||||
|
||||
|
||||
def _expected_sha(sha_text, filename):
|
||||
for line in sha_text.splitlines():
|
||||
parts = line.split()
|
||||
if len(parts) == 2 and parts[1].lstrip("*") == filename:
|
||||
return parts[0]
|
||||
return None
|
||||
|
||||
|
||||
def ensure_image():
|
||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
img = CACHE_DIR / IMAGE_NAME
|
||||
if img.exists():
|
||||
return img
|
||||
print(f"Downloading {IMAGE_URL} ...", file=sys.stderr)
|
||||
tmp = img.with_suffix(".part")
|
||||
urllib.request.urlretrieve(IMAGE_URL, tmp)
|
||||
sha_text = urllib.request.urlopen(SHA_URL).read().decode()
|
||||
want = _expected_sha(sha_text, IMAGE_NAME)
|
||||
if not want:
|
||||
tmp.unlink(missing_ok=True)
|
||||
raise SystemExit(f"checksum for {IMAGE_NAME} not found at {SHA_URL}")
|
||||
h = hashlib.sha512()
|
||||
with open(tmp, "rb") as fh:
|
||||
for chunk in iter(lambda: fh.read(1 << 20), b""):
|
||||
h.update(chunk)
|
||||
if h.hexdigest() != want:
|
||||
tmp.unlink(missing_ok=True)
|
||||
raise SystemExit("golden image SHA512 mismatch — refusing to use it")
|
||||
tmp.rename(img)
|
||||
return img
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="integration-vm", description=__doc__)
|
||||
sub = p.add_subparsers(dest="cmd", required=True)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue