Removed volume specific tests

This commit is contained in:
Yulia Portnova 2013-09-05 16:41:32 +03:00
parent a005c85ef1
commit 35fe8d3b7f
59 changed files with 2 additions and 22227 deletions

View File

@ -1,860 +0,0 @@
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
# 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.
"""
Tests for Backup code.
"""
import json
from xml.dom import minidom
import webob
# needed for stubs to work
import manila.backup
from manila import context
from manila import db
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.tests.api import fakes
# needed for stubs to work
import manila.volume
LOG = logging.getLogger(__name__)
class BackupsAPITestCase(test.TestCase):
"""Test Case for backups API."""
def setUp(self):
super(BackupsAPITestCase, self).setUp()
def tearDown(self):
super(BackupsAPITestCase, self).tearDown()
@staticmethod
def _create_backup(volume_id=1,
display_name='test_backup',
display_description='this is a test backup',
container='volumebackups',
status='creating',
size=0, object_count=0):
"""Create a backup object."""
backup = {}
backup['volume_id'] = volume_id
backup['user_id'] = 'fake'
backup['project_id'] = 'fake'
backup['host'] = 'testhost'
backup['availability_zone'] = 'az1'
backup['display_name'] = display_name
backup['display_description'] = display_description
backup['container'] = container
backup['status'] = status
backup['fail_reason'] = ''
backup['size'] = size
backup['object_count'] = object_count
return db.backup_create(context.get_admin_context(), backup)['id']
@staticmethod
def _get_backup_attrib(backup_id, attrib_name):
return db.backup_get(context.get_admin_context(),
backup_id)[attrib_name]
@staticmethod
def _create_volume(display_name='test_volume',
display_description='this is a test volume',
status='creating',
size=1):
"""Create a volume object."""
vol = {}
vol['size'] = size
vol['user_id'] = 'fake'
vol['project_id'] = 'fake'
vol['status'] = status
vol['display_name'] = display_name
vol['display_description'] = display_description
vol['attach_status'] = 'detached'
return db.volume_create(context.get_admin_context(), vol)['id']
def test_show_backup(self):
volume_id = self._create_volume(size=5)
backup_id = self._create_backup(volume_id)
LOG.debug('Created backup with id %s' % backup_id)
req = webob.Request.blank('/v2/fake/backups/%s' %
backup_id)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200)
self.assertEqual(res_dict['backup']['availability_zone'], 'az1')
self.assertEqual(res_dict['backup']['container'], 'volumebackups')
self.assertEqual(res_dict['backup']['description'],
'this is a test backup')
self.assertEqual(res_dict['backup']['name'], 'test_backup')
self.assertEqual(res_dict['backup']['id'], backup_id)
self.assertEqual(res_dict['backup']['object_count'], 0)
self.assertEqual(res_dict['backup']['size'], 0)
self.assertEqual(res_dict['backup']['status'], 'creating')
self.assertEqual(res_dict['backup']['volume_id'], volume_id)
db.backup_destroy(context.get_admin_context(), backup_id)
db.volume_destroy(context.get_admin_context(), volume_id)
def test_show_backup_xml_content_type(self):
volume_id = self._create_volume(size=5)
backup_id = self._create_backup(volume_id)
req = webob.Request.blank('/v2/fake/backups/%s' % backup_id)
req.method = 'GET'
req.headers['Content-Type'] = 'application/xml'
req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
dom = minidom.parseString(res.body)
backup = dom.getElementsByTagName('backup')
name = backup.item(0).getAttribute('name')
container_name = backup.item(0).getAttribute('container')
self.assertEquals(container_name.strip(), "volumebackups")
self.assertEquals(name.strip(), "test_backup")
db.backup_destroy(context.get_admin_context(), backup_id)
db.volume_destroy(context.get_admin_context(), volume_id)
def test_show_backup_with_backup_NotFound(self):
req = webob.Request.blank('/v2/fake/backups/9999')
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404)
self.assertEqual(res_dict['itemNotFound']['code'], 404)
self.assertEqual(res_dict['itemNotFound']['message'],
'Backup 9999 could not be found.')
def test_list_backups_json(self):
backup_id1 = self._create_backup()
backup_id2 = self._create_backup()
backup_id3 = self._create_backup()
req = webob.Request.blank('/v2/fake/backups')
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200)
self.assertEqual(len(res_dict['backups'][0]), 3)
self.assertEqual(res_dict['backups'][0]['id'], backup_id1)
self.assertEqual(res_dict['backups'][0]['name'], 'test_backup')
self.assertEqual(len(res_dict['backups'][1]), 3)
self.assertEqual(res_dict['backups'][1]['id'], backup_id2)
self.assertEqual(res_dict['backups'][1]['name'], 'test_backup')
self.assertEqual(len(res_dict['backups'][2]), 3)
self.assertEqual(res_dict['backups'][2]['id'], backup_id3)
self.assertEqual(res_dict['backups'][2]['name'], 'test_backup')
db.backup_destroy(context.get_admin_context(), backup_id3)
db.backup_destroy(context.get_admin_context(), backup_id2)
db.backup_destroy(context.get_admin_context(), backup_id1)
def test_list_backups_xml(self):
backup_id1 = self._create_backup()
backup_id2 = self._create_backup()
backup_id3 = self._create_backup()
req = webob.Request.blank('/v2/fake/backups')
req.method = 'GET'
req.headers['Content-Type'] = 'application/xml'
req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
dom = minidom.parseString(res.body)
backup_list = dom.getElementsByTagName('backup')
self.assertEqual(backup_list.item(0).attributes.length, 2)
self.assertEqual(backup_list.item(0).getAttribute('id'),
backup_id1)
self.assertEqual(backup_list.item(1).attributes.length, 2)
self.assertEqual(backup_list.item(1).getAttribute('id'),
backup_id2)
self.assertEqual(backup_list.item(2).attributes.length, 2)
self.assertEqual(backup_list.item(2).getAttribute('id'),
backup_id3)
db.backup_destroy(context.get_admin_context(), backup_id3)
db.backup_destroy(context.get_admin_context(), backup_id2)
db.backup_destroy(context.get_admin_context(), backup_id1)
def test_list_backups_detail_json(self):
backup_id1 = self._create_backup()
backup_id2 = self._create_backup()
backup_id3 = self._create_backup()
req = webob.Request.blank('/v2/fake/backups/detail')
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200)
self.assertEqual(len(res_dict['backups'][0]), 12)
self.assertEqual(res_dict['backups'][0]['availability_zone'], 'az1')
self.assertEqual(res_dict['backups'][0]['container'],
'volumebackups')
self.assertEqual(res_dict['backups'][0]['description'],
'this is a test backup')
self.assertEqual(res_dict['backups'][0]['name'],
'test_backup')
self.assertEqual(res_dict['backups'][0]['id'], backup_id1)
self.assertEqual(res_dict['backups'][0]['object_count'], 0)
self.assertEqual(res_dict['backups'][0]['size'], 0)
self.assertEqual(res_dict['backups'][0]['status'], 'creating')
self.assertEqual(res_dict['backups'][0]['volume_id'], '1')
self.assertEqual(len(res_dict['backups'][1]), 12)
self.assertEqual(res_dict['backups'][1]['availability_zone'], 'az1')
self.assertEqual(res_dict['backups'][1]['container'],
'volumebackups')
self.assertEqual(res_dict['backups'][1]['description'],
'this is a test backup')
self.assertEqual(res_dict['backups'][1]['name'],
'test_backup')
self.assertEqual(res_dict['backups'][1]['id'], backup_id2)
self.assertEqual(res_dict['backups'][1]['object_count'], 0)
self.assertEqual(res_dict['backups'][1]['size'], 0)
self.assertEqual(res_dict['backups'][1]['status'], 'creating')
self.assertEqual(res_dict['backups'][1]['volume_id'], '1')
self.assertEqual(len(res_dict['backups'][2]), 12)
self.assertEqual(res_dict['backups'][2]['availability_zone'], 'az1')
self.assertEqual(res_dict['backups'][2]['container'],
'volumebackups')
self.assertEqual(res_dict['backups'][2]['description'],
'this is a test backup')
self.assertEqual(res_dict['backups'][2]['name'],
'test_backup')
self.assertEqual(res_dict['backups'][2]['id'], backup_id3)
self.assertEqual(res_dict['backups'][2]['object_count'], 0)
self.assertEqual(res_dict['backups'][2]['size'], 0)
self.assertEqual(res_dict['backups'][2]['status'], 'creating')
self.assertEqual(res_dict['backups'][2]['volume_id'], '1')
db.backup_destroy(context.get_admin_context(), backup_id3)
db.backup_destroy(context.get_admin_context(), backup_id2)
db.backup_destroy(context.get_admin_context(), backup_id1)
def test_list_backups_detail_xml(self):
backup_id1 = self._create_backup()
backup_id2 = self._create_backup()
backup_id3 = self._create_backup()
req = webob.Request.blank('/v2/fake/backups/detail')
req.method = 'GET'
req.headers['Content-Type'] = 'application/xml'
req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
dom = minidom.parseString(res.body)
backup_detail = dom.getElementsByTagName('backup')
self.assertEqual(backup_detail.item(0).attributes.length, 11)
self.assertEqual(
backup_detail.item(0).getAttribute('availability_zone'), 'az1')
self.assertEqual(
backup_detail.item(0).getAttribute('container'), 'volumebackups')
self.assertEqual(
backup_detail.item(0).getAttribute('description'),
'this is a test backup')
self.assertEqual(
backup_detail.item(0).getAttribute('name'), 'test_backup')
self.assertEqual(
backup_detail.item(0).getAttribute('id'), backup_id1)
self.assertEqual(
int(backup_detail.item(0).getAttribute('object_count')), 0)
self.assertEqual(
int(backup_detail.item(0).getAttribute('size')), 0)
self.assertEqual(
backup_detail.item(0).getAttribute('status'), 'creating')
self.assertEqual(
int(backup_detail.item(0).getAttribute('volume_id')), 1)
self.assertEqual(backup_detail.item(1).attributes.length, 11)
self.assertEqual(
backup_detail.item(1).getAttribute('availability_zone'), 'az1')
self.assertEqual(
backup_detail.item(1).getAttribute('container'), 'volumebackups')
self.assertEqual(
backup_detail.item(1).getAttribute('description'),
'this is a test backup')
self.assertEqual(
backup_detail.item(1).getAttribute('name'), 'test_backup')
self.assertEqual(
backup_detail.item(1).getAttribute('id'), backup_id2)
self.assertEqual(
int(backup_detail.item(1).getAttribute('object_count')), 0)
self.assertEqual(
int(backup_detail.item(1).getAttribute('size')), 0)
self.assertEqual(
backup_detail.item(1).getAttribute('status'), 'creating')
self.assertEqual(
int(backup_detail.item(1).getAttribute('volume_id')), 1)
self.assertEqual(backup_detail.item(2).attributes.length, 11)
self.assertEqual(
backup_detail.item(2).getAttribute('availability_zone'), 'az1')
self.assertEqual(
backup_detail.item(2).getAttribute('container'), 'volumebackups')
self.assertEqual(
backup_detail.item(2).getAttribute('description'),
'this is a test backup')
self.assertEqual(
backup_detail.item(2).getAttribute('name'), 'test_backup')
self.assertEqual(
backup_detail.item(2).getAttribute('id'), backup_id3)
self.assertEqual(
int(backup_detail.item(2).getAttribute('object_count')), 0)
self.assertEqual(
int(backup_detail.item(2).getAttribute('size')), 0)
self.assertEqual(
backup_detail.item(2).getAttribute('status'), 'creating')
self.assertEqual(
int(backup_detail.item(2).getAttribute('volume_id')), 1)
db.backup_destroy(context.get_admin_context(), backup_id3)
db.backup_destroy(context.get_admin_context(), backup_id2)
db.backup_destroy(context.get_admin_context(), backup_id1)
def test_create_backup_json(self):
volume_id = self._create_volume(status='available', size=5)
body = {"backup": {"display_name": "nightly001",
"display_description":
"Nightly Backup 03-Sep-2012",
"volume_id": volume_id,
"container": "nightlybackups",
}
}
req = webob.Request.blank('/v2/fake/backups')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
LOG.info(res_dict)
self.assertEqual(res.status_int, 202)
self.assertTrue('id' in res_dict['backup'])
db.volume_destroy(context.get_admin_context(), volume_id)
def test_create_backup_xml(self):
volume_size = 2
volume_id = self._create_volume(status='available', size=volume_size)
req = webob.Request.blank('/v2/fake/backups')
req.body = ('<backup display_name="backup-001" '
'display_description="Nightly Backup" '
'volume_id="%s" container="Container001"/>' % volume_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/xml'
req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
dom = minidom.parseString(res.body)
backup = dom.getElementsByTagName('backup')
self.assertTrue(backup.item(0).hasAttribute('id'))
db.volume_destroy(context.get_admin_context(), volume_id)
def test_create_backup_with_no_body(self):
# omit body from the request
req = webob.Request.blank('/v2/fake/backups')
req.body = json.dumps(None)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'The server could not comply with the request since'
' it is either malformed or otherwise incorrect.')
def test_create_backup_with_body_KeyError(self):
# omit volume_id from body
body = {"backup": {"display_name": "nightly001",
"display_description":
"Nightly Backup 03-Sep-2012",
"container": "nightlybackups",
}
}
req = webob.Request.blank('/v2/fake/backups')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Incorrect request body format')
def test_create_backup_with_VolumeNotFound(self):
body = {"backup": {"display_name": "nightly001",
"display_description":
"Nightly Backup 03-Sep-2012",
"volume_id": 9999,
"container": "nightlybackups",
}
}
req = webob.Request.blank('/v2/fake/backups')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404)
self.assertEqual(res_dict['itemNotFound']['code'], 404)
self.assertEqual(res_dict['itemNotFound']['message'],
'Volume 9999 could not be found.')
def test_create_backup_with_InvalidVolume(self):
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='restoring', size=volume_size)
body = {"backup": {"display_name": "nightly001",
"display_description":
"Nightly Backup 03-Sep-2012",
"volume_id": volume_id,
"container": "nightlybackups",
}
}
req = webob.Request.blank('/v2/fake/backups')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Invalid volume: Volume to be backed up must'
' be available')
def test_delete_backup_available(self):
backup_id = self._create_backup(status='available')
req = webob.Request.blank('/v2/fake/backups/%s' %
backup_id)
req.method = 'DELETE'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
self.assertEqual(self._get_backup_attrib(backup_id, 'status'),
'deleting')
db.backup_destroy(context.get_admin_context(), backup_id)
def test_delete_backup_error(self):
backup_id = self._create_backup(status='error')
req = webob.Request.blank('/v2/fake/backups/%s' %
backup_id)
req.method = 'DELETE'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
self.assertEqual(self._get_backup_attrib(backup_id, 'status'),
'deleting')
db.backup_destroy(context.get_admin_context(), backup_id)
def test_delete_backup_with_backup_NotFound(self):
req = webob.Request.blank('/v2/fake/backups/9999')
req.method = 'DELETE'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404)
self.assertEqual(res_dict['itemNotFound']['code'], 404)
self.assertEqual(res_dict['itemNotFound']['message'],
'Backup 9999 could not be found.')
def test_delete_backup_with_InvalidBackup(self):
backup_id = self._create_backup()
req = webob.Request.blank('/v2/fake/backups/%s' %
backup_id)
req.method = 'DELETE'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Invalid backup: Backup status must be '
'available or error')
db.backup_destroy(context.get_admin_context(), backup_id)
def test_restore_backup_volume_id_specified_json(self):
backup_id = self._create_backup(status='available')
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 202)
self.assertEqual(res_dict['restore']['backup_id'], backup_id)
self.assertEqual(res_dict['restore']['volume_id'], volume_id)
def test_restore_backup_volume_id_specified_xml(self):
backup_id = self._create_backup(status='available')
volume_size = 2
volume_id = self._create_volume(status='available', size=volume_size)
req = webob.Request.blank('/v2/fake/backups/%s/restore' % backup_id)
req.body = '<restore volume_id="%s"/>' % volume_id
req.method = 'POST'
req.headers['Content-Type'] = 'application/xml'
req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
dom = minidom.parseString(res.body)
restore = dom.getElementsByTagName('restore')
self.assertEqual(restore.item(0).getAttribute('backup_id'),
backup_id)
self.assertEqual(restore.item(0).getAttribute('volume_id'), volume_id)
db.backup_destroy(context.get_admin_context(), backup_id)
db.volume_destroy(context.get_admin_context(), volume_id)
def test_restore_backup_with_no_body(self):
# omit body from the request
backup_id = self._create_backup(status='available')
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.body = json.dumps(None)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'The server could not comply with the request since'
' it is either malformed or otherwise incorrect.')
db.backup_destroy(context.get_admin_context(), backup_id)
def test_restore_backup_with_body_KeyError(self):
# omit restore from body
backup_id = self._create_backup(status='available')
req = webob.Request.blank('/v2/fake/backups/%s/restore' % backup_id)
body = {"": {}}
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'The server could not comply with the request since'
' it is either malformed or otherwise incorrect.')
def test_restore_backup_volume_id_unspecified(self):
# intercept volume creation to ensure created volume
# has status of available
def fake_volume_api_create(cls, context, size, name, description):
volume_id = self._create_volume(status='available', size=size)
return db.volume_get(context, volume_id)
self.stubs.Set(manila.volume.API, 'create',
fake_volume_api_create)
backup_id = self._create_backup(size=5, status='available')
body = {"restore": {}}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 202)
self.assertEqual(res_dict['restore']['backup_id'], backup_id)
def test_restore_backup_with_InvalidInput(self):
def fake_backup_api_restore_throwing_InvalidInput(cls, context,
backup_id,
volume_id):
msg = _("Invalid input")
raise exception.InvalidInput(reason=msg)
self.stubs.Set(manila.backup.API, 'restore',
fake_backup_api_restore_throwing_InvalidInput)
backup_id = self._create_backup(status='available')
# need to create the volume referenced below first
volume_size = 0
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Invalid input received: Invalid input')
def test_restore_backup_with_InvalidVolume(self):
backup_id = self._create_backup(status='available')
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='attaching', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Invalid volume: Volume to be restored to must '
'be available')
db.volume_destroy(context.get_admin_context(), volume_id)
db.backup_destroy(context.get_admin_context(), backup_id)
def test_restore_backup_with_InvalidBackup(self):
backup_id = self._create_backup(status='restoring')
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Invalid backup: Backup status must be available')
db.volume_destroy(context.get_admin_context(), volume_id)
db.backup_destroy(context.get_admin_context(), backup_id)
def test_restore_backup_with_BackupNotFound(self):
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/9999/restore')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404)
self.assertEqual(res_dict['itemNotFound']['code'], 404)
self.assertEqual(res_dict['itemNotFound']['message'],
'Backup 9999 could not be found.')
db.volume_destroy(context.get_admin_context(), volume_id)
def test_restore_backup_with_VolumeNotFound(self):
backup_id = self._create_backup(status='available')
body = {"restore": {"volume_id": "9999", }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404)
self.assertEqual(res_dict['itemNotFound']['code'], 404)
self.assertEqual(res_dict['itemNotFound']['message'],
'Volume 9999 could not be found.')
db.backup_destroy(context.get_admin_context(), backup_id)
def test_restore_backup_with_VolumeSizeExceedsAvailableQuota(self):
def fake_backup_api_restore_throwing_VolumeSizeExceedsAvailableQuota(
cls, context, backup_id, volume_id):
raise exception.VolumeSizeExceedsAvailableQuota()
self.stubs.Set(
manila.backup.API,
'restore',
fake_backup_api_restore_throwing_VolumeSizeExceedsAvailableQuota)
backup_id = self._create_backup(status='available')
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 413)
self.assertEqual(res_dict['overLimit']['code'], 413)
self.assertEqual(res_dict['overLimit']['message'],
'Requested volume or snapshot exceeds allowed '
'Gigabytes quota')
def test_restore_backup_with_VolumeLimitExceeded(self):
def fake_backup_api_restore_throwing_VolumeLimitExceeded(cls,
context,
backup_id,
volume_id):
raise exception.VolumeLimitExceeded(allowed=1)
self.stubs.Set(manila.backup.API, 'restore',
fake_backup_api_restore_throwing_VolumeLimitExceeded)
backup_id = self._create_backup(status='available')
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 413)
self.assertEqual(res_dict['overLimit']['code'], 413)
self.assertEqual(res_dict['overLimit']['message'],
'Maximum number of volumes allowed '
'(%(allowed)d) exceeded')
def test_restore_backup_to_undersized_volume(self):
backup_size = 10
backup_id = self._create_backup(status='available', size=backup_size)
# need to create the volume referenced below first
volume_size = 5
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400)
self.assertEqual(res_dict['badRequest']['code'], 400)
self.assertEqual(res_dict['badRequest']['message'],
'Invalid volume: volume size %d is too '
'small to restore backup of size %d.'
% (volume_size, backup_size))
db.volume_destroy(context.get_admin_context(), volume_id)
db.backup_destroy(context.get_admin_context(), backup_id)
def test_restore_backup_to_oversized_volume(self):
backup_id = self._create_backup(status='available', size=10)
# need to create the volume referenced below first
volume_size = 15
volume_id = self._create_volume(status='available', size=volume_size)
body = {"restore": {"volume_id": volume_id, }}
req = webob.Request.blank('/v2/fake/backups/%s/restore' %
backup_id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 202)
self.assertEqual(res_dict['restore']['backup_id'], backup_id)
self.assertEqual(res_dict['restore']['volume_id'], volume_id)
db.volume_destroy(context.get_admin_context(), volume_id)
db.backup_destroy(context.get_admin_context(), backup_id)

View File

@ -1,124 +0,0 @@
# Copyright 2012 OpenStack LLC.
# 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.
from lxml import etree
import webob
from manila.api.contrib import extended_snapshot_attributes
from manila import exception
from manila import flags
from manila.openstack.common import jsonutils
from manila import test
from manila.tests.api import fakes
from manila import volume
FLAGS = flags.FLAGS
UUID1 = '00000000-0000-0000-0000-000000000001'
UUID2 = '00000000-0000-0000-0000-000000000002'
def _get_default_snapshot_param():
return {'id': UUID1,
'volume_id': 12,
'status': 'available',
'volume_size': 100,
'created_at': None,
'display_name': 'Default name',
'display_description': 'Default description',
'project_id': 'fake',
'progress': '0%'}
def fake_snapshot_get(self, context, snapshot_id):
param = _get_default_snapshot_param()
return param
def fake_snapshot_get_all(self, context, search_opts=None):
param = _get_default_snapshot_param()
return [param]
class ExtendedSnapshotAttributesTest(test.TestCase):
content_type = 'application/json'
prefix = 'os-extended-snapshot-attributes:'
def setUp(self):
super(ExtendedSnapshotAttributesTest, self).setUp()
self.stubs.Set(volume.api.API, 'get_snapshot', fake_snapshot_get)
self.stubs.Set(volume.api.API, 'get_all_snapshots',
fake_snapshot_get_all)
def _make_request(self, url):
req = webob.Request.blank(url)
req.headers['Accept'] = self.content_type
res = req.get_response(fakes.wsgi_app())
return res
def _get_snapshot(self, body):
return jsonutils.loads(body).get('snapshot')
def _get_snapshots(self, body):
return jsonutils.loads(body).get('snapshots')
def assertSnapshotAttributes(self, snapshot, project_id, progress):
self.assertEqual(snapshot.get('%sproject_id' % self.prefix),
project_id)
self.assertEqual(snapshot.get('%sprogress' % self.prefix), progress)
def test_show(self):
url = '/v2/fake/snapshots/%s' % UUID2
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
self.assertSnapshotAttributes(self._get_snapshot(res.body),
project_id='fake',
progress='0%')
def test_detail(self):
url = '/v2/fake/snapshots/detail'
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
for i, snapshot in enumerate(self._get_snapshots(res.body)):
self.assertSnapshotAttributes(snapshot,
project_id='fake',
progress='0%')
def test_no_instance_passthrough_404(self):
def fake_snapshot_get(*args, **kwargs):
raise exception.InstanceNotFound(instance_id='fake')
self.stubs.Set(volume.api.API, 'get_snapshot', fake_snapshot_get)
url = '/v2/fake/snapshots/70f6db34-de8d-4fbd-aafb-4065bdfa6115'
res = self._make_request(url)
self.assertEqual(res.status_int, 404)
class ExtendedSnapshotAttributesXmlTest(ExtendedSnapshotAttributesTest):
content_type = 'application/xml'
ext = extended_snapshot_attributes
prefix = '{%s}' % ext.Extended_snapshot_attributes.namespace
def _get_snapshot(self, body):
return etree.XML(body)
def _get_snapshots(self, body):
return etree.XML(body).getchildren()

View File

@ -1,232 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 Zadara Storage Inc.
# Copyright (c) 2011 OpenStack LLC.
# Copyright 2011 University of Southern California
# 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.
from lxml import etree
import webob
from manila.api.contrib import types_extra_specs
from manila.openstack.common.notifier import api as notifier_api
from manila.openstack.common.notifier import test_notifier
from manila import test
from manila.tests.api import fakes
import manila.wsgi
def return_create_volume_type_extra_specs(context, volume_type_id,
extra_specs):
return stub_volume_type_extra_specs()
def return_volume_type_extra_specs(context, volume_type_id):
return stub_volume_type_extra_specs()
def return_empty_volume_type_extra_specs(context, volume_type_id):
return {}
def delete_volume_type_extra_specs(context, volume_type_id, key):
pass
def stub_volume_type_extra_specs():
specs = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4",
"key5": "value5"}
return specs
def volume_type_get(context, volume_type_id):
pass
class VolumeTypesExtraSpecsTest(test.TestCase):
def setUp(self):
super(VolumeTypesExtraSpecsTest, self).setUp()
self.flags(connection_type='fake',
host='fake',
notification_driver=[test_notifier.__name__])
self.stubs.Set(manila.db, 'volume_type_get', volume_type_get)
self.api_path = '/v2/fake/os-volume-types/1/extra_specs'
self.controller = types_extra_specs.VolumeTypeExtraSpecsController()
"""to reset notifier drivers left over from other api/contrib tests"""
notifier_api._reset_drivers()
test_notifier.NOTIFICATIONS = []
def tearDown(self):
notifier_api._reset_drivers()
super(VolumeTypesExtraSpecsTest, self).tearDown()
def test_index(self):
self.stubs.Set(manila.db, 'volume_type_extra_specs_get',
return_volume_type_extra_specs)
req = fakes.HTTPRequest.blank(self.api_path)
res_dict = self.controller.index(req, 1)
self.assertEqual('value1', res_dict['extra_specs']['key1'])
def test_index_no_data(self):
self.stubs.Set(manila.db, 'volume_type_extra_specs_get',
return_empty_volume_type_extra_specs)
req = fakes.HTTPRequest.blank(self.api_path)
res_dict = self.controller.index(req, 1)
self.assertEqual(0, len(res_dict['extra_specs']))
def test_show(self):
self.stubs.Set(manila.db, 'volume_type_extra_specs_get',
return_volume_type_extra_specs)
req = fakes.HTTPRequest.blank(self.api_path + '/key5')
res_dict = self.controller.show(req, 1, 'key5')
self.assertEqual('value5', res_dict['key5'])
def test_show_spec_not_found(self):
self.stubs.Set(manila.db, 'volume_type_extra_specs_get',
return_empty_volume_type_extra_specs)
req = fakes.HTTPRequest.blank(self.api_path + '/key6')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
req, 1, 'key6')
def test_delete(self):
self.stubs.Set(manila.db, 'volume_type_extra_specs_delete',
delete_volume_type_extra_specs)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
req = fakes.HTTPRequest.blank(self.api_path + '/key5')
self.controller.delete(req, 1, 'key5')
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
def test_create(self):
self.stubs.Set(manila.db,
'volume_type_extra_specs_update_or_create',
return_create_volume_type_extra_specs)
body = {"extra_specs": {"key1": "value1"}}
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
req = fakes.HTTPRequest.blank(self.api_path)
res_dict = self.controller.create(req, 1, body)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
self.assertEqual('value1', res_dict['extra_specs']['key1'])
def test_update_item(self):
self.stubs.Set(manila.db,
'volume_type_extra_specs_update_or_create',
return_create_volume_type_extra_specs)
body = {"key1": "value1"}
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
req = fakes.HTTPRequest.blank(self.api_path + '/key1')
res_dict = self.controller.update(req, 1, 'key1', body)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
self.assertEqual('value1', res_dict['key1'])
def test_update_item_too_many_keys(self):
self.stubs.Set(manila.db,
'volume_type_extra_specs_update_or_create',
return_create_volume_type_extra_specs)
body = {"key1": "value1", "key2": "value2"}
req = fakes.HTTPRequest.blank(self.api_path + '/key1')
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
req, 1, 'key1', body)
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(manila.db,
'volume_type_extra_specs_update_or_create',
return_create_volume_type_extra_specs)
body = {"key1": "value1"}
req = fakes.HTTPRequest.blank(self.api_path + '/bad')
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
req, 1, 'bad', body)
def _extra_specs_empty_update(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/types/1/extra_specs')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, '1', body)
def test_update_no_body(self):
self._extra_specs_empty_update(body=None)
def test_update_empty_body(self):
self._extra_specs_empty_update(body={})
def _extra_specs_create_bad_body(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/types/1/extra_specs')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, '1', body)
def test_create_no_body(self):
self._extra_specs_create_bad_body(body=None)
def test_create_missing_volume(self):
body = {'foo': {'a': 'b'}}
self._extra_specs_create_bad_body(body=body)
def test_create_malformed_entity(self):
body = {'extra_specs': 'string'}
self._extra_specs_create_bad_body(body=body)
class VolumeTypeExtraSpecsSerializerTest(test.TestCase):
def test_index_create_serializer(self):
serializer = types_extra_specs.VolumeTypeExtraSpecsTemplate()
# Just getting some input data
extra_specs = stub_volume_type_extra_specs()
text = serializer.serialize(dict(extra_specs=extra_specs))
print text
tree = etree.fromstring(text)
self.assertEqual('extra_specs', tree.tag)
self.assertEqual(len(extra_specs), len(tree))
seen = set(extra_specs.keys())
for child in tree:
self.assertTrue(child.tag in seen)
self.assertEqual(extra_specs[child.tag], child.text)
seen.remove(child.tag)
self.assertEqual(len(seen), 0)
def test_update_show_serializer(self):
serializer = types_extra_specs.VolumeTypeExtraSpecTemplate()
exemplar = dict(key1='value1')
text = serializer.serialize(exemplar)
print text
tree = etree.fromstring(text)
self.assertEqual('key1', tree.tag)
self.assertEqual('value1', tree.text)
self.assertEqual(0, len(tree))

View File

@ -1,129 +0,0 @@
# Copyright 2011 OpenStack LLC.
# 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 webob
from manila.api.contrib import types_manage
from manila import exception
from manila.openstack.common.notifier import api as notifier_api
from manila.openstack.common.notifier import test_notifier
from manila import test
from manila.tests.api import fakes
from manila.volume import volume_types
def stub_volume_type(id):
specs = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4",
"key5": "value5"}
return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs)
def return_volume_types_get_volume_type(context, id):
if id == "777":
raise exception.VolumeTypeNotFound(volume_type_id=id)
return stub_volume_type(int(id))
def return_volume_types_destroy(context, name):
if name == "777":
raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
pass
def return_volume_types_create(context, name, specs):
pass
def return_volume_types_get_by_name(context, name):
if name == "777":
raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
return stub_volume_type(int(name.split("_")[2]))
class VolumeTypesManageApiTest(test.TestCase):
def setUp(self):
super(VolumeTypesManageApiTest, self).setUp()
self.flags(connection_type='fake',
host='fake',
notification_driver=[test_notifier.__name__])
self.controller = types_manage.VolumeTypesManageController()
"""to reset notifier drivers left over from other api/contrib tests"""
notifier_api._reset_drivers()
test_notifier.NOTIFICATIONS = []
def tearDown(self):
notifier_api._reset_drivers()
super(VolumeTypesManageApiTest, self).tearDown()
def test_volume_types_delete(self):
self.stubs.Set(volume_types, 'get_volume_type',
return_volume_types_get_volume_type)
self.stubs.Set(volume_types, 'destroy',
return_volume_types_destroy)
req = fakes.HTTPRequest.blank('/v2/fake/types/1')
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
self.controller._delete(req, 1)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
def test_volume_types_delete_not_found(self):
self.stubs.Set(volume_types, 'get_volume_type',
return_volume_types_get_volume_type)
self.stubs.Set(volume_types, 'destroy',
return_volume_types_destroy)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
req = fakes.HTTPRequest.blank('/v2/fake/types/777')
self.assertRaises(webob.exc.HTTPNotFound, self.controller._delete,
req, '777')
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
def test_create(self):
self.stubs.Set(volume_types, 'create',
return_volume_types_create)
self.stubs.Set(volume_types, 'get_volume_type_by_name',
return_volume_types_get_by_name)
body = {"volume_type": {"name": "vol_type_1",
"extra_specs": {"key1": "value1"}}}
req = fakes.HTTPRequest.blank('/v2/fake/types')
self.assertEquals(len(test_notifier.NOTIFICATIONS), 0)
res_dict = self.controller._create(req, body)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
self.assertEqual(1, len(res_dict))
self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
def _create_volume_type_bad_body(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/types')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._create, req, body)
def test_create_no_body(self):
self._create_volume_type_bad_body(body=None)
def test_create_missing_volume(self):
body = {'foo': {'a': 'b'}}
self._create_volume_type_bad_body(body=body)
def test_create_malformed_entity(self):
body = {'volume_type': 'string'}
self._create_volume_type_bad_body(body=body)

View File

@ -1,248 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
#
# 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 datetime
import uuid
import webob
from manila.api.contrib import volume_actions
from manila import exception
from manila import flags
from manila.openstack.common import jsonutils
from manila.openstack.common.rpc import common as rpc_common
from manila import test
from manila.tests.api import fakes
from manila.tests.api.v2 import stubs
from manila import volume
from manila.volume import api as volume_api
FLAGS = flags.FLAGS
def fake_volume_api(*args, **kwargs):
return True
def fake_volume_get(*args, **kwargs):
return {'id': 'fake', 'host': 'fake'}
class VolumeActionsTest(test.TestCase):
_actions = ('os-detach', 'os-reserve', 'os-unreserve')
_methods = ('attach', 'detach', 'reserve_volume', 'unreserve_volume')
def setUp(self):
super(VolumeActionsTest, self).setUp()
self.stubs.Set(volume.API, 'get', fake_volume_api)
self.UUID = uuid.uuid4()
for _method in self._methods:
self.stubs.Set(volume.API, _method, fake_volume_api)
self.stubs.Set(volume.API, 'get', fake_volume_get)
def test_simple_api_actions(self):
app = fakes.wsgi_app()
for _action in self._actions:
req = webob.Request.blank('/v2/fake/volumes/%s/action' %
self.UUID)
req.method = 'POST'
req.body = jsonutils.dumps({_action: None})
req.content_type = 'application/json'
res = req.get_response(app)
self.assertEqual(res.status_int, 202)
def test_initialize_connection(self):
def fake_initialize_connection(*args, **kwargs):
return {}
self.stubs.Set(volume.API, 'initialize_connection',
fake_initialize_connection)
body = {'os-initialize_connection': {'connector': 'fake'}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
def test_terminate_connection(self):
def fake_terminate_connection(*args, **kwargs):
return {}
self.stubs.Set(volume.API, 'terminate_connection',
fake_terminate_connection)
body = {'os-terminate_connection': {'connector': 'fake'}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_attach(self):
body = {'os-attach': {'instance_uuid': 'fake',
'mountpoint': '/dev/vdc'}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def stub_volume_get(self, context, volume_id):
volume = stubs.stub_volume(volume_id)
if volume_id == 5:
volume['status'] = 'in-use'
else:
volume['status'] = 'available'
return volume
def stub_upload_volume_to_image_service(self, context, volume, metadata,
force):
ret = {"id": volume['id'],
"updated_at": datetime.datetime(1, 1, 1, 1, 1, 1),
"status": 'uploading',
"display_description": volume['display_description'],
"size": volume['size'],
"volume_type": volume['volume_type'],
"image_id": 1,
"container_format": 'bare',
"disk_format": 'raw',
"image_name": 'image_name'}
return ret
class VolumeImageActionsTest(test.TestCase):
def setUp(self):
super(VolumeImageActionsTest, self).setUp()
self.controller = volume_actions.VolumeActionsController()
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
def test_copy_volume_to_image(self):
self.stubs.Set(volume_api.API,
"copy_volume_to_image",
stub_upload_volume_to_image_service)
id = 1
vol = {"container_format": 'bare',
"disk_format": 'raw',
"image_name": 'image_name',
"force": True}
body = {"os-volume_upload_image": vol}
req = fakes.HTTPRequest.blank('/v2/tenant1/volumes/%s/action' % id)
res_dict = self.controller._volume_upload_image(req, id, body)
expected = {'os-volume_upload_image': {'id': id,
'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'status': 'uploading',
'display_description': 'displaydesc',
'size': 1,
'volume_type': {'name': 'vol_type_name'},
'image_id': 1,
'container_format': 'bare',
'disk_format': 'raw',
'image_name': 'image_name'}}
self.assertDictMatch(res_dict, expected)
def test_copy_volume_to_image_volumenotfound(self):
def stub_volume_get_raise_exc(self, context, volume_id):
raise exception.VolumeNotFound(volume_id=volume_id)
self.stubs.Set(volume_api.API, 'get', stub_volume_get_raise_exc)
id = 1
vol = {"container_format": 'bare',
"disk_format": 'raw',
"image_name": 'image_name',
"force": True}
body = {"os-volume_upload_image": vol}
req = fakes.HTTPRequest.blank('/v2/tenant1/volumes/%s/action' % id)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller._volume_upload_image,
req,
id,
body)
def test_copy_volume_to_image_invalidvolume(self):
def stub_upload_volume_to_image_service_raise(self, context, volume,
metadata, force):
raise exception.InvalidVolume(reason='blah')
self.stubs.Set(volume_api.API,
"copy_volume_to_image",
stub_upload_volume_to_image_service_raise)
id = 1
vol = {"container_format": 'bare',
"disk_format": 'raw',
"image_name": 'image_name',
"force": True}
body = {"os-volume_upload_image": vol}
req = fakes.HTTPRequest.blank('/v2/tenant1/volumes/%s/action' % id)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._volume_upload_image,
req,
id,
body)
def test_copy_volume_to_image_valueerror(self):
def stub_upload_volume_to_image_service_raise(self, context, volume,
metadata, force):
raise ValueError
self.stubs.Set(volume_api.API,
"copy_volume_to_image",
stub_upload_volume_to_image_service_raise)
id = 1
vol = {"container_format": 'bare',
"disk_format": 'raw',
"image_name": 'image_name',
"force": True}
body = {"os-volume_upload_image": vol}
req = fakes.HTTPRequest.blank('/v2/tenant1/volumes/%s/action' % id)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._volume_upload_image,
req,
id,
body)
def test_copy_volume_to_image_remoteerror(self):
def stub_upload_volume_to_image_service_raise(self, context, volume,
metadata, force):
raise rpc_common.RemoteError
self.stubs.Set(volume_api.API,
"copy_volume_to_image",
stub_upload_volume_to_image_service_raise)
id = 1
vol = {"container_format": 'bare',
"disk_format": 'raw',
"image_name": 'image_name',
"force": True}
body = {"os-volume_upload_image": vol}
req = fakes.HTTPRequest.blank('/v2/tenant1/volumes/%s/action' % id)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._volume_upload_image,
req,
id,
body)

View File

@ -1,134 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
#
# 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 datetime
import json
import uuid
from lxml import etree
import webob
from manila import context
from manila import test
from manila.tests.api import fakes
from manila import volume
def fake_volume_get(*args, **kwargs):
return {
'id': 'fake',
'host': 'host001',
'status': 'available',
'size': 5,
'availability_zone': 'somewhere',
'created_at': datetime.datetime.now(),
'attach_status': None,
'display_name': 'anothervolume',
'display_description': 'Just another volume!',
'volume_type_id': None,
'snapshot_id': None,
'project_id': 'fake',
}
def fake_volume_get_all(*args, **kwargs):
return [fake_volume_get()]
def app():
# no auth, just let environ['manila.context'] pass through
api = fakes.router.APIRouter()
mapper = fakes.urlmap.URLMap()
mapper['/v2'] = api
return mapper
class VolumeHostAttributeTest(test.TestCase):
def setUp(self):
super(VolumeHostAttributeTest, self).setUp()
self.stubs.Set(volume.API, 'get', fake_volume_get)
self.stubs.Set(volume.API, 'get_all', fake_volume_get_all)
self.UUID = uuid.uuid4()
def test_get_volume_allowed(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/%s' % self.UUID)
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volume']
self.assertEqual(vol['os-vol-host-attr:host'], 'host001')
def test_get_volume_unallowed(self):
ctx = context.RequestContext('non-admin', 'fake', False)
req = webob.Request.blank('/v2/fake/volumes/%s' % self.UUID)
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volume']
self.assertFalse('os-vol-host-attr:host' in vol)
def test_list_detail_volumes_allowed(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/detail')
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volumes']
self.assertEqual(vol[0]['os-vol-host-attr:host'], 'host001')
def test_list_detail_volumes_unallowed(self):
ctx = context.RequestContext('non-admin', 'fake', False)
req = webob.Request.blank('/v2/fake/volumes/detail')
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volumes']
self.assertFalse('os-vol-host-attr:host' in vol[0])
def test_list_simple_volumes_no_host(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes')
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volumes']
self.assertFalse('os-vol-host-attr:host' in vol[0])
def test_get_volume_xml(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/%s' % self.UUID)
req.method = 'GET'
req.accept = 'application/xml'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = etree.XML(res.body)
host_key = ('{http://docs.openstack.org/volume/ext/'
'volume_host_attribute/api/v1}host')
self.assertEqual(vol.get(host_key), 'host001')
def test_list_volumes_detail_xml(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/detail')
req.method = 'GET'
req.accept = 'application/xml'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = list(etree.XML(res.body))[0]
host_key = ('{http://docs.openstack.org/volume/ext/'
'volume_host_attribute/api/v1}host')
self.assertEqual(vol.get(host_key), 'host001')

View File

@ -1,130 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
#
# 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 datetime
import json
import uuid
from xml.dom import minidom
import webob
from manila.api import common
from manila.api.openstack.wsgi import MetadataXMLDeserializer
from manila.api.openstack.wsgi import XMLDeserializer
from manila import test
from manila.tests.api import fakes
from manila import volume
def fake_volume_get(*args, **kwargs):
return {
'id': 'fake',
'host': 'host001',
'status': 'available',
'size': 5,
'availability_zone': 'somewhere',
'created_at': datetime.datetime.now(),
'attach_status': None,
'display_name': 'anothervolume',
'display_description': 'Just another volume!',
'volume_type_id': None,
'snapshot_id': None,
'project_id': 'fake',
}
def fake_volume_get_all(*args, **kwargs):
return [fake_volume_get()]
fake_image_metadata = {
'image_id': 'someid',
'image_name': 'fake',
'kernel_id': 'somekernel',
'ramdisk_id': 'someramdisk',
}
def fake_get_volume_image_metadata(*args, **kwargs):
return fake_image_metadata
class VolumeImageMetadataTest(test.TestCase):
content_type = 'application/json'
def setUp(self):
super(VolumeImageMetadataTest, self).setUp()
self.stubs.Set(volume.API, 'get', fake_volume_get)
self.stubs.Set(volume.API, 'get_all', fake_volume_get_all)
self.stubs.Set(volume.API, 'get_volume_image_metadata',
fake_get_volume_image_metadata)
self.UUID = uuid.uuid4()
def _make_request(self, url):
req = webob.Request.blank(url)
req.accept = self.content_type
res = req.get_response(fakes.wsgi_app())
return res
def _get_image_metadata(self, body):
return json.loads(body)['volume']['volume_image_metadata']
def _get_image_metadata_list(self, body):
return [
volume['volume_image_metadata']
for volume in json.loads(body)['volumes']
]
def test_get_volume(self):
res = self._make_request('/v2/fake/volumes/%s' % self.UUID)
self.assertEqual(res.status_int, 200)
self.assertEqual(self._get_image_metadata(res.body),
fake_image_metadata)
def test_list_detail_volumes(self):
res = self._make_request('/v2/fake/volumes/detail')
self.assertEqual(res.status_int, 200)
self.assertEqual(self._get_image_metadata_list(res.body)[0],
fake_image_metadata)
class ImageMetadataXMLDeserializer(common.MetadataXMLDeserializer):
metadata_node_name = "volume_image_metadata"
class VolumeImageMetadataXMLTest(VolumeImageMetadataTest):
content_type = 'application/xml'
def _get_image_metadata(self, body):
deserializer = XMLDeserializer()
volume = deserializer.find_first_child_named(
minidom.parseString(body), 'volume')
image_metadata = deserializer.find_first_child_named(
volume, 'volume_image_metadata')
return MetadataXMLDeserializer().extract_metadata(image_metadata)
def _get_image_metadata_list(self, body):
deserializer = XMLDeserializer()
volumes = deserializer.find_first_child_named(
minidom.parseString(body), 'volumes')
volume_list = deserializer.find_children_named(volumes, 'volume')
image_metadata_list = [
deserializer.find_first_child_named(
volume, 'volume_image_metadata'
)
for volume in volume_list]
return map(MetadataXMLDeserializer().extract_metadata,
image_metadata_list)

View File

@ -1,137 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
#
# 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 datetime
import json
import uuid
from lxml import etree
import webob
from manila import context
from manila import test
from manila.tests.api import fakes
from manila import volume
PROJECT_ID = '88fd1da4-f464-4a87-9ce5-26f2f40743b9'
def fake_volume_get(*args, **kwargs):
return {
'id': 'fake',
'host': 'host001',
'status': 'available',
'size': 5,
'availability_zone': 'somewhere',
'created_at': datetime.datetime.now(),
'attach_status': None,
'display_name': 'anothervolume',
'display_description': 'Just another volume!',
'volume_type_id': None,
'snapshot_id': None,
'project_id': PROJECT_ID,
}
def fake_volume_get_all(*args, **kwargs):
return [fake_volume_get()]
def app():
# no auth, just let environ['manila.context'] pass through
api = fakes.router.APIRouter()
mapper = fakes.urlmap.URLMap()
mapper['/v2'] = api
return mapper
class VolumeTenantAttributeTest(test.TestCase):
def setUp(self):
super(VolumeTenantAttributeTest, self).setUp()
self.stubs.Set(volume.API, 'get', fake_volume_get)
self.stubs.Set(volume.API, 'get_all', fake_volume_get_all)
self.UUID = uuid.uuid4()
def test_get_volume_allowed(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/%s' % self.UUID)
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volume']
self.assertEqual(vol['os-vol-tenant-attr:tenant_id'], PROJECT_ID)
def test_get_volume_unallowed(self):
ctx = context.RequestContext('non-admin', 'fake', False)
req = webob.Request.blank('/v2/fake/volumes/%s' % self.UUID)
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volume']
self.assertFalse('os-vol-tenant-attr:tenant_id' in vol)
def test_list_detail_volumes_allowed(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/detail')
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volumes']
self.assertEqual(vol[0]['os-vol-tenant-attr:tenant_id'], PROJECT_ID)
def test_list_detail_volumes_unallowed(self):
ctx = context.RequestContext('non-admin', 'fake', False)
req = webob.Request.blank('/v2/fake/volumes/detail')
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volumes']
self.assertFalse('os-vol-tenant-attr:tenant_id' in vol[0])
def test_list_simple_volumes_no_tenant_id(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes')
req.method = 'GET'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = json.loads(res.body)['volumes']
self.assertFalse('os-vol-tenant-attr:tenant_id' in vol[0])
def test_get_volume_xml(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/%s' % self.UUID)
req.method = 'GET'
req.accept = 'application/xml'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = etree.XML(res.body)
tenant_key = ('{http://docs.openstack.org/volume/ext/'
'volume_tenant_attribute/api/v1}tenant_id')
self.assertEqual(vol.get(tenant_key), PROJECT_ID)
def test_list_volumes_detail_xml(self):
ctx = context.RequestContext('admin', 'fake', True)
req = webob.Request.blank('/v2/fake/volumes/detail')
req.method = 'GET'
req.accept = 'application/xml'
req.environ['manila.context'] = ctx
res = req.get_response(app())
vol = list(etree.XML(res.body))[0]
tenant_key = ('{http://docs.openstack.org/volume/ext/'
'volume_tenant_attribute/api/v1}tenant_id')
self.assertEqual(vol.get(tenant_key), PROJECT_ID)

View File

@ -1,458 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# 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 uuid
from oslo.config import cfg
import webob
from manila.api import extensions
from manila.api.v1 import snapshot_metadata
from manila.api.v1 import snapshots
import manila.db
from manila import exception
from manila.openstack.common import jsonutils
from manila import test
from manila.tests.api import fakes
CONF = cfg.CONF
def return_create_snapshot_metadata_max(context,
snapshot_id,
metadata,
delete):
return stub_max_snapshot_metadata()
def return_create_snapshot_metadata(context, snapshot_id, metadata, delete):
return stub_snapshot_metadata()
def return_snapshot_metadata(context, snapshot_id):
if not isinstance(snapshot_id, str) or not len(snapshot_id) == 36:
msg = 'id %s must be a uuid in return snapshot metadata' % snapshot_id
raise Exception(msg)
return stub_snapshot_metadata()
def return_empty_snapshot_metadata(context, snapshot_id):
return {}
def delete_snapshot_metadata(context, snapshot_id, key):
pass
def stub_snapshot_metadata():
metadata = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
return metadata
def stub_max_snapshot_metadata():
metadata = {"metadata": {}}
for num in range(CONF.quota_metadata_items):
metadata['metadata']['key%i' % num] = "blah"
return metadata
def return_snapshot(context, snapshot_id):
return {'id': '0cc3346e-9fef-4445-abe6-5d2b2690ec64',
'name': 'fake',
'status': 'available',
'metadata': {}}
def return_volume(context, volume_id):
return {'id': 'fake-vol-id',
'size': 100,
'name': 'fake',
'host': 'fake-host',
'status': 'available',
'metadata': {}}
def return_snapshot_nonexistent(context, snapshot_id):
raise exception.SnapshotNotFound('bogus test message')
def fake_update_snapshot_metadata(self, context, snapshot, diff):
pass
class SnapshotMetaDataTest(test.TestCase):
def setUp(self):
super(SnapshotMetaDataTest, self).setUp()
self.volume_api = manila.volume.api.API()
fakes.stub_out_key_pair_funcs(self.stubs)
self.stubs.Set(manila.db, 'volume_get', return_volume)
self.stubs.Set(manila.db, 'snapshot_get', return_snapshot)
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_metadata)
self.stubs.Set(self.volume_api, 'update_snapshot_metadata',
fake_update_snapshot_metadata)
self.ext_mgr = extensions.ExtensionManager()
self.ext_mgr.extensions = {}
self.snapshot_controller = snapshots.SnapshotsController(self.ext_mgr)
self.controller = snapshot_metadata.Controller()
self.id = str(uuid.uuid4())
self.url = '/v1/fake/snapshots/%s/metadata' % self.id
snap = {"volume_size": 100,
"volume_id": "fake-vol-id",
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "zone1:host1",
"host": "fake-host",
"metadata": {}}
body = {"snapshot": snap}
req = fakes.HTTPRequest.blank('/v1/snapshots')
self.snapshot_controller.create(req, body)
def test_index(self):
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.id)
expected = {
'metadata': {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
},
}
self.assertEqual(expected, res_dict)
def test_index_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.index, req, self.url)
def test_index_no_data(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.id)
expected = {'metadata': {}}
self.assertEqual(expected, res_dict)
def test_show(self):
req = fakes.HTTPRequest.blank(self.url + '/key2')
res_dict = self.controller.show(req, self.id, 'key2')
expected = {'meta': {'key2': 'value2'}}
self.assertEqual(expected, res_dict)
def test_show_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url + '/key2')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, self.id, 'key2')
def test_show_meta_not_found(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key6')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, self.id, 'key6')
def test_delete(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_metadata)
self.stubs.Set(manila.db, 'snapshot_metadata_delete',
delete_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key2')
req.method = 'DELETE'
res = self.controller.delete(req, self.id, 'key2')
self.assertEqual(200, res.status_int)
def test_delete_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, req, self.id, 'key1')
def test_delete_meta_not_found(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key6')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, req, self.id, 'key6')
def test_create(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank('/v1/snapshot_metadata')
req.method = 'POST'
req.content_type = "application/json"
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
res_dict = self.controller.create(req, self.id, body)
self.assertEqual(body, res_dict)
def test_create_empty_body(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'POST'
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, None)
def test_create_item_empty_key(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, body)
def test_create_item_key_too_long(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {("a" * 260): "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req, self.id, body)
def test_create_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get',
return_snapshot_nonexistent)
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_metadata)
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank('/v1/snapshot_metadata')
req.method = 'POST'
req.content_type = "application/json"
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.create, req, self.id, body)
def test_update_all(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {
'metadata': {
'key10': 'value10',
'key99': 'value99',
},
}
req.body = jsonutils.dumps(expected)
res_dict = self.controller.update_all(req, self.id, expected)
self.assertEqual(expected, res_dict)
def test_update_all_empty_container(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'metadata': {}}
req.body = jsonutils.dumps(expected)
res_dict = self.controller.update_all(req, self.id, expected)
self.assertEqual(expected, res_dict)
def test_update_all_malformed_container(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'meta': {}}
req.body = jsonutils.dumps(expected)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.id, expected)
def test_update_all_malformed_data(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'metadata': ['asdf']}
req.body = jsonutils.dumps(expected)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.id, expected)
def test_update_all_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get', return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
body = {'metadata': {'key10': 'value10'}}
req.body = jsonutils.dumps(body)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update_all, req, '100', body)
def test_update_item(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res_dict = self.controller.update(req, self.id, 'key1', body)
expected = {'meta': {'key1': 'value1'}}
self.assertEqual(expected, res_dict)
def test_update_item_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(
'/v1.1/fake/snapshots/asdf/metadata/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update, req, self.id, 'key1', body)
def test_update_item_empty_body(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'key1', None)
def test_update_item_empty_key(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, '', body)
def test_update_item_key_too_long(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {("a" * 260): "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.update,
req, self.id, ("a" * 260), body)
def test_update_item_value_too_long(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": ("a" * 260)}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.update,
req, self.id, "key1", body)
def test_update_item_too_many_keys(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1", "key2": "value2"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'key1', body)
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/bad')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'bad', body)
def test_invalid_metadata_items_on_create(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'POST'
req.headers["content-type"] = "application/json"
#test for long key
data = {"metadata": {"a" * 260: "value1"}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.create, req, self.id, data)
#test for long value
data = {"metadata": {"key": "v" * 260}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.create, req, self.id, data)
#test for empty key.
data = {"metadata": {"": "value1"}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, data)

View File

@ -1,417 +0,0 @@
# Copyright 2011 Denali 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 datetime
from lxml import etree
import webob
from manila.api.v1 import snapshots
from manila import db
from manila import exception
from manila import flags
from manila.openstack.common import log as logging
from manila import test
from manila.tests.api import fakes
from manila.tests.api.v1 import stubs
from manila import volume
FLAGS = flags.FLAGS
LOG = logging.getLogger(__name__)
UUID = '00000000-0000-0000-0000-000000000001'
INVALID_UUID = '00000000-0000-0000-0000-000000000002'
def _get_default_snapshot_param():
return {'id': UUID,
'volume_id': 12,
'status': 'available',
'volume_size': 100,
'created_at': None,
'display_name': 'Default name',
'display_description': 'Default description', }
def stub_snapshot_create(self, context,
volume_id, name,
description, metadata):
snapshot = _get_default_snapshot_param()
snapshot['volume_id'] = volume_id
snapshot['display_name'] = name
snapshot['display_description'] = description
snapshot['metadata'] = metadata
return snapshot
def stub_snapshot_delete(self, context, snapshot):
if snapshot['id'] != UUID:
raise exception.NotFound
def stub_snapshot_get(self, context, snapshot_id):
if snapshot_id != UUID:
raise exception.NotFound
param = _get_default_snapshot_param()
return param
def stub_snapshot_get_all(self, context, search_opts=None):
param = _get_default_snapshot_param()
return [param]
class SnapshotApiTest(test.TestCase):
def setUp(self):
super(SnapshotApiTest, self).setUp()
self.controller = snapshots.SnapshotsController()
self.stubs.Set(db, 'snapshot_get_all_by_project',
stubs.stub_snapshot_get_all_by_project)
self.stubs.Set(db, 'snapshot_get_all',
stubs.stub_snapshot_get_all)
def test_snapshot_create(self):
self.stubs.Set(volume.api.API, "create_snapshot", stub_snapshot_create)
self.stubs.Set(volume.api.API, 'get', stubs.stub_volume_get)
snapshot = {"volume_id": '12',
"force": False,
"display_name": "Snapshot Test Name",
"display_description": "Snapshot Test Desc"}
body = dict(snapshot=snapshot)
req = fakes.HTTPRequest.blank('/v1/snapshots')
resp_dict = self.controller.create(req, body)
self.assertTrue('snapshot' in resp_dict)
self.assertEqual(resp_dict['snapshot']['display_name'],
snapshot['display_name'])
self.assertEqual(resp_dict['snapshot']['display_description'],
snapshot['display_description'])
def test_snapshot_create_force(self):
self.stubs.Set(volume.api.API,
"create_snapshot_force",
stub_snapshot_create)
self.stubs.Set(volume.api.API, 'get', stubs.stub_volume_get)
snapshot = {"volume_id": '12',
"force": True,
"display_name": "Snapshot Test Name",
"display_description": "Snapshot Test Desc"}
body = dict(snapshot=snapshot)
req = fakes.HTTPRequest.blank('/v1/snapshots')
resp_dict = self.controller.create(req, body)
self.assertTrue('snapshot' in resp_dict)
self.assertEqual(resp_dict['snapshot']['display_name'],
snapshot['display_name'])
self.assertEqual(resp_dict['snapshot']['display_description'],
snapshot['display_description'])
snapshot = {"volume_id": "12",
"force": "**&&^^%%$$##@@",
"display_name": "Snapshot Test Name",
"display_description": "Snapshot Test Desc"}
body = dict(snapshot=snapshot)
req = fakes.HTTPRequest.blank('/v1/snapshots')
self.assertRaises(exception.InvalidParameterValue,
self.controller.create,
req,
body)
def test_snapshot_update(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
self.stubs.Set(volume.api.API, "update_snapshot",
stubs.stub_snapshot_update)
updates = {"display_name": "Updated Test Name", }
body = {"snapshot": updates}
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
res_dict = self.controller.update(req, UUID, body)
expected = {'snapshot': {
'id': UUID,
'volume_id': 12,
'status': 'available',
'size': 100,
'created_at': None,
'display_name': 'Updated Test Name',
'display_description': 'Default description',
'metadata': {},
}}
self.assertEquals(expected, res_dict)
def test_snapshot_update_missing_body(self):
body = {}
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update, req, UUID, body)
def test_snapshot_update_invalid_body(self):
body = {'display_name': 'missing top level snapshot key'}
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update, req, UUID, body)
def test_snapshot_update_not_found(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
updates = {
"display_name": "Updated Test Name",
}
body = {"snapshot": updates}
req = fakes.HTTPRequest.blank('/v1/snapshots/not-the-uuid')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.update, req,
'not-the-uuid', body)
def test_snapshot_delete(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
snapshot_id = UUID
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % snapshot_id)
resp = self.controller.delete(req, snapshot_id)
self.assertEqual(resp.status_int, 202)
def test_snapshot_delete_invalid_id(self):
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
snapshot_id = INVALID_UUID
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % snapshot_id)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete,
req,
snapshot_id)
def test_snapshot_show(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % UUID)
resp_dict = self.controller.show(req, UUID)
self.assertTrue('snapshot' in resp_dict)
self.assertEqual(resp_dict['snapshot']['id'], UUID)
def test_snapshot_show_invalid_id(self):
snapshot_id = INVALID_UUID
req = fakes.HTTPRequest.blank('/v1/snapshots/%s' % snapshot_id)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show,
req,
snapshot_id)
def test_snapshot_detail(self):
self.stubs.Set(volume.api.API,
"get_all_snapshots",
stub_snapshot_get_all)
req = fakes.HTTPRequest.blank('/v1/snapshots/detail')
resp_dict = self.controller.detail(req)
self.assertTrue('snapshots' in resp_dict)
resp_snapshots = resp_dict['snapshots']
self.assertEqual(len(resp_snapshots), 1)
resp_snapshot = resp_snapshots.pop()
self.assertEqual(resp_snapshot['id'], UUID)
def test_snapshot_list_by_status(self):
def stub_snapshot_get_all_by_project(context, project_id):
return [
stubs.stub_snapshot(1, display_name='backup1',
status='available'),
stubs.stub_snapshot(2, display_name='backup2',
status='available'),
stubs.stub_snapshot(3, display_name='backup3',
status='creating'),
]
self.stubs.Set(db, 'snapshot_get_all_by_project',
stub_snapshot_get_all_by_project)
# no status filter
req = fakes.HTTPRequest.blank('/v1/snapshots')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 3)
# single match
req = fakes.HTTPRequest.blank('/v1/snapshots?status=creating')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEqual(resp['snapshots'][0]['status'], 'creating')
# multiple match
req = fakes.HTTPRequest.blank('/v1/snapshots?status=available')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 2)
for snapshot in resp['snapshots']:
self.assertEquals(snapshot['status'], 'available')
# no match
req = fakes.HTTPRequest.blank('/v1/snapshots?status=error')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 0)
def test_snapshot_list_by_volume(self):
def stub_snapshot_get_all_by_project(context, project_id):
return [
stubs.stub_snapshot(1, volume_id='vol1', status='creating'),
stubs.stub_snapshot(2, volume_id='vol1', status='available'),
stubs.stub_snapshot(3, volume_id='vol2', status='available'),
]
self.stubs.Set(db, 'snapshot_get_all_by_project',
stub_snapshot_get_all_by_project)
# single match
req = fakes.HTTPRequest.blank('/v1/snapshots?volume_id=vol2')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEqual(resp['snapshots'][0]['volume_id'], 'vol2')
# multiple match
req = fakes.HTTPRequest.blank('/v1/snapshots?volume_id=vol1')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 2)
for snapshot in resp['snapshots']:
self.assertEqual(snapshot['volume_id'], 'vol1')
# multiple filters
req = fakes.HTTPRequest.blank('/v1/snapshots?volume_id=vol1'
'&status=available')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEqual(resp['snapshots'][0]['volume_id'], 'vol1')
self.assertEqual(resp['snapshots'][0]['status'], 'available')
def test_snapshot_list_by_name(self):
def stub_snapshot_get_all_by_project(context, project_id):
return [
stubs.stub_snapshot(1, display_name='backup1'),
stubs.stub_snapshot(2, display_name='backup2'),
stubs.stub_snapshot(3, display_name='backup3'),
]
self.stubs.Set(db, 'snapshot_get_all_by_project',
stub_snapshot_get_all_by_project)
# no display_name filter
req = fakes.HTTPRequest.blank('/v1/snapshots')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 3)
# filter by one name
req = fakes.HTTPRequest.blank('/v1/snapshots?display_name=backup2')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEquals(resp['snapshots'][0]['display_name'], 'backup2')
# filter no match
req = fakes.HTTPRequest.blank('/v1/snapshots?display_name=backup4')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 0)
def test_admin_list_snapshots_limited_to_project(self):
req = fakes.HTTPRequest.blank('/v1/fake/snapshots',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(1, len(res['snapshots']))
def test_admin_list_snapshots_all_tenants(self):
req = fakes.HTTPRequest.blank('/v1/fake/snapshots?all_tenants=1',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(3, len(res['snapshots']))
def test_all_tenants_non_admin_gets_all_tenants(self):
req = fakes.HTTPRequest.blank('/v1/fake/snapshots?all_tenants=1')
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(1, len(res['snapshots']))
def test_non_admin_get_by_project(self):
req = fakes.HTTPRequest.blank('/v1/fake/snapshots')
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(1, len(res['snapshots']))
class SnapshotSerializerTest(test.TestCase):
def _verify_snapshot(self, snap, tree):
self.assertEqual(tree.tag, 'snapshot')
for attr in ('id', 'status', 'size', 'created_at',
'display_name', 'display_description', 'volume_id'):
self.assertEqual(str(snap[attr]), tree.get(attr))
def test_snapshot_show_create_serializer(self):
serializer = snapshots.SnapshotTemplate()
raw_snapshot = dict(
id='snap_id',
status='snap_status',
size=1024,
created_at=datetime.datetime.now(),
display_name='snap_name',
display_description='snap_desc',
volume_id='vol_id', )
text = serializer.serialize(dict(snapshot=raw_snapshot))
print text
tree = etree.fromstring(text)
self._verify_snapshot(raw_snapshot, tree)
def test_snapshot_index_detail_serializer(self):
serializer = snapshots.SnapshotsTemplate()
raw_snapshots = [dict(id='snap1_id',
status='snap1_status',
size=1024,
created_at=datetime.datetime.now(),
display_name='snap1_name',
display_description='snap1_desc',
volume_id='vol1_id', ),
dict(id='snap2_id',
status='snap2_status',
size=1024,
created_at=datetime.datetime.now(),
display_name='snap2_name',
display_description='snap2_desc',
volume_id='vol2_id', )]
text = serializer.serialize(dict(snapshots=raw_snapshots))
print text
tree = etree.fromstring(text)
self.assertEqual('snapshots', tree.tag)
self.assertEqual(len(raw_snapshots), len(tree))
for idx, child in enumerate(tree):
self._verify_snapshot(raw_snapshots[idx], child)
class SnapshotsUnprocessableEntityTestCase(test.TestCase):
"""
Tests of places we throw 422 Unprocessable Entity from
"""
def setUp(self):
super(SnapshotsUnprocessableEntityTestCase, self).setUp()
self.controller = snapshots.SnapshotsController()
def _unprocessable_snapshot_create(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/snapshots')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.create, req, body)
def test_create_no_body(self):
self._unprocessable_snapshot_create(body=None)
def test_create_missing_snapshot(self):
body = {'foo': {'a': 'b'}}
self._unprocessable_snapshot_create(body=body)
def test_create_malformed_entity(self):
body = {'snapshot': 'string'}
self._unprocessable_snapshot_create(body=body)

View File

@ -1,194 +0,0 @@
# Copyright 2011 OpenStack LLC.
# 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.
from lxml import etree
import webob
from manila.api.v1 import types
from manila.api.views import types as views_types
from manila import exception
from manila.openstack.common import timeutils
from manila import test
from manila.tests.api import fakes
from manila.volume import volume_types
def stub_volume_type(id):
specs = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4",
"key5": "value5"}
return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs)
def return_volume_types_get_all_types(context):
return dict(vol_type_1=stub_volume_type(1),
vol_type_2=stub_volume_type(2),
vol_type_3=stub_volume_type(3))
def return_empty_volume_types_get_all_types(context):
return {}
def return_volume_types_get_volume_type(context, id):
if id == "777":
raise exception.VolumeTypeNotFound(volume_type_id=id)
return stub_volume_type(int(id))
def return_volume_types_get_by_name(context, name):
if name == "777":
raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
return stub_volume_type(int(name.split("_")[2]))
class VolumeTypesApiTest(test.TestCase):
def setUp(self):
super(VolumeTypesApiTest, self).setUp()
self.controller = types.VolumeTypesController()
def test_volume_types_index(self):
self.stubs.Set(volume_types, 'get_all_types',
return_volume_types_get_all_types)
req = fakes.HTTPRequest.blank('/v1/fake/types')
res_dict = self.controller.index(req)
self.assertEqual(3, len(res_dict['volume_types']))
expected_names = ['vol_type_1', 'vol_type_2', 'vol_type_3']
actual_names = map(lambda e: e['name'], res_dict['volume_types'])
self.assertEqual(set(actual_names), set(expected_names))
for entry in res_dict['volume_types']:
self.assertEqual('value1', entry['extra_specs']['key1'])
def test_volume_types_index_no_data(self):
self.stubs.Set(volume_types, 'get_all_types',
return_empty_volume_types_get_all_types)
req = fakes.HTTPRequest.blank('/v1/fake/types')
res_dict = self.controller.index(req)
self.assertEqual(0, len(res_dict['volume_types']))
def test_volume_types_show(self):
self.stubs.Set(volume_types, 'get_volume_type',
return_volume_types_get_volume_type)
req = fakes.HTTPRequest.blank('/v1/fake/types/1')
res_dict = self.controller.show(req, 1)
self.assertEqual(1, len(res_dict))
self.assertEqual('1', res_dict['volume_type']['id'])
self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
def test_volume_types_show_not_found(self):
self.stubs.Set(volume_types, 'get_volume_type',
return_volume_types_get_volume_type)
req = fakes.HTTPRequest.blank('/v1/fake/types/777')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
req, '777')
def test_view_builder_show(self):
view_builder = views_types.ViewBuilder()
now = timeutils.isotime()
raw_volume_type = dict(name='new_type',
deleted=False,
created_at=now,
updated_at=now,
extra_specs={},
deleted_at=None,
id=42)
request = fakes.HTTPRequest.blank("/v1")
output = view_builder.show(request, raw_volume_type)
self.assertTrue('volume_type' in output)
expected_volume_type = dict(name='new_type',
extra_specs={},
id=42)
self.assertDictMatch(output['volume_type'], expected_volume_type)
def test_view_builder_list(self):
view_builder = views_types.ViewBuilder()
now = timeutils.isotime()
raw_volume_types = []
for i in range(0, 10):
raw_volume_types.append(dict(name='new_type',
deleted=False,
created_at=now,
updated_at=now,
extra_specs={},
deleted_at=None,
id=42 + i))
request = fakes.HTTPRequest.blank("/v1")
output = view_builder.index(request, raw_volume_types)
self.assertTrue('volume_types' in output)
for i in range(0, 10):
expected_volume_type = dict(name='new_type',
extra_specs={},
id=42 + i)
self.assertDictMatch(output['volume_types'][i],
expected_volume_type)
class VolumeTypesSerializerTest(test.TestCase):
def _verify_volume_type(self, vtype, tree):
self.assertEqual('volume_type', tree.tag)
self.assertEqual(vtype['name'], tree.get('name'))
self.assertEqual(str(vtype['id']), tree.get('id'))
self.assertEqual(1, len(tree))
extra_specs = tree[0]
self.assertEqual('extra_specs', extra_specs.tag)
seen = set(vtype['extra_specs'].keys())
for child in extra_specs:
self.assertTrue(child.tag in seen)
self.assertEqual(vtype['extra_specs'][child.tag], child.text)
seen.remove(child.tag)
self.assertEqual(len(seen), 0)
def test_index_serializer(self):
serializer = types.VolumeTypesTemplate()
# Just getting some input data
vtypes = return_volume_types_get_all_types(None)
text = serializer.serialize({'volume_types': vtypes.values()})
tree = etree.fromstring(text)
self.assertEqual('volume_types', tree.tag)
self.assertEqual(len(vtypes), len(tree))
for child in tree:
name = child.get('name')
self.assertTrue(name in vtypes)
self._verify_volume_type(vtypes[name], child)
def test_voltype_serializer(self):
serializer = types.VolumeTypeTemplate()
vtype = stub_volume_type(1)
text = serializer.serialize(dict(volume_type=vtype))
tree = etree.fromstring(text)
self._verify_volume_type(vtype, tree)

View File

@ -1,441 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# 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 uuid
from oslo.config import cfg
import webob
from manila.api import extensions
from manila.api.v1 import volume_metadata
from manila.api.v1 import volumes
import manila.db
from manila import exception
from manila.openstack.common import jsonutils
from manila import test
from manila.tests.api import fakes
CONF = cfg.CONF
def return_create_volume_metadata_max(context, volume_id, metadata, delete):
return stub_max_volume_metadata()
def return_create_volume_metadata(context, volume_id, metadata, delete):
return stub_volume_metadata()
def return_volume_metadata(context, volume_id):
if not isinstance(volume_id, str) or not len(volume_id) == 36:
msg = 'id %s must be a uuid in return volume metadata' % volume_id
raise Exception(msg)
return stub_volume_metadata()
def return_empty_volume_metadata(context, volume_id):
return {}
def delete_volume_metadata(context, volume_id, key):
pass
def stub_volume_metadata():
metadata = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
return metadata
def stub_max_volume_metadata():
metadata = {"metadata": {}}
for num in range(CONF.quota_metadata_items):
metadata['metadata']['key%i' % num] = "blah"
return metadata
def return_volume(context, volume_id):
return {'id': '0cc3346e-9fef-4445-abe6-5d2b2690ec64',
'name': 'fake',
'metadata': {}}
def return_volume_nonexistent(context, volume_id):
raise exception.VolumeNotFound('bogus test message')
def fake_update_volume_metadata(self, context, volume, diff):
pass
class volumeMetaDataTest(test.TestCase):
def setUp(self):
super(volumeMetaDataTest, self).setUp()
self.volume_api = manila.volume.api.API()
fakes.stub_out_key_pair_funcs(self.stubs)
self.stubs.Set(manila.db, 'volume_get', return_volume)
self.stubs.Set(manila.db, 'volume_metadata_get',
return_volume_metadata)
self.stubs.Set(self.volume_api, 'update_volume_metadata',
fake_update_volume_metadata)
self.ext_mgr = extensions.ExtensionManager()
self.ext_mgr.extensions = {}
self.volume_controller = volumes.VolumeController(self.ext_mgr)
self.controller = volume_metadata.Controller()
self.id = str(uuid.uuid4())
self.url = '/v1/fake/volumes/%s/metadata' % self.id
vol = {"size": 100,
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "zone1:host1",
"metadata": {}}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
self.volume_controller.create(req, body)
def test_index(self):
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.id)
expected = {
'metadata': {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
},
}
self.assertEqual(expected, res_dict)
def test_index_nonexistent_volume(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_volume_nonexistent)
req = fakes.HTTPRequest.blank(self.url)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.index, req, self.url)
def test_index_no_data(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_empty_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.id)
expected = {'metadata': {}}
self.assertEqual(expected, res_dict)
def test_show(self):
req = fakes.HTTPRequest.blank(self.url + '/key2')
res_dict = self.controller.show(req, self.id, 'key2')
expected = {'meta': {'key2': 'value2'}}
self.assertEqual(expected, res_dict)
def test_show_nonexistent_volume(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_volume_nonexistent)
req = fakes.HTTPRequest.blank(self.url + '/key2')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, self.id, 'key2')
def test_show_meta_not_found(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_empty_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key6')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, self.id, 'key6')
def test_delete(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_volume_metadata)
self.stubs.Set(manila.db, 'volume_metadata_delete',
delete_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key2')
req.method = 'DELETE'
res = self.controller.delete(req, self.id, 'key2')
self.assertEqual(200, res.status_int)
def test_delete_nonexistent_volume(self):
self.stubs.Set(manila.db, 'volume_get',
return_volume_nonexistent)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, req, self.id, 'key1')
def test_delete_meta_not_found(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_empty_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key6')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, req, self.id, 'key6')
def test_create(self):
self.stubs.Set(manila.db, 'volume_metadata_get',
return_empty_volume_metadata)
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank('/v1/volume_metadata')
req.method = 'POST'
req.content_type = "application/json"
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
res_dict = self.controller.create(req, self.id, body)
self.assertEqual(body, res_dict)
def test_create_empty_body(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'POST'
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, None)
def test_create_item_empty_key(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, body)
def test_create_item_key_too_long(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {("a" * 260): "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req, self.id, body)
def test_create_nonexistent_volume(self):
self.stubs.Set(manila.db, 'volume_get',
return_volume_nonexistent)
self.stubs.Set(manila.db, 'volume_metadata_get',
return_volume_metadata)
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank('/v1/volume_metadata')
req.method = 'POST'
req.content_type = "application/json"
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.create, req, self.id, body)
def test_update_all(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {
'metadata': {
'key10': 'value10',
'key99': 'value99',
},
}
req.body = jsonutils.dumps(expected)
res_dict = self.controller.update_all(req, self.id, expected)
self.assertEqual(expected, res_dict)
def test_update_all_empty_container(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'metadata': {}}
req.body = jsonutils.dumps(expected)
res_dict = self.controller.update_all(req, self.id, expected)
self.assertEqual(expected, res_dict)
def test_update_all_malformed_container(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'meta': {}}
req.body = jsonutils.dumps(expected)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.id, expected)
def test_update_all_malformed_data(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'metadata': ['asdf']}
req.body = jsonutils.dumps(expected)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.id, expected)
def test_update_all_nonexistent_volume(self):
self.stubs.Set(manila.db, 'volume_get', return_volume_nonexistent)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
body = {'metadata': {'key10': 'value10'}}
req.body = jsonutils.dumps(body)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update_all, req, '100', body)
def test_update_item(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res_dict = self.controller.update(req, self.id, 'key1', body)
expected = {'meta': {'key1': 'value1'}}
self.assertEqual(expected, res_dict)
def test_update_item_nonexistent_volume(self):
self.stubs.Set(manila.db, 'volume_get',
return_volume_nonexistent)
req = fakes.HTTPRequest.blank('/v1.1/fake/volumes/asdf/metadata/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update, req, self.id, 'key1', body)
def test_update_item_empty_body(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'key1', None)
def test_update_item_empty_key(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, '', body)
def test_update_item_key_too_long(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {("a" * 260): "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.update,
req, self.id, ("a" * 260), body)
def test_update_item_value_too_long(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": ("a" * 260)}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.update,
req, self.id, "key1", body)
def test_update_item_too_many_keys(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1", "key2": "value2"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'key1', body)
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url + '/bad')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'bad', body)
def test_invalid_metadata_items_on_create(self):
self.stubs.Set(manila.db, 'volume_metadata_update',
return_create_volume_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'POST'
req.headers["content-type"] = "application/json"
#test for long key
data = {"metadata": {"a" * 260: "value1"}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.create, req, self.id, data)
#test for long value
data = {"metadata": {"key": "v" * 260}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.create, req, self.id, data)
#test for empty key.
data = {"metadata": {"": "value1"}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, data)

View File

@ -1,764 +0,0 @@
# Copyright 2013 Josh Durgin
# 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 datetime
from lxml import etree
import webob
from manila.api import extensions
from manila.api.v1 import volumes
from manila import context
from manila import db
from manila import exception
from manila import flags
from manila import test
from manila.tests.api import fakes
from manila.tests.api.v2 import stubs
from manila.tests.image import fake as fake_image
from manila.volume import api as volume_api
FLAGS = flags.FLAGS
NS = '{http://docs.openstack.org/volume/api/v1}'
TEST_SNAPSHOT_UUID = '00000000-0000-0000-0000-000000000001'
def stub_snapshot_get(self, context, snapshot_id):
if snapshot_id != TEST_SNAPSHOT_UUID:
raise exception.NotFound
return {'id': snapshot_id,
'volume_id': 12,
'status': 'available',
'volume_size': 100,
'created_at': None,
'display_name': 'Default name',
'display_description': 'Default description', }
class VolumeApiTest(test.TestCase):
def setUp(self):
super(VolumeApiTest, self).setUp()
self.ext_mgr = extensions.ExtensionManager()
self.ext_mgr.extensions = {}
fake_image.stub_out_image_service(self.stubs)
self.controller = volumes.VolumeController(self.ext_mgr)
self.stubs.Set(db, 'volume_get_all', stubs.stub_volume_get_all)
self.stubs.Set(db, 'volume_get_all_by_project',
stubs.stub_volume_get_all_by_project)
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
self.stubs.Set(volume_api.API, 'delete', stubs.stub_volume_delete)
def test_volume_create(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
vol = {"size": 100,
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "zone1:host1"}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
res_dict = self.controller.create(req, body)
expected = {'volume': {'status': 'fakestatus',
'display_description': 'Volume Test Desc',
'availability_zone': 'zone1:host1',
'display_name': 'Volume Test Name',
'attachments': [{'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': 100}}
self.assertEqual(res_dict, expected)
def test_volume_create_with_type(self):
vol_type = FLAGS.default_volume_type
db.volume_type_create(context.get_admin_context(),
dict(name=vol_type, extra_specs={}))
db_vol_type = db.volume_type_get_by_name(context.get_admin_context(),
vol_type)
vol = {"size": 100,
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "zone1:host1",
"volume_type": db_vol_type['name'], }
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
res_dict = self.controller.create(req, body)
self.assertEquals(res_dict['volume']['volume_type'],
db_vol_type['name'])
def test_volume_creation_fails_with_bad_size(self):
vol = {"size": '',
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "zone1:host1"}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
self.assertRaises(exception.InvalidInput,
self.controller.create,
req,
body)
def test_volume_create_with_image_id(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
self.ext_mgr.extensions = {'os-image-create': 'fake'}
test_id = "c905cedb-7281-47e4-8a62-f26bc5fc4c77"
vol = {"size": '1',
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "nova",
"imageRef": test_id}
expected = {'volume': {'status': 'fakestatus',
'display_description': 'Volume Test Desc',
'availability_zone': 'nova',
'display_name': 'Volume Test Name',
'attachments': [{'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'image_id': test_id,
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': '1'}}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
res_dict = self.controller.create(req, body)
self.assertEqual(res_dict, expected)
def test_volume_create_with_image_id_is_integer(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
self.ext_mgr.extensions = {'os-image-create': 'fake'}
vol = {"size": '1',
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "manila",
"imageRef": 1234}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req,
body)
def test_volume_create_with_image_id_not_uuid_format(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
self.ext_mgr.extensions = {'os-image-create': 'fake'}
vol = {"size": '1',
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "manila",
"imageRef": '12345'}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v1/volumes')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req,
body)
def test_volume_update(self):
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
updates = {
"display_name": "Updated Test Name",
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
res_dict = self.controller.update(req, '1', body)
expected = {'volume': {
'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'Updated Test Name',
'attachments': [{
'id': '1',
'volume_id': '1',
'server_id': 'fakeuuid',
'device': '/',
}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
}}
self.assertEquals(res_dict, expected)
def test_volume_update_metadata(self):
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
updates = {
"metadata": {"qos_max_iops": 2000}
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
res_dict = self.controller.update(req, '1', body)
expected = {'volume': {
'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'displayname',
'attachments': [{
'id': '1',
'volume_id': '1',
'server_id': 'fakeuuid',
'device': '/',
}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {"qos_max_iops": 2000},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
}}
self.assertEquals(res_dict, expected)
def test_update_empty_body(self):
body = {}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update,
req, '1', body)
def test_update_invalid_body(self):
body = {'display_name': 'missing top level volume key'}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.update,
req, '1', body)
def test_update_not_found(self):
self.stubs.Set(volume_api.API, "get", stubs.stub_volume_get_notfound)
updates = {
"display_name": "Updated Test Name",
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update,
req, '1', body)
def test_volume_list(self):
self.stubs.Set(volume_api.API, 'get_all',
stubs.stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v1/volumes')
res_dict = self.controller.index(req)
expected = {'volumes': [{'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'displayname',
'attachments': [{'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': 1}]}
self.assertEqual(res_dict, expected)
def test_volume_list_detail(self):
self.stubs.Set(volume_api.API, 'get_all',
stubs.stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v1/volumes/detail')
res_dict = self.controller.index(req)
expected = {'volumes': [{'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'displayname',
'attachments': [{'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': 1}]}
self.assertEqual(res_dict, expected)
def test_volume_list_by_name(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1'),
stubs.stub_volume(2, display_name='vol2'),
stubs.stub_volume(3, display_name='vol3'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
# no display_name filter
req = fakes.HTTPRequest.blank('/v1/volumes')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 3)
# filter on display_name
req = fakes.HTTPRequest.blank('/v1/volumes?display_name=vol2')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 1)
self.assertEqual(resp['volumes'][0]['display_name'], 'vol2')
# filter no match
req = fakes.HTTPRequest.blank('/v1/volumes?display_name=vol4')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 0)
def test_volume_list_by_status(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1', status='available'),
stubs.stub_volume(2, display_name='vol2', status='available'),
stubs.stub_volume(3, display_name='vol3', status='in-use'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
# no status filter
req = fakes.HTTPRequest.blank('/v1/volumes')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 3)
# single match
req = fakes.HTTPRequest.blank('/v1/volumes?status=in-use')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 1)
self.assertEqual(resp['volumes'][0]['status'], 'in-use')
# multiple match
req = fakes.HTTPRequest.blank('/v1/volumes?status=available')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 2)
for volume in resp['volumes']:
self.assertEqual(volume['status'], 'available')
# multiple filters
req = fakes.HTTPRequest.blank('/v1/volumes?status=available&'
'display_name=vol1')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 1)
self.assertEqual(resp['volumes'][0]['display_name'], 'vol1')
self.assertEqual(resp['volumes'][0]['status'], 'available')
# no match
req = fakes.HTTPRequest.blank('/v1/volumes?status=in-use&'
'display_name=vol1')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 0)
def test_volume_show(self):
req = fakes.HTTPRequest.blank('/v1/volumes/1')
res_dict = self.controller.show(req, '1')
expected = {'volume': {'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'displayname',
'attachments': [{'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'}],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': 1}}
self.assertEqual(res_dict, expected)
def test_volume_show_no_attachments(self):
def stub_volume_get(self, context, volume_id):
return stubs.stub_volume(volume_id, attach_status='detached')
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
req = fakes.HTTPRequest.blank('/v1/volumes/1')
res_dict = self.controller.show(req, '1')
expected = {'volume': {'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'displayname',
'attachments': [],
'bootable': 'false',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': 1}}
self.assertEqual(res_dict, expected)
def test_volume_show_bootable(self):
def stub_volume_get(self, context, volume_id):
return (stubs.stub_volume(volume_id,
volume_glance_metadata=dict(foo='bar')))
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
req = fakes.HTTPRequest.blank('/v1/volumes/1')
res_dict = self.controller.show(req, '1')
expected = {'volume': {'status': 'fakestatus',
'display_description': 'displaydesc',
'availability_zone': 'fakeaz',
'display_name': 'displayname',
'attachments': [{'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'}],
'bootable': 'true',
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1,
1, 1, 1),
'size': 1}}
self.assertEqual(res_dict, expected)
def test_volume_show_no_volume(self):
self.stubs.Set(volume_api.API, "get", stubs.stub_volume_get_notfound)
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show,
req,
1)
def test_volume_delete(self):
req = fakes.HTTPRequest.blank('/v1/volumes/1')
resp = self.controller.delete(req, 1)
self.assertEqual(resp.status_int, 202)
def test_volume_delete_no_volume(self):
self.stubs.Set(volume_api.API, "get", stubs.stub_volume_get_notfound)
req = fakes.HTTPRequest.blank('/v1/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete,
req,
1)
def test_admin_list_volumes_limited_to_project(self):
req = fakes.HTTPRequest.blank('/v1/fake/volumes',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(1, len(res['volumes']))
def test_admin_list_volumes_all_tenants(self):
req = fakes.HTTPRequest.blank('/v1/fake/volumes?all_tenants=1',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(3, len(res['volumes']))
def test_all_tenants_non_admin_gets_all_tenants(self):
req = fakes.HTTPRequest.blank('/v1/fake/volumes?all_tenants=1')
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(1, len(res['volumes']))
def test_non_admin_get_by_project(self):
req = fakes.HTTPRequest.blank('/v1/fake/volumes')
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(1, len(res['volumes']))
class VolumeSerializerTest(test.TestCase):
def _verify_volume_attachment(self, attach, tree):
for attr in ('id', 'volume_id', 'server_id', 'device'):
self.assertEqual(str(attach[attr]), tree.get(attr))
def _verify_volume(self, vol, tree):
self.assertEqual(tree.tag, NS + 'volume')
for attr in ('id', 'status', 'size', 'availability_zone', 'created_at',
'display_name', 'display_description', 'volume_type',
'snapshot_id'):
self.assertEqual(str(vol[attr]), tree.get(attr))
for child in tree:
print child.tag
self.assertTrue(child.tag in (NS + 'attachments', NS + 'metadata'))
if child.tag == 'attachments':
self.assertEqual(1, len(child))
self.assertEqual('attachment', child[0].tag)
self._verify_volume_attachment(vol['attachments'][0], child[0])
elif child.tag == 'metadata':
not_seen = set(vol['metadata'].keys())
for gr_child in child:
self.assertTrue(gr_child.get("key") in not_seen)
self.assertEqual(str(vol['metadata'][gr_child.get("key")]),
gr_child.text)
not_seen.remove(gr_child.get('key'))
self.assertEqual(0, len(not_seen))
def test_volume_show_create_serializer(self):
serializer = volumes.VolumeTemplate()
raw_volume = dict(
id='vol_id',
status='vol_status',
size=1024,
availability_zone='vol_availability',
created_at=datetime.datetime.now(),
attachments=[dict(id='vol_id',
volume_id='vol_id',
server_id='instance_uuid',
device='/foo')],
display_name='vol_name',
display_description='vol_desc',
volume_type='vol_type',
snapshot_id='snap_id',
source_volid='source_volid',
metadata=dict(foo='bar',
baz='quux', ), )
text = serializer.serialize(dict(volume=raw_volume))
print text
tree = etree.fromstring(text)
self._verify_volume(raw_volume, tree)
def test_volume_index_detail_serializer(self):
serializer = volumes.VolumesTemplate()
raw_volumes = [dict(id='vol1_id',
status='vol1_status',
size=1024,
availability_zone='vol1_availability',
created_at=datetime.datetime.now(),
attachments=[dict(id='vol1_id',
volume_id='vol1_id',
server_id='instance_uuid',
device='/foo1')],
display_name='vol1_name',
display_description='vol1_desc',
volume_type='vol1_type',
snapshot_id='snap1_id',
source_volid=None,
metadata=dict(foo='vol1_foo',
bar='vol1_bar', ), ),
dict(id='vol2_id',
status='vol2_status',
size=1024,
availability_zone='vol2_availability',
created_at=datetime.datetime.now(),
attachments=[dict(id='vol2_id',
volume_id='vol2_id',
server_id='instance_uuid',
device='/foo2')],
display_name='vol2_name',
display_description='vol2_desc',
volume_type='vol2_type',
snapshot_id='snap2_id',
source_volid=None,
metadata=dict(foo='vol2_foo',
bar='vol2_bar', ), )]
text = serializer.serialize(dict(volumes=raw_volumes))
print text
tree = etree.fromstring(text)
self.assertEqual(NS + 'volumes', tree.tag)
self.assertEqual(len(raw_volumes), len(tree))
for idx, child in enumerate(tree):
self._verify_volume(raw_volumes[idx], child)
class TestVolumeCreateRequestXMLDeserializer(test.TestCase):
def setUp(self):
super(TestVolumeCreateRequestXMLDeserializer, self).setUp()
self.deserializer = volumes.CreateDeserializer()
def test_minimal_volume(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
size="1"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {"volume": {"size": "1", }, }
self.assertEquals(request['body'], expected)
def test_display_name(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
size="1"
display_name="Volume-xml"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"display_name": "Volume-xml",
},
}
self.assertEquals(request['body'], expected)
def test_display_description(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
size="1"
display_name="Volume-xml"
display_description="description"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"display_name": "Volume-xml",
"display_description": "description",
},
}
self.assertEquals(request['body'], expected)
def test_volume_type(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
size="1"
display_name="Volume-xml"
display_description="description"
volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"display_name": "Volume-xml",
"size": "1",
"display_name": "Volume-xml",
"display_description": "description",
"volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
},
}
self.assertEquals(request['body'], expected)
def test_availability_zone(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
size="1"
display_name="Volume-xml"
display_description="description"
volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"
availability_zone="us-east1"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"display_name": "Volume-xml",
"display_description": "description",
"volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
"availability_zone": "us-east1",
},
}
self.assertEquals(request['body'], expected)
def test_metadata(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
display_name="Volume-xml"
size="1">
<metadata><meta key="Type">work</meta></metadata></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"display_name": "Volume-xml",
"size": "1",
"metadata": {
"Type": "work",
},
},
}
self.assertEquals(request['body'], expected)
def test_full_volume(self):
self_request = """
<volume xmlns="http://docs.openstack.org/compute/api/v1.1"
size="1"
display_name="Volume-xml"
display_description="description"
volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"
availability_zone="us-east1">
<metadata><meta key="Type">work</meta></metadata></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"display_name": "Volume-xml",
"display_description": "description",
"volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
"availability_zone": "us-east1",
"metadata": {
"Type": "work",
},
},
}
self.assertEquals(request['body'], expected)
class VolumesUnprocessableEntityTestCase(test.TestCase):
"""
Tests of places we throw 422 Unprocessable Entity from
"""
def setUp(self):
super(VolumesUnprocessableEntityTestCase, self).setUp()
self.ext_mgr = extensions.ExtensionManager()
self.ext_mgr.extensions = {}
self.controller = volumes.VolumeController(self.ext_mgr)
def _unprocessable_volume_create(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/volumes')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.create, req, body)
def test_create_no_body(self):
self._unprocessable_volume_create(body=None)
def test_create_missing_volume(self):
body = {'foo': {'a': 'b'}}
self._unprocessable_volume_create(body=body)
def test_create_malformed_entity(self):
body = {'volume': 'string'}
self._unprocessable_volume_create(body=body)

View File

@ -1,458 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# 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 uuid
from oslo.config import cfg
import webob
from manila.api import extensions
from manila.api.v2 import snapshot_metadata
from manila.api.v2 import snapshots
import manila.db
from manila import exception
from manila.openstack.common import jsonutils
from manila import test
from manila.tests.api import fakes
CONF = cfg.CONF
def return_create_snapshot_metadata_max(context,
snapshot_id,
metadata,
delete):
return stub_max_snapshot_metadata()
def return_create_snapshot_metadata(context, snapshot_id, metadata, delete):
return stub_snapshot_metadata()
def return_snapshot_metadata(context, snapshot_id):
if not isinstance(snapshot_id, str) or not len(snapshot_id) == 36:
msg = 'id %s must be a uuid in return snapshot metadata' % snapshot_id
raise Exception(msg)
return stub_snapshot_metadata()
def return_empty_snapshot_metadata(context, snapshot_id):
return {}
def delete_snapshot_metadata(context, snapshot_id, key):
pass
def stub_snapshot_metadata():
metadata = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
return metadata
def stub_max_snapshot_metadata():
metadata = {"metadata": {}}
for num in range(CONF.quota_metadata_items):
metadata['metadata']['key%i' % num] = "blah"
return metadata
def return_snapshot(context, snapshot_id):
return {'id': '0cc3346e-9fef-4445-abe6-5d2b2690ec64',
'name': 'fake',
'status': 'available',
'metadata': {}}
def return_volume(context, volume_id):
return {'id': 'fake-vol-id',
'size': 100,
'name': 'fake',
'host': 'fake-host',
'status': 'available',
'metadata': {}}
def return_snapshot_nonexistent(context, snapshot_id):
raise exception.SnapshotNotFound('bogus test message')
def fake_update_snapshot_metadata(self, context, snapshot, diff):
pass
class SnapshotMetaDataTest(test.TestCase):
def setUp(self):
super(SnapshotMetaDataTest, self).setUp()
self.volume_api = manila.volume.api.API()
fakes.stub_out_key_pair_funcs(self.stubs)
self.stubs.Set(manila.db, 'volume_get', return_volume)
self.stubs.Set(manila.db, 'snapshot_get', return_snapshot)
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_metadata)
self.stubs.Set(self.volume_api, 'update_snapshot_metadata',
fake_update_snapshot_metadata)
self.ext_mgr = extensions.ExtensionManager()
self.ext_mgr.extensions = {}
self.snapshot_controller = snapshots.SnapshotsController(self.ext_mgr)
self.controller = snapshot_metadata.Controller()
self.id = str(uuid.uuid4())
self.url = '/v2/fake/snapshots/%s/metadata' % self.id
snap = {"volume_size": 100,
"volume_id": "fake-vol-id",
"display_name": "Volume Test Name",
"display_description": "Volume Test Desc",
"availability_zone": "zone1:host1",
"host": "fake-host",
"metadata": {}}
body = {"snapshot": snap}
req = fakes.HTTPRequest.blank('/v2/snapshots')
self.snapshot_controller.create(req, body)
def test_index(self):
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.id)
expected = {
'metadata': {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
},
}
self.assertEqual(expected, res_dict)
def test_index_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.index, req, self.url)
def test_index_no_data(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.id)
expected = {'metadata': {}}
self.assertEqual(expected, res_dict)
def test_show(self):
req = fakes.HTTPRequest.blank(self.url + '/key2')
res_dict = self.controller.show(req, self.id, 'key2')
expected = {'meta': {'key2': 'value2'}}
self.assertEqual(expected, res_dict)
def test_show_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url + '/key2')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, self.id, 'key2')
def test_show_meta_not_found(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key6')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, self.id, 'key6')
def test_delete(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_metadata)
self.stubs.Set(manila.db, 'snapshot_metadata_delete',
delete_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key2')
req.method = 'DELETE'
res = self.controller.delete(req, self.id, 'key2')
self.assertEqual(200, res.status_int)
def test_delete_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, req, self.id, 'key1')
def test_delete_meta_not_found(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key6')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, req, self.id, 'key6')
def test_create(self):
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_empty_snapshot_metadata)
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank('/v2/snapshot_metadata')
req.method = 'POST'
req.content_type = "application/json"
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
res_dict = self.controller.create(req, self.id, body)
self.assertEqual(body, res_dict)
def test_create_empty_body(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'POST'
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, None)
def test_create_item_empty_key(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, body)
def test_create_item_key_too_long(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {("a" * 260): "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req, self.id, body)
def test_create_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get',
return_snapshot_nonexistent)
self.stubs.Set(manila.db, 'snapshot_metadata_get',
return_snapshot_metadata)
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank('/v2/snapshot_metadata')
req.method = 'POST'
req.content_type = "application/json"
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.create, req, self.id, body)
def test_update_all(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {
'metadata': {
'key10': 'value10',
'key99': 'value99',
},
}
req.body = jsonutils.dumps(expected)
res_dict = self.controller.update_all(req, self.id, expected)
self.assertEqual(expected, res_dict)
def test_update_all_empty_container(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'metadata': {}}
req.body = jsonutils.dumps(expected)
res_dict = self.controller.update_all(req, self.id, expected)
self.assertEqual(expected, res_dict)
def test_update_all_malformed_container(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'meta': {}}
req.body = jsonutils.dumps(expected)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.id, expected)
def test_update_all_malformed_data(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
expected = {'metadata': ['asdf']}
req.body = jsonutils.dumps(expected)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update_all, req, self.id, expected)
def test_update_all_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get', return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'PUT'
req.content_type = "application/json"
body = {'metadata': {'key10': 'value10'}}
req.body = jsonutils.dumps(body)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update_all, req, '100', body)
def test_update_item(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res_dict = self.controller.update(req, self.id, 'key1', body)
expected = {'meta': {'key1': 'value1'}}
self.assertEqual(expected, res_dict)
def test_update_item_nonexistent_snapshot(self):
self.stubs.Set(manila.db, 'snapshot_get',
return_snapshot_nonexistent)
req = fakes.HTTPRequest.blank(
'/v2/fake/snapshots/asdf/metadata/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update, req, self.id, 'key1', body)
def test_update_item_empty_body(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'key1', None)
def test_update_item_empty_key(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, '', body)
def test_update_item_key_too_long(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {("a" * 260): "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.update,
req, self.id, ("a" * 260), body)
def test_update_item_value_too_long(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": ("a" * 260)}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.update,
req, self.id, "key1", body)
def test_update_item_too_many_keys(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/key1')
req.method = 'PUT'
body = {"meta": {"key1": "value1", "key2": "value2"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'key1', body)
def test_update_item_body_uri_mismatch(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url + '/bad')
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, self.id, 'bad', body)
def test_invalid_metadata_items_on_create(self):
self.stubs.Set(manila.db, 'snapshot_metadata_update',
return_create_snapshot_metadata)
req = fakes.HTTPRequest.blank(self.url)
req.method = 'POST'
req.headers["content-type"] = "application/json"
#test for long key
data = {"metadata": {"a" * 260: "value1"}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.create, req, self.id, data)
#test for long value
data = {"metadata": {"key": "v" * 260}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
self.controller.create, req, self.id, data)
#test for empty key.
data = {"metadata": {"": "value1"}}
req.body = jsonutils.dumps(data)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, self.id, data)

View File

@ -1,425 +0,0 @@
# Copyright 2011 Denali 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 datetime
from lxml import etree
import webob
from manila.api.v2 import snapshots
from manila import db
from manila import exception
from manila import flags
from manila.openstack.common import log as logging
from manila import test
from manila.tests.api import fakes
from manila.tests.api.v2 import stubs
from manila import volume
FLAGS = flags.FLAGS
LOG = logging.getLogger(__name__)
UUID = '00000000-0000-0000-0000-000000000001'
INVALID_UUID = '00000000-0000-0000-0000-000000000002'
def _get_default_snapshot_param():
return {
'id': UUID,
'volume_id': 12,
'status': 'available',
'volume_size': 100,
'created_at': None,
'display_name': 'Default name',
'display_description': 'Default description',
}
def stub_snapshot_create(self, context,
volume_id, name,
description, metadata):
snapshot = _get_default_snapshot_param()
snapshot['volume_id'] = volume_id
snapshot['display_name'] = name
snapshot['display_description'] = description
snapshot['metadata'] = metadata
return snapshot
def stub_snapshot_delete(self, context, snapshot):
if snapshot['id'] != UUID:
raise exception.NotFound
def stub_snapshot_get(self, context, snapshot_id):
if snapshot_id != UUID:
raise exception.NotFound
param = _get_default_snapshot_param()
return param
def stub_snapshot_get_all(self, context, search_opts=None):
param = _get_default_snapshot_param()
return [param]
class SnapshotApiTest(test.TestCase):
def setUp(self):
super(SnapshotApiTest, self).setUp()
self.controller = snapshots.SnapshotsController()
self.stubs.Set(db, 'snapshot_get_all_by_project',
stubs.stub_snapshot_get_all_by_project)
self.stubs.Set(db, 'snapshot_get_all',
stubs.stub_snapshot_get_all)
def test_snapshot_create(self):
self.stubs.Set(volume.api.API, "create_snapshot", stub_snapshot_create)
self.stubs.Set(volume.api.API, 'get', stubs.stub_volume_get)
snapshot_name = 'Snapshot Test Name'
snapshot_description = 'Snapshot Test Desc'
snapshot = {
"volume_id": '12',
"force": False,
"name": snapshot_name,
"description": snapshot_description
}
body = dict(snapshot=snapshot)
req = fakes.HTTPRequest.blank('/v2/snapshots')
resp_dict = self.controller.create(req, body)
self.assertTrue('snapshot' in resp_dict)
self.assertEqual(resp_dict['snapshot']['name'],
snapshot_name)
self.assertEqual(resp_dict['snapshot']['description'],
snapshot_description)
def test_snapshot_create_force(self):
self.stubs.Set(volume.api.API, "create_snapshot_force",
stub_snapshot_create)
self.stubs.Set(volume.api.API, 'get', stubs.stub_volume_get)
snapshot_name = 'Snapshot Test Name'
snapshot_description = 'Snapshot Test Desc'
snapshot = {
"volume_id": '12',
"force": True,
"name": snapshot_name,
"description": snapshot_description
}
body = dict(snapshot=snapshot)
req = fakes.HTTPRequest.blank('/v2/snapshots')
resp_dict = self.controller.create(req, body)
self.assertTrue('snapshot' in resp_dict)
self.assertEqual(resp_dict['snapshot']['name'],
snapshot_name)
self.assertEqual(resp_dict['snapshot']['description'],
snapshot_description)
snapshot = {
"volume_id": "12",
"force": "**&&^^%%$$##@@",
"name": "Snapshot Test Name",
"description": "Snapshot Test Desc"
}
body = dict(snapshot=snapshot)
req = fakes.HTTPRequest.blank('/v2/snapshots')
self.assertRaises(exception.InvalidParameterValue,
self.controller.create,
req,
body)
def test_snapshot_update(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
self.stubs.Set(volume.api.API, "update_snapshot",
stubs.stub_snapshot_update)
updates = {
"name": "Updated Test Name",
}
body = {"snapshot": updates}
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % UUID)
res_dict = self.controller.update(req, UUID, body)
expected = {
'snapshot': {
'id': UUID,
'volume_id': 12,
'status': 'available',
'size': 100,
'created_at': None,
'name': 'Updated Test Name',
'description': 'Default description',
'metadata': {},
}
}
self.assertEquals(expected, res_dict)
def test_snapshot_update_missing_body(self):
body = {}
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % UUID)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, UUID, body)
def test_snapshot_update_invalid_body(self):
body = {'name': 'missing top level snapshot key'}
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % UUID)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, UUID, body)
def test_snapshot_update_not_found(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
updates = {
"name": "Updated Test Name",
}
body = {"snapshot": updates}
req = fakes.HTTPRequest.blank('/v2/snapshots/not-the-uuid')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.update, req,
'not-the-uuid', body)
def test_snapshot_delete(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
snapshot_id = UUID
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % snapshot_id)
resp = self.controller.delete(req, snapshot_id)
self.assertEqual(resp.status_int, 202)
def test_snapshot_delete_invalid_id(self):
self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
snapshot_id = INVALID_UUID
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % snapshot_id)
self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
req, snapshot_id)
def test_snapshot_show(self):
self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % UUID)
resp_dict = self.controller.show(req, UUID)
self.assertTrue('snapshot' in resp_dict)
self.assertEqual(resp_dict['snapshot']['id'], UUID)
def test_snapshot_show_invalid_id(self):
snapshot_id = INVALID_UUID
req = fakes.HTTPRequest.blank('/v2/snapshots/%s' % snapshot_id)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, snapshot_id)
def test_snapshot_detail(self):
self.stubs.Set(volume.api.API, "get_all_snapshots",
stub_snapshot_get_all)
req = fakes.HTTPRequest.blank('/v2/snapshots/detail')
resp_dict = self.controller.detail(req)
self.assertTrue('snapshots' in resp_dict)
resp_snapshots = resp_dict['snapshots']
self.assertEqual(len(resp_snapshots), 1)
resp_snapshot = resp_snapshots.pop()
self.assertEqual(resp_snapshot['id'], UUID)
def test_snapshot_list_by_status(self):
def stub_snapshot_get_all_by_project(context, project_id):
return [
stubs.stub_snapshot(1, display_name='backup1',
status='available'),
stubs.stub_snapshot(2, display_name='backup2',
status='available'),
stubs.stub_snapshot(3, display_name='backup3',
status='creating'),
]
self.stubs.Set(db, 'snapshot_get_all_by_project',
stub_snapshot_get_all_by_project)
# no status filter
req = fakes.HTTPRequest.blank('/v2/snapshots')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 3)
# single match
req = fakes.HTTPRequest.blank('/v2/snapshots?status=creating')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEqual(resp['snapshots'][0]['status'], 'creating')
# multiple match
req = fakes.HTTPRequest.blank('/v2/snapshots?status=available')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 2)
for snapshot in resp['snapshots']:
self.assertEquals(snapshot['status'], 'available')
# no match
req = fakes.HTTPRequest.blank('/v2/snapshots?status=error')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 0)
def test_snapshot_list_by_volume(self):
def stub_snapshot_get_all_by_project(context, project_id):
return [
stubs.stub_snapshot(1, volume_id='vol1', status='creating'),
stubs.stub_snapshot(2, volume_id='vol1', status='available'),
stubs.stub_snapshot(3, volume_id='vol2', status='available'),
]
self.stubs.Set(db, 'snapshot_get_all_by_project',
stub_snapshot_get_all_by_project)
# single match
req = fakes.HTTPRequest.blank('/v2/snapshots?volume_id=vol2')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEqual(resp['snapshots'][0]['volume_id'], 'vol2')
# multiple match
req = fakes.HTTPRequest.blank('/v2/snapshots?volume_id=vol1')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 2)
for snapshot in resp['snapshots']:
self.assertEqual(snapshot['volume_id'], 'vol1')
# multiple filters
req = fakes.HTTPRequest.blank('/v2/snapshots?volume_id=vol1'
'&status=available')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEqual(resp['snapshots'][0]['volume_id'], 'vol1')
self.assertEqual(resp['snapshots'][0]['status'], 'available')
def test_snapshot_list_by_name(self):
def stub_snapshot_get_all_by_project(context, project_id):
return [
stubs.stub_snapshot(1, display_name='backup1'),
stubs.stub_snapshot(2, display_name='backup2'),
stubs.stub_snapshot(3, display_name='backup3'),
]
self.stubs.Set(db, 'snapshot_get_all_by_project',
stub_snapshot_get_all_by_project)
# no name filter
req = fakes.HTTPRequest.blank('/v2/snapshots')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 3)
# filter by one name
req = fakes.HTTPRequest.blank('/v2/snapshots?name=backup2')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 1)
self.assertEquals(resp['snapshots'][0]['name'], 'backup2')
# filter no match
req = fakes.HTTPRequest.blank('/v2/snapshots?name=backup4')
resp = self.controller.index(req)
self.assertEqual(len(resp['snapshots']), 0)
def test_admin_list_snapshots_limited_to_project(self):
req = fakes.HTTPRequest.blank('/v2/fake/snapshots',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(1, len(res['snapshots']))
def test_admin_list_snapshots_all_tenants(self):
req = fakes.HTTPRequest.blank('/v2/fake/snapshots?all_tenants=1',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(3, len(res['snapshots']))
def test_all_tenants_non_admin_gets_all_tenants(self):
req = fakes.HTTPRequest.blank('/v2/fake/snapshots?all_tenants=1')
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(1, len(res['snapshots']))
def test_non_admin_get_by_project(self):
req = fakes.HTTPRequest.blank('/v2/fake/snapshots')
res = self.controller.index(req)
self.assertTrue('snapshots' in res)
self.assertEqual(1, len(res['snapshots']))
def _create_snapshot_bad_body(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/snapshots')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, body)
def test_create_no_body(self):
self._create_snapshot_bad_body(body=None)
def test_create_missing_snapshot(self):
body = {'foo': {'a': 'b'}}
self._create_snapshot_bad_body(body=body)
def test_create_malformed_entity(self):
body = {'snapshot': 'string'}
self._create_snapshot_bad_body(body=body)
class SnapshotSerializerTest(test.TestCase):
def _verify_snapshot(self, snap, tree):
self.assertEqual(tree.tag, 'snapshot')
for attr in ('id', 'status', 'size', 'created_at',
'name', 'description', 'volume_id'):
self.assertEqual(str(snap[attr]), tree.get(attr))
def test_snapshot_show_create_serializer(self):
serializer = snapshots.SnapshotTemplate()
raw_snapshot = dict(
id='snap_id',
status='snap_status',
size=1024,
created_at=datetime.datetime.now(),
name='snap_name',
description='snap_desc',
display_description='snap_desc',
volume_id='vol_id',
)
text = serializer.serialize(dict(snapshot=raw_snapshot))
print text
tree = etree.fromstring(text)
self._verify_snapshot(raw_snapshot, tree)
def test_snapshot_index_detail_serializer(self):
serializer = snapshots.SnapshotsTemplate()
raw_snapshots = [
dict(
id='snap1_id',
status='snap1_status',
size=1024,
created_at=datetime.datetime.now(),
name='snap1_name',
description='snap1_desc',
volume_id='vol1_id',
),
dict(
id='snap2_id',
status='snap2_status',
size=1024,
created_at=datetime.datetime.now(),
name='snap2_name',
description='snap2_desc',
volume_id='vol2_id',
)
]
text = serializer.serialize(dict(snapshots=raw_snapshots))
print text
tree = etree.fromstring(text)
self.assertEqual('snapshots', tree.tag)
self.assertEqual(len(raw_snapshots), len(tree))
for idx, child in enumerate(tree):
self._verify_snapshot(raw_snapshots[idx], child)

View File

@ -1,211 +0,0 @@
# Copyright 2011 OpenStack LLC.
# 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.
from lxml import etree
import webob
from manila.api.v2 import types
from manila.api.views import types as views_types
from manila import exception
from manila.openstack.common import timeutils
from manila import test
from manila.tests.api import fakes
from manila.volume import volume_types
def stub_volume_type(id):
specs = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4",
"key5": "value5"
}
return dict(
id=id,
name='vol_type_%s' % str(id),
extra_specs=specs,
)
def return_volume_types_get_all_types(context):
return dict(
vol_type_1=stub_volume_type(1),
vol_type_2=stub_volume_type(2),
vol_type_3=stub_volume_type(3)
)
def return_empty_volume_types_get_all_types(context):
return {}
def return_volume_types_get_volume_type(context, id):
if id == "777":
raise exception.VolumeTypeNotFound(volume_type_id=id)
return stub_volume_type(int(id))
def return_volume_types_get_by_name(context, name):
if name == "777":
raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
return stub_volume_type(int(name.split("_")[2]))
class VolumeTypesApiTest(test.TestCase):
def setUp(self):
super(VolumeTypesApiTest, self).setUp()
self.controller = types.VolumeTypesController()
def test_volume_types_index(self):
self.stubs.Set(volume_types, 'get_all_types',
return_volume_types_get_all_types)
req = fakes.HTTPRequest.blank('/v2/fake/types')
res_dict = self.controller.index(req)
self.assertEqual(3, len(res_dict['volume_types']))
expected_names = ['vol_type_1', 'vol_type_2', 'vol_type_3']
actual_names = map(lambda e: e['name'], res_dict['volume_types'])
self.assertEqual(set(actual_names), set(expected_names))
for entry in res_dict['volume_types']:
self.assertEqual('value1', entry['extra_specs']['key1'])
def test_volume_types_index_no_data(self):
self.stubs.Set(volume_types, 'get_all_types',
return_empty_volume_types_get_all_types)
req = fakes.HTTPRequest.blank('/v2/fake/types')
res_dict = self.controller.index(req)
self.assertEqual(0, len(res_dict['volume_types']))
def test_volume_types_show(self):
self.stubs.Set(volume_types, 'get_volume_type',
return_volume_types_get_volume_type)
req = fakes.HTTPRequest.blank('/v2/fake/types/1')
res_dict = self.controller.show(req, 1)
self.assertEqual(1, len(res_dict))
self.assertEqual('1', res_dict['volume_type']['id'])
self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
def test_volume_types_show_not_found(self):
self.stubs.Set(volume_types, 'get_volume_type',
return_volume_types_get_volume_type)
req = fakes.HTTPRequest.blank('/v2/fake/types/777')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
req, '777')
def test_view_builder_show(self):
view_builder = views_types.ViewBuilder()
now = timeutils.isotime()
raw_volume_type = dict(
name='new_type',
deleted=False,
created_at=now,
updated_at=now,
extra_specs={},
deleted_at=None,
id=42,
)
request = fakes.HTTPRequest.blank("/v2")
output = view_builder.show(request, raw_volume_type)
self.assertTrue('volume_type' in output)
expected_volume_type = dict(
name='new_type',
extra_specs={},
id=42,
)
self.assertDictMatch(output['volume_type'], expected_volume_type)
def test_view_builder_list(self):
view_builder = views_types.ViewBuilder()
now = timeutils.isotime()
raw_volume_types = []
for i in range(0, 10):
raw_volume_types.append(
dict(
name='new_type',
deleted=False,
created_at=now,
updated_at=now,
extra_specs={},
deleted_at=None,
id=42 + i
)
)
request = fakes.HTTPRequest.blank("/v2")
output = view_builder.index(request, raw_volume_types)
self.assertTrue('volume_types' in output)
for i in range(0, 10):
expected_volume_type = dict(
name='new_type',
extra_specs={},
id=42 + i
)
self.assertDictMatch(output['volume_types'][i],
expected_volume_type)
class VolumeTypesSerializerTest(test.TestCase):
def _verify_volume_type(self, vtype, tree):
self.assertEqual('volume_type', tree.tag)
self.assertEqual(vtype['name'], tree.get('name'))
self.assertEqual(str(vtype['id']), tree.get('id'))
self.assertEqual(1, len(tree))
extra_specs = tree[0]
self.assertEqual('extra_specs', extra_specs.tag)
seen = set(vtype['extra_specs'].keys())
for child in extra_specs:
self.assertTrue(child.tag in seen)
self.assertEqual(vtype['extra_specs'][child.tag], child.text)
seen.remove(child.tag)
self.assertEqual(len(seen), 0)
def test_index_serializer(self):
serializer = types.VolumeTypesTemplate()
# Just getting some input data
vtypes = return_volume_types_get_all_types(None)
text = serializer.serialize({'volume_types': vtypes.values()})
tree = etree.fromstring(text)
self.assertEqual('volume_types', tree.tag)
self.assertEqual(len(vtypes), len(tree))
for child in tree:
name = child.get('name')
self.assertTrue(name in vtypes)
self._verify_volume_type(vtypes[name], child)
def test_voltype_serializer(self):
serializer = types.VolumeTypeTemplate()
vtype = stub_volume_type(1)
text = serializer.serialize(dict(volume_type=vtype))
tree = etree.fromstring(text)
self._verify_volume_type(vtype, tree)

View File

@ -1,955 +0,0 @@
# Copyright 2013 Josh Durgin
# 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 datetime
from lxml import etree
import webob
from manila.api import extensions
from manila.api.v2 import volumes
from manila import context
from manila import db
from manila import exception
from manila import flags
from manila import test
from manila.tests.api import fakes
from manila.tests.api.v2 import stubs
from manila.tests.image import fake as fake_image
from manila.volume import api as volume_api
FLAGS = flags.FLAGS
NS = '{http://docs.openstack.org/api/openstack-volume/2.0/content}'
TEST_SNAPSHOT_UUID = '00000000-0000-0000-0000-000000000001'
def stub_snapshot_get(self, context, snapshot_id):
if snapshot_id != TEST_SNAPSHOT_UUID:
raise exception.NotFound
return {
'id': snapshot_id,
'volume_id': 12,
'status': 'available',
'volume_size': 100,
'created_at': None,
'name': 'Default name',
'description': 'Default description',
}
class VolumeApiTest(test.TestCase):
def setUp(self):
super(VolumeApiTest, self).setUp()
self.ext_mgr = extensions.ExtensionManager()
self.ext_mgr.extensions = {}
fake_image.stub_out_image_service(self.stubs)
self.controller = volumes.VolumeController(self.ext_mgr)
self.stubs.Set(db, 'volume_get_all', stubs.stub_volume_get_all)
self.stubs.Set(db, 'volume_get_all_by_project',
stubs.stub_volume_get_all_by_project)
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
self.stubs.Set(volume_api.API, 'delete', stubs.stub_volume_delete)
self.maxDiff = None
def test_volume_create(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
vol = {
"size": 100,
"name": "Volume Test Name",
"description": "Volume Test Desc",
"availability_zone": "zone1:host1"
}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v2/volumes')
res_dict = self.controller.create(req, body)
expected = {
'volume': {
'name': 'Volume Test Name',
'id': '1',
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
}
self.assertEqual(res_dict, expected)
def test_volume_create_with_type(self):
vol_type = db.volume_type_create(context.get_admin_context(),
dict(name=FLAGS.default_volume_type,
extra_specs={}))
db_vol_type = db.volume_type_get(context.get_admin_context(),
vol_type.id)
vol = {
"size": 100,
"name": "Volume Test Name",
"description": "Volume Test Desc",
"availability_zone": "zone1:host1",
"volume_type": db_vol_type['id'],
}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v2/volumes')
res_dict = self.controller.create(req, body)
volume_id = res_dict['volume']['id']
self.assertEquals(len(res_dict), 1)
self.stubs.Set(volume_api.API, 'get_all',
lambda *args, **kwargs:
[stubs.stub_volume(volume_id,
volume_type={'name': vol_type})])
req = fakes.HTTPRequest.blank('/v2/volumes/detail')
res_dict = self.controller.detail(req)
def test_volume_creation_fails_with_bad_size(self):
vol = {"size": '',
"name": "Volume Test Name",
"description": "Volume Test Desc",
"availability_zone": "zone1:host1"}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v2/volumes')
self.assertRaises(exception.InvalidInput,
self.controller.create,
req,
body)
def test_volume_create_with_image_id(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
self.ext_mgr.extensions = {'os-image-create': 'fake'}
vol = {"size": '1',
"name": "Volume Test Name",
"description": "Volume Test Desc",
"availability_zone": "nova",
"imageRef": 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'}
expected = {
'volume': {
'name': 'Volume Test Name',
'id': '1',
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v2/volumes')
res_dict = self.controller.create(req, body)
self.assertEqual(res_dict, expected)
def test_volume_create_with_image_id_is_integer(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
self.ext_mgr.extensions = {'os-image-create': 'fake'}
vol = {
"size": '1',
"name": "Volume Test Name",
"description": "Volume Test Desc",
"availability_zone": "manila",
"imageRef": 1234,
}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v2/volumes')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req,
body)
def test_volume_create_with_image_id_not_uuid_format(self):
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
self.ext_mgr.extensions = {'os-image-create': 'fake'}
vol = {
"size": '1',
"name": "Volume Test Name",
"description": "Volume Test Desc",
"availability_zone": "manila",
"imageRef": '12345'
}
body = {"volume": vol}
req = fakes.HTTPRequest.blank('/v2/volumes')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req,
body)
def test_volume_update(self):
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
updates = {
"name": "Updated Test Name",
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v2/volumes/1')
res_dict = self.controller.update(req, '1', body)
expected = {
'volume': {
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'Updated Test Name',
'attachments': [
{
'id': '1',
'volume_id': '1',
'server_id': 'fakeuuid',
'device': '/',
}
],
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
}
self.assertEquals(res_dict, expected)
def test_volume_update_metadata(self):
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
updates = {
"metadata": {"qos_max_iops": 2000}
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v2/volumes/1')
res_dict = self.controller.update(req, '1', body)
expected = {'volume': {
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'displayname',
'attachments': [{
'id': '1',
'volume_id': '1',
'server_id': 'fakeuuid',
'device': '/',
}],
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {"qos_max_iops": 2000},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}}
self.assertEquals(res_dict, expected)
def test_update_empty_body(self):
body = {}
req = fakes.HTTPRequest.blank('/v2/volumes/1')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update,
req, '1', body)
def test_update_invalid_body(self):
body = {
'name': 'missing top level volume key'
}
req = fakes.HTTPRequest.blank('/v2/volumes/1')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update,
req, '1', body)
def test_update_not_found(self):
self.stubs.Set(volume_api.API, "get", stubs.stub_volume_get_notfound)
updates = {
"name": "Updated Test Name",
}
body = {"volume": updates}
req = fakes.HTTPRequest.blank('/v2/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update,
req, '1', body)
def test_volume_list_summary(self):
self.stubs.Set(volume_api.API, 'get_all',
stubs.stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v2/volumes')
res_dict = self.controller.index(req)
expected = {
'volumes': [
{
'name': 'displayname',
'id': '1',
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
]
}
self.assertEqual(res_dict, expected)
def test_volume_list_detail(self):
self.stubs.Set(volume_api.API, 'get_all',
stubs.stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v2/volumes/detail')
res_dict = self.controller.detail(req)
expected = {
'volumes': [
{
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'displayname',
'attachments': [
{
'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'
}
],
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
]
}
self.assertEqual(res_dict, expected)
def test_volume_index_with_marker(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1'),
stubs.stub_volume(2, display_name='vol2'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v2/volumes?marker=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 2)
self.assertEquals(volumes[0]['id'], 1)
self.assertEquals(volumes[1]['id'], 2)
def test_volume_index_limit(self):
req = fakes.HTTPRequest.blank('/v2/volumes?limit=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 1)
def test_volume_index_limit_negative(self):
req = fakes.HTTPRequest.blank('/v2/volumes?limit=-1')
self.assertRaises(exception.Invalid,
self.controller.index,
req)
def test_volume_index_limit_non_int(self):
req = fakes.HTTPRequest.blank('/v2/volumes?limit=a')
self.assertRaises(exception.Invalid,
self.controller.index,
req)
def test_volume_index_limit_marker(self):
req = fakes.HTTPRequest.blank('/v2/volumes?marker=1&limit=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 1)
self.assertEquals(volumes[0]['id'], '1')
def test_volume_index_limit_offset(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1'),
stubs.stub_volume(2, display_name='vol2'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v2/volumes?limit=2&offset=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 1)
self.assertEquals(volumes[0]['id'], 2)
req = fakes.HTTPRequest.blank('/v2/volumes?limit=-1&offset=1')
self.assertRaises(exception.InvalidInput,
self.controller.index,
req)
req = fakes.HTTPRequest.blank('/v2/volumes?limit=a&offset=1')
self.assertRaises(exception.InvalidInput,
self.controller.index,
req)
def test_volume_detail_with_marker(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1'),
stubs.stub_volume(2, display_name='vol2'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v2/volumes/detail?marker=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 2)
self.assertEquals(volumes[0]['id'], 1)
self.assertEquals(volumes[1]['id'], 2)
def test_volume_detail_limit(self):
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 1)
def test_volume_detail_limit_negative(self):
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=-1')
self.assertRaises(exception.Invalid,
self.controller.index,
req)
def test_volume_detail_limit_non_int(self):
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=a')
self.assertRaises(exception.Invalid,
self.controller.index,
req)
def test_volume_detail_limit_marker(self):
req = fakes.HTTPRequest.blank('/v2/volumes/detail?marker=1&limit=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 1)
self.assertEquals(volumes[0]['id'], '1')
def test_volume_detail_limit_offset(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1'),
stubs.stub_volume(2, display_name='vol2'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=2&offset=1')
res_dict = self.controller.index(req)
volumes = res_dict['volumes']
self.assertEquals(len(volumes), 1)
self.assertEquals(volumes[0]['id'], 2)
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=-1&offset=1')
self.assertRaises(exception.InvalidInput,
self.controller.index,
req)
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=a&offset=1')
self.assertRaises(exception.InvalidInput,
self.controller.index,
req)
def test_volume_list_by_name(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1'),
stubs.stub_volume(2, display_name='vol2'),
stubs.stub_volume(3, display_name='vol3'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
# no name filter
req = fakes.HTTPRequest.blank('/v2/volumes')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 3)
# filter on name
req = fakes.HTTPRequest.blank('/v2/volumes?name=vol2')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 1)
self.assertEqual(resp['volumes'][0]['name'], 'vol2')
# filter no match
req = fakes.HTTPRequest.blank('/v2/volumes?name=vol4')
resp = self.controller.index(req)
self.assertEqual(len(resp['volumes']), 0)
def test_volume_list_by_status(self):
def stub_volume_get_all_by_project(context, project_id, marker, limit,
sort_key, sort_dir):
return [
stubs.stub_volume(1, display_name='vol1', status='available'),
stubs.stub_volume(2, display_name='vol2', status='available'),
stubs.stub_volume(3, display_name='vol3', status='in-use'),
]
self.stubs.Set(db, 'volume_get_all_by_project',
stub_volume_get_all_by_project)
# no status filter
req = fakes.HTTPRequest.blank('/v2/volumes/details')
resp = self.controller.detail(req)
self.assertEqual(len(resp['volumes']), 3)
# single match
req = fakes.HTTPRequest.blank('/v2/volumes/details?status=in-use')
resp = self.controller.detail(req)
self.assertEqual(len(resp['volumes']), 1)
self.assertEqual(resp['volumes'][0]['status'], 'in-use')
# multiple match
req = fakes.HTTPRequest.blank('/v2/volumes/details/?status=available')
resp = self.controller.detail(req)
self.assertEqual(len(resp['volumes']), 2)
for volume in resp['volumes']:
self.assertEqual(volume['status'], 'available')
# multiple filters
req = fakes.HTTPRequest.blank('/v2/volumes/details/?status=available&'
'name=vol1')
resp = self.controller.detail(req)
self.assertEqual(len(resp['volumes']), 1)
self.assertEqual(resp['volumes'][0]['name'], 'vol1')
self.assertEqual(resp['volumes'][0]['status'], 'available')
# no match
req = fakes.HTTPRequest.blank('/v2/volumes/details?status=in-use&'
'name=vol1')
resp = self.controller.detail(req)
self.assertEqual(len(resp['volumes']), 0)
def test_volume_show(self):
req = fakes.HTTPRequest.blank('/v2/volumes/1')
res_dict = self.controller.show(req, '1')
expected = {
'volume': {
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'displayname',
'attachments': [
{
'device': '/',
'server_id': 'fakeuuid',
'id': '1',
'volume_id': '1'
}
],
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
}
self.assertEqual(res_dict, expected)
def test_volume_show_no_attachments(self):
def stub_volume_get(self, context, volume_id):
return stubs.stub_volume(volume_id, attach_status='detached')
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
req = fakes.HTTPRequest.blank('/v2/volumes/1')
res_dict = self.controller.show(req, '1')
expected = {
'volume': {
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'displayname',
'attachments': [],
'volume_type': 'vol_type_name',
'snapshot_id': None,
'source_volid': None,
'metadata': {},
'id': '1',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'links': [
{
'href': 'http://localhost/v1/fake/volumes/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/volumes/1',
'rel': 'bookmark'
}
],
}
}
self.assertEqual(res_dict, expected)
def test_volume_show_no_volume(self):
self.stubs.Set(volume_api.API, "get", stubs.stub_volume_get_notfound)
req = fakes.HTTPRequest.blank('/v2/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
req, 1)
def test_volume_delete(self):
req = fakes.HTTPRequest.blank('/v2/volumes/1')
resp = self.controller.delete(req, 1)
self.assertEqual(resp.status_int, 202)
def test_volume_delete_no_volume(self):
self.stubs.Set(volume_api.API, "get", stubs.stub_volume_get_notfound)
req = fakes.HTTPRequest.blank('/v2/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
req, 1)
def test_admin_list_volumes_limited_to_project(self):
req = fakes.HTTPRequest.blank('/v2/fake/volumes',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(1, len(res['volumes']))
def test_admin_list_volumes_all_tenants(self):
req = fakes.HTTPRequest.blank('/v2/fake/volumes?all_tenants=1',
use_admin_context=True)
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(3, len(res['volumes']))
def test_all_tenants_non_admin_gets_all_tenants(self):
req = fakes.HTTPRequest.blank('/v2/fake/volumes?all_tenants=1')
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(1, len(res['volumes']))
def test_non_admin_get_by_project(self):
req = fakes.HTTPRequest.blank('/v2/fake/volumes')
res = self.controller.index(req)
self.assertTrue('volumes' in res)
self.assertEqual(1, len(res['volumes']))
def _create_volume_bad_request(self, body):
req = fakes.HTTPRequest.blank('/v2/fake/volumes')
req.method = 'POST'
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, body)
def test_create_no_body(self):
self._create_volume_bad_request(body=None)
def test_create_missing_volume(self):
body = {'foo': {'a': 'b'}}
self._create_volume_bad_request(body=body)
def test_create_malformed_entity(self):
body = {'volume': 'string'}
self._create_volume_bad_request(body=body)
class VolumeSerializerTest(test.TestCase):
def _verify_volume_attachment(self, attach, tree):
for attr in ('id', 'volume_id', 'server_id', 'device'):
self.assertEqual(str(attach[attr]), tree.get(attr))
def _verify_volume(self, vol, tree):
self.assertEqual(tree.tag, NS + 'volume')
for attr in ('id', 'status', 'size', 'availability_zone', 'created_at',
'name', 'description', 'volume_type',
'snapshot_id', 'source_volid'):
self.assertEqual(str(vol[attr]), tree.get(attr))
for child in tree:
print child.tag
self.assertTrue(child.tag in (NS + 'attachments', NS + 'metadata'))
if child.tag == 'attachments':
self.assertEqual(1, len(child))
self.assertEqual('attachment', child[0].tag)
self._verify_volume_attachment(vol['attachments'][0], child[0])
elif child.tag == 'metadata':
not_seen = set(vol['metadata'].keys())
for gr_child in child:
self.assertTrue(gr_child.get("key") in not_seen)
self.assertEqual(str(vol['metadata'][gr_child.get("key")]),
gr_child.text)
not_seen.remove(gr_child.get('key'))
self.assertEqual(0, len(not_seen))
def test_volume_show_create_serializer(self):
serializer = volumes.VolumeTemplate()
raw_volume = dict(
id='vol_id',
status='vol_status',
size=1024,
availability_zone='vol_availability',
created_at=datetime.datetime.now(),
attachments=[
dict(
id='vol_id',
volume_id='vol_id',
server_id='instance_uuid',
device='/foo'
)
],
name='vol_name',
description='vol_desc',
volume_type='vol_type',
snapshot_id='snap_id',
source_volid='source_volid',
metadata=dict(
foo='bar',
baz='quux',
),
)
text = serializer.serialize(dict(volume=raw_volume))
print text
tree = etree.fromstring(text)
self._verify_volume(raw_volume, tree)
def test_volume_index_detail_serializer(self):
serializer = volumes.VolumesTemplate()
raw_volumes = [
dict(
id='vol1_id',
status='vol1_status',
size=1024,
availability_zone='vol1_availability',
created_at=datetime.datetime.now(),
attachments=[
dict(
id='vol1_id',
volume_id='vol1_id',
server_id='instance_uuid',
device='/foo1'
)
],
name='vol1_name',
description='vol1_desc',
volume_type='vol1_type',
snapshot_id='snap1_id',
source_volid=None,
metadata=dict(foo='vol1_foo',
bar='vol1_bar', ), ),
dict(
id='vol2_id',
status='vol2_status',
size=1024,
availability_zone='vol2_availability',
created_at=datetime.datetime.now(),
attachments=[dict(id='vol2_id',
volume_id='vol2_id',
server_id='instance_uuid',
device='/foo2')],
name='vol2_name',
description='vol2_desc',
volume_type='vol2_type',
snapshot_id='snap2_id',
source_volid=None,
metadata=dict(foo='vol2_foo',
bar='vol2_bar', ), )]
text = serializer.serialize(dict(volumes=raw_volumes))
print text
tree = etree.fromstring(text)
self.assertEqual(NS + 'volumes', tree.tag)
self.assertEqual(len(raw_volumes), len(tree))
for idx, child in enumerate(tree):
self._verify_volume(raw_volumes[idx], child)
class TestVolumeCreateRequestXMLDeserializer(test.TestCase):
def setUp(self):
super(TestVolumeCreateRequestXMLDeserializer, self).setUp()
self.deserializer = volumes.CreateDeserializer()
def test_minimal_volume(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
size="1"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
},
}
self.assertEquals(request['body'], expected)
def test_name(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
size="1"
name="Volume-xml"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"name": "Volume-xml",
},
}
self.assertEquals(request['body'], expected)
def test_description(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
size="1"
name="Volume-xml"
description="description"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"name": "Volume-xml",
"description": "description",
},
}
self.assertEquals(request['body'], expected)
def test_volume_type(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
size="1"
name="Volume-xml"
description="description"
volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"name": "Volume-xml",
"size": "1",
"name": "Volume-xml",
"description": "description",
"volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
},
}
self.assertEquals(request['body'], expected)
def test_availability_zone(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
size="1"
name="Volume-xml"
description="description"
volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"
availability_zone="us-east1"></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"name": "Volume-xml",
"description": "description",
"volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
"availability_zone": "us-east1",
},
}
self.assertEquals(request['body'], expected)
def test_metadata(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
name="Volume-xml"
size="1">
<metadata><meta key="Type">work</meta></metadata></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"name": "Volume-xml",
"size": "1",
"metadata": {
"Type": "work",
},
},
}
self.assertEquals(request['body'], expected)
def test_full_volume(self):
self_request = """
<volume xmlns="http://docs.openstack.org/api/openstack-volume/2.0/content"
size="1"
name="Volume-xml"
description="description"
volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"
availability_zone="us-east1">
<metadata><meta key="Type">work</meta></metadata></volume>"""
request = self.deserializer.deserialize(self_request)
expected = {
"volume": {
"size": "1",
"name": "Volume-xml",
"description": "description",
"volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
"availability_zone": "us-east1",
"metadata": {
"Type": "work",
},
},
}
self.assertEquals(request['body'], expected)

View File

@ -1,14 +0,0 @@
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
# 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.

View File

@ -1,41 +0,0 @@
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
# 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.
from manila.db import base
from manila.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class FakeBackupService(base.Base):
def __init__(self, context, db_driver=None):
super(FakeBackupService, self).__init__(db_driver)
def backup(self, backup, volume_file):
pass
def restore(self, backup, volume_id, volume_file):
pass
def delete(self, backup):
# if backup has magic name of 'fail_on_delete'
# we raise an error - useful for some tests -
# otherwise we return without error
if backup['display_name'] == 'fail_on_delete':
raise IOError('fake')
def get_backup_service(context):
return FakeBackupService(context)

View File

@ -1,111 +0,0 @@
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
# 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 httplib
import json
import os
import socket
import zlib
from manila.openstack.common import log as logging
from swiftclient import client as swift
LOG = logging.getLogger(__name__)
class FakeSwiftClient(object):
"""Logs calls instead of executing."""
def __init__(self, *args, **kwargs):
pass
@classmethod
def Connection(self, *args, **kargs):
LOG.debug("fake FakeSwiftClient Connection")
return FakeSwiftConnection()
class FakeSwiftConnection(object):
"""Logging calls instead of executing"""
def __init__(self, *args, **kwargs):
pass
def head_container(self, container):
LOG.debug("fake head_container(%s)" % container)
if container == 'missing_container':
raise swift.ClientException('fake exception',
http_status=httplib.NOT_FOUND)
elif container == 'unauthorized_container':
raise swift.ClientException('fake exception',
http_status=httplib.UNAUTHORIZED)
elif container == 'socket_error_on_head':
raise socket.error(111, 'ECONNREFUSED')
pass
def put_container(self, container):
LOG.debug("fake put_container(%s)" % container)
pass
def get_container(self, container, **kwargs):
LOG.debug("fake get_container(%s)" % container)
fake_header = None
fake_body = [{'name': 'backup_001'},
{'name': 'backup_002'},
{'name': 'backup_003'}]
return fake_header, fake_body
def head_object(self, container, name):
LOG.debug("fake put_container(%s, %s)" % (container, name))
return {'etag': 'fake-md5-sum'}
def get_object(self, container, name):
LOG.debug("fake get_object(%s, %s)" % (container, name))
if container == 'socket_error_on_get':
raise socket.error(111, 'ECONNREFUSED')
if 'metadata' in name:
fake_object_header = None
metadata = {}
if container == 'unsupported_version':
metadata['version'] = '9.9.9'
else:
metadata['version'] = '1.0.0'
metadata['backup_id'] = 123
metadata['volume_id'] = 123
metadata['backup_name'] = 'fake backup'
metadata['backup_description'] = 'fake backup description'
metadata['created_at'] = '2013-02-19 11:20:54,805'
metadata['objects'] = [{
'backup_001': {'compression': 'zlib', 'length': 10},
'backup_002': {'compression': 'zlib', 'length': 10},
'backup_003': {'compression': 'zlib', 'length': 10}
}]
metadata_json = json.dumps(metadata, sort_keys=True, indent=2)
fake_object_body = metadata_json
return (fake_object_header, fake_object_body)
fake_header = None
fake_object_body = os.urandom(1024 * 1024)
return (fake_header, zlib.compress(fake_object_body))
def put_object(self, container, name, reader):
LOG.debug("fake put_object(%s, %s)" % (container, name))
if container == 'socket_error_on_put':
raise socket.error(111, 'ECONNREFUSED')
return 'fake-md5-sum'
def delete_object(self, container, name):
LOG.debug("fake delete_object(%s, %s)" % (container, name))
if container == 'socket_error_on_delete':
raise socket.error(111, 'ECONNREFUSED')
pass

View File

@ -1,16 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation.
# 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.

View File

@ -1,144 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
# 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 mox
from manila.brick.local_dev import lvm as brick
from manila.openstack.common import log as logging
from manila.openstack.common import processutils
from manila import test
from manila.volume import configuration as conf
LOG = logging.getLogger(__name__)
def create_configuration():
configuration = mox.MockObject(conf.Configuration)
configuration.append_config_values(mox.IgnoreArg())
return configuration
class BrickLvmTestCase(test.TestCase):
def setUp(self):
self._mox = mox.Mox()
self.configuration = mox.MockObject(conf.Configuration)
self.configuration.volume_group_name = 'fake-volumes'
super(BrickLvmTestCase, self).setUp()
self.stubs.Set(processutils, 'execute',
self.fake_execute)
self.vg = brick.LVM(self.configuration.volume_group_name)
def failed_fake_execute(obj, *cmd, **kwargs):
return ("\n", "fake-error")
def fake_pretend_lvm_version(obj, *cmd, **kwargs):
return (" LVM version: 2.03.00 (2012-03-06)\n", "")
def fake_old_lvm_version(obj, *cmd, **kwargs):
return (" LVM version: 2.02.65(2) (2012-03-06)\n", "")
def fake_execute(obj, *cmd, **kwargs):
cmd_string = ', '.join(cmd)
data = "\n"
if 'vgs, --noheadings, -o, name' == cmd_string:
data = " fake-volumes\n"
if 'vgs, --version' in cmd_string:
data = " LVM version: 2.02.95(2) (2012-03-06)\n"
elif 'vgs, --noheadings, -o uuid, fake-volumes' in cmd_string:
data = " kVxztV-dKpG-Rz7E-xtKY-jeju-QsYU-SLG6Z1\n"
elif 'vgs, --noheadings, -o, name,size,free,lv_count,uuid' in\
cmd_string:
data = " fake-volumes:10.00g:10.00g:0:"\
"kVxztV-dKpG-Rz7E-xtKY-jeju-QsYU-SLG6Z1\n"
if 'fake-volumes' in cmd_string:
return (data, "")
data += " fake-volumes-2:10.00g:10.00g:0:"\
"lWyauW-dKpG-Rz7E-xtKY-jeju-QsYU-SLG7Z2\n"
data += " fake-volumes-3:10.00g:10.00g:0:"\
"mXzbuX-dKpG-Rz7E-xtKY-jeju-QsYU-SLG8Z3\n"
elif 'lvs, --noheadings, -o, vg_name,name,size' in cmd_string:
data = " fake-volumes fake-1 1.00g\n"
data += " fake-volumes fake-2 1.00g\n"
elif 'lvs, --noheadings, -o, vg_name,name,size' in cmd_string:
data = " fake-volumes fake-1 1.00g\n"
data += " fake-volumes fake-2 1.00g\n"
elif 'pvs, --noheadings' and 'fake-volumes' in cmd_string:
data = " fake-volumes:/dev/sda:10.00g:8.99g\n"
elif 'pvs, --noheadings' in cmd_string:
data = " fake-volumes:/dev/sda:10.00g:8.99g\n"
data += " fake-volumes-2:/dev/sdb:10.00g:8.99g\n"
data += " fake-volumes-3:/dev/sdc:10.00g:8.99g\n"
else:
pass
return (data, "")
def test_vg_exists(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
self.assertEqual(self.vg._vg_exists(), True)
self.stubs.Set(processutils, 'execute', self.failed_fake_execute)
self.assertEqual(self.vg._vg_exists(), False)
def test_get_vg_uuid(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
self.assertEqual(self.vg._get_vg_uuid()[0],
'kVxztV-dKpG-Rz7E-xtKY-jeju-QsYU-SLG6Z1')
def test_get_all_volumes(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
out = self.vg.get_volumes()
self.assertEqual(out[0]['name'], 'fake-1')
self.assertEqual(out[0]['size'], '1.00g')
self.assertEqual(out[0]['vg'], 'fake-volumes')
def test_get_volume(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
self.assertEqual(self.vg.get_volume('fake-1')['name'], 'fake-1')
def test_get_all_physical_volumes(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
pvs = self.vg.get_all_physical_volumes()
self.assertEqual(len(pvs), 3)
def test_get_physical_volumes(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
pvs = self.vg.get_physical_volumes()
self.assertEqual(len(pvs), 1)
def test_get_volume_groups(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
self.assertEqual(len(self.vg.get_all_volume_groups()), 3)
self.assertEqual(len(self.vg.get_all_volume_groups('fake-volumes')), 1)
def test_update_vg_info(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
self.assertEqual(self.vg.update_volume_group_info()['name'],
'fake-volumes')
def test_thin_support(self):
self.stubs.Set(processutils, 'execute', self.fake_execute)
self.assertTrue(self.vg.supports_thin_provisioning())
self.stubs.Set(processutils, 'execute', self.fake_pretend_lvm_version)
self.assertTrue(self.vg.supports_thin_provisioning())
self.stubs.Set(processutils, 'execute', self.fake_old_lvm_version)
self.assertFalse(self.vg.supports_thin_provisioning())

View File

@ -201,19 +201,3 @@ class TestOpenStackClient(object):
kwargs['method'] = 'DELETE'
kwargs.setdefault('check_response_status', [200, 202, 204])
return self.api_request(relative_uri, **kwargs)
def get_volume(self, volume_id):
return self.api_get('/volumes/%s' % volume_id)['volume']
def get_volumes(self, detail=True):
rel_url = '/volumes/detail' if detail else '/volumes'
return self.api_get(rel_url)['volumes']
def post_volume(self, volume):
return self.api_post('/volumes', volume)['volume']
def delete_volume(self, volume_id):
return self.api_delete('/volumes/%s' % volume_id)
def put_volume(self, volume_id, volume):
return self.api_put('/volumes/%s' % volume_id, volume)['volume']

View File

@ -14,7 +14,7 @@
# 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 unittest import skip
from manila.openstack.common import log as logging
from manila.tests.integrated import integrated_helpers
@ -24,6 +24,7 @@ LOG = logging.getLogger(__name__)
class LoginTest(integrated_helpers._IntegratedTestBase):
@skip('We do not have self.api.get_volumes()')
def test_login(self):
"""Simple check - we list volumes - so we know we're logged in."""
volumes = self.api.get_volumes()

View File

@ -1,198 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Justin Santa Barbara
# 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 time
import unittest
from manila.openstack.common import log as logging
from manila import service
from manila.tests import fake_driver
from manila.tests.integrated.api import client
from manila.tests.integrated import integrated_helpers
from manila.volume import driver
LOG = logging.getLogger(__name__)
class VolumesTest(integrated_helpers._IntegratedTestBase):
def setUp(self):
super(VolumesTest, self).setUp()
fake_driver.LoggingVolumeDriver.clear_logs()
def _start_api_service(self):
self.osapi = service.WSGIService("osapi_share")
self.osapi.start()
self.auth_url = 'http://%s:%s/v1' % (self.osapi.host, self.osapi.port)
LOG.warn(self.auth_url)
def _get_flags(self):
f = super(VolumesTest, self)._get_flags()
f['volume_driver'] = 'manila.tests.fake_driver.LoggingVolumeDriver'
return f
def test_get_volumes_summary(self):
"""Simple check that listing volumes works."""
volumes = self.api.get_volumes(False)
for volume in volumes:
LOG.debug("volume: %s" % volume)
def test_get_volumes(self):
"""Simple check that listing volumes works."""
volumes = self.api.get_volumes()
for volume in volumes:
LOG.debug("volume: %s" % volume)
def _poll_while(self, volume_id, continue_states, max_retries=5):
"""Poll (briefly) while the state is in continue_states."""
retries = 0
while True:
try:
found_volume = self.api.get_volume(volume_id)
except client.OpenStackApiNotFoundException:
found_volume = None
LOG.debug("Got 404, proceeding")
break
LOG.debug("Found %s" % found_volume)
self.assertEqual(volume_id, found_volume['id'])
if found_volume['status'] not in continue_states:
break
time.sleep(1)
retries = retries + 1
if retries > max_retries:
break
return found_volume
def test_create_and_delete_volume(self):
"""Creates and deletes a volume."""
# Create volume
created_volume = self.api.post_volume({'volume': {'size': 1}})
LOG.debug("created_volume: %s" % created_volume)
self.assertTrue(created_volume['id'])
created_volume_id = created_volume['id']
# Check it's there
found_volume = self.api.get_volume(created_volume_id)
self.assertEqual(created_volume_id, found_volume['id'])
# It should also be in the all-volume list
volumes = self.api.get_volumes()
volume_names = [volume['id'] for volume in volumes]
self.assertTrue(created_volume_id in volume_names)
# Wait (briefly) for creation. Delay is due to the 'message queue'
found_volume = self._poll_while(created_volume_id, ['creating'])
# It should be available...
self.assertEqual('available', found_volume['status'])
# Delete the volume
self.api.delete_volume(created_volume_id)
# Wait (briefly) for deletion. Delay is due to the 'message queue'
found_volume = self._poll_while(created_volume_id, ['deleting'])
# Should be gone
self.assertFalse(found_volume)
LOG.debug("Logs: %s" % fake_driver.LoggingVolumeDriver.all_logs())
create_actions = fake_driver.LoggingVolumeDriver.logs_like(
'create_volume',
id=created_volume_id)
LOG.debug("Create_Actions: %s" % create_actions)
self.assertEquals(1, len(create_actions))
create_action = create_actions[0]
self.assertEquals(create_action['id'], created_volume_id)
self.assertEquals(create_action['availability_zone'], 'nova')
self.assertEquals(create_action['size'], 1)
export_actions = fake_driver.LoggingVolumeDriver.logs_like(
'create_export',
id=created_volume_id)
self.assertEquals(1, len(export_actions))
export_action = export_actions[0]
self.assertEquals(export_action['id'], created_volume_id)
self.assertEquals(export_action['availability_zone'], 'nova')
delete_actions = fake_driver.LoggingVolumeDriver.logs_like(
'delete_volume',
id=created_volume_id)
self.assertEquals(1, len(delete_actions))
delete_action = export_actions[0]
self.assertEquals(delete_action['id'], created_volume_id)
def test_create_volume_with_metadata(self):
"""Creates a volume with metadata."""
# Create volume
metadata = {'key1': 'value1',
'key2': 'value2'}
created_volume = self.api.post_volume(
{'volume': {'size': 1,
'metadata': metadata}})
LOG.debug("created_volume: %s" % created_volume)
self.assertTrue(created_volume['id'])
created_volume_id = created_volume['id']
# Check it's there and metadata present
found_volume = self.api.get_volume(created_volume_id)
self.assertEqual(created_volume_id, found_volume['id'])
self.assertEqual(metadata, found_volume['metadata'])
def test_create_volume_in_availability_zone(self):
"""Creates a volume in availability_zone."""
# Create volume
availability_zone = 'zone1:host1'
created_volume = self.api.post_volume(
{'volume': {'size': 1,
'availability_zone': availability_zone}})
LOG.debug("created_volume: %s" % created_volume)
self.assertTrue(created_volume['id'])
created_volume_id = created_volume['id']
# Check it's there and availability zone present
found_volume = self.api.get_volume(created_volume_id)
self.assertEqual(created_volume_id, found_volume['id'])
self.assertEqual(availability_zone, found_volume['availability_zone'])
def test_create_and_update_volume(self):
# Create vol1
created_volume = self.api.post_volume({'volume': {
'size': 1, 'display_name': 'vol1'}})
self.assertEqual(created_volume['display_name'], 'vol1')
created_volume_id = created_volume['id']
# update volume
body = {'volume': {'display_name': 'vol-one'}}
updated_volume = self.api.put_volume(created_volume_id, body)
self.assertEqual(updated_volume['display_name'], 'vol-one')
# check for update
found_volume = self.api.get_volume(created_volume_id)
self.assertEqual(created_volume_id, found_volume['id'])
self.assertEqual(found_volume['display_name'], 'vol-one')
if __name__ == "__main__":
unittest.main()

View File

@ -37,81 +37,6 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
driver_cls = filter_scheduler.FilterScheduler
@test.skip_if(not test_utils.is_manila_installed(),
'Test requires Manila installed (try setup.py develop')
def test_create_volume_no_hosts(self):
"""
Ensure empty hosts & child_zones result in NoValidHosts exception.
"""
def _fake_empty_call_zone_method(*args, **kwargs):
return []
sched = fakes.FakeFilterScheduler()
fake_context = context.RequestContext('user', 'project')
request_spec = {'volume_properties': {'project_id': 1,
'size': 1},
'volume_type': {'name': 'LVM_iSCSI'},
'volume_id': ['fake-id1']}
self.assertRaises(exception.NoValidHost, sched.schedule_create_volume,
fake_context, request_spec, {})
@test.skip_if(not test_utils.is_manila_installed(),
'Test requires Manila installed (try setup.py develop')
def test_create_volume_non_admin(self):
"""Test creating an instance locally using run_instance, passing
a non-admin context. DB actions should work."""
self.was_admin = False
def fake_get(context, *args, **kwargs):
# make sure this is called with admin context, even though
# we're using user context below
self.was_admin = context.is_admin
return {}
sched = fakes.FakeFilterScheduler()
self.stubs.Set(sched.host_manager, 'get_all_host_states', fake_get)
fake_context = context.RequestContext('user', 'project')
request_spec = {'volume_properties': {'project_id': 1,
'size': 1},
'volume_type': {'name': 'LVM_iSCSI'},
'volume_id': ['fake-id1']}
self.assertRaises(exception.NoValidHost, sched.schedule_create_volume,
fake_context, request_spec, {})
self.assertTrue(self.was_admin)
@test.skip_if(not test_utils.is_manila_installed(),
'Test requires Manila installed (try setup.py develop')
def test_schedule_happy_day(self):
"""Make sure there's nothing glaringly wrong with _schedule()
by doing a happy day pass through."""
self.next_weight = 1.0
def _fake_weigh_objects(_self, functions, hosts, options):
self.next_weight += 2.0
host_state = hosts[0]
return [weights.WeighedHost(host_state, self.next_weight)]
sched = fakes.FakeFilterScheduler()
fake_context = context.RequestContext('user', 'project',
is_admin=True)
self.stubs.Set(sched.host_manager, 'get_filtered_hosts',
fake_get_filtered_hosts)
self.stubs.Set(weights.HostWeightHandler,
'get_weighed_objects', _fake_weigh_objects)
fakes.mox_host_manager_db_calls(self.mox, fake_context)
request_spec = {'volume_type': {'name': 'LVM_iSCSI'},
'volume_properties': {'project_id': 1,
'size': 1}}
self.mox.ReplayAll()
weighed_host = sched._schedule(fake_context, request_spec, {})
self.assertTrue(weighed_host.obj is not None)
@test.skip_if(not test_utils.is_manila_installed(),
'Test requires Manila installed (try setup.py develop')
def test_create_share_no_hosts(self):

View File

@ -222,43 +222,6 @@ class HostManagerTestCase(test.TestCase):
class HostStateTestCase(test.TestCase):
"""Test case for HostState class."""
def test_update_from_volume_capability(self):
fake_host = host_manager.HostState('host1')
self.assertEqual(fake_host.free_capacity_gb, None)
volume_capability = {'total_capacity_gb': 1024,
'free_capacity_gb': 512,
'reserved_percentage': 0,
'timestamp': None}
fake_host.update_from_volume_capability(volume_capability)
self.assertEqual(fake_host.free_capacity_gb, 512)
def test_update_from_volume_infinite_capability(self):
fake_host = host_manager.HostState('host1')
self.assertEqual(fake_host.free_capacity_gb, None)
volume_capability = {'total_capacity_gb': 'infinite',
'free_capacity_gb': 'infinite',
'reserved_percentage': 0,
'timestamp': None}
fake_host.update_from_volume_capability(volume_capability)
self.assertEqual(fake_host.total_capacity_gb, 'infinite')
self.assertEqual(fake_host.free_capacity_gb, 'infinite')
def test_update_from_volume_unknown_capability(self):
fake_host = host_manager.HostState('host1')
self.assertEqual(fake_host.free_capacity_gb, None)
volume_capability = {'total_capacity_gb': 'infinite',
'free_capacity_gb': 'unknown',
'reserved_percentage': 0,
'timestamp': None}
fake_host.update_from_volume_capability(volume_capability)
self.assertEqual(fake_host.total_capacity_gb, 'infinite')
self.assertEqual(fake_host.free_capacity_gb, 'unknown')
def test_update_from_share_capability(self):
fake_host = host_manager.HostState('host1')

View File

@ -89,29 +89,6 @@ class SchedulerManagerTestCase(test.TestCase):
service_name=service_name, host=host,
capabilities=capabilities)
def test_create_volume_exception_puts_volume_in_error_state(self):
"""Test that a NoValideHost exception for create_volume.
Puts the volume in 'error' state and eats the exception.
"""
fake_volume_id = 1
self._mox_schedule_method_helper('schedule_create_volume')
self.mox.StubOutWithMock(db, 'volume_update')
topic = 'fake_topic'
volume_id = fake_volume_id
request_spec = {'volume_id': fake_volume_id}
self.manager.driver.schedule_create_volume(
self.context,
request_spec, {}).AndRaise(exception.NoValidHost(reason=""))
db.volume_update(self.context, fake_volume_id, {'status': 'error'})
self.mox.ReplayAll()
self.manager.create_volume(self.context, topic, volume_id,
request_spec=request_spec,
filter_properties={})
def test_create_share_exception_puts_share_in_error_state(self):
"""Test that a NoValideHost exception for create_share.
@ -212,18 +189,6 @@ class SchedulerDriverModuleTestCase(test.TestCase):
super(SchedulerDriverModuleTestCase, self).setUp()
self.context = context.RequestContext('fake_user', 'fake_project')
def test_volume_host_update_db(self):
self.mox.StubOutWithMock(timeutils, 'utcnow')
self.mox.StubOutWithMock(db, 'volume_update')
timeutils.utcnow().AndReturn('fake-now')
db.volume_update(self.context, 31337,
{'host': 'fake_host',
'scheduled_at': 'fake-now'})
self.mox.ReplayAll()
driver.volume_update_db(self.context, 31337, 'fake_host')
def test_share_host_update_db(self):
self.mox.StubOutWithMock(timeutils, 'utcnow')
self.mox.StubOutWithMock(db, 'share_update')

View File

@ -1,245 +0,0 @@
# Copyright 2012 OpenStack LLC
#
# 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 mox
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers.san.hp_lefthand import HpSanISCSIDriver
LOG = logging.getLogger(__name__)
class HpSanISCSITestCase(test.TestCase):
def setUp(self):
super(HpSanISCSITestCase, self).setUp()
self.stubs.Set(HpSanISCSIDriver, "_cliq_run",
self._fake_cliq_run)
self.stubs.Set(HpSanISCSIDriver, "_get_iscsi_properties",
self._fake_get_iscsi_properties)
configuration = mox.MockObject(conf.Configuration)
configuration.san_is_local = False
configuration.san_ip = "10.0.0.1"
configuration.san_login = "foo"
configuration.san_password = "bar"
configuration.san_ssh_port = 16022
configuration.san_clustername = "CloudCluster1"
configuration.san_thin_provision = True
configuration.append_config_values(mox.IgnoreArg())
self.driver = HpSanISCSIDriver(configuration=configuration)
self.volume_name = "fakevolume"
self.connector = {'ip': '10.0.0.2',
'initiator': 'iqn.1993-08.org.debian:01:222',
'host': 'fakehost'}
self.properties = {
'target_discoverd': True,
'target_portal': '10.0.1.6:3260',
'target_iqn':
'iqn.2003-10.com.lefthandnetworks:group01:25366:fakev',
'volume_id': 1}
def tearDown(self):
super(HpSanISCSITestCase, self).tearDown()
def _fake_get_iscsi_properties(self, volume):
return self.properties
def _fake_cliq_run(self, verb, cliq_args, check_exit_code=True):
"""Return fake results for the various methods."""
def create_volume(cliq_args):
"""
input = "createVolume description="fake description"
clusterName=Cluster01 volumeName=fakevolume
thinProvision=0 output=XML size=1GB"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="181" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['thinProvision'], '1')
self.assertEqual(cliq_args['size'], '1GB')
return output, None
def delete_volume(cliq_args):
"""
input = "deleteVolume volumeName=fakevolume prompt=false
output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="164" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['prompt'], 'false')
return output, None
def assign_volume(cliq_args):
"""
input = "assignVolumeToServer volumeName=fakevolume
serverName=fakehost
output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="174" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['serverName'], self.connector['host'])
return output, None
def unassign_volume(cliq_args):
"""
input = "unassignVolumeToServer volumeName=fakevolume
serverName=fakehost output=XML
"""
output = """<gauche version="1.0">
<response description="Operation succeeded."
name="CliqSuccess" processingTime="205" result="0"/>
</gauche>"""
self.assertEqual(cliq_args['volumeName'], self.volume_name)
self.assertEqual(cliq_args['serverName'], self.connector['host'])
return output, None
def get_cluster_info(cliq_args):
"""
input = "getClusterInfo clusterName=Cluster01 searchDepth=1
verbose=0 output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded." name="CliqSuccess"
processingTime="1164" result="0">
<cluster blockSize="1024" description=""
maxVolumeSizeReplication1="622957690"
maxVolumeSizeReplication2="311480287"
minVolumeSize="262144" name="Cluster01"
pageSize="262144" spaceTotal="633697992"
storageNodeCount="2" unprovisionedSpace="622960574"
useVip="true">
<nsm ipAddress="10.0.1.7" name="111-vsa"/>
<nsm ipAddress="10.0.1.8" name="112-vsa"/>
<vip ipAddress="10.0.1.6" subnetMask="255.255.255.0"/>
</cluster></response></gauche>"""
return output, None
def get_volume_info(cliq_args):
"""
input = "getVolumeInfo volumeName=fakevolume output=XML"
"""
output = """<gauche version="1.0">
<response description="Operation succeeded." name="CliqSuccess"
processingTime="87" result="0">
<volume autogrowPages="4" availability="online"
blockSize="1024" bytesWritten="0" checkSum="false"
clusterName="Cluster01" created="2011-02-08T19:56:53Z"
deleting="false" description="" groupName="Group01"
initialQuota="536870912" isPrimary="true"
iscsiIqn="iqn.2003-10.com.lefthandnetworks:group01:25366:fakev"
maxSize="6865387257856" md5="9fa5c8b2cca54b2948a63d833097e1ca"
minReplication="1" name="vol-b" parity="0" replication="2"
reserveQuota="536870912" scratchQuota="4194304"
serialNumber="9fa5c8b2cca54b2948a63d8"
size="1073741824" stridePages="32" thinProvision="true">
<status description="OK" value="2"/>
<permission access="rw" authGroup="api-1"
chapName="chapusername" chapRequired="true"
id="25369" initiatorSecret="" iqn=""
iscsiEnabled="true" loadBalance="true"
targetSecret="supersecret"/>
</volume></response></gauche>"""
return output, None
def get_server_info(cliq_args):
"""
input = "getServerInfo serverName=fakeName"
"""
output = """<gauche version="1.0"><response result="0"/>
</gauche>"""
return output, None
def create_server(cliq_args):
"""
input = "createServer serverName=fakeName initiator=something"
"""
output = """<gauche version="1.0"><response result="0"/>
</gauche>"""
return output, None
def test_error(cliq_args):
output = """<gauche version="1.0">
<response description="Volume '134234' not found."
name="CliqVolumeNotFound" processingTime="1083"
result="8000100c"/>
</gauche>"""
return output, None
self.assertEqual(cliq_args['output'], 'XML')
try:
verbs = {'createVolume': create_volume,
'deleteVolume': delete_volume,
'assignVolumeToServer': assign_volume,
'unassignVolumeToServer': unassign_volume,
'getClusterInfo': get_cluster_info,
'getVolumeInfo': get_volume_info,
'getServerInfo': get_server_info,
'createServer': create_server,
'testError': test_error}
except KeyError:
raise NotImplementedError()
return verbs[verb](cliq_args)
def test_create_volume(self):
volume = {'name': self.volume_name, 'size': 1}
model_update = self.driver.create_volume(volume)
expected_iqn = "iqn.2003-10.com.lefthandnetworks:group01:25366:fakev 0"
expected_location = "10.0.1.6:3260,1 %s" % expected_iqn
self.assertEqual(model_update['provider_location'], expected_location)
def test_delete_volume(self):
volume = {'name': self.volume_name}
self.driver.delete_volume(volume)
def test_initialize_connection(self):
volume = {'name': self.volume_name}
result = self.driver.initialize_connection(volume, self.connector)
self.assertEqual(result['driver_volume_type'], 'iscsi')
self.assertDictMatch(result['data'], self.properties)
def test_terminate_connection(self):
volume = {'name': self.volume_name}
self.driver.terminate_connection(volume, self.connector)
def test_create_snapshot(self):
try:
self.driver.create_snapshot("")
except NotImplementedError:
pass
def test_create_volume_from_snapshot(self):
try:
self.driver.create_volume_from_snapshot("", "")
except NotImplementedError:
pass
def test_cliq_error(self):
try:
self.driver._cliq_run_xml("testError", {})
except exception.ShareBackendAPIException:
pass

View File

@ -1,395 +0,0 @@
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
# 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.
"""
Tests for Backup code.
"""
import tempfile
from manila import context
from manila import db
from manila import exception
from manila import flags
from manila.openstack.common import importutils
from manila.openstack.common import log as logging
from manila.openstack.common import timeutils
from manila import test
FLAGS = flags.FLAGS
LOG = logging.getLogger(__name__)
class FakeBackupException(Exception):
pass
class BackupTestCase(test.TestCase):
"""Test Case for backups."""
def setUp(self):
super(BackupTestCase, self).setUp()
vol_tmpdir = tempfile.mkdtemp()
self.flags(connection_type='fake',
volumes_dir=vol_tmpdir)
self.backup_mgr = \
importutils.import_object(FLAGS.backup_manager)
self.backup_mgr.host = 'testhost'
self.ctxt = context.get_admin_context()
def tearDown(self):
super(BackupTestCase, self).tearDown()
def _create_backup_db_entry(self, volume_id=1, display_name='test_backup',
display_description='this is a test backup',
container='volumebackups',
status='creating',
size=0,
object_count=0,
project_id='fake'):
"""
Create a backup entry in the DB.
Return the entry ID
"""
backup = {}
backup['volume_id'] = volume_id
backup['user_id'] = 'fake'
backup['project_id'] = project_id
backup['host'] = 'testhost'
backup['availability_zone'] = '1'
backup['display_name'] = display_name
backup['display_description'] = display_description
backup['container'] = container
backup['status'] = status
backup['fail_reason'] = ''
backup['service'] = FLAGS.backup_service
backup['size'] = size
backup['object_count'] = object_count
return db.backup_create(self.ctxt, backup)['id']
def _create_volume_db_entry(self, display_name='test_volume',
display_description='this is a test volume',
status='backing-up',
size=1):
"""
Create a volume entry in the DB.
Return the entry ID
"""
vol = {}
vol['size'] = size
vol['host'] = 'testhost'
vol['user_id'] = 'fake'
vol['project_id'] = 'fake'
vol['status'] = status
vol['display_name'] = display_name
vol['display_description'] = display_description
vol['attach_status'] = 'detached'
return db.volume_create(self.ctxt, vol)['id']
def test_init_host(self):
"""Make sure stuck volumes and backups are reset to correct
states when backup_manager.init_host() is called"""
vol1_id = self._create_volume_db_entry(status='backing-up')
vol2_id = self._create_volume_db_entry(status='restoring-backup')
backup1_id = self._create_backup_db_entry(status='creating')
backup2_id = self._create_backup_db_entry(status='restoring')
backup3_id = self._create_backup_db_entry(status='deleting')
self.backup_mgr.init_host()
vol1 = db.volume_get(self.ctxt, vol1_id)
self.assertEquals(vol1['status'], 'available')
vol2 = db.volume_get(self.ctxt, vol2_id)
self.assertEquals(vol2['status'], 'error_restoring')
backup1 = db.backup_get(self.ctxt, backup1_id)
self.assertEquals(backup1['status'], 'error')
backup2 = db.backup_get(self.ctxt, backup2_id)
self.assertEquals(backup2['status'], 'available')
self.assertRaises(exception.BackupNotFound,
db.backup_get,
self.ctxt,
backup3_id)
def test_create_backup_with_bad_volume_status(self):
"""Test error handling when creating a backup from a volume
with a bad status"""
vol_id = self._create_volume_db_entry(status='available', size=1)
backup_id = self._create_backup_db_entry(volume_id=vol_id)
self.assertRaises(exception.InvalidVolume,
self.backup_mgr.create_backup,
self.ctxt,
backup_id)
def test_create_backup_with_bad_backup_status(self):
"""Test error handling when creating a backup with a backup
with a bad status"""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(status='available',
volume_id=vol_id)
self.assertRaises(exception.InvalidBackup,
self.backup_mgr.create_backup,
self.ctxt,
backup_id)
def test_create_backup_with_error(self):
"""Test error handling when an error occurs during backup creation"""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(volume_id=vol_id)
def fake_backup_volume(context, backup, backup_service):
raise FakeBackupException('fake')
self.stubs.Set(self.backup_mgr.driver, 'backup_volume',
fake_backup_volume)
self.assertRaises(FakeBackupException,
self.backup_mgr.create_backup,
self.ctxt,
backup_id)
vol = db.volume_get(self.ctxt, vol_id)
self.assertEquals(vol['status'], 'available')
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'error')
def test_create_backup(self):
"""Test normal backup creation"""
vol_size = 1
vol_id = self._create_volume_db_entry(size=vol_size)
backup_id = self._create_backup_db_entry(volume_id=vol_id)
def fake_backup_volume(context, backup, backup_service):
pass
self.stubs.Set(self.backup_mgr.driver, 'backup_volume',
fake_backup_volume)
self.backup_mgr.create_backup(self.ctxt, backup_id)
vol = db.volume_get(self.ctxt, vol_id)
self.assertEquals(vol['status'], 'available')
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'available')
self.assertEqual(backup['size'], vol_size)
def test_restore_backup_with_bad_volume_status(self):
"""Test error handling when restoring a backup to a volume
with a bad status"""
vol_id = self._create_volume_db_entry(status='available', size=1)
backup_id = self._create_backup_db_entry(volume_id=vol_id)
self.assertRaises(exception.InvalidVolume,
self.backup_mgr.restore_backup,
self.ctxt,
backup_id,
vol_id)
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'available')
def test_restore_backup_with_bad_backup_status(self):
"""Test error handling when restoring a backup with a backup
with a bad status"""
vol_id = self._create_volume_db_entry(status='restoring-backup',
size=1)
backup_id = self._create_backup_db_entry(status='available',
volume_id=vol_id)
self.assertRaises(exception.InvalidBackup,
self.backup_mgr.restore_backup,
self.ctxt,
backup_id,
vol_id)
vol = db.volume_get(self.ctxt, vol_id)
self.assertEquals(vol['status'], 'error')
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'error')
def test_restore_backup_with_driver_error(self):
"""Test error handling when an error occurs during backup restore"""
vol_id = self._create_volume_db_entry(status='restoring-backup',
size=1)
backup_id = self._create_backup_db_entry(status='restoring',
volume_id=vol_id)
def fake_restore_backup(context, backup, volume, backup_service):
raise FakeBackupException('fake')
self.stubs.Set(self.backup_mgr.driver, 'restore_backup',
fake_restore_backup)
self.assertRaises(FakeBackupException,
self.backup_mgr.restore_backup,
self.ctxt,
backup_id,
vol_id)
vol = db.volume_get(self.ctxt, vol_id)
self.assertEquals(vol['status'], 'error_restoring')
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'available')
def test_restore_backup_with_bad_service(self):
"""Test error handling when attempting a restore of a backup
with a different service to that used to create the backup"""
vol_id = self._create_volume_db_entry(status='restoring-backup',
size=1)
backup_id = self._create_backup_db_entry(status='restoring',
volume_id=vol_id)
def fake_restore_backup(context, backup, volume, backup_service):
pass
self.stubs.Set(self.backup_mgr.driver, 'restore_backup',
fake_restore_backup)
service = 'manila.tests.backup.bad_service'
db.backup_update(self.ctxt, backup_id, {'service': service})
self.assertRaises(exception.InvalidBackup,
self.backup_mgr.restore_backup,
self.ctxt,
backup_id,
vol_id)
vol = db.volume_get(self.ctxt, vol_id)
self.assertEquals(vol['status'], 'error')
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'available')
def test_restore_backup(self):
"""Test normal backup restoration"""
vol_size = 1
vol_id = self._create_volume_db_entry(status='restoring-backup',
size=vol_size)
backup_id = self._create_backup_db_entry(status='restoring',
volume_id=vol_id)
def fake_restore_backup(context, backup, volume, backup_service):
pass
self.stubs.Set(self.backup_mgr.driver, 'restore_backup',
fake_restore_backup)
self.backup_mgr.restore_backup(self.ctxt, backup_id, vol_id)
vol = db.volume_get(self.ctxt, vol_id)
self.assertEquals(vol['status'], 'available')
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'available')
def test_delete_backup_with_bad_backup_status(self):
"""Test error handling when deleting a backup with a backup
with a bad status"""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(status='available',
volume_id=vol_id)
self.assertRaises(exception.InvalidBackup,
self.backup_mgr.delete_backup,
self.ctxt,
backup_id)
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'error')
def test_delete_backup_with_error(self):
"""Test error handling when an error occurs during backup deletion."""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(status='deleting',
display_name='fail_on_delete',
volume_id=vol_id)
self.assertRaises(IOError,
self.backup_mgr.delete_backup,
self.ctxt,
backup_id)
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'error')
def test_delete_backup_with_bad_service(self):
"""Test error handling when attempting a delete of a backup
with a different service to that used to create the backup"""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(status='deleting',
volume_id=vol_id)
service = 'manila.tests.backup.bad_service'
db.backup_update(self.ctxt, backup_id, {'service': service})
self.assertRaises(exception.InvalidBackup,
self.backup_mgr.delete_backup,
self.ctxt,
backup_id)
backup = db.backup_get(self.ctxt, backup_id)
self.assertEquals(backup['status'], 'error')
def test_delete_backup_with_no_service(self):
"""Test error handling when attempting a delete of a backup
with no service defined for that backup, relates to bug #1162908"""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(status='deleting',
volume_id=vol_id)
db.backup_update(self.ctxt, backup_id, {'service': None})
self.backup_mgr.delete_backup(self.ctxt, backup_id)
def test_delete_backup(self):
"""Test normal backup deletion"""
vol_id = self._create_volume_db_entry(size=1)
backup_id = self._create_backup_db_entry(status='deleting',
volume_id=vol_id)
self.backup_mgr.delete_backup(self.ctxt, backup_id)
self.assertRaises(exception.BackupNotFound,
db.backup_get,
self.ctxt,
backup_id)
ctxt_read_deleted = context.get_admin_context('yes')
backup = db.backup_get(ctxt_read_deleted, backup_id)
self.assertEqual(backup.deleted, True)
self.assertTrue(timeutils.utcnow() > backup.deleted_at)
self.assertEqual(backup.status, 'deleted')
def test_list_backup(self):
backups = db.backup_get_all_by_project(self.ctxt, 'project1')
self.assertEqual(len(backups), 0)
b1 = self._create_backup_db_entry()
b2 = self._create_backup_db_entry(project_id='project1')
backups = db.backup_get_all_by_project(self.ctxt, 'project1')
self.assertEqual(len(backups), 1)
self.assertEqual(backups[0].id, b2)
def test_backup_get_all_by_project_with_deleted(self):
"""Test deleted backups don't show up in backup_get_all_by_project.
Unless context.read_deleted is 'yes'"""
backups = db.backup_get_all_by_project(self.ctxt, 'fake')
self.assertEqual(len(backups), 0)
backup_id_keep = self._create_backup_db_entry()
backup_id = self._create_backup_db_entry()
db.backup_destroy(self.ctxt, backup_id)
backups = db.backup_get_all_by_project(self.ctxt, 'fake')
self.assertEqual(len(backups), 1)
self.assertEqual(backups[0].id, backup_id_keep)
ctxt_read_deleted = context.get_admin_context('yes')
backups = db.backup_get_all_by_project(ctxt_read_deleted, 'fake')
self.assertEqual(len(backups), 2)
def test_backup_get_all_by_host_with_deleted(self):
"""Test deleted backups don't show up in backup_get_all_by_project.
Unless context.read_deleted is 'yes'"""
backups = db.backup_get_all_by_host(self.ctxt, 'testhost')
self.assertEqual(len(backups), 0)
backup_id_keep = self._create_backup_db_entry()
backup_id = self._create_backup_db_entry()
db.backup_destroy(self.ctxt, backup_id)
backups = db.backup_get_all_by_host(self.ctxt, 'testhost')
self.assertEqual(len(backups), 1)
self.assertEqual(backups[0].id, backup_id_keep)
ctxt_read_deleted = context.get_admin_context('yes')
backups = db.backup_get_all_by_host(ctxt_read_deleted, 'testhost')
self.assertEqual(len(backups), 2)

View File

@ -1,208 +0,0 @@
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
# 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.
"""
Tests for Backup swift code.
"""
import bz2
import hashlib
import os
import tempfile
import zlib
from manila.backup.services.swift import SwiftBackupService
from manila import context
from manila import db
from manila import exception
from manila import flags
from manila.openstack.common import log as logging
from manila import test
from manila.tests.backup.fake_swift_client import FakeSwiftClient
from swiftclient import client as swift
FLAGS = flags.FLAGS
LOG = logging.getLogger(__name__)
def fake_md5(arg):
class result(object):
def hexdigest(self):
return 'fake-md5-sum'
ret = result()
return ret
class BackupSwiftTestCase(test.TestCase):
"""Test Case for swift."""
def _create_volume_db_entry(self):
vol = {'id': '1234-5678-1234-8888',
'size': 1,
'status': 'available'}
return db.volume_create(self.ctxt, vol)['id']
def _create_backup_db_entry(self, container='test-container'):
backup = {'id': 123,
'size': 1,
'container': container,
'volume_id': '1234-5678-1234-8888'}
return db.backup_create(self.ctxt, backup)['id']
def setUp(self):
super(BackupSwiftTestCase, self).setUp()
self.ctxt = context.get_admin_context()
self.stubs.Set(swift, 'Connection', FakeSwiftClient.Connection)
self.stubs.Set(hashlib, 'md5', fake_md5)
self._create_volume_db_entry()
self.volume_file = tempfile.NamedTemporaryFile()
for i in xrange(0, 128):
self.volume_file.write(os.urandom(1024))
def tearDown(self):
self.volume_file.close()
super(BackupSwiftTestCase, self).tearDown()
def test_backup_uncompressed(self):
self._create_backup_db_entry()
self.flags(backup_compression_algorithm='none')
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_bz2(self):
self._create_backup_db_entry()
self.flags(backup_compression_algorithm='bz2')
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_zlib(self):
self._create_backup_db_entry()
self.flags(backup_compression_algorithm='zlib')
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_default_container(self):
self._create_backup_db_entry(container=None)
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
backup = db.backup_get(self.ctxt, 123)
self.assertEquals(backup['container'], 'volumebackups')
def test_backup_custom_container(self):
container_name = 'fake99'
self._create_backup_db_entry(container=container_name)
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
backup = db.backup_get(self.ctxt, 123)
self.assertEquals(backup['container'], container_name)
def test_create_backup_container_check_wraps_socket_error(self):
container_name = 'socket_error_on_head'
self._create_backup_db_entry(container=container_name)
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
service.backup,
backup, self.volume_file)
def test_create_backup_put_object_wraps_socket_error(self):
container_name = 'socket_error_on_put'
self._create_backup_db_entry(container=container_name)
service = SwiftBackupService(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
service.backup,
backup, self.volume_file)
def test_restore(self):
self._create_backup_db_entry()
service = SwiftBackupService(self.ctxt)
with tempfile.NamedTemporaryFile() as volume_file:
backup = db.backup_get(self.ctxt, 123)
service.restore(backup, '1234-5678-1234-8888', volume_file)
def test_restore_wraps_socket_error(self):
container_name = 'socket_error_on_get'
self._create_backup_db_entry(container=container_name)
service = SwiftBackupService(self.ctxt)
with tempfile.NamedTemporaryFile() as volume_file:
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
service.restore,
backup, '1234-5678-1234-8888', volume_file)
def test_restore_unsupported_version(self):
container_name = 'unsupported_version'
self._create_backup_db_entry(container=container_name)
service = SwiftBackupService(self.ctxt)
with tempfile.NamedTemporaryFile() as volume_file:
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.InvalidBackup,
service.restore,
backup, '1234-5678-1234-8888', volume_file)
def test_delete(self):
self._create_backup_db_entry()
service = SwiftBackupService(self.ctxt)
backup = db.backup_get(self.ctxt, 123)
service.delete(backup)
def test_delete_wraps_socket_error(self):
container_name = 'socket_error_on_delete'
self._create_backup_db_entry(container=container_name)
service = SwiftBackupService(self.ctxt)
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
service.delete,
backup)
def test_get_compressor(self):
service = SwiftBackupService(self.ctxt)
compressor = service._get_compressor('None')
self.assertEquals(compressor, None)
compressor = service._get_compressor('zlib')
self.assertEquals(compressor, zlib)
compressor = service._get_compressor('bz2')
self.assertEquals(compressor, bz2)
self.assertRaises(ValueError, service._get_compressor, 'fake')
def test_check_container_exists(self):
service = SwiftBackupService(self.ctxt)
exists = service._check_container_exists('fake_container')
self.assertEquals(exists, True)
exists = service._check_container_exists('missing_container')
self.assertEquals(exists, False)
self.assertRaises(swift.ClientException,
service._check_container_exists,
'unauthorized_container')

View File

@ -1,268 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
# 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 mox
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers import coraid
from manila.volume.drivers.coraid import CoraidDriver
from manila.volume.drivers.coraid import CoraidESMException
from manila.volume.drivers.coraid import CoraidRESTClient
import cookielib
import urllib2
LOG = logging.getLogger(__name__)
fake_esm_ipaddress = "192.168.0.1"
fake_esm_username = "darmok"
fake_esm_group = "tanagra"
fake_esm_password = "12345678"
fake_volume_name = "volume-12345678-1234-1234-1234-1234567890ab"
fake_volume_size = "10"
fake_repository_name = "A-B:C:D"
fake_pool_name = "FakePool"
fake_aoetarget = 4081
fake_shelf = 16
fake_lun = 241
fake_str_aoetarget = str(fake_aoetarget)
fake_lun_addr = {"shelf": fake_shelf, "lun": fake_lun}
fake_volume = {"name": fake_volume_name,
"size": fake_volume_size,
"volume_type": {"id": 1}}
fake_volume_info = {"pool": fake_pool_name,
"repo": fake_repository_name,
"vsxidx": fake_aoetarget,
"index": fake_lun,
"shelf": fake_shelf}
fake_lun_info = {"shelf": fake_shelf, "lun": fake_lun}
fake_snapshot_name = "snapshot-12345678-8888-8888-1234-1234567890ab"
fake_snapshot_id = "12345678-8888-8888-1234-1234567890ab"
fake_volume_id = "12345678-1234-1234-1234-1234567890ab"
fake_snapshot = {"id": fake_snapshot_id,
"volume_id": fake_volume_id}
fake_configure_data = [{"addr": "cms", "data": "FAKE"}]
fake_esm_fetch = [[
{"command": "super_fake_command_of_death"},
{"reply": [
{"lv":
{"containingPool": fake_pool_name,
"lunIndex": fake_aoetarget,
"name": fake_volume_name,
"lvStatus":
{"exportedLun":
{"lun": fake_lun,
"shelf": fake_shelf}}
},
"repoName": fake_repository_name}]}]]
fake_esm_success = {"category": "provider",
"tracking": False,
"configState": "completedSuccessfully",
"heldPending": False,
"metaCROp": "noAction",
"message": None}
fake_group_fullpath = "admin group:%s" % (fake_esm_group)
fake_group_id = 4
fake_login_reply = {"values": [
{"fullPath": fake_group_fullpath,
"groupId": fake_group_id}],
"message": "",
"state": "adminSucceed",
"metaCROp": "noAction"}
fake_group_fail_fullpath = "fail group:%s" % (fake_esm_group)
fake_group_fail_id = 5
fake_login_reply_group_fail = {"values": [
{"fullPath": fake_group_fail_fullpath,
"groupId": fake_group_fail_id}],
"message": "",
"state": "adminSucceed",
"metaCROp": "noAction"}
class TestCoraidDriver(test.TestCase):
def setUp(self):
super(TestCoraidDriver, self).setUp()
self.esm_mock = self.mox.CreateMockAnything()
self.stubs.Set(coraid, 'CoraidRESTClient',
lambda *_, **__: self.esm_mock)
configuration = mox.MockObject(conf.Configuration)
configuration.append_config_values(mox.IgnoreArg())
configuration.coraid_esm_address = fake_esm_ipaddress
configuration.coraid_user = fake_esm_username
configuration.coraid_group = fake_esm_group
configuration.coraid_password = fake_esm_password
self.drv = CoraidDriver(configuration=configuration)
self.drv.do_setup({})
def test_create_volume(self):
setattr(self.esm_mock, 'create_lun', lambda *_: True)
self.stubs.Set(CoraidDriver, '_get_repository',
lambda *_: fake_repository_name)
self.drv.create_volume(fake_volume)
def test_delete_volume(self):
setattr(self.esm_mock, 'delete_lun',
lambda *_: True)
self.drv.delete_volume(fake_volume)
def test_initialize_connection(self):
setattr(self.esm_mock, '_get_lun_address',
lambda *_: fake_lun_addr)
self.drv.initialize_connection(fake_volume, '')
def test_create_snapshot(self):
setattr(self.esm_mock, 'create_snapshot',
lambda *_: True)
self.drv.create_snapshot(fake_snapshot)
def test_delete_snapshot(self):
setattr(self.esm_mock, 'delete_snapshot',
lambda *_: True)
self.drv.delete_snapshot(fake_snapshot)
def test_create_volume_from_snapshot(self):
setattr(self.esm_mock, 'create_volume_from_snapshot',
lambda *_: True)
self.stubs.Set(CoraidDriver, '_get_repository',
lambda *_: fake_repository_name)
self.drv.create_volume_from_snapshot(fake_volume, fake_snapshot)
class TestCoraidRESTClient(test.TestCase):
def setUp(self):
super(TestCoraidRESTClient, self).setUp()
self.stubs.Set(cookielib, 'CookieJar', lambda *_: True)
self.stubs.Set(urllib2, 'build_opener', lambda *_: True)
self.stubs.Set(urllib2, 'HTTPCookieProcessor', lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_login', lambda *_: True)
self.rest_mock = self.mox.CreateMockAnything()
self.stubs.Set(coraid, 'CoraidRESTClient',
lambda *_, **__: self.rest_mock)
self.drv = CoraidRESTClient(fake_esm_ipaddress,
fake_esm_username,
fake_esm_group,
fake_esm_password)
def test__get_group_id(self):
setattr(self.rest_mock, '_get_group_id',
lambda *_: True)
self.assertEquals(self.drv._get_group_id(fake_esm_group,
fake_login_reply),
fake_group_id)
def test__set_group(self):
setattr(self.rest_mock, '_set_group',
lambda *_: fake_group_id)
self.stubs.Set(CoraidRESTClient, '_admin_esm_cmd',
lambda *_: fake_login_reply)
self.drv._set_group(fake_login_reply)
def test__set_group_fails_no_group(self):
setattr(self.rest_mock, '_set_group',
lambda *_: False)
self.stubs.Set(CoraidRESTClient, '_admin_esm_cmd',
lambda *_: fake_login_reply_group_fail)
self.assertRaises(CoraidESMException,
self.drv._set_group,
fake_login_reply_group_fail)
def test__configure(self):
setattr(self.rest_mock, '_configure',
lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_esm_cmd',
lambda *_: fake_esm_success)
self.drv._configure(fake_configure_data)
def test__get_volume_info(self):
setattr(self.rest_mock, '_get_volume_info',
lambda *_: fake_volume_info)
self.stubs.Set(CoraidRESTClient, '_esm_cmd',
lambda *_: fake_esm_fetch)
self.drv._get_volume_info(fake_volume_name)
def test__get_lun_address(self):
setattr(self.rest_mock, '_get_lun_address',
lambda *_: fake_lun_info)
self.stubs.Set(CoraidRESTClient, '_get_volume_info',
lambda *_: fake_volume_info)
self.drv._get_lun_address(fake_volume_name)
def test_create_lun(self):
setattr(self.rest_mock, 'create_lun',
lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_configure',
lambda *_: fake_esm_success)
self.rest_mock.create_lun(fake_volume_name, '10',
fake_repository_name)
self.drv.create_lun(fake_volume_name, '10',
fake_repository_name)
def test_delete_lun(self):
setattr(self.rest_mock, 'delete_lun',
lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_get_volume_info',
lambda *_: fake_volume_info)
self.stubs.Set(CoraidRESTClient, '_configure',
lambda *_: fake_esm_success)
self.rest_mock.delete_lun(fake_volume_name)
self.drv.delete_lun(fake_volume_name)
def test_create_snapshot(self):
setattr(self.rest_mock, 'create_snapshot',
lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_get_volume_info',
lambda *_: fake_volume_info)
self.stubs.Set(CoraidRESTClient, '_configure',
lambda *_: fake_esm_success)
self.drv.create_snapshot(fake_volume_name,
fake_volume_name)
def test_delete_snapshot(self):
setattr(self.rest_mock, 'delete_snapshot',
lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_get_volume_info',
lambda *_: fake_volume_info)
self.stubs.Set(CoraidRESTClient, '_configure',
lambda *_: fake_esm_success)
self.drv.delete_snapshot(fake_volume_name)
def test_create_volume_from_snapshot(self):
setattr(self.rest_mock, 'create_volume_from_snapshot',
lambda *_: True)
self.stubs.Set(CoraidRESTClient, '_get_volume_info',
lambda *_: fake_volume_info)
self.stubs.Set(CoraidRESTClient, '_configure',
lambda *_: fake_esm_success)
self.drv.create_volume_from_snapshot(fake_volume_name,
fake_volume_name,
fake_repository_name)

View File

@ -1,184 +0,0 @@
# Copyright 2012 OpenStack LLC
#
# 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 manila import context
from manila import flags
from manila.openstack.common import importutils
from manila import test
from manila.volume.drivers.solidfire import SolidFire
FLAGS = flags.FLAGS
RBD_MODULE = "manila.volume.drivers.rbd.RBDDriver"
SHEEPDOG_MODULE = "manila.volume.drivers.sheepdog.SheepdogDriver"
NEXENTA_MODULE = "manila.volume.drivers.nexenta.volume.NexentaDriver"
SAN_MODULE = "manila.volume.drivers.san.san.SanISCSIDriver"
SOLARIS_MODULE = "manila.volume.drivers.san.solaris.SolarisISCSIDriver"
LEFTHAND_MODULE = "manila.volume.drivers.san.hp_lefthand.HpSanISCSIDriver"
NETAPP_MODULE = "manila.volume.drivers.netapp.iscsi.NetAppISCSIDriver"
NETAPP_CMODE_MODULE =\
"manila.volume.drivers.netapp.iscsi.NetAppCmodeISCSIDriver"
NETAPP_NFS_MODULE = "manila.volume.drivers.netapp.nfs.NetAppNFSDriver"
NFS_MODULE = "manila.volume.drivers.nfs.NfsDriver"
SOLIDFIRE_MODULE = "manila.volume.drivers.solidfire.SolidFire"
STORWIZE_SVC_MODULE = "manila.volume.drivers.storwize_svc.StorwizeSVCDriver"
WINDOWS_MODULE = "manila.volume.drivers.windows.WindowsDriver"
XIV_MODULE = "manila.volume.drivers.xiv.XIVDriver"
ZADARA_MODULE = "manila.volume.drivers.zadara.ZadaraVPSAISCSIDriver"
class VolumeDriverCompatibility(test.TestCase):
"""Test backwards compatibility for volume drivers."""
def fake_update_cluster_status(self):
return
def setUp(self):
super(VolumeDriverCompatibility, self).setUp()
self.manager = importutils.import_object(FLAGS.volume_manager)
self.context = context.get_admin_context()
def tearDown(self):
super(VolumeDriverCompatibility, self).tearDown()
def _load_driver(self, driver):
if 'SolidFire' in driver:
# SolidFire driver does update_cluster stat on init
self.stubs.Set(SolidFire, '_update_cluster_status',
self.fake_update_cluster_status)
self.manager.__init__(volume_driver=driver)
def _driver_module_name(self):
return "%s.%s" % (self.manager.driver.__class__.__module__,
self.manager.driver.__class__.__name__)
def test_rbd_old(self):
self._load_driver('manila.volume.driver.RBDDriver')
self.assertEquals(self._driver_module_name(), RBD_MODULE)
def test_rbd_new(self):
self._load_driver(RBD_MODULE)
self.assertEquals(self._driver_module_name(), RBD_MODULE)
def test_sheepdog_old(self):
self._load_driver('manila.volume.driver.SheepdogDriver')
self.assertEquals(self._driver_module_name(), SHEEPDOG_MODULE)
def test_sheepdog_new(self):
self._load_driver(SHEEPDOG_MODULE)
self.assertEquals(self._driver_module_name(), SHEEPDOG_MODULE)
def test_nexenta_old(self):
self._load_driver('manila.volume.nexenta.volume.NexentaDriver')
self.assertEquals(self._driver_module_name(), NEXENTA_MODULE)
def test_nexenta_new(self):
self._load_driver(NEXENTA_MODULE)
self.assertEquals(self._driver_module_name(), NEXENTA_MODULE)
def test_san_old(self):
self._load_driver('manila.volume.san.SanISCSIDriver')
self.assertEquals(self._driver_module_name(), SAN_MODULE)
def test_san_new(self):
self._load_driver(SAN_MODULE)
self.assertEquals(self._driver_module_name(), SAN_MODULE)
def test_solaris_old(self):
self._load_driver('manila.volume.san.SolarisISCSIDriver')
self.assertEquals(self._driver_module_name(), SOLARIS_MODULE)
def test_solaris_new(self):
self._load_driver(SOLARIS_MODULE)
self.assertEquals(self._driver_module_name(), SOLARIS_MODULE)
def test_hp_lefthand_old(self):
self._load_driver('manila.volume.san.HpSanISCSIDriver')
self.assertEquals(self._driver_module_name(), LEFTHAND_MODULE)
def test_hp_lefthand_new(self):
self._load_driver(LEFTHAND_MODULE)
self.assertEquals(self._driver_module_name(), LEFTHAND_MODULE)
def test_netapp_old(self):
self._load_driver('manila.volume.netapp.NetAppISCSIDriver')
self.assertEquals(self._driver_module_name(), NETAPP_MODULE)
def test_netapp_new(self):
self._load_driver(NETAPP_MODULE)
self.assertEquals(self._driver_module_name(), NETAPP_MODULE)
def test_netapp_cmode_old(self):
self._load_driver('manila.volume.netapp.NetAppCmodeISCSIDriver')
self.assertEquals(self._driver_module_name(), NETAPP_CMODE_MODULE)
def test_netapp_cmode_new(self):
self._load_driver(NETAPP_CMODE_MODULE)
self.assertEquals(self._driver_module_name(), NETAPP_CMODE_MODULE)
def test_netapp_nfs_old(self):
self._load_driver('manila.volume.netapp_nfs.NetAppNFSDriver')
self.assertEquals(self._driver_module_name(), NETAPP_NFS_MODULE)
def test_netapp_nfs_new(self):
self._load_driver(NETAPP_NFS_MODULE)
self.assertEquals(self._driver_module_name(), NETAPP_NFS_MODULE)
def test_nfs_old(self):
self._load_driver('manila.volume.nfs.NfsDriver')
self.assertEquals(self._driver_module_name(), NFS_MODULE)
def test_nfs_new(self):
self._load_driver(NFS_MODULE)
self.assertEquals(self._driver_module_name(), NFS_MODULE)
def test_solidfire_old(self):
self._load_driver('manila.volume.solidfire.SolidFire')
self.assertEquals(self._driver_module_name(), SOLIDFIRE_MODULE)
def test_solidfire_new(self):
self._load_driver(SOLIDFIRE_MODULE)
self.assertEquals(self._driver_module_name(), SOLIDFIRE_MODULE)
def test_storwize_svc_old(self):
self._load_driver('manila.volume.storwize_svc.StorwizeSVCDriver')
self.assertEquals(self._driver_module_name(), STORWIZE_SVC_MODULE)
def test_storwize_svc_new(self):
self._load_driver(STORWIZE_SVC_MODULE)
self.assertEquals(self._driver_module_name(), STORWIZE_SVC_MODULE)
def test_windows_old(self):
self._load_driver('manila.volume.windows.WindowsDriver')
self.assertEquals(self._driver_module_name(), WINDOWS_MODULE)
def test_windows_new(self):
self._load_driver(WINDOWS_MODULE)
self.assertEquals(self._driver_module_name(), WINDOWS_MODULE)
def test_xiv_old(self):
self._load_driver('manila.volume.xiv.XIVDriver')
self.assertEquals(self._driver_module_name(), XIV_MODULE)
def test_xiv_new(self):
self._load_driver(XIV_MODULE)
self.assertEquals(self._driver_module_name(), XIV_MODULE)
def test_zadara_old(self):
self._load_driver('manila.volume.zadara.ZadaraVPSAISCSIDriver')
self.assertEquals(self._driver_module_name(), ZADARA_MODULE)
def test_zadara_new(self):
self._load_driver(ZADARA_MODULE)
self.assertEquals(self._driver_module_name(), ZADARA_MODULE)

View File

@ -1,766 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 EMC Corporation, Inc.
# Copyright (c) 2012 OpenStack LLC.
# 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 mox
import os
import shutil
import tempfile
from xml.dom.minidom import Document
from manila import exception
from manila import flags
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers.emc.emc_smis_common import EMCSMISCommon
from manila.volume.drivers.emc.emc_smis_iscsi import EMCSMISISCSIDriver
MANILA_EMC_CONFIG_FILE = '/etc/manila/manila_emc_config.xml'
LOG = logging.getLogger(__name__)
config_file_name = 'manila_emc_config.xml'
storage_system = 'CLARiiON+APM00123456789'
storage_system_vmax = 'SYMMETRIX+000195900551'
lunmaskctrl_id = 'CLARiiON+APM00123456789+00aa11bb22cc33dd44ff55gg66hh77ii88jj'
initiator1 = 'iqn.1993-08.org.debian:01:1a2b3c4d5f6g'
stconf_service_creationclass = 'Clar_StorageConfigurationService'
ctrlconf_service_creationclass = 'Clar_ControllerConfigurationService'
rep_service_creationclass = 'Clar_ReplicationService'
vol_creationclass = 'Clar_StorageVolume'
pool_creationclass = 'Clar_UnifiedStoragePool'
lunmask_creationclass = 'Clar_LunMaskingSCSIProtocolController'
unit_creationclass = 'CIM_ProtocolControllerForUnit'
storage_type = 'gold'
test_volume = {'name': 'vol1',
'size': 1,
'volume_name': 'vol1',
'id': '1',
'provider_auth': None,
'project_id': 'project',
'display_name': 'vol1',
'display_description': 'test volume',
'volume_type_id': None}
test_failed_volume = {'name': 'failed_vol',
'size': 1,
'volume_name': 'failed_vol',
'id': '4',
'provider_auth': None,
'project_id': 'project',
'display_name': 'failed_vol',
'display_description': 'test failed volume',
'volume_type_id': None}
test_snapshot = {'name': 'snapshot1',
'size': 1,
'id': '4444',
'volume_name': 'vol1',
'volume_size': 1,
'project_id': 'project'}
test_clone = {'name': 'clone1',
'size': 1,
'volume_name': 'vol1',
'id': '2',
'provider_auth': None,
'project_id': 'project',
'display_name': 'clone1',
'display_description': 'volume created from snapshot',
'volume_type_id': None}
test_clone3 = {'name': 'clone3',
'size': 1,
'volume_name': 'vol1',
'id': '3',
'provider_auth': None,
'project_id': 'project',
'display_name': 'clone3',
'display_description': 'cloned volume',
'volume_type_id': None}
test_snapshot_vmax = {'name': 'snapshot_vmax',
'size': 1,
'id': '4445',
'volume_name': 'vol1',
'volume_size': 1,
'project_id': 'project'}
failed_snapshot_replica = {'name': 'failed_snapshot_replica',
'size': 1,
'volume_name': 'vol1',
'id': '5',
'provider_auth': None,
'project_id': 'project',
'display_name': 'vol1',
'display_description': 'failed snapshot replica',
'volume_type_id': None}
failed_snapshot_sync = {'name': 'failed_snapshot_sync',
'size': 1,
'volume_name': 'vol1',
'id': '6',
'provider_auth': None,
'project_id': 'project',
'display_name': 'failed_snapshot_sync',
'display_description': 'failed snapshot sync',
'volume_type_id': None}
failed_clone_replica = {'name': 'failed_clone_replica',
'size': 1,
'volume_name': 'vol1',
'id': '7',
'provider_auth': None,
'project_id': 'project',
'display_name': 'vol1',
'display_description': 'failed clone replica',
'volume_type_id': None}
failed_clone_sync = {'name': 'failed_clone_sync',
'size': 1,
'volume_name': 'vol1',
'id': '8',
'provider_auth': None,
'project_id': 'project',
'display_name': 'vol1',
'display_description': 'failed clone sync',
'volume_type_id': None}
failed_delete_vol = {'name': 'failed_delete_vol',
'size': 1,
'volume_name': 'failed_delete_vol',
'id': '99999',
'provider_auth': None,
'project_id': 'project',
'display_name': 'failed delete vol',
'display_description': 'failed delete volume',
'volume_type_id': None}
class EMC_StorageVolume(dict):
pass
class SE_ConcreteJob(dict):
pass
class FakeEcomConnection():
def InvokeMethod(self, MethodName, Service, ElementName=None, InPool=None,
ElementType=None, Size=None,
SyncType=None, SourceElement=None,
Operation=None, Synchronization=None,
TheElements=None,
LUNames=None, InitiatorPortIDs=None, DeviceAccesses=None,
ProtocolControllers=None,
MaskingGroup=None, Members=None):
rc = 0L
myjob = SE_ConcreteJob()
myjob.classname = 'SE_ConcreteJob'
myjob['InstanceID'] = '9999'
myjob['status'] = 'success'
if ElementName == 'failed_vol' and \
MethodName == 'CreateOrModifyElementFromStoragePool':
rc = 10L
myjob['status'] = 'failure'
elif ElementName == 'failed_snapshot_replica' and \
MethodName == 'CreateElementReplica':
rc = 10L
myjob['status'] = 'failure'
elif Synchronization and \
Synchronization['SyncedElement']['ElementName'] \
== 'failed_snapshot_sync' and \
MethodName == 'ModifyReplicaSynchronization':
rc = 10L
myjob['status'] = 'failure'
elif ElementName == 'failed_clone_replica' and \
MethodName == 'CreateElementReplica':
rc = 10L
myjob['status'] = 'failure'
elif Synchronization and \
Synchronization['SyncedElement']['ElementName'] \
== 'failed_clone_sync' and \
MethodName == 'ModifyReplicaSynchronization':
rc = 10L
myjob['status'] = 'failure'
elif TheElements and \
TheElements[0]['DeviceID'] == '99999' and \
MethodName == 'EMCReturnToStoragePool':
rc = 10L
myjob['status'] = 'failure'
job = {'Job': myjob}
return rc, job
def EnumerateInstanceNames(self, name):
result = None
if name == 'EMC_ReplicationService':
result = self._enum_replicationservices()
elif name == 'EMC_StorageConfigurationService':
result = self._enum_stconfsvcs()
elif name == 'EMC_ControllerConfigurationService':
result = self._enum_ctrlconfsvcs()
elif name == 'EMC_VirtualProvisioningPool':
result = self._enum_pools()
elif name == 'EMC_UnifiedStoragePool':
result = self._enum_pools()
elif name == 'EMC_StorageVolume':
result = self._enum_storagevolumes()
elif name == 'Clar_StorageVolume':
result = self._enum_storagevolumes()
elif name == 'SE_StorageSynchronized_SV_SV':
result = self._enum_syncsvsvs()
elif name == 'CIM_ProtocolControllerForUnit':
result = self._enum_unitnames()
elif name == 'EMC_LunMaskingSCSIProtocolController':
result = self._enum_lunmaskctrls()
elif name == 'EMC_StorageProcessorSystem':
result = self._enum_processors()
else:
result = self._default_enum()
return result
def EnumerateInstances(self, name):
result = None
if name == 'EMC_VirtualProvisioningPool':
result = self._enum_pool_details()
elif name == 'EMC_UnifiedStoragePool':
result = self._enum_pool_details()
else:
result = self._default_enum()
return result
def GetInstance(self, objectpath, LocalOnly=False):
try:
name = objectpath['CreationClassName']
except KeyError:
name = objectpath.classname
result = None
if name == 'Clar_StorageVolume':
result = self._getinstance_storagevolume(objectpath)
elif name == 'CIM_ProtocolControllerForUnit':
result = self._getinstance_unit(objectpath)
elif name == 'Clar_LunMaskingSCSIProtocolController':
result = self._getinstance_lunmask()
elif name == 'SE_ConcreteJob':
result = self._getinstance_job(objectpath)
elif name == 'SE_StorageSynchronized_SV_SV':
result = self._getinstance_syncsvsv(objectpath)
else:
result = self._default_getinstance(objectpath)
return result
def Associators(self, objectpath, resultClass='EMC_StorageHardwareID'):
result = None
if resultClass == 'EMC_StorageHardwareID':
result = self._assoc_hdwid()
elif resultClass == 'EMC_iSCSIProtocolEndpoint':
result = self._assoc_endpoint()
else:
result = self._default_assoc(objectpath)
return result
def AssociatorNames(self, objectpath,
resultClass='EMC_LunMaskingSCSIProtocolController'):
result = None
if resultClass == 'EMC_LunMaskingSCSIProtocolController':
result = self._assocnames_lunmaskctrl()
else:
result = self._default_assocnames(objectpath)
return result
def ReferenceNames(self, objectpath,
ResultClass='CIM_ProtocolControllerForUnit'):
result = None
if ResultClass == 'CIM_ProtocolControllerForUnit':
result = self._ref_unitnames()
else:
result = self._default_ref(objectpath)
return result
def _ref_unitnames(self):
units = []
unit = {}
dependent = {}
dependent['CreationClassName'] = vol_creationclass
dependent['DeviceID'] = test_volume['id']
dependent['ElementName'] = test_volume['name']
dependent['SystemName'] = storage_system
antecedent = {}
antecedent['CreationClassName'] = lunmask_creationclass
antecedent['DeviceID'] = lunmaskctrl_id
antecedent['SystemName'] = storage_system
unit['Dependent'] = dependent
unit['Antecedent'] = antecedent
unit['CreationClassName'] = unit_creationclass
units.append(unit)
return units
def _default_ref(self, objectpath):
return objectpath
def _assoc_hdwid(self):
assocs = []
assoc = {}
assoc['StorageID'] = initiator1
assocs.append(assoc)
return assocs
def _assoc_endpoint(self):
assocs = []
assoc = {}
assoc['Name'] = 'iqn.1992-04.com.emc:cx.apm00123907237.a8,t,0x0001'
assoc['SystemName'] = storage_system + '+SP_A+8'
assocs.append(assoc)
return assocs
def _default_assoc(self, objectpath):
return objectpath
def _assocnames_lunmaskctrl(self):
return self._enum_lunmaskctrls()
def _default_assocnames(self, objectpath):
return objectpath
def _getinstance_storagevolume(self, objectpath):
instance = EMC_StorageVolume()
vols = self._enum_storagevolumes()
for vol in vols:
if vol['DeviceID'] == objectpath['DeviceID']:
instance = vol
break
return instance
def _getinstance_syncsvsv(self, objectpath):
foundsync = None
syncs = self._enum_syncsvsvs()
for sync in syncs:
if (sync['SyncedElement'] == objectpath['SyncedElement'] and
sync['SystemElement'] == objectpath['SystemElement']):
foundsync = sync
break
return foundsync
def _getinstance_lunmask(self):
lunmask = {}
lunmask['CreationClassName'] = lunmask_creationclass
lunmask['DeviceID'] = lunmaskctrl_id
lunmask['SystemName'] = storage_system
return lunmask
def _getinstance_unit(self, objectpath):
unit = {}
dependent = {}
dependent['CreationClassName'] = vol_creationclass
dependent['DeviceID'] = test_volume['id']
dependent['ElementName'] = test_volume['name']
dependent['SystemName'] = storage_system
antecedent = {}
antecedent['CreationClassName'] = lunmask_creationclass
antecedent['DeviceID'] = lunmaskctrl_id
antecedent['SystemName'] = storage_system
unit['Dependent'] = dependent
unit['Antecedent'] = antecedent
unit['CreationClassName'] = unit_creationclass
unit['DeviceNumber'] = '0'
return unit
def _getinstance_job(self, jobpath):
jobinstance = {}
jobinstance['InstanceID'] = '9999'
if jobpath['status'] == 'failure':
jobinstance['JobState'] = 10
jobinstance['ErrorCode'] = 99
jobinstance['ErrorDescription'] = 'Failure'
else:
jobinstance['JobState'] = 7
jobinstance['ErrorCode'] = 0
jobinstance['ErrorDescription'] = ''
return jobinstance
def _default_getinstance(self, objectpath):
return objectpath
def _enum_replicationservices(self):
rep_services = []
rep_service = {}
rep_service['SystemName'] = storage_system
rep_service['CreationClassName'] = rep_service_creationclass
rep_services.append(rep_service)
return rep_services
def _enum_stconfsvcs(self):
conf_services = []
conf_service = {}
conf_service['SystemName'] = storage_system
conf_service['CreationClassName'] = stconf_service_creationclass
conf_services.append(conf_service)
return conf_services
def _enum_ctrlconfsvcs(self):
conf_services = []
conf_service = {}
conf_service['SystemName'] = storage_system
conf_service['CreationClassName'] = ctrlconf_service_creationclass
conf_services.append(conf_service)
return conf_services
def _enum_pools(self):
pools = []
pool = {}
pool['InstanceID'] = storage_system + '+U+' + storage_type
pool['CreationClassName'] = 'Clar_UnifiedStoragePool'
pools.append(pool)
return pools
def _enum_pool_details(self):
pools = []
pool = {}
pool['InstanceID'] = storage_system + '+U+' + storage_type
pool['CreationClassName'] = 'Clar_UnifiedStoragePool'
pool['TotalManagedSpace'] = 12345678
pool['RemainingManagedSpace'] = 123456
pools.append(pool)
return pools
def _enum_storagevolumes(self):
vols = []
vol = EMC_StorageVolume()
vol['CreationClassName'] = 'Clar_StorageVolume'
vol['ElementName'] = test_volume['name']
vol['DeviceID'] = test_volume['id']
vol['SystemName'] = storage_system
vol.path = {'DeviceID': vol['DeviceID']}
vols.append(vol)
snap_vol = EMC_StorageVolume()
snap_vol['CreationClassName'] = 'Clar_StorageVolume'
snap_vol['ElementName'] = test_snapshot['name']
snap_vol['DeviceID'] = test_snapshot['id']
snap_vol['SystemName'] = storage_system
snap_vol.path = {'DeviceID': snap_vol['DeviceID']}
vols.append(snap_vol)
clone_vol = EMC_StorageVolume()
clone_vol['CreationClassName'] = 'Clar_StorageVolume'
clone_vol['ElementName'] = test_clone['name']
clone_vol['DeviceID'] = test_clone['id']
clone_vol['SystemName'] = storage_system
clone_vol.path = {'DeviceID': clone_vol['DeviceID']}
vols.append(clone_vol)
clone_vol3 = EMC_StorageVolume()
clone_vol3['CreationClassName'] = 'Clar_StorageVolume'
clone_vol3['ElementName'] = test_clone3['name']
clone_vol3['DeviceID'] = test_clone3['id']
clone_vol3['SystemName'] = storage_system
clone_vol3.path = {'DeviceID': clone_vol3['DeviceID']}
vols.append(clone_vol3)
snap_vol_vmax = EMC_StorageVolume()
snap_vol_vmax['CreationClassName'] = 'Symm_StorageVolume'
snap_vol_vmax['ElementName'] = test_snapshot_vmax['name']
snap_vol_vmax['DeviceID'] = test_snapshot_vmax['id']
snap_vol_vmax['SystemName'] = storage_system_vmax
snap_vol_vmax.path = {'DeviceID': snap_vol_vmax['DeviceID']}
vols.append(snap_vol_vmax)
failed_snap_replica = EMC_StorageVolume()
failed_snap_replica['CreationClassName'] = 'Clar_StorageVolume'
failed_snap_replica['ElementName'] = failed_snapshot_replica['name']
failed_snap_replica['DeviceID'] = failed_snapshot_replica['id']
failed_snap_replica['SystemName'] = storage_system
failed_snap_replica.path = {
'DeviceID': failed_snap_replica['DeviceID']}
vols.append(failed_snap_replica)
failed_snap_sync = EMC_StorageVolume()
failed_snap_sync['CreationClassName'] = 'Clar_StorageVolume'
failed_snap_sync['ElementName'] = failed_snapshot_sync['name']
failed_snap_sync['DeviceID'] = failed_snapshot_sync['id']
failed_snap_sync['SystemName'] = storage_system
failed_snap_sync.path = {
'DeviceID': failed_snap_sync['DeviceID']}
vols.append(failed_snap_sync)
failed_clone_rep = EMC_StorageVolume()
failed_clone_rep['CreationClassName'] = 'Clar_StorageVolume'
failed_clone_rep['ElementName'] = failed_clone_replica['name']
failed_clone_rep['DeviceID'] = failed_clone_replica['id']
failed_clone_rep['SystemName'] = storage_system
failed_clone_rep.path = {
'DeviceID': failed_clone_rep['DeviceID']}
vols.append(failed_clone_rep)
failed_clone_s = EMC_StorageVolume()
failed_clone_s['CreationClassName'] = 'Clar_StorageVolume'
failed_clone_s['ElementName'] = failed_clone_sync['name']
failed_clone_s['DeviceID'] = failed_clone_sync['id']
failed_clone_s['SystemName'] = storage_system
failed_clone_s.path = {
'DeviceID': failed_clone_s['DeviceID']}
vols.append(failed_clone_s)
failed_delete_vol = EMC_StorageVolume()
failed_delete_vol['CreationClassName'] = 'Clar_StorageVolume'
failed_delete_vol['ElementName'] = 'failed_delete_vol'
failed_delete_vol['DeviceID'] = '99999'
failed_delete_vol['SystemName'] = storage_system
failed_delete_vol.path = {'DeviceID': failed_delete_vol['DeviceID']}
vols.append(failed_delete_vol)
return vols
def _enum_syncsvsvs(self):
syncs = []
vols = self._enum_storagevolumes()
sync = self._create_sync(vols[0], vols[1], 100)
syncs.append(sync)
sync2 = self._create_sync(vols[1], vols[2], 100)
syncs.append(sync2)
sync3 = self._create_sync(vols[0], vols[3], 100)
syncs.append(sync3)
objpath1 = vols[1]
for vol in vols:
if vol['ElementName'] == 'failed_snapshot_sync':
objpath2 = vol
break
sync4 = self._create_sync(objpath1, objpath2, 100)
syncs.append(sync4)
objpath1 = vols[0]
for vol in vols:
if vol['ElementName'] == 'failed_clone_sync':
objpath2 = vol
break
sync5 = self._create_sync(objpath1, objpath2, 100)
syncs.append(sync5)
return syncs
def _create_sync(self, objpath1, objpath2, percentsynced):
sync = {}
sync['SyncedElement'] = objpath2
sync['SystemElement'] = objpath1
sync['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
sync['PercentSynced'] = percentsynced
return sync
def _enum_unitnames(self):
return self._ref_unitnames()
def _enum_lunmaskctrls(self):
ctrls = []
ctrl = {}
ctrl['CreationClassName'] = lunmask_creationclass
ctrl['DeviceID'] = lunmaskctrl_id
ctrl['SystemName'] = storage_system
ctrls.append(ctrl)
return ctrls
def _enum_processors(self):
ctrls = []
ctrl = {}
ctrl['CreationClassName'] = 'Clar_StorageProcessorSystem'
ctrl['Name'] = storage_system + '+SP_A'
ctrls.append(ctrl)
return ctrls
def _default_enum(self):
names = []
name = {}
name['Name'] = 'default'
names.append(name)
return names
class EMCSMISISCSIDriverTestCase(test.TestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
super(EMCSMISISCSIDriverTestCase, self).setUp()
self.config_file_path = None
self.create_fake_config_file()
configuration = mox.MockObject(conf.Configuration)
configuration.manila_emc_config_file = self.config_file_path
configuration.append_config_values(mox.IgnoreArg())
self.stubs.Set(EMCSMISISCSIDriver, '_do_iscsi_discovery',
self.fake_do_iscsi_discovery)
self.stubs.Set(EMCSMISCommon, '_get_ecom_connection',
self.fake_ecom_connection)
driver = EMCSMISISCSIDriver(configuration=configuration)
self.driver = driver
def create_fake_config_file(self):
doc = Document()
emc = doc.createElement("EMC")
doc.appendChild(emc)
storagetype = doc.createElement("StorageType")
storagetypetext = doc.createTextNode("gold")
emc.appendChild(storagetype)
storagetype.appendChild(storagetypetext)
ecomserverip = doc.createElement("EcomServerIp")
ecomserveriptext = doc.createTextNode("1.1.1.1")
emc.appendChild(ecomserverip)
ecomserverip.appendChild(ecomserveriptext)
ecomserverport = doc.createElement("EcomServerPort")
ecomserverporttext = doc.createTextNode("10")
emc.appendChild(ecomserverport)
ecomserverport.appendChild(ecomserverporttext)
ecomusername = doc.createElement("EcomUserName")
ecomusernametext = doc.createTextNode("user")
emc.appendChild(ecomusername)
ecomusername.appendChild(ecomusernametext)
ecompassword = doc.createElement("EcomPassword")
ecompasswordtext = doc.createTextNode("pass")
emc.appendChild(ecompassword)
ecompassword.appendChild(ecompasswordtext)
self.config_file_path = self.tempdir + '/' + config_file_name
f = open(self.config_file_path, 'w')
doc.writexml(f)
f.close()
def fake_ecom_connection(self):
conn = FakeEcomConnection()
return conn
def fake_do_iscsi_discovery(self, volume):
output = []
item = '10.0.0.3:3260,1 iqn.1992-04.com.emc:cx.apm00123907237.a8'
item2 = '10.0.0.4:3260,2 iqn.1992-04.com.emc:cx.apm00123907237.b8'
output.append(item)
output.append(item2)
return output
def test_get_volume_stats(self):
self.driver.get_volume_stats(True)
def test_create_destroy(self):
self.driver.create_volume(test_volume)
self.driver.delete_volume(test_volume)
def test_create_volume_snapshot_destroy(self):
self.driver.create_volume(test_volume)
self.driver.create_snapshot(test_snapshot)
self.driver.create_volume_from_snapshot(
test_clone, test_snapshot)
self.driver.create_cloned_volume(
test_clone3, test_volume)
self.driver.delete_volume(test_clone)
self.driver.delete_volume(test_clone3)
self.driver.delete_snapshot(test_snapshot)
self.driver.delete_volume(test_volume)
def test_map_unmap(self):
self.driver.create_volume(test_volume)
export = self.driver.create_export(None, test_volume)
test_volume['provider_location'] = export['provider_location']
test_volume['EMCCurrentOwningStorageProcessor'] = 'SP_A'
connector = {'initiator': initiator1}
connection_info = self.driver.initialize_connection(test_volume,
connector)
self.driver.terminate_connection(test_volume, connector)
self.driver.remove_export(None, test_volume)
self.driver.delete_volume(test_volume)
def test_create_volume_failed(self):
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume,
test_failed_volume)
def test_create_volume_snapshot_unsupported(self):
self.driver.create_volume(test_volume)
self.driver.create_snapshot(test_snapshot_vmax)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume_from_snapshot,
test_clone,
test_snapshot_vmax)
self.driver.delete_snapshot(test_snapshot_vmax)
self.driver.delete_volume(test_volume)
def test_create_volume_snapshot_replica_failed(self):
self.driver.create_volume(test_volume)
self.driver.create_snapshot(test_snapshot)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume_from_snapshot,
failed_snapshot_replica,
test_snapshot)
self.driver.delete_snapshot(test_snapshot)
self.driver.delete_volume(test_volume)
def test_create_volume_snapshot_sync_failed(self):
self.driver.create_volume(test_volume)
self.driver.create_snapshot(test_snapshot)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume_from_snapshot,
failed_snapshot_sync,
test_snapshot)
self.driver.delete_snapshot(test_snapshot)
self.driver.delete_volume(test_volume)
def test_create_volume_clone_replica_failed(self):
self.driver.create_volume(test_volume)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_cloned_volume,
failed_clone_replica,
test_volume)
self.driver.delete_volume(test_volume)
def test_create_volume_clone_sync_failed(self):
self.driver.create_volume(test_volume)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_cloned_volume,
failed_clone_sync,
test_volume)
self.driver.delete_volume(test_volume)
def test_delete_volume_notfound(self):
notfound_delete_vol = {}
notfound_delete_vol['name'] = 'notfound_delete_vol'
notfound_delete_vol['id'] = '10'
self.driver.delete_volume(notfound_delete_vol)
def test_delete_volume_failed(self):
self.driver.create_volume(failed_delete_vol)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.delete_volume,
failed_delete_vol)
def _cleanup(self):
bExists = os.path.exists(self.config_file_path)
if bExists:
os.remove(self.config_file_path)
shutil.rmtree(self.tempdir)
def tearDown(self):
self._cleanup()
super(EMCSMISISCSIDriverTestCase, self).tearDown()

View File

@ -1,579 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2013 Red Hat, 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 the GlusterFS driver module."""
import __builtin__
import errno
import os
import mox as mox_lib
from mox import IgnoreArg
from mox import IsA
from mox import stubout
from manila import context
from manila import exception
from manila.exception import ProcessExecutionError
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers import glusterfs
class DumbVolume(object):
fields = {}
def __setitem__(self, key, value):
self.fields[key] = value
def __getitem__(self, item):
return self.fields[item]
class GlusterFsDriverTestCase(test.TestCase):
"""Test case for GlusterFS driver."""
TEST_EXPORT1 = 'glusterfs-host1:/export'
TEST_EXPORT2 = 'glusterfs-host2:/export'
TEST_SIZE_IN_GB = 1
TEST_MNT_POINT = '/mnt/glusterfs'
TEST_MNT_POINT_BASE = '/mnt/test'
TEST_LOCAL_PATH = '/mnt/glusterfs/volume-123'
TEST_FILE_NAME = 'test.txt'
TEST_SHARES_CONFIG_FILE = '/etc/manila/test-shares.conf'
ONE_GB_IN_BYTES = 1024 * 1024 * 1024
def setUp(self):
self._mox = mox_lib.Mox()
self._configuration = mox_lib.MockObject(conf.Configuration)
self._configuration.append_config_values(mox_lib.IgnoreArg())
self._configuration.glusterfs_shares_config = \
self.TEST_SHARES_CONFIG_FILE
self._configuration.glusterfs_mount_point_base = \
self.TEST_MNT_POINT_BASE
self._configuration.glusterfs_disk_util = 'df'
self._configuration.glusterfs_sparsed_volumes = True
self.stubs = stubout.StubOutForTesting()
self._driver = glusterfs.GlusterfsDriver(
configuration=self._configuration)
def tearDown(self):
self._mox.UnsetStubs()
self.stubs.UnsetAll()
def stub_out_not_replaying(self, obj, attr_name):
attr_to_replace = getattr(obj, attr_name)
stub = mox_lib.MockObject(attr_to_replace)
self.stubs.Set(obj, attr_name, stub)
def test_local_path(self):
"""local_path common use case."""
glusterfs.FLAGS.glusterfs_mount_point_base = self.TEST_MNT_POINT_BASE
drv = self._driver
volume = DumbVolume()
volume['provider_location'] = self.TEST_EXPORT1
volume['name'] = 'volume-123'
self.assertEqual(
'/mnt/test/ab03ab34eaca46a5fb81878f7e9b91fc/volume-123',
drv.local_path(volume))
def test_mount_glusterfs_should_mount_correctly(self):
"""_mount_glusterfs common case usage."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute('mount', '-t', 'glusterfs', self.TEST_EXPORT1,
self.TEST_MNT_POINT, run_as_root=True)
mox.ReplayAll()
drv._mount_glusterfs(self.TEST_EXPORT1, self.TEST_MNT_POINT)
mox.VerifyAll()
def test_mount_glusterfs_should_suppress_already_mounted_error(self):
"""_mount_glusterfs should suppress already mounted error if
ensure=True
"""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute('mount', '-t', 'glusterfs', self.TEST_EXPORT1,
self.TEST_MNT_POINT, run_as_root=True).\
AndRaise(ProcessExecutionError(
stderr='is busy or already mounted'))
mox.ReplayAll()
drv._mount_glusterfs(self.TEST_EXPORT1, self.TEST_MNT_POINT,
ensure=True)
mox.VerifyAll()
def test_mount_glusterfs_should_reraise_already_mounted_error(self):
"""_mount_glusterfs should not suppress already mounted error
if ensure=False
"""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute(
'mount',
'-t',
'glusterfs',
self.TEST_EXPORT1,
self.TEST_MNT_POINT,
run_as_root=True). \
AndRaise(ProcessExecutionError(stderr='is busy or '
'already mounted'))
mox.ReplayAll()
self.assertRaises(ProcessExecutionError, drv._mount_glusterfs,
self.TEST_EXPORT1, self.TEST_MNT_POINT,
ensure=False)
mox.VerifyAll()
def test_mount_glusterfs_should_create_mountpoint_if_not_yet(self):
"""_mount_glusterfs should create mountpoint if it doesn't exist."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute(*([IgnoreArg()] * 5), run_as_root=IgnoreArg())
mox.ReplayAll()
drv._mount_glusterfs(self.TEST_EXPORT1, self.TEST_MNT_POINT)
mox.VerifyAll()
def test_get_hash_str(self):
"""_get_hash_str should calculation correct value."""
drv = self._driver
self.assertEqual('ab03ab34eaca46a5fb81878f7e9b91fc',
drv._get_hash_str(self.TEST_EXPORT1))
def test_get_mount_point_for_share(self):
"""_get_mount_point_for_share should calculate correct value."""
drv = self._driver
glusterfs.FLAGS.glusterfs_mount_point_base = self.TEST_MNT_POINT_BASE
self.assertEqual('/mnt/test/ab03ab34eaca46a5fb81878f7e9b91fc',
drv._get_mount_point_for_share(
self.TEST_EXPORT1))
def test_get_available_capacity_with_df(self):
"""_get_available_capacity should calculate correct value."""
mox = self._mox
drv = self._driver
df_total_size = 2620544
df_avail = 1490560
df_head = 'Filesystem 1K-blocks Used Available Use% Mounted on\n'
df_data = 'glusterfs-host:/export %d 996864 %d 41%% /mnt' % \
(df_total_size, df_avail)
df_output = df_head + df_data
setattr(glusterfs.FLAGS, 'glusterfs_disk_util', 'df')
mox.StubOutWithMock(drv, '_get_mount_point_for_share')
drv._get_mount_point_for_share(self.TEST_EXPORT1).\
AndReturn(self.TEST_MNT_POINT)
mox.StubOutWithMock(drv, '_execute')
drv._execute('df', '--portability', '--block-size', '1',
self.TEST_MNT_POINT,
run_as_root=True).AndReturn((df_output, None))
mox.ReplayAll()
self.assertEquals((df_avail, df_total_size),
drv._get_available_capacity(
self.TEST_EXPORT1))
mox.VerifyAll()
delattr(glusterfs.FLAGS, 'glusterfs_disk_util')
def test_get_available_capacity_with_du(self):
"""_get_available_capacity should calculate correct value."""
mox = self._mox
drv = self._driver
old_value = self._configuration.glusterfs_disk_util
self._configuration.glusterfs_disk_util = 'du'
df_total_size = 2620544
df_used_size = 996864
df_avail_size = 1490560
df_title = 'Filesystem 1-blocks Used Available Use% Mounted on\n'
df_mnt_data = 'glusterfs-host:/export %d %d %d 41%% /mnt' % \
(df_total_size,
df_used_size,
df_avail_size)
df_output = df_title + df_mnt_data
du_used = 490560
du_output = '%d /mnt' % du_used
mox.StubOutWithMock(drv, '_get_mount_point_for_share')
drv._get_mount_point_for_share(self.TEST_EXPORT1).\
AndReturn(self.TEST_MNT_POINT)
mox.StubOutWithMock(drv, '_execute')
drv._execute('df', '--portability', '--block-size', '1',
self.TEST_MNT_POINT,
run_as_root=True).\
AndReturn((df_output, None))
drv._execute('du', '-sb', '--apparent-size',
'--exclude', '*snapshot*',
self.TEST_MNT_POINT,
run_as_root=True).AndReturn((du_output, None))
mox.ReplayAll()
self.assertEquals((df_total_size - du_used, df_total_size),
drv._get_available_capacity(
self.TEST_EXPORT1))
mox.VerifyAll()
self._configuration.glusterfs_disk_util = old_value
def test_load_shares_config(self):
mox = self._mox
drv = self._driver
glusterfs.FLAGS.glusterfs_shares_config = self.TEST_SHARES_CONFIG_FILE
mox.StubOutWithMock(__builtin__, 'open')
config_data = []
config_data.append(self.TEST_EXPORT1)
config_data.append('#' + self.TEST_EXPORT2)
config_data.append('')
__builtin__.open(self.TEST_SHARES_CONFIG_FILE).AndReturn(config_data)
mox.ReplayAll()
shares = drv._load_shares_config()
self.assertEqual([self.TEST_EXPORT1], shares)
mox.VerifyAll()
def test_ensure_share_mounted(self):
"""_ensure_share_mounted simple use case."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_get_mount_point_for_share')
drv._get_mount_point_for_share(self.TEST_EXPORT1).\
AndReturn(self.TEST_MNT_POINT)
mox.StubOutWithMock(drv, '_mount_glusterfs')
drv._mount_glusterfs(self.TEST_EXPORT1, self.TEST_MNT_POINT,
ensure=True)
mox.ReplayAll()
drv._ensure_share_mounted(self.TEST_EXPORT1)
mox.VerifyAll()
def test_ensure_shares_mounted_should_save_mounting_successfully(self):
"""_ensure_shares_mounted should save share if mounted with success."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_load_shares_config')
drv._load_shares_config().AndReturn([self.TEST_EXPORT1])
mox.StubOutWithMock(drv, '_ensure_share_mounted')
drv._ensure_share_mounted(self.TEST_EXPORT1)
mox.ReplayAll()
drv._ensure_shares_mounted()
self.assertEqual(1, len(drv._mounted_shares))
self.assertEqual(self.TEST_EXPORT1, drv._mounted_shares[0])
mox.VerifyAll()
def test_ensure_shares_mounted_should_not_save_mounting_with_error(self):
"""_ensure_shares_mounted should not save share if failed to mount."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_load_shares_config')
drv._load_shares_config().AndReturn([self.TEST_EXPORT1])
mox.StubOutWithMock(drv, '_ensure_share_mounted')
drv._ensure_share_mounted(self.TEST_EXPORT1).AndRaise(Exception())
mox.ReplayAll()
drv._ensure_shares_mounted()
self.assertEqual(0, len(drv._mounted_shares))
mox.VerifyAll()
def test_setup_should_throw_error_if_shares_config_not_configured(self):
"""do_setup should throw error if shares config is not configured."""
drv = self._driver
glusterfs.FLAGS.glusterfs_shares_config = self.TEST_SHARES_CONFIG_FILE
self.assertRaises(exception.GlusterfsException,
drv.do_setup, IsA(context.RequestContext))
def test_setup_should_throw_exception_if_client_is_not_installed(self):
"""do_setup should throw exception if client is not installed."""
mox = self._mox
drv = self._driver
glusterfs.FLAGS.glusterfs_shares_config = self.TEST_SHARES_CONFIG_FILE
mox.StubOutWithMock(os.path, 'exists')
os.path.exists(self.TEST_SHARES_CONFIG_FILE).AndReturn(True)
mox.StubOutWithMock(drv, '_execute')
drv._execute('mount.glusterfs', check_exit_code=False).\
AndRaise(OSError(errno.ENOENT, 'No such file or directory'))
mox.ReplayAll()
self.assertRaises(exception.GlusterfsException,
drv.do_setup, IsA(context.RequestContext))
mox.VerifyAll()
def test_find_share_should_throw_error_if_there_is_no_mounted_shares(self):
"""_find_share should throw error if there is no mounted shares."""
drv = self._driver
drv._mounted_shares = []
self.assertRaises(exception.NotFound, drv._find_share,
self.TEST_SIZE_IN_GB)
def test_find_share(self):
"""_find_share simple use case."""
mox = self._mox
drv = self._driver
drv._mounted_shares = [self.TEST_EXPORT1, self.TEST_EXPORT2]
mox.StubOutWithMock(drv, '_get_available_capacity')
drv._get_available_capacity(self.TEST_EXPORT1).\
AndReturn((2 * self.ONE_GB_IN_BYTES, 5 * self.ONE_GB_IN_BYTES))
drv._get_available_capacity(self.TEST_EXPORT2).\
AndReturn((3 * self.ONE_GB_IN_BYTES, 10 * self.ONE_GB_IN_BYTES))
mox.ReplayAll()
self.assertEqual(self.TEST_EXPORT2,
drv._find_share(self.TEST_SIZE_IN_GB))
mox.VerifyAll()
def test_find_share_should_throw_error_if_there_is_no_enough_place(self):
"""_find_share should throw error if there is no share to host vol."""
mox = self._mox
drv = self._driver
drv._mounted_shares = [self.TEST_EXPORT1,
self.TEST_EXPORT2]
mox.StubOutWithMock(drv, '_get_available_capacity')
drv._get_available_capacity(self.TEST_EXPORT1).\
AndReturn((0, 5 * self.ONE_GB_IN_BYTES))
drv._get_available_capacity(self.TEST_EXPORT2).\
AndReturn((0, 10 * self.ONE_GB_IN_BYTES))
mox.ReplayAll()
self.assertRaises(exception.GlusterfsNoSuitableShareFound,
drv._find_share,
self.TEST_SIZE_IN_GB)
mox.VerifyAll()
def _simple_volume(self):
volume = DumbVolume()
volume['provider_location'] = '127.0.0.1:/mnt'
volume['name'] = 'volume_name'
volume['size'] = 10
return volume
def test_create_sparsed_volume(self):
mox = self._mox
drv = self._driver
volume = self._simple_volume()
setattr(glusterfs.FLAGS, 'glusterfs_sparsed_volumes', True)
mox.StubOutWithMock(drv, '_create_sparsed_file')
mox.StubOutWithMock(drv, '_set_rw_permissions_for_all')
drv._create_sparsed_file(IgnoreArg(), IgnoreArg())
drv._set_rw_permissions_for_all(IgnoreArg())
mox.ReplayAll()
drv._do_create_volume(volume)
mox.VerifyAll()
delattr(glusterfs.FLAGS, 'glusterfs_sparsed_volumes')
def test_create_nonsparsed_volume(self):
mox = self._mox
drv = self._driver
volume = self._simple_volume()
old_value = self._configuration.glusterfs_sparsed_volumes
self._configuration.glusterfs_sparsed_volumes = False
mox.StubOutWithMock(drv, '_create_regular_file')
mox.StubOutWithMock(drv, '_set_rw_permissions_for_all')
drv._create_regular_file(IgnoreArg(), IgnoreArg())
drv._set_rw_permissions_for_all(IgnoreArg())
mox.ReplayAll()
drv._do_create_volume(volume)
mox.VerifyAll()
self._configuration.glusterfs_sparsed_volumes = old_value
def test_create_volume_should_ensure_glusterfs_mounted(self):
"""create_volume ensures shares provided in config are mounted."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(glusterfs, 'LOG')
self.stub_out_not_replaying(drv, '_find_share')
self.stub_out_not_replaying(drv, '_do_create_volume')
mox.StubOutWithMock(drv, '_ensure_shares_mounted')
drv._ensure_shares_mounted()
mox.ReplayAll()
volume = DumbVolume()
volume['size'] = self.TEST_SIZE_IN_GB
drv.create_volume(volume)
mox.VerifyAll()
def test_create_volume_should_return_provider_location(self):
"""create_volume should return provider_location with found share."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(glusterfs, 'LOG')
self.stub_out_not_replaying(drv, '_ensure_shares_mounted')
self.stub_out_not_replaying(drv, '_do_create_volume')
mox.StubOutWithMock(drv, '_find_share')
drv._find_share(self.TEST_SIZE_IN_GB).AndReturn(self.TEST_EXPORT1)
mox.ReplayAll()
volume = DumbVolume()
volume['size'] = self.TEST_SIZE_IN_GB
result = drv.create_volume(volume)
self.assertEqual(self.TEST_EXPORT1, result['provider_location'])
mox.VerifyAll()
def test_delete_volume(self):
"""delete_volume simple test case."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(drv, '_ensure_share_mounted')
volume = DumbVolume()
volume['name'] = 'volume-123'
volume['provider_location'] = self.TEST_EXPORT1
mox.StubOutWithMock(drv, 'local_path')
drv.local_path(volume).AndReturn(self.TEST_LOCAL_PATH)
mox.StubOutWithMock(drv, '_execute')
drv._execute('rm', '-f', self.TEST_LOCAL_PATH, run_as_root=True)
mox.ReplayAll()
drv.delete_volume(volume)
mox.VerifyAll()
def test_delete_should_ensure_share_mounted(self):
"""delete_volume should ensure that corresponding share is mounted."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(drv, '_execute')
volume = DumbVolume()
volume['name'] = 'volume-123'
volume['provider_location'] = self.TEST_EXPORT1
mox.StubOutWithMock(drv, '_ensure_share_mounted')
drv._ensure_share_mounted(self.TEST_EXPORT1)
mox.ReplayAll()
drv.delete_volume(volume)
mox.VerifyAll()
def test_delete_should_not_delete_if_provider_location_not_provided(self):
"""delete_volume shouldn't delete if provider_location missed."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(drv, '_ensure_share_mounted')
volume = DumbVolume()
volume['name'] = 'volume-123'
volume['provider_location'] = None
mox.StubOutWithMock(drv, '_execute')
mox.ReplayAll()
drv.delete_volume(volume)
mox.VerifyAll()

File diff suppressed because it is too large Load Diff

View File

@ -1,859 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 Huawei Technologies Co., Ltd.
# Copyright (c) 2012 OpenStack LLC.
# 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.
"""
Tests for HUAWEI volume driver.
"""
import mox
import os
import shutil
import tempfile
from xml.dom.minidom import Document
from xml.etree import ElementTree as ET
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers.huawei import huawei_iscsi
LOG = logging.getLogger(__name__)
LUNInfo = {'ID': None,
'Name': None,
'Size': None,
'LUN WWN': None,
'Status': None,
'Visible Capacity': None,
'Stripe Unit Size': None,
'Disk Pool ID': None,
'Format Progress': None,
'Cache Prefetch Strategy': None,
'LUNType': None,
'Cache Write Strategy': None,
'Running Cache Write Strategy': None,
'Consumed Capacity': None,
'Pool ID': None,
'SnapShot ID': None,
'LunCopy ID': None,
'Whether Private LUN': None,
'Remote Replication ID': None,
'Split mirror ID': None,
'Owner Controller': None,
'Worker Controller': None,
'RAID Group ID': None}
LUNInfoCopy = {'ID': None,
'Name': None,
'Size': None,
'LUN WWN': None,
'Status': None,
'Visible Capacity': None,
'Stripe Unit Size': None,
'Disk Pool ID': None,
'Format Progress': None,
'Cache Prefetch Strategy': None,
'LUNType': None,
'Cache Write Strategy': None,
'Running Cache Write Strategy': None,
'Consumed Capacity': None,
'Pool ID': None,
'SnapShot ID': None,
'LunCopy ID': None,
'Whether Private LUN': None,
'Remote Replication ID': None,
'Split mirror ID': None,
'Owner Controller': None,
'Worker Controller': None,
'RAID Group ID': None}
SnapshotInfo = {'Source LUN ID': None,
'Source LUN Name': None,
'ID': None,
'Name': None,
'Type': 'Public',
'Status': None,
'Time Stamp': '2013-01-15 14:00:00',
'Rollback Start Time': '--',
'Rollback End Time': '--',
'Rollback Speed': '--',
'Rollback Progress': '--'}
MapInfo = {'Host Group ID': None,
'Host Group Name': None,
'File Engine Cluster': None,
'Host ID': None,
'Host Name': None,
'Os Type': None,
'INI Port ID': None,
'INI Port Name': None,
'INI Port Info': None,
'Port Type': None,
'Link Status': None,
'LUN WWN': None,
'DEV LUN ID': None,
'Host LUN ID': None}
HostPort = {'ID': None,
'Name': None,
'Info': None}
LUNCopy = {'Name': None,
'ID': None,
'Type': None,
'State': None,
'Status': 'Disable'}
FakeVolume = {'name': 'Volume-lele34fe-223f-dd33-4423-asdfghjklqwe',
'size': '2',
'id': '0',
'wwn': '630303710030303701094b2b00000031',
'provider_auth': None}
FakeVolumeCopy = {'name': 'Volume-jeje34fe-223f-dd33-4423-asdfghjklqwg',
'size': '3',
'ID': '1',
'wwn': '630303710030303701094b2b0000003'}
FakeLUNCopy = {'ID': '1',
'Type': 'FULL',
'State': 'Created',
'Status': 'Normal'}
FakeSnapshot = {'name': 'keke34fe-223f-dd33-4423-asdfghjklqwf',
'volume_name': 'Volume-lele34fe-223f-dd33-4423-asdfghjklqwe',
'id': '3'}
FakePoolInfo = {'ID': '2',
'Level': 'RAID6',
'Status': 'Normal',
'Free Capacity': '10240',
'Disk List': '0,1;0,2;0,3;0,4;0,5;0,6',
'Name': 'RAID_001',
'Type': 'Thick'}
FakeConfInfo = {'HostGroup': 'HostGroup_OpenStack',
'HostnamePrefix': 'Host_',
'DefaultTargetIP': '192.168.100.1',
'TargetIQN': 'iqn.2006-08.com.huawei:oceanspace:2103037:',
'TargetIQN-T': 'iqn.2006-08.com.huawei:oceanspace:2103037::'
'20001:192.168.100.2',
'TargetIQN-Dorado5100': 'iqn.2006-08.com.huawei:oceanspace:'
'2103037::192.168.100.2',
'TargetIQN-Dorado2100G2': 'iqn.2006-08.com.huawei:oceanspace:'
'2103037::192.168.100.2-20001',
'Initiator Name': 'iqn.1993-08.debian:01:ec2bff7ac3a3',
'Initiator TargetIP': '192.168.100.2'}
FakeConnector = {'initiator': "iqn.1993-08.debian:01:ec2bff7ac3a3"}
class HuaweiVolumeTestCase(test.TestCase):
def __init__(self, *args, **kwargs):
super(HuaweiVolumeTestCase, self).__init__(*args, **kwargs)
self.tmp_dir = tempfile.mkdtemp()
self.fake_conf_file = self.tmp_dir + '/manila_huawei_conf.xml'
self._create_fake_conf_file()
configuration = mox.MockObject(conf.Configuration)
configuration.manila_huawei_conf_file = self.fake_conf_file
configuration.append_config_values(mox.IgnoreArg())
self.driver = FakeHuaweiStorage(configuration=configuration)
self.driver.do_setup({})
def setUp(self):
super(HuaweiVolumeTestCase, self).setUp()
self.driver._test_flg = 'check_for_fail'
self._test_check_for_setup_errors()
def test_create_export_failed(self):
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_export,
{}, FakeVolume)
def test_delete_volume_failed(self):
self._test_delete_volume()
def test_create_snapshot_failed(self):
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_snapshot,
FakeSnapshot)
def test_delete_snapshot_failed(self):
self._test_delete_snapshot()
def test_create_luncopy_failed(self):
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume_from_snapshot,
FakeVolumeCopy, FakeSnapshot)
def test_initialize_failed(self):
self.assertRaises(exception.ShareBackendAPIException,
self.driver.initialize_connection,
FakeVolume, FakeConnector)
def test_terminate_connection_failed(self):
self.assertRaises(exception.ShareBackendAPIException,
self.driver.terminate_connection,
FakeVolume, FakeConnector)
def test_normal(self):
# test for T Series
self.driver._test_flg = 'check_for_T'
self._test_check_for_setup_errors()
self._test_create_volume()
self._test_create_export()
self._test_create_snapshot()
self._test_create_volume_from_snapshot()
self._test_initialize_connection_for_T()
self._test_terminate_connection()
self._test_delete_snapshot()
self._test_delete_volume()
self._test_get_get_volume_stats()
# test for Dorado2100 G2
self.driver._test_flg = 'check_for_Dorado2100G2'
self._test_check_for_setup_errors()
self._test_create_volume()
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_snapshot,
FakeSnapshot)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume_from_snapshot,
FakeVolumeCopy, FakeSnapshot)
self._test_initialize_connection_for_Dorado2100G2()
self._test_terminate_connection()
self.assertRaises(exception.ShareBackendAPIException,
self.driver.delete_snapshot,
FakeSnapshot)
self._test_delete_volume()
# test for Dorado5100
self.driver._test_flg = 'check_for_Dorado5100'
self._test_check_for_setup_errors()
self._test_create_volume()
self._test_create_snapshot()
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume_from_snapshot,
FakeVolumeCopy, FakeSnapshot)
self._test_initialize_connection_for_Dorado5100()
self._test_terminate_connection()
self._test_delete_snapshot()
self._test_delete_volume()
def cleanup(self):
if os.path.exists(self.fake_conf_file):
os.remove(self.fake_conf_file)
shutil.rmtree(self.tmp_dir)
def _create_fake_conf_file(self):
doc = Document()
config = doc.createElement('config')
doc.appendChild(config)
storage = doc.createElement('Storage')
config.appendChild(storage)
controllerip0 = doc.createElement('ControllerIP0')
controllerip0_text = doc.createTextNode('10.10.10.1')
controllerip0.appendChild(controllerip0_text)
storage.appendChild(controllerip0)
controllerip1 = doc.createElement('ControllerIP1')
controllerip1_text = doc.createTextNode('10.10.10.2')
controllerip1.appendChild(controllerip1_text)
storage.appendChild(controllerip1)
username = doc.createElement('UserName')
username_text = doc.createTextNode('admin')
username.appendChild(username_text)
storage.appendChild(username)
userpassword = doc.createElement('UserPassword')
userpassword_text = doc.createTextNode('123456')
userpassword.appendChild(userpassword_text)
storage.appendChild(userpassword)
lun = doc.createElement('LUN')
config.appendChild(lun)
storagepool = doc.createElement('StoragePool')
storagepool.setAttribute('Name', 'RAID_001')
lun.appendChild(storagepool)
storagepool = doc.createElement('StoragePool')
storagepool.setAttribute('Name', 'RAID_002')
lun.appendChild(storagepool)
iscsi = doc.createElement('iSCSI')
config.appendChild(iscsi)
defaulttargetip = doc.createElement('DefaultTargetIP')
defaulttargetip_text = doc.createTextNode('192.168.100.1')
defaulttargetip.appendChild(defaulttargetip_text)
iscsi.appendChild(defaulttargetip)
initiator = doc.createElement('Initiator')
initiator.setAttribute('Name', 'iqn.1993-08.debian:01:ec2bff7ac3a3')
initiator.setAttribute('TargetIP', '192.168.100.2')
iscsi.appendChild(initiator)
file = open(self.fake_conf_file, 'w')
file.write(doc.toprettyxml(indent=''))
file.close()
def _test_check_for_setup_errors(self):
self.driver.check_for_setup_error()
def _test_create_volume(self):
self.driver.create_volume(FakeVolume)
self.assertNotEqual(LUNInfo["ID"], None)
self.assertEqual(LUNInfo["RAID Group ID"], FakePoolInfo['ID'])
def _test_delete_volume(self):
self.driver.delete_volume(FakeVolume)
self.assertEqual(LUNInfo["ID"], None)
def _test_create_snapshot(self):
self.driver.create_snapshot(FakeSnapshot)
self.assertNotEqual(SnapshotInfo["ID"], None)
self.assertNotEqual(LUNInfo["ID"], None)
self.assertEqual(SnapshotInfo["Status"], 'Active')
self.assertEqual(SnapshotInfo["Source LUN ID"], LUNInfo["ID"])
def _test_delete_snapshot(self):
self.driver.delete_snapshot(FakeSnapshot)
self.assertEqual(SnapshotInfo["ID"], None)
def _test_create_volume_from_snapshot(self):
self.driver.create_volume_from_snapshot(FakeVolumeCopy, FakeSnapshot)
self.assertNotEqual(LUNInfoCopy["ID"], None)
def _test_create_export(self):
retval = self.driver.create_export({}, FakeVolume)
self.assertNotEqual(retval, FakeVolume["id"])
def _test_initialize_connection_for_T(self):
connection_data = self.driver.initialize_connection(FakeVolume,
FakeConnector)
iscsi_properties = connection_data['data']
self.assertEquals(iscsi_properties['target_iqn'],
FakeConfInfo['TargetIQN-T'])
self.assertEquals(iscsi_properties['target_portal'],
FakeConfInfo['Initiator TargetIP'] + ':3260')
self.assertEqual(MapInfo["DEV LUN ID"], FakeVolume['id'])
self.assertEqual(MapInfo["INI Port Info"],
FakeConnector['initiator'])
def _test_initialize_connection_for_Dorado2100G2(self):
connection_data = self.driver.initialize_connection(FakeVolume,
FakeConnector)
iscsi_properties = connection_data['data']
self.assertEquals(iscsi_properties['target_iqn'],
FakeConfInfo['TargetIQN-Dorado2100G2'])
self.assertEquals(iscsi_properties['target_portal'],
FakeConfInfo['Initiator TargetIP'] + ':3260')
self.assertEqual(MapInfo["DEV LUN ID"], FakeVolume['id'])
self.assertEqual(MapInfo["INI Port Info"],
FakeConnector['initiator'])
def _test_initialize_connection_for_Dorado5100(self):
connection_data = self.driver.initialize_connection(FakeVolume,
FakeConnector)
iscsi_properties = connection_data['data']
self.assertEquals(iscsi_properties['target_iqn'],
FakeConfInfo['TargetIQN-Dorado5100'])
self.assertEquals(iscsi_properties['target_portal'],
FakeConfInfo['Initiator TargetIP'] + ':3260')
self.assertEqual(MapInfo["DEV LUN ID"], FakeVolume['id'])
self.assertEqual(MapInfo["INI Port Info"],
FakeConnector['initiator'])
def _test_terminate_connection(self):
self.driver.terminate_connection(FakeVolume, FakeConnector)
self.assertEqual(MapInfo["DEV LUN ID"], None)
self.assertEqual(MapInfo["Host LUN ID"], None)
self.assertEqual(MapInfo["INI Port Info"], None)
def _test_get_get_volume_stats(self):
stats = self.driver.get_volume_stats(True)
fakecapacity = float(FakePoolInfo['Free Capacity']) / 1024
self.assertEqual(stats['free_capacity_gb'], fakecapacity)
class FakeHuaweiStorage(huawei_iscsi.HuaweiISCSIDriver):
"""Fake Huawei Storage, Rewrite some methods of HuaweiISCSIDriver."""
def __init__(self, *args, **kwargs):
super(FakeHuaweiStorage, self).__init__(*args, **kwargs)
self._test_flg = None
def _execute_cli(self, cmdIn):
cmd = cmdIn.split(' ')[0].lower()
if cmd == 'showsys':
if ((self._test_flg == 'check_for_fail') or
(self._test_flg == 'check_for_T')):
out = """/>showsys
==========================================================================
System Information
--------------------------------------------------------------------------
System Name | SN_S5500T-xu-0123456789
Device Type | Oceanstor S5500T
Current System Mode | Double Controllers Normal
Mirroring Link Status | Link Up
Location |
Time | 2013-01-01 01:01:01
Product Version | V100R005C00
===========================================================================
"""
elif self._test_flg == 'check_for_Dorado2100G2':
out = """/>showsys
==========================================================================
System Information
--------------------------------------------------------------------------
System Name | SN_Dorado2100_G2
Device Type | Oceanstor Dorado2100 G2
Current System Mode | Double Controllers Normal
Mirroring Link Status | Link Up
Location |
Time | 2013-01-01 01:01:01
Product Version | V100R001C00
===========================================================================
"""
elif self._test_flg == 'check_for_Dorado5100':
out = """/>showsys
==========================================================================
System Information
--------------------------------------------------------------------------
System Name | SN_Dorado5100
Device Type | Oceanstor Dorado5100
Current System Mode | Double Controllers Normal
Mirroring Link Status | Link Up
Location |
Time | 2013-01-01 01:01:01
Product Version | V100R001C00
===========================================================================
"""
elif cmd == 'addhostmap':
MapInfo['DEV LUN ID'] = LUNInfo['ID']
MapInfo['LUN WWN'] = LUNInfo['LUN WWN']
MapInfo['Host LUN ID'] = '0'
out = 'command operates successfully'
elif cmd == 'showhostmap':
if MapInfo['DEV LUN ID'] is None:
out = 'command operates successfully, but no information.'
else:
out = """/>showhostmap
==========================================================================
Map Information
--------------------------------------------------------------------------
Map ID Working Controller Dev LUN ID LUN WWN Host LUN ID Mapped to \
RAID ID Dev LUN Cap(MB) Map Type Whether Command LUN Pool ID
---------------------------------------------------------------------------
2147483649 %s %s %s %s Host: %s %s %s HOST No --
===========================================================================
""" % (LUNInfo['Worker Controller'], LUNInfo['ID'], LUNInfo['LUN WWN'],
MapInfo['Host ID'], MapInfo['Host ID'], LUNInfo['RAID Group ID'],
str(int(LUNInfo['Size']) * 1024))
elif cmd == 'delhostmap':
MapInfo['DEV LUN ID'] = None
MapInfo['LUN WWN'] = None
MapInfo['Host LUN ID'] = None
out = 'command operates successfully'
elif cmd == 'createsnapshot':
SnapshotInfo['Source LUN ID'] = LUNInfo['ID']
SnapshotInfo['Source LUN Name'] = LUNInfo['Name']
SnapshotInfo['ID'] = FakeSnapshot['id']
SnapshotInfo['Name'] = self._name_translate(FakeSnapshot['name'])
SnapshotInfo['Status'] = 'Disable'
out = 'command operates successfully'
elif cmd == 'actvsnapshot':
SnapshotInfo['Status'] = 'Active'
out = 'command operates successfully'
elif cmd == 'disablesnapshot':
SnapshotInfo['Status'] = 'Disable'
out = 'command operates successfully'
elif cmd == 'delsnapshot':
SnapshotInfo['Source LUN ID'] = None
SnapshotInfo['Source LUN Name'] = None
SnapshotInfo['ID'] = None
SnapshotInfo['Name'] = None
SnapshotInfo['Status'] = None
out = 'command operates successfully'
elif cmd == 'showsnapshot':
if SnapshotInfo['ID'] is None:
out = 'command operates successfully, but no information.'
else:
out = """/>showsnapshot
==========================================================================
Snapshot Information
--------------------------------------------------------------------------
Name ID Type Status Time Stamp
--------------------------------------------------------------------------
%s %s Public %s 2013-01-15 14:21:13
==========================================================================
""" % (SnapshotInfo['Name'], SnapshotInfo['ID'], SnapshotInfo['Status'])
elif cmd == 'showlunsnapshot':
if SnapshotInfo['ID'] is None:
out = """Current LUN is not a source LUN"""
else:
out = """/>showlunsnapshot -lun 2
==========================================================================
Snapshot of LUN
--------------------------------------------------------------------------
Name ID Type Status Time Stamp
--------------------------------------------------------------------------
%s %s Public %s 2013-01-15 14:17:19
==========================================================================
""" % (SnapshotInfo['Name'], SnapshotInfo['ID'], SnapshotInfo['Status'])
elif cmd == 'createlun':
if LUNInfo['ID'] is None:
LUNInfo['Name'] = self._name_translate(FakeVolume['name'])
LUNInfo['ID'] = FakeVolume['id']
LUNInfo['Size'] = FakeVolume['size']
LUNInfo['LUN WWN'] = FakeVolume['wwn']
LUNInfo['Owner Controller'] = 'A'
LUNInfo['Worker Controller'] = 'A'
LUNInfo['RAID Group ID'] = FakePoolInfo['ID']
else:
LUNInfoCopy['Name'] = \
self._name_translate(FakeVolumeCopy['name'])
LUNInfoCopy['ID'] = FakeVolumeCopy['ID']
LUNInfoCopy['Size'] = FakeVolumeCopy['size']
LUNInfoCopy['LUN WWN'] = FakeVolumeCopy['wwn']
LUNInfoCopy['Owner Controller'] = 'A'
LUNInfoCopy['Worker Controller'] = 'A'
LUNInfoCopy['RAID Group ID'] = FakePoolInfo['ID']
out = 'command operates successfully'
elif cmd == 'dellun':
LUNInfo['Name'] = None
LUNInfo['ID'] = None
LUNInfo['Size'] = None
LUNInfo['LUN WWN'] = None
LUNInfo['Owner Controller'] = None
LUNInfo['Worker Controller'] = None
LUNInfo['RAID Group ID'] = None
out = 'command operates successfully'
elif cmd == 'showlun':
if LUNInfo['ID'] is None:
out = 'command operates successfully, but no information.'
elif LUNInfoCopy['ID'] is None:
if ((self._test_flg == 'check_for_fail') or
(self._test_flg == 'check_for_T')):
out = """/>showlun
===========================================================================
LUN Information
---------------------------------------------------------------------------
ID RAID Group ID Disk Pool ID Status Controller Visible Capacity(MB) \
LUN Name Stripe Unit Size(KB) Lun Type
---------------------------------------------------------------------------
%s %s -- Normal %s %s %s 64 THICK
===========================================================================
""" % (LUNInfo['ID'], LUNInfo['RAID Group ID'], LUNInfo['Owner Controller'],
str(int(LUNInfo['Size']) * 1024), LUNInfo['Name'])
elif self._test_flg == 'check_for_Dorado2100G2':
out = """/>showlun
===========================================================================
LUN Information
---------------------------------------------------------------------------
ID Status Controller Visible Capacity(MB) LUN Name Lun Type
---------------------------------------------------------------------------
%s Normal %s %s %s THICK
===========================================================================
""" % (LUNInfo['ID'], LUNInfo['Owner Controller'],
str(int(LUNInfo['Size']) * 1024), LUNInfo['Name'])
elif self._test_flg == 'check_for_Dorado5100':
out = """/>showlun
===========================================================================
LUN Information
---------------------------------------------------------------------------
ID RAIDgroup ID Status Controller Visible Capacity(MB) LUN Name
Strip Unit Size(KB) Lun Type
---------------------------------------------------------------------------
%s %s Normal %s %s %s 64 THICK
===========================================================================
""" % (LUNInfo['ID'], LUNInfo['RAID Group ID'],
LUNInfo['Owner Controller'], str(int(LUNInfo['Size']) * 1024),
LUNInfo['Name'])
else:
if ((self._test_flg == 'check_for_fail') or
(self._test_flg == 'check_for_T')):
out = """/>showlun
============================================================================
LUN Information
----------------------------------------------------------------------------
ID RAID Group ID Disk Pool ID Status Controller Visible Capacity(MB)\
LUN Name Stripe Unit Size(KB) Lun Type
----------------------------------------------------------------------------
%s %s -- Normal %s %s %s 64 THICK
%s %s -- Normal %s %s %s 64 THICK
============================================================================
""" % (LUNInfo['ID'], LUNInfo['RAID Group ID'], LUNInfo['Owner Controller'],
str(int(LUNInfo['Size']) * 1024), LUNInfo['Name'], LUNInfoCopy['ID'],
LUNInfoCopy['RAID Group ID'], LUNInfoCopy['Owner Controller'],
str(int(LUNInfoCopy['Size']) * 1024), LUNInfoCopy['Name'])
elif self._test_flg == 'check_for_Dorado2100G2':
out = """/>showlun
===========================================================================
LUN Information
---------------------------------------------------------------------------
ID Status Controller Visible Capacity(MB) LUN Name Lun Type
---------------------------------------------------------------------------
%s Normal %s %s %s THICK
%s Normal %s %s %s THICK
===========================================================================
""" % (LUNInfo['ID'], LUNInfo['Owner Controller'],
str(int(LUNInfo['Size']) * 1024), LUNInfo['Name'],
LUNInfoCopy['ID'], LUNInfoCopy['Owner Controller'],
str(int(LUNInfoCopy['Size']) * 1024), LUNInfoCopy['Name'])
elif self._test_flg == 'check_for_Dorado5100':
out = """/>showlun
===========================================================================
LUN Information
---------------------------------------------------------------------------
ID RAIDgroup ID Status Controller Visible Capacity(MB) LUN Name \
Strip Unit Size(KB) Lun Type
---------------------------------------------------------------------------
%s %s Normal %s %s %s 64 THICK
%s %s Norma %s %s %s 64 THICK
===========================================================================
""" % (LUNInfo['ID'], LUNInfo['RAID Group ID'], LUNInfo['Owner Controller'],
str(int(LUNInfo['Size']) * 1024), LUNInfo['Name'],
LUNInfoCopy['ID'], LUNInfoCopy['RAID Group ID'],
LUNInfoCopy['Owner Controller'], str(int(LUNInfoCopy['Size']) * 1024),
LUNInfoCopy['Name'])
elif cmd == 'createhostgroup':
MapInfo['Host Group ID'] = '1'
MapInfo['Host Group Name'] = FakeConfInfo['HostGroup']
out = 'command operates successfully'
elif cmd == 'showhostgroup':
if MapInfo['Host Group ID'] is None:
out = """/>showhostgroup
============================================================
Host Group Information
------------------------------------------------------------
Host Group ID Name File Engine Cluster
------------------------------------------------------------
0 Default Group NO
============================================================
"""
else:
out = """/>showhostgroup
============================================================
Host Group Information
------------------------------------------------------------
Host Group ID Name File Engine Cluster
------------------------------------------------------------
0 Default Group NO
%s %s NO
============================================================
""" % (MapInfo['Host Group ID'], MapInfo['Host Group Name'])
elif cmd == 'addhost':
MapInfo['Host ID'] = '1'
MapInfo['Host Name'] = FakeConfInfo['HostnamePrefix'] + \
str(hash(FakeConnector['initiator']))
MapInfo['Os Type'] = 'Linux'
out = 'command operates successfully'
elif cmd == 'delhost':
MapInfo['Host ID'] = None
MapInfo['Host Name'] = None
MapInfo['Os Type'] = None
out = 'command operates successfully'
elif cmd == 'showhost':
if MapInfo['Host ID'] is None:
out = 'command operates successfully, but no information.'
else:
out = """/>showhost
=======================================================
Host Information
-------------------------------------------------------
Host ID Host Name Host Group ID Os Type
-------------------------------------------------------
%s %s %s Linux
=======================================================
""" % (MapInfo['Host ID'], MapInfo['Host Name'], MapInfo['Host Group ID'])
elif cmd == 'createluncopy':
LUNCopy['Name'] = LUNInfoCopy['Name']
LUNCopy['ID'] = FakeLUNCopy['ID']
LUNCopy['Type'] = FakeLUNCopy['Type']
LUNCopy['State'] = FakeLUNCopy['State']
LUNCopy['Status'] = FakeLUNCopy['Status']
out = 'command operates successfully'
elif cmd == 'delluncopy':
LUNCopy['Name'] = None
LUNCopy['ID'] = None
LUNCopy['Type'] = None
LUNCopy['State'] = None
LUNCopy['Status'] = None
out = 'command operates successfully'
elif cmd == 'chgluncopystatus':
LUNCopy['State'] = 'Complete'
out = 'command operates successfully'
elif cmd == 'showluncopy':
if LUNCopy['ID'] is None:
out = 'command operates successfully, but no information.'
else:
out = """/>showluncopy
============================================================================
LUN Copy Information
----------------------------------------------------------------------------
LUN Copy Name LUN Copy ID Type LUN Copy State LUN Copy Status
----------------------------------------------------------------------------
%s %s %s %s %s
============================================================================
""" % (LUNCopy['Name'], LUNCopy['ID'], LUNCopy['Type'],
LUNCopy['State'], LUNCopy['Status'])
elif cmd == 'showiscsitgtname':
if ((self._test_flg == 'check_for_fail') or
(self._test_flg == 'check_for_T')):
out = """/>showiscsitgtname
============================================================================
ISCSI Name
----------------------------------------------------------------------------
Iscsi Name | %s
============================================================================
""" % FakeConfInfo['TargetIQN']
elif (self._test_flg == 'check_for_Dorado2100G2' or
self._test_flg == 'check_for_Dorado5100'):
out = """/>showiscsitgtname
============================================================================
ISCSI Name
----------------------------------------------------------------------------
Iscsi Name | %s
============================================================================
""" % FakeConfInfo['TargetIQN']
elif cmd == 'showiscsiip':
out = """/>showiscsiip
============================================================================
iSCSI IP Information
----------------------------------------------------------------------------
Controller ID Interface Module ID Port ID IP Address Mask
----------------------------------------------------------------------------
A 0 P1 %s 255.255.255.0
============================================================================
""" % FakeConfInfo['Initiator TargetIP']
elif cmd == 'addhostport':
MapInfo['INI Port ID'] = HostPort['ID']
MapInfo['INI Port Name'] = HostPort['Name']
MapInfo['INI Port Info'] = HostPort['Info']
out = 'command operates successfully'
elif cmd == 'delhostport':
MapInfo['INI Port ID'] = None
MapInfo['INI Port Name'] = None
MapInfo['INI Port Info'] = None
out = 'command operates successfully'
elif cmd == 'showhostport':
if MapInfo['INI Port ID'] is None:
out = 'command operates successfully, but no information.'
else:
out = """/>showhostport -host 3
==============================================================================
Host Port Information
------------------------------------------------------------------------------
Port ID Port Name Port Information Port Type Host ID \
Link Status Multipath Type
------------------------------------------------------------------------------
%s %s %s ISCSITGT %s Unconnected Default
==============================================================================
""" % (MapInfo['INI Port ID'], MapInfo['INI Port Name'],
MapInfo['INI Port Info'], MapInfo['Host ID'])
elif cmd == 'addiscsiini':
HostPort['ID'] = '1'
HostPort['Name'] = 'iSCSIInitiator001'
HostPort['Info'] = FakeConfInfo['Initiator Name']
out = 'command operates successfully'
elif cmd == 'deliscsiini':
HostPort['ID'] = None
HostPort['Name'] = None
HostPort['Info'] = None
out = 'command operates successfully'
elif cmd == 'showiscsiini':
if HostPort['ID'] is None:
out = 'Error: The parameter is wrong.'
else:
out = """/>showiscsiini -ini iqn.1993-08.org\
.debian:01:503629a9d3f
========================================================
Initiator Information
--------------------------------------------------------
Initiator Name Chap Status
--------------------------------------------------------
%s Disable
========================================================
""" % (HostPort['Info'])
elif cmd == 'showrg':
out = """/>showrg
=====================================================================
RAID Group Information
---------------------------------------------------------------------
ID Level Status Free Capacity(MB) Disk List Name
---------------------------------------------------------------------
0 RAID6 Normal 1024 0,0;0,2;0,4;0,5;0,6;0,7; RAID003
%s %s %s %s %s %s
=====================================================================
""" % (FakePoolInfo['ID'], FakePoolInfo['Level'],
FakePoolInfo['Status'], FakePoolInfo['Free Capacity'],
FakePoolInfo['Disk List'], FakePoolInfo['Name'])
elif cmd == 'showrespool':
out = """/>showrespool
============================================================================
Resource Pool Information
----------------------------------------------------------------------------
Pool ID Size(MB) Usage(MB) Valid Size(MB) Alarm Threshold(%)
----------------------------------------------------------------------------
A 5130.0 0.0 5130.0 80
B 3082.0 0.0 3082.0 80
============================================================================
"""
elif cmd == 'chglun':
out = 'command operates successfully'
out = out.replace('\n', '\r\n')
return out
def _get_lun_controller(self, lunid):
pass

View File

@ -1,190 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Red Hat, Inc.
#
# 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 os.path
import shutil
import string
import tempfile
from manila.brick.iscsi import iscsi
from manila import test
from manila.volume import utils as volume_utils
class TargetAdminTestCase(object):
def setUp(self):
self.cmds = []
self.tid = 1
self.target_name = 'iqn.2011-09.org.foo.bar:blaa'
self.lun = 10
self.path = '/foo'
self.vol_id = 'blaa'
self.script_template = None
self.stubs.Set(os.path, 'isfile', lambda _: True)
self.stubs.Set(os, 'unlink', lambda _: '')
self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target)
self.stubs.Set(iscsi.LioAdm, '_get_target', self.fake_get_target)
self.stubs.Set(iscsi.LioAdm, '__init__', self.fake_init)
def fake_init(obj):
return
def fake_get_target(obj, iqn):
return 1
def get_script_params(self):
return {'tid': self.tid,
'target_name': self.target_name,
'lun': self.lun,
'path': self.path}
def get_script(self):
return self.script_template % self.get_script_params()
def fake_execute(self, *cmd, **kwargs):
self.cmds.append(string.join(cmd))
return "", None
def clear_cmds(self):
self.cmds = []
def verify_cmds(self, cmds):
self.assertEqual(len(cmds), len(self.cmds))
for a, b in zip(cmds, self.cmds):
self.assertEqual(a, b)
def verify(self):
script = self.get_script()
cmds = []
for line in script.split('\n'):
if not line.strip():
continue
cmds.append(line)
self.verify_cmds(cmds)
def run_commands(self):
tgtadm = iscsi.get_target_admin()
tgtadm.set_execute(self.fake_execute)
tgtadm.create_iscsi_target(self.target_name, self.tid,
self.lun, self.path)
tgtadm.show_target(self.tid, iqn=self.target_name)
tgtadm.remove_iscsi_target(self.tid, self.lun, self.vol_id)
def test_target_admin(self):
self.clear_cmds()
self.run_commands()
self.verify()
class TgtAdmTestCase(test.TestCase, TargetAdminTestCase):
def setUp(self):
super(TgtAdmTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.persist_tempdir = tempfile.mkdtemp()
self.flags(iscsi_helper='tgtadm')
self.flags(volumes_dir=self.persist_tempdir)
self.script_template = "\n".join([
'tgt-admin --update iqn.2011-09.org.foo.bar:blaa',
'tgt-admin --force '
'--delete iqn.2010-10.org.openstack:volume-blaa'])
def tearDown(self):
try:
shutil.rmtree(self.persist_tempdir)
except OSError:
pass
super(TgtAdmTestCase, self).tearDown()
class IetAdmTestCase(test.TestCase, TargetAdminTestCase):
def setUp(self):
super(IetAdmTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.flags(iscsi_helper='ietadm')
self.script_template = "\n".join([
'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s',
'ietadm --op new --tid=%(tid)s --lun=%(lun)s '
'--params Path=%(path)s,Type=fileio',
'ietadm --op show --tid=%(tid)s',
'ietadm --op delete --tid=%(tid)s --lun=%(lun)s',
'ietadm --op delete --tid=%(tid)s'])
class IetAdmBlockIOTestCase(test.TestCase, TargetAdminTestCase):
def setUp(self):
super(IetAdmBlockIOTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.flags(iscsi_helper='ietadm')
self.flags(iscsi_iotype='blockio')
self.script_template = "\n".join([
'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s',
'ietadm --op new --tid=%(tid)s --lun=%(lun)s '
'--params Path=%(path)s,Type=blockio',
'ietadm --op show --tid=%(tid)s',
'ietadm --op delete --tid=%(tid)s --lun=%(lun)s',
'ietadm --op delete --tid=%(tid)s'])
class IetAdmFileIOTestCase(test.TestCase, TargetAdminTestCase):
def setUp(self):
super(IetAdmFileIOTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.flags(iscsi_helper='ietadm')
self.flags(iscsi_iotype='fileio')
self.script_template = "\n".join([
'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s',
'ietadm --op new --tid=%(tid)s --lun=%(lun)s '
'--params Path=%(path)s,Type=fileio',
'ietadm --op show --tid=%(tid)s',
'ietadm --op delete --tid=%(tid)s --lun=%(lun)s',
'ietadm --op delete --tid=%(tid)s'])
class IetAdmAutoIOTestCase(test.TestCase, TargetAdminTestCase):
def setUp(self):
super(IetAdmAutoIOTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.stubs.Set(volume_utils, 'is_block', lambda _: True)
self.flags(iscsi_helper='ietadm')
self.flags(iscsi_iotype='auto')
self.script_template = "\n".join([
'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s',
'ietadm --op new --tid=%(tid)s --lun=%(lun)s '
'--params Path=%(path)s,Type=blockio',
'ietadm --op show --tid=%(tid)s',
'ietadm --op delete --tid=%(tid)s --lun=%(lun)s',
'ietadm --op delete --tid=%(tid)s'])
class LioAdmTestCase(test.TestCase, TargetAdminTestCase):
def setUp(self):
super(LioAdmTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.persist_tempdir = tempfile.mkdtemp()
self.flags(iscsi_helper='lioadm')
self.script_template = "\n".join([
'rtstool create '
'/foo iqn.2011-09.org.foo.bar:blaa test_id test_pass',
'rtstool delete iqn.2010-10.org.openstack:volume-blaa'])

File diff suppressed because it is too large Load Diff

View File

@ -1,695 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NetApp, 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 the NetApp-specific NFS driver module (netapp_nfs)."""
from manila import context
from manila import exception
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers.netapp import api
from manila.volume.drivers.netapp import nfs as netapp_nfs
from manila.volume.drivers import nfs
from lxml import etree
from mox import IgnoreArg
from mox import IsA
from mox import MockObject
import mox
import suds
import types
def create_configuration():
configuration = mox.MockObject(conf.Configuration)
configuration.append_config_values(mox.IgnoreArg())
return configuration
class FakeVolume(object):
def __init__(self, size=0):
self.size = size
self.id = hash(self)
self.name = None
def __getitem__(self, key):
return self.__dict__[key]
class FakeSnapshot(object):
def __init__(self, volume_size=0):
self.volume_name = None
self.name = None
self.volume_id = None
self.volume_size = volume_size
self.user_id = None
self.status = None
def __getitem__(self, key):
return self.__dict__[key]
class FakeResponce(object):
def __init__(self, status):
"""
:param status: Either 'failed' or 'passed'
"""
self.Status = status
if status == 'failed':
self.Reason = 'Sample error'
class NetappNfsDriverTestCase(test.TestCase):
"""Test case for NetApp specific NFS clone driver."""
def setUp(self):
self._mox = mox.Mox()
self._driver = netapp_nfs.NetAppNFSDriver(
configuration=create_configuration())
def tearDown(self):
self._mox.UnsetStubs()
def test_check_for_setup_error(self):
mox = self._mox
drv = self._driver
required_flags = ['netapp_wsdl_url',
'netapp_login',
'netapp_password',
'netapp_server_hostname',
'netapp_server_port']
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, None)
# check exception raises when flags are not set
self.assertRaises(exception.ManilaException,
drv.check_for_setup_error)
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, 'val')
mox.StubOutWithMock(nfs.NfsDriver, 'check_for_setup_error')
nfs.NfsDriver.check_for_setup_error()
mox.ReplayAll()
drv.check_for_setup_error()
mox.VerifyAll()
# restore initial FLAGS
for flag in required_flags:
delattr(drv.configuration, flag)
def test_do_setup(self):
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, 'check_for_setup_error')
mox.StubOutWithMock(drv, '_get_client')
drv.check_for_setup_error()
drv._get_client()
mox.ReplayAll()
drv.do_setup(IsA(context.RequestContext))
mox.VerifyAll()
def test_create_snapshot(self):
"""Test snapshot can be created and deleted."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_clone_volume')
drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg())
mox.ReplayAll()
drv.create_snapshot(FakeSnapshot())
mox.VerifyAll()
def test_create_volume_from_snapshot(self):
"""Tests volume creation from snapshot."""
drv = self._driver
mox = self._mox
volume = FakeVolume(1)
snapshot = FakeSnapshot(2)
self.assertRaises(exception.ManilaException,
drv.create_volume_from_snapshot,
volume,
snapshot)
snapshot = FakeSnapshot(1)
location = '127.0.0.1:/nfs'
expected_result = {'provider_location': location}
mox.StubOutWithMock(drv, '_clone_volume')
mox.StubOutWithMock(drv, '_get_volume_location')
drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg())
drv._get_volume_location(IgnoreArg()).AndReturn(location)
mox.ReplayAll()
loc = drv.create_volume_from_snapshot(volume, snapshot)
self.assertEquals(loc, expected_result)
mox.VerifyAll()
def _prepare_delete_snapshot_mock(self, snapshot_exists):
drv = self._driver
mox = self._mox
mox.StubOutWithMock(drv, '_get_provider_location')
mox.StubOutWithMock(drv, '_volume_not_present')
if snapshot_exists:
mox.StubOutWithMock(drv, '_execute')
mox.StubOutWithMock(drv, '_get_volume_path')
drv._get_provider_location(IgnoreArg())
drv._volume_not_present(IgnoreArg(),
IgnoreArg()).AndReturn(not snapshot_exists)
if snapshot_exists:
drv._get_volume_path(IgnoreArg(), IgnoreArg())
drv._execute('rm', None, run_as_root=True)
mox.ReplayAll()
return mox
def test_delete_existing_snapshot(self):
drv = self._driver
mox = self._prepare_delete_snapshot_mock(True)
drv.delete_snapshot(FakeSnapshot())
mox.VerifyAll()
def test_delete_missing_snapshot(self):
drv = self._driver
mox = self._prepare_delete_snapshot_mock(False)
drv.delete_snapshot(FakeSnapshot())
mox.VerifyAll()
def _prepare_clone_mock(self, status):
drv = self._driver
mox = self._mox
volume = FakeVolume()
setattr(volume, 'provider_location', '127.0.0.1:/nfs')
drv._client = MockObject(suds.client.Client)
drv._client.factory = MockObject(suds.client.Factory)
drv._client.service = MockObject(suds.client.ServiceSelector)
# ApiProxy() method is generated by ServiceSelector at runtime from the
# XML, so mocking is impossible.
setattr(drv._client.service,
'ApiProxy',
types.MethodType(lambda *args, **kwargs: FakeResponce(status),
suds.client.ServiceSelector))
mox.StubOutWithMock(drv, '_get_host_id')
mox.StubOutWithMock(drv, '_get_full_export_path')
drv._get_host_id(IgnoreArg()).AndReturn('10')
drv._get_full_export_path(IgnoreArg(), IgnoreArg()).AndReturn('/nfs')
return mox
def test_successfull_clone_volume(self):
drv = self._driver
mox = self._prepare_clone_mock('passed')
# set required flags
setattr(drv.configuration, 'synchronous_snapshot_create', False)
mox.ReplayAll()
volume_name = 'volume_name'
clone_name = 'clone_name'
volume_id = volume_name + str(hash(volume_name))
drv._clone_volume(volume_name, clone_name, volume_id)
mox.VerifyAll()
def test_failed_clone_volume(self):
drv = self._driver
mox = self._prepare_clone_mock('failed')
mox.ReplayAll()
volume_name = 'volume_name'
clone_name = 'clone_name'
volume_id = volume_name + str(hash(volume_name))
self.assertRaises(exception.ManilaException,
drv._clone_volume,
volume_name, clone_name, volume_id)
mox.VerifyAll()
def test_cloned_volume_size_fail(self):
volume_clone_fail = FakeVolume(1)
volume_src = FakeVolume(2)
try:
self._driver.create_cloned_volume(volume_clone_fail,
volume_src)
raise AssertionError()
except exception.ManilaException:
pass
class NetappCmodeNfsDriverTestCase(test.TestCase):
"""Test case for NetApp C Mode specific NFS clone driver"""
def setUp(self):
self._mox = mox.Mox()
self._custom_setup()
def _custom_setup(self):
self._driver = netapp_nfs.NetAppCmodeNfsDriver(
configuration=create_configuration())
def tearDown(self):
self._mox.UnsetStubs()
def test_check_for_setup_error(self):
mox = self._mox
drv = self._driver
required_flags = [
'netapp_wsdl_url',
'netapp_login',
'netapp_password',
'netapp_server_hostname',
'netapp_server_port']
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, None)
# check exception raises when flags are not set
self.assertRaises(exception.ManilaException,
drv.check_for_setup_error)
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, 'val')
mox.ReplayAll()
drv.check_for_setup_error()
mox.VerifyAll()
# restore initial FLAGS
for flag in required_flags:
delattr(drv.configuration, flag)
def test_do_setup(self):
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, 'check_for_setup_error')
mox.StubOutWithMock(drv, '_get_client')
drv.check_for_setup_error()
drv._get_client()
mox.ReplayAll()
drv.do_setup(IsA(context.RequestContext))
mox.VerifyAll()
def test_create_snapshot(self):
"""Test snapshot can be created and deleted"""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_clone_volume')
drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg())
mox.ReplayAll()
drv.create_snapshot(FakeSnapshot())
mox.VerifyAll()
def test_create_volume_from_snapshot(self):
"""Tests volume creation from snapshot"""
drv = self._driver
mox = self._mox
volume = FakeVolume(1)
snapshot = FakeSnapshot(2)
self.assertRaises(exception.ManilaException,
drv.create_volume_from_snapshot,
volume,
snapshot)
snapshot = FakeSnapshot(1)
location = '127.0.0.1:/nfs'
expected_result = {'provider_location': location}
mox.StubOutWithMock(drv, '_clone_volume')
mox.StubOutWithMock(drv, '_get_volume_location')
drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg())
drv._get_volume_location(IgnoreArg()).AndReturn(location)
mox.ReplayAll()
loc = drv.create_volume_from_snapshot(volume, snapshot)
self.assertEquals(loc, expected_result)
mox.VerifyAll()
def _prepare_delete_snapshot_mock(self, snapshot_exists):
drv = self._driver
mox = self._mox
mox.StubOutWithMock(drv, '_get_provider_location')
mox.StubOutWithMock(drv, '_volume_not_present')
if snapshot_exists:
mox.StubOutWithMock(drv, '_execute')
mox.StubOutWithMock(drv, '_get_volume_path')
drv._get_provider_location(IgnoreArg())
drv._volume_not_present(IgnoreArg(), IgnoreArg())\
.AndReturn(not snapshot_exists)
if snapshot_exists:
drv._get_volume_path(IgnoreArg(), IgnoreArg())
drv._execute('rm', None, run_as_root=True)
mox.ReplayAll()
return mox
def test_delete_existing_snapshot(self):
drv = self._driver
mox = self._prepare_delete_snapshot_mock(True)
drv.delete_snapshot(FakeSnapshot())
mox.VerifyAll()
def test_delete_missing_snapshot(self):
drv = self._driver
mox = self._prepare_delete_snapshot_mock(False)
drv.delete_snapshot(FakeSnapshot())
mox.VerifyAll()
def _prepare_clone_mock(self, status):
drv = self._driver
mox = self._mox
volume = FakeVolume()
setattr(volume, 'provider_location', '127.0.0.1:/nfs')
drv._client = MockObject(suds.client.Client)
drv._client.factory = MockObject(suds.client.Factory)
drv._client.service = MockObject(suds.client.ServiceSelector)
# CloneNasFile method is generated by ServiceSelector at runtime from
# the
# XML, so mocking is impossible.
setattr(drv._client.service,
'CloneNasFile',
types.MethodType(lambda *args, **kwargs: FakeResponce(status),
suds.client.ServiceSelector))
mox.StubOutWithMock(drv, '_get_host_ip')
mox.StubOutWithMock(drv, '_get_export_path')
drv._get_host_ip(IgnoreArg()).AndReturn('127.0.0.1')
drv._get_export_path(IgnoreArg()).AndReturn('/nfs')
return mox
def test_clone_volume(self):
drv = self._driver
mox = self._prepare_clone_mock('passed')
mox.ReplayAll()
volume_name = 'volume_name'
clone_name = 'clone_name'
volume_id = volume_name + str(hash(volume_name))
drv._clone_volume(volume_name, clone_name, volume_id)
mox.VerifyAll()
def test_cloned_volume_size_fail(self):
volume_clone_fail = FakeVolume(1)
volume_src = FakeVolume(2)
try:
self._driver.create_cloned_volume(volume_clone_fail,
volume_src)
raise AssertionError()
except exception.ManilaException:
pass
class NetappDirectCmodeNfsDriverTestCase(NetappCmodeNfsDriverTestCase):
"""Test direct NetApp C Mode driver"""
def _custom_setup(self):
self._driver = netapp_nfs.NetAppDirectCmodeNfsDriver(
configuration=create_configuration())
def test_check_for_setup_error(self):
mox = self._mox
drv = self._driver
required_flags = [
'netapp_transport_type',
'netapp_login',
'netapp_password',
'netapp_server_hostname',
'netapp_server_port']
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, None)
# check exception raises when flags are not set
self.assertRaises(exception.ManilaException,
drv.check_for_setup_error)
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, 'val')
mox.ReplayAll()
drv.check_for_setup_error()
mox.VerifyAll()
# restore initial FLAGS
for flag in required_flags:
delattr(drv.configuration, flag)
def test_do_setup(self):
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, 'check_for_setup_error')
mox.StubOutWithMock(drv, '_get_client')
mox.StubOutWithMock(drv, '_do_custom_setup')
drv.check_for_setup_error()
drv._get_client()
drv._do_custom_setup(IgnoreArg())
mox.ReplayAll()
drv.do_setup(IsA(context.RequestContext))
mox.VerifyAll()
def _prepare_clone_mock(self, status):
drv = self._driver
mox = self._mox
volume = FakeVolume()
setattr(volume, 'provider_location', '127.0.0.1:/nfs')
mox.StubOutWithMock(drv, '_get_host_ip')
mox.StubOutWithMock(drv, '_get_export_path')
mox.StubOutWithMock(drv, '_get_if_info_by_ip')
mox.StubOutWithMock(drv, '_get_vol_by_junc_vserver')
mox.StubOutWithMock(drv, '_clone_file')
drv._get_host_ip(IgnoreArg()).AndReturn('127.0.0.1')
drv._get_export_path(IgnoreArg()).AndReturn('/nfs')
drv._get_if_info_by_ip('127.0.0.1').AndReturn(
self._prepare_info_by_ip_response())
drv._get_vol_by_junc_vserver('openstack', '/nfs').AndReturn('nfsvol')
drv._clone_file('nfsvol', 'volume_name', 'clone_name',
'openstack')
return mox
def _prepare_info_by_ip_response(self):
res = """<attributes-list>
<net-interface-info>
<address>127.0.0.1</address>
<administrative-status>up</administrative-status>
<current-node>fas3170rre-cmode-01</current-node>
<current-port>e1b-1165</current-port>
<data-protocols>
<data-protocol>nfs</data-protocol>
</data-protocols>
<dns-domain-name>none</dns-domain-name>
<failover-group/>
<failover-policy>disabled</failover-policy>
<firewall-policy>data</firewall-policy>
<home-node>fas3170rre-cmode-01</home-node>
<home-port>e1b-1165</home-port>
<interface-name>nfs_data1</interface-name>
<is-auto-revert>false</is-auto-revert>
<is-home>true</is-home>
<netmask>255.255.255.0</netmask>
<netmask-length>24</netmask-length>
<operational-status>up</operational-status>
<role>data</role>
<routing-group-name>c10.63.165.0/24</routing-group-name>
<use-failover-group>disabled</use-failover-group>
<vserver>openstack</vserver>
</net-interface-info></attributes-list>"""
response_el = etree.XML(res)
return api.NaElement(response_el).get_children()
def test_clone_volume(self):
drv = self._driver
mox = self._prepare_clone_mock('pass')
mox.ReplayAll()
volume_name = 'volume_name'
clone_name = 'clone_name'
volume_id = volume_name + str(hash(volume_name))
drv._clone_volume(volume_name, clone_name, volume_id)
mox.VerifyAll()
class NetappDirect7modeNfsDriverTestCase(NetappDirectCmodeNfsDriverTestCase):
"""Test direct NetApp C Mode driver"""
def _custom_setup(self):
self._driver = netapp_nfs.NetAppDirect7modeNfsDriver(
configuration=create_configuration())
def test_check_for_setup_error(self):
mox = self._mox
drv = self._driver
required_flags = [
'netapp_transport_type',
'netapp_login',
'netapp_password',
'netapp_server_hostname',
'netapp_server_port']
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, None)
# check exception raises when flags are not set
self.assertRaises(exception.ManilaException,
drv.check_for_setup_error)
# set required flags
for flag in required_flags:
setattr(drv.configuration, flag, 'val')
mox.ReplayAll()
drv.check_for_setup_error()
mox.VerifyAll()
# restore initial FLAGS
for flag in required_flags:
delattr(drv.configuration, flag)
def test_do_setup(self):
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, 'check_for_setup_error')
mox.StubOutWithMock(drv, '_get_client')
mox.StubOutWithMock(drv, '_do_custom_setup')
drv.check_for_setup_error()
drv._get_client()
drv._do_custom_setup(IgnoreArg())
mox.ReplayAll()
drv.do_setup(IsA(context.RequestContext))
mox.VerifyAll()
def _prepare_clone_mock(self, status):
drv = self._driver
mox = self._mox
volume = FakeVolume()
setattr(volume, 'provider_location', '127.0.0.1:/nfs')
mox.StubOutWithMock(drv, '_get_export_path')
mox.StubOutWithMock(drv, '_get_actual_path_for_export')
mox.StubOutWithMock(drv, '_start_clone')
mox.StubOutWithMock(drv, '_wait_for_clone_finish')
if status == 'fail':
mox.StubOutWithMock(drv, '_clear_clone')
drv._get_export_path(IgnoreArg()).AndReturn('/nfs')
drv._get_actual_path_for_export(IgnoreArg()).AndReturn('/vol/vol1/nfs')
drv._start_clone(IgnoreArg(), IgnoreArg()).AndReturn(('1', '2'))
if status == 'fail':
drv._wait_for_clone_finish('1', '2').AndRaise(
api.NaApiError('error', 'error'))
drv._clear_clone('1')
else:
drv._wait_for_clone_finish('1', '2')
return mox
def test_clone_volume_clear(self):
drv = self._driver
mox = self._prepare_clone_mock('fail')
mox.ReplayAll()
volume_name = 'volume_name'
clone_name = 'clone_name'
volume_id = volume_name + str(hash(volume_name))
try:
drv._clone_volume(volume_name, clone_name, volume_id)
except Exception as e:
if isinstance(e, api.NaApiError):
pass
else:
raise e
mox.VerifyAll()

View File

@ -1,302 +0,0 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2011 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 OpenStack Manila volume driver
"""
import base64
import urllib2
import manila.flags
from manila import test
from manila.volume.drivers import nexenta
from manila.volume.drivers.nexenta import jsonrpc
from manila.volume.drivers.nexenta import volume
FLAGS = manila.flags.FLAGS
class TestNexentaDriver(test.TestCase):
TEST_VOLUME_NAME = 'volume1'
TEST_VOLUME_NAME2 = 'volume2'
TEST_SNAPSHOT_NAME = 'snapshot1'
TEST_VOLUME_REF = {
'name': TEST_VOLUME_NAME,
'size': 1,
}
TEST_VOLUME_REF2 = {
'name': TEST_VOLUME_NAME2,
'size': 1,
}
TEST_SNAPSHOT_REF = {
'name': TEST_SNAPSHOT_NAME,
'volume_name': TEST_VOLUME_NAME,
}
def __init__(self, method):
super(TestNexentaDriver, self).__init__(method)
def setUp(self):
super(TestNexentaDriver, self).setUp()
self.flags(
nexenta_host='1.1.1.1',
nexenta_volume='manila',
nexenta_target_prefix='iqn:',
nexenta_target_group_prefix='manila/',
nexenta_blocksize='8K',
nexenta_sparse=True,
)
self.nms_mock = self.mox.CreateMockAnything()
for mod in ['volume', 'zvol', 'iscsitarget',
'stmf', 'scsidisk', 'snapshot']:
setattr(self.nms_mock, mod, self.mox.CreateMockAnything())
self.stubs.Set(jsonrpc, 'NexentaJSONProxy',
lambda *_, **__: self.nms_mock)
self.drv = volume.NexentaDriver()
self.drv.do_setup({})
def test_setup_error(self):
self.nms_mock.volume.object_exists('manila').AndReturn(True)
self.mox.ReplayAll()
self.drv.check_for_setup_error()
def test_setup_error_fail(self):
self.nms_mock.volume.object_exists('manila').AndReturn(False)
self.mox.ReplayAll()
self.assertRaises(LookupError, self.drv.check_for_setup_error)
def test_local_path(self):
self.assertRaises(NotImplementedError, self.drv.local_path, '')
def test_create_volume(self):
self.nms_mock.zvol.create('manila/volume1', '1G', '8K', True)
self.mox.ReplayAll()
self.drv.create_volume(self.TEST_VOLUME_REF)
def test_delete_volume(self):
self.nms_mock.zvol.destroy('manila/volume1', '')
self.mox.ReplayAll()
self.drv.delete_volume(self.TEST_VOLUME_REF)
def test_create_snapshot(self):
self.nms_mock.zvol.create_snapshot('manila/volume1', 'snapshot1', '')
self.mox.ReplayAll()
self.drv.create_snapshot(self.TEST_SNAPSHOT_REF)
def test_create_volume_from_snapshot(self):
self.nms_mock.zvol.clone('manila/volume1@snapshot1', 'manila/volume2')
self.mox.ReplayAll()
self.drv.create_volume_from_snapshot(self.TEST_VOLUME_REF2,
self.TEST_SNAPSHOT_REF)
def test_delete_snapshot(self):
self.nms_mock.snapshot.destroy('manila/volume1@snapshot1', '')
self.mox.ReplayAll()
self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF)
_CREATE_EXPORT_METHODS = [
('iscsitarget', 'create_target', ({'target_name': 'iqn:volume1'},),
u'Unable to create iscsi target\n'
u' iSCSI target iqn.1986-03.com.sun:02:manila-volume1 already'
u' configured\n'
u' itadm create-target failed with error 17\n', ),
('stmf', 'create_targetgroup', ('manila/volume1',),
u'Unable to create targetgroup: stmfadm: manila/volume1:'
u' already exists\n', ),
('stmf', 'add_targetgroup_member', ('manila/volume1', 'iqn:volume1'),
u'Unable to add member to targetgroup: stmfadm:'
u' iqn.1986-03.com.sun:02:manila-volume1: already exists\n', ),
('scsidisk', 'create_lu', ('manila/volume1', {}),
u"Unable to create lu with zvol 'manila/volume1':\n"
u" sbdadm: filename /dev/zvol/rdsk/manila/volume1: in use\n", ),
('scsidisk', 'add_lun_mapping_entry', ('manila/volume1', {
'target_group': 'manila/volume1', 'lun': '0'}),
u"Unable to add view to zvol 'manila/volume1' (LUNs in use: ):\n"
u" stmfadm: view entry exists\n", ),
]
def _stub_export_method(self, module, method, args, error, fail=False):
m = getattr(self.nms_mock, module)
m = getattr(m, method)
mock = m(*args)
if fail:
mock.AndRaise(nexenta.NexentaException(error))
def _stub_all_export_methods(self, fail=False):
for params in self._CREATE_EXPORT_METHODS:
self._stub_export_method(*params, fail=fail)
def test_create_export(self):
self._stub_all_export_methods()
self.mox.ReplayAll()
retval = self.drv.create_export({}, self.TEST_VOLUME_REF)
self.assertEquals(
retval,
{'provider_location':
'%s:%s,1 %s%s 0' % (FLAGS.nexenta_host,
FLAGS.nexenta_iscsi_target_portal_port,
FLAGS.nexenta_target_prefix,
self.TEST_VOLUME_NAME)})
def __get_test(i):
def _test_create_export_fail(self):
for params in self._CREATE_EXPORT_METHODS[:i]:
self._stub_export_method(*params)
self._stub_export_method(*self._CREATE_EXPORT_METHODS[i],
fail=True)
self.mox.ReplayAll()
self.assertRaises(nexenta.NexentaException,
self.drv.create_export,
{},
self.TEST_VOLUME_REF)
return _test_create_export_fail
for i in range(len(_CREATE_EXPORT_METHODS)):
locals()['test_create_export_fail_%d' % i] = __get_test(i)
def test_ensure_export(self):
self._stub_all_export_methods(fail=True)
self.mox.ReplayAll()
self.drv.ensure_export({}, self.TEST_VOLUME_REF)
def test_remove_export(self):
self.nms_mock.scsidisk.delete_lu('manila/volume1')
self.nms_mock.stmf.destroy_targetgroup('manila/volume1')
self.nms_mock.iscsitarget.delete_target('iqn:volume1')
self.mox.ReplayAll()
self.drv.remove_export({}, self.TEST_VOLUME_REF)
def test_remove_export_fail_0(self):
self.nms_mock.scsidisk.delete_lu('manila/volume1')
self.nms_mock.stmf.destroy_targetgroup(
'manila/volume1').AndRaise(nexenta.NexentaException())
self.nms_mock.iscsitarget.delete_target('iqn:volume1')
self.mox.ReplayAll()
self.drv.remove_export({}, self.TEST_VOLUME_REF)
def test_remove_export_fail_1(self):
self.nms_mock.scsidisk.delete_lu('manila/volume1')
self.nms_mock.stmf.destroy_targetgroup('manila/volume1')
self.nms_mock.iscsitarget.delete_target(
'iqn:volume1').AndRaise(nexenta.NexentaException())
self.mox.ReplayAll()
self.drv.remove_export({}, self.TEST_VOLUME_REF)
def test_get_volume_stats(self):
stats = {'size': '5368709120G',
'used': '5368709120G',
'available': '5368709120G',
'health': 'ONLINE'}
self.nms_mock.volume.get_child_props(
FLAGS.nexenta_volume,
'health|size|used|available').AndReturn(stats)
self.mox.ReplayAll()
stats = self.drv.get_volume_stats(True)
self.assertEquals(stats['storage_protocol'], 'iSCSI')
self.assertEquals(stats['volume_backend_name'], 'NexentaDriver')
self.assertEquals(stats['total_capacity_gb'], 5368709120.0)
self.assertEquals(stats['free_capacity_gb'], 5368709120.0)
self.assertEquals(stats['reserved_percentage'], 0)
self.assertEquals(stats['QoS_support'], False)
class TestNexentaJSONRPC(test.TestCase):
URL = 'http://example.com/'
URL_S = 'https://example.com/'
USER = 'user'
PASSWORD = 'password'
HEADERS = {'Authorization': 'Basic %s' % (
base64.b64encode(':'.join((USER, PASSWORD))),),
'Content-Type': 'application/json'}
REQUEST = 'the request'
def setUp(self):
super(TestNexentaJSONRPC, self).setUp()
self.proxy = jsonrpc.NexentaJSONProxy(
self.URL, self.USER, self.PASSWORD, auto=True)
self.mox.StubOutWithMock(urllib2, 'Request', True)
self.mox.StubOutWithMock(urllib2, 'urlopen')
self.resp_mock = self.mox.CreateMockAnything()
self.resp_info_mock = self.mox.CreateMockAnything()
self.resp_mock.info().AndReturn(self.resp_info_mock)
urllib2.urlopen(self.REQUEST).AndReturn(self.resp_mock)
def test_call(self):
urllib2.Request(
self.URL,
'{"object": null, "params": ["arg1", "arg2"], "method": null}',
self.HEADERS).AndReturn(self.REQUEST)
self.resp_info_mock.status = ''
self.resp_mock.read().AndReturn(
'{"error": null, "result": "the result"}')
self.mox.ReplayAll()
result = self.proxy('arg1', 'arg2')
self.assertEquals("the result", result)
def test_call_deep(self):
urllib2.Request(
self.URL,
'{"object": "obj1.subobj", "params": ["arg1", "arg2"],'
' "method": "meth"}',
self.HEADERS).AndReturn(self.REQUEST)
self.resp_info_mock.status = ''
self.resp_mock.read().AndReturn(
'{"error": null, "result": "the result"}')
self.mox.ReplayAll()
result = self.proxy.obj1.subobj.meth('arg1', 'arg2')
self.assertEquals("the result", result)
def test_call_auto(self):
urllib2.Request(
self.URL,
'{"object": null, "params": ["arg1", "arg2"], "method": null}',
self.HEADERS).AndReturn(self.REQUEST)
urllib2.Request(
self.URL_S,
'{"object": null, "params": ["arg1", "arg2"], "method": null}',
self.HEADERS).AndReturn(self.REQUEST)
self.resp_info_mock.status = 'EOF in headers'
self.resp_mock.read().AndReturn(
'{"error": null, "result": "the result"}')
urllib2.urlopen(self.REQUEST).AndReturn(self.resp_mock)
self.mox.ReplayAll()
result = self.proxy('arg1', 'arg2')
self.assertEquals("the result", result)
def test_call_error(self):
urllib2.Request(
self.URL,
'{"object": null, "params": ["arg1", "arg2"], "method": null}',
self.HEADERS).AndReturn(self.REQUEST)
self.resp_info_mock.status = ''
self.resp_mock.read().AndReturn(
'{"error": {"message": "the error"}, "result": "the result"}')
self.mox.ReplayAll()
self.assertRaises(jsonrpc.NexentaJSONException,
self.proxy, 'arg1', 'arg2')
def test_call_fail(self):
urllib2.Request(
self.URL,
'{"object": null, "params": ["arg1", "arg2"], "method": null}',
self.HEADERS).AndReturn(self.REQUEST)
self.resp_info_mock.status = 'EOF in headers'
self.proxy.auto = False
self.mox.ReplayAll()
self.assertRaises(jsonrpc.NexentaJSONException,
self.proxy, 'arg1', 'arg2')

View File

@ -1,654 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 NetApp, 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 the NFS driver module."""
import __builtin__
import errno
import os
from oslo.config import cfg
import mox as mox_lib
from mox import IgnoreArg
from mox import IsA
from mox import stubout
from manila import context
from manila import exception
from manila.exception import ProcessExecutionError
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers import nfs
class DumbVolume(object):
fields = {}
def __setitem__(self, key, value):
self.fields[key] = value
def __getitem__(self, item):
return self.fields[item]
class RemoteFsDriverTestCase(test.TestCase):
TEST_EXPORT = '1.2.3.4/export1'
TEST_FILE_NAME = 'test.txt'
def setUp(self):
self._driver = nfs.RemoteFsDriver()
self._mox = mox_lib.Mox()
pass
def tearDown(self):
self._mox.UnsetStubs()
def test_create_sparsed_file(self):
(mox, drv) = self._mox, self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('truncate', '-s', '1G', '/path', run_as_root=True).\
AndReturn("")
mox.ReplayAll()
drv._create_sparsed_file('/path', 1)
mox.VerifyAll()
def test_create_regular_file(self):
(mox, drv) = self._mox, self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('dd', 'if=/dev/zero', 'of=/path', 'bs=1M', 'count=1024',
run_as_root=True)
mox.ReplayAll()
drv._create_regular_file('/path', 1)
mox.VerifyAll()
def test_set_rw_permissions_for_all(self):
(mox, drv) = self._mox, self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('chmod', 'ugo+rw', '/path', run_as_root=True)
mox.ReplayAll()
drv._set_rw_permissions_for_all('/path')
mox.VerifyAll()
def test_get_hash_str(self):
"""_get_hash_str should calculation correct value."""
drv = self._driver
self.assertEqual('4d664fd43b6ff86d80a4ea969c07b3b9',
drv._get_hash_str(self.TEST_EXPORT))
class NfsDriverTestCase(test.TestCase):
"""Test case for NFS driver."""
TEST_NFS_EXPORT1 = 'nfs-host1:/export'
TEST_NFS_EXPORT2 = 'nfs-host2:/export'
TEST_SIZE_IN_GB = 1
TEST_MNT_POINT = '/mnt/nfs'
TEST_MNT_POINT_BASE = '/mnt/test'
TEST_LOCAL_PATH = '/mnt/nfs/volume-123'
TEST_FILE_NAME = 'test.txt'
TEST_SHARES_CONFIG_FILE = '/etc/manila/test-shares.conf'
ONE_GB_IN_BYTES = 1024 * 1024 * 1024
def setUp(self):
self._mox = mox_lib.Mox()
self.stubs = stubout.StubOutForTesting()
self.configuration = mox_lib.MockObject(conf.Configuration)
self.configuration.append_config_values(mox_lib.IgnoreArg())
self.configuration.nfs_shares_config = None
self.configuration.nfs_mount_options = None
self.configuration.nfs_mount_point_base = '$state_path/mnt'
self.configuration.nfs_disk_util = 'df'
self.configuration.nfs_sparsed_volumes = True
self._driver = nfs.NfsDriver(configuration=self.configuration)
def tearDown(self):
self._mox.UnsetStubs()
self.stubs.UnsetAll()
def stub_out_not_replaying(self, obj, attr_name):
attr_to_replace = getattr(obj, attr_name)
stub = mox_lib.MockObject(attr_to_replace)
self.stubs.Set(obj, attr_name, stub)
def test_local_path(self):
"""local_path common use case."""
self.configuration.nfs_mount_point_base = self.TEST_MNT_POINT_BASE
drv = self._driver
volume = DumbVolume()
volume['provider_location'] = self.TEST_NFS_EXPORT1
volume['name'] = 'volume-123'
self.assertEqual(
'/mnt/test/2f4f60214cf43c595666dd815f0360a4/volume-123',
drv.local_path(volume))
def test_mount_nfs_should_mount_correctly(self):
"""_mount_nfs common case usage."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute('mount', '-t', 'nfs', self.TEST_NFS_EXPORT1,
self.TEST_MNT_POINT, run_as_root=True)
mox.ReplayAll()
drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT)
mox.VerifyAll()
def test_mount_nfs_should_suppress_already_mounted_error(self):
"""_mount_nfs should suppress already mounted error if ensure=True
"""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute('mount', '-t', 'nfs', self.TEST_NFS_EXPORT1,
self.TEST_MNT_POINT, run_as_root=True).\
AndRaise(ProcessExecutionError(
stderr='is busy or already mounted'))
mox.ReplayAll()
drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT, ensure=True)
mox.VerifyAll()
def test_mount_nfs_should_reraise_already_mounted_error(self):
"""_mount_nfs should not suppress already mounted error if ensure=False
"""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute(
'mount',
'-t',
'nfs',
self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT, run_as_root=True).\
AndRaise(ProcessExecutionError(stderr='is busy or '
'already mounted'))
mox.ReplayAll()
self.assertRaises(ProcessExecutionError, drv._mount_nfs,
self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT,
ensure=False)
mox.VerifyAll()
def test_mount_nfs_should_create_mountpoint_if_not_yet(self):
"""_mount_nfs should create mountpoint if it doesn't exist."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute(*([IgnoreArg()] * 5), run_as_root=IgnoreArg())
mox.ReplayAll()
drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT)
mox.VerifyAll()
def test_mount_nfs_should_not_create_mountpoint_if_already(self):
"""_mount_nfs should not create mountpoint if it already exists."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_execute')
drv._execute('mkdir', '-p', self.TEST_MNT_POINT)
drv._execute(*([IgnoreArg()] * 5), run_as_root=IgnoreArg())
mox.ReplayAll()
drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT)
mox.VerifyAll()
def test_get_hash_str(self):
"""_get_hash_str should calculation correct value."""
drv = self._driver
self.assertEqual('2f4f60214cf43c595666dd815f0360a4',
drv._get_hash_str(self.TEST_NFS_EXPORT1))
def test_get_mount_point_for_share(self):
"""_get_mount_point_for_share should calculate correct value."""
drv = self._driver
self.configuration.nfs_mount_point_base = self.TEST_MNT_POINT_BASE
self.assertEqual('/mnt/test/2f4f60214cf43c595666dd815f0360a4',
drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1))
def test_get_available_capacity_with_df(self):
"""_get_available_capacity should calculate correct value."""
mox = self._mox
drv = self._driver
df_total_size = 2620544
df_avail = 1490560
df_head = 'Filesystem 1K-blocks Used Available Use% Mounted on\n'
df_data = 'nfs-host:/export %d 996864 %d 41%% /mnt' % (df_total_size,
df_avail)
df_output = df_head + df_data
self.configuration.nfs_disk_util = 'df'
mox.StubOutWithMock(drv, '_get_mount_point_for_share')
drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1).\
AndReturn(self.TEST_MNT_POINT)
mox.StubOutWithMock(drv, '_execute')
drv._execute('df', '-P', '-B', '1', self.TEST_MNT_POINT,
run_as_root=True).AndReturn((df_output, None))
mox.ReplayAll()
self.assertEquals((df_avail, df_total_size),
drv._get_available_capacity(self.TEST_NFS_EXPORT1))
mox.VerifyAll()
def test_get_available_capacity_with_du(self):
"""_get_available_capacity should calculate correct value."""
mox = self._mox
drv = self._driver
self.configuration.nfs_disk_util = 'du'
df_total_size = 2620544
df_used_size = 996864
df_avail_size = 1490560
df_title = 'Filesystem 1-blocks Used Available Use% Mounted on\n'
df_mnt_data = 'nfs-host:/export %d %d %d 41%% /mnt' % (df_total_size,
df_used_size,
df_avail_size)
df_output = df_title + df_mnt_data
du_used = 490560
du_output = '%d /mnt' % du_used
mox.StubOutWithMock(drv, '_get_mount_point_for_share')
drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1).\
AndReturn(self.TEST_MNT_POINT)
mox.StubOutWithMock(drv, '_execute')
drv._execute('df', '-P', '-B', '1', self.TEST_MNT_POINT,
run_as_root=True).\
AndReturn((df_output, None))
drv._execute('du', '-sb', '--apparent-size',
'--exclude', '*snapshot*',
self.TEST_MNT_POINT,
run_as_root=True).AndReturn((du_output, None))
mox.ReplayAll()
self.assertEquals((df_total_size - du_used, df_total_size),
drv._get_available_capacity(self.TEST_NFS_EXPORT1))
mox.VerifyAll()
def test_load_shares_config(self):
mox = self._mox
drv = self._driver
self.configuration.nfs_shares_config = self.TEST_SHARES_CONFIG_FILE
mox.StubOutWithMock(__builtin__, 'open')
config_data = []
config_data.append(self.TEST_NFS_EXPORT1)
config_data.append('#' + self.TEST_NFS_EXPORT2)
config_data.append('')
__builtin__.open(self.TEST_SHARES_CONFIG_FILE).AndReturn(config_data)
mox.ReplayAll()
shares = drv._load_shares_config()
self.assertEqual([self.TEST_NFS_EXPORT1], shares)
mox.VerifyAll()
def test_ensure_share_mounted(self):
"""_ensure_share_mounted simple use case."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_get_mount_point_for_share')
drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1).\
AndReturn(self.TEST_MNT_POINT)
mox.StubOutWithMock(drv, '_mount_nfs')
drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT, ensure=True)
mox.ReplayAll()
drv._ensure_share_mounted(self.TEST_NFS_EXPORT1)
mox.VerifyAll()
def test_ensure_shares_mounted_should_save_mounting_successfully(self):
"""_ensure_shares_mounted should save share if mounted with success."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_load_shares_config')
drv._load_shares_config().AndReturn([self.TEST_NFS_EXPORT1])
mox.StubOutWithMock(drv, '_ensure_share_mounted')
drv._ensure_share_mounted(self.TEST_NFS_EXPORT1)
mox.ReplayAll()
drv._ensure_shares_mounted()
self.assertEqual(1, len(drv._mounted_shares))
self.assertEqual(self.TEST_NFS_EXPORT1, drv._mounted_shares[0])
mox.VerifyAll()
def test_ensure_shares_mounted_should_not_save_mounting_with_error(self):
"""_ensure_shares_mounted should not save share if failed to mount."""
mox = self._mox
drv = self._driver
mox.StubOutWithMock(drv, '_load_shares_config')
drv._load_shares_config().AndReturn([self.TEST_NFS_EXPORT1])
mox.StubOutWithMock(drv, '_ensure_share_mounted')
drv._ensure_share_mounted(self.TEST_NFS_EXPORT1).AndRaise(Exception())
mox.ReplayAll()
drv._ensure_shares_mounted()
self.assertEqual(0, len(drv._mounted_shares))
mox.VerifyAll()
def test_setup_should_throw_error_if_shares_config_not_configured(self):
"""do_setup should throw error if shares config is not configured."""
drv = self._driver
self.configuration.nfs_shares_config = self.TEST_SHARES_CONFIG_FILE
self.assertRaises(exception.NfsException,
drv.do_setup, IsA(context.RequestContext))
def test_setup_should_throw_exception_if_nfs_client_is_not_installed(self):
"""do_setup should throw error if nfs client is not installed."""
mox = self._mox
drv = self._driver
self.configuration.nfs_shares_config = self.TEST_SHARES_CONFIG_FILE
mox.StubOutWithMock(os.path, 'exists')
os.path.exists(self.TEST_SHARES_CONFIG_FILE).AndReturn(True)
mox.StubOutWithMock(drv, '_execute')
drv._execute('mount.nfs', check_exit_code=False).\
AndRaise(OSError(errno.ENOENT, 'No such file or directory'))
mox.ReplayAll()
self.assertRaises(exception.NfsException,
drv.do_setup, IsA(context.RequestContext))
mox.VerifyAll()
def test_find_share_should_throw_error_if_there_is_no_mounted_shares(self):
"""_find_share should throw error if there is no mounted shares."""
drv = self._driver
drv._mounted_shares = []
self.assertRaises(exception.NotFound, drv._find_share,
self.TEST_SIZE_IN_GB)
def test_find_share(self):
"""_find_share simple use case."""
mox = self._mox
drv = self._driver
drv._mounted_shares = [self.TEST_NFS_EXPORT1, self.TEST_NFS_EXPORT2]
mox.StubOutWithMock(drv, '_get_available_capacity')
drv._get_available_capacity(self.TEST_NFS_EXPORT1).\
AndReturn((2 * self.ONE_GB_IN_BYTES, 5 * self.ONE_GB_IN_BYTES))
drv._get_available_capacity(self.TEST_NFS_EXPORT2).\
AndReturn((3 * self.ONE_GB_IN_BYTES, 10 * self.ONE_GB_IN_BYTES))
mox.ReplayAll()
self.assertEqual(self.TEST_NFS_EXPORT2,
drv._find_share(self.TEST_SIZE_IN_GB))
mox.VerifyAll()
def test_find_share_should_throw_error_if_there_is_no_enough_place(self):
"""_find_share should throw error if there is no share to host vol."""
mox = self._mox
drv = self._driver
drv._mounted_shares = [self.TEST_NFS_EXPORT1, self.TEST_NFS_EXPORT2]
mox.StubOutWithMock(drv, '_get_available_capacity')
drv._get_available_capacity(self.TEST_NFS_EXPORT1).\
AndReturn((0, 5 * self.ONE_GB_IN_BYTES))
drv._get_available_capacity(self.TEST_NFS_EXPORT2).\
AndReturn((0, 10 * self.ONE_GB_IN_BYTES))
mox.ReplayAll()
self.assertRaises(exception.NfsNoSuitableShareFound, drv._find_share,
self.TEST_SIZE_IN_GB)
mox.VerifyAll()
def _simple_volume(self):
volume = DumbVolume()
volume['provider_location'] = '127.0.0.1:/mnt'
volume['name'] = 'volume_name'
volume['size'] = 10
return volume
def test_create_sparsed_volume(self):
mox = self._mox
drv = self._driver
volume = self._simple_volume()
setattr(cfg.CONF, 'nfs_sparsed_volumes', True)
mox.StubOutWithMock(drv, '_create_sparsed_file')
mox.StubOutWithMock(drv, '_set_rw_permissions_for_all')
drv._create_sparsed_file(IgnoreArg(), IgnoreArg())
drv._set_rw_permissions_for_all(IgnoreArg())
mox.ReplayAll()
drv._do_create_volume(volume)
mox.VerifyAll()
delattr(cfg.CONF, 'nfs_sparsed_volumes')
def test_create_nonsparsed_volume(self):
mox = self._mox
drv = self._driver
self.configuration.nfs_sparsed_volumes = False
volume = self._simple_volume()
setattr(cfg.CONF, 'nfs_sparsed_volumes', False)
mox.StubOutWithMock(drv, '_create_regular_file')
mox.StubOutWithMock(drv, '_set_rw_permissions_for_all')
drv._create_regular_file(IgnoreArg(), IgnoreArg())
drv._set_rw_permissions_for_all(IgnoreArg())
mox.ReplayAll()
drv._do_create_volume(volume)
mox.VerifyAll()
delattr(cfg.CONF, 'nfs_sparsed_volumes')
def test_create_volume_should_ensure_nfs_mounted(self):
"""create_volume ensures shares provided in config are mounted."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(nfs, 'LOG')
self.stub_out_not_replaying(drv, '_find_share')
self.stub_out_not_replaying(drv, '_do_create_volume')
mox.StubOutWithMock(drv, '_ensure_shares_mounted')
drv._ensure_shares_mounted()
mox.ReplayAll()
volume = DumbVolume()
volume['size'] = self.TEST_SIZE_IN_GB
drv.create_volume(volume)
mox.VerifyAll()
def test_create_volume_should_return_provider_location(self):
"""create_volume should return provider_location with found share."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(nfs, 'LOG')
self.stub_out_not_replaying(drv, '_ensure_shares_mounted')
self.stub_out_not_replaying(drv, '_do_create_volume')
mox.StubOutWithMock(drv, '_find_share')
drv._find_share(self.TEST_SIZE_IN_GB).AndReturn(self.TEST_NFS_EXPORT1)
mox.ReplayAll()
volume = DumbVolume()
volume['size'] = self.TEST_SIZE_IN_GB
result = drv.create_volume(volume)
self.assertEqual(self.TEST_NFS_EXPORT1, result['provider_location'])
mox.VerifyAll()
def test_delete_volume(self):
"""delete_volume simple test case."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(drv, '_ensure_share_mounted')
volume = DumbVolume()
volume['name'] = 'volume-123'
volume['provider_location'] = self.TEST_NFS_EXPORT1
mox.StubOutWithMock(drv, 'local_path')
drv.local_path(volume).AndReturn(self.TEST_LOCAL_PATH)
mox.StubOutWithMock(drv, '_execute')
drv._execute('rm', '-f', self.TEST_LOCAL_PATH, run_as_root=True)
mox.ReplayAll()
drv.delete_volume(volume)
mox.VerifyAll()
def test_delete_should_ensure_share_mounted(self):
"""delete_volume should ensure that corresponding share is mounted."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(drv, '_execute')
volume = DumbVolume()
volume['name'] = 'volume-123'
volume['provider_location'] = self.TEST_NFS_EXPORT1
mox.StubOutWithMock(drv, '_ensure_share_mounted')
drv._ensure_share_mounted(self.TEST_NFS_EXPORT1)
mox.ReplayAll()
drv.delete_volume(volume)
mox.VerifyAll()
def test_delete_should_not_delete_if_provider_location_not_provided(self):
"""delete_volume shouldn't delete if provider_location missed."""
mox = self._mox
drv = self._driver
self.stub_out_not_replaying(drv, '_ensure_share_mounted')
volume = DumbVolume()
volume['name'] = 'volume-123'
volume['provider_location'] = None
mox.StubOutWithMock(drv, '_execute')
mox.ReplayAll()
drv.delete_volume(volume)
mox.VerifyAll()
def test_get_volume_stats(self):
"""get_volume_stats must fill the correct values"""
mox = self._mox
drv = self._driver
drv._mounted_shares = [self.TEST_NFS_EXPORT1, self.TEST_NFS_EXPORT2]
mox.StubOutWithMock(drv, '_ensure_shares_mounted')
mox.StubOutWithMock(drv, '_get_available_capacity')
drv._ensure_shares_mounted()
drv._get_available_capacity(self.TEST_NFS_EXPORT1).\
AndReturn((2 * self.ONE_GB_IN_BYTES, 10 * self.ONE_GB_IN_BYTES))
drv._get_available_capacity(self.TEST_NFS_EXPORT2).\
AndReturn((3 * self.ONE_GB_IN_BYTES, 20 * self.ONE_GB_IN_BYTES))
mox.ReplayAll()
drv.get_volume_stats()
self.assertEqual(drv._stats['total_capacity_gb'], 30.0)
self.assertEqual(drv._stats['free_capacity_gb'], 5.0)
mox.VerifyAll()

View File

@ -29,7 +29,6 @@ from manila.openstack.common import timeutils
from manila import quota
from manila import test
import manila.tests.image.fake
from manila import volume
FLAGS = flags.FLAGS

View File

@ -1,266 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Josh Durgin
# 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 contextlib
import mox
import os
import tempfile
from manila import db
from manila import exception
from manila.image import image_utils
from manila.openstack.common import log as logging
from manila.openstack.common import timeutils
from manila import test
from manila.tests.image import fake as fake_image
from manila.tests.test_volume import DriverTestCase
from manila.volume import configuration as conf
from manila.volume.drivers.rbd import RBDDriver
from manila.volume.drivers.rbd import VERSION as DRIVER_VERSION
LOG = logging.getLogger(__name__)
class FakeImageService:
def download(self, context, image_id, path):
pass
RADOS_DF_OUT = """
{
"total_space" : "958931232",
"total_used" : "123906196",
"total_objects" : "4221",
"total_avail" : "787024012",
"pools" : [
{
"name" : "volumes",
"categories" : [
{
"write_bytes" : "226833",
"size_kb" : "17038386",
"read_bytes" : "221865",
"num_objects" : "4186",
"name" : "",
"size_bytes" : "17447306589",
"write_kb" : "20302730",
"num_object_copies" : "8372",
"read_kb" : "30",
"num_objects_unfound" : "0",
"num_object_clones" : "9",
"num_objects_missing_on_primary" : "0",
"num_objects_degraded" : "0"
}
],
"id" : "4"
}
]
}
"""
class RBDTestCase(test.TestCase):
def setUp(self):
super(RBDTestCase, self).setUp()
def fake_execute(*args, **kwargs):
return '', ''
self._mox = mox.Mox()
self.configuration = mox.MockObject(conf.Configuration)
self.configuration.volume_tmp_dir = None
self.configuration.rbd_pool = 'rbd'
self.configuration.rbd_secret_uuid = None
self.configuration.rbd_user = None
self.configuration.append_config_values(mox.IgnoreArg())
self.driver = RBDDriver(execute=fake_execute,
configuration=self.configuration)
self._mox.ReplayAll()
def test_good_locations(self):
locations = ['rbd://fsid/pool/image/snap',
'rbd://%2F/%2F/%2F/%2F', ]
map(self.driver._parse_location, locations)
def test_bad_locations(self):
locations = ['rbd://image',
'http://path/to/somewhere/else',
'rbd://image/extra',
'rbd://image/',
'rbd://fsid/pool/image/',
'rbd://fsid/pool/image/snap/',
'rbd://///', ]
for loc in locations:
self.assertRaises(exception.ImageUnacceptable,
self.driver._parse_location,
loc)
self.assertFalse(self.driver._is_cloneable(loc))
def test_cloneable(self):
self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc')
location = 'rbd://abc/pool/image/snap'
self.assertTrue(self.driver._is_cloneable(location))
def test_uncloneable_different_fsid(self):
self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc')
location = 'rbd://def/pool/image/snap'
self.assertFalse(self.driver._is_cloneable(location))
def test_uncloneable_unreadable(self):
def fake_exc(*args):
raise exception.ProcessExecutionError()
self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc')
self.stubs.Set(self.driver, '_execute', fake_exc)
location = 'rbd://abc/pool/image/snap'
self.assertFalse(self.driver._is_cloneable(location))
def _copy_image(self):
@contextlib.contextmanager
def fake_temp_file(dir):
class FakeTmp:
def __init__(self, name):
self.name = name
yield FakeTmp('test')
self.stubs.Set(tempfile, 'NamedTemporaryFile', fake_temp_file)
self.stubs.Set(os.path, 'exists', lambda x: True)
self.stubs.Set(image_utils, 'fetch_to_raw', lambda w, x, y, z: None)
self.driver.copy_image_to_volume(None, {'name': 'test',
'size': 1},
FakeImageService(), None)
def test_copy_image_no_volume_tmp(self):
self.configuration.volume_tmp_dir = None
self._copy_image()
def test_copy_image_volume_tmp(self):
self.configuration.volume_tmp_dir = '/var/run/manila/tmp'
self._copy_image()
def test_update_volume_stats(self):
def fake_stats(*args):
return RADOS_DF_OUT, ''
def fake_safe_get(*args):
return "RBD"
self.stubs.Set(self.driver, '_execute', fake_stats)
self.stubs.Set(self.driver.configuration, 'safe_get', fake_safe_get)
expected = dict(
volume_backend_name='RBD',
vendor_name='Open Source',
driver_version=DRIVER_VERSION,
storage_protocol='ceph',
total_capacity_gb=914,
free_capacity_gb=750,
reserved_percentage=0)
actual = self.driver.get_volume_stats(True)
self.assertDictMatch(expected, actual)
def test_update_volume_stats_error(self):
def fake_exc(*args):
raise exception.ProcessExecutionError()
def fake_safe_get(*args):
return "RBD"
self.stubs.Set(self.driver, '_execute', fake_exc)
self.stubs.Set(self.driver.configuration, 'safe_get', fake_safe_get)
expected = dict(
volume_backend_name='RBD',
vendor_name='Open Source',
driver_version=DRIVER_VERSION,
storage_protocol='ceph',
total_capacity_gb='unknown',
free_capacity_gb='unknown',
reserved_percentage=0)
actual = self.driver.get_volume_stats(True)
self.assertDictMatch(expected, actual)
class ManagedRBDTestCase(DriverTestCase):
driver_name = "manila.volume.drivers.rbd.RBDDriver"
def setUp(self):
super(ManagedRBDTestCase, self).setUp()
fake_image.stub_out_image_service(self.stubs)
def _clone_volume_from_image(self, expected_status,
clone_works=True):
"""Try to clone a volume from an image, and check the status
afterwards"""
def fake_clone_image(volume, image_location):
return True
def fake_clone_error(volume, image_location):
raise exception.ManilaException()
self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True)
if clone_works:
self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_image)
else:
self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_error)
image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
volume_id = 1
# creating volume testdata
db.volume_create(self.context,
{'id': volume_id,
'updated_at': timeutils.utcnow(),
'display_description': 'Test Desc',
'size': 20,
'status': 'creating',
'instance_uuid': None,
'host': 'dummy'})
try:
if clone_works:
self.volume.create_volume(self.context,
volume_id,
image_id=image_id)
else:
self.assertRaises(exception.ManilaException,
self.volume.create_volume,
self.context,
volume_id,
image_id=image_id)
volume = db.volume_get(self.context, volume_id)
self.assertEqual(volume['status'], expected_status)
finally:
# cleanup
db.volume_destroy(self.context, volume_id)
def test_clone_image_status_available(self):
"""Verify that before cloning, an image is in the available state."""
self._clone_volume_from_image('available', True)
def test_clone_image_status_error(self):
"""Verify that before cloning, an image is in the available state."""
self._clone_volume_from_image('error', False)
def test_clone_success(self):
self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True)
self.stubs.Set(self.volume.driver, 'clone_image', lambda a, b: True)
image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
self.assertTrue(self.volume.driver.clone_image({}, image_id))
def test_clone_bad_image_id(self):
self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True)
self.assertFalse(self.volume.driver.clone_image({}, None))
def test_clone_uncloneable(self):
self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: False)
self.assertFalse(self.volume.driver.clone_image({}, 'dne'))

View File

@ -1,185 +0,0 @@
# Copyright (c) 2013 Scality
#
# 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 the Scality SOFS Volume Driver.
"""
import errno
import os
from manila import exception
from manila import test
from manila import utils
from manila.volume.drivers import scality
class ScalityDriverTestCase(test.TestCase):
"""Test case for the Scality driver."""
TEST_MOUNT = '/tmp/fake_mount'
TEST_CONFIG = '/tmp/fake_config'
TEST_VOLDIR = 'volumes'
TEST_VOLNAME = 'volume_name'
TEST_VOLSIZE = '0'
TEST_VOLUME = {
'name': TEST_VOLNAME,
'size': TEST_VOLSIZE
}
TEST_VOLPATH = os.path.join(TEST_MOUNT,
TEST_VOLDIR,
TEST_VOLNAME)
TEST_SNAPNAME = 'snapshot_name'
TEST_SNAPSHOT = {
'name': TEST_SNAPNAME,
'volume_name': TEST_VOLNAME,
'volume_size': TEST_VOLSIZE
}
TEST_SNAPPATH = os.path.join(TEST_MOUNT,
TEST_VOLDIR,
TEST_SNAPNAME)
def _makedirs(self, path):
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise e
def _create_fake_config(self):
open(self.TEST_CONFIG, "w+").close()
def _create_fake_mount(self):
self._makedirs(os.path.join(self.TEST_MOUNT, 'sys'))
self._makedirs(os.path.join(self.TEST_MOUNT, self.TEST_VOLDIR))
def _remove_fake_mount(self):
utils.execute('rm', '-rf', self.TEST_MOUNT)
def _remove_fake_config(self):
try:
os.unlink(self.TEST_CONFIG)
except OSError as e:
if e.errno != errno.ENOENT:
raise e
def _configure_driver(self):
scality.FLAGS.scality_sofs_config = self.TEST_CONFIG
scality.FLAGS.scality_sofs_mount_point = self.TEST_MOUNT
scality.FLAGS.scality_sofs_volume_dir = self.TEST_VOLDIR
def _execute_wrapper(self, cmd, *args, **kwargs):
try:
kwargs.pop('run_as_root')
except KeyError:
pass
utils.execute(cmd, *args, **kwargs)
def _set_access_wrapper(self, is_visible):
def _access_wrapper(path, flags):
if path == '/sbin/mount.sofs':
return is_visible
else:
return os.access(path, flags)
self.stubs.Set(os, 'access', _access_wrapper)
def setUp(self):
super(ScalityDriverTestCase, self).setUp()
self._remove_fake_mount()
self._driver = scality.ScalityDriver()
self._driver.set_execute(self._execute_wrapper)
self._create_fake_mount()
self._create_fake_config()
self._configure_driver()
def tearDown(self):
self._remove_fake_mount()
self._remove_fake_config()
super(ScalityDriverTestCase, self).tearDown()
def test_setup_no_config(self):
"""Missing SOFS configuration shall raise an error."""
scality.FLAGS.scality_sofs_config = None
self.assertRaises(exception.ShareBackendAPIException,
self._driver.do_setup, None)
def test_setup_missing_config(self):
"""Non-existent SOFS configuration file shall raise an error."""
scality.FLAGS.scality_sofs_config = 'nonexistent.conf'
self.assertRaises(exception.ShareBackendAPIException,
self._driver.do_setup, None)
def test_setup_no_mount_helper(self):
"""SOFS must be installed to use the driver."""
self._set_access_wrapper(False)
self.assertRaises(exception.ShareBackendAPIException,
self._driver.do_setup, None)
def test_setup_make_voldir(self):
"""The directory for volumes shall be created automatically."""
self._set_access_wrapper(True)
voldir_path = os.path.join(self.TEST_MOUNT, self.TEST_VOLDIR)
os.rmdir(voldir_path)
self._driver.do_setup(None)
self.assertTrue(os.path.isdir(voldir_path))
def test_local_path(self):
"""Expected behaviour for local_path."""
self.assertEqual(self._driver.local_path(self.TEST_VOLUME),
self.TEST_VOLPATH)
def test_create_volume(self):
"""Expected behaviour for create_volume."""
ret = self._driver.create_volume(self.TEST_VOLUME)
self.assertEqual(ret['provider_location'],
os.path.join(self.TEST_VOLDIR,
self.TEST_VOLNAME))
self.assertTrue(os.path.isfile(self.TEST_VOLPATH))
self.assertEqual(os.stat(self.TEST_VOLPATH).st_size,
100 * 1024 * 1024)
def test_delete_volume(self):
"""Expected behaviour for delete_volume."""
self._driver.create_volume(self.TEST_VOLUME)
self._driver.delete_volume(self.TEST_VOLUME)
self.assertFalse(os.path.isfile(self.TEST_VOLPATH))
def test_create_snapshot(self):
"""Expected behaviour for create_snapshot."""
self._driver.create_volume(self.TEST_VOLUME)
self._driver.create_snapshot(self.TEST_SNAPSHOT)
self.assertTrue(os.path.isfile(self.TEST_SNAPPATH))
self.assertEqual(os.stat(self.TEST_SNAPPATH).st_size,
100 * 1024 * 1024)
def test_delete_snapshot(self):
"""Expected behaviour for delete_snapshot."""
self._driver.create_volume(self.TEST_VOLUME)
self._driver.create_snapshot(self.TEST_SNAPSHOT)
self._driver.delete_snapshot(self.TEST_SNAPSHOT)
self.assertFalse(os.path.isfile(self.TEST_SNAPPATH))
def test_initialize_connection(self):
"""Expected behaviour for initialize_connection."""
ret = self._driver.initialize_connection(self.TEST_VOLUME, None)
self.assertEqual(ret['driver_volume_type'], 'scality')
self.assertEqual(ret['data']['sofs_path'],
os.path.join(self.TEST_VOLDIR,
self.TEST_VOLNAME))

View File

@ -1,64 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Wenhao Xu
# 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.
from manila import exception
from manila import test
from manila.volume.drivers.sheepdog import SheepdogDriver
COLLIE_NODE_INFO = """
0 107287605248 3623897354 3%
Total 107287605248 3623897354 3% 54760833024
"""
class SheepdogTestCase(test.TestCase):
def setUp(self):
super(SheepdogTestCase, self).setUp()
self.driver = SheepdogDriver()
def test_update_volume_stats(self):
def fake_stats(*args):
return COLLIE_NODE_INFO, ''
self.stubs.Set(self.driver, '_execute', fake_stats)
expected = dict(
volume_backend_name='sheepdog',
vendor_name='Open Source',
dirver_version='1.0',
storage_protocol='sheepdog',
total_capacity_gb=float(107287605248) / (1024 ** 3),
free_capacity_gb=float(107287605248 - 3623897354) / (1024 ** 3),
reserved_percentage=0,
QoS_support=False)
actual = self.driver.get_volume_stats(True)
self.assertDictMatch(expected, actual)
def test_update_volume_stats_error(self):
def fake_stats(*args):
raise exception.ProcessExecutionError()
self.stubs.Set(self.driver, '_execute', fake_stats)
expected = dict(
volume_backend_name='sheepdog',
vendor_name='Open Source',
dirver_version='1.0',
storage_protocol='sheepdog',
total_capacity_gb='unknown',
free_capacity_gb='unknown',
reserved_percentage=0,
QoS_support=False)
actual = self.driver.get_volume_stats(True)
self.assertDictMatch(expected, actual)

View File

@ -1,283 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
# 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 mox
from mox import IgnoreArg
from mox import IsA
from mox import stubout
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers.solidfire import SolidFire
LOG = logging.getLogger(__name__)
def create_configuration():
configuration = mox.MockObject(conf.Configuration)
configuration.san_is_local = False
configuration.append_config_values(mox.IgnoreArg())
return configuration
class SolidFireVolumeTestCase(test.TestCase):
def setUp(self):
self._mox = mox.Mox()
self.configuration = mox.MockObject(conf.Configuration)
self.configuration.sf_allow_tenant_qos = True
self.configuration.san_is_local = True
self.configuration.sf_emulate_512 = True
self.configuration.sf_account_prefix = 'manila'
super(SolidFireVolumeTestCase, self).setUp()
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
def fake_issue_api_request(obj, method, params):
if method is 'GetClusterCapacity':
LOG.info('Called Fake GetClusterCapacity...')
data = {}
data = {'result':
{'clusterCapacity': {'maxProvisionedSpace': 99999999,
'usedSpace': 999,
'compressionPercent': 100,
'deDuplicationPercent': 100,
'thinProvisioningPercent': 100}}}
return data
if method is 'GetClusterInfo':
LOG.info('Called Fake GetClusterInfo...')
results = {'result': {'clusterInfo':
{'name': 'fake-cluster',
'mvip': '1.1.1.1',
'svip': '1.1.1.1',
'uniqueID': 'unqid',
'repCount': 2,
'attributes': {}}}}
return results
elif method is 'AddAccount':
LOG.info('Called Fake AddAccount...')
return {'result': {'accountID': 25}, 'id': 1}
elif method is 'GetAccountByName':
LOG.info('Called Fake GetAccountByName...')
results = {'result': {'account':
{'accountID': 25,
'username': params['username'],
'status': 'active',
'initiatorSecret': '123456789012',
'targetSecret': '123456789012',
'attributes': {},
'volumes': [6, 7, 20]}},
"id": 1}
return results
elif method is 'CreateVolume':
LOG.info('Called Fake CreateVolume...')
return {'result': {'volumeID': 5}, 'id': 1}
elif method is 'DeleteVolume':
LOG.info('Called Fake DeleteVolume...')
return {'result': {}, 'id': 1}
elif method is 'ListVolumesForAccount':
test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66'
LOG.info('Called Fake ListVolumesForAccount...')
result = {'result': {
'volumes': [{'volumeID': 5,
'name': test_name,
'accountID': 25,
'sliceCount': 1,
'totalSize': 1048576 * 1024,
'enable512e': True,
'access': "readWrite",
'status': "active",
'attributes': None,
'qos': None,
'iqn': test_name}]}}
return result
else:
LOG.error('Crap, unimplemented API call in Fake:%s' % method)
def fake_issue_api_request_fails(obj, method, params):
return {'error': {'code': 000,
'name': 'DummyError',
'message': 'This is a fake error response'},
'id': 1}
def fake_set_qos_by_volume_type(self, type_id, ctxt):
return {'minIOPS': 500,
'maxIOPS': 1000,
'burstIOPS': 1000}
def fake_volume_get(obj, key, default=None):
return {'qos': 'fast'}
def fake_update_cluster_status(self):
return
def test_create_with_qos_type(self):
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
self.stubs.Set(SolidFire, '_set_qos_by_volume_type',
self.fake_set_qos_by_volume_type)
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'volume_type_id': 'fast'}
sfv = SolidFire(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
self.assertNotEqual(model_update, None)
def test_create_volume(self):
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'volume_type_id': None}
sfv = SolidFire(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
self.assertNotEqual(model_update, None)
def test_create_volume_with_qos(self):
preset_qos = {}
preset_qos['qos'] = 'fast'
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'metadata': [preset_qos],
'volume_type_id': None}
sfv = SolidFire(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
self.assertNotEqual(model_update, None)
def test_create_volume_fails(self):
# NOTE(JDG) This test just fakes update_cluster_status
# this is inentional for this test
self.stubs.Set(SolidFire, '_update_cluster_status',
self.fake_update_cluster_status)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request_fails)
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
sfv = SolidFire(configuration=self.configuration)
try:
sfv.create_volume(testvol)
self.fail("Should have thrown Error")
except Exception:
pass
def test_create_sfaccount(self):
sfv = SolidFire(configuration=self.configuration)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
account = sfv._create_sfaccount('project-id')
self.assertNotEqual(account, None)
def test_create_sfaccount_fails(self):
sfv = SolidFire(configuration=self.configuration)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request_fails)
account = sfv._create_sfaccount('project-id')
self.assertEqual(account, None)
def test_get_sfaccount_by_name(self):
sfv = SolidFire(configuration=self.configuration)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
account = sfv._get_sfaccount_by_name('some-name')
self.assertNotEqual(account, None)
def test_get_sfaccount_by_name_fails(self):
sfv = SolidFire(configuration=self.configuration)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request_fails)
account = sfv._get_sfaccount_by_name('some-name')
self.assertEqual(account, None)
def test_delete_volume(self):
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
testvol = {'project_id': 'testprjid',
'name': 'test_volume',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
sfv = SolidFire(configuration=self.configuration)
sfv.delete_volume(testvol)
def test_delete_volume_fails_no_volume(self):
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
testvol = {'project_id': 'testprjid',
'name': 'no-name',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
sfv = SolidFire(configuration=self.configuration)
try:
sfv.delete_volume(testvol)
self.fail("Should have thrown Error")
except Exception:
pass
def test_delete_volume_fails_account_lookup(self):
# NOTE(JDG) This test just fakes update_cluster_status
# this is inentional for this test
self.stubs.Set(SolidFire, '_update_cluster_status',
self.fake_update_cluster_status)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request_fails)
testvol = {'project_id': 'testprjid',
'name': 'no-name',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
sfv = SolidFire(configuration=self.configuration)
self.assertRaises(exception.SfAccountNotFound,
sfv.delete_volume,
testvol)
def test_get_cluster_info(self):
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
sfv = SolidFire(configuration=self.configuration)
sfv._get_cluster_info()
def test_get_cluster_info_fail(self):
# NOTE(JDG) This test just fakes update_cluster_status
# this is inentional for this test
self.stubs.Set(SolidFire, '_update_cluster_status',
self.fake_update_cluster_status)
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request_fails)
sfv = SolidFire(configuration=self.configuration)
self.assertRaises(exception.SolidFireAPIException,
sfv._get_cluster_info)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +0,0 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2012 Rackspace Hosting
# 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.
"""Tests for the configuration wrapper in volume drivers."""
from oslo.config import cfg
from manila import flags
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration
from manila.volume import driver
LOG = logging.getLogger(__name__)
FLAGS = flags.FLAGS
volume_opts = [
cfg.StrOpt('str_opt', default='STR_OPT'),
cfg.BoolOpt('bool_opt', default=False)
]
more_volume_opts = [
cfg.IntOpt('int_opt', default=1),
]
FLAGS.register_opts(volume_opts)
FLAGS.register_opts(more_volume_opts)
class VolumeConfigurationTest(test.TestCase):
def setUp(self):
super(VolumeConfigurationTest, self).setUp()
def tearDown(self):
super(VolumeConfigurationTest, self).tearDown()
def test_group_grafts_opts(self):
c = configuration.Configuration(volume_opts, config_group='foo')
self.assertEquals(c.str_opt, FLAGS.foo.str_opt)
self.assertEquals(c.bool_opt, FLAGS.foo.bool_opt)
def test_opts_no_group(self):
c = configuration.Configuration(volume_opts)
self.assertEquals(c.str_opt, FLAGS.str_opt)
self.assertEquals(c.bool_opt, FLAGS.bool_opt)
def test_grafting_multiple_opts(self):
c = configuration.Configuration(volume_opts, config_group='foo')
c.append_config_values(more_volume_opts)
self.assertEquals(c.str_opt, FLAGS.foo.str_opt)
self.assertEquals(c.bool_opt, FLAGS.foo.bool_opt)
self.assertEquals(c.int_opt, FLAGS.foo.int_opt)
def test_safe_get(self):
c = configuration.Configuration(volume_opts, config_group='foo')
self.assertEquals(c.safe_get('none_opt'), None)

View File

@ -1,131 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 Zadara Storage Inc.
# Copyright (c) 2011 OpenStack LLC.
# Copyright 2011 University of Southern California
# 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 volume types extra specs code
"""
from manila import context
from manila import db
from manila import exception
from manila import test
class VolumeGlanceMetadataTestCase(test.TestCase):
def setUp(self):
super(VolumeGlanceMetadataTestCase, self).setUp()
self.context = context.get_admin_context()
def tearDown(self):
super(VolumeGlanceMetadataTestCase, self).tearDown()
def test_vol_glance_metadata_bad_vol_id(self):
ctxt = context.get_admin_context()
self.assertRaises(exception.VolumeNotFound,
db.volume_glance_metadata_create,
ctxt, 1, 'key1', 'value1')
self.assertRaises(exception.VolumeNotFound,
db.volume_glance_metadata_get, ctxt, 1)
db.volume_glance_metadata_delete_by_volume(ctxt, 10)
def test_vol_update_glance_metadata(self):
ctxt = context.get_admin_context()
db.volume_create(ctxt, {'id': 1})
db.volume_create(ctxt, {'id': 2})
vol_metadata = db.volume_glance_metadata_create(ctxt, 1, 'key1',
'value1')
vol_metadata = db.volume_glance_metadata_create(ctxt, 2, 'key1',
'value1')
vol_metadata = db.volume_glance_metadata_create(ctxt, 2,
'key2',
'value2')
expected_metadata_1 = {'volume_id': '1',
'key': 'key1',
'value': 'value1'}
metadata = db.volume_glance_metadata_get(ctxt, 1)
self.assertEqual(len(metadata), 1)
for key, value in expected_metadata_1.items():
self.assertEqual(metadata[0][key], value)
expected_metadata_2 = ({'volume_id': '2',
'key': 'key1',
'value': 'value1'},
{'volume_id': '2',
'key': 'key2',
'value': 'value2'})
metadata = db.volume_glance_metadata_get(ctxt, 2)
self.assertEqual(len(metadata), 2)
for expected, meta in zip(expected_metadata_2, metadata):
for key, value in expected.iteritems():
self.assertEqual(meta[key], value)
self.assertRaises(exception.GlanceMetadataExists,
db.volume_glance_metadata_create,
ctxt, 1, 'key1', 'value1a')
metadata = db.volume_glance_metadata_get(ctxt, 1)
self.assertEqual(len(metadata), 1)
for key, value in expected_metadata_1.items():
self.assertEqual(metadata[0][key], value)
def test_vol_delete_glance_metadata(self):
ctxt = context.get_admin_context()
db.volume_create(ctxt, {'id': 1})
db.volume_glance_metadata_delete_by_volume(ctxt, 1)
vol_metadata = db.volume_glance_metadata_create(ctxt, 1, 'key1',
'value1')
db.volume_glance_metadata_delete_by_volume(ctxt, 1)
metadata = db.volume_glance_metadata_get(ctxt, 1)
self.assertEqual(len(metadata), 0)
db.volume_glance_metadata_delete_by_volume(ctxt, 1)
metadata = db.volume_glance_metadata_get(ctxt, 1)
self.assertEqual(len(metadata), 0)
def test_vol_glance_metadata_copy_to_snapshot(self):
ctxt = context.get_admin_context()
db.volume_create(ctxt, {'id': 1})
db.snapshot_create(ctxt, {'id': 100, 'volume_id': 1})
vol_meta = db.volume_glance_metadata_create(ctxt, 1, 'key1',
'value1')
db.volume_glance_metadata_copy_to_snapshot(ctxt, 100, 1)
expected_meta = {'snapshot_id': '100',
'key': 'key1',
'value': 'value1'}
for meta in db.volume_snapshot_glance_metadata_get(ctxt, 100):
for (key, value) in expected_meta.items():
self.assertEquals(meta[key], value)
def test_vol_glance_metadata_copy_to_volume(self):
ctxt = context.get_admin_context()
db.volume_create(ctxt, {'id': 1})
db.volume_create(ctxt, {'id': 100, 'source_volid': 1})
vol_meta = db.volume_glance_metadata_create(ctxt, 1, 'key1',
'value1')
db.volume_glance_metadata_copy_from_volume_to_volume(ctxt, 100, 1)
expected_meta = {'id': '100',
'key': 'key1',
'value': 'value1'}
for meta in db.volume_glance_metadata_get(ctxt, 100):
for (key, value) in expected_meta.items():
self.assertEquals(meta[key], value)

View File

@ -1,172 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012, Intel, Inc.
#
# 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 manila.volume.rpcapi
"""
from manila import context
from manila import db
from manila import flags
from manila.openstack.common import jsonutils
from manila.openstack.common import rpc
from manila import test
from manila.volume import rpcapi as volume_rpcapi
FLAGS = flags.FLAGS
class VolumeRpcAPITestCase(test.TestCase):
def setUp(self):
self.context = context.get_admin_context()
vol = {}
vol['host'] = 'fake_host'
vol['availability_zone'] = FLAGS.storage_availability_zone
vol['status'] = "available"
vol['attach_status'] = "detached"
volume = db.volume_create(self.context, vol)
snpshot = {
'volume_id': 'fake_id',
'status': "creating",
'progress': '0%',
'volume_size': 0,
'display_name': 'fake_name',
'display_description': 'fake_description'}
snapshot = db.snapshot_create(self.context, snpshot)
self.fake_volume = jsonutils.to_primitive(volume)
self.fake_snapshot = jsonutils.to_primitive(snapshot)
super(VolumeRpcAPITestCase, self).setUp()
def test_serialized_volume_has_id(self):
self.assertTrue('id' in self.fake_volume)
def _test_volume_api(self, method, rpc_method, **kwargs):
ctxt = context.RequestContext('fake_user', 'fake_project')
if 'rpcapi_class' in kwargs:
rpcapi_class = kwargs['rpcapi_class']
del kwargs['rpcapi_class']
else:
rpcapi_class = volume_rpcapi.VolumeAPI
rpcapi = rpcapi_class()
expected_retval = 'foo' if method == 'call' else None
expected_version = kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION)
expected_msg = rpcapi.make_msg(method, **kwargs)
if 'volume' in expected_msg['args']:
volume = expected_msg['args']['volume']
del expected_msg['args']['volume']
expected_msg['args']['volume_id'] = volume['id']
if 'snapshot' in expected_msg['args']:
snapshot = expected_msg['args']['snapshot']
del expected_msg['args']['snapshot']
expected_msg['args']['snapshot_id'] = snapshot['id']
if 'host' in expected_msg['args']:
del expected_msg['args']['host']
expected_msg['version'] = expected_version
if 'host' in kwargs:
host = kwargs['host']
else:
host = kwargs['volume']['host']
expected_topic = '%s.%s' % (FLAGS.volume_topic, host)
self.fake_args = None
self.fake_kwargs = None
def _fake_rpc_method(*args, **kwargs):
self.fake_args = args
self.fake_kwargs = kwargs
if expected_retval:
return expected_retval
self.stubs.Set(rpc, rpc_method, _fake_rpc_method)
retval = getattr(rpcapi, method)(ctxt, **kwargs)
self.assertEqual(retval, expected_retval)
expected_args = [ctxt, expected_topic, expected_msg]
for arg, expected_arg in zip(self.fake_args, expected_args):
self.assertEqual(arg, expected_arg)
def test_create_volume(self):
self._test_volume_api('create_volume',
rpc_method='cast',
volume=self.fake_volume,
host='fake_host1',
request_spec='fake_request_spec',
filter_properties='fake_properties',
allow_reschedule=True,
snapshot_id='fake_snapshot_id',
image_id='fake_image_id',
source_volid='fake_src_id',
version='1.4')
def test_delete_volume(self):
self._test_volume_api('delete_volume',
rpc_method='cast',
volume=self.fake_volume)
def test_create_snapshot(self):
self._test_volume_api('create_snapshot',
rpc_method='cast',
volume=self.fake_volume,
snapshot=self.fake_snapshot)
def test_delete_snapshot(self):
self._test_volume_api('delete_snapshot',
rpc_method='cast',
snapshot=self.fake_snapshot,
host='fake_host')
def test_attach_volume(self):
self._test_volume_api('attach_volume',
rpc_method='call',
volume=self.fake_volume,
instance_uuid='fake_uuid',
mountpoint='fake_mountpoint')
def test_detach_volume(self):
self._test_volume_api('detach_volume',
rpc_method='call',
volume=self.fake_volume)
def test_copy_volume_to_image(self):
self._test_volume_api('copy_volume_to_image',
rpc_method='cast',
volume=self.fake_volume,
image_meta={'id': 'fake_image_id',
'container_format': 'fake_type',
'disk_format': 'fake_type'},
version='1.3')
def test_initialize_connection(self):
self._test_volume_api('initialize_connection',
rpc_method='call',
volume=self.fake_volume,
connector='fake_connector')
def test_terminate_connection(self):
self._test_volume_api('terminate_connection',
rpc_method='call',
volume=self.fake_volume,
connector='fake_connector',
force=False)

View File

@ -1,187 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 Zadara Storage Inc.
# Copyright (c) 2011 OpenStack LLC.
# 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 volume types code
"""
import time
from manila import context
from manila.db.sqlalchemy import models
from manila.db.sqlalchemy import session as sql_session
from manila import exception
from manila import flags
from manila.openstack.common import log as logging
from manila import test
from manila.tests import fake_flags
from manila.volume import volume_types
FLAGS = flags.FLAGS
LOG = logging.getLogger(__name__)
class VolumeTypeTestCase(test.TestCase):
"""Test cases for volume type code."""
def setUp(self):
super(VolumeTypeTestCase, self).setUp()
self.ctxt = context.get_admin_context()
self.vol_type1_name = str(int(time.time()))
self.vol_type1_specs = dict(type="physical drive",
drive_type="SAS",
size="300",
rpm="7200",
visible="True")
def test_volume_type_create_then_destroy(self):
"""Ensure volume types can be created and deleted."""
prev_all_vtypes = volume_types.get_all_types(self.ctxt)
type_ref = volume_types.create(self.ctxt,
self.vol_type1_name,
self.vol_type1_specs)
new = volume_types.get_volume_type_by_name(self.ctxt,
self.vol_type1_name)
LOG.info(_("Given data: %s"), self.vol_type1_specs)
LOG.info(_("Result data: %s"), new)
for k, v in self.vol_type1_specs.iteritems():
self.assertEqual(v, new['extra_specs'][k],
'one of fields doesnt match')
new_all_vtypes = volume_types.get_all_types(self.ctxt)
self.assertEqual(len(prev_all_vtypes) + 1,
len(new_all_vtypes),
'drive type was not created')
volume_types.destroy(self.ctxt, type_ref['id'])
new_all_vtypes = volume_types.get_all_types(self.ctxt)
self.assertEqual(prev_all_vtypes,
new_all_vtypes,
'drive type was not deleted')
def test_get_all_volume_types(self):
"""Ensures that all volume types can be retrieved."""
session = sql_session.get_session()
total_volume_types = session.query(models.VolumeTypes).count()
vol_types = volume_types.get_all_types(self.ctxt)
self.assertEqual(total_volume_types, len(vol_types))
def test_get_default_volume_type(self):
"""Ensures default volume type can be retrieved."""
type_ref = volume_types.create(self.ctxt,
fake_flags.def_vol_type,
{})
default_vol_type = volume_types.get_default_volume_type()
self.assertEqual(default_vol_type.get('name'),
fake_flags.def_vol_type)
def test_default_volume_type_missing_in_db(self):
"""Ensures proper exception raised if default volume type
is not in database."""
session = sql_session.get_session()
default_vol_type = volume_types.get_default_volume_type()
self.assertEqual(default_vol_type, {})
def test_non_existent_vol_type_shouldnt_delete(self):
"""Ensures that volume type creation fails with invalid args."""
self.assertRaises(exception.VolumeTypeNotFound,
volume_types.destroy, self.ctxt, "sfsfsdfdfs")
def test_repeated_vol_types_shouldnt_raise(self):
"""Ensures that volume duplicates don't raise."""
new_name = self.vol_type1_name + "dup"
type_ref = volume_types.create(self.ctxt, new_name)
volume_types.destroy(self.ctxt, type_ref['id'])
type_ref = volume_types.create(self.ctxt, new_name)
def test_invalid_volume_types_params(self):
"""Ensures that volume type creation fails with invalid args."""
self.assertRaises(exception.InvalidVolumeType,
volume_types.destroy, self.ctxt, None)
self.assertRaises(exception.InvalidVolumeType,
volume_types.get_volume_type, self.ctxt, None)
self.assertRaises(exception.InvalidVolumeType,
volume_types.get_volume_type_by_name,
self.ctxt, None)
def test_volume_type_get_by_id_and_name(self):
"""Ensure volume types get returns same entry."""
volume_types.create(self.ctxt,
self.vol_type1_name,
self.vol_type1_specs)
new = volume_types.get_volume_type_by_name(self.ctxt,
self.vol_type1_name)
new2 = volume_types.get_volume_type(self.ctxt, new['id'])
self.assertEqual(new, new2)
def test_volume_type_search_by_extra_spec(self):
"""Ensure volume types get by extra spec returns correct type."""
volume_types.create(self.ctxt, "type1", {"key1": "val1",
"key2": "val2"})
volume_types.create(self.ctxt, "type2", {"key2": "val2",
"key3": "val3"})
volume_types.create(self.ctxt, "type3", {"key3": "another_value",
"key4": "val4"})
vol_types = volume_types.get_all_types(
self.ctxt,
search_opts={'extra_specs': {"key1": "val1"}})
LOG.info("vol_types: %s" % vol_types)
self.assertEqual(len(vol_types), 1)
self.assertTrue("type1" in vol_types.keys())
self.assertEqual(vol_types['type1']['extra_specs'],
{"key1": "val1", "key2": "val2"})
vol_types = volume_types.get_all_types(
self.ctxt,
search_opts={'extra_specs': {"key2": "val2"}})
LOG.info("vol_types: %s" % vol_types)
self.assertEqual(len(vol_types), 2)
self.assertTrue("type1" in vol_types.keys())
self.assertTrue("type2" in vol_types.keys())
vol_types = volume_types.get_all_types(
self.ctxt,
search_opts={'extra_specs': {"key3": "val3"}})
LOG.info("vol_types: %s" % vol_types)
self.assertEqual(len(vol_types), 1)
self.assertTrue("type2" in vol_types.keys())
def test_volume_type_search_by_extra_spec_multiple(self):
"""Ensure volume types get by extra spec returns correct type."""
volume_types.create(self.ctxt, "type1", {"key1": "val1",
"key2": "val2",
"key3": "val3"})
volume_types.create(self.ctxt, "type2", {"key2": "val2",
"key3": "val3"})
volume_types.create(self.ctxt, "type3", {"key1": "val1",
"key3": "val3",
"key4": "val4"})
vol_types = volume_types.get_all_types(
self.ctxt,
search_opts={'extra_specs': {"key1": "val1",
"key3": "val3"}})
LOG.info("vol_types: %s" % vol_types)
self.assertEqual(len(vol_types), 2)
self.assertTrue("type1" in vol_types.keys())
self.assertTrue("type3" in vol_types.keys())
self.assertEqual(vol_types['type1']['extra_specs'],
{"key1": "val1", "key2": "val2", "key3": "val3"})
self.assertEqual(vol_types['type3']['extra_specs'],
{"key1": "val1", "key3": "val3", "key4": "val4"})

View File

@ -1,130 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2011 Zadara Storage Inc.
# Copyright (c) 2011 OpenStack LLC.
# Copyright 2011 University of Southern California
# 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 volume types extra specs code
"""
from manila import context
from manila import db
from manila import test
class VolumeTypeExtraSpecsTestCase(test.TestCase):
def setUp(self):
super(VolumeTypeExtraSpecsTestCase, self).setUp()
self.context = context.get_admin_context()
self.vol_type1 = dict(name="TEST: Regular volume test")
self.vol_type1_specs = dict(vol_extra1="value1",
vol_extra2="value2",
vol_extra3=3)
self.vol_type1['extra_specs'] = self.vol_type1_specs
ref = db.volume_type_create(self.context, self.vol_type1)
self.volume_type1_id = ref.id
for k, v in self.vol_type1_specs.iteritems():
self.vol_type1_specs[k] = str(v)
self.vol_type2_noextra = dict(name="TEST: Volume type without extra")
ref = db.volume_type_create(self.context, self.vol_type2_noextra)
self.vol_type2_id = ref.id
def tearDown(self):
# Remove the volume type from the database
db.volume_type_destroy(context.get_admin_context(),
self.vol_type1['id'])
db.volume_type_destroy(context.get_admin_context(),
self.vol_type2_noextra['id'])
super(VolumeTypeExtraSpecsTestCase, self).tearDown()
def test_volume_type_specs_get(self):
expected_specs = self.vol_type1_specs.copy()
actual_specs = db.volume_type_extra_specs_get(
context.get_admin_context(),
self.volume_type1_id)
self.assertEquals(expected_specs, actual_specs)
def test_volume_type_extra_specs_delete(self):
expected_specs = self.vol_type1_specs.copy()
del expected_specs['vol_extra2']
db.volume_type_extra_specs_delete(context.get_admin_context(),
self.volume_type1_id,
'vol_extra2')
actual_specs = db.volume_type_extra_specs_get(
context.get_admin_context(),
self.volume_type1_id)
self.assertEquals(expected_specs, actual_specs)
def test_volume_type_extra_specs_update(self):
expected_specs = self.vol_type1_specs.copy()
expected_specs['vol_extra3'] = "4"
db.volume_type_extra_specs_update_or_create(
context.get_admin_context(),
self.volume_type1_id,
dict(vol_extra3=4))
actual_specs = db.volume_type_extra_specs_get(
context.get_admin_context(),
self.volume_type1_id)
self.assertEquals(expected_specs, actual_specs)
def test_volume_type_extra_specs_create(self):
expected_specs = self.vol_type1_specs.copy()
expected_specs['vol_extra4'] = 'value4'
expected_specs['vol_extra5'] = 'value5'
db.volume_type_extra_specs_update_or_create(
context.get_admin_context(),
self.volume_type1_id,
dict(vol_extra4="value4",
vol_extra5="value5"))
actual_specs = db.volume_type_extra_specs_get(
context.get_admin_context(),
self.volume_type1_id)
self.assertEquals(expected_specs, actual_specs)
def test_volume_type_get_with_extra_specs(self):
volume_type = db.volume_type_get(
context.get_admin_context(),
self.volume_type1_id)
self.assertEquals(volume_type['extra_specs'],
self.vol_type1_specs)
volume_type = db.volume_type_get(
context.get_admin_context(),
self.vol_type2_id)
self.assertEquals(volume_type['extra_specs'], {})
def test_volume_type_get_by_name_with_extra_specs(self):
volume_type = db.volume_type_get_by_name(
context.get_admin_context(),
self.vol_type1['name'])
self.assertEquals(volume_type['extra_specs'],
self.vol_type1_specs)
volume_type = db.volume_type_get_by_name(
context.get_admin_context(),
self.vol_type2_noextra['name'])
self.assertEquals(volume_type['extra_specs'], {})
def test_volume_type_get_all(self):
expected_specs = self.vol_type1_specs.copy()
types = db.volume_type_get_all(context.get_admin_context())
self.assertEquals(
types[self.vol_type1['name']]['extra_specs'], expected_specs)
self.assertEquals(
types[self.vol_type2_noextra['name']]['extra_specs'], {})

View File

@ -1,117 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# 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.
"""Tests For miscellaneous util methods used with volume."""
from manila import context
from manila import db
from manila import flags
from manila.openstack.common import importutils
from manila.openstack.common import log as logging
from manila.openstack.common.notifier import api as notifier_api
from manila.openstack.common.notifier import test_notifier
from manila import test
from manila.volume import utils as volume_utils
LOG = logging.getLogger(__name__)
FLAGS = flags.FLAGS
class UsageInfoTestCase(test.TestCase):
QUEUE_NAME = 'manila-volume'
HOSTNAME = 'my-host.com'
HOSTIP = '10.0.0.1'
BACKEND = 'test_backend'
MULTI_AT_BACKEND = 'test_b@ckend'
def setUp(self):
super(UsageInfoTestCase, self).setUp()
self.flags(connection_type='fake',
host='fake',
notification_driver=[test_notifier.__name__])
self.volume = importutils.import_object(FLAGS.volume_manager)
self.user_id = 'fake'
self.project_id = 'fake'
self.snapshot_id = 'fake'
self.volume_size = 0
self.context = context.RequestContext(self.user_id, self.project_id)
test_notifier.NOTIFICATIONS = []
def tearDown(self):
notifier_api._reset_drivers()
super(UsageInfoTestCase, self).tearDown()
def _create_volume(self, params={}):
"""Create a test volume."""
vol = {}
vol['snapshot_id'] = self.snapshot_id
vol['user_id'] = self.user_id
vol['project_id'] = self.project_id
vol['host'] = FLAGS.host
vol['availability_zone'] = FLAGS.storage_availability_zone
vol['status'] = "creating"
vol['attach_status'] = "detached"
vol['size'] = self.volume_size
vol.update(params)
return db.volume_create(self.context, vol)['id']
def test_notify_usage_exists(self):
"""Ensure 'exists' notification generates appropriate usage data."""
volume_id = self._create_volume()
volume = db.volume_get(self.context, volume_id)
volume_utils.notify_usage_exists(self.context, volume)
LOG.info("%r" % test_notifier.NOTIFICATIONS)
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
msg = test_notifier.NOTIFICATIONS[0]
self.assertEquals(msg['priority'], 'INFO')
self.assertEquals(msg['event_type'], 'volume.exists')
payload = msg['payload']
self.assertEquals(payload['tenant_id'], self.project_id)
self.assertEquals(payload['user_id'], self.user_id)
self.assertEquals(payload['snapshot_id'], self.snapshot_id)
self.assertEquals(payload['volume_id'], volume.id)
self.assertEquals(payload['size'], self.volume_size)
for attr in ('display_name', 'created_at', 'launched_at',
'status', 'audit_period_beginning',
'audit_period_ending'):
self.assertTrue(attr in payload,
msg="Key %s not in payload" % attr)
db.volume_destroy(context.get_admin_context(), volume['id'])
def test_get_host_from_queue_simple(self):
fullname = "%s.%s@%s" % (self.QUEUE_NAME, self.HOSTNAME, self.BACKEND)
self.assertEquals(volume_utils.get_host_from_queue(fullname),
self.HOSTNAME)
def test_get_host_from_queue_ip(self):
fullname = "%s.%s@%s" % (self.QUEUE_NAME, self.HOSTIP, self.BACKEND)
self.assertEquals(volume_utils.get_host_from_queue(fullname),
self.HOSTIP)
def test_get_host_from_queue_multi_at_symbol(self):
fullname = "%s.%s@%s" % (self.QUEUE_NAME, self.HOSTNAME,
self.MULTI_AT_BACKEND)
self.assertEquals(volume_utils.get_host_from_queue(fullname),
self.HOSTNAME)
def test_get_host_from_queue_ip_multi_at_symbol(self):
fullname = "%s.%s@%s" % (self.QUEUE_NAME, self.HOSTIP,
self.MULTI_AT_BACKEND)
self.assertEquals(volume_utils.get_host_from_queue(fullname),
self.HOSTIP)

View File

@ -1,220 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Pedro Navarro Perez
# 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 Windows Server 2012 OpenStack Manila volume driver
"""
import sys
import manila.flags
from manila.tests.windows import basetestcase
from manila.tests.windows import db_fakes
from manila.tests.windows import windowsutils
from manila.volume.drivers import windows
FLAGS = manila.flags.FLAGS
class TestWindowsDriver(basetestcase.BaseTestCase):
def __init__(self, method):
super(TestWindowsDriver, self).__init__(method)
def setUp(self):
super(TestWindowsDriver, self).setUp()
self.flags(
windows_iscsi_lun_path='C:\iSCSIVirtualDisks',
)
self._volume_data = None
self._volume_data_2 = None
self._snapshot_data = None
self._connector_data = None
self._volume_id = '10958016-e196-42e3-9e7f-5d8927ae3099'
self._volume_id_2 = '20958016-e196-42e3-9e7f-5d8927ae3098'
self._snapshot_id = '30958016-e196-42e3-9e7f-5d8927ae3097'
self._iqn = "iqn.1991-05.com.microsoft:dell1160dsy"
self._setup_stubs()
self._drv = windows.WindowsDriver()
self._drv.do_setup({})
self._wutils = windowsutils.WindowsUtils()
def _setup_stubs(self):
# Modules to mock
modules_to_mock = [
'wmi',
'os',
'subprocess',
'multiprocessing'
]
modules_to_test = [
windows,
windowsutils,
sys.modules[__name__]
]
self._inject_mocks_in_modules(modules_to_mock, modules_to_test)
def tearDown(self):
try:
if (self._volume_data_2 and
self._wutils.volume_exists(self._volume_data_2['name'])):
self._wutils.delete_volume(self._volume_data_2['name'])
if (self._volume_data and
self._wutils.volume_exists(
self._volume_data['name'])):
self._wutils.delete_volume(self._volume_data['name'])
if (self._snapshot_data and
self._wutils.snapshot_exists(
self._snapshot_data['name'])):
self._wutils.delete_snapshot(self._snapshot_data['name'])
if (self._connector_data and
self._wutils.initiator_id_exists(
"%s%s" % (FLAGS.iscsi_target_prefix,
self._volume_data['name']),
self._connector_data['initiator'])):
target_name = "%s%s" % (FLAGS.iscsi_target_prefix,
self._volume_data['name'])
initiator_name = self._connector_data['initiator']
self._wutils.delete_initiator_id(target_name, initiator_name)
if (self._volume_data and
self._wutils.export_exists("%s%s" %
(FLAGS.iscsi_target_prefix,
self._volume_data['name']))):
self._wutils.delete_export(
"%s%s" % (FLAGS.iscsi_target_prefix,
self._volume_data['name']))
finally:
super(TestWindowsDriver, self).tearDown()
def test_check_for_setup_errors(self):
self._drv.check_for_setup_error()
def test_create_volume(self):
self._create_volume()
wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name'])
self.assertEquals(len(wt_disks), 1)
def _create_volume(self):
self._volume_data = db_fakes.get_fake_volume_info(self._volume_id)
self._drv.create_volume(self._volume_data)
def test_delete_volume(self):
self._create_volume()
self._drv.delete_volume(self._volume_data)
wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name'])
self.assertEquals(len(wt_disks), 0)
def test_create_snapshot(self):
#Create a volume
self._create_volume()
wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name'])
self.assertEquals(len(wt_disks), 1)
#Create a snapshot from the previous volume
self._create_snapshot()
snapshot_name = self._snapshot_data['name']
wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name)
self.assertEquals(len(wt_snapshots), 1)
def _create_snapshot(self):
volume_name = self._volume_data['name']
snapshot_id = self._snapshot_id
self._snapshot_data = db_fakes.get_fake_snapshot_info(volume_name,
snapshot_id)
self._drv.create_snapshot(self._snapshot_data)
def test_create_volume_from_snapshot(self):
#Create a volume
self._create_volume()
#Create a snapshot from the previous volume
self._create_snapshot()
self._volume_data_2 = db_fakes.get_fake_volume_info(self._volume_id_2)
self._drv.create_volume_from_snapshot(self._volume_data_2,
self._snapshot_data)
wt_disks = self._wutils.find_vhd_by_name(self._volume_data_2['name'])
self.assertEquals(len(wt_disks), 1)
def test_delete_snapshot(self):
#Create a volume
self._create_volume()
#Create a snapshot from the previous volume
self._create_snapshot()
self._drv.delete_snapshot(self._snapshot_data)
snapshot_name = self._snapshot_data['name']
wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name)
self.assertEquals(len(wt_snapshots), 0)
def test_create_export(self):
#Create a volume
self._create_volume()
retval = self._drv.create_export({}, self._volume_data)
volume_name = self._volume_data['name']
self.assertEquals(
retval,
{'provider_location': "%s%s" % (FLAGS.iscsi_target_prefix,
volume_name)})
def test_initialize_connection(self):
#Create a volume
self._create_volume()
self._drv.create_export({}, self._volume_data)
self._connector_data = db_fakes.get_fake_connector_info(self._iqn)
init_data = self._drv.initialize_connection(self._volume_data,
self._connector_data)
target_name = self._volume_data['provider_location']
initiator_name = self._connector_data['initiator']
wt_initiator_ids = self._wutils.find_initiator_ids(target_name,
initiator_name)
self.assertEquals(len(wt_initiator_ids), 1)
properties = init_data['data']
self.assertNotEqual(properties['target_iqn'], None)
def test_ensure_export(self):
#Create a volume
self._create_volume()
self._drv.ensure_export({}, self._volume_data)
def test_remove_export(self):
#Create a volume
self._create_volume()
self._drv.create_export({}, self._volume_data)
self._drv.remove_export({}, self._volume_data)

View File

@ -1,509 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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 contextlib
import StringIO
import unittest
import mock
import mox
from oslo.config import cfg
from manila.db import api as db_api
from manila import exception
from manila.volume import configuration as conf
from manila.volume import driver as parent_driver
from manila.volume.drivers.xenapi import lib
from manila.volume.drivers.xenapi import sm as driver
from manila.volume.drivers.xenapi import tools
class MockContext(object):
def __init__(ctxt, auth_token):
ctxt.auth_token = auth_token
@contextlib.contextmanager
def simple_context(value):
yield value
def get_configured_driver(server='ignore_server', path='ignore_path'):
configuration = mox.MockObject(conf.Configuration)
configuration.xenapi_nfs_server = server
configuration.xenapi_nfs_serverpath = path
configuration.append_config_values(mox.IgnoreArg())
return driver.XenAPINFSDriver(configuration=configuration)
class DriverTestCase(unittest.TestCase):
def assert_flag(self, flagname):
self.assertTrue(hasattr(driver.FLAGS, flagname))
def test_config_options(self):
self.assert_flag('xenapi_connection_url')
self.assert_flag('xenapi_connection_username')
self.assert_flag('xenapi_connection_password')
self.assert_flag('xenapi_nfs_server')
self.assert_flag('xenapi_nfs_serverpath')
self.assert_flag('xenapi_sr_base_path')
def test_do_setup(self):
mock = mox.Mox()
mock.StubOutWithMock(driver, 'xenapi_lib')
mock.StubOutWithMock(driver, 'xenapi_opts')
configuration = mox.MockObject(conf.Configuration)
configuration.xenapi_connection_url = 'url'
configuration.xenapi_connection_username = 'user'
configuration.xenapi_connection_password = 'pass'
configuration.append_config_values(mox.IgnoreArg())
session_factory = object()
nfsops = object()
driver.xenapi_lib.SessionFactory('url', 'user', 'pass').AndReturn(
session_factory)
driver.xenapi_lib.NFSBasedVolumeOperations(
session_factory).AndReturn(nfsops)
drv = driver.XenAPINFSDriver(configuration=configuration)
mock.ReplayAll()
drv.do_setup('context')
mock.VerifyAll()
self.assertEquals(nfsops, drv.nfs_ops)
def test_create_volume(self):
mock = mox.Mox()
ops = mock.CreateMock(lib.NFSBasedVolumeOperations)
drv = get_configured_driver('server', 'path')
drv.nfs_ops = ops
volume_details = dict(
sr_uuid='sr_uuid',
vdi_uuid='vdi_uuid'
)
ops.create_volume(
'server', 'path', 1, 'name', 'desc').AndReturn(volume_details)
mock.ReplayAll()
result = drv.create_volume(dict(
size=1, display_name='name', display_description='desc'))
mock.VerifyAll()
self.assertEquals(dict(provider_location='sr_uuid/vdi_uuid'), result)
def test_delete_volume(self):
mock = mox.Mox()
ops = mock.CreateMock(lib.NFSBasedVolumeOperations)
drv = get_configured_driver('server', 'path')
drv.nfs_ops = ops
ops.delete_volume('server', 'path', 'sr_uuid', 'vdi_uuid')
mock.ReplayAll()
result = drv.delete_volume(dict(
provider_location='sr_uuid/vdi_uuid'))
mock.VerifyAll()
def test_create_export_does_not_raise_exception(self):
configuration = conf.Configuration([])
drv = driver.XenAPINFSDriver(configuration=configuration)
drv.create_export('context', 'volume')
def test_remove_export_does_not_raise_exception(self):
configuration = conf.Configuration([])
drv = driver.XenAPINFSDriver(configuration=configuration)
drv.remove_export('context', 'volume')
def test_initialize_connection(self):
mock = mox.Mox()
drv = get_configured_driver('server', 'path')
mock.ReplayAll()
result = drv.initialize_connection(
dict(
display_name='name',
display_description='desc',
provider_location='sr_uuid/vdi_uuid'),
'connector'
)
mock.VerifyAll()
self.assertEquals(
dict(
driver_volume_type='xensm',
data=dict(
name_label='name',
name_description='desc',
sr_uuid='sr_uuid',
vdi_uuid='vdi_uuid',
sr_type='nfs',
server='server',
serverpath='path',
introduce_sr_keys=['sr_type', 'server', 'serverpath']
)
),
result
)
def test_initialize_connection_null_values(self):
mock = mox.Mox()
drv = get_configured_driver('server', 'path')
mock.ReplayAll()
result = drv.initialize_connection(
dict(
display_name=None,
display_description=None,
provider_location='sr_uuid/vdi_uuid'),
'connector'
)
mock.VerifyAll()
self.assertEquals(
dict(
driver_volume_type='xensm',
data=dict(
name_label='',
name_description='',
sr_uuid='sr_uuid',
vdi_uuid='vdi_uuid',
sr_type='nfs',
server='server',
serverpath='path',
introduce_sr_keys=['sr_type', 'server', 'serverpath']
)
),
result
)
def _setup_mock_driver(self, server, serverpath, sr_base_path="_srbp"):
mock = mox.Mox()
drv = get_configured_driver(server, serverpath)
ops = mock.CreateMock(lib.NFSBasedVolumeOperations)
db = mock.CreateMock(db_api)
drv.nfs_ops = ops
drv.db = db
mock.StubOutWithMock(driver, 'FLAGS')
driver.FLAGS.xenapi_nfs_server = server
driver.FLAGS.xenapi_nfs_serverpath = serverpath
driver.FLAGS.xenapi_sr_base_path = sr_base_path
return mock, drv
def test_create_snapshot(self):
mock, drv = self._setup_mock_driver('server', 'serverpath')
snapshot = dict(
volume_id="volume-id",
display_name="snapshot-name",
display_description="snapshot-desc",
volume=dict(provider_location="sr-uuid/vdi-uuid"))
drv.nfs_ops.copy_volume(
"server", "serverpath", "sr-uuid", "vdi-uuid",
"snapshot-name", "snapshot-desc"
).AndReturn(dict(sr_uuid="copied-sr", vdi_uuid="copied-vdi"))
mock.ReplayAll()
result = drv.create_snapshot(snapshot)
mock.VerifyAll()
self.assertEquals(
dict(provider_location="copied-sr/copied-vdi"),
result)
def test_create_volume_from_snapshot(self):
mock, drv = self._setup_mock_driver('server', 'serverpath')
snapshot = dict(
provider_location='src-sr-uuid/src-vdi-uuid')
volume = dict(
display_name='tgt-name', name_description='tgt-desc')
drv.nfs_ops.copy_volume(
"server", "serverpath", "src-sr-uuid", "src-vdi-uuid",
"tgt-name", "tgt-desc"
).AndReturn(dict(sr_uuid="copied-sr", vdi_uuid="copied-vdi"))
mock.ReplayAll()
result = drv.create_volume_from_snapshot(volume, snapshot)
mock.VerifyAll()
self.assertEquals(
dict(provider_location='copied-sr/copied-vdi'), result)
def test_delete_snapshot(self):
mock, drv = self._setup_mock_driver('server', 'serverpath')
snapshot = dict(
provider_location='src-sr-uuid/src-vdi-uuid')
drv.nfs_ops.delete_volume(
"server", "serverpath", "src-sr-uuid", "src-vdi-uuid")
mock.ReplayAll()
drv.delete_snapshot(snapshot)
mock.VerifyAll()
def test_copy_volume_to_image_xenserver_case(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
mock.StubOutWithMock(drv, '_use_glance_plugin_to_upload_volume')
mock.StubOutWithMock(driver, 'is_xenserver_format')
context = MockContext('token')
driver.is_xenserver_format('image_meta').AndReturn(True)
drv._use_glance_plugin_to_upload_volume(
context, 'volume', 'image_service', 'image_meta').AndReturn(
'result')
mock.ReplayAll()
result = drv.copy_volume_to_image(
context, "volume", "image_service", "image_meta")
self.assertEquals('result', result)
mock.VerifyAll()
def test_copy_volume_to_image_non_xenserver_case(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
mock.StubOutWithMock(drv, '_use_image_utils_to_upload_volume')
mock.StubOutWithMock(driver, 'is_xenserver_format')
context = MockContext('token')
driver.is_xenserver_format('image_meta').AndReturn(False)
drv._use_image_utils_to_upload_volume(
context, 'volume', 'image_service', 'image_meta').AndReturn(
'result')
mock.ReplayAll()
result = drv.copy_volume_to_image(
context, "volume", "image_service", "image_meta")
self.assertEquals('result', result)
mock.VerifyAll()
def test_use_image_utils_to_upload_volume(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
volume = dict(provider_location='sr-uuid/vdi-uuid')
context = MockContext('token')
mock.StubOutWithMock(driver.image_utils, 'upload_volume')
drv.nfs_ops.volume_attached_here(
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', True).AndReturn(
simple_context('device'))
driver.image_utils.upload_volume(
context, 'image_service', 'image_meta', 'device')
mock.ReplayAll()
drv._use_image_utils_to_upload_volume(
context, volume, "image_service", "image_meta")
mock.VerifyAll()
def test_use_glance_plugin_to_upload_volume(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
volume = dict(provider_location='sr-uuid/vdi-uuid')
context = MockContext('token')
mock.StubOutWithMock(driver.glance, 'get_api_servers')
driver.glance.get_api_servers().AndReturn((x for x in ['glancesrv']))
drv.nfs_ops.use_glance_plugin_to_upload_volume(
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 'glancesrv',
'image-id', 'token', '/var/run/sr-mount')
mock.ReplayAll()
drv._use_glance_plugin_to_upload_volume(
context, volume, "image_service", {"id": "image-id"})
mock.VerifyAll()
def test_copy_image_to_volume_xenserver_case(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
mock.StubOutWithMock(drv, '_use_glance_plugin_to_copy_image_to_volume')
mock.StubOutWithMock(driver, 'is_xenserver_image')
context = MockContext('token')
driver.is_xenserver_image(
context, 'image_service', 'image_id').AndReturn(True)
drv._use_glance_plugin_to_copy_image_to_volume(
context, 'volume', 'image_service', 'image_id').AndReturn('result')
mock.ReplayAll()
result = drv.copy_image_to_volume(
context, "volume", "image_service", "image_id")
self.assertEquals('result', result)
mock.VerifyAll()
def test_copy_image_to_volume_non_xenserver_case(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
mock.StubOutWithMock(drv, '_use_image_utils_to_pipe_bytes_to_volume')
mock.StubOutWithMock(driver, 'is_xenserver_image')
context = MockContext('token')
driver.is_xenserver_image(
context, 'image_service', 'image_id').AndReturn(False)
drv._use_image_utils_to_pipe_bytes_to_volume(
context, 'volume', 'image_service', 'image_id').AndReturn(True)
mock.ReplayAll()
drv.copy_image_to_volume(
context, "volume", "image_service", "image_id")
mock.VerifyAll()
def test_use_image_utils_to_pipe_bytes_to_volume(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
volume = dict(provider_location='sr-uuid/vdi-uuid')
context = MockContext('token')
mock.StubOutWithMock(driver.image_utils, 'fetch_to_raw')
drv.nfs_ops.volume_attached_here(
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', False).AndReturn(
simple_context('device'))
driver.image_utils.fetch_to_raw(
context, 'image_service', 'image_id', 'device')
mock.ReplayAll()
drv._use_image_utils_to_pipe_bytes_to_volume(
context, volume, "image_service", "image_id")
mock.VerifyAll()
def test_use_glance_plugin_to_copy_image_to_volume_success(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
volume = dict(
provider_location='sr-uuid/vdi-uuid',
size=2)
mock.StubOutWithMock(driver.glance, 'get_api_servers')
driver.glance.get_api_servers().AndReturn((x for x in ['glancesrv']))
drv.nfs_ops.use_glance_plugin_to_overwrite_volume(
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 'glancesrv',
'image_id', 'token', '/var/run/sr-mount').AndReturn(True)
drv.nfs_ops.resize_volume(
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 2)
mock.ReplayAll()
drv._use_glance_plugin_to_copy_image_to_volume(
MockContext('token'), volume, "ignore", "image_id")
mock.VerifyAll()
def test_use_glance_plugin_to_copy_image_to_volume_fail(self):
mock, drv = self._setup_mock_driver(
'server', 'serverpath', '/var/run/sr-mount')
volume = dict(
provider_location='sr-uuid/vdi-uuid',
size=2)
mock.StubOutWithMock(driver.glance, 'get_api_servers')
driver.glance.get_api_servers().AndReturn((x for x in ['glancesrv']))
drv.nfs_ops.use_glance_plugin_to_overwrite_volume(
'server', 'serverpath', 'sr-uuid', 'vdi-uuid', 'glancesrv',
'image_id', 'token', '/var/run/sr-mount').AndReturn(False)
mock.ReplayAll()
self.assertRaises(
exception.ImageCopyFailure,
lambda: drv._use_glance_plugin_to_copy_image_to_volume(
MockContext('token'), volume, "ignore", "image_id"))
mock.VerifyAll()
def test_get_volume_stats_reports_required_keys(self):
drv = get_configured_driver()
stats = drv.get_volume_stats()
required_metrics = [
'volume_backend_name', 'vendor_name', 'driver_version',
'storage_protocol', 'total_capacity_gb', 'free_capacity_gb',
'reserved_percentage'
]
for metric in required_metrics:
self.assertTrue(metric in stats)
def test_get_volume_stats_reports_unknown_cap(self):
drv = get_configured_driver()
stats = drv.get_volume_stats()
self.assertEquals('unknown', stats['free_capacity_gb'])
def test_reported_driver_type(self):
drv = get_configured_driver()
stats = drv.get_volume_stats()
self.assertEquals('xensm', stats['storage_protocol'])
class ToolsTest(unittest.TestCase):
@mock.patch('manila.volume.drivers.xenapi.tools._stripped_first_line_of')
def test_get_this_vm_uuid(self, mock_read_first_line):
mock_read_first_line.return_value = 'someuuid'
self.assertEquals('someuuid', tools.get_this_vm_uuid())
mock_read_first_line.assert_called_once_with('/sys/hypervisor/uuid')
def test_stripped_first_line_of(self):
mock_context_manager = mock.Mock()
mock_context_manager.__enter__ = mock.Mock(
return_value=StringIO.StringIO(' blah \n second line \n'))
mock_context_manager.__exit__ = mock.Mock(return_value=False)
mock_open = mock.Mock(return_value=mock_context_manager)
with mock.patch('__builtin__.open', mock_open):
self.assertEquals(
'blah', tools._stripped_first_line_of('/somefile'))
mock_open.assert_called_once_with('/somefile', 'rb')

View File

@ -1,245 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 IBM Corp.
# Copyright (c) 2012 OpenStack LLC.
# 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.
#
# Authors:
# Erik Zaadi <erikz@il.ibm.com>
# Avishay Traeger <avishay@il.ibm.com>
import mox
from manila import exception
from manila import flags
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers import xiv
FLAGS = flags.FLAGS
FAKE = "fake"
VOLUME = {'size': 16,
'name': FAKE,
'id': 1}
CONNECTOR = {'initiator': "iqn.2012-07.org.fake:01:948f189c4695", }
class XIVFakeProxyDriver(object):
"""Fake XIV Proxy Driver."""
def __init__(self, xiv_info, logger, expt):
"""
Initialize Proxy
"""
self.xiv_info = xiv_info
self.logger = logger
self.exception = expt
self.xiv_portal = \
self.xiv_iqn = FAKE
self.volumes = {}
def setup(self, context):
if self.xiv_info['xiv_user'] != FLAGS.san_login:
raise self.exception.NotAuthorized()
if self.xiv_info['xiv_address'] != FLAGS.san_ip:
raise self.exception.HostNotFound(host='fake')
def create_volume(self, volume):
if volume['size'] > 100:
raise self.exception.VolumeBackendAPIException(data='blah')
self.volumes[volume['name']] = volume
def volume_exists(self, volume):
return self.volumes.get(volume['name'], None) is not None
def delete_volume(self, volume):
if self.volumes.get(volume['name'], None) is not None:
del self.volumes[volume['name']]
def initialize_connection(self, volume, connector):
if not self.volume_exists(volume):
raise self.exception.VolumeNotFound(volume_id=volume['id'])
lun_id = volume['id']
self.volumes[volume['name']]['attached'] = connector
return {'driver_volume_type': 'iscsi',
'data': {'target_discovered': True,
'target_discovered': True,
'target_portal': self.xiv_portal,
'target_iqn': self.xiv_iqn,
'target_lun': lun_id,
'volume_id': volume['id'],
'multipath': True,
'provider_location': "%s,1 %s %s" % (
self.xiv_portal,
self.xiv_iqn,
lun_id), },
}
def terminate_connection(self, volume, connector):
if not self.volume_exists(volume):
raise self.exception.VolumeNotFound(volume_id=volume['id'])
if not self.is_volume_attached(volume, connector):
raise self.exception.VolumeNotFoundForInstance(instance_id='fake')
del self.volumes[volume['name']]['attached']
def is_volume_attached(self, volume, connector):
if not self.volume_exists(volume):
raise self.exception.VolumeNotFound(volume_id=volume['id'])
return (self.volumes[volume['name']].get('attached', None)
== connector)
class XIVVolumeDriverTest(test.TestCase):
"""Test IBM XIV volume driver."""
def setUp(self):
"""Initialize IVM XIV Driver."""
super(XIVVolumeDriverTest, self).setUp()
configuration = mox.MockObject(conf.Configuration)
configuration.san_is_local = False
configuration.append_config_values(mox.IgnoreArg())
self.driver = xiv.XIVDriver(configuration=configuration)
def test_initialized_should_set_xiv_info(self):
"""Test that the san flags are passed to the XIV proxy."""
self.assertEquals(self.driver.xiv_proxy.xiv_info['xiv_user'],
FLAGS.san_login)
self.assertEquals(self.driver.xiv_proxy.xiv_info['xiv_pass'],
FLAGS.san_password)
self.assertEquals(self.driver.xiv_proxy.xiv_info['xiv_address'],
FLAGS.san_ip)
self.assertEquals(self.driver.xiv_proxy.xiv_info['xiv_vol_pool'],
FLAGS.san_clustername)
def test_setup_should_fail_if_credentials_are_invalid(self):
"""Test that the xiv_proxy validates credentials."""
self.driver.xiv_proxy.xiv_info['xiv_user'] = 'invalid'
self.assertRaises(exception.NotAuthorized, self.driver.do_setup, None)
def test_setup_should_fail_if_connection_is_invalid(self):
"""Test that the xiv_proxy validates connection."""
self.driver.xiv_proxy.xiv_info['xiv_address'] = 'invalid'
self.assertRaises(exception.HostNotFound, self.driver.do_setup, None)
def test_create_volume(self):
"""Test creating a volume."""
self.driver.do_setup(None)
self.driver.create_volume(VOLUME)
has_volume = self.driver.xiv_proxy.volume_exists(VOLUME)
self.assertTrue(has_volume)
self.driver.delete_volume(VOLUME)
def test_volume_exists(self):
"""Test the volume exist method with a volume that doesn't exist."""
self.driver.do_setup(None)
self.assertFalse(self.driver.xiv_proxy.volume_exists({'name': FAKE}))
def test_delete_volume(self):
"""Verify that a volume is deleted."""
self.driver.do_setup(None)
self.driver.create_volume(VOLUME)
self.driver.delete_volume(VOLUME)
has_volume = self.driver.xiv_proxy.volume_exists(VOLUME)
self.assertFalse(has_volume)
def test_delete_volume_should_fail_for_not_existing_volume(self):
"""Verify that deleting a non-existing volume is OK."""
self.driver.do_setup(None)
self.driver.delete_volume(VOLUME)
def test_create_volume_should_fail_if_no_pool_space_left(self):
"""Vertify that the xiv_proxy validates volume pool space."""
self.driver.do_setup(None)
self.assertRaises(exception.ShareBackendAPIException,
self.driver.create_volume,
{'name': FAKE,
'id': 1,
'size': 12000})
def test_initialize_connection(self):
"""Test that inititialize connection attaches volume to host."""
self.driver.do_setup(None)
self.driver.create_volume(VOLUME)
self.driver.initialize_connection(VOLUME, CONNECTOR)
self.assertTrue(
self.driver.xiv_proxy.is_volume_attached(VOLUME, CONNECTOR))
self.driver.terminate_connection(VOLUME, CONNECTOR)
self.driver.delete_volume(VOLUME)
def test_initialize_connection_should_fail_for_non_existing_volume(self):
"""Verify that initialize won't work for non-existing volume."""
self.driver.do_setup(None)
self.assertRaises(exception.VolumeNotFound,
self.driver.initialize_connection,
VOLUME,
CONNECTOR)
def test_terminate_connection(self):
"""Test terminating a connection."""
self.driver.do_setup(None)
self.driver.create_volume(VOLUME)
self.driver.initialize_connection(VOLUME, CONNECTOR)
self.driver.terminate_connection(VOLUME, CONNECTOR)
self.assertFalse(self.driver.xiv_proxy.is_volume_attached(VOLUME,
CONNECTOR))
self.driver.delete_volume(VOLUME)
def test_terminate_connection_should_fail_on_non_existing_volume(self):
"""Test that terminate won't work for non-existing volumes."""
self.driver.do_setup(None)
self.assertRaises(exception.VolumeNotFound,
self.driver.terminate_connection,
VOLUME,
CONNECTOR)
def test_terminate_connection_should_fail_on_non_attached_volume(self):
"""Test that terminate won't work for volumes that are not attached."""
self.driver.do_setup(None)
self.driver.create_volume(VOLUME)
self.assertRaises(exception.VolumeNotFoundForInstance,
self.driver.terminate_connection,
VOLUME,
CONNECTOR)
self.driver.delete_volume(VOLUME)

View File

@ -1,581 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2012 Zadara Storage, Inc.
# Copyright (c) 2012 OpenStack LLC.
# 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.
"""
Tests for Zadara VPSA volume driver
"""
import copy
import httplib
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.volume.drivers import zadara
from lxml import etree
LOG = logging.getLogger("manila.volume.driver")
DEFAULT_RUNTIME_VARS = {
'status': 200,
'user': 'test',
'password': 'test_password',
'access_key': '0123456789ABCDEF',
'volumes': [],
'servers': [],
'controllers': [('active_ctrl', {'display_name': 'test_ctrl'})],
'counter': 1000,
'login': """
<hash>
<user>
<updated-at type="datetime">2012-04-30...</updated-at>
<access-key>%s</access-key>
<id type="integer">1</id>
<created-at type="datetime">2012-02-21...</created-at>
<email>jsmith@example.com</email>
<username>jsmith</username>
</user>
<status type="integer">0</status>
</hash>""",
'good': """
<hash>
<status type="integer">0</status>
</hash>""",
'bad_login': """
<hash>
<status type="integer">5</status>
<status-msg>Some message...</status-msg>
</hash>""",
'bad_volume': """
<hash>
<status type="integer">10081</status>
<status-msg>Virtual volume xxx not found</status-msg>
</hash>""",
'bad_server': """
<hash>
<status type="integer">10086</status>
<status-msg>Server xxx not found</status-msg>
</hash>""",
'server_created': """
<create-server-response>
<server-name>%s</server-name>
<status type='integer'>0</status>
</create-server-response>""",
}
RUNTIME_VARS = None
class FakeRequest(object):
def __init__(self, method, url, body):
self.method = method
self.url = url
self.body = body
self.status = RUNTIME_VARS['status']
def read(self):
ops = {'POST': [('/api/users/login.xml', self._login),
('/api/volumes.xml', self._create_volume),
('/api/servers.xml', self._create_server),
('/api/servers/*/volumes.xml', self._attach),
('/api/volumes/*/detach.xml', self._detach)],
'DELETE': [('/api/volumes/*', self._delete)],
'GET': [('/api/volumes.xml', self._list_volumes),
('/api/vcontrollers.xml', self._list_controllers),
('/api/servers.xml', self._list_servers),
('/api/volumes/*/servers.xml',
self._list_vol_attachments)]
}
ops_list = ops[self.method]
modified_url = self.url.split('?')[0]
for (templ_url, func) in ops_list:
if self._compare_url(modified_url, templ_url):
result = func()
return result
def _compare_url(self, url, template_url):
items = url.split('/')
titems = template_url.split('/')
for (i, titem) in enumerate(titems):
if titem != '*' and titem != items[i]:
return False
return True
def _get_parameters(self, data):
items = data.split('&')
params = {}
for item in items:
if item:
(k, v) = item.split('=')
params[k] = v
return params
def _get_counter(self):
cnt = RUNTIME_VARS['counter']
RUNTIME_VARS['counter'] += 1
return cnt
def _login(self):
params = self._get_parameters(self.body)
if (params['user'] == RUNTIME_VARS['user'] and
params['password'] == RUNTIME_VARS['password']):
return RUNTIME_VARS['login'] % RUNTIME_VARS['access_key']
else:
return RUNTIME_VARS['bad_login']
def _incorrect_access_key(self, params):
if params['access_key'] != RUNTIME_VARS['access_key']:
return True
else:
return False
def _create_volume(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
params['attachments'] = []
vpsa_vol = 'volume-%07d' % self._get_counter()
RUNTIME_VARS['volumes'].append((vpsa_vol, params))
return RUNTIME_VARS['good']
def _create_server(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
vpsa_srv = 'srv-%07d' % self._get_counter()
RUNTIME_VARS['servers'].append((vpsa_srv, params))
return RUNTIME_VARS['server_created'] % vpsa_srv
def _attach(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
srv = self.url.split('/')[3]
vol = params['volume_name[]']
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
attachments = params['attachments']
if srv in attachments:
#already attached - ok
return RUNTIME_VARS['good']
else:
attachments.append(srv)
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _detach(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
vol = self.url.split('/')[3]
srv = params['server_name[]']
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
attachments = params['attachments']
if srv not in attachments:
return RUNTIME_VARS['bad_server']
else:
attachments.remove(srv)
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _delete(self):
vol = self.url.split('/')[3].split('.')[0]
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
if params['attachments']:
# there are attachments - should be volume busy error
return RUNTIME_VARS['bad_volume']
else:
RUNTIME_VARS['volumes'].remove((vol_name, params))
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _generate_list_resp(self, header, footer, body, lst):
resp = header
for (obj, params) in lst:
resp += body % (obj, params['display_name'])
resp += footer
return resp
def _list_volumes(self):
header = """<show-volumes-response>
<status type='integer'>0</status>
<volumes type='array'>"""
footer = "</volumes></show-volumes-response>"
body = """<volume>
<name>%s</name>
<display-name>%s</display-name>
<status>Available</status>
<virtual-capacity type='integer'>1</virtual-capacity>
<allocated-capacity type='integer'>1</allocated-capacity>
<raid-group-name>r5</raid-group-name>
<cache>write-through</cache>
<created-at type='datetime'>2012-01-28...</created-at>
<modified-at type='datetime'>2012-01-28...</modified-at>
</volume>"""
return self._generate_list_resp(header,
footer,
body,
RUNTIME_VARS['volumes'])
def _list_controllers(self):
header = """<show-vcontrollers-response>
<status type='integer'>0</status>
<vcontrollers type='array'>"""
footer = "</vcontrollers></show-vcontrollers-response>"
body = """<vcontroller>
<name>%s</name>
<display-name>%s</display-name>
<state>active</state>
<target>iqn.2011-04.com.zadarastorage:vsa-xxx:1</target>
<iscsi-ip>1.1.1.1</iscsi-ip>
<mgmt-ip>1.1.1.1</mgmt-ip>
<software-ver>0.0.09-05.1--77.7</software-ver>
<heartbeat1>ok</heartbeat1>
<heartbeat2>ok</heartbeat2>
<chap-username>test_chap_user</chap-username>
<chap-target-secret>test_chap_secret</chap-target-secret>
</vcontroller>"""
return self._generate_list_resp(header,
footer,
body,
RUNTIME_VARS['controllers'])
def _list_servers(self):
header = """<show-servers-response>
<status type='integer'>0</status>
<servers type='array'>"""
footer = "</servers></show-servers-response>"
body = """<server>
<name>%s</name>
<display-name>%s</display-name>
<iqn>%s</iqn>
<status>Active</status>
<created-at type='datetime'>2012-01-28...</created-at>
<modified-at type='datetime'>2012-01-28...</modified-at>
</server>"""
resp = header
for (obj, params) in RUNTIME_VARS['servers']:
resp += body % (obj, params['display_name'], params['iqn'])
resp += footer
return resp
def _get_server_obj(self, name):
for (srv_name, params) in RUNTIME_VARS['servers']:
if srv_name == name:
return params
def _list_vol_attachments(self):
vol = self.url.split('/')[3]
header = """<show-servers-response>
<status type="integer">0</status>
<servers type="array">"""
footer = "</servers></show-servers-response>"
body = """<server>
<name>%s</name>
<display-name>%s</display-name>
<iqn>%s</iqn>
<target>iqn.2011-04.com.zadarastorage:vsa-xxx:1</target>
<lun>0</lun>
</server>"""
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
attachments = params['attachments']
resp = header
for server in attachments:
srv_params = self._get_server_obj(server)
resp += body % (server,
srv_params['display_name'],
srv_params['iqn'])
resp += footer
return resp
return RUNTIME_VARS['bad_volume']
class FakeHTTPConnection(object):
"""A fake httplib.HTTPConnection for zadara volume driver tests."""
def __init__(self, host, port, use_ssl=False):
LOG.debug('Enter: __init__ FakeHTTPConnection')
self.host = host
self.port = port
self.use_ssl = use_ssl
self.req = None
def request(self, method, url, body):
LOG.debug('Enter: request')
self.req = FakeRequest(method, url, body)
def getresponse(self):
LOG.debug('Enter: getresponse')
return self.req
def close(self):
LOG.debug('Enter: close')
self.req = None
class FakeHTTPSConnection(FakeHTTPConnection):
def __init__(self, host, port):
LOG.debug('Enter: __init__ FakeHTTPSConnection')
super(FakeHTTPSConnection, self).__init__(host, port, use_ssl=True)
class ZadaraVPSADriverTestCase(test.TestCase):
"""Test case for Zadara VPSA volume driver."""
def setUp(self):
LOG.debug('Enter: setUp')
super(ZadaraVPSADriverTestCase, self).setUp()
self.flags(
zadara_user='test',
zadara_password='test_password',
)
global RUNTIME_VARS
RUNTIME_VARS = copy.deepcopy(DEFAULT_RUNTIME_VARS)
self.driver = zadara.ZadaraVPSAISCSIDriver()
self.stubs.Set(httplib, 'HTTPConnection', FakeHTTPConnection)
self.stubs.Set(httplib, 'HTTPSConnection', FakeHTTPSConnection)
self.driver.do_setup(None)
def tearDown(self):
super(ZadaraVPSADriverTestCase, self).tearDown()
def test_create_destroy(self):
"""Create/Delete volume."""
volume = {'name': 'test_volume_01', 'size': 1}
self.driver.create_volume(volume)
self.driver.delete_volume(volume)
def test_create_destroy_multiple(self):
"""Create/Delete multiple volumes."""
self.flags(zadara_vpsa_allow_nonexistent_delete=False)
self.driver.create_volume({'name': 'test_volume_01', 'size': 1})
self.driver.create_volume({'name': 'test_volume_02', 'size': 2})
self.driver.create_volume({'name': 'test_volume_03', 'size': 3})
self.driver.delete_volume({'name': 'test_volume_02'})
self.driver.delete_volume({'name': 'test_volume_03'})
self.driver.delete_volume({'name': 'test_volume_01'})
self.assertRaises(exception.VolumeNotFound,
self.driver.delete_volume,
{'name': 'test_volume_04'})
self.flags(zadara_vpsa_allow_nonexistent_delete=True)
self.driver.delete_volume({'name': 'test_volume_04'})
def test_destroy_non_existent(self):
"""Delete non-existent volume."""
self.flags(zadara_vpsa_allow_nonexistent_delete=False)
volume = {'name': 'test_volume_02', 'size': 1}
self.assertRaises(exception.VolumeNotFound,
self.driver.delete_volume,
volume)
self.flags(zadara_vpsa_allow_nonexistent_delete=True)
def test_empty_apis(self):
"""Test empty func (for coverage only)."""
context = None
volume = {'name': 'test_volume_01', 'size': 1}
self.driver.create_export(context, volume)
self.driver.ensure_export(context, volume)
self.driver.remove_export(context, volume)
self.assertRaises(NotImplementedError,
self.driver.create_volume_from_snapshot,
volume, None)
self.assertRaises(NotImplementedError,
self.driver.create_snapshot,
None)
self.assertRaises(NotImplementedError,
self.driver.delete_snapshot,
None)
self.assertRaises(NotImplementedError,
self.driver.local_path,
None)
self.driver.check_for_setup_error()
def test_volume_attach_detach(self):
"""Test volume attachment and detach."""
volume = {'name': 'test_volume_01', 'size': 1, 'id': 123}
connector = dict(initiator='test_iqn.1')
self.driver.create_volume(volume)
props = self.driver.initialize_connection(volume, connector)
self.assertEqual(props['driver_volume_type'], 'iscsi')
data = props['data']
self.assertEqual(data['target_portal'], '1.1.1.1:3260')
self.assertEqual(data['target_iqn'],
'iqn.2011-04.com.zadarastorage:vsa-xxx:1')
self.assertEqual(data['target_lun'], '0')
self.assertEqual(data['volume_id'], 123)
self.assertEqual(data['auth_method'], 'CHAP')
self.assertEqual(data['auth_username'], 'test_chap_user')
self.assertEqual(data['auth_password'], 'test_chap_secret')
self.driver.terminate_connection(volume, connector)
self.driver.delete_volume(volume)
def test_volume_attach_multiple_detach(self):
"""Test multiple volume attachment and detach."""
volume = {'name': 'test_volume_01', 'size': 1, 'id': 123}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.driver.create_volume(volume)
props1 = self.driver.initialize_connection(volume, connector1)
props2 = self.driver.initialize_connection(volume, connector2)
props3 = self.driver.initialize_connection(volume, connector3)
self.driver.terminate_connection(volume, connector1)
self.driver.terminate_connection(volume, connector3)
self.driver.terminate_connection(volume, connector2)
self.driver.delete_volume(volume)
def test_wrong_attach_params(self):
"""Test different wrong attach scenarios."""
volume1 = {'name': 'test_volume_01', 'size': 1, 'id': 101}
volume2 = {'name': 'test_volume_02', 'size': 1, 'id': 102}
volume3 = {'name': 'test_volume_03', 'size': 1, 'id': 103}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.assertRaises(exception.VolumeNotFound,
self.driver.initialize_connection,
volume1, connector1)
def test_wrong_detach_params(self):
"""Test different wrong detachment scenarios."""
volume1 = {'name': 'test_volume_01', 'size': 1, 'id': 101}
volume2 = {'name': 'test_volume_02', 'size': 1, 'id': 102}
volume3 = {'name': 'test_volume_03', 'size': 1, 'id': 103}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.driver.create_volume(volume1)
self.driver.create_volume(volume2)
props1 = self.driver.initialize_connection(volume1, connector1)
props2 = self.driver.initialize_connection(volume2, connector2)
self.assertRaises(exception.ZadaraServerNotFound,
self.driver.terminate_connection,
volume1, connector3)
self.assertRaises(exception.VolumeNotFound,
self.driver.terminate_connection,
volume3, connector1)
self.assertRaises(exception.FailedCmdWithDump,
self.driver.terminate_connection,
volume1, connector2)
def test_wrong_login_reply(self):
"""Test wrong login reply."""
RUNTIME_VARS['login'] = """<hash>
<access-key>%s</access-key>
<status type="integer">0</status>
</hash>"""
self.assertRaises(exception.MalformedResponse,
self.driver.do_setup, None)
RUNTIME_VARS['login'] = """
<hash>
<user>
<updated-at type="datetime">2012-04-30...</updated-at>
<id type="integer">1</id>
<created-at type="datetime">2012-02-21...</created-at>
<email>jsmith@example.com</email>
<username>jsmith</username>
</user>
<access-key>%s</access-key>
<status type="integer">0</status>
</hash>"""
self.assertRaises(exception.MalformedResponse,
self.driver.do_setup, None)
def test_ssl_use(self):
"""Coverage test for SSL connection."""
self.flags(zadara_vpsa_use_ssl=True)
self.driver.do_setup(None)
self.flags(zadara_vpsa_use_ssl=False)
def test_bad_http_response(self):
"""Coverage test for non-good HTTP response."""
RUNTIME_VARS['status'] = 400
volume = {'name': 'test_volume_01', 'size': 1}
self.assertRaises(exception.BadHTTPResponseStatus,
self.driver.create_volume, volume)
def test_delete_without_detach(self):
"""Test volume deletion without detach."""
volume1 = {'name': 'test_volume_01', 'size': 1, 'id': 101}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.driver.create_volume(volume1)
props1 = self.driver.initialize_connection(volume1, connector1)
props2 = self.driver.initialize_connection(volume1, connector2)
props3 = self.driver.initialize_connection(volume1, connector3)
self.flags(zadara_vpsa_auto_detach_on_delete=False)
self.assertRaises(exception.VolumeAttached,
self.driver.delete_volume, volume1)
self.flags(zadara_vpsa_auto_detach_on_delete=True)
self.driver.delete_volume(volume1)
def test_no_active_ctrl(self):
RUNTIME_VARS['controllers'] = []
volume = {'name': 'test_volume_01', 'size': 1, 'id': 123}
connector = dict(initiator='test_iqn.1')
self.driver.create_volume(volume)
self.assertRaises(exception.ZadaraVPSANoActiveController,
self.driver.initialize_connection,
volume, connector)