Add --platform support when uploading images
Adding --platform when uploading images will set a tripleo_platform image meta data property and prefix all images with the platform (and arch) to make them stand out in an openstack image list. Support is added in such a way that that image names are not altered if no --platform is specified. As platform really only makes sense *within* and architecture we ensure that both options are supplied. Blueprint: multiarch-support Change-Id: Ia56d22b244cfa5dddb5d110b54a525dfd80a7aaf
This commit is contained in:
parent
b5500956d3
commit
3e786fe832
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
In certain situations it may be desirable to provide optimised overcloud
|
||||
images for deployed nodes. In order to achieve this add a ``--platform``
|
||||
option to ``openstack overcloud image upload``. This option will then be
|
||||
used to select appropriate images based on the combination of architecture
|
||||
and platform.
|
@ -781,6 +781,17 @@ class TestOvercloudNameScenarios(TestWithScenarios):
|
||||
basename='overcloud-full',
|
||||
arch='x86_64',
|
||||
expected=('x86_64-overcloud-full-vmlinuz', '.vmlinuz'))),
|
||||
('kernel_arch_platform',
|
||||
dict(func=utils.overcloud_kernel,
|
||||
basename='overcloud-full',
|
||||
arch='x86_64',
|
||||
platform='SNB',
|
||||
expected=('SNB-x86_64-overcloud-full-vmlinuz', '.vmlinuz'))),
|
||||
('kernel_platform',
|
||||
dict(func=utils.overcloud_kernel,
|
||||
basename='overcloud-full',
|
||||
platform='SNB',
|
||||
expected=('overcloud-full-vmlinuz', '.vmlinuz'))),
|
||||
('ramdisk_default',
|
||||
dict(func=utils.overcloud_ramdisk,
|
||||
basename='overcloud-full',
|
||||
@ -790,6 +801,17 @@ class TestOvercloudNameScenarios(TestWithScenarios):
|
||||
basename='overcloud-full',
|
||||
arch='x86_64',
|
||||
expected=('x86_64-overcloud-full-initrd', '.initrd'))),
|
||||
('ramdisk_arch_platform',
|
||||
dict(func=utils.overcloud_ramdisk,
|
||||
basename='overcloud-full',
|
||||
arch='x86_64',
|
||||
platform='SNB',
|
||||
expected=('SNB-x86_64-overcloud-full-initrd', '.initrd'))),
|
||||
('ramdisk_platform',
|
||||
dict(func=utils.overcloud_ramdisk,
|
||||
basename='overcloud-full',
|
||||
platform='SNB',
|
||||
expected=('overcloud-full-initrd', '.initrd'))),
|
||||
('image_default',
|
||||
dict(func=utils.overcloud_image,
|
||||
basename='overcloud-full',
|
||||
@ -799,11 +821,22 @@ class TestOvercloudNameScenarios(TestWithScenarios):
|
||||
basename='overcloud-full',
|
||||
arch='x86_64',
|
||||
expected=('x86_64-overcloud-full', '.qcow2'))),
|
||||
('image_arch_platform',
|
||||
dict(func=utils.overcloud_image,
|
||||
basename='overcloud-full',
|
||||
arch='x86_64',
|
||||
platform='SNB',
|
||||
expected=('SNB-x86_64-overcloud-full', '.qcow2'))),
|
||||
('image_platform',
|
||||
dict(func=utils.overcloud_image,
|
||||
basename='overcloud-full',
|
||||
platform='SNB',
|
||||
expected=('overcloud-full', '.qcow2'))),
|
||||
]
|
||||
|
||||
def test_overcloud_params(self):
|
||||
kwargs = dict()
|
||||
for attr in ['arch']:
|
||||
for attr in ['arch', 'platform']:
|
||||
if hasattr(self, attr):
|
||||
kwargs[attr] = getattr(self, attr)
|
||||
|
||||
@ -824,6 +857,15 @@ class TestDeployNameScenarios(TestWithScenarios):
|
||||
dict(func=utils.deploy_kernel,
|
||||
arch='x86_64',
|
||||
expected=('x86_64-bm-deploy-kernel', '.kernel'))),
|
||||
('kernel_arch_platform',
|
||||
dict(func=utils.deploy_kernel,
|
||||
arch='x86_64',
|
||||
platform='SNB',
|
||||
expected=('SNB-x86_64-bm-deploy-kernel', '.kernel'))),
|
||||
('kernel_platform',
|
||||
dict(func=utils.deploy_kernel,
|
||||
platform='SNB',
|
||||
expected=('bm-deploy-kernel', '.kernel'))),
|
||||
('ramdisk_default',
|
||||
dict(func=utils.deploy_ramdisk,
|
||||
expected=('bm-deploy-ramdisk', '.initramfs'))),
|
||||
@ -831,11 +873,20 @@ class TestDeployNameScenarios(TestWithScenarios):
|
||||
dict(func=utils.deploy_ramdisk,
|
||||
arch='x86_64',
|
||||
expected=('x86_64-bm-deploy-ramdisk', '.initramfs'))),
|
||||
('ramdisk_arch_platform',
|
||||
dict(func=utils.deploy_ramdisk,
|
||||
arch='x86_64',
|
||||
platform='SNB',
|
||||
expected=('SNB-x86_64-bm-deploy-ramdisk', '.initramfs'))),
|
||||
('ramdisk_platform',
|
||||
dict(func=utils.deploy_ramdisk,
|
||||
platform='SNB',
|
||||
expected=('bm-deploy-ramdisk', '.initramfs'))),
|
||||
]
|
||||
|
||||
def test_deploy_params(self):
|
||||
kwargs = {}
|
||||
for attr in ['arch']:
|
||||
for attr in ['arch', 'platform']:
|
||||
if hasattr(self, attr):
|
||||
kwargs[attr] = getattr(self, attr)
|
||||
|
||||
|
@ -209,6 +209,12 @@ class TestUploadOvercloudImage(TestPluginV1):
|
||||
self.cmd._copy_file.call_count
|
||||
)
|
||||
|
||||
def test_platform_without_architecture_fail(self):
|
||||
parsed_args = self.check_parser(self.cmd, ['--platform', 'SNB'], [])
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
self.cmd.take_action,
|
||||
parsed_args)
|
||||
|
||||
@mock.patch('os.path.isfile', autospec=True)
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_overcloud_create_images_v2(self, mock_subprocess_call,
|
||||
@ -644,6 +650,9 @@ class TestUploadOvercloudImageFullMultiArch(TestPluginV1):
|
||||
mock.Mock(id=13, name='ppc64le-overcloud-full'),
|
||||
mock.Mock(id=14, name='ppc64le-bm-deploy-kernel'),
|
||||
mock.Mock(id=15, name='ppc64le-bm-deploy-initrd'),
|
||||
mock.Mock(id=16, name='p9-ppc64le-overcloud-full'),
|
||||
mock.Mock(id=17, name='p9-ppc64le-bm-deploy-kernel'),
|
||||
mock.Mock(id=18, name='p9-ppc64le-bm-deploy-initrd'),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
@ -738,3 +747,108 @@ class TestUploadOvercloudImageFullMultiArch(TestPluginV1):
|
||||
mock.call('sudo cp -f "./ironic-python-agent.initramfs" '
|
||||
'"/httpboot/ppc64le/agent.ramdisk"', shell=True),
|
||||
])
|
||||
|
||||
@mock.patch('os.path.isfile', autospec=True)
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_overcloud_create_images_with_arch_and_pltform(self,
|
||||
mock_subprocess,
|
||||
mock_isfile):
|
||||
mock_isfile.return_value = False
|
||||
|
||||
self.cmd._get_image = mock.Mock(return_value=None)
|
||||
mock.patch
|
||||
|
||||
parsed_args = self.check_parser(self.cmd,
|
||||
['--whole-disk'],
|
||||
[])
|
||||
self.cmd.take_action(parsed_args)
|
||||
parsed_args = self.check_parser(self.cmd,
|
||||
['--whole-disk',
|
||||
'--http-boot', '/httpboot/ppc64le',
|
||||
'--architecture', 'ppc64le'],
|
||||
[])
|
||||
self.cmd.take_action(parsed_args)
|
||||
parsed_args = self.check_parser(self.cmd,
|
||||
['--whole-disk',
|
||||
'--http-boot', '/httpboot/p9-ppc64le',
|
||||
'--architecture', 'ppc64le',
|
||||
'--platform', 'p9'],
|
||||
[])
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.delete.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
9,
|
||||
self.app.client_manager.image.images.create.call_count
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
[mock.call(name='overcloud-full',
|
||||
disk_format='qcow2',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='bm-deploy-kernel',
|
||||
disk_format='aki',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='bm-deploy-ramdisk',
|
||||
disk_format='ari',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='ppc64le-overcloud-full',
|
||||
disk_format='qcow2',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='ppc64le-bm-deploy-kernel',
|
||||
disk_format='aki',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='ppc64le-bm-deploy-ramdisk',
|
||||
disk_format='ari',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='p9-ppc64le-overcloud-full',
|
||||
disk_format='qcow2',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='p9-ppc64le-bm-deploy-kernel',
|
||||
disk_format='aki',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='p9-ppc64le-bm-deploy-ramdisk',
|
||||
disk_format='ari',
|
||||
container_format='bare',
|
||||
visibility='public')
|
||||
], self.app.client_manager.image.images.create.call_args_list
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
[mock.call(13, hw_architecture='ppc64le'),
|
||||
mock.call(14, hw_architecture='ppc64le'),
|
||||
mock.call(15, hw_architecture='ppc64le'),
|
||||
mock.call(16, hw_architecture='ppc64le', tripleo_platform='p9'),
|
||||
mock.call(17, hw_architecture='ppc64le', tripleo_platform='p9'),
|
||||
mock.call(18, hw_architecture='ppc64le', tripleo_platform='p9'),
|
||||
], self.app.client_manager.image.images.update.call_args_list
|
||||
)
|
||||
self.assertEqual(mock_subprocess.call_count, 6)
|
||||
# FIXME(tonyb): this is the wrong way around
|
||||
self.assertEqual(
|
||||
mock_subprocess.call_args_list, [
|
||||
mock.call('sudo cp -f "./ironic-python-agent.kernel" '
|
||||
'"/httpboot/agent.kernel"', shell=True),
|
||||
mock.call('sudo cp -f "./ironic-python-agent.initramfs" '
|
||||
'"/httpboot/agent.ramdisk"', shell=True),
|
||||
mock.call('sudo cp -f "./ironic-python-agent.kernel" '
|
||||
'"/httpboot/ppc64le/agent.kernel"', shell=True),
|
||||
mock.call('sudo cp -f "./ironic-python-agent.initramfs" '
|
||||
'"/httpboot/ppc64le/agent.ramdisk"', shell=True),
|
||||
# FIXME(tonyb): wrong
|
||||
mock.call('sudo cp -f "./ironic-python-agent.kernel" '
|
||||
'"/httpboot/p9-ppc64le/agent.kernel"', shell=True),
|
||||
mock.call('sudo cp -f "./ironic-python-agent.initramfs" '
|
||||
'"/httpboot/p9-ppc64le/agent.ramdisk"', shell=True),
|
||||
])
|
||||
|
@ -1186,32 +1186,39 @@ def configure_logging(log, level, log_file):
|
||||
log.addHandler(fhandler)
|
||||
|
||||
|
||||
def _name_helper(basename, arch=None):
|
||||
if arch:
|
||||
def _name_helper(basename, arch=None, platform=None):
|
||||
# NOTE(tonyb): We don't accept a platform with an arch. This caught when
|
||||
# import the nodes / process args, but lets be a little cautious here
|
||||
# anyway.
|
||||
if arch and platform:
|
||||
basename = platform + '-' + arch + '-' + basename
|
||||
elif arch:
|
||||
basename = arch + '-' + basename
|
||||
return basename
|
||||
|
||||
|
||||
def overcloud_kernel(basename, arch=None):
|
||||
return (_name_helper('%s-vmlinuz' % basename, arch=arch),
|
||||
def overcloud_kernel(basename, arch=None, platform=None):
|
||||
return (_name_helper('%s-vmlinuz' % basename, arch=arch,
|
||||
platform=platform),
|
||||
'.vmlinuz')
|
||||
|
||||
|
||||
def overcloud_ramdisk(basename, arch=None):
|
||||
return (_name_helper('%s-initrd' % basename, arch=arch),
|
||||
def overcloud_ramdisk(basename, arch=None, platform=None):
|
||||
return (_name_helper('%s-initrd' % basename, arch=arch,
|
||||
platform=platform),
|
||||
'.initrd')
|
||||
|
||||
|
||||
def overcloud_image(basename, arch=None):
|
||||
return (_name_helper(basename, arch=arch),
|
||||
def overcloud_image(basename, arch=None, platform=None):
|
||||
return (_name_helper(basename, arch=arch, platform=platform),
|
||||
'.qcow2')
|
||||
|
||||
|
||||
def deploy_kernel(arch=None):
|
||||
return (_name_helper('bm-deploy-kernel', arch=arch),
|
||||
def deploy_kernel(arch=None, platform=None):
|
||||
return (_name_helper('bm-deploy-kernel', arch=arch, platform=platform),
|
||||
'.kernel')
|
||||
|
||||
|
||||
def deploy_ramdisk(arch=None):
|
||||
return (_name_helper('bm-deploy-ramdisk', arch=arch),
|
||||
def deploy_ramdisk(arch=None, platform=None):
|
||||
return (_name_helper('bm-deploy-ramdisk', arch=arch, platform=platform),
|
||||
'.initramfs')
|
||||
|
@ -282,12 +282,24 @@ class UploadOvercloudImage(command.Command):
|
||||
"are common options. This option should match at least "
|
||||
"one \'arch\' value in instackenv.json"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--platform",
|
||||
help=_("Platform type for these images. Platform is a "
|
||||
"sub-category of architecture. For example you may have "
|
||||
"generic images for x86_64 but offer images specific to "
|
||||
"SandyBridge (SNB)."),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
glance_client_adaptor = self._get_glance_client_adaptor()
|
||||
|
||||
if parsed_args.platform and not parsed_args.architecture:
|
||||
raise exceptions.CommandError('You supplied a platform (%s) '
|
||||
'without specifying the '
|
||||
'architecture')
|
||||
|
||||
self.log.debug("checking if image files exist")
|
||||
|
||||
if parsed_args.whole_disk:
|
||||
@ -316,12 +328,15 @@ class UploadOvercloudImage(command.Command):
|
||||
arch = parsed_args.architecture
|
||||
if arch:
|
||||
properties['hw_architecture'] = arch
|
||||
platform = parsed_args.platform
|
||||
if platform:
|
||||
properties['tripleo_platform'] = platform
|
||||
|
||||
# vmlinuz and initrd only need to be uploaded for a partition image
|
||||
if not parsed_args.whole_disk:
|
||||
(oc_vmlinuz_name,
|
||||
oc_vmlinuz_extension) = plugin_utils.overcloud_kernel(image_name,
|
||||
arch=arch)
|
||||
oc_vmlinuz_extension) = plugin_utils.overcloud_kernel(
|
||||
image_name, arch=arch, platform=platform)
|
||||
oc_vmlinuz_file = os.path.join(parsed_args.image_path,
|
||||
image_name +
|
||||
oc_vmlinuz_extension)
|
||||
@ -338,8 +353,8 @@ class UploadOvercloudImage(command.Command):
|
||||
))
|
||||
|
||||
(oc_initrd_name,
|
||||
oc_initrd_extension) = plugin_utils.overcloud_ramdisk(image_name,
|
||||
arch=arch)
|
||||
oc_initrd_extension) = plugin_utils.overcloud_ramdisk(
|
||||
image_name, arch=arch, platform=platform)
|
||||
oc_initrd_file = os.path.join(parsed_args.image_path,
|
||||
image_name +
|
||||
oc_initrd_extension)
|
||||
@ -356,8 +371,8 @@ class UploadOvercloudImage(command.Command):
|
||||
))
|
||||
|
||||
(oc_name,
|
||||
oc_extension) = plugin_utils.overcloud_image(image_name,
|
||||
arch=arch)
|
||||
oc_extension) = plugin_utils.overcloud_image(
|
||||
image_name, arch=arch, platform=platform)
|
||||
oc_file = os.path.join(parsed_args.image_path,
|
||||
image_name +
|
||||
oc_extension)
|
||||
@ -387,8 +402,8 @@ class UploadOvercloudImage(command.Command):
|
||||
|
||||
else:
|
||||
(oc_name,
|
||||
oc_extension) = plugin_utils.overcloud_image(image_name,
|
||||
arch=arch)
|
||||
oc_extension) = plugin_utils.overcloud_image(
|
||||
image_name, arch=arch, platform=platform)
|
||||
oc_file = os.path.join(parsed_args.image_path,
|
||||
image_name +
|
||||
oc_extension)
|
||||
@ -407,7 +422,8 @@ class UploadOvercloudImage(command.Command):
|
||||
self.log.debug("uploading bm images to glance")
|
||||
|
||||
(deploy_kernel_name,
|
||||
deploy_kernel_extension) = plugin_utils.deploy_kernel(arch=arch)
|
||||
deploy_kernel_extension) = plugin_utils.deploy_kernel(
|
||||
arch=arch, platform=platform)
|
||||
deploy_kernel_file = os.path.join(parsed_args.image_path,
|
||||
parsed_args.ipa_name +
|
||||
deploy_kernel_extension)
|
||||
@ -423,7 +439,8 @@ class UploadOvercloudImage(command.Command):
|
||||
deploy_kernel_file))
|
||||
|
||||
(deploy_ramdisk_name,
|
||||
deploy_ramdisk_extension) = plugin_utils.deploy_ramdisk(arch=arch)
|
||||
deploy_ramdisk_extension) = plugin_utils.deploy_ramdisk(
|
||||
arch=arch, platform=platform)
|
||||
deploy_ramdisk_file = os.path.join(parsed_args.image_path,
|
||||
parsed_args.ipa_name +
|
||||
deploy_ramdisk_extension)
|
||||
@ -439,6 +456,9 @@ class UploadOvercloudImage(command.Command):
|
||||
|
||||
self.log.debug("copy agent images to HTTP BOOT dir")
|
||||
|
||||
# TODO(tonyb) Decide how to handle platform specific httpboot
|
||||
# files/names
|
||||
|
||||
self._file_create_or_update(
|
||||
os.path.join(parsed_args.image_path,
|
||||
'%s.kernel' % parsed_args.ipa_name),
|
||||
|
Loading…
x
Reference in New Issue
Block a user