Commit 01d7f0be authored by Tristan Cavelier's avatar Tristan Cavelier

monitor: make it work

parent 5a60ad67
...@@ -12,10 +12,20 @@ parts = ...@@ -12,10 +12,20 @@ parts =
dcron dcron
monitor-eggs monitor-eggs
extra-eggs extra-eggs
monitor-conf
monitor-bin monitor-bin
monitor-web-index-html
monitor-web-monitor-css
monitor-web-monitor-js
monitor-template monitor-template
rss-bin rss-bin
[monitor-download-base]
recipe = hexagonit.recipe.download
download-only = true
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[monitor-eggs] [monitor-eggs]
recipe = zc.recipe.egg recipe = zc.recipe.egg
eggs = eggs =
...@@ -36,25 +46,45 @@ md5sum = 98c8f6fd81e405b0ad10db07c3776321 ...@@ -36,25 +46,45 @@ md5sum = 98c8f6fd81e405b0ad10db07c3776321
output = ${buildout:directory}/template-make-rss.sh.in output = ${buildout:directory}/template-make-rss.sh.in
mode = 0644 mode = 0644
[monitor-template] [monitor-conf]
recipe = slapos.recipe.template <= monitor-download-base
url = ${:_profile_base_location_}/monitor.cfg.in filename = monitor.conf.in
output = ${buildout:directory}/monitor.cfg md5sum = 2db5c08c7e8658981b4b1e3f27fd5967
filename = monitor.cfg
md5sum = 51284c0aeb62eccd37f8a4e1621ee28c [monitor-bin]
mode = 0644 <= monitor-download-base
filename = monitor.py.in
md5sum = 1a376c4063121db33ffab25b4cd99c76
[monitor-web-index-html]
<= monitor-download-base
filename = index.html
md5sum = 262db07691c145301252a49b6b51d11d
[monitor-web-monitor-css]
<= monitor-download-base
filename = monitor.css
md5sum = a18ab932e5e2e656995f47c7d4a7853a
[monitor-site-template] [monitor-web-monitor-js]
<= monitor-download-base
filename = monitor.js.in
md5sum = 4f8f1f7f26f589bfdae8fbfee74fc1cc
[monitor-template]
recipe = slapos.recipe.template:jinja2 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 = c792bdee9049d7061e36c12e2343eb87 md5sum = c9bcc845671f78bc3e4c544aa84313e3
context = context =
key apache_location apache:location key apache_location apache:location
key gzip_location gzip:location key gzip_location gzip:location
key monitor_static_html monitor-html-static:location
raw monitor_bin ${monitor-bin:location}/${monitor-bin:filename} raw monitor_bin ${monitor-bin:location}/${monitor-bin:filename}
raw monitor_conf_template ${monitor-conf:location}/${monitor-conf:filename}
raw monitor_web_index_html ${monitor-web-index-html:location}/${monitor-web-index-html:filename}
raw monitor_web_monitor_css ${monitor-web-monitor-css:location}/${monitor-web-monitor-css:filename}
raw monitor_web_monitor_js ${monitor-web-monitor-js:location}/${monitor-web-monitor-js:filename}
raw curl_executable_location ${curl:location}/bin/curl raw curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash raw dash_executable_location ${dash:location}/bin/dash
raw dcron_executable_location ${dcron:location}/sbin/crond raw dcron_executable_location ${dcron:location}/sbin/crond
...@@ -97,21 +127,10 @@ url = https://nexedi.erp5.net/monitor-5c66a4518b466d45cb31cb7e8a225cde20247589.t ...@@ -97,21 +127,10 @@ url = https://nexedi.erp5.net/monitor-5c66a4518b466d45cb31cb7e8a225cde20247589.t
#md5sum #md5sum
strip-top-level-dir = true strip-top-level-dir = true
[monitor-bin]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
download-only = true
md5sum = 68a17075eeeebabd01965be2ee25721d
filename = monitor.py.in
mode = 0644
[run-promise-py] [run-promise-py]
recipe = hexagonit.recipe.download <= monitor-download-base
url = ${:_profile_base_location_}/${:filename}
download-only = true
md5sum = 0454e5e28b83da48e52770c977eade8b
filename = run-promise.py filename = run-promise.py
mode = 0644 md5sum = 6db26ce13becf8a190e34c14cb8b6f9f
[monitor-httpd-template] [monitor-httpd-template]
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
......
...@@ -47,11 +47,11 @@ log = ${:var}/log ...@@ -47,11 +47,11 @@ log = ${:var}/log
scripts = ${:etc}/run scripts = ${:etc}/run
services = ${:etc}/service services = ${:etc}/service
promises = ${:etc}/promise promises = ${:etc}/promise
ssl = ${:etc}/ssl
monitor = ${:srv}/monitor monitor = ${:srv}/monitor
[monitor-directory] [monitor-directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
bin = ${directory:bin}
etc = ${directory:etc} etc = ${directory:etc}
run = ${directory:monitor}/run run = ${directory:monitor}/run
#run = ${directory:scripts} #run = ${directory:scripts}
...@@ -59,8 +59,10 @@ pids = ${directory:run}/monitor ...@@ -59,8 +59,10 @@ pids = ${directory:run}/monitor
cgi-bin = ${directory:monitor}/cgi-bin cgi-bin = ${directory:monitor}/cgi-bin
public = ${directory:monitor}/public public = ${directory:monitor}/public
private = ${directory:monitor}/private private = ${directory:monitor}/private
services = ${directory:services}
services-conf = ${directory:etc}/monitor.conf.d services-conf = ${directory:etc}/monitor.conf.d
www = ${directory:monitor}/web www = ${directory:monitor}/web
web-dir = ${directory:monitor}/web
log = ${directory:log}/monitor log = ${directory:log}/monitor
promises = ${directory:monitor}/promise-scripts promises = ${directory:monitor}/promise-scripts
...@@ -80,16 +82,17 @@ log = ${buildout:directory}/var/log ...@@ -80,16 +82,17 @@ log = ${buildout:directory}/var/log
[ca-directory] [ca-directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
requests = ${directory:ssl}/requests/ root = ${directory:srv}/ssl
private = ${directory:ssl}/private/ requests = ${:root}/requests
certs = ${directory:ssl}/certs/ private = ${:root}/private
newcerts = ${directory:ssl}/newcerts/ certs = ${:root}/certs
crl = ${directory:ssl}/crl/ newcerts = ${:root}/newcerts
crl = ${:root}/crl
[certificate-authority] [certificate-authority]
recipe = slapos.cookbook:certificate_authority recipe = slapos.cookbook:certificate_authority
openssl-binary = {{ openssl_executable_location }} openssl-binary = {{ openssl_executable_location }}
ca-dir = ${monitor-directory:ca-dir} ca-dir = ${ca-directory:root}
requests-directory = ${ca-directory:requests} requests-directory = ${ca-directory:requests}
wrapper = ${monitor-directory:services}/certificate_authority wrapper = ${monitor-directory:services}/certificate_authority
ca-private = ${ca-directory:private} ca-private = ${ca-directory:private}
...@@ -105,17 +108,14 @@ cert-file = ${monitor-httpd-conf:cert-file} ...@@ -105,17 +108,14 @@ cert-file = ${monitor-httpd-conf:cert-file}
executable = ${httpd-wrapper:wrapper-path} executable = ${httpd-wrapper:wrapper-path}
wrapper = ${directory:services}/monitor-httpd wrapper = ${directory:services}/monitor-httpd
[monitor] [monitor-conf-parameters]
recipe = slapos.cookbook:zero-knowledge.write title = ${monitor-instance-parameter:monitor-title}
filename = ${monitor-directory:etc}/monitor.conf
title = ${slap-parameter:monitor-title}
service-executable-dir = ${monitor-directory:run} service-executable-dir = ${monitor-directory:run}
template-service-run = {{ monitor_service_run }} template-service-run = {{ monitor_service_run }}
public-folder = ${monitor-directory:public} public-folder = ${monitor-directory:public}
private-folder = ${monitor-directory:private} private-folder = ${monitor-directory:private}
web-folder = ${monitor-static-web:web-dir} web-folder = ${monitor-directory:web-dir}
monitor-hal-json = ${monitor-static-web:web-dir}/monitor.haljson monitor-hal-json = ${monitor-directory:web-dir}/monitor.haljson
service-pid-folder = ${monitor-directory:pids} service-pid-folder = ${monitor-directory:pids}
crond-folder = ${logrotate-directory:cron-entries} crond-folder = ${logrotate-directory:cron-entries}
public-path-list = public-path-list =
...@@ -124,6 +124,12 @@ private-path-list = ...@@ -124,6 +124,12 @@ private-path-list =
monitor-url-list = monitor-url-list =
[monitor-conf]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_conf_template }}
rendered = ${directory:etc}/${:filename}
filename = monitor.conf
context = section parameter_dict monitor-conf-parameters
[httpd-monitor-htaccess] [httpd-monitor-htaccess]
recipe = plone.recipe.command recipe = plone.recipe.command
...@@ -134,8 +140,8 @@ user = admin ...@@ -134,8 +140,8 @@ user = admin
password = admin password = admin
[monitor-httpd-conf] [monitor-httpd-conf]
listening-ip = ${slap-network-information:global-ipv6} listening-ip = ${monitor-instance-parameter:monitor-httpd-ipv6}
port = 9206 port = ${monitor-instance-parameter:monitor-httpd-port}
pid-file = ${directory:run}/httpd.pid pid-file = ${directory:run}/httpd.pid
cgid-pid-file = ${directory:run}/cgid.pid cgid-pid-file = ${directory:run}/cgid.pid
access-log = ${monitor-directory:log}/httpd-access.log access-log = ${monitor-directory:log}/httpd-access.log
...@@ -143,7 +149,7 @@ error-log = ${monitor-directory:log}/httpd-error.log ...@@ -143,7 +149,7 @@ 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
htaccess-file = ${httpd-monitor-htaccess:htaccess-path} htaccess-file = ${httpd-monitor-htaccess:htaccess-path}
url = https://[${slap-network-information:global-ipv6}]:${:port}/ url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}/
[monitor-httpd-conf] [monitor-httpd-conf]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
...@@ -152,7 +158,7 @@ rendered = ${monitor-directory:etc}/monitor-httpd.conf ...@@ -152,7 +158,7 @@ rendered = ${monitor-directory:etc}/monitor-httpd.conf
mode = 0744 mode = 0744
context = context =
section directory monitor-directory section directory monitor-directory
section monitor_parameters monitor section monitor_parameters monitor-conf
section monitor_httpd monitor-httpd-conf section monitor_httpd monitor-httpd-conf
[httpd-wrapper] [httpd-wrapper]
...@@ -173,13 +179,24 @@ context = ...@@ -173,13 +179,24 @@ context =
key content :command key content :command
command = kill -USR1 $(cat ${monitor-httpd-conf:pid-file}) command = kill -USR1 $(cat ${monitor-httpd-conf:pid-file})
[monitor-static-web] [monitor-web-index-html]
recipe = plone.recipe.command recipe = slapos.recipe.template:jinja2
web-dir = ${monitor-directory:www}/ template = {{ monitor_web_index_html }}
command = rendered = ${monitor-directory:web-dir}/index.html
cp -ax {{monitor_static_html}}/* ${:web-dir} context =
update-command =
stop-on-error = true [monitor-web-monitor-css]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_css }}
rendered = ${monitor-directory:web-dir}/monitor.css
context =
[monitor-web-monitor-js]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_js }}
rendered = ${monitor-directory:web-dir}/monitor.js
context =
key monitor_title monitor-instance-parameter:monitor-title
[start-monitor] [start-monitor]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
...@@ -187,12 +204,14 @@ template = {{ monitor_bin }} ...@@ -187,12 +204,14 @@ template = {{ monitor_bin }}
rendered = ${directory:scripts}/bootstrap-monitor rendered = ${directory:scripts}/bootstrap-monitor
context = context =
raw python_executable {{ python_executable }} raw python_executable {{ python_executable }}
key configuration_location monitor:filename key public_folder monitor-directory:public
key configuration_location monitor-conf:rendered
key promise_runner_path monitor-run-promise:rendered
[monitor-run-promise] [monitor-run-promise]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
template = {{ promise_executor_py }} template = {{ promise_executor_py }}
rendered = ${directory:bin}/monitor-promise rendered = ${directory:bin}/monitor-run-promise
mode = 700 mode = 700
context = context =
raw python_executable {{ python_executable }} raw python_executable {{ python_executable }}
...@@ -240,19 +259,22 @@ title = Monitor promise httpd ...@@ -240,19 +259,22 @@ title = Monitor promise httpd
executable-file = ${monitor-monitor-promise:wrapper-path} executable-file = ${monitor-monitor-promise:wrapper-path}
frequency = */5 * * * * frequency = */5 * * * *
[publish-connection-information] [monitor-publish]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
monitor_url_v6 = ${monitor-httpd-conf:url} monitor_url_v6 = ${monitor-httpd-conf:url}
[slap-parameter] [monitor-instance-parameter]
monitor-title = Monitoring interface monitor-title = Monitoring interface
[buildout] [buildout]
parts = parts =
monitor-web-index-html
monitor-web-monitor-css
monitor-web-monitor-js
cron-entry-logrotate cron-entry-logrotate
certificate-authority certificate-authority
monitor monitor-conf
start-monitor start-monitor
ca-httpd ca-httpd
conf-monitor-promise # conf-monitor-promise
publish-connection-information monitor-publish
[monitor]
{% for key, value in parameter_dict.items() -%}
{{ key }} = {{ value.strip().replace("\n", "\n ") }}
{% endfor -%}
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
(function () { (function () {
"use strict"; "use strict";
var monitor_title = '{{ dumps(monitor_title)[5:-1] }}';
function loadJson(url) { function loadJson(url) {
/*global XMLHttpRequest */ /*global XMLHttpRequest */
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
...@@ -55,10 +57,15 @@ ...@@ -55,10 +57,15 @@
return [value]; return [value];
} }
/////////////////// function softGetPropertyAsList(object, path) {
try {
return forceList(getProperty(object, path));
} catch (ignored) {
return [];
}
}
var monitor_json_list = []; ///////////////////
function htmlToElementList(html) { function htmlToElementList(html) {
/*global document */ /*global document */
...@@ -80,7 +87,7 @@ ...@@ -80,7 +87,7 @@
} }
function loadAndRenderMonitorSection(root, monitor_dict, monitor_url) { function loadAndRenderMonitorSection(root, monitor_dict, monitor_url) {
var table, service_list = forceList(softGetProperty(monitor_dict, ["_embedded", "service"])); var table, service_list = softGetPropertyAsList(monitor_dict, ["_embedded", "service"]);
if (!service_list) { if (!service_list) {
root.textContent = ""; root.textContent = "";
return; return;
...@@ -116,10 +123,10 @@ ...@@ -116,10 +123,10 @@
function loadAndRenderMonitorJson(root) { function loadAndRenderMonitorJson(root) {
root.textContent = "Loading monitor section..."; root.textContent = "Loading monitor section...";
return loadJson("monitor.haljson").then(function (monitor_dict) { return loadJson("monitor.haljson").then(function (monitor_dict) {
monitor_json_list.push(monitor_dict); //monitor_json_list.push(monitor_dict);
root.innerHTML = ""; root.innerHTML = "";
var loading = loadAndRenderMonitorSection(root, monitor_dict), related_monitor_list = forceList(softGetProperty(monitor_dict, ["_links", "related_monitor"])); var loading = loadAndRenderMonitorSection(root, monitor_dict), related_monitor_list = softGetPropertyAsList(monitor_dict, ["_links", "related_monitor"]);
if (!related_monitor_list) { return loading; } if (!related_monitor_list.length) { return loading; }
return Promise.all([loading, Promise.all(related_monitor_list.map(function (link) { return Promise.all([loading, Promise.all(related_monitor_list.map(function (link) {
var div = htmlToElementList("<div>Loading monitor section...</div>")[0]; var div = htmlToElementList("<div>Loading monitor section...</div>")[0];
root.appendChild(div); root.appendChild(div);
...@@ -130,7 +137,7 @@ ...@@ -130,7 +137,7 @@
return loadJson(link.href).catch(function (reason) { return loadJson(link.href).catch(function (reason) {
div.textContent = (reason && (reason.name + ": " + reason.message)); div.textContent = (reason && (reason.name + ": " + reason.message));
}).then(function (monitor_dict) { }).then(function (monitor_dict) {
monitor_json_list.push(monitor_dict); //monitor_json_list.push(monitor_dict);
div.remove(); div.remove();
return loadAndRenderMonitorSection(root, monitor_dict, link.href); return loadAndRenderMonitorSection(root, monitor_dict, link.href);
}); });
...@@ -141,15 +148,17 @@ ...@@ -141,15 +148,17 @@
function bootstrap(root) { function bootstrap(root) {
var element_list = htmlToElementList([ var element_list = htmlToElementList([
"<header><a href=\"\" class=\"as-button\">Refresh</a></header>", "<header><a href=\"\" class=\"as-button\">Refresh</a></header>",
"<h1>KVM Monitoring interface</h1>", "<h1>" + monitor_title + "</h1>",
"<h2>System health status</h2>", "<h2>System health status</h2>",
"<p>This interface allow to see the status of several features, it may show problems and sometimes provides a way to fix them.</p>", "<p>This interface allow to see the status of several features, it may show problems and sometimes provides a way to fix them.</p>",
"<p>Red square means the feature has a problem, green square means it is ok.</p>", "<p>Red square means the feature has a problem, green square means it is ok.</p>",
"<p>You can click on a feature below to get more precise information.</p>" "<p>You can click on a feature below to get more precise information.</p>"
].join("\n")), div = document.createElement("div"), tmp; ].join("\n")), div = document.createElement("div"), tmp;
[].forEach.call(element_list, function (element) { [].forEach.call(element_list, function (element) {
if (element.parentNode.parentNode) { return; }
root.appendChild(element); root.appendChild(element);
}); });
document.title = monitor_title;
root.appendChild(div); root.appendChild(div);
/*global alert */ /*global alert */
tmp = loadAndRenderMonitorJson(div); tmp = loadAndRenderMonitorJson(div);
......
#!{{ python_executable }} #!{{ python_executable }}
configuration_location = "{{ configuration_location }}" configuration_location = "{{ configuration_location }}"
promise_runner_path = "{{ promise_runner_path }}"
public_folder = "{{ public_folder }}"
import sys import sys
import os import os
...@@ -12,9 +14,6 @@ import ConfigParser ...@@ -12,9 +14,6 @@ import ConfigParser
def main(): def main():
# initialisation # initialisation
config = loadConfig([configuration_location]) config = loadConfig([configuration_location])
# create symlinks from monitor.conf
createSymlinksFromConfig((config, "monitor", "public-folder"), (config, "monitor", "public-path-list"))
createSymlinksFromConfig((config, "monitor", "private-folder"), (config, "monitor", "private-path-list"))
# search for configurations in monitor.conf.d # search for configurations in monitor.conf.d
configuration_folder_location = configuration_location + ".d" configuration_folder_location = configuration_location + ".d"
service_config_list = [ service_config_list = [
...@@ -22,7 +21,7 @@ def main(): ...@@ -22,7 +21,7 @@ def main():
for filename in os.listdir(configuration_folder_location) for filename in os.listdir(configuration_folder_location)
if os.path.isfile(os.path.join(configuration_folder_location, filename)) if os.path.isfile(os.path.join(configuration_folder_location, filename))
] ]
# search for promises in ...? # search for promises in ...? or let promises be on some service conf files?
# XXX see old monitor.py.in # XXX see old monitor.py.in
# generate monitor.json # generate monitor.json
monitor_dict = {} monitor_dict = {}
...@@ -43,38 +42,39 @@ def main(): ...@@ -43,38 +42,39 @@ def main():
tmp = softConfigGet(service_config, "service", "title") tmp = softConfigGet(service_config, "service", "title")
if tmp: if tmp:
service_dict["title"] = tmp service_dict["title"] = tmp
tmp = softConfigGet(service_config, "service", "interface-url") tmp = softConfigGet(service_config, "service", "interface-path")
if tmp: if tmp:
service_dict["_links"]["interface"] = {"href": tmp} service_dict["_links"]["interface"] = {"href": "/%s.html" % service_name} # XXX hardcoded
with open(config.get("monitor", "monitor-hal-json"), "w") as fp: with open(config.get("monitor", "monitor-hal-json"), "w") as fp:
json.dump(monitor_dict, fp) json.dump(monitor_dict, fp)
# create symlinks from service configurations # create symlinks from service configurations
for service_config in service_config_list: for service_config in service_config_list:
createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list")) service_name = service_config.get("service", "name")
createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list")) createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list"), service_name)
# run scripts according to frequency createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list"), service_name)
# XXX # put promises to a cron file
# XXX if manifest is modified then: # add manifest to avoid to write every minutes on cron.d...
for filename in os.listdir(configuration_folder_location): service_pid_folder = config.get("monitor", "service-pid-folder")
config_file = os.path.join(configuration_folder_location, filename) crond_folder = config.get("monitor", "crond-folder")
script_config = loadConfig(config_file) cron_line_list = []
base_name = script_config.get("service", "name") for service_config in service_config_list:
pid_file = os.path.join(config.get("monitor", "service-pid-folder"), service_name = service_config.get("service", "name")
"%s.pid" % base_name) service_status_path = "%s/%s/status.json" % (public_folder, service_name)
service_run_location = os.path.join(config.get("monitor", "service-executable-dir"), mkdirAll(os.path.dirname(service_status_path))
base_name) service_cron_path = os.path.join(crond_folder, service_name)
cron_run_location = os.path.join(config.get("monitor", "crond-folder"), cron_line_list.append("%s %s %s %s " % (
base_name) service_config.get("service", "frequency"),
mapping_dict = {"configuration_location": config_file, promise_runner_path,
"process_pid_file": pid_file} os.path.join(service_pid_folder, "%s.pid" % service_name),
createServiceWrapper(mapping_dict, service_run_location, service_status_path,
config.get("monitor", "template-service-run")) ) + service_config.get("service", "promise-path").replace("%", "\\%"))
addCronEntry(cron_run_location, with open(crond_folder + "/monitor-promises", "w") as fp:
[service_run_location], fp.write("\n".join(cron_line_list))
script_config.get("service", "frequency")) # create symlinks from monitor.conf
createSymlinksFromConfig((config, "monitor", "public-folder"), (config, "monitor", "public-path-list"))
createSymlinksFromConfig((config, "monitor", "private-folder"), (config, "monitor", "private-path-list"))
return 0 return 0
def loadConfig(pathes): def loadConfig(pathes):
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
config.read(pathes) config.read(pathes)
...@@ -86,66 +86,27 @@ def softConfigGet(config, *args, **kwargs): ...@@ -86,66 +86,27 @@ def softConfigGet(config, *args, **kwargs):
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return None return None
def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple): def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple, service_name=""):
destination_folder = softConfigGet(*destination_folder_config_tuple) destination_folder = softConfigGet(*destination_folder_config_tuple)
if destination_folder: if destination_folder:
source_path_str = softConfigGet(*source_list_config_tuple) source_path_str = softConfigGet(*source_list_config_tuple)
if source_path_str: if source_path_str:
for path in source_path_str.split(): for path in source_path_str.split():
dirname = os.path.join(destination_folder, service_name)
try: try:
os.symlink(path, os.path.join(destination_folder, os.path.basename(path))) mkdirAll(dirname) # could also raise OSError
os.symlink(path, os.path.join(dirname, os.path.basename(path)))
except OSError, e: except OSError, e:
if e.errno != os.errno.EEXIST: if e.errno != os.errno.EEXIST:
raise raise
def createServiceWrapper(mapping_dict, wrapper_file, template_wrapper): def mkdirAll(path):
with open(template_wrapper, 'r') as template: try:
with open(wrapper_file, 'w') as wrapper: os.makedirs(path)
wrapper.write(template.read() % mapping_dict) except OSError, e:
os.chmod(wrapper_file, 0700) if e.errno == os.errno.EEXIST and os.path.isdir(path):
pass
def addCronEntry(file_path, command_list, frequency): else: raise
with open(file_path, 'w') as cfile:
cfile.write("%s %s" % (frequency, ' '.join(command_list)))
class Popen(subprocess.Popen):
def set_timeout(self, timeout):
self.set_timeout = None # assert we're not called twice
event = threading.Event()
killed = [False] # we just need a mutable
def t():
# do not call wait() or poll() because they're not thread-safe
if not event.wait(timeout) and self.returncode is None:
# race condition if waitpid completes just before the signal sent ?
self.terminate()
killed[0] = True
if event.wait(5):
return
if self.returncode is None:
self.kill() # same race as for terminate ?
t = threading.Thread(target=t)
t.daemon = True
t.start()
def isKilled():
event.set()
t.join()
return killed[0]
return isKilled
def executePath(path):
# XXX script_timeout could be passed as parameters
script_timeout = 3600 # in seconds
with open(os.devnull, 'r+') as f:
p = Popen(command, cwd=instance_path,
env=None if sys.platform == 'cygwin' else {},
stdin=f, stdout=f, stderr=subprocess.PIPE)
killed = p.set_timeout(script_timeout)
stderr = p.communicate()[1]
if killed():
return "Timed Out"
elif p.returncode:
return stderr.strip()
return None
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())
...@@ -56,6 +56,5 @@ def executeCommand(args): ...@@ -56,6 +56,5 @@ def executeCommand(args):
stderr=subprocess.PIPE stderr=subprocess.PIPE
) )
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())
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