Support whole disk images in TripleO
Enable to upload whole disk images from the client,
not forcing to upload kernel and initrd images, and
not setting the parameters for those in the glance
qcow2 image.
Change-Id: I9fbac888b3e709212cc6c72153a3ca465101987c
Partially-Implements: blueprint support-full-disk-images
(cherry picked from commit 92bd4c43d6
)
This commit is contained in:
parent
d963159bcc
commit
cfa87167c4
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
features:
|
||||
- Allow client to support whole disk images. Client
|
||||
will now accept a --whole-disk flag on the
|
||||
overcloud image upload command. When this flag is
|
||||
set, it will only look for qcow2 image, not enforcing
|
||||
the upload of initrd and vmlinuz images. It will also
|
||||
not set these properties on the qcow2 image on glance.
|
||||
This will allow Ironic to consider the uploaded image
|
||||
as full disk image, giving the possibility to provide
|
||||
full disk images in TripleO instead of single partition
|
||||
ones.
|
||||
Please look at `Ironic documentation <http://docs.openstack.org/project-install-guide/baremetal/draft/configure-integration.html#create-and-add-images-to-the-image-service>`_
|
||||
for reference
|
||||
|
|
@ -472,3 +472,121 @@ class TestUploadOvercloudImage(TestPluginV1):
|
|||
self.app.client_manager.image.images.update.call_count
|
||||
)
|
||||
self.assertEqual(mock_subprocess_call.call_count, 2)
|
||||
|
||||
|
||||
class TestUploadOvercloudImageFull(TestPluginV1):
|
||||
def setUp(self):
|
||||
super(TestUploadOvercloudImageFull, 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._read_image_file_pointer = mock.Mock(return_value=b'IMGDATA')
|
||||
self.cmd._check_file_exists = mock.Mock(return_value=True)
|
||||
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_overcloud_create_images(self, mock_subprocess_call):
|
||||
parsed_args = self.check_parser(self.cmd, ['--whole-disk'], [])
|
||||
os.path.isfile = mock.Mock(return_value=False)
|
||||
|
||||
self.cmd._get_image = mock.Mock(return_value=None)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.delete.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
3,
|
||||
self.app.client_manager.image.images.create.call_count
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
[mock.call(container_format='bare',
|
||||
data=b'IMGDATA',
|
||||
disk_format='qcow2',
|
||||
is_public=True,
|
||||
name='overcloud-full',
|
||||
properties={}),
|
||||
mock.call(data=b'IMGDATA',
|
||||
disk_format='aki',
|
||||
is_public=True,
|
||||
name='bm-deploy-kernel'),
|
||||
mock.call(data=b'IMGDATA',
|
||||
disk_format='ari',
|
||||
is_public=True,
|
||||
name='bm-deploy-ramdisk')
|
||||
], self.app.client_manager.image.images.create.call_args_list
|
||||
)
|
||||
|
||||
self.assertEqual(mock_subprocess_call.call_count, 2)
|
||||
self.assertEqual(
|
||||
mock_subprocess_call.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.patch('subprocess.check_call', autospec=True)
|
||||
def test_overcloud_create_noupdate_images(self, mock_subprocess_call):
|
||||
parsed_args = self.check_parser(self.cmd, ['--whole-disk'], [])
|
||||
os.path.isfile = mock.Mock(return_value=True)
|
||||
self.cmd._files_changed = mock.Mock(return_value=True)
|
||||
|
||||
existing_image = mock.Mock(id=10, name='imgname',
|
||||
properties={})
|
||||
self.cmd._get_image = mock.Mock(return_value=existing_image)
|
||||
self.cmd._image_changed = mock.Mock(return_value=True)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.delete.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.create.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.update.call_count
|
||||
)
|
||||
|
||||
self.assertEqual(mock_subprocess_call.call_count, 0)
|
||||
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_overcloud_create_update_images(self, mock_subprocess_call):
|
||||
parsed_args = self.check_parser(
|
||||
self.cmd, ['--update-existing', '--whole-disk'], [])
|
||||
self.cmd._files_changed = mock.Mock(return_value=True)
|
||||
|
||||
existing_image = mock.Mock(id=10, name='imgname',
|
||||
properties={},
|
||||
created_at='2015-07-31T14:37:22.000000')
|
||||
self.cmd._get_image = mock.Mock(return_value=existing_image)
|
||||
self.cmd._image_changed = mock.Mock(return_value=True)
|
||||
self.app.client_manager.image.images.update.return_value = (
|
||||
existing_image)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.delete.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
3,
|
||||
self.app.client_manager.image.images.create.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
3,
|
||||
self.app.client_manager.image.images.update.call_count
|
||||
)
|
||||
self.assertEqual(mock_subprocess_call.call_count, 2)
|
||||
|
|
|
@ -668,6 +668,14 @@ class UploadOvercloudImage(command.Command):
|
|||
action="store_true",
|
||||
help=_("Update images if already exist"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--whole-disk",
|
||||
dest="whole_disk",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=_("When set, the overcloud-full image to be uploaded "
|
||||
"will be considered as a whole disk one"),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
|
@ -677,11 +685,18 @@ class UploadOvercloudImage(command.Command):
|
|||
|
||||
self.log.debug("checking if image files exist")
|
||||
|
||||
image_files = [
|
||||
'%s.initramfs' % os.environ['AGENT_NAME'],
|
||||
'%s.kernel' % os.environ['AGENT_NAME'],
|
||||
parsed_args.os_image
|
||||
]
|
||||
if parsed_args.whole_disk:
|
||||
image_files = [
|
||||
parsed_args.os_image
|
||||
]
|
||||
overcloud_image_type = 'whole disk'
|
||||
else:
|
||||
image_files = [
|
||||
'%s.initramfs' % os.environ['AGENT_NAME'],
|
||||
'%s.kernel' % os.environ['AGENT_NAME'],
|
||||
parsed_args.os_image
|
||||
]
|
||||
overcloud_image_type = 'partition'
|
||||
|
||||
for image in image_files:
|
||||
self._check_file_exists(os.path.join(parsed_args.image_path,
|
||||
|
@ -689,55 +704,72 @@ class UploadOvercloudImage(command.Command):
|
|||
|
||||
image_name = parsed_args.os_image.split('.')[0]
|
||||
|
||||
self.log.debug("uploading overcloud images to glance")
|
||||
self.log.debug("uploading %s overcloud images to glance" %
|
||||
overcloud_image_type)
|
||||
|
||||
oc_vmlinuz_name = '%s-vmlinuz' % image_name
|
||||
oc_vmlinuz_file = '%s.vmlinuz' % image_name
|
||||
kernel = (self._image_try_update(oc_vmlinuz_name,
|
||||
oc_vmlinuz_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_vmlinuz_name,
|
||||
is_public=True,
|
||||
disk_format='aki',
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_vmlinuz_file)
|
||||
))
|
||||
# vmlinuz and initrd only need to be uploaded for a partition image
|
||||
if not parsed_args.whole_disk:
|
||||
oc_vmlinuz_name = '%s-vmlinuz' % image_name
|
||||
oc_vmlinuz_file = '%s.vmlinuz' % image_name
|
||||
kernel = (self._image_try_update(oc_vmlinuz_name,
|
||||
oc_vmlinuz_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_vmlinuz_name,
|
||||
is_public=True,
|
||||
disk_format='aki',
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_vmlinuz_file)
|
||||
))
|
||||
|
||||
oc_initrd_name = '%s-initrd' % image_name
|
||||
oc_initrd_file = '%s.initrd' % image_name
|
||||
ramdisk = (self._image_try_update(oc_initrd_name,
|
||||
oc_initrd_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_initrd_name,
|
||||
is_public=True,
|
||||
disk_format='ari',
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_initrd_file)
|
||||
))
|
||||
oc_initrd_name = '%s-initrd' % image_name
|
||||
oc_initrd_file = '%s.initrd' % image_name
|
||||
ramdisk = (self._image_try_update(oc_initrd_name,
|
||||
oc_initrd_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_initrd_name,
|
||||
is_public=True,
|
||||
disk_format='ari',
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_initrd_file)
|
||||
))
|
||||
|
||||
oc_name = image_name
|
||||
oc_file = '%s.qcow2' % image_name
|
||||
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_name,
|
||||
is_public=True,
|
||||
disk_format='qcow2',
|
||||
container_format='bare',
|
||||
properties={'kernel_id': kernel.id,
|
||||
'ramdisk_id': ramdisk.id},
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_file)
|
||||
))
|
||||
oc_name = image_name
|
||||
oc_file = '%s.qcow2' % image_name
|
||||
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_name,
|
||||
is_public=True,
|
||||
disk_format='qcow2',
|
||||
container_format='bare',
|
||||
properties={'kernel_id': kernel.id,
|
||||
'ramdisk_id': ramdisk.id},
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_file)
|
||||
))
|
||||
|
||||
# check overcloud image links
|
||||
if (overcloud_image.properties['kernel_id'] != kernel.id or
|
||||
overcloud_image.properties['ramdisk_id'] != ramdisk.id):
|
||||
self.log.error('Link overcloud image to it\'s initrd and kernel'
|
||||
' images is MISSING OR leads to OLD image.'
|
||||
' You can keep it or fix it manually.')
|
||||
# check overcloud image links
|
||||
if (overcloud_image.properties['kernel_id'] != kernel.id or
|
||||
overcloud_image.properties['ramdisk_id'] != ramdisk.id):
|
||||
self.log.error('Link overcloud image to it\'s initrd and '
|
||||
'kernel images is MISSING OR leads to OLD '
|
||||
'image.You can keep it or fix it manually.')
|
||||
else:
|
||||
oc_name = image_name
|
||||
oc_file = '%s.qcow2' % image_name
|
||||
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
name=oc_name,
|
||||
is_public=True,
|
||||
disk_format='qcow2',
|
||||
container_format='bare',
|
||||
properties={},
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path, oc_file)
|
||||
))
|
||||
|
||||
self.log.debug("uploading bm images to glance")
|
||||
|
||||
|
|
Loading…
Reference in New Issue