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:
parent
d96ff4ab09
commit
2c5f580f48
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)}
|
||||
|
|
Loading…
Reference in New Issue