Add --work-dir option to container image build command

Add --work-dir to openstack overcloud container image build command and
every run will create a unique workspace which where will be stored Kolla
configs and build logs. Default directory will be in
/tmp/container-builds. UUIDs are used to identify each time we run the
command and will be the directory name in the work dir.

Depends-On: https://review.opendev.org/#/c/709389/
Related-Bug: #1864108
Change-Id: Id3e52ba920c54c98529ecb5f723ba452362a0b32
This commit is contained in:
Emilien Macchi 2020-02-20 22:41:18 -05:00 committed by yatin
parent c923a4de9b
commit 7aeba8f51a
3 changed files with 97 additions and 60 deletions

View File

@ -0,0 +1,8 @@
---
features:
- |
Add --work-dir to openstack overcloud container image build command and
every run will create a unique workspace which where will be stored Kolla
configs and build logs. Default directory will be in
/tmp/container-builds. UUIDs are used to identify each time we run the
command and will be the directory name in the work dir.

View File

@ -21,6 +21,7 @@ import shutil
import six import six
import sys import sys
import tempfile import tempfile
import uuid
import yaml import yaml
from osc_lib import exceptions as oscexc from osc_lib import exceptions as oscexc
@ -927,7 +928,11 @@ class TestContainerImageBuild(TestPluginV1):
# Get the command object to test # Get the command object to test
self.cmd = container_image.BuildImage(self.app, None) self.cmd = container_image.BuildImage(self.app, None)
self.cmd.app.stdout = six.StringIO() self.cmd.app.stdout = six.StringIO()
self.temp_dir = self.useFixture(fixtures.TempDir()).join() self.uuid = str(uuid.uuid4())
self.temp_dir = os.path.join(self.useFixture(
fixtures.TempDir()).join())
self.temp_dir_uuid = os.path.join(self.temp_dir, self.uuid)
# Default conf file # Default conf file
self.default_kolla_conf = os.path.join( self.default_kolla_conf = os.path.join(
sys.prefix, 'share', 'tripleo-common', 'container-images', sys.prefix, 'share', 'tripleo-common', 'container-images',
@ -936,7 +941,9 @@ class TestContainerImageBuild(TestPluginV1):
@mock.patch('sys.exit') @mock.patch('sys.exit')
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True) autospec=True)
def test_container_image_build_noargs(self, mock_builder, exit_mock): @mock.patch('os.makedirs')
def test_container_image_build_noargs(self, mock_mkdirs, mock_builder,
exit_mock):
arglist = [] arglist = []
verifylist = [] verifylist = []
mock_builder.return_value.build_images.return_value = 'done' mock_builder.return_value.build_images.return_value = 'done'
@ -953,38 +960,39 @@ class TestContainerImageBuild(TestPluginV1):
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True) autospec=True)
def test_container_image_build(self, mock_builder): @mock.patch('uuid.uuid4')
def test_container_image_build(self, mock_uuid, mock_builder):
arglist = [ arglist = [
'--config-file', '--config-file',
'/tmp/foo.yaml', '/tmp/foo.yaml',
'--config-file', '--config-file',
'/tmp/bar.yaml', '/tmp/bar.yaml',
'--work-dir',
self.temp_dir,
'--kolla-config-file', '--kolla-config-file',
'/tmp/kolla.conf' '/tmp/kolla.conf'
] ]
verifylist = [] verifylist = []
mock_builder.return_value.build_images.return_value = 'done' mock_builder.return_value.build_images.return_value = 'done'
mock_uuid.return_value = self.uuid
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
f, path = tempfile.mkstemp(dir=self.temp_dir) f, path = tempfile.mkstemp(dir=self.temp_dir)
with mock.patch('tempfile.mkdtemp') as mock_mkd: with mock.patch('tempfile.mkstemp') as mock_mkstemp:
mock_mkd.return_value = '/tmp/testing' with mock.patch('os.chdir'):
with mock.patch('tempfile.mkstemp') as mock_mkstemp: mock_mkstemp.return_value = f, path
with mock.patch('os.chdir'): self.cmd.take_action(parsed_args)
mock_mkstemp.return_value = f, path
self.cmd.take_action(parsed_args)
mock_builder.assert_called_once_with([ mock_builder.assert_called_once_with([
'/tmp/foo.yaml', '/tmp/bar.yaml']) '/tmp/foo.yaml', '/tmp/bar.yaml'])
mock_builder.return_value.build_images.assert_called_once_with([ mock_builder.return_value.build_images.assert_called_once_with([
self.default_kolla_conf, '/tmp/kolla.conf', self.default_kolla_conf, '/tmp/kolla.conf',
path path
], [], False, '/tmp/testing') ], [], False, self.temp_dir_uuid)
@mock.patch('os.chdir') @mock.patch('os.chdir')
@mock.patch('os.fdopen', autospec=True) @mock.patch('os.fdopen', autospec=True)
@mock.patch('tempfile.mkdtemp')
@mock.patch('tempfile.mkstemp') @mock.patch('tempfile.mkstemp')
@mock.patch( @mock.patch(
'tripleoclient.utils.get_from_cfg') 'tripleoclient.utils.get_from_cfg')
@ -1001,14 +1009,15 @@ class TestContainerImageBuild(TestPluginV1):
mock_builder, mock_buildah, mock_builder, mock_buildah,
mock_kolla_boolean_cfg, mock_kolla_boolean_cfg,
mock_kolla_cfg, mock_mkstemp, mock_kolla_cfg, mock_mkstemp,
mock_mkdtemp, mock_fdopen, mock_fdopen, mock_chdir):
mock_chdir):
arglist = [ arglist = [
'--config-file', '--config-file',
'/tmp/bar.yaml', '/tmp/bar.yaml',
'--kolla-config-file', '--kolla-config-file',
'/tmp/kolla.conf', '/tmp/kolla.conf',
'--use-buildah' '--use-buildah',
'--work-dir',
self.temp_dir,
] ]
parsed_args = self.check_parser(self.cmd, arglist, []) parsed_args = self.check_parser(self.cmd, arglist, [])
@ -1016,7 +1025,6 @@ class TestContainerImageBuild(TestPluginV1):
mock_builder.return_value.build_images.return_value = deps mock_builder.return_value.build_images.return_value = deps
mock_mkstemp.return_value = (1, '/tmp/whatever_file') mock_mkstemp.return_value = (1, '/tmp/whatever_file')
mock_mkdtemp.return_value = '/tmp/whatever_dir'
mock_bb = mock.MagicMock() mock_bb = mock.MagicMock()
mock_bb.build_all = mock.MagicMock() mock_bb.build_all = mock.MagicMock()
@ -1042,7 +1050,8 @@ class TestContainerImageBuild(TestPluginV1):
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True) autospec=True)
def test_container_image_build_with_exclude(self, mock_builder): @mock.patch('uuid.uuid4')
def test_container_image_build_with_exclude(self, mock_uuid, mock_builder):
arglist = [ arglist = [
'--config-file', '--config-file',
'/tmp/foo.yaml', '/tmp/foo.yaml',
@ -1050,6 +1059,8 @@ class TestContainerImageBuild(TestPluginV1):
'/tmp/bar.yaml', '/tmp/bar.yaml',
'--kolla-config-file', '--kolla-config-file',
'/tmp/kolla.conf', '/tmp/kolla.conf',
'--work-dir',
'/tmp/testing',
'--exclude', '--exclude',
'foo', 'foo',
'--exclude', '--exclude',
@ -1057,6 +1068,7 @@ class TestContainerImageBuild(TestPluginV1):
] ]
verifylist = [] verifylist = []
mock_builder.return_value.build_images.return_value = 'done' mock_builder.return_value.build_images.return_value = 'done'
mock_uuid.return_value = '123'
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -1073,7 +1085,7 @@ class TestContainerImageBuild(TestPluginV1):
mock_builder.return_value.build_images.assert_called_once_with([ mock_builder.return_value.build_images.assert_called_once_with([
self.default_kolla_conf, '/tmp/kolla.conf', self.default_kolla_conf, '/tmp/kolla.conf',
path path
], ['foo', 'bar'], False, '/tmp/testing') ], ['foo', 'bar'], False, '/tmp/testing/123')
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True) autospec=True)
@ -1084,6 +1096,8 @@ class TestContainerImageBuild(TestPluginV1):
'--list-images', '--list-images',
'--config-file', '--config-file',
'/tmp/bar.yaml', '/tmp/bar.yaml',
'--work-dir',
'/tmp/testing',
'--kolla-config-file', '--kolla-config-file',
'/tmp/kolla.conf' '/tmp/kolla.conf'
] ]
@ -1105,7 +1119,9 @@ class TestContainerImageBuild(TestPluginV1):
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder', @mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True) autospec=True)
@mock.patch('os.remove') @mock.patch('os.remove')
def test_container_image_build_list_deps(self, mock_remove, mock_builder): @mock.patch('os.makedirs')
def test_container_image_build_list_deps(self, mock_mkdirs, mock_remove,
mock_builder):
arglist = [ arglist = [
'--config-file', '--config-file',
'/tmp/bar.yaml', '/tmp/bar.yaml',

View File

@ -22,6 +22,7 @@ import shutil
import sys import sys
import tempfile import tempfile
import time import time
import uuid
from osc_lib import exceptions as oscexc from osc_lib import exceptions as oscexc
from osc_lib.i18n import _ from osc_lib.i18n import _
@ -182,6 +183,14 @@ class BuildImage(command.Command):
help=_('Use Buildah instead of Docker to build the images ' help=_('Use Buildah instead of Docker to build the images '
'with Kolla.') 'with Kolla.')
) )
parser.add_argument(
"--work-dir",
dest="work_dir",
default='/tmp/container-builds',
metavar='<container builds directory>',
help=_("TripleO container builds directory, storing configs and "
"logs for each image and its dependencies.")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -194,49 +203,53 @@ class BuildImage(command.Command):
tmp.write('list_dependencies=true') tmp.write('list_dependencies=true')
kolla_config_files = list(parsed_args.kolla_config_files) kolla_config_files = list(parsed_args.kolla_config_files)
kolla_config_files.append(path) kolla_config_files.append(path)
with utils.TempDirs(dir_prefix='kolla-') as kolla_tmp_dir: # Generate an unique work directory so we can keep configs and logs
try: # each time we run the command; they'll be stored in work_dir.
builder = kolla_builder.KollaImageBuilder( kolla_work_dir = os.path.join(parsed_args.work_dir, str(uuid.uuid4()))
parsed_args.config_files
)
result = builder.build_images(kolla_config_files,
parsed_args.excludes,
parsed_args.use_buildah,
kolla_tmp_dir)
if parsed_args.use_buildah: # Make sure the unique work directory exists
deps = json.loads(result) if not os.path.exists(kolla_work_dir):
kolla_cfg = utils.get_read_config(kolla_config_files) self.log.debug("Creating container builds "
bb = buildah.BuildahBuilder( "workspace in: %s" % kolla_work_dir)
kolla_tmp_dir, deps, os.makedirs(kolla_work_dir)
utils.get_from_cfg(kolla_cfg, "base"),
utils.get_from_cfg(kolla_cfg, "type"), builder = kolla_builder.KollaImageBuilder(parsed_args.config_files)
utils.get_from_cfg(kolla_cfg, "tag"), result = builder.build_images(kolla_config_files,
utils.get_from_cfg(kolla_cfg, "namespace"), parsed_args.excludes,
utils.get_from_cfg(kolla_cfg, "registry"), parsed_args.use_buildah,
utils.getboolean_from_cfg(kolla_cfg, "push")) kolla_work_dir)
bb.build_all()
elif parsed_args.list_dependencies: if parsed_args.use_buildah:
deps = json.loads(result) deps = json.loads(result)
yaml.safe_dump( kolla_cfg = utils.get_read_config(kolla_config_files)
deps, bb = buildah.BuildahBuilder(
self.app.stdout, kolla_work_dir, deps,
indent=2, utils.get_from_cfg(kolla_cfg, "base"),
default_flow_style=False utils.get_from_cfg(kolla_cfg, "type"),
) utils.get_from_cfg(kolla_cfg, "tag"),
elif parsed_args.list_images: utils.get_from_cfg(kolla_cfg, "namespace"),
deps = json.loads(result) utils.get_from_cfg(kolla_cfg, "registry"),
images = [] utils.getboolean_from_cfg(kolla_cfg, "push"))
BuildImage.images_from_deps(images, deps) bb.build_all()
yaml.safe_dump( elif parsed_args.list_dependencies:
images, deps = json.loads(result)
self.app.stdout, yaml.safe_dump(
default_flow_style=False deps,
) self.app.stdout,
elif result: indent=2,
self.app.stdout.write(result) default_flow_style=False
finally: )
os.remove(path) 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)
class PrepareImageFiles(command.Command): class PrepareImageFiles(command.Command):