mirror of https://github.com/ipxe/ipxe.git
147 lines
5.7 KiB
Python
147 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import textwrap
|
|
import time
|
|
from uuid import uuid4
|
|
|
|
from google.cloud import compute
|
|
|
|
IPXE_LOG_PREFIX = 'ipxe-log-temp-'
|
|
IPXE_LOG_MAGIC = 'iPXE LOG'
|
|
IPXE_LOG_END = '----- END OF iPXE LOG -----'
|
|
|
|
def get_log_disk(instances, project, zone, name):
|
|
"""Get log disk source URL"""
|
|
instance = instances.get(project=project, zone=zone, instance=name)
|
|
disk = next(x for x in instance.disks if x.boot)
|
|
return disk.source
|
|
|
|
def delete_temp_snapshot(snapshots, project, name):
|
|
"""Delete temporary snapshot"""
|
|
assert name.startswith(IPXE_LOG_PREFIX)
|
|
snapshots.delete(project=project, snapshot=name)
|
|
|
|
def delete_temp_snapshots(snapshots, project):
|
|
"""Delete all old temporary snapshots"""
|
|
filter = "name eq %s.+" % IPXE_LOG_PREFIX
|
|
request = compute.ListSnapshotsRequest(project=project, filter=filter)
|
|
for snapshot in snapshots.list(request=request):
|
|
delete_temp_snapshot(snapshots, project, snapshot.name)
|
|
|
|
def create_temp_snapshot(snapshots, project, source):
|
|
"""Create temporary snapshot"""
|
|
name = '%s%s' % (IPXE_LOG_PREFIX, uuid4())
|
|
snapshot = compute.Snapshot(name=name, source_disk=source)
|
|
snapshots.insert(project=project, snapshot_resource=snapshot).result()
|
|
return name
|
|
|
|
def delete_temp_instance(instances, project, zone, name):
|
|
"""Delete log dumper temporary instance"""
|
|
assert name.startswith(IPXE_LOG_PREFIX)
|
|
instances.delete(project=project, zone=zone, instance=name)
|
|
|
|
def delete_temp_instances(instances, project, zone):
|
|
"""Delete all old log dumper temporary instances"""
|
|
filter = "name eq %s.+" % IPXE_LOG_PREFIX
|
|
request = compute.ListInstancesRequest(project=project, zone=zone,
|
|
filter=filter)
|
|
for instance in instances.list(request=request):
|
|
delete_temp_instance(instances, project, zone, instance.name)
|
|
|
|
def create_temp_instance(instances, project, zone, family, image, machine,
|
|
snapshot):
|
|
"""Create log dumper temporary instance"""
|
|
image = "projects/%s/global/images/family/%s" % (family, image)
|
|
machine_type = "zones/%s/machineTypes/%s" % (zone, machine)
|
|
logsource = "global/snapshots/%s" % snapshot
|
|
bootparams = compute.AttachedDiskInitializeParams(source_image=image)
|
|
bootdisk = compute.AttachedDisk(boot=True, auto_delete=True,
|
|
initialize_params=bootparams)
|
|
logparams = compute.AttachedDiskInitializeParams(source_snapshot=logsource)
|
|
logdisk = compute.AttachedDisk(boot=False, auto_delete=True,
|
|
initialize_params=logparams,
|
|
device_name="ipxelog")
|
|
nic = compute.NetworkInterface()
|
|
name = '%s%s' % (IPXE_LOG_PREFIX, uuid4())
|
|
script = textwrap.dedent(f"""
|
|
#!/bin/sh
|
|
tr -d '\\000' < /dev/disk/by-id/google-ipxelog-part3 > /dev/ttyS3
|
|
echo "{IPXE_LOG_END}" > /dev/ttyS3
|
|
""").strip()
|
|
items = compute.Items(key="startup-script", value=script)
|
|
metadata = compute.Metadata(items=[items])
|
|
instance = compute.Instance(name=name, machine_type=machine_type,
|
|
network_interfaces=[nic], metadata=metadata,
|
|
disks=[bootdisk, logdisk])
|
|
instances.insert(project=project, zone=zone,
|
|
instance_resource=instance).result()
|
|
return name
|
|
|
|
def get_log_output(instances, project, zone, name):
|
|
"""Get iPXE log output"""
|
|
request = compute.GetSerialPortOutputInstanceRequest(project=project,
|
|
zone=zone, port=4,
|
|
instance=name)
|
|
while True:
|
|
log = instances.get_serial_port_output(request=request).contents.strip()
|
|
if log.endswith(IPXE_LOG_END):
|
|
if log.startswith(IPXE_LOG_MAGIC):
|
|
return log[len(IPXE_LOG_MAGIC):-len(IPXE_LOG_END)]
|
|
else:
|
|
return log[:-len(IPXE_LOG_END)]
|
|
time.sleep(1)
|
|
|
|
# Parse command-line arguments
|
|
#
|
|
parser = argparse.ArgumentParser(description="Import Google Cloud image")
|
|
parser.add_argument('--project', '-j', default="ipxe-images",
|
|
help="Google Cloud project")
|
|
parser.add_argument('--zone', '-z', required=True,
|
|
help="Google Cloud zone")
|
|
parser.add_argument('--family', '-f', default="debian-cloud",
|
|
help="Helper OS image family")
|
|
parser.add_argument('--image', '-i', default="debian-12",
|
|
help="Helper OS image")
|
|
parser.add_argument('--machine', '-m', default="e2-micro",
|
|
help="Helper machine type")
|
|
parser.add_argument('instance', help="Instance name")
|
|
args = parser.parse_args()
|
|
|
|
# Construct client objects
|
|
#
|
|
instances = compute.InstancesClient()
|
|
snapshots = compute.SnapshotsClient()
|
|
|
|
# Clean up old temporary objects
|
|
#
|
|
delete_temp_instances(instances, project=args.project, zone=args.zone)
|
|
delete_temp_snapshots(snapshots, project=args.project)
|
|
|
|
# Create log disk snapshot
|
|
#
|
|
logdisk = get_log_disk(instances, project=args.project, zone=args.zone,
|
|
name=args.instance)
|
|
logsnap = create_temp_snapshot(snapshots, project=args.project, source=logdisk)
|
|
|
|
# Create log dumper instance
|
|
#
|
|
dumper = create_temp_instance(instances, project=args.project, zone=args.zone,
|
|
family=args.family, image=args.image,
|
|
machine=args.machine, snapshot=logsnap)
|
|
|
|
# Wait for log output
|
|
#
|
|
output = get_log_output(instances, project=args.project, zone=args.zone,
|
|
name=dumper)
|
|
|
|
# Print log output
|
|
#
|
|
print(output)
|
|
|
|
# Clean up
|
|
#
|
|
delete_temp_instance(instances, project=args.project, zone=args.zone,
|
|
name=dumper)
|
|
delete_temp_snapshot(snapshots, project=args.project, name=logsnap)
|