Add list options to overcloud container image build
This change adds the options --list-images and --list-dependencies to the "overcloud container image build" command. With these options, images will not be built, but the command will return structured data for what images would be built. This provides parsable data to allow other standard image building pipelines to do the actual image building. The order of --list-images is determined by doing a depth-first traversal of the dependencies structure, which provides a reasonable order for image building. Change-Id: Ibabbb487465566dc2550a9b89e76800dfcae8257
This commit is contained in:
parent
daf0f04bcf
commit
16cfbd2b97
@ -13,9 +13,11 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
import os
|
||||
import shutil
|
||||
import six
|
||||
import tempfile
|
||||
import yaml
|
||||
|
||||
@ -171,6 +173,8 @@ class TestContainerImageBuild(TestPluginV1):
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = container_image.BuildImage(self.app, None)
|
||||
self.cmd.app.stdout = six.StringIO()
|
||||
self.temp_dir = self.useFixture(fixtures.TempDir()).join()
|
||||
|
||||
@mock.patch('sys.exit')
|
||||
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
||||
@ -178,12 +182,16 @@ class TestContainerImageBuild(TestPluginV1):
|
||||
def test_container_image_build_noargs(self, mock_builder, exit_mock):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
mock_builder.return_value.build_images.return_value = 'done'
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
# argparse will complain that --config-file and --kolla-config are
|
||||
# missing exit with 2
|
||||
f, path = tempfile.mkstemp(dir=self.temp_dir)
|
||||
with mock.patch('tempfile.mkstemp') as mock_mkstemp:
|
||||
mock_mkstemp.return_value = f, path
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
# argparse will complain that --config-file is missing and exit with 2
|
||||
exit_mock.assert_called_with(2)
|
||||
|
||||
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
||||
@ -198,13 +206,122 @@ class TestContainerImageBuild(TestPluginV1):
|
||||
'/tmp/kolla.conf'
|
||||
]
|
||||
verifylist = []
|
||||
mock_builder.return_value.build_images.return_value = 'done'
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
f, path = tempfile.mkstemp(dir=self.temp_dir)
|
||||
with mock.patch('tempfile.mkstemp') as mock_mkstemp:
|
||||
mock_mkstemp.return_value = f, path
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_builder.assert_called_once_with([
|
||||
'/tmp/foo.yaml', '/tmp/bar.yaml'])
|
||||
mock_builder.return_value.build_images.assert_called_once_with([
|
||||
'/tmp/kolla.conf'
|
||||
'/tmp/kolla.conf',
|
||||
path
|
||||
])
|
||||
|
||||
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
||||
autospec=True)
|
||||
@mock.patch('os.remove')
|
||||
def test_container_image_build_list_images(self, mock_remove,
|
||||
mock_builder):
|
||||
arglist = [
|
||||
'--list-images',
|
||||
'--config-file',
|
||||
'/tmp/bar.yaml',
|
||||
'--kolla-config-file',
|
||||
'/tmp/kolla.conf'
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
deps = '{"base": ["qrouterd"]}'
|
||||
mock_builder.return_value.build_images.return_value = deps
|
||||
|
||||
f, path = tempfile.mkstemp(dir=self.temp_dir)
|
||||
with mock.patch('tempfile.mkstemp') as mock_mkstemp:
|
||||
mock_mkstemp.return_value = f, path
|
||||
self.cmd.take_action(parsed_args)
|
||||
with open(path, 'r') as conf_file:
|
||||
self.assertEqual(
|
||||
conf_file.readlines(),
|
||||
['[DEFAULT]\n', 'list_dependencies=true'])
|
||||
self.assertEqual('- base\n- qrouterd\n',
|
||||
self.cmd.app.stdout.getvalue())
|
||||
|
||||
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
||||
autospec=True)
|
||||
@mock.patch('os.remove')
|
||||
def test_container_image_build_list_deps(self, mock_remove, mock_builder):
|
||||
arglist = [
|
||||
'--config-file',
|
||||
'/tmp/bar.yaml',
|
||||
'--kolla-config-file',
|
||||
'/tmp/kolla.conf',
|
||||
'--list-dependencies',
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
deps = '{"base": ["qrouterd"]}'
|
||||
mock_builder.return_value.build_images.return_value = deps
|
||||
|
||||
f, path = tempfile.mkstemp(dir=self.temp_dir)
|
||||
with mock.patch('tempfile.mkstemp') as mock_mkstemp:
|
||||
mock_mkstemp.return_value = f, path
|
||||
self.cmd.take_action(parsed_args)
|
||||
with open(path, 'r') as conf_file:
|
||||
self.assertEqual(
|
||||
conf_file.readlines(),
|
||||
['[DEFAULT]\n', 'list_dependencies=true'])
|
||||
self.assertEqual('base:\n- qrouterd\n',
|
||||
self.cmd.app.stdout.getvalue())
|
||||
|
||||
def test_images_from_deps(self):
|
||||
deps = yaml.safe_load('''base:
|
||||
- qdrouterd
|
||||
- cron
|
||||
- ceph-base:
|
||||
- ceph-osd
|
||||
- ceph-rgw
|
||||
- ceph-mon
|
||||
- cephfs-fuse
|
||||
- ceph-mds
|
||||
- redis
|
||||
- etcd
|
||||
- kubernetes-entrypoint
|
||||
- kolla-toolbox
|
||||
- telegraf
|
||||
- openstack-base:
|
||||
- swift-base:
|
||||
- swift-proxy-server
|
||||
- swift-account
|
||||
- swift-container
|
||||
- swift-object-expirer
|
||||
- swift-rsyncd
|
||||
- swift-object''')
|
||||
|
||||
images_yaml = '''- base
|
||||
- qdrouterd
|
||||
- cron
|
||||
- ceph-base
|
||||
- ceph-osd
|
||||
- ceph-rgw
|
||||
- ceph-mon
|
||||
- cephfs-fuse
|
||||
- ceph-mds
|
||||
- redis
|
||||
- etcd
|
||||
- kubernetes-entrypoint
|
||||
- kolla-toolbox
|
||||
- telegraf
|
||||
- openstack-base
|
||||
- swift-base
|
||||
- swift-proxy-server
|
||||
- swift-account
|
||||
- swift-container
|
||||
- swift-object-expirer
|
||||
- swift-rsyncd
|
||||
- swift-object
|
||||
'''
|
||||
images = []
|
||||
self.cmd.images_from_deps(images, deps)
|
||||
self.assertEqual(yaml.safe_load(images_yaml), images)
|
||||
|
@ -14,10 +14,12 @@
|
||||
#
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib.i18n import _
|
||||
@ -62,6 +64,19 @@ class BuildImage(command.Command):
|
||||
auth_required = False
|
||||
log = logging.getLogger(__name__ + ".BuildImage")
|
||||
|
||||
@staticmethod
|
||||
def images_from_deps(images, dep):
|
||||
'''Builds a list from the dependencies depth-first. '''
|
||||
if isinstance(dep, list):
|
||||
for v in dep:
|
||||
BuildImage.images_from_deps(images, v)
|
||||
elif isinstance(dep, dict):
|
||||
for k, v in dep.items():
|
||||
images.append(k)
|
||||
BuildImage.images_from_deps(images, v)
|
||||
else:
|
||||
images.append(dep)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(BuildImage, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
@ -87,12 +102,52 @@ class BuildImage(command.Command):
|
||||
"can be specified, with values in later files taking "
|
||||
"precedence."),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--list-images',
|
||||
dest='list_images',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Show the images which would be built instead of '
|
||||
'building them.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--list-dependencies',
|
||||
dest='list_dependencies',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Show the image build dependencies instead of '
|
||||
'building them.')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
builder = kolla_builder.KollaImageBuilder(parsed_args.config_files)
|
||||
builder.build_images(parsed_args.kolla_config_files)
|
||||
|
||||
fd, path = tempfile.mkstemp(prefix='kolla_conf_')
|
||||
with os.fdopen(fd, 'w') as tmp:
|
||||
tmp.write('[DEFAULT]\n')
|
||||
if parsed_args.list_images or parsed_args.list_dependencies:
|
||||
tmp.write('list_dependencies=true')
|
||||
kolla_config_files = list(parsed_args.kolla_config_files)
|
||||
kolla_config_files.append(path)
|
||||
|
||||
try:
|
||||
builder = kolla_builder.KollaImageBuilder(parsed_args.config_files)
|
||||
result = builder.build_images(kolla_config_files)
|
||||
if parsed_args.list_dependencies:
|
||||
deps = json.loads(result)
|
||||
yaml.safe_dump(deps, self.app.stdout, indent=2,
|
||||
default_flow_style=False)
|
||||
elif parsed_args.list_images:
|
||||
deps = json.loads(result)
|
||||
images = []
|
||||
BuildImage.images_from_deps(images, deps)
|
||||
yaml.safe_dump(images, self.app.stdout,
|
||||
default_flow_style=False)
|
||||
elif result:
|
||||
self.app.stdout.write(result)
|
||||
finally:
|
||||
os.remove(path)
|
||||
|
||||
|
||||
class PrepareImageFiles(command.Command):
|
||||
|
Loading…
Reference in New Issue
Block a user