Merge "Allow drivers to ask for additional share_servers"

This commit is contained in:
Jenkins 2015-06-23 23:58:37 +00:00 committed by Gerrit Code Review
commit 828341fac8
8 changed files with 218 additions and 55 deletions

View File

@ -625,14 +625,12 @@ def share_server_get_by_host_and_share_net(context, host, share_net_id,
session=session)
def share_server_get_by_host_and_share_net_valid(context, host,
share_net_id,
session=None):
def share_server_get_all_by_host_and_share_net_valid(context, host,
share_net_id,
session=None):
"""Get share server DB records by host and share net not error."""
return IMPL.share_server_get_by_host_and_share_net_valid(context,
host,
share_net_id,
session=session)
return IMPL.share_server_get_all_by_host_and_share_net_valid(
context, host, share_net_id, session=session)
def share_server_get_all(context):

View File

@ -2003,13 +2003,14 @@ def share_server_get(context, server_id, session=None):
@require_context
def share_server_get_by_host_and_share_net_valid(context, host, share_net_id,
session=None):
def share_server_get_all_by_host_and_share_net_valid(context, host,
share_net_id,
session=None):
result = _server_get_query(context, session).filter_by(host=host)\
.filter_by(share_network_id=share_net_id)\
.filter(models.ShareServer.status.in_(
(constants.STATUS_CREATING, constants.STATUS_ACTIVE))).first()
if result is None:
(constants.STATUS_CREATING, constants.STATUS_ACTIVE))).all()
if not result:
filters_description = ('share_network_id is "%(share_net_id)s",'
' host is "%(host)s" and status in'
' "%(status_cr)s" or "%(status_act)s"') % {

View File

@ -194,6 +194,10 @@ class ShareServerInUse(InUse):
message = _("Share server %(share_server_id)s is in use.")
class InvalidShareServer(Invalid):
message = _("Share server %(share_server_id)s is not valid.")
class ShareServerNotCreated(ManilaException):
message = _("Share server %(share_server_id)s failed on creation.")

View File

@ -327,6 +327,20 @@ class ShareDriver(object):
if self.get_network_allocations_number():
self.network_api.deallocate_network(context, share_server_id)
def choose_share_server_compatible_with_share(self, context, share_servers,
share, snapshot=None):
"""Method that allows driver to choose share server for provided share.
If compatible share-server is not found, method should return None.
:param context: Current context
:param share_servers: list with share-server models
:param share: share model
:param snapshot: snapshot model
:returns: share-server or None
"""
return share_servers[0] if share_servers else None
def setup_server(self, *args, **kwargs):
if self.driver_handles_share_servers:
return self._setup_server(*args, **kwargs)

View File

@ -206,7 +206,7 @@ class ShareManager(manager.SchedulerDependentManager):
self.publish_service_capabilities(ctxt)
def _provide_share_server_for_share(self, context, share_network_id,
share_id):
share, snapshot=None):
"""Gets or creates share_server and updates share with its id.
Active share_server can be deleted if there are no dependent shares
@ -218,21 +218,87 @@ class ShareManager(manager.SchedulerDependentManager):
For this purpose used shared lock between this method and the one
with deletion of share_server.
:param context: Current context
:param share_network_id: Share network where existing share server
should be found or created. If
share_network_id is None method use
share_network_id from provided snapshot.
:param share: Share model
:param snapshot: Optional -- Snapshot model
:returns: dict, dict -- first value is share_server, that
has been chosen for share schedule. Second value is
share updated with share_server_id.
"""
if not (share_network_id or snapshot):
msg = _("'share_network_id' parameter or 'snapshot'"
" should be provided. ")
raise ValueError(msg)
parent_share_server = None
def error(msg, *args):
LOG.error(msg, *args)
self.db.share_update(context, share['id'],
{'status': constants.STATUS_ERROR})
if snapshot:
parent_share_server_id = snapshot['share']['share_server_id']
try:
parent_share_server = self.db.share_server_get(
context, parent_share_server_id)
except exception.ShareServerNotFound:
with excutils.save_and_reraise_exception():
error(_LE("Parent share server %s does not exist."),
parent_share_server_id)
if parent_share_server['status'] != constants.STATUS_ACTIVE:
error_params = {
'id': parent_share_server_id,
'status': parent_share_server['status'],
}
error(_LE("Parent share server %(id)s has invalid status "
"'%(status)s'."), error_params)
raise exception.InvalidShareServer(
share_server_id=parent_share_server
)
if parent_share_server and not share_network_id:
share_network_id = parent_share_server['share_network_id']
def get_available_share_servers():
if parent_share_server:
return [parent_share_server]
else:
return (
self.db.share_server_get_all_by_host_and_share_net_valid(
context, self.host, share_network_id)
)
@utils.synchronized("share_manager_%s" % share_network_id)
def _provide_share_server_for_share():
exist = False
try:
share_server = \
self.db.share_server_get_by_host_and_share_net_valid(
context, self.host, share_network_id)
exist = True
available_share_servers = get_available_share_servers()
except exception.ShareServerNotFound:
share_server = self.db.share_server_create(
available_share_servers = None
compatible_share_server = None
if available_share_servers:
try:
compatible_share_server = (
self.driver.choose_share_server_compatible_with_share(
context, available_share_servers, share,
snapshot=snapshot
)
)
except Exception as e:
with excutils.save_and_reraise_exception():
error(_LE("Cannot choose compatible share-server: %s"),
e)
if not compatible_share_server:
compatible_share_server = self.db.share_server_create(
context,
{
'host': self.host,
@ -241,23 +307,28 @@ class ShareManager(manager.SchedulerDependentManager):
}
)
LOG.debug("Using share_server %s for share %s" % (
share_server['id'], share_id))
msg = "Using share_server %(share_server)s for share %(share_id)s"
LOG.debug(msg, {
'share_server': compatible_share_server['id'],
'share_id': share['id']
})
share_ref = self.db.share_update(
context,
share_id,
{'share_server_id': share_server['id']},
share['id'],
{'share_server_id': compatible_share_server['id']},
)
if not exist:
# Create share server on backend with data from db
share_server = self._setup_server(context, share_server)
if compatible_share_server['status'] == constants.STATUS_CREATING:
# Create share server on backend with data from db.
compatible_share_server = self._setup_server(
context, compatible_share_server)
LOG.info(_LI("Share server created successfully."))
else:
LOG.info(_LI("Used already existed share server "
LOG.info(_LI("Used preexisting share server "
"'%(share_server_id)s'"),
{'share_server_id': share_server['id']})
return share_server, share_ref
{'share_server_id': compatible_share_server['id']})
return compatible_share_server, share_ref
return _provide_share_server_for_share()
@ -292,24 +363,12 @@ class ShareManager(manager.SchedulerDependentManager):
snapshot_ref = None
parent_share_server_id = None
if parent_share_server_id:
try:
share_server = self.db.share_server_get(context,
parent_share_server_id)
LOG.debug("Using share_server "
"%s for share %s" % (share_server['id'], share_id))
share_ref = self.db.share_update(
context, share_id, {'share_server_id': share_server['id']})
except exception.ShareServerNotFound:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Share server %s does not exist."),
parent_share_server_id)
self.db.share_update(context, share_id,
{'status': constants.STATUS_ERROR})
elif share_network_id:
if share_network_id or parent_share_server_id:
try:
share_server, share_ref = self._provide_share_server_for_share(
context, share_network_id, share_id)
context, share_network_id, share_ref,
snapshot=snapshot_ref
)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Failed to get share server"

View File

@ -1384,6 +1384,21 @@ class GenericShareDriverTestCase(test.TestCase):
fake_server_details, ['sudo', 'resize2fs', '/dev/fake'])
self.assertEqual(2, self._driver._ssh_exec.call_count)
@ddt.data({'share_servers': [], 'result': None},
{'share_servers': None, 'result': None},
{'share_servers': ['fake'], 'result': 'fake'},
{'share_servers': ['fake', 'test'], 'result': 'fake'})
@ddt.unpack
def tests_choose_share_server_compatible_with_share(self, share_servers,
result):
fake_share = "fake"
actual_result = self._driver.choose_share_server_compatible_with_share(
self._context, share_servers, fake_share
)
self.assertEqual(result, actual_result)
@generic.ensure_server
def fake(driver_instance, context, share_server=None):

View File

@ -571,7 +571,10 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_with_share_network_server_creation_failed(self):
fake_share = {'id': 'fake_share_id', 'share_network_id': 'fake_sn_id'}
fake_server = {'id': 'fake_srv_id'}
fake_server = {
'id': 'fake_srv_id',
'status': constants.STATUS_CREATING,
}
self.mock_object(db, 'share_server_create',
mock.Mock(return_value=fake_server))
self.mock_object(db, 'share_update',
@ -586,7 +589,8 @@ class ShareManagerTestCase(test.TestCase):
def raise_manila_exception(*args, **kwargs):
raise exception.ManilaException()
self.mock_object(db, 'share_server_get_by_host_and_share_net_valid',
self.mock_object(db,
'share_server_get_all_by_host_and_share_net_valid',
mock.Mock(side_effect=raise_share_server_not_found))
self.mock_object(self.share_manager, '_setup_server',
mock.Mock(side_effect=raise_manila_exception))
@ -597,7 +601,7 @@ class ShareManagerTestCase(test.TestCase):
self.context,
fake_share['id'],
)
db.share_server_get_by_host_and_share_net_valid.\
db.share_server_get_all_by_host_and_share_net_valid.\
assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
self.share_manager.host,
@ -643,8 +647,12 @@ class ShareManagerTestCase(test.TestCase):
share_id = share['id']
self.share_manager.driver = mock.Mock()
self.share_manager.driver.create_share.return_value = "fake_location"
driver_mock = mock.Mock()
driver_mock.create_share.return_value = "fake_location"
driver_mock.choose_share_server_compatible_with_share.return_value = (
share_srv
)
self.share_manager.driver = driver_mock
self.share_manager.create_share(self.context, share_id)
self.assertFalse(self.share_manager.driver.setup_network.called)
self.assertEqual(share_id, db.share_get(context.get_admin_context(),
@ -683,7 +691,10 @@ class ShareManagerTestCase(test.TestCase):
share_network_id=share_net['id'], host=self.share_manager.host,
state=constants.STATUS_ERROR)
share_id = share['id']
fake_server = {'id': 'fake_srv_id'}
fake_server = {
'id': 'fake_srv_id',
'status': constants.STATUS_CREATING,
}
self.mock_object(db, 'share_server_create',
mock.Mock(return_value=fake_server))
self.mock_object(self.share_manager, '_setup_server',
@ -737,6 +748,67 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(models.Share),
share_server=None)
def test_provide_share_server_for_share_incompatible_servers(self):
fake_exception = exception.ManilaException("fake")
fake_share_server = {'id': 'fake'}
share = self._create_share()
self.mock_object(db,
'share_server_get_all_by_host_and_share_net_valid',
mock.Mock(return_value=[fake_share_server]))
self.mock_object(
self.share_manager.driver,
"choose_share_server_compatible_with_share",
mock.Mock(side_effect=fake_exception)
)
self.assertRaises(exception.ManilaException,
self.share_manager._provide_share_server_for_share,
self.context, "fake_id", share)
driver_mock = self.share_manager.driver
driver_method_mock = (
driver_mock.choose_share_server_compatible_with_share
)
driver_method_mock.assert_called_once_with(
self.context, [fake_share_server], share, snapshot=None)
def test_provide_share_server_for_share_invalid_arguments(self):
self.assertRaises(ValueError,
self.share_manager._provide_share_server_for_share,
self.context, None, None)
def test_provide_share_server_for_share_parent_ss_not_found(self):
fake_parent_id = "fake_server_id"
fake_exception = exception.ShareServerNotFound("fake")
share = self._create_share()
fake_snapshot = {'share': {'share_server_id': fake_parent_id}}
self.mock_object(db, 'share_server_get',
mock.Mock(side_effect=fake_exception))
self.assertRaises(exception.ShareServerNotFound,
self.share_manager._provide_share_server_for_share,
self.context, "fake_id", share,
snapshot=fake_snapshot)
db.share_server_get.assert_called_once_with(
self.context, fake_parent_id)
def test_provide_share_server_for_share_parent_ss_invalid(self):
fake_parent_id = "fake_server_id"
share = self._create_share()
fake_snapshot = {'share': {'share_server_id': fake_parent_id}}
fake_parent_share_server = {'status': 'fake'}
self.mock_object(db, 'share_server_get',
mock.Mock(return_value=fake_parent_share_server))
self.assertRaises(exception.InvalidShareServer,
self.share_manager._provide_share_server_for_share,
self.context, "fake_id", share,
snapshot=fake_snapshot)
db.share_server_get.assert_called_once_with(
self.context, fake_parent_id)
def test_manage_share_invalid_driver(self):
self.mock_object(self.share_manager, 'driver', mock.Mock())
self.share_manager.driver.driver_handles_share_servers = True

View File

@ -105,7 +105,7 @@ class ShareServerTableTestCase(test.TestCase):
db.share_server_update,
self.ctxt, fake_id, {})
def test_share_server_get_by_host_and_share_net_valid(self):
def test_share_server_get_all_by_host_and_share_net_valid(self):
valid = {
'share_network_id': '1',
'host': 'host1',
@ -125,15 +125,15 @@ class ShareServerTableTestCase(test.TestCase):
self._create_share_server(invalid)
self._create_share_server(other)
servers = db.share_server_get_by_host_and_share_net_valid(
servers = db.share_server_get_all_by_host_and_share_net_valid(
self.ctxt,
host='host1',
share_net_id='1')
self.assertEqual(servers['id'], valid['id'])
self.assertEqual(servers[0]['id'], valid['id'])
def test_share_server_get_by_host_and_share_net_not_found(self):
def test_share_server_get_all_by_host_and_share_net_not_found(self):
self.assertRaises(exception.ShareServerNotFound,
db.share_server_get_by_host_and_share_net_valid,
db.share_server_get_all_by_host_and_share_net_valid,
self.ctxt, host='fake', share_net_id='fake')
def test_share_server_get_all(self):