Revision f93f2016
b/daemons/ganeti-masterd | ||
---|---|---|
108 | 108 |
"""Add task to workerpool to process request. |
109 | 109 |
|
110 | 110 |
""" |
111 |
(pid, uid, gid) = utils.GetSocketCredentials(request) |
|
112 |
logging.info("Accepted connection from pid=%s, uid=%s, gid=%s", |
|
113 |
pid, uid, gid) |
|
114 |
|
|
111 | 115 |
self.request_workers.AddTask(self, request, client_address) |
112 | 116 |
|
117 |
def handle_error(self, request, client_address): |
|
118 |
logging.exception("Error while handling request") |
|
119 |
|
|
113 | 120 |
@utils.SignalHandled([signal.SIGINT, signal.SIGTERM]) |
114 | 121 |
def serve_forever(self, signal_handlers=None): # pylint: disable-msg=W0221 |
115 | 122 |
"""Handle one request at a time until told to quit.""" |
b/lib/utils.py | ||
---|---|---|
46 | 46 |
import datetime |
47 | 47 |
import calendar |
48 | 48 |
import collections |
49 |
import struct |
|
50 |
import IN |
|
49 | 51 |
|
50 | 52 |
from cStringIO import StringIO |
51 | 53 |
|
... | ... | |
69 | 71 |
|
70 | 72 |
_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid" |
71 | 73 |
|
74 |
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...): |
|
75 |
# struct ucred { pid_t pid; uid_t uid; gid_t gid; }; |
|
76 |
# |
|
77 |
# The GNU C Library defines gid_t and uid_t to be "unsigned int" and |
|
78 |
# pid_t to "int". |
|
79 |
# |
|
80 |
# IEEE Std 1003.1-2008: |
|
81 |
# "nlink_t, uid_t, gid_t, and id_t shall be integer types" |
|
82 |
# "blksize_t, pid_t, and ssize_t shall be signed integer types" |
|
83 |
_STRUCT_UCRED = "iII" |
|
84 |
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED) |
|
85 |
|
|
72 | 86 |
|
73 | 87 |
class RunResult(object): |
74 | 88 |
"""Holds the result of running external programs. |
... | ... | |
328 | 342 |
return rr |
329 | 343 |
|
330 | 344 |
|
345 |
def GetSocketCredentials(sock): |
|
346 |
"""Returns the credentials of the foreign process connected to a socket. |
|
347 |
|
|
348 |
@param sock: Unix socket |
|
349 |
@rtype: tuple; (number, number, number) |
|
350 |
@return: The PID, UID and GID of the connected foreign process. |
|
351 |
|
|
352 |
""" |
|
353 |
peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED, |
|
354 |
_STRUCT_UCRED_SIZE) |
|
355 |
return struct.unpack(_STRUCT_UCRED, peercred) |
|
356 |
|
|
357 |
|
|
331 | 358 |
def RemoveFile(filename): |
332 | 359 |
"""Remove a file ignoring some errors. |
333 | 360 |
|
b/test/ganeti.utils_unittest.py | ||
---|---|---|
44 | 44 |
from ganeti import constants |
45 | 45 |
from ganeti import utils |
46 | 46 |
from ganeti import errors |
47 |
from ganeti import serializer |
|
47 | 48 |
from ganeti.utils import IsProcessAlive, RunCmd, \ |
48 | 49 |
RemoveFile, MatchNameComponent, FormatUnit, \ |
49 | 50 |
ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \ |
... | ... | |
910 | 911 |
self.failIf(OwnIpAddress(DST_IP), "Should not own IP address %s" % DST_IP) |
911 | 912 |
|
912 | 913 |
|
914 |
def _GetSocketCredentials(path): |
|
915 |
"""Connect to a Unix socket and return remote credentials. |
|
916 |
|
|
917 |
""" |
|
918 |
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
|
919 |
try: |
|
920 |
sock.settimeout(10) |
|
921 |
sock.connect(path) |
|
922 |
return utils.GetSocketCredentials(sock) |
|
923 |
finally: |
|
924 |
sock.close() |
|
925 |
|
|
926 |
|
|
927 |
class TestGetSocketCredentials(unittest.TestCase): |
|
928 |
def setUp(self): |
|
929 |
self.tmpdir = tempfile.mkdtemp() |
|
930 |
self.sockpath = utils.PathJoin(self.tmpdir, "sock") |
|
931 |
|
|
932 |
self.listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
|
933 |
self.listener.settimeout(10) |
|
934 |
self.listener.bind(self.sockpath) |
|
935 |
self.listener.listen(1) |
|
936 |
|
|
937 |
def tearDown(self): |
|
938 |
self.listener.shutdown(socket.SHUT_RDWR) |
|
939 |
self.listener.close() |
|
940 |
shutil.rmtree(self.tmpdir) |
|
941 |
|
|
942 |
def test(self): |
|
943 |
(c2pr, c2pw) = os.pipe() |
|
944 |
|
|
945 |
# Start child process |
|
946 |
child = os.fork() |
|
947 |
if child == 0: |
|
948 |
try: |
|
949 |
data = serializer.DumpJson(_GetSocketCredentials(self.sockpath)) |
|
950 |
|
|
951 |
os.write(c2pw, data) |
|
952 |
os.close(c2pw) |
|
953 |
|
|
954 |
os._exit(0) |
|
955 |
finally: |
|
956 |
os._exit(1) |
|
957 |
|
|
958 |
os.close(c2pw) |
|
959 |
|
|
960 |
# Wait for one connection |
|
961 |
(conn, _) = self.listener.accept() |
|
962 |
conn.recv(1) |
|
963 |
conn.close() |
|
964 |
|
|
965 |
# Wait for result |
|
966 |
result = os.read(c2pr, 4096) |
|
967 |
os.close(c2pr) |
|
968 |
|
|
969 |
# Check child's exit code |
|
970 |
(_, status) = os.waitpid(child, 0) |
|
971 |
self.assertFalse(os.WIFSIGNALED(status)) |
|
972 |
self.assertEqual(os.WEXITSTATUS(status), 0) |
|
973 |
|
|
974 |
# Check result |
|
975 |
(pid, uid, gid) = serializer.LoadJson(result) |
|
976 |
self.assertEqual(pid, os.getpid()) |
|
977 |
self.assertEqual(uid, os.getuid()) |
|
978 |
self.assertEqual(gid, os.getgid()) |
|
979 |
|
|
980 |
|
|
913 | 981 |
class TestListVisibleFiles(unittest.TestCase): |
914 | 982 |
"""Test case for ListVisibleFiles""" |
915 | 983 |
|
Also available in: Unified diff