Commit a3763e67 authored by Alain Takoudjou's avatar Alain Takoudjou

monitor2 stack: first version for renderjs web interface

parent d6634962
...@@ -33,6 +33,12 @@ on-update = true ...@@ -33,6 +33,12 @@ on-update = true
<= monitor-download-base <= monitor-download-base
url = ${:_profile_base_location_}/templates/${:filename} url = ${:_profile_base_location_}/templates/${:filename}
[monitor-template-script]
<= monitor-download-base
url = ${:_profile_base_location_}/scripts/${:filename}
destination = ${buildout:parts-directory}/monitor-scripts
on-update = true
[eggs] [eggs]
recipe = zc.recipe.egg recipe = zc.recipe.egg
eggs += eggs +=
...@@ -40,9 +46,10 @@ eggs += ...@@ -40,9 +46,10 @@ eggs +=
cns.recipe.symlink cns.recipe.symlink
[extra-eggs] [extra-eggs]
recipe = zc.recipe.egg <= eggs
interpreter = pythonwitheggs interpreter = pythonwitheggs
eggs = eggs +=
psutil
PyRSS2Gen PyRSS2Gen
Jinja2 Jinja2
...@@ -85,7 +92,7 @@ md5sum = 04b664dfb47bfd3d01502768311aa239 ...@@ -85,7 +92,7 @@ md5sum = 04b664dfb47bfd3d01502768311aa239
# Monitor templates files # Monitor templates files
[monitor-httpd-conf] [monitor-httpd-conf]
<= monitor-template-base <= monitor-template-base
md5sum = 8a1aa7cba281877d6cf63cb8ade64b5e md5sum = 68a7e4d3304fc78d173f30ad99534762
filename = monitor-httpd.conf.in filename = monitor-httpd.conf.in
[monitor-service-conf-template] [monitor-service-conf-template]
...@@ -102,6 +109,11 @@ md5sum = 8cde04bfd0c0e9bd56744b988275cfd8 ...@@ -102,6 +109,11 @@ md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
<= monitor-template-base <= monitor-template-base
filename = monitor.conf.in filename = monitor.conf.in
md5sum = 2db5c08c7e8658981b4b1e3f27fd5967 md5sum = 2db5c08c7e8658981b4b1e3f27fd5967
[monitor-instance-info]
<= monitor-template-base
filename = instance-info.conf.in
md5sum = d506e335e366c1d873a3490333842398
# End templates files # End templates files
...@@ -110,12 +122,15 @@ recipe = slapos.recipe.template:jinja2 ...@@ -110,12 +122,15 @@ recipe = slapos.recipe.template:jinja2
filename = template-monitor.cfg filename = template-monitor.cfg
template = ${:_profile_base_location_}/instance-monitor.cfg.jinja2.in template = ${:_profile_base_location_}/instance-monitor.cfg.jinja2.in
rendered = ${buildout:directory}/template-monitor.cfg rendered = ${buildout:directory}/template-monitor.cfg
md5sum = bf0578bb6863fea73c1c40bc009c7654 md5sum = 8763a92c2c22103a9f6c9052ba322fc5
context = context =
key apache_location apache:location key apache_location apache:location
key gzip_location gzip:location key gzip_location gzip:location
raw monitor_bin ${monitor2-bin:location}/${monitor2-bin:filename} raw monitor_bin ${monitor2-bin:location}/${monitor2-bin:filename}
raw monitor_collect ${monitor-collect:location}/${monitor-collect:filename}
raw monitor_conf_template ${monitor-conf:location}/${monitor-conf:filename} raw monitor_conf_template ${monitor-conf:location}/${monitor-conf:filename}
raw monitor_instance_info ${monitor-instance-info:location}/${monitor-instance-info:filename}
raw monitor_globalstate ${monitor-globalstate:location}/${monitor-globalstate:filename}
raw monitor_password_promise_template ${monitor-password-promise:location}/${monitor-password-promise:filename} raw monitor_password_promise_template ${monitor-password-promise:location}/${monitor-password-promise:filename}
raw monitor_password_cgi_template ${monitor-password-py-cgi:location}/${monitor-password-py-cgi:filename} raw monitor_password_cgi_template ${monitor-password-py-cgi:location}/${monitor-password-py-cgi:filename}
raw monitor_password_promise_interface_template ${monitor-password-promise-interface:location}/${monitor-password-promise-interface:filename} raw monitor_password_promise_interface_template ${monitor-password-promise-interface:location}/${monitor-password-promise-interface:filename}
...@@ -135,35 +150,44 @@ context = ...@@ -135,35 +150,44 @@ context =
raw monitor_service_conf_template ${monitor-service-conf-template:location}/${monitor-service-conf-template:filename} raw monitor_service_conf_template ${monitor-service-conf-template:location}/${monitor-service-conf-template:filename}
raw openssl_executable_location ${openssl:location}/bin/openssl raw openssl_executable_location ${openssl:location}/bin/openssl
raw python_executable ${buildout:executable} raw python_executable ${buildout:executable}
raw promise_executor_py ${run-promise-py:location}/${run-promise-py:filename} raw python_with_eggs ${buildout:directory}/bin/${extra-eggs:interpreter}
raw promise_executor_py ${run-promise-py:rendered}
raw template_wrapper ${template-wrapper:output} raw template_wrapper ${template-wrapper:output}
raw status2rss_executable_path ${status2rss-executable:location}/${status2rss-executable:filename} raw status2rss_executable_path ${status2rss-executable:location}/${status2rss-executable:filename}
[monitor2-bin] [monitor2-bin]
<= monitor-download-base <= monitor-template-script
filename = monitor.py filename = monitor.py
md5sum = 7e1f2210a87b2212d11524e06985dd49 md5sum = 3d2035d7c02b9d37c5c680e142dcb845
url = ${:_profile_base_location_}/scripts/${:filename}
[run-promise-py] [run-promise-py]
<= monitor-download-base recipe = slapos.recipe.template:jinja2
filename = run-promise.py template = ${:_profile_base_location_}/scripts/run-promise.py
md5sum = 8a46adcbc126ec9589d1810ba291d048 rendered = ${buildout:parts-directory}/monitor-scripts/run-promise.py
md5sum = 4f99c09125c201ee988e71662b8c9bf9
mode = 0755 mode = 0755
url = ${:_profile_base_location_}/scripts/${:filename} context =
raw python ${buildout:directory}/bin/${extra-eggs:interpreter}
[monitor-password-promise] [monitor-password-promise]
<= monitor-download-base <= monitor-template-script
filename = monitor-password-promise.py filename = monitor-password-promise.py
md5sum = f7e937d6619eb674f39f34718928d91d md5sum = f7e937d6619eb674f39f34718928d91d
url = ${:_profile_base_location_}/scripts/${:filename}
[status2rss-executable] [status2rss-executable]
<= monitor-download-base <= monitor-template-script
filename = status2rss.py filename = status2rss.py
md5sum = 65315ded80cd72f54f6e12d06ce813c4 md5sum = 40dcda69f1ccb8639d7ef0ad65bceb5e
url = ${:_profile_base_location_}/scripts/${:filename}
[monitor-globalstate]
<= monitor-template-script
filename = globalstate.py
md5sum = 906776302bfe511b21a7eee3c9bcb6a5
[monitor-collect]
<= monitor-template-script
filename = collect.py
md5sum = 8f4f36039ac8b30e59c11dea0bfeb65e
[make-rss-script] [make-rss-script]
......
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = ${slap-connection:computer-id}
partition = ${slap-connection:partition-id}
url = ${slap-connection:server-url}
key = ${slap-connection:key-file}
cert = ${slap-connection:cert-file}
[cron] [cron]
recipe = slapos.cookbook:cron recipe = slapos.cookbook:cron
cron-entries = ${logrotate-directory:cron-entries} cron-entries = ${logrotate-directory:cron-entries}
...@@ -58,6 +66,7 @@ run = ${directory:monitor}/run ...@@ -58,6 +66,7 @@ run = ${directory:monitor}/run
#run = ${directory:scripts} #run = ${directory:scripts}
pids = ${directory:run}/monitor pids = ${directory:run}/monitor
cgi-bin = ${directory:monitor}/cgi-bin cgi-bin = ${directory:monitor}/cgi-bin
webdav = ${directory:monitor}/webdav
public = ${directory:monitor}/public public = ${directory:monitor}/public
private = ${directory:monitor}/private private = ${directory:monitor}/private
services = ${directory:services} services = ${directory:services}
...@@ -117,10 +126,13 @@ wrapper = ${directory:services}/monitor-httpd ...@@ -117,10 +126,13 @@ wrapper = ${directory:services}/monitor-httpd
title = ${monitor-instance-parameter:monitor-title} title = ${monitor-instance-parameter:monitor-title}
public-folder = ${monitor-directory:public} public-folder = ${monitor-directory:public}
private-folder = ${monitor-directory:private} private-folder = ${monitor-directory:private}
webdav-folder = ${monitor-directory:webdav}
web-folder = ${monitor-directory:web-dir} web-folder = ${monitor-directory:web-dir}
monitor-hal-json = ${monitor-directory:web-dir}/monitor.haljson base-url = ${monitor-httpd-conf-parameter:url}
monitor-hal-json = ${monitor-directory:public}/monitor.hal.json
service-pid-folder = ${monitor-directory:pids} service-pid-folder = ${monitor-directory:pids}
crond-folder = ${logrotate-directory:cron-entries} crond-folder = ${logrotate-directory:cron-entries}
logrotate-folder = ${logrotate:logrotate-entries}
wraper-folder = ${monitor-directory:promise-wrapper} wraper-folder = ${monitor-directory:promise-wrapper}
promise-runner = {{ promise_executor_py }} promise-runner = {{ promise_executor_py }}
promise-folder-list = promise-folder-list =
...@@ -128,11 +140,15 @@ promise-folder-list = ...@@ -128,11 +140,15 @@ promise-folder-list =
${directory:monitor-promise} ${directory:monitor-promise}
public-path-list = public-path-list =
${directory:log}
private-path-list = private-path-list =
${directory:log}
#
monitor-url-list = monitor-url-list =
collector-db = ${monitor-instance-parameter:collector-db}
collect-script = {{ monitor_collect }}
python = {{ python_with_eggs }}
[monitor-conf] [monitor-conf]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
template = {{ monitor_conf_template }} template = {{ monitor_conf_template }}
...@@ -140,10 +156,26 @@ rendered = ${directory:etc}/${:filename} ...@@ -140,10 +156,26 @@ rendered = ${directory:etc}/${:filename}
filename = monitor.conf filename = monitor.conf
context = section parameter_dict monitor-conf-parameters context = section parameter_dict monitor-conf-parameters
[instance-info-parameters]
name = ${monitor-instance-parameter:monitor-title}
computer-id = ${slap-connection:computer-id}
ipv4 = ${slap-configuration:ipv4-random}
ipv6 = ${slap-configuration:ipv6-random}
software-release = ${slap-connection:software-release-url}
software-type = ${slap-configuration:slap-software-type}
partition-id = ${slap-connection:partition-id}
[monitor-instance-info]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_instance_info }}
rendered = ${directory:etc}/${:filename}
filename = instance-info.conf
context = section instance_dict instance-info-parameters
[python-symlink] [python-symlink]
recipe = plone.recipe.command recipe = plone.recipe.command
target = ${directory:bin} target = ${directory:bin}
command = ln -sf {{ python_executable }} ${:target}/python command = ln -sf {{ python_with_eggs }} ${:target}/python
update-command = ${:command} update-command = ${:command}
[start-monitor] [start-monitor]
...@@ -171,7 +203,8 @@ error-log = ${monitor-directory:log}/httpd-error.log ...@@ -171,7 +203,8 @@ error-log = ${monitor-directory:log}/httpd-error.log
cert-file = ${ca-directory:certs}/httpd.crt cert-file = ${ca-directory:certs}/httpd.crt
key-file = ${ca-directory:certs}/httpd.key key-file = ${ca-directory:certs}/httpd.key
htpasswd-file = ${httpd-monitor-htpasswd:htpasswd-path} htpasswd-file = ${httpd-monitor-htpasswd:htpasswd-path}
url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}/ url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}
httpd-cors-config-file = ${monitor-httpd-cors:location}
[monitor-httpd-conf] [monitor-httpd-conf]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
...@@ -182,6 +215,13 @@ context = ...@@ -182,6 +215,13 @@ context =
section directory monitor-directory section directory monitor-directory
section parameter_dict monitor-httpd-conf-parameter section parameter_dict monitor-httpd-conf-parameter
[monitor-httpd-cors]
recipe = plone.recipe.command
command = if [ ! -f ${:location} ]; then echo 'Header set Access-Control-Allow-Origin "*"' > ${:location}; fi
location = ${directory:etc}/${:filename}
filename = httpd-cors.cfg
stop-on-error = true
[httpd-wrapper] [httpd-wrapper]
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = {{ apache_location }}/bin/httpd -f ${monitor-httpd-conf:rendered} -DFOREGROUND command-line = {{ apache_location }}/bin/httpd -f ${monitor-httpd-conf:rendered} -DFOREGROUND
...@@ -202,7 +242,7 @@ command = kill -USR1 $(cat ${monitor-httpd-conf-parameter:pid-file}) ...@@ -202,7 +242,7 @@ command = kill -USR1 $(cat ${monitor-httpd-conf-parameter:pid-file})
[monitor-status2rss-wrapper] [monitor-status2rss-wrapper]
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = {{ python_executable }} {{ status2rss_executable_path }} '${monitor-instance-parameter:monitor-title}' '${monitor-httpd-conf-parameter:url}' ${monitor-directory:public} ${monitor-directory:monitor-status2rss-var}/previous_status ${monitor-directory:web-dir}/feed command-line = {{ python_with_eggs }} {{ status2rss_executable_path }} '${monitor-instance-parameter:monitor-title}' '${monitor-httpd-conf-parameter:url}' '${monitor-httpd-conf-parameter:url}/public' ${monitor-directory:public} ${monitor-directory:public}/feed
wrapper-path = ${directory:bin}/monitor-status2rss.py wrapper-path = ${directory:bin}/monitor-status2rss.py
[monitor-status2rss-cron-entry] [monitor-status2rss-cron-entry]
...@@ -212,6 +252,18 @@ name = monitor-status2rss ...@@ -212,6 +252,18 @@ name = monitor-status2rss
frequency = * * * * * frequency = * * * * *
command = ${monitor-status2rss-wrapper:wrapper-path} command = ${monitor-status2rss-wrapper:wrapper-path}
[monitor-globalstate-wrapper]
recipe = slapos.cookbook:wrapper
command-line = {{ python_with_eggs }} {{ monitor_globalstate }} '${monitor-conf:rendered}' '${monitor-instance-info:rendered}'
wrapper-path = ${directory:bin}/monitor-globalstate
[monitor-globalstate-cron-entry]
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = monitor-globalstate
frequency = * * * * *
command = ${monitor-globalstate-wrapper:wrapper-path}
[monitor-web-directory] [monitor-web-directory]
recipe = plone.recipe.command recipe = plone.recipe.command
command = cp -f {{ monitor_web_directory }}/* ${monitor-directory:web-dir} command = cp -f {{ monitor_web_directory }}/* ${monitor-directory:web-dir}
...@@ -252,8 +304,8 @@ context = section parameter_dict monitor-httpd-promise-conf-parameter ...@@ -252,8 +304,8 @@ context = section parameter_dict monitor-httpd-promise-conf-parameter
[monitor-httpd-promise-conf-parameter] [monitor-httpd-promise-conf-parameter]
title = Monitor httpd listening title = Monitor httpd listening
# frequency minute hour day mounth weekday # frequency 5 minute hour day mounth weekday
frequency = * * * * * frequency = */5 * * * *
public-path-list = ${monitor-httpd-conf-parameter:access-log} ${monitor-httpd-conf-parameter:error-log} public-path-list = ${monitor-httpd-conf-parameter:access-log} ${monitor-httpd-conf-parameter:error-log}
#private-path-list = #private-path-list =
...@@ -301,15 +353,23 @@ context = ...@@ -301,15 +353,23 @@ context =
[publish] [publish]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
monitor-url = ${monitor-httpd-conf-parameter:url} monitor-url = ${monitor-httpd-conf-parameter:url}
monitor-config-url = ${monitor-httpd-conf-parameter:url}/share/jio_public
[monitor-instance-parameter] [monitor-instance-parameter]
monitor-title = Monitoring interface monitor-title = Monitoring interface
# XXX Hard coded parameter
collector-db = /srv/slapgrid/var/data-log/collector.db
[monitor-base]
# create dependencies between required monitor parts
recipe = plone.recipe.command
command = true
update-command =
monitor-globalstate = ${monitor-globalstate-cron-entry:name}
[buildout] [buildout]
parts = parts =
monitor-web-directory monitor-base
monitor-web-monitor-logout-cgi
monitor-web-monitor-promise-runner-cgi
cron-entry-logrotate cron-entry-logrotate
certificate-authority certificate-authority
monitor-conf monitor-conf
...@@ -317,9 +377,5 @@ parts = ...@@ -317,9 +377,5 @@ parts =
ca-httpd ca-httpd
monitor-httpd-promise monitor-httpd-promise
monitor-httpd-promise-conf monitor-httpd-promise-conf
monitor-password-promise
monitor-password-promise-conf
monitor-password-cgi
monitor-password-promise-interface
monitor-status2rss-cron-entry monitor-status2rss-cron-entry
publish publish
This diff is collapsed.
#!/usr/bin/env python
import sys
import os
import glob
import json
import ConfigParser
import time
def softConfigGet(config, *args, **kwargs):
try:
return config.get(*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return ""
def generateStatisticsData(stat_file_path, content):
# csv document for statictics
if not os.path.exists(stat_file_path):
with open(stat_file_path, 'w') as fstat:
data_dict = {
"date": time.time(),
"data": ["Date, Success, Error, Warning"]
}
fstat.write(json.dumps(data_dict))
current_state = ''
if content.has_key('state'):
current_state = '%s, %s, %s, %s' % (
content['date'],
content['state']['success'],
content['state']['error'],
content['state']['warning'])
# append to file
if current_state:
with open (stat_file_path, mode="r+") as fstat:
fstat.seek(0,2)
position = fstat.tell() -2
fstat.seek(position)
fstat.write('%s}' % ',"{}"]'.format(current_state))
def main(args_list):
monitor_file, instance_file = args_list
monitor_config = ConfigParser.ConfigParser()
monitor_config.read(monitor_file)
base_folder = monitor_config.get('monitor', 'public-folder')
base_url = monitor_config.get('monitor', 'base-url')
related_monitor_list = monitor_config.get("monitor", "monitor-url-list").split()
statistic_folder = os.path.join(base_folder, 'data', '.jio_documents')
if not os.path.exists(statistic_folder):
try:
os.makedirs(statistic_folder)
except OSError, e:
if e.errno == os.errno.EEXIST and os.path.isdir(statistic_folder):
pass
else: raise
# search for all status files
file_list = filter(os.path.isfile,
glob.glob("%s/*.status.json" % base_folder)
)
error = warning = success = 0
latest_date = ''
status = 'OK'
promise_list = []
global_state_file = os.path.join(base_folder, 'monitor.global.json')
for file in file_list:
try:
with open(file, 'r') as temp_file:
tmp_json = json.loads(temp_file.read())
except ValueError:
# bad json file ?
continue
if tmp_json['status'] == 'ERROR':
error += 1
elif tmp_json['status'] == 'OK':
success += 1
elif tmp_json['status'] == 'WARNING':
warning += 1
if tmp_json['start-date'] > latest_date:
latest_date = tmp_json['start-date']
tmp_json['time'] = tmp_json['start-date'].split(' ')[1]
del tmp_json['start-date']
promise_list.append(tmp_json)
if error:
status = 'ERROR'
elif warning:
status = 'WARNING'
global_state_dict = dict(
status=status,
state={
'error': error,
'success': success,
'warning': warning,
},
date=latest_date,
_links={"rss_url": {"href": "%s/public/feed" % base_url},
"public_url": {"href": "%s/share/jio_public" % base_url},
"private_url": {"href": "%s/share/jio_private" % base_url},
"data_url": {"href": '%s/public/data' % base_url}
},
data={'state': 'monitor_state.data',
'process_state': 'monitor_process_resource.status',
'process_resource': 'monitor_resource_process.data',
'memory_resource': 'monitor_resource_memory.data',
'io_resource': 'monitor_resource_io.data',
'monitor_process_state': 'monitor_resource.status'}
)
global_state_dict['_embedded'] = {'promises': promise_list}
if os.path.exists(instance_file):
config = ConfigParser.ConfigParser()
config.read(instance_file)
if 'instance' in config.sections():
instance_dict = {}
global_state_dict['title'] = config.get('instance', 'name')
if not global_state_dict['title']:
global_state_dict['title'] = 'Instance Monitoring'
instance_dict['computer'] = config.get('instance', 'computer')
instance_dict['ipv4'] = config.get('instance', 'ipv4')
instance_dict['ipv6'] = config.get('instance', 'ipv6')
instance_dict['software-release'] = config.get('instance', 'software-release')
instance_dict['software-type'] = config.get('instance', 'software-type')
instance_dict['partition'] = config.get('instance', 'partition')
global_state_dict['_embedded'].update({'instance' : instance_dict})
if related_monitor_list:
global_state_dict['_links']['related_monitor'] = [{'href': "%s/share/jio_public" % url}
for url in related_monitor_list]
with open(global_state_file, 'w') as fglobal:
fglobal.write(json.dumps(global_state_dict))
generateStatisticsData(
os.path.join(statistic_folder, 'monitor_state.data.json'),
global_state_dict)
return 0
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: %s <monitor_conf_path> <instance_conf_path>" % sys.argv[0])
sys.exit(2)
sys.exit(main(sys.argv[1:]))
This diff is collapsed.
#!/usr/bin/env python
import json
import os
import time
from datetime import datetime
OPML_START = """<?xml version="1.0" encoding="UTF-8"?>
<!-- OPML generated by SlapOS -->
<opml version="1.1">
<head>
<title>SlapOS Monitoring Status Lists</title>
<dateCreated>%(creation_date)s</dateCreated>
<dateModified>%(mondification_date)s</dateModified>
</head>
<body>
<outline text="%(outline_title)s">"""
OPML_END = """ </outline>
</body>
</opml>"""
OPML_OUTLINE_FEED = '<outline text="%(title)s" title="%(title)s" type="rss" version="RSS" htmlUrl="%(html_url)s" xmlUrl="%(xml_url)s" />'
def main(config_file, output_file):
feed_url_list = []
if os.path.exists(output_file):
creation_date = datetime.fromtimestamp(os.path.getctime(output_file)).utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
modification_date = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
else:
creation_date = modification_date = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
with open(config_file, 'r') as fconfig:
feed_url_list = json.loads(fconfig.read())
opml_content = OPML_START
for feed_line in feed_url_list:
opml_content += OPML_OUTLINE_FEED % {'title': feed_line['title'], 'html_url': feed_line['url'], 'xml_url': feed_line['url']}
opml_content += OPML_END
with open(output_file, 'w') as wfile:
wfile.write(opml_content)
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: %s <rss_conf_file> <output_path>" % sys.argv[0])
sys.exit(2)
config_file = sys.argv[1]
output_file = sys.argv[2]
main(config_file, output_file)
\ No newline at end of file
#!/usr/bin/env python #!{{ python }}
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys
import os import os
import subprocess import subprocess
import json import json
import psutil
import time
from shutil import copyfile
import glob
def main(): def main():
if len(sys.argv) < 4: if len(sys.argv) < 4:
print("Usage: %s <pid_path> <output_path> <command...>" % sys.argv[0]) print("Usage: %s <pid_path> <output_path> <command> [<name>] [...]" % sys.argv[0])
return 2 return 2
pid_path=sys.argv[1] pid_path=sys.argv[1]
output_path=sys.argv[2] output_path=sys.argv[2]
promise_name = history_folder = related_url = ""
if len(sys.argv) >= 5:
promise_name = sys.argv[4]
if len(sys.argv) >= 6:
related_url = sys.argv[5]
if len(sys.argv) >= 7:
history_folder = sys.argv[6]
if os.path.exists(pid_path): if os.path.exists(pid_path):
with open(pid_path, "r") as pidfile: with open(pid_path, "r") as pidfile:
try: try:
...@@ -21,27 +32,82 @@ def main(): ...@@ -21,27 +32,82 @@ def main():
if pid and os.path.exists("/proc/" + str(pid)): if pid and os.path.exists("/proc/" + str(pid)):
print("A process is already running with pid " + str(pid)) print("A process is already running with pid " + str(pid))
return 1 return 1
start_date = ""
with open(pid_path, "w") as pidfile: with open(pid_path, "w") as pidfile:
process = executeCommand(sys.argv[3:]) process = executeCommand(sys.argv[3:])
ps_process = psutil.Process(process.pid)
start_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ps_process.create_time()))
pidfile.write(str(process.pid)) pidfile.write(str(process.pid))
status_json = generateStatusJsonFromProcess(process)
status_json = generateStatusJsonFromProcess(process, start_date=start_date, title=promise_name)
# Save the lastest status change date (needed for rss)
if related_url:
status_json['_links'] = {"monitor": {"href": related_url}}
status_json['change-time'] = ps_process.create_time()
if os.path.exists(output_path):
with open(output_path) as f:
last_result = json.loads(f.read())
if status_json['status'] == last_result['status'] and last_result.has_key('change-time'):
status_json['change-time'] = last_result['change-time']
if history_folder:
updateStatusHistoryFolder(promise_name, output_path, history_folder)
with open(output_path, "w") as outputfile: with open(output_path, "w") as outputfile:
json.dump(status_json, outputfile) json.dump(status_json, outputfile)
os.remove(pid_path) os.remove(pid_path)
def updateStatusHistoryFolder(name, status_file, history_folder):
old_history_list = []
history_path = os.path.join(history_folder, name, '.jio_documents')
if not os.path.exists(status_file):
return
if not os.path.exists(history_folder):
return
if not os.path.exists(history_path):
try:
os.makedirs(history_path)
except OSError, e:
if e.errno == os.errno.EEXIST and os.path.isdir(history_path):
pass
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(':', ''))
copyfile(status_file, os.path.join(history_path, filename))
# Don't let history foler grow too much, keep 30 files
file_list = filter(os.path.isfile,
glob.glob("%s/*.status.json" % history_path)
)
file_count = len(file_list)
if file_count > 30:
file_list.sort(key=lambda x: os.path.getmtime(x))
while file_count > 30:
to_delete = file_list.pop(0)
try:
os.unlink(to_delete)
file_count -= 1
except OSError:
raise
def generateStatusJsonFromProcess(process): def generateStatusJsonFromProcess(process, start_date=None, title=None):
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
try: try:
status_json = json.loads(stdout) status_json = json.loads(stdout)
except ValueError: except ValueError:
status_json = {} status_json = {}
if process.returncode != 0: if process.returncode != 0:
status_json["status"] = "error" status_json["status"] = "ERROR"
elif not status_json.get("status"): elif not status_json.get("status"):
status_json["status"] = "OK" status_json["status"] = "OK"
if stderr: if stderr:
status_json["error"] = stderr status_json["message"] = stderr
if start_date:
status_json["start-date"] = start_date
if title:
status_json["title"] = title
return status_json return status_json
......
...@@ -4,104 +4,47 @@ import json ...@@ -4,104 +4,47 @@ import json
import datetime import datetime
import base64 import base64
import hashlib import hashlib
import PyRSS2Gen
def getKey(item):
return item.pubDate
def main(): def main():
_, title, link, public_folder, previous_status_path, output_path = sys.argv _, title, link, base_url, status_folder, output_path = sys.argv
final_status = "OK";
# getting status rss_item_list = []
for filename in os.listdir(public_folder): for filename in os.listdir(status_folder):
if filename.endswith(".status.json"): if filename.endswith(".status.json"):
filepath = os.path.join(public_folder, filename) filepath = os.path.join(status_folder, filename)
status = None result_dict = None
try: try:
status = json.load(open(filepath, "r")) result_dict = json.load(open(filepath, "r"))
except ValueError: except ValueError:
print "Failed to load json file: %s" % filepath
continue continue
try: description = result_dict.get('message', '')
if status["status"] != "OK": event_time = datetime.datetime.fromtimestamp(result_dict['change-time'])
final_status = "BAD" rss_item = PyRSS2Gen.RSSItem(
break title = '[%s] %s' % (result_dict['status'], result_dict['title']),
except KeyError: description = "%s: %s\n%s" % (event_time, result_dict['status'], description),
final_status = "BAD" link = '%s/%s' % (base_url, filename),
break pubDate = event_time,
# checking previous status guid = PyRSS2Gen.Guid(base64.b64encode("%s, %s" % (event_time, result_dict['status'])))
try:
status = open(previous_status_path, "r").readline(4)
if status == final_status:
return 0
except IOError:
pass
# update status
open(previous_status_path, "w").write(final_status)
# generating RSS
utcnow = datetime.datetime.utcnow()
open(output_path, "w").write(
newRssString(
title,
title,
link,
utcnow,
utcnow,
"60",
[
newRssItemString(
"Status is %s" % final_status,
"Status is %s" % final_status,
link,
newGuid("%s, %s" % (utcnow, final_status)),
utcnow,
)
],
) )
) rss_item_list.append(rss_item)
def escapeHtml(string):
return string.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;")
def newGuid(string):
sha256 = hashlib.sha256()
sha256.update(string)
return sha256.hexdigest()
def newRssItemString(title, description, link, guid, pub_date, guid_is_perma_link=True): ### Build the rss feed
return """<item> sorted(rss_item_list, key=getKey)
<title>%(title)s</title> rss_feed = PyRSS2Gen.RSS2 (
<description>%(description)s</description> title = title,
<link>%(link)s</link> link = link,
<guid isPermaLink="%(guid_is_perma_link)s">%(guid)s</guid> description = '',
<pubDate>%(pub_date)s</pubDate> lastBuildDate = datetime.datetime.utcnow(),
</item>""" % { items = rss_item_list
"title": escapeHtml(title), )
"description": escapeHtml(description), with open(output_path, 'w') as frss:
"link": escapeHtml(link), frss.write(rss_feed.to_xml())
"guid": escapeHtml(guid),
"pub_date": escapeHtml(pub_date.strftime("%a, %d %b %Y %H:%M:%S +0000")),
"guid_is_perma_link": escapeHtml(repr(guid_is_perma_link).lower()),
}
def newRssString(title, description, link, last_build_date, pub_date, ttl, rss_item_string_list):
return """<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>%(title)s</title>
<description>%(description)s</description>
<link>%(link)s</link>
<lastBuildDate>%(last_build_date)s</lastBuildDate>
<pubDate>%(pub_date)s</pubDate>
<ttl>%(ttl)s</ttl>
%(items)s
</channel>
</rss>
""" % {
"title": escapeHtml(title),
"description": escapeHtml(description),
"link": escapeHtml(link),
"last_build_date": escapeHtml(last_build_date.strftime("%a, %d %b %Y %H:%M:%S +0000")),
"pub_date": escapeHtml(pub_date.strftime("%a, %d %b %Y %H:%M:%S +0000")),
"ttl": escapeHtml(str(ttl)),
"items": "\n\n".join([" " + item.replace("\n", "\n ") for item in rss_item_string_list]),
}
if __name__ == "__main__": if __name__ == "__main__":
exit(main()) exit(main())
[instance]
name = {{ instance_dict['name'] }}
computer = {{ instance_dict['computer-id'] }}
ipv4 = {{ instance_dict['ipv4'] }}
ipv6 = {{ instance_dict['ipv6'] }}
software-release = {{ instance_dict['software-release'] }}
software-type = {{ instance_dict['software-type'] }}
partition = {{ instance_dict['partition-id'] }}
\ No newline at end of file
...@@ -11,7 +11,7 @@ ServerAdmin someone@email ...@@ -11,7 +11,7 @@ ServerAdmin someone@email
Listen [{{ parameter_dict.get('listening-ip') }}]:{{ parameter_dict.get('port') }} Listen [{{ parameter_dict.get('listening-ip') }}]:{{ parameter_dict.get('port') }}
Define MonitorPort Define MonitorPort
</IfDefine> </IfDefine>
DocumentRoot "{{ directory.get('www') }}" DocumentRoot "{{ directory.get('webdav') }}"
ErrorLog "{{ parameter_dict.get('error-log') }}" ErrorLog "{{ parameter_dict.get('error-log') }}"
LoadModule unixd_module modules/mod_unixd.so LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so LoadModule access_compat_module modules/mod_access_compat.so
...@@ -31,6 +31,8 @@ LoadModule proxy_module modules/mod_proxy.so ...@@ -31,6 +31,8 @@ LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so LoadModule headers_module modules/mod_headers.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
# SSL Configuration # SSL Configuration
<IfDefine !SSLConfigured> <IfDefine !SSLConfigured>
...@@ -49,6 +51,11 @@ SSLCipherSuite RC4-SHA:HIGH:!ADH ...@@ -49,6 +51,11 @@ SSLCipherSuite RC4-SHA:HIGH:!ADH
AddType application/hal+json .haljson AddType application/hal+json .haljson
SSLEngine On SSLEngine On
Include {{ parameter_dict.get('httpd-cors-config-file') }}
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Methods "PROPFIND, PROPPATCH, COPY, MOVE, DELETE, MKCOL, LOCK, UNLOCK, PUT, GETLIB, VERSION-CONTROL, CHECKIN, CHECKOUT, UNCHECKOUT, REPORT, UPDATE, CANCELUPLOAD, HEAD, OPTIONS, GET, POST"
Header set Access-Control-Allow-Headers "Overwrite, Destination, Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Authorization"
{% if parameter_dict.has_key('monitor-url-list') -%} {% if parameter_dict.has_key('monitor-url-list') -%}
RewriteEngine on RewriteEngine on
SSLProxyEngine on SSLProxyEngine on
...@@ -66,6 +73,27 @@ RewriteRule /monitor{{ index }}/(.*) {{ url }}/$1 [L,P] ...@@ -66,6 +73,27 @@ RewriteRule /monitor{{ index }}/(.*) {{ url }}/$1 [L,P]
{% endfor -%} {% endfor -%}
{% endif -%} {% endif -%}
DavLockDB {{ directory.get('monitor-var') }}/DavLock
Alias /share {{ directory.get('webdav') }}
<Directory {{ directory.get('webdav') }}>
DirectoryIndex disabled
DAV On
Options Indexes FollowSymLinks
AuthType Basic
AuthName "webdav"
AuthUserFile "{{ parameter_dict.get('htpasswd-file') }}"
<LimitExcept OPTIONS>
Require valid-user
</LimitExcept>
</Directory>
<LocationMatch "/share/(jio_)?public">
<Limit GET HEAD OPTIONS REPORT PROPFIND>
Allow from all
Satisfy any
</Limit>
</LocationMatch>
ScriptSock {{ parameter_dict.get('cgid-pid-file') }} ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}> <Directory {{ directory.get('www') }}>
SSLVerifyDepth 1 SSLVerifyDepth 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment