Cinder Support For Boot Volume
When use cinder to store data dir of database, also create rootdisk in cinder. Story: #2009245 Task: #43418 Change-Id: Ia5841222c7a70cb0c88078575b4d8b4f7988d5e0
This commit is contained in:
parent
22469809ec
commit
8b6ff821a1
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- Implements nova instances with root disk in cinder backend
|
||||
if the configuration `volume_rootdisk_support` is True
|
||||
The size of root disk being created is `volume_rootdisk_size`
|
||||
|
||||
fixes:
|
||||
- When creating Nova instances with a root disk in the Cinder
|
||||
backend, it will allow live migration of Nova instances
|
||||
and features when using Cinder as the storage backend.
|
@ -63,8 +63,12 @@ common_opts = [
|
||||
help='Port the API server will listen on.'),
|
||||
cfg.StrOpt('api_paste_config', default="api-paste.ini",
|
||||
help='File name for the paste.deploy config for trove-api.'),
|
||||
cfg.BoolOpt('trove_volume_support', default=True,
|
||||
cfg.BoolOpt('trove_volume_support', default=False,
|
||||
help='Whether to provision a Cinder volume for datadir.'),
|
||||
cfg.BoolOpt('volume_rootdisk_support', default=False,
|
||||
help='Whether to provision a Cinder volume for rootdisk.'),
|
||||
cfg.IntOpt('volume_rootdisk_size', default=10,
|
||||
help='Size of volume rootdisk for Database instance'),
|
||||
cfg.ListOpt('admin_roles', default=['admin'],
|
||||
help='Roles to add to an admin user.'),
|
||||
cfg.BoolOpt('update_status_on_fail', default=True,
|
||||
|
@ -880,7 +880,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||
def _create_server_volume(self, flavor_id, image_id, datastore_manager,
|
||||
volume_size, availability_zone, nics, files,
|
||||
volume_type, scheduler_hints):
|
||||
LOG.debug("Begin _create_server_volume for id: %s", self.id)
|
||||
LOG.debug("Begin _create_server_volume for instance: %s", self.id)
|
||||
server = None
|
||||
volume_info = self._build_volume_info(
|
||||
datastore_manager,
|
||||
@ -888,6 +888,17 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||
volume_type=volume_type,
|
||||
availability_zone=availability_zone)
|
||||
block_device_mapping_v2 = volume_info['block_device']
|
||||
|
||||
if CONF.volume_rootdisk_support:
|
||||
block_device_mapping_v2.insert(
|
||||
0, self._create_root_volume(
|
||||
image_id,
|
||||
CONF.volume_rootdisk_size,
|
||||
volume_type,
|
||||
availability_zone
|
||||
))
|
||||
image_id = None
|
||||
|
||||
try:
|
||||
server = self._create_server(
|
||||
flavor_id, image_id,
|
||||
@ -904,7 +915,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||
exc_fmt = _("Failed to create server for instance %s")
|
||||
err = inst_models.InstanceTasks.BUILDING_ERROR_SERVER
|
||||
self._log_and_raise(e, log_fmt, exc_fmt, self.id, err)
|
||||
LOG.debug("End _create_server_volume for id: %s", self.id)
|
||||
LOG.debug("End _create_server_volume for instance: %s", self.id)
|
||||
return volume_info
|
||||
|
||||
def _build_volume_info(self, datastore_manager, volume_size=None,
|
||||
@ -953,6 +964,44 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||
full_message = "%s%s" % (exc_fmt % fmt_content, exc_message)
|
||||
raise TroveError(message=full_message)
|
||||
|
||||
def _create_root_volume(self, image_id,
|
||||
volume_size, volume_type, availability_zone):
|
||||
LOG.debug("Begin _create_root_volume for instance: %s", self.id)
|
||||
volume_client = create_cinder_client(self.context, self.region_name)
|
||||
volume_desc = ("root volume for %s" % self.id)
|
||||
volume_kwargs = {
|
||||
'size': volume_size,
|
||||
'name': "trove-%s" % self.id,
|
||||
'description': volume_desc,
|
||||
'volume_type': volume_type,
|
||||
'imageRef': image_id
|
||||
}
|
||||
if CONF.enable_volume_az:
|
||||
volume_kwargs['availability_zone'] = availability_zone
|
||||
|
||||
volume_ref = volume_client.volumes.create(**volume_kwargs)
|
||||
|
||||
utils.poll_until(
|
||||
lambda: volume_client.volumes.get(volume_ref.id),
|
||||
lambda v_ref: v_ref.status in ['available', 'error'],
|
||||
sleep_time=2,
|
||||
time_out=CONF.volume_time_out)
|
||||
|
||||
v_ref = volume_client.volumes.get(volume_ref.id)
|
||||
if v_ref.status in ['error']:
|
||||
raise VolumeCreationFailure()
|
||||
|
||||
block_device_mapping_v2 = {
|
||||
"uuid": v_ref.id,
|
||||
"boot_index": 0,
|
||||
"source_type": "volume",
|
||||
"destination_type": "volume",
|
||||
"delete_on_termination": True
|
||||
}
|
||||
|
||||
LOG.debug("End _create_root_volume for instance: %s", self.id)
|
||||
return block_device_mapping_v2
|
||||
|
||||
def _create_volume(self, volume_size, volume_type, datastore_manager,
|
||||
availability_zone):
|
||||
LOG.debug("Begin _create_volume for id: %s", self.id)
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
import json
|
||||
import os
|
||||
|
||||
from tempfile import NamedTemporaryFile
|
||||
from unittest import mock
|
||||
from unittest.mock import call
|
||||
@ -21,17 +22,19 @@ from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import PropertyMock
|
||||
|
||||
from cinderclient import exceptions as cinder_exceptions
|
||||
import cinderclient.v3.client as cinderclient
|
||||
from cinderclient.v3 import volumes as cinderclient_volumes
|
||||
import neutronclient.v2_0.client as neutronclient
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
import novaclient.v2.flavors
|
||||
import novaclient.v2.servers
|
||||
|
||||
from cinderclient import exceptions as cinder_exceptions
|
||||
from cinderclient.v3 import volumes as cinderclient_volumes
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
from oslo_config import cfg
|
||||
from swiftclient.client import ClientException
|
||||
from testtools.matchers import Equals
|
||||
from testtools.matchers import Is
|
||||
|
||||
import trove.backup.models
|
||||
import trove.common.context
|
||||
import trove.common.template as template
|
||||
@ -405,6 +408,7 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_create_server')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_create_secgroup')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_build_volume_info')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_create_root_volume')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_guest_prepare')
|
||||
@patch.object(template, 'SingleInstanceConfigTemplate')
|
||||
@patch('trove.taskmanager.models.FreshInstanceTasks._create_port')
|
||||
@ -412,6 +416,7 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
mock_create_port,
|
||||
mock_single_instance_template,
|
||||
mock_guest_prepare,
|
||||
mock_create_root_volume,
|
||||
mock_build_volume_info,
|
||||
mock_create_secgroup,
|
||||
mock_create_server,
|
||||
@ -445,6 +450,12 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
is_mgmt=False,
|
||||
is_public=False
|
||||
)
|
||||
image_id = 'mysql-image-id'
|
||||
if cfg.CONF.volume_rootdisk_support:
|
||||
mock_create_root_volume.assert_called_with(
|
||||
'mysql-image-id', 10, 'volume_type', None)
|
||||
image_id = None
|
||||
|
||||
mock_build_volume_info.assert_called_with(
|
||||
'mysql', availability_zone=None, volume_size=2,
|
||||
volume_type='volume_type'
|
||||
@ -454,7 +465,7 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
config_content, None, overrides, None, None, None, ds_version=None
|
||||
)
|
||||
mock_create_server.assert_called_with(
|
||||
8, 'mysql-image-id', 'mysql',
|
||||
8, image_id, 'mysql',
|
||||
mock_build_volume_info()['block_device'], None,
|
||||
[{'port-id': 'fake-port-id'}],
|
||||
mock_get_injected_files(),
|
||||
@ -466,6 +477,7 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, 'get_injected_files')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_create_server')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_build_volume_info')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_create_root_volume')
|
||||
@patch.object(taskmanager_models.FreshInstanceTasks, '_guest_prepare')
|
||||
@patch.object(template, 'SingleInstanceConfigTemplate')
|
||||
@patch('trove.common.clients_admin.neutron_client_trove_admin')
|
||||
@ -473,6 +485,7 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
mock_neutron_client,
|
||||
mock_single_instance_template,
|
||||
mock_guest_prepare,
|
||||
mock_create_root_volume,
|
||||
mock_build_volume_info,
|
||||
mock_create_server,
|
||||
mock_get_injected_files,
|
||||
@ -516,6 +529,11 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
access={'is_public': True, 'allowed_cidrs': ['192.168.0.1/24']}
|
||||
)
|
||||
|
||||
image_id = 'mysql-image-id'
|
||||
if cfg.CONF.volume_rootdisk_support:
|
||||
mock_create_root_volume.assert_called_with(
|
||||
'mysql-image-id', 10, 'volume_type', None)
|
||||
image_id = None
|
||||
mock_build_volume_info.assert_called_with(
|
||||
'mysql', availability_zone=None, volume_size=2,
|
||||
volume_type='volume_type'
|
||||
@ -524,7 +542,7 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
768, mock_build_volume_info(), 'mysql-server', None, None, None,
|
||||
config_content, None, mock.ANY, None, None, None, ds_version=None)
|
||||
mock_create_server.assert_called_with(
|
||||
8, 'mysql-image-id', 'mysql',
|
||||
8, image_id, 'mysql',
|
||||
mock_build_volume_info()['block_device'], None,
|
||||
[
|
||||
{'port-id': 'fake-user-port-id'},
|
||||
|
Loading…
Reference in New Issue
Block a user