Files
python-tripleoclient/tripleoclient/tests/v1/test_container_image.py
Alex Schultz 5abe17dc4a Fix pathing for container image prepare
When we pass the paths to the ansible playbook, they need to be absolute
paths as the relative cwd changes when it runs.

Change-Id: I8a434e38eb1a69530190df96d3b555ea14e4488a
Closes-Bug: #1895194
2020-09-14 07:29:57 -06:00

1241 lines
45 KiB
Python

# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import fixtures
import mock
import os
import requests
import shutil
import six
import sys
import tempfile
import uuid
import yaml
from osc_lib import exceptions as oscexc
from six.moves.urllib import parse
from tripleo_common.image import image_uploader
from tripleo_common.image import kolla_builder
from tripleoclient import constants
from tripleoclient.tests.v1.test_plugin import TestPluginV1
from tripleoclient.v1 import container_image
# TODO(sbaker) Remove after a tripleo-common release contains this attribute
CLEANUP = (
CLEANUP_FULL, CLEANUP_PARTIAL, CLEANUP_NONE
) = (
'full', 'partial', 'none'
)
if not hasattr(image_uploader, 'CLEANUP'):
setattr(image_uploader, 'CLEANUP', CLEANUP)
setattr(image_uploader, 'CLEANUP_FULL', CLEANUP_FULL)
setattr(image_uploader, 'CLEANUP_PARTIAL', CLEANUP_PARTIAL)
setattr(image_uploader, 'CLEANUP_NONE', CLEANUP_NONE)
class TestContainerImageUpload(TestPluginV1):
def setUp(self):
super(TestContainerImageUpload, self).setUp()
# Get the command object to test
self.cmd = container_image.UploadImage(self.app, None)
@mock.patch('tripleo_common.utils.locks.processlock.'
'ProcessLock')
@mock.patch('sys.exit')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_container_image_upload_noargs(self, mock_manager, exit_mock,
mock_lock):
arglist = []
verifylist = []
mock_lockobj = mock.MagicMock()
mock_lock.return_value = mock_lockobj
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
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.utils.locks.processlock.'
'ProcessLock')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_container_image_upload_conf_files(self, mock_manager, mock_lock):
arglist = [
'--config-file',
'/tmp/foo.yaml',
'--config-file',
'/tmp/bar.yaml'
]
verifylist = []
mock_lockobj = mock.MagicMock()
mock_lock.return_value = mock_lockobj
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
mock_manager.assert_called_once_with(
['/tmp/foo.yaml', '/tmp/bar.yaml'], cleanup='full',
lock=mock_lockobj)
mock_manager.return_value.upload.assert_called_once_with()
class TestContainerImagePush(TestPluginV1):
def setUp(self):
super(TestContainerImagePush, self).setUp()
lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock')
self.mock_lock = lock.start()
self.addCleanup(lock.stop)
self.cmd = container_image.TripleOContainerImagePush(self.app, None)
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.UploadTask')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action(self, mock_manager, mock_task, mock_get_uc_registry):
arglist = ['docker.io/namespace/foo']
verifylist = [('image_to_push', 'docker.io/namespace/foo')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
# mock upload task
mock_uploadtask = mock.Mock()
mock_task.return_value = mock_uploadtask
# mock add upload task action
mock_add_upload = mock.Mock()
data = []
mock_add_upload.return_value = data
mock_uploader.add_upload_task = mock_add_upload
# mock run tasks action
mock_run_tasks = mock.Mock()
mock_uploader.run_tasks = mock_run_tasks
self.cmd.take_action(parsed_args)
mock_task.assert_called_once_with(
image_name='namespace/foo',
pull_source='docker.io',
push_destination='uc.ctlplane.somedomain',
append_tag=parsed_args.append_tag,
modify_role=None,
modify_vars=None,
cleanup=False,
multi_arch=parsed_args.multi_arch)
mock_add_upload.assert_called_once_with(mock_uploadtask)
mock_run_tasks.assert_called_once()
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.UploadTask')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action_local(self, mock_manager, mock_task,
mock_get_uc_registry):
arglist = ['docker.io/namespace/foo', '--local']
verifylist = [('image_to_push', 'docker.io/namespace/foo'),
('local', True)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
# mock upload task
mock_uploadtask = mock.Mock()
mock_task.return_value = mock_uploadtask
# mock add upload task action
mock_add_upload = mock.Mock()
data = []
mock_add_upload.return_value = data
mock_uploader.add_upload_task = mock_add_upload
# mock run tasks action
mock_run_tasks = mock.Mock()
mock_uploader.run_tasks = mock_run_tasks
self.cmd.take_action(parsed_args)
mock_task.assert_called_once_with(
image_name='containers-storage:docker.io/namespace/foo',
pull_source=None,
push_destination='uc.ctlplane.somedomain',
append_tag=parsed_args.append_tag,
modify_role=None,
modify_vars=None,
cleanup=False,
multi_arch=parsed_args.multi_arch)
mock_add_upload.assert_called_once_with(mock_uploadtask)
mock_run_tasks.assert_called_once()
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.UploadTask')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action_local_path(self, mock_manager, mock_task,
mock_get_uc_registry):
arglist = ['containers-storage:docker.io/namespace/foo']
verifylist = [('image_to_push',
'containers-storage:docker.io/namespace/foo')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
# mock upload task
mock_uploadtask = mock.Mock()
mock_task.return_value = mock_uploadtask
# mock add upload task action
mock_add_upload = mock.Mock()
data = []
mock_add_upload.return_value = data
mock_uploader.add_upload_task = mock_add_upload
# mock run tasks action
mock_run_tasks = mock.Mock()
mock_uploader.run_tasks = mock_run_tasks
self.cmd.take_action(parsed_args)
mock_task.assert_called_once_with(
image_name='containers-storage:docker.io/namespace/foo',
pull_source=None,
push_destination='uc.ctlplane.somedomain',
append_tag=parsed_args.append_tag,
modify_role=None,
modify_vars=None,
cleanup=False,
multi_arch=parsed_args.multi_arch)
mock_add_upload.assert_called_once_with(mock_uploadtask)
mock_run_tasks.assert_called_once()
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.UploadTask')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action_oserror(self, mock_manager, mock_task,
mock_get_uc_registry):
arglist = ['docker.io/namespace/foo']
verifylist = [('image_to_push', 'docker.io/namespace/foo')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
# mock upload task
mock_uploadtask = mock.Mock()
mock_task.return_value = mock_uploadtask
# mock add upload task action
mock_add_upload = mock.Mock()
data = []
mock_add_upload.return_value = data
mock_uploader.add_upload_task = mock_add_upload
# mock run tasks action
mock_run_tasks = mock.Mock()
mock_run_tasks.side_effect = OSError('Fail')
mock_uploader.run_tasks = mock_run_tasks
self.assertRaises(oscexc.CommandError,
self.cmd.take_action,
parsed_args)
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.UploadTask')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action_all_options(self, mock_manager, mock_task,
mock_get_uc_registry):
arglist = ['--registry-url', '127.0.0.1:8787',
'--append-tag', 'test',
'--source-username', 'sourceuser',
'--source-password', 'sourcepassword',
'--username', 'user',
'--password', 'password',
'--dry-run',
'--multi-arch',
'--cleanup',
'docker.io/namespace/foo:tag']
verifylist = [('registry_url', '127.0.0.1:8787'),
('append_tag', 'test'),
('username', 'user'),
('password', 'password'),
('dry_run', True),
('multi_arch', True),
('cleanup', True),
('image_to_push', 'docker.io/namespace/foo:tag')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
# mock upload task
mock_uploadtask = mock.Mock()
mock_task.return_value = mock_uploadtask
# mock add upload task action
mock_add_upload = mock.Mock()
data = []
mock_add_upload.return_value = data
mock_uploader.add_upload_task = mock_add_upload
# mock run tasks action
mock_run_tasks = mock.Mock()
mock_uploader.run_tasks = mock_run_tasks
self.cmd.take_action(parsed_args)
source_url = parse.urlparse("docker://docker.io/namespace/foo:tag")
registry_url = parse.urlparse("docker://127.0.0.1:8787")
auth_calls = [mock.call(source_url,
parsed_args.source_username,
parsed_args.source_password),
mock.call(registry_url,
parsed_args.username,
parsed_args.password)]
mock_uploader.authenticate.assert_has_calls(auth_calls)
mock_task.assert_not_called()
mock_add_upload.assert_not_called()
mock_run_tasks.assert_not_called()
class TestContainerImageDelete(TestPluginV1):
def setUp(self):
super(TestContainerImageDelete, self).setUp()
lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock')
self.mock_lock = lock.start()
self.addCleanup(lock.stop)
self.cmd = container_image.TripleOContainerImageDelete(self.app, None)
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_oserror(self, mock_manager, mock_get_uc_registry):
arglist = ['-y', 'foo']
verifylist = [('yes', True),
('image_to_delete', 'foo')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return url object from uploader._image_to_url
mock_url = mock.Mock()
mock_url.geturl.return_value = 'munged-reg-url'
mock_uploader._image_to_url.return_value = mock_url
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
mock_uploader.delete.side_effect = OSError('Errno 13')
self.assertRaises(oscexc.CommandError,
self.cmd.take_action,
parsed_args)
mock_uploader.delete.assert_called_once_with('foo',
session=mock_session)
class TestContainerImageList(TestPluginV1):
def setUp(self):
super(TestContainerImageList, self).setUp()
lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock')
self.mock_lock = lock.start()
self.addCleanup(lock.stop)
self.cmd = container_image.TripleOContainerImageList(self.app, None)
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action(self, mock_manager, mock_get_uc_registry):
arglist = []
verifylist = []
mock_manager.return_value.uploader.return_value.list.return_value = \
['a', 'b']
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
rv = self.cmd.take_action(parsed_args)
actual = (('Image Name',), [('a',), ('b',)])
self.assertEqual(actual, rv)
@mock.patch('tripleo_common.image.image_uploader.get_undercloud_registry',
return_value='uc.ctlplane.somedomain')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action_auth(self, mock_manager, mock_get_uc_registry):
# check arg parsing items
arglist = ['--registry-url', 'reg-url',
'--username', 'foo',
'--password', 'bar']
verifylist = [('registry_url', 'reg-url'),
('username', 'foo'),
('password', 'bar')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return url object from uploader._image_to_url
mock_url = mock.Mock()
mock_url.geturl.return_value = 'munged-reg-url'
mock_uploader._image_to_url.return_value = mock_url
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
# mock image list function
mock_uploader.list.return_value = ['a', 'b']
rv = self.cmd.take_action(parsed_args)
# check various functions are called with expected inputs
mock_mgr.uploader.assert_called_with('python')
mock_uploader._image_to_url.assert_called_with('reg-url')
mock_uploader.authenticate.assert_called_with(mock_url, 'foo', 'bar')
mock_uploader.list.assert_called_with('munged-reg-url',
session=mock_session)
# check data format for lister
actual = (('Image Name',), [('a',), ('b',)])
self.assertEqual(actual, rv)
class TestContainerImageShow(TestPluginV1):
def setUp(self):
super(TestContainerImageShow, self).setUp()
lock = mock.patch('tripleo_common.utils.locks.processlock.ProcessLock')
self.mock_lock = lock.start()
self.addCleanup(lock.stop)
self.cmd = container_image.TripleOContainerImageShow(self.app, None)
@mock.patch('tripleoclient.v1.container_image.TripleOContainerImageShow.'
'format_image_inspect')
@mock.patch('tripleo_common.image.image_uploader.ImageUploadManager')
def test_take_action(self, mock_manager, mock_formatter):
arglist = ['foo']
verifylist = [('image_to_inspect', 'foo')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# mock manager object
mock_mgr = mock.Mock()
mock_manager.return_value = mock_mgr
# mock uploader object
mock_uploader = mock.Mock()
mock_mgr.uploader.return_value = mock_uploader
# mock return url object from uploader._image_to_url
mock_url = mock.Mock()
mock_url.geturl.return_value = 'munged-reg-url'
mock_uploader._image_to_url.return_value = mock_url
# mock return session object from uploader.authenticate
mock_session = mock.Mock()
mock_uploader.authenticate.return_value = mock_session
mock_inspect = mock.Mock()
data = {'Name': 'a', 'Layers': 'b'}
mock_inspect.return_value = data
mock_uploader.inspect = mock_inspect
# mock format image inspect
formatted_data = (['Name', 'Layers'], ['a', 'b'])
mock_formatter.return_value = formatted_data
rv = self.cmd.take_action(parsed_args)
mock_formatter.assert_called_once_with(data)
self.assertEqual(formatted_data, rv)
def test_format_image_inspect(self):
test_data = {'Name': 'foo', 'Layers': 'bar'}
self.assertEqual(self.cmd.format_image_inspect(test_data),
(['Name', 'Layers'], ['foo', 'bar']))
class TestContainerImagePrepare(TestPluginV1):
def setUp(self):
super(TestContainerImagePrepare, self).setUp()
# Get the command object to test
self.cmd = container_image.PrepareImageFiles(self.app, None)
kolla_builder.DEFAULT_TEMPLATE_FILE = os.path.join(
'/tmp/overcloud_containers.yaml.j2'
)
self.roles_yaml = '''
- name: EnabledRole
CountDefault: 1
ServicesDefault:
- OS::TripleO::Services::AodhEvaluator
- name: RoleDisabledViaRolesData
CountDefault: 0
ServicesDefault:
- OS::TripleO::Services::AodhApi
- name: RoleDisabledViaEnvironment
CountDefault: 1
ServicesDefault:
- OS::TripleO::Services::Disabled
- name: RoleOverwrittenViaEnvironment
CountDefault: 1
ServicesDefault:
- OS::TripleO::Services::Overwritten
'''
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_defaults', create=True)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare', create=True)
@mock.patch('requests.get')
@mock.patch('tripleo_common.image.kolla_builder.'
'build_service_filter')
def test_container_image_prepare_noargs(self, mock_bsf, mock_get, mock_cip,
mock_cipd):
mock_bsf.return_value = None
mock_cipd.return_value = {
'neutron_driver': 'ovn',
'name_suffix': '',
'tag': 'latest',
'namespace': 'docker.io/tripleomaster',
'name_prefix':
'centos-binary-'
}
arglist = []
verifylist = []
mock_cip.return_value = {'container_images.yaml': {}}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
mock_cip.assert_called_with(
excludes=[],
includes=[],
mapping_args={
'neutron_driver': 'ovn',
'name_suffix': '',
'tag': 'latest',
'namespace': 'docker.io/tripleomaster',
'name_prefix':
'centos-binary-'
},
output_env_file=None,
output_images_file='container_images.yaml',
push_destination=None,
service_filter=None,
tag_from_label=None,
modify_role=None,
modify_vars=None,
append_tag=None,
template_file=kolla_builder.DEFAULT_TEMPLATE_FILE
)
@mock.patch('tripleoclient.utils.fetch_roles_file')
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare_defaults', create=True)
@mock.patch('tripleo_common.image.kolla_builder.'
'container_images_prepare', create=True)
@mock.patch('heatclient.common.template_utils.'
'process_multiple_environments_and_files')
@mock.patch('tripleo_common.image.kolla_builder.'
'build_service_filter')
@mock.patch('requests.get')
def test_container_image_prepare(self, mock_get, mock_bsf, pmef, mock_cip,
mock_cipd, mock_roles):
temp = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, temp)
images_file = os.path.join(temp, 'overcloud_containers.yaml')
env_file = os.path.join(temp, 'containers_env.yaml')
tmpl_file = os.path.join(temp, 'overcloud_containers.yaml.j2')
aodh_file = os.path.join(temp, 'docker', 'services', 'aodh.yaml')
roles_file = os.path.join(temp, 'roles_data.yaml')
with open(roles_file, 'w') as f:
f.write(self.roles_yaml)
modify_vars_file = os.path.join(temp, 'modify_vars.yaml')
with open(modify_vars_file, 'w') as f:
f.write('foo: bar')
mock_get.side_effect = requests.exceptions.SSLError('ouch')
mock_bsf.return_value = set(['OS::TripleO::Services::AodhEvaluator'])
resource_registry = {
'parameter_defaults': {
'NeutronMechanismDrivers': 'ovn',
},
'resource_registry': {
'OS::TripleO::Services::AodhEvaluator': aodh_file,
'OS::TripleO::Services::AodhApi': aodh_file
}
}
pmef.return_value = None, resource_registry
arglist = [
'--template-file',
tmpl_file,
'--tag',
'passed-ci',
'--namespace',
'192.0.2.0:8787/t',
'--prefix',
'os-',
'--suffix',
'foo',
'--output-images-file',
images_file,
'--output-env-file',
env_file,
'--set',
'ceph_namespace=myceph',
'--set',
'ceph_image=mydaemon',
'--set',
'ceph_tag=mytag',
'-e',
'environment/docker-ha.yaml',
'--roles-file',
roles_file,
'--modify-role',
'foo-role',
'--modify-vars',
modify_vars_file
]
self.cmd.app.command_options = arglist
verifylist = []
mock_cip.return_value = {images_file: [{
'imagename': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci',
}, {
'imagename': '192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci',
}], env_file: {
'DockerAodhApiImage':
'192.0.2.0:8787/t/os-aodh-apifoo:passed-ci',
'DockerAodhConfigImage':
'192.0.2.0:8787/t/os-aodh-apifoo:passed-ci',
'DockerAodhEvaluatorImage':
'192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci',
'DockerInsecureRegistryAddress': ['192.0.2.0:8787']
}
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
pmef.assert_called_once_with(['environment/docker-ha.yaml'],
env_path_is_object=mock.ANY,
object_request=mock.ANY)
mock_cip.assert_called_once_with(
excludes=[],
includes=[],
mapping_args={
'namespace': '192.0.2.0:8787/t',
'name_suffix': 'foo',
'ceph_tag': 'mytag',
'ceph_image': 'mydaemon',
'tag': 'passed-ci',
'neutron_driver': 'ovn',
'ceph_namespace': 'myceph',
'name_prefix': 'os-'
},
output_env_file=env_file,
output_images_file=images_file,
push_destination=None,
service_filter=set([
'OS::TripleO::Services::AodhEvaluator',
]),
tag_from_label=None,
modify_role='foo-role',
modify_vars={'foo': 'bar'},
append_tag=mock.ANY,
template_file=tmpl_file
)
ci_data = {
'container_images': [{
'imagename': '192.0.2.0:8787/t/os-aodh-apifoo:passed-ci',
}, {
'imagename': '192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci',
}]
}
env_data = {
'parameter_defaults': {
'DockerAodhApiImage':
'192.0.2.0:8787/t/os-aodh-apifoo:passed-ci',
'DockerAodhConfigImage':
'192.0.2.0:8787/t/os-aodh-apifoo:passed-ci',
'DockerAodhEvaluatorImage':
'192.0.2.0:8787/t/os-aodh-evaluatorfoo:passed-ci',
'DockerInsecureRegistryAddress': ['192.0.2.0:8787']
}
}
with open(images_file) as f:
self.assertEqual(ci_data, yaml.safe_load(f))
with open(env_file) as f:
self.assertEqual(env_data, yaml.safe_load(f))
class TestTripleoImagePrepare(TestPluginV1):
def setUp(self):
super(TestTripleoImagePrepare, self).setUp()
# Get the command object to test
self.cmd = container_image.TripleOImagePrepare(self.app, None)
self.cmd.app_args = mock.Mock()
self.cmd.app_args.verbose_level = 3
self.temp_dir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, self.temp_dir)
self.prepare_default_file = os.path.join(
self.temp_dir, 'prepare_env.yaml')
default_param = kolla_builder.CONTAINER_IMAGE_PREPARE_PARAM
self.default_env = {
'parameter_defaults': {
'ContainerImagePrepare': default_param
}
}
with open(self.prepare_default_file, 'w') as f:
yaml.safe_dump(self.default_env, f)
self.roles_yaml = '''
- name: EnabledRole
CountDefault: 1
ServicesDefault:
- OS::TripleO::Services::AodhEvaluator
- name: RoleDisabledViaRolesData
CountDefault: 0
ServicesDefault:
- OS::TripleO::Services::AodhApi
- name: RoleDisabledViaEnvironment
CountDefault: 1
ServicesDefault:
- OS::TripleO::Services::Disabled
- name: RoleOverwrittenViaEnvironment
CountDefault: 1
ServicesDefault:
- OS::TripleO::Services::Overwritten
'''
self.roles_data_file = os.path.join(
self.temp_dir, 'roles_data.yaml')
with open(self.roles_data_file, 'w') as f:
f.write(self.roles_yaml)
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_tripleo_container_image_prepare(self, mock_playbook):
env_file = os.path.join(self.temp_dir, 'containers_env.yaml')
arglist = [
'--environment-file', self.prepare_default_file,
'--roles-file', self.roles_data_file,
'--output-env-file', env_file
]
verifylist = []
self.app.command_options = [
'tripleo', 'container', 'image', 'prepare'
] + arglist
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
e_vars = {'roles_file': self.roles_data_file,
'environment_directories': [mock.ANY],
'environment_files': [self.temp_dir + '/prepare_env.yaml'],
'cleanup': 'full', 'dry_run': False,
'log_file': 'container_image_prepare.log', 'debug': True,
'output_env_file': self.temp_dir + '/containers_env.yaml'}
mock_playbook.assert_called_with(
extra_vars=e_vars,
inventory='localhost,',
playbook='cli-container-image-prepare.yaml',
playbook_dir='/usr/share/ansible/tripleo-playbooks',
verbosity=3, workdir=mock.ANY)
@mock.patch('tripleoclient.utils.rel_or_abs_path')
@mock.patch('tripleoclient.utils.run_ansible_playbook',
autospec=True)
def test_tripleo_container_image_prepare_paths(self, mock_playbook,
mock_path):
arglist = ['-e', 'foo.yaml',
'-e', '/bar.yaml',
'--environment-directory', 'foo',
'--environment-directory', '/bar',
'-r', 'foo.yaml']
verifylist = []
self.app.command_options = [
'tripleo', 'container', 'image', 'prepare'
] + arglist
mock_path.return_value = ('/usr/share/openstack-tripleo-heat-templates'
'/foo.yaml')
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
e_vars = {'roles_file': ('/usr/share/'
'openstack-tripleo-heat-templates/foo.yaml'),
'environment_directories': [
os.path.expanduser(constants.DEFAULT_ENV_DIRECTORY),
os.getcwd() + '/foo',
'/bar'
],
'environment_files': [
os.getcwd() + '/foo.yaml',
'/bar.yaml'
],
'cleanup': 'full', 'dry_run': False,
'log_file': 'container_image_prepare.log', 'debug': True}
mock_playbook.assert_called_with(
extra_vars=e_vars,
inventory='localhost,',
playbook='cli-container-image-prepare.yaml',
playbook_dir='/usr/share/ansible/tripleo-playbooks',
verbosity=3, workdir=mock.ANY)
class TestTripleoImagePrepareDefault(TestPluginV1):
def setUp(self):
super(TestTripleoImagePrepareDefault, self).setUp()
# Get the command object to test
self.cmd = container_image.TripleOImagePrepareDefault(self.app, None)
def test_prepare_default(self):
arglist = []
verifylist = []
self.app.command_options = [
'tripleo', 'container', 'image', 'prepare', 'default'
] + arglist
self.cmd.app.stdout = six.StringIO()
cmd = container_image.TripleOImagePrepareDefault(self.app, None)
parsed_args = self.check_parser(cmd, arglist, verifylist)
cmd.take_action(parsed_args)
result = self.app.stdout.getvalue()
expected_param = kolla_builder.CONTAINER_IMAGE_PREPARE_PARAM
expected = {
'parameter_defaults': {
'ContainerImagePrepare': expected_param
}
}
self.assertEqual(expected, yaml.safe_load(result))
def test_prepare_default_local_registry(self):
temp = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, temp)
env_file = os.path.join(temp, 'containers_env.yaml')
arglist = ['--local-push-destination', '--output-env-file', env_file]
verifylist = []
self.app.command_options = [
'tripleo', 'container', 'image', 'prepare', 'default'
] + arglist
cmd = container_image.TripleOImagePrepareDefault(self.app, None)
parsed_args = self.check_parser(cmd, arglist, verifylist)
cmd.take_action(parsed_args)
with open(env_file) as f:
result = yaml.safe_load(f)
self.assertEqual(
True,
result['parameter_defaults']['ContainerImagePrepare']
[0]['push_destination']
)
def test_prepare_default_registyr_login(self):
temp = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, temp)
env_file = os.path.join(temp, 'containers_env.yaml')
arglist = ['--enable-registry-login', '--output-env-file', env_file]
verifylist = []
self.app.command_options = [
'tripleo', 'container', 'image', 'prepare', 'default'
] + arglist
cmd = container_image.TripleOImagePrepareDefault(self.app, None)
parsed_args = self.check_parser(cmd, arglist, verifylist)
cmd.take_action(parsed_args)
with open(env_file) as f:
result = yaml.safe_load(f)
self.assertEqual(
True,
result['parameter_defaults']['ContainerImageRegistryLogin']
)
class TestContainerImageBuild(TestPluginV1):
def setUp(self):
super(TestContainerImageBuild, self).setUp()
# Get the command object to test
self.cmd = container_image.BuildImage(self.app, None)
self.cmd.app.stdout = six.StringIO()
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
self.default_kolla_conf = os.path.join(
sys.prefix, 'share', 'tripleo-common', 'container-images',
'tripleo_kolla_config_overrides.conf')
@mock.patch('sys.exit')
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True)
@mock.patch('os.makedirs')
def test_container_image_build_noargs(self, mock_mkdirs, mock_builder,
exit_mock):
arglist = []
verifylist = []
mock_builder.return_value.build_images.return_value = 'done'
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
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',
autospec=True)
@mock.patch('uuid.uuid4')
def test_container_image_build(self, mock_uuid, mock_builder):
arglist = [
'--config-file',
'/tmp/foo.yaml',
'--config-file',
'/tmp/bar.yaml',
'--work-dir',
self.temp_dir,
'--kolla-config-file',
'/tmp/kolla.conf'
]
verifylist = []
mock_builder.return_value.build_images.return_value = 'done'
mock_uuid.return_value = self.uuid
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
f, path = tempfile.mkstemp(dir=self.temp_dir)
with mock.patch('tempfile.mkstemp') as mock_mkstemp:
with mock.patch('os.chdir'):
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([
self.default_kolla_conf, '/tmp/kolla.conf',
path
], [], False, self.temp_dir_uuid)
@mock.patch('os.chdir')
@mock.patch('os.fdopen', autospec=True)
@mock.patch('tempfile.mkstemp')
@mock.patch(
'tripleoclient.utils.get_from_cfg')
@mock.patch(
'tripleoclient.utils.getboolean_from_cfg')
@mock.patch('tripleo_common.image.builder.buildah.BuildahBuilder',
autospec=True)
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True)
@mock.patch('tripleoclient.utils.get_read_config')
@mock.patch('os.remove')
def test_container_image_build_with_buildah(self, mock_remove,
mock_read_conf,
mock_builder, mock_buildah,
mock_kolla_boolean_cfg,
mock_kolla_cfg, mock_mkstemp,
mock_fdopen, mock_chdir):
arglist = [
'--config-file',
'/tmp/bar.yaml',
'--kolla-config-file',
'/tmp/kolla.conf',
'--use-buildah',
'--work-dir',
self.temp_dir,
]
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_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')
mock_read_conf.assert_any_call(cfg_files)
cfg_calls = [
mock.call(mock_read_conf.return_value, 'base'),
mock.call(mock_read_conf.return_value, 'type'),
mock.call(mock_read_conf.return_value, 'tag'),
mock.call(mock_read_conf.return_value, 'namespace'),
mock.call(mock_read_conf.return_value, 'registry'),
]
cfg_boolean_calls = [
mock.call(mock_read_conf.return_value, 'push'),
]
mock_kolla_cfg.assert_has_calls(cfg_calls)
mock_kolla_boolean_cfg.assert_has_calls(cfg_boolean_calls)
mock_bb.build_all.assert_called_once()
@mock.patch('tripleo_common.image.kolla_builder.KollaImageBuilder',
autospec=True)
@mock.patch('uuid.uuid4')
def test_container_image_build_with_exclude(self, mock_uuid, mock_builder):
arglist = [
'--config-file',
'/tmp/foo.yaml',
'--config-file',
'/tmp/bar.yaml',
'--kolla-config-file',
'/tmp/kolla.conf',
'--work-dir',
'/tmp/testing',
'--exclude',
'foo',
'--exclude',
'bar'
]
verifylist = []
mock_builder.return_value.build_images.return_value = 'done'
mock_uuid.return_value = '123'
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
f, path = tempfile.mkstemp(dir=self.temp_dir)
with mock.patch('tempfile.mkdtemp') as mock_mkd:
mock_mkd.return_value = '/tmp/testing'
with mock.patch('tempfile.mkstemp') as mock_mkstemp:
with mock.patch('os.chdir'):
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([
self.default_kolla_conf, '/tmp/kolla.conf',
path
], ['foo', 'bar'], False, '/tmp/testing/123')
@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',
'--work-dir',
'/tmp/testing',
'--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')
@mock.patch('os.makedirs')
def test_container_image_build_list_deps(self, mock_mkdirs, 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)