From 16b33bfe76a33dc8eba5631c71d164d5344684de Mon Sep 17 00:00:00 2001 From: Alain Takoudjou <alain.takoudjou@nexedi.com> Date: Wed, 27 Apr 2016 13:45:06 +0200 Subject: [PATCH] monitor: add support for report script folder --- stack/monitor/buildout.cfg | 6 +- stack/monitor/instance-monitor.cfg.jinja2.in | 3 +- stack/monitor/scripts/monitor.py | 80 +++++++++++++++++--- stack/monitor/scripts/run-promise.py | 26 ++++--- stack/resilient/buildout.cfg | 2 +- stack/resilient/instance-pull-backup.cfg.in | 3 +- 6 files changed, 94 insertions(+), 26 deletions(-) diff --git a/stack/monitor/buildout.cfg b/stack/monitor/buildout.cfg index dd9c8bd29..e02165900 100644 --- a/stack/monitor/buildout.cfg +++ b/stack/monitor/buildout.cfg @@ -99,7 +99,7 @@ recipe = slapos.recipe.template:jinja2 filename = template-monitor.cfg template = ${:_profile_base_location_}/instance-monitor.cfg.jinja2.in rendered = ${buildout:directory}/template-monitor.cfg -md5sum = cd7f386fe1b5066d8508758249b408d3 +md5sum = b6da7709da533c5c8280e5e103809c58 context = key apache_location apache:location key gzip_location gzip:location @@ -130,13 +130,13 @@ depends = [monitor2-bin] <= monitor-template-script filename = monitor.py -md5sum = 31beec15d3c3cd7979d04ecb834c439a +md5sum = 6db3d9fcfff32c556f2bedee804ffb47 [run-promise-py] recipe = slapos.recipe.template:jinja2 template = ${:_profile_base_location_}/scripts/run-promise.py rendered = ${buildout:parts-directory}/monitor-scripts/run-promise.py -md5sum = 8ba8b661c55f2c5a379e9e42573be486 +md5sum = 5694920c5789f4d953cb5d41adfa7f8b mode = 0755 context = raw python ${buildout:directory}/bin/${extra-eggs:interpreter} diff --git a/stack/monitor/instance-monitor.cfg.jinja2.in b/stack/monitor/instance-monitor.cfg.jinja2.in index 81b4b9417..5de39730d 100644 --- a/stack/monitor/instance-monitor.cfg.jinja2.in +++ b/stack/monitor/instance-monitor.cfg.jinja2.in @@ -70,7 +70,7 @@ etc = ${directory:etc} run = ${directory:monitor}/run #run = ${directory:scripts} promises = ${directory:monitor-promise} -report = ${directory:monitor-report} +reports = ${directory:monitor-report} pids = ${directory:run}/monitor cgi-bin = ${directory:monitor}/cgi-bin webdav = ${directory:monitor}/webdav @@ -134,6 +134,7 @@ root-title = ${monitor-instance-parameter:root-instance-title} public-folder = ${monitor-directory:public} private-folder = ${monitor-directory:private} webdav-folder = ${monitor-directory:webdav} +report-folder = ${monitor-directory:reports} web-folder = ${monitor-directory:web-dir} base-url = ${monitor-instance-parameter:monitor-base-url} monitor-hal-json = ${monitor-directory:public}/monitor.hal.json diff --git a/stack/monitor/scripts/monitor.py b/stack/monitor/scripts/monitor.py index 19cfcfaf7..38e4ad472 100644 --- a/stack/monitor/scripts/monitor.py +++ b/stack/monitor/scripts/monitor.py @@ -94,6 +94,7 @@ class Monitoring(object): self.collector_db = config.get("monitor", "collector-db") self.collect_script = config.get("monitor", "collect-script") self.webdav_folder = config.get("monitor", "webdav-folder") + self.report_script_folder = config.get("monitor", "report-folder") self.webdav_url = '%s/share' % config.get("monitor", "base-url") self.public_url = '%s/public' % config.get("monitor", "base-url") self.status_history_folder = os.path.join(self.public_folder, 'history') @@ -106,6 +107,7 @@ class Monitoring(object): self.parameter_cfg_file = config.get("monitor", "parameter-file-path").strip() self.config_folder = os.path.join(self.private_folder, 'config') + self.report_folder = os.path.join(self.private_folder, 'report') self.promise_dict = {} for promise_folder in self.promise_folder_list: @@ -267,9 +269,11 @@ class Monitoring(object): raise self.data_folder = os.path.join(self.private_folder, 'data', '.jio_documents') + self.report_folder = os.path.join(self.report_folder, '.jio_documents') config_folder = os.path.join(self.config_folder, '.jio_documents') mkdirAll(self.data_folder) mkdirAll(config_folder) + mkdirAll(self.report_folder) try: os.symlink(os.path.join(self.private_folder, 'data'), os.path.join(jio_private, 'data')) @@ -281,6 +285,11 @@ class Monitoring(object): except OSError, e: if e.errno != os.errno.EEXIST: raise + try: + os.symlink(self.report_folder, os.path.join(jio_private, 'report')) + except OSError, e: + if e.errno != os.errno.EEXIST: + raise def makeConfigurationFiles(self): config_folder = os.path.join(self.config_folder, '.jio_documents') @@ -385,6 +394,53 @@ class Monitoring(object): with open(self.monitor_hal_json, "w") as fp: json.dump(self.monitor_dict, fp) + def generateReportCronEntries(self): + cron_line_list = [] + # We should add the possibility to modify this parameter later from monitor interface + report_frequency = "*/30 * * * *" + + report_name_list = [name.replace('.report.json', '') + for name in os.listdir(self.report_folder) if name.endswith('.report.json')] + + for filename in os.listdir(self.report_script_folder): + report_script = os.path.join(self.report_script_folder, filename) + if os.path.isfile(report_script) and os.access(report_script, os.X_OK): + report_name = os.path.splitext(filename)[0] + report_json_path = "%s.report.json" % report_name + + report_cmd_line = [ + report_frequency, + self.promise_runner, + '--pid_path "%s"' % os.path.join(self.service_pid_folder, + "%s.pid" % filename), + '--output "%s"' % os.path.join(self.report_folder,report_json_path), + '--promise_script "%s"' % report_script, + '--promise_name "%s"' % report_name, + '--monitor_url "%s/jio_private/"' % self.webdav_url, # XXX hardcoded, + '--history_folder "%s"' % self.report_folder, + '--instance_name "%s"' % self.title, + '--hosting_name "%s"' % self.root_title, + '--promise_type "report"'] + + cron_line_list.append(' '.join(report_cmd_line)) + + if report_name in report_name_list: + report_name_list.pop(report_name_list.index(report_name)) + + # cleanup removed report json result + if report_name_list != []: + for report_name in report_name_list: + result_path = os.path.join(self.public_folder, '%s.report.json' % report_name) + if os.path.exists(result_path): + try: + os.unlink(result_path) + except OSError, e: + print "Error: Failed to delete %s" % result_path, str(e) + pass + + with open(self.crond_folder + "/monitor-reports", "w") as freport: + freport.write("\n".join(cron_line_list)) + def generateServiceCronEntries(self): # XXX only if at least one configuration file is modified, then write in the cron #cron_line_list = ['PATH=%s\n' % os.environ['PATH']] @@ -401,13 +457,13 @@ class Monitoring(object): promise_cmd_line = [ softConfigGet(service_config, "service", "frequency") or "* * * * *", self.promise_runner, - '--pid_path %s' % os.path.join(self.service_pid_folder, + '--pid_path "%s"' % os.path.join(self.service_pid_folder, "%s.pid" % service_name), - '--output %s' % service_status_path, - '--promise_script %s' % promise["path"], + '--output "%s"' % service_status_path, + '--promise_script "%s"' % promise["path"], '--promise_name "%s"' % service_name, '--monitor_url "%s/jio_private/"' % self.webdav_url, # XXX hardcoded, - '--history_folder %s' % self.status_history_folder, + '--history_folder "%s"' % self.status_history_folder, '--instance_name "%s"' % self.title, '--hosting_name "%s"' % self.root_title] @@ -442,6 +498,13 @@ class Monitoring(object): cronf.write(entry_line) def bootstrapMonitor(self): + + # create symlinks from monitor.conf + self.createSymlinksFromConfig(self.public_folder, self.public_path_list) + self.createSymlinksFromConfig(self.private_folder, self.private_path_list) + + self.configureFolders() + # create symlinks from service configurations self.promise_items = self.promise_dict.items() for service_name, promise in self.promise_items: @@ -457,12 +520,6 @@ class Monitoring(object): private_path_list.split(), service_name) - # create symlinks from monitor.conf - self.createSymlinksFromConfig(self.public_folder, self.public_path_list) - self.createSymlinksFromConfig(self.private_folder, self.private_path_list) - - self.configureFolders() - # generate monitor.json self.monitor_dict = {} self.generateMonitorHalJson() @@ -474,6 +531,9 @@ class Monitoring(object): # put promises to a cron file self.generateServiceCronEntries() + # put report script to cron + self.generateReportCronEntries() + # Generate parameters files and scripts self.makeConfigurationFiles() diff --git a/stack/monitor/scripts/run-promise.py b/stack/monitor/scripts/run-promise.py index 50a1b806f..5bfad4102 100644 --- a/stack/monitor/scripts/run-promise.py +++ b/stack/monitor/scripts/run-promise.py @@ -24,15 +24,18 @@ def parseArguments(): help='Promise script to execute.') parser.add_argument('--promise_name', help='Title to give to this promise.') + parser.add_argument('--promise_type', + default='status', + help='Type of promise to execute. [status, report].') parser.add_argument('--monitor_url', help='Monitor Instance website URL.') parser.add_argument('--history_folder', help='Path where old result file will be placed before generate a new json result file.') parser.add_argument('--instance_name', - default='UNKNOW Software Instance', + default='UNKNOWN Software Instance', help='Software Instance name.') parser.add_argument('--hosting_name', - default='UNKNOW Hosting Subscription', + default='UNKNOWN Hosting Subscription', help='Hosting Subscription name.') return parser.parse_args() @@ -74,14 +77,16 @@ def main(): updateStatusHistoryFolder( parser.promise_name, parser.output, - parser.history_folder + parser.history_folder, + parser.promise_type ) with open(parser.output, "w") as outputfile: json.dump(status_json, outputfile) os.remove(parser.pid_path) -def updateStatusHistoryFolder(name, status_file, history_folder): +def updateStatusHistoryFolder(name, status_file, history_folder, promise_type): old_history_list = [] + keep_item_amount = 25 history_path = os.path.join(history_folder, name, '.jio_documents') if not os.path.exists(status_file): return @@ -96,18 +101,19 @@ def updateStatusHistoryFolder(name, status_file, history_folder): else: raise with open(status_file, 'r') as sf: status_dict = json.loads(sf.read()) - filename = '%s.status.json' % ( - status_dict['start-date'].replace(' ', '_').replace(':', '')) + filename = '%s.%s.json' % ( + status_dict['start-date'].replace(' ', '_').replace(':', ''), + promise_type) copyfile(status_file, os.path.join(history_path, filename)) - # Don't let history foler grow too much, keep 40 files + # Don't let history foler grow too much, keep xx files file_list = filter(os.path.isfile, - glob.glob("%s/*.status.json" % history_path) + glob.glob("%s/*.%s.json" % (history_path, promise_type)) ) file_count = len(file_list) - if file_count > 40: + if file_count > keep_item_amount: file_list.sort(key=lambda x: os.path.getmtime(x)) - while file_count > 40: + while file_count > keep_item_amount: to_delete = file_list.pop(0) try: os.unlink(to_delete) diff --git a/stack/resilient/buildout.cfg b/stack/resilient/buildout.cfg index b6b5c2fe7..b279e6711 100644 --- a/stack/resilient/buildout.cfg +++ b/stack/resilient/buildout.cfg @@ -63,7 +63,7 @@ mode = 0644 recipe = slapos.recipe.template url = ${:_profile_base_location_}/instance-pull-backup.cfg.in output = ${buildout:directory}/instance-pull-backup.cfg -md5sum = 028dfc01dfb0d738e1b4793f67b24e8c +md5sum = cb7acac7ab41bf44c20d6d03bfad8217 mode = 0644 [template-replicated] diff --git a/stack/resilient/instance-pull-backup.cfg.in b/stack/resilient/instance-pull-backup.cfg.in index 47d95389f..26156b3aa 100644 --- a/stack/resilient/instance-pull-backup.cfg.in +++ b/stack/resilient/instance-pull-backup.cfg.in @@ -11,6 +11,7 @@ parts = ## Monitor for pbs + monitor-base monitor-check-resilient-feed-file extends = ${monitor2-template:rendered} @@ -266,7 +267,7 @@ private-path-list += [monitor-check-resilient-feed-file] recipe = slapos.recipe.template:jinja2 template = ${template-monitor-check-resilient-feed:location}/${template-monitor-check-resilient-feed:filename} -rendered = $${monitor-directory:promises}/check-create-resilient-feed-files +rendered = $${monitor-directory:reports}/check-create-resilient-feed-files mode = 700 context = key input_feed_directory directory:notifier-feeds -- 2.30.9