Merge "Support whole disk images in TripleO"
This commit is contained in:
commit
c212fbd065
@ -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
|
||||
|
@ -594,3 +594,119 @@ 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(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')
|
||||
], 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)
|
||||
|
@ -771,6 +771,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):
|
||||
@ -781,11 +789,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,
|
||||
@ -793,58 +808,76 @@ 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
|
||||
glance_client_adaptor.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
|
||||
glance_client_adaptor.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
|
||||
glance_client_adaptor.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
|
||||
glance_client_adaptor.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
|
||||
glance_client_adaptor.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
|
||||
glance_client_adaptor.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)
|
||||
))
|
||||
|
||||
img_kernel_id = glance_client_adaptor.get_image_property(
|
||||
overcloud_image, 'kernel_id')
|
||||
img_ramdisk_id = glance_client_adaptor.get_image_property(
|
||||
overcloud_image, 'ramdisk_id')
|
||||
# check overcloud image links
|
||||
if (img_kernel_id != kernel.id or img_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.')
|
||||
img_kernel_id = glance_client_adaptor.get_image_property(
|
||||
overcloud_image, 'kernel_id')
|
||||
img_ramdisk_id = glance_client_adaptor.get_image_property(
|
||||
overcloud_image, 'ramdisk_id')
|
||||
# check overcloud image links
|
||||
if (img_kernel_id != kernel.id or img_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
|
||||
glance_client_adaptor.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
Block a user