cinder/cinder/tests/unit/volume/drivers/nexenta/test_nexenta5_jsonrpc.py

1209 lines
43 KiB
Python

# Copyright 2019 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.
"""Unit tests for NexentaStor 5 REST API helper."""
import copy
import json
import posixpath
from unittest import mock
import uuid
from oslo_utils.secretutils import md5
import requests
import six
from cinder.tests.unit import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.nexenta.ns5 import jsonrpc
class FakeNefProxy(object):
def __init__(self):
self.scheme = 'https'
self.port = 8443
self.hosts = ['1.1.1.1', '2.2.2.2']
self.host = self.hosts[0]
self.root = 'pool/share'
self.username = 'username'
self.password = 'password'
self.retries = 3
self.timeout = 5
self.session = mock.Mock()
self.session.headers = {}
def __getattr__(self, name):
pass
def delay(self, interval):
pass
def delete_bearer(self):
pass
def update_lock(self):
pass
def update_token(self, token):
pass
def update_host(self, host):
pass
def url(self, path):
return '%s://%s:%s/%s' % (self.scheme, self.host, self.port, path)
class TestNefException(test.TestCase):
def test_message(self):
message = 'test message 1'
result = jsonrpc.NefException(message)
self.assertIn(message, result.msg)
def test_message_kwargs(self):
code = 'EAGAIN'
message = 'test message 2'
result = jsonrpc.NefException(message, code=code)
self.assertEqual(code, result.code)
self.assertIn(message, result.msg)
def test_no_message_kwargs(self):
code = 'ESRCH'
message = 'test message 3'
result = jsonrpc.NefException(None, code=code, message=message)
self.assertEqual(code, result.code)
self.assertIn(message, result.msg)
def test_message_plus_kwargs(self):
code = 'ENODEV'
message1 = 'test message 4'
message2 = 'test message 5'
result = jsonrpc.NefException(message1, code=code, message=message2)
self.assertEqual(code, result.code)
self.assertIn(message2, result.msg)
def test_dict(self):
code = 'ENOENT'
message = 'test message 4'
result = jsonrpc.NefException({'code': code, 'message': message})
self.assertEqual(code, result.code)
self.assertIn(message, result.msg)
def test_kwargs(self):
code = 'EPERM'
message = 'test message 5'
result = jsonrpc.NefException(code=code, message=message)
self.assertEqual(code, result.code)
self.assertIn(message, result.msg)
def test_dict_kwargs(self):
code = 'EINVAL'
message = 'test message 6'
result = jsonrpc.NefException({'code': code}, message=message)
self.assertEqual(code, result.code)
self.assertIn(message, result.msg)
def test_defaults(self):
code = 'EBADMSG'
message = 'NexentaError'
result = jsonrpc.NefException()
self.assertEqual(code, result.code)
self.assertIn(message, result.msg)
class TestNefRequest(test.TestCase):
def setUp(self):
super(TestNefRequest, self).setUp()
self.proxy = FakeNefProxy()
def fake_response(self, method, path, payload, code, content):
request = requests.PreparedRequest()
request.method = method
request.url = self.proxy.url(path)
request.headers = {'Content-Type': 'application/json'}
request.body = None
if method in ['get', 'delete']:
request.params = payload
elif method in ['put', 'post']:
request.data = json.dumps(payload)
response = requests.Response()
response.request = request
response.status_code = code
if content:
response._content = json.dumps(content)
else:
response._content = ''
return response
def test___call___invalid_method(self):
method = 'unsupported'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
self.assertRaises(jsonrpc.NefException, instance, path)
def test___call___none_path(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
self.assertRaises(jsonrpc.NefException, instance, None)
def test___call___empty_path(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
self.assertRaises(jsonrpc.NefException, instance, '')
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___get(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {}
content = {'name': 'snapshot'}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
request.assert_called_with(method, path)
self.assertEqual(content, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___get_payload(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'name': 'snapshot'}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
params = {'params': payload}
request.assert_called_with(method, path, **params)
self.assertEqual(content, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___get_data_payload(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
data = [
{
'name': 'fs1',
'path': 'pool/fs1'
},
{
'name': 'fs2',
'path': 'pool/fs2'
}
]
content = {'data': data}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
instance.data = data
result = instance(path, payload)
params = {'params': payload}
request.assert_called_with(method, path, **params)
self.assertEqual(data, result)
def test___call___get_invalid_payload(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = 'bad data'
self.assertRaises(jsonrpc.NefException, instance, path, payload)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___delete(self, request):
method = 'delete'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {}
content = {'name': 'snapshot'}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
request.assert_called_with(method, path)
self.assertEqual(content, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___delete_payload(self, request):
method = 'delete'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'name': 'snapshot'}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
params = {'params': payload}
request.assert_called_with(method, path, **params)
self.assertEqual(content, result)
def test___call___delete_invalid_payload(self):
method = 'delete'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = 'bad data'
self.assertRaises(jsonrpc.NefException, instance, path, payload)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___post(self, request):
method = 'post'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {}
content = None
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
request.assert_called_with(method, path)
self.assertEqual(content, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___post_payload(self, request):
method = 'post'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = None
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
params = {'data': json.dumps(payload)}
request.assert_called_with(method, path, **params)
self.assertEqual(content, result)
def test___call___post_invalid_payload(self):
method = 'post'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = 'bad data'
self.assertRaises(jsonrpc.NefException, instance, path, payload)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___put(self, request):
method = 'put'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {}
content = None
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
request.assert_called_with(method, path)
self.assertEqual(content, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___put_payload(self, request):
method = 'put'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = None
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance(path, payload)
params = {'data': json.dumps(payload)}
request.assert_called_with(method, path, **params)
self.assertEqual(content, result)
def test___call___put_invalid_payload(self):
method = 'put'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = 'bad data'
self.assertRaises(jsonrpc.NefException, instance, path, payload)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___non_ok_response(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'ENOENT', 'message': 'error'}
response = self.fake_response(method, path, payload, 500, content)
request.return_value = response
self.assertRaises(jsonrpc.NefException, instance, path, payload)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.failover')
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___request_after_failover(self, request, failover):
method = 'post'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = None
response = self.fake_response(method, path, payload, 200, content)
request.side_effect = [requests.exceptions.Timeout, response]
failover.return_value = True
result = instance(path, payload)
params = {'data': json.dumps(payload)}
request.assert_called_with(method, path, **params)
self.assertEqual(content, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.failover')
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test___call___request_failover_error(self, request, failover):
method = 'put'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
request.side_effect = requests.exceptions.Timeout
failover.return_value = False
self.assertRaises(requests.exceptions.Timeout, instance, path, payload)
def test_hook_default(self):
method = 'post'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'name': 'dataset'}
response = self.fake_response(method, path, payload, 303, content)
result = instance.hook(response)
self.assertEqual(response, result)
def test_hook_200_empty(self):
method = 'delete'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'storage/filesystems'
payload = {'force': True}
content = None
response = self.fake_response(method, path, payload, 200, content)
result = instance.hook(response)
self.assertEqual(response, result)
def test_hook_201_empty(self):
method = 'post'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'storage/snapshots'
payload = {'path': 'parent/child@name'}
content = None
response = self.fake_response(method, path, payload, 201, content)
result = instance.hook(response)
self.assertEqual(response, result)
def test_hook_500_empty(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'storage/pools'
payload = {'poolName': 'tank'}
content = None
response = self.fake_response(method, path, payload, 500, content)
self.assertRaises(jsonrpc.NefException, instance.hook, response)
def test_hook_200_bad_content(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'storage/volumes'
payload = {'name': 'test'}
content = None
response = self.fake_response(method, path, payload, 200, content)
response._content = 'bad_content'
self.assertRaises(jsonrpc.NefException, instance.hook, response)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.auth')
def test_hook_401(self, auth, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'EAUTH'}
response = self.fake_response(method, path, payload, 401, content)
auth.return_value = True
content2 = {'name': 'test'}
response2 = self.fake_response(method, path, payload, 200, content2)
request.return_value = response2
self.proxy.session.send.return_value = content2
result = instance.hook(response)
self.assertEqual(content2, result)
def test_hook_401_max_retries(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
instance.stat[401] = self.proxy.retries
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'EAUTH'}
response = self.fake_response(method, path, payload, 401, content)
self.assertRaises(jsonrpc.NefException, instance.hook, response)
def test_hook_404_nested(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
instance.lock = True
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'ENOENT'}
response = self.fake_response(method, path, payload, 404, content)
result = instance.hook(response)
self.assertEqual(response, result)
def test_hook_404_max_retries(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
instance.stat[404] = self.proxy.retries
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'ENOENT'}
response = self.fake_response(method, path, payload, 404, content)
self.assertRaises(jsonrpc.NefException, instance.hook, response)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.failover')
def test_hook_404_failover_error(self, failover):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'ENOENT'}
response = self.fake_response(method, path, payload, 404, content)
failover.return_value = False
result = instance.hook(response)
self.assertEqual(response, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.failover')
def test_hook_404_failover_ok(self, failover, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'ENOENT'}
response = self.fake_response(method, path, payload, 404, content)
failover.return_value = True
content2 = {'name': 'test'}
response2 = self.fake_response(method, path, payload, 200, content2)
request.return_value = response2
result = instance.hook(response)
self.assertEqual(response2, result)
def test_hook_500_permanent(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'EINVAL'}
response = self.fake_response(method, path, payload, 500, content)
self.assertRaises(jsonrpc.NefException, instance.hook, response)
def test_hook_500_busy_max_retries(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
instance.stat[500] = self.proxy.retries
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'EBUSY'}
response = self.fake_response(method, path, payload, 500, content)
self.assertRaises(jsonrpc.NefException, instance.hook, response)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_hook_500_busy_ok(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'code': 'EBUSY'}
response = self.fake_response(method, path, payload, 500, content)
content2 = {'name': 'test'}
response2 = self.fake_response(method, path, payload, 200, content2)
request.return_value = response2
result = instance.hook(response)
self.assertEqual(response2, result)
def test_hook_201_no_monitor(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'monitor': 'unknown'}
response = self.fake_response(method, path, payload, 202, content)
self.assertRaises(jsonrpc.NefException, instance.hook, response)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_hook_201_ok(self, request):
method = 'delete'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {
'links': [{
'rel': 'monitor',
'href': '/jobStatus/jobID'
}]
}
response = self.fake_response(method, path, payload, 202, content)
content2 = None
response2 = self.fake_response(method, path, payload, 201, content2)
request.return_value = response2
result = instance.hook(response)
self.assertEqual(response2, result)
def test_200_no_data(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'name': 'test'}
response = self.fake_response(method, path, payload, 200, content)
result = instance.hook(response)
self.assertEqual(response, result)
def test_200_pagination_end(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {'data': 'value'}
response = self.fake_response(method, path, payload, 200, content)
result = instance.hook(response)
self.assertEqual(response, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_200_pagination_next(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
content = {
'data': [{
'name': 'test'
}],
'links': [{
'rel': 'next',
'href': path
}]
}
response = self.fake_response(method, path, payload, 200, content)
response2 = self.fake_response(method, path, payload, 200, content)
request.return_value = response2
result = instance.hook(response)
self.assertEqual(response2, result)
def test_request(self):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = 'parent/child'
payload = {'key': 'value'}
expected = {'name': 'dataset'}
url = self.proxy.url(path)
kwargs = payload.copy()
kwargs['timeout'] = self.proxy.timeout
kwargs['hooks'] = {'response': instance.hook}
self.proxy.session.request.return_value = expected
result = instance.request(method, path, **payload)
self.proxy.session.request.assert_called_with(method, url, **kwargs)
self.assertEqual(expected, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_auth(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
method = 'post'
path = 'auth/login'
payload = {
'data': json.dumps({
'username': self.proxy.username,
'password': self.proxy.password
})
}
content = {'token': 'test'}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
instance.auth()
request.assert_called_with(method, path, **payload)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_auth_error(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
method = 'post'
path = 'auth/login'
payload = {
'data': json.dumps({
'username': self.proxy.username,
'password': self.proxy.password
})
}
content = {'data': 'noauth'}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
self.assertRaises(jsonrpc.NefException, instance.auth)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_failover(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = self.proxy.root
payload = {}
content = {'path': path}
response = self.fake_response(method, path, payload, 200, content)
request.return_value = response
result = instance.failover()
request.assert_called_with(method, path)
expected = True
self.assertEqual(expected, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_failover_timeout(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = self.proxy.root
payload = {}
content = {'path': path}
response = self.fake_response(method, path, payload, 200, content)
request.side_effect = [requests.exceptions.Timeout, response]
result = instance.failover()
request.assert_called_with(method, path)
expected = True
self.assertEqual(expected, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_failover_404(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = self.proxy.root
payload = {}
content = {}
response = self.fake_response(method, path, payload, 404, content)
request.side_effect = [response, response]
result = instance.failover()
request.assert_called_with(method, path)
expected = False
self.assertEqual(expected, result)
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefRequest.request')
def test_failover_error(self, request):
method = 'get'
instance = jsonrpc.NefRequest(self.proxy, method)
path = self.proxy.root
request.side_effect = [
requests.exceptions.Timeout,
requests.exceptions.ConnectionError
]
result = instance.failover()
request.assert_called_with(method, path)
expected = False
self.assertEqual(expected, result)
def test_getpath(self):
method = 'get'
rel = 'monitor'
href = 'jobStatus/jobID'
content = {
'links': [
[1, 2],
'bad link',
{
'rel': 'next',
'href': href
},
{
'rel': rel,
'href': href
}
]
}
instance = jsonrpc.NefRequest(self.proxy, method)
result = instance.getpath(content, rel)
expected = href
self.assertEqual(expected, result)
def test_getpath_no_content(self):
method = 'get'
rel = 'next'
content = None
instance = jsonrpc.NefRequest(self.proxy, method)
result = instance.getpath(content, rel)
expected = None
self.assertEqual(expected, result)
def test_getpath_no_links(self):
method = 'get'
rel = 'next'
content = {'a': 'b'}
instance = jsonrpc.NefRequest(self.proxy, method)
result = instance.getpath(content, rel)
expected = None
self.assertEqual(expected, result)
def test_getpath_no_rel(self):
method = 'get'
rel = 'next'
content = {
'links': [
{
'rel': 'monitor',
'href': '/jobs/jobID'
}
]
}
instance = jsonrpc.NefRequest(self.proxy, method)
result = instance.getpath(content, rel)
expected = None
self.assertEqual(expected, result)
def test_getpath_no_href(self):
method = 'get'
rel = 'next'
content = {
'links': [
{
'rel': rel
}
]
}
instance = jsonrpc.NefRequest(self.proxy, method)
result = instance.getpath(content, rel)
expected = None
self.assertEqual(expected, result)
class TestNefCollections(test.TestCase):
def setUp(self):
super(TestNefCollections, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefCollections(self.proxy)
def test_path(self):
path = 'path/to/item name + - & # $ = 0'
result = self.instance.path(path)
quoted_path = six.moves.urllib.parse.quote_plus(path)
expected = posixpath.join(self.instance.root, quoted_path)
self.assertEqual(expected, result)
def test_get(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = {'name': 'dataset'}
path = self.instance.path(name)
self.proxy.get.return_value = expected
result = self.instance.get(name, payload)
self.proxy.get.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_set(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
self.proxy.put.return_value = expected
result = self.instance.set(name, payload)
self.proxy.put.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_list(self):
payload = {'key': 'value'}
expected = [{'name': 'dataset'}]
self.proxy.get.return_value = expected
result = self.instance.list(payload)
self.proxy.get.assert_called_with(self.instance.root, payload)
self.assertEqual(expected, result)
def test_create(self):
payload = {'key': 'value'}
expected = None
self.proxy.post.return_value = expected
result = self.instance.create(payload)
self.proxy.post.assert_called_with(self.instance.root, payload)
self.assertEqual(expected, result)
def test_create_exist(self):
payload = {'key': 'value'}
expected = None
self.proxy.post.side_effect = jsonrpc.NefException(code='EEXIST')
result = self.instance.create(payload)
self.proxy.post.assert_called_with(self.instance.root, payload)
self.assertEqual(expected, result)
def test_create_error(self):
payload = {'key': 'value'}
self.proxy.post.side_effect = jsonrpc.NefException(code='EBUSY')
self.assertRaises(jsonrpc.NefException, self.instance.create, payload)
self.proxy.post.assert_called_with(self.instance.root, payload)
def test_delete(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
self.proxy.delete.return_value = expected
result = self.instance.delete(name, payload)
self.proxy.delete.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_delete_not_found(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
self.proxy.delete.side_effect = jsonrpc.NefException(code='ENOENT')
result = self.instance.delete(name, payload)
self.proxy.delete.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_delete_error(self):
name = 'parent/child'
payload = {'key': 'value'}
path = self.instance.path(name)
self.proxy.delete.side_effect = jsonrpc.NefException(code='EINVAL')
self.assertRaises(jsonrpc.NefException, self.instance.delete, name,
payload)
self.proxy.delete.assert_called_with(path, payload)
class TestNefSettings(test.TestCase):
def setUp(self):
super(TestNefSettings, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefSettings(self.proxy)
def test_create(self):
payload = {'key': 'value'}
result = self.instance.create(payload)
expected = NotImplemented
self.assertEqual(expected, result)
def test_delete(self):
name = 'parent/child'
payload = {'key': 'value'}
result = self.instance.delete(name, payload)
expected = NotImplemented
self.assertEqual(expected, result)
class TestNefDatasets(test.TestCase):
def setUp(self):
super(TestNefDatasets, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefDatasets(self.proxy)
def test_rename(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'rename')
self.proxy.post.return_value = expected
result = self.instance.rename(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
class TestNefSnapshots(test.TestCase):
def setUp(self):
super(TestNefSnapshots, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefSnapshots(self.proxy)
def test_clone(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'clone')
self.proxy.post.return_value = expected
result = self.instance.clone(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
class TestNefVolumeGroups(test.TestCase):
def setUp(self):
super(TestNefVolumeGroups, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefVolumeGroups(self.proxy)
def test_rollback(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'rollback')
self.proxy.post.return_value = expected
result = self.instance.rollback(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
class TestNefVolumes(test.TestCase):
def setUp(self):
super(TestNefVolumes, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefVolumes(self.proxy)
def test_promote(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'promote')
self.proxy.post.return_value = expected
result = self.instance.promote(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
class TestNefFilesystems(test.TestCase):
def setUp(self):
super(TestNefFilesystems, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefFilesystems(self.proxy)
def test_mount(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'mount')
self.proxy.post.return_value = expected
result = self.instance.mount(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_unmount(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'unmount')
self.proxy.post.return_value = expected
result = self.instance.unmount(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_acl(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = self.instance.path(name)
path = posixpath.join(path, 'acl')
self.proxy.post.return_value = expected
result = self.instance.acl(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
class TestNefHpr(test.TestCase):
def setUp(self):
super(TestNefHpr, self).setUp()
self.proxy = mock.Mock()
self.instance = jsonrpc.NefHpr(self.proxy)
def test_activate(self):
payload = {'key': 'value'}
expected = None
path = posixpath.join(self.instance.root, 'activate')
self.proxy.post.return_value = expected
result = self.instance.activate(payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
def test_start(self):
name = 'parent/child'
payload = {'key': 'value'}
expected = None
path = posixpath.join(self.instance.path(name), 'start')
self.proxy.post.return_value = expected
result = self.instance.start(name, payload)
self.proxy.post.assert_called_with(path, payload)
self.assertEqual(expected, result)
class TestNefProxy(test.TestCase):
def setUp(self):
super(TestNefProxy, self).setUp()
self.cfg = mock.Mock(spec=conf.Configuration)
self.cfg.nexenta_use_https = True
self.cfg.driver_ssl_cert_verify = True
self.cfg.nexenta_user = 'user'
self.cfg.nexenta_password = 'pass'
self.cfg.nexenta_rest_address = '1.1.1.1,2.2.2.2'
self.cfg.nexenta_rest_port = 8443
self.cfg.nexenta_rest_backoff_factor = 1
self.cfg.nexenta_rest_retry_count = 3
self.cfg.nexenta_rest_connect_timeout = 1
self.cfg.nexenta_rest_read_timeout = 1
self.cfg.nas_host = '3.3.3.3'
self.cfg.nas_share_path = 'pool/path/to/share'
self.nef_mock = mock.Mock()
self.mock_object(jsonrpc, 'NefRequest',
return_value=self.nef_mock)
self.proto = 'nfs'
self.proxy = jsonrpc.NefProxy(self.proto,
self.cfg.nas_share_path,
self.cfg)
def test___init___http(self):
proto = 'nfs'
cfg = copy.copy(self.cfg)
cfg.nexenta_use_https = False
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
self.assertIsInstance(result, jsonrpc.NefProxy)
def test___init___no_rest_port_http(self):
proto = 'nfs'
cfg = copy.copy(self.cfg)
cfg.nexenta_rest_port = 0
cfg.nexenta_use_https = False
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
self.assertIsInstance(result, jsonrpc.NefProxy)
def test___init___no_rest_port_https(self):
proto = 'nfs'
cfg = copy.copy(self.cfg)
cfg.nexenta_rest_port = 0
cfg.nexenta_use_https = True
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
self.assertIsInstance(result, jsonrpc.NefProxy)
def test___init___iscsi(self):
proto = 'iscsi'
cfg = copy.copy(self.cfg)
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
self.assertIsInstance(result, jsonrpc.NefProxy)
def test___init___nfs_no_rest_address(self):
proto = 'nfs'
cfg = copy.copy(self.cfg)
cfg.nexenta_rest_address = ''
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
self.assertIsInstance(result, jsonrpc.NefProxy)
def test___init___iscsi_no_rest_address(self):
proto = 'iscsi'
cfg = copy.copy(self.cfg)
cfg.nexenta_rest_address = ''
cfg.nexenta_host = '4.4.4.4'
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
self.assertIsInstance(result, jsonrpc.NefProxy)
def test___init___invalid_storage_protocol(self):
proto = 'invalid'
cfg = copy.copy(self.cfg)
self.assertRaises(jsonrpc.NefException, jsonrpc.NefProxy,
proto, cfg.nas_share_path, cfg)
@mock.patch('requests.packages.urllib3.disable_warnings')
def test___init___no_ssl_cert_verify(self, disable_warnings):
proto = 'nfs'
cfg = copy.copy(self.cfg)
cfg.driver_ssl_cert_verify = False
disable_warnings.return_value = None
result = jsonrpc.NefProxy(proto, cfg.nas_share_path, cfg)
disable_warnings.assert_called()
self.assertIsInstance(result, jsonrpc.NefProxy)
def test_delete_bearer(self):
self.assertIsNone(self.proxy.delete_bearer())
self.assertNotIn('Authorization', self.proxy.session.headers)
self.proxy.session.headers['Authorization'] = 'Bearer token'
self.assertIsNone(self.proxy.delete_bearer())
self.assertNotIn('Authorization', self.proxy.session.headers)
def test_update_bearer(self):
token = 'token'
bearer = 'Bearer %s' % token
self.assertNotIn('Authorization', self.proxy.session.headers)
self.assertIsNone(self.proxy.update_bearer(token))
self.assertIn('Authorization', self.proxy.session.headers)
self.assertEqual(self.proxy.session.headers['Authorization'], bearer)
def test_update_token(self):
token = 'token'
bearer = 'Bearer %s' % token
self.assertIsNone(self.proxy.update_token(token))
self.assertEqual(self.proxy.tokens[self.proxy.host], token)
self.assertEqual(self.proxy.session.headers['Authorization'], bearer)
def test_update_host(self):
token = 'token'
bearer = 'Bearer %s' % token
host = self.cfg.nexenta_rest_address
self.proxy.tokens[host] = token
self.assertIsNone(self.proxy.update_host(host))
self.assertEqual(self.proxy.session.headers['Authorization'], bearer)
def test_skip_update_host(self):
host = 'nonexistent'
self.assertIsNone(self.proxy.update_host(host))
@mock.patch('cinder.volume.drivers.nexenta.ns5.'
'jsonrpc.NefSettings.get')
def test_update_lock(self, get_settings):
guid = uuid.uuid4().hex
settings = {'value': guid}
get_settings.return_value = settings
self.assertIsNone(self.proxy.update_lock())
path = '%s:%s' % (guid, self.proxy.path)
if isinstance(path, six.text_type):
path = path.encode('utf-8')
expected = md5(path, usedforsecurity=False).hexdigest()
self.assertEqual(expected, self.proxy.lock)
def test_url(self):
path = '/path/to/api'
result = self.proxy.url(path)
expected = '%s://%s:%s%s' % (self.proxy.scheme,
self.proxy.host,
self.proxy.port,
path)
self.assertEqual(expected, result)
@mock.patch('eventlet.greenthread.sleep')
def test_delay(self, sleep):
sleep.return_value = None
for attempt in range(0, 10):
expected = int(self.proxy.backoff_factor * (2 ** (attempt - 1)))
self.assertIsNone(self.proxy.delay(attempt))
sleep.assert_called_with(expected)