-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathstart_ns_online.py
More file actions
189 lines (158 loc) · 5.56 KB
/
start_ns_online.py
File metadata and controls
189 lines (158 loc) · 5.56 KB
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
188
189
'''
SPDX-License-Identifier: Apache-2.0
Copyright 2023 Cisco Systems, Inc. and its affiliates
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
"""
Start (or restart) the Network Sketcher Online web server.
Usage:
python start_ns_online.py
All running ns_web_start.py processes are stopped first (including any
that were started outside of this script), then a fresh server is launched.
Works on Windows, Mac OS, and Linux.
"""
import subprocess
import sys
import os
import platform
import signal
import time
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent
ONLINE_DIR = BASE_DIR / 'network-sketcher_online'
SERVER_SCRIPT = ONLINE_DIR / 'ns_web_start.py'
PID_FILE = ONLINE_DIR / 'ns_online.pid'
def _find_all_ns_server_pids():
"""Return a list of PIDs for all running ns_web_start.py processes.
Searches the OS process list directly so that processes started outside
of this script (e.g. from a terminal or IDE) are also found.
"""
own_pid = os.getpid()
pids = []
try:
if platform.system() == 'Windows':
result = subprocess.run(
['wmic', 'process', 'where',
'(CommandLine like "%ns_web_start.py%") AND (Name like "%python%")',
'get', 'ProcessId', '/VALUE'],
capture_output=True, text=True,
)
for line in result.stdout.splitlines():
line = line.strip()
if line.startswith('ProcessId='):
try:
pid = int(line.split('=', 1)[1])
if pid and pid != own_pid:
pids.append(pid)
except ValueError:
pass
else:
result = subprocess.run(
['pgrep', '-f', 'ns_web_start.py'],
capture_output=True, text=True,
)
for line in result.stdout.splitlines():
try:
pid = int(line.strip())
if pid != own_pid:
pids.append(pid)
except ValueError:
pass
except Exception:
pass
# Also include any PID recorded in the PID file that was missed above
if PID_FILE.exists():
try:
pid = int(PID_FILE.read_text().strip())
if pid and pid != own_pid and pid not in pids:
pids.append(pid)
except (ValueError, OSError):
pass
return pids
def _is_process_running(pid):
"""Check if a process with the given PID is still running."""
try:
if platform.system() == 'Windows':
result = subprocess.run(
['tasklist', '/FI', f'PID eq {pid}', '/NH'],
capture_output=True, text=True,
)
return str(pid) in result.stdout
else:
os.kill(pid, 0)
return True
except (OSError, ProcessLookupError):
return False
def _stop_all():
"""Stop all running ns_web_start.py processes. Returns True if any were stopped."""
pids = _find_all_ns_server_pids()
if not pids:
return False
print(f' Found {len(pids)} running server process(es): {pids}')
for pid in pids:
print(f' Stopping PID {pid}...')
try:
if platform.system() == 'Windows':
subprocess.run(
['taskkill', '/F', '/T', '/PID', str(pid)],
capture_output=True,
)
else:
os.kill(pid, signal.SIGTERM)
except (OSError, ProcessLookupError):
pass
# Wait up to 5 seconds for all processes to exit
deadline = time.time() + 5.0
while time.time() < deadline:
time.sleep(0.3)
if not any(_is_process_running(pid) for pid in pids):
break
PID_FILE.unlink(missing_ok=True)
print(' All server processes stopped.')
return True
def main():
if not SERVER_SCRIPT.exists():
print(f'Error: {SERVER_SCRIPT} not found.')
sys.exit(1)
print('=' * 56)
print(' Network Sketcher Online — Start')
print('=' * 56)
_stop_all()
log_dir = ONLINE_DIR / 'logs'
log_dir.mkdir(exist_ok=True)
server_log = log_dir / 'server.log'
kwargs = {}
log_file = open(str(server_log), 'a', encoding='utf-8')
if platform.system() == 'Windows':
kwargs['creationflags'] = (
subprocess.DETACHED_PROCESS
| subprocess.CREATE_NEW_PROCESS_GROUP
| subprocess.CREATE_NO_WINDOW
)
kwargs['stdin'] = subprocess.DEVNULL
kwargs['stdout'] = log_file
kwargs['stderr'] = log_file
else:
kwargs['start_new_session'] = True
kwargs['stdin'] = subprocess.DEVNULL
kwargs['stdout'] = log_file
kwargs['stderr'] = log_file
proc = subprocess.Popen(
[sys.executable, str(SERVER_SCRIPT)],
cwd=str(ONLINE_DIR),
**kwargs,
)
PID_FILE.write_text(str(proc.pid))
print(f' Server started (PID: {proc.pid})')
print(f' PID file: {PID_FILE}')
print('=' * 56)
if __name__ == '__main__':
main()