Commit 88a44a76 authored by Tristan Cavelier's avatar Tristan Cavelier

monitor: cgi mechanism + add promise rerunner cgi

parent 15df3830
...@@ -56,12 +56,12 @@ md5sum = 2db5c08c7e8658981b4b1e3f27fd5967 ...@@ -56,12 +56,12 @@ md5sum = 2db5c08c7e8658981b4b1e3f27fd5967
[monitor-bin] [monitor-bin]
<= monitor-download-base <= monitor-download-base
filename = monitor.py.in filename = monitor.py.in
md5sum = 0f9c69954d3b9e952ac6cb63c293f127 md5sum = 2484cb185c391890a05db26c2163af8e
[monitor-web-default-promise-interface] [monitor-web-default-promise-interface]
<= monitor-download-base <= monitor-download-base
filename = default-promise-interface.html filename = default-promise-interface.html
md5sum = 81fde0e082165ade03c5a9c8abf11136 md5sum = 29c899529f4539c9dd1432907b37b7b1
[monitor-web-index-html] [monitor-web-index-html]
<= monitor-download-base <= monitor-download-base
...@@ -79,22 +79,30 @@ filename = monitor.js.in ...@@ -79,22 +79,30 @@ filename = monitor.js.in
md5sum = 8bc4b8368a752f90da2571866768e81f md5sum = 8bc4b8368a752f90da2571866768e81f
[monitor-web-monitor-logout-cgi] [monitor-web-monitor-logout-cgi]
<= monitor-download-base recipe = slapos.recipe.template:jinja2
filename = monitor-logout.sh.cgi filename = monitor-logout.py.cgi
md5sum = 1daf20f1d6c025e33c608fd9c390e057 md5sum = 5b3c0aa559722a3bae5a692ea9a0a441
mode = 0755 mode = 0755
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/monitor-logout.cgi
context = key python_executable buildout:executable
[monitor-web-monitor-logout-page] [monitor-web-monitor-logout-page]
<= monitor-download-base <= monitor-download-base
filename = monitor-logout.html filename = monitor-logout.html
md5sum = b210c6842df541305d299081bc1bf81e md5sum = b210c6842df541305d299081bc1bf81e
[monitor-web-monitor-promise-runner-cgi]
<= monitor-download-base
filename = monitor-run-promise.py.cgi
md5sum = 15625e5bf6c1b57b9199250951ffc16e
[monitor-template] [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 = 008a25e95a87e0e74e8cf4fbefa9ae82 md5sum = fde8b1c9ff04c64a3b7bb0ae11ffe0c5
context = context =
key apache_location apache:location key apache_location apache:location
key gzip_location gzip:location key gzip_location gzip:location
...@@ -103,8 +111,9 @@ context = ...@@ -103,8 +111,9 @@ context =
raw monitor_web_default_promise_interface ${monitor-web-default-promise-interface:location}/${monitor-web-default-promise-interface:filename} raw monitor_web_default_promise_interface ${monitor-web-default-promise-interface:location}/${monitor-web-default-promise-interface:filename}
raw monitor_web_index_html ${monitor-web-index-html:location}/${monitor-web-index-html: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_css ${monitor-web-monitor-css:location}/${monitor-web-monitor-css:filename}
raw monitor_web_monitor_logout_cgi ${monitor-web-monitor-logout-cgi:location}/${monitor-web-monitor-logout-cgi:filename} key monitor_web_monitor_logout_cgi monitor-web-monitor-logout-cgi:rendered
raw monitor_web_monitor_logout_page ${monitor-web-monitor-logout-page:location}/${monitor-web-monitor-logout-page:filename} raw monitor_web_monitor_logout_page ${monitor-web-monitor-logout-page:location}/${monitor-web-monitor-logout-page:filename}
raw monitor_web_monitor_promise_runner_cgi ${monitor-web-monitor-promise-runner-cgi:location}/${monitor-web-monitor-promise-runner-cgi:filename}
raw monitor_web_monitor_js ${monitor-web-monitor-js:location}/${monitor-web-monitor-js: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
...@@ -122,7 +131,7 @@ context = ...@@ -122,7 +131,7 @@ context =
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/templates/${:filename} url = ${:_profile_base_location_}/templates/${:filename}
download-only = true download-only = true
md5sum = 5be55c3918daa9cc9f8425bfc40e70b1 md5sum = 625d3d948c0af7b4848d7fad92bfb844
filename = monitor-httpd.conf.in filename = monitor-httpd.conf.in
mode = 0644 mode = 0644
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
var service_name = getServiceName(), var service_name = getServiceName(),
monitor_json_url = "/monitor.haljson", monitor_json_url = "/monitor.haljson",
status_json_url = "/public/" + service_name + ".status.json"; status_json_url = "/public/" + service_name + ".status.json",
rerun_cgi_url = "/cgi-bin/monitor-run-promise.cgi?service=" + service_name;
function newDeferred() { function newDeferred() {
var d = { var d = {
...@@ -105,6 +106,14 @@ ...@@ -105,6 +106,14 @@
a.appendChild(button); a.appendChild(button);
button.textContent = "Refresh"; button.textContent = "Refresh";
button = document.createElement("button");
header.appendChild(button);
button.textContent = "Run promise now";
button.onclick = function () {
this.runPromiseNow();
}.bind(this);
this.runPromiseNowButton = button;
this.element.appendChild(h1); this.element.appendChild(h1);
h1.textContent = "Promise status"; h1.textContent = "Promise status";
...@@ -185,6 +194,16 @@ ...@@ -185,6 +194,16 @@
this.errorPre.textContent = "Status Json Error: " + (message || "Unknown error"); this.errorPre.textContent = "Status Json Error: " + (message || "Unknown error");
}.bind(this)).catch(unexpectedError); }.bind(this)).catch(unexpectedError);
}; };
PromiseStatusInterface.prototype.runPromiseNow = function () {
this.runPromiseNowButton.disabled = true;
var original_text = this.runPromiseNowButton.textContent;
this.runPromiseNowButton.textContent = "Sending message...";
return Promise.resolve().then(function () {
return xhr({url: rerun_cgi_url, method: "POST", withCredentials: true});
}).catch(unexpectedError).then(function () {
this.runPromiseNowButton.textContent = original_text;
}.bind(this));
};
/*global setTimeout */ /*global setTimeout */
setTimeout(function () { setTimeout(function () {
......
...@@ -65,7 +65,7 @@ services-conf = ${directory:etc}/monitor.conf.d ...@@ -65,7 +65,7 @@ services-conf = ${directory:etc}/monitor.conf.d
www = ${directory:monitor}/web www = ${directory:monitor}/web
web-dir = ${directory:monitor}/web web-dir = ${directory:monitor}/web
log = ${directory:log}/monitor log = ${directory:log}/monitor
promises = ${directory:monitor}/promise-scripts promise-wrapper = ${directory:var}/monitor-promise-wrapper
[logrotate-directory] [logrotate-directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
...@@ -217,6 +217,15 @@ template = {{ monitor_web_monitor_logout_page }} ...@@ -217,6 +217,15 @@ template = {{ monitor_web_monitor_logout_page }}
rendered = ${monitor-directory:web-dir}/logout rendered = ${monitor-directory:web-dir}/logout
context = context =
[monitor-web-monitor-promise-runner-cgi]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_promise_runner_cgi }}
rendered = ${monitor-directory:cgi-bin}/monitor-run-promise.cgi
mode = 0755
context =
raw python_executable {{ python_executable }}
key promise_wrapper_folder monitor-directory:promise-wrapper
[start-monitor] [start-monitor]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
template = {{ monitor_bin }} template = {{ monitor_bin }}
...@@ -229,6 +238,7 @@ context = ...@@ -229,6 +238,7 @@ context =
key promise_runner_path monitor-run-promise:rendered key promise_runner_path monitor-run-promise:rendered
key promise_folder directory:promises key promise_folder directory:promises
key monitor_promise_folder directory:monitor-promise key monitor_promise_folder directory:monitor-promise
key promise_wrapper_folder monitor-directory:promise-wrapper
[monitor-run-promise] [monitor-run-promise]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
...@@ -276,6 +286,7 @@ parts = ...@@ -276,6 +286,7 @@ parts =
monitor-web-monitor-js monitor-web-monitor-js
monitor-web-monitor-logout-cgi monitor-web-monitor-logout-cgi
monitor-web-monitor-logout-page monitor-web-monitor-logout-page
monitor-web-monitor-promise-runner-cgi
cron-entry-logrotate cron-entry-logrotate
certificate-authority certificate-authority
monitor-conf monitor-conf
......
#!{{ python_executable }}
print("Status: 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"Private access\"\r\n\r")
#!/bin/sh
echo -en 'Status: 401 Unauthorized\r\nWWW-Authenticate: Basic realm="Private access"\r\n\r\n'
#!{{ python_executable }}
# Put this file in the software release
promise_wrapper_folder = "{{ promise_wrapper_folder }}"
import cgi
import cgitb
import os
cgitb.enable(display=0)
def main():
form = cgi.FieldStorage()
promise_name = form["service"].value
if "/" not in promise_name:
promise_path = os.path.join(promise_wrapper_folder, promise_name)
os.spawnl(os.P_NOWAIT, promise_path, promise_path)
print("Status: 204 No Content\r\n\r")
if __name__ == "__main__":
exit(main())
...@@ -6,9 +6,11 @@ private_folder = "{{ private_folder }}" ...@@ -6,9 +6,11 @@ private_folder = "{{ private_folder }}"
monitor_configuration_path = "{{ monitor_configuration_path }}" monitor_configuration_path = "{{ monitor_configuration_path }}"
promise_folder = "{{ promise_folder }}" promise_folder = "{{ promise_folder }}"
monitor_promise_folder = "{{ monitor_promise_folder }}" monitor_promise_folder = "{{ monitor_promise_folder }}"
promise_wrapper_folder = "{{ promise_wrapper_folder }}"
import sys import sys
import os import os
import stat
import subprocess import subprocess
import threading import threading
import json import json
...@@ -75,12 +77,19 @@ def main(): ...@@ -75,12 +77,19 @@ def main():
for service_name, promise in promise_items: for service_name, promise in promise_items:
service_status_path = "%s/%s.status.json" % (public_folder, service_name) # hardcoded service_status_path = "%s/%s.status.json" % (public_folder, service_name) # hardcoded
mkdirAll(os.path.dirname(service_status_path)) mkdirAll(os.path.dirname(service_status_path))
cron_line_list.append("%s %s %s %s " % ( command = ("%s %s %s " % (
softConfigGet(service_config, "service", "frequency") or "* * * * *",
promise_runner_path, promise_runner_path,
os.path.join(service_pid_folder, "%s.pid" % service_name), os.path.join(service_pid_folder, "%s.pid" % service_name),
service_status_path, service_status_path,
) + promise["path"].replace("%", "\\%")) )) + promise["path"]
cron_line_list.append("%s %s" % (
softConfigGet(service_config, "service", "frequency") or "* * * * *",
command.replace("%", "\\%"),
))
wrapper_path = os.path.join(promise_wrapper_folder, service_name)
with open(wrapper_path, "w") as fp:
fp.write("#!/bin/sh\n%s" % command) # XXX hardcoded, use dash, sh or bash binary!
os.chmod(wrapper_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH )
with open(crond_folder + "/monitor-promises", "w") as fp: with open(crond_folder + "/monitor-promises", "w") as fp:
fp.write("\n".join(cron_line_list)) fp.write("\n".join(cron_line_list))
return 0 return 0
......
...@@ -53,8 +53,6 @@ ScriptSock {{ parameter_dict.get('cgid-pid-file') }} ...@@ -53,8 +53,6 @@ ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
SSLRequireSSL SSLRequireSSL
SSLOptions +StrictRequire SSLOptions +StrictRequire
# XXX: security???? # XXX: security????
#Options +ExecCGI
#AddHandler cgi-script .cgi
DirectoryIndex index.html DirectoryIndex index.html
Options FollowSymLinks Options FollowSymLinks
Order Deny,Allow Order Deny,Allow
...@@ -86,3 +84,22 @@ Alias /public {{ directory.get('public') }}/ ...@@ -86,3 +84,22 @@ Alias /public {{ directory.get('public') }}/
Order Allow,Deny Order Allow,Deny
Allow from all Allow from all
</Directory> </Directory>
Alias /cgi-bin {{ directory.get('cgi-bin') }}
<Directory {{ directory.get('cgi-bin') }}>
# XXX security ???
Order Deny,Allow
Deny from all
<Files "*.cgi">
Order Deny,Allow
Deny from env=AUTHREQUIRED
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ parameter_dict.get('htpasswd-file') }}"
Require valid-user
</Files>
Options +ExecCGI
AddHandler cgi-script .cgi
Options Indexes FollowSymLinks
Satisfy all
</Directory>
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