258 lines
12 KiB
Python
258 lines
12 KiB
Python
# Copyright 2015, 2017 IBM Corp.
|
|
#
|
|
# 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 __future__ import absolute_import
|
|
|
|
import fixtures
|
|
import mock
|
|
from oslo_utils import uuidutils
|
|
from pypowervm import const as pvm_const
|
|
from pypowervm import exceptions as pvm_exc
|
|
from pypowervm.tasks import storage as tsk_stg
|
|
from pypowervm.utils import transaction as pvm_tx
|
|
from pypowervm.wrappers import cluster as pvm_clust
|
|
from pypowervm.wrappers import storage as pvm_stg
|
|
from pypowervm.wrappers import virtual_io_server as pvm_vios
|
|
|
|
from nova import exception
|
|
from nova import test
|
|
from nova.tests.unit.virt import powervm
|
|
from nova.virt.powervm.disk import ssp as ssp_dvr
|
|
from nova.virt.powervm import vm
|
|
|
|
FAKE_INST_UUID = uuidutils.generate_uuid(dashed=True)
|
|
FAKE_INST_UUID_PVM = vm.get_pvm_uuid(mock.Mock(uuid=FAKE_INST_UUID))
|
|
|
|
|
|
class TestSSPDiskAdapter(test.TestCase):
|
|
"""Unit Tests for the LocalDisk storage driver."""
|
|
|
|
def setUp(self):
|
|
super(TestSSPDiskAdapter, self).setUp()
|
|
|
|
self.inst = powervm.TEST_INSTANCE
|
|
|
|
self.apt = mock.Mock()
|
|
self.host_uuid = 'host_uuid'
|
|
|
|
self.ssp_wrap = mock.create_autospec(pvm_stg.SSP, instance=True)
|
|
|
|
# SSP.refresh() returns itself
|
|
self.ssp_wrap.refresh.return_value = self.ssp_wrap
|
|
self.node1 = mock.create_autospec(pvm_clust.Node, instance=True)
|
|
self.node2 = mock.create_autospec(pvm_clust.Node, instance=True)
|
|
self.clust_wrap = mock.create_autospec(
|
|
pvm_clust.Cluster, instance=True)
|
|
self.clust_wrap.nodes = [self.node1, self.node2]
|
|
self.clust_wrap.refresh.return_value = self.clust_wrap
|
|
self.tier_wrap = mock.create_autospec(pvm_stg.Tier, instance=True)
|
|
# Tier.refresh() returns itself
|
|
self.tier_wrap.refresh.return_value = self.tier_wrap
|
|
self.vio_wrap = mock.create_autospec(pvm_vios.VIOS, instance=True)
|
|
|
|
# For _cluster
|
|
self.mock_clust = self.useFixture(fixtures.MockPatch(
|
|
'pypowervm.wrappers.cluster.Cluster', autospec=True)).mock
|
|
self.mock_clust.get.return_value = [self.clust_wrap]
|
|
|
|
# For _ssp
|
|
self.mock_ssp_gbhref = self.useFixture(fixtures.MockPatch(
|
|
'pypowervm.wrappers.storage.SSP.get_by_href')).mock
|
|
self.mock_ssp_gbhref.return_value = self.ssp_wrap
|
|
|
|
# For _tier
|
|
self.mock_get_tier = self.useFixture(fixtures.MockPatch(
|
|
'pypowervm.tasks.storage.default_tier_for_ssp',
|
|
autospec=True)).mock
|
|
self.mock_get_tier.return_value = self.tier_wrap
|
|
|
|
# A FeedTask
|
|
self.mock_afs = self.useFixture(fixtures.MockPatch(
|
|
'pypowervm.utils.transaction.FeedTask.add_functor_subtask',
|
|
autospec=True)).mock
|
|
self.mock_wtsk = mock.create_autospec(
|
|
pvm_tx.WrapperTask, instance=True)
|
|
self.mock_wtsk.configure_mock(wrapper=self.vio_wrap)
|
|
self.mock_ftsk = mock.create_autospec(pvm_tx.FeedTask, instance=True)
|
|
self.mock_ftsk.configure_mock(
|
|
wrapper_tasks={self.vio_wrap.uuid: self.mock_wtsk})
|
|
|
|
self.pvm_uuid = self.useFixture(fixtures.MockPatch(
|
|
'nova.virt.powervm.vm.get_pvm_uuid')).mock
|
|
|
|
# The SSP disk adapter
|
|
self.ssp_drv = ssp_dvr.SSPDiskAdapter(self.apt, self.host_uuid)
|
|
|
|
def test_init(self):
|
|
self.assertEqual(self.apt, self.ssp_drv._adapter)
|
|
self.assertEqual(self.host_uuid, self.ssp_drv._host_uuid)
|
|
self.mock_clust.get.assert_called_once_with(self.apt)
|
|
self.assertEqual(self.mock_clust.get.return_value,
|
|
[self.ssp_drv._clust])
|
|
self.mock_ssp_gbhref.assert_called_once_with(
|
|
self.apt, self.clust_wrap.ssp_uri)
|
|
self.assertEqual(self.mock_ssp_gbhref.return_value, self.ssp_drv._ssp)
|
|
self.mock_get_tier.assert_called_once_with(self.ssp_wrap)
|
|
self.assertEqual(self.mock_get_tier.return_value, self.ssp_drv._tier)
|
|
|
|
def test_init_error(self):
|
|
# Do these in reverse order to verify we trap all of 'em
|
|
for raiser in (self.mock_get_tier, self.mock_ssp_gbhref,
|
|
self.mock_clust.get):
|
|
raiser.side_effect = pvm_exc.TimeoutError("timed out")
|
|
self.assertRaises(exception.NotFound,
|
|
ssp_dvr.SSPDiskAdapter, self.apt, self.host_uuid)
|
|
raiser.side_effect = ValueError
|
|
self.assertRaises(ValueError,
|
|
ssp_dvr.SSPDiskAdapter, self.apt, self.host_uuid)
|
|
|
|
def test_capabilities(self):
|
|
self.assertTrue(self.ssp_drv.capabilities.get('shared_storage'))
|
|
|
|
@mock.patch('pypowervm.util.get_req_path_uuid', autospec=True)
|
|
def test_vios_uuids(self, mock_rpu):
|
|
mock_rpu.return_value = self.host_uuid
|
|
vios_uuids = self.ssp_drv._vios_uuids
|
|
self.assertEqual({self.node1.vios_uuid, self.node2.vios_uuid},
|
|
set(vios_uuids))
|
|
mock_rpu.assert_has_calls(
|
|
[mock.call(node.vios_uri, preserve_case=True, root=True)
|
|
for node in [self.node1, self.node2]])
|
|
|
|
mock_rpu.reset_mock()
|
|
|
|
# Test VIOSes on other nodes, which won't have uuid or url
|
|
node1 = mock.Mock(vios_uuid=None, vios_uri='uri1')
|
|
node2 = mock.Mock(vios_uuid='2', vios_uri=None)
|
|
# This mock is good and should be returned
|
|
node3 = mock.Mock(vios_uuid='3', vios_uri='uri3')
|
|
self.clust_wrap.nodes = [node1, node2, node3]
|
|
self.assertEqual(['3'], self.ssp_drv._vios_uuids)
|
|
# get_req_path_uuid was only called on the good one
|
|
mock_rpu.assert_called_once_with('uri3', preserve_case=True, root=True)
|
|
|
|
def test_capacity(self):
|
|
self.tier_wrap.capacity = 10
|
|
self.assertAlmostEqual(10.0, self.ssp_drv.capacity)
|
|
self.tier_wrap.refresh.assert_called_once_with()
|
|
|
|
def test_capacity_used(self):
|
|
self.ssp_wrap.capacity = 4.56
|
|
self.ssp_wrap.free_space = 1.23
|
|
self.assertAlmostEqual((4.56 - 1.23), self.ssp_drv.capacity_used)
|
|
self.ssp_wrap.refresh.assert_called_once_with()
|
|
|
|
@mock.patch('pypowervm.tasks.cluster_ssp.get_or_upload_image_lu',
|
|
autospec=True)
|
|
@mock.patch('nova.virt.powervm.disk.ssp.SSPDiskAdapter._vios_uuids',
|
|
new_callable=mock.PropertyMock)
|
|
@mock.patch('pypowervm.util.sanitize_file_name_for_api', autospec=True)
|
|
@mock.patch('pypowervm.tasks.storage.crt_lu', autospec=True)
|
|
@mock.patch('nova.image.api.API.download')
|
|
@mock.patch('nova.virt.powervm.disk.ssp.IterableToFileAdapter')
|
|
def test_create_disk_from_image(self, mock_it2f, mock_dl, mock_crt_lu,
|
|
mock_san, mock_vuuid, mock_goru):
|
|
img = powervm.TEST_IMAGE1
|
|
|
|
mock_crt_lu.return_value = self.ssp_drv._ssp, 'boot_lu'
|
|
mock_san.return_value = 'disk_name'
|
|
mock_vuuid.return_value = ['vuuid']
|
|
|
|
self.assertEqual('boot_lu', self.ssp_drv.create_disk_from_image(
|
|
'context', self.inst, img))
|
|
mock_dl.assert_called_once_with('context', img.id)
|
|
mock_san.assert_has_calls([
|
|
mock.call(img.name, prefix='image_', suffix='_' + img.checksum),
|
|
mock.call(self.inst.name, prefix='boot_')])
|
|
mock_it2f.assert_called_once_with(mock_dl.return_value)
|
|
mock_goru.assert_called_once_with(
|
|
self.ssp_drv._tier, 'disk_name', 'vuuid',
|
|
mock_it2f.return_value, img.size,
|
|
upload_type=tsk_stg.UploadType.IO_STREAM)
|
|
mock_crt_lu.assert_called_once_with(
|
|
self.mock_get_tier.return_value, mock_san.return_value,
|
|
self.inst.flavor.root_gb, typ=pvm_stg.LUType.DISK,
|
|
clone=mock_goru.return_value)
|
|
|
|
@mock.patch('nova.virt.powervm.disk.ssp.SSPDiskAdapter._vios_uuids',
|
|
new_callable=mock.PropertyMock)
|
|
@mock.patch('pypowervm.tasks.scsi_mapper.add_map', autospec=True)
|
|
@mock.patch('pypowervm.tasks.scsi_mapper.build_vscsi_mapping',
|
|
autospec=True)
|
|
@mock.patch('pypowervm.wrappers.storage.LU', autospec=True)
|
|
def test_connect_disk(self, mock_lu, mock_bldmap, mock_addmap,
|
|
mock_vio_uuids):
|
|
disk_info = mock.Mock()
|
|
disk_info.configure_mock(name='dname', udid='dudid')
|
|
mock_vio_uuids.return_value = [self.vio_wrap.uuid]
|
|
|
|
def test_afs(add_func):
|
|
# Verify the internal add_func
|
|
self.assertEqual(mock_addmap.return_value, add_func(self.vio_wrap))
|
|
mock_bldmap.assert_called_once_with(
|
|
self.host_uuid, self.vio_wrap, self.pvm_uuid.return_value,
|
|
mock_lu.bld_ref.return_value)
|
|
mock_addmap.assert_called_once_with(
|
|
self.vio_wrap, mock_bldmap.return_value)
|
|
self.mock_wtsk.add_functor_subtask.side_effect = test_afs
|
|
|
|
self.ssp_drv.attach_disk(self.inst, disk_info, self.mock_ftsk)
|
|
mock_lu.bld_ref.assert_called_once_with(self.apt, 'dname', 'dudid')
|
|
self.pvm_uuid.assert_called_once_with(self.inst)
|
|
self.assertEqual(1, self.mock_wtsk.add_functor_subtask.call_count)
|
|
|
|
@mock.patch('pypowervm.tasks.storage.rm_tier_storage')
|
|
def test_delete_disks(self, mock_rm_tstor):
|
|
self.ssp_drv.delete_disks(['disk1', 'disk2'])
|
|
mock_rm_tstor.assert_called_once_with(['disk1', 'disk2'],
|
|
tier=self.ssp_drv._tier)
|
|
|
|
@mock.patch('nova.virt.powervm.disk.ssp.SSPDiskAdapter._vios_uuids',
|
|
new_callable=mock.PropertyMock)
|
|
@mock.patch('pypowervm.tasks.scsi_mapper.find_maps', autospec=True)
|
|
@mock.patch('pypowervm.tasks.scsi_mapper.remove_maps', autospec=True)
|
|
@mock.patch('pypowervm.tasks.scsi_mapper.gen_match_func', autospec=True)
|
|
@mock.patch('pypowervm.tasks.partition.build_active_vio_feed_task',
|
|
autospec=True)
|
|
def test_disconnect_disk(self, mock_bld_ftsk, mock_gmf, mock_rmmaps,
|
|
mock_findmaps, mock_vio_uuids):
|
|
mock_vio_uuids.return_value = [self.vio_wrap.uuid]
|
|
mock_bld_ftsk.return_value = self.mock_ftsk
|
|
lu1, lu2 = [mock.create_autospec(pvm_stg.LU, instance=True)] * 2
|
|
# Two mappings have the same LU, to verify set behavior
|
|
mock_findmaps.return_value = [
|
|
mock.Mock(spec=pvm_vios.VSCSIMapping, backing_storage=lu)
|
|
for lu in (lu1, lu2, lu1)]
|
|
|
|
def test_afs(rm_func):
|
|
# verify the internal rm_func
|
|
self.assertEqual(mock_rmmaps.return_value, rm_func(self.vio_wrap))
|
|
mock_rmmaps.assert_called_once_with(
|
|
self.vio_wrap, self.pvm_uuid.return_value,
|
|
match_func=mock_gmf.return_value)
|
|
self.mock_wtsk.add_functor_subtask.side_effect = test_afs
|
|
|
|
self.assertEqual(
|
|
{lu1, lu2}, set(self.ssp_drv.detach_disk(self.inst)))
|
|
mock_bld_ftsk.assert_called_once_with(
|
|
self.apt, name='ssp', xag=[pvm_const.XAG.VIO_SMAP])
|
|
self.pvm_uuid.assert_called_once_with(self.inst)
|
|
mock_gmf.assert_called_once_with(pvm_stg.LU)
|
|
self.assertEqual(1, self.mock_wtsk.add_functor_subtask.call_count)
|
|
mock_findmaps.assert_called_once_with(
|
|
self.vio_wrap.scsi_mappings,
|
|
client_lpar_id=self.pvm_uuid.return_value,
|
|
match_func=mock_gmf.return_value)
|
|
self.mock_ftsk.execute.assert_called_once_with()
|