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:
@@ -146,7 +146,7 @@ testscenarios===0.4
|
|||||||
testtools==2.2.0
|
testtools==2.2.0
|
||||||
tooz==1.58.0
|
tooz==1.58.0
|
||||||
traceback2==1.4.0
|
traceback2==1.4.0
|
||||||
tripleo-common==10.2.0
|
tripleo-common==10.4.0
|
||||||
ujson==1.35
|
ujson==1.35
|
||||||
unittest2==1.1.0
|
unittest2==1.1.0
|
||||||
vine==1.1.4
|
vine==1.1.4
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ simplejson>=3.5.1 # MIT
|
|||||||
six>=1.10.0 # MIT
|
six>=1.10.0 # MIT
|
||||||
osc-lib>=1.8.0 # Apache-2.0
|
osc-lib>=1.8.0 # Apache-2.0
|
||||||
websocket-client>=0.44.0 # LGPLv2+
|
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
|
cryptography>=2.1 # BSD/Apache-2.0
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import logging
|
|||||||
import mock
|
import mock
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -37,6 +38,7 @@ import yaml
|
|||||||
from tripleoclient import exceptions
|
from tripleoclient import exceptions
|
||||||
from tripleoclient import utils
|
from tripleoclient import utils
|
||||||
|
|
||||||
|
from six.moves.configparser import ConfigParser
|
||||||
from six.moves.urllib import error as url_error
|
from six.moves.urllib import error as url_error
|
||||||
|
|
||||||
|
|
||||||
@@ -1302,3 +1304,44 @@ class TestCheckEnvForProxy(TestCase):
|
|||||||
self.assertRaises(RuntimeError,
|
self.assertRaises(RuntimeError,
|
||||||
utils.check_env_for_proxy,
|
utils.check_env_for_proxy,
|
||||||
['foo', 'bar'])
|
['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')
|
||||||
|
|||||||
@@ -500,7 +500,52 @@ 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
|
||||||
], [])
|
], [], 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',
|
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@@ -532,7 +577,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'])
|
], ['foo', 'bar'], False, None)
|
||||||
|
|
||||||
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import glob
|
|||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
|
from six.moves.configparser import ConfigParser
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
@@ -1457,3 +1458,17 @@ def check_env_for_proxy(no_proxy_hosts=None):
|
|||||||
'addresses "{}" may be missing from the no_proxy '
|
'addresses "{}" may be missing from the no_proxy '
|
||||||
'environment variable').format(','.join(missing_hosts))
|
'environment variable').format(','.join(missing_hosts))
|
||||||
raise RuntimeError(message)
|
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
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from osc_lib.i18n import _
|
|||||||
import six
|
import six
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from tripleo_common.image.builder import buildah
|
||||||
from tripleo_common.image import image_uploader
|
from tripleo_common.image import image_uploader
|
||||||
from tripleo_common.image import kolla_builder
|
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 "
|
"containers to be built to skip. Can be specified multiple "
|
||||||
"times."),
|
"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
|
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):
|
def take_action(self, parsed_args):
|
||||||
self.log.debug("take_action(%s)" % parsed_args)
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
|
|
||||||
@@ -182,12 +196,32 @@ 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)
|
||||||
|
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:
|
try:
|
||||||
builder = kolla_builder.KollaImageBuilder(parsed_args.config_files)
|
builder = kolla_builder.KollaImageBuilder(parsed_args.config_files)
|
||||||
result = builder.build_images(kolla_config_files,
|
result = builder.build_images(kolla_config_files,
|
||||||
parsed_args.excludes)
|
parsed_args.excludes,
|
||||||
if parsed_args.list_dependencies:
|
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)
|
deps = json.loads(result)
|
||||||
yaml.safe_dump(deps, self.app.stdout, indent=2,
|
yaml.safe_dump(deps, self.app.stdout, indent=2,
|
||||||
default_flow_style=False)
|
default_flow_style=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user