Merge "Enable creating images with Glance v2"
This commit is contained in:
commit
6a15a7728f
|
@ -361,6 +361,7 @@ class TestUploadOvercloudImage(TestPluginV1):
|
|||
# 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={'kernel_id': 10,
|
||||
'ramdisk_id': 10},
|
||||
|
@ -433,7 +434,7 @@ class TestUploadOvercloudImage(TestPluginV1):
|
|||
)
|
||||
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_overcloud_create_images(self, mock_subprocess_call):
|
||||
def test_overcloud_create_images_v2(self, mock_subprocess_call):
|
||||
parsed_args = self.check_parser(self.cmd, [], [])
|
||||
os.path.isfile = mock.Mock(return_value=False)
|
||||
|
||||
|
@ -441,6 +442,57 @@ class TestUploadOvercloudImage(TestPluginV1):
|
|||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.delete.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
5,
|
||||
self.app.client_manager.image.images.create.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
[mock.call(name='overcloud-full-vmlinuz',
|
||||
disk_format='aki',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
mock.call(name='overcloud-full-initrd',
|
||||
disk_format='ari',
|
||||
container_format='bare',
|
||||
visibility='public'),
|
||||
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_images_v1(self, mock_subprocess_call):
|
||||
parsed_args = self.check_parser(self.cmd, [], [])
|
||||
os.path.isfile = mock.Mock(return_value=False)
|
||||
|
||||
self.cmd._get_image = mock.Mock(return_value=None)
|
||||
self.app.client_manager.image.version = 1.0
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(
|
||||
0,
|
||||
self.app.client_manager.image.images.delete.call_count
|
||||
|
@ -538,7 +590,7 @@ class TestUploadOvercloudImage(TestPluginV1):
|
|||
self.app.client_manager.image.images.create.call_count
|
||||
)
|
||||
self.assertEqual(
|
||||
5,
|
||||
6,
|
||||
self.app.client_manager.image.images.update.call_count
|
||||
)
|
||||
self.assertEqual(mock_subprocess_call.call_count, 2)
|
||||
|
|
|
@ -603,6 +603,53 @@ class BuildOvercloudImage(command.Command):
|
|||
manager.build()
|
||||
|
||||
|
||||
class GlanceBaseClientAdapter(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
def print_image_info(self, image):
|
||||
table = PrettyTable(['ID', 'Name', 'Disk Format', 'Size', 'Status'])
|
||||
table.add_row([image.id, image.name, image.disk_format, image.size,
|
||||
image.status])
|
||||
print(table, file=sys.stdout)
|
||||
|
||||
|
||||
class GlanceV1ClientAdapter(GlanceBaseClientAdapter):
|
||||
def upload_image(self, *args, **kwargs):
|
||||
image = self.client.images.create(*args, **kwargs)
|
||||
|
||||
print('Image "%s" was uploaded.' % image.name, file=sys.stdout)
|
||||
self.print_image_info(image)
|
||||
return image
|
||||
|
||||
def get_image_property(self, image, prop):
|
||||
return image.properties[prop]
|
||||
|
||||
|
||||
class GlanceV2ClientAdapter(GlanceBaseClientAdapter):
|
||||
def upload_image(self, *args, **kwargs):
|
||||
is_public = kwargs.pop('is_public')
|
||||
data = kwargs.pop('data')
|
||||
properties = kwargs.pop('properties', None)
|
||||
kwargs['visibility'] = 'public' if is_public else 'private'
|
||||
kwargs.setdefault('container_format', 'bare')
|
||||
|
||||
image = self.client.images.create(*args, **kwargs)
|
||||
|
||||
self.client.images.upload(image.id, image_data=data)
|
||||
if properties:
|
||||
self.client.images.update(image.id, **properties)
|
||||
# Refresh image info
|
||||
image = self.client.images.get(image.id)
|
||||
|
||||
print('Image "%s" was uploaded.' % image.name, file=sys.stdout)
|
||||
self.print_image_info(image)
|
||||
return image
|
||||
|
||||
def get_image_property(self, image, prop):
|
||||
return getattr(image, prop)
|
||||
|
||||
|
||||
class UploadOvercloudImage(command.Command):
|
||||
"""Create overcloud glance images from existing image files."""
|
||||
log = logging.getLogger(__name__ + ".UploadOvercloudImage")
|
||||
|
@ -695,17 +742,11 @@ class UploadOvercloudImage(command.Command):
|
|||
else:
|
||||
self._copy_file(src_file, dest_file)
|
||||
|
||||
def _print_image_info(self, image):
|
||||
table = PrettyTable(['ID', 'Name', 'Disk Format', 'Size', 'Status'])
|
||||
table.add_row([image.id, image.name, image.disk_format, image.size,
|
||||
image.status])
|
||||
print(table, file=sys.stdout)
|
||||
|
||||
def _upload_image(self, *args, **kwargs):
|
||||
image = self.app.client_manager.image.images.create(*args, **kwargs)
|
||||
print('Image "%s" was uploaded.' % image.name, file=sys.stdout)
|
||||
self._print_image_info(image)
|
||||
return image
|
||||
def _get_glance_client_adaptor(self):
|
||||
if self.app.client_manager.image.version >= 2.0:
|
||||
return GlanceV2ClientAdapter(self.app.client_manager.image)
|
||||
else:
|
||||
return GlanceV1ClientAdapter(self.app.client_manager.image)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UploadOvercloudImage, self).get_parser(prog_name)
|
||||
|
@ -734,6 +775,7 @@ class UploadOvercloudImage(command.Command):
|
|||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
glance_client_adaptor = self._get_glance_client_adaptor()
|
||||
|
||||
self._env_variable_or_set('AGENT_NAME', 'ironic-python-agent')
|
||||
|
||||
|
@ -758,7 +800,7 @@ class UploadOvercloudImage(command.Command):
|
|||
kernel = (self._image_try_update(oc_vmlinuz_name,
|
||||
oc_vmlinuz_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
glance_client_adaptor.upload_image(
|
||||
name=oc_vmlinuz_name,
|
||||
is_public=True,
|
||||
disk_format='aki',
|
||||
|
@ -771,7 +813,7 @@ class UploadOvercloudImage(command.Command):
|
|||
ramdisk = (self._image_try_update(oc_initrd_name,
|
||||
oc_initrd_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
glance_client_adaptor.upload_image(
|
||||
name=oc_initrd_name,
|
||||
is_public=True,
|
||||
disk_format='ari',
|
||||
|
@ -783,7 +825,7 @@ class UploadOvercloudImage(command.Command):
|
|||
oc_file = '%s.qcow2' % image_name
|
||||
overcloud_image = (self._image_try_update(oc_name, oc_file,
|
||||
parsed_args) or
|
||||
self._upload_image(
|
||||
glance_client_adaptor.upload_image(
|
||||
name=oc_name,
|
||||
is_public=True,
|
||||
disk_format='qcow2',
|
||||
|
@ -794,9 +836,12 @@ class UploadOvercloudImage(command.Command):
|
|||
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 (overcloud_image.properties['kernel_id'] != kernel.id or
|
||||
overcloud_image.properties['ramdisk_id'] != ramdisk.id):
|
||||
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.')
|
||||
|
@ -806,25 +851,25 @@ class UploadOvercloudImage(command.Command):
|
|||
deploy_kernel_name = 'bm-deploy-kernel'
|
||||
deploy_kernel_file = '%s.kernel' % os.environ['AGENT_NAME']
|
||||
self._image_try_update(deploy_kernel_name, deploy_kernel_file,
|
||||
parsed_args) or self._upload_image(
|
||||
name=deploy_kernel_name,
|
||||
is_public=True,
|
||||
disk_format='aki',
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path,
|
||||
deploy_kernel_file)
|
||||
)
|
||||
parsed_args) or \
|
||||
glance_client_adaptor.upload_image(
|
||||
name=deploy_kernel_name,
|
||||
is_public=True,
|
||||
disk_format='aki',
|
||||
data=self._read_image_file_pointer(
|
||||
parsed_args.image_path,
|
||||
deploy_kernel_file))
|
||||
|
||||
deploy_ramdisk_name = 'bm-deploy-ramdisk'
|
||||
deploy_ramdisk_file = '%s.initramfs' % os.environ['AGENT_NAME']
|
||||
self._image_try_update(deploy_ramdisk_name, deploy_ramdisk_file,
|
||||
parsed_args) or self._upload_image(
|
||||
name=deploy_ramdisk_name,
|
||||
is_public=True,
|
||||
disk_format='ari',
|
||||
data=self._read_image_file_pointer(parsed_args.image_path,
|
||||
deploy_ramdisk_file)
|
||||
)
|
||||
parsed_args) or \
|
||||
glance_client_adaptor.upload_image(
|
||||
name=deploy_ramdisk_name,
|
||||
is_public=True,
|
||||
disk_format='ari',
|
||||
data=self._read_image_file_pointer(parsed_args.image_path,
|
||||
deploy_ramdisk_file))
|
||||
|
||||
self.log.debug("copy agent images to HTTP BOOT dir")
|
||||
|
||||
|
|
Loading…
Reference in New Issue