DiskAdapter Parent Class In-tree Backports

This contains backports for code changes made during in-tree driver
DiskAdapter parent class development [1].

- Forces subclasses to implement capacity methods
- Marks abstract methods/properties in the parent class
- Introduces a fake disk adapter to allow testing with abstract methods
  and properties.

[1] https://review.openstack.org/#/c/549053/

Change-Id: I1f8ebe64571c009020be7f3888167e3450d2fd4d
This commit is contained in:
esberglu 2018-06-21 10:02:18 -05:00
parent e3b112dc93
commit 5b70f32b74
5 changed files with 111 additions and 25 deletions

View File

@ -0,0 +1,60 @@
# Copyright IBM Corp. and contributors
#
# 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 nova_powervm.virt.powervm.disk import driver as disk_dvr
class FakeDiskAdapter(disk_dvr.DiskAdapter):
"""A fake subclass of DiskAdapter.
This is done so that the abstract methods/properties can be stubbed and the
class can be instantiated for testing.
"""
def vios_uuids(self):
pass
def _disk_match_func(self, disk_type, instance):
pass
def disconnect_disk_from_mgmt(self, vios_uuid, disk_name):
pass
def capacity(self):
pass
def capacity_used(self):
pass
def disconnect_disk(self, instance):
pass
def delete_disks(self, storage_elems):
pass
def create_disk_from_image(self, context, instance, image_meta):
pass
def connect_disk(self, instance, disk_info, stg_ftsk):
pass
def extend_disk(self, instance, disk_info, size):
pass
def check_instance_shared_storage_local(self, context, instance):
pass
def check_instance_shared_storage_remote(self, context, data):
pass

View File

@ -1,4 +1,4 @@
# Copyright 2015, 2017 IBM Corp. # Copyright IBM Corp. and contributors
# #
# All Rights Reserved. # All Rights Reserved.
# #
@ -19,8 +19,8 @@ import mock
from nova import test from nova import test
from pypowervm import const as pvm_const from pypowervm import const as pvm_const
from nova_powervm.tests.virt.powervm.disk import fake_adapter
from nova_powervm.tests.virt.powervm import fixtures as fx from nova_powervm.tests.virt.powervm import fixtures as fx
from nova_powervm.virt.powervm.disk import driver as disk_dvr
class TestDiskAdapter(test.NoDBTestCase): class TestDiskAdapter(test.NoDBTestCase):
@ -36,13 +36,9 @@ class TestDiskAdapter(test.NoDBTestCase):
self.mgmt_uuid.return_value = 'mp_uuid' self.mgmt_uuid.return_value = 'mp_uuid'
# The values (adapter and host uuid) are not used in the base. # The values (adapter and host uuid) are not used in the base.
# Default them to None. # Default them to None. We use the fake adapter here because we can't
self.st_adpt = disk_dvr.DiskAdapter(None, None) # instantiate DiskAdapter which is an abstract base class.
self.st_adpt = fake_adapter.FakeDiskAdapter(None, None)
def test_capacity(self):
"""These are arbitrary capacity numbers."""
self.assertEqual(2097152, self.st_adpt.capacity)
self.assertEqual(0, self.st_adpt.capacity_used)
def test_get_info(self): def test_get_info(self):
# Ensure the base method returns empty dict # Ensure the base method returns empty dict

View File

@ -87,7 +87,7 @@ class DiskAdapter(object):
self.host_uuid = host_uuid self.host_uuid = host_uuid
self.mp_uuid = mgmt.mgmt_uuid(self.adapter) self.mp_uuid = mgmt.mgmt_uuid(self.adapter)
@property @abc.abstractproperty
def vios_uuids(self): def vios_uuids(self):
"""List the UUIDs of the Virtual I/O Servers hosting the storage.""" """List the UUIDs of the Virtual I/O Servers hosting the storage."""
raise NotImplementedError() raise NotImplementedError()
@ -129,6 +129,7 @@ class DiskAdapter(object):
return _('The configured disk driver does not support migration ' return _('The configured disk driver does not support migration '
'or resize.') 'or resize.')
@abc.abstractmethod
def _disk_match_func(self, disk_type, instance): def _disk_match_func(self, disk_type, instance):
"""Return a matching function to locate the disk for an instance. """Return a matching function to locate the disk for an instance.
@ -214,6 +215,7 @@ class DiskAdapter(object):
# We either didn't find the boot dev, or failed all attempts to map it. # We either didn't find the boot dev, or failed all attempts to map it.
raise npvmex.InstanceDiskMappingFailed(instance_name=instance.name) raise npvmex.InstanceDiskMappingFailed(instance_name=instance.name)
@abc.abstractmethod
def disconnect_disk_from_mgmt(self, vios_uuid, disk_name): def disconnect_disk_from_mgmt(self, vios_uuid, disk_name):
"""Disconnect a disk from the management partition. """Disconnect a disk from the management partition.
@ -223,21 +225,15 @@ class DiskAdapter(object):
""" """
raise NotImplementedError() raise NotImplementedError()
@property @abc.abstractproperty
def capacity(self): def capacity(self):
"""Capacity of the storage in gigabytes """Capacity of the storage in gigabytes."""
raise NotImplementedError()
Default is to make the capacity arbitrarily large @abc.abstractproperty
"""
return 1 << 21
@property
def capacity_used(self): def capacity_used(self):
"""Capacity of the storage in gigabytes that is used """Capacity of the storage in gigabytes that is used."""
raise NotImplementedError()
Default is to say none of it is used.
"""
return 0
@staticmethod @staticmethod
def _get_disk_name(disk_type, instance, short=False): def _get_disk_name(disk_type, instance, short=False):
@ -301,6 +297,7 @@ class DiskAdapter(object):
disk_bytes = floor disk_bytes = floor
return disk_bytes return disk_bytes
@abc.abstractmethod
def disconnect_disk(self, instance, stg_ftsk=None, disk_type=None): def disconnect_disk(self, instance, stg_ftsk=None, disk_type=None):
"""Disconnects the storage adapters from the image disk. """Disconnects the storage adapters from the image disk.
@ -316,8 +313,9 @@ class DiskAdapter(object):
:return: A list of all the backing storage elements that were :return: A list of all the backing storage elements that were
disconnected from the I/O Server and VM. disconnected from the I/O Server and VM.
""" """
pass raise NotImplementedError()
@abc.abstractmethod
def delete_disks(self, storage_elems): def delete_disks(self, storage_elems):
"""Removes the disks specified by the mappings. """Removes the disks specified by the mappings.
@ -325,7 +323,7 @@ class DiskAdapter(object):
deleted. Derived from the return value from deleted. Derived from the return value from
disconnect_disk. disconnect_disk.
""" """
pass raise NotImplementedError()
def create_disk_from_image(self, context, instance, image_meta, def create_disk_from_image(self, context, instance, image_meta,
image_type=DiskType.BOOT): image_type=DiskType.BOOT):
@ -370,6 +368,7 @@ class DiskAdapter(object):
""" """
pass pass
@abc.abstractmethod
def connect_disk(self, instance, disk_info, stg_ftsk=None): def connect_disk(self, instance, disk_info, stg_ftsk=None):
"""Connects the disk image to the Virtual Machine. """Connects the disk image to the Virtual Machine.
@ -384,8 +383,9 @@ class DiskAdapter(object):
the FeedTask is not provided, the updates will be run the FeedTask is not provided, the updates will be run
immediately when this method is executed. immediately when this method is executed.
""" """
pass raise NotImplementedError()
@abc.abstractmethod
def extend_disk(self, instance, disk_info, size): def extend_disk(self, instance, disk_info, size):
"""Extends the disk. """Extends the disk.
@ -395,6 +395,7 @@ class DiskAdapter(object):
""" """
raise NotImplementedError() raise NotImplementedError()
@abc.abstractmethod
def check_instance_shared_storage_local(self, context, instance): def check_instance_shared_storage_local(self, context, instance):
"""Check if instance files located on shared storage. """Check if instance files located on shared storage.
@ -406,6 +407,7 @@ class DiskAdapter(object):
""" """
raise NotImplementedError() raise NotImplementedError()
@abc.abstractmethod
def check_instance_shared_storage_remote(self, context, data): def check_instance_shared_storage_remote(self, context, data):
"""Check if instance files located on shared storage. """Check if instance files located on shared storage.

View File

@ -339,6 +339,25 @@ class LocalStorage(disk_dvr.DiskAdapter):
LOG.exception("PowerVM Error extending disk.", LOG.exception("PowerVM Error extending disk.",
instance=instance) instance=instance)
def check_instance_shared_storage_local(self, context, instance):
"""Check if instance files located on shared storage.
This runs check on the destination host, and then calls
back to the source host to check the results.
:param context: security context
:param instance: nova.objects.instance.Instance object
"""
raise NotImplementedError()
def check_instance_shared_storage_remote(self, context, data):
"""Check if instance files located on shared storage.
:param context: security context
:param data: result of check_instance_shared_storage_local
"""
raise NotImplementedError()
def _get_vg_wrap(self): def _get_vg_wrap(self):
return pvm_stg.VG.get(self.adapter, uuid=self.vg_uuid, return pvm_stg.VG.get(self.adapter, uuid=self.vg_uuid,
parent_type=pvm_vios.VIOS, parent_type=pvm_vios.VIOS,

View File

@ -286,6 +286,15 @@ class SSPDiskAdapter(disk_drv.DiskAdapter):
if stg_ftsk.name == 'ssp': if stg_ftsk.name == 'ssp':
stg_ftsk.execute() stg_ftsk.execute()
def extend_disk(self, instance, disk_info, size):
"""Extends the disk.
:param instance: instance to extend the disk for.
:param disk_info: dictionary with disk info.
:param size: the new size in gb.
"""
raise NotImplementedError()
def check_instance_shared_storage_local(self, context, instance): def check_instance_shared_storage_local(self, context, instance):
"""Check if instance files located on shared storage. """Check if instance files located on shared storage.