Volume sync and create/attach/detach implement for multiattach function

This bug tracks the implementation for volume sync and create/attach/detach
for multiattach function. Host status update also fixed along with this bug.

Change-Id: I45a776775473818c75388c3554664982849c4fae
Closes-Bug: #1491723
This commit is contained in:
Jerry Cai 2015-09-03 16:16:38 +08:00
parent d96ff4ab09
commit 2c5f580f48
6 changed files with 140 additions and 45 deletions

View File

@ -180,6 +180,7 @@ class PowerVCDriver(VolumeDriver):
display_description = getattr(volume, 'display_description', None)
volume_type_obj = getattr(volume, 'volume_type', None)
metadatas = getattr(volume, 'volume_metadata', None)
multiattach = getattr(volume, 'multiattach', False)
meta = {}
if metadatas:
# Use map() to get a list of 'key', 'value' tuple
@ -200,7 +201,8 @@ class PowerVCDriver(VolumeDriver):
display_description=display_description,
metadata=meta,
volume_type=getattr(volume_type_obj, 'id',
None))
None),
multiattach=multiattach)
return volume_data_updates

View File

@ -42,7 +42,7 @@ class PowerVCService(object):
display_name=None, display_description=None,
volume_type=None, user_id=None,
project_id=None, availability_zone=None,
metadata=None, imageRef=None):
metadata=None, imageRef=None, multiattach=False):
"""
Creates a volume on powervc
"""
@ -60,7 +60,8 @@ class PowerVCService(object):
project_id,
availability_zone,
{},
imageRef)
imageRef,
multiattach)
# update powervc uuid to db immediately to avoid duplicated
# synchronization
@ -281,9 +282,9 @@ class PowerVCService(object):
if metaDataItem.key == constants.LOCAL_PVC_PREFIX + 'id':
pvc_volume_id = metaDataItem.value
break
else:
LOG.warning('Fail to get pvc_id %s' % volume_id)
raise exceptions.BadRequest
else:
LOG.warning('Fail to get pvc_id.')
raise exceptions.BadRequest
LOG.debug('wait until PVC volume %s status to in-use', pvc_volume_id)
FILPC = loopingcall.FixedIntervalLoopingCall
@ -310,9 +311,9 @@ class PowerVCService(object):
if metaDataItem.key == constants.LOCAL_PVC_PREFIX + 'id':
pvc_volume_id = metaDataItem.value
break
else:
LOG.warning('Fail to get pvc_id %s' % volume_id)
raise exceptions.BadRequest
else:
LOG.warning('Fail to get pvc_id')
raise exceptions.BadRequest
LOG.debug('wait until PVC volume %s status to available',
pvc_volume_id)

View File

@ -977,6 +977,7 @@ class PowerVCCinderManager(service.Service):
try:
db.volume_update(context, local_volume.get('id'), values)
self._update_volume_attachments(context, pvc_volume, local_volume)
ret = True
except Exception as e:
ret = False
@ -1065,7 +1066,8 @@ class PowerVCCinderManager(service.Service):
return None
else:
try:
db.volume_create(context, values)
local_volume = db.volume_create(context, values)
self._update_volume_attachments(context, volume, local_volume)
except Exception as e:
LOG.debug(_("Failed to create volume %s. Exception: %s")
% (str(values), str(e)))
@ -1123,24 +1125,6 @@ class PowerVCCinderManager(service.Service):
if volume_type is not None:
volume_type_id = volume_type.get('id')
# Get attachment information
attachments = volume.get('attachments')
# attach_time = None
attach_status = None
attached_host = None
mountpoint = None
instance_uuid = None
if attachments is not None and len(attachments) > 0:
attach_status = 'attached'
attach = attachments[0]
attached_host = attach.get('host_name')
mountpoint = attach.get('device')
# Here instance_uuid also can be assigned metadata['instance_uuid']
# metadata['instance_uuid'] equal to attach['server_id']
instance_uuid = attach.get('server_id')
instance_uuid = self._get_local_instance_id(instance_uuid)
bootable = 0
if volume.get('bootable') == 'true':
bootable = 1
@ -1151,6 +1135,7 @@ class PowerVCCinderManager(service.Service):
host = "%s@%s" % (CONF.host, constants.BACKEND_POWERVCDRIVER)
disp_name = volume.get('display_name') or volume.get('name')
LOG.debug(_("volume disp_name: %s") % disp_name)
multiattach = volume.get('multiattach', False) or False
values = {'display_name': disp_name,
'display_description': volume.get('display_description'),
# 'volume_type_id': volume_type_id,
@ -1165,10 +1150,7 @@ class PowerVCCinderManager(service.Service):
'metadata': metadata,
'project_id': project_id,
'user_id': user_id,
'attached_host': attached_host,
'mountpoint': mountpoint,
'instance_uuid': instance_uuid,
'attach_status': attach_status
'multiattach': multiattach
}
if(volume_type_id is not None):
@ -1176,6 +1158,67 @@ class PowerVCCinderManager(service.Service):
return values
def _update_volume_attachments(self, context, pvc_volume, local_volume):
"""
Add/Delete/Update volume attachments information which includes
attaching instance, mountpoint, volume id, etc.
Note that pvc driver passes pvc volume attachments' "attachment_id" to
db api, which will be set as local attachment_id.
"""
# Get attachment information
attachments = pvc_volume.get('attachments')
pvc_att_list = []
for attachment in attachments:
pvc_att_id = attachment.get('attachment_id')
pvc_att_list.append(pvc_att_id)
try:
local_att = db.volume_attachment_get(context, pvc_att_id)
if local_att:
# if found local attachments by pvc attachments'
# attachment_id, then update
self._update_volume_attachment(context, attachment,
local_att.get('id'))
except:
# if no local attachment found, then insert a new one, which
# id maps to pvc attachments' attachment_id
self._insert_volume_attachment(context, pvc_att_id, attachment,
local_volume)
# Cleanup the local attachments
local_vid = local_volume.get('id')
attachments = db.volume_attachment_get_used_by_volume_id(context,
local_vid)
attachments_tbd = [att for att in attachments
if att.get('id') not in pvc_att_list]
for attachment_tbd in attachments_tbd:
db.volume_detached(context, local_vid,
attachment_tbd.get('id'))
def _insert_volume_attachment(self, context, pvc_att_id, pvc_attachment,
local_volume):
# set new local att id equal with pvc id to make the sync possible
local_att_id = pvc_att_id
pvc_instance_uuid = pvc_attachment.get('server_id')
local_instance_uuid = self._get_local_instance_id(pvc_instance_uuid)
mountpoint = pvc_attachment.get('device')
hostname = pvc_attachment.get('host_name')
values = {'id': local_att_id,
'volume_id': local_volume.get('id'),
'server_id': local_instance_uuid}
attachment = db.volume_attach(context, values)
db.volume_attached(context, attachment['id'],
local_instance_uuid, hostname, mountpoint)
def _update_volume_attachment(self, context, pvc_attachment,
local_att_id):
mountpoint = pvc_attachment.get('device')
hostname = pvc_attachment.get('host_name')
pvc_instance_uuid = pvc_attachment.get('server_id')
local_instance_uuid = self._get_local_instance_id(pvc_instance_uuid)
values = {'server_id': local_instance_uuid,
'host_name': hostname,
'device': mountpoint}
db.volume_attachment_update(context, local_att_id, values)
def _start_periodic_volume_sync(self, context):
"""
Initialize the periodic syncing of instances from PowerVC into the

View File

@ -158,6 +158,49 @@ class PVCVolumeManager(volumes.VolumeManager):
return self._list("/volumes%s%s" % (detail, query_string),
"volumes")
def create(self, size, snapshot_id=None, source_volid=None,
display_name=None, display_description=None,
volume_type=None, user_id=None,
project_id=None, availability_zone=None,
metadata=None, imageRef=None, multiattach=False):
"""
Creates a pvc volume with multiattach specified.
:param size: Size of volume in GB
:param snapshot_id: ID of the snapshot
:param display_name: Name of the volume
:param display_description: Description of the volume
:param volume_type: Type of volume
:param user_id: User id derived from context
:param project_id: Project id derived from context
:param availability_zone: Availability Zone to use
:param metadata: Optional metadata to set on volume creation
:param imageRef: reference to an image stored in glance
:param multiattach: if enable the multiattach
:rtype: :class:`Volume`
"""
if metadata is None:
volume_metadata = {}
else:
volume_metadata = metadata
body = {'volume': {'size': size,
'snapshot_id': snapshot_id,
'display_name': display_name,
'display_description': display_description,
'volume_type': volume_type,
'user_id': user_id,
'project_id': project_id,
'availability_zone': availability_zone,
'status': "creating",
'attach_status': "detached",
'metadata': volume_metadata,
'imageRef': imageRef,
'source_volid': source_volid,
'multiattach': multiattach
}}
return self._create('/volumes', body, 'volume')
class PVCStorageTemplateManager(volume_types.VolumeTypeManager):
"""

View File

@ -192,11 +192,15 @@ class ComputeServiceManager(object):
if local_service is None:
LOG.debug("local service not found for %s" % remote_service.host)
return
if remote_service.state == "down" and local_service.started:
if (remote_service.state == "down" or
remote_service.hypervisor_state != "operating") \
and local_service.started:
LOG.debug("Stopping remote service %s" % local_service.host)
local_service.stop()
return
if remote_service.state == "up" and not local_service.started:
if (remote_service.state == "up" and
remote_service.hypervisor_state == "operating") \
and not local_service.started:
LOG.debug("Starting remote service %s" % local_service.host)
local_service.start()

View File

@ -1298,31 +1298,33 @@ class PowerVCDriver(driver.ComputeDriver):
return None
info = hypervisor._info
local_gb = info["local_gb"]
local_gb = info.get("local_gb") or 0
if 0 == int(local_gb):
local_gb = info["local_gb_used"]
local_gb = info.get("local_gb_used") or 0
# avoid value too large to damage the hosting os
m_size = CONF.powervc.max_host_disk_size
local_gb = m_size if local_gb > m_size else local_gb
disk_available_least = info["disk_available_least"]
disk_available_least = info.get("disk_available_least") or 0
disk_available_least = m_size if disk_available_least > m_size else\
disk_available_least
vcpus = int(float(info["vcpus"]) - float(info["proc_units_reserved"]))
memory_mb = int(info["memory_mb"]) - int(info["memory_mb_reserved"])
p_u_r = float(info.get("proc_units_reserved") or 0)
vcpus = int(float(info.get("vcpus") or 0) - p_u_r)
m_m_r = int(info.get("memory_mb_reserved") or 0)
memory_mb = int(info.get("memory_mb") or 0) - m_m_r
used_memory = info.get("memory_mb_used") or\
(memory_mb - int(info.get("free_ram_mb")))
(memory_mb - int(info.get("free_ram_mb") or 0))
data = {'vcpus': vcpus,
'vcpus_used': info["vcpus_used"],
'vcpus_used': info.get("vcpus_used"),
'memory_mb': memory_mb,
'memory_mb_used': used_memory,
'local_gb': local_gb,
'local_gb_used': info["local_gb_used"],
'local_gb_used': info.get("local_gb_used") or 0,
'disk_available_least': disk_available_least,
'hypervisor_hostname': info["hypervisor_hostname"],
'hypervisor_type': info["hypervisor_type"],
'hypervisor_version': info["hypervisor_version"],
'hypervisor_hostname': info.get("hypervisor_hostname"),
'hypervisor_type': info.get("hypervisor_type"),
'hypervisor_version': info.get("hypervisor_version"),
'cpu_info': info["cpu_info"],
'supported_instances': jsonutils.dumps(
constants.POWERVC_SUPPORTED_INSTANCES)}