Merge "Add manila share type"

This commit is contained in:
Jenkins 2015-04-21 04:29:03 +00:00 committed by Gerrit Code Review
commit 5b1080ddc5
4 changed files with 225 additions and 0 deletions

View File

@ -0,0 +1,109 @@
#
# 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
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.common.i18n import _
from heat.engine import clients
from heat.engine import properties
from heat.engine import resource
from heat.engine import support
class ManilaShareType(resource.Resource):
"""
A resource for creating manila share type.
A share_type is an administrator-defined "type of service", comprised of
a tenant visible description, and a list of non-tenant-visible key/value
pairs (extra_specs) which the Manila scheduler uses to make scheduling
decisions for shared filesystem tasks.
Please note that share type is intended to use mostly by administrators.
So it is very likely that Manila will prohibit creation of the resource
without administration grants.
"""
support_status = support.SupportStatus(version='2015.2')
PROPERTIES = (
NAME, IS_PUBLIC, DRIVER_HANDLES_SHARE_SERVERS, EXTRA_SPECS
) = (
'name', 'is_public', 'driver_handles_share_servers', 'extra_specs'
)
properties_schema = {
NAME: properties.Schema(
properties.Schema.STRING,
_('Name of the share type.'),
required=True
),
IS_PUBLIC: properties.Schema(
properties.Schema.BOOLEAN,
_('Defines if share type is accessible to the public.'),
default=True
),
DRIVER_HANDLES_SHARE_SERVERS: properties.Schema(
properties.Schema.BOOLEAN,
_('Required extra specification. '
'Defines if share drivers handles share servers. '),
required=True,
),
EXTRA_SPECS: properties.Schema(
properties.Schema.MAP,
_("Extra specs key-value pairs defined for share type."),
update_allowed=True
)
}
default_client_name = 'manila'
def handle_create(self):
share_type = self.client().share_types.create(
name=self.properties.get(self.NAME),
spec_driver_handles_share_servers=self.properties.get(
self.DRIVER_HANDLES_SHARE_SERVERS),
is_public=self.properties.get(self.IS_PUBLIC)
)
self.resource_id_set(share_type.id)
extra_specs = self.properties.get(self.EXTRA_SPECS)
if extra_specs:
share_type.set_keys(extra_specs)
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if self.EXTRA_SPECS in prop_diff:
share_type = self.client().share_types.get(self.resource_id)
extra_specs_old = self.properties.get(self.EXTRA_SPECS)
if extra_specs_old:
share_type.unset_keys(extra_specs_old)
share_type.set_keys(prop_diff.get(self.EXTRA_SPECS))
def handle_delete(self):
if not self.resource_id:
return True
try:
self.client().share_types.delete(self.resource_id)
except Exception as ex:
self.client_plugin().ignore_not_found(ex)
def resource_mapping():
return {
'OS::Manila::ShareType': ManilaShareType
}
def available_resource_mapping():
if not clients.has_client('manila'):
return {}
return resource_mapping()

View File

@ -0,0 +1,116 @@
#
# 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
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import mock
from heat.common import exception
from heat.common import template_format
from heat.engine import resource
from heat.engine import rsrc_defn
from heat.engine import scheduler
from heat.tests import common
from heat.tests import utils
from ..resources import share_type as mshare_type # noqa
manila_template = """
heat_template_version: 2013-05-23
resources:
test_share_type:
type: OS::Manila::ShareType
properties:
name: test_share_type
driver_handles_share_servers: True
extra_specs: {"test":"test"}
is_public: False
"""
class ManilaShareTypeTest(common.HeatTestCase):
def setUp(self):
super(ManilaShareTypeTest, self).setUp()
utils.setup_dummy_db()
self.ctx = utils.dummy_context()
resource._register_class("OS::Manila::ShareType",
mshare_type.ManilaShareType)
@staticmethod
def _init_share(stack_name, share_type_name="test_share_type"):
# parse stack
tmp = template_format.parse(manila_template)
stack = utils.parse_stack(tmp, stack_name=stack_name)
res_def = stack.t.resource_definitions(stack)["test_share_type"]
share_type = mshare_type.ManilaShareType(
share_type_name, res_def, stack)
# mock clients and plugins
mock_client = mock.MagicMock()
client = mock.MagicMock(return_value=mock_client)
share_type.client = client
mock_plugin = mock.MagicMock()
client_plugin = mock.MagicMock(return_value=mock_plugin)
share_type.client_plugin = client_plugin
return share_type
def test_share_type_create(self):
share_type = self._init_share("stack_share_type_create")
fake_share_type = mock.MagicMock(id="type_id")
share_type.client().share_types.create.return_value = fake_share_type
scheduler.TaskRunner(share_type.create)()
self.assertEqual("type_id", share_type.resource_id)
share_type.client().share_types.create.assert_called_once_with(
name="test_share_type", spec_driver_handles_share_servers=True,
is_public=False)
fake_share_type.set_keys.assert_called_once_with({"test": "test"})
def test_share_type_delete(self):
share_type = self._init_share("stack_share_type_delete")
fake_share_type = mock.MagicMock(id="type_id")
share_type.client().share_types.create.return_value = fake_share_type
scheduler.TaskRunner(share_type.create)()
scheduler.TaskRunner(share_type.delete)()
share_type.client().share_types.delete.assert_called_once_with(
"type_id")
def test_share_type_delete_not_found(self):
share_type = self._init_share("stack_share_type_delete_not_found")
fake_share_type = mock.MagicMock(id="type_id")
share_type.client().share_types.create.return_value = fake_share_type
scheduler.TaskRunner(share_type.create)()
exc = exception.NotFound()
share_type.client().share_types.delete.side_effect = exc
scheduler.TaskRunner(share_type.delete)()
share_type.client_plugin().ignore_not_found.assert_called_once_with(
exc)
def test_share_type_update(self):
share_type = self._init_share("stack_share_type_update")
share_type.client().share_types.create.return_value = mock.MagicMock(
id="type_id")
fake_share_type = mock.MagicMock()
share_type.client().share_types.get.return_value = fake_share_type
scheduler.TaskRunner(share_type.create)()
updated_props = copy.deepcopy(share_type.properties.data)
updated_props[mshare_type.ManilaShareType.EXTRA_SPECS] = {
"fake_key": "fake_value"}
after = rsrc_defn.ResourceDefinition(share_type.name,
share_type.type(), updated_props)
scheduler.TaskRunner(share_type.update, after)()
fake_share_type.unset_keys.assert_called_once_with({"test": "test"})
fake_share_type.set_keys.assert_called_with(
updated_props[mshare_type.ManilaShareType.EXTRA_SPECS])