Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-95023: Added os.setns and os.unshare to easily switch between namespaces on Linux#95046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
0bdd8bc3685a278f227405115c8a8845a86d7bb582987613a4c914137d23963b7abf20af74db551811263a37ac21386833ae4b66157b2c84b2df7f7b4a68b6dc51d015a3cff51d4519684c4b8cb9d3a3451c60d4225e06bfb64bb701d4af415e6d8b375165b7e2b44c3ae952c432d274afa9a0054c7bce01713eca6bb3451c0fb83dac402aff7f961cc44f0158bc8a6b14396e50c4809de7dd3d5c1bbdd29129d994883a43e365d2File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -590,6 +590,44 @@ process and user. | ||
| See the documentation for :func:`getgroups` for cases where it may not | ||
| return the same group list set by calling setgroups(). | ||
| .. function:: setns(fd, nstype=0) | ||
| Reassociate the current thread with a Linux namespace. | ||
| See the :manpage:`setns(2)` and :manpage:`namespaces(7)` man pages for more | ||
| details. | ||
| If *fd* refers to a :file:`/proc/{pid}/ns/` link, ``setns()`` reassociates the | ||
| calling thread with the namespace associated with that link, | ||
| and *nstype* may be set to one of the | ||
| :ref:`CLONE_NEW* constants <os-unshare-clone-flags>` | ||
| to impose constraints on the operation | ||
| (``0`` means no constraints). | ||
| Since Linux 5.8, *fd* may refer to a PID file descriptor obtained from | ||
| :func:`~os.pidfd_open`. In this case, ``setns()`` reassociates the calling thread | ||
| into one or more of the same namespaces as the thread referred to by *fd*. | ||
| This is subject to any constraints imposed by *nstype*, | ||
| which is a bit mask combining one or more of the | ||
| :ref:`CLONE_NEW* constants <os-unshare-clone-flags>`, | ||
| e.g. ``setns(fd, os.CLONE_NEWUTS | os.CLONE_NEWPID)``. | ||
| The caller's memberships in unspecified namespaces are left unchanged. | ||
| *fd* can be any object with a :meth:`~io.IOBase.fileno` method, or a raw file descriptor. | ||
| This example reassociates the thread with the ``init`` process's network namespace:: | ||
| fd = os.open("/proc/1/ns/net", os.O_RDONLY) | ||
| os.setns(fd, os.CLONE_NEWNET) | ||
| os.close(fd) | ||
| .. availability:: Linux >= 3.0 with glibc >= 2.14. | ||
| .. versionadded:: 3.12 | ||
noamcohen97 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| .. seealso:: | ||
| The :func:`~os.unshare` function. | ||
| .. function:: setpgrp() | ||
| Call the system call :c:func:`setpgrp` or ``setpgrp(0, 0)`` depending on | ||
| @@ -756,6 +794,49 @@ process and user. | ||
| The function is now always available and is also available on Windows. | ||
| .. function:: unshare(flags) | ||
| Disassociate parts of the process execution context, and move them into a | ||
| newly created namespace. | ||
| See the :manpage:`unshare(2)` | ||
| man page for more details. | ||
| The *flags* argument is a bit mask, combining zero or more of the | ||
| :ref:`CLONE_* constants <os-unshare-clone-flags>`, | ||
| that specifies which parts of the execution context should be | ||
| unshared from their existing associations and moved to a new namespace. | ||
| If the *flags* argument is ``0``, no changes are made to the calling process's | ||
| execution context. | ||
| .. availability:: Linux >= 2.6.16. | ||
| .. versionadded:: 3.12 | ||
| .. seealso:: | ||
| The :func:`~os.setns` function. | ||
noamcohen97 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| .. _os-unshare-clone-flags: | ||
| Flags to the :func:`unshare` function, if the implementation supports them. | ||
| See :manpage:`unshare(2)` in the Linux manual | ||
| for their exact effect and availability. | ||
| .. data:: CLONE_FILES | ||
| CLONE_FS | ||
| CLONE_NEWCGROUP | ||
| CLONE_NEWIPC | ||
| CLONE_NEWNET | ||
| CLONE_NEWNS | ||
| CLONE_NEWPID | ||
| CLONE_NEWTIME | ||
| CLONE_NEWUSER | ||
| CLONE_NEWUTS | ||
| CLONE_SIGHAND | ||
| CLONE_SYSVSEM | ||
| CLONE_THREAD | ||
| CLONE_VM | ||
| .. _os-newstreams: | ||
| File Object Creation | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2194,6 +2194,53 @@ def test_utime(self): | ||
| 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 | ||
noamcohen97 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| finally: | ||
| os.close(fd) | ||
| """ | ||
| assert_python_ok("-c", code) | ||
| def tearDownModule(): | ||
| support.reap_children() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Implement :func:`os.setns` and :func:`os.unshare` for Linux. Patch by Noam Cohen. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.