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 0fc4ad018c8a33a0907c5b888784ee4c9d418fc3 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Fri Jul 10 17:42:08 2015 +0200 hostpage : selection of subparts to monitore on modal configuration for the module. + added "see modules currently loaded" option. + filters on dashboard for every view . + log in file if error 500 occures. --- README | 2 +- app/module_loader.py | 3 + app/modules/connection_modules/ssh.py | 2 +- app/modules/monitoring_modules/disk_snmp_linux.py | 3 + app/modules/monitoring_modules/disk_ssh_linux.py | 4 + app/modules/monitoring_modules/memory_ssh_linux.py | 2 +- app/modules/storage_modules/shelve_db.py | 18 +++++ app/mum.py | 13 ++-- app/websocket_func.py | 19 ++++- static/js/controllers/headCtrl.js | 31 +++++++- static/js/controllers/hostPageCtrl.js | 89 +++++++++++++++------- views/dashboard.html | 34 +++++++++ views/hostpage.html | 46 +++++------ views/index.html | 23 +++++- 14 files changed, 223 insertions(+), 66 deletions(-) diff --git a/README b/README index a83d94c..00c4b3f 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ ------------ -Installation +Installation from the sources ------------ Get the sources: - git clone https://git.chorem.org/mum.git diff --git a/app/module_loader.py b/app/module_loader.py index 1ceeb73..787f770 100644 --- a/app/module_loader.py +++ b/app/module_loader.py @@ -243,6 +243,9 @@ class ModuleLoader: self.logger.warning("Error : internal detection module " + mod_name + " could not have been loaded.") self.logger.debug(traceback.format_exc()) + def get_loaded_detection_modules(self): + return self.loaded_mod_detect + def run_all_detection_modules(self, addr_host): """ Instanciates and runs the run_detection() method from each detection modules loaded on loaded_mod_detect diff --git a/app/modules/connection_modules/ssh.py b/app/modules/connection_modules/ssh.py index c24490b..2bec2c6 100644 --- a/app/modules/connection_modules/ssh.py +++ b/app/modules/connection_modules/ssh.py @@ -35,7 +35,7 @@ class SSH: key_path = str(key_loc) + str(params['private_key']) key = paramiko.RSAKey.from_private_key_file(key_path) - if params['password'] == "": + if 'password' not in params or params['password'] == "": params['password'] = None self.ssh = paramiko.SSHClient() diff --git a/app/modules/monitoring_modules/disk_snmp_linux.py b/app/modules/monitoring_modules/disk_snmp_linux.py index 6c7576f..44352cb 100644 --- a/app/modules/monitoring_modules/disk_snmp_linux.py +++ b/app/modules/monitoring_modules/disk_snmp_linux.py @@ -25,6 +25,9 @@ name = "Disk SNMP" unit = "%" connection = "snmp_walk" +param = { + "Disk": {'type': 'detection', 'value': ['/'], 'doc': "The partitions to verify"} +} def check(conn, mnce, subparts): res_check = {} diff --git a/app/modules/monitoring_modules/disk_ssh_linux.py b/app/modules/monitoring_modules/disk_ssh_linux.py index 74895c6..7e6d016 100644 --- a/app/modules/monitoring_modules/disk_ssh_linux.py +++ b/app/modules/monitoring_modules/disk_ssh_linux.py @@ -28,6 +28,10 @@ name = "Disk SSH" unit = "%" connection = "ssh" +# if detection, name must be the SAME as the name of the part attribute on the detection module +param = { + "Disk": {'type': 'detection', 'value': ['/'], 'doc': "The partitions to verify"} +} def check(conn, mnce, subparts): cmd = "df -h" diff --git a/app/modules/monitoring_modules/memory_ssh_linux.py b/app/modules/monitoring_modules/memory_ssh_linux.py index 82b6c7c..986e678 100644 --- a/app/modules/monitoring_modules/memory_ssh_linux.py +++ b/app/modules/monitoring_modules/memory_ssh_linux.py @@ -53,7 +53,7 @@ def check(conn, mnce, subparts): memfree = re.sub("[^0-9]", "", tab_res[1]) memused = int(memtotal) - int(memfree) - if memused == 0: + if memused <= 0: exception_inst = getattr(mnce, "ModuleNotCompatibleException")( part, conn.get_addr_host() ) diff --git a/app/modules/storage_modules/shelve_db.py b/app/modules/storage_modules/shelve_db.py index ab78bf8..0143b76 100644 --- a/app/modules/storage_modules/shelve_db.py +++ b/app/modules/storage_modules/shelve_db.py @@ -504,6 +504,7 @@ class shelve_db: info_host["warning"] = [] info_host["danger"] = [] info_host["success"] = [] + info_host["partial_subscribers"] = False for mod in self.db["hosts"][host]["monitoring"]: if self.db["hosts"][host]["monitoring"][mod]["state"] == "warning": info_host["warning"].append(mod) @@ -511,6 +512,10 @@ class shelve_db: info_host["danger"].append(mod) else: info_host["success"].append(mod) + + if 'subscribers' in self.db["hosts"][host]["monitoring"][mod] and \ + len(self.db["hosts"][host]["monitoring"][mod]["subscribers"].keys()) > 0: + info_host["partial_subscribers"] = True info_host['nb_subscribers'] = len(self.db['hosts'][host]['conf']['subscribers'].keys()) info_host['subscribers'] = self.db['hosts'][host]['conf']['subscribers'] info_host['display_name'] = self.db['hosts'][host]['conf']['display_name'] @@ -830,6 +835,19 @@ class shelve_db: finally: self.close_db() return dict_instr + """ + @staticmethod + def get_lastest_instance_number(mod_list, mod_name): + instances_keys = [] + for instance_id in mod_list: + if re.sub('[0-9]+$', '', instance_id) == mod_name: + str_id = re.sub('^.*_', '', instance_id) + instances_keys.append(int(str_id)) + if instances_keys == []: + return 0 + else: + return max(instances_keys) + """ def get_conf_mod(self, args): """ diff --git a/app/mum.py b/app/mum.py index 7dc6b4b..41d441c 100755 --- a/app/mum.py +++ b/app/mum.py @@ -68,11 +68,6 @@ def angular(): def angular(): return template('users') -@error(404) -def error404(error): - return '<h1>Cette page n\'existe pas</h1>' - - # To get static files @get('/static/<filepath:path>') def static(filepath): @@ -114,6 +109,14 @@ def do_upload(): except IOError: return 'This file already exists. <a href="/">Back to dashboard.</a>' +@error(500) +def handle_500_error(error_obj): + logger = logging.getLogger("mum_log") + logger.error("Error 500.") + logger.error(error_obj.body) + logger.error(error_obj.traceback) + return "Error 500 "+ error_obj.body + " (see the log for traceback)" + def create_logger(dict_conf): logger = logging.getLogger("mum_log") level = getattr(logging, dict_conf["log_level"]) diff --git a/app/websocket_func.py b/app/websocket_func.py index 5f8de81..ac12441 100644 --- a/app/websocket_func.py +++ b/app/websocket_func.py @@ -173,4 +173,21 @@ def GET_SCAN_OPTIONS(msg, ws, ml): def GET_LOGS(msg, ws, ml): log_size = msg['GET_LOGS'] - ws.send(json.dumps({'RES_GET_LOGS': ml.get_logs(log_size)})) \ No newline at end of file + ws.send(json.dumps({'RES_GET_LOGS': ml.get_logs(log_size)})) + + +def GET_ALL_MODULES_LIST(msg, ws, ml): + res = {} + res['monitoring'] = [] + res['connection'] = [] + res['detection'] = [] + res['notification'] = [] + for moni_mod in ml.get_info_mod_monitoring(): + res['monitoring'].append(moni_mod) + for conn_mod in ml.get_conection_modules_list(): + res['connection'].append(conn_mod) + for detect_mod in ml.get_loaded_detection_modules(): + res['detection'].append(detect_mod) + for notif_mod in ml.get_info_mod_notification(): + res['notification'].append(notif_mod) + ws.send(json.dumps({'RES_GET_ALL_MODULES_LIST': res})) \ No newline at end of file diff --git a/static/js/controllers/headCtrl.js b/static/js/controllers/headCtrl.js index 37e8c7a..5594f31 100644 --- a/static/js/controllers/headCtrl.js +++ b/static/js/controllers/headCtrl.js @@ -117,6 +117,9 @@ mumApp.controller('headCtrl', function ($scope, $rootScope, toastr, $interval, $ $scope.pop_danger("Connection test", "The connection could not have been established. Please verify its configuration."); } break; + case "RES_GET_ALL_MODULES_LIST": + $rootScope.$broadcast("resGetAllModulesList", obj[key]); + break; case "CURRENT_STATE_INFO": $scope.$apply(function(){ $scope.state = obj[key]; @@ -206,6 +209,14 @@ mumApp.controller('headCtrl', function ($scope, $rootScope, toastr, $interval, $ }); }; + $scope.open_modal_mod_list = function () { + var modalInstance = $modal.open({ + templateUrl: 'modal_modules_list.html', + controller: 'ModalModulesListCtrl', + size: 'lg' + }); + }; + }); mumApp.controller('ModalNotifInstanceCtrl', function ($scope, $rootScope, $modalInstance, $route, $timeout, notif_args) { @@ -362,4 +373,22 @@ mumApp.controller('ModalLogInstanceCtrl', function ($scope, $rootScope, $modalIn $scope.close = function () { $modalInstance.close(); }; -}); \ No newline at end of file +}); + +mumApp.controller('ModalModulesListCtrl', function ($scope, $rootScope, $modalInstance, $route, $timeout) { + $scope.modules_struct = {} /* {'monitoring': [...], + ... + */ + + $rootScope.$broadcast("sendViaWs", JSON.stringify({"GET_ALL_MODULES_LIST": null})); + + $scope.$on("resGetAllModulesList", function (event, args) { + $timeout(function () { + $scope.modules_struct = args; + }, 0); + }); + + $scope.close = function () { + $modalInstance.close(); + }; +}); diff --git a/static/js/controllers/hostPageCtrl.js b/static/js/controllers/hostPageCtrl.js index ca2a81e..651f517 100644 --- a/static/js/controllers/hostPageCtrl.js +++ b/static/js/controllers/hostPageCtrl.js @@ -63,13 +63,15 @@ mumApp.controller('hostPageCtrl', function ($scope, $rootScope, $route, $routePa 'compatible_conn': [val1, ...] => a list of connection modules } } + "subparts":{ + modname: [...], + ... + } } */ $scope.collapsed = {}; - $scope.subparts_checked = {}; - $scope.show_display_name_input = false; $scope.selectedAll = false; @@ -116,26 +118,6 @@ mumApp.controller('hostPageCtrl', function ($scope, $rootScope, $route, $routePa args['addr_host'] = $scope.addr_host; args['display_name'] = $scope.items.display_name; $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'change_display_name', 'args': args}})); - } - - $scope.save_subpart = function (modname) { - var args = {}; - args['addr_host'] = $scope.addr_host; - args['modname'] = modname; - args['subpart_list'] = []; - for (key in $scope.subparts_checked[modname]) { - if ($scope.subparts_checked[modname][key]) { - args['subpart_list'].push(key); - } - } - $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'set_subpart', 'args': args}})); - }; - - $scope.checkAll = function (modname, bool) { - $scope.selectedAll = bool; - for(key in $scope.subparts_checked[modname]) { - $scope.subparts_checked[modname][key] = bool; - } }; $scope.get_unit = function (mod_name) { @@ -226,10 +208,6 @@ mumApp.controller('hostPageCtrl', function ($scope, $rootScope, $route, $routePa $scope.model['compatible_os_list'] = args['compatible_os_list']; for (var modname in args.monitoring) { $scope.collapsed[modname] = true; - $scope.subparts_checked[modname] = {} - for (var key in args.detected[modname]) { - $scope.subparts_checked[modname][args.detected[modname][key]] = args.subparts[modname].hasOwnProperty(key); - } } } @@ -293,7 +271,11 @@ mumApp.controller('hostPageCtrl', function ($scope, $rootScope, $route, $routePa controller: 'ModalConfInstanceCtrl', resolve: { conf_args: function () { - return {'addr_host' : $scope.addr_host, 'mod_name': mod_name}; + return {'addr_host' : $scope.addr_host, + 'mod_name': mod_name, + 'detected': $scope.items.detected, + 'subparts': $scope.items.subparts + }; } } }); @@ -382,7 +364,22 @@ mumApp.controller('hostPageCtrl', function ($scope, $rootScope, $route, $routePa // modals controllers mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalInstance, $route, $timeout, conf_args) { - $scope.conf_args = conf_args; // {'addr_host' : val, 'mod_name', val} + $scope.conf_args = conf_args; /* {'addr_host' : val, + 'mod_name', val, + "detected": + { + modname: + { + key:val, + ... + } + } + "subparts":{ + modname: [...], + ... + } + } + */ $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'get_conf_mod', 'args': conf_args}})); @@ -398,7 +395,11 @@ mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalI } */ - $scope.param_struct = {}; + $scope.param_struct = {}; /* + {param_type:[{"doc":str,"type":"string","value":val,"param_name":str}, ... }]} + */ + + $scope.subparts_checked = {}; // init fields $scope.freq_days = 0; @@ -449,10 +450,40 @@ mumApp.controller('ModalConfInstanceCtrl', function ($scope, $rootScope, $modalI $scope.arch_month = args.res.nb_month; $scope.arch_year = args.res.nb_year; update_param_struct(); + + + for (var i=0, size=$scope.param_struct.detection.length ; i<size ; i++) { + var modname = $scope.param_struct.detection[i].param_name; + $scope.subparts_checked[modname] = {} + for (var key in $scope.conf_args.detected[modname]) { + var subpart_name = $scope.conf_args.detected[modname][key]; + $scope.subparts_checked[modname][subpart_name] = $scope.conf_args.subparts[modname].hasOwnProperty(key); + } + } }, 0); } }); + $scope.save_subpart = function (modname) { + var args = {}; + args['addr_host'] = $scope.conf_args.addr_host; + args['modname'] = modname; + args['subpart_list'] = []; + for (key in $scope.subparts_checked[modname]) { + if ($scope.subparts_checked[modname][key]) { + args['subpart_list'].push(key); + } + } + $rootScope.$broadcast("sendViaWs", JSON.stringify({"CALL_FUNC_DB": {'func': 'set_subpart', 'args': args}})); + }; + + $scope.checkAll = function (modname, bool) { + $scope.selectedAll = bool; + for(key in $scope.subparts_checked[modname]) { + $scope.subparts_checked[modname][key] = bool; + } + }; + var update_param_struct = function (){ /* Formats the custom parameters to have the type as a key. Permits to generate the form with ng-repeat. diff --git a/views/dashboard.html b/views/dashboard.html index 0159b11..a263101 100644 --- a/views/dashboard.html +++ b/views/dashboard.html @@ -276,6 +276,23 @@ <!-- Service View --> <div ng-show="view == 'service_view' && items.length > 0"> + <div class="row" + ng-show="!fullscreen"> + <div class="col-xs-2"> + <label for="status_fv">Status filter</label> + <select multiple class="form-control input-sm" + id="status_fv" + ng-model="status_filter" + ng-change="update_url()"> + <option>success</option> + <option>warning</option> + <option>danger</option> + <option>idling</option> + </select> + </div> + + </div> + <div ng-show="is_services_in_alert()"> <h2 class="sub-header" ng-show="!fullscreen">Services in alert...</h2> @@ -316,6 +333,23 @@ <!-- Category View --> <div ng-show="view == 'category_view' && items.length > 0"> + <div class="row" + ng-show="!fullscreen"> + <div class="col-xs-2"> + <label for="status_fc">Status filter</label> + <select multiple class="form-control input-sm" + id="status_fc" + ng-model="status_filter" + ng-change="update_url()"> + <option>success</option> + <option>warning</option> + <option>danger</option> + <option>idling</option> + </select> + </div> + + </div> + <div ng-show="is_category_in_alert()"> <h2 class="sub-header" ng-show="!fullscreen">Categories in alert...</h2> diff --git a/views/hostpage.html b/views/hostpage.html index eb49af9..aad99cd 100644 --- a/views/hostpage.html +++ b/views/hostpage.html @@ -201,30 +201,6 @@ </accordion-group> - <accordion-group heading="Detected configuration (select the subparts to monitore here)"> - - <table class="table table-bordered table-hover"> - <tr ng-repeat-start="(modname, mod) in items.detected" - ng-show="modname != 'nmap'"> - <th>{{modname}}</th> - <th> - <input type="checkbox" ng-model="selectedAll" ng-click="checkAll(modname, !selectedAll)"> - <button type="button" class="btn btn-info btn-xs" - ng-click="save_subpart(modname)"> - Monitore selected subparts - </button> - </th> - </tr> - <tr ng-repeat-end - ng-repeat="(key, val) in mod | orderBy : val" - ng-show="modname != 'nmap'"> - <td>{{val}}</td> - <td><input type="checkbox" ng-model="subparts_checked[modname][val]"></td> - </tr> - </table> - - </accordion-group> - <accordion-group heading="Custom informations"> <label for="custom_info">Add any information here :</label> @@ -278,8 +254,6 @@ </div> <div class="modal-body"> - {{items}}<br/><br/><br/> - {{param_struct}} <form> <div class="form-group"> <label for="arch">Archives to keep (in check numbers). Keep empty for no limit.</label> @@ -400,6 +374,26 @@ </div> </div> + <table class="table table-bordered table-hover"> + <tr ng-repeat-start="dict_param in param_struct.detection"> + <th> + {{dict_param.param_name}} + </th> + <th> + <input type="checkbox" ng-model="selectedAll" ng-click="checkAll(dict_param.param_name, !selectedAll)"> + <button type="button" class="btn btn-info btn-xs" + ng-click="save_subpart(dict_param.param_name)"> + Monitore selected subparts + </button> + </th> + </tr> + <tr ng-repeat-end + ng-repeat="(key, val) in conf_args.detected[dict_param.param_name] | orderBy : val"> + <td>{{val}}</td> + <td><input type="checkbox" ng-model="subparts_checked[dict_param.param_name][val]"></td> + </tr> + </table> + </div> <div class="modal-footer"> diff --git a/views/index.html b/views/index.html index a44f81e..b859cc7 100644 --- a/views/index.html +++ b/views/index.html @@ -19,7 +19,7 @@ <link href="bower_components/angular-ui-select/dist/select.min.css" rel="stylesheet"/> <link href="bower_components/fontawesome/css/font-awesome.css" rel="stylesheet"/> - <!-- AngularJS --> + <!-- JS libraries --> <script src="bower_components/angular/angular.min.js"></script> <script src="bower_components/angular-file-upload/angular-file-upload.min.js"></script> <script src="bower_components/angular-sanitize/angular-sanitize.min.js"></script> @@ -101,6 +101,7 @@ <li><a href="#settings">Global settings</a></li> <li><a href="#notifications">Notifications summary</a></li> <li><hr/></li> + <li><a ng-click="open_modal_mod_list()">Modules currently loaded</a></li> <li><a ng-click="open_modal_log()">See the logs...</a></li> </ul> </div> @@ -223,6 +224,26 @@ </div> </script> + <script type="text/ng-template" id="modal_modules_list.html"> + <div class="modal-header"> + <h3 class="modal-title">List of loaded modules by the service</h3> + </div> + + <div class="modal-body"> + <div ng-repeat="(mod_type_name, mod_obj) in modules_struct"> + {{mod_type_name}} + <ul> + <li ng-repeat="mod_name in mod_obj"> + {{mod_name}} + </li> + </ul> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal" ng-click="close()">Close</button> + </div> + </script> + </body> </html> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.