gh-95023: Added os.setns and os.unshare functions (#95046)

Added os.setns and os.unshare to easily switch between namespaces
on Linux.

Co-authored-by: Christian Heimes <christian@python.org>
Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Noam Cohen 2022-10-20 12:08:54 +03:00 committed by GitHub
parent c1e02d4e4e
commit a371a7e03e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 418 additions and 1 deletions

View file

@ -2191,6 +2191,53 @@ class TestPosixWeaklinking(unittest.TestCase):
os.utime("path", dir_fd=0)
class NamespacesTests(unittest.TestCase):
"""Tests for os.unshare() and os.setns()."""
@unittest.skipUnless(hasattr(os, 'unshare'), 'needs os.unshare()')
@unittest.skipUnless(hasattr(os, 'setns'), 'needs os.setns()')
@unittest.skipUnless(os.path.exists('/proc/self/ns/uts'), 'need /proc/self/ns/uts')
@support.requires_linux_version(3, 0, 0)
def test_unshare_setns(self):
code = """if 1:
import errno
import os
import sys
fd = os.open('/proc/self/ns/uts', os.O_RDONLY)
try:
original = os.readlink('/proc/self/ns/uts')
try:
os.unshare(os.CLONE_NEWUTS)
except OSError as e:
if e.errno == errno.ENOSPC:
# skip test if limit is exceeded
sys.exit()
raise
new = os.readlink('/proc/self/ns/uts')
if original == new:
raise Exception('os.unshare failed')
os.setns(fd, os.CLONE_NEWUTS)
restored = os.readlink('/proc/self/ns/uts')
if original != restored:
raise Exception('os.setns failed')
except PermissionError:
# The calling process did not have the required privileges
# for this operation
pass
except OSError as e:
# Skip the test on these errors:
# - ENOSYS: syscall not available
# - EINVAL: kernel was not configured with the CONFIG_UTS_NS option
# - ENOMEM: not enough memory
if e.errno not in (errno.ENOSYS, errno.EINVAL, errno.ENOMEM):
raise
finally:
os.close(fd)
"""
assert_python_ok("-c", code)
def tearDownModule():
support.reap_children()