Initial attempt at a koji task based on the Indirection plugin

This creates a new koji task type and CLI option called
image-build-indirection

This task builds an output image using the Image Factory "Indirection"
plugin

It takes as its input two already built images, either as explicit
task numbers of NVR and arch.  It also requires a modified TDL
file as described in the Image Factory source.

The two input images are referred to as the base_image, which contains
content to be turned into another output image, and the utility_image,
which is a full system that will be booted to do the transformation.

The TDL, or "indirection_template" describes the tasks to be performed
inside of the running base image to generate the output.

This feature has the potential to build all of the following types of
images:

Disk Image Builder disk images, built with DIB elements using DIB itself
Live ISO images created using Live Media Creator
Docker layered images built using an arbitrary Docker version and a
Docker base image already built inside of koji
This commit is contained in:
Ian McLeod 2014-09-17 10:21:57 -05:00 committed by Mike McLean
parent 3461af8475
commit 987fb03cee
3 changed files with 502 additions and 0 deletions

146
cli/koji
View file

@ -5146,6 +5146,152 @@ def handle_spin_appliance(options, session, args):
assert False
_build_image(options, task_options, session, args, 'appliance')
def handle_image_build_indirection(options, session, args):
"""Create a disk image using other disk images via the Indirection plugin"""
usage = _("usage: %prog image-build-indirection [base_image] " +
"[utility_image] [indirection_build_template]")
usage += _("\n %prog image-build --config FILE")
usage += _("\n\n(Specify the --help global option for a list of other " +
"help options)")
parser = OptionParser(usage=usage)
parser.add_option("--config",
help=_("Use a configuration file to define image-build options " +
"instead of command line options (they will be ignored)."))
parser.add_option("--background", action="store_true",
help=_("Run the image creation task at a lower priority"))
parser.add_option("--name",
help=_("Name of the output image"))
parser.add_option("--version",
help=_("Version of the output image"))
parser.add_option("--release",
help=_("Release of the output image"))
parser.add_option("--arch",
help=_("Architecture of the output image and input images"))
parser.add_option("--target",
help=_("Build target to use for the indirection build"))
parser.add_option("--skip-tag", action="store_true",
help=_("Do not tag the resulting build"))
parser.add_option("--base-image-task",
help=_("ID of the createImage task of the base image to be used"))
parser.add_option("--base-image-build",
help=_("NVR or build ID of the base image to be used"))
parser.add_option("--utility-image-task",
help=_("ID of the createImage task of the utility image to be used"))
parser.add_option("--utility-image-build",
help=_("NVR or build ID of the utility image to be used"))
parser.add_option("--indirection-template",
help=_("Name of the local file, or SCM file containing the template used to drive the indirection plugin"))
parser.add_option("--indirection-template-url",
help=_("SCM URL containing the template used to drive the indirection plugin"))
parser.add_option("--results-loc",
help=_("Relative path inside the working space image where the results should be extracted from"))
parser.add_option("--scratch", action="store_true",
help=_("Create a scratch image"))
parser.add_option("--wait", action="store_true",
help=_("Wait on the image creation, even if running in the background"))
parser.add_option("--noprogress", action="store_true",
help=_("Do not display progress of the upload"))
(task_options, args) = parser.parse_args(args)
_build_image_indirection(options, task_options, session, args)
def _build_image_indirection(options, task_opts, session, args):
"""
A private helper function for builds using the indirection plugin of ImageFactory
"""
# Do some sanity checks before even attempting to create the session
if not (bool(task_opts.utility_image_task) !=
bool(task_opts.utility_image_build)):
raise koji.GenericError, _("You must specify either a utility-image task or build ID/NVR")
if not (bool(task_opts.base_image_task) !=
bool(task_opts.base_image_build)):
raise koji.GenericError, _("You must specify either a base-image task or build ID/NVR")
required_opts = [ 'name', 'version', 'arch', 'target', 'indirection_template', 'results_loc' ]
optional_opts = [ 'indirection_template_url', 'scratch', 'utility_image_task', 'utility_image_build',
'base_image_task', 'base_image_build', 'release', 'skip_tag' ]
missing = [ ]
for opt in required_opts:
if not getattr(task_opts, opt, None):
missing.append(opt)
if len(missing) > 0:
print "Missing the following required options:" ,
for opt in missing:
print "--" + opt.replace('_','-') ,
print
raise koji.GenericError, _("Missing required options specified above")
activate_session(session)
# Set the task's priority. Users can only lower it with --background.
priority = None
if task_opts.background:
# relative to koji.PRIO_DEFAULT; higher means a "lower" priority.
priority = 5
if _running_in_bg() or task_opts.noprogress:
callback = None
else:
callback = _progress_callback
# We do some early sanity checking of the given target.
# Kojid gets these values again later on, but we check now as a convenience
# for the user.
tmp_target = session.getBuildTarget(task_opts.target)
if not tmp_target:
raise koji.GenericError, _("Unknown build target: %s" % target)
dest_tag = session.getTag(tmp_target['dest_tag'])
if not dest_tag:
raise koji.GenericError, _("Unknown destination tag: %s" %
tmp_target['dest_tag_name'])
# Set the architecture
task_opts.arch = koji.canonArch(task_opts.arch)
# Upload the indirection template file to the staging area.
# If it's a URL, it's kojid's job to go get it when it does the checkout.
if not task_opts.indirection_template_url:
if not task_opts.scratch:
# only scratch builds can omit indirection_template_url
raise koji.GenericError, _("Non-scratch builds must provide a URL for the indirection template")
templatefile = task_opts.indirection_template
serverdir = _unique_path('cli-image-indirection')
session.uploadWrapper(templatefile, serverdir, callback=callback)
task_opts.indirection_template = os.path.join('work', serverdir,
os.path.basename(templatefile))
print
hub_opts = { }
# Just pass everything in as opts. No posiitonal arguments at all. Why not?
for opt in required_opts + optional_opts:
val = getattr(task_opts, opt, None)
# We pass these through even if they are None
# The builder code can then check if they are set without using getattr
hub_opts[opt] = val
# finally, create the task.
task_id = session.buildImageIndirection(opts=hub_opts,
priority=priority)
if not options.quiet:
print "Created task:", task_id
print "Task info: %s/taskinfo?taskID=%s" % (options.weburl, task_id)
#if task_opts.wait or (task_opts.wait is None and not _running_in_bg()):
# session.logout()
# return watch_tasks(session, [task_id], quiet=options.quiet)
#else:
# return
def handle_image_build(options, session, args):
"""Create a disk image given an install tree"""
formats = ('vmdk', 'qcow', 'qcow2', 'vdi', 'rhevm-ova', 'vsphere-ova',