image build: prepare for different generation methods

Isolate the bits creating the command line invocations to
disk-image-create/ramdisk-image-create into a small class;
introduce a new parameter to decide which method to use for generating
the images, with the only value of 'dib', representing the current
diskimage-builder method.

Force the use of dib in TestOvercloudImageBuild, and mock the methods of
DibImageBuilder.

Change-Id: I9287cd9375fbc496f3d2bb570a61cd320a2e451b
This commit is contained in:
Pino Toscano 2015-09-17 18:15:32 +02:00 committed by Dougal Matthews
parent 0ae6ca78d9
commit f6b5d4ea23
2 changed files with 110 additions and 46 deletions

View File

@ -27,10 +27,17 @@ class TestOvercloudImageBuild(TestPluginV1):
def setUp(self):
super(TestOvercloudImageBuild, self).setUp()
def _force_builder(dummy):
builder = overcloud_image.DibImageBuilder()
builder._disk_image_create = mock.Mock()
self.mock_disk_image_create = builder._disk_image_create
builder._ramdisk_image_create = mock.Mock()
self.mock_ramdisk_image_create = builder._ramdisk_image_create
return builder
# Get the command object to test
self.cmd = overcloud_image.BuildOvercloudImage(self.app, None)
self.cmd._disk_image_create = mock.Mock()
self.cmd._ramdisk_image_create = mock.Mock()
self.cmd._create_builder = _force_builder
@mock.patch.object(overcloud_image.BuildOvercloudImage,
'_build_image_fedora_user', autospec=True)
@ -45,8 +52,8 @@ class TestOvercloudImageBuild(TestPluginV1):
return_value=redhat_release, create=True):
self.cmd.take_action(parsed_args)
self.assertEqual(2, self.cmd._ramdisk_image_create.call_count)
self.assertEqual(1, self.cmd._disk_image_create.call_count)
self.assertEqual(2, self.mock_ramdisk_image_create.call_count)
self.assertEqual(1, self.mock_disk_image_create.call_count)
self.assertEqual(1, mock_fedora_user.call_count)
@mock.patch('subprocess.call', autospec=True)
@ -109,7 +116,7 @@ class TestOvercloudImageBuild(TestPluginV1):
with mock.patch('six.moves.builtins.open', mock_open_context):
self.cmd.take_action(parsed_args)
self.cmd._disk_image_create.assert_called_once_with(
self.mock_disk_image_create.assert_called_once_with(
"-a amd64 -o "
"overcloud-full.qcow2 rhel7 overcloud-full overcloud-controller "
"overcloud-compute overcloud-ceph-storage ntp sysctl hosts "
@ -145,7 +152,7 @@ class TestOvercloudImageBuild(TestPluginV1):
with mock.patch('six.moves.builtins.open', mock_open_context):
self.cmd.take_action(parsed_args)
self.cmd._ramdisk_image_create.assert_called_once_with(
self.mock_ramdisk_image_create.assert_called_once_with(
"-a amd64 -o deploy-ramdisk-ironic --ramdisk-element "
"dracut-ramdisk rhel7 deploy-ironic "
"element-manifest network-gateway epel rdo-release "

View File

@ -15,11 +15,13 @@
from __future__ import print_function
import abc
import logging
import os
import re
import requests
import shutil
import six
import stat
import subprocess
import sys
@ -31,6 +33,76 @@ from prettytable import PrettyTable
from tripleoclient import utils as plugin_utils
@six.add_metaclass(abc.ABCMeta)
class ImageBuilder(object):
"""Base representation of an image building method"""
@abc.abstractmethod
def build_ramdisk(self, parsed_args, ramdisk_type):
"""Build a ramdisk"""
pass
@abc.abstractmethod
def build_image(self, parsed_args, node_type):
"""Build a disk image"""
pass
def preprocess_parsed_args(self, parsed_args):
"""Eventually preprocess the parsed arguments"""
pass
class DibImageBuilder(ImageBuilder):
"""Build images using diskimage-builder"""
def _disk_image_create(self, args):
subprocess.call('disk-image-create {0}'.format(args), shell=True)
def _ramdisk_image_create(self, args):
subprocess.call('ramdisk-image-create {0}'.format(args), shell=True)
def build_ramdisk(self, parsed_args, ramdisk_type):
image_name = vars(parsed_args)["%s_name" % ramdisk_type]
args = ("-a %(arch)s -o %(name)s "
"--ramdisk-element dracut-ramdisk %(node_dist)s "
"%(image_element)s %(dib_common_elements)s "
"2>&1 | tee dib-%(ramdisk_type)s.log" %
{
'arch': parsed_args.node_arch,
'name': image_name,
'node_dist': parsed_args.node_dist,
'image_element':
vars(parsed_args)["%s_image_element" %
ramdisk_type],
'dib_common_elements':
parsed_args.dib_common_elements,
'ramdisk_type': ramdisk_type,
})
os.environ.update(parsed_args.dib_env_vars)
self._ramdisk_image_create(args)
def build_image(self, parsed_args, node_type):
image_name = "%s.qcow2" % vars(parsed_args)['overcloud_%s_name' %
node_type]
extra_args = vars(parsed_args)["overcloud_%s_dib_extra_args" %
node_type]
args = ("-a %(arch)s -o %(name)s "
"%(node_dist)s %(overcloud_dib_extra_args)s "
"%(dib_common_elements)s 2>&1 | "
"tee dib-overcloud-%(image_type)s.log" %
{
'arch': parsed_args.node_arch,
'name': image_name,
'node_dist': parsed_args.node_dist,
'overcloud_dib_extra_args': extra_args,
'dib_common_elements':
parsed_args.dib_common_elements,
'image_type': node_type,
})
os.environ.update(parsed_args.dib_env_vars)
self._disk_image_create(args)
class BuildOvercloudImage(command.Command):
"""Build images for the overcloud"""
@ -85,6 +157,10 @@ class BuildOvercloudImage(command.Command):
'overcloud-full',
]
_BUILDERS = [
'dib',
]
def get_parser(self, prog_name):
parser = super(BuildOvercloudImage, self).get_parser(prog_name)
image_group = parser.add_mutually_exclusive_group(required=True)
@ -250,14 +326,17 @@ class BuildOvercloudImage(command.Command):
" ".join(self.DISCOVERY_IMAGE_ELEMENT)),
help="DIB elements for discovery image",
)
image_group.add_argument(
"--builder",
dest="builder",
metavar='<builder>',
choices=self._BUILDERS,
default='dib',
help="Image builder. One of "
"%s" % ", ".join(self._BUILDERS),
)
return parser
def _disk_image_create(self, args):
subprocess.call('disk-image-create {0}'.format(args), shell=True)
def _ramdisk_image_create(self, args):
subprocess.call('ramdisk-image-create {0}'.format(args), shell=True)
def _set_env_var(self, dest_dict, key_name, default_value):
dest_dict[key_name] = os.environ.get(key_name, default_value)
@ -350,23 +429,7 @@ class BuildOvercloudImage(command.Command):
image_name = vars(parsed_args)["%s_name" % ramdisk_type]
if (not os.path.isfile("%s.initramfs" % image_name) or
not os.path.isfile("%s.kernel" % image_name)):
args = ("-a %(arch)s -o %(name)s "
"--ramdisk-element dracut-ramdisk %(node_dist)s "
"%(image_element)s %(dib_common_elements)s "
"2>&1 | tee dib-%(ramdisk_type)s.log" %
{
'arch': parsed_args.node_arch,
'name': image_name,
'node_dist': parsed_args.node_dist,
'image_element':
vars(parsed_args)["%s_image_element" %
ramdisk_type],
'dib_common_elements':
parsed_args.dib_common_elements,
'ramdisk_type': ramdisk_type,
})
os.environ.update(parsed_args.dib_env_vars)
self._ramdisk_image_create(args)
parsed_args._builder.build_ramdisk(parsed_args, ramdisk_type)
def _build_image_ramdisks(self, parsed_args):
self._build_image_ramdisk_deploy(parsed_args)
@ -404,23 +467,7 @@ class BuildOvercloudImage(command.Command):
image_name = "%s.qcow2" % vars(parsed_args)['overcloud_%s_name' %
node_type]
if not os.path.isfile(image_name):
args = ("-a %(arch)s -o %(name)s "
"%(node_dist)s %(overcloud_dib_extra_args)s "
"%(dib_common_elements)s 2>&1 | "
"tee dib-overcloud-%(image_type)s.log" %
{
'arch': parsed_args.node_arch,
'name': image_name,
'node_dist': parsed_args.node_dist,
'overcloud_dib_extra_args':
vars(parsed_args)["overcloud_%s_dib_extra_args" %
node_type],
'dib_common_elements':
parsed_args.dib_common_elements,
'image_type': node_type,
})
os.environ.update(parsed_args.dib_env_vars)
self._disk_image_create(args)
parsed_args._builder.build_image(parsed_args, node_type)
def _build_image_overcloud_full(self, parsed_args):
self._build_image_overcloud(parsed_args, 'full')
@ -446,10 +493,20 @@ class BuildOvercloudImage(command.Command):
image_name,
stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
def _create_builder(self, builder):
if builder == 'dib':
return DibImageBuilder()
# Assert here, as the command line handling should have ensured
# that the builder is one among a limited choice
assert False, "unhandled builder in _create_builder"
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
parsed_args._builder = self._create_builder(parsed_args.builder)
self._prepare_env_variables(parsed_args)
parsed_args._builder.preprocess_parsed_args(parsed_args)
self.log.debug("Environment: %s" % parsed_args.dib_env_vars)
if parsed_args.all: