initial import

This commit is contained in:
2009-12-10 20:45:56 +02:00
commit 14f518ce91
44 changed files with 1867 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.DS_Store

22
LICENSE Normal file
View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2009 Jim Myhrberg
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

51
README.md Normal file
View File

@@ -0,0 +1,51 @@
# Skyhook
This is a set of Ruby scripts, and unix service configuration files I put together in a hurry back in September to scale a then fast growing Facebook application using Amazon EC2's AutoScaling technologies.
It's a combination of service controlling and project deployment. It's not great, but it did do what I needed it for. I haven't touched the code since September when the system went live.
## For Learning
This project depends highly on custom changes within the Linux OS that you are running on EC2. As well as it's alpha quality, I'm putting it on Github for learning purposes mainly. Hopefully you'll find some parts of this project interesting.
## SVN and no Git?!
The project Skyhook was initially intended for was using Subversion, despite my cries. As such, Git is not supported.
## The Future
I am planning on cleanup, rewrite, add Git support, and many other things to Skyhook in the future when I have time. For now, dig through the code and config files if you're curious.
## Forking
Please don't hesitate to fork and improve if you feel like it :)
# License
(The MIT License)
Copyright (c) 2009 Jim Myhrberg
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

306
etc/monit/monitrc Normal file
View File

@@ -0,0 +1,306 @@
# set polling interval
set daemon 60
# default log file
set logfile /var/log/monit/monit.log
# mail server configuration
set mailserver
localhost
# set "from" email address
set mail-format { from: monit@heartb.it }
# default email address to send alerts to
set alert serverstatus@heartb.it
# event queue configuration
set eventqueue
basedir /var/monit/queue
slots 5000
# web-interface setup
set httpd port 2812
allow "admin":"admin"
# monitor nginx
check process nginx with pidfile /var/run/nginx.pid
start = "/etc/init.d/nginx start"
stop = "/etc/init.d/nginx stop"
if failed host localhost port 4041 then restart
if cpu usage > 95% for 3 cycles then restart
if 5 restarts within 15 cycles then timeout
group app
# monitor memcahe
check process memcache with pidfile /var/run/memcached.pid
start = "/etc/init.d/memcached start"
stop = "/etc/init.d/memcached stop"
if totalmem > 90% for 2 cycles then restart
if 5 restarts within 15 cycles then timeout
group app
# monitor starling
check process starling with pidfile /var/run/starling.pid
start = "/etc/init.d/starling start"
stop = "/etc/init.d/starling stop"
if cpu usage > 20% for 2 cycles then alert
if cpu usage > 75% for 2 cycles then restart
if totalmem > 50% for 2 cycles then restart
if 5 restarts within 15 cycles then timeout
group app
# monitor apache
# check process apache with pidfile /var/run/apache2.pid
# start = "/etc/init.d/apache2 start"
# stop = "/etc/init.d/apache2 stop"
# if failed host 127.0.0.1 port 81 for 2 cycles then restart
# if cpu usage > 60% for 2 cycles then alert
# if cpu usage > 98% for 5 cycles then restart
# if 5 restarts within 5 cycles then timeout
# group server
# monitor main file system
check device root with path /dev/sda1
if space usage > 80% for 5 times within 15 cycles then alert
group server
# monitor /mnt file system
check device mnt with path /dev/sda2
if space usage > 80% for 5 times within 15 cycles then alert
group server
###############################################################################
## Monit control file
###############################################################################
##
## Comments begin with a '#' and extend through the end of the line. Keywords
## are case insensitive. All path's MUST BE FULLY QUALIFIED, starting with '/'.
##
## Below you will find examples of some frequently used statements. For
## information about the control file, a complete list of statements and
## options please have a look in the monit manual.
##
##
###############################################################################
## Global section
###############################################################################
##
## Start monit in the background (run as a daemon) and check services at
## 2-minute intervals.
#
# set daemon 120
#
#
## Set syslog logging with the 'daemon' facility. If the FACILITY option is
## omitted, monit will use 'user' facility by default. If you want to log to
## a stand alone log file instead, specify the path to a log file
#
# set logfile syslog facility log_daemon
#
#
## Set the list of mail servers for alert delivery. Multiple servers may be
## specified using comma separator. By default monit uses port 25 - this
## is possible to override with the PORT option.
#
# set mailserver mail.bar.baz, # primary mailserver
# backup.bar.baz port 10025, # backup mailserver on port 10025
# localhost # fallback relay
#
#
## By default monit will drop alert events if no mail servers are available.
## If you want to keep the alerts for a later delivery retry, you can use the
## EVENTQUEUE statement. The base directory where undelivered alerts will be
## stored is specified by the BASEDIR option. You can limit the maximal queue
## size using the SLOTS option (if omitted, the queue is limited by space
## available in the back end filesystem).
#
# set eventqueue
# basedir /var/monit # set the base directory where events will be stored
# slots 100 # optionaly limit the queue size
#
#
## Monit by default uses the following alert mail format:
##
## --8<--
## From: monit@$HOST # sender
## Subject: monit alert -- $EVENT $SERVICE # subject
##
## $EVENT Service $SERVICE #
## #
## Date: $DATE #
## Action: $ACTION #
## Host: $HOST # body
## Description: $DESCRIPTION #
## #
## Your faithful employee, #
## monit #
## --8<--
##
## You can override this message format or parts of it, such as subject
## or sender using the MAIL-FORMAT statement. Macros such as $DATE, etc.
## are expanded at runtime. For example, to override the sender:
#
# set mail-format { from: monit@foo.bar }
#
#
## You can set alert recipients here whom will receive alerts if/when a
## service defined in this file has errors. Alerts may be restricted on
## events by using a filter as in the second example below.
#
# set alert sysadm@foo.bar # receive all alerts
# set alert manager@foo.bar only on { timeout } # receive just service-
# # timeout alert
#
#
## Monit has an embedded web server which can be used to view status of
## services monitored, the current configuration, actual services parameters
## and manage services from a web interface.
#
# set httpd port 2812 and
# use address localhost # only accept connection from localhost
# allow localhost # allow localhost to connect to the server and
# allow admin:monit # require user 'admin' with password 'monit'
#
#
###############################################################################
## Services
###############################################################################
##
## Check general system resources such as load average, cpu and memory
## usage. Each test specifies a resource, conditions and the action to be
## performed should a test fail.
#
# check system myhost.mydomain.tld
# if loadavg (1min) > 4 then alert
# if loadavg (5min) > 2 then alert
# if memory usage > 75% then alert
# if cpu usage (user) > 70% then alert
# if cpu usage (system) > 30% then alert
# if cpu usage (wait) > 20% then alert
#
#
## Check a file for existence, checksum, permissions, uid and gid. In addition
## to alert recipients in the global section, customized alert will be sent to
## additional recipients by specifying a local alert handler. The service may
## be grouped using the GROUP option.
#
# check file apache_bin with path /usr/local/apache/bin/httpd
# if failed checksum and
# expect the sum 8f7f419955cefa0b33a2ba316cba3659 then unmonitor
# if failed permission 755 then unmonitor
# if failed uid root then unmonitor
# if failed gid root then unmonitor
# alert security@foo.bar on {
# checksum, permission, uid, gid, unmonitor
# } with the mail-format { subject: Alarm! }
# group server
#
#
## Check that a process is running, in this case Apache, and that it respond
## to HTTP and HTTPS requests. Check its resource usage such as cpu and memory,
## and number of children. If the process is not running, monit will restart
## it by default. In case the service was restarted very often and the
## problem remains, it is possible to disable monitoring using the TIMEOUT
## statement. This service depends on another service (apache_bin) which
## is defined above.
#
# check process apache with pidfile /usr/local/apache/logs/httpd.pid
# start program = "/etc/init.d/httpd start"
# stop program = "/etc/init.d/httpd stop"
# if cpu > 60% for 2 cycles then alert
# if cpu > 80% for 5 cycles then restart
# if totalmem > 200.0 MB for 5 cycles then restart
# if children > 250 then restart
# if loadavg(5min) greater than 10 for 8 cycles then stop
# if failed host www.tildeslash.com port 80 protocol http
# and request "/monit/doc/next.php"
# then restart
# if failed port 443 type tcpssl protocol http
# with timeout 15 seconds
# then restart
# if 3 restarts within 5 cycles then timeout
# depends on apache_bin
# group server
#
#
## Check device permissions, uid, gid, space and inode usage. Other services,
## such as databases, may depend on this resource and an automatically graceful
## stop may be cascaded to them before the filesystem will become full and data
## lost.
#
# check device datafs with path /dev/sdb1
# start program = "/bin/mount /data"
# stop program = "/bin/umount /data"
# if failed permission 660 then unmonitor
# if failed uid root then unmonitor
# if failed gid disk then unmonitor
# if space usage > 80% for 5 times within 15 cycles then alert
# if space usage > 99% then stop
# if inode usage > 30000 then alert
# if inode usage > 99% then stop
# group server
#
#
## Check a file's timestamp. In this example, we test if a file is older
## than 15 minutes and assume something is wrong if its not updated. Also,
## if the file size exceed a given limit, execute a script
#
# check file database with path /data/mydatabase.db
# if failed permission 700 then alert
# if failed uid data then alert
# if failed gid data then alert
# if timestamp > 15 minutes then alert
# if size > 100 MB then exec "/my/cleanup/script"
#
#
## Check directory permission, uid and gid. An event is triggered if the
## directory does not belong to the user with uid 0 and gid 0. In addition,
## the permissions have to match the octal description of 755 (see chmod(1)).
#
# check directory bin with path /bin
# if failed permission 755 then unmonitor
# if failed uid 0 then unmonitor
# if failed gid 0 then unmonitor
#
#
## Check a remote host network services availability using a ping test and
## check response content from a web server. Up to three pings are sent and
## connection to a port and a application level network check is performed.
#
# check host myserver with address 192.168.1.1
# if failed icmp type echo count 3 with timeout 3 seconds then alert
# if failed port 3306 protocol mysql with timeout 15 seconds then alert
# if failed url
# http://user:password@www.foo.bar:8080/?querystring
# and content == 'action="j_security_check"'
# then alert
#
#
###############################################################################
## Includes
###############################################################################
##
## It is possible to include additional configuration parts from other files or
## directories.
#
# include /etc/monit.d/*
#
#

23
etc/nginx/fastcgi_params Normal file
View File

@@ -0,0 +1,23 @@
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;

109
etc/nginx/koi-utf Normal file
View File

@@ -0,0 +1,109 @@
# This map is not a full koi8-r <> utf8 map: it does not contain
# box-drawing and some other characters. Besides this map contains
# several koi8-u and Byelorussian letters which are not in koi8-r.
# If you need a full and standard map, use contrib/unicode2nginx/koi-utf
# map instead.
charset_map koi8-r utf-8 {
80 E282AC ; # euro
95 E280A2 ; # bullet
9A C2A0 ; # &nbsp;
9E C2B7 ; # &middot;
A3 D191 ; # small yo
A4 D194 ; # small Ukrainian ye
A6 D196 ; # small Ukrainian i
A7 D197 ; # small Ukrainian yi
AD D291 ; # small Ukrainian soft g
AE D19E ; # small Byelorussian short u
B0 C2B0 ; # &deg;
B3 D081 ; # capital YO
B4 D084 ; # capital Ukrainian YE
B6 D086 ; # capital Ukrainian I
B7 D087 ; # capital Ukrainian YI
B9 E28496 ; # numero sign
BD D290 ; # capital Ukrainian soft G
BE D18E ; # capital Byelorussian short U
BF C2A9 ; # (C)
C0 D18E ; # small yu
C1 D0B0 ; # small a
C2 D0B1 ; # small b
C3 D186 ; # small ts
C4 D0B4 ; # small d
C5 D0B5 ; # small ye
C6 D184 ; # small f
C7 D0B3 ; # small g
C8 D185 ; # small kh
C9 D0B8 ; # small i
CA D0B9 ; # small j
CB D0BA ; # small k
CC D0BB ; # small l
CD D0BC ; # small m
CE D0BD ; # small n
CF D0BE ; # small o
D0 D0BF ; # small p
D1 D18F ; # small ya
D2 D180 ; # small r
D3 D181 ; # small s
D4 D182 ; # small t
D5 D183 ; # small u
D6 D0B6 ; # small zh
D7 D0B2 ; # small v
D8 D18C ; # small soft sign
D9 D18B ; # small y
DA D0B7 ; # small z
DB D188 ; # small sh
DC D18D ; # small e
DD D189 ; # small shch
DE D187 ; # small ch
DF D18A ; # small hard sign
E0 D0AE ; # capital YU
E1 D090 ; # capital A
E2 D091 ; # capital B
E3 D0A6 ; # capital TS
E4 D094 ; # capital D
E5 D095 ; # capital YE
E6 D0A4 ; # capital F
E7 D093 ; # capital G
E8 D0A5 ; # capital KH
E9 D098 ; # capital I
EA D099 ; # capital J
EB D09A ; # capital K
EC D09B ; # capital L
ED D09C ; # capital M
EE D09D ; # capital N
EF D09E ; # capital O
F0 D09F ; # capital P
F1 D0AF ; # capital YA
F2 D0A0 ; # capital R
F3 D0A1 ; # capital S
F4 D0A2 ; # capital T
F5 D0A3 ; # capital U
F6 D096 ; # capital ZH
F7 D092 ; # capital V
F8 D0AC ; # capital soft sign
F9 D0AB ; # capital Y
FA D097 ; # capital Z
FB D0A8 ; # capital SH
FC D0AD ; # capital E
FD D0A9 ; # capital SHCH
FE D0A7 ; # capital CH
FF D0AA ; # capital hard sign
}

103
etc/nginx/koi-win Normal file
View File

@@ -0,0 +1,103 @@
charset_map koi8-r windows-1251 {
80 88 ; # euro
95 95 ; # bullet
9A A0 ; # &nbsp;
9E B7 ; # &middot;
A3 B8 ; # small yo
A4 BA ; # small Ukrainian ye
A6 B3 ; # small Ukrainian i
A7 BF ; # small Ukrainian yi
AD B4 ; # small Ukrainian soft g
AE A2 ; # small Byelorussian short u
B0 B0 ; # &deg;
B3 A8 ; # capital YO
B4 AA ; # capital Ukrainian YE
B6 B2 ; # capital Ukrainian I
B7 AF ; # capital Ukrainian YI
B9 B9 ; # numero sign
BD A5 ; # capital Ukrainian soft G
BE A1 ; # capital Byelorussian short U
BF A9 ; # (C)
C0 FE ; # small yu
C1 E0 ; # small a
C2 E1 ; # small b
C3 F6 ; # small ts
C4 E4 ; # small d
C5 E5 ; # small ye
C6 F4 ; # small f
C7 E3 ; # small g
C8 F5 ; # small kh
C9 E8 ; # small i
CA E9 ; # small j
CB EA ; # small k
CC EB ; # small l
CD EC ; # small m
CE ED ; # small n
CF EE ; # small o
D0 EF ; # small p
D1 FF ; # small ya
D2 F0 ; # small r
D3 F1 ; # small s
D4 F2 ; # small t
D5 F3 ; # small u
D6 E6 ; # small zh
D7 E2 ; # small v
D8 FC ; # small soft sign
D9 FB ; # small y
DA E7 ; # small z
DB F8 ; # small sh
DC FD ; # small e
DD F9 ; # small shch
DE F7 ; # small ch
DF FA ; # small hard sign
E0 DE ; # capital YU
E1 C0 ; # capital A
E2 C1 ; # capital B
E3 D6 ; # capital TS
E4 C4 ; # capital D
E5 C5 ; # capital YE
E6 D4 ; # capital F
E7 C3 ; # capital G
E8 D5 ; # capital KH
E9 C8 ; # capital I
EA C9 ; # capital J
EB CA ; # capital K
EC CB ; # capital L
ED CC ; # capital M
EE CD ; # capital N
EF CE ; # capital O
F0 CF ; # capital P
F1 DF ; # capital YA
F2 D0 ; # capital R
F3 D1 ; # capital S
F4 D2 ; # capital T
F5 D3 ; # capital U
F6 C6 ; # capital ZH
F7 C2 ; # capital V
F8 DC ; # capital soft sign
F9 DB ; # capital Y
FA C7 ; # capital Z
FB D8 ; # capital SH
FC DD ; # capital E
FD D9 ; # capital SHCH
FE D7 ; # capital CH
FF DA ; # capital hard sign
}

69
etc/nginx/mime.types Normal file
View File

@@ -0,0 +1,69 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml rss;
image/gif gif;
image/jpeg jpeg jpg;
application/x-javascript js;
application/atom+xml atom;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.wap.xhtml+xml xhtml;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mpeg mpeg mpg;
video/quicktime mov;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

33
etc/nginx/nginx.conf Normal file
View File

@@ -0,0 +1,33 @@
user www-data;
worker_processes 1;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
passenger_root /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-2.2.5;
passenger_ruby /opt/ruby-enterprise/bin/ruby;
passenger_default_user www-data;
passenger_max_pool_size 20;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

View File

@@ -0,0 +1,16 @@
# server {
# listen 80 default;
# server_name _;
# access_log /var/log/nginx/localhost.access.log;
#
# server_name_in_redirect off;
#
# location / {
# index index.html index.htm;
# root /var/www/default;
# }
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# root /var/www/default;
# }
# }

View File

@@ -0,0 +1,15 @@
server {
listen 80 default;
server_name _;
server_name_in_redirect off;
location / {
index index.html index.htm;
root /var/www/maintenance/htdocs;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/maintenance/htdocs;
}
}

View File

@@ -0,0 +1,5 @@
server {
listen 4041;
server_name localhost;
root /var/www/monit-status;
}

View File

@@ -0,0 +1 @@
include /etc/nginx/projects/*.conf;

126
etc/nginx/win-utf Normal file
View File

@@ -0,0 +1,126 @@
# This map is not a full windows-1251 <> utf8 map: it does not
# contain Serbian and Macedonian letters. If you need a full map,
# use contrib/unicode2nginx/win-utf map instead.
charset_map windows-1251 utf-8 {
82 E2809A ; # single low-9 quotation mark
84 E2809E ; # double low-9 quotation mark
85 E280A6 ; # ellipsis
86 E280A0 ; # dagger
87 E280A1 ; # double dagger
88 E282AC ; # euro
89 E280B0 ; # per mille
91 E28098 ; # left single quotation mark
92 E28099 ; # right single quotation mark
93 E2809C ; # left double quotation mark
94 E2809D ; # right double quotation mark
95 E280A2 ; # bullet
96 E28093 ; # en dash
97 E28094 ; # em dash
99 E284A2 ; # trade mark sign
A0 C2A0 ; # &nbsp;
A1 D18E ; # capital Byelorussian short U
A2 D19E ; # small Byelorussian short u
A4 C2A4 ; # currency sign
A5 D290 ; # capital Ukrainian soft G
A6 C2A6 ; # borken bar
A7 C2A7 ; # section sign
A8 D081 ; # capital YO
A9 C2A9 ; # (C)
AA D084 ; # capital Ukrainian YE
AB C2AB ; # left-pointing double angle quotation mark
AC C2AC ; # not sign
AD C2AD ; # soft hypen
AE C2AE ; # (R)
AF D087 ; # capital Ukrainian YI
B0 C2B0 ; # &deg;
B1 C2B1 ; # plus-minus sign
B2 D086 ; # capital Ukrainian I
B3 D196 ; # small Ukrainian i
B4 D291 ; # small Ukrainian soft g
B5 C2B5 ; # micro sign
B6 C2B6 ; # pilcrow sign
B7 C2B7 ; # &middot;
B8 D191 ; # small yo
B9 E28496 ; # numero sign
BA D194 ; # small Ukrainian ye
BB C2BB ; # right-pointing double angle quotation mark
BF D197 ; # small Ukrainian yi
C0 D090 ; # capital A
C1 D091 ; # capital B
C2 D092 ; # capital V
C3 D093 ; # capital G
C4 D094 ; # capital D
C5 D095 ; # capital YE
C6 D096 ; # capital ZH
C7 D097 ; # capital Z
C8 D098 ; # capital I
C9 D099 ; # capital J
CA D09A ; # capital K
CB D09B ; # capital L
CC D09C ; # capital M
CD D09D ; # capital N
CE D09E ; # capital O
CF D09F ; # capital P
D0 D0A0 ; # capital R
D1 D0A1 ; # capital S
D2 D0A2 ; # capital T
D3 D0A3 ; # capital U
D4 D0A4 ; # capital F
D5 D0A5 ; # capital KH
D6 D0A6 ; # capital TS
D7 D0A7 ; # capital CH
D8 D0A8 ; # capital SH
D9 D0A9 ; # capital SHCH
DA D0AA ; # capital hard sign
DB D0AB ; # capital Y
DC D0AC ; # capital soft sign
DD D0AD ; # capital E
DE D0AE ; # capital YU
DF D0AF ; # capital YA
E0 D0B0 ; # small a
E1 D0B1 ; # small b
E2 D0B2 ; # small v
E3 D0B3 ; # small g
E4 D0B4 ; # small d
E5 D0B5 ; # small ye
E6 D0B6 ; # small zh
E7 D0B7 ; # small z
E8 D0B8 ; # small i
E9 D0B9 ; # small j
EA D0BA ; # small k
EB D0BB ; # small l
EC D0BC ; # small m
ED D0BD ; # small n
EE D0BE ; # small o
EF D0BF ; # small p
F0 D180 ; # small r
F1 D181 ; # small s
F2 D182 ; # small t
F3 D183 ; # small u
F4 D184 ; # small f
F5 D185 ; # small kh
F6 D186 ; # small ts
F7 D187 ; # small ch
F8 D188 ; # small sh
F9 D189 ; # small shch
FA D18A ; # small hard sign
FB D18B ; # small y
FC D18C ; # small soft sign
FD D18D ; # small e
FE D18E ; # small yu
FF D18F ; # small ya
}

17
init/actions/activate.rb Normal file
View File

@@ -0,0 +1,17 @@
class ActivateAction < Action
def default
puts "please specify project"
end
def method_missing(project, *args)
Projects.send(project).activate(*args)
Action.perms :ensure
end
def all
Projects.activate
Action.perms :ensure
end
end

17
init/actions/active.rb Normal file
View File

@@ -0,0 +1,17 @@
class ActiveAction < Action
def default
puts "please specify project"
end
def method_missing(project, *args)
puts Projects.send(project).status["active"]
end
def all
Projects.list.each do |name, project|
puts "#{name.camelize}: #{project.status["active"]}"
end
end
end

15
init/actions/checkout.rb Normal file
View File

@@ -0,0 +1,15 @@
class CheckoutAction < Action
def default
puts "please specify project"
end
def method_missing(project, *args)
Projects.send(project).checkout(*args)
end
def all
Projects.checkout
end
end

View File

@@ -0,0 +1,11 @@
class HasLatestAction < Action
def default
Projects.has_latest?
end
def method_missing(*args)
Projects.has_latest?(*args)
end
end

7
init/actions/perms.rb Normal file
View File

@@ -0,0 +1,7 @@
class PermsAction < Action
def ensure
shell "chown -R www-data:www-data #{$skyhook_root}/www"
end
end

35
init/actions/update.rb Normal file
View File

@@ -0,0 +1,35 @@
class UpdateAction < Action
def default
skyhook
end
def all
skyhook
projects
end
def method_missing(project, *args)
Projects.send(project).checkout(*args)
Action.perms :ensure
end
def projects(*args)
Projects.checkout(*args)
Action.perms :ensure
end
def skyhook
SVN.up(nil, $skyhook_root)
shell "#{$skyhook_root}/init/rc.rb update.post_skyhook"
if $console
exec "irb -r #{$skyhook_root}/init/init.rb"
end
end
def post_skyhook
Action.perms :ensure
Projects.init
end
end

15
init/config.rb Normal file
View File

@@ -0,0 +1,15 @@
##
# Skyhook Services - Config
##
# config
$skyhook_root = File.dirname(File.dirname(__FILE__.gsub(/^.\/(.*)$/, "#{ENV["PWD"]}/\\1")))
$checkout_path = "/mnt/system"
$projects_path = "#{$skyhook_root}/www/projects"
$status_file = "#{$skyhook_root}/init/status.tmp"
$nginx_config_path = "#{$skyhook_root}/etc/nginx"
$nginx_projects_config_path = "#{$nginx_config_path}/projects"
$projects_config_path = "#{$skyhook_root}/init/projects"
$actions_config_path = "#{$skyhook_root}/init/actions"
$modes_config_path = "#{$skyhook_root}/init/modes"

9
init/init.rb Normal file
View File

@@ -0,0 +1,9 @@
if !$LOAD_PATH.include?(File.dirname(__FILE__))
$LOAD_PATH << File.dirname(__FILE__)
end
require "config"
require "lib/skyhook"
$console = true if $console.nil?
# $debug = 2

92
init/lib/skyhook.rb Normal file
View File

@@ -0,0 +1,92 @@
##
# Skyhook Services - Libraries
##
require "yaml"
require "fileutils"
require "lib/skyhook/utils"
require "lib/skyhook/utils/initd"
require "lib/skyhook/utils/monit"
require "lib/skyhook/utils/nginx"
require "lib/skyhook/utils/object_overloads"
require "lib/skyhook/utils/svn"
require "lib/skyhook/project"
require "lib/skyhook/projects"
require "lib/skyhook/action"
require "lib/skyhook/mode"
class Skyhook
@info = {}
class << self
attr_accessor :info
end
def self.start
save_status if !load_status
if !@info.nil? && (!@info.has_key?(:booted) || @info[:booted] != true)
save_status({:booted => true})
end
if !Nginx.restore_enabled
Nginx.ensite("projects")
Nginx.ensite("default")
Nginx.ensite("monit-status")
end
Projects.boot
Action.perms :ensure
puts "Starting Skyhook services."
Initd.monit :start
sleep 1
Monit.start :all
sleep 1
Projects.start
write_status(1)
end
def self.stop
puts "Stopping Skyhook services."
Projects.stop
Monit.stop :all
sleep 1
Initd.monit :stop
write_status(0)
end
def self.restart
puts "Restarting Skyhook services."
Projects.restart
Monit.restart :all
sleep 1
Initd.monit :restart
end
def self.status
if File.exist?($status_file)
puts "Skyhook services are running."
else
puts "Skyhook services are not running."
end
end
def self.method_missing(method, *args)
call = (args.size > 0) ? args.shift : nil
Action.send(method, call, *args)
end
def self.load_status
if File.exist?("#{$skyhook_root}/init/status.yml")
@info = YAML.load_file("#{$skyhook_root}/init/status.yml")
return true
end
return false
end
def self.save_status(input = {})
@info = @info.merge(input)
File.open("#{$skyhook_root}/init/status.yml", "w") do |f|
YAML.dump(@info, f)
end
end
end

View File

@@ -0,0 +1,32 @@
class Action
@list = {}
class << self
attr_accessor :list
end
def default
puts "no default action defined"
end
def self.method_missing(action, call = nil, *args)
if @list.has_key?(action)
call = :default if call.nil?
@list[action].send(call, *args) rescue return false
return true
end
return false
end
def self.load
Dir.glob("#{$actions_config_path}/*.rb").each do |item|
item = item.gsub(/^.*\/(.*?)\.rb/, "\\1")
require "actions/#{item}"
@list[item.to_sym] = "#{item}Action".camelize.constantize.new
end
end
end
Action.load

102
init/lib/skyhook/mode.rb Normal file
View File

@@ -0,0 +1,102 @@
class Mode
@list = {}
@status = {}
class << self
attr_accessor :list
attr_reader :status
end
def self.enable(*args)
self.switch(:enable, *args)
end
def self.disable(*args)
self.switch(:disable, *args)
end
def self.switch(state, *args)
if args.size > 0
ret = true
result = nil
args.each do |mode|
if @list.has_key?(mode.to_sym)
if (state == :enable && !@status[mode.to_s]) || (state == :disable && @status[mode.to_s])
self.display_switch(mode, state)
result = @list[mode.to_sym].send(state) if @list[mode.to_sym].respond_to?(state)
ret = false if result == false
@status[mode.to_s] = (state == :enable) ? true : false
else
self.display_no_switch(mode, state)
end
else
self.display_not_found(mode)
end
end
self.save_status
return ret
end
end
def self.do(options = nil)
if !options.nil?
if options.is_a?(String)
options = options.split(" ")
end
if options.is_a?(Array)
options.each do |option|
if option =~ /([\-\+])([a-z0-9]+)/
state = ($1 == "+") ? :enable : :disable
mode = $2.to_sym
self.switch(state, mode)
end
end
end
end
end
def self.load_status
if File.exist?("#{$modes_config_path}/status.yml")
@status = YAML.load_file("#{$modes_config_path}/status.yml")
return true
end
return false
end
def self.save_status(input = {})
@status = @status.merge(input)
File.open("#{$modes_config_path}/status.yml", "w") do |f|
YAML.dump(@status, f)
end
end
def self.display_switch(mode, state)
msg = (state == :enable) ? "Enabling" : "Disabling"
puts "#{msg} #{mode.to_s.camelize} mode"
end
def self.display_no_switch(mode, state)
msg = (state == :enable) ? "enabled" : "disabled"
puts "#{mode.to_s.camelize} mode is already #{msg}"
end
def self.display_not_found(mode)
puts "ERROR: #{mode.to_s.camelize} mode does not exist"
end
def self.load
self.save_status if !self.load_status
Dir.glob("#{$modes_config_path}/*.rb").each do |item|
item = item.gsub(/^.*\/(.*?)\.rb/, "\\1")
require "modes/#{item}"
@list[item.to_sym] = "#{item}Mode".camelize.constantize.new
@status[item.to_s] = false if !@status.has_key?(item.to_s)
end
self.save_status
end
end
Mode.load

136
init/lib/skyhook/project.rb Normal file
View File

@@ -0,0 +1,136 @@
class Project
attr_reader :name
attr_reader :path
attr_reader :repo
attr_reader :revision
attr_reader :status
def initialize
@status = {} if @status.nil?
if File.exist?(@path)
save_status if !load_status
end
end
def active
@status["active"] if @status.has_key?("active")
end
def boot
init
checkout
activate
end
def update(*args)
checkout(*args)
end
# def restart
# shell "touch #{@path}/r#{@status[:active]}/tmp/restart.txt"
# end
def init
if !File.exist?(@path)
shell "mkdir -p #{@path}"
end
if File.exist?("#{$projects_config_path}/#{@name}.conf")
shell "rm #{$nginx_projects_config_path}/#{@name}.conf" if File.exist?("#{$nginx_projects_config_path}/#{@name}.conf")
shell "cp #{$projects_config_path}/#{@name}.conf #{$nginx_projects_config_path}/#{@name}.conf"
end
end
def has_latest?
versions = get_available_versions
if !@revision.nil? && versions.include?(@revision)
return true
end
head = SVN.last_changed_rev(@repo)
if !@status.has_key?("head") || @status["head"].nil? || @status["head"] != head
save_status("head" => head)
end
if !versions.include?(head)
return false
end
return true
end
def checkout(rev = nil)
if File.exist?(@path)
has_latest?
rev = @revision if rev.nil? && !@revision.nil?
version = (rev.nil? || rev.to_i > @status["head"] || rev.to_s.downcase == "head") ? @status["head"] : rev.to_i
if !version.nil?
rev_path = "#{@path}/r#{version}"
if !File.exist?(rev_path)
SVN.export @repo, rev_path, version
return true
end
return nil
end
end
return false
end
def activate(rev = nil)
versions = get_available_versions
version = nil
if rev.nil? && !@revision.nil?
version = @revision
elsif rev.to_s.downcase == "head" || rev.nil?
version = versions.last
elsif versions.include?(rev.to_i)
version = rev.to_i
else
version = versions.last
end
active = (@status.has_key?("active")) ? @status["active"] : nil
return nil if version == active
if !version.nil?
shell "rm #{@path}/htdocs" if File.exist?("#{@path}/htdocs")
shell "ln -s r#{version} #{@path}/htdocs"
save_status("active" => version)
return true
end
return false
end
def clean
leave = 5 # number of version copies to keep
versions = get_available_versions
keep = []
keep << @revision if !@revision.nil?
keep << active if !active.nil? && !keep.include?(active)
(leave-keep.size).times { versions.pop }
versions.each do |version|
if !keep.include?(version)
shell "rm -rf #{@path}/r#{version}"
end
end
end
def load_status
if File.exist?("#{@path}/status.yml")
@status = YAML.load_file("#{@path}/status.yml")
return true
end
return false
end
def save_status(input = {})
@status = @status.merge(input)
File.open("#{@path}/status.yml", "w") do |f|
YAML.dump(@status, f)
end
end
def get_available_versions
dirs = []
Dir.glob("#{@path}/r*").each do |item|
dirs << $1.to_i if item =~ /^.*\/r(\d+)$/
end
return dirs.sort
end
end

View File

@@ -0,0 +1,86 @@
##
# Skyhook Services - Require projects
##
class Projects
@list = {}
class << self
attr_accessor :list
end
def self.method_missing(method, *args)
if @list.has_key?(method)
return @list[method]
else
return self.do(method, *args)
end
end
def self.checkout(*args)
if args.size > 0
return self.do_on_projects(*(args << :update))
else
return self.do(:update)
end
end
def self.activate(*args)
if args.size > 0
return self.do_on_projects(*(args << :activate))
else
return self.do(:activate)
end
end
def self.has_latest?(*args)
ret = self.do_on_projects(*(args << :has_latest?))
puts (ret) ? "yes" : "no"
return ret
end
def self.load
Dir.glob("#{$projects_config_path}/*.rb").each do |item|
item = item.gsub(/^.*\/(.*?)\.rb/, "\\1")
require "projects/#{item}"
@list[item.to_sym] = "#{item}Project".camelize.constantize.new
end
end
private
def self.do(what, *args)
ret = true
result = nil
@list.each do |name, project|
result = project.send(what, *args) if project.respond_to?(what)
ret = false if result == false
end
return ret
end
def self.do_on_projects(*args)
if args.size > 0
method = args.pop.to_sym
if args.size > 0
ret = true
result = nil
args.each do |item|
if @list.has_key?(item.to_sym)
result = @list[item.to_sym].send(method)
ret = false if result == false
end
end
return ret
else
return self.do(method)
end
end
end
end
Projects.load

18
init/lib/skyhook/utils.rb Normal file
View File

@@ -0,0 +1,18 @@
# utility methods
def shell(*args)
if $debug.nil? || $debug > 1
send(:system, *args)
else
puts "DEBUG: " + args.join(" ")
end
end
def write_status(status)
case status
when 1
shell "echo '1' > #{$status_file}"
when 0
shell "rm #{$status_file}"
end
end

View File

@@ -0,0 +1,11 @@
class Initd
def self.method_missing(service, *args)
if $debug.nil? || $debug <= 1
shell "/etc/init.d/#{service.to_s} " + args.map { |i| i.to_s }.join(" ") if File.exist?("/etc/init.d/#{service.to_s}")
else
puts "DEBUG: /etc/init.d/#{service.to_s} " + args.map { |i| i.to_s }.join(" ")
end
end
end

View File

@@ -0,0 +1,11 @@
class Monit
def self.method_missing(cmd, *args)
if $debug.nil? || $debug <= 1
shell "monit #{cmd.to_s} " + args.map { |i| i.to_s }.join(" ")
else
puts "DEBUG: monit #{cmd.to_s} " + args.map { |i| i.to_s }.join(" ")
end
end
end

View File

@@ -0,0 +1,67 @@
class Nginx
@sites_enabled = []
@nginx_conf = "#{$nginx_config_path}"
@available_path = "#{@nginx_conf}/sites-available"
@enabled_path = "#{@nginx_conf}/sites-enabled"
class << self
attr_accessor :sites_enabled
attr_accessor :nginx_conf
attr_accessor :available
attr_accessor :enabled
end
def self.restore_enabled
if @sites_enabled.size > 0
@sites_enabled.each do |site|
self.ensite(site)
end
return true
end
return false
end
def self.ensite(site)
if File.exist?("#{@available_path}/#{site.to_s}")
self.dissite(site)
if $debug.nil? || $debug <= 1
shell "ln -s \"#{@available_path}/#{site.to_s}\" \"#{@enabled_path}/#{site.to_s}\""
@sites_enabled << site.to_s
self.save_status
else
puts "DEBUG: ln -s \"#{@available_path}/#{site.to_s}\" \"#{@enabled_path}/#{site.to_s}\""
end
end
end
def self.dissite(site)
if File.exist?("#{@enabled_path}/#{site.to_s}")
if $debug.nil? || $debug <= 1
shell "rm \"#{@enabled_path}/#{site.to_s}\""
@sites_enabled.delete(site.to_s)
self.save_status
else
puts "DEBUG: rm \"#{@enabled_path}/#{site.to_s}\""
end
end
end
def self.load_status
if File.exist?("#{$skyhook_root}/init/sites-enabled.yml")
@sites_enabled = YAML.load_file("#{$skyhook_root}/init/sites-enabled.yml")
return true
end
return false
end
def self.save_status(input = [])
@sites_enabled = @sites_enabled + input
File.open("#{$skyhook_root}/init/sites-enabled.yml", "w") do |f|
YAML.dump(@sites_enabled, f)
end
end
end
Nginx.save_status if !Nginx.load_status

View File

@@ -0,0 +1,26 @@
class Object
def constantize
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
raise NameError, "#{self.inspect} is not a valid constant name!"
end
Object.module_eval("::#{$1}", __FILE__, __LINE__)
end
def camelize(first_letter_in_uppercase = true)
if first_letter_in_uppercase
self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
else
self.first + camelize(lower_case_and_underscored_word)[1..-1]
end
end
def underscore
self.to_s.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end

View File

@@ -0,0 +1,52 @@
class SVN
def self.checkout(repo, target = "", revision = nil)
self.checkout_or_export(:checkout, repo, target, revision)
end
def self.co(repo, target = "", revision = nil)
self.checkout_or_export(:co, repo, target, revision)
end
def self.export(repo, target = "", revision = nil)
self.checkout_or_export(:export, repo, target, revision)
end
def self.up(revision = nil, target = "")
rev = parse_revision(revision)
shell "svn up #{rev} #{target}"
end
def self.revision(repo)
self.info(repo)["Revision"].to_i
end
def self.last_changed_rev(repo)
self.info(repo)["Last Changed Rev"].to_i
end
def self.info(path)
data = `svn info #{path}`.split(/\n\r|\n|\r/)
info = {}
data.each do |item|
info[$1.strip] = $2.strip if item =~ /(.+?)\:(.+)/
end
return info
end
private
def self.checkout_or_export(method, repo, target = "", revision = nil)
if ["export", "co", "checkout"].include?(method.to_s)
rev = parse_revision(revision)
shell "svn #{method.to_s} #{rev} #{repo} #{target}"
return true
end
return false
end
def self.parse_revision(revision)
(!revision.to_s.match(/^\d+$/).nil?) ? "-r#{revision.to_s.match(/^\d+$/).to_s}" : ""
end
end

19
init/modes/maintenance.rb Normal file
View File

@@ -0,0 +1,19 @@
class MaintenanceMode
def enable
Nginx.ensite :maintenance
Nginx.dissite :projects
Nginx.dissite :default
Initd.nginx :restart
Projects.stop
end
def disable
Nginx.ensite :projects
Nginx.ensite :default
Nginx.dissite :maintenance
Projects.start
Initd.nginx :restart
end
end

View File

@@ -0,0 +1,6 @@
server {
listen 80;
server_name skyhookdemo.jimeh.me;
passenger_enabled on;
root /var/www/projects/sinatra_demo/htdocs/public;
}

View File

@@ -0,0 +1,19 @@
class SinatraDemoProject < Project
def initialize
@name = "sinatra_demo" # Project name
@path = "#{$projects_path}/#{@name}" # Local checkout path
@revision = nil # Default revision to checkout
@repo = "https://heartbit.springloops.com/source/skyhookdemo/projects/sinatra_demo"
super
end
def start
file = "#{@path}/htdocs/config.ru"
configru = File.read(file)
File.open(file, "w+") do |f|
f.write(configru.gsub("development", "production"))
end
end
end

View File

@@ -0,0 +1,9 @@
server {
listen 80 default;
server_name _;
passenger_enabled on;
passenger_use_global_queue on;
rack_env production;
index index.html index.htm;
root /var/www/projects/skyhook_demo/htdocs/public;
}

View File

@@ -0,0 +1,24 @@
class SkyhookDemoProject < Project
def initialize
@name = "skyhook_demo" # Project name
@path = "#{$projects_path}/#{@name}" # Local checkout path
@revision = nil # Default revision to checkout
@repo = "https://heartbit.springloops.com/source/skyhookdemo/projects/skyhook_demo"
super
end
def start
# shell "export RAILS_ENV=production; #{@path}/htdocs/script/delayed_job start"
end
def stop
# shell "export RAILS_ENV=production; #{@path}/htdocs/script/delayed_job stop"
end
def restart
# stop
# start
end
end

33
init/rc.rb Executable file
View File

@@ -0,0 +1,33 @@
#! /usr/bin/env ruby
##
# Skyhook Services - Remote Init Script
##
$console = false
$LOAD_PATH << File.dirname(__FILE__)
require "init"
# parse input and run
case ARGV[0]
when "start"
Skyhook.start
when "stop"
Skyhook.stop
when "restart"
Skyhook.restart
when "status"
Skyhook.status
when "mode"
ARGV.shift
Mode.do(ARGV)
else
which = ARGV.shift.to_s.split(".")
action = Action.send(which[0].to_s.downcase.to_sym, which[1], *ARGV) rescue Process.exit(1)
if !action
Process.exit(1)
end
end
Process.exit(0)

18
www/default/50x.html Normal file
View File

@@ -0,0 +1,18 @@
<html>
<head>
<title>The page is temporarily unavailable</title>
<style>
body { font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body bgcolor="white" text="black">
<table width="100%" height="100%">
<tr>
<td align="center" valign="middle">
The page you are looking for is temporarily unavailable.<br/>
Please try again later.
</td>
</tr>
</table>
</body>
</html>

38
www/default/index.html Normal file
View File

@@ -0,0 +1,38 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8"/>
<title>hello</title>
<style type="text/css" media="screen">
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
#hello {
height: 40px;
width: 150px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -75px;
margin-top: -20px;
text-align: center;
}
</style>
</head>
<body>
<div id="hello">
hello
</div>
</body>
</html>

18
www/maintenance/50x.html Normal file
View File

@@ -0,0 +1,18 @@
<html>
<head>
<title>The page is temporarily unavailable</title>
<style>
body { font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body bgcolor="white" text="black">
<table width="100%" height="100%">
<tr>
<td align="center" valign="middle">
The page you are looking for is temporarily unavailable.<br/>
Please try again later.
</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=utf-8"/>
<title>Under Maintenance</title>
<style type="text/css" media="screen">
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
#hello {
height: 40px;
width: 300px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -20px;
text-align: center;
}
#sub {
font-size: 0.8em;
}
</style>
</head>
<body>
<div id="hello">
We are currently under maintenace.
<div id="sub">Please try again in a few minutes.</div>
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
OK