· 7 years ago · Nov 30, 2018, 12:22 PM
1# -*- coding: utf-8 -*-
2
3import os
4import socket
5import getpass
6
7from fabric.api import local, run, sudo, cd, prefix, put
8from fabric.state import env
9from fabric.contrib.files import sed, exists, append, contains, uncomment
10from fabric.network import join_host_strings, normalize
11from fabric.context_managers import settings
12
13"""
14Fab settings
15"""
16env.hosts = ['djangoproject.vir']
17env.git_code_url = 'git://github.com/django-ja/djangoproject.jp.git'
18env.git_docs_url = 'git://github.com/django-docs-ja/django-docs-ja.git'
19env.mysqluser = env.user
20env.mysqlpassword = 'enterpassword'
21env.mysqlport = '3308'
22env.dbname = 'djangoprojectjp'
23env.secret_key = 'entersecretkey'
24env.akismet_api_key = 'enterakismetkey'
25
26def change_ssh_port(after=22):
27 """
28 For security changing the default ssh port.
29 """
30 host = normalize(env.host_string)[1]
31 before = str(env.port)
32
33 host_string=join_host_strings(env.user,host,before)
34 with settings(host_string=host_string, user=env.user):
35 print env.host, "CHANGING SSH PORT TO: "+str(after)
36 sed('/etc/ssh/sshd_config','Port '+ str(before),'Port '+str(after),use_sudo=True)
37 sudo('/etc/init.d/ssh restart')
38 return True
39
40def upload_ssh_key(rollback=False):
41 """
42 Upload your ssh key for passwordless logins
43 """
44 auth_keys = '/home/%s/.ssh/authorized_keys' % env.user
45 if not rollback:
46 local_user = getpass.getuser()
47 host = socket.gethostname()
48 u = '@'.join([local_user,host])
49 u = 'ssh-key-uploaded-%s'% u
50 with cd('/home/%s' % env.user):
51 if not exists('.ssh'):
52 sudo('mkdir .ssh')
53
54 # determine local .ssh dir
55 home = os.path.expanduser('~')
56 ssh_key = None
57 ssh_dsa = os.path.join(home,'.ssh/id_dsa.pub')
58 ssh_rsa = os.path.join(home,'.ssh/id_rsa.pub')
59 if os.path.exists(ssh_dsa):
60 ssh_key = ssh_dsa
61 elif os.path.exists(ssh_rsa):
62 ssh_key = ssh_rsa
63
64 if ssh_key:
65 ssh_file = open(ssh_key,'r').read()
66
67 print env.host, "UPLOADING SSH KEY"
68 append(auth_keys,ssh_file, use_sudo=True)
69 return
70 else:
71 return
72
73def restrict_ssh():
74 """
75 Restrict password login, and root login.
76 """
77 sshd_config = '/etc/ssh/sshd_config'
78 if not exists('/home/%s/.ssh/authorized_keys' % env.user):
79 print env.host, 'You need to upload_ssh_key first.'
80 return False
81 sed(sshd_config, 'PermitRootLogin yes', 'PermitRootLogin no', use_sudo=True)
82 uncomment(sshd_config,'#(\s?)PermitRootLogin(\s*)no',use_sudo=True)
83 sed(sshd_config, 'PermitEmptyPassword yes', 'PermitEmptyPassword no', use_sudo=True)
84 uncomment(sshd_config,'#(\s?)PermitEmptyPassword(\s*)no',use_sudo=True)
85 sed(sshd_config, 'PasswordAuthentication yes', 'PasswordAuthentication no', use_sudo=True)
86 uncomment(sshd_config,'#(\s?)PasswordAuthentication(\s*)no',use_sudo=True)
87
88 sudo('/etc/init.d/ssh restart')
89
90def setup_ufw_rules(sshport):
91 """
92 Setup ufw app rules.
93
94 """
95 firewall_rules = ['default deny', 'allow 80/tcp', 'allow 443/tcp', 'allow %s/tcp' % sshport]
96
97 print 'deleting all rules'
98 sudo('ufw reset')
99
100 print 'enable ufw'
101 sudo('ufw enable')
102
103 for rule in firewall_rules:
104 with settings(warn_only=True):
105 print 'ufw', rule
106 sudo('ufw %s'% rule)
107
108 output = sudo('ufw reload')
109 print output
110
111def disable_services():
112 """
113 For performance, disable unnecesaly daemon.
114 """
115 disables = ['acpid', 'apmd', 'atd', 'dns-clean', 'pppd-dns']
116
117 for d in disables:
118 if exists('/etc/init.d/%s', d):
119 sudo('update-rc.d %s disable' % d)
120
121def install_packages():
122 """
123 Install a set of baseline packages and configure where necessary
124 """
125 base_packages = ['nginx', 'mysql-server', 'python-setuptools', 'python-dev', 'libmysqlclient-dev', 'build-essential', 'git']
126 python_packages = ['virtualenv', 'pip']
127
128 sudo('apt-get update')
129
130 for p in base_packages:
131 sudo('apt-get install %s' % p)
132
133 with cd('/tmp'):
134 for p in python_packages:
135 sudo('easy_install %s' % p)
136
137def deploy_code():
138 """
139 Update code on the servers from Git.
140 """
141 if not exists('~/djangoproject.jp/'):
142 with cd('~'):
143 print "cloning djangoproject.jp: %s" % env.git_code_url
144 run('git clone %s' % env.git_code_url)
145 with cd('/home/%s/djangoproject.jp/' % env.user):
146 run('git fetch && git reset --hard origin/master')
147
148def update_virtualenv(env_name, packages, reqs=None):
149 """
150 Update virtualenv for the project, and update depencies.
151 """
152 if not exists('~/envs/%s' % env_name):
153 if not exists('~/envs'):
154 run('mkdir envs')
155 with cd('~/envs'):
156 run('virtualenv %s' % env_name)
157 with prefix('source ~/envs/%s/bin/activate' % env_name):
158 run('export PIP_RESPECT_VIRTUALENV=true')
159 for p in packages:
160 sudo('pip install "%s"' % p)
161 if reqs:
162 sudo('pip install -r %s' % reqs)
163
164def deploy_doc(doc_version):
165 """
166 Update docs on the servers from Git.
167 """
168 with prefix('source ~/envs/djangoproject.jp/bin/activate'):
169 run('export PIP_RESPECT_VIRTUALENV=true')
170 # ドã‚ュメントã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«å¿œã˜ãŸvirtualenvを作æˆ
171 if doc_version == "1.0":
172 update_virtualenv('1.0', ['Sphinx==0.4.3'])
173 else:
174 sudo('pip install Sphinx')
175
176 if not exists('~/doc/%s/' % doc_version):
177 if not exists('~/doc/'):
178 run('mkdir doc')
179 with cd('~/doc'):
180 run('git clone %s' % (env.git_docs_url))
181 run('mv django-docs-ja %s' % doc_version)
182 with cd('~/doc/%s' % doc_version):
183 with prefix('source ~/envs/%s/bin/activate' % doc_version):
184 run('git fetch && git reset --hard %s' % doc_version)
185 run('make html')
186
187def setup_mysql():
188 """
189 Setup mysql
190 """
191 # my.cnfã®è¨å®š
192 sudo('/etc/init.d/mysql stop')
193 put('./my.cnf', '/etc/mysql/my.cnf', use_sudo=True)
194 sed('/etc/mysql/my.cnf', 'port = 3306', 'port = %s' % env.mysqlport, use_sudo=True)
195 sudo('mkdir -p -m 660 /var/lib/mysql/backup')
196 sudo('mv /var/lib/mysql/ib_logfile* /var/lib/mysql/backup')
197 sudo('mv /var/lib/mysql/ibdata* ./backup')
198 sudo('/etc/init.d/mysql start')
199
200 # アクセス用ユーザã®ä½œæˆ
201 create_user_sql = "grant select,insert,delete,update,create,drop,file,alter,index on *.* to '%s'@'localhost' identified by '%s';" % (env.mysqluser, env.mysqlpassword)
202 run('echo "%s" | mysql --user=root --password' % create_user_sql)
203
204 run('mysqladmin -u %s -p%s --default-character-set=utf8 create %s' % (env.mysqluser, env.mysqlpassword, env.dbname))
205
206def deploy_static():
207 with cd('djangoproject.jp'):
208 with prefix('source ~/envs/djangoproject.jp/bin/activate'):
209 run('mkdir -p static')
210 run('python manage.py collectstatic -v0 --noinput')
211
212def setup_gunicorn():
213 """
214 Setup gunicorn, and start daemon.
215 """
216 run('source ~/envs/djangoproject.jp/bin/activate && python djangoproject.jp/manage.py run_gunicorn -w 1 -b 127.0.0.1:5000 -D && ps -aux | grep gunicorn')
217 run('ps -aux | grep gunicorn')
218
219def setup_nginx():
220 """
221 Setup nginx.
222 """
223 # plain_defaultã‹ã‚‰defaultを生æˆã—アップãƒãƒ¼ãƒ‰
224 local('cp ./plain_default ./default')
225 local('sed -i -e "s/{{ username }}/%s/g" ./default' % env.user)
226 put('./default', '/etc/nginx/sites-available/default', use_sudo=True)
227
228 sudo('nginx -t')
229 sudo('/etc/init.d/nginx reload')
230
231def setup_environments():
232 """
233 Update enviroments.json which to set secret informetions.
234 """
235 with cd('~/djangoproject.jp'):
236 # environmentsãŒã™ã§ã«å˜åœ¨ã—ã¦ã„ã‚‹å ´åˆã¯å‰Šé™¤
237 if exists('environments.json'):
238 run('rm environments.json')
239
240 put(os.path.dirname(__file__)+'/environments.json', '/home/%s/djangoproject.jp/environments.json' % env.user)
241 sed('environments.json', '"secret_key":', '"secret_key":"%s",' % env.secret_key)
242 sed('environments.json', '"akismet_api_key":', '"akismet_api_key":"%s",' % env.akismet_api_key)
243 sed('environments.json', '"db_default_user":', '"db_default_user":"%s",' % env.mysqluser)
244 sed('environments.json', '"db_default_password":', '"db_default_password":"%s",' % env.mysqlpassword)
245 sed('environments.json', '"db_default_host":', '"db_default_host":"localhost",')
246 sed('environments.json', '"db_default_port":', '"db_default_port":"%s"' % env.mysqlport)
247
248def setup_logrotate():
249 put('./logrotate.conf', '/etc/logrotate.conf', use_sudo=True)
250
251def managepy(cmd):
252 """
253 Helper: run a management command remotely.
254 """
255 with prefix('source ~/envs/djangoproject.jp/bin/activate'):
256 with cd('~/djangoproject.jp'):
257 run('python manage.py %s' % cmd)
258
259def syncdb():
260 """
261 Run syncdb.
262 """
263 managepy('syncdb')
264
265def base_deploy(sshport):
266 """
267 Base deploy: secure login, firewall, disable unnecessaly searvicies.
268 """
269 change_ssh_port(sshport)
270 upload_ssh_key()
271 restrict_ssh()
272 setup_ufw_rules(sshport)
273 disable_services()
274 sudo('reboot')
275
276def full_deploy():
277 """
278 Full deploy: new code, update dependencies, migrate, and restart services.
279 """
280 install_packages()
281 deploy_code()
282 setup_environments()
283 update_virtualenv('djangoproject.jp', ['MySQL-python'], '~/djangoproject.jp/requirement.txt')
284 deploy_doc('1.0')
285 setup_mysql()
286 setup_logrotate()
287 syncdb()
288 deploy_static()
289 setup_gunicorn()
290 setup_nginx()