Commit fcfc62001ca075034b035ec620f14809ded9c69f
1 parent
1a15d30a
Exists in
dev
ajout nouvelle commande "pyros.py dbshell" (+ update doc)
Showing
7 changed files
with
98 additions
and
1031 deletions
Show diff stats
.gitignore
README.md
... | ... | @@ -67,15 +67,14 @@ This software has been tested and validated with the following configurations : |
67 | 67 | -------------------------------------------------------------------------------------------- |
68 | 68 | ## LAST VERSION |
69 | 69 | |
70 | -Date: 28/02/2019 | |
70 | +Date: 04/03/2019 | |
71 | 71 | |
72 | 72 | Author: E. Pallier |
73 | 73 | |
74 | -VERSION: 0.20.3 | |
74 | +VERSION: 0.20.4 | |
75 | 75 | |
76 | 76 | Comment: |
77 | - Agent.py improvements : | |
78 | - - read_db_commands() : ajout algo | |
77 | + pyros.py : ajout nouvelle commande "dbshell" | |
79 | 78 | |
80 | 79 | |
81 | 80 | -------------------------------------------------------------------------------------------- | ... | ... |
pyros.py
... | ... | @@ -234,6 +234,21 @@ def shell(): |
234 | 234 | return True |
235 | 235 | |
236 | 236 | |
237 | +@pyros_launcher.command(help="Run a database (Mysql) shell") | |
238 | +def dbshell(): | |
239 | + print() | |
240 | + print("Launching a database (mysql) shell") | |
241 | + print("From this shell, type 'use database pyros;' to select the pyros database") | |
242 | + print("Then type 'show tables;' to see all the pyros tables") | |
243 | + print("Then for example, type 'select * from config;' to see the content of the 'config' table") | |
244 | + print("Type 'exit' to quit") | |
245 | + print() | |
246 | + # execProcess("python install.py install") | |
247 | + if not test_mode(): execProcessFromVenv("src/manage.py dbshell") | |
248 | + # Go back to the initial dir | |
249 | + return True | |
250 | + | |
251 | + | |
237 | 252 | @pyros_launcher.command(help="Install the pyros software") |
238 | 253 | #@global_test_options |
239 | 254 | def install(): | ... | ... |
pyros_old.py deleted
... | ... | @@ -1,994 +0,0 @@ |
1 | -#!/usr/bin/env python3 | |
2 | - | |
3 | -import sys | |
4 | -import os | |
5 | -import subprocess | |
6 | -import platform | |
7 | -import fileinput | |
8 | -import argparse | |
9 | -import time | |
10 | -import signal | |
11 | - | |
12 | - | |
13 | -DEBUG = True | |
14 | -SIMULATOR_CONFIG_FILE = "conf.json" #default config file | |
15 | - | |
16 | -''' | |
17 | - Pyros Manager, able to launch processes and handle all project commands | |
18 | -''' | |
19 | - | |
20 | - | |
21 | -class Utils: | |
22 | - system = platform.system() | |
23 | - columns = 100 | |
24 | - row = 1000 | |
25 | - disp = True | |
26 | - | |
27 | - def __init__(self): | |
28 | - if (platform.system() != 'Windows'): | |
29 | - try: | |
30 | - rows, columns = os.popen('stty size', 'r').read().split() | |
31 | - self.columns = int(columns) | |
32 | - except: | |
33 | - self.columns = 100 | |
34 | - if DEBUG: | |
35 | - print("Could not get terminal size") | |
36 | - | |
37 | - def printFullTerm(self, color, string): | |
38 | - value = int(self.columns / 2 - len(string) / 2) | |
39 | - self.printColor(color, "-" * value, eol='') | |
40 | - self.printColor(color, string, eol='') | |
41 | - value += len(string) | |
42 | - self.printColor(color, "-" * (self.columns - value)) | |
43 | - return 0 | |
44 | - | |
45 | - def changeDirectory(self, path): | |
46 | - if DEBUG: | |
47 | - print("Moving to : " + path) | |
48 | - os.chdir(path) | |
49 | - if DEBUG: | |
50 | - print("Current directory : " + str(os.getcwd())) | |
51 | - return 0 | |
52 | - | |
53 | - def replacePatternInFile(self, pattern, replacement, file_path): | |
54 | - #try: | |
55 | - with fileinput.FileInput(file_path, inplace=True, backup='.bak') as file: | |
56 | - for line in file: | |
57 | - print(line.replace(pattern, replacement), end='') | |
58 | - ''' | |
59 | - except: | |
60 | - return 1 | |
61 | - return 0 | |
62 | - ''' | |
63 | - # Now, check that replacement has been done or else ERROR !!! | |
64 | - FOUND=False | |
65 | - #with fileinput.FileInput(file_path) as file: | |
66 | - with open(file_path) as file: | |
67 | - for line in file: | |
68 | - #if replacement in line: | |
69 | - if line.startswith(replacement): | |
70 | - FOUND = True | |
71 | - break | |
72 | - #if FOUND: print("pattern "+pattern+" found in file "+file_path) | |
73 | - if not FOUND: raise(Exception("pattern "+replacement+" not found in file "+file_path)) | |
74 | - | |
75 | - | |
76 | - def printColor(self, color, message, file=sys.stdout, eol=os.linesep, forced=False): | |
77 | - if (self.disp == False and forced == False): | |
78 | - return 0 | |
79 | - if (self.system == 'Windows'): | |
80 | - print(message, file=file, end=eol) | |
81 | - else: | |
82 | - print(color + message + Colors.ENDC, file=file, end=eol) | |
83 | - return 0 | |
84 | - | |
85 | - def askQuestion(self, message, default = ""): | |
86 | - self.printColor(Colors.BLUE, message, forced=True) | |
87 | - self.printColor(Colors.BOLD, "Answer (default="+default+"): ", eol='', forced=True) | |
88 | - sys.stdout.flush() | |
89 | - ret = sys.stdin.readline().replace('\n', '').replace('\r', '') | |
90 | - if ret == "": | |
91 | - return default | |
92 | - return ret | |
93 | - | |
94 | - def sleep(self, t): | |
95 | - time.sleep(t) | |
96 | - return 0 | |
97 | - | |
98 | -''' | |
99 | - Manager class : manager of your project | |
100 | -''' | |
101 | - | |
102 | - | |
103 | -class AManager(Utils): | |
104 | - path = os.path.realpath(__file__) | |
105 | - path_dir = os.getcwd() | |
106 | - path_dir_file = os.path.dirname(os.path.realpath(__file__)) | |
107 | - python_path = sys.executable | |
108 | - python_version = sys.version_info | |
109 | - | |
110 | - bin_dir = "" | |
111 | - venv_pip = "pip" | |
112 | - venv_bin = "python" | |
113 | - wait = True | |
114 | - current_command = "" | |
115 | - config = None | |
116 | - commandMatcher = {} | |
117 | - commandDescription = {} | |
118 | - commands = [] | |
119 | - errors = {} | |
120 | - executed = {} | |
121 | - subproc = [] | |
122 | - | |
123 | - def __init__(self, param): | |
124 | - super(AManager, self).__init__() | |
125 | - self.wait = param.getWait() | |
126 | - self.commands = param.getCommandList() | |
127 | - self.disp = param.getPrint() | |
128 | - config = param.getConfig() | |
129 | - self.config = config | |
130 | - signal.signal(signal.SIGINT, self.signal_handler) | |
131 | - | |
132 | - self.changeDirectory(self.path_dir_file) | |
133 | - | |
134 | - if self.system == 'Windows': | |
135 | - self.bin_dir = "Scripts" | |
136 | - self.bin_name = "python.exe" | |
137 | - self.pip_name = "pip.exe" | |
138 | - else: | |
139 | - self.bin_dir = "bin" | |
140 | - self.bin_name = "python" | |
141 | - self.pip_name = "pip" | |
142 | - self.venv_pip = self.path_dir_file + os.sep + config["path"] + os.sep + config["env"] + os.sep + self.bin_dir + os.sep + self.pip_name | |
143 | - self.venv_bin = self.path_dir_file + os.sep + config["path"] + os.sep + config["env"] + os.sep + self.bin_dir + os.sep + self.bin_name | |
144 | - | |
145 | - def help(self): | |
146 | - print("This function must be implemented") | |
147 | - raise(NotImplementedError("Function not implemented")) | |
148 | - | |
149 | - | |
150 | - def set_simulator_mode_to(self, set_it:bool): | |
151 | - file_path = "pyros/settings.py" | |
152 | - ''' | |
153 | - if simulator: self.replacePatternInFile("SIMULATOR = False", "SIMULATOR = True", file_path) | |
154 | - ''' | |
155 | - self.replacePatternInFile("SIMULATOR = "+str(not set_it), "SIMULATOR = "+str(set_it), file_path) | |
156 | - | |
157 | - | |
158 | - def signal_handler(self, signal, frame): | |
159 | - self.printFullTerm(Colors.WARNING, "Ctrl-c catched") | |
160 | - self.set_simulator_mode_to(False) | |
161 | - for p in self.subproc: | |
162 | - proc, name = p | |
163 | - self.printColor(Colors.BLUE, "Killing process " + str(name)) | |
164 | - proc.kill() | |
165 | - self.printFullTerm(Colors.WARNING, "Exiting") | |
166 | - sys.exit(0) | |
167 | - | |
168 | - def addExecuted(self, src, message): | |
169 | - if (src in self.executed): | |
170 | - self.executed[src].append(str(message)) | |
171 | - else: | |
172 | - self.executed[src] = [str(message)] | |
173 | - return 0 | |
174 | - | |
175 | - def addError(self, src, message): | |
176 | - if (src in self.errors): | |
177 | - self.errors[src].append(str(message)) | |
178 | - else: | |
179 | - self.errors[src] = [str(message)] | |
180 | - return 0 | |
181 | - | |
182 | - def execProcess(self, command): | |
183 | - self.printFullTerm(Colors.BLUE, "Executing command [" + command + "]") | |
184 | - process = subprocess.Popen(command, shell=True) | |
185 | - process.wait() | |
186 | - if process.returncode == 0: | |
187 | - self.printFullTerm(Colors.GREEN, "Process executed successfully") | |
188 | - self.addExecuted(self.current_command, command) | |
189 | - else: | |
190 | - self.printFullTerm(Colors.WARNING, "Process execution failed") | |
191 | - self.addError(self.current_command, command) | |
192 | - return process.returncode | |
193 | - | |
194 | - def execProcessSilent(self, command): | |
195 | - process = subprocess.Popen(command, shell=True) | |
196 | - process.wait() | |
197 | - return process.returncode | |
198 | - | |
199 | - def execProcessFromVenv(self, command): | |
200 | - args = command.split() | |
201 | - self.printFullTerm(Colors.BLUE, "Executing command from venv [" + str(' '.join(args[1:])) + "]") | |
202 | - process = subprocess.Popen(args) | |
203 | - process.wait() | |
204 | - if process.returncode == 0: | |
205 | - self.printFullTerm(Colors.GREEN, "Process executed successfully") | |
206 | - self.addExecuted(self.current_command, str(' '.join(args[1:]))) | |
207 | - else: | |
208 | - self.printFullTerm(Colors.WARNING, "Process execution failed") | |
209 | - self.addError(self.current_command, str(' '.join(args[1:]))) | |
210 | - return process.returncode | |
211 | - | |
212 | - def execProcessAsync(self, command): | |
213 | - self.printFullTerm(Colors.BLUE, "Executing command [" + command + "]") | |
214 | - p = subprocess.Popen(command, shell=True) | |
215 | - self.subproc.append((p, command)) | |
216 | - self.printFullTerm(Colors.GREEN, "Process launched successfully") | |
217 | - self.addExecuted(self.current_command, command) | |
218 | - return p | |
219 | - | |
220 | - def execProcessFromVenvAsync(self, command: str): | |
221 | - args = command.split() | |
222 | - self.printFullTerm(Colors.BLUE, "Executing command from venv [" + str(' '.join(args[1:])) + "]") | |
223 | - p = subprocess.Popen(args) | |
224 | - self.subproc.append((p, ' '.join(args[1:]))) | |
225 | - self.printFullTerm(Colors.GREEN, "Process launched successfully") | |
226 | - self.addExecuted(self.current_command, str(' '.join(args[1:]))) | |
227 | - return p | |
228 | - | |
229 | - def waitProcesses(self): | |
230 | - if (self.wait): | |
231 | - for p in self.subproc: | |
232 | - proc, name = p | |
233 | - proc.wait() | |
234 | - return 0 | |
235 | - | |
236 | - def end(self): | |
237 | - count = 0 | |
238 | - self.waitProcesses() | |
239 | - self.printFullTerm(Colors.WARNING, "Summary") | |
240 | - self.printColor(Colors.GREEN, "Success : ") | |
241 | - for command, valid in self.executed.items(): | |
242 | - if not valid: | |
243 | - self.printColor(Colors.BLUE, "\t- Command : " + command + " success !") | |
244 | - else: | |
245 | - self.printColor(Colors.WARNING, "\t- In commmand : " + command) | |
246 | - for exe in valid: | |
247 | - self.printColor(Colors.GREEN, "\t\t - Command : " + exe + " success !") | |
248 | - self.printColor(Colors.FAIL, "Errors : ") | |
249 | - if not self.errors: | |
250 | - self.printColor(Colors.GREEN, "\tNone") | |
251 | - for command, items in self.errors.items(): | |
252 | - count += 1 | |
253 | - if (not items): | |
254 | - self.printColor(Colors.FAIL, "Command : " + command + " failed !") | |
255 | - else: | |
256 | - self.printColor(Colors.WARNING, "\t- In commmand : " + command) | |
257 | - for exe in items: | |
258 | - self.printColor(Colors.FAIL, "\t\t - Command : " + exe) | |
259 | - return count | |
260 | - | |
261 | - def exec(self): | |
262 | - if (not self.commands): | |
263 | - self.commandMatcher["help"]() | |
264 | - return 0 | |
265 | - for command in self.commands: | |
266 | - self.current_command = command | |
267 | - if command in self.commandMatcher: | |
268 | - self.commandMatcher[command]() | |
269 | - else: | |
270 | - self.addError(str(command), "invalid command") | |
271 | - return self.end() | |
272 | - | |
273 | - def logError(self, message): | |
274 | - self.printColor(Colors.FAIL, "Pyros : An error occurred [" + message + "]", file=sys.stderr) | |
275 | - return 0 | |
276 | - | |
277 | -''' | |
278 | - Config file representation (able to parse and give informations) | |
279 | -''' | |
280 | - | |
281 | - | |
282 | -class Config: | |
283 | - __parser = argparse.ArgumentParser("Project Pyros") | |
284 | - __content = { | |
285 | - "path": "private", | |
286 | - "env": "venv_py3_pyros" | |
287 | - } | |
288 | - __wait = True | |
289 | - __print = True | |
290 | - usage = "" | |
291 | - __command_list = [] | |
292 | - | |
293 | - def __init__(self): | |
294 | - self.__parser.add_argument("command", nargs='*', default="help", help="The command you want to execute (default=help)") | |
295 | - self.__parser.add_argument("--env", help="Your environment directory name default=venv") | |
296 | - self.__parser.add_argument("--path", help="Path to the virtual env (from the source file directory) (default=private)") | |
297 | - self.__parser.add_argument("--nowait", action='store_true', help="Don't wait the end of a program") | |
298 | - self.__parser.add_argument("--noprint", action='store_true', help="Won't print") | |
299 | - self.usage = self.__parser.format_usage() | |
300 | - | |
301 | - def parse(self): | |
302 | - try: | |
303 | - res = self.__parser.parse_args(), self.__parser.format_usage() | |
304 | - return (res) | |
305 | - except SystemExit as e: | |
306 | - # print(e, file=sys.stderr) | |
307 | - sys.exit(1) | |
308 | - | |
309 | - def parseConf(self): | |
310 | - res, usage = self.parse() | |
311 | - try: | |
312 | - if (res.env): | |
313 | - self.__content["env"] = res.env | |
314 | - if (res.path): | |
315 | - self.__content["path"] = res.path | |
316 | - if (res.nowait): | |
317 | - self.__wait = False | |
318 | - if (res.noprint): | |
319 | - self.__print = False | |
320 | - self.__command_list.append(res.command[0]) | |
321 | - #return | |
322 | - return True | |
323 | - except Exception as e: | |
324 | - print(e, file=sys.stderr) | |
325 | - #return 1 | |
326 | - return False | |
327 | - | |
328 | - def getPath(self): | |
329 | - return self.__content["path"] | |
330 | - | |
331 | - def getEnv(self): | |
332 | - return self.__content["env"] | |
333 | - | |
334 | - def getWait(self): | |
335 | - return self.__wait | |
336 | - | |
337 | - def getPrint(self): | |
338 | - return self.__print | |
339 | - | |
340 | - def setPrint(self, value): | |
341 | - self.__print = value | |
342 | - return 0 | |
343 | - | |
344 | - def setWait(self, value): | |
345 | - self.__wait = value | |
346 | - return 0 | |
347 | - | |
348 | - def getCommandList(self): | |
349 | - return self.__command_list | |
350 | - | |
351 | - def printUsage(self): | |
352 | - print(self.usage, file=sys.stderr) | |
353 | - | |
354 | - def addConf(self, key, value): | |
355 | - if isinstance(key, str) and isinstance(value, str): | |
356 | - self.__content[key] = value | |
357 | - return 0 | |
358 | - return 1 | |
359 | - | |
360 | - def setPath(self, path): | |
361 | - if (os.path.isdir(path)): | |
362 | - if (path == ""): | |
363 | - path = "." | |
364 | - self.__content["path"] = path | |
365 | - return 0 | |
366 | - return 1 | |
367 | - | |
368 | - def setEnvName(self, name): | |
369 | - self.__content["env"] = name | |
370 | - return 0 | |
371 | - | |
372 | - def getConfig(self): | |
373 | - return self.__content | |
374 | - | |
375 | - | |
376 | -''' | |
377 | - Color class | |
378 | -''' | |
379 | - | |
380 | - | |
381 | -class Colors: | |
382 | - HEADER = '\033[95m' | |
383 | - BLUE = '\033[94m' | |
384 | - GREEN = '\033[92m' | |
385 | - WARNING = '\033[93m' | |
386 | - FAIL = '\033[91m' | |
387 | - ENDC = '\033[0m' | |
388 | - BOLD = '\033[1m' | |
389 | - UNDERLINE = '\033[4m' | |
390 | - | |
391 | - | |
392 | -''' | |
393 | - Pyros class | |
394 | -''' | |
395 | - | |
396 | - | |
397 | -class Pyros(AManager): | |
398 | - help_message = "python neo.py" | |
399 | - init_fixture = "initial_fixture.json" | |
400 | - | |
401 | - def signal_handler(self, signal, frame): | |
402 | - self.printFullTerm(Colors.WARNING, "Ctrl-c catched") | |
403 | - for p in self.subproc: | |
404 | - proc, name = p | |
405 | - self.printColor(Colors.BLUE, "Killing process " + str(name)) | |
406 | - proc.kill() | |
407 | - if self.current_command == "simulator" or self.current_command == "simulator_development": | |
408 | - self.changeDirectory(self.path_dir_file) | |
409 | - self.kill_simulation() | |
410 | - self.printFullTerm(Colors.WARNING, "Exiting") | |
411 | - sys.exit(0) | |
412 | - | |
413 | - def install(self): | |
414 | - if (self.system == "Windows"): | |
415 | - self.execProcess("python install/install.py install") | |
416 | - else: | |
417 | - self.execProcess("python3 install/install.py install") | |
418 | - return 0 | |
419 | - | |
420 | - def update(self): | |
421 | - if (self.system == "Windows"): | |
422 | - self.execProcess("python install/install.py update") | |
423 | - else: | |
424 | - self.execProcess("python3 install/install.py update") | |
425 | - return 0 | |
426 | - | |
427 | - def server(self): | |
428 | - self.changeDirectory("src") | |
429 | - self.execProcessFromVenvAsync(self.venv_bin + " manage.py runserver") | |
430 | - self.changeDirectory("..") | |
431 | - return 0 | |
432 | - | |
433 | - def clean(self): | |
434 | - return self.clean_logs() | |
435 | - | |
436 | - def clean_logs(self): | |
437 | - return self.execProcess("rm logs/*.log") | |
438 | - | |
439 | - def test(self): | |
440 | - self.changeDirectory("src") | |
441 | - ##self.execProcessFromVenv(self.venv_bin + " manage.py test") | |
442 | - self.execProcessFromVenvAsync(self.venv_bin + " manage.py test") | |
443 | - self.changeDirectory("..") | |
444 | - return 0 | |
445 | - | |
446 | - def migrate(self): | |
447 | - self.changeDirectory("src") | |
448 | - self.execProcessFromVenv(self.venv_bin + " manage.py migrate") | |
449 | - self.changeDirectory("..") | |
450 | - return 0 | |
451 | - | |
452 | - def makemigrations(self): | |
453 | - self.changeDirectory("src") | |
454 | - self.execProcessFromVenv(self.venv_bin + " manage.py makemigrations") | |
455 | - self.changeDirectory("..") | |
456 | - return 0 | |
457 | - | |
458 | - def help(self): | |
459 | - count = 0 | |
460 | - self.printFullTerm(Colors.WARNING, "Help Message") | |
461 | - for command, message in self.commandDescription.items(): | |
462 | - count += 1 | |
463 | - if (self.columns > 100): | |
464 | - self.printColor(Colors.BLUE, "\t"+str(count)+(' ' if count < 10 else '')+": " + command + ": ", eol='') | |
465 | - else: | |
466 | - self.printColor(Colors.BLUE, "-> " + command + ": ", eol='') | |
467 | - self.printColor(Colors.GREEN, message) | |
468 | - return 0 | |
469 | - | |
470 | - def updatedb(self): | |
471 | - self.makemigrations() | |
472 | - self.migrate() | |
473 | - return 0 | |
474 | - | |
475 | - def reset_config(self): | |
476 | - self.changeDirectory("src") | |
477 | - self.set_simulator_mode_to(False) | |
478 | - self.addExecuted(self.current_command, "reset configuration") | |
479 | - self.changeDirectory("..") | |
480 | - return 0 | |
481 | - | |
482 | - def unittest(self): | |
483 | - #self.changeDirectory("src") | |
484 | - apps = ['common', 'scheduler', 'routine_manager', 'user_manager', 'alert_manager.tests.TestStrategyChange'] | |
485 | - for app in apps: | |
486 | - self.loaddata() | |
487 | - self.changeDirectory("src") | |
488 | - self.execProcessFromVenv(self.venv_bin + ' manage.py test ' + app) | |
489 | - self.changeDirectory("..") | |
490 | - return 0 | |
491 | - | |
492 | - def test_all(self): | |
493 | - self.unittest() | |
494 | - return 0 | |
495 | - | |
496 | - #TODO: mettre la fixture en date naive (sans time zone) | |
497 | - def loaddata(self): | |
498 | - self.changeDirectory("src") | |
499 | - self.execProcessFromVenv(self.venv_bin + " manage.py loaddata misc" + os.sep + "fixtures" + os.sep + self.init_fixture) | |
500 | - self.changeDirectory("..") | |
501 | - return 0 | |
502 | - | |
503 | - | |
504 | - def init_database(self): | |
505 | - self.makemigrations() | |
506 | - self.migrate() | |
507 | - self.loaddata() | |
508 | - return 0 | |
509 | - | |
510 | - | |
511 | - # Start the PyROS software | |
512 | - | |
513 | - # Start only the (django) Web server (pyros website) | |
514 | - def start_web(self): | |
515 | - self.start("web") | |
516 | - #self.start(3) | |
517 | - | |
518 | - # Start only the agents (all of them) | |
519 | - def start_agents(self): | |
520 | - self.start("agents") | |
521 | - | |
522 | - # Start only 1 agent | |
523 | - def start_agent_monitoring(self): | |
524 | - self.start("monitoring") | |
525 | - def start_agent_majordome(self): | |
526 | - self.start("majordome") | |
527 | - def start_agent_alertmanager(self): | |
528 | - self.start("alert_manager") | |
529 | - | |
530 | - # Start the PyROS software | |
531 | - # By default (what=None), start everything : all the agents and also the web server (website, web viewing, for global monitoring) | |
532 | - def start(self, what:str = None): | |
533 | - #agents = ("alert_manager", "majordome", "monitoring") | |
534 | - agents = ("majordome", "monitoring") | |
535 | - ''' | |
536 | - what="monitoring" | |
537 | - what="majordome" | |
538 | - what="alert_manager" | |
539 | - what="all" | |
540 | - ''' | |
541 | - | |
542 | - # Go into src/ | |
543 | - self.changeDirectory("src") | |
544 | - #print("Current directory : " + str(os.getcwd())) | |
545 | - | |
546 | - # Start (Django) Web server (pyros website) | |
547 | - if what=='web' or what is None: | |
548 | - self.execProcessFromVenvAsync(self.venv_bin + " manage.py runserver") | |
549 | - #self.changeDirectory("..") | |
550 | - | |
551 | - # DJANGO setup | |
552 | - ''' (optional) | |
553 | - import sys | |
554 | - sys.path.append('/PROJECTS/GFT/SOFT/PYROS_SOFT/PYROS201802/src') | |
555 | - ''' | |
556 | - ''' | |
557 | - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.pyros.settings") | |
558 | - #os.environ['SECRET_KEY'] = 'abc' | |
559 | - #os.environ['ENVIRONMENT'] = 'production' | |
560 | - import django | |
561 | - django.setup() | |
562 | - ''' | |
563 | - | |
564 | - # Start Agents | |
565 | - ''' | |
566 | - if agent=="majordome" or agent=="all": | |
567 | - from majordome.tasks import Majordome | |
568 | - Majordome().run() | |
569 | - if agent=="alert_manager" or agent=="all": | |
570 | - from alert_manager.tasks import AlertListener | |
571 | - AlertListener().run() | |
572 | - ''' | |
573 | - for agent in agents: | |
574 | - if what==agent or what=="agents" or what is None: | |
575 | - #os.chdir('src') | |
576 | - ''' | |
577 | - from monitoring.tasks import Monitoring | |
578 | - Monitoring().run() | |
579 | - ''' | |
580 | - #self.changeDirectory("src/monitoring") | |
581 | - #self.changeDirectory("src") | |
582 | - self.changeDirectory(agent) | |
583 | - self.execProcessFromVenvAsync(self.venv_bin + ' start_agent_'+agent+'.py') | |
584 | - # Go back to src/ | |
585 | - self.changeDirectory('..') | |
586 | - #os.chdir('..') | |
587 | - # Go back to root folder (/) | |
588 | - self.changeDirectory('..') | |
589 | - | |
590 | - | |
591 | - | |
592 | - # Reset the database content | |
593 | - def reset_database_sim(self): | |
594 | - self.changeDirectory("src") | |
595 | - self.set_simulator_mode_to(True, False) | |
596 | - ''' | |
597 | - Supprime toutes les donnรฉes de la base de donnรฉes | |
598 | - et rรฉexรฉcute tout gestionnaire de post-synchronisation. | |
599 | - La table contenant les informations dโapplication des migrations nโest pas effacรฉe | |
600 | - ''' | |
601 | - #TODO: remplacer par manage.py --noinput flush pour eviter le "echo yes"... | |
602 | - self.execProcess( self.venv_bin + " manage.py flush --noinput") | |
603 | - self.set_simulator_mode_to(True, False) | |
604 | - self.changeDirectory("..") | |
605 | - | |
606 | - | |
607 | - # Simulation for the scheduler ONLY | |
608 | - def simulator_development(self): | |
609 | - self.simulator(False) | |
610 | - | |
611 | - ''' | |
612 | - (EP) utile pour le debug avec phpmyadmin pour remettre ร zรฉro la bd pyros_test | |
613 | - delete from plan; | |
614 | - delete from album; | |
615 | - delete from schedule_has_sequences; | |
616 | - delete from schedule; | |
617 | - delete from sequence; | |
618 | - delete from request; | |
619 | - ''' | |
620 | - | |
621 | - # Simulation (by default, with ALL simulators) | |
622 | - def simulator(self, TOTAL=True): | |
623 | - self.changeDirectory("src") | |
624 | - | |
625 | - # Set SIMULATOR mode ON | |
626 | - self.replacePatternInFile("SIMULATOR = False", "SIMULATOR = True", "pyros/settings.py") | |
627 | - | |
628 | - # 0) Reset the database (Empty the database from any data) | |
629 | - #TODO: je crois qu'on n'utilise plus sqlite... donc ce code est inutile ? | |
630 | - if self.system == "Windows" : self.execProcess("del /f testdb.sqlite3") | |
631 | - else : self.execProcess("rm -f testdb.sqlite3") | |
632 | - self.changeDirectory("..") | |
633 | - if TOTAL: self.reset_database_sim() | |
634 | - # EP added: | |
635 | - if not TOTAL: self.reset_database_sim() | |
636 | - # Actualise lโรฉtat de la DB en accord avec lโensemble des modรจles et des migrations actuels | |
637 | - self.makemigrations() | |
638 | - self.migrate() | |
639 | - # Load fixture initial_fixture.json | |
640 | - self.loaddata() | |
641 | - | |
642 | - # | |
643 | - # 1) Launch web server | |
644 | - # | |
645 | - self.server() | |
646 | - self.sleep(2) | |
647 | - | |
648 | - self.printFullTerm(Colors.WARNING, "SUMMARY") | |
649 | - self.printColor(Colors.GREEN, "The simulator has been successfully initialised") | |
650 | - #TODO: (EP) verifier mais je pense que cette info est obsolete, c'est MySQL qui est utilisรฉ, pas sqlite | |
651 | - #self.printColor(Colors.GREEN, "The simulator runs on a temp database : src/testdb.sqlite3") | |
652 | - self.printColor(Colors.GREEN, "The simulation will be ended by the task 'simulator herself'") | |
653 | - self.printColor(Colors.GREEN, "If you want to shutdown the simulation, please run :") | |
654 | - self.printColor(Colors.GREEN, "CTRL-C or pyros.py kill_simulation") | |
655 | - self.printColor(Colors.GREEN, "If the simulation isn't correctly killed, please switch the variable") | |
656 | - self.printColor(Colors.GREEN, "SIMULATOR in src/pyros/settings.py to False") | |
657 | - self.printFullTerm(Colors.WARNING, "SUMMARY") | |
658 | - | |
659 | - # | |
660 | - # 2) Start simulator(s) : | |
661 | - # | |
662 | - self.sims_launch(TOTAL) | |
663 | - | |
664 | - ''' | |
665 | - # (DEFAULT NORMAL) TOTAL RUN | |
666 | - # - Launch ALL simulators | |
667 | - if TOTAL: | |
668 | - # Launch ALL simulators and WAIT until finished: | |
669 | - #self.sims_launch(conf) | |
670 | - self.sims_launch(TOTAL) | |
671 | - | |
672 | - # (DEV) PARTIAL RUN | |
673 | - # - Launch only USER simulator | |
674 | - else: | |
675 | - # EP: bugfix: inutile si TOTAL, car refait dans sims_launch !!! | |
676 | - self.changeDirectory("simulators/config") | |
677 | - self.printColor(Colors.BOLD, "Existing simulations : ", eol='') | |
678 | - sys.stdout.flush() | |
679 | - if (self.system == "Windows") : self.execProcessSilent("dir /B conf*.json") | |
680 | - else: self.execProcessSilent("ls conf*.json") | |
681 | - self.changeDirectory("..") | |
682 | - conf = self.askQuestion("Which simulation do you want to use", default="conf.json") | |
683 | - self.changeDirectory("..") | |
684 | - | |
685 | - procs = [] | |
686 | - self.changeDirectory("simulators") | |
687 | - self.changeDirectory("user") | |
688 | - # Launch only 1 simulator : UserSimulator | |
689 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " userSimulator.py " + conf)) | |
690 | - self.changeDirectory("..") | |
691 | - for p in procs: | |
692 | - p.wait() | |
693 | - self.changeDirectory("..") | |
694 | - ''' | |
695 | - | |
696 | - # When simulators are finished: | |
697 | - #self.kill_simulation() | |
698 | - return 0 | |
699 | - | |
700 | - | |
701 | - | |
702 | - | |
703 | - # Test of the Majordome agent | |
704 | - def test_majordome(self): | |
705 | - self.changeDirectory("src") | |
706 | - | |
707 | - # Set SIMULATOR mode ON | |
708 | - self.set_simulator_mode_to(True) | |
709 | - | |
710 | - # 0) Reset the database (Empty the database from any data) | |
711 | - self.changeDirectory("..") | |
712 | - self.reset_database_sim() | |
713 | - # Actualise lโรฉtat de la DB en accord avec lโensemble des modรจles et des migrations actuels | |
714 | - self.migrate() | |
715 | - # Load fixture initial_fixture.json | |
716 | - self.loaddata() | |
717 | - return | |
718 | - | |
719 | - # | |
720 | - # 1) Launch Django web server | |
721 | - # | |
722 | - ''' | |
723 | - self.server() | |
724 | - self.sleep(2) | |
725 | - ''' | |
726 | - | |
727 | - self.printFullTerm(Colors.WARNING, "SUMMARY") | |
728 | - self.printColor(Colors.GREEN, "The simulation will be ended by the task 'simulator herself'") | |
729 | - self.printColor(Colors.GREEN, "If you want to shutdown the simulation, please run :") | |
730 | - self.printColor(Colors.GREEN, "CTRL-C or pyros.py kill_simulation") | |
731 | - self.printColor(Colors.GREEN, "If the simulation isn't correctly killed, please switch the variable") | |
732 | - self.printColor(Colors.GREEN, "SIMULATOR in src/pyros/settings.py to False") | |
733 | - self.printFullTerm(Colors.WARNING, "SUMMARY") | |
734 | - | |
735 | - # | |
736 | - # 2) Start simulator(s) : | |
737 | - # | |
738 | - #self.sims_launch(True) | |
739 | - agent='majordome' | |
740 | - self.changeDirectory(agent) | |
741 | - p = self.execProcessFromVenvAsync(self.venv_bin + ' start_agent_'+agent+'.py') | |
742 | - os.chdir('..') | |
743 | - time.sleep(5) | |
744 | - | |
745 | - | |
746 | - # Wait for end of simulators : | |
747 | - #p.wait() | |
748 | - | |
749 | - # When simulators are finished: | |
750 | - #self.kill_simulation() | |
751 | - #self.changeDirectory("src") | |
752 | - self.set_simulator_mode_to(False) | |
753 | - self.changeDirectory("..") | |
754 | - self.execProcessAsync("ps aux | grep \"start_agent_majordome.py\" | awk '{ print $2 }' | xargs kill") | |
755 | - | |
756 | - return 0 | |
757 | - | |
758 | - | |
759 | - | |
760 | - | |
761 | - | |
762 | - | |
763 | - | |
764 | - def kill_server(self): | |
765 | - self.execProcessAsync("fuser -k 8000/tcp") | |
766 | - return 0 | |
767 | - | |
768 | - def kill_simulation(self): | |
769 | - self.changeDirectory("src") | |
770 | - self.set_simulator_mode_to(False) | |
771 | - self.changeDirectory("..") | |
772 | - if (self.system == "Windows"): | |
773 | - self.execProcessAsync("taskkill /f /im python.exe") | |
774 | - #self.execProcessAsync("del /f testdb.sqlite3") obsolete | |
775 | - #self.changeDirectory("..") POURQUOI ? | |
776 | - return 0 | |
777 | - #else: self.execProcessAsync("rm -f testdb.sqlite3") | |
778 | - | |
779 | - # Kill web server (processes using TCP port 8000) : | |
780 | - #self.execProcessAsync("fuser -k 8000/tcp") | |
781 | - | |
782 | - self.kill_server() | |
783 | - | |
784 | - # Kill all agents : | |
785 | - self.execProcessAsync("ps aux | grep \"start_agent_alert_manager.py\" | awk '{ print $2 }' | xargs kill") | |
786 | - self.execProcessAsync("ps aux | grep \"start_agent_monitoring.py\" | awk '{ print $2 }' | xargs kill") | |
787 | - self.execProcessAsync("ps aux | grep \"start_agent_majordome.py\" | awk '{ print $2 }' | xargs kill") | |
788 | - #self.execProcessAsync("ps aux | grep \"start_agent_majordome.py\" | awk '{ print $2 }' | xargs kill") | |
789 | - | |
790 | - # Kill all simulators : | |
791 | - self.execProcessAsync("ps aux | grep \" domeSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
792 | - self.execProcessAsync("ps aux | grep \" userSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
793 | - self.execProcessAsync("ps aux | grep \" alertSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
794 | - self.execProcessAsync("ps aux | grep \" plcSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
795 | - self.execProcessAsync("ps aux | grep \" telescopeSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
796 | - self.execProcessAsync("ps aux | grep \" cameraNIRSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
797 | - self.execProcessAsync("ps aux | grep \" cameraVISSimulator.py\" | awk '{ print $2 }' | xargs kill") | |
798 | - self.changeDirectory("..") | |
799 | - | |
800 | - self.printFullTerm(Colors.GREEN, "simulation ended") | |
801 | - return 0 | |
802 | - | |
803 | - | |
804 | - | |
805 | - # EP 25/7/18 | |
806 | - # Start one, some, or all agents and simulators | |
807 | - | |
808 | - def start_agents_and_simulators_for_majordome(self): | |
809 | - self.start_agents_and_simulators("majordome") | |
810 | - | |
811 | - def start_agents_and_simulators(self, agent:str=None): | |
812 | - | |
813 | - simulators = ('user', 'plc', 'dome', 'alert', 'cameraVIS', 'cameraNIR', 'telescope') | |
814 | - #simulators = ('plc', 'user') | |
815 | - #simulators = () | |
816 | - | |
817 | - agents = ("alert_manager", "majordome", "monitoring") | |
818 | - | |
819 | - if agent=="majordome": | |
820 | - simulators = ("plc",) | |
821 | - agents = (agent, "monitoring") | |
822 | - | |
823 | - # Start simulators | |
824 | - p_sims = [] | |
825 | - self.changeDirectory("simulators/") | |
826 | - for simulator in simulators: | |
827 | - print() | |
828 | - print("Start simulator", ' '+simulator+"Simulator.py ") | |
829 | - self.changeDirectory(simulator) | |
830 | - #p_sims.append( self.execProcessFromVenvAsync(self.venv_bin + ' '+simulator+"Simulator.py " + conf) ) | |
831 | - p_sims.append( self.execProcessFromVenvAsync(self.venv_bin + ' '+simulator+"Simulator.py ") ) | |
832 | - self.changeDirectory("../") | |
833 | - | |
834 | - # Start agents | |
835 | - #self.start_agents() | |
836 | - p_agents = [] | |
837 | - self.changeDirectory("../src/") | |
838 | - for agent in agents: | |
839 | - print() | |
840 | - print("Start agent", 'start_agent_'+agent+'.py') | |
841 | - self.changeDirectory(agent) | |
842 | - p_agents.append( self.execProcessFromVenvAsync(self.venv_bin + ' start_agent_'+agent+'.py') ) | |
843 | - self.changeDirectory('..') | |
844 | - | |
845 | - | |
846 | - | |
847 | - # Simulators only | |
848 | - def sims_launch(self, TOTAL=True): | |
849 | - conf = SIMULATOR_CONFIG_FILE | |
850 | - # Read simulators scenario file | |
851 | - self.changeDirectory("simulators/config") | |
852 | - # if (conf == ""): | |
853 | - # self.printColor(Colors.BOLD, "Existing simulations : ", eol='') | |
854 | - # sys.stdout.flush() | |
855 | - # if (self.system == "Windows"): | |
856 | - # self.execProcessSilent("dir /B conf*.json") | |
857 | - # else: | |
858 | - # self.execProcessSilent("ls conf*.json") | |
859 | - # conf = self.askQuestion("Which simulation do you want to use ?", default="conf.json") | |
860 | - if not os.path.isfile(conf): | |
861 | - self.printColor(Colors.FAIL, "The simulation file " + conf + " does not exist") | |
862 | - return 1 | |
863 | - # Go back to simulators/ | |
864 | - self.changeDirectory("..") | |
865 | - | |
866 | - procs = [] | |
867 | - | |
868 | - # Launch the User simulator: | |
869 | - self.changeDirectory("user") | |
870 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " userSimulator.py " + conf)) | |
871 | - self.changeDirectory("..") | |
872 | - | |
873 | - # (if TOTAL) Launch all other simulators | |
874 | - if TOTAL: | |
875 | - | |
876 | - self.changeDirectory("dome") | |
877 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " domeSimulator.py " + conf)) | |
878 | - self.changeDirectory("..") | |
879 | - | |
880 | - self.changeDirectory("alert") | |
881 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " alertSimulator.py " + conf)) | |
882 | - self.changeDirectory("..") | |
883 | - | |
884 | - self.changeDirectory("plc") | |
885 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " plcSimulator.py " + conf)) | |
886 | - self.changeDirectory("..") | |
887 | - | |
888 | - self.changeDirectory("camera") | |
889 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " cameraVISSimulator.py " + conf)) | |
890 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " cameraNIRSimulator.py " + conf)) | |
891 | - self.changeDirectory("..") | |
892 | - | |
893 | - self.changeDirectory("telescope") | |
894 | - procs.append(self.execProcessFromVenvAsync(self.venv_bin + " telescopeSimulator.py " + conf)) | |
895 | - self.changeDirectory("..") | |
896 | - | |
897 | - # Get back to project root folder | |
898 | - self.changeDirectory("..") | |
899 | - | |
900 | - # Launch agents (env monitor, major, alert mgr) | |
901 | - self.start_agents() | |
902 | - | |
903 | - # Wait for end of simulators : | |
904 | - for p in procs: p.wait() | |
905 | - | |
906 | - # Kill all processes | |
907 | - self.kill_simulation() | |
908 | - return 0 | |
909 | - | |
910 | - | |
911 | - def mysql_on(self): | |
912 | - self.changeDirectory("src") | |
913 | - self.replacePatternInFile("MYSQL = False", "MYSQL = True", "pyros/settings.py") | |
914 | - self.addExecuted(self.current_command, "Switch to mysql") | |
915 | - self.changeDirectory("..") | |
916 | - return 0 | |
917 | - | |
918 | - def mysql_off(self): | |
919 | - self.changeDirectory("src") | |
920 | - self.replacePatternInFile("MYSQL = True", "MYSQL = False", "pyros/settings.py") | |
921 | - self.addExecuted(self.current_command, "Switch to sqlite") | |
922 | - self.changeDirectory("..") | |
923 | - return 0 | |
924 | - | |
925 | - def __init__(self, argv): | |
926 | - super(Pyros, self).__init__(argv) | |
927 | - self.commandMatcher = { | |
928 | - "install": self.install, | |
929 | - "update": self.update, | |
930 | - "server": self.server, | |
931 | - "clean": self.clean, | |
932 | - "simulator_development": self.simulator_development, | |
933 | - "clean_logs": self.clean_logs, | |
934 | - "test": self.test, | |
935 | - "migrate": self.migrate, | |
936 | - "mysql_on": self.mysql_on, | |
937 | - "mysql_off": self.mysql_off, | |
938 | - "makemigrations": self.makemigrations, | |
939 | - "updatedb": self.updatedb, | |
940 | - "unittest": self.unittest, | |
941 | - "reset_config": self.reset_config, | |
942 | - "test_all": self.test_all, | |
943 | - "reset_database_sim": self.reset_database_sim, | |
944 | - "init_database": self.init_database, | |
945 | - "kill_server": self.kill_server, | |
946 | - "loaddata": self.loaddata, | |
947 | - "start": self.start, | |
948 | - "start_web": self.start_web, | |
949 | - "start_agents": self.start_agents, | |
950 | - "start_agents_and_simulators": self.start_agents_and_simulators, | |
951 | - "start_agents_and_simulators_for_majordome": self.start_agents_and_simulators_for_majordome, | |
952 | - "start_agent_monitoring": self.start_agent_monitoring, | |
953 | - "start_agent_majordome": self.start_agent_majordome, | |
954 | - "start_agent_alertmanager": self.start_agent_alertmanager, | |
955 | - "test_majordome": self.test_majordome, | |
956 | - | |
957 | - "simulator": self.simulator, | |
958 | - "kill_simulation": self.kill_simulation, | |
959 | - "sims_launch": self.sims_launch, | |
960 | - "help": self.help, | |
961 | - } | |
962 | - self.commandDescription = { | |
963 | - "install": "Launch the server installation", | |
964 | - "update": "Update the server", | |
965 | - "server": "Launch the web server", | |
966 | - "loaddata": "Load the initial fixture in database", | |
967 | - "clean": "clean the repository", | |
968 | - "clean_logs": "clean the log directory", | |
969 | - "test": "launch the server tests", | |
970 | - "migrate": "execute migrations", | |
971 | - "mysql_on": "switch the database to be used to MYSQL", | |
972 | - "mysql_off": "switch the database to be used usage to SQLITE", | |
973 | - "makemigrations": "create new migrations", | |
974 | - "reset_config": "Reset the configuration in settings.py", | |
975 | - "reset_database_sim": "Reset the database content", | |
976 | - "help": "Help message", | |
977 | - "updatedb": "Update the database", | |
978 | - "kill_server": "Kill the web server on port 8000", | |
979 | - "init_database": "Create a standard initial context for pyros in db", | |
980 | - "unittest": "Runs the unit tests", | |
981 | - "test_all": "Run all the existing tests (this command needs to be updated when tests are added in the project", | |
982 | - "simulator": "Launch a simulation", | |
983 | - "simulator_development": "Simulation for the scheduler only", | |
984 | - "kill_simulation": "kill the simulators & web server", | |
985 | - "sims_launch": "Launch only the simulators", | |
986 | - } | |
987 | - | |
988 | -if __name__ == "__main__": | |
989 | - if len(sys.argv) == 3 and sys.argv[1].startswith("simulator"): | |
990 | - SIMULATOR_CONFIG_FILE = sys.argv[2] | |
991 | - conf = Config() | |
992 | - if not conf.parseConf(): sys.exit(1) | |
993 | - pyros = Pyros(conf) | |
994 | - sys.exit(pyros.exec()) |
src/agent/Agent.py
... | ... | @@ -115,8 +115,11 @@ class Agent: |
115 | 115 | self.config = ConfigPyros(config_filename) |
116 | 116 | if self.config.get_last_errno() != self.config.NO_ERROR: |
117 | 117 | raise Exception(f"Bad config file name '{config_filename}', error {str(self.config.get_last_errno())}: {str(self.config.get_last_errmsg())}") |
118 | - tmp = AgentsSurvey.objects.filter(name=self.name) | |
119 | - if len(tmp) == 0: | |
118 | + #tmp = AgentsSurvey.objects.filter(name=self.name) | |
119 | + #if len(tmp) == 0: | |
120 | + #nb_agents = AgentsSurvey.objects.filter(name=self.name).count() | |
121 | + #if nb_agents == 0: | |
122 | + if not AgentsSurvey.objects.filter(name=self.name).exists(): | |
120 | 123 | self._agent_survey = AgentsSurvey.objects.create(name=self.name, validity_duration_sec=60, mode=self.mode, status=self.status) |
121 | 124 | #self._agent_survey = AgentsSurvey(name=self.name, validity_duration_sec=60, mode=self.mode, status=self.status) |
122 | 125 | #self._agent_survey.save() |
... | ... | @@ -172,11 +175,12 @@ class Agent: |
172 | 175 | |
173 | 176 | self.load_config() |
174 | 177 | |
175 | - self.update_db_survey() | |
176 | - | |
177 | - self.read_db_commands() | |
178 | + self.update_survey() | |
178 | 179 | |
180 | + # generic cmd in json format | |
181 | + cmd = self.read_next_command() | |
179 | 182 | |
183 | + self.general_process(cmd) | |
180 | 184 | ''' |
181 | 185 | if self.config.majordome_state == "STOP": |
182 | 186 | break |
... | ... | @@ -190,7 +194,7 @@ class Agent: |
190 | 194 | # Sub-level loop (only if ACTIVE) |
191 | 195 | if self.is_active(): |
192 | 196 | self.set_status(self.STATUS_PROCESS_LOOP) |
193 | - self.core_process() | |
197 | + self.specific_process(cmd) | |
194 | 198 | |
195 | 199 | self.waitfor(self.mainloop_waittime) |
196 | 200 | |
... | ... | @@ -200,6 +204,14 @@ class Agent: |
200 | 204 | |
201 | 205 | |
202 | 206 | |
207 | + def general_process(self, cmd): | |
208 | + pass | |
209 | + | |
210 | + # @abstract | |
211 | + # to be implemented by subclasses | |
212 | + def specific_process(self, cmd): | |
213 | + raise NotImplemented() | |
214 | + | |
203 | 215 | def waitfor(self, nbsec): |
204 | 216 | print(f"Now, waiting for {nbsec} seconds...") |
205 | 217 | time.sleep(nbsec) |
... | ... | @@ -330,9 +342,9 @@ class Agent: |
330 | 342 | self._agent_survey.status = self.status |
331 | 343 | self._agent_survey.save() |
332 | 344 | |
333 | - def read_db_commands(self): | |
345 | + def read_next_command(self): | |
334 | 346 | print("Looking for new commands from the database ...") |
335 | - _agent_commands = AgentsCommand.objects.filter(receiver=self.name) | |
347 | + _agent_commands = AgentsCommand.objects.filter(receiver=self.name, receiver_error_code=1) | |
336 | 348 | # Is there any command for me to execute ? |
337 | 349 | if _agent_commands: |
338 | 350 | print(f"I have received {len(_agent_commands)} new command(s) to execute") | ... | ... |
src/agent/AgentX.py
... | ... | @@ -33,17 +33,17 @@ class AgentX(Agent): |
33 | 33 | super().load_config() |
34 | 34 | |
35 | 35 | # @override |
36 | - def update_db_survey(self): | |
36 | + def update_survey(self): | |
37 | 37 | super().update_db_survey() |
38 | 38 | |
39 | 39 | # @override |
40 | - def read_db_commands(self): | |
41 | - super().read_db_commands() | |
40 | + def read_next_command(self): | |
41 | + return super().read_next_command() | |
42 | 42 | |
43 | 43 | # @override |
44 | 44 | def do_log(self): |
45 | 45 | super().do_log() |
46 | 46 | |
47 | 47 | # @override |
48 | - def core_process(self): | |
49 | - super().core_process() | |
48 | + def specific_process(self, cmd): | |
49 | + pass | |
50 | 50 | \ No newline at end of file | ... | ... |
src/common/models.py
1 | -from __future__ import unicode_literals | |
1 | +##from __future__ import unicode_literals | |
2 | + | |
3 | +from enum import Enum | |
2 | 4 | |
3 | 5 | from django.contrib.auth.models import AbstractUser |
4 | 6 | from django.db import models |
5 | -from enum import Enum | |
7 | +from django.core.validators import MaxValueValidator, MinValueValidator | |
8 | + | |
6 | 9 | |
7 | 10 | |
8 | 11 | ''' |
... | ... | @@ -22,25 +25,24 @@ class PyrosState(Enum): |
22 | 25 | """ |
23 | 26 | STYLE RULES |
24 | 27 | =========== |
25 | -(https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html) | |
28 | +https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html | |
29 | +https://steelkiwi.com/blog/best-practices-working-django-models-python/ | |
26 | 30 | |
27 | -- The model definition is a class, so always use CapWords convention (no underscores) | |
31 | +- Model name => singular | |
32 | + Call it Company instead of Companies. | |
33 | + A model definition is the representation of a single object (the object in this example is a company), | |
34 | + and not a collection of companies | |
35 | + The model definition is a class, so always use CapWords convention (no underscores) | |
28 | 36 | E.g. User, Permission, ContentType, etc. |
29 | 37 | |
30 | 38 | - For the modelโs attributes use snake_case. |
31 | 39 | E.g. first_name, last_name, etc |
32 | 40 | |
33 | -- Always name your models using singular. | |
34 | - Call it Company instead of Companies. | |
35 | - A model definition is the representation of a single object (the object in this example is a company), | |
36 | - and not a collection of companies | |
37 | - | |
38 | -- Blank and Null Fields | |
41 | +- Blank and Null Fields (https://simpleisbetterthancomplex.com/tips/2016/07/25/django-tip-8-blank-or-null.html) | |
39 | 42 | - Null: It is database-related. Defines if a given database column will accept null values or not. |
40 | 43 | - Blank: It is validation-related. It will be used during forms validation, when calling form.is_valid(). |
41 | 44 | Do not use null=True for text-based fields that are optional. |
42 | - Otherwise, you will end up having two possible values for โno dataโ, | |
43 | - that is: None and an empty string. | |
45 | + Otherwise, you will end up having two possible values for โno dataโ, that is: None and an empty string. | |
44 | 46 | Having two possible values for โno dataโ is redundant. |
45 | 47 | The Django convention is to use the empty string, not NULL. |
46 | 48 | Example: |
... | ... | @@ -49,6 +51,16 @@ STYLE RULES |
49 | 51 | name = models.CharField(max_length=255) # Mandatory |
50 | 52 | bio = models.TextField(max_length=500, blank=True) # Optional (don't put null=True) |
51 | 53 | birth_date = models.DateField(null=True, blank=True) # Optional (here you may add null=True) |
54 | + The default values of null and blank are False. | |
55 | + Special case, when you need to accept NULL values for a BooleanField, use NullBooleanField instead. | |
56 | + | |
57 | +- Choices : you can use Choices from the model_utils library. Take model Article, for instance: | |
58 | + from model_utils import Choices | |
59 | + class Article(models.Model): | |
60 | + STATUSES = Choices( | |
61 | + (0, 'draft', _('draft')), | |
62 | + (1, 'published', _('published')) ) | |
63 | + status = models.IntegerField(choices=STATUSES, default=STATUSES.draft) | |
52 | 64 | |
53 | 65 | - Reverse Relationships |
54 | 66 | |
... | ... | @@ -203,10 +215,11 @@ class AgentsCommand(models.Model): |
203 | 215 | (l'agent destinataire en profite pour supprimer les commandes pรฉrimรฉes qui le concernent) |
204 | 216 | """ |
205 | 217 | #sender = models.CharField(max_length=50, blank=True, null=True, unique=True) |
206 | - sender = models.CharField(max_length=50, unique=True) | |
218 | + sender = models.CharField(max_length=50, unique=True, help_text='sender agent name') | |
207 | 219 | receiver = models.CharField(max_length=50, unique=True) |
208 | 220 | command = models.CharField(max_length=400) |
209 | - validity_duration_sec = models.PositiveIntegerField(default=60) | |
221 | + #validity_duration_sec = models.PositiveIntegerField(default=60) | |
222 | + validity_duration_sec = models.DurationField(default=60) | |
210 | 223 | |
211 | 224 | # Automatically set at table line creation (line created by the sender) |
212 | 225 | sender_deposit_time = models.DateTimeField(blank=True, null=True, auto_now_add=True) |
... | ... | @@ -231,6 +244,9 @@ class AgentsSurvey(models.Model): |
231 | 244 | """ |
232 | 245 | | id | name | created | updated | validity_duration_sec (default=1mn) | mode (active/idle) | status (launch/init/loop/exit/...) | |
233 | 246 | """ |
247 | + | |
248 | + #STATUSES = Choices('new', 'verified', 'published') | |
249 | + | |
234 | 250 | # Statuses |
235 | 251 | STATUS_LAUNCH = "LAUNCHED" |
236 | 252 | STATUS_INIT = "INITIALIZING" |
... | ... | @@ -255,13 +271,15 @@ class AgentsSurvey(models.Model): |
255 | 271 | (STATUS_EXIT, "EXITING"), |
256 | 272 | ) |
257 | 273 | |
258 | - name = models.CharField(max_length=50, blank=True, null=True, unique=True) | |
274 | + name = models.CharField(max_length=50, unique=True) | |
275 | + #name = models.CharField(max_length=50, blank=True, null=True, unique=True) | |
259 | 276 | #created = models.DateTimeField(blank=True, null=True, auto_now_add=True) |
260 | 277 | created = models.DateTimeField(blank=True, null=True, auto_now_add=True) |
261 | 278 | updated = models.DateTimeField(blank=True, null=True, auto_now=True) |
262 | - validity_duration_sec = models.PositiveIntegerField(blank=True, null=True) | |
263 | - mode = models.CharField('agent mode', max_length=15, blank=True, null=True, choices=MODE_CHOICES) | |
264 | - status = models.CharField(max_length=15, blank=True, null=True, choices=STATUS_CHOICES) | |
279 | + #validity_duration_sec = models.PositiveIntegerField(blank=True, null=True) | |
280 | + validity_duration_sec = models.DurationField(default=90) | |
281 | + mode = models.CharField('agent mode', max_length=15, blank=True, choices=MODE_CHOICES) | |
282 | + status = models.CharField(max_length=15, blank=True, choices=STATUS_CHOICES) | |
265 | 283 | |
266 | 284 | class Meta: |
267 | 285 | managed = True |
... | ... | @@ -330,9 +348,25 @@ class Config(models.Model): |
330 | 348 | PYROS_STATE = ["Starting", "Passive", "Standby", "Remote", "Startup", "Scheduler", "Closing" ] |
331 | 349 | |
332 | 350 | id = models.IntegerField(default='1', primary_key=True) |
333 | - latitude = models.FloatField(default=1) | |
351 | + #latitude = models.FloatField(default=1) | |
352 | + latitude = models.DecimalField( | |
353 | + max_digits=4, decimal_places=2, | |
354 | + default=1, | |
355 | + validators=[ | |
356 | + MaxValueValidator(90), | |
357 | + MinValueValidator(-90) | |
358 | + ] | |
359 | + ) | |
334 | 360 | local_time_zone = models.FloatField(default=1) |
335 | - longitude = models.FloatField(default=1) | |
361 | + #longitude = models.FloatField(default=1) | |
362 | + longitude = models.DecimalField( | |
363 | + max_digits=5, decimal_places=2, | |
364 | + default=1, | |
365 | + validators=[ | |
366 | + MaxValueValidator(360), | |
367 | + MinValueValidator(-360) | |
368 | + ] | |
369 | + ) | |
336 | 370 | altitude = models.FloatField(default=1) |
337 | 371 | horizon_line = models.FloatField(default=1) |
338 | 372 | row_data_save_frequency = models.IntegerField(default='300') | ... | ... |