You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
10 KiB
243 lines
10 KiB
# |
|
# 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 DummyShare(object): |
|
def __init__(self): |
|
self.availability_zone = 'az' |
|
self.host = 'host' |
|
self.export_locations = 'el' |
|
self.share_server_id = 'id' |
|
self.created_at = 'ca' |
|
self.status = 's' |
|
self.project_id = 'p_id' |
|
|
|
|
|
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]) |
|
|
|
def test_attributes(self): |
|
share = self._create_share("share") |
|
share.client().shares.get.return_value = DummyShare() |
|
self.assertEqual('az', share.FnGetAtt('availability_zone')) |
|
self.assertEqual('host', share.FnGetAtt('host')) |
|
self.assertEqual('el', share.FnGetAtt('export_locations')) |
|
self.assertEqual('id', share.FnGetAtt('share_server_id')) |
|
self.assertEqual('ca', share.FnGetAtt('created_at')) |
|
self.assertEqual('s', share.FnGetAtt('status')) |
|
self.assertEqual('p_id', share.FnGetAtt('project_id'))
|
|
|