You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
5.0 KiB

#!/usr/bin/env python3
import argparse
import glob
import logging
import os
import shutil
import subprocess
import sys
scriptdir = os.path.dirname(os.path.realpath(__file__))
def resolvepath(path):
return os.path.realpath(os.path.normpath(os.path.expanduser(path)))
def buildpacker(packerfile, outdir, force=False, whatif=False):
packerfile = resolvepath(packerfile)
if not os.path.isfile(packerfile):
raise Exception("No such packerfile: '{}'".format(packerfile))
outdir = resolvepath(outdir)
if not os.path.isdir(outdir):
os.makedirs(outdir, exist_ok=True)
logdir = os.path.join(outdir, "packer_log")
cachedir = os.path.join(outdir, "packer_cache")
packerdir = os.path.dirname(packerfile)
oldoutputs = glob.glob("{}/output-*".format(packerdir))
if len(oldoutputs) > 0:
for oldoutput in oldoutputs:
if force:
shutil.rmtree(oldoutput)
else:
raise Exception("A packer output directory exists at '{}'".format(oldoutput))
cli = 'packer.exe build -var output_directory="{}" {}'.format(outdir, packerfile)
# NOTE: Packer gives a very weird error if you do not COPY the entire environment
# When I was setting env to be just a dictionary with the PACKER_* variables I needed,
# I was seeing errors like this:
# Failed to initialize build 'virtualbox-iso': error initializing builder 'virtualbox-iso': Unrecognized remote plugin message: Error starting plugin server: Couldn't bind plugin TCP listener
# Once I copied the entire environment, it was fine. I have no idea why.
env = os.environ
env['PACKER_CACHE_DIR'] = cachedir
env['PACKER_DEBUG'] = '1'
env['PACKER_LOG'] = '1'
env['PACKER_LOG_PATH'] = logdir
env['CHECKPOINT_DISABLE'] = '1'
logging.info("Running command:\n {}\n from directory: {}\n with environment:\n {}".format(cli, packerdir, env))
if whatif:
return
subprocess.check_call(cli, env=env, cwd=packerdir)
boxes = glob.glob("{}/*.box".format(outdir))
if len(boxes) > 1:
raise Exception("Somehow you came up with more than one box here: '{}'".format(boxes))
elif len(boxes) < 1:
raise Exception("Apparently the packer process failed, no boxes were created")
logging.info("Packed .box file: '{}'".format(boxes[0]))
return boxes[0]
def addvagrantbox(vagrantboxname, packedboxpath, force, whatif):
"""Add the box to vagrant directly
Note that doing it this way means that Vagrant doesn't know your box's version, and cannot upgrade it
"""
packedboxdir = os.path.dirname(packedboxpath)
packedboxname = os.path.basename(packedboxpath)
forcearg = '--force' if force else ''
cli = "vagrant.exe box add {} --name {} {}".format(forcearg, vagrantboxname, packedboxname)
print("Running vagrant:\n {}".format(cli))
if whatif:
return
else:
subprocess.check_call(cli, cwd=packedboxdir)
def main(*args, **kwargs):
parser = argparse.ArgumentParser(
description="Windows Trial Lab: build trial Vagrant boxes.",
epilog="NOTE: requires packer 0.8.6 or higher and vagrant 1.8 or higher. EXAMPLE: buildlab --baseconfigname windows_10_x86; cd vagrant/FreyjaA; vagrant up")
parser.add_argument(
"baseconfigname", action='store',
help="The name of one of the subdirs of the 'packer' directory, like windows_81_x86")
parser.add_argument(
"--base-out-dir", "-o", action='store', default="{}/output".format(scriptdir),
help="The base output directory, where Packer does its work and saves its final output. (NOT the VM directory, which is a setting in VirtualBox.)")
parser.add_argument(
"--action", "-a", action='store', default="packervagrant",
choices=['packer', 'vagrant', 'packervagrant'],
help="The action to perform. By default, build with packer and add to vagrant.")
parser.add_argument(
"--whatif", "-w", action='store_true',
help="Do not perform any actions, only say what would have been done")
parser.add_argument(
"--force", "-f", action='store_true',
help="Force continue, even if old output directories already exist")
parser.add_argument(
"--verbose", "-v", action='store_true',
help="Print verbose messages")
parsed = parser.parse_args()
if parsed.verbose:
logging.basicConfig(level=logging.DEBUG)
fullconfigname = "wintriallab-{}".format(parsed.baseconfigname)
packeroutdir = os.path.join(resolvepath(parsed.base_out_dir), fullconfigname)
packerfile = os.path.join(scriptdir, 'packer', parsed.baseconfigname, '{}_packerfile.json'.format(parsed.baseconfigname))
if 'packer' in parsed.action:
buildpacker(packerfile, packeroutdir, force=parsed.force, whatif=parsed.whatif)
packedboxpath = glob.glob("{}/{}_*_virtualbox.box".format(packeroutdir, parsed.baseconfigname))[0]
if 'vagrant' in parsed.action:
addvagrantbox(fullconfigname, packedboxpath, force=parsed.force, whatif=parsed.whatif)
if __name__ == '__main__':
sys.exit(main(*sys.argv))