This repository was archived by the owner on Jul 20, 2022. It is now read-only.
forked from amrik/fabutil
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfabutil.py
More file actions
237 lines (183 loc) · 7.33 KB
/
fabutil.py
File metadata and controls
237 lines (183 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
'''Utilities for fabric.
For some functions, you may need to provide the global fabric environment with
some information, e.g.::
import fabutil
...
fabutil.env = env
# Optional, defaults to 1.5.1 release of virtualenv
env.ve_source = 'http://.../virtualenv.py'
env.env_root = '/path/to/virtual-env/root/'
'''
import os
import random
import tempfile
from fabric.api import run, put, cd, env, settings
from fabric.contrib import files
VE_URL = 'http://bitbucket.org/ianb/virtualenv/raw/eb94c9ebe0ba/virtualenv.py'
def vrun(command):
'Run a command with the virtual environment activated.'
source = 'source "%(env_root)s/bin/activate" && '
run(' '.join((source, command)) % env)
def install_bash_aliases(initfile='.profile'):
"Install some helper utilities and aliases."
aliases = [
'alias psa="ps faux |egrep ^`egrep ^$USER /etc/passwd | cut -f3 -d:`"',
'alias activate="source ~/bin/activate"',
]
files.append(aliases, initfile)
def kill(pidfile, rmpid=True, sig=''):
if files.exists(pidfile):
run('kill -%s `cat "%s"`' % (sig, pidfile))
if rmpid:
run('rm -f "%s"' % (pidfile,))
else:
print 'WARNING: PID file %s does not exist!' % pidfile
def sed(file, sedexpr):
'Run a sed expression ``sedexpr`` in-place on ``file``.'
run('sed -i\'\' "%s" "%s"' % (sedexpr, file))
def strput(text, target):
'Put the contents of the string ``text`` into remote file ``target``.'
df = tempfile.NamedTemporaryFile()
df.write(text)
df.flush()
put(df.name, target)
# Must be performed last as closing deletes the temp. file.
df.close()
def bootstrap_ve(python='python', require=None):
'Bootstrap a Python environment and install dependencies.'
context = {
'staging_dir': os.path.join('/var/tmp', str(random.random())),
've_source': getattr(env, 've_source', VE_URL),
}
env.update(context)
run('mkdir -p %(staging_dir)s' % env)
with cd(env.staging_dir):
run('curl -L "%(ve_source)s" > virtualenv.py' % env)
run(' '.join((python,
'virtualenv.py --clear',
'--no-site-packages',
'--distribute',
env.env_root)))
if require is not None:
put(require, env.staging_dir)
vrun('pip install -r %(staging_dir)s/requirements.txt' % env)
run('rm -r "%(staging_dir)s"' % env)
run('mkdir -p %(env_root)s/{etc,var,tmp}' % env)
def install_nginx(src='http://nginx.org/download/nginx-0.8.52.tar.gz'):
'''Install nginx web server in the virtual environment.
Minimally, you'll need libpcre3-dev libglobus-openssl-dev for Ubuntu or the
equivalent on some other distribution.
'''
ng_distro = os.path.basename(src)
for ext, topts in (
('.tar', 'xf'),
('.tar.gz', 'zxf'),
('.tgz', 'zxf'),
('.tar.bz2', 'jxf'),
('.tbz2', 'jxf')):
if ng_distro.endswith(ext):
ng_src_dir = ng_distro.rstrip(ext)
untar_opts = topts
break
with cd(os.path.join(env.env_root, 'src')):
run('wget "%s"' % src)
run(' '.join(('tar', untar_opts, ng_distro)))
with cd(os.path.join(env.env_root, 'src', ng_src_dir)):
run('./configure'
' --with-http_stub_status_module'
' --prefix=%(env_root)s'
' --sbin-path=%(env_root)s/bin/nginx'
' --pid-path=%(env_root)s/var/nginx.pid'
' --http-client-body-temp-path=%(env_root)s/tmp/http_client_body_temp/'
' --http-proxy-temp-path=%(env_root)s/tmp/proxy_temp/'
' --http-fastcgi-temp-path=%(env_root)s/tmp/fastcgi_temp/'
' --http-uwsgi-temp-path=%(env_root)s/tmp/uwsgi_temp/'
' --http-scgi-temp-path=%(env_root)s/tmp/scgi_temp/'
' --conf-path=%(env_root)s/etc/nginx/nginx.conf' % env)
run('make')
run('make install')
# Some management commands follow:
def _sighup(pid):
kill(pid, sig='HUP', rmpid=False)
def start_stack():
'Alias for: start_nginx start_uwsgi'
start_nginx()
start_uwsgi()
def stop_stack():
'Alias for: kill_nginx kill_uwsgi'
kill_nginx()
kill_uwsgi()
def start_nginx():
'''Start web server.
TERM/INT: Quick shutdown
QUIT: Graceful shutdown
HUP: Configuration reload; Start the new worker processes with a new
configuration and gracefully shutdown the old worker processes
USR1 Reopen the log files
USR2: Upgrade Executable on the fly
WINCH: Gracefully shutdown the worker processes
http://wiki.nginx.org/CommandLine
'''
kill(os.path.join(env.env_root, 'var', 'nginx.pid'), sig='QUIT')
vrun('nginx')
def sighup_nginx():
'Gracefully restart nginx.'
_sighup(os.path.join(env.env_root, 'var', 'nginx.pid'))
def kill_nginx():
'Stop nginx.'
kill(os.path.join(env.env_root, 'var', 'nginx.pid'), sig='QUIT')
def start_uwsgi():
'''Start uWSGI.
The uWSGI server responds to this signals[1]:
SIGHUP: reload (gracefully) all the workers and the master process
SIGTERM: brutally reload all the workers and the master process
SIGINT/SIGQUIT: kill all the uWSGI stack
SIGUSR1: print statistics
[1] http://projects.unbit.it/uwsgi/wiki/uWSGISignals
'''
# Note! Need to start uWSGI with the full path to the binary.
# > This is caused by your binary path changing after startup.
# > For example you start uwsgi with
# > ./uwsgi
# > in directory /tmp than you chdir to something else.
# > When uWSGI restarts ./uwsgi is no more valid. There are other cases but
# > they are all fixed in the patch 0966_0967 that you will find in the list
# > archives, or you can wait til tomorrow when uwsgi-0.9.6.7 will be
# > released.
if files.exists(os.path.join(env.env_root, 'var', 'uwsgi.pid')):
print 'PID File exists, running sighup_uwsgi()'
sighup_uwsgi()
else:
vrun('%(env_root)s/bin/uwsgi'
' --ini %(env_root)s/etc/uwsgi.ini'
' -d %(env_root)s/logs/uwsgi.log' % env)
def kill_uwsgi():
'Stop uWSGI master and worker processes.'
kill(os.path.join(env.env_root, 'var', 'uwsgi.pid'), sig='SIGINT')
def sighup_uwsgi():
'Gracefully restart uWSGI.'
_sighup(os.path.join(env.env_root, 'var', 'uwsgi.pid'))
def copytree(source, destroot, mkdir=True, excl=[], exclfunc=lambda x: False):
'''
Copy the contents of a directory tree.
If ``mkdir`` is True, the destination directory will be created on the
remote host. ``excl`` is a list of file names to be excluded (note this
function compares it with the source **path**). For more complex logic you
can specify a function ``exclfunc`` taking the source path and returning a
True if the src path should be exluded.
'''
if mkdir is True:
run('mkdir -p %s' % destroot)
dircache = set()
for dpath, dnames, fnames in os.walk(source):
for f in fnames:
src = os.path.join(dpath, f)
target = os.path.join(destroot, src)
if src in excl:
continue
if exclfunc(src) is True:
continue
if dpath not in dircache:
run('mkdir -p %s' % os.path.join(destroot, dpath))
dircache.add(dpath)
put(src, target)