пятница, 25 ноября 2011 г.

nginx и imagecache

Мало кто знает что я помимо своих Баз и кое-какого программирования занимаюсь еще и администрированием web-сервера.
Там много чего крутится и хостится, и настал такой случай, который описан и решен не раз и не одним мной.

Итак, фронтэнд - nginx, бэкэнд - apache2, на сайте установлен Drupal. Когда imagecache должен генерить картинки и выдавать их, nginx воспринимает их как статику, пытается найти и не может. Соответственно, в логах куча ошибок, а в интерфейсе пусто, вместо картинок.

Решается все следующим образом: когда nginx не может найти что-то, он выдает ошибку 404. Ну вот мы и сделаем, чтоб он вместо своей 404 ошибки он перенаправлял запросы в апач, а тот уже разберется сам:

# то, что будет отдавать nginx
                location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|swf|js)$ {
                        root /var/www/vhosts/example.com/www;
                        error_page 404 = @backend;
                }
# запрещаем доступ к .ht - файлам
                location ~ /\.ht {
                        deny  all;
                }
# описываем наш бэкэнд
                location @backend {
                        proxy_pass http://example.com:8888;
                        proxy_set_header Host $host;
                        proxy_set_header X-Real-IP $remote_addr;
                        proxy_set_header X-Forwarded-For $remote_addr;

                        proxy_connect_timeout 120;
                        proxy_send_timeout    120;
                        proxy_read_timeout    180;
                }
# все что не попало в предыдущие правила уходит на бэкэнд
                location / {
                        try_files $uri @backend;
                }

пятница, 14 октября 2011 г.

Запуск приложения с параметрами. Python

Столкнулся с интересной особенностью (хотя какая к черту особенность, баг это) при запуске приложений через spawnl Есть приложение callbuilder, которому надо передать параметры '/O1' чтоб не спрашивал оператора при запуске, '/c' чтоб закрывался после обработки файла и сам файл. Пишу

import os
callbuilder = 'c:\\callbuilder\\SMPCallBuilder.exe'
filename = 'c:\\CDR\\comlog_14_10_2011.tfs'
os.spawnl (os.P_WAIT, callbuilder, '/c', '/O1', filename)

Запускается, не спрашивает оператора при старте, но не закрывается.
Меняю на os.spawnl (os.P_WAIT, callbuilder, '/O1', '/c', filename) спрашивает при старте, но закрывается как отработает.
Пишу os.spawnl (os.P_WAIT, callbuilder, '/1', '/c', '/O1', filename) Все ок.
В итоге получается, что первый ключ, который я прописываю после имени исполняемого файла - не используется. Почему - не знаю.

вторник, 9 августа 2011 г.

Распаковываю большой файл. Python

Есть у меня коллекторы, где собираются и обрабатываются flow-потоки с оборудования. Их надо обрабатывать, считать кто сколько и куда байтов послал/получил.
С изменением сети, объемы растут и наступил такой момент, что мой старый скрипт отказался распаковывать 850 метровый архив с ошибкой "Memory Error".
Спасибо, что добрый человек (Гриша, привет!) подсказал как справиться с этим. Ну и спасибо, конечно stackowerflow.com
Итак код:

def read_by_pieces(file_object, piece_size = 1048576): ## 1Mb
    while True:
        data = file_object.read(piece_size)
        if not data:
            break
        yield data

if __name__ == '__main__':
    import gzip
    gz = gzip.open ('d:\\2011-08-07_04.txt.gz') # largefile ~ 850 Mb
    ungz = open ('d:\\2011-08-07_04.txt', 'wb')
    for piece in read_by_pieces(gz, 10485760): ## 10 Mb
        ungz.write(piece)


В результате, распаковывается 850 Mb файл в 3.5 Гб файл за примерно 5 минут.
Я думаю, можно добиться и лучших результатов, но мне сейчас нужно именно такое наколенное решение.

понедельник, 8 августа 2011 г.

Параметры для скрипта. Python

Таких постов сотни, но я ж для себя пишу, правильно?
Передаем параметры из командной строки нашему скрипту


from optparse import OptionParser

parser = OptionParser()
parser.add_option("-r", "--remotehost", dest = "ftphost", help = "FTP host")
parser.add_option("-l", "--login", dest = "ftpu", help = "FTP login")
parser.add_option("-p", "--password", dest = "ftpp", help = "FTP password")
parser.add_option("-d", "--directory", dest = "ftpdir", 
help = "FTP directory", default = "\pub\")
(options, args) = parser.parse_args()

# read options
ftpdir = options.ftpdir
ftphost = options.ftphost
ftpu = options.ftpu
ftpp = options.ftpp



А теперь из ini-файла
Сначала пишем

import configparser
config = configparser.RawConfigParser ()
config.add_section('mail')
config.set ('mail', 'server', 'smtp.server.local')
config.set ('mail', 'from', 'user1@server.local')
config.set ('mail', 'to', 'user2@server.local')
with open('settings.ini', 'w') as cfile:
    config.write (cfile)




Теперь читаем


import configparser 
cfg = configparser.RawConfigParser ()
cfg.read ('settings.ini')
print (cfg.get ('mail', 'server'))
print (cfg.get ('mail', 'from'))
print (cfg.get ('mail', 'to'))

четверг, 14 июля 2011 г.

find

Саша!
Запомни как пишется print в команде find:


find /var/ftp/ -ctime +1 -name "*_in.wav" -printf 'Name: %f Date: %TY-%Tm-%Td %TT\n'

вторник, 24 мая 2011 г.

Oracle и я

Пост о том, как я сначала боролся, а потом подружился с Oracle.

Задача: развернуть "горячий" бэкап БД
Средства: любые

Во-первых, я нашел внятный мануал как поставить Oracle на Linux.
Во-вторых сам Oracle. Я брал версию 10g r2 для Linux
Сначала меня удивил установщик,его надо обязательно запускать из-под иксов(!), что на мой взгляд не совсем удобно. Продолжая действовать по шагам у меня все получилось, за исключением web-менеджера (я так подумал, он мне нахер не нужен).
А потом началось самое интересное. Бекап и рестор баз данных на Oracle.
Какое-то время все шло хорошо и даже возникающие ошибки были нормальным делом в такой ситтуации.
Меня подкосила команда
recover database  until  cancel   using  backup  controlfile;
После ее запуска я ввел AUTO и рестор стал просить у меня архивные логи. Как оказалось, ему они требовались все и я их копировал и копировал с работающей базы.
В конце концов он меня попросил дать ему архивный файл, которого не было на сервере с работающей базой.
Решил я подойти с другой стороны. Так как мне не важно было на какой момент восстановится база, а важно чтоб она в принципе восстановилась, то я изменил команду на
recover database  until  change 88654992150   using  backup  controlfile;

Вот это загадочное длинное число - это (я так понял) номер изменения в базе после начала бэкапа. И соответственно все изменения до него, рековер должен брать в архивных файлах.
Кстати, есть еще вариант с until date, но я его приберегу до следующего раза.
Затем, естественно, при попытке
alter database open resetlogs;
он выдавал мне ошибку, что мол, не могу. В логах я нашел, что версия не подходящая, версия базы 10.2.0.3.0, а версия сервера 10.2.0.1.0.
Ок, давай ставить патч. Искал я его очень долго, в конце концов нашел на торрентах, потому что с oracle.com скачать я его не смог.
После установки патча я сначала проапгрейдил тестовую базу, которая ставится вместе с Oracle, а потом принялся за свою. Как обычно бывает в таких ситтуациях, в первом случае все прошло отлично, во втором случае были проблемы.
Не буду описывать все свои мытарства, а расскажу решение.
Запускаем $sqlplus /nolog
SQL> connect / as sysdba
SQL> startup upgrade
Тут база монтируется и открывается для апгрейда.
SQL> @?/rdbms/admin/utlirp.sql
Долго-долго выполняется скрипт. Он исправляет все неправильные объекты в БД
SQL> shut
Вырубаем и запускаем. Затем делаем:
SQL> startup upgrade
SQL> @?/rdbms/admin/catupgrd.sql
Опять долго-долго выполняется скрипт. Но это последнее, что нужно сделать для апгрейда.
SQL> shut
Теперь вырубаем и запускаем в нормальном режиме
SQL> startup
Проапгрейдить базу мне помогли здесь и здесь
После этого осталось только настроить tsnlistener и работать.

Upd. Я забыл про temp-файл. его надо создать командой:
SQL> alter tablespace temp add  tempfile '/path/to/base/temp/temp01.dbf' SIZE 500M;
Удалить его можно другой командой
alter database tempfile '/path/to/base/temp/temp01.dbf' drop;

Upd2.Восстановление до времени
SQL> recover database until time '2011-07-27:15:30:00' using backup controlfile

пятница, 15 апреля 2011 г.

Hello, Android!

Встречаются два фотографа:
- Я теперь стоматолог!
- Как так?
- Да вот, бор-машинку купил.

Ну так вот, я теперь Andoid-программист =)

четверг, 14 апреля 2011 г.

Linux Maniacs: Управленеи квотами

Linux Maniacs: Управленеи квотами: "Немного информации: 1. Что такое квотирование? Квотирование позволяет ограничить два аспекта использования диска: количество файлов, кото..."

среда, 13 апреля 2011 г.

ох уж этот Delphi

Написал сервис в делфи. Работает прекрасно, качает файлы с фтп по маске, все как надо.
А когда не может соединиться или еще какие проблемы у него - должен отсылать письмо.
Ну, казалось бы, в чем проблема, есть SMTP, есть ящик и пароль

  IDMessage1.Subject := smtpSubj;
  IDMessage1.Recipients.EMailAddresses := smtpRcpt + ';';
  IDMessage1.From.Address := smtpFrom;
  IDMessage1.Body.Text := text;

  smtp1.Connect();
  smtp1.Send(IDMessage1);
  smtp1.Disconnect;

Но не тут то было. Если тема написано по русски, то приходит не пойми что.
Решается проблема так:
В IDMessage1 есть событие OnInitializeISO. В нем пишем следущее:


  VCharset := 'windows-1251';
  VHeaderEncoding := 'B';

Ну или ту кодировку, которая вам нужна. И тогда сообщения приходят на русском.

четверг, 3 февраля 2011 г.

Листинг директории по маске. Python

Сегодня был слегка удивлен, когда узнал что listdir не может делать листинг по заданной маске. На помощь пришли регулярные выражения и замечательный сайт.
Итак

import os
import re

settings = re.compile ('settings(\d*)\.ini$', re.IGNORECASE)
flist = filter (settings.search, os.listdir('.'))
for f in flist:
   print (f)

В результате у меня имеются все файлы settings*.ini, которые находятся в текущей директории.
И как бонус, у меня пропал страх перед регэкспами