Commit 255f61e9 authored by Alain Takoudjou's avatar Alain Takoudjou

monitor stack replaced by new monitor2 stack

parent 1ff00594
......@@ -16,7 +16,7 @@ extends =
../../stack/slapos.cfg
../../stack/nodejs.cfg
../../stack/resilient/buildout.cfg
../../stack/monitor2/buildout.cfg
../../stack/monitor/buildout.cfg
# stacks are listed from most generic to most specific,
# to avoid versioning issues
......
......@@ -21,7 +21,7 @@ extends =
../../stack/slapos.cfg
../../stack/flask.cfg
../../stack/resilient/buildout.cfg
../../stack/monitor2/buildout.cfg
../../stack/monitor/buildout.cfg
# stacks are listed from most generic to most specific,
# to avoid versioning issues
......
* This stack has for purpose to know if all promises, services, custom monitoring scripts went/are ok.
* The second purpose of this stack is to implement a zero-knowledge feature : it means you can use its control interface to provide the user with sensible data. It can also let the user change some parameters
* It also provides a web interface, to see which promises, services and custom scripts failed. It also provide a rss feed to easily know the actual state of your instance, and to know when it started to went bad. You can also add your own monitoring scripts, or cgi files (or just files) that you would want to check easily using a web interface.
Implementation :
----------------
1/ In the software.cfg of your Software Release, extends the stack
2/ In the template that will be copied for the buildout in the instance folder (instance.cfg ?), you have to add these parts:
###Parts to add for monitoring
slap-parameters
certificate-authority
cron
cron-entry-monitor
cron-entry-rss
deploy-index
deploy-index-template
deploy-monitor-script
deploy-rss-script
deploy-settings-cgi
deploy-status-cgi
make-rss
monitor-promise
setup-static-files
certificate-authority
public
zero-parameters
cgi-httpd-wrappers
public-symlink
* If you want to add a custom monitoring script, you can write it (in whatever language you wish) and save it in YOUR_INSTANCE_FOLDER/etc/monitor.
The only thing to know, is that if your script successfully passed, do not return or print nothing. If there is a problem, you can print the explanation on stdout or stderr
* Here are 2 promises that you can add to your instance buildout, to see if it is working (one is ok, not the other) :
[google-promise]
recipe = slapos.cookbook:check_url_available
path = $${directory:promise}/google
url = http://www.google.com
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[failing-promise]
recipe = slapos.cookbook:check_url_available
path = $${directory:promise}/fail
url = http://127.0.0.2
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
CGI Scripts:
------------
This stack also provides a web interface, in wich you can execute custom cgi scripts, or just print files. The web link is provided in the published parameters, as for the password that you have to change as soon as possible
In that interface you will have access to the previous scripts and the RSS feed. You can also add your files/scripts.
For that, there exists a folder /var/cgi-bin. You should see that directory as a tree having of deep 2. In /var/cgi-bin, you must create only folders, which are called categories. In each category, you can then add your own files.
The backend system will automatically render the webpage according to the inside structure of the cgi-bin directory. Moreover, it will also let you access to your scripts only if you are logged in : you do not need do do your own authentication system !
Notice :
--------
* /!\A default password is set up at the installation : "passwordtochange". It has to be rewritten in the control interface by the user itself
* /!\ If you use the recipe zeroknown, never name a parameter "recipe" or "password".
* The control interface will let you change the values of the options declared in the [public] section of the config file (see zeroknown recipe). Other section's values will just be printed. These values won't be overwritten by buildout.
* If you want to allow a user to change a parameter, use the recipe zeroknown, with the buildout section name : "[public]"
* If you manually change a parameter, it could take some time for the modifications to be applied (at least 1 or 2 slapgrid-cp)
* If you need to change the port of the web interface of the monitoring stack, just create in your software release file a part called [monitor-parameters] and give the new port value to the parameter "port".
[buildout]
# XXX THIS STACK IS A KIND OF FORK OF `stack/monitor`. THIS ONE WAS
# CREATED AS A REDESIGNED ONE TO REMOVE UNWANTED FEATURES AND
# TO GO FURTHER TO THE GOOD DESIGN DIRECTION. SEE THE README FOR
# MORE INFORMATION.
extends =
../../component/apache/buildout.cfg
......@@ -7,151 +11,176 @@ extends =
../../component/dcron/buildout.cfg
../../component/openssl/buildout.cfg
parts =
parts +=
slapos-cookbook
dcron
monitor-eggs
eggs
extra-eggs
monitor-bin
monitor-template
rss-bin
monitor2-template
[monitor-eggs]
[monitor-download-base]
recipe = hexagonit.recipe.download
download-only = true
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[monitor-web-base]
<= monitor-download-base
url = ${:_profile_base_location_}/web/${:filename}
destination = ${buildout:parts-directory}/monitor-web
on-update = true
[monitor-template-base]
<= monitor-download-base
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]
recipe = zc.recipe.egg
eggs =
eggs +=
collective.recipe.template
cns.recipe.symlink
[extra-eggs]
recipe = zc.recipe.egg
<= eggs
interpreter = pythonwitheggs
eggs =
eggs +=
psutil
PyRSS2Gen
Jinja2
[make-rss-script]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/make-rss.sh.in
md5sum = 98c8f6fd81e405b0ad10db07c3776321
output = ${buildout:directory}/template-make-rss.sh.in
mode = 0644
[monitor-template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/monitor.cfg.in
output = ${buildout:directory}/monitor.cfg
filename = monitor.cfg
md5sum = 9b31959560d3cde094199e267bbb013b
mode = 0644
# Monitor templates files
[monitor-httpd-conf]
<= monitor-template-base
md5sum = 08137be9b80e0e13d9a906c264a2f51f
filename = monitor-httpd.conf.in
[monitor-bin]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
download-only = true
md5sum = 5b12e864f1762d7984f7d4863d0b795d
destination = ${buildout:parts-directory}/monitor-template-monitor-bin
filename = monitor.py.in
mode = 0644
[monitor-service-conf-template]
<= monitor-template-base
filename = monitor-service.cfg.in
md5sum = 5913d2a0096b50537f394a49b762b3e5
[monitor-httpd-template]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
download-only = true
md5sum = 93e1dda50cb71bfe29966b2946c02dd1
filename = cgi-httpd.conf.in
mode = 0644
[template-wrapper]
<= monitor-template-base
filename = wrapper.in
md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
[index]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = e759977b21c70213daa4c2701f2c2078
destination = ${buildout:parts-directory}/monitor-index
filename = index.cgi.in
mode = 0644
[monitor-conf]
<= monitor-template-base
filename = monitor.conf.in
md5sum = c8f024d741c6494d7c9ba01601d0b917
[monitor-instance-info]
<= monitor-template-base
filename = instance-info.conf.in
md5sum = 1bdb4e05c6be04f4e5766c64467fbcec
[monitor-httpd-cors]
<= monitor-template-base
filename = httpd-cors.cfg.in
md5sum = 5afad2bb6e088e080e907f1d837effbb
# End templates files
[monitor2-template]
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 = e439e22e754a50e1a3500cd4a995f6d8
context =
key apache_location apache:location
key gzip_location gzip:location
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_document_edit ${monitor-document-edit:location}/${monitor-document-edit:filename}
raw monitor_https_cors ${monitor-httpd-cors:location}/${monitor-httpd-cors: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 curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash
raw dcron_executable_location ${dcron:location}/sbin/crond
raw logrotate_executable_location ${logrotate:location}/usr/sbin/logrotate
raw monitor_httpd_template ${monitor-httpd-conf:location}/${monitor-httpd-conf: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 python_executable ${buildout:executable}
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 status2rss_executable_path ${status2rss-executable:location}/${status2rss-executable:filename}
[monitor2-bin]
<= monitor-template-script
filename = monitor.py
md5sum = 927501a8c4ce8dcc39d55af1efdc66ed
[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
mode = 0755
context =
raw python ${buildout:directory}/bin/${extra-eggs:interpreter}
[monitor-password-promise]
<= monitor-template-script
filename = monitor-password-promise.py
md5sum = f7e937d6619eb674f39f34718928d91d
[status2rss-executable]
<= monitor-template-script
filename = status2rss.py
md5sum = f297779d0881f4bd48081506efb492a4
[index-template]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
destination = ${buildout:parts-directory}/monitor-template-index
md5sum = 7400c8cfa16a15a0d41f512b8bbb1581
filename = index.html.jinja2
mode = 0644
[monitor-globalstate]
<= monitor-template-script
filename = globalstate.py
md5sum = 384a1148cb3da9cf353a108fe70709c5
[status-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = e43d79bec8824265e22df7960744113a
destination = ${buildout:parts-directory}/monitor-template-status-cgi
filename = status.cgi.in
mode = 0644
[monitor-collect]
<= monitor-template-script
filename = collect.py
md5sum = cc65aebd4c35b3172a7ca83abde761bc
[status-history-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
#md5sum = 4fb26753ee669b8ac90ffe33dbd12e8f
destination = ${buildout:parts-directory}/monitor-template-status-history-cgi
filename = status-history.cgi.in
mode = 0644
[monitor-document-edit]
<= monitor-template-script
filename = monitor-document.py
md5sum = 79c53518e53ae8c8487b09bb49bc7b80
[settings-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = b4cef123a3273e848e8fe496e22b20a8
destination = ${buildout:parts-directory}/monitor-template-settings-cgi
filename = settings.cgi.in
mode = 0644
[monitor-password-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = c7ba7ecb09d0d1d24e7cb73a212cc33f
destination = ${buildout:parts-directory}/monitor-template-monitor-password-cgi
filename = monitor-password.cgi.in
[make-rss-script]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/make-rss.sh.in
md5sum = 98c8f6fd81e405b0ad10db07c3776321
output = ${buildout:directory}/template-make-rss.sh.in
mode = 0644
[rss-bin]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
download-only = true
md5sum = 6c84a826778cb059754623f39b33651b
destination = ${buildout:parts-directory}/monitor-template-rss-bin
filename = status2rss.py
mode = 0644
[dcron-service]
recipe = slapos.recipe.template
url = ${template-dcron-service:output}
output = $${directory:services}/crond
mode = 0700
logfile = $${directory:log}/crond.log
[download-monitor-static]
recipe = hexagonit.recipe.download
url = http://git.erp5.org/gitweb/slapos.git/snapshot/930be99041ea26b7b1186830e5eb56ef0acc1bdf.tar.gz
download-only = false
filename = monitor-static.tar.gz
destination = ${buildout:parts-directory}/monitor-static-files
ignore-existing = true
strip-top-level-dir = true
mode = 0644
[monitor-web-monitor-logout-cgi]
recipe = slapos.recipe.template:jinja2
filename = monitor-logout.py.cgi
md5sum = 5b3c0aa559722a3bae5a692ea9a0a441
mode = 0755
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/monitor-logout.cgi
context = key python_executable buildout:executable
[download-monitor-jquery]
recipe = hexagonit.recipe.download
url = http://code.jquery.com/jquery-1.10.2.min.js
download-only = true
destination = ${download-monitor-static:destination}
filename = jquery-1.10.2.min.js
mode = 0644
[monitor-web-monitor-promise-runner-cgi]
<= monitor-download-base
filename = monitor-run-promise.py.cgi
md5sum = 15625e5bf6c1b57b9199250951ffc16e
[template-wrapper]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/wrapper.in
output = ${buildout:directory}/template-wrapper.cfg
mode = 0644
md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
[monitor-password-py-cgi]
<= monitor-download-base
md5sum = 04fc7e6d892d29a601cfd43d1700eeda
filename = monitor-password.py.cgi
PidFile "{{ httpd_configuration.get('pid-file') }}"
StartServers 1
ServerLimit 1
ThreadLimit 4
ThreadsPerChild 4
ServerName example.com
ServerAdmin someone@email
<IfDefine !MonitorPort>
Listen [{{ httpd_configuration.get('listening-ip') }}]:{{ monitor_parameters.get('port') }}
Define MonitorPort
</IfDefine>
DocumentRoot "{{ directory.get('www') }}"
ErrorLog "{{ httpd_configuration.get('error-log') }}"
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule mime_module modules/mod_mime.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule dir_module modules/mod_dir.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule alias_module modules/mod_alias.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
# SSL Configuration
<IfDefine !SSLConfigured>
Define SSLConfigured
SSLCertificateFile {{ httpd_configuration.get('certificate') }}
SSLCertificateKeyFile {{ httpd_configuration.get('key') }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLRandomSeed startup /dev/urandom 256
SSLRandomSeed connect builtin
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH
</IfDefine>
SSLEngine On
ScriptSock {{ httpd_configuration.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
SSLVerifyDepth 1
SSLRequireSSL
SSLOptions +StrictRequire
# XXX: security????
Options +ExecCGI
AddHandler cgi-script .cgi
DirectoryIndex {{ monitor_parameters.get('index-filename') }}
</Directory>
Alias /private/ {{ directory.get('private-directory') }}/
<Directory {{ directory.get('private-directory') }}>
Order Deny,Allow
Deny from env=AUTHREQUIRED
<Files ".??*">
Order Allow,Deny
Deny from all
</Files>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ monitor_parameters.get('htaccess-file') }}"
Require valid-user
Options Indexes FollowSymLinks
Satisfy all
</Directory>
<Location /rewrite>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ monitor_parameters.get('htaccess-file') }}"
Require valid-user
</Location>
ProxyVia On
RewriteEngine On
{% for key, value in monitor_rewrite_rule.iteritems() %}
RewriteRule ^/rewrite/{{ key }}($|/.*) {{ value }}/$1 [P,L]
{% endfor %}
[slap-parameters]
recipe = slapos.cookbook:slapconfiguration
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}
[monitor-parameters]
json-filename = monitor.json
json-path = $${monitor-directory:monitor-result}/$${:json-filename}
rss-filename = rssfeed.html
rss-path = $${monitor-directory:public-cgi}/$${:rss-filename}
executable = $${monitor-directory:bin}/monitor.py
port = 9685
htaccess-file = $${monitor-directory:etc}/.htaccess-monitor
url = https://[$${slap-parameters:ipv6-random}]:$${:port}
index-filename = index.cgi
index-path = $${monitor-directory:www}/$${:index-filename}
db-path = $${monitor-directory:etc}/monitor.db
monitor-password-path = $${monitor-directory:etc}/.monitor.shadow
[monitor-directory]
recipe = slapos.cookbook:mkdirectory
# Standard directory needed by monitoring stack
home = $${buildout:directory}
etc = $${:home}/etc
bin = $${:home}/bin
srv = $${:home}/srv
var = $${:home}/var
log = $${:var}/log
run = $${:var}/run
service = $${:etc}/service/
etc-run = $${:etc}/run/
tmp = $${:home}/tmp
promise = $${:etc}/promise
cron-entries = $${:etc}/cron.d
crontabs = $${:etc}/crontabs
cronstamps = $${:etc}/cronstamps
ca-dir = $${:srv}/ssl
www = $${:var}/www
cgi-bin = $${:var}/cgi-bin
monitoring-cgi = $${:cgi-bin}/monitoring
knowledge0-cgi = $${:cgi-bin}/zero-knowledge
public-cgi = $${:cgi-bin}/monitor-public
monitor-custom-scripts = $${:etc}/monitor
monitor-result = $${:var}/monitor
private-directory = $${:srv}/monitor-private
[public-symlink]
recipe = cns.recipe.symlink
symlink = $${monitor-directory:public-cgi} = $${monitor-directory:www}/monitor-public
autocreate = true
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${monitor-directory:cron-entries}
crontabs = $${monitor-directory:crontabs}
cronstamps = $${monitor-directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${monitor-directory:service}/crond
# Add log to cron
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${monitor-directory:bin}/cron_simplelogger
log = $${monitor-directory:log}/cron.log
[cron-entry-monitor]
<= cron
recipe = slapos.cookbook:cron.d
name = launch-monitor
frequency = */5 * * * *
command = $${deploy-monitor-script:rendered} -a
[cron-entry-rss]
<= cron
recipe = slapos.cookbook:cron.d
name = build-rss
frequency = */5 * * * *
command = $${make-rss:rendered}
[setup-static-files]
recipe = plone.recipe.command
command = ln -s ${download-monitor-jquery:destination} $${monitor-directory:www}/static
update-command = $${:command}
[deploy-index]
recipe = slapos.recipe.template:jinja2
template = ${index:location}/${index:filename}
rendered = $${monitor-parameters:index-path}
update-apache-access = ${apache:location}/bin/htpasswd -cb $${monitor-parameters:htaccess-file} admin
mode = 0744
context =
key cgi_directory monitor-directory:cgi-bin
raw index_template $${deploy-index-template:location}/$${deploy-index-template:filename}
key monitor_password_path monitor-parameters:monitor-password-path
key monitor_password_script_path deploy-monitor-password-cgi:rendered
key apache_update_command :update-apache-access
raw extra_eggs_interpreter ${buildout:directory}/bin/${extra-eggs:interpreter}
raw default_page /static/welcome.html
section rewrite_element monitor-rewrite-rule
[deploy-index-template]
recipe = hexagonit.recipe.download
url = ${index-template:location}/$${:filename}
destination = $${monitor-directory:www}
filename = ${index-template:filename}
download-only = true
mode = 0644
[deploy-status-cgi]
recipe = slapos.recipe.template:jinja2
template = ${status-cgi:location}/${status-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = status.cgi
mode = 0744
context =
key json_file monitor-parameters:json-path
key monitor_bin monitor-parameters:executable
key pwd monitor-directory:monitoring-cgi
key this_file :filename
raw python_executable ${buildout:executable}
[deploy-status-history-cgi]
recipe = slapos.recipe.template:jinja2
template = ${status-history-cgi:location}/${status-history-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = status-history.cgi
mode = 0744
context =
key monitor_db_path monitor-parameters:db-path
key status_history_length zero-parameters:status-history-length
raw python_executable ${buildout:executable}
[deploy-settings-cgi]
recipe = slapos.recipe.template:jinja2
template = ${settings-cgi:location}/${settings-cgi:filename}
rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
filename = settings.cgi
mode = 0744
context =
raw config_cfg $${buildout:directory}/knowledge0.cfg
raw timestamp $${buildout:directory}/.timestamp
raw python_executable ${buildout:executable}
key pwd monitor-directory:knowledge0-cgi
key this_file :filename
[deploy-monitor-password-cgi]
recipe = slapos.recipe.template:jinja2
template = ${monitor-password-cgi:location}/${monitor-password-cgi:filename}
rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
filename = monitor-password.cgi
mode = 0744
context =
raw python_executable ${buildout:executable}
key pwd monitor-directory:knowledge0-cgi
key this_file :filename
[deploy-monitor-script]
recipe = slapos.recipe.template:jinja2
template = ${monitor-bin:location}/${monitor-bin:filename}
rendered = $${monitor-parameters:executable}
mode = 0744
context =
section directory monitor-directory
section monitor_parameter monitor-parameters
key monitoring_file_json monitor-parameters:json-path
raw python_executable ${buildout:executable}
[make-rss]
recipe = slapos.recipe.template:jinja2
template = ${make-rss-script:output}
rendered = $${monitor-directory:bin}/make-rss.sh
mode = 0744
context =
section directory monitor-directory
section monitor_parameters monitor-parameters
[monitor-directory-access]
recipe = plone.recipe.command
command = ln -s $${:source} $${monitor-directory:private-directory}
source =
[monitor-instance-log-access]
recipe = plone.recipe.command
command = if [ -d $${:source} ]; then ln -s $${:source} $${monitor-directory:private-directory}/instance-logs; fi
update-command = if [ -d $${:source} ]; then ln -s $${:source} $${monitor-directory:private-directory}/instance-logs; fi
source = $${monitor-directory:home}/.slapgrid/log/
location = $${:source}
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${monitor-directory:ca-dir}/requests/
private = $${monitor-directory:ca-dir}/private/
certs = $${monitor-directory:ca-dir}/certs/
newcerts = $${monitor-directory:ca-dir}/newcerts/
crl = $${monitor-directory:ca-dir}/crl/
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${monitor-directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${monitor-directory:service}/certificate_authority
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[ca-httpd]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${cadirectory:certs}/httpd.key
cert-file = $${cadirectory:certs}/httpd.crt
executable = $${monitor-directory:bin}/cgi-httpd
wrapper = $${monitor-directory:service}/cgi-httpd
# Put domain name
name = example.com
###########
# Deploy a webserver running cgi scripts for monitoring
###########
[public]
recipe = slapos.cookbook:zero-knowledge.write
filename = knowledge0.cfg
status-history-length = 5
[zero-parameters]
recipe = slapos.cookbook:zero-knowledge.read
filename = $${public:filename}
[monitor-rewrite-rule]
# XXX could it be something lighter?
[monitor-httpd-configuration]
pid-file = $${monitor-directory:run}/cgi-httpd.pid
cgid-pid-file = $${monitor-directory:run}/cgi-httpd-cgid.pid
error-log = $${monitor-directory:log}/cgi-httpd-error-log
listening-ip = $${slap-parameters:ipv6-random}
certificate = $${ca-httpd:cert-file}
key = $${ca-httpd:key-file}
[monitor-httpd-configuration-file]
recipe = slapos.recipe.template:jinja2
template = ${monitor-httpd-template:destination}/${monitor-httpd-template:filename}
rendered = $${monitor-directory:etc}/cgi-httpd.conf
mode = 0744
context =
section directory monitor-directory
section monitor_parameters monitor-parameters
section httpd_configuration monitor-httpd-configuration
section monitor_rewrite_rule monitor-rewrite-rule
[cgi-httpd-wrapper]
recipe = slapos.cookbook:wrapper
apache-executable = ${apache:location}/bin/httpd
command-line = $${:apache-executable} -f $${monitor-httpd-configuration-file:rendered} -DFOREGROUND
wrapper-path = $${ca-httpd:executable}
wait-for-files =
$${cadirectory:certs}/httpd.key
$${cadirectory:certs}/httpd.crt
[cgi-httpd-graceful-wrapper]
recipe = slapos.recipe.template:jinja2
template = ${template-wrapper:output}
rendered = $${monitor-directory:etc-run}/cgi-httpd-graceful
mode = 0700
context =
key content :command
command = kill -USR1 $(cat $${monitor-httpd-configuration:pid-file})
[monitor-promise]
recipe = slapos.cookbook:check_url_available
path = $${monitor-directory:promise}/monitor
url = $${monitor-parameters:url}/$${monitor-parameters:index-filename}
check-secure = 1
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[publish-connection-informations]
recipe = slapos.cookbook:publish
monitor_url = $${monitor-parameters:url}
[publish-connection-information]
<= publish-connection-informations
#!{{ python_executable }}
import json
import os
import subprocess
import sys
import sqlite3
import time
import threading
from optparse import OptionParser, make_option
FAILURE = "FAILURE"
SUCCESS = "SUCCESS"
db_path = "{{ monitor_parameter['db-path'] }}"
instance_path = "{{ directory['home'] }}"
monitor_dir = "{{ directory['monitor-custom-scripts'] }}"
pid_dir = "{{ directory['run'] }}"
promise_dir = "{{ directory['promise'] }}"
monitoring_file_json = "{{ monitoring_file_json }}"
option_list = [
make_option("-a", "--all", action="store_true", dest="all",
help="test everything : promises, services, customs"),
make_option("-n", "--no-write", action="store_true", dest="only_stdout",
help="just show the json output on stdout"),
make_option("-m", "--monitors", action="store_true", dest="monitor",
help="add the custom monitoring file to the files to monitor"),
make_option("-p", "--promises", action="store_true", dest="promise",
help="add the promises\'file to the files to monitor"),
make_option("-s", "--services", action="store_true", dest="service",
help="add the file containing services\'pid to the files to monitor")
]
class Popen(subprocess.Popen):
def set_timeout(self, timeout):
self.set_timeout = None # assert we're not called twice
event = threading.Event()
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()
event.__killed = 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 killed():
event.set()
t.join()
return event.__killed
return killed
def init_db(db):
db.executescript("""
CREATE TABLE IF NOT EXISTS status (
timestamp INTEGER UNIQUE,
status VARCHAR(255));
CREATE TABLE IF NOT EXISTS individual_status (
timestamp INTEGER,
status VARCHAR(255),
element VARCHAR(255),
output TEXT);
""")
def getListOfScripts(directory):
"""
Get the list of script inside of a directory (not recursive)
"""
scripts = []
if os.path.exists(directory) and os.path.isdir(directory):
for file_name in os.listdir(directory):
file = os.path.join(directory, file_name)
if os.access(file, os.X_OK) and not os.path.isdir(file):
scripts.append(file)
else:
exit("There is a problem in your directories" \
"of monitoring. Please check them")
return scripts
def runServices(directory):
services = getListOfScripts(directory)
result = {}
for service in services:
service_path = os.path.join(pid_dir, service)
service_name = os.path.basename(service_path)
try:
pid = int(open(service_path).read())
### because apache (or others) can write sockets
### We also ignore not readable pid files
except (IOError, ValueError):
continue
try:
os.kill(pid, 0)
result[service_name] = ''
except OSError:
result[service_name] = "This service is not running anymore"
return result
def runScripts(directory):
# XXX script_timeout could be passed as parameters
script_timeout = 60 # in seconds
result = {}
with open(os.devnull, 'r+') as f:
for script in getListOfScripts(directory):
command = os.path.join(promise_dir, script),
script = os.path.basename(script)
result[script] = ''
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():
result[script] = "Time Out"
elif p.returncode:
result[script] = stderr.strip()
return result
def writeFiles(monitors):
timestamp = int(time.time())
db = sqlite3.connect(db_path)
init_db(db)
status = SUCCESS
for key, value in monitors.iteritems():
if value:
element_status = status = FAILURE
else:
element_status = SUCCESS
db.execute("insert into individual_status(timestamp, element, output, status) values (?, ?, ?, ?)", (timestamp, key, value, element_status))
db.execute("insert into status(timestamp, status) values (?, ?)", (timestamp, status))
db.commit()
db.close()
monitors['datetime'] = time.ctime(timestamp)
json.dump(monitors, open(monitoring_file_json, "w+"))
def main():
parser = OptionParser(option_list=option_list)
monitors = {}
(options, args) = parser.parse_args()
if not (options.monitor or options.promise
or options.service or options.all):
exit("Please provide at list one arg in : -a, -m, -p, -s")
if options.monitor or options.all:
monitors.update(runScripts(monitor_dir))
if options.promise or options.all:
monitors.update(runScripts(promise_dir))
if options.service or options.all:
monitors.update(runServices(pid_dir))
if options.only_stdout:
print json.dumps(monitors)
else:
writeFiles(monitors)
if __name__ == "__main__":
main()
import datetime
import PyRSS2Gen
import sys
import sqlite3
import time
import base64
# Based on http://thehelpfulhacker.net/2011/03/27/a-rss-feed-for-your-crontabs/
# ### Defaults
TITLE = sys.argv[1]
LINK = sys.argv[2]
db_path = sys.argv[3]
DESCRIPTION = TITLE
SUCCESS = "SUCCESS"
FAILURE = "FAILURE"
items = []
status = ""
current_timestamp = int(time.time())
# We only build the RSS for the last ten days
period = 3600 * 24 * 10
db = sqlite3.connect(db_path)
rows = db.execute("select timestamp, status from status where timestamp>? order by timestamp", (current_timestamp - period,))
for row in rows:
line_timestamp, line_status = row
line_status = line_status.encode()
if line_status == status:
continue
status = line_status
event_time = datetime.datetime.fromtimestamp(line_timestamp).strftime('%Y-%m-%d %H:%M:%S')
individual_rows = db.execute("select status, element, output from individual_status where timestamp=?", (line_timestamp,))
description = '\n'.join(['%s: %s %s' % row for row in individual_rows])
rss_item = PyRSS2Gen.RSSItem(
title = status,
description = "%s: %s\n%s" % (event_time, status, description),
link = LINK,
pubDate = event_time,
guid = PyRSS2Gen.Guid(base64.b64encode("%s, %s" % (event_time, status)))
)
items.append(rss_item)
### Build the rss feed
items.reverse()
rss_feed = PyRSS2Gen.RSS2 (
title = TITLE,
link = LINK,
description = DESCRIPTION,
lastBuildDate = datetime.datetime.utcnow(),
items = items
)
print rss_feed.to_xml()
#!{{ extra_eggs_interpreter }}
import cgi
import cgitb
import Cookie
import base64
import hashlib
import hmac
import jinja2
import os
import subprocess
import urllib
cgitb.enable(display=0, logdir="/tmp/cgi.log")
form = cgi.FieldStorage()
cookie = Cookie.SimpleCookie()
cgi_path = "{{ cgi_directory }}"
monitor_password_path = "{{ monitor_password_path }}"
monitor_password_script_path = "{{ monitor_password_script_path }}"
monitor_apache_password_command = "{{ apache_update_command }}"
monitor_rewrite = "{{ ' '.join(rewrite_element.keys()) }}"
########
# Password functions
#######
def crypt(word, salt="$$"):
salt = salt.split("$")
algo = salt[0] or 'sha1'
if algo in hashlib.algorithms:
H = getattr(hashlib, algo)
elif algo == "plain":
return "%s$%s" % (algo, word)
else:
raise ValueError
rounds = min(max(0, int(salt[1])), 30) if salt[1] else 9
salt = salt[2] or base64.b64encode(os.urandom(12), "./")
h = hmac.new(salt, word, H).digest()
for x in xrange(1, 1 << rounds):
h = H(h).digest()
return "%s$%s$%s$%s" % (algo, rounds, salt,
base64.b64encode(h, "./").rstrip("="))
def is_password_set():
if not os.path.exists(monitor_password_path):
return False
hashed_password = open(monitor_password_path, 'r').read()
try:
void, algo, salt, hsh = hashed_password.split('$')
except ValueError:
return False
return True
def set_password(raw_password):
hashed_password = crypt(raw_password)
subprocess.check_call(monitor_apache_password_command + " %s" % raw_password,
shell=True)
open(monitor_password_path, 'w').write(hashed_password)
def check_password(raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes.
"""
if not os.path.exists(monitor_password_path) or not raw_password:
return False
hashed_password = open(monitor_password_path, 'r').read()
return hashed_password == crypt(raw_password, hashed_password)
### End of password functions
def forward_form():
command = os.path.join(cgi_path, form['posting-script'].value)
params_dict = {}
for f in form:
params_dict[f] = form[f].value
del params_dict['posting-script']
os.environ['QUERY_STRING'] = urllib.urlencode(params_dict)
try:
if os.access(command, os.X_OK):
print '\n', subprocess.check_output([command])
except subprocess.CalledProcessError:
print "There is a problem with sub-process"
pass
def return_document(command=None):
if not command:
script = form['script'].value
command = os.path.join(cgi_path, script)
#XXX this functions should be called only for display,
#so a priori it doesn't need form data
os.environ['QUERY_STRING'] = ''
try:
if os.access(command, os.X_OK):
print '\n', subprocess.check_output([command])
elif os.access(command, os.R_OK):
print open(command).read()
else:
raise OSError
except (subprocess.CalledProcessError, OSError) as e:
print "<p>Error :</p><pre>%s</pre>" % e
def make_menu():
# Transform deep-2 tree in json
folder_list = {}
for folder in os.listdir(cgi_path):
if os.path.isdir(os.path.join(cgi_path, folder)):
folder_list[folder] = []
for folder in folder_list:
for file in os.listdir(os.path.join(cgi_path, folder)):
if os.path.isfile(os.path.join(cgi_path, folder, file)):
folder_list[folder].append(file)
return folder_list
def get_cookie_password():
cookie_string = os.environ.get('HTTP_COOKIE')
if cookie_string:
cookie.load(cookie_string)
try:
return cookie['password'].value
except KeyError:
pass
return None
def set_cookie_password(password):
cookie['password'] = password
print cookie, "; Path=/; HttpOnly"
# Beginning of response
print "Content-Type: text/html"
password = None
# Check if user is logged
if "password_2" in form and "password" in form:
password_2 = form['password_2'].value
password_1 = form['password'].value
password = get_cookie_password()
if not is_password_set() or check_password(password):
if password_2 == password_1:
password = password_1
set_password(password)
set_cookie_password(password)
elif "password" in form:
password = form['password'].value
if is_password_set() and check_password(password):
set_cookie_password(password)
else:
password = get_cookie_password()
print '\n'
if not is_password_set():
return_document(monitor_password_script_path)
elif not check_password(password):
print "<html><head>"
print """
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">"""
print "</head><body>"
if password is None:
print "<h1>This is the monitoring interface</h1>"
else:
print "<h1>Error</h1><p>Wrong password</p>"
print """
<p>Please enter the monitor_password in the next field to access the data</p>
<form action="/index.cgi" method="post" class="pure-form-aligned">
Password : <input type="password" name="password">
<button type="submit" class="pure-button pure-button-primary">Access</button>
</form>
</body></html>"""
# redirection to the required script/page
else:
print
if "posting-script" in form:
forward_form()
elif "script" in form:
return_document()
else:
html_base = jinja2.Template(open('{{ index_template }}').read())
print
print html_base.render(tree=make_menu(), default_page="{{ default_page }}", monitor_rewrite=monitor_rewrite)
<html>
<head>
<title>Monitoring Interface</title>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
<script src="static/jquery-1.10.2.min.js"></script>
<script src="static/script.js"></script>
</head>
<body>
<div id="div-menu">
<h1>Monitoring</h1>
<div id="script-categories" class="pure-menu pure-menu-open">
<ul>
{% for category in tree %}
<li class="pure-menu-heading category">{{ category }}</li>
{% for script in tree[category] %}
<li><a href="{{ category }}/{{ script }}" class="script">{{ script }}</a></li>
{% endfor %}
{% endfor %}
<li class="pure-menu-heading category">Files</li>
<li><a href="./private/" class="link"> User: admin</br> Password is yours</a></li>
<li class="pure-menu-heading category">Local Service</li>
{% set rewrite_list = monitor_rewrite.split() %}
{% for path in rewrite_list %}
<li><a href="./rewrite/{{path}}/" class="link">{{path}}</a></li>
{% endfor %}
</ul>
</div>
</div>
<div id="content">
<iframe src="{{ default_page }}">
</iframe>
</div>
</body>
</html>
#!{{ python_executable }}
import cgitb
cgitb.enable()
print "<html><head>"
print """
<script type="text/javascript" src="static/jquery-1.10.2.min.js"></script>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">"""
print "</head><body>"
print "<h1>This is the monitoring interface</h1>"
print "<h2>Please set your password for later access</h2>"
print """
<form action="/index.cgi" method="post" class="pure-form-aligned">
<div class="pure-control-group">
<label for="password">Password*:</label>
<input placeholder="Set your password" type="password" name="password" id="password"></br>
</div><div class="pure-control-group">
<label for="password">Verify Password*:</label>
<input placeholder="Verify password" type="password" name="password_2" id="password_2"></br>
</div><p id="validate-status" style="color:red"></p>
<div class="pure-controls">
<button id="register-button" type="submit" class="pure-button pure-button-primary" disabled>Access</button></div>
</form>
<script type="text/javascript" src="static/monitor-register.js"></script>
</body></html>
"""
#!{{ python_executable }}
import cgi
import cgitb
import ConfigParser
import os
cgitb.enable()
form = cgi.FieldStorage()
print "<html><head>"
print "<link rel=\"stylesheet\" href=\"static/pure-min.css\">"
print "<link rel=\"stylesheet\" href=\"static/style.css\">"
print "</head><body>"
config_file = "{{ config_cfg }}"
if not os.path.exists(config_file):
print "Your software does <b>not</b> embed 0-knowledge. \
This interface is useless in this case</body></html>"
exit(0)
parser = ConfigParser.ConfigParser()
parser.read(config_file)
if not parser.has_section('public'):
print "<p>Your software does not use 0-knowledge settings.</p></body></html>"
exit(0)
for name in form:
if parser.has_option('public', name):
parser.set('public', name, form[name].value)
with open(config_file, 'w') as file:
parser.write(file)
if len(form) > 0:
try:
os.remove("{{ timestamp }}")
except OSError:
pass
print "<h1>Values that can be defined :</h1>"
print "<form action=\"/index.cgi\" method=\"post\" class=\"pure-form-aligned\">"
print "<input type=\"hidden\" name=\"posting-script\" value=\"{{ pwd }}/{{ this_file }}\">"
for option in parser.options("public"):
print "<div class=\"pure-control-group\">"
print "<label for=\"%s\">%s</label>" % (cgi.escape(option, quote=True), cgi.escape(option))
print "<input type=\"text\" name=\"%s\" value=\"%s\">" % (cgi.escape(option, quote=True), cgi.escape(parser.get('public', option), quote=True))
print "</div>"
print "<div class=\"pure-controls\"><button type=\"submit\" class=\"pure-button \
pure-button-primary\">Save</button></div></form>"
print "<br><h1>Other values :</h1>"
print "<form class=\"pure-form-aligned\">"
for section in parser.sections():
if section != 'public':
for option in parser.options(section):
print "<div class=\"pure-control-group\">"
print "<label for=\"%s\">%s</label>" % (cgi.escape(option, quote=True), cgi.escape(option))
print "<input type=\"text\" name=\"%s\" value=\"%s\" readonly>" %(cgi.escape(option, quote=True), cgi.escape(parser.get(section, option), quote=True))
print "</div>"
print "</form>"
print "</body></html>"
$(window).load(function(){
$(document).ready(function() {
$("#password_2").keyup(validate);
});
function validate() {
var password1 = $("#password").val();
var password2 = $("#password_2").val();
if(password1 == password2) {
$("#register-button").removeAttr("disabled");
$("#validate-status").attr("style", "display:none");
}
else {
$("#register-button").attr("disabled", "disabled");
$("#validate-status").attr("style", "").text("Passwords do not match");
}
}
});
\ No newline at end of file
This diff is collapsed.
$(document).ready(function() {
function doDataUrl (data) {
var frame_content = document.getElementsByTagName("iframe")[0].contentWindow;
var b64 = btoa(data);
dataurl = 'data:text/html;base64,' + b64;
$("iframe").attr('src', dataurl);
}
if ( window.self === window.top ) {
//not in an iframe
$(".script").click(function(e) {
e.preventDefault();
var message = $(this).attr('href');
var slash_pos = message.search('/');
//let's differenciate kind of script called
if ( slash_pos === -1 || slash_pos === 0) {
url = message;
}
else {
url = '/index.cgi';
}
$("iframe").attr('src', url + '?script=' + encodeURIComponent(message));
});
$(".link").click(function(e) {
e.preventDefault();
var url = $(this).attr('href');
$("iframe").attr('src', url);
});
}
else {
//in an iframe
$("body").empty();
}
});
body {
padding: 15px;
}
.pure-menu .pure-menu-heading {
font-size: 120%;
}
#content {
display: inline-block;
min-width: 72%;
height: 97%;
margin-left: 30px;
}
#div-menu {
display: inline-block;
vertical-align: top;
}
#div-menu h1 {
text-align: center;
}
iframe {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
border-style: none;
}
<html>
<head>
<title>Welcome to the Monitoring Interface</title>
<link rel="stylesheet" href="pure-min.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Welcome to your monitoring interface</h1>
<p>From this interface you can monitor, configure your instance</p>
</body>
</html>
#!{{ python_executable }}
import cgi
import datetime
import os
import sqlite3
db_path = '{{ monitor_db_path }}'
status_history_length = '{{ status_history_length }}'
db = sqlite3.connect(db_path)
print """<html><head>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
</head><body>
<h1>Monitor Status History :</h1>"""
def get_date_from_timestamp(timestamp):
return datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
def print_individual_status(timestamp):
print "<div><h3>Failure on %s</h3><ul>" % get_date_from_timestamp(timestamp)
rows = db.execute("select status, element, output from individual_status where timestamp=?", (timestamp,))
for row in rows:
status, element, output = row
print "<li>%s , %s :</br><pre>%s</pre></li>" % (status, cgi.escape(element), cgi.escape(output))
print "</ul></div>"
if not os.path.exists(db_path):
print """No status history found</p></body></html>"""
exit(0)
failure_row_list = db.execute("select timestamp from status where status='FAILURE' order by timestamp desc limit ?", status_history_length )
for failure_row in failure_row_list:
timestamp, = failure_row
print_individual_status(timestamp)
print "</body></html>"
#!{{ python_executable }}
import cgi
import cgitb
import json
import os
import subprocess
def refresh():
command = ["{{ monitor_bin }}", "-a"]
subprocess.call(command)
cgitb.enable(display=0, logdir="/tmp/cgi.log")
form = cgi.FieldStorage()
json_file = "{{ json_file }}"
if not os.path.exists(json_file) or "refresh" in form:
refresh()
if not os.path.exists(json_file):
print """<html><head>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
</head><body>
<h1>Monitoring :</h1>
No status file found</p></body></html>"""
exit(0)
result = json.load(open(json_file))
print "<html><head>"
print "<link rel=\"stylesheet\" href=\"static/pure-min.css\">"
print "<link rel=\"stylesheet\" href=\"static/style.css\">"
print "</head><body>"
print "<h1>Monitoring :</h1>"
print "<form action=\"/index.cgi\" method=\"post\" class=\"pure-form-aligned\">"
print "<input type=\"hidden\" name=\"posting-script\" value=\"{{ pwd }}/{{ this_file }}\">"
print "<p><em>Last time of monitoring process : %s</em></p>" % (result['datetime'])
del result['datetime']
print "<div class=\"pure-controls\"><button type=\"submit\" class=\"pure-button \
pure-button-primary\" name=\"refresh\" value=\"refresh\">Refresh</button></div></form>"
print "<br/>"
print "<h2>These scripts and promises have failed :</h2>"
for r in result:
if result[r] != '':
print "<h3>%s</h3><pre style=\"padding-left:30px;\">%s</pre>" % (cgi.escape(r), cgi.escape(result[r]))
print "<br/>"
print "<h2>These scripts and promises were successful :</h2>"
print "<ul>"
for r in result:
if result[r] == '':
print "<li>%s</li>" % (r)
print "</ul>"
print "</body></html>"
[buildout]
# XXX THIS STACK IS A KIND OF FORK OF `stack/monitor`. THIS ONE WAS
# CREATED AS A REDESIGNED ONE TO REMOVE UNWANTED FEATURES AND
# TO GO FURTHER TO THE GOOD DESIGN DIRECTION. SEE THE README FOR
# MORE INFORMATION.
extends =
../../component/apache/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/dcron/buildout.cfg
../../component/openssl/buildout.cfg
parts +=
slapos-cookbook
eggs
extra-eggs
monitor2-template
[monitor-download-base]
recipe = hexagonit.recipe.download
download-only = true
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[monitor-web-base]
<= monitor-download-base
url = ${:_profile_base_location_}/web/${:filename}
destination = ${buildout:parts-directory}/monitor-web
on-update = true
[monitor-template-base]
<= monitor-download-base
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]
recipe = zc.recipe.egg
eggs +=
collective.recipe.template
cns.recipe.symlink
[extra-eggs]
<= eggs
interpreter = pythonwitheggs
eggs +=
psutil
PyRSS2Gen
Jinja2
# Monitor templates files
[monitor-httpd-conf]
<= monitor-template-base
md5sum = 08137be9b80e0e13d9a906c264a2f51f
filename = monitor-httpd.conf.in
[monitor-service-conf-template]
<= monitor-template-base
filename = monitor-service.cfg.in
md5sum = 5913d2a0096b50537f394a49b762b3e5
[template-wrapper]
<= monitor-template-base
filename = wrapper.in
md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
[monitor-conf]
<= monitor-template-base
filename = monitor.conf.in
md5sum = c8f024d741c6494d7c9ba01601d0b917
[monitor-instance-info]
<= monitor-template-base
filename = instance-info.conf.in
md5sum = 1bdb4e05c6be04f4e5766c64467fbcec
[monitor-httpd-cors]
<= monitor-template-base
filename = httpd-cors.cfg.in
md5sum = 5afad2bb6e088e080e907f1d837effbb
# End templates files
[monitor2-template]
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 = e439e22e754a50e1a3500cd4a995f6d8
context =
key apache_location apache:location
key gzip_location gzip:location
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_document_edit ${monitor-document-edit:location}/${monitor-document-edit:filename}
raw monitor_https_cors ${monitor-httpd-cors:location}/${monitor-httpd-cors: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 curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash
raw dcron_executable_location ${dcron:location}/sbin/crond
raw logrotate_executable_location ${logrotate:location}/usr/sbin/logrotate
raw monitor_httpd_template ${monitor-httpd-conf:location}/${monitor-httpd-conf: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 python_executable ${buildout:executable}
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 status2rss_executable_path ${status2rss-executable:location}/${status2rss-executable:filename}
[monitor2-bin]
<= monitor-template-script
filename = monitor.py
md5sum = 927501a8c4ce8dcc39d55af1efdc66ed
[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
mode = 0755
context =
raw python ${buildout:directory}/bin/${extra-eggs:interpreter}
[monitor-password-promise]
<= monitor-template-script
filename = monitor-password-promise.py
md5sum = f7e937d6619eb674f39f34718928d91d
[status2rss-executable]
<= monitor-template-script
filename = status2rss.py
md5sum = f297779d0881f4bd48081506efb492a4
[monitor-globalstate]
<= monitor-template-script
filename = globalstate.py
md5sum = 384a1148cb3da9cf353a108fe70709c5
[monitor-collect]
<= monitor-template-script
filename = collect.py
md5sum = cc65aebd4c35b3172a7ca83abde761bc
[monitor-document-edit]
<= monitor-template-script
filename = monitor-document.py
md5sum = 79c53518e53ae8c8487b09bb49bc7b80
[make-rss-script]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/make-rss.sh.in
md5sum = 98c8f6fd81e405b0ad10db07c3776321
output = ${buildout:directory}/template-make-rss.sh.in
mode = 0644
[monitor-web-monitor-logout-cgi]
recipe = slapos.recipe.template:jinja2
filename = monitor-logout.py.cgi
md5sum = 5b3c0aa559722a3bae5a692ea9a0a441
mode = 0755
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/monitor-logout.cgi
context = key python_executable buildout:executable
[monitor-web-monitor-promise-runner-cgi]
<= monitor-download-base
filename = monitor-run-promise.py.cgi
md5sum = 15625e5bf6c1b57b9199250951ffc16e
[monitor-password-py-cgi]
<= monitor-download-base
md5sum = 04fc7e6d892d29a601cfd43d1700eeda
filename = monitor-password.py.cgi
#!${dash-output:dash}
STATUS_DB={{ monitor_parameters['db-path'] }}
RSS_FILE={{ monitor_parameters['rss-path'] }}
PYTHON=${buildout:directory}/bin/${extra-eggs:interpreter}
STATUS2RSS=${rss-bin:location}/${rss-bin:filename}
$PYTHON $STATUS2RSS "Monitoring RSS feed" "{{ monitor_parameters['url'] }}/{{ monitor_parameters['index-filename'] }}" $STATUS_DB > $RSS_FILE
#!${dash-output:dash}
{{ content }}
\ No newline at end of file
......@@ -6,7 +6,7 @@ extends =
../../component/gzip/buildout.cfg
../../component/rdiff-backup/buildout.cfg
../../component/rsync/buildout.cfg
../monitor2/buildout.cfg
../monitor/buildout.cfg
parts =
collective.recipe.template-egg
......
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