Fix creation of share from snapshot
Current behaviour does not take into accout source host of snapshot for share creation from snapshot. It leads to impossibility to create share if improper host was scheduled using multibackend setup. Solution: Implement config opt that allows us call required host directly without scheduling in case we have host restriction and allow scheduling in case we don't. We do not have such restricion, for example, using multibackend installation with generic drivers onboard. Change-Id: I0743c92b55e123409133ea623e0f8ec03d8e9aaa Closes-Bug: #1373882
This commit is contained in:
parent
207dc1a1dc
commit
0655b58eaf
|
@ -31,7 +31,17 @@ from manila import quota
|
|||
from manila.scheduler import rpcapi as scheduler_rpcapi
|
||||
from manila.share import rpcapi as share_rpcapi
|
||||
|
||||
share_api_opts = [
|
||||
cfg.BoolOpt('use_scheduler_creating_share_from_snapshot',
|
||||
default=False,
|
||||
help='If set to False, then share creation from snapshot will '
|
||||
'be performed on the same host. '
|
||||
'If set to True, then scheduling step will be used.')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(share_api_opts)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
GB = 1048576 * 1024
|
||||
QUOTAS = quota.QUOTAS
|
||||
|
@ -152,22 +162,40 @@ class API(base.Base):
|
|||
finally:
|
||||
QUOTAS.rollback(context, reservations)
|
||||
|
||||
request_spec = {'share_properties': options,
|
||||
'share_proto': share_proto,
|
||||
'share_id': share['id'],
|
||||
'snapshot_id': share['snapshot_id'],
|
||||
'volume_type': volume_type
|
||||
}
|
||||
|
||||
request_spec = {
|
||||
'share_properties': options,
|
||||
'share_proto': share_proto,
|
||||
'share_id': share['id'],
|
||||
'snapshot_id': snapshot_id,
|
||||
'volume_type': volume_type,
|
||||
}
|
||||
filter_properties = {}
|
||||
|
||||
self.scheduler_rpcapi.create_share(
|
||||
context,
|
||||
CONF.share_topic,
|
||||
share['id'],
|
||||
snapshot_id,
|
||||
request_spec=request_spec,
|
||||
filter_properties=filter_properties)
|
||||
if (snapshot and not CONF.use_scheduler_creating_share_from_snapshot):
|
||||
# Shares from snapshots with restriction - source host only.
|
||||
# It is common situation for different types of backends.
|
||||
host = snapshot['share']['host']
|
||||
share = self.db.share_update(context, share['id'], {'host': host})
|
||||
self.share_rpcapi.create_share(
|
||||
context,
|
||||
share,
|
||||
host,
|
||||
request_spec=request_spec,
|
||||
filter_properties=filter_properties,
|
||||
snapshot_id=snapshot_id,
|
||||
)
|
||||
else:
|
||||
# Shares from scratch and from snapshots when source host is not
|
||||
# the only allowed, it is possible, for example, in multibackend
|
||||
# installation with Generic drivers only.
|
||||
self.scheduler_rpcapi.create_share(
|
||||
context,
|
||||
CONF.share_topic,
|
||||
share['id'],
|
||||
snapshot_id,
|
||||
request_spec=request_spec,
|
||||
filter_properties=filter_properties,
|
||||
)
|
||||
|
||||
return share
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import datetime
|
|||
import uuid
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from manila import context
|
||||
from manila import db as db_driver
|
||||
|
@ -30,6 +31,8 @@ from manila import test
|
|||
from manila.tests.db import fakes as db_fakes
|
||||
from manila import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def fake_share(id, **kwargs):
|
||||
share = {
|
||||
|
@ -73,7 +76,8 @@ def fake_snapshot(id, **kwargs):
|
|||
'progress': 'fakeprogress99%',
|
||||
'scheduled_at': datetime.datetime(1, 1, 1, 1, 1, 1),
|
||||
'launched_at': datetime.datetime(1, 1, 1, 1, 1, 1),
|
||||
'terminated_at': datetime.datetime(1, 1, 1, 1, 1, 1)
|
||||
'terminated_at': datetime.datetime(1, 1, 1, 1, 1, 1),
|
||||
'share': {'host': 'fake_source_host'},
|
||||
}
|
||||
snapshot.update(kwargs)
|
||||
return snapshot
|
||||
|
@ -439,6 +443,7 @@ class ShareAPITestCase(test.TestCase):
|
|||
mock.Mock(return_value='reservation'))
|
||||
@mock.patch.object(quota.QUOTAS, 'commit', mock.Mock())
|
||||
def test_create_from_snapshot_available(self):
|
||||
CONF.set_default("use_scheduler_creating_share_from_snapshot", False)
|
||||
date = datetime.datetime(1, 1, 1, 1, 1, 1)
|
||||
self.mock_utcnow.return_value = date
|
||||
snapshot = fake_snapshot('fakesnapshotid',
|
||||
|
@ -460,28 +465,80 @@ class ShareAPITestCase(test.TestCase):
|
|||
'volume_type': None,
|
||||
'snapshot_id': share['snapshot_id'],
|
||||
}
|
||||
with mock.patch.object(db_driver, 'share_create',
|
||||
mock.Mock(return_value=share)):
|
||||
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
|
||||
snapshot=snapshot, availability_zone='fakeaz')
|
||||
self.scheduler_rpcapi.create_share.assert_called_once_with(
|
||||
self.context, 'manila-share', share['id'],
|
||||
share['snapshot_id'], request_spec=request_spec,
|
||||
filter_properties={})
|
||||
db_driver.share_create.assert_called_once_with(
|
||||
self.context, options)
|
||||
share_api.policy.check_policy.assert_called_once_with(
|
||||
self.context, 'share', 'create')
|
||||
quota.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, gigabytes=1, shares=1)
|
||||
quota.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, 'reservation')
|
||||
self.stubs.Set(db_driver, 'share_create',
|
||||
mock.Mock(return_value=share))
|
||||
self.stubs.Set(db_driver, 'share_update',
|
||||
mock.Mock(return_value=share))
|
||||
|
||||
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
|
||||
snapshot=snapshot, availability_zone='fakeaz')
|
||||
|
||||
self.share_rpcapi.create_share.assert_called_once_with(
|
||||
self.context, share, snapshot['share']['host'],
|
||||
request_spec=request_spec, filter_properties={},
|
||||
snapshot_id=snapshot['id'])
|
||||
db_driver.share_create.assert_called_once_with(
|
||||
self.context, options)
|
||||
share_api.policy.check_policy.assert_called_once_with(
|
||||
self.context, 'share', 'create')
|
||||
quota.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, gigabytes=1, shares=1)
|
||||
quota.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, 'reservation')
|
||||
|
||||
@mock.patch.object(quota.QUOTAS, 'reserve',
|
||||
mock.Mock(return_value='reservation'))
|
||||
@mock.patch.object(quota.QUOTAS, 'commit', mock.Mock())
|
||||
def test_create_from_snapshot_without_host_restriction(self):
|
||||
CONF.set_default("use_scheduler_creating_share_from_snapshot", True)
|
||||
date = datetime.datetime(1, 1, 1, 1, 1, 1)
|
||||
self.mock_utcnow.return_value = date
|
||||
snapshot = fake_snapshot('fakesnapshotid',
|
||||
share_id='fakeshare_id',
|
||||
status='available')
|
||||
share = fake_share('fakeid',
|
||||
user_id=self.context.user_id,
|
||||
project_id=self.context.project_id,
|
||||
snapshot_id=snapshot['id'],
|
||||
status='creating')
|
||||
options = share.copy()
|
||||
for name in ('id', 'export_location', 'host', 'launched_at',
|
||||
'terminated_at'):
|
||||
options.pop(name, None)
|
||||
request_spec = {
|
||||
'share_properties': options,
|
||||
'share_proto': share['share_proto'],
|
||||
'share_id': share['id'],
|
||||
'volume_type': None,
|
||||
'snapshot_id': share['snapshot_id'],
|
||||
}
|
||||
self.stubs.Set(db_driver, 'share_create',
|
||||
mock.Mock(return_value=share))
|
||||
self.stubs.Set(db_driver, 'share_update',
|
||||
mock.Mock(return_value=share))
|
||||
|
||||
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
|
||||
snapshot=snapshot, availability_zone='fakeaz')
|
||||
|
||||
self.scheduler_rpcapi.create_share.assert_called_once_with(
|
||||
self.context, 'manila-share', share['id'],
|
||||
share['snapshot_id'], request_spec=request_spec,
|
||||
filter_properties={})
|
||||
db_driver.share_create.assert_called_once_with(
|
||||
self.context, options)
|
||||
share_api.policy.check_policy.assert_called_once_with(
|
||||
self.context, 'share', 'create')
|
||||
quota.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, gigabytes=1, shares=1)
|
||||
quota.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, 'reservation')
|
||||
|
||||
@mock.patch.object(quota.QUOTAS, 'reserve',
|
||||
mock.Mock(return_value='reservation'))
|
||||
@mock.patch.object(quota.QUOTAS, 'commit', mock.Mock())
|
||||
def test_create_from_snapshot_with_volume_type_same(self):
|
||||
# Prepare data for test
|
||||
CONF.set_default("use_scheduler_creating_share_from_snapshot", False)
|
||||
date = datetime.datetime(1, 1, 1, 1, 1, 1)
|
||||
self.mock_utcnow.return_value = date
|
||||
share_id = 'fake_share_id'
|
||||
|
@ -506,6 +563,8 @@ class ShareAPITestCase(test.TestCase):
|
|||
}
|
||||
self.stubs.Set(db_driver, 'share_create',
|
||||
mock.Mock(return_value=share))
|
||||
self.stubs.Set(db_driver, 'share_update',
|
||||
mock.Mock(return_value=share))
|
||||
self.stubs.Set(db_driver, 'share_get', mock.Mock(return_value=share))
|
||||
|
||||
# Call tested method
|
||||
|
@ -514,10 +573,10 @@ class ShareAPITestCase(test.TestCase):
|
|||
volume_type=volume_type)
|
||||
|
||||
# Verify results
|
||||
self.scheduler_rpcapi.create_share.assert_called_once_with(
|
||||
self.context, 'manila-share', share_id,
|
||||
share['snapshot_id'], request_spec=request_spec,
|
||||
filter_properties={})
|
||||
self.share_rpcapi.create_share.assert_called_once_with(
|
||||
self.context, share, snapshot['share']['host'],
|
||||
request_spec=request_spec, filter_properties={},
|
||||
snapshot_id=snapshot['id'])
|
||||
db_driver.share_create.assert_called_once_with(
|
||||
self.context, options)
|
||||
share_api.policy.check_policy.assert_called_once_with(
|
||||
|
@ -528,6 +587,8 @@ class ShareAPITestCase(test.TestCase):
|
|||
self.context, 'reservation')
|
||||
db_driver.share_get.assert_called_once_with(
|
||||
self.context, share_id)
|
||||
db_driver.share_update.assert_called_once_with(
|
||||
self.context, share_id, {'host': snapshot['share']['host']})
|
||||
|
||||
@mock.patch.object(quota.QUOTAS, 'reserve',
|
||||
mock.Mock(return_value='reservation'))
|
||||
|
|
Loading…
Reference in New Issue