Kill all processes running in a namespace before deletion
In "NamespaceFixture", before deleting the namespace, this patch introduces a check to first kill all processes running on it. Closes-Bug: #1838793 Change-Id: I27f3db33f2e7ab685523fd2d6922177d7c9cb71b
This commit is contained in:
parent
de54e3c3c6
commit
be7bb4d0f5
@ -15,4 +15,8 @@
|
|||||||
ping: RegExpFilter, ping, root, ping, -w, \d+, -c, \d+, [0-9\.]+
|
ping: RegExpFilter, ping, root, ping, -w, \d+, -c, \d+, [0-9\.]+
|
||||||
ping_alt: RegExpFilter, ping, root, ping, -c, \d+, -w, \d+, [0-9\.]+
|
ping_alt: RegExpFilter, ping, root, ping, -c, \d+, -w, \d+, [0-9\.]+
|
||||||
ping6: RegExpFilter, ping6, root, ping6, -w, \d+, -c, \d+, [0-9A-Fa-f:]+
|
ping6: RegExpFilter, ping6, root, ping6, -w, \d+, -c, \d+, [0-9A-Fa-f:]+
|
||||||
ping6_alt: RegExpFilter, ping6, root, ping6, -c, \d+, -w, \d+, [0-9A-Fa-f:]+
|
ping6_alt: RegExpFilter, ping6, root, ping6, -c, \d+, -w, \d+, [0-9A-Fa-f:]+
|
||||||
|
|
||||||
|
# "sleep" command, only for testing
|
||||||
|
sleep: RegExpFilter, sleep, root, sleep, \d+
|
||||||
|
kill_sleep: KillFilter, root, sleep, -9
|
||||||
|
@ -932,6 +932,15 @@ def network_namespace_exists(namespace, try_is_ready=False, **kwargs):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def list_namespace_pids(namespace):
|
||||||
|
"""List namespace process PIDs
|
||||||
|
|
||||||
|
:param namespace: (string) the name of the namespace
|
||||||
|
:return: (tuple)
|
||||||
|
"""
|
||||||
|
return privileged.list_ns_pids(namespace)
|
||||||
|
|
||||||
|
|
||||||
def ensure_device_is_ready(device_name, namespace=None):
|
def ensure_device_is_ready(device_name, namespace=None):
|
||||||
dev = IPDevice(device_name, namespace=namespace)
|
dev = IPDevice(device_name, namespace=namespace)
|
||||||
try:
|
try:
|
||||||
|
@ -25,5 +25,6 @@ default = priv_context.PrivContext(
|
|||||||
capabilities=[caps.CAP_SYS_ADMIN,
|
capabilities=[caps.CAP_SYS_ADMIN,
|
||||||
caps.CAP_NET_ADMIN,
|
caps.CAP_NET_ADMIN,
|
||||||
caps.CAP_DAC_OVERRIDE,
|
caps.CAP_DAC_OVERRIDE,
|
||||||
caps.CAP_DAC_READ_SEARCH],
|
caps.CAP_DAC_READ_SEARCH,
|
||||||
|
caps.CAP_SYS_PTRACE],
|
||||||
)
|
)
|
||||||
|
@ -187,6 +187,12 @@ def open_namespace(namespace):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.default.entrypoint
|
||||||
|
def list_ns_pids(namespace):
|
||||||
|
"""List namespace process PIDs"""
|
||||||
|
return netns.ns_pids().get(namespace, [])
|
||||||
|
|
||||||
|
|
||||||
def _translate_ip_device_exception(e, device=None, namespace=None):
|
def _translate_ip_device_exception(e, device=None, namespace=None):
|
||||||
if e.code == errno.ENODEV:
|
if e.code == errno.ENODEV:
|
||||||
raise NetworkInterfaceNotFound(device=device, namespace=namespace)
|
raise NetworkInterfaceNotFound(device=device, namespace=namespace)
|
||||||
|
@ -585,6 +585,8 @@ class NamespaceFixture(fixtures.Fixture):
|
|||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
if self.ip_wrapper.netns.exists(self.name):
|
if self.ip_wrapper.netns.exists(self.name):
|
||||||
|
for pid in ip_lib.list_namespace_pids(self.name):
|
||||||
|
utils.kill_process(pid, signal.SIGKILL, run_as_root=True)
|
||||||
self.ip_wrapper.netns.delete(self.name)
|
self.ip_wrapper.netns.delete(self.name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
|
import eventlet
|
||||||
import netaddr
|
import netaddr
|
||||||
from neutron_lib import constants as n_cons
|
from neutron_lib import constants as n_cons
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
@ -618,3 +621,35 @@ class GetLinkAttributesTestCase(functional_base.BaseSudoTestCase):
|
|||||||
'alias', 'allmulticast', 'link_kind']
|
'alias', 'allmulticast', 'link_kind']
|
||||||
attr = self.device.link.attributes
|
attr = self.device.link.attributes
|
||||||
self.assertSetEqual(set(expected_attr), set(attr.keys()))
|
self.assertSetEqual(set(expected_attr), set(attr.keys()))
|
||||||
|
|
||||||
|
|
||||||
|
class ListNamespacePids(functional_base.BaseSudoTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ListNamespacePids, self).setUp()
|
||||||
|
self.namespace = self.useFixture(net_helpers.NamespaceFixture()).name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _run_sleep(namespace):
|
||||||
|
ip_wrapper = ip_lib.IPWrapper(namespace=namespace)
|
||||||
|
ip_wrapper.netns.execute(['sleep', '100'], check_exit_code=False)
|
||||||
|
|
||||||
|
def _check_pids(self, num_pids, namespace=None):
|
||||||
|
namespace = self.namespace if not namespace else namespace
|
||||||
|
self.pids = priv_ip_lib.list_ns_pids(namespace)
|
||||||
|
return len(self.pids) == num_pids
|
||||||
|
|
||||||
|
def test_list_namespace_pids(self):
|
||||||
|
eventlet.spawn_n(self._run_sleep, self.namespace)
|
||||||
|
|
||||||
|
try:
|
||||||
|
check_pids = functools.partial(self._check_pids, 1)
|
||||||
|
common_utils.wait_until_true(check_pids, timeout=5)
|
||||||
|
except common_utils.WaitTimeout:
|
||||||
|
self.fail('Process no found in namespace %s' % self.namespace)
|
||||||
|
|
||||||
|
def test_list_namespace_pids_nothing_running_inside(self):
|
||||||
|
self.assertTrue(self._check_pids(0))
|
||||||
|
|
||||||
|
def test_list_namespace_not_created(self):
|
||||||
|
self.assertTrue(self._check_pids(0, namespace='othernamespace'))
|
||||||
|
Loading…
Reference in New Issue
Block a user