четверг, 11 декабря 2014 г.

Django. GeoIP. Установка (Ubuntu, Mac OS X). Настройка.

Установка

Выполнение следующей команды часто заканчивается неуспешно

pip install geoip


Возникновение подобной ошибки говорит о необходимости установки GeoIP C Library

#include "GeoIP.h"

        ^

1 error generated.

error: command 'cc' failed with exit status 1


Решение этой проблемы зависит от используемой платформы.

Для Ubuntu достаточно установить следующий пакет



sudo apt-get install libgeoip-dev


Решение для Mac OS X



Качаем последнюю версию исходников. На момент написания статьи GeoIP-1.5.1.tar.gz


Распаковываем скаченный архив, заходим в директорию архива и выполняем команды

./configure
make
make check
sudo make install


Настройка


Для полноценной работы в проекте с GeoIP, необходимо скачать базу данных


База данных представлена в двух файлах

GeoIP.dat - база стран
GeoLiteCity.dat - база городов

В настройках проекта (setting.py) необходимо указать следующие настройки

  GEOIP_PATH = BASE_DIR     #  Директория с файлами-бд GeoIP (в данном случает корень проекта)
  GEOIP_COUNTRY = 'GeoIP.dat'     #  Имя файла с информацией о странах
  GEOIP_CITY = 'GeoLiteCity.dat'     #  Имя файла с информацией о городах


Пример использования


from django.contrib.gis.geoip import GeoIP

GeoIP().country(request.META['REMOTE_ADDR'])
#  {'country_name': u'Russian Federation', 'country_code': u'RU'}
GeoIP().city(request.META['REMOTE_ADDR'])
#  {'city': None, 'continent_code': u'EU', 'region': None, 'charset': 0, 'area_code': 0, 'longitude': 37.616600036621094, 'country_code3': u'RUS', 'latitude': 55.75, 'postal_code': None, 'dma_code': 0, 'country_code': u'RU', 'country_name': u'Russian Federation'}


Дополнительная информация

вторник, 18 ноября 2014 г.

Python. Генерация SSL сертификатов.

Для создания SSL сертификатов потребуется pyOpenSSL

Далее описан материал создания:
 1. Cамоподписанных сертификатов
 2. Подписанных сертификатов

 Установка:
pip install pyopenssl

1. Создание самоподписанных сертификатов
# _*_ coding: utf-8 _*_

import os
from OpenSSL import crypto

KEY_FILE = "app.key"
CERT_FILE = "app.crt"

def create_self_signed_cert(cert_dir):
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 1024)   #  размер может быть 2048, 4196

    #  Создание сертификата
    cert = crypto.X509()
    cert.get_subject().C = "RU"   #  указываем свои данные
    cert.get_subject().ST = "Tatarstan"   #  указываем свои данные
    cert.get_subject().L = "Naberezhnye Chelny"   #  указываем свои данные
    cert.get_subject().O = "xazrad"   #  указываем свои данные
    cert.get_subject().OU = "xazrad"   #  указываем свои данные
    cert.get_subject().CN = "xazrad.blogspot.com"   #  указываем свои данные
    cert.set_serial_number(1000)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(10*365*24*60*60)   #  срок "жизни" сертификата
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha1')

    with open(os.path.join(cert_dir, CERT_FILE), "w") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))

    with open(os.path.join(cert_dir, KEY_FILE), "w") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))


2. Создание подписанных сертификатов
# _*_ coding: utf-8 _*_

import os
from OpenSSL import crypto

KEY_FILE = "app.key"
CERT_FILE = "app.crt"
CA_CRT = "CA_CRT.crt"   #  сертификат, которым производится подпись
CA_KEY = "CA_KEY.key"   #  ключ, которым производится подпись

def create_signed_cert(cert_dir):
    #  Загружаем промежуточный сертификат для подписи
    ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, open(CA_CRT).read())
    #  Загружаем промежуточный ключ, последний параметр пароль
    ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, open(CA_KEY).read(), "password")

    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 1024)    # размер может быть 2048, 4196

    cert = crypto.X509()     cert.get_subject().C = "RU"    #  указываем свои данные
    cert.get_subject().ST = "Tatarstan"    #  указываем свои данные
    cert.get_subject().L = "Naberezhnye Chelny"    #  указываем свои данные
    cert.get_subject().O = "xazrad"    #  указываем свои данные
    cert.get_subject().OU = "xazrad"    #  указываем свои данные
    cert.get_subject().CN = "xazrad.blogspot.com"    #  указываем свои данные
    cert.set_serial_number(1000)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(10*365*24*60*60)    #  срок "жизни" сертификата
    cert.set_issuer(ca_cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(ca_key, "sha1")

    with open(os.path.join(cert_dir, CERT_FILE), "w") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))

    with open(os.path.join(cert_dir, KEY_FILE), "w") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))

Использование crypto.FILETYPE_ASN1 (вместо crypto.FILETYPE_PEM) возвращает битовое значение сертификатов.

суббота, 8 ноября 2014 г.

Virualenv & Node.js

Для установки Node.js в vitualenv необходима библиотека nodeenv
source .../bin/activate     #  активирование Python virtualenv
pip install nodeenv     #  установка nodeenv
nodeenv --python-virtualenv     #  установка nodejs в текущее окружение (может занять продолжительное время)

Далее через npm можно устанавливать пакеты. Например:
npm install -g less

Django. Pgbouncer. PostgreSQL schemas

Для работы django c Pgbouncer можно использовать библиотеку Django-PostgresPool

Если в проекте django используется несколько схем для подключения к БД, то в настройку DATABASES необходимо добавить ключ 'OPTIONS' например:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'django',
'PASSWORD': 'django',
'HOST': '127.0.0.1',
'PORT': '5432',
'OPTIONS': {'options':'-c search_path=schema1,schema2'}
}

'schema1,schema2' - перечисление используемых схем в БД

Однако, если используется пул соединений Pgbouncer эта опция работать не будет

Для решения этой проблемы необходимо подключиться к сигналу connection_created. Для этого в модуле models.py достаточно разместить этот код

from django.dispatch import receiver
from django.db.backends.signals import connection_created

@receiver(connection_created)
def connection_created_handler(sender, **kwargs):
    conn = kwargs.get('connection')
    if conn is not None:
        cursor = conn.cursor()
        cursor.execute("SET search_path={}".format('schema1,schema2',))

При возникновении ошибки:
ProgrammingError: autocommit cannot be used inside a transaction
Установите psycopg2 версии 2.4.1
pip install psycopg2==2.4.1

понедельник, 4 февраля 2013 г.

Запуск скрипта Python как Daemon с добавлением в автозагрузку

ОС: Ubuntu.
Для примера "поднимем" web-сервер на Pyhton.
Определим директорию нашего проекта: /home/webserver/

Скрипт для запуска web-сервера /home/webserver/webserver.py
#!/usr/bin/python
#! _*_ coding: UTF-8 _*_
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write('Hello, word')
 
     
def start():
    server = HTTPServer(('',8082), Handler)
    server.serve_forever()

if __name__ == '__main__':
    start()

Сделаем данные файлы исполняемые командой:
sudo chmod 777 -R /home/webserver

Запустим скрипт
/home/webserver/webserver.py

Набрав в браузере: http://127.0.0.1:8082/ увидим: "Hello, word"
Однако стоит закрыть терминал и скрипт перестанет работать.
Создаем файл-заготовку для старта демона /home/webserver/daemon.py с содержимым:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, os, time, atexit
from signal import SIGTERM

class Daemon:
    """
    Родительский класс дeмона
    Использование: создайте подкласс и переопределите метод run()
    """
    def __init__(self, pidfile, stdin='/dev/null',  stdout='/dev/null', stderr='/dev/null'):
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.pidfile = pidfile
 
    def daemonize(self):
        try:
            pid = os.fork()
            if pid > 0:
                sys.exit(0)
        except OSError, e:
            sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
            sys.exit(1)
 
        os.chdir(".")
        os.setsid()
        os.umask(0)
 
        # делаем второй fork
        try:
            pid = os.fork()
            if pid > 0:
                sys.exit(0)
        except OSError, e:
            sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
            sys.exit(1)
 
        # перенаправление стандартного ввода/вывода
        sys.stdout.flush()
        sys.stderr.flush()
        si = file(self.stdin, 'r')
        so = file(self.stdout, 'a+')
        se = file(self.stderr, 'a+', 0)
        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())
 
        # записываем pidfile
        atexit.register(self.delpid)
        pid = str(os.getpid())
        file(self.pidfile,'w+').write("%s\n" % pid)
 
    def delpid(self):
        os.remove(self.pidfile)

    def start(self):
        """
        Запуск дeмона
        """
        # Проверяем pidfile, чтоб узнать не запущен ли уже процесс
        try:
            pf = file(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None
 
        if pid:
            message = "pidfile %s already exist. Daemon already running?\n"
            sys.stderr.write(message % self.pidfile)
            sys.exit(1)
     
        # Запуск дeмона
        self.daemonize()
        self.run()

    def stop(self):
        """
        Остановка дeмона
        """
        # Берем pid из pidfile
        try:
            pf = file(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None
 
        if not pid:
            message = "pidfile %s does not exist. Daemon not running?\n"
            sys.stderr.write(message % self.pidfile)
            return # не считается ошибкой при перезапуске

        # Убиваем процесс дeмона
        try:
            while 1:
                os.kill(pid, SIGTERM)
                time.sleep(0.1)
        except OSError, err:
            err = str(err)
            if err.find("No such process") > 0:
                if os.path.exists(self.pidfile):
                    os.remove(self.pidfile)
            else:
                print str(err)
                sys.exit(1)

    def restart(self):
        """
        Перезапуск дeмона
        """
        self.stop()
        self.start()

    def run(self):
        """
        Вы должны переопределить данный метод в подклассе. Он должен быть вызван
        после вызова метода daemonize() в методе start().
        """

Скрипт для запуска в качестве дeмона /home/webserver/webserverdaemon.py:
#!/usr/bin/env python
# -*- coding: utf8 -*-
import sys
import webserver
from daemon import Daemon

class MyDaemon(Daemon):
    def run(self):
        webserver.start()

if __name__ == "__main__":
    my_daemon = MyDaemon('/var/run/webserver.pid')

    if len(sys.argv) >= 2:
        if 'start' == sys.argv[1]:
            print 'starting webserver'
            my_daemon.start()
        elif 'stop' == sys.argv[1]:
            print 'stoping webserver'
            my_daemon.stop()
        elif 'restart' == sys.argv[1]:
            print 'restarting webserver'
            my_daemon.restart()
    else:
        print "Unknown command"
        sys.exit(2)
    sys.exit(0)


Стартовые скрипты при запуске Системы находятся в /etc/init.d
Создаем файл /etc/init.d/webserver со следующим содержимым:
#!/bin/sh
# Description: Starts Python scripts
### BEGIN INIT INFO
# Provides: Scripts
# Required-Start: $network $local_fs $syslog
# Required-Stop: $local_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Start Python scripts
### END INIT INFO

case $1 in
  start)
/home/webserver/webserverdaemon.py start
;;
  stop)
/home/webserver/webserverdaemon.py stop
;;
  restart)
/home/webserver/webserverdaemon.py restart
;;
  *)
 echo "Usage: scripts {start|stop|restart}"
exit 1
esac

Не забываем сделать файлы исполняемыми:
sudo chmod 777 -R /home/webserver
sudo chmod 777 /etc/init.d/webserver

Теперь управлять скриптом можно как дeмон командами:
sudo /etc/init.d/webserver start
sudo /etc/init.d/webserver restart
sudo /etc/init.d/webserver stop
Для того чтобы скрипт запускался с загрузкой системы введите команду:
sudo update-rc.d webserver defaults
Для того чтобы удалить скрипт из автозагрузки :
sudo update-rc.d webserver remove

воскресенье, 23 декабря 2012 г.

Django установка и настройка виртуального хоста Apache в Ubuntu

 Последнюю версию Django берем от сюда
 Распаковываем архив. Заходим в папку с распакованным архивом. Запускаем команду
sudo python setup.py install

 Для проверки корректности установки:
python -c "import django; print django.VERSION;"
(1, 3, 1, 'final', 0)
 Django успешно установлен.
 Далее создадим проект Django. Определим место положения проектов. В моем случае это /home/user/django.
sudo mkdir /home/user/django
cd /home/user/django
 Для создания проекта вводим (в моем случае название проекта mysite):
django-admin.py startproject mysite
 Для связки Apache и Django нужен пакет mod_wsgi
 Для установки данного пакета вводим команду:
sudo apt-get install libapache2-mod-wsgi

 Проверим, что в Apache подгружается mod_wsgi:
ls -l /etc/apache2/mods-enabled/ | grep wsgi
 Должно появиться:
lrwxrwxrwx 1 root root 27 2009-02-18 22:41 wsgi.conf -> ../mods-available/wsgi.conf
lrwxrwxrwx 1 root root 27 2009-02-18 22:41 wsgi.load -> ../mods-available/wsgi.load
 Далее "научим" Apache запускать наш проект.
 В папке с проектом (в моем случае /home/user/django/mysite) создайте каталог (допустим apache). В данном каталоге создайте файле django.wsgi
Содержимое данного файла (Обратите внимание на sys.path.append() и os.environ['DJANGO_SETTINGS_MODULE']):
import os
import sys

sys.path.append('/home/user/django/mysite/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
 Создали интерфейс между Django и WSGI
 Конфигурация виртуального хоста
 Откройте конфигурационный файл вашего сервер, например, /etc/apache2/sites-available/django.example.ru.conf и внесите в него изменения:
<virtualhost *:80*>
   ServerName django.example.ru
   DocumentRoot /home/user/django/mysite
   WSGIScriptAlias / /home/user/django/mysite/apache/django.wsgi
</virtualhost>
 Включаем виртуальный хост:
cd/etc/apache2/sites-available
sudo a2ensite django.example.ru.cong
 Рестарт Apache
sudo /etc/init.d/apache2 restart
 Чтобы проверить, что Django корректно работает через mod_wsgi необходимо попытаться открыть URL
It worked!
Congratulations on your first Django-powered page.

Of course, you haven't actually done any work yet. Here's what to do next:
* If you plan to use a database, edit the DATABASE_* settings in settings/settings.py.
* Start your first app by running python settings/manage.py startapp [appname].
 Использованные ссылки:
http://www.vdsadmin.ru/webserver-apache-wsgi-django

понедельник, 24 сентября 2012 г.

Добавление кодировок в Ubuntu


Для просмотра установленных кодировок.
locale -a

Запускаем реконфиг локалей
sudo dpkg-reconfigure locales

Генерируем локаль
locale-gen ru_RU.CP1251
или
locale-gen ru_RU.UTF-8