Add overcloud image create method

Adding overcloud image create method to replace instack
code (method instack-prepare-for-overcloud) and do overcloud
deployment via rdomanager commands.

Main functionality is to take locally stored image files and
upload them to glance.

Change-Id: Icc39744c511013d663242f5b544b0ac4a2fd6893
This commit is contained in:
Marek Aufart 2015-03-26 10:52:56 +01:00
parent bb804c6ce8
commit 937e848460
3 changed files with 191 additions and 6 deletions

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
# #
import mock
from rdomanager_oscplugin.tests.v1.test_plugin import TestPluginV1 from rdomanager_oscplugin.tests.v1.test_plugin import TestPluginV1
# Load the plugin init module for the plugin list and show commands # Load the plugin init module for the plugin list and show commands
@ -39,4 +40,58 @@ class TestOvercloudImageCreate(TestPluginV1):
super(TestOvercloudImageCreate, self).setUp() super(TestOvercloudImageCreate, self).setUp()
# Get the command object to test # Get the command object to test
self.cmd = overcloud_image.CreatePlugin(self.app, None) self.cmd = overcloud_image.CreateOvercloud(self.app, None)
self.app.client_manager.image = mock.Mock()
self.app.client_manager.image.images.create.return_value = \
mock.Mock(id=10)
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.call')
def test_overcloud_create_images(self, mock_subprocess_call):
parsed_args = self.check_parser(self.cmd, [], [])
self.cmd.take_action(parsed_args)
self.assertEqual(
2,
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(data=b'IMGDATA',
name='overcloud-full-vmlinuz',
disk_format='aki',
is_public=True),
mock.call(data=b'IMGDATA',
name='overcloud-full-initrd',
disk_format='ari',
is_public=True),
mock.call(properties={'kernel_id': 10, 'ramdisk_id': 10},
name='overcloud-full',
data=b'IMGDATA',
container_format='bare',
disk_format='qcow2',
is_public=True),
mock.call(data=b'IMGDATA',
name='bm-deploy-kernel',
disk_format='aki',
is_public=True),
mock.call(data=b'IMGDATA',
name='bm-deploy-ramdisk',
disk_format='ari',
is_public=True)
], 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 "./discovery-ramdisk.kernel" '
'"/tftpboot/discovery.kernel"', shell=True),
mock.call('sudo cp -f "./discovery-ramdisk.initramfs" '
'"/tftpboot/discovery.ramdisk"', shell=True)
])

View File

@ -16,8 +16,12 @@
"""Plugin action implementation""" """Plugin action implementation"""
import logging import logging
import os
import subprocess
from cliff import command from cliff import command
from openstackclient.common import exceptions
from openstackclient.common import utils
class BuildPlugin(command.Command): class BuildPlugin(command.Command):
@ -31,11 +35,137 @@ class BuildPlugin(command.Command):
pass pass
class CreatePlugin(command.Command): class CreateOvercloud(command.Command):
"""Overcloud Image Create plugin""" """Create overcloud glance images from existing image files."""
auth_required = False auth_required = False
log = logging.getLogger(__name__ + ".CreatePlugin") log = logging.getLogger(__name__ + ".CreateOvercloud")
def _env_variable_or_set(self, key_name, default_value):
os.environ[key_name] = os.environ.get(key_name, default_value)
def _delete_image_if_exists(self, image_client, name):
try:
image = utils.find_resource(image_client.images, name)
image_client.images.delete(image.id)
except exceptions.CommandError:
self.log.debug('Image "%s" have already not existed, '
'no problem.' % name)
def _check_file_exists(self, file_path):
if not os.path.isfile(file_path):
print('ERROR: Required file "%s" does not exist' % file_path)
exit(1)
def _read_image_file_pointer(self, dirname, filename):
filepath = os.path.join(dirname, filename)
self._check_file_exists(filepath)
return open(filepath, 'rb')
def _copy_file(self, src, dest):
subprocess.call('sudo cp -f "{0}" "{1}"'.format(src, dest), shell=True)
def _load_image(self, image_path, image_name, image_client):
self.log.debug("uploading images to glance")
kernel_id = image_client.images.create(
name='%s-vmlinuz' % image_name,
is_public=True,
disk_format='aki',
data=self._read_image_file_pointer(image_path,
'%s.vmlinuz' % image_name)
).id
ramdisk_id = image_client.images.create(
name='%s-initrd' % image_name,
is_public=True,
disk_format='ari',
data=self._read_image_file_pointer(image_path,
'%s.initrd' % image_name)
).id
image_client.images.create(
name=image_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(image_path,
'%s.qcow2' % image_name)
)
def get_parser(self, prog_name):
parser = super(CreateOvercloud, self).get_parser(prog_name)
parser.add_argument(
"--image-path",
default='./',
help="Path to directory containing image files",
)
parser.add_argument(
"--os-image",
default='overcloud-full.qcow2',
help="OpenStack disk image filename",
)
return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args) self.log.debug("take_action(%s)" % parsed_args)
pass image_client = self.app.client_manager.image
self._env_variable_or_set('DEPLOY_NAME', 'deploy-ramdisk-ironic')
self._env_variable_or_set('DISCOVERY_NAME', 'discovery-ramdisk')
self._env_variable_or_set('TFTP_ROOT', '/tftpboot')
self.log.debug("check image files")
image_files = [
'%s.initramfs' % os.environ['DEPLOY_NAME'],
'%s.kernel' % os.environ['DEPLOY_NAME'],
'%s.initramfs' % os.environ['DISCOVERY_NAME'],
'%s.kernel' % os.environ['DISCOVERY_NAME'],
parsed_args.os_image
]
for image in image_files:
self._check_file_exists(os.path.join(parsed_args.image_path,
image))
self.log.debug("prepare glance images")
self._load_image(parsed_args.image_path,
parsed_args.os_image.split('.')[0],
image_client)
self._delete_image_if_exists(image_client, 'bm_deploy_kernel')
self._delete_image_if_exists(image_client, 'bm_deploy_ramdisk')
image_client.images.create(
name='bm-deploy-kernel',
is_public=True,
disk_format='aki',
data=self._read_image_file_pointer(parsed_args.image_path,
'%s.kernel' %
os.environ['DEPLOY_NAME'])
)
image_client.images.create(
name='bm-deploy-ramdisk',
is_public=True,
disk_format='ari',
data=self._read_image_file_pointer(parsed_args.image_path,
'%s.initramfs' %
os.environ['DEPLOY_NAME'])
)
self.log.debug("copy discovery images to TFTP")
self._copy_file(
os.path.join(parsed_args.image_path,
'%s.kernel' % os.environ['DISCOVERY_NAME']),
os.path.join(os.environ['TFTP_ROOT'], 'discovery.kernel')
)
self._copy_file(
os.path.join(parsed_args.image_path,
'%s.initramfs' % os.environ['DISCOVERY_NAME']),
os.path.join(os.environ['TFTP_ROOT'], 'discovery.ramdisk')
)

View File

@ -60,5 +60,5 @@ openstack.rdomanager_oscplugin.v1 =
baremetal_configure_boot = rdomanager_oscplugin.v1.baremetal:ConfigureBootPlugin baremetal_configure_boot = rdomanager_oscplugin.v1.baremetal:ConfigureBootPlugin
overcloud_deploy = rdomanager_oscplugin.v1.overcloud_deploy:DeployPlugin overcloud_deploy = rdomanager_oscplugin.v1.overcloud_deploy:DeployPlugin
overcloud_image_build = rdomanager_oscplugin.v1.overcloud_image:BuildPlugin overcloud_image_build = rdomanager_oscplugin.v1.overcloud_image:BuildPlugin
overcloud_image_create = rdomanager_oscplugin.v1.overcloud_image:CreatePlugin overcloud_image_create = rdomanager_oscplugin.v1.overcloud_image:CreateOvercloud
undercloud_install = rdomanager_oscplugin.v1.undercloud:InstallPlugin undercloud_install = rdomanager_oscplugin.v1.undercloud:InstallPlugin