Remove use of storage extra spec from VIM

The setting of the storage extra spec on each flavor was
removed from nova recently. However, the VIM still relies
on this extra spec being set and this results in the VIM
not making proper decisions on whether to live migrate,
cold migrate or evacuate instances during various system
events (e.g. a host lock).

The solution is to remove the storage extra spec from the
VIM. Live migration is now supported for instances,
regardless of the storage type. The cold migrate and
evacuate decisions will assume local storage is being
used until support for remote storage has been added to
the containers configuration.

Change-Id: I42d2d755c5cc61acb8e23bc278cd920a3b782562
Story: 2004386
Task: 28911
Signed-off-by: Bart Wensley <barton.wensley@windriver.com>
This commit is contained in:
Bart Wensley 2019-01-16 12:55:50 -06:00
parent 936724ec6a
commit 24ec8517ff
19 changed files with 106 additions and 104 deletions

View File

@ -336,12 +336,8 @@ def flavor_data_extra_get(flavor_data_extra):
nfvi_objs.INSTANCE_TYPE_EXTENSION.LIVE_MIGRATION_MAX_DOWNTIME,
None)
storage_type = flavor_data_extra.get(
nfvi_objs.INSTANCE_TYPE_EXTENSION.STORAGE_TYPE,
None)
return (guest_heartbeat, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type)
live_migration_max_downtime)
class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
@ -1322,7 +1318,6 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
auto_recovery = None
live_migration_timeout = None
live_migration_max_downtime = None
storage_type = None
if extra_specs:
future.work(nova.set_flavor_extra_specs, self._token,
@ -1335,7 +1330,7 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
flavor_data_extra = future.result.data['extra_specs']
(guest_heartbeat, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type) = \
live_migration_max_downtime) = \
flavor_data_extra_get(flavor_data_extra)
if guest_heartbeat is not None:
@ -1346,8 +1341,7 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
ephemeral_gb, swap_gb, guest_services=guest_services,
auto_recovery=auto_recovery,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=live_migration_max_downtime,
storage_type=storage_type)
live_migration_max_downtime=live_migration_max_downtime)
response['result-data'] = instance_type_obj
response['completed'] = True
@ -1469,14 +1463,13 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
auto_recovery = None
live_migration_timeout = None
live_migration_max_downtime = None
storage_type = None
if future.result.is_complete():
flavor_data_extra = future.result.data.get('extra_specs')
if flavor_data_extra is not None:
(guest_heartbeat, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type) = \
live_migration_max_downtime) = \
flavor_data_extra_get(flavor_data_extra)
if guest_heartbeat is not None:
@ -1497,8 +1490,7 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
ephemeral_gb, swap_gb, guest_services=guest_services,
auto_recovery=auto_recovery,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=live_migration_max_downtime,
storage_type=storage_type)
live_migration_max_downtime=live_migration_max_downtime)
response['result-data'] = instance_type_obj
response['completed'] = True

View File

@ -145,8 +145,7 @@ class TestInstance(testcase.NFVTestCase):
swap_gb=0, guest_services=None,
auto_recovery=True,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=500,
storage_type='local_image')
live_migration_max_downtime=500)
self._instance_type_table[instance_type_uuid] = instance_type
def create_image(self, image_name, properties=None):

View File

@ -101,8 +101,7 @@ class TestInstanceDirector(testcase.NFVTestCase):
guest_services=None,
auto_recovery=True,
live_migration_timeout=800,
live_migration_max_downtime=500,
storage_type='local_image')
live_migration_max_downtime=500)
self._instance_type_table[instance_type_uuid] = instance_type
self._director = InstanceDirector(

View File

@ -196,8 +196,7 @@ class TestSwPatchStrategy(testcase.NFVTestCase):
guest_services=None,
auto_recovery=True,
live_migration_timeout=800,
live_migration_max_downtime=500,
storage_type='local_image')
live_migration_max_downtime=500)
self._instance_type_table[instance_type_uuid] = instance_type
def tearDown(self):

View File

@ -174,8 +174,7 @@ class TestSwUpgradeStrategy(testcase.NFVTestCase):
guest_services=None,
auto_recovery=True,
live_migration_timeout=800,
live_migration_max_downtime=500,
storage_type='local_image')
live_migration_max_downtime=500)
self._instance_type_table[instance_type_uuid] = instance_type
def tearDown(self):

View File

@ -22,9 +22,6 @@ def instance_type_to_flavor_dict(instance_type):
extra_specs[
nfvi.objects.v1.INSTANCE_TYPE_EXTENSION.LIVE_MIGRATION_MAX_DOWNTIME] = \
instance_type.live_migration_max_downtime
extra_specs[
nfvi.objects.v1.INSTANCE_TYPE_EXTENSION.STORAGE_TYPE] = \
instance_type.storage_type
flavor['extra_specs'] = extra_specs
return flavor

View File

@ -356,8 +356,7 @@ def _audit_nfvi_instance_types_callback(timer_id):
nfvi_instance_type.guest_services,
nfvi_instance_type.auto_recovery,
nfvi_instance_type.live_migration_timeout,
nfvi_instance_type.live_migration_max_downtime,
nfvi_instance_type.storage_type)
nfvi_instance_type.live_migration_max_downtime)
if _nfvi_instance_types_paging.done:
for instance_type_uuid in _deletable_instance_types:
@ -1075,8 +1074,7 @@ def _audit_nfvi_instance_type_callback(instance_type_uuid):
instance_type.swap_gb, instance_type.guest_services,
instance_type.auto_recovery,
instance_type.live_migration_timeout,
instance_type.live_migration_max_downtime,
instance_type.storage_type)
instance_type.live_migration_max_downtime)
instance_type_table = tables.tables_get_instance_type_table()
instance_type_table[instance_type.uuid] = instance_type_obj

View File

@ -164,11 +164,11 @@ def database_instance_type_add(instance_type_obj):
"""
db = database_get()
session = db.session()
query = session.query(model.InstanceType)
query = query.filter(model.InstanceType.uuid == instance_type_obj.uuid)
query = session.query(model.InstanceType_v5)
query = query.filter(model.InstanceType_v5.uuid == instance_type_obj.uuid)
instance_type = query.first()
if not instance_type:
instance_type = model.InstanceType()
instance_type = model.InstanceType_v5()
instance_type.uuid = instance_type_obj.uuid
instance_type.name = instance_type_obj.name
if instance_type_obj.have_details():
@ -186,7 +186,6 @@ def database_instance_type_add(instance_type_obj):
= instance_type_obj.live_migration_timeout
instance_type.live_migration_max_downtime \
= instance_type_obj.live_migration_max_downtime
instance_type.storage_type = instance_type_obj.storage_type
session.add(instance_type)
else:
if instance_type_obj.have_details():
@ -204,7 +203,6 @@ def database_instance_type_add(instance_type_obj):
= instance_type_obj.live_migration_timeout
instance_type.live_migration_max_downtime \
= instance_type_obj.live_migration_max_downtime
instance_type.storage_type = instance_type_obj.storage_type
db.commit()
@ -214,8 +212,8 @@ def database_instance_type_delete(instance_type_uuid):
"""
db = database_get()
session = db.session()
query = session.query(model.InstanceType)
query.filter(model.InstanceType.uuid == instance_type_uuid).delete()
query = session.query(model.InstanceType_v5)
query.filter(model.InstanceType_v5.uuid == instance_type_uuid).delete()
session.commit()
@ -225,7 +223,7 @@ def database_instance_type_get_list():
"""
db = database_get()
session = db.session()
query = session.query(model.InstanceType)
query = session.query(model.InstanceType_v5)
instance_type_objs = list()
for instance_type in query.all():
@ -237,7 +235,7 @@ def database_instance_type_get_list():
instance_type.vcpus, instance_type.mem_mb, instance_type.disk_gb,
instance_type.ephemeral_gb, instance_type.swap_gb, guest_services,
instance_type.auto_recovery, instance_type.live_migration_timeout,
instance_type.live_migration_max_downtime, instance_type.storage_type)
instance_type.live_migration_max_downtime)
instance_type_objs.append(instance_type_obj)
return instance_type_objs

View File

@ -27,6 +27,19 @@ def _migrate_hosts_v5_to_v6(session, hosts_v5, hosts_v6):
session.add(host_v6)
def _migrate_instance_types_v4_to_v5(session, instance_types_v4,
instance_types_v5):
"""
Migrate instance_types_v4 table to instance_types_v5 table
"""
if 0 == len(instance_types_v5):
for instance_type_v4 in instance_types_v4:
instance_type_v5 = model.InstanceType_v5()
del instance_type_v4.data['storage_type']
instance_type_v5.data = instance_type_v4.data
session.add(instance_type_v5)
def migrate_tables(session, table_names):
"""
Migrate database tables
@ -38,3 +51,13 @@ def migrate_tables(session, table_names):
hosts_v6 = hosts_v6_query.all()
_migrate_hosts_v5_to_v6(session, hosts_v5, hosts_v6)
hosts_v5_query.delete()
if 'instance_types_v4' in table_names and \
'instance_types_v5' in table_names:
instance_types_v4_query = session.query(model.InstanceType)
instance_types_v4 = instance_types_v4_query.all()
instance_types_v5_query = session.query(model.InstanceType_v5)
instance_types_v5 = instance_types_v5_query.all()
_migrate_instance_types_v4_to_v5(session, instance_types_v4,
instance_types_v5)
instance_types_v4_query.delete()

View File

@ -15,6 +15,7 @@ from nfv_vim.database.model._instance import Instance_v4 # noqa: F401
from nfv_vim.database.model._instance import Instance_v5 # noqa: F401
from nfv_vim.database.model._instance_group import InstanceGroup # noqa: F401
from nfv_vim.database.model._instance_type import InstanceType # noqa: F401
from nfv_vim.database.model._instance_type import InstanceType_v5 # noqa: F401
from nfv_vim.database.model._network import Network # noqa: F401
from nfv_vim.database.model._service_host import ServiceHost # noqa: F401
from nfv_vim.database.model._subnet import Subnet # noqa: F401

View File

@ -12,6 +12,51 @@ from nfv_vim.database.model._base import AsDictMixin
from nfv_vim.database.model._base import Base
class InstanceType_v5(AsDictMixin, Base):
"""
Instance Type Database Table
"""
__tablename__ = 'instance_types_v5'
uuid = Column(String(64), nullable=False, primary_key=True)
name = Column(String(64), nullable=False)
have_details = Column(Boolean, nullable=False)
vcpus = Column(Integer, nullable=False)
mem_mb = Column(Integer, nullable=False)
disk_gb = Column(Integer, nullable=False)
ephemeral_gb = Column(Integer, nullable=False)
swap_gb = Column(Integer, nullable=False)
guest_services = Column(String(2048), nullable=False)
auto_recovery = Column(Boolean, nullable=True)
live_migration_timeout = Column(Integer, nullable=True)
live_migration_max_downtime = Column(Integer, nullable=True)
def __init__(self):
"""
Default some of the settings of the flavor
"""
self.have_details = False
self.vcpus = 0
self.mem_mb = 0
self.disk_gb = 0
self.ephemeral_gb = 0
self.swap_gb = 0
self.guest_services = "{}"
self.auto_recovery = None
self.live_migration_timeout = None
self.live_migration_max_downtime = None
def __repr__(self):
if self.have_details:
return ("<Instance Type(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r )>"
% (self.uuid, self.name, self.vcpus, self.mem_mb,
self.disk_gb, self.ephemeral_gb, self.swap_gb,
self.guest_services, self.auto_recovery,
self.live_migration_timeout,
self.live_migration_max_downtime))
return "<Instance Type(%r, %r)>" % (self.uuid, self.name)
class InstanceType(AsDictMixin, Base):
"""
Instance Type Database Table

View File

@ -1555,8 +1555,7 @@ class InstanceDirector(object):
instance_type_attributes = \
nfvi.objects.v1.InstanceTypeAttributes(
vcpus, mem_mb, disk_gb, ephemeral_gb, swap_gb, None, auto_recovery,
live_migration_timeout, live_migration_max_downtime,
nfvi.objects.v1.STORAGE_TYPE.LOCAL_IMAGE_BACKED)
live_migration_timeout, live_migration_max_downtime)
nfvi.nfvi_create_instance_type(instance_type_uuid, instance_type_name,
instance_type_attributes,
instance_type_create_callback)

View File

@ -47,7 +47,6 @@ from nfv_vim.nfvi.objects.v1._instance_group import InstanceGroup # noqa: F401
from nfv_vim.nfvi.objects.v1._instance_type import INSTANCE_TYPE_EXTENSION # noqa: F401
from nfv_vim.nfvi.objects.v1._instance_type import InstanceType # noqa: F401
from nfv_vim.nfvi.objects.v1._instance_type import InstanceTypeAttributes # noqa: F401
from nfv_vim.nfvi.objects.v1._instance_type import STORAGE_TYPE # noqa: F401
from nfv_vim.nfvi.objects.v1._network import Network # noqa: F401
from nfv_vim.nfvi.objects.v1._network import NETWORK_ADMIN_STATE # noqa: F401
from nfv_vim.nfvi.objects.v1._network import NETWORK_AVAIL_STATUS # noqa: F401

View File

@ -523,16 +523,3 @@ class Instance(ObjectData):
INSTANCE_TYPE_EXTENSION.LIVE_MIGRATION_MAX_DOWNTIME, None)
return live_migration_max_downtime
@property
def instance_type_storage_type(self):
"""
Returns the storage type from the flavor extra specs
"""
storage_type = None
flavor_data_extra = self.get('instance_type').get('extra_specs', None)
if flavor_data_extra is not None:
storage_type = flavor_data_extra.get(
INSTANCE_TYPE_EXTENSION.STORAGE_TYPE, None)
return storage_type

View File

@ -26,7 +26,6 @@ class InstanceTypeExtension(Constants):
"""
Instance Type Extension Constants
"""
STORAGE_TYPE = Constant('aggregate_instance_extra_specs:storage')
INSTANCE_AUTO_RECOVERY = Constant('sw:wrs:auto_recovery')
LIVE_MIGRATION_TIMEOUT = Constant('hw:wrs:live_migration_timeout')
LIVE_MIGRATION_MAX_DOWNTIME = Constant('hw:wrs:live_migration_max_downtime')
@ -34,7 +33,6 @@ class InstanceTypeExtension(Constants):
# Instance Type Constant Instantiation
STORAGE_TYPE = InstanceTypeStorage()
INSTANCE_TYPE_EXTENSION = InstanceTypeExtension()
@ -44,15 +42,14 @@ class InstanceTypeAttributes(ObjectData):
"""
def __init__(self, vcpus, mem_mb, disk_gb, ephemeral_gb, swap_gb,
guest_services, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type):
live_migration_max_downtime):
super(InstanceTypeAttributes, self).__init__('1.0.0')
self.update(dict(vcpus=vcpus, mem_mb=mem_mb, disk_gb=disk_gb,
ephemeral_gb=ephemeral_gb, swap_gb=swap_gb,
guest_services=guest_services,
auto_recovery=auto_recovery,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=live_migration_max_downtime,
storage_type=storage_type))
live_migration_max_downtime=live_migration_max_downtime))
class InstanceType(ObjectData):
@ -65,14 +62,13 @@ class InstanceType(ObjectData):
def update_details(self, vcpus, mem_mb, disk_gb, ephemeral_gb, swap_gb,
guest_services, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type):
live_migration_max_downtime):
self.update(dict(vcpus=vcpus, mem_mb=mem_mb, disk_gb=disk_gb,
ephemeral_gb=ephemeral_gb, swap_gb=swap_gb,
guest_services=guest_services,
auto_recovery=auto_recovery,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=live_migration_max_downtime,
storage_type=storage_type))
live_migration_max_downtime=live_migration_max_downtime))
def have_details(self):
return self.get('vcpus', None) is not None

View File

@ -25,7 +25,6 @@ from nfv_vim.objects._instance_group import InstanceGroup # noqa: F401
from nfv_vim.objects._instance_type import INSTANCE_TYPE_EXTENSION # noqa: F401
from nfv_vim.objects._instance_type import InstanceType # noqa: F401
from nfv_vim.objects._instance_type import InstanceTypeAttributes # noqa: F401
from nfv_vim.objects._instance_type import STORAGE_TYPE # noqa: F401
from nfv_vim.objects._network import Network # noqa: F401
from nfv_vim.objects._network import NetworkProviderData # noqa: F401
from nfv_vim.objects._service_host import ServiceHost # noqa: F401

View File

@ -26,7 +26,6 @@ from nfv_vim import instance_fsm
from nfv_vim import nfvi
from nfv_vim.objects._guest_services import GuestServices
from nfv_vim.objects._instance_type import STORAGE_TYPE
DLOG = debug.debug_get_logger('nfv_vim.objects.instance')
MAX_EVENT_REASON_LENGTH = 255
@ -1465,18 +1464,13 @@ class Instance(ObjectData):
# Always allow cold migration when booted from a volume
return True
storage_type = self._nfvi_instance.instance_type_storage_type
# TODO(bwensley): Always allow cold migration for instances using
# remote storage. There is currently no way to determine this, but we
# should eventually be able to check for a label on the compute host.
if STORAGE_TYPE.REMOTE_BACKED == storage_type:
# Always allow cold migration with remote storage
return True
config_option = 'max_cold_migrate_local_image_disk_gb'
config_option = None
if STORAGE_TYPE.LOCAL_IMAGE_BACKED == storage_type:
config_option = 'max_cold_migrate_local_image_disk_gb'
if (config_option is not None and
config.section_exists('instance-configuration')):
if config.section_exists('instance-configuration'):
section = config.CONF['instance-configuration']
max_disk_gb = int(section.get(config_option, 20))
else:
@ -1501,18 +1495,13 @@ class Instance(ObjectData):
# Always allow evacuate when booted from a volume
return True
storage_type = self._nfvi_instance.instance_type_storage_type
# TODO(bwensley): Always allow evacuate for instances using remote
# storage. There is currently no way to determine this, but we should
# eventually be able to check for a label on the compute host.
if STORAGE_TYPE.REMOTE_BACKED == storage_type:
# Always allow evacuate with remote storage
return True
config_option = 'max_evacuate_local_image_disk_gb'
config_option = None
if STORAGE_TYPE.LOCAL_IMAGE_BACKED == storage_type:
config_option = 'max_evacuate_local_image_disk_gb'
if (config_option is not None and
config.section_exists('instance-configuration')):
if config.section_exists('instance-configuration'):
section = config.CONF['instance-configuration']
max_disk_gb = int(section.get(config_option, 20))
else:
@ -1533,17 +1522,6 @@ class Instance(ObjectData):
if not self._live_migration_support:
return False
if self.image_uuid is None:
if (self._nfvi_instance.instance_type_swap_gb or
self._nfvi_instance.instance_type_ephemeral_gb):
return (STORAGE_TYPE.REMOTE_BACKED ==
self._nfvi_instance.instance_type_storage_type)
return True
else:
return (self._nfvi_instance.instance_type_storage_type in [
STORAGE_TYPE.LOCAL_IMAGE_BACKED,
STORAGE_TYPE.REMOTE_BACKED])
return True
def is_locked(self):

View File

@ -29,7 +29,6 @@ class InstanceTypeExtension(Constants):
"""
Instance Type Extension Constants
"""
STORAGE_TYPE = Constant('aggregate_instance_extra_specs:storage')
INSTANCE_AUTO_RECOVERY = Constant('sw:wrs:auto_recovery')
LIVE_MIGRATION_TIMEOUT = Constant('hw:wrs:live_migration_timeout')
LIVE_MIGRATION_MAX_DOWNTIME = Constant('hw:wrs:live_migration_max_downtime')
@ -37,7 +36,6 @@ class InstanceTypeExtension(Constants):
# Instance Type Constant Instantiation
STORAGE_TYPE = InstanceTypeStorage()
INSTANCE_TYPE_EXTENSION = InstanceTypeExtension()
@ -47,15 +45,14 @@ class InstanceTypeAttributes(ObjectData):
"""
def __init__(self, vcpus, mem_mb, disk_gb, ephemeral_gb, swap_gb,
guest_services, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type):
live_migration_max_downtime):
super(InstanceTypeAttributes, self).__init__('1.0.0')
self.update(dict(vcpus=vcpus, mem_mb=mem_mb, disk_gb=disk_gb,
ephemeral_gb=ephemeral_gb, swap_gb=swap_gb,
guest_services=guest_services,
auto_recovery=auto_recovery,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=live_migration_max_downtime,
storage_type=storage_type))
live_migration_max_downtime=live_migration_max_downtime))
class InstanceType(ObjectData):
@ -68,14 +65,13 @@ class InstanceType(ObjectData):
def update_details(self, vcpus, mem_mb, disk_gb, ephemeral_gb, swap_gb,
guest_services, auto_recovery, live_migration_timeout,
live_migration_max_downtime, storage_type):
live_migration_max_downtime):
self.update(dict(vcpus=vcpus, mem_mb=mem_mb, disk_gb=disk_gb,
ephemeral_gb=ephemeral_gb, swap_gb=swap_gb,
guest_services=guest_services,
auto_recovery=auto_recovery,
live_migration_timeout=live_migration_timeout,
live_migration_max_downtime=live_migration_max_downtime,
storage_type=storage_type))
live_migration_max_downtime=live_migration_max_downtime))
def have_details(self):
return self.get('vcpus', None) is not None

View File

@ -19,7 +19,6 @@
<th class="sortable normal_column">Disk</th>
<th class="sortable normal_column">Ephemeral</th>
<th class="sortable normal_column">Swap</th>
<th class="sortable normal_column">Storage-Type</th>
</tr>
</thead>
<tbody>
@ -32,7 +31,6 @@
<td>{{disk_gb}}GB</td>
<td>{{ephemeral_gb}}GB</td>
<td>{{swap_gb}}GB</td>
<td>{{storage_type}}</td>
</tr>
{{/instance_types}}
<tfoot>