171 lines
6.0 KiB
Python
171 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import glob
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
scriptdir = os.path.dirname(os.path.realpath(__file__))
|
|
debug = False
|
|
verbose = False
|
|
|
|
|
|
# TODO: use logging module?
|
|
|
|
|
|
def strace():
|
|
import pdb
|
|
pdb.set_trace()
|
|
|
|
|
|
def debugprint(message):
|
|
global debug
|
|
if debug:
|
|
print("DEBUG: " + message)
|
|
|
|
|
|
def verboseprint(message):
|
|
global verbose
|
|
if verbose:
|
|
print("VERBOSE: " + message)
|
|
|
|
|
|
def resolvepath(path):
|
|
return os.path.realpath(os.path.normpath(os.path.expanduser(path)))
|
|
|
|
|
|
def which(commandname):
|
|
def is_exe(fpath):
|
|
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
|
for path in os.environ["PATH"].split(os.pathsep):
|
|
path = path.strip('"')
|
|
exe_file = os.path.join(path, commandname)
|
|
if is_exe(exe_file):
|
|
return exe_file
|
|
print("Exe path is {}".format(exe_file))
|
|
raise Exception("No such command '{}' in %PATH%".format(commandname))
|
|
|
|
|
|
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))
|
|
|
|
caryatidpath = resolvepath("~/Documents/caryatid")
|
|
caryatiddestination = resolvepath("D:\\Micah\\Vagrant")
|
|
cli = 'packer.exe build -var output_directory="{}" -var caryatidpath="{}" -var caryatid_destination="{}" {}'.format(outdir, caryatidpath, caryatiddestination, 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'
|
|
|
|
verboseprint("Running command:\n {}\n from directory: {}\n with environment:\n {}".format(cli, packerdir, env))
|
|
if whatif:
|
|
return
|
|
else:
|
|
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")
|
|
|
|
verboseprint("Packed .box file: '{}'".format(boxes[0]))
|
|
|
|
|
|
def addvagrantbox(vagrantboxname, packedboxpath, force, whatif):
|
|
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)
|
|
|
|
verboseprint("Running command:\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 this directory, like windows_81_x86")
|
|
|
|
parser.add_argument(
|
|
"--base-out-dir", "-o", action='store', default="~/Documents/WinTrialLab",
|
|
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="all", choices=['all', 'packer', 'vagrant'],
|
|
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(
|
|
"--debug", "-d", action='store_true',
|
|
help="Print debug and verbose messages")
|
|
parser.add_argument(
|
|
"--verbose", "-v", action='store_true',
|
|
help="Print verbose messages")
|
|
|
|
parsed = parser.parse_args()
|
|
if parsed.debug:
|
|
global debug
|
|
debug = True
|
|
if parsed.debug or parsed.verbose:
|
|
global verbose
|
|
verbose = True
|
|
|
|
if parsed.action == "all":
|
|
actions = ['packer', 'vagrant']
|
|
else:
|
|
actions = [parsed.action]
|
|
|
|
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))
|
|
packedboxpath = os.path.join(packeroutdir, '{}.virtualbox.box'.format(parsed.baseconfigname))
|
|
|
|
if 'packer' in actions:
|
|
buildpacker(packerfile, packeroutdir, force=parsed.force, whatif=parsed.whatif)
|
|
if 'vagrant' in actions:
|
|
addvagrantbox(fullconfigname, packedboxpath, force=parsed.force, whatif=parsed.whatif)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(*sys.argv))
|