heat/heat/tests/manila/test_manila_share.py

222 lines
9.4 KiB
Python

#
# 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 collections
import copy
import mock
import six
from heat.common import exception
from heat.common import template_format
from heat.engine import resource
from heat.engine.resources.openstack.manila import share as mshare
from heat.engine import rsrc_defn
from heat.engine import scheduler
from heat.tests import common
from heat.tests import utils
manila_template = """
heat_template_version: 2015-04-30
resources:
test_share:
type: OS::Manila::Share
properties:
share_protocol: NFS
size: 1
access_rules:
- access_to: 127.0.0.1
access_type: ip
access_level: ro
name: basic_test_share
description: basic test share
is_public: True
metadata: {"key": "value"}
"""
class ManilaShareTest(common.HeatTestCase):
def setUp(self):
super(ManilaShareTest, self).setUp()
utils.setup_dummy_db()
self.ctx = utils.dummy_context()
self.fake_share = mock.MagicMock(id="test_share_id")
self.available_share = mock.MagicMock(
id="test_share_id",
status=mshare.ManilaShare.STATUS_AVAILABLE)
self.failed_share = mock.MagicMock(
id="test_share_id",
status=mshare.ManilaShare.STATUS_ERROR)
self.deleting_share = mock.MagicMock(
id="test_share_id",
status=mshare.ManilaShare.STATUS_DELETING)
def _init_share(self, stack_name):
tmp = template_format.parse(manila_template)
self.stack = utils.parse_stack(tmp, stack_name=stack_name)
res_def = self.stack.t.resource_definitions(self.stack)["test_share"]
share = mshare.ManilaShare("test_share", res_def, self.stack)
# replace clients and plugins with mocks
mock_client = mock.MagicMock()
client = mock.MagicMock(return_value=mock_client)
share.client = client
mock_plugin = mock.MagicMock()
client_plugin = mock.MagicMock(return_value=mock_plugin)
share.client_plugin = client_plugin
return share
def _create_share(self, stack_name):
share = self._init_share(stack_name)
share.client().shares.create.return_value = self.fake_share
share.client().shares.get.return_value = self.available_share
scheduler.TaskRunner(share.create)()
return share
def test_share_create(self):
share = self._create_share("stack_share_create")
expected_state = (share.CREATE, share.COMPLETE)
self.assertEqual(expected_state, share.state,
"Share is not in expected state")
self.assertEqual(self.fake_share.id, share.resource_id,
"Expected share ID was not propagated to share")
share.client().shares.allow.assert_called_once_with(
access="127.0.0.1", access_level="ro",
share=share.resource_id, access_type="ip")
args, kwargs = share.client().shares.create.call_args
message_end = " parameter was not passed to manila client"
self.assertEqual(u"NFS", kwargs["share_proto"],
"Share protocol" + message_end)
self.assertEqual(1, kwargs["size"], "Share size" + message_end)
self.assertEqual("basic_test_share", kwargs["name"],
"Share name" + message_end)
self.assertEqual("basic test share", kwargs["description"],
"Share description" + message_end)
self.assertEqual({u"key": u"value"}, kwargs["metadata"],
"Metadata" + message_end)
self.assertTrue(kwargs["is_public"])
share.client().shares.get.assert_called_once_with(self.fake_share.id)
def test_share_create_fail(self):
share = self._init_share("stack_share_create_fail")
share.client().shares.get.return_value = self.failed_share
exc = self.assertRaises(resource.ResourceInError,
share.check_create_complete,
self.failed_share)
self.assertIn("Error during creation", six.text_type(exc))
def test_share_create_unknown_status(self):
share = self._init_share("stack_share_create_unknown")
share.client().shares.get.return_value = self.deleting_share
exc = self.assertRaises(resource.ResourceUnknownStatus,
share.check_create_complete,
self.deleting_share)
self.assertIn("Unknown status", six.text_type(exc))
def test_share_delete(self):
share = self._create_share("stack_share_delete")
share.client().shares.get.side_effect = exception.NotFound()
share.client_plugin().ignore_not_found.return_value = None
scheduler.TaskRunner(share.delete)()
share.client().shares.delete.assert_called_once_with(
self.fake_share.id)
def test_share_delete_fail(self):
share = self._create_share("stack_share_delete_fail")
share.client().shares.delete.return_value = None
share.client().shares.get.return_value = self.failed_share
exc = self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(share.delete))
self.assertIn("Error during deleting share", six.text_type(exc))
def test_share_check(self):
share = self._create_share("stack_share_check")
scheduler.TaskRunner(share.check)()
expected_state = (share.CHECK, share.COMPLETE)
self.assertEqual(expected_state, share.state,
"Share is not in expected state")
def test_share_check_fail(self):
share = self._create_share("stack_share_check_fail")
share.client().shares.get.return_value = self.failed_share
exc = self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(share.check))
self.assertIn("Error: resources.test_share: 'status': expected "
"'['available']'", six.text_type(exc))
def test_share_update(self):
share = self._create_share("stack_share_update")
updated_share_props = copy.deepcopy(share.properties.data)
updated_share_props[mshare.ManilaShare.DESCRIPTION] = "desc"
updated_share_props[mshare.ManilaShare.NAME] = "name"
updated_share_props[mshare.ManilaShare.IS_PUBLIC] = True
share.client().shares.update.return_value = None
after = rsrc_defn.ResourceDefinition(share.name, share.type(),
updated_share_props)
scheduler.TaskRunner(share.update, after)()
kwargs = {
"display_name": "name",
"display_description": "desc",
}
share.client().shares.update.assert_called_once_with(
share.resource_id, **kwargs)
def test_share_update_access_rules(self):
share = self._create_share("stack_share_update_access_rules")
updated_share_props = copy.deepcopy(share.properties.data)
updated_share_props[mshare.ManilaShare.ACCESS_RULES] = [
{mshare.ManilaShare.ACCESS_TO: "127.0.0.2",
mshare.ManilaShare.ACCESS_TYPE: "ip",
mshare.ManilaShare.ACCESS_LEVEL: "ro"}]
share.client().shares.deny.return_value = None
current_rule = {
mshare.ManilaShare.ACCESS_TO: "127.0.0.1",
mshare.ManilaShare.ACCESS_TYPE: "ip",
mshare.ManilaShare.ACCESS_LEVEL: "ro",
"id": "test_access_rule"
}
rule_tuple = collections.namedtuple("DummyRule",
list(current_rule.keys()))
share.client().shares.access_list.return_value = [
rule_tuple(**current_rule)]
after = rsrc_defn.ResourceDefinition(share.name, share.type(),
updated_share_props)
scheduler.TaskRunner(share.update, after)()
share.client().shares.access_list.assert_called_once_with(
share.resource_id)
share.client().shares.allow.assert_called_with(
share=share.resource_id, access_type="ip",
access="127.0.0.2", access_level="ro")
share.client().shares.deny.assert_called_once_with(
share=share.resource_id, id="test_access_rule")
def test_share_update_metadata(self):
share = self._create_share("stack_share_update_metadata")
updated_share_props = copy.deepcopy(share.properties.data)
updated_share_props[mshare.ManilaShare.METADATA] = {
"fake_key": "fake_value"}
share.client().shares.update_all_metadata.return_value = None
after = rsrc_defn.ResourceDefinition(share.name, share.type(),
updated_share_props)
scheduler.TaskRunner(share.update, after)()
share.client().shares.update_all_metadata.assert_called_once_with(
share.resource_id,
updated_share_props[mshare.ManilaShare.METADATA])