[PATCH] add mechanism for general purpose parameter passing to Image Factory
Ian McLeod
imcleod at redhat.com
Wed Oct 28 03:32:33 UTC 2015
Apologies. This appears to be mangled. Resending with some guidance
from dgilmore.
On 10/27/2015 05:21 PM, Ian McLeod wrote:
> We originally added semi-generic parameter passing for OVA support and
> then overloaded it for Vagrant support, before breaking that back out
> as specific image types.
>
> This change adds a fairly generic mechanism for parameter passthrough
> to plugins and the base builder that does not require patching the
> builder and CLI each time a new class of parameter is added to Factory.
>
> The immediate reason for doing this is to expose the Docker plugin's
> ability to set custom labels, environments and commands, but it is
> likely to be useful for other things in the future.
> ---
> builder/kojid | 39 ++++++++++++++++++++++++++++++++++-----
> cli/koji | 15 ++++++++++++++-
> 2 files changed, 48 insertions(+), 6 deletions(-)
>
> diff --git a/builder/kojid b/builder/kojid
> index 4ea93f2..ad427cd 100755
> --- a/builder/kojid
> +++ b/builder/kojid
> @@ -3178,6 +3178,25 @@ class BaseImageTask(OzImageTask):
> raise koji.ApplianceError('Image status is %s: %s' %
> (status, details))
> + def _mergeFactoryParams(self, img_opts, fixed_params):
> + """
> + Merge any KV pairs passed in via --factory-parameter CLI options
> + into an existing dictionary that will eventually be passed to
> + factory build commands. This allows a fairly generic mechanism
> + for parameter passthrough to plugins and the base builder that does
> + not require patching the builder and CLI each time.
> +
> + @args:
> + img_opts - an existing dict with any pre-existing parameters
> + fixed_params - list of parameters that must not be overriden
> + @returns:
> + nothing - dict is modified in place
> + """
> + if self.opts.get('factory_parameter'):
> + for kvp in self.opts.get('factory_parameter'):
> + if kvp[0] not in fixed_params:
> + img_opts[kvp[0]] = kvp[1]
> +
> def _buildBase(self, template, params, wait=True):
> """
> Build a base image using ImageFactory. This is a "raw" image.
> @@ -3194,7 +3213,10 @@ class BaseImageTask(OzImageTask):
> # may need to still upload ozlog and remove the log handler
> self.logger.info('dispatching a baseimg builder')
> self.logger.debug('templates: %s' % template)
> - self.logger.debug('params: %s' % params)
> + self.logger.debug('pre-merge params: %s' % params)
> + # We enforce various things related to the ks file - do not allow override
> + self._mergeFactoryParams(params, [ 'install_script' ])
> + self.logger.debug('post-merge params: %s' % params)
> base = self.bd.builder_for_base_image(template, parameters=params)
> if wait:
> base.base_thread.join()
> @@ -3245,19 +3267,22 @@ class BaseImageTask(OzImageTask):
> if format == 'vagrant-virtualbox':
> format = 'vsphere-ova'
> img_opts['vsphere_ova_format'] = 'vagrant-virtualbox'
> + fixed_params = [ 'vsphere_ova_format' ]
> if format == 'vagrant-libvirt':
> format = 'rhevm-ova'
> img_opts['rhevm_ova_format'] = 'vagrant-libvirt'
> + fixed_params = [ 'rhevm_ova_format' ]
> if format == 'vagrant-vmware-fusion':
> format = 'vsphere-ova'
> img_opts['vsphere_ova_format'] = 'vagrant-vmware-fusion'
> # The initial disk image transform for VMWare Fusion/Workstation requires a "standard" VMDK
> # not the stream oriented format used for VirtualBox or regular VMWare OVAs
> img_opts['vsphere_vmdk_format'] = 'standard'
> + fixed_params = [ 'vsphere_ova_format', 'vsphere_vmdk_format' ]
> targ = self._do_target_image(self.base_img.base_image.identifier,
> - format.replace('-ova', ''), img_opts=img_opts)
> + format.replace('-ova', ''), img_opts=img_opts, fixed_params=fixed_params)
> targ2 = self._do_target_image(targ.target_image.identifier, 'OVA',
> - img_opts=img_opts)
> + img_opts=img_opts, fixed_params=fixed_params)
> return {'image': targ2.target_image.data}
> def _buildDocker(self, format):
> @@ -3275,7 +3300,7 @@ class BaseImageTask(OzImageTask):
> 'docker', img_opts=img_opts)
> return {'image': targ.target_image.data}
> - def _do_target_image(self, base_id, image_type, img_opts={}):
> + def _do_target_image(self, base_id, image_type, img_opts={}, fixed_params=[]):
> """
> A generic method for building what ImageFactory calls "target images".
> These are images based on a raw disk that was built before using the
> @@ -3287,6 +3312,8 @@ class BaseImageTask(OzImageTask):
> uses this to figure out what plugin to run
> img_opts - a dict of additional options that specific to the target
> type we pass in via image_type
> + fixed_params - a list of parameter keys that should not be overriden
> + by the --factory-parameter CLI
> @returns:
> A Builder() object from ImageFactory that contains information
> about the image building include state and progress.
> @@ -3294,7 +3321,9 @@ class BaseImageTask(OzImageTask):
> # TODO: test the failure case where IF itself throws an exception
> # ungracefully (missing a plugin for example)
> # may need to still upload ozlog and remove the log handler
> - self.logger.debug('img_opts: %s' % img_opts)
> + self.logger.debug('img_opts_pre_merge: %s' % img_opts)
> + self._mergeFactoryParams(img_opts, fixed_params)
> + self.logger.debug('img_opts_post_merge: %s' % img_opts)
> target = self.bd.builder_for_target_image(image_type,
> image_id=base_id, template=None, parameters=img_opts)
> target.target_thread.join()
> diff --git a/cli/koji b/cli/koji
> index 64c5356..cbfa2d0 100755
> --- a/cli/koji
> +++ b/cli/koji
> @@ -5306,6 +5306,11 @@ def handle_image_build(options, session, args):
> parser.add_option("--ova-option", action="append",
> help=_("Override a value in the OVA description XML. Provide a value " +
> "in a name=value format, such as 'ovf_memory_mb=6144'"))
> + parser.add_option("--factory-parameter", nargs=2, action="append",
> + help=_("Pass a parameter to Image Factory. The results are highly specific " +
> + "to the image format being created. This is a two argument parameter " +
> + "that can be specified an arbitrary number of times. For example: "
> + "--factory-parameter docker_cmd '[ \"/bin/echo Hello World\" ]'"))
> parser.add_option("--release", help=_("Forcibly set the release field"))
> parser.add_option("--repo", action="append",
> help=_("Specify a repo that will override the repo used to install " +
> @@ -5355,6 +5360,14 @@ def handle_image_build(options, session, args):
> for k, v in config.items(section):
> task_options.ova_option.append('%s=%s' % (k, v))
> + # as do factory-parameters
> + section = 'factory-parameters'
> + if config.has_section(section):
> + task_options.factory_parameter = [ ]
> + for k, v in config.items(section):
> + # We do this, rather than a dict, to match what argparse spits out
> + task_options.factory_parameter.append( (k, v) )
> +
> else:
> if len(args) < 5:
> parser.error(_("At least five arguments are required: a name, " +
> @@ -5483,7 +5496,7 @@ def _build_image_oz(options, task_opts, session, args):
> hub_opts = {}
> for opt in ('ksurl', 'ksversion', 'kickstart', 'scratch', 'repo',
> 'release', 'skip_tag', 'specfile', 'distro', 'format',
> - 'disk_size', 'ova_option'):
> + 'disk_size', 'ova_option', 'factory_parameter'):
> val = getattr(task_opts, opt, None)
> if val is not None:
> hub_opts[opt] = val
More information about the buildsys
mailing list