manila/manila/tests/share/drivers/nexenta/ns5/test_nexenta_nas.py

379 lines
14 KiB
Python

# Copyright 2016 Nexenta Systems, Inc.
# 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
# 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 ddt
import mock
from mock import patch
from oslo_utils import units
from manila import context
from manila import exception
from manila.share import configuration as conf
from manila.share.drivers.nexenta.ns5 import nexenta_nas
from manila import test
PATH_TO_RPC = 'manila.share.drivers.nexenta.ns5.jsonrpc.NexentaJSONProxy'
DRV_PATH = 'manila.share.drivers.nexenta.ns5.nexenta_nas.NexentaNasDriver'
@ddt.ddt
class TestNexentaNasDriver(test.TestCase):
def setUp(self):
def _safe_get(opt):
return getattr(self.cfg, opt)
self.cfg = conf.Configuration(None)
self.cfg.nexenta_host = '1.1.1.1'
super(TestNexentaNasDriver, self).setUp()
self.ctx = context.get_admin_context()
self.mock_object(
self.cfg, 'safe_get', mock.Mock(side_effect=_safe_get))
self.cfg.nexenta_rest_port = 8080
self.cfg.nexenta_rest_protocol = 'auto'
self.cfg.nexenta_pool = 'pool1'
self.cfg.reserved_share_percentage = 0
self.cfg.nexenta_nfs_share = 'nfs_share'
self.cfg.nexenta_user = 'user'
self.cfg.share_backend_name = 'NexentaStor5'
self.cfg.nexenta_password = 'password'
self.cfg.nexenta_thin_provisioning = False
self.cfg.nexenta_mount_point_base = 'mnt'
self.cfg.enabled_share_protocols = 'NFS'
self.cfg.nexenta_mount_point_base = '$state_path/mnt'
self.cfg.nexenta_dataset_compression = 'on'
self.cfg.network_config_group = 'DEFAULT'
self.cfg.admin_network_config_group = (
'fake_admin_network_config_group')
self.cfg.driver_handles_share_servers = False
self.drv = nexenta_nas.NexentaNasDriver(configuration=self.cfg)
self.drv.do_setup(self.ctx)
self.mock_rpc = self.mock_class(PATH_TO_RPC)
self.pool_name = self.cfg.nexenta_pool
self.fs_prefix = self.cfg.nexenta_nfs_share
def test_backend_name(self):
self.assertEqual('NexentaStor5', self.drv.share_backend_name)
@patch('%s._get_provisioned_capacity' % DRV_PATH)
def test_check_for_setup_error(self, mock_provisioned):
self.drv.nef.get.return_value = None
self.assertRaises(LookupError, self.drv.check_for_setup_error)
@patch('%s._get_provisioned_capacity' % DRV_PATH)
def test_check_for_setup_error__none(self, mock_provisioned):
self.drv.nef.get.return_value = {
'data': [{'filesystem': 'pool1/nfs_share', 'quotaSize': 1}]
}
self.assertIsNone(self.drv.check_for_setup_error())
@patch('%s._get_provisioned_capacity' % DRV_PATH)
def test_check_for_setup_error__with_data(self, mock_provisioned):
self.drv.nef.get.return_value = {
'data': [{'filesystem': 'asd', 'quotaSize': 1}]}
self.assertRaises(LookupError, self.drv.check_for_setup_error)
def test__get_provisioned_capacity(self):
self.drv.nef.get.return_value = {
'data': [
{'path': 'pool1/nfs_share/123', 'quotaSize': 1 * units.Gi}]
}
self.drv._get_provisioned_capacity()
self.assertEqual(1, self.drv.provisioned_capacity)
def test_create_share(self):
share = {'name': 'share', 'size': 1}
self.assertEqual(
[{
'path': '{}:/{}/{}/{}'.format(
self.cfg.nexenta_host, self.pool_name,
self.fs_prefix, share['name'])
}],
self.drv.create_share(self.ctx, share))
@patch('%s.delete_share' % DRV_PATH)
@patch('%s._add_permission' % DRV_PATH)
def test_create_share__error_on_add_permission(
self, add_permission_mock, delete_share):
share = {'name': 'share', 'size': 1}
add_permission_mock.side_effect = exception.NexentaException(
'An error occurred while adding permission')
delete_share.side_effect = exception.NexentaException(
'An error occurred while deleting')
self.assertRaises(
exception.NexentaException, self.drv.create_share, self.ctx, share)
def test_create_share_from_snapshot(self):
share = {'name': 'share', 'size': 1}
snapshot = {'name': 'share@first', 'share_name': 'share'}
self.assertEqual(
[{
'path': '{}:/{}/{}/{}'.format(
self.cfg.nexenta_host, self.pool_name,
self.fs_prefix, share['name'])
}],
self.drv.create_share_from_snapshot(self.ctx, share, snapshot)
)
@patch('%s.delete_share' % DRV_PATH)
@patch('%s._add_permission' % DRV_PATH)
def test_create_share_from_snapshot__add_permission_error(
self, add_permission_mock, delete_share):
share = {'name': 'share', 'size': 1}
snapshot = {'share_name': 'share', 'name': 'share@first'}
delete_share.side_effect = exception.NexentaException(
'An error occurred while deleting')
add_permission_mock.side_effect = exception.NexentaException(
'Some exception')
self.assertRaises(
exception.NexentaException, self.drv.create_share_from_snapshot,
self.ctx, share, snapshot)
@patch('%s._add_permission' % DRV_PATH)
def test_create_share_from_snapshot__add_permission_error_error(
self, add_permission_mock):
share = {'name': 'share', 'size': 1}
snapshot = {'share_name': 'share', 'name': 'share@first'}
add_permission_mock.side_effect = exception.NexentaException(
'Some exception')
self.drv.nef.delete.side_effect = exception.NexentaException(
'Some exception 2')
self.assertRaises(
exception.NexentaException, self.drv.create_share_from_snapshot,
self.ctx, share, snapshot)
def test_delete_share(self):
share = {'name': 'share', 'size': 1}
self.assertIsNone(self.drv.delete_share(self.ctx, share))
def test_extend_share(self):
share = {'name': 'share', 'size': 1}
new_size = 2
quota = new_size * units.Gi
data = {
'reservationSize': quota,
'quotaSize': quota,
}
url = 'storage/pools/{}/filesystems/{}%2F{}'.format(
self.pool_name, self.fs_prefix, share['name'])
self.drv.extend_share(share, new_size)
self.drv.nef.post.assert_called_with(url, data)
def test_shrink_share(self):
share = {'name': 'share', 'size': 2}
new_size = 1
quota = new_size * units.Gi
data = {
'reservationSize': quota,
'quotaSize': quota
}
url = 'storage/pools/{}/filesystems/{}%2F{}'.format(
self.pool_name, self.fs_prefix, share['name'])
self.drv.nef.get.return_value = {'bytesUsed': 512}
self.drv.shrink_share(share, new_size)
self.drv.nef.post.assert_called_with(url, data)
def test_create_snapshot(self):
snapshot = {'share_name': 'share', 'name': 'share@first'}
url = 'storage/pools/%(pool)s/filesystems/%(fs)s/snapshots' % {
'pool': self.pool_name,
'fs': nexenta_nas.PATH_DELIMITER.join(
[self.fs_prefix, snapshot['share_name']])
}
data = {'name': snapshot['name']}
self.drv.create_snapshot(self.ctx, snapshot)
self.drv.nef.post.assert_called_with(url, data)
def test_delete_snapshot(self):
self.mock_rpc.side_effect = exception.NexentaException(
'err', code='ENOENT')
snapshot = {'share_name': 'share', 'name': 'share@first'}
self.assertIsNone(self.drv.delete_snapshot(self.ctx, snapshot))
self.mock_rpc.side_effect = exception.NexentaException(
'err', code='somecode')
self.assertRaises(
exception.NexentaException, self.drv.delete_snapshot,
self.ctx, snapshot)
def build_access_security_context(self, level, ip, mask=None):
ls = [{"allow": True, "etype": "network", "entity": ip}]
if mask is not None:
ls[0]['mask'] = mask
new_sc = {
"securityModes": ["sys"],
}
if level == 'rw':
new_sc['readWriteList'] = ls
elif level == 'ro':
new_sc['readOnlyList'] = ls
else:
raise exception.ManilaException('Wrong access level')
return new_sc
def test_update_access__unsupported_access_type(self):
share = {'name': 'share', 'size': 1}
access = {
'access_type': 'group',
'access_to': 'ordinary_users',
'access_level': 'rw'
}
self.assertRaises(exception.InvalidShareAccess, self.drv.update_access,
self.ctx, share, [access], None, None)
def test_update_access__cidr(self):
share = {'name': 'share', 'size': 1}
access = {
'access_type': 'ip',
'access_to': '1.1.1.1/24',
'access_level': 'rw'
}
url = 'nas/nfs/' + nexenta_nas.PATH_DELIMITER.join(
(self.pool_name, self.fs_prefix, share['name']))
self.drv.nef.get.return_value = {}
self.drv.update_access(self.ctx, share, [access], None, None)
self.drv.nef.put.assert_called_with(
url, {'securityContexts': [
self.build_access_security_context('rw', '1.1.1.1', 24)]})
def test_update_access__ip(self):
share = {'name': 'share', 'size': 1}
access = {
'access_type': 'ip',
'access_to': '1.1.1.1',
'access_level': 'rw'
}
url = 'nas/nfs/' + nexenta_nas.PATH_DELIMITER.join(
(self.pool_name, self.fs_prefix, share['name']))
self.drv.nef.get.return_value = {}
self.drv.update_access(self.ctx, share, [access], None, None)
self.drv.nef.put.assert_called_with(
url, {'securityContexts': [
self.build_access_security_context('rw', '1.1.1.1')]})
@ddt.data('rw', 'ro')
def test_update_access__cidr_wrong_mask(self, access_level):
share = {'name': 'share', 'size': 1}
access = {
'access_type': 'ip',
'access_to': '1.1.1.1/aa',
'access_level': access_level,
}
self.assertRaises(exception.InvalidInput, self.drv.update_access,
self.ctx, share, [access], None, None)
def test_update_access__one_ip_ro_add_rule_to_existing(self):
share = {'name': 'share', 'size': 1}
access = [
{
'access_type': 'ip',
'access_to': '5.5.5.5',
'access_level': 'ro'
},
{
'access_type': 'ip',
'access_to': '1.1.1.1/24',
'access_level': 'rw'
}
]
url = 'nas/nfs/' + nexenta_nas.PATH_DELIMITER.join(
(self.pool_name, self.fs_prefix, share['name']))
sc = self.build_access_security_context('rw', '1.1.1.1', 24)
self.drv.nef.get.return_value = {'securityContexts': [sc]}
self.drv.update_access(self.ctx, share, access, None, None)
self.drv.nef.put.assert_called_with(
url, {'securityContexts': [
sc, self.build_access_security_context('ro', '5.5.5.5')]})
def test_update_access__one_ip_ro_add_rule_to_existing_wrong_mask(
self):
share = {'name': 'share', 'size': 1}
access = [
{
'access_type': 'ip',
'access_to': '5.5.5.5/aa',
'access_level': 'ro'
},
{
'access_type': 'ip',
'access_to': '1.1.1.1/24',
'access_level': 'rw'
}
]
sc = self.build_access_security_context('rw', '1.1.1.1', 24)
self.drv.nef.get.return_value = {'securityContexts': [sc]}
self.assertRaises(exception.InvalidInput, self.drv.update_access,
self.ctx, share, access, None, None)
@patch('%s._get_capacity_info' % DRV_PATH)
@patch('manila.share.driver.ShareDriver._update_share_stats')
def test_update_share_stats(self, super_stats, info):
info.return_value = (100, 90, 10)
stats = {
'vendor_name': 'Nexenta',
'storage_protocol': 'NFS',
'nfs_mount_point_base': self.cfg.nexenta_mount_point_base,
'driver_version': '1.0',
'share_backend_name': self.cfg.share_backend_name,
'pools': [{
'pool_name': 'pool1',
'total_capacity_gb': 100,
'free_capacity_gb': 90,
'provisioned_capacity_gb': 0,
'max_over_subscription_ratio': 20.0,
'reserved_percentage': (
self.cfg.reserved_share_percentage),
'thin_provisioning': self.cfg.nexenta_thin_provisioning,
}],
}
self.drv._update_share_stats()
self.assertEqual(stats, self.drv._stats)
def test_get_capacity_info(self):
self.drv.nef.get.return_value = {
'bytesAvailable': 10 * units.Gi, 'bytesUsed': 1 * units.Gi}
self.assertEqual((10, 9, 1), self.drv._get_capacity_info())