Fix leak of ports on share server deletion
- Manila share server deletion happens asynchronously. If deletion of
share server fails in between, share server network ports remained as
it is. So we should better delete share network ports first and then
continue share server deletion.
- It may be possible, that there are ports existing without a
corresponding manila network allocation entry in the manila db, because
port create request may have been successfully sent to neutron, but not
stored in db. So query(and delete) those from neutron after db entries
are deleted.
Closes-bug: #2067266
Change-Id: Id86dade1194494e599aea9adad06e4ca6cb119b6
(cherry picked from commit 76d0329698
)
This commit is contained in:
parent
b46096fcdc
commit
19622387dc
@ -107,7 +107,8 @@ class NetworkBaseAPI(db_base.Base, metaclass=abc.ABCMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def deallocate_network(self, context, share_server_id):
|
def deallocate_network(self, context, share_server_id, share_network=None,
|
||||||
|
share_network_subnet=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
@ -296,7 +296,8 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
ip_version}
|
ip_version}
|
||||||
raise exception.NetworkBadConfigurationException(reason=msg)
|
raise exception.NetworkBadConfigurationException(reason=msg)
|
||||||
|
|
||||||
def deallocate_network(self, context, share_server_id):
|
def deallocate_network(self, context, share_server_id,
|
||||||
|
share_network=None, share_network_subnet=None):
|
||||||
"""Deallocate neutron network resources for the given share server.
|
"""Deallocate neutron network resources for the given share server.
|
||||||
|
|
||||||
Delete previously allocated neutron ports, delete manila db
|
Delete previously allocated neutron ports, delete manila db
|
||||||
@ -304,6 +305,8 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
|
|
||||||
:param context: RequestContext object
|
:param context: RequestContext object
|
||||||
:param share_server_id: id of share server
|
:param share_server_id: id of share server
|
||||||
|
:param share_network: share network data
|
||||||
|
:param share_network_subnet: share network subnet data
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
ports = self.db.network_allocations_get_for_share_server(
|
ports = self.db.network_allocations_get_for_share_server(
|
||||||
@ -312,6 +315,24 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
for port in ports:
|
for port in ports:
|
||||||
self._delete_port(context, port)
|
self._delete_port(context, port)
|
||||||
|
|
||||||
|
# It may be possible that there are ports existing without a
|
||||||
|
# corresponding manila network allocation entry in the manila db,
|
||||||
|
# because port create request may have been successfully sent to
|
||||||
|
# neutron, but the response, the created port could not be stored
|
||||||
|
# in manila due to unreachable db
|
||||||
|
if share_network_subnet:
|
||||||
|
ports = []
|
||||||
|
try:
|
||||||
|
ports = self.neutron_api.list_ports(
|
||||||
|
network_id=share_network_subnet['neutron_net_id'],
|
||||||
|
device_owner='manila:share',
|
||||||
|
device_id=share_server_id)
|
||||||
|
except exception.NetworkException:
|
||||||
|
LOG.warning("Failed to list ports using neutron API during "
|
||||||
|
"deallocate_network.")
|
||||||
|
for port in ports:
|
||||||
|
self._delete_port(context, port, ignore_db=True)
|
||||||
|
|
||||||
def _get_port_create_args(self, share_server, share_network_subnet,
|
def _get_port_create_args(self, share_server, share_network_subnet,
|
||||||
device_owner, count=0):
|
device_owner, count=0):
|
||||||
return {
|
return {
|
||||||
@ -354,7 +375,7 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
|
|
||||||
return self.db.network_allocation_create(context, port_dict)
|
return self.db.network_allocation_create(context, port_dict)
|
||||||
|
|
||||||
def _delete_port(self, context, port):
|
def _delete_port(self, context, port, ignore_db=False):
|
||||||
try:
|
try:
|
||||||
self.neutron_api.delete_port(port['id'])
|
self.neutron_api.delete_port(port['id'])
|
||||||
except exception.NetworkException:
|
except exception.NetworkException:
|
||||||
@ -362,7 +383,8 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
context, port['id'], {'status': constants.STATUS_ERROR})
|
context, port['id'], {'status': constants.STATUS_ERROR})
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
self.db.network_allocation_delete(context, port['id'])
|
if not ignore_db:
|
||||||
|
self.db.network_allocation_delete(context, port['id'])
|
||||||
|
|
||||||
def _has_provider_network_extension(self):
|
def _has_provider_network_extension(self):
|
||||||
extensions = self.neutron_api.list_extensions()
|
extensions = self.neutron_api.list_extensions()
|
||||||
|
@ -314,7 +314,8 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
self.db.network_allocation_create(context, data))
|
self.db.network_allocation_create(context, data))
|
||||||
return allocations
|
return allocations
|
||||||
|
|
||||||
def deallocate_network(self, context, share_server_id):
|
def deallocate_network(self, context, share_server_id,
|
||||||
|
share_network=None, share_network_subnet=None):
|
||||||
"""Deallocate network resources for share server."""
|
"""Deallocate network resources for share server."""
|
||||||
allocations = self.db.network_allocations_get_for_share_server(
|
allocations = self.db.network_allocations_get_for_share_server(
|
||||||
context, share_server_id)
|
context, share_server_id)
|
||||||
|
@ -960,10 +960,13 @@ class ShareDriver(object):
|
|||||||
self.admin_network_api.allocate_network(
|
self.admin_network_api.allocate_network(
|
||||||
context, share_server, **kwargs)
|
context, share_server, **kwargs)
|
||||||
|
|
||||||
def deallocate_network(self, context, share_server_id):
|
def deallocate_network(self, context, share_server_id, share_network=None,
|
||||||
|
share_network_subnet=None):
|
||||||
"""Deallocate network resources for the given share server."""
|
"""Deallocate network resources for the given share server."""
|
||||||
if self.get_network_allocations_number():
|
if self.get_network_allocations_number():
|
||||||
self.network_api.deallocate_network(context, share_server_id)
|
self.network_api.deallocate_network(
|
||||||
|
context, share_server_id, share_network=share_network,
|
||||||
|
share_network_subnet=share_network_subnet)
|
||||||
|
|
||||||
def choose_share_server_compatible_with_share(self, context, share_servers,
|
def choose_share_server_compatible_with_share(self, context, share_servers,
|
||||||
share, snapshot=None,
|
share, snapshot=None,
|
||||||
|
@ -4605,6 +4605,22 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
self.db.share_server_update(context, server_id,
|
self.db.share_server_update(context, server_id,
|
||||||
{'status': constants.STATUS_DELETING})
|
{'status': constants.STATUS_DELETING})
|
||||||
try:
|
try:
|
||||||
|
LOG.debug("Deleting network of share server '%s'", server_id)
|
||||||
|
share_net = None
|
||||||
|
share_net_subnet = None
|
||||||
|
if subnet_id:
|
||||||
|
try:
|
||||||
|
share_net_subnet = self.db.share_network_subnet_get(
|
||||||
|
context, subnet_id)
|
||||||
|
share_net = self.db.share_network_get(
|
||||||
|
context, share_net_subnet['share_network_id'])
|
||||||
|
except Exception:
|
||||||
|
LOG.warning('Share network subnet not found during '
|
||||||
|
'deletion of share server.')
|
||||||
|
self.driver.deallocate_network(context, share_server['id'],
|
||||||
|
share_net,
|
||||||
|
share_net_subnet)
|
||||||
|
|
||||||
LOG.debug("Deleting share server '%s'", server_id)
|
LOG.debug("Deleting share server '%s'", server_id)
|
||||||
security_services = []
|
security_services = []
|
||||||
for ss_name in constants.SECURITY_SERVICES_ALLOWED_TYPES:
|
for ss_name in constants.SECURITY_SERVICES_ALLOWED_TYPES:
|
||||||
@ -4629,7 +4645,6 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
LOG.info(
|
LOG.info(
|
||||||
"Share server '%s' has been deleted successfully.",
|
"Share server '%s' has been deleted successfully.",
|
||||||
share_server['id'])
|
share_server['id'])
|
||||||
self.driver.deallocate_network(context, share_server['id'])
|
|
||||||
|
|
||||||
@add_hooks
|
@add_hooks
|
||||||
@utils.require_driver_initialized
|
@utils.require_driver_initialized
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Share server deletion happens asynchronously and failure during this delete
|
||||||
|
results in leakage of neutron ports. This is fixed in two steps, first by
|
||||||
|
trying to delete ports before share server deletion. Second, after ports
|
||||||
|
from Manila db entries are deleted, query is made to neutron to get ports
|
||||||
|
which are allocated for share server and missing in db. And then try to
|
||||||
|
delete those ports. For more details please check
|
||||||
|
Launchpad `bug 2067266 <https://bugs.launchpad.net/manila/+bug/2067266>`_
|
Loading…
Reference in New Issue
Block a user