1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
#!/usr/bin/env python3
import socket
import os
import struct
import time
sockr_path = '/etc/lxc/rebinds/devlog/log'
def get_namespace_from_proc(pid):
'''Get lxc cgroup namespace name associated with pid, or None'''
try:
with open('/proc/%s/cgroup' % pid, 'rb') as fin:
data = fin.read()
data = data.splitlines()[0]
truncation_index = data.index(b'/lxc/')
return data[truncation_index+len(b'/lxc/'):]
except (FileNotFoundError, ProcessLookupError, ValueError): pass
def get_namespace(pid, namespace_cache=dict(), timeout_time=30):
'''
Get cached namespace name (works only with /lxc/* cgroup names). If
request is made on a name which is cached, the timeout of the name is
reset. If the name is not found or the timeout is over, the name is
got from proc and cached.
There is a catch though: if there is pid overflow on the host system
(pid restart from count 1) there might be a chance the pid is no
longer on the same cached namespace name. But the chance are very
unlikely and the consequences are ok for my usage. If this is
important for you, you can set timeout_time to 0 (or rewrite this
part). Thus, each time a line is received from /dev/log in
a container, an open call is done to get the name which is bad for
performances.
'''
tcur = time.time()
name, timeout = namespace_cache.get(pid, (None, None))
if name and timeout >= tcur:
namespace_cache[pid][1] = tcur + timeout_time
#print('debug: got cached name')
return name
else:
name = get_namespace_from_proc(pid)
timeout = tcur + timeout_time
namespace_cache[pid] = [name, timeout]
#print('debug: name cache miss')
return name
def main():
sockr = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sockr.setsockopt(socket.SOL_SOCKET, socket.SO_PASSCRED, 1)
os.unlink(sockr_path)
sockr.bind(sockr_path)
os.chmod(sockr_path, mode=0o666)
socks = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
while True:
data = sockr.recvmsg(8192, 256)
pid = 0
for cmsg in data[1]:
if cmsg[0] == socket.SOL_SOCKET and cmsg[1] == socket.SCM_CREDENTIALS:
pid = struct.unpack('i', cmsg[2][0:4])[0]
data_mangled = data[0]
name = pid and get_namespace(pid)
if name:
first_space_index = data[0].find(b' ')
marker_end_index = data[0].find(b': ', first_space_index + 16)
insert_index = data[0].rfind(b' ', 0, marker_end_index) + 1
data_mangled = data[0][0:insert_index] + name + b'/' + data[0][insert_index:]
#print('debug:', data_mangled)
socks.sendto(data_mangled, '/dev/log')
if __name__ == '__main__':
main()
|