branch develop updated (492e5c1 -> 61c296b)
This is an automated email from the git hooks/post-receive script. New change to branch develop in repository mum. See http://git.chorem.org/mum.git from 492e5c1 Les modules de monitoring sont maintenant chargés : d'une part ceux internes, d'autre part ceux dans le dossier extérieur spécifiés dans conf.txt new b47efae les modules de connection sont chargés comme ceux de monitoring new 2231aed code d'instruction websocket devenus textuels new 61c296b hostpage : modal des priorités de connection => OK The 3 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 61c296b19fc612d72ba25919739d857e3dcc94f2 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 17:24:00 2015 +0100 hostpage : modal des priorités de connection => OK commit 2231aed98bbc6c0ce773fc60b475d49c64c5ff69 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 17:03:37 2015 +0100 code d'instruction websocket devenus textuels commit b47efaed91b459bd51ec86eff159cf44aaac7b6d Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 12:10:52 2015 +0100 les modules de connection sont chargés comme ceux de monitoring Summary of changes: app/app.py | 43 ++--- app/module_loader.py | 211 ++++++++++----------- app/modules/connection_modules/__init__.py | 3 +- app/modules/connection_modules/nagios.py | 1 - app/modules/connection_modules/snmp.py | 1 - app/modules/connection_modules/ssh.py | 25 ++- app/modules/detection_modules/nmap_detection.py | 17 +- app/modules/monitoring_modules/__init__.py | 3 +- app/modules/monitoring_modules/disk.py | 7 +- app/modules/monitoring_modules/memory.py | 8 +- .../notification_modules/websocket_container.py | 2 +- app/modules/storage_modules/shelve_db.py | 63 ++++-- static/js/controllers/headCtrl.js | 18 +- static/js/controllers/hostPageCtrl.js | 63 +++++- static/js/controllers/scanCtrl.js | 2 +- views/hostpage.html | 86 +-------- 16 files changed, 264 insertions(+), 289 deletions(-) delete mode 100644 app/modules/connection_modules/nagios.py delete mode 100644 app/modules/connection_modules/snmp.py -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit b47efaed91b459bd51ec86eff159cf44aaac7b6d Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 12:10:52 2015 +0100 les modules de connection sont chargés comme ceux de monitoring --- app/app.py | 5 +- app/module_loader.py | 184 ++++++++++-------------- app/modules/connection_modules/__init__.py | 3 +- app/modules/connection_modules/nagios.py | 1 - app/modules/connection_modules/snmp.py | 1 - app/modules/connection_modules/ssh.py | 25 +++- app/modules/detection_modules/nmap_detection.py | 5 +- app/modules/monitoring_modules/__init__.py | 3 +- app/modules/monitoring_modules/disk.py | 7 +- app/modules/monitoring_modules/memory.py | 8 +- app/modules/storage_modules/shelve_db.py | 55 ++++--- 11 files changed, 145 insertions(+), 152 deletions(-) diff --git a/app/app.py b/app/app.py index 81a94f3..2d6d636 100755 --- a/app/app.py +++ b/app/app.py @@ -168,8 +168,9 @@ if __name__ == '__main__': global ml global wsc ml = ModuleLoader() - ml.get_all_monitoring_modules() + ml.load_all_monitoring_modules() + ml.load_all_connection_modules() wsc = WebSocketContainer(ml.get_db()) - process_monitoring.init(ml, wsc) + #process_monitoring.init(ml, wsc) port = int(os.environ.get('PORT', 1337)) run(host='0.0.0.0', port=port, debug=True, server=GeventWebSocketServer) \ No newline at end of file diff --git a/app/module_loader.py b/app/module_loader.py index 4abb83e..92bf62b 100644 --- a/app/module_loader.py +++ b/app/module_loader.py @@ -14,20 +14,24 @@ import re import pkgutil import sys + class ModuleLoader: """ - Loads dynamically modules from packages connection_modules, detection_modules, monitoring_modules, storage_modules. + Loads dynamically modules from packages connection_modules, detection_modules, monitoring_modules, storage_modules + and contains several methods in order to call the methods once these modules loaded. """ def __init__(self): - fconf = open('conf.txt') - dict_conf = {} + dict_conf = {} # See conf.txt + fconf = open('conf.txt', 'r') for line in fconf.read().splitlines(): fields = line.split('=') dict_conf[fields[0]] = fields[1] + fconf.close() self.db_loc = dict_conf['db_location'] self.external_mod_loc = dict_conf['external_modules_location'] self.db = self.load_db() - self.loaded_mod_infos = {} + self.loaded_mod_moni = {} # See load_all_monitoring_modules + self.loaded_mod_conn = {} # See load_all_connection_modules def load_db(self): """ @@ -42,7 +46,8 @@ class ModuleLoader: def get_db(self): return self.db - def run_nmap_detection(self, param, opt, db, ws, list_mod_conn, dict_mod_monitoring): + @staticmethod + def run_nmap_detection(param, opt, db, ws, list_mod_conn, dict_mod_monitoring): """ Instanciates the nmap_detection module from detection_modules, and runs the detection. :param param: parameter to put in nmap command. can be a hostname, a ip address or a ip range @@ -64,18 +69,6 @@ class ModuleLoader: ws.send(json.dumps({"40": hnfe.__str__()})) return None - def load_conn(self, conn_name, addr_host, username, key_location): # /home/aguilbaud/.ssh/id_rsa - """ - Instanciates and creates a connection with a connection module. - :param conn_name: the name of the detection module - :param addr_host: the IP adress of the host we want to create a connection - :param key_location: the location of the public key - :return: the instance of connection module created - """ - conn = __import__("modules.connection_modules." + conn_name, fromlist=modules.connection_modules) - conn_instance = getattr(conn, conn_name)(addr_host, username, key_location, modules.CommandNotFoundException) - return conn_instance - def run_all_detection_modules(self, os, conn, db, ws): """ Instanciates and runs every detection_modules listed in the __init__.py file of the package corresponding to @@ -97,64 +90,50 @@ class ModuleLoader: if ws is not None: ws.send(json.dumps({"40": cnfe.__str__()})) - def get_all_monitoring_modules(self): + def load_all_monitoring_modules(self): """ Instanciates and stores the informations about each monitoring modules avaliable (internal and loaded - externally) + externally) on the loaded_mod_moni attribute """ for importer, mod_name, ispkg in pkgutil.iter_modules(["app/modules/monitoring_modules/"]): if mod_name not in sys.modules: - loaded_mod = __import__("modules.monitoring_modules." + mod_name, fromlist=[mod_name]) - class_name = getattr(loaded_mod, "get_class_name")() - if mod_name == 'ping': - mod_inst = getattr(loaded_mod, class_name)(None, None) - else: - mod_inst = getattr(loaded_mod, class_name)(None, None, None) - infos_mod = {} - infos_mod['imported'] = loaded_mod - infos_mod['class_name'] = getattr(mod_inst, 'get_name')() - infos_mod['compatible_os'] = getattr(mod_inst, 'get_compatible_os')() - infos_mod['block'] = getattr(mod_inst, 'get_block')() - infos_mod['unit'] = getattr(mod_inst, 'get_unit')() - infos_mod['external'] = False - self.loaded_mod_infos[mod_name] = infos_mod - - # Now for external modules - # Adding the external diretory into pythonpath : - sys.path.insert(0, self.external_mod_loc) + try: + loaded_mod = __import__("modules.monitoring_modules." + mod_name, fromlist=[mod_name]) + class_name = getattr(loaded_mod, "get_class_name")() + if mod_name == 'ping': + mod_inst = getattr(loaded_mod, class_name)(None, None) + else: + mod_inst = getattr(loaded_mod, class_name)(None, None, None) + infos_mod = {} + infos_mod['imported'] = loaded_mod + infos_mod['class_name'] = getattr(mod_inst, 'get_name')() + infos_mod['compatible_os'] = getattr(mod_inst, 'get_compatible_os')() + infos_mod['block'] = getattr(mod_inst, 'get_block')() + infos_mod['unit'] = getattr(mod_inst, 'get_unit')() + infos_mod['external'] = False + self.loaded_mod_moni[mod_name] = infos_mod + except AttributeError: + print "Error : internal monitoring module " + mod_name + " could not have been loaded. " + + # Now for external modules: + sys.path.insert(0, self.external_mod_loc) # Adding the external diretory into pythonpath for importer, mod_name, ispkg in pkgutil.iter_modules([self.external_mod_loc]): if mod_name not in sys.modules: - loaded_mod = __import__(mod_name, fromlist=[mod_name]) - class_name = getattr(loaded_mod, "get_class_name")() - mod_inst = getattr(loaded_mod, class_name)(None, None, None) - infos_mod = {} - infos_mod['imported'] = loaded_mod - infos_mod['class_name'] = getattr(mod_inst, 'get_name')() - infos_mod['compatible_os'] = getattr(mod_inst, 'get_compatible_os')() - infos_mod['block'] = getattr(mod_inst, 'get_block')() - infos_mod['unit'] = getattr(mod_inst, 'get_unit')() - infos_mod['external'] = True - self.loaded_mod_infos[mod_name] = infos_mod - - - - """ - __import__("modules.monitoring_modules." + os) - pack_mod_os = __import__("modules.monitoring_modules." + os, fromlist=modules.monitoring_modules.__all__) - for mod_name in pack_mod_os.__all__: - mod = __import__("modules.monitoring_modules." + os + "." + mod_name, fromlist=modules.monitoring_modules.unix.__all__) # on charge le module - mod_instance = getattr(mod, mod_name)(conn, db, modules.ModuleNotCompatibleException) # on appelle le constructeur - try: - mod_instance.check() - except modules.ModuleNotCompatibleException.ModuleNotCompatibleException as mnce: - print mnce.__str__() - if ws is not None: - ws.send(json.dumps({"40": mnce.__str__()})) - except modules.CommandNotFoundException.CommandNotFoundException as cnfe: - print cnfe.__str__() - if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__()})) - """ + try: + loaded_mod = __import__(mod_name, fromlist=[mod_name]) + class_name = getattr(loaded_mod, "get_class_name")() + mod_inst = getattr(loaded_mod, class_name)(None, None, None) + infos_mod = {} + infos_mod['imported'] = loaded_mod + infos_mod['class_name'] = getattr(mod_inst, 'get_name')() + infos_mod['compatible_os'] = getattr(mod_inst, 'get_compatible_os')() + infos_mod['block'] = getattr(mod_inst, 'get_block')() + infos_mod['unit'] = getattr(mod_inst, 'get_unit')() + infos_mod['external'] = True + self.loaded_mod_moni[mod_name] = infos_mod + except AttributeError: + print "Error : external monitoring module " + mod_name + " could not have been loaded. " + print "Please verify that every necessary methods have been implemented." def run_one_monitoring_module(self, mod_name, addr_host, conn, db): """ @@ -163,42 +142,23 @@ class ModuleLoader: :param mod_name: the name of the monitoring_module to run :param conn: an instance of a connection module :param db: an instance of a storage module - :param ws: a websocket connection if the function have been called from a client. Is None otherwise """ if db is None: db = self.get_db() if mod_name == 'ping': - mod_inst = getattr(self.loaded_mod_infos[mod_name]['imported'], - self.loaded_mod_infos[mod_name]['class_name'])(db, addr_host) + mod_inst = getattr(self.loaded_mod_moni[mod_name]['imported'], + self.loaded_mod_moni[mod_name]['class_name'])(db, addr_host) mod_inst.check() else: - mod_inst = getattr(self.loaded_mod_infos[mod_name]['imported'], - self.loaded_mod_infos[mod_name]['class_name'])(conn, db, + mod_inst = getattr(self.loaded_mod_moni[mod_name]['imported'], + self.loaded_mod_moni[mod_name]['class_name'])(conn, db, modules.ModuleNotCompatibleException) - mod_inst.check() - """ - if conn is None: - if mod_name == 'ping': - # in this case, the connection have not been configurated yet, so we just launch a ping check - ping_mod = __import__("modules.monitoring_modules.ping", fromlist=modules.monitoring_modules.special_modules) - ping_mod_inst = getattr(ping_mod, "ping")(db, addr_host) - ping_mod_inst.check() - else: - conn = load_conn("ssh", addr_host, "aguilbaud", "/home/aguilbaud/.ssh/id_rsa") - __import__("modules.monitoring_modules." + os) - mod = __import__("modules.monitoring_modules." + os + "." + mod_name, fromlist=modules.monitoring_modules.unix.__all__) - mod_instance = getattr(mod, mod_name)(conn, db, modules.ModuleNotCompatibleException) # on appelle le constructeur - try: - mod_instance.check() - except modules.ModuleNotCompatibleException.ModuleNotCompatibleException as mnce: - print mnce.__str__() - if ws is not None: - ws.send(json.dumps({"40": mnce.__str__()})) - except modules.CommandNotFoundException.CommandNotFoundException as cnfe: - print cnfe.__str__() - if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__()})) - """ + try: + mod_inst.check() + except modules.ModuleNotCompatibleException.ModuleNotCompatibleException as mnce: + print mnce.__str__() + except modules.CommandNotFoundException.CommandNotFoundException as cnfe: + print cnfe.__str__() def get_info_mod_monitoring(self): """ @@ -217,7 +177,23 @@ class ModuleLoader: } } """ - return self.loaded_mod_infos + return self.loaded_mod_moni + + def load_all_connection_modules(self): + """ + Instanciates and stores the informations about each connection modules avaliable + on the loaded_mod_conn attribute + """ + for importer, mod_name, ispkg in pkgutil.iter_modules(["app/modules/connection_modules/"]): + if mod_name not in sys.modules: + loaded_mod = __import__("modules.connection_modules." + mod_name, fromlist=[mod_name]) + class_name = getattr(loaded_mod, "get_class_name")() + mod_inst = getattr(loaded_mod, class_name)(None, None, None) + infos_mod = {} + infos_mod['imported'] = loaded_mod + infos_mod['class_name'] = getattr(mod_inst, 'get_name')() + infos_mod['params'] = getattr(mod_inst, 'get_parameters')() + self.loaded_mod_conn[mod_name] = infos_mod def get_conection_modules_list(self): """ @@ -226,25 +202,23 @@ class ModuleLoader: :return: a list containing the names of the different connection modules declared on the __init__.py file of the connection_modules package. """ - pack_conn_os = __import__("modules.connection_modules", fromlist=modules.connection_modules.__all__) - return pack_conn_os.__all__ + return self.loaded_mod_conn def update_global_conf(self): """ Asks the database to update the configuration if new monitoring modules are added in function of the modules informations stored. """ - self.db.create_global_conf(self.loaded_mod_infos) + self.db.create_global_conf(self.loaded_mod_moni) - def get_all_monitoring_instructions(self, db): + def get_all_monitoring_instructions(self): """ runs on the database the function get_monitoring_instructions for all hosts under monitoring - :param db: the database to perform operation :return:the monitoring instructions for all hosts """ res = [] - for addr_host in db.get_list_addr_hosts(): - for instr in db.get_monitoring_instructions(addr_host): + for addr_host in self.db.get_list_addr_hosts(): + for instr in self.db.get_monitoring_instructions(addr_host): res.append(instr) return res diff --git a/app/modules/connection_modules/__init__.py b/app/modules/connection_modules/__init__.py index ef5647c..6ed406e 100644 --- a/app/modules/connection_modules/__init__.py +++ b/app/modules/connection_modules/__init__.py @@ -1,2 +1 @@ -__author__ = 'aguilbaud' -__all__ = ['ssh'] \ No newline at end of file +__author__ = 'aguilbaud' \ No newline at end of file diff --git a/app/modules/connection_modules/nagios.py b/app/modules/connection_modules/nagios.py deleted file mode 100644 index fcb43f2..0000000 --- a/app/modules/connection_modules/nagios.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'aguilbaud' diff --git a/app/modules/connection_modules/snmp.py b/app/modules/connection_modules/snmp.py deleted file mode 100644 index fcb43f2..0000000 --- a/app/modules/connection_modules/snmp.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'aguilbaud' diff --git a/app/modules/connection_modules/ssh.py b/app/modules/connection_modules/ssh.py index 74786cb..b407dc8 100644 --- a/app/modules/connection_modules/ssh.py +++ b/app/modules/connection_modules/ssh.py @@ -1,19 +1,32 @@ import paramiko -class ssh: +def get_class_name(): + return "SSH" - def __init__(self, addr_host, usrname, key_location, cnfe): - key = paramiko.RSAKey.from_private_key_file(key_location) # "/home/aguilbaud/.ssh/id_rsa" - self.ssh = paramiko.SSHClient() - self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.ssh.connect(addr_host, username=usrname, pkey=key) + +class SSH: + def __init__(self, addr_host, params, cnfe): + self.parameters = {"username": "string", "public_key": "file", "port": "int"} + self.name = get_class_name() self.addr_host = addr_host self.CommandNotFoundException = cnfe + if params is not None: + key = paramiko.RSAKey.from_private_key_file(params['public_key']) + self.ssh = paramiko.SSHClient() + self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.ssh.connect(addr_host, username=params['username'], pkey=key, port=params['port']) + + def get_name(self): + return self.name def get_addr_host(self): + # Called by monitoring modules return self.addr_host + def get_parameters(self): + return self.parameters + def exec_command(self, cmd): stdin, stdout, stderr = self.ssh.exec_command(cmd) out = stdout.read() diff --git a/app/modules/detection_modules/nmap_detection.py b/app/modules/detection_modules/nmap_detection.py index 4e78d7e..80216c9 100644 --- a/app/modules/detection_modules/nmap_detection.py +++ b/app/modules/detection_modules/nmap_detection.py @@ -158,10 +158,7 @@ class nmap_detection: state = port.getElementsByTagName('state')[0] service = port.getElementsByTagName('service')[0] if service.hasAttribute("ostype"): - if service.getAttribute("ostype").lower() == "linux": - dict_host['os'] = 'unix' - else: - dict_host['os'] = service.getAttribute("ostype").lower() + dict_host['os'] = service.getAttribute("ostype").lower() if state.getAttribute('state') == 'open': dict_port['portid'] = port.getAttribute('portid') dict_port['portname'] = service.getAttribute('name') diff --git a/app/modules/monitoring_modules/__init__.py b/app/modules/monitoring_modules/__init__.py index 30c04b0..6ed406e 100644 --- a/app/modules/monitoring_modules/__init__.py +++ b/app/modules/monitoring_modules/__init__.py @@ -1,2 +1 @@ -__author__ = 'aguilbaud' -special_modules = ['ping'] \ No newline at end of file +__author__ = 'aguilbaud' \ No newline at end of file diff --git a/app/modules/monitoring_modules/disk.py b/app/modules/monitoring_modules/disk.py index 57b3ba7..33ceec1 100644 --- a/app/modules/monitoring_modules/disk.py +++ b/app/modules/monitoring_modules/disk.py @@ -2,16 +2,15 @@ __author__ = 'aguilbaud' import re -""" -Check and returns the percentage of disk used ( = percentage of use of the partition mounted on /) -""" - def get_class_name(): return "Disk" class Disk: + """ + Check and returns the percentage of disk used ( = percentage of use of the partition mounted on /) + """ def __init__(self, conn, db, mnce): self.conn = conn self.db = db diff --git a/app/modules/monitoring_modules/memory.py b/app/modules/monitoring_modules/memory.py index 5c7f4cf..521fcf8 100644 --- a/app/modules/monitoring_modules/memory.py +++ b/app/modules/monitoring_modules/memory.py @@ -3,16 +3,14 @@ __author__ = 'aguilbaud' import re -""" -Check and returns the percentage of total memory used of the machine -""" - - def get_class_name(): return "Memory" class Memory: + """ + Check and returns the percentage of total memory used of the machine + """ def __init__(self, conn, db, mnce): self.conn = conn self.db = db diff --git a/app/modules/storage_modules/shelve_db.py b/app/modules/storage_modules/shelve_db.py index e8adf8e..1f739b6 100644 --- a/app/modules/storage_modules/shelve_db.py +++ b/app/modules/storage_modules/shelve_db.py @@ -62,7 +62,7 @@ class shelve_db: self.db["hosts"][addr_host]["detected"]["nmap"] = nmap_res # Preconfiguration self.db["hosts"][addr_host]["conf"] = {} - self.db["hosts"][addr_host]["conf"]["connections"] = {} #self.init_conn(json.loads(nmap_res), list_mod_conn) + self.db["hosts"][addr_host]["conf"]["connections"] = self.init_conn(json.loads(nmap_res), list_mod_conn) os_host = json.loads(nmap_res)['os'] self.db["hosts"][addr_host]["conf"]["monitoring"] = self.generate_global_conf(dict_mod_info, addr_host, os_host) @@ -79,6 +79,32 @@ class shelve_db: finally: self.close_db() + @staticmethod + def init_conn(dict_nmap_res, conn_list): + """ + Returns an initialization for the connection configuration on a host. + :param dict_nmap_res: The result of the nmap detection formatted to datastructures. + :param conn_list: A list of all connection modules avaliable + :return: + """ + dict_conn = {} + cpt = 1 + for port in dict_nmap_res['openports']: + if port["portname"] in conn_list: + dict_conn[port["portname"]] = { + "priority": cpt, + "portid": int(port["portid"]) + } + cpt += 1 + else: + dict_conn[port["portname"]] = { + "priority": 0, + "portid": None + } + dict_conn[port["portname"]]["login"] = None + dict_conn[port["portname"]]["key_couple"] = None + return dict_conn + def generate_global_conf(self, dict_mod_info, addr_host, os_host): """ Configures automatically the monitoring for a host for each of the monitoring modules avaliable, in @@ -141,23 +167,14 @@ class shelve_db: res['ping'] = ping_conf return res - def init_conn(self, dict_nmap_res, conn_list): - """ - Returns an initialization for the connection configuration on a host. - :param dict_nmap_res: The result of the nmap detection formatted to datastructures. - :param conn_list: A list of all connection modules avaliable - :return: - """ - dict_conn = {} - cpt = 1 - for port in dict_nmap_res['openports']: - if port["portname"] in conn_list: - dict_conn[port["portname"]] = { - "priority": cpt, - "portid": int(port["portid"]), - } - cpt += 1 - return dict_conn + def get_conn_param(self, addr_host): + self.open_db() + res = None + try: + res = self.db['hosts'][addr_host]['conf']['connections'] + finally: + self.close_db() + return res def get_monitoring_instructions(self, addr_host): """ @@ -620,8 +637,6 @@ class shelve_db: os = detected['os'].lower() if os == "Unknown": raise Exception('Os not detected') - if os == "linux": - os = "unix" return os finally: self.close_db() \ No newline at end of file -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit 2231aed98bbc6c0ce773fc60b475d49c64c5ff69 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 17:03:37 2015 +0100 code d'instruction websocket devenus textuels --- app/app.py | 38 +++++------------ app/module_loader.py | 45 ++++++++++++-------- app/modules/detection_modules/nmap_detection.py | 12 +++--- .../notification_modules/websocket_container.py | 2 +- app/modules/storage_modules/shelve_db.py | 48 +++++++++++++--------- static/js/controllers/headCtrl.js | 18 ++++---- static/js/controllers/hostPageCtrl.js | 48 +++++++++++++++++++--- static/js/controllers/scanCtrl.js | 2 +- views/hostpage.html | 26 +++--------- 9 files changed, 132 insertions(+), 107 deletions(-) diff --git a/app/app.py b/app/app.py index 2d6d636..eeb595d 100755 --- a/app/app.py +++ b/app/app.py @@ -11,23 +11,6 @@ from module_loader import ModuleLoader import process_monitoring from modules.notification_modules.websocket_container import WebSocketContainer -NMAP_SCAN_DEMAND = "10" -DETECTION_DEMAND = "11" -MONITORING_DEMAND = "12" -HOST_INFO_DEMAND = "13" -GET_HOSTS_DEMAND = "14" -CALL_FUNC_DB = "15" - -SUCCESS_MODULE = "20" -INFO_HOST = "21" -GET_HOSTS_RESPONSE = "22" -RES_CALL_FUNC_DB = "23" - -CURRENT_STATE_INFO = "30" -BROWSER_NOTIFICATION = "31" - -ERROR = "40" - wsc = None ml = None @@ -46,7 +29,7 @@ class ThreadDetect(threading.Thread): self.ml.get_conection_modules_list(), self.ml.get_info_mod_monitoring()) if scanned_ip is not None: - self.ws.send(json.dumps({SUCCESS_MODULE: scanned_ip})) + self.ws.send(json.dumps({"SUCCESS_MODULE": scanned_ip})) for ip in json.loads(scanned_ip): monitoring_intructions = db.get_monitoring_instructions(ip) for instr in monitoring_intructions: @@ -142,18 +125,19 @@ def receive(ws): if response is not None: msg = json.loads(response) for code in msg: - if code == NMAP_SCAN_DEMAND: - start_first_detection(msg[NMAP_SCAN_DEMAND], ml, ws) - elif code == GET_HOSTS_DEMAND: + if code == "NMAP_SCAN_DEMAND": + start_first_detection(msg["NMAP_SCAN_DEMAND"], ml, ws) + elif code == "GET_HOSTS": db = ml.get_db() - ws.send(json.dumps({GET_HOSTS_RESPONSE: db.get_hosts()})) - elif code == HOST_INFO_DEMAND: + ws.send(json.dumps({"RES_GET_HOSTS": db.get_hosts()})) + elif code == "GET_HOST_INFO": db = ml.get_db() - ws.send(json.dumps({INFO_HOST: db.get_host_informations(msg[HOST_INFO_DEMAND])})) - elif code == CALL_FUNC_DB: - res = ml.launch_db_function(msg[CALL_FUNC_DB]) + ws.send(json.dumps({"RES_INFO_HOST": db.get_host_informations(msg["GET_HOST_INFO"])})) + elif code == "CALL_FUNC_DB": + res = ml.launch_db_function(msg["CALL_FUNC_DB"]) if res is not None: - ws.send(json.dumps({RES_CALL_FUNC_DB: res})) + print res + ws.send(json.dumps({"RES_CALL_FUNC_DB": res})) else: print 'res is None' else: diff --git a/app/module_loader.py b/app/module_loader.py index 92bf62b..57ae88b 100644 --- a/app/module_loader.py +++ b/app/module_loader.py @@ -66,7 +66,7 @@ class ModuleLoader: return ip_range except modules.HostNotFoundException.HostNotFoundException as hnfe: print hnfe.__str__() - ws.send(json.dumps({"40": hnfe.__str__()})) + ws.send(json.dumps({"ERROR": hnfe.__str__()})) return None def run_all_detection_modules(self, os, conn, db, ws): @@ -88,7 +88,7 @@ class ModuleLoader: except modules.CommandNotFoundException.CommandNotFoundException as cnfe: print cnfe.__str__() if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__()})) + ws.send(json.dumps({"ERROR": cnfe.__str__()})) def load_all_monitoring_modules(self): """ @@ -163,13 +163,13 @@ class ModuleLoader: def get_info_mod_monitoring(self): """ Get information about the output, block, compatible os and class name of the monitoring modules. - These informations must be specified on each modules, and are loaded at the launch of the application with - the + These informations must be specified on each modules, and must be loaded at the launch of the application. :return: a dictionary containing these informations on the form : { mod_name: { 'class_name': val, => the name of the class to instanciate + 'imported': module => the module imported 'compatible_os': [val1, val2, ...], => a list containing the compatibles os 'unit': val, => the unit type of return ('%', 'bool' or other) 'block': val, => the monitoring block of the module @@ -182,25 +182,36 @@ class ModuleLoader: def load_all_connection_modules(self): """ Instanciates and stores the informations about each connection modules avaliable - on the loaded_mod_conn attribute + on the loaded_mod_conn attribute. """ for importer, mod_name, ispkg in pkgutil.iter_modules(["app/modules/connection_modules/"]): if mod_name not in sys.modules: - loaded_mod = __import__("modules.connection_modules." + mod_name, fromlist=[mod_name]) - class_name = getattr(loaded_mod, "get_class_name")() - mod_inst = getattr(loaded_mod, class_name)(None, None, None) - infos_mod = {} - infos_mod['imported'] = loaded_mod - infos_mod['class_name'] = getattr(mod_inst, 'get_name')() - infos_mod['params'] = getattr(mod_inst, 'get_parameters')() - self.loaded_mod_conn[mod_name] = infos_mod + try: + loaded_mod = __import__("modules.connection_modules." + mod_name, fromlist=[mod_name]) + class_name = getattr(loaded_mod, "get_class_name")() + mod_inst = getattr(loaded_mod, class_name)(None, None, None) + infos_mod = {} + infos_mod['imported'] = loaded_mod + infos_mod['class_name'] = getattr(mod_inst, 'get_name')() + infos_mod['params'] = getattr(mod_inst, 'get_parameters')() + self.loaded_mod_conn[mod_name] = infos_mod + except AttributeError: + print "Error : internal connection module " + mod_name + " could not have been loaded. " def get_conection_modules_list(self): """ - Get a list containing the names of the different connection modules declared on the __init__.py file - of the connection_modules package. - :return: a list containing the names of the different connection modules declared on the __init__.py file - of the connection_modules package. + Get informations about of the connection modules loaded and their parameters necessary to instanciate the + connection. The type of the parameters is necessary for the web application in order to show a corresponding + form (can be 'string' for a textfield, 'int' for a number field, 'file' for a file location). + :return: a dictionary containing these informations on the form : + { + mod_name: + { + 'class_name': val, => the name of the class to instanciate + 'imported': module, => the module imported + 'params': {param1: type1, param2: type2, ...} => the parameters necessary to create the connection + } + } """ return self.loaded_mod_conn diff --git a/app/modules/detection_modules/nmap_detection.py b/app/modules/detection_modules/nmap_detection.py index 80216c9..1d6d84c 100644 --- a/app/modules/detection_modules/nmap_detection.py +++ b/app/modules/detection_modules/nmap_detection.py @@ -86,7 +86,7 @@ class nmap_detection: # launch the nmap detection for the IP adress represented by the 4 bytes in parameters def launch_detection(self, byte_1, byte_2, byte_3, byte_4): ip = str(byte_1) + '.' + str(byte_2) + '.' + str(byte_3) + '.' + str(byte_4) - self.ws.send(json.dumps({"30": "Scanning ip : " + ip})) + self.ws.send(json.dumps({"CURRENT_STATE_INFO": "Scanning ip : " + ip})) try: child = pexpect.spawn('nmap ' + self.opt + ' ' + ip + ' -oX ' + self.filename) while child.isalive(): @@ -97,12 +97,12 @@ class nmap_detection: #except: # self.ws.send(json.dumps({"40": "Database error"})) except pexpect.TIMEOUT: - self.ws.send(json.dumps({"40": "Timeout on nmap execution"})) + self.ws.send(json.dumps({"ERROR": "Timeout on nmap execution"})) except pexpect.ExceptionPexpect: - self.ws.send(json.dumps({"40": "nmap command not avaliable on server"})) + self.ws.send(json.dumps({"ERROR": "nmap command not avaliable on server"})) def launch_detection_with_hostname(self, hostname): - self.ws.send(json.dumps({"30": "Scanning host : " + hostname})) + self.ws.send(json.dumps({"CURRENT_STATE_INFO": "Scanning host : " + hostname})) try: child = pexpect.spawn('nmap ' + self.opt + ' ' + hostname + ' -oX ' + self.filename) while child.isalive(): @@ -114,9 +114,9 @@ class nmap_detection: #except: # self.ws.send(json.dumps({"40": "Database error"})) except pexpect.TIMEOUT: - self.ws.send(json.dumps({"40": "Timeout on nmap execution"})) + self.ws.send(json.dumps({"ERROR": "Timeout on nmap execution"})) except pexpect.ExceptionPexpect: - self.ws.send(json.dumps({"40": "nmap command not avaliable on server"})) + self.ws.send(json.dumps({"ERROR": "nmap command not avaliable on server"})) # parse the xml result to keep only interesting values # save directly it on the database diff --git a/app/modules/notification_modules/websocket_container.py b/app/modules/notification_modules/websocket_container.py index 15c5c04..28dce07 100644 --- a/app/modules/notification_modules/websocket_container.py +++ b/app/modules/notification_modules/websocket_container.py @@ -16,4 +16,4 @@ class WebSocketContainer: def notify_state_change(self): for ws in self.ws_set: - ws.send(json.dumps({"22": self.db.get_hosts()})) \ No newline at end of file + ws.send(json.dumps({"RES_HOST_DEMAND": self.db.get_hosts()})) \ No newline at end of file diff --git a/app/modules/storage_modules/shelve_db.py b/app/modules/storage_modules/shelve_db.py index 1f739b6..cb1f914 100644 --- a/app/modules/storage_modules/shelve_db.py +++ b/app/modules/storage_modules/shelve_db.py @@ -62,10 +62,11 @@ class shelve_db: self.db["hosts"][addr_host]["detected"]["nmap"] = nmap_res # Preconfiguration self.db["hosts"][addr_host]["conf"] = {} - self.db["hosts"][addr_host]["conf"]["connections"] = self.init_conn(json.loads(nmap_res), list_mod_conn) - os_host = json.loads(nmap_res)['os'] + nmap_res_data = json.loads(nmap_res) + self.db["hosts"][addr_host]["conf"]["connections"] = self.init_conn(nmap_res_data, list_mod_conn) self.db["hosts"][addr_host]["conf"]["monitoring"] = self.generate_global_conf(dict_mod_info, - addr_host, os_host) + addr_host, + nmap_res_data['os']) self.db["hosts"][addr_host]["conf"]["groups"] = ["all"] # Every host is in group "all" self.db["hosts"][addr_host]["conf"]["subscribers"] = {} # Add current user automatically ? self.db["hosts"][addr_host]["conf"]["custom_info"] = "" @@ -80,29 +81,27 @@ class shelve_db: self.close_db() @staticmethod - def init_conn(dict_nmap_res, conn_list): + def init_conn(dict_nmap_res, conn_infos): """ Returns an initialization for the connection configuration on a host. - :param dict_nmap_res: The result of the nmap detection formatted to datastructures. - :param conn_list: A list of all connection modules avaliable + :param dict_nmap_res: The result of the nmap detection in dictionnary form + :param conn_infos: A dictionnary containing informations about connection modules in the form : + { + mod_name: { + 'params': {param1: type1, param2: type2, ...} + } + } :return: """ dict_conn = {} - cpt = 1 for port in dict_nmap_res['openports']: - if port["portname"] in conn_list: - dict_conn[port["portname"]] = { - "priority": cpt, - "portid": int(port["portid"]) - } - cpt += 1 - else: + if port["portname"] in conn_infos: dict_conn[port["portname"]] = { "priority": 0, - "portid": None + "portid": int(port["portid"]) } - dict_conn[port["portname"]]["login"] = None - dict_conn[port["portname"]]["key_couple"] = None + for param in conn_infos[port["portname"]]['params']: + dict_conn[port["portname"]][param] = None return dict_conn def generate_global_conf(self, dict_mod_info, addr_host, os_host): @@ -167,14 +166,23 @@ class shelve_db: res['ping'] = ping_conf return res - def get_conn_param(self, addr_host): + def get_conn_param(self, args): + """ + Returns the connection parameters of an host. + :param args: A dictionnary containing : + {'addr_host': val} + :return: The connection parameters in the form: + mod_name: { + {param1: val1, param2: val2, ...} + } + """ self.open_db() res = None try: - res = self.db['hosts'][addr_host]['conf']['connections'] + res = self.db['hosts'][args['addr_host']]['conf']['connections'] finally: self.close_db() - return res + return json.dumps(res) def get_monitoring_instructions(self, addr_host): """ diff --git a/static/js/controllers/headCtrl.js b/static/js/controllers/headCtrl.js index 1a1e748..e8aeb8d 100644 --- a/static/js/controllers/headCtrl.js +++ b/static/js/controllers/headCtrl.js @@ -13,7 +13,7 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r var ws = new WebSocket("ws://" + $location.host() + ":1337/websocket"); ws.onopen = function() { - var request = '{"14" : ""}'; + var request = JSON.stringify({"GET_HOSTS": ""}); ws.send(request); }; @@ -25,24 +25,24 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r ws.onmessage = function (evt) { // actions effectuees lors de la reception d'un message via la websocket JSON.parse(evt.data, function (key, value) { - switch(parseInt(key)){ - case 20: // Success of a module execution + switch(key){ + case "SUCCESS_MODULE": // Success of a module execution $rootScope.$broadcast("success", value); toastr.success(value, "Success on module execution"); - case 21: // Informations concerning one host + case "RES_INFO_HOST": // Informations concerning one host $rootScope.$broadcast("hostInfos", JSON.parse(value)); break; - case 22: // List of hosts under monitoring + case "RES_GET_HOSTS": // List of hosts under monitoring DataHosts.Items = JSON.parse(value); $rootScope.$broadcast("hostsUpdate"); $scope.$apply(function(){ $scope.items = DataHosts.Items; }); break; - case 23: // Get a result after calling a funcion on the db + case "RES_CALL_FUNC_DB": // Get a result after calling a funcion on the db $rootScope.$broadcast("resCall", JSON.parse(value)); break; - case 30: + case "CURRENT_STATE_INFO": $scope.$apply(function(){ $scope.state = value; }); @@ -53,7 +53,7 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r $scope.state = value });*/ break; - case 31: + case "BROWSER_NOTIFICATION": params = value.split(','); if(params[0]=='success'){ $scope.pop_success("Success on " + params[1], params[2]); @@ -65,7 +65,7 @@ mumApp.controller('headCtrl', function($scope, $rootScope, toastr, $interval, $r $scope.pop_danger("Danger on "+ params[1], params[2]); } break; - case 40: + case "ERROR": toastr.error(value, "Server error"); break; default: diff --git a/static/js/controllers/hostPageCtrl.js b/static/js/controllers/hostPageCtrl.js index 5ad0fa2..0c915fd 100644 --- a/static/js/controllers/hostPageCtrl.js +++ b/static/js/controllers/hostPageCtrl.js @@ -3,7 +3,7 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo $scope.addr_host = $routeParams.param // asks for host informations - $rootScope.$broadcast("sendViaWs", JSON.stringify({"13": $routeParams.param})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"GET_HOST_INFO": $routeParams.param})); $scope.items = [];/* result of get_host_informations => { @@ -52,7 +52,7 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo var args = {}; args.addr_host = $scope.addr_host; args.txt = $scope.model.custom_infos; - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'update_custom_informations', 'args': args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'update_custom_informations', 'args': args}})); }; // creation of modals @@ -79,6 +79,18 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo } }); }; + + $scope.open_modal_conn = function () { + var modalInstance = $modal.open({ + templateUrl: 'modal_conn_label.html', + controller: 'ModalConnInstanceCtrl', + resolve: { + conn_args: function(){ + return {'addr_host' : $scope.addr_host}; + } + } + }); + }; }); // modals controllers @@ -86,7 +98,7 @@ mumApp.controller('hostPageCtrl', function($scope, $rootScope, $routeParams, $mo mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalInstance, conf_args) { $scope.conf_args = conf_args; // {'addr_host' : val, 'mod_name', val} - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'get_conf_mod', 'args': conf_args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'get_conf_mod', 'args': conf_args}})); $scope.items = {} /* { 'unit' : val, // the unit of the value @@ -146,7 +158,7 @@ mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalI args.minor_limit = $scope.minor_limit_unit; args.major_limit = $scope.major_limit_unit; } - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'set_conf_mod', 'args': args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'set_conf_mod', 'args': args}})); $modalInstance.close(); }; @@ -170,7 +182,33 @@ mumApp.controller('ModalIntervInstanceCtrl', function ($scope, $rootScope, $moda args.date = $scope.date; args.details = $scope.details; - $rootScope.$broadcast("sendViaWs", JSON.stringify({"15": {'func': 'add_intervention', 'args': args}})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'add_intervention', 'args': args}})); + + $modalInstance.close(); + }; + + $scope.cancel = function () { + $modalInstance.close(); + }; +}); + +mumApp.controller('ModalConnInstanceCtrl', function ($scope, $rootScope, $modalInstance, conn_args) { + $scope.conn_args = conn_args; // {'addr_host' : val} + + $scope.current_config = {}; + + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'get_conn_param','args': {'addr_host': $scope.conn_args['addr_host']}}})); + + // when the configuration of the connection is received + $scope.$on("resCall", function (event, args) { + $scope.$apply(function(){ + $scope.current_config = args; + }); + }); + + $scope.ok = function () { + var args = {}; + $modalInstance.close(); }; diff --git a/static/js/controllers/scanCtrl.js b/static/js/controllers/scanCtrl.js index 43d810b..7c2b0ce 100644 --- a/static/js/controllers/scanCtrl.js +++ b/static/js/controllers/scanCtrl.js @@ -24,6 +24,6 @@ mumApp.controller('scanCtrl', function($scope, $rootScope) { var args = {}; args.ip_range = $scope.ip_range; args.nmap_options = $scope.nmap_options; - $rootScope.$broadcast("sendViaWs", JSON.stringify({"10": args})); + $rootScope.$broadcast("sendViaWs", JSON.stringify({"NMAP_SCAN_DEMAND": args})); }; }); \ No newline at end of file diff --git a/views/hostpage.html b/views/hostpage.html index 6010696..6a24b18 100644 --- a/views/hostpage.html +++ b/views/hostpage.html @@ -2,7 +2,7 @@ <div class="col-md-offset-2 main"> <h1 class="page-header">Current state of {{addr_host}} <small>{{items.hostname}}</small></h1> <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#modal_block">Activate/Deactivate</button> - <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#modal_conn">Connection settings</button> + <button type="button" class="btn btn-primary btn-xs" ng-click="open_modal_conn()">Connection settings</button> <button type="button" class="btn btn-info btn-xs">Launch a new detection</button> <button type="button" class="btn btn-danger btn-xs" ng-click="call_func('remove_host', [addr_host])">Remove this host</button> <table class="table table-condensed table-hover"> @@ -146,6 +146,7 @@ <h3 class="modal-title">Connection configuration</h3> </div> <div class="modal-body"> + {{current_config}} <form> <div class="form-group"> <h3>Choose the priority of each avaliable connection</h3> @@ -158,32 +159,15 @@ </tr> </thead> <tbody> - <tr> - <td>SSH</td> - <td><input type="number" min="0" placeholder=1></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - - </tr> - <tr> - <td>SNMP</td> - <td><input type="number" min="0" placeholder=0 disabled></td> + <tr ng-repeat="(modname, modconf) in current_config"> + <td>{{modname}}</td> + <td><input type="number" min="0" ng-model="prio_{{modname}}"></td> <td> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> <button type="button" class="btn btn-success">Test</button> </td> </tr> - <tr> - <td>Nagios</td> - <td><input type="number" min="0" placeholder=0 disabled></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - </tr> </tbody> </table> </div> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit 61c296b19fc612d72ba25919739d857e3dcc94f2 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Mon Mar 9 17:24:00 2015 +0100 hostpage : modal des priorités de connection => OK --- static/js/controllers/hostPageCtrl.js | 15 +++++++++ views/hostpage.html | 62 ++--------------------------------- 2 files changed, 17 insertions(+), 60 deletions(-) diff --git a/static/js/controllers/hostPageCtrl.js b/static/js/controllers/hostPageCtrl.js index 0c915fd..b49ef66 100644 --- a/static/js/controllers/hostPageCtrl.js +++ b/static/js/controllers/hostPageCtrl.js @@ -197,12 +197,27 @@ mumApp.controller('ModalConnInstanceCtrl', function ($scope, $rootScope, $modalI $scope.current_config = {}; + $scope.priorities = {}; + + $scope.isNotConfigured = function(modname){ + res = false; + for(param in $scope.current_config[modname]){ + if($scope.current_config[modname][param] == null){ + res = true; + } + } + return res; + } + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'get_conn_param','args': {'addr_host': $scope.conn_args['addr_host']}}})); // when the configuration of the connection is received $scope.$on("resCall", function (event, args) { $scope.$apply(function(){ $scope.current_config = args; + for(mod in args){ + $scope.priorities[mod] = args[mod]['priority'] + } }); }); diff --git a/views/hostpage.html b/views/hostpage.html index 6a24b18..3e2c553 100644 --- a/views/hostpage.html +++ b/views/hostpage.html @@ -147,6 +147,7 @@ </div> <div class="modal-body"> {{current_config}} + {{priorities}} <form> <div class="form-group"> <h3>Choose the priority of each avaliable connection</h3> @@ -161,7 +162,7 @@ <tbody> <tr ng-repeat="(modname, modconf) in current_config"> <td>{{modname}}</td> - <td><input type="number" min="0" ng-model="prio_{{modname}}"></td> + <td><input type="number" min="0" ng-model="priorities[modname]" disabled="{{isNotConfigured(modname)}}"></td> <td> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> <button type="button" class="btn btn-success">Test</button> @@ -180,65 +181,6 @@ </script> <!-- - <div class="modal fade" id="modal_conn" tabindex="-1" role="dialog" aria-labelledby="modal_conn_label" aria-hidden="true"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> - <h4 class="modal-title" id="modal_conn_label">Connection configuration</h4> - </div> - <div class="modal-body"> - <form> - <div class="form-group"> - <h3>Choose the priority of each avaliable connection</h3> - <table class="table table-bordered table-hover"> - <thead> - <tr> - <th>Protocol </th> - <th>Priority </th> - <th>Options </th> - </tr> - </thead> - <tbody> - <tr> - <td>SSH</td> - <td><input type="number" min="0" placeholder=1></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - - </tr> - <tr> - <td>SNMP</td> - <td><input type="number" min="0" placeholder=0 disabled></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - - </tr> - <tr> - <td>Nagios</td> - <td><input type="number" min="0" placeholder=0 disabled></td> - <td> - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#modal_conf_conn">Advanced configuration</button> - <button type="button" class="btn btn-success">Test</button> - </td> - </tr> - </tbody> - </table> - </div> - </form> - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> - <button type="button" class="btn btn-primary">Save changes</button> - </div> - </div> - </div> - </div> - <div class="modal fade bs-example-modal-lg" id="modal_conf_conn" tabindex="-1" role="dialog" aria-labelledby="modal_conf_conn_label" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
participants (1)
-
chorem.org scm