forked from mapsme/omim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSiblingKiller.py
187 lines (129 loc) · 5.94 KB
/
SiblingKiller.py
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
from __future__ import print_function
import logging
import os
import re
import urllib2
import socket
from subprocess import Popen, PIPE
from time import sleep
import sys
import logging
class SiblingKiller:
def __init__(self, port, ping_timeout):
self.all_processes = self.ps_dash_w()
self.all_pids = self.all_process_ids()
self.__allow_serving = False
self.__my_pid = self.my_process_id()
self.port = port
self.ping_timeout = ping_timeout
logging.debug("Sibling killer: my process id = {}".format(self.__my_pid))
def allow_serving(self):
return self.__allow_serving
def give_process_time_to_kill_port_user(self):
sleep(5)
def kill_siblings(self):
"""
The idea is to get the list of all processes by the current user, check which one of them is using the port.
If there is such a process, let's wait for 10 seconds for it to start serving, if it doesn't, kill it.
If there is NO such process, let's see if there is a process with the same name as us but with a lower process id.
We shall wait for 10 seconds for it to start, if it doesn't, kill it.
If we are the process with the same name as ours and with the lowest process id, let's start serving and kill everyone else.
"""
if self.wait_for_server():
self.__allow_serving = False
logging.debug("There is a server that is currently serving on our port... Disallowing to start a new one")
return
logging.debug("There are no servers that are currently serving. Will try to kill our siblings.")
sibs = self.siblings()
for sibling in sibs:
logging.debug("Checking whether we should kill sibling id: {}".format(sibling))
self.give_process_time_to_kill_port_user()
if self.wait_for_server():
serving_pid = self.serving_process_id()
if serving_pid:
logging.debug("There is a serving sibling with process id: {}".format(serving_pid))
self.kill(pids=map(lambda x: x != serving_pid, sibs))
self.__allow_serving = False
return
else:
self.kill(pid=sibling)
self.kill_process_on_port() # changes __allow_serving to True if the process was alive and serving
def kill(self, pid=0, pids=list()):
if not pid and not pids:
logging.debug("There are no siblings to kill")
return
if pid and pids:
raise Exception("Use either one pid or multiple pids")
hitlist = ""
if pid:
hitlist = str(pid)
if pids:
hitlist = " ".join(map(str, pids))
command = "kill -9 {hitlist}".format(hitlist=hitlist)
self.exec_command(command)
def siblings(self):
my_name = self.my_process_name()
return filter(lambda x: x < self.__my_pid,
map(lambda x: int(x.split(" ")[1]),
filter(lambda x: my_name in x, self.all_processes)))
def kill_process_on_port(self):
process_on_port = self.process_using_port(self.port)
if not self.wait_for_server():
self.kill(pid=process_on_port)
self.__allow_serving = True
def all_process_ids(self):
pid = lambda x: int(x.split(" ")[1])
return map(pid, self.all_processes)
def process_using_port(self, port):
lsof = lambda x : (self.exec_command("lsof -a -p{process} -i4".format(process=str(x))), x) #ignore the return code
listenning_on_port = lambda (info_line, id) : info_line and info_line.endswith("(LISTEN)") and str(port) in info_line
ids = lambda (info_line, id) : id
listening_process = map(ids, filter(listenning_on_port, map(lsof, self.all_pids)))
if len(listening_process) > 1:
pass
# We should panic here
if not listening_process:
return None
return listening_process[0]
def my_process_id(self):
return os.getpid()
def my_process_name(self):
return " ".join(sys.argv)
def ps_dash_w(self):
not_header = lambda x: x and not x.startswith("UID")
return filter(not_header, self.gen_to_list(re.sub("\s{1,}", " ", x.strip()) for x in self.exec_command("ps -f").split("\n")))
def wait_for_server(self):
for i in range(0, 2):
if self.ping(): # unsuccessful ping takes 5 seconds (look at PING_TIMEOUT) iff there is a dead server occupying the port
return True
return False
def ping(self):
html = str()
try:
response = urllib2.urlopen('http://localhost:{port}/ping'.format(port=self.port), timeout=self.ping_timeout);
html = response.read()
except (urllib2.URLError, socket.timeout):
pass
logging.debug("Pinging returned html: {}".format(html))
return html == "pong"
def serving_process_id(self):
resp = str()
try:
response = urllib2.urlopen('http://localhost:{port}/id'.format(port=self.port), timeout=self.ping_timeout);
resp = response.read()
id = int(resp)
return id
except:
logging.info("Couldn't get id of a serving process (the PID of the server that responded to pinging)")
return None
def gen_to_list(self, generator):
l = list()
for i in generator:
l.append(i)
return l
def exec_command(self, command):
logging.debug(">> {}".format(command))
p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)
output, err = p.communicate()
p.wait()
return output