Set share-type on share created from snapshot

This commit ensures that when one creates a share from a snapshot
the new share has the same share-type as the share on which the
snapshot is based.

Closes-bug: 1420369

Change-Id: Icad04edd3eab6d40e56352a9a7d298b6efd80e93
This commit is contained in:
Tom Barron 2015-02-10 05:02:07 -08:00
parent e7259cb867
commit ee14370097
3 changed files with 118 additions and 15 deletions

View File

@ -1,5 +1,5 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
# Copyright 2014 Mirantis Inc. All Rights Reserved.
# Copyright (c) 2015 Yogesh Kshirsagar. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -178,7 +178,7 @@ class SharesActionsAdminTest(base.BaseSharesAdminTest):
self.assertTrue(len(shares) > 0)
shares_ids = [s["id"] for s in shares]
self.assertTrue(self.share["id"] in shares_ids)
self.assertFalse(self.share2["id"] in shares_ids)
self.assertTrue(self.share2["id"] in shares_ids)
for share in shares:
__, st_list = self.shares_client.list_share_types()
# find its name or id, get id
@ -224,7 +224,9 @@ class SharesActionsAdminTest(base.BaseSharesAdminTest):
)
self.assertEqual(
filters['share_type_id'], st_id)
self.assertFalse(self.share2['id'] in [s['id'] for s in shares])
share_ids = [share['id'] for share in shares]
self.assertTrue(self.share['id'] in share_ids)
self.assertTrue(self.share2['id'] in share_ids)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_host(self):

View File

@ -1,6 +1,7 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
# Copyright (c) 2015 Tom Barron. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -36,6 +37,7 @@ from manila import policy
from manila import quota
from manila.scheduler import rpcapi as scheduler_rpcapi
from manila.share import rpcapi as share_rpcapi
from manila.share import share_types
share_api_opts = [
cfg.BoolOpt('use_scheduler_creating_share_from_snapshot',
@ -99,13 +101,25 @@ class API(base.Base):
"than snapshot size") % size)
raise exception.InvalidInput(reason=msg)
if snapshot and share_type:
if snapshot is None:
share_type_id = share_type['id'] if share_type else None
else:
source_share = self.db.share_get(context, snapshot['share_id'])
if share_type['id'] != source_share['share_type_id']:
msg = _("Invalid share_type provided (requested type "
"must match source snapshot, or be omitted). "
"You should omit the argument.")
raise exception.InvalidInput(reason=msg)
if share_type is None:
share_type_id = source_share['share_type_id']
if share_type_id is not None:
share_type = share_types.get_share_type(context,
share_type_id)
else:
share_type_id = share_type['id']
if share_type_id != source_share['share_type_id']:
msg = _("Invalid share type specified: the requested "
"share type must match the type of the source "
"share. If a share type is not specified when "
"requesting a new share from a snapshot, the "
"share type of the source share will be applied "
"to the new share.")
raise exception.InvalidInput(reason=msg)
supported_share_protocols = (
proto.upper() for proto in CONF.enabled_share_protocols)
@ -165,7 +179,7 @@ class API(base.Base):
'display_name': name,
'display_description': description,
'share_proto': share_proto,
'share_type_id': share_type['id'] if share_type else None,
'share_type_id': share_type_id,
'is_public': is_public,
}

View File

@ -1,5 +1,5 @@
# Copyright 2012 NetApp
# All Rights Reserved.
# Copyright 2012 NetApp. All rights reserved.
# Copyright (c) 2015 Tom Barron. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@ -34,6 +34,7 @@ from manila import exception
from manila import quota
from manila import share
from manila.share import api as share_api
from manila.share import share_types
from manila import test
from manila.tests.db import fakes as db_fakes
from manila.tests import utils as test_utils
@ -749,8 +750,12 @@ class ShareAPITestCase(test.TestCase):
CONF.set_default("use_scheduler_creating_share_from_snapshot", False)
date = datetime.datetime(1, 1, 1, 1, 1, 1)
timeutils.utcnow.return_value = date
original_share = fake_share('fake_original_id',
user_id=self.context.user_id,
project_id=self.context.project_id,
status='available')
snapshot = fake_snapshot('fakesnapshotid',
share_id='fakeshare_id',
share_id=original_share['id'],
status='available')
share = fake_share('fakeid',
user_id=self.context.user_id,
@ -768,6 +773,9 @@ class ShareAPITestCase(test.TestCase):
'share_type': None,
'snapshot_id': share['snapshot_id'],
}
self.mock_object(db_driver, 'share_get',
mock.Mock(return_value=original_share))
self.mock_object(share_types, 'get_share_type')
self.mock_object(db_driver, 'share_create',
mock.Mock(return_value=share))
self.mock_object(db_driver, 'share_update',
@ -776,6 +784,9 @@ class ShareAPITestCase(test.TestCase):
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
snapshot=snapshot, availability_zone='fakeaz')
db_driver.share_get.assert_called_once_with(
self.context, snapshot['share_id'])
self.assertEqual(0, share_types.get_share_type.call_count)
self.share_rpcapi.create_share.assert_called_once_with(
self.context, share, snapshot['share']['host'],
request_spec=request_spec, filter_properties={},
@ -796,8 +807,12 @@ class ShareAPITestCase(test.TestCase):
CONF.set_default("use_scheduler_creating_share_from_snapshot", True)
date = datetime.datetime(1, 1, 1, 1, 1, 1)
timeutils.utcnow.return_value = date
original_share = fake_share('fake_original_id',
user_id=self.context.user_id,
project_id=self.context.project_id,
status='available')
snapshot = fake_snapshot('fakesnapshotid',
share_id='fakeshare_id',
share_id=original_share['id'],
status='available')
share = fake_share('fakeid',
user_id=self.context.user_id,
@ -815,6 +830,9 @@ class ShareAPITestCase(test.TestCase):
'share_type': None,
'snapshot_id': share['snapshot_id'],
}
self.mock_object(db_driver, 'share_get',
mock.Mock(return_value=original_share))
self.mock_object(share_types, 'get_share_type')
self.mock_object(db_driver, 'share_create',
mock.Mock(return_value=share))
self.mock_object(db_driver, 'share_update',
@ -823,6 +841,9 @@ class ShareAPITestCase(test.TestCase):
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
snapshot=snapshot, availability_zone='fakeaz')
db_driver.share_get.assert_called_once_with(
self.context, snapshot['share_id'])
self.assertEqual(0, share_types.get_share_type.call_count)
self.scheduler_rpcapi.create_share.assert_called_once_with(
self.context, 'manila-share', share['id'],
share['snapshot_id'], request_spec=request_spec,
@ -935,6 +956,72 @@ class ShareAPITestCase(test.TestCase):
db_driver.share_get.assert_called_once_with(
self.context, share_id)
@mock.patch.object(quota.QUOTAS, 'reserve',
mock.Mock(return_value='reservation'))
@mock.patch.object(quota.QUOTAS, 'commit', mock.Mock())
def test_create_from_snapshot_share_type_from_original(self):
# Prepare data for test
CONF.set_default("use_scheduler_creating_share_from_snapshot", False)
date = datetime.datetime(1, 1, 1, 1, 1, 1)
timeutils.utcnow.return_value = date
share_type = {'id': 'fake_share_type'}
original_share = fake_share('fake_original_id',
user_id=self.context.user_id,
project_id=self.context.project_id,
share_type_id='fake_share_type_id',
status='available')
share_id = 'fake_share_id'
snapshot = fake_snapshot('fakesnapshotid',
share_id=original_share['id'],
status='available')
share = fake_share(share_id, user_id=self.context.user_id,
project_id=self.context.project_id,
snapshot_id=snapshot['id'], status='creating',
share_type_id=original_share['share_type_id'])
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,
'share_type': share_type,
'snapshot_id': share['snapshot_id'],
}
self.mock_object(db_driver, 'share_get',
mock.Mock(return_value=original_share))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=share_type))
self.mock_object(db_driver, 'share_create',
mock.Mock(return_value=share))
self.mock_object(db_driver, 'share_update',
mock.Mock(return_value=share))
self.mock_object(db_driver, 'share_get',
mock.Mock(return_value=share))
# Call tested method
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
snapshot=snapshot, availability_zone='fakeaz')
# Verify results
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')
db_driver.share_get.assert_called_once_with(
self.context, original_share['id'])
db_driver.share_update.assert_called_once_with(
self.context, share_id, {'host': snapshot['share']['host']})
def test_get_snapshot(self):
fake_get_snap = {'fake_key': 'fake_val'}
with mock.patch.object(db_driver, 'share_snapshot_get',