Блог python на хабрахабре
Python / Python пакеты и их использование
- 01 Сен 12:47
C:\>c:\Python26\Scripts\pip.exe install django-maintenancemode
Downloading/unpacking django-maintenancemode
Downloading django-maintenancemode-0.9.2.tar.gz
Running setup.py egg_info for package django-maintenancemode
Installing collected packages: django-maintenancemode
Running setup.py install for django-maintenancemode
Successfully installed django-maintenancemode
Cleaning up...


$ sudo aptitude install ufw
$ sudo ufw enable
$ sudo ufw logging on
$ sudo ufw allow 80/tcp
$ sudo ufw allow
$ sudo ufw default deny
# apt-get install gcc libssl-dev libpcre++-dev make
# wget http://sysoev.ru/nginx/nginx-0.8.44.tar.gz
# tar -xzvf nginx-0.8.44.tar.gz
# cd nginx-0.8.44/
# ./configure --conf-path=/etc/nginx/nginx.conf \
--prefix=/usr \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--with-http_dav_module \
--http-client-body-temp-path=/var/lib/nginx/body \
--with-http_ssl_module \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--with-http_stub_status_module \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--with-debug \
--with-http_flv_module
# make
# make install
/srv/musicmans
| backups
--| src
--| db
| logs
| root
--| src
--| www
import os
import sys
import django.core.handlers.wsgi
DIR=(os.path.abspath(__file__))
sys.path.append(DIR)
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings.production'
application = django.core.handlers.wsgi.WSGIHandler()

INSTALLED_APPS += (
'django.contrib.admin',
)
if settings.DEBUG and command == "test":
settings.MAINTENANCE_MODE = False
execute_manager(settings)
$ ssh-keygen -t dsa
$ cat ~/.ssh/id_dsa.pub
$svn checkout --depth=empty svn+ssh://codesrv/repos/musicmans/trunk/backend root
$cd root/
$svn update --set-depth=infinity www
$svn update --set-depth=infinity src
vermus@musicmans:~$ cd /srv/musicmans/root/src
vermus@musicmans:~$ sudo pip install -r requirements.txt --download-cache /usr/src/pipcache/
# apt-get install postgresql python-psycopg2
# su postgres
$ createuser musicmans --no-superuser --no-createdb --no-createrole --login --pwprompt --encrypted
$ createdb --owner=musicmans --encoding=utf-8 musicmans
vermus@musicmans:~$ cd /srv/musicmans/root/src/
vermus@musicmans:/srv/musicmans/root/src$ python manage.py syncdb
$ cd /usr/src/
$ sudo pip install http://projects.unbit.it/downloads/uwsgi-latest.tar.gz
# cat uwsgi
### BEGIN INIT INFO
# Provides: uwsgi
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the uwsgi app server
# Description: starts uwsgi app server using start-stop-daemon
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/uwsgi
OWNER=uwsgirun
NAME=uwsgi
DESC=uwsgi
test -x $DAEMON || exit 0
# Include uwsgi defaults if available
if [ -f /etc/uwsgi ] ; then
. /etc/uwsgi
fi
set -e
DAEMON_OPTS="--socket /var/lib/nginx/uwsgi/musicmans.sock --chmod-socket -d /srv/musicmans/logs/uwsgi.log --pythonpath $PYTHONPATH --module $MODULE"
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --chuid $OWNER:$OWNER --user $OWNER \
--exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --signal 3 --user $OWNER --quiet --retry 2 --stop \
--exec $DAEMON
echo "$NAME."
;;
reload)
killall -1 $DAEMON
;;
force-reload)
killall -15 $DAEMON
;;
restart)
echo -n "Restarting $DESC: "
start-stop-daemon --signal 3 --user $OWNER --quiet --retry 2 --stop \
--exec $DAEMON
sleep 1
start-stop-daemon --user $OWNER --start --quiet --chuid $OWNER:$OWNER \
--exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
status)
killall -10 $DAEMON
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
exit 1
;;
esac
exit 0
PYTHONPATH=/srv/musicmans/root/src
MODULE=wsgi
root@musicmans:/var/lib/nginx# chown -R uwsgirun uwsgi
root@musicmans:/etc/init.d# chmod 755 uwsgi
root@musicmans:/etc/init.d# update-rc.d -f uwsgi defaults
root@musicmans:/etc/init.d# /etc/init.d/uwsgi start
root@musicmans:/etc/nginx/sites-available# cat musicmans
#serving Django.
upstream django {
ip_hash;
server unix:/var/lib/nginx/uwsgi/musicmans.sock;
}
server {
listen 80;
server_name musicmans.ru;
charset utf-8;
error_log /srv/musicmans/logs/nginx_error.log info;
access_log /srv/musicmans/logs/nginx_access.log;
# Django admin media.
#location /media/admin/ {
# alias lib/python2.6/site-packages/django/contrib/admin/media/;
# }
# Your project's static media.
location /media/ {
alias /srv/musicmans/root/www/;
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include uwsgi_params;
}
}
location ~ /.svn/ {
deny all;
}.
# ln -s /etc/nginx/sites-available/musicmans /etc/nginx/sites-enabled/musicmans

#pip install fabric
# -*- mode: python; coding: utf-8; -*-
import sys
from fabric.api import env, run, prompt, local, get, cd, sudo, require
from fabric.state import output
from fabric.contrib.files import uncomment
import datetime
now = datetime.datetime.now()
def production():
#здесь данные об удаленном сервере с сайтом
env.environment = "production"
env.hosts = ['codesrv']
env.user = 'vermus'
env.path = '/srv/musicmans/root'
env.root_path = '/srv/musicmans'
env.db_name = 'musicmans'
env.db_user = 'musicmans'
def deploy():
"""
In the current version fabfile no initial database creation and configure the virtual server host.
"""
require('environment', provided_by=[production])#дописать по желанию dev и stage
if env.environment == 'production':
if "y" != prompt('Are you sure you want to update the production site (test & check in trunk release code!)? (y/[n])?', default="n"):
return
if "y" == prompt('Install the necessary applications (y/n)?', default="n"):
install_requirements();
if "y" == prompt('Set MAINTENANCE_MODE (y/n)?', default="y"):
maintenance_mode() #выключается автоматически, при апдейте production.py с svn сервера
if "y" == prompt('Create database backup? (y/n)?', default="y"):
backup_db()
if "y" == prompt('Create source code backup? (y/n)?', default="y"):
backup_src()
update_from_svn()
migrate_database()
restart_webserver()
def install_requirements():
require('environment', provided_by=[production])#дописать по желанию dev и stage
print(" * install the necessary applications...")
requirements_file = env.path+'/src/requirements.txt'
args = ['install',
'-r', requirements_file,
'--download-cache', '/usr/src/pipcache/'
]
run('pip %s' % ' '.join(args))
def maintenance_mode():
require('environment', provided_by=[production])#дописать по желанию dev и stage
print(" * change production.py and restart nginx...")
uncomment(env.path+'/src/settings/production.py', '#MAINTENANCE_MODE = True')
restart_webserver()
def backup_db():
require('environment', provided_by=[production])#дописать по желанию dev и stage
print(" * create database dump...")
db_name = env.db_name
db_user = env.db_user
backup_file = "backup_%d_%d_%d_%d_%d.sqlgzip" % (now.day, now.month, now.year, now.hour, now.minute)
backup_dir = env.root_path+'/backups/db'
with cd(backup_dir):
run("echo dbpassword | pg_dump -W -U %s -F c %s > %s" % (db_user, db_name, backup_file))
def backup_src():
require('environment', provided_by=[production])#дописать по желанию dev и stage
print(" * create source code backup...")
backup_dir = env.root_path+'/backups/src'
backup_file = "backup_%d_%d_%d_%d_%d.tar.gz" % (now.day, now.month, now.year, now.hour, now.minute)
src_dir = env.path+'/src'
run("mkdir -p %s" % backup_dir+'/all')
run("cp -f -R %s %s" % (src_dir, backup_dir+'/all'))
run("cp -f -R %s %s" % (env.path+'/www/static', backup_dir+'/all'))
with cd(backup_dir):
run ('tar -zcf %s %s' % (backup_file, backup_dir+'/all'))
run ('rm -f -R %s' % (backup_dir+'/all'))
def update_from_svn():
require('environment', provided_by=[production])#дописать по желанию dev и stage
with cd(env.path):
run('svn update') #svn checkout сделаем вручную первый раз
def migrate_database():
require('environment', provided_by=[production])#дописать по желанию dev и stage
with cd(env.path+'/src'):
run('python manage.py migrate --no-initial-data')
run('python manage.py syncdb')
def restart_webserver():
require('environment', provided_by=[production])#дописать по желанию dev и stage
print(" * restart nginx")
sudo('/etc/init.d/nginx force-reload', pty=True)
# "local" is for Unix domain socket connections only
local musicmans musicmans md5
local all all ident

Наверное, нет смысла подробно останавливаться на том, что такое virtualenv или pip, про эти трендовые понятия питоньего мира написана уже не одна статья. Так что сегодня, я просто поделюсь способом разворачивания проекта основуясь на этих технологиях.
Итак, на самом деле все просто. Для начала надо создать новое виртуальное окружение, а затем установить туда все зависимости. Также было бы неплохо получить Makefile со всеми необходимыми целями, которые будут облегчать работу с проектом.
Конечно, все это можно делать и руками для каждого следующего проекта. Благо запоминать там немного:
$ virtualenv ENV
да:
$ pip install -E ENV -r REQUIREMENTS.pip
где REQUIREMENTS.pip - файл со всеми необходимыми зависимостями для проекта. Ну а потом прописать прямо в Makefile или в Makefile.def путь к "новому" Python'у, в нашем случае это может выглядеть как-то так:
PYTHON=ENV/bin/python
Но, когда новые проекты начинают сыпаться как из рога изобилия хочется автоматизировать все эти действия. Для этого я на коленке написал bootstrap скрипт. Разберемся с тем, что он делает.
Во-первых, его нужно сохранить в директорию с проектом (это ограничение я думаю преодолеть по-позже, когда разберусь с созданием проекта с шаблона).
Во-вторых, для настройки тех или иных параметров скрипта, например, названия файла с зависимостями или имени нового виртуального окружения, вы можете создать файл bootstrap.cfg в директории проекта. Скрипт попытается считать настройки оттуда и обновит их.
В-третьих, скрипт создат для Вас новое виртуальное окружение, если оно еще не создано. По умолчанию, это виртуальное окружение создатся с опциями --no-site-packages --unzip-setuptools.
В-четвертых, скрипт попытается создать Makefile, используя шаблонный файл Makefile.template, который должен быть ранее создан в директории проекта.
В-пятых, скрипт установит все зависимости, находящиеся, по умолчанию, в файле REQUIREMENTS.pip и сохранит все скачанные архивы с питоньими пакетами в ENV/src. Формат файлов зависимостей описан в документации к pip.
Собственно все. После обновления зависимостей или шаблона Makefile - просто выполните bootstrap.py еще раз and have fun.
Как уже говорил, в будущем хочется разобраться с созданием проекта с шаблона, чтобы тратить как можно меньше времени на начало каждого следующего проекта.