Add extra logic to handle port detach issue

nova manager will first delete local neutron port before call driver to
detach port on PowerVC. This behavior will trigger a local port deleted
event and cause current driver code failed to retrieve remote PowerVC
port id when doing interface detach

1. First priority is to use local port id to retrieve remote PowerVC
port id, which is the current logic.
2. If local port id cannot be retrieved, it will call interface_list on
remote PowerVC instance and get all attached interface information. Then
the code will scan all the local port IP addresses and compare to remote
IP addresses and find the matched port id to detach.

Change-Id: I3a87f3780c2cb949a0dc80380a37ab17bb98e059
Closes-Bug: #1392540
(cherry picked from commit 8c766d0861)
This commit is contained in:
Yi Ming Yin 2014-11-14 16:57:01 +08:00
parent 7a82ac4a32
commit 7fc7fc17e9
2 changed files with 71 additions and 14 deletions

View File

@ -448,6 +448,8 @@ class PowerVCDriver(driver.ComputeDriver):
def attach_interface(self, instance, image_meta, vif):
"""Attach an interface to the instance.
"""
LOG.debug(_('enter PowerVC driver attach_interface for instance %s'
' with vif info as %s'), instance, vif)
context = nova.context.get_admin_context()
try:
server_id = instance.get('uuid')
@ -466,11 +468,12 @@ class PowerVCDriver(driver.ComputeDriver):
port_id,
network_id,
ipAddress)
LOG.debug(_('exit PowerVC driver attach_interface for instance %s'
' with vif info as %s'), instance, vif)
def _get_port_network_ipaddress_from_vif(self, vif):
"""Get port uuid, network uuid, and ip Address from vif
"""
local_port_id = ''
local_network_id = ''
ipAddress = ''
@ -490,18 +493,19 @@ class PowerVCDriver(driver.ComputeDriver):
return (local_port_id, local_network_id, ipAddress)
def detach_interface(self, instance, vif):
"""Detach an interface from the instance.
"""
Detach an interface from the instance.
This method is called AFTER nova compute manager deleted local port.
"""
LOG.debug(_('enter PowerVC driver detach_interface for instance %s'
' with vif info as %s'), instance, vif)
context = nova.context.get_admin_context()
local_port_id = vif.get('id')
LOG.debug(_("Local port uuid: %s") % local_port_id)
if not local_port_id:
LOG.error(_("no port id found to detach the interface."))
return
# call service to detach interface
self._service.detach_interface(context,
instance,
local_port_id)
vif)
LOG.debug(_('exit PowerVC driver detach_interface for instance %s'
' with vif info as %s'), instance, vif)
def migrate_disk_and_power_off(self, context, instance, dest,
instance_type, network_info,

View File

@ -1383,20 +1383,73 @@ class PowerVCService(object):
# TODO Loop to get the pvc_id from local db. Return this method until
# pvc_id got verified in local db, Default timeout is 150s
def detach_interface(self, context, instance, local_port_id):
def detach_interface(self, context, instance, vif):
"""detach a port from a specified vm
:param context: context for this action
:param instance: the vm instance that new interface attach to
:param local_port_id: the local port uuid
:param vif: the local interface info
"""
pvc_port_uuid = self._api.get_pvc_port_uuid(context, local_port_id)
LOG.debug(_("pvc_port_uuid to be detach: %s"), pvc_port_uuid)
# get client server instance from a db instance
server_with_pvc_id = self._get_server(instance)
# get the powervc client server instance from novaclient
server_client_obj = self._manager.get(server_with_pvc_id)
pvc_port_uuid = None
local_port_id = vif.get('id')
if local_port_id:
pvc_port_uuid = self._api.get_pvc_port_uuid(context,
local_port_id)
if not pvc_port_uuid:
LOG.warning(_('Cannot retrieve pvc port id for local port %s.'
' Attempt to filter out pvc port id with IP'
' addresses attached to pvc instance %s'),
local_port_id, server_with_pvc_id.id)
# Failed to retrieve powervc port uuid through local port id
# This can be caused by local port deleted has already been handled
# Try to locate pvc port id by IP address
local_ips = vif.fixed_ips()
if not local_ips:
LOG.warning(_('Cannot locate detach port id for pvc server %s'
', because no local ips found on local VIF %s'),
server_with_pvc_id.id, vif)
return
candidate_ips = []
for local_ip in local_ips:
ip_addr = local_ip.get('address')
if ip_addr:
candidate_ips.append(ip_addr)
if not candidate_ips:
LOG.warning(_('Cannot locate detach port id for pvc server %s'
', because no ip address found on local VIF %s'),
server_with_pvc_id.id, vif)
return
pvc_interface_list = server_client_obj.interface_list()
for pvc_intf in pvc_interface_list:
pvc_fixed_ips = pvc_intf._info.get('fixed_ips')
if not pvc_fixed_ips:
continue
pvc_ips = []
for pvc_ip in pvc_fixed_ips:
pvc_ips.append(pvc_ip.get('ip_address'))
cmp_ips = [x for x in pvc_ips if x not in candidate_ips]
if len(cmp_ips) == 0:
pvc_port_uuid = pvc_intf._info.get('port_id')
break
else:
LOG.warning(_('Cannot locate detach port id for pvc server %s'
', because cannot retrieve matched pvc'
' interface for addresses %s from %s'),
server_with_pvc_id.id, candidate_ips,
pvc_interface_list)
return
LOG.debug(_('pvc_port_uuid to be detach: %s'), pvc_port_uuid)
# get the powervc client server instance from novaclient
response = server_client_obj.interface_detach(pvc_port_uuid)
LOG.debug(_("detach response: %s"), response)
LOG.debug(_('detach response: %s'), response)
return response
def set_pvc_id_to_port(self, ctx, local_port_id, pvc_port_id):