container image build: introduce --use-buildah

Support Buildah instead of Docker by calling:
  $ openstack container image build --use-buildah

And it will build TripleO containers with Buildah and not Docker.

Co-Authored-By: Alex Schultz <aschultz@redhat.com>
Change-Id: I7608136cb213bdca81348a0c3c751b488f48d712
This commit is contained in:
Emilien Macchi 2019-01-31 16:55:32 -05:00
parent f848e42d93
commit 48525b19bc
6 changed files with 143 additions and 6 deletions

View File

@ -146,7 +146,7 @@ testscenarios===0.4
testtools==2.2.0
tooz==1.58.0
traceback2==1.4.0
tripleo-common==10.2.0
tripleo-common==10.4.0
ujson==1.35
unittest2==1.1.0
vine==1.1.4

View File

@ -16,5 +16,5 @@ simplejson>=3.5.1 # MIT
six>=1.10.0 # MIT
osc-lib>=1.8.0 # Apache-2.0
websocket-client>=0.44.0 # LGPLv2+
tripleo-common>=10.2.0 # Apache-2.0
tripleo-common>=10.4.0 # Apache-2.0
cryptography>=2.1 # BSD/Apache-2.0

View File

@ -20,6 +20,7 @@ import logging
import mock
import os
import os.path
import shutil
import socket
import subprocess
import tempfile
@ -37,6 +38,7 @@ import yaml
from tripleoclient import exceptions
from tripleoclient import utils
from six.moves.configparser import ConfigParser
from six.moves.urllib import error as url_error
@ -1302,3 +1304,44 @@ class TestCheckEnvForProxy(TestCase):
self.assertRaises(RuntimeError,
utils.check_env_for_proxy,
['foo', 'bar'])
class TestConfigParser(TestCase):
def setUp(self):
self.tmp_dir = tempfile.mkdtemp()
def tearDown(self):
if self.tmp_dir:
shutil.rmtree(self.tmp_dir)
self.tmp_dir = None
def test_get_config_value(self):
cfile, cfile_name = tempfile.mkstemp(dir=self.tmp_dir)
cfp = open(cfile_name, 'w')
cfg = ConfigParser()
cfg.add_section('foo')
cfg.set('foo', 'bar', 'baz')
cfg.write(cfp)
cfp.close()
config = utils.get_config_value(cfile_name, 'foo', 'bar')
self.assertEqual(config, 'baz')
def test_get_config_value_multiple_files(self):
_, cfile1_name = tempfile.mkstemp(dir=self.tmp_dir, text=True)
_, cfile2_name = tempfile.mkstemp(dir=self.tmp_dir, text=True)
cfiles = [cfile1_name, cfile2_name]
cfg = ConfigParser()
cfg.add_section('foo')
cfg.set('foo', 'bar', 'baz')
with open(cfile1_name, 'w') as fp:
cfg.write(fp)
cfg.set('foo', 'bar', 'boop')
with open(cfile2_name, 'w') as fp:
cfg.write(fp)
config = utils.get_config_value(cfiles, 'foo', 'bar')
self.assertEqual(config, 'boop')
def test_get_config_value_bad_file(self):
self.assertRaises(exceptions.NotFound,
utils.get_config_value,
'does-not-exist', 'foo', 'bar')

View File

@ -500,7 +500,52 @@ class TestContainerImageBuild(TestPluginV1):
mock_builder.return_value.build_images.assert_called_once_with([
self.default_kolla_conf, '/tmp/kolla.conf',
path
], [])
], [], False, None)
@mock.patch('os.fdopen', autospec=True)
@mock.patch('tempfile.mkdtemp')
@mock.patch('tempfile.mkstemp')
@mock.patch('tripleoclient.v1.container_image.BuildImage.kolla_cfg')
@mock.patch('tripleo_common.image.builder.buildah.BuildahBuilder',
autospec=True)
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True)
@mock.patch('os.remove')
def test_container_image_build_with_buildah(self, mock_remove,
mock_builder, mock_buildah,
mock_kolla_cfg, mock_mkstemp,
mock_mkdtemp, mock_fdopen):
arglist = [
'--config-file',
'/tmp/bar.yaml',
'--kolla-config-file',
'/tmp/kolla.conf',
'--use-buildah'
]
parsed_args = self.check_parser(self.cmd, arglist, [])
deps = '{"base": ["qrouterd"]}'
mock_builder.return_value.build_images.return_value = deps
mock_mkstemp.return_value = (1, '/tmp/whatever_file')
mock_mkdtemp.return_value = '/tmp/whatever_dir'
mock_bb = mock.MagicMock()
mock_bb.build_all = mock.MagicMock()
mock_buildah.return_value = mock_bb
self.cmd.take_action(parsed_args)
cfg_files = list(parsed_args.kolla_config_files)
cfg_files.append('/tmp/whatever_file')
cfg_calls = [
mock.call(cfg_files, 'base'),
mock.call(cfg_files, 'type'),
mock.call(cfg_files, 'tag'),
mock.call(cfg_files, 'namespace'),
mock.call(cfg_files, 'registry'),
]
mock_kolla_cfg.assert_has_calls(cfg_calls)
mock_bb.build_all.assert_called_once()
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True)
@ -532,7 +577,7 @@ class TestContainerImageBuild(TestPluginV1):
mock_builder.return_value.build_images.assert_called_once_with([
self.default_kolla_conf, '/tmp/kolla.conf',
path
], ['foo', 'bar'])
], ['foo', 'bar'], False, None)
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True)

View File

@ -21,6 +21,7 @@ import glob
import hashlib
import logging
import shutil
from six.moves.configparser import ConfigParser
import os
import os.path
@ -1457,3 +1458,17 @@ def check_env_for_proxy(no_proxy_hosts=None):
'addresses "{}" may be missing from the no_proxy '
'environment variable').format(','.join(missing_hosts))
raise RuntimeError(message)
def get_config_value(cfg, section, option):
"""Return the value of an option in ini config file(s)"""
config = ConfigParser()
config.read(cfg)
try:
val = config.get(section, option)
except Exception:
raise exceptions.NotFound(_('Unable to find {section}/{option} in '
'{config}').format(section=section,
option=option,
config=cfg))
return val

View File

@ -28,6 +28,7 @@ from osc_lib.i18n import _
import six
import yaml
from tripleo_common.image.builder import buildah
from tripleo_common.image import image_uploader
from tripleo_common.image import kolla_builder
@ -170,8 +171,21 @@ class BuildImage(command.Command):
"containers to be built to skip. Can be specified multiple "
"times."),
)
parser.add_argument(
'--use-buildah',
dest='use_buildah',
action='store_true',
default=False,
help=_('Use Buildah instead of Docker to build the images '
'with Kolla.')
)
return parser
@staticmethod
def kolla_cfg(cfg, param):
"""Return a parameter from Kolla config"""
return utils.get_config_value(cfg, 'DEFAULT', param)
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
@ -182,12 +196,32 @@ class BuildImage(command.Command):
tmp.write('list_dependencies=true')
kolla_config_files = list(parsed_args.kolla_config_files)
kolla_config_files.append(path)
kolla_tmp_dir = None
if parsed_args.use_buildah:
# A temporary directory is needed to let Kolla generates the
# Dockerfiles that will be used by Buildah to build the images.
kolla_tmp_dir = tempfile.mkdtemp(prefix='kolla-')
try:
builder = kolla_builder.KollaImageBuilder(parsed_args.config_files)
result = builder.build_images(kolla_config_files,
parsed_args.excludes)
if parsed_args.list_dependencies:
parsed_args.excludes,
parsed_args.use_buildah,
kolla_tmp_dir)
if parsed_args.use_buildah:
deps = json.loads(result)
cfg = kolla_config_files
bb = buildah.BuildahBuilder(kolla_tmp_dir, deps,
BuildImage.kolla_cfg(cfg, 'base'),
BuildImage.kolla_cfg(cfg, 'type'),
BuildImage.kolla_cfg(cfg, 'tag'),
BuildImage.kolla_cfg(cfg,
'namespace'),
BuildImage.kolla_cfg(cfg,
'registry'))
bb.build_all()
elif parsed_args.list_dependencies:
deps = json.loads(result)
yaml.safe_dump(deps, self.app.stdout, indent=2,
default_flow_style=False)