MongoDB + Django

mongodb
mongoDB — документо-ориентированная система управления базами данных (СУБД) с открытым исходным кодом, не требующая описания схемы таблиц. Написана на языке C++ и распространяется в рамках лицензии Creative Commons.

В последнее время становится довольно популярной и восстребованой. И вот возникла идея использовать ее в связке с фреймворком Django. Собственно о чем далее и пойдет речь.

Для решения поставленной задачи мы будем использовать приложение mongodb-engine. Данное приложение тесно связано еще с несколькими приложениями, установкой которых мы и займемся вначале.

Django-nonrel — используется для поддержки NoSQL в Django.

pip install hg+https://bitbucket.org/wkornewald/django-nonrel

djangotoolbox — набор инструментов для работы с нереляционными базами данных, лишним не будет.

pip install hg+https://bitbucket.org/wkornewald/djangotoolbox

А теперь уже ставим и mongodb-engine:

pip install git+https://github.com/django-nonrel/mongodb-engine

Указываем нашу базу данных в settings:

DATABASES = {
   'default' : {
      'ENGINE' : 'django_mongodb_engine',
      'NAME' : 'my_database'
   }
}

При необходимости также можно указать host, port, user, password.

Данное приложение предоставляет два типа полей для хранения произвольных данных, не входящих в стандартную django модель.

ListField

Списки и им подобные, представление массивов в формате BSON

from djangotoolbox.fields import ListField

class Post(models.Model):
    ...
    tags = ListField()
>>> Post(tags=['django', 'mongodb'], ...).save()
>>> Post.objecs.get(...).tags
['django', 'mongodb']

Вариант с указанием типа:

class Post(models.Model):
    ...
    edited_on = ListField(models.DateTimeField())
>>> post = Post(edited_on=['1010-10-10 10:10:10'])
>>> post.save()
>>> Post.objects.get(...).edited_on
[datetime.datetime([1010, 10, 10, 10, 10, 10])]

Данный тип поля удобно использовать для организации связи один-ко-многим:

from djangotoolbox.fields import EmbeddedModelField, ListField

class Post(models.Model):
    ...
    comments = ListField(EmbeddedModelField('Comment'))

class Comment(models.Model):
    ...
    text = models.TextField()

EmbeddedModelField — используется для организации связей между моделями.

DictField

Второй тип поля DictField, который используется в BSON для обьектов.

from djangotoolbox.fields import DictField

class Image(models.Model):
    ...
    exif = DictField()
>>> Image(exif=get_exif_data(...), ...).save()
>>> Image.objects.get(...).exif
{u'camera_model' : 'Spamcams 4242', 'exposure_time' : 0.3, ...}

Вариант с указанием типа:

class Poll(models.Model):
    ...
    votes = DictField(models.IntegerField())
>>> Poll(votes={'bob' : 3.14, 'alice' : '42'}, ...).save()
>>> Poll.objects.get(...).votes
{u'bob' : 3, u'alice' : 42}
Обновление данных
Post.objects.filter(...).update(title='Everything is the same')

Можно использовать для обновления оператор $set

.update(..., {'$set': {'title': 'Everything is the same'}})

А также функцию F()

Post.objects.filter(...).update(visits=F('visits')+1)

В результате получится что то такое:

.update(..., {'$inc': {'visits': 1}})
Использование низко-уровневых запросов

Если Вам не хватает возможностей Django ORM, можно использовать запросы к MongoDB минуя стандартный механизм.

raw_query() — принимает один аргумент, возвращает данные в виде стандартного Django queryset. Что хорошо для дальнейшей обработки данных.

Пример с geo данными, модель:

from djangotoolbox.fields import EmbeddedModelField
from django_mongodb_engine.contrib import MongoDBManager

class Point(models.Model):
    latitude = models.FloatField()
    longtitude = models.FloatField()

class Place(models.Model):
    ...
    location = EmbeddedModelField(Point)

    objects = MongoDBManager()

получим все точки рядом с конкретными координатами:

>>> here = {'latitude' : 42, 'longtitude' : 3.14}
>>> Place.objects.raw_query({'location' : {'$near' : here}})

raw_update() — используется если нам недостаточно стандартных средств для обновления данных.

Модель:

from django_mongodb_engine.contrib import MongoDBManager

class FancyNumbers(models.Model):
    foo = models.IntegerField()

    objects = MongoDBManager()

использование:

FancyNumbers.objects.raw_update({}, {'$bit' : {'foo' : {'or' : 42}}})

В данном примере выполняется побитовое or для каждого foo в базе.

На этом возможности данной связки не заканчиваются, но если пречислять все, то статья не оправдано затянется. Полное описание и примеры можно будет посмотреть по представленным ниже ссылкам.

Ссылки:
MongoDB
mongodb-engine
GitHub

Python и Twisted

twistedTwisted — это фреймворк на Python для разработки сетевых приложений, который среди многих других применений, может быть использован и для параллельной обработки данных — мультипроцессности. Это замечательно, но мне пришлось попотеть для того, чтобы найти то, что мне нужно.

twisted_ntwk_pro_ess_comp.indd

Я листал документацию Twisted и книгу O’Reilly Twisted. Существует также рецепт в Python Cookbook. Однако, самое интересное я нашел в статье Брюса Эккель — Параллельность с Python, Twisted и Flex. Также стоит прочитать первоначальные статьи Брюса Эккель про Twisted: Grokking Twisted.

Вот мои замечания о текущем примере Брюса.

Python CookbookЯ убрал Flex — отчасти потому, что мне это не нужно и я ничего не хочу знать об этом. В примере запускается контроллер, который инициализирует ряд отдельных параллельных процессов-вычислителей, в которых уже запускаются какие-то сложные действия (эти процессы называют solvers). Также тут имеется взаимодействие между контроллером и вычислителями. Хотя этот пример запускается только на одной машине, те принципы, о которых говориться в статье — не трудно распространить и на систему из нескольких компьютеров.

Для хорошего примера, как это работает, пожалуйста, смотрите оригинал статьи.

Вот solver.py который скопирован с оригинала. Настоящая «работа» происходит в методе step(). Я только добавил некоторую отладочную информацию для себя.

"""
solver.py
Original version by Bruce Eckel
Solves one portion of a problem, in a separate process on a separate CPU
"""
import sys, random, math
from twisted.spread import pb
from twisted.internet import reactor

class Solver(pb.Root):

    def __init__(self, id):
        print "solver.py %s: solver init" % id
        self.id = id

    def __str__(self): # String representation
        return "Solver %s" % self.id

    def remote_initialize(self, initArg):
        return "%s initialized" % self

    def step(self, arg):
        print "solver.py %s: solver step" % self.id
        "Simulate work and return result"
        result = 0
        for i in range(random.randint(1000000, 3000000)):
            angle = math.radians(random.randint(0, 45))
            result += math.tanh(angle)/math.cosh(angle)
        return "%s, %s, result: %.2f" % (self, str(arg), result)

    # Alias methods, for demonstration version:
    remote_step1 = step
    remote_step2 = step
    remote_step3 = step

    def remote_status(self):
        print "solver.py %s: remote_status" % self.id
        return "%s operational" % self

    def remote_terminate(self):
        print "solver.py %s: remote_terminate" % self.id
        reactor.callLater(0.5, reactor.stop)
        return "%s terminating..." % self

if __name__ == "__main__":
    port = int(sys.argv[1])
    reactor.listenTCP(port, pb.PBServerFactory(Solver(sys.argv[1])))
    reactor.run()

Вот controller.py. Он также скопирован из оригинальной статьи, но я убрал Flex и создал сигналы start и terminate в классе контроллера. Я не уверен, что это имеет смысл, но, по крайней мере, это позволило мне нормально использовать пример. Я также перенес метод terminate из FlexInterface в Controller.

"""
Controller.py
Original version by Bruce Eckel
Starts and manages solvers in separate processes for parallel processing.
"""
import sys
from subprocess import Popen
from twisted.spread import pb
from twisted.internet import reactor, defer

START_PORT = 5566
MAX_PROCESSES = 2

class Controller(object):

    def broadcastCommand(self, remoteMethodName, arguments, nextStep, failureMessage):
        print "controller.py: broadcasting..."
        deferreds = [solver.callRemote(remoteMethodName, arguments) 
                     for solver in self.solvers.values()]
        print "controller.py: broadcasted"
        reactor.callLater(3, self.checkStatus)

        defer.DeferredList(deferreds, consumeErrors=True).addCallbacks(
            nextStep, self.failed, errbackArgs=(failureMessage))

    def checkStatus(self):
        print "controller.py: checkStatus"
        for solver in self.solvers.values():
            solver.callRemote("status").addCallbacks(
                lambda r: sys.stdout.write(r + "\n"), self.failed, 
                errbackArgs=("Status Check Failed"))

    def failed(self, results, failureMessage="Call Failed"):
        print "controller.py: failed"
        for (success, returnValue), (address, port) in zip(results, self.solvers):
            if not success:
                raise Exception("address: %s port: %d %s" % (address, port, failureMessage))

    def __init__(self):
        print "controller.py: init"
        self.solvers = dict.fromkeys(
            [("localhost", i) for i in range(START_PORT, START_PORT+MAX_PROCESSES)])
        self.pids = [Popen(["python", "solver.py", str(port)]).pid
                     for ip, port in self.solvers]
        print "PIDS: ", self.pids
        self.connected = False
        reactor.callLater(1, self.connect)

    def connect(self):
        print "controller.py: connect"
        connections = []
        for address, port in self.solvers:
            factory = pb.PBClientFactory()
            reactor.connectTCP(address, port, factory)
            connections.append(factory.getRootObject())
        defer.DeferredList(connections, consumeErrors=True).addCallbacks(
            self.storeConnections, self.failed, errbackArgs=("Failed to Connect"))

        print "controller.py: starting parallel jobs"
        self.start()

    def storeConnections(self, results):
        print "controller.py: storeconnections"
        for (success, solver), (address, port) in zip(results, self.solvers):
            self.solvers[address, port] = solver
        print "controller.py: Connected; self.solvers:", self.solvers
        self.connected = True

    def start(self):
        "controller.py: Begin the solving process"
        if not self.connected:
            return reactor.callLater(0.5, self.start)
        self.broadcastCommand("step1", ("step 1"), self.step2, "Failed Step 1")

    def step2(self, results):
        print "controller.py: step 1 results:", results
        self.broadcastCommand("step2", ("step 2"), self.step3, "Failed Step 2")

    def step3(self, results):
        print "controller.py: step 2 results:", results
        self.broadcastCommand("step3", ("step 3"), self.collectResults, "Failed Step 3")

    def collectResults(self, results):
        print "controller.py: step 3 results:", results
        self.terminate()

    def terminate(self):
        print "controller.py: terminate"
        for solver in self.solvers.values():
            solver.callRemote("terminate").addErrback(self.failed, "Termination Failed")
        reactor.callLater(1, reactor.stop)
        return "Terminating remote solvers"

if __name__ == "__main__":
    controller = Controller()
    reactor.run()

Чтобы запустить программу, положите оба файла в одну папку и запустите

python controller.py

Вы должны увидеть, как загрузка двух процессоров (если их, конечно, у вас — 2) поднимется до 100%. А вот и вывод скрипта на экран:

controller.py: init
PIDS:  [12173, 12174]
solver.py 5567: solver init
solver.py 5566: solver init
controller.py: connect
controller.py: starting parallel jobs
controller.py: storeconnections
controller.py: Connected; self.solvers: {('localhost', 5567): , ('localhost', 5566): }
controller.py: broadcasting...
controller.py: broadcasted
solver.py 5566: solver step
solver.py 5567: solver step
controller.py: checkStatus
solver.py 5566: remote_status
Solver 5566 operational
solver.py 5567: remote_status
controller.py: step 1 results: [(True, 'Solver 5567, step 1, result: 683825.75'), (True, 'Solver 5566, step 1, result: 543177.17')]
controller.py: broadcasting...
controller.py: broadcasted
Solver 5567 operational
solver.py 5566: solver step
solver.py 5567: solver step
controller.py: checkStatus
solver.py 5566: remote_status
Solver 5566 operational
solver.py 5567: remote_status
controller.py: step 2 results: [(True, 'Solver 5567, step 2, result: 636793.90'), (True, 'Solver 5566, step 2, result: 335358.16')]
controller.py: broadcasting...
controller.py: broadcasted
Solver 5567 operational
solver.py 5566: solver step
solver.py 5567: solver step
controller.py: checkStatus
solver.py 5566: remote_status
Solver 5566 operational
solver.py 5567: remote_status
controller.py: step 3 results: [(True, 'Solver 5567, step 3, result: 847386.43'), (True, 'Solver 5566, step 3, result: 512120.15')]
controller.py: terminate
Solver 5567 operational
solver.py 5566: remote_terminate
solver.py 5567: remote_terminate

Интерфейсы к SOCKS5

anonymous-proxy-server

PHP

Используется cURL:

$ch=curl_init("http://www.fbi.gov");

   @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   // возвращаем результат, а не выводим его в печать
   @curl_setopt($ch, CURLOPT_VERBOSE, 0);
   //запрещаем выводить подробные сообщения о всех действиях
   @curl_setopt($ch, CURLOPT_HEADER, 0);
   // запрещаем Headers
   @curl_setopt($ch, CURLOPT_PROXY, "192.168.0.100:47047");
   //IP адрес и порт SOCKS5
   @curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); 
   //включаем использование SOCKS5
   $x=@curl_exec($ch);

curl_close($ch);

echo $x;
//выводим содержимое страницы в браузер

Python

Используем SocksiPy через wrapmodule()

1. Импортируем SocksiPy и другие модули
2. Запускаем setdefaultproxy() и передаем нужные данные
3. Загружаем целевой модуль внутри модуля wrapmodule()

# Импортируем нужные модули
import ftplib
import telnetlib
import urllib2

# Импортитуем SocksiPy
import socks

# Загружаем прокси
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, 'localhost', 9050)

# Перенаправляем FTP-сессию через SOCKS прокси
socks.wrapmodule(ftplib)
ftp = ftplib.FTP('cdimage.ubuntu.com')
ftp.login('anonymous', 'chicago@ic.fbi.gov')
print ftp.dir('cdimage')
ftp.close()

# Перенаправляем соединение telnet через SOCKS прокси
socks.wrapmodule(telnetlib)
tn = telnetlib.Telnet('achaea.com')
print tn.read_very_eager()
tn.close()

# Перенаправляем HTTP-запросы через SOCKS прокси
socks.wrapmodule(urllib2)
print urllib2.urlopen('http://www.whatismyip.com/automation/n09230945.asp').read()

 

Используем SocksiPy через socksocket

1. Импортируем SocksiPy
2. Загружаем socks.socksocket, который возвращает несколько параметров для socket.socket.
3. Запускаем setproxy() и передаем нужные данные
4. Подключаемся и используем сокет, как обычный…

import socks
s = socks.socksocket()
s.setproxy(socks.PROXY_TYPE_SOCKS5, 'localhost', 9050)
s.connect(('www.whatismyip.com', 80))
s.send('GET /automation/n09230945.asp HTTP/1.1\r\n\r\n')

data = ''
buf = s.recv(1024)
while len(buf):
data += buf
buf = s.recv(1024)
s.close()

print("Connected from %s." % (data))

Open Graph тэги вручную для тем WordPress

open-graph-facebookДля начала нужно заменить стандартный тег <html> на тот, что нам нужен. Открываете файл header.php и заменяете стандартный тег:

<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>

на этот код:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:fb="http://ogp.me/ns/fb#" 
      xmlns:og="http://ogp.me/ns#" <?php language_attributes(); ?>>

В этом же файле header.php перед закрывающим тегом </head> вставляете код тегов Open Graph Facebook:

<!--Open Graph Facebook-->

<?php if (have_posts()):while(have_posts()):the_post(); endwhile; endif;?>  

<!-- постоянные значения -->  

<meta property="fb:admins" content="ВАШ_ЛИЧНЫЙ_ID_FACEBOOK" />  

<!-- если это статья -->  

<?php if (is_single()) { ?>  
<meta property="og:url" content="<?php the_permalink(); ?> "/>  
<meta property="og:title" content="<?php single_post_title(''); ?>" />  
<meta property="og:description" 
         content="<?php echo strip_tags(get_the_excerpt($post->ID)); ?>" />  
<meta property="og:type" content="article" />  
<meta property="og:image" 
content="<?php if (function_exists('wp_get_attachment_thumb_url')) {echo 
wp_get_attachment_thumb_url(get_post_thumbnail_id($post->ID)); } ?>" />  

<!-- если это любая другая страница -->  

<?php } else { ?>  
<meta property="og:site_name" content="<?php bloginfo('name'); ?>" />  
<meta property="og:description" 
       content="<?php bloginfo('description'); ?>" />  
<meta property="og:type" content="website" />  
<meta property="og:image" content="http://ПУТЬ-К-КАРТИНКЕ/КАРТИНКА.jpg" /> 
<?php } ?>

Вставьте ссылку на картинку, которая будет отображаться по умолчанию, если в статье или на странице нет других картинок. Как правило, сюда вставляется ссылка на логотип.

Сохраняете изменения и проверяете работу тегов Open Graph, нажав на кнопку «Мне нравится» в любой статье блога.

Может быть ситуация, при которой картинка статьи всё равно публикуется некорректно или вся статья просто не отображается (как было у меня). Это значит, что функция wp_get_attachment_thumb_url() не работает. Тогда необходимо сделать следующие действия.

Замените этот тег:

<meta property="og:image" 
content="<?php if (function_exists('wp_get_attachment_thumb_url')) {echo 
wp_get_attachment_thumb_url(get_post_thumbnail_id($post->ID)); }?>" />

на этот тег:

<meta property="og:image" 
      content="<?php if (function_exists('catch_that_image')) 
      {echo catch_that_image(); }?>" />

Сохраните изменения. Затем справа в панели управления найдите ссылку на файл «Функции темы» (functions.php), откройте его и в конце кода перед знаком ?> вставьте следующий код:

function catch_that_image() {  
    global $post, $posts;  
    $first_img = '';  
    ob_start();  
    ob_end_clean();  
    $output = preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"] title="3 варианта, как настроить теги Open Graph Facebook для WordPress?" alt="3 варианта, как настроить теги Open Graph Facebook для WordPress?">/i', $post->post_content, $matches);  
    $first_img = $matches [1] [0];  
    if(empty($first_img)){  
            //Определяет картинку по умолчанию 
            $first_img = "http://ПУТЬ_К_КАРТИНКЕ_ПО_УМОЛЧАНИЮ/ФОТО.jpg";  
        }  
    return $first_img;  
}

Этот код описывает функцию catch_that_image(), которая находит первую картинку в статье блога и вставляет её ссылку в тег изображения Open Graph. Если в статье нет картинки, то эта функция использует изображение по умолчанию. Для этого вставьте ссылку нужного изображения в эту переменную:

$first_img = "http://ПУТЬ_К_КАРТИНКЕ_ПО_УМОЛЧАНИЮ/ФОТО.jpg";

Теперь сохраняйте изменения в файле functions.php, заходите на блог и проверяйте работу кнопок «Мне нравится». Всё должно работать корректно.

Compiling Kernel 3.8 on Debian Testing/Wheezy

linuxNOTE: It seems like series 3.8 has issues with intel (i915) graphics — it occasionally generates kworker threads that causes unresponsiveness as seen by slow mouse and keyboard response when e.g. plugging or unplugging mains power. No issues on e.g. nvidia though.

http://verahill.blogspot.com.au/2013/03/368-slow-mouse-and-keyboard-triggered.html
http://forums.gentoo.org/viewtopic-p-7278760.html
https://bbs.archlinux.org/viewtopic.php?pid=1248190

Post: Kernel 3.8 is out now. Not much to say — the compilation works well using the standard method. The compressed kernel is about 81 Mb to download.

The approach below shows how to compile the kernel on Debian. If you’re interested in a more generic approach, see this post:

http://verahill.blogspot.com.au/2013/02/344-compile-kernel-38-without-using-kpkg.html

NOTE: kernel 3.8 — in contrast to the 3.7 series — now compiles fine on AMD FX 8150.

NOTE: kernel 3.8 plays well with nvidia dkms

Here we go:

sudo apt-get install kernel-package fakeroot build-essential ncurses-dev
mkdir ~/tmp
cd ~/tmp
wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.8.tar.bz2
tar xvf linux-3.8.tar.bz2
cd linux-3.8/
cat /boot/config-`uname -r`>.config
make oldconfig

You will be asked a lot of questions — how many depends on what version you upgrade from. If in doubt, pick the default answer (i.e. hit enter). If really in doubt, use google.

Then continue:

make-kpkg clean

Do

make menuconfig

if you want to make any specific changes to the kernel (e.g. add support for certain devices)

Then continue:

time fakeroot make-kpkg -j4 --initrd kernel_image kernel_headers
As usual 4 is the number of threads you wish to launch — make it equal to the number of cores that you have for optimum performance during compilation (more about that here).
The build takes around 20 minutes on a four-core intel i5-2400 with -j4, and 14 minutes on an fx-8150 with -j8 (96 minutes with -j1).
Install:
sudo dpkg -i ../linux-image-3.8.0_3.8.0-10.00.Custom_amd64.deb ../linux-headers-3.8.0_3.8.0-10.00.Custom_amd64.deb
New stuff/Questions:
Offload RCU callback processing from boot-selected CPUs (RCU_NOCB_CPU) [N/y/?] (NEW) *
Memory placement aware NUMA scheduler (NUMA_BALANCING) [N/y/?] (NEW) *
Enable to assign a node which has only movable memory (MOVABLE_NODE) [N/y/?] (NEW)
Allow for memory hot-add (MEMORY_HOTPLUG) [Y/n] y
Allow for balloon memory compaction/migration (BALLOON_COMPACTION) [Y/n/?] (NEW)
Set default setting of cpu0_hotpluggable (BOOTPARAM_HOTPLUG_CPU0) [N/y/?] (NEW
Debug CPU0 hotplug (DEBUG_HOTPLUG_CPU0) [N/y/?] (NEW)
ACPI tables can be passed via uncompressed cpio in initrd (ACPI_INITRD_TABLE_OVERRIDE) [N/y/?] (NEW)
Support multiple cpuidle drivers (CPU_IDLE_MULTIPLE_DRIVERS) [N/y/?] (NEW)
"NOTRACK" target support (DEPRECATED) (NETFILTER_XT_TARGET_NOTRACK) [N/m] (NEW

Default SCTP cookie HMAC encoding
  > 1. Enable optional MD5 hmac cookie generation (SCTP_DEFAULT_COOKIE_HMAC_MD5) (NEW)
    2. Enable optional SHA1 hmac cookie generation (SCTP_DEFAULT_COOKIE_HMAC_SHA1) (NEW)
    3. Use no hmac alg in SCTP cookie generation (SCTP_DEFAULT_COOKIE_HMAC_NONE) (NEW)
  choice[1-3?]:   Enable optional MD5 hmac cookie generation (SCTP_COOKIE_HMAC_MD5) [Y/?] (NEW) y

Enable optional SHA1 hmac cookie generation (SCTP_COOKIE_HMAC_SHA1) [N/y/?] (NEW) *
Enable optional MD5 hmac cookie generation (SCTP_COOKIE_HMAC_MD5) [Y/?] (NEW) y
Distributed ARP Table (BATMAN_ADV_DAT) [N/y/?] (NEW)
Kvaser CAN/USB interface (CAN_KVASER_USB) [N/m/?] (NEW)
LSI MPT Fusion SAS 3.0 Device Driver (SCSI_MPT3SAS) [N/m/?] (NEW)
Chelsio Communications FCoE support (SCSI_CHELSIO_FCOE) [N/m/?] (NEW) *
Marvell 88E6060 ethernet switch chip support (NET_DSA_MV88E6060) [N/m/y/?] (NEW)
Marvell 88E6085/6095/6095F/6131 ethernet switch chip support (NET_DSA_MV88E6131) [N/m/y/?] (NEW)
Marvell 88E6123/6161/6165 ethernet switch chip support (NET_DSA_MV88E6123_61_65) [N/m/y/?] (NEW) *
Cadence devices (NET_CADENCE) [Y/n/?] (NEW)
AT91RM9200 Ethernet support (ARM_AT91_ETHER) [N/m/y/?] (NEW)
Cadence MACB/GEM support (MACB) [N/m/y/?] (NEW)
Broadcom devices (NET_VENDOR_BROADCOM) [Y/?] y
Marvell MDIO interface support (MVMDIO) [N/m/y/?] (NEW)
CDC MBIM support (USB_NET_CDC_MBIM) [N/m/?] (NEW)
Atheros Wireless Cards (ATH_CARDS) [N/m/?] (NEW)
Atheros AR5523 wireless driver support (AR5523) [N/m/?] (NEW)
Wilocity 60g WiFi card wil6210 support (WIL6210) [N/m/?] (NEW) *
Realtek RTL8723AE PCIe Wireless Network Adapter (RTL8723AE) [N/m/?] (NEW)
ARC UART driver support (SERIAL_ARC) [N/m/y/?] (NEW) *
CBUS I2C driver (I2C_CBUS_GPIO) [N/m/?] (NEW)
TS-5500 DIO blocks and compatibles (GPIO_TS5500) [N/m/y/?] (NEW) 
TI BQ2415x battery charger driver (CHARGER_BQ2415X) [N/m/?] (NEW)
Board level reset or power off (POWER_RESET) [N/y/?] (NEW) *

 Default Thermal governor
  > 1. step_wise (THERMAL_DEFAULT_GOV_STEP_WISE) (NEW)
    2. fair_share (THERMAL_DEFAULT_GOV_FAIR_SHARE) (NEW)
    3. user_space (THERMAL_DEFAULT_GOV_USER_SPACE) (NEW)
  choice[1-3?]:   Fair-share thermal governor (FAIR_SHARE) [N/y/?] (NEW)

Step_wise thermal governor (STEP_WISE) [Y/?] (NEW) y
User_space thermal governor (USER_SPACE) [N/y/?] (NEW)
SSB GPIO driver (SSB_DRIVER_GPIO) [N/y/?] (NEW) *
BCMA GPIO driver (BCMA_DRIVER_GPIO) [N/y/?] (NEW)
Support for Realtek PCI-E card reader (MFD_RTSX_PCI) [N/m/y/?] (NEW)
TI ADC / Touch Screen chip support (MFD_TI_AM335X_TSCADC) [N/m/y/?] (NEW)
Support for Nano River Technologies Viperboard (MFD_VIPERBOARD) [N/m/?] (NEW)
Support for Retu multi-function device (MFD_RETU) [N/m/?] (NEW) *
Maxim MAX8973 voltage regulator  (REGULATOR_MAX8973) [N/m/?] (NEW)
TI TPS51632 Power Regulator (REGULATOR_TPS51632) [N/m/?] (NEW)
Siano SMS1xxx based MDTV receiver (SMS_USB_DRV) [N/m/?] (NEW)
Siano SMS1xxx based MDTV via SDIO interface (SMS_SDIO_DRV) [N/m/?] (NEW)   *
Stanton Control System 1 MIDI (SND_SCS1X) [N/m/?] (NEW) *
ION iCade arcade controller (HID_ICADE) [N/m/?] (NEW)
HID over I2C transport layer (I2C_HID) [N/m/?] (NEW) *
Renesas R-Car USB phy support (USB_RCAR_PHY) [N/m/?] (NEW)   *
SDHCI support for ACPI enumerated SDHCI controllers (MMC_SDHCI_ACPI) [N/m/?] (NEW)
NXP PCF8523 (RTC_DRV_PCF8523) [N/m/?] (NEW)
Philips PCF8563/Epson RTC8564 (RTC_DRV_PCF8563) [M/n/?] m
Userspace platform driver with generic irq and dynamic memory (UIO_DMEM_GENIRQ) [N/m/?] (NEW)
Microsoft Hyper-V Balloon driver (HYPERV_BALLOON) [N/m/?] (NEW) *
SystemBase PCI Multiport UART (SB105X) [N/m/y/?] (NEW)
TTY over Firewire (FIREWIRE_SERIAL) [N/m/?] (NEW) *
F2FS filesystem support (EXPERIMENTAL) (F2FS_FS) [N/m/y/?] (NEW) *
Enable CIFS debugging routines (CIFS_DEBUG) [Y/n/?] (NEW)
Simplified Mandatory Access Control Kernel Support (SECURITY_SMACK) [N/y/?] (NEW)
Camellia cipher algorithm (x86_64/AES-NI/AVX) (CRYPTO_CAMELLIA_AESNI_AVX_X86_64) [N/m/y/?] (NEW)

Поиск файлов в Linux

find

Для начала создаем файл заданного размера, который в последующем будем искать.

0. Создадим файл размером 10 Мбайт с размером блока 100 Кбайт:

rootoor@srv:~/dd-test$ dd if=/dev/zero of=file1.test bs=100K count=100
100+0 записей считано
100+0 записей написано
скопировано 10240000 байт (10 MB), 0,0448225 c, 228 MB/c

rootoor@srv:~/dd-test$ ls -l
итого 10000
-rw-r--r-- 1 rootoor rootoor 10240000 2013-05-05 13:47 file1.test

rootoor@srv:~/dd-test$

/dev/zero – специальный файл в UNIX-подобных системах, представляющий собой источник нулевых байтов (ASCII NUL, 0x00)

of=file.test – файл который создаем

bs=100K – размер блока, 100 КБайт (может быть: К — КБайт, М — МБайт, — ГБайт)

count=100 – количество блоков

В результате мы получили заданный файл, размером 100К*100=10 МБ

rootoor@srv:~# dd if=/dev/zero of=/var/www/file1.test bs=1M count=52
52+0 records in
52+0 records out
54525952 bytes (55 MB) copied, 0.453559 s, 120 MB/s

теперь в директории /var/www/ находится файл file1.test размером 52 МБ.

1. Поиск файлов в текущей директории размером больше 10 Мбайт

rootoor@srv:/var/www$ find . -size +10M -print
./var/www/file1.test

find – утилита для поиска файлов

. – где ищем. В нашем случае текущей директории (/var/www/* – поиск в директории /var/www/~ — поиск в домашней директории/ – поиск в корне файловой системы$HOME – поиск в домашней директории )

-size +10M – размер искомого файла. Больше 10 Мбайт (b – блок, размером 512 байт, c – байт, w – слово, размером 2 байта, k – килобайт, M – мегабайт и G– гигабайт )

-print – вывод на экран

2. Поиск файлов больше 50 Мб с выводом детальной информации

Усложним задачу и попробуем вывести на экран кроме имени файла еще некоторую информацию о нем.

rootoor@srv:~# find /var/www/* -type f -size +50000k -exec ls -lh {} \; | awk '{ print $8 " " $5 " " $1 " " $3":"$4 }'

./var/www/test1.file 110M -rw-r--r-- rootoor:rootoor
./var/www/file1.test 52M -rw-r--r-- rootoor:rootoor

-type f – тип, который ищем (f – файл, d – директория, l – символичная ссылка, s – сокет, b – блок)

-exec ls -lh {} \; – выполняет команду ls -lh над найденными файлами (вывод содержимого директории)

awk ‘{ print $8 » » $5 » » $1 » » $3″:»$4 }’ – обрабатываем вывод информации командой ls -lh

и выводим более детальную информацию в нужном нам порядке:
$8 – имя файла
$5 – размер файла
$1 – права доступа
$3 – владелец
$4 – группа

3. Поиск файлов заданного размера и определенного имени

rootoor@srv:~# find $HOME -name w*  -size +1M -exec ls -lh {} \; | awk '{ print $8 " " $5 }'

/home/rootoor/kawabanga.tar.gz 17M

-name w* – любой файл имя, которого содержит w*

 

Разделение большого файла на несколько частей

Split

$ split --bytes=<размер части> <исходный файл> <префикс имени части>

Размер частей может иметь суффикс, означающий множитель.

b — 512
kB — 1000
K — 1024
MB — 1000*1000
M — 1024*1024
GB — 1000*1000*1000
G — 1024*1024*1024

и так далее для T, P, E, Z, Y.

Пример:

$ split -a 1 -d -b 100M big.iso small.iso.part

Получим много файлов по 100 Мб, с суффиксами part0, part1, part2, part3…:

small.iso.part0
small.iso.part1
small.iso.part2
small.iso.part3

и т.д.

Чтобы снова объединить все части воедино, можно использовать команду cat:

$ cat small.iso.part* > big.iso

Утилита cat соберет все файлы, начиная с small.iso.part0.

Бесплатные DNS-сервера

DNS-servers

Primary only:
primaryns.kiev.ua — доступен только для Украины

Primary and secondary:
zoneedit.com — 5 доменов, меня все устраивает
everydns.net — 20 доменов, нет email-forwarding
dnspark.com — 3 домена
soa.granitecanyon.com — доменов неограничено
domain-dns.com — доменов неограничено, нельзя создавать NS-записи
xname.org
mydomain.com — очень перегружен, очень тормознут
dns.xtremeweb.de = gratisdns.de — нету mail-forwarding
freedns.afraid.org — нет описания
editdns.net — нет описания
prosto.name — Хороший новенький русский сервис
dnsexit.com
1gb.ru
freedns.sgh.waw.pl — как xname.org
freedns.ws
namecheap.com
www.netbreeze.net/dns/ — панель на русском
help.yandex.ru/pdd/hosting.xml

Secondary only:
ns2.trifle.net
secondary.net.ua

Оперативная реакция на DDoS-атаки

DDoS-network-mapОдин из ресурсов, за которым я присматриваю, вдруг стал неожиданно популярным как у хороших пользователей, так и у плохих. Мощное, в общем-то, железо перестало справляться с нагрузкой. Софт на сервере самый обычный — Linux, Nginx, PHP-FPM (+APC), MySQL, версии — самые последние. На сайтах крутится Drupal и phpBB. Оптимизация на уровне софта (memcached, индексы в базе, где их не хватало) чуть помогла, но кардинально проблему не решила. А проблема — большое количество запросов, к статике, динамике и особенно базе. Поставил следующие лимиты в Nginx:

на соединения

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 100;

и скорость запросов на динамику (fastcgi_pass на php-fpm)

limit_req_zone $binary_remote_addr zone=dynamic:10m rate=2r/s;
limit_req zone=dynamic burst=10 nodelay;

Сильно полегчало, по логам видно, что в первую зону никто не попадает, зато вторая отрабатывает по полной.

Но плохиши продолжали долбить, и захотелось их отбрасывать раньше — на уровне фаервола, и надолго.

Сначала сам парсил логи, и особо настырных добавлял через iptables в баню. Потом парсил уже по крону каждые 5 минут. Пробовал fail2ban. Когда понял, что плохишей стало очень много, перенёс их в ipset ip hash.

Почти всё хорошо стало, но есть неприятные моменты:
— парсинг/сортировка логов тоже приличное (процессорное) время отнимает
— сервер тупит, если началась новая волна между соседними разборками (логов)

Нужно было придумать как быстро добавлять нарушителей в черный список. Сначала была идея написать/дописать модуль к Nginx + демон, который будет ipset-ы обновлять. Можно и без демона, но тогда придётся запускать Nginx от рута, что не есть красиво. Написать это реально, но понял, что нет столько времени. Ничего похожего не нашёл (может плохо искал?), и придумал вот такой алгоритм.

При привышении лимита, Nginx выбрасывает 503-юю ошибку Service Temporarily Unavailable. Вот я решил на неё и прицепиться!

Для каждого location создаём свою страничку с ошибкой

error_page 503 =429 @blacklist;

И соответствующий именованный location

location @blacklist {
    fastcgi_pass    localhost:1234;
    fastcgi_param   SCRIPT_FILENAME    /data/web/cgi/blacklist.sh;
    include         fastcgi_params;
}

Дальше интересней.

Нам нужна поддержка CGI-скриптов. Ставим, настраиваем, запускаем spawn-fcgi и fcgiwrap. У меня уже было готовое для collectd.

Сам CGI-скрипт fc

#!/bin/bash

BAN_TIME=5
DB_NAME="web_black_list"
SQLITE_DB="/data/web/cgi/${DB_NAME}.sqlite3"
CREATE_TABLE_SQL="\
CREATE TABLE $DB_NAME (\
    ip varchar(16) NOT NULL PRIMARY KEY,\
    added DATETIME NOT NULL DEFAULT (DATETIME()),\
    updated DATETIME NOT NULL DEFAULT (DATETIME()),\
    counter INTEGER NOT NULL DEFAULT 0
)"
ADD_ENTRY_SQL="INSERT OR IGNORE INTO $DB_NAME (ip) VALUES (\"$REMOTE_ADDR\")"
UPD_ENTRY_SQL="UPDATE $DB_NAME SET updated=DATETIME(), counter=(counter+1) WHERE ip=\"$REMOTE_ADDR\""
SQLITE_CMD="/usr/bin/sqlite3 $SQLITE_DB"
IPSET_CMD="/usr/sbin/ipset"

$IPSET_CMD add $DB_NAME $REMOTE_ADDR > /dev/null 2>&1

if [ ! -f $SQLITE_DB ]; then
     $SQLITE_CMD "$CREATE_TABLE_SQL"
fi

$SQLITE_CMD "$ADD_ENTRY_SQL"
$SQLITE_CMD "$UPD_ENTRY_SQL"

echo "Content-type: text/html"
echo ""

echo "<html>"
echo "<head><title>429 Too Many Requests</title></head>"
echo "<body bgcolor=\"white\">"
echo "<center><h1>429 Too Many Requests</h1></center>"
echo "<center><small><p>Your address ($REMOTE_ADDR) is blacklisted for $BAN_TIME minutes</p></small></center>"
echo "<hr><center>$SERVER_SOFTWARE</center>"
echo "</body>"
echo "</html>"

Собственно всё очевидно, кроме, разве что, SQLite. Я его добавил пока просто для статистики, но в принципе можно использовать и для удаления устаревших плохишей из черного списка. Время 5 минут пока тоже не используется.

Черный список создавался вот так

ipset create web_black_list hash:ip

Правило в iptables у каждого может быть своё, в зависимости от конфигурации и фантазии.

З.Ы.: Улыбнуло сообщение одного «хакера» на форуме, как быстро он положил сервер. Он и не догадывался, что это сервер положил на него.

Источник: http://habrahabr.ru/post/176119/