Allow to specify the image type to upload
When trying to just replace a single image in the overcloud, the client is asking for all the images to be present in the working directory. Allowing to pass an image-type flag (with os/ipa values), that will restrict the upload to that type. Change-Id: I4e48458f83d2a646aad873b0577dc3bea766d2d7 Fixes-Bug: #1778500
This commit is contained in:
parent
fa372dee34
commit
84a270a418
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add a new feature called image-type, that accepts 'os' and
|
||||||
|
'ironic-python-agent' values.
|
||||||
|
When specified, it restricts the image to upload to that type, making it
|
||||||
|
easier to replace ipa/os images without having to collect the full set in
|
||||||
|
our working directory.
|
|
@ -831,3 +831,120 @@ class TestUploadOvercloudImageFullMultiArch(TestPluginV1):
|
||||||
mock.call('sudo cp -f "./ironic-python-agent.initramfs" '
|
mock.call('sudo cp -f "./ironic-python-agent.initramfs" '
|
||||||
'"/httpboot/p9-ppc64le/agent.ramdisk"', shell=True),
|
'"/httpboot/p9-ppc64le/agent.ramdisk"', shell=True),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class TestUploadOnlyExisting(TestPluginV1):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestUploadOnlyExisting, self).setUp()
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = overcloud_image.UploadOvercloudImage(self.app, None)
|
||||||
|
self.app.client_manager.image = mock.Mock()
|
||||||
|
self.app.client_manager.image.version = 2.0
|
||||||
|
self.app.client_manager.image.images.create.return_value = (
|
||||||
|
mock.Mock(id=10, name='imgname', properties={},
|
||||||
|
created_at='2015-07-31T14:37:22.000000'))
|
||||||
|
self.cmd._check_file_exists = mock.Mock()
|
||||||
|
self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA')
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call', autospec=True)
|
||||||
|
@mock.patch('os.path.isfile', autospec=True)
|
||||||
|
def test_overcloud_upload_just_ipa_wholedisk(
|
||||||
|
self, mock_isfile_call, mock_subprocess_call):
|
||||||
|
self.cmd._image_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd._image_try_update = mock.Mock(return_value=None)
|
||||||
|
self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA')
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(
|
||||||
|
self.cmd, ['--whole-disk', '--image-type=ironic-python-agent'], [])
|
||||||
|
|
||||||
|
self.cmd._files_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# ensure check_file_exists has not been called
|
||||||
|
self.assertItemsEqual(self.cmd._check_file_exists.call_args_list,
|
||||||
|
[mock.call('./ironic-python-agent.initramfs'),
|
||||||
|
mock.call('./ironic-python-agent.kernel')])
|
||||||
|
|
||||||
|
# ensure try_update has been called just with ipa
|
||||||
|
files = []
|
||||||
|
for item in self.cmd._image_try_update.call_args_list:
|
||||||
|
files.append(item[0][1])
|
||||||
|
self.assertEqual(files, ['./ironic-python-agent.kernel',
|
||||||
|
'./ironic-python-agent.initramfs'])
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call', autospec=True)
|
||||||
|
@mock.patch('os.path.isfile', autospec=True)
|
||||||
|
def test_overcloud_upload_just_os_wholedisk(
|
||||||
|
self, mock_isfile_call, mock_subprocess_call):
|
||||||
|
self.cmd._image_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd._image_try_update = mock.Mock(return_value=None)
|
||||||
|
self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA')
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(
|
||||||
|
self.cmd, ['--whole-disk', '--image-type=os'], [])
|
||||||
|
|
||||||
|
self.cmd._files_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# ensure check_file_exists has been called just with ipa
|
||||||
|
self.assertItemsEqual(self.cmd._check_file_exists.call_args_list,
|
||||||
|
[mock.call('./overcloud-full.qcow2')])
|
||||||
|
|
||||||
|
# ensure try_update has been called just with ipa
|
||||||
|
files = []
|
||||||
|
for item in self.cmd._image_try_update.call_args_list:
|
||||||
|
files.append(item[0][1])
|
||||||
|
self.assertEqual(files, ['./overcloud-full.qcow2'])
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call', autospec=True)
|
||||||
|
@mock.patch('os.path.isfile', autospec=True)
|
||||||
|
def test_overcloud_upload_just_ipa(
|
||||||
|
self, mock_isfile_call, mock_subprocess_call):
|
||||||
|
self.cmd._image_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd._image_try_update = mock.Mock(return_value=None)
|
||||||
|
self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA')
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(
|
||||||
|
self.cmd, ['--image-type=ironic-python-agent'], [])
|
||||||
|
|
||||||
|
self.cmd._files_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# ensure check_file_exists has been called just with ipa
|
||||||
|
self.assertItemsEqual(self.cmd._check_file_exists.call_args_list,
|
||||||
|
[mock.call('./ironic-python-agent.initramfs'),
|
||||||
|
mock.call('./ironic-python-agent.kernel')])
|
||||||
|
|
||||||
|
# ensure try_update has been called just with ipa
|
||||||
|
files = []
|
||||||
|
for item in self.cmd._image_try_update.call_args_list:
|
||||||
|
files.append(item[0][1])
|
||||||
|
self.assertEqual(files, ['./ironic-python-agent.kernel',
|
||||||
|
'./ironic-python-agent.initramfs'])
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call', autospec=True)
|
||||||
|
@mock.patch('os.path.isfile', autospec=True)
|
||||||
|
def test_overcloud_upload_just_os(
|
||||||
|
self, mock_isfile_call, mock_subprocess_call):
|
||||||
|
self.cmd._image_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd._image_try_update = mock.Mock(return_value=None)
|
||||||
|
self.cmd._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA')
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(
|
||||||
|
self.cmd, ['--image-type=os'], [])
|
||||||
|
|
||||||
|
self.cmd._files_changed = mock.Mock(return_value=True)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# ensure check_file_exists has been called just with ipa
|
||||||
|
self.assertItemsEqual(self.cmd._check_file_exists.call_args_list,
|
||||||
|
[mock.call('./overcloud-full.qcow2')])
|
||||||
|
|
||||||
|
# ensure try_update has been called just with ipa
|
||||||
|
files = []
|
||||||
|
for item in self.cmd._image_try_update.call_args_list:
|
||||||
|
files.append(item[0][1])
|
||||||
|
self.assertEqual(files, ['./overcloud-full.vmlinuz',
|
||||||
|
'./overcloud-full.initrd',
|
||||||
|
'./overcloud-full.qcow2'])
|
||||||
|
|
|
@ -289,6 +289,14 @@ class UploadOvercloudImage(command.Command):
|
||||||
"generic images for x86_64 but offer images specific to "
|
"generic images for x86_64 but offer images specific to "
|
||||||
"SandyBridge (SNB)."),
|
"SandyBridge (SNB)."),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--image-type",
|
||||||
|
dest="image_type",
|
||||||
|
choices=["os", "ironic-python-agent"],
|
||||||
|
help=_("If specified, allows to restrict the image type to upload "
|
||||||
|
"(os for the overcloud image or ironic-python-agent for "
|
||||||
|
"the ironic-python-agent one)"),
|
||||||
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
|
@ -302,17 +310,18 @@ class UploadOvercloudImage(command.Command):
|
||||||
|
|
||||||
self.log.debug("checking if image files exist")
|
self.log.debug("checking if image files exist")
|
||||||
|
|
||||||
|
image_files = []
|
||||||
|
if parsed_args.image_type is None or \
|
||||||
|
parsed_args.image_type == 'ironic-python-agent':
|
||||||
|
image_files.append('%s.initramfs' % parsed_args.ipa_name)
|
||||||
|
image_files.append('%s.kernel' % parsed_args.ipa_name)
|
||||||
|
|
||||||
|
if parsed_args.image_type is None or parsed_args.image_type == 'os':
|
||||||
|
image_files.append(parsed_args.os_image_name)
|
||||||
|
|
||||||
if parsed_args.whole_disk:
|
if parsed_args.whole_disk:
|
||||||
image_files = [
|
|
||||||
parsed_args.os_image_name
|
|
||||||
]
|
|
||||||
overcloud_image_type = 'whole disk'
|
overcloud_image_type = 'whole disk'
|
||||||
else:
|
else:
|
||||||
image_files = [
|
|
||||||
'%s.initramfs' % parsed_args.ipa_name,
|
|
||||||
'%s.kernel' % parsed_args.ipa_name,
|
|
||||||
parsed_args.os_image_name
|
|
||||||
]
|
|
||||||
overcloud_image_type = 'partition'
|
overcloud_image_type = 'partition'
|
||||||
|
|
||||||
for image in image_files:
|
for image in image_files:
|
||||||
|
@ -332,143 +341,149 @@ class UploadOvercloudImage(command.Command):
|
||||||
if platform:
|
if platform:
|
||||||
properties['tripleo_platform'] = platform
|
properties['tripleo_platform'] = platform
|
||||||
|
|
||||||
# vmlinuz and initrd only need to be uploaded for a partition image
|
if parsed_args.image_type is None or parsed_args.image_type == 'os':
|
||||||
if not parsed_args.whole_disk:
|
# vmlinuz and initrd only need to be uploaded for a partition image
|
||||||
(oc_vmlinuz_name,
|
if not parsed_args.whole_disk:
|
||||||
oc_vmlinuz_extension) = plugin_utils.overcloud_kernel(
|
(oc_vmlinuz_name,
|
||||||
image_name, arch=arch, platform=platform)
|
oc_vmlinuz_extension) = plugin_utils.overcloud_kernel(
|
||||||
oc_vmlinuz_file = os.path.join(parsed_args.image_path,
|
image_name, arch=arch, platform=platform)
|
||||||
image_name +
|
oc_vmlinuz_file = os.path.join(parsed_args.image_path,
|
||||||
oc_vmlinuz_extension)
|
image_name +
|
||||||
kernel = (self._image_try_update(oc_vmlinuz_name,
|
oc_vmlinuz_extension)
|
||||||
oc_vmlinuz_file,
|
kernel = (self._image_try_update(oc_vmlinuz_name,
|
||||||
parsed_args) or
|
oc_vmlinuz_file,
|
||||||
glance_client_adaptor.upload_image(
|
parsed_args) or
|
||||||
name=oc_vmlinuz_name,
|
glance_client_adaptor.upload_image(
|
||||||
is_public=True,
|
name=oc_vmlinuz_name,
|
||||||
disk_format='aki',
|
is_public=True,
|
||||||
properties=properties,
|
disk_format='aki',
|
||||||
data=self._read_image_file_pointer(
|
properties=properties,
|
||||||
parsed_args.image_path, oc_vmlinuz_file)
|
data=self._read_image_file_pointer(
|
||||||
))
|
parsed_args.image_path, oc_vmlinuz_file)
|
||||||
|
))
|
||||||
|
|
||||||
(oc_initrd_name,
|
(oc_initrd_name,
|
||||||
oc_initrd_extension) = plugin_utils.overcloud_ramdisk(
|
oc_initrd_extension) = plugin_utils.overcloud_ramdisk(
|
||||||
image_name, arch=arch, platform=platform)
|
image_name, arch=arch, platform=platform)
|
||||||
oc_initrd_file = os.path.join(parsed_args.image_path,
|
oc_initrd_file = os.path.join(parsed_args.image_path,
|
||||||
image_name +
|
image_name +
|
||||||
oc_initrd_extension)
|
oc_initrd_extension)
|
||||||
ramdisk = (self._image_try_update(oc_initrd_name,
|
ramdisk = (self._image_try_update(oc_initrd_name,
|
||||||
oc_initrd_file,
|
oc_initrd_file,
|
||||||
parsed_args) or
|
parsed_args) or
|
||||||
glance_client_adaptor.upload_image(
|
glance_client_adaptor.upload_image(
|
||||||
name=oc_initrd_name,
|
name=oc_initrd_name,
|
||||||
is_public=True,
|
is_public=True,
|
||||||
disk_format='ari',
|
disk_format='ari',
|
||||||
properties=properties,
|
properties=properties,
|
||||||
data=self._read_image_file_pointer(
|
data=self._read_image_file_pointer(
|
||||||
parsed_args.image_path, oc_initrd_file)
|
parsed_args.image_path, oc_initrd_file)
|
||||||
))
|
))
|
||||||
|
|
||||||
(oc_name,
|
(oc_name,
|
||||||
oc_extension) = plugin_utils.overcloud_image(
|
oc_extension) = plugin_utils.overcloud_image(
|
||||||
image_name, arch=arch, platform=platform)
|
image_name, arch=arch, platform=platform)
|
||||||
oc_file = os.path.join(parsed_args.image_path,
|
oc_file = os.path.join(parsed_args.image_path,
|
||||||
image_name +
|
image_name +
|
||||||
oc_extension)
|
oc_extension)
|
||||||
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
||||||
parsed_args) or
|
parsed_args) or
|
||||||
glance_client_adaptor.upload_image(
|
glance_client_adaptor.upload_image(
|
||||||
name=oc_name,
|
name=oc_name,
|
||||||
is_public=True,
|
is_public=True,
|
||||||
disk_format='qcow2',
|
disk_format='qcow2',
|
||||||
container_format='bare',
|
container_format='bare',
|
||||||
properties=dict({'kernel_id': kernel.id,
|
properties=dict(
|
||||||
'ramdisk_id': ramdisk.id},
|
{'kernel_id': kernel.id,
|
||||||
**properties),
|
'ramdisk_id': ramdisk.id},
|
||||||
data=self._read_image_file_pointer(
|
**properties),
|
||||||
parsed_args.image_path, oc_file)
|
data=self._read_image_file_pointer(
|
||||||
))
|
parsed_args.image_path, oc_file)
|
||||||
|
))
|
||||||
|
|
||||||
img_kernel_id = glance_client_adaptor.get_image_property(
|
img_kernel_id = glance_client_adaptor.get_image_property(
|
||||||
overcloud_image, 'kernel_id')
|
overcloud_image, 'kernel_id')
|
||||||
img_ramdisk_id = glance_client_adaptor.get_image_property(
|
img_ramdisk_id = glance_client_adaptor.get_image_property(
|
||||||
overcloud_image, 'ramdisk_id')
|
overcloud_image, 'ramdisk_id')
|
||||||
# check overcloud image links
|
# check overcloud image links
|
||||||
if (img_kernel_id != kernel.id or img_ramdisk_id != ramdisk.id):
|
if (img_kernel_id != kernel.id or
|
||||||
self.log.error('Link overcloud image to it\'s initrd and '
|
img_ramdisk_id != ramdisk.id):
|
||||||
'kernel images is MISSING OR leads to OLD '
|
self.log.error('Link overcloud image to it\'s initrd and '
|
||||||
'image. You can keep it or fix it manually.')
|
'kernel images is MISSING OR leads to OLD '
|
||||||
|
'image. You can keep it or fix it '
|
||||||
|
'manually.')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
(oc_name,
|
(oc_name,
|
||||||
oc_extension) = plugin_utils.overcloud_image(
|
oc_extension) = plugin_utils.overcloud_image(
|
||||||
image_name, arch=arch, platform=platform)
|
image_name, arch=arch, platform=platform)
|
||||||
oc_file = os.path.join(parsed_args.image_path,
|
oc_file = os.path.join(parsed_args.image_path,
|
||||||
image_name +
|
image_name +
|
||||||
oc_extension)
|
oc_extension)
|
||||||
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
||||||
parsed_args) or
|
parsed_args) or
|
||||||
glance_client_adaptor.upload_image(
|
glance_client_adaptor.upload_image(
|
||||||
name=oc_name,
|
name=oc_name,
|
||||||
is_public=True,
|
is_public=True,
|
||||||
disk_format='qcow2',
|
disk_format='qcow2',
|
||||||
container_format='bare',
|
container_format='bare',
|
||||||
properties=properties,
|
properties=properties,
|
||||||
data=self._read_image_file_pointer(
|
data=self._read_image_file_pointer(
|
||||||
parsed_args.image_path, oc_file)
|
parsed_args.image_path, oc_file)
|
||||||
))
|
))
|
||||||
|
|
||||||
self.log.debug("uploading bm images to glance")
|
self.log.debug("uploading bm images to glance")
|
||||||
|
|
||||||
(deploy_kernel_name,
|
if parsed_args.image_type is None or \
|
||||||
deploy_kernel_extension) = plugin_utils.deploy_kernel(
|
parsed_args.image_type == 'ironic-python-agent':
|
||||||
arch=arch, platform=platform)
|
(deploy_kernel_name,
|
||||||
deploy_kernel_file = os.path.join(parsed_args.image_path,
|
deploy_kernel_extension) = plugin_utils.deploy_kernel(
|
||||||
parsed_args.ipa_name +
|
arch=arch, platform=platform)
|
||||||
deploy_kernel_extension)
|
deploy_kernel_file = os.path.join(parsed_args.image_path,
|
||||||
self._image_try_update(deploy_kernel_name, deploy_kernel_file,
|
parsed_args.ipa_name +
|
||||||
parsed_args) or \
|
deploy_kernel_extension)
|
||||||
glance_client_adaptor.upload_image(
|
self._image_try_update(deploy_kernel_name, deploy_kernel_file,
|
||||||
name=deploy_kernel_name,
|
parsed_args) or \
|
||||||
is_public=True,
|
glance_client_adaptor.upload_image(
|
||||||
disk_format='aki',
|
name=deploy_kernel_name,
|
||||||
properties=properties,
|
is_public=True,
|
||||||
data=self._read_image_file_pointer(
|
disk_format='aki',
|
||||||
parsed_args.image_path,
|
properties=properties,
|
||||||
deploy_kernel_file))
|
data=self._read_image_file_pointer(
|
||||||
|
parsed_args.image_path,
|
||||||
|
deploy_kernel_file))
|
||||||
|
|
||||||
(deploy_ramdisk_name,
|
(deploy_ramdisk_name,
|
||||||
deploy_ramdisk_extension) = plugin_utils.deploy_ramdisk(
|
deploy_ramdisk_extension) = plugin_utils.deploy_ramdisk(
|
||||||
arch=arch, platform=platform)
|
arch=arch, platform=platform)
|
||||||
deploy_ramdisk_file = os.path.join(parsed_args.image_path,
|
deploy_ramdisk_file = os.path.join(parsed_args.image_path,
|
||||||
parsed_args.ipa_name +
|
parsed_args.ipa_name +
|
||||||
deploy_ramdisk_extension)
|
deploy_ramdisk_extension)
|
||||||
self._image_try_update(deploy_ramdisk_name, deploy_ramdisk_file,
|
self._image_try_update(deploy_ramdisk_name, deploy_ramdisk_file,
|
||||||
parsed_args) or \
|
parsed_args) or \
|
||||||
glance_client_adaptor.upload_image(
|
glance_client_adaptor.upload_image(
|
||||||
name=deploy_ramdisk_name,
|
name=deploy_ramdisk_name,
|
||||||
is_public=True,
|
is_public=True,
|
||||||
disk_format='ari',
|
disk_format='ari',
|
||||||
properties=properties,
|
properties=properties,
|
||||||
data=self._read_image_file_pointer(parsed_args.image_path,
|
data=self._read_image_file_pointer(parsed_args.image_path,
|
||||||
deploy_ramdisk_file))
|
deploy_ramdisk_file))
|
||||||
|
|
||||||
self.log.debug("copy agent images to HTTP BOOT dir")
|
self.log.debug("copy agent images to HTTP BOOT dir")
|
||||||
|
|
||||||
# TODO(tonyb) Decide how to handle platform specific httpboot
|
# TODO(tonyb) Decide how to handle platform specific httpboot
|
||||||
# files/names
|
# files/names
|
||||||
|
|
||||||
self._file_create_or_update(
|
self._file_create_or_update(
|
||||||
os.path.join(parsed_args.image_path,
|
os.path.join(parsed_args.image_path,
|
||||||
'%s.kernel' % parsed_args.ipa_name),
|
'%s.kernel' % parsed_args.ipa_name),
|
||||||
os.path.join(parsed_args.http_boot, 'agent.kernel'),
|
os.path.join(parsed_args.http_boot, 'agent.kernel'),
|
||||||
parsed_args.update_existing
|
parsed_args.update_existing
|
||||||
)
|
)
|
||||||
|
|
||||||
self._file_create_or_update(
|
self._file_create_or_update(
|
||||||
os.path.join(parsed_args.image_path,
|
os.path.join(parsed_args.image_path,
|
||||||
'%s.initramfs' % parsed_args.ipa_name),
|
'%s.initramfs' % parsed_args.ipa_name),
|
||||||
os.path.join(parsed_args.http_boot, 'agent.ramdisk'),
|
os.path.join(parsed_args.http_boot, 'agent.ramdisk'),
|
||||||
parsed_args.update_existing
|
parsed_args.update_existing
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue