Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
107
Merge Requests
107
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
slapos
Commits
d6634962
Commit
d6634962
authored
Dec 28, 2015
by
Alain Takoudjou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cleanup monitor2 stack
parent
b1dcbf77
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
397 additions
and
1257 deletions
+397
-1257
stack/monitor2/buildout.cfg
stack/monitor2/buildout.cfg
+94
-139
stack/monitor2/cgi-httpd.conf.in
stack/monitor2/cgi-httpd.conf.in
+0
-85
stack/monitor2/index.html
stack/monitor2/index.html
+0
-10
stack/monitor2/instance-monitor.cfg.jinja2.in
stack/monitor2/instance-monitor.cfg.jinja2.in
+24
-58
stack/monitor2/monitor-service-run.in
stack/monitor2/monitor-service-run.in
+4
-0
stack/monitor2/monitor.cfg.in
stack/monitor2/monitor.cfg.in
+0
-290
stack/monitor2/monitor.py.in
stack/monitor2/monitor.py.in
+0
-141
stack/monitor2/scripts/monitor-password-promise.py
stack/monitor2/scripts/monitor-password-promise.py
+2
-1
stack/monitor2/scripts/monitor.py
stack/monitor2/scripts/monitor.py
+203
-0
stack/monitor2/scripts/run-promise.py
stack/monitor2/scripts/run-promise.py
+1
-2
stack/monitor2/scripts/status2rss.py
stack/monitor2/scripts/status2rss.py
+0
-0
stack/monitor2/templates/monitor-httpd.conf.in
stack/monitor2/templates/monitor-httpd.conf.in
+20
-0
stack/monitor2/templates/monitor-service.cfg.in
stack/monitor2/templates/monitor-service.cfg.in
+0
-0
stack/monitor2/templates/monitor.conf.in
stack/monitor2/templates/monitor.conf.in
+0
-0
stack/monitor2/templates/wrapper.in
stack/monitor2/templates/wrapper.in
+0
-0
stack/monitor2/web/default-promise-interface.html
stack/monitor2/web/default-promise-interface.html
+0
-0
stack/monitor2/web/index.html
stack/monitor2/web/index.html
+22
-0
stack/monitor2/web/logout.html
stack/monitor2/web/logout.html
+0
-0
stack/monitor2/web/monitor-password-interface.html
stack/monitor2/web/monitor-password-interface.html
+0
-0
stack/monitor2/web/monitor.css
stack/monitor2/web/monitor.css
+7
-0
stack/monitor2/web/monitor.js
stack/monitor2/web/monitor.js
+20
-7
stack/monitor2/webfile-directory/ansible-report.cgi.in
stack/monitor2/webfile-directory/ansible-report.cgi.in
+0
-0
stack/monitor2/webfile-directory/index.cgi.in
stack/monitor2/webfile-directory/index.cgi.in
+0
-190
stack/monitor2/webfile-directory/index.html.jinja2
stack/monitor2/webfile-directory/index.html.jinja2
+0
-35
stack/monitor2/webfile-directory/monitor-password.cgi.in
stack/monitor2/webfile-directory/monitor-password.cgi.in
+0
-29
stack/monitor2/webfile-directory/settings.cgi.in
stack/monitor2/webfile-directory/settings.cgi.in
+0
-64
stack/monitor2/webfile-directory/static/monitor-register.js
stack/monitor2/webfile-directory/static/monitor-register.js
+0
-17
stack/monitor2/webfile-directory/static/pure-min.css
stack/monitor2/webfile-directory/static/pure-min.css
+0
-11
stack/monitor2/webfile-directory/static/script.js
stack/monitor2/webfile-directory/static/script.js
+0
-35
stack/monitor2/webfile-directory/static/style.css
stack/monitor2/webfile-directory/static/style.css
+0
-31
stack/monitor2/webfile-directory/static/welcome.html
stack/monitor2/webfile-directory/static/welcome.html
+0
-11
stack/monitor2/webfile-directory/status-history.cgi.in
stack/monitor2/webfile-directory/status-history.cgi.in
+0
-44
stack/monitor2/webfile-directory/status.cgi.in
stack/monitor2/webfile-directory/status.cgi.in
+0
-57
No files found.
stack/monitor2/buildout.cfg
View file @
d6634962
...
...
@@ -13,18 +13,9 @@ extends =
parts +=
slapos-cookbook
dcron
monitor-eggs
eggs
extra-eggs
monitor-conf
monitor-bin
monitor-web-index-html
monitor-web-monitor-css
monitor-web-monitor-js
monitor-web-monitor-logout-cgi
monitor-web-monitor-logout-page
monitor-template
rss-bin
monitor2-template
[monitor-download-base]
recipe = hexagonit.recipe.download
...
...
@@ -32,9 +23,19 @@ download-only = true
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[monitor-eggs]
[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}
[eggs]
recipe = zc.recipe.egg
eggs =
eggs
+
=
collective.recipe.template
cns.recipe.symlink
...
...
@@ -45,79 +46,83 @@ eggs =
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-conf]
<= monitor-download-base
filename = monitor.conf.in
md5sum = 2db5c08c7e8658981b4b1e3f27fd5967
[monitor-bin]
<= monitor-download-base
filename = monitor.py.in
md5sum = 2484cb185c391890a05db26c2163af8e
# Monitor html files
# XXX Can be removed from software release
[monitor-web-default-promise-interface]
<= monitor-
download
-base
<= monitor-
web
-base
filename = default-promise-interface.html
md5sum = eaedae330cd155f8b693b418286d0d98
[monitor-web-index-html]
<= monitor-
download
-base
<= monitor-
web
-base
filename = index.html
md5sum =
262db07691c145301252a49b6b51d11d
md5sum =
58fe6ada21d1b0b25a2a38374ec676d3
[monitor-web-monitor-css]
<= monitor-
download
-base
<= monitor-
web
-base
filename = monitor.css
md5sum =
a18ab932e5e2e656995f47c7d4a7853a
md5sum =
3cb91de30c729143af78461431fc6f8c
[monitor-web-monitor-js]
<= monitor-download-base
filename = monitor.js.in
md5sum = 3451788c49d3664cd9b72551fab34a9b
[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-base
filename = monitor.js
md5sum = 29ee4b9a99a7164581ccf5cbf75d33ba
[monitor-web-monitor-logout-page]
<= monitor-
download
-base
filename =
monitor-
logout.html
<= monitor-
web
-base
filename = logout.html
md5sum = b210c6842df541305d299081bc1bf81e
[monitor-
web-monitor-promise-runner-cgi
]
[monitor-
password-promise-interface
]
<= monitor-download-base
filename = monitor-run-promise.py.cgi
md5sum = 15625e5bf6c1b57b9199250951ffc16e
filename = monitor-password-interface.html
url = ${:_profile_base_location_}/web/${:filename}
md5sum = 04b664dfb47bfd3d01502768311aa239
# End Monitor web files
[monitor-template]
# Monitor templates files
[monitor-httpd-conf]
<= monitor-template-base
md5sum = 8a1aa7cba281877d6cf63cb8ade64b5e
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 = 2db5c08c7e8658981b4b1e3f27fd5967
# 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 =
6d5f1ceff198262319566ee25093c350
md5sum =
bf0578bb6863fea73c1c40bc009c7654
context =
key apache_location apache:location
key gzip_location gzip:location
raw monitor_bin ${monitor
-bin:location}/${monitor
-bin:filename}
raw monitor_bin ${monitor
2-bin:location}/${monitor2
-bin:filename}
raw monitor_conf_template ${monitor-conf:location}/${monitor-conf:filename}
raw monitor_password_promise_template ${monitor-password-promise:location}/${monitor-password-promise:filename}
raw monitor_password_cgi_template ${monitor-password-
cgi:location}/${monitor-password
-cgi:filename}
raw monitor_password_cgi_template ${monitor-password-
py-cgi:location}/${monitor-password-py
-cgi:filename}
raw monitor_password_promise_interface_template ${monitor-password-promise-interface:location}/${monitor-password-promise-interface:filename}
raw monitor_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_monitor_css ${monitor-web-monitor-css:location}/${monitor-web-monitor-css:filename}
raw monitor_web_directory ${monitor-web-index-html:location}
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_promise_runner_cgi ${monitor-web-monitor-promise-runner-cgi:location}/${monitor-web-monitor-promise-runner-cgi:filename}
...
...
@@ -128,113 +133,63 @@ context =
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 monitor_service_run ${monitor-service-template-run:location}/${monitor-service-template-run:filename}
raw openssl_executable_location ${openssl:location}/bin/openssl
raw python_executable ${buildout:executable}
raw promise_executor_py ${run-promise-py:location}/${run-promise-py:filename}
raw template_wrapper ${template-wrapper:output}
raw status2rss_executable_path ${status2rss-executable:location}/${status2rss-executable:filename}
[monitor
-httpd-conf
]
[monitor
2-bin
]
<= monitor-download-base
md5sum = 625d3d948c0af7b4848d7fad92bfb844
filename = monitor-httpd.conf.in
filename = monitor.py
md5sum = 7e1f2210a87b2212d11524e06985dd49
url = ${:_profile_base_location_}/scripts/${:filename}
[
monitor-service-conf-template
]
[
run-promise-py
]
<= monitor-download-base
filename = monitor-service.cfg.in
md5sum = 5913d2a0096b50537f394a49b762b3e5
filename = run-promise.py
md5sum = 8a46adcbc126ec9589d1810ba291d048
mode = 0755
url = ${:_profile_base_location_}/scripts/${:filename}
[monitor-
service-template-run
]
[monitor-
password-promise
]
<= monitor-download-base
md5sum = d5f29fa859a45696e1ff1bb174ab1111
filename = monitor-service-run.in
filename = monitor-password-promise.py
md5sum = f7e937d6619eb674f39f34718928d91d
url = ${:_profile_base_location_}/scripts/${:filename}
[
run-promise-py
]
[
status2rss-executable
]
<= monitor-download-base
filename = run-promise.py
md5sum = 6db26ce13becf8a190e34c14cb8b6f9f
filename = status2rss.py
md5sum = 65315ded80cd72f54f6e12d06ce813c4
url = ${:_profile_base_location_}/scripts/${:filename}
[monitor-httpd-template]
<= monitor-download-base
md5sum = 93e1dda50cb71bfe29966b2946c02dd1
filename = cgi-httpd.conf.in
[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
[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
[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
[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
[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
[
settings
-cgi]
recipe =
hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
m
d5sum = b4cef123a3273e848e8fe496e22b20a8
destination = ${buildout:parts-directory}/monitor-template-settings-cgi
filename = settings.cgi.in
mode = 0644
[
monitor-web-monitor-logout
-cgi]
recipe =
slapos.recipe.template:jinja2
filename = monitor-logout.py.cgi
md5sum = 5b3c0aa559722a3bae5a692ea9a0a441
m
ode = 0755
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/monitor-logout.cgi
context = key python_executable buildout:executable
[monitor-
password-promise
]
[monitor-
web-monitor-promise-runner-cgi
]
<= monitor-download-base
filename = monitor-
password-promise.py.in
md5sum =
0a9a42551ed6bdb973fd1f0dd1d4ec86
filename = monitor-
run-promise.py.cgi
md5sum =
15625e5bf6c1b57b9199250951ffc16e
[monitor-password-cgi]
[monitor-password-
py-
cgi]
<= monitor-download-base
md5sum = 04fc7e6d892d29a601cfd43d1700eeda
filename = monitor-password.py.cgi
[monitor-password-promise-interface]
<= monitor-download-base
filename = monitor-password-interface.html
md5sum = 04b664dfb47bfd3d01502768311aa239
[status2rss-executable]
<= monitor-download-base
filename = status2rss.py
md5sum = 65315ded80cd72f54f6e12d06ce813c4
[dcron-service]
recipe = slapos.recipe.template
url = ${template-dcron-service:output}
output = $${directory:services}/crond
mode = 0700
logfile = $${directory:log}/crond.log
[template-wrapper]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/wrapper.in
output = ${buildout:directory}/template-wrapper.cfg
mode = 0644
md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
stack/monitor2/cgi-httpd.conf.in
deleted
100644 → 0
View file @
b1dcbf77
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 %}
stack/monitor2/index.html
deleted
100644 → 0
View file @
b1dcbf77
<!DOCTYPE html>
<html>
<head>
<link
rel=
"stylesheet"
href=
"monitor.css"
/>
<script
src=
"monitor.js"
></script>
</head>
<body>
<noscript>
Please enable javascript on your browser to make this application to work.
</noscript>
</body>
</html>
stack/monitor2/instance-monitor.cfg.jinja2.in
View file @
d6634962
...
...
@@ -115,14 +115,18 @@ wrapper = ${directory:services}/monitor-httpd
[monitor-conf-parameters]
title = ${monitor-instance-parameter:monitor-title}
service-executable-dir = ${monitor-directory:run}
template-service-run = {{ monitor_service_run }}
public-folder = ${monitor-directory:public}
private-folder = ${monitor-directory:private}
web-folder = ${monitor-directory:web-dir}
monitor-hal-json = ${monitor-directory:web-dir}/monitor.haljson
service-pid-folder = ${monitor-directory:pids}
crond-folder = ${logrotate-directory:cron-entries}
wraper-folder = ${monitor-directory:promise-wrapper}
promise-runner = {{ promise_executor_py }}
promise-folder-list =
${directory:promises}
${directory:monitor-promise}
public-path-list =
${directory:log}
private-path-list =
...
...
@@ -136,6 +140,19 @@ rendered = ${directory:etc}/${:filename}
filename = monitor.conf
context = section parameter_dict monitor-conf-parameters
[python-symlink]
recipe = plone.recipe.command
target = ${directory:bin}
command = ln -sf {{ python_executable }} ${:target}/python
update-command = ${:command}
[start-monitor]
recipe = slapos.cookbook:wrapper
command-line = {{ python_executable }} {{ monitor_bin }} --config_file ${monitor-conf:rendered}
wrapper-path = ${directory:scripts}/bootstrap-monitor
environment =
PATH=${python-symlink:target}:/usr/local/bin:/usr/bin:/bin
[httpd-monitor-htpasswd]
recipe = plone.recipe.command
stop-on-error = true
...
...
@@ -195,30 +212,11 @@ name = monitor-status2rss
frequency = * * * * *
command = ${monitor-status2rss-wrapper:wrapper-path}
[monitor-web-default-promise-interface]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_default_promise_interface }}
rendered = ${monitor-directory:web-dir}/default-promise-interface.html
context =
[monitor-web-index-html]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_index_html }}
rendered = ${monitor-directory:web-dir}/index.html
context =
[monitor-web-monitor-css]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_css }}
rendered = ${monitor-directory:web-dir}/monitor.css
context =
[monitor-web-directory]
recipe = plone.recipe.command
command = cp -f {{ monitor_web_directory }}/* ${monitor-directory:web-dir}
update-command = ${:command}
[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
[monitor-web-monitor-logout-cgi]
recipe = slapos.recipe.template:jinja2
...
...
@@ -227,12 +225,6 @@ rendered = ${monitor-directory:cgi-bin}/monitor-logout.cgi
mode = 0755
context =
[monitor-web-monitor-logout-page]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_logout_page }}
rendered = ${monitor-directory:web-dir}/logout
context =
[monitor-web-monitor-promise-runner-cgi]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_web_monitor_promise_runner_cgi }}
...
...
@@ -242,28 +234,6 @@ context =
raw python_executable {{ python_executable }}
key promise_wrapper_folder monitor-directory:promise-wrapper
[start-monitor]
recipe = slapos.recipe.template:jinja2
template = {{ monitor_bin }}
rendered = ${directory:scripts}/bootstrap-monitor
context =
raw python_executable {{ python_executable }}
key public_folder monitor-directory:public
key private_folder monitor-directory:private
key monitor_configuration_path monitor-conf:rendered
key promise_runner_path monitor-run-promise:rendered
key promise_folder directory:promises
key monitor_promise_folder directory:monitor-promise
key promise_wrapper_folder monitor-directory:promise-wrapper
[monitor-run-promise]
recipe = slapos.recipe.template:jinja2
template = {{ promise_executor_py }}
rendered = ${directory:bin}/monitor-run-promise
mode = 700
context =
raw python_executable {{ python_executable }}
[monitor-httpd-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/${:filename}
...
...
@@ -337,12 +307,8 @@ monitor-title = Monitoring interface
[buildout]
parts =
monitor-web-default-promise-interface
monitor-web-index-html
monitor-web-monitor-css
monitor-web-monitor-js
monitor-web-directory
monitor-web-monitor-logout-cgi
monitor-web-monitor-logout-page
monitor-web-monitor-promise-runner-cgi
cron-entry-logrotate
certificate-authority
...
...
stack/monitor2/monitor-service-run.in
View file @
d6634962
...
...
@@ -34,4 +34,8 @@ def main():
pidfile
.
write
(
str
(
process
.
pid
))
if
__name__
==
"__main__"
:
if
len
(
sys
.
argv
)
==
1
:
print
"Use: %s Monitor_Config_File"
sys
.
exit
(
1
)
sys
.
exit
(
main
())
\ No newline at end of file
stack/monitor2/monitor.cfg.in
deleted
100644 → 0
View file @
b1dcbf77
[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}
stack/monitor2/monitor.py.in
deleted
100644 → 0
View file @
b1dcbf77
#!{{ python_executable }}
# Put this file in the software release
promise_runner_path = "{{ promise_runner_path }}"
public_folder = "{{ public_folder }}"
private_folder = "{{ private_folder }}"
monitor_configuration_path = "{{ monitor_configuration_path }}"
promise_folder = "{{ promise_folder }}"
monitor_promise_folder = "{{ monitor_promise_folder }}"
promise_wrapper_folder = "{{ promise_wrapper_folder }}"
import sys
import os
import stat
import subprocess
import threading
import json
import ConfigParser
import traceback
def main():
# initialisation
config = loadConfig([monitor_configuration_path])
# get promises in monitor_promise_folder
promise_dict = {}
fillPromiseDictFromFolder(promise_dict, monitor_promise_folder)
# get promises in promise_folder
fillPromiseDictFromFolder(promise_dict, promise_folder)
# get promises configurations
for filename in os.listdir(monitor_promise_folder):
path = os.path.join(monitor_promise_folder, filename)
if os.path.isfile(path) and filename[-4:] == ".cfg":
promise_name = filename[:-4]
if promise_name in promise_dict:
loadConfig([path], promise_dict[promise_name]["configuration"])
promise_items = promise_dict.items()
# create symlinks from service configurations
for service_name, promise in promise_items:
service_config = promise["configuration"]
createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list"), service_name)
createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list"), service_name)
# 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"))
# generate monitor.json
monitor_dict = {}
tmp = softConfigGet(config, "monitor", "title")
if tmp:
monitor_dict["title"] = tmp
tmp = softConfigGet(config, "monitor", "monitor-url-list")
if tmp:
monitor_dict["_links"] = {"related_monitor": [{"href": url} for url in tmp.split()]}
if promise_items:
service_list = []
monitor_dict["_embedded"] = {"service": service_list}
for service_name, promise in promise_items:
service_config = promise["configuration"]
service_dict = {}
service_list.append(service_dict)
service_dict["id"] = service_name
service_dict["_links"] = {"status": {"href": "/public/%s.status.json" % service_name}} # hardcoded
tmp = softConfigGet(service_config, "service", "title")
if tmp:
service_dict["title"] = tmp
interface_path = os.path.join(private_folder, service_name, "interface/index.html") # hardcoded
if os.path.isfile(interface_path):
service_dict["_links"]["interface"] = {"href": "/private/%s/interface/" % service_name} # hardcoded
else:
service_dict["_links"]["interface"] = {"href": "/default-promise-interface.html?service_name=%s" % service_name} # XXX hardcoded
with open(config.get("monitor", "monitor-hal-json"), "w") as fp:
json.dump(monitor_dict, fp)
# put promises to a cron file
# XXX only if at least one configuration file is modified, then write in the cron
service_pid_folder = config.get("monitor", "service-pid-folder")
crond_folder = config.get("monitor", "crond-folder")
cron_line_list = []
for service_name, promise in promise_items:
service_status_path = "%s/%s.status.json" % (public_folder, service_name) # hardcoded
mkdirAll(os.path.dirname(service_status_path))
command = ("%s %s %s " % (
promise_runner_path,
os.path.join(service_pid_folder, "%s.pid" % service_name),
service_status_path,
)) + 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:
fp.write("\n".join(cron_line_list))
return 0
def loadConfig(pathes, config=None):
if config is None:
config = ConfigParser.ConfigParser()
try:
config.read(pathes)
except ConfigParser.MissingSectionHeaderError:
traceback.print_exc()
return config
def fillPromiseDictFromFolder(promise_dict, folder):
for filename in os.listdir(folder):
path = os.path.join(folder, filename)
if os.path.isfile(path) and os.access(path, os.X_OK):
promise_dict[filename] = {"path": path, "configuration": ConfigParser.ConfigParser()}
def softConfigGet(config, *args, **kwargs):
try:
return config.get(*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return None
def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple, service_name=""):
destination_folder = softConfigGet(*destination_folder_config_tuple)
if destination_folder:
source_path_str = softConfigGet(*source_list_config_tuple)
if source_path_str:
for path in source_path_str.split():
dirname = os.path.join(destination_folder, service_name)
try:
mkdirAll(dirname) # could also raise OSError
os.symlink(path, os.path.join(dirname, os.path.basename(path)))
except OSError, e:
if e.errno != os.errno.EEXIST:
raise
def mkdirAll(path):
try:
os.makedirs(path)
except OSError, e:
if e.errno == os.errno.EEXIST and os.path.isdir(path):
pass
else: raise
if __name__ == "__main__":
sys.exit(main())
stack/monitor2/
monitor-password-promise.py.in
→
stack/monitor2/
scripts/monitor-password-promise.py
View file @
d6634962
#!{{ python_executable }}
#!/usr/bin/env python
password_changed_once_path
=
"{{ password_changed_once_path }}"
import
os
...
...
stack/monitor2/scripts/monitor.py
0 → 100644
View file @
d6634962
#!/usr/bin/env python
import
sys
import
os
import
stat
import
subprocess
import
threading
import
json
import
ConfigParser
import
traceback
import
argparse
def
parseArguments
():
"""
Parse arguments for monitor instance.
"""
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'--config_file'
,
default
=
'monitor.cfg'
,
help
=
'Monitor Configuration file'
)
parser
.
add_argument
(
'--promise-folder'
,
action
=
'append'
,
dest
=
'promise_folder_list'
,
default
=
[],
help
=
'The path to get promise executable files'
)
parser
.
add_argument
(
'--public-folder'
,
action
=
'append'
,
dest
=
'public_folder'
,
help
=
'The path of public folder. All files in this folders will have public acess'
)
parser
.
add_argument
(
'--private-folder'
,
action
=
'append'
,
dest
=
'private_folder'
,
help
=
'The path of private folder. All files in this folders will be accessible with password'
)
parser
.
add_argument
(
'--promise-runner'
,
help
=
'The path of promise runner, use to run promise files'
)
parser
.
add_argument
(
'--wrapper-path'
,
help
=
'Path of monitor generated promise scripts files.'
)
return
parser
.
parse_args
()
def
mkdirAll
(
path
):
try
:
os
.
makedirs
(
path
)
except
OSError
,
e
:
if
e
.
errno
==
os
.
errno
.
EEXIST
and
os
.
path
.
isdir
(
path
):
pass
else
:
raise
def
softConfigGet
(
config
,
*
args
,
**
kwargs
):
try
:
return
config
.
get
(
*
args
,
**
kwargs
)
except
(
ConfigParser
.
NoOptionError
,
ConfigParser
.
NoSectionError
):
return
None
class
Monitoring
(
object
):
def
__init__
(
self
,
configuration_file
):
config
=
self
.
loadConfig
([
configuration_file
])
# Set Monitor variables
self
.
monitor_hal_json
=
config
.
get
(
"monitor"
,
"monitor-hal-json"
)
self
.
title
=
config
.
get
(
"monitor"
,
"title"
)
self
.
service_pid_folder
=
config
.
get
(
"monitor"
,
"service-pid-folder"
)
self
.
crond_folder
=
config
.
get
(
"monitor"
,
"crond-folder"
)
self
.
wraper_folder
=
config
.
get
(
"monitor"
,
"wraper-folder"
)
self
.
promise_runner
=
config
.
get
(
"monitor"
,
"promise-runner"
)
self
.
promise_folder_list
=
config
.
get
(
"monitor"
,
"promise-folder-list"
).
split
()
self
.
public_folder
=
config
.
get
(
"monitor"
,
"public-folder"
)
self
.
private_folder
=
config
.
get
(
"monitor"
,
"private-folder"
)
self
.
public_path_list
=
config
.
get
(
"monitor"
,
"public-path-list"
).
split
()
self
.
private_path_list
=
config
.
get
(
"monitor"
,
"private-path-list"
).
split
()
self
.
monitor_url_list
=
config
.
get
(
"monitor"
,
"monitor-url-list"
).
split
()
self
.
promise_dict
=
{}
for
promise_folder
in
self
.
promise_folder_list
:
self
.
setupPromiseDictFromFolder
(
promise_folder
)
def
loadConfig
(
self
,
pathes
,
config
=
None
):
if
config
is
None
:
config
=
ConfigParser
.
ConfigParser
()
try
:
config
.
read
(
pathes
)
except
ConfigParser
.
MissingSectionHeaderError
:
traceback
.
print_exc
()
return
config
def
setupPromiseDictFromFolder
(
self
,
folder
):
for
filename
in
os
.
listdir
(
folder
):
path
=
os
.
path
.
join
(
folder
,
filename
)
if
os
.
path
.
isfile
(
path
)
and
os
.
access
(
path
,
os
.
X_OK
):
self
.
promise_dict
[
filename
]
=
{
"path"
:
path
,
"configuration"
:
ConfigParser
.
ConfigParser
()}
# get promises configurations
#for filename in os.listdir(monitor_promise_folder):
# path = os.path.join(monitor_promise_folder, filename)
# if os.path.isfile(path) and filename[-4:] == ".cfg":
# promise_name = filename[:-4]
# if promise_name in promise_dict:
# loadConfig([path], promise_dict[promise_name]["configuration"])
def
createSymlinksFromConfig
(
self
,
destination_folder
,
source_path_list
,
service_name
=
""
):
if
destination_folder
:
if
source_path_list
:
for
path
in
source_path_list
:
dirname
=
os
.
path
.
join
(
destination_folder
,
service_name
)
try
:
mkdirAll
(
dirname
)
# could also raise OSError
os
.
symlink
(
path
,
os
.
path
.
join
(
dirname
,
os
.
path
.
basename
(
path
)))
except
OSError
,
e
:
if
e
.
errno
!=
os
.
errno
.
EEXIST
:
raise
def
generateMonitorHalJson
(
self
):
if
self
.
title
:
self
.
monitor_dict
[
"title"
]
=
self
.
title
if
self
.
monitor_url_list
:
self
.
monitor_dict
[
"_links"
]
=
{
"related_monitor"
:
[{
"href"
:
url
}
for
url
in
self
.
monitor_url_list
]}
if
self
.
promise_items
:
service_list
=
[]
for
service_name
,
promise
in
self
.
promise_items
:
service_config
=
promise
[
"configuration"
]
service_dict
=
{}
service_dict
[
"id"
]
=
service_name
service_dict
[
"_links"
]
=
{
"status"
:
{
"href"
:
"/public/%s.status.json"
%
service_name
}}
# hardcoded
tmp
=
softConfigGet
(
service_config
,
"service"
,
"title"
)
if
tmp
:
service_dict
[
"title"
]
=
tmp
interface_path
=
os
.
path
.
join
(
self
.
private_folder
,
service_name
,
"interface/index.html"
)
# hardcoded
if
os
.
path
.
isfile
(
interface_path
):
service_dict
[
"_links"
][
"interface"
]
=
{
"href"
:
"/private/%s/interface/"
%
service_name
}
# hardcoded
else
:
service_dict
[
"_links"
][
"interface"
]
=
{
"href"
:
"/default-promise-interface.html?service_name=%s"
%
service_name
}
# XXX hardcoded
service_list
.
append
(
service_dict
)
self
.
monitor_dict
[
"_embedded"
]
=
{
"service"
:
service_list
}
with
open
(
self
.
monitor_hal_json
,
"w"
)
as
fp
:
json
.
dump
(
self
.
monitor_dict
,
fp
)
def
generateServiceCronEntries
(
self
):
# XXX only if at least one configuration file is modified, then write in the cron
cron_line_list
=
[]
for
service_name
,
promise
in
self
.
promise_items
:
service_config
=
promise
[
"configuration"
]
service_status_path
=
"%s/%s.status.json"
%
(
self
.
public_folder
,
service_name
)
# hardcoded
mkdirAll
(
os
.
path
.
dirname
(
service_status_path
))
command
=
(
"%s %s %s "
%
(
self
.
promise_runner
,
os
.
path
.
join
(
self
.
service_pid_folder
,
"%s.pid"
%
service_name
),
service_status_path
,)
)
+
promise
[
"path"
]
cron_line_list
.
append
(
"%s %s"
%
(
softConfigGet
(
service_config
,
"service"
,
"frequency"
)
or
"* * * * *"
,
command
.
replace
(
"%"
,
"
\
\
%"
),
))
wrapper_path
=
os
.
path
.
join
(
self
.
wraper_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
(
self
.
crond_folder
+
"/monitor-promises"
,
"w"
)
as
fp
:
fp
.
write
(
"
\
n
"
.
join
(
cron_line_list
))
def
bootstrapMonitor
(
self
):
# create symlinks from service configurations
self
.
promise_items
=
self
.
promise_dict
.
items
()
for
service_name
,
promise
in
self
.
promise_items
:
service_config
=
promise
[
"configuration"
]
public_path_list
=
softConfigGet
(
service_config
,
"service"
,
"public-path-list"
)
private_path_list
=
softConfigGet
(
service_config
,
"service"
,
"private-path-list"
)
if
public_path_list
:
self
.
createSymlinksFromConfig
(
self
.
public_folder
,
public_path_list
.
split
(),
service_name
)
if
private_path_list
:
self
.
createSymlinksFromConfig
(
self
.
private_folder
,
private_path_list
.
split
(),
service_name
)
# create symlinks from monitor.conf
self
.
createSymlinksFromConfig
(
self
.
public_folder
,
self
.
public_path_list
)
self
.
createSymlinksFromConfig
(
self
.
private_folder
,
self
.
private_path_list
)
# generate monitor.json
self
.
monitor_dict
=
{}
self
.
generateMonitorHalJson
()
# put promises to a cron file
self
.
generateServiceCronEntries
()
return
0
if
__name__
==
"__main__"
:
parser
=
parseArguments
()
monitor
=
Monitoring
(
parser
.
config_file
)
sys
.
exit
(
monitor
.
bootstrapMonitor
())
stack/monitor2/run-promise.py
→
stack/monitor2/
scripts/
run-promise.py
View file @
d6634962
#!
{{ python_executable }}
#!
/usr/bin/env python
# -*- coding: utf-8 -*-
import
sys
import
os
import
subprocess
import
json
from
cStringIO
import
StringIO
def
main
():
if
len
(
sys
.
argv
)
<
4
:
...
...
stack/monitor2/status2rss.py
→
stack/monitor2/s
cripts/s
tatus2rss.py
View file @
d6634962
File moved
stack/monitor2/monitor-httpd.conf.in
→
stack/monitor2/
templates/
monitor-httpd.conf.in
View file @
d6634962
...
...
@@ -30,6 +30,7 @@ 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
LoadModule headers_module modules/mod_headers.so
# SSL Configuration
<IfDefine !SSLConfigured>
...
...
@@ -47,6 +48,24 @@ SSLCipherSuite RC4-SHA:HIGH:!ADH
AddType application/hal+json .haljson
SSLEngine On
{% if parameter_dict.has_key('monitor-url-list') -%}
RewriteEngine on
SSLProxyEngine on
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
{% set index=1 -%}
{% set monitor_url_list = parameter_dict.get('monitor-url-list').split('\n') -%}
{% for url in monitor_url_list -%}
{% if url.strip() -%}
RewriteRule /monitor{{ index }}/(.*) {{ url }}/$1 [L,P]
{% set index = index + 1 -%}
{% endif -%}
{% endfor -%}
{% endif -%}
ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
SSLVerifyDepth 1
...
...
@@ -55,6 +74,7 @@ ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
# XXX: security????
DirectoryIndex index.html
Options FollowSymLinks
AllowOverride All
Order Deny,Allow
AuthType Basic
AuthName "Private access"
...
...
stack/monitor2/monitor-service.cfg.in
→
stack/monitor2/
templates/
monitor-service.cfg.in
View file @
d6634962
File moved
stack/monitor2/monitor.conf.in
→
stack/monitor2/
templates/
monitor.conf.in
View file @
d6634962
File moved
stack/monitor2/wrapper.in
→
stack/monitor2/
templates/
wrapper.in
View file @
d6634962
File moved
stack/monitor2/default-promise-interface.html
→
stack/monitor2/
web/
default-promise-interface.html
View file @
d6634962
File moved
stack/monitor2/web/index.html
0 → 100644
View file @
d6634962
<!DOCTYPE html>
<html>
<head>
<meta
charset=
"utf-8"
>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script
src=
"https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"
></script>
<!-- Latest compiled and minified CSS -->
<link
rel=
"stylesheet"
href=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity=
"sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7"
crossorigin=
"anonymous"
>
<!-- Optional theme -->
<link
rel=
"stylesheet"
href=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css"
integrity=
"sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r"
crossorigin=
"anonymous"
>
<!-- Latest compiled and minified JavaScript -->
<script
src=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
integrity=
"sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
crossorigin=
"anonymous"
></script>
<link
rel=
"stylesheet"
href=
"monitor.css"
/>
<script
src=
"monitor.js"
></script>
</head>
<body>
<noscript>
Please enable javascript on your browser to make this application to work.
</noscript>
</body>
</html>
stack/monitor2/
monitor-
logout.html
→
stack/monitor2/
web/
logout.html
View file @
d6634962
File moved
stack/monitor2/monitor-password-interface.html
→
stack/monitor2/
web/
monitor-password-interface.html
View file @
d6634962
File moved
stack/monitor2/monitor.css
→
stack/monitor2/
web/
monitor.css
View file @
d6634962
...
...
@@ -48,3 +48,10 @@ a.as-button:active, button:active {
a
.as-button
:hover
,
button
:hover
{
border-color
:
#777777
;
}
.monitor-section
{
float
:
left
;
table-layout
:
fixed
;
margin-top
:
30px
;
margin-right
:
30px
;
}
\ No newline at end of file
stack/monitor2/
monitor.js.in
→
stack/monitor2/
web/monitor.js
View file @
d6634962
/*jslint indent:
2 */
/*jslint indent:2 */
(
function
()
{
"
use strict
"
;
var monitor_title = '
{{ dumps(monitor_title)[5:-1] }}
',
var
monitor_title
=
'
Monitoring interface
'
,
RSS_ICON_DATA_URI
=
[
"
data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwhRE9DVFlQR
"
,
"
SBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cu
"
,
...
...
@@ -25,7 +25,8 @@
var
response
=
event
.
target
;
if
(
response
.
status
<
400
)
{
try
{
resolve(JSON.parse(response.responseText));
var
data
=
(
response
.
responseType
===
'
text
'
||
response
.
responseType
===
''
)
?
JSON
.
parse
(
response
.
responseText
)
:
response
.
response
;
resolve
(
data
);
}
catch
(
e
)
{
reject
(
e
);
}
...
...
@@ -95,6 +96,16 @@
return
url
.
href
;
}
function
joinUrl
(
url
,
path
)
{
if
(
path
&&
path
[
0
]
===
'
/
'
)
{
path
=
path
.
slice
(
1
);
}
if
(
url
.
indexOf
(
'
/
'
,
url
.
length
-
1
)
===
-
1
)
{
return
url
+
'
/
'
+
path
;
}
return
url
+
escapeHtml
(
path
);
}
function
escapeHtml
(
html
)
{
return
html
.
replace
(
/&/g
,
"
&
"
).
replace
(
/</g
,
"
<
"
).
replace
(
/>/g
,
"
>
"
).
replace
(
/"/g
,
"
"
"
).
replace
(
/'/g
,
"
'
"
);
}
...
...
@@ -106,6 +117,7 @@
return
;
}
table
=
document
.
createElement
(
"
table
"
);
table
.
className
=
"
monitor-section
"
;
root
.
appendChild
(
table
);
return
Promise
.
all
(
service_list
.
map
(
function
(
service_dict
)
{
var
interface_url
=
softGetProperty
(
service_dict
,
[
"
_links
"
,
"
interface
"
,
"
href
"
]),
...
...
@@ -118,7 +130,8 @@
row
[
5
].
textContent
=
"
No status
"
;
return
;
}
return loadJson(resolveUrl(monitor_url, status_url)).then(function (status_dict) {
var
full_status_url
=
(
monitor_url
===
undefined
)
?
resolveUrl
(
monitor_url
,
status_url
):
joinUrl
(
monitor_url
,
status_url
);
return
loadJson
(
full_status_url
).
then
(
function
(
status_dict
)
{
if
(
status_dict
.
description
)
{
row
[
2
].
title
=
status_dict
.
description
;
}
...
...
@@ -144,8 +157,8 @@
if
(
link
.
href
[
link
.
href
.
length
-
1
]
!==
"
/
"
)
{
link
.
href
+=
"
/
"
;
}
link.href
= resolveUrl(link.href, "monitor.haljson");
return loadJson(
link.href
).catch(function (reason) {
var
haljson_link
=
resolveUrl
(
link
.
href
,
"
monitor.haljson
"
);
return
loadJson
(
haljson_link
).
catch
(
function
(
reason
)
{
div
.
textContent
=
(
reason
&&
(
reason
.
name
+
"
:
"
+
reason
.
message
));
}).
then
(
function
(
monitor_dict
)
{
//monitor_json_list.push(monitor_dict);
...
...
@@ -160,7 +173,7 @@
var
element_list
=
htmlToElementList
([
"
<header>
"
,
"
<a href=
\"\"
class=
\"
as-button
\"
>Refresh</a>
"
,
" <a href=\"/logout\" class=\"as-button\">Logout</a>",
"
<a href=
\"
/logout
.html
\"
class=
\"
as-button
\"
>Logout</a>
"
,
"
<a href=
\"
/feed
\"
><img src=
\"
"
+
RSS_ICON_DATA_URI
+
"
\"
style=
\"
width: 10mm; height: 10mm; vertical-align: middle;
\"
alt=
\"
[RSS Feed]
\"
/></a>
"
,
"
</header>
"
,
"
<h1>
"
+
monitor_title
+
"
</h1>
"
,
...
...
stack/monitor2/webfile-directory/ansible-report.cgi.in
deleted
100644 → 0
View file @
b1dcbf77
stack/monitor2/webfile-directory/index.cgi.in
deleted
100755 → 0
View file @
b1dcbf77
#!{{ 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)
stack/monitor2/webfile-directory/index.html.jinja2
deleted
100644 → 0
View file @
b1dcbf77
<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>
stack/monitor2/webfile-directory/monitor-password.cgi.in
deleted
100644 → 0
View file @
b1dcbf77
#!{{ 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>
"""
stack/monitor2/webfile-directory/settings.cgi.in
deleted
100755 → 0
View file @
b1dcbf77
#!{{ 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>
"
stack/monitor2/webfile-directory/static/monitor-register.js
deleted
100644 → 0
View file @
b1dcbf77
$
(
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
stack/monitor2/webfile-directory/static/pure-min.css
deleted
100644 → 0
View file @
b1dcbf77
/*!
Pure v0.3.0
Copyright 2013 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
https://github.com/yui/pure/blob/master/LICENSE.md
*/
/*!
normalize.css v1.1.2 | MIT License | git.io/normalize
Copyright (c) Nicolas Gallagher and Jonathan Neal
*/
/*! normalize.css v1.1.2 | MIT License | git.io/normalize */
article
,
aside
,
details
,
figcaption
,
figure
,
footer
,
header
,
hgroup
,
main
,
nav
,
section
,
summary
{
display
:
block
}
audio
,
canvas
,
video
{
display
:
inline-block
;
*
display
:
inline
;
*
zoom
:
1
}
audio
:not
([
controls
])
{
display
:
none
;
height
:
0
}
[
hidden
]
{
display
:
none
}
html
{
font-size
:
100%
;
-ms-text-size-adjust
:
100%
;
-webkit-text-size-adjust
:
100%
}
html
,
button
,
input
,
select
,
textarea
{
font-family
:
sans-serif
}
body
{
margin
:
0
}
a
:focus
{
outline
:
thin
dotted
}
a
:active
,
a
:hover
{
outline
:
0
}
h1
{
font-size
:
2em
;
margin
:
.67em
0
}
h2
{
font-size
:
1.5em
;
margin
:
.83em
0
}
h3
{
font-size
:
1.17em
;
margin
:
1em
0
}
h4
{
font-size
:
1em
;
margin
:
1.33em
0
}
h5
{
font-size
:
.83em
;
margin
:
1.67em
0
}
h6
{
font-size
:
.67em
;
margin
:
2.33em
0
}
abbr
[
title
]
{
border-bottom
:
1px
dotted
}
b
,
strong
{
font-weight
:
700
}
blockquote
{
margin
:
1em
40px
}
dfn
{
font-style
:
italic
}
hr
{
-moz-box-sizing
:
content-box
;
box-sizing
:
content-box
;
height
:
0
}
mark
{
background
:
#ff0
;
color
:
#000
}
p
,
pre
{
margin
:
1em
0
}
code
,
kbd
,
pre
,
samp
{
font-family
:
monospace
,
serif
;
_font-family
:
'courier new'
,
monospace
;
font-size
:
1em
}
pre
{
white-space
:
pre
;
white-space
:
pre-wrap
;
word-wrap
:
break-word
}
q
{
quotes
:
none
}
q
:before
,
q
:after
{
content
:
''
;
content
:
none
}
small
{
font-size
:
80%
}
sub
,
sup
{
font-size
:
75%
;
line-height
:
0
;
position
:
relative
;
vertical-align
:
baseline
}
sup
{
top
:
-.5em
}
sub
{
bottom
:
-.25em
}
dl
,
menu
,
ol
,
ul
{
margin
:
1em
0
}
dd
{
margin
:
0
0
0
40px
}
menu
,
ol
,
ul
{
padding
:
0
0
0
40px
}
nav
ul
,
nav
ol
{
list-style
:
none
;
list-style-image
:
none
}
img
{
border
:
0
;
-ms-interpolation-mode
:
bicubic
}
svg
:not
(
:root
)
{
overflow
:
hidden
}
figure
{
margin
:
0
}
form
{
margin
:
0
}
fieldset
{
border
:
1px
solid
silver
;
margin
:
0
2px
;
padding
:
.35em
.625em
.75em
}
legend
{
border
:
0
;
padding
:
0
;
white-space
:
normal
;
*
margin-left
:
-7px
}
button
,
input
,
select
,
textarea
{
font-size
:
100%
;
margin
:
0
;
vertical-align
:
baseline
;
*
vertical-align
:
middle
}
button
,
input
{
line-height
:
normal
}
button
,
select
{
text-transform
:
none
}
button
,
html
input
[
type
=
button
],
input
[
type
=
reset
],
input
[
type
=
submit
]
{
-webkit-appearance
:
button
;
cursor
:
pointer
;
*
overflow
:
visible
}
button
[
disabled
],
html
input
[
disabled
]
{
cursor
:
default
}
input
[
type
=
checkbox
],
input
[
type
=
radio
]
{
box-sizing
:
border-box
;
padding
:
0
;
*
height
:
13px
;
*
width
:
13px
}
input
[
type
=
search
]
{
-webkit-appearance
:
textfield
;
-moz-box-sizing
:
content-box
;
-webkit-box-sizing
:
content-box
;
box-sizing
:
content-box
}
input
[
type
=
search
]
::-webkit-search-cancel-button
,
input
[
type
=
search
]
::-webkit-search-decoration
{
-webkit-appearance
:
none
}
button
::-moz-focus-inner
,
input
::-moz-focus-inner
{
border
:
0
;
padding
:
0
}
textarea
{
overflow
:
auto
;
vertical-align
:
top
}
table
{
border-collapse
:
collapse
;
border-spacing
:
0
}
.pure-button
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
line-height
:
normal
;
white-space
:
nowrap
;
vertical-align
:
baseline
;
text-align
:
center
;
cursor
:
pointer
;
-webkit-user-drag
:
none
;
-webkit-user-select
:
none
;
-moz-user-select
:
none
;
-ms-user-select
:
none
;
user-select
:
none
}
.pure-button
::-moz-focus-inner
{
padding
:
0
;
border
:
0
}
.pure-button
{
font-size
:
100%
;
*
font-size
:
90%
;
*
overflow
:
visible
;
padding
:
.5em
1.5em
;
color
:
#444
;
color
:
rgba
(
0
,
0
,
0
,
.8
);
*
color
:
#444
;
border
:
1px
solid
#999
;
border
:
0
rgba
(
0
,
0
,
0
,
0
);
background-color
:
#E6E6E6
;
text-decoration
:
none
;
border-radius
:
2px
;
-webkit-transition
:
.1s
linear
-webkit-box-shadow
;
-moz-transition
:
.1s
linear
-moz-box-shadow
;
-ms-transition
:
.1s
linear
box-shadow
;
-o-transition
:
.1s
linear
box-shadow
;
transition
:
.1s
linear
box-shadow
}
.pure-button-hover
,
.pure-button
:hover
,
.pure-button
:focus
{
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
startColorstr
=
'#00000000'
,
endColorstr
=
'#1a000000'
,
GradientType
=
0
);
background-image
:
-webkit-gradient
(
linear
,
0
0
,
0
100%
,
from
(
transparent
),
color-stop
(
40%
,
rgba
(
0
,
0
,
0
,
.05
)),
to
(
rgba
(
0
,
0
,
0
,
.1
)));
background-image
:
-webkit-linear-gradient
(
transparent
,
rgba
(
0
,
0
,
0
,
.05
)
40%
,
rgba
(
0
,
0
,
0
,
.1
));
background-image
:
-moz-linear-gradient
(
top
,
rgba
(
0
,
0
,
0
,
.05
)
0
,
rgba
(
0
,
0
,
0
,
.1
));
background-image
:
-ms-linear-gradient
(
transparent
,
rgba
(
0
,
0
,
0
,
.05
)
40%
,
rgba
(
0
,
0
,
0
,
.1
));
background-image
:
-o-linear-gradient
(
transparent
,
rgba
(
0
,
0
,
0
,
.05
)
40%
,
rgba
(
0
,
0
,
0
,
.1
));
background-image
:
linear-gradient
(
transparent
,
rgba
(
0
,
0
,
0
,
.05
)
40%
,
rgba
(
0
,
0
,
0
,
.1
))}
.pure-button
:focus
{
outline
:
0
}
.pure-button-active
,
.pure-button
:active
{
box-shadow
:
0
0
0
1px
rgba
(
0
,
0
,
0
,
.15
)
inset
,
0
0
6px
rgba
(
0
,
0
,
0
,
.2
)
inset
}
.pure-button
[
disabled
],
.pure-button-disabled
,
.pure-button-disabled
:hover
,
.pure-button-disabled
:focus
,
.pure-button-disabled
:active
{
border
:
0
;
background-image
:
none
;
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
enabled
=
false
);
filter
:
alpha
(
opacity
=
40
);
-khtml-opacity
:
.4
;
-moz-opacity
:
.4
;
opacity
:
.4
;
cursor
:
not-allowed
;
box-shadow
:
none
}
.pure-button-hidden
{
display
:
none
}
.pure-button
::-moz-focus-inner
{
padding
:
0
;
border
:
0
}
.pure-button-primary
,
.pure-button-selected
,
a
.pure-button-primary
,
a
.pure-button-selected
{
background-color
:
#0078e7
;
color
:
#fff
}
.pure-form
input
[
type
=
text
],
.pure-form
input
[
type
=
password
],
.pure-form
input
[
type
=
email
],
.pure-form
input
[
type
=
url
],
.pure-form
input
[
type
=
date
],
.pure-form
input
[
type
=
month
],
.pure-form
input
[
type
=
time
],
.pure-form
input
[
type
=
datetime
],
.pure-form
input
[
type
=
datetime-local
],
.pure-form
input
[
type
=
week
],
.pure-form
input
[
type
=
number
],
.pure-form
input
[
type
=
search
],
.pure-form
input
[
type
=
tel
],
.pure-form
input
[
type
=
color
],
.pure-form
select
,
.pure-form
textarea
{
padding
:
.5em
.6em
;
display
:
inline-block
;
border
:
1px
solid
#ccc
;
font-size
:
.8em
;
box-shadow
:
inset
0
1px
3px
#ddd
;
border-radius
:
4px
;
-webkit-transition
:
.3s
linear
border
;
-moz-transition
:
.3s
linear
border
;
-ms-transition
:
.3s
linear
border
;
-o-transition
:
.3s
linear
border
;
transition
:
.3s
linear
border
;
-webkit-box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
box-sizing
:
border-box
}
.pure-form
input
[
type
=
text
]
:focus
,
.pure-form
input
[
type
=
password
]
:focus
,
.pure-form
input
[
type
=
email
]
:focus
,
.pure-form
input
[
type
=
url
]
:focus
,
.pure-form
input
[
type
=
date
]
:focus
,
.pure-form
input
[
type
=
month
]
:focus
,
.pure-form
input
[
type
=
time
]
:focus
,
.pure-form
input
[
type
=
datetime
]
:focus
,
.pure-form
input
[
type
=
datetime-local
]
:focus
,
.pure-form
input
[
type
=
week
]
:focus
,
.pure-form
input
[
type
=
number
]
:focus
,
.pure-form
input
[
type
=
search
]
:focus
,
.pure-form
input
[
type
=
tel
]
:focus
,
.pure-form
input
[
type
=
color
]
:focus
,
.pure-form
select
:focus
,
.pure-form
textarea
:focus
{
outline
:
0
;
outline
:
thin
dotted
\
9
;
border-color
:
#129FEA
}
.pure-form
input
[
type
=
file
]
:focus
,
.pure-form
input
[
type
=
radio
]
:focus
,
.pure-form
input
[
type
=
checkbox
]
:focus
{
outline
:
thin
dotted
#333
;
outline
:
1px
auto
#129FEA
}
.pure-form
.pure-checkbox
,
.pure-form
.pure-radio
{
margin
:
.5em
0
;
display
:
block
}
.pure-form
input
[
type
=
text
][
disabled
],
.pure-form
input
[
type
=
password
][
disabled
],
.pure-form
input
[
type
=
email
][
disabled
],
.pure-form
input
[
type
=
url
][
disabled
],
.pure-form
input
[
type
=
date
][
disabled
],
.pure-form
input
[
type
=
month
][
disabled
],
.pure-form
input
[
type
=
time
][
disabled
],
.pure-form
input
[
type
=
datetime
][
disabled
],
.pure-form
input
[
type
=
datetime-local
][
disabled
],
.pure-form
input
[
type
=
week
][
disabled
],
.pure-form
input
[
type
=
number
][
disabled
],
.pure-form
input
[
type
=
search
][
disabled
],
.pure-form
input
[
type
=
tel
][
disabled
],
.pure-form
input
[
type
=
color
][
disabled
],
.pure-form
select
[
disabled
],
.pure-form
textarea
[
disabled
]
{
cursor
:
not-allowed
;
background-color
:
#eaeded
;
color
:
#cad2d3
}
.pure-form
input
[
readonly
],
.pure-form
select
[
readonly
],
.pure-form
textarea
[
readonly
]
{
background
:
#eee
;
color
:
#777
;
border-color
:
#ccc
}
.pure-form
input
:focus:invalid
,
.pure-form
textarea
:focus:invalid
,
.pure-form
select
:focus:invalid
{
color
:
#b94a48
;
border
:
1px
solid
#ee5f5b
}
.pure-form
input
:focus:invalid:focus
,
.pure-form
textarea
:focus:invalid:focus
,
.pure-form
select
:focus:invalid:focus
{
border-color
:
#e9322d
}
.pure-form
input
[
type
=
file
]
:focus:invalid:focus
,
.pure-form
input
[
type
=
radio
]
:focus:invalid:focus
,
.pure-form
input
[
type
=
checkbox
]
:focus:invalid:focus
{
outline-color
:
#e9322d
}
.pure-form
select
{
border
:
1px
solid
#ccc
;
background-color
:
#fff
}
.pure-form
select
[
multiple
]
{
height
:
auto
}
.pure-form
label
{
margin
:
.5em
0
.2em
;
font-size
:
90%
}
.pure-form
fieldset
{
margin
:
0
;
padding
:
.35em
0
.75em
;
border
:
0
}
.pure-form
legend
{
display
:
block
;
width
:
100%
;
padding
:
.3em
0
;
margin-bottom
:
.3em
;
font-size
:
125%
;
color
:
#333
;
border-bottom
:
1px
solid
#e5e5e5
}
.pure-form-stacked
input
[
type
=
text
],
.pure-form-stacked
input
[
type
=
password
],
.pure-form-stacked
input
[
type
=
email
],
.pure-form-stacked
input
[
type
=
url
],
.pure-form-stacked
input
[
type
=
date
],
.pure-form-stacked
input
[
type
=
month
],
.pure-form-stacked
input
[
type
=
time
],
.pure-form-stacked
input
[
type
=
datetime
],
.pure-form-stacked
input
[
type
=
datetime-local
],
.pure-form-stacked
input
[
type
=
week
],
.pure-form-stacked
input
[
type
=
number
],
.pure-form-stacked
input
[
type
=
search
],
.pure-form-stacked
input
[
type
=
tel
],
.pure-form-stacked
input
[
type
=
color
],
.pure-form-stacked
select
,
.pure-form-stacked
label
,
.pure-form-stacked
textarea
{
display
:
block
;
margin
:
.25em
0
}
.pure-form-aligned
input
,
.pure-form-aligned
textarea
,
.pure-form-aligned
select
,
.pure-form-aligned
.pure-help-inline
,
.pure-form-message-inline
{
display
:
inline-block
;
*
display
:
inline
;
*
zoom
:
1
;
vertical-align
:
middle
}
.pure-form-aligned
.pure-control-group
{
margin-bottom
:
.5em
}
.pure-form-aligned
.pure-control-group
label
{
text-align
:
right
;
display
:
inline-block
;
vertical-align
:
middle
;
width
:
10em
;
margin
:
0
1em
0
0
}
.pure-form-aligned
.pure-controls
{
margin
:
1.5em
0
0
10em
}
.pure-form
input
.pure-input-rounded
,
.pure-form
.pure-input-rounded
{
border-radius
:
2em
;
padding
:
.5em
1em
}
.pure-form
.pure-group
fieldset
{
margin-bottom
:
10px
}
.pure-form
.pure-group
input
{
display
:
block
;
padding
:
10px
;
margin
:
0
;
border-radius
:
0
;
position
:
relative
;
top
:
-1px
}
.pure-form
.pure-group
input
:focus
{
z-index
:
2
}
.pure-form
.pure-group
input
:first-child
{
top
:
1px
;
border-radius
:
4px
4px
0
0
}
.pure-form
.pure-group
input
:last-child
{
top
:
-2px
;
border-radius
:
0
0
4px
4px
}
.pure-form
.pure-group
button
{
margin
:
.35em
0
}
.pure-form
.pure-input-1
{
width
:
100%
}
.pure-form
.pure-input-2-3
{
width
:
66%
}
.pure-form
.pure-input-1-2
{
width
:
50%
}
.pure-form
.pure-input-1-3
{
width
:
33%
}
.pure-form
.pure-input-1-4
{
width
:
25%
}
.pure-form
.pure-help-inline
,
.pure-form-message-inline
{
display
:
inline-block
;
padding-left
:
.3em
;
color
:
#666
;
vertical-align
:
middle
;
font-size
:
90%
}
.pure-form-message
{
display
:
block
;
color
:
#666
;
font-size
:
90%
}
@media
only
screen
and
(
max-width
:
480px
){
.pure-form
button
[
type
=
submit
]
{
margin
:
.7em
0
0
}
.pure-form
input
[
type
=
text
],
.pure-form
input
[
type
=
password
],
.pure-form
input
[
type
=
email
],
.pure-form
input
[
type
=
url
],
.pure-form
input
[
type
=
date
],
.pure-form
input
[
type
=
month
],
.pure-form
input
[
type
=
time
],
.pure-form
input
[
type
=
datetime
],
.pure-form
input
[
type
=
datetime-local
],
.pure-form
input
[
type
=
week
],
.pure-form
input
[
type
=
number
],
.pure-form
input
[
type
=
search
],
.pure-form
input
[
type
=
tel
],
.pure-form
input
[
type
=
color
],
.pure-form
label
{
margin-bottom
:
.3em
;
display
:
block
}
.pure-group
input
[
type
=
text
],
.pure-group
input
[
type
=
password
],
.pure-group
input
[
type
=
email
],
.pure-group
input
[
type
=
url
],
.pure-group
input
[
type
=
date
],
.pure-group
input
[
type
=
month
],
.pure-group
input
[
type
=
time
],
.pure-group
input
[
type
=
datetime
],
.pure-group
input
[
type
=
datetime-local
],
.pure-group
input
[
type
=
week
],
.pure-group
input
[
type
=
number
],
.pure-group
input
[
type
=
search
],
.pure-group
input
[
type
=
tel
],
.pure-group
input
[
type
=
color
]
{
margin-bottom
:
0
}
.pure-form-aligned
.pure-control-group
label
{
margin-bottom
:
.3em
;
text-align
:
left
;
display
:
block
;
width
:
100%
}
.pure-form-aligned
.pure-controls
{
margin
:
1.5em
0
0
}
.pure-form
.pure-help-inline
,
.pure-form-message-inline
,
.pure-form-message
{
display
:
block
;
font-size
:
80%
;
padding
:
.2em
0
.8em
}}
.pure-g
{
letter-spacing
:
-.31em
;
*
letter-spacing
:
normal
;
*
word-spacing
:
-.43em
;
text-rendering
:
optimizespeed
;
font-family
:
FreeSans
,
Arimo
,
"Droid Sans"
,
Helvetica
,
Arial
,
sans-serif
;
display
:
-webkit-flex
;
-webkit-flex-flow
:
row
wrap
;
display
:
-ms-flexbox
;
-ms-flex-flow
:
row
wrap
}
.opera-only
:-o-prefocus
,
.pure-g
{
word-spacing
:
-.43em
}
.pure-u
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
letter-spacing
:
normal
;
word-spacing
:
normal
;
vertical-align
:
top
;
text-rendering
:
auto
}
.pure-g
[
class
*=
"pure-u"
]
{
font-family
:
sans-serif
}
.pure-u-1
,
.pure-u-1-2
,
.pure-u-1-3
,
.pure-u-2-3
,
.pure-u-1-4
,
.pure-u-3-4
,
.pure-u-1-5
,
.pure-u-2-5
,
.pure-u-3-5
,
.pure-u-4-5
,
.pure-u-1-6
,
.pure-u-5-6
,
.pure-u-1-8
,
.pure-u-3-8
,
.pure-u-5-8
,
.pure-u-7-8
,
.pure-u-1-12
,
.pure-u-5-12
,
.pure-u-7-12
,
.pure-u-11-12
,
.pure-u-1-24
,
.pure-u-5-24
,
.pure-u-7-24
,
.pure-u-11-24
,
.pure-u-13-24
,
.pure-u-17-24
,
.pure-u-19-24
,
.pure-u-23-24
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
letter-spacing
:
normal
;
word-spacing
:
normal
;
vertical-align
:
top
;
text-rendering
:
auto
}
.pure-u-1
{
width
:
100%
}
.pure-u-1-2
{
width
:
50%
;
*
width
:
49.969%
}
.pure-u-1-3
{
width
:
33.3333%
;
*
width
:
33.3023%
}
.pure-u-2-3
{
width
:
66.6667%
;
*
width
:
66.6357%
}
.pure-u-1-4
{
width
:
25%
;
*
width
:
24.969%
}
.pure-u-3-4
{
width
:
75%
;
*
width
:
74.969%
}
.pure-u-1-5
{
width
:
20%
;
*
width
:
19.969%
}
.pure-u-2-5
{
width
:
40%
;
*
width
:
39.969%
}
.pure-u-3-5
{
width
:
60%
;
*
width
:
59.969%
}
.pure-u-4-5
{
width
:
80%
;
*
width
:
79.969%
}
.pure-u-1-6
{
width
:
16.6667%
;
*
width
:
16.6357%
}
.pure-u-5-6
{
width
:
83.3333%
;
*
width
:
83.3023%
}
.pure-u-1-8
{
width
:
12.5%
;
*
width
:
12.469%
}
.pure-u-3-8
{
width
:
37.5%
;
*
width
:
37.469%
}
.pure-u-5-8
{
width
:
62.5%
;
*
width
:
62.469%
}
.pure-u-7-8
{
width
:
87.5%
;
*
width
:
87.469%
}
.pure-u-1-12
{
width
:
8.3333%
;
*
width
:
8.3023%
}
.pure-u-5-12
{
width
:
41.6667%
;
*
width
:
41.6357%
}
.pure-u-7-12
{
width
:
58.3333%
;
*
width
:
58.3023%
}
.pure-u-11-12
{
width
:
91.6667%
;
*
width
:
91.6357%
}
.pure-u-1-24
{
width
:
4.1667%
;
*
width
:
4.1357%
}
.pure-u-5-24
{
width
:
20.8333%
;
*
width
:
20.8023%
}
.pure-u-7-24
{
width
:
29.1667%
;
*
width
:
29.1357%
}
.pure-u-11-24
{
width
:
45.8333%
;
*
width
:
45.8023%
}
.pure-u-13-24
{
width
:
54.1667%
;
*
width
:
54.1357%
}
.pure-u-17-24
{
width
:
70.8333%
;
*
width
:
70.8023%
}
.pure-u-19-24
{
width
:
79.1667%
;
*
width
:
79.1357%
}
.pure-u-23-24
{
width
:
95.8333%
;
*
width
:
95.8023%
}
.pure-g-r
{
letter-spacing
:
-.31em
;
*
letter-spacing
:
normal
;
*
word-spacing
:
-.43em
;
font-family
:
FreeSans
,
Arimo
,
"Droid Sans"
,
Helvetica
,
Arial
,
sans-serif
;
display
:
-webkit-flex
;
-webkit-flex-flow
:
row
wrap
;
display
:
-ms-flexbox
;
-ms-flex-flow
:
row
wrap
}
.opera-only
:-o-prefocus
,
.pure-g-r
{
word-spacing
:
-.43em
}
.pure-g-r
[
class
*=
"pure-u"
]
{
font-family
:
sans-serif
}
.pure-g-r
img
{
max-width
:
100%
;
height
:
auto
}
@media
(
min-width
:
980px
){
.pure-visible-phone
{
display
:
none
}
.pure-visible-tablet
{
display
:
none
}
.pure-hidden-desktop
{
display
:
none
}}
@media
(
max-width
:
480px
){
.pure-g-r
>
.pure-u
,
.pure-g-r
>[
class
*=
"pure-u-"
]
{
width
:
100%
}}
@media
(
max-width
:
767px
){
.pure-g-r
>
.pure-u
,
.pure-g-r
>[
class
*=
"pure-u-"
]
{
width
:
100%
}
.pure-hidden-phone
{
display
:
none
}
.pure-visible-desktop
{
display
:
none
}}
@media
(
min-width
:
768px
)
and
(
max-width
:
979px
){
.pure-hidden-tablet
{
display
:
none
}
.pure-visible-desktop
{
display
:
none
}}
.pure-menu
ul
{
position
:
absolute
;
visibility
:
hidden
}
.pure-menu.pure-menu-open
{
visibility
:
visible
;
z-index
:
2
;
width
:
100%
}
.pure-menu
ul
{
left
:
-10000px
;
list-style
:
none
;
margin
:
0
;
padding
:
0
;
top
:
-10000px
;
z-index
:
1
}
.pure-menu
>
ul
{
position
:
relative
}
.pure-menu-open
>
ul
{
left
:
0
;
top
:
0
;
visibility
:
visible
}
.pure-menu-open
>
ul
:focus
{
outline
:
0
}
.pure-menu
li
{
position
:
relative
}
.pure-menu
a
,
.pure-menu
.pure-menu-heading
{
display
:
block
;
color
:
inherit
;
line-height
:
1.5em
;
padding
:
5px
20px
;
text-decoration
:
none
;
white-space
:
nowrap
}
.pure-menu.pure-menu-horizontal
>
.pure-menu-heading
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
margin
:
0
;
vertical-align
:
middle
}
.pure-menu.pure-menu-horizontal
>
ul
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
vertical-align
:
middle
;
height
:
2.4em
}
.pure-menu
li
a
{
padding
:
5px
20px
}
.pure-menu-can-have-children
>
.pure-menu-label
:after
{
content
:
'\25B8'
;
float
:
right
;
font-family
:
'Lucida Grande'
,
'Lucida Sans Unicode'
,
'DejaVu Sans'
,
sans-serif
;
margin-right
:
-20px
;
margin-top
:
-1px
}
.pure-menu-can-have-children
>
.pure-menu-label
{
padding-right
:
30px
}
.pure-menu-separator
{
background-color
:
#dfdfdf
;
display
:
block
;
height
:
1px
;
font-size
:
0
;
margin
:
7px
2px
;
overflow
:
hidden
}
.pure-menu-hidden
{
display
:
none
}
.pure-menu-fixed
{
position
:
fixed
;
top
:
0
;
left
:
0
;
width
:
100%
}
.pure-menu-horizontal
li
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
vertical-align
:
middle
}
.pure-menu-horizontal
li
li
{
display
:
block
}
.pure-menu-horizontal
>
.pure-menu-children
>
.pure-menu-can-have-children
>
.pure-menu-label
:after
{
content
:
"\25BE"
}
.pure-menu-horizontal
>
.pure-menu-children
>
.pure-menu-can-have-children
>
.pure-menu-label
{
padding-right
:
30px
}
.pure-menu-horizontal
li
.pure-menu-separator
{
height
:
50%
;
width
:
1px
;
margin
:
0
7px
}
.pure-menu-horizontal
li
li
.pure-menu-separator
{
height
:
1px
;
width
:
auto
;
margin
:
7px
2px
}
.pure-menu.pure-menu-open
,
.pure-menu.pure-menu-horizontal
li
.pure-menu-children
{
background
:
#fff
;
border
:
1px
solid
#b7b7b7
}
.pure-menu.pure-menu-horizontal
,
.pure-menu.pure-menu-horizontal
.pure-menu-heading
{
border
:
0
}
.pure-menu
a
{
border
:
1px
solid
transparent
;
border-left
:
0
;
border-right
:
0
}
.pure-menu
a
,
.pure-menu
.pure-menu-can-have-children
>
li
:after
{
color
:
#777
}
.pure-menu
.pure-menu-can-have-children
>
li
:hover:after
{
color
:
#fff
}
.pure-menu
.pure-menu-open
{
background
:
#dedede
}
.pure-menu
li
a
:hover
,
.pure-menu
li
a
:focus
{
background
:
#eee
}
.pure-menu
li
.pure-menu-disabled
a
:hover
,
.pure-menu
li
.pure-menu-disabled
a
:focus
{
background
:
#fff
;
color
:
#bfbfbf
}
.pure-menu
.pure-menu-disabled
>
a
{
background-image
:
none
;
border-color
:
transparent
;
cursor
:
default
}
.pure-menu
.pure-menu-disabled
>
a
,
.pure-menu
.pure-menu-can-have-children.pure-menu-disabled
>
a
:after
{
color
:
#bfbfbf
}
.pure-menu
.pure-menu-heading
{
color
:
#565d64
;
text-transform
:
uppercase
;
font-size
:
90%
;
margin-top
:
.5em
;
border-bottom-width
:
1px
;
border-bottom-style
:
solid
;
border-bottom-color
:
#dfdfdf
}
.pure-menu
.pure-menu-selected
a
{
color
:
#000
}
.pure-menu.pure-menu-open.pure-menu-fixed
{
border
:
0
;
border-bottom
:
1px
solid
#b7b7b7
}
.pure-paginator
{
letter-spacing
:
-.31em
;
*
letter-spacing
:
normal
;
*
word-spacing
:
-.43em
;
text-rendering
:
optimizespeed
;
list-style
:
none
;
margin
:
0
;
padding
:
0
}
.opera-only
:-o-prefocus
,
.pure-paginator
{
word-spacing
:
-.43em
}
.pure-paginator
li
{
display
:
inline-block
;
*
display
:
inline
;
zoom
:
1
;
letter-spacing
:
normal
;
word-spacing
:
normal
;
vertical-align
:
top
;
text-rendering
:
auto
}
.pure-paginator
.pure-button
{
border-radius
:
0
;
padding
:
.8em
1.4em
;
vertical-align
:
top
;
height
:
1.1em
}
.pure-paginator
.pure-button
:focus
,
.pure-paginator
.pure-button
:active
{
outline-style
:
none
}
.pure-paginator
.prev
,
.pure-paginator
.next
{
color
:
#C0C1C3
;
text-shadow
:
0
-1px
0
rgba
(
0
,
0
,
0
,
.45
)}
.pure-paginator
.prev
{
border-radius
:
2px
0
0
2px
}
.pure-paginator
.next
{
border-radius
:
0
2px
2px
0
}
@media
(
max-width
:
480px
){
.pure-menu-horizontal
{
width
:
100%
}
.pure-menu-children
li
{
display
:
block
;
border-bottom
:
1px
solid
#000
}}
.pure-table
{
border-collapse
:
collapse
;
border-spacing
:
0
;
empty-cells
:
show
;
border
:
1px
solid
#cbcbcb
}
.pure-table
caption
{
color
:
#000
;
font
:
italic
85%
/
1
arial
,
sans-serif
;
padding
:
1em
0
;
text-align
:
center
}
.pure-table
td
,
.pure-table
th
{
border-left
:
1px
solid
#cbcbcb
;
border-width
:
0
0
0
1px
;
font-size
:
inherit
;
margin
:
0
;
overflow
:
visible
;
padding
:
6px
12px
}
.pure-table
td
:first-child
,
.pure-table
th
:first-child
{
border-left-width
:
0
}
.pure-table
thead
{
background
:
#e0e0e0
;
color
:
#000
;
text-align
:
left
;
vertical-align
:
bottom
}
.pure-table
td
{
background-color
:
transparent
}
.pure-table-odd
td
{
background-color
:
#f2f2f2
}
.pure-table-striped
tr
:nth-child
(
2n-1
)
td
{
background-color
:
#f2f2f2
}
.pure-table-bordered
td
{
border-bottom
:
1px
solid
#cbcbcb
}
.pure-table-bordered
tbody
>
tr
:last-child
td
,
.pure-table-horizontal
tbody
>
tr
:last-child
td
{
border-bottom-width
:
0
}
.pure-table-horizontal
td
,
.pure-table-horizontal
th
{
border-width
:
0
0
1px
;
border-bottom
:
1px
solid
#cbcbcb
}
.pure-table-horizontal
tbody
>
tr
:last-child
td
{
border-bottom-width
:
0
}
\ No newline at end of file
stack/monitor2/webfile-directory/static/script.js
deleted
100644 → 0
View file @
b1dcbf77
$
(
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
();
}
});
stack/monitor2/webfile-directory/static/style.css
deleted
100644 → 0
View file @
b1dcbf77
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
;
}
stack/monitor2/webfile-directory/static/welcome.html
deleted
100644 → 0
View file @
b1dcbf77
<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>
stack/monitor2/webfile-directory/status-history.cgi.in
deleted
100644 → 0
View file @
b1dcbf77
#!{{ 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>
"
stack/monitor2/webfile-directory/status.cgi.in
deleted
100755 → 0
View file @
b1dcbf77
#!{{ 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>
"
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment