Skip to content
This repository was archived by the owner on Dec 5, 2022. It is now read-only.

Commit 3155ad0

Browse files
committed
added option to specify different path to /proc file system (useful in containers); documentation updates
1 parent adcfe14 commit 3155ad0

File tree

3 files changed

+35
-28
lines changed

3 files changed

+35
-28
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ NSEnter
55
This Python package allows entering Linux kernel namespaces (mount, IPC, net, PID, user and UTS) by doing the "setns" syscall.
66
The command line interface tries to be similar to the nsenter_ C program.
77

8-
Requires Python 3.4.
8+
Requires Python 2.6 or higher
99

1010
See the introductory `blog post "Entering Kernel Namespaces from Python"`_.
1111

nsenter/__init__.py

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/env python
22

33
"""
44
nsenter - run program with namespaces of other processes
@@ -15,7 +15,7 @@
1515
except ImportError:
1616
from contextlib2 import ExitStack
1717

18-
NAMESPACE_NAMES = frozenset(['mnt','ipc','net','pid','user','uts'])
18+
NAMESPACE_NAMES = frozenset(['mnt', 'ipc', 'net', 'pid', 'user', 'uts'])
1919

2020

2121
class Namespace(object):
@@ -25,6 +25,9 @@ class Namespace(object):
2525
pid: The PID for the owner of the namespace to enter
2626
ns_type: The type of namespace to enter must be one of
2727
mnt ipc net pid user uts
28+
proc: The path to the /proc file system. If running in a container
29+
the host proc file system may be binded mounted in a different
30+
location
2831
2932
Raises:
3033
IOError: A non existent PID was provided
@@ -40,35 +43,36 @@ class Namespace(object):
4043
_log = logging.getLogger(__name__)
4144
_libc = ctypes.CDLL('libc.so.6', use_errno=True)
4245

43-
def __init__(self, pid, ns_type):
46+
def __init__(self, pid, ns_type, proc='/proc'):
4447
if ns_type not in NAMESPACE_NAMES:
4548
raise ValueError('ns_type must be one of {0}'.format(
4649
', '.join(NAMESPACE_NAMES)
4750
))
4851

4952
self.pid = pid
5053
self.ns_type = ns_type
54+
self.proc = proc
5155

5256
self.target_fd = self._nsfd(pid, ns_type).open()
5357
self.target_fileno = self.target_fd.fileno()
5458

5559
self.parent_fd = self._nsfd('self', ns_type).open()
5660
self.parent_fileno = self.parent_fd.fileno()
5761

58-
__init__.__annotations__ = {'pid': str, 'ns_type': str}
62+
__init__.__annotations__ = {'pid': str, 'ns_type': str}
5963

6064
def _nsfd(self, pid, ns_type):
61-
"""Utility method to build a pathlib.Path instance pointing at the
65+
"""Utility method to build a pathlib.Path instance pointing at the
6266
requested namespace entry
6367
6468
Args:
65-
pid: The PID
69+
pid: The PID
6670
ns_type: The namespace type to enter
6771
6872
Returns:
6973
pathlib.Path pointing to the /proc namespace entry
7074
"""
71-
return Path('/proc') / str(pid) / 'ns' / ns_type
75+
return Path(self.proc) / str(pid) / 'ns' / ns_type
7276

7377
_nsfd.__annotations__ = {'process': str, 'ns_type': str, 'return': Path}
7478

@@ -78,50 +82,55 @@ def _close_files(self):
7882
self.target_fd.close()
7983
except:
8084
pass
81-
self.parent_fd.close()
85+
self.parent_fd.close()
8286

8387
def __enter__(self):
8488
self._log.debug('Entering %s namespace %s', self.ns_type, self.pid)
8589

8690
if self._libc.setns(self.target_fileno, 0) == -1:
8791
e = ctypes.get_errno()
8892
self._close_files()
89-
raise OSError(e, errno.errorcode[e])
93+
raise OSError(e, errno.errorcode[e])
9094

9195
def __exit__(self, type, value, tb):
9296
self._log.debug('Leaving %s namespace %s', self.ns_type, self.pid)
93-
97+
9498
if self._libc.setns(self.parent_fileno, 0) == -1:
9599
e = ctypes.get_errno()
96100
self._close_files()
97-
raise OSError(e, errno.errorcode[e])
101+
raise OSError(e, errno.errorcode[e])
98102

99103
self._close_files()
100-
101-
def main(): #pragma: no cover
102-
"""Command line interface to the Namespace Contet Manager"""
104+
105+
106+
def main(): # pragma: no cover
107+
"""Command line interface to the Namespace context manager"""
103108

104109
parser = argparse.ArgumentParser(prog='nsenter', description=__doc__)
105-
110+
106111
parser.add_argument('--target', '-t', required=True, metavar='PID',
107112
help='A target process to get contexts from')
108113

109114
group = parser.add_argument_group('Namespaces')
110115

111116
for ns in NAMESPACE_NAMES:
112-
group.add_argument('--{0}'.format(ns), action='store_true',
113-
help='Enter the {0} namespace'.format(ns))
114-
115-
parser.add_argument('--all', action='store_true',
116-
help='Enter all namespaces')
117+
group.add_argument('--{0}'.format(ns),
118+
action='store_true',
119+
help='Enter the {0} namespace'.format(ns)
120+
)
121+
122+
parser.add_argument('--all',
123+
action='store_true',
124+
help='Enter all namespaces'
125+
)
117126

118127
parser.add_argument('command', nargs='*', default=['/bin/sh'])
119128

120129
args = parser.parse_args()
121130

122-
#make sure we have --all or at least one namespace
131+
# make sure we have --all or at least one namespace
123132
if (True not in [getattr(args, ns) for ns in NAMESPACE_NAMES]
124-
and not args.all):
133+
and not args.all):
125134
parser.error('You must specify at least one namespace')
126135

127136
try:
@@ -130,9 +139,9 @@ def main(): #pragma: no cover
130139
for ns in NAMESPACE_NAMES:
131140
if getattr(args, ns) or args.all:
132141
namespaces.append(Namespace(args.target, ns))
133-
142+
134143
for ns in namespaces:
135-
stack.enter_context(ns)
144+
stack.enter_context(ns)
136145

137146
os.execlp(args.command[0], *args.command)
138147
except IOError as exc:
@@ -143,5 +152,5 @@ def main(): #pragma: no cover
143152
))
144153

145154

146-
if __name__ == '__main__': #pragma: no cover
155+
if __name__ == '__main__': # pragma: no cover
147156
main()

tests.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ def tearDown(self):
1919

2020
def test_namespaces_except_user(self):
2121
"""Test entering all namespaces execept user
22-
23-
Must have CAP_SYS_ADMIN to run these tests properly
2422
"""
2523

2624
#Can't use the assertRaises context manager in python2.6

0 commit comments

Comments
 (0)