2009-09-14

Настройка bucardo 4.x.x попытка 1 (пока удачная)

Итак, после выхода 4-й версии bucardo, будем спрыгивать на неё. Посмотрел changelog, много вкусного. Так что считаю, что смена версии оправдана.
В который раз жалею, что данный проект не собирается в rpm варианте и не обновляется через репозитарии SUSE.

Сервер bucardo: 22.22.11.71

Делать все будем с нуля. И начнем с того, что выкосим сушествующую версию 3.0.9.

alexsf@shaman:~> ssh alexsf@22.22.11.71
alexsf@bucardik:~> sudo -s
bucardik:/home/alexsf # su - root
bucardik:~ # /etc/init.d/bucardo_stop
bucardik:~ # su - postgres
postgres@bucardik:~> psql -h 22.22.11.71 -U bucardo bucardo
bucardo=# DELETE FROM bucardo.sync;
bucardo=# DELETE FROM bucardo.herdmap;
bucardo=# DELETE FROM bucardo.herd;
bucardo=# DELETE FROM bucardo.goat;
bucardo=# DELETE FROM bucardo.dbmap;
bucardo=# DELETE FROM bucardo.dbgroup;
bucardo=# DELETE FROM bucardo.db;
bucardo=# \q
postgres@bucardik:~> psql -h 22.22.25.2 -U postgres UTF8_sk
UTF8_sk=# DROP SCHEMA bucardo CASCADE;
UTF8_sk=# \q
postgres@bucardik:~> psql -h 22.22.50.2 -U postgres ntres
ntres=# DROP SCHEMA bucardo CASCADE;
ntres=# \q
postgres@bucardik:~> psql -h 22.22.11.71 -U postgres postgres
postgres=# DROP DATABASE bucardo;
postgres=# \q
postgres@bucardik:~> exit

При этом оставляем пользователя БД bucardo (CREATE ROLE bucardo LOGIN SUPERUSER INHERIT NOCREATEDB NOCREATEROLE;), БД bucardo(CREATE DATABASE bucardo WITH ENCODING='UTF8' OWNER=bucardo
CONNECTION LIMIT=-1 TABLESPACE=bucardo;) и табличное пространство bucardo (CREATE TABLESPACE bucardo OWNER bucardo LOCATION '/u02/pgdata/bucardo';), ну и локального пользователя bucardo (bucardo:x:1001:100:Bucardo Replication:/home/bucardo:/bin/bash)

Кроме того, у нас уже проставлена толпа perl модулей. Их тоже пока не трогаем.

Ну а теперь получаем свежую версию bucardo и начинаем танцы с бубном :).

bucardik:~ # mkdir /opt/bucardo; cd /opt
bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.0.1.tar.gz"
bucardik:/opt # wget -c "http://bucardo.org/downloads/DBIx-Safe-1.2.5.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.0.1.tar.gz
bucardik:/opt # tar -xvzf DBIx-Safe-1.2.5.tar.gz
bucardik:/opt # cd DBIx-Safe-1.2.5/
bucardik:/opt/DBIx-Safe-1.2.5 # perl Makefile.PL
bucardik:/opt/DBIx-Safe-1.2.5 # make
bucardik:/opt/DBIx-Safe-1.2.5 # make test
bucardik:/opt/DBIx-Safe-1.2.5 # make install

Теперь ради приличия проверим, устраивают ли нас версии установленных perl модулей. И видим:

Надо "DBD::Pg, at least version 2.0.0", установлено "1.49"

Вытягиваем и ставим.
bucardik:/opt/bucardo/DBIx-Safe-1.2.5 # cd ..
bucardik:/opt # wget -c "http://search.cpan.org/CPAN/authors/id/T/TU/TURNSTEP/DBD-Pg-2.15.1.tar.gz"
bucardik:/opt # tar -xvzf DBD-Pg-2.15.1.tar.gz
bucardik:/opt # cd DBD-Pg-2.15.1/
bucardik:/opt/DBD-Pg-2.15.1 # perl Makefile.PL

И получаем, что версия DBI 1.51 не канает. Нужна 1.52

bucardik:/opt/DBD-Pg-2.15.1 # cd ..
bucardik:/opt # wget -c "http://search.cpan.org/CPAN/authors/id/T/TI/TIMB/DBI-1.52.tar.gz"
bucardik:/opt # tar -xvzf DBI-1.52.tar.gz
bucardik:/opt # cd DBI-1.52
bucardik:/opt/DBI-1.52 # perl Makefile.PL
bucardik:/opt/DBI-1.52 # make
bucardik:/opt/DBI-1.52 # make test
bucardik:/opt/DBI-1.52 # make install
bucardik:/opt/DBI-1.52 # cd ../DBD-Pg-2.15.1
bucardik:/opt/DBD-Pg-2.15.1 # perl Makefile.PL
bucardik:/opt/DBD-Pg-2.15.1 # make
bucardik:/opt/DBD-Pg-2.15.1 # make test
bucardik:/opt/DBD-Pg-2.15.1 # make install

Так. Теперь собственно bucardo. Дока щас там весьма размазанная на сайте. Будем разбираться.

Создаем файл /etc/bucardorc со следующим содержимым:

dbport=5432
dbhost=22.22.11.71
dbname=bucardo
dbuser=bucardo
dbpass=bucardo

Затем:

bucardik:/opt/DBD-Pg-2.15.1 # cd ../Bucardo-4.0.1/
bucardik:/opt/Bucardo-4.0.1 # perl Makefile.PL
bucardik:/opt/Bucardo-4.0.1 # make
bucardik:/opt/Bucardo-4.0.1 # make test
bucardik:/opt/Bucardo-4.0.1 # make install
bucardik:/opt/Bucardo-4.0.1 # cd /opt
bucardik:/opt # ln -s Bucardo-4.0.1 bucardo

Малёко приберемся для порядку, а то у нас в /opt всякого хламу насобиралось...

bucardik:/opt # mkdir bucardo.install
bucardik:/opt # mv Bucardo-4.0.1.tar.gz bucardo.install/
bucardik:/opt # mv DBD-Pg-2.15.1* bucardo.install/
bucardik:/opt # mv DBI* bucardo.install/

Проверим, что работает скрипт /opt/bucardo/bucardo_ctl

bucardik:/opt # /opt/bucardo/bucardo_ctl --version
bucardik:/opt # /opt/bucardo/bucardo_ctl --help
bucardik:/opt # man bucardo_ctl
bucardik:/opt # whereis bucardo_ctl
bucardik:/opt # bucardo_ctl --version

Ух ты, сколько всего интересного... Самое интересное, что корректно прописаны маны bucardo, и bucardo_ctl прописался в /usr/bin. Им и будем пользоваться. Ну будем считать, что установку bucardo закончили.

Теперь настройка...

bucardik:/opt # bucardo_ctl install

И после того, как нас спрашивает пароль на пользователя bucardo, какого-то хрена получаем ошибку авторизации... Возможно виноваты настройки pg_hba.conf... самое интересное, что объекты БД создаются. Вопрос только в том, до конца ли... Как вариант, поставить версию bucardo поновее. Там в git уже 4.0.2 есть. И bucardo_ctl по размеру существенно отличается...

Ну вот, пока думал, появилась версия 4.0.3. Пробуем...

bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.0.3.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.0.3.tar.gz
bucardik:/opt # cd Bucardo-4.0.3/
bucardik:/opt/Bucardo-4.0.3 # make
bucardik:/opt/Bucardo-4.0.3 # make test
bucardik:/opt/Bucardo-4.0.3 # make install
bucardik:/opt/Bucardo-4.0.3 # cd ..
bucardik:/opt # mv Bucardo-4.0.3.tar.gz bucardo.install/
bucardik:/opt # ln -s Bucardo-4.0.3 bucardo
bucardik:/opt # bucardo_ctl install

Получаем следующий вывод:

Current connection settings:
1. Host: 22.22.11.71
2. Port: 5432
3. User: postgres
4. Database: postgres
5. PID directory: /var/run/bucardo

Это при том, что в bucardorc прописаны совершенно другие настройки. Да что за блядство такое??? Ладно, проверим установку ничего не меняя... И получаем ту же ошибку...
Так... Изменим подробности логирования postgres, чтобы попытаться получить более подробную информацию о том, почему не получается подключиться к БД. В /var/lib/pgsql/data/postgresql.conf добавляем:

log_min_messages = INFO
log_error_verbosity = VERBOSE
log_min_error_statement = INFO
log_connections = on
log_disconnections = on
log_statement = all

и перезапускаем postgres. Пытаемся снова bucardo_ctl install, смотрим логи, и ничего толкового не видим. Кроме одной вещи - объекты под пользователем bucardo создаются, потом bucardo отключается, пытается опять подключиться и не может. Может пароль пользователя меняется??? отключим подробное логирование и перезапустим postgres.

Попробуем сделать тест установки bucardo более совершенным и проверить, а не вываливаются ли там какие-нибудь ошибки...

Как всегда, все гениально просто!!! В pg_hba.conf делаем бешеную настройку на время установки. Потом вертаем в зад. А настройка такая:

local all all trust
host all all 127.0.0.1/32 trust
host all all 0.0.0.0/0 trust

После этого:

bucardik:/opt # bucardo_ctl install

И радуемся, потому что всё получилось :)

Поднастроим малеько:

bucardik:/opt # bucardo_ctl set log_conflict_file=/var/log/bucardo/bucardo_conflict.log
bucardik:/opt # bucardo_ctl set reason_file=/var/log/bucardo/bucardo.restart.reason.log
bucardik:/opt # bucardo_ctl set warning_file=/var/log/bucardo/bucardo.warning.log

Пробуем добавить Скадовск:


bucardik:/opt/Bucardo-4.0.3 # cd ../bucardo
bucardik:/opt/bucardo # bucardo_ctl add database allres name=res host=22.22.11.71 user=res pass=somepass
bucardik:/opt/bucardo # bucardo_ctl add database skres name=UTF8_sk host=22.22.25.3 user=res pass=somepass
bucardik:/opt/bucardo # bucardo_ctl add dbgroup master
bucardik:/opt/bucardo # bucardo_ctl add dbgroup slave

И тут я понял, что напутал. Как теперь удалить то, что я добавил?

Пока то да сё, разные проблемы, вышла очередная версия bucardo 4.1.2. Обновимся.

bucardik:/opt/bucardo # cd ..
bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.1.2.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.1.2.tar.gz
bucardik:/opt # su - postgres
postgres@bucardik:~> psql
postgres=# drop database bucardo;
postgres=# CREATE DATABASE bucardo WITH ENCODING='UTF8' OWNER=bucardo
postgres-# CONNECTION LIMIT=-1 TABLESPACE=bucardo;
postgres=# \q
postgres@bucardik:~> exit
bucardik:/opt # rm bucardo
bucardik:/opt # ln -s Bucardo-4.1.2 bucardo
bucardik:/opt # mv Bucardo-4.1.2.tar.gz bucardo.install/
bucardik:/opt # cd bucardo
bucardik:/opt/bucardo # perl Makefile.PL
bucardik:/opt/bucardo # make
bucardik:/opt/bucardo # make install
bucardik:/opt/bucardo # bucardo_ctl --version

Видим, что версия 4.1.2. Гуд. Теперь устанавливаем БД bucardo. Для этого, как раньше, меняем в pg_hba.conf все на trust, и...

bucardik:/opt/bucardo # /etc/init.d/postgresql reload
bucardik:/opt/bucardo # bucardo_ctl install

Потом в pg_hba.conf вертаем всё в зад, и...

bucardik:/opt/bucardo # /etc/init.d/postgresql reload

Немного настраиваем глобальные параметры:

bucardik:/opt/bucardo # bucardo_ctl set default_email_from=bucardo@co.ksoe.com.ua
bucardik:/opt/bucardo # bucardo_ctl set default_email_to=fa@co.ksoe.com.ua
bucardik:/opt/bucardo # bucardo_ctl set default_email_host=22.22.11.51

Ну и наконец-то пробуем добавить Скадовск:

bucardik:/opt/bucardo # bucardo_ctl add database res name=allres host=22.22.11.71 user=res pass=somepasswd
bucardik:/opt/bucardo # bucardo_ctl add database UTF8_sk name=skres host=22.22.25.2 user=res pass=jsdgfj
bucardik:/opt/bucardo # bucardo_ctl add dbgroup master
bucardik:/opt/bucardo # bucardo_ctl add dbgroup slave

Пришел с утра на работу, и опять новая версия, 4.2.0 Ур-р-р-р-а-а-а-а!!! Вперед!!!!

bucardik:/opt/bucardo # cd ..
bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.2.0.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.2.0.tar.gz
bucardik:/opt # bucardo_ctl stop "for upgrade"
bucardik:/opt # cd Bucardo-4.2.0/
bucardik:/opt/Bucardo-4.2.0 # perl Makefile.PL
bucardik:/opt/Bucardo-4.2.0 # make
bucardik:/opt/Bucardo-4.2.0 # make install
bucardik:/opt/Bucardo-4.2.0 # cd ..; rm bucardo
bucardik:/opt # ln -s Bucardo-4.2.0 bucardo
bucardik:/opt # mv Bucardo-4.2.0.tar.gz bucardo.install/

Тут не забываем поменять pg_hba.conf

bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl validate all

А после этого не забываем вернуть pg_hba.conf на место.

И несмотря на то, что мы вроде в процессе не получили ни одной ошибки, при выводе bucardo_ctl show all нам показывает версию 4.1.2... Ну че за херня??? Будем надеяться, что просто девелоперы провтыкали при обновлении изменить версию bucardo_config? Отправил баг по этому поводу на bucardo.org. Посмотрим, как они отреагируют...

Так, Скадовск. Делаем заново... Для начала всё вычищаем:

bucardik:/opt # su - postgres
postgres@bucardik:~> psql -h 22.22.11.71 bucardo bucardo
bucardo=# delete from sync;
bucardo=# delete from herdmap;
bucardo=# delete from herd;
bucardo=# delete from goat;
bucardo=# delete from db;
bucardo=# \q
postgres@bucardik:~> postgres@bucardik:~> psql -h 22.22.11.71 res res
res=# drop schema res cascade;
res=# create schema res authorization res;
res=# \q
postgres@bucardik:~> mv work work.old
postgres@bucardik:~> mkdir work; cd work

Вроде всё вычистили. Теперь настраиваем Скадовск...

postgres@bucardik:~/work> pg_dump -h 22.22.25.2 -p 5432 -U postgres -F p -s -s -v -f "skres_schema.sql" -n 'res' "UTF8_sk"
postgres@bucardik:~/work> psql -f skres_schema.sql -h 22.22.11.71 -U res res
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \o drop_constr.sql \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'c'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY con.conname;
res=# \o drop_rule.sql
res=# SELECT 'DROP RULE '||rulename||' ON '||tablename||';'
res-# FROM pg_rules
res-# WHERE schemaname = 'res'
res-# ORDER BY tablename, rulename;
res=# \o drop_rule_constr.log
res=# \i drop_constr.sql
res=# \i drop_rule.sql
res=# \q
postgres@bucardik:~/work> exit
bucardik:/opt # bucardo_ctl add database UTF8_sk name=skres host=22.22.25.2 user=res pass=password
bucardik:/opt # bucardo_ctl add database res name=allres host=22.22.11.71 user=res pass=password
bucardik:/opt # bucardo_ctl add all tables db=skres --herd=skres_herd --verbose
bucardik:/opt # psql -h 22.22.11.71 bucardo bucardo
bucardo=# DELETE FROM bucardo.herdmap
bucardo-# WHERE goat IN (SELECT id
bucardo(# FROM bucardo.goat WHERE tablename IN
bucardo(# ('rp_abon','log','dual','billsqlreport'));
bucardo=# DELETE FROM bucardo.goat
bucardo-# WHERE tablename IN
bucardo-# ('rp_abon','log','dual','billsqlreport');
bucardo=# \q
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> ssh root@22.22.25.2
linux01:~ # su - postgres -c "cd /files/ftp; pg_dump -C -F c -b -f pgsql.UTF8_sk "UTF8_sk""; exit
postgres@bucardik:~/work> exit
bucardik:/opt # bucardo_ctl add sync skres_sync type=pushdelta source=skres_herd targetdb=allres --verbose
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> wget --no-proxy -c --ftp-user=sit --ftp-password=? ftp://22.22.25.2/ftp/pgsql.UTF8_sk
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \o drop_fk.sql \t
res=# SELECT 'ALTER TABLE res.'||t.tablename
res-# ||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t,
res-# information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'f'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY t.tablename, con.conname;
res=# \o drop_fk.log
res=# \i drop_fk.sql \q
postgres@bucardik:~/work> pg_restore -h 22.22.11.71 -U res -d res -a -v "pgsql.UTF8_sk"
postgres@bucardik:~/work> grep FOREIGN -B 1 skres_schema.sql > restore_fk.sql
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \i restore_fk.sql \q
postgres@bucardik:~/work> exit
bucardik:/opt # bucardo_ctl start "first start"

Проверяем, и видим, что замечательно работает!!!! Ура, товарищи!!!
Ну а пока мы тут занимались Скадовском, разработчики не дремлют, и успели выпустить версию 4.2.1. Обновимся, товарищи, ибо в актуальности наша сила!!! Тем более, что нам нужно провести тест обновления софта при настроеной репликации!!!

bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.2.1.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.2.1.tar.gz
bucardik:/opt # bucardo_ctl stop "for upgrade from 4.2.0 to 4.2.1"
bucardik:/opt # cd Bucardo-4.2.1/
bucardik:/opt/Bucardo-4.2.1 # perl Makefile.PL
bucardik:/opt/Bucardo-4.2.1 # make
bucardik:/opt/Bucardo-4.2.1 # make install
bucardik:/opt/Bucardo-4.2.1 # bucardo_ctl --version
bucardik:/opt/Bucardo-4.2.1 # cd ..; rm bucardo
bucardik:/opt # ln -s Bucardo-4.2.1 bucardo
bucardik:/opt # mv Bucardo-4.2.1.tar.gz bucardo.install/
Меняем pg_hba.conf на trust
bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl upgrade
Меняем pg_hba.conf на password
bucardik:/opt # bucardo_ctl validate all
bucardik:/opt # bucardo_ctl start "after upgrade from 4.2.0 to 4.2.1"

Проверяем и радуемся, репликация бегает нормально.
Теперь нужно поменять пароль на пользователя res, создать пользователя только на чтение. Приступим.

bucardik:/opt # bucardo_ctl stop "for change some password"
bucardik:/opt # psql -h 22.22.11.71 postgres postgres
postgres=# alter role res password 'frr';
postgres=# \q
bucardik:/opt # psql -h 22.22.11.71 bucardo bucardo
bucardo=# UPDATE bucardo.db SET dbpass='frr' WHERE name='allres';
bucardo=# \q
bucardik:/opt # bucardo_ctl start "after change password for db allres"

bucardik:/opt # psql -h 22.22.11.71 postgres postgres
postgres=# CREATE ROLE res_read LOGIN PASSWORD 'res_read';
postgres=# \q
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \o grant_table.sql \t
res=# SELECT 'GRANT SELECT, REFERENCES ON TABLE '
res-# ||schemaname||'.'||tablename||' TO res_read;'
res-# FROM pg_tables
res-# WHERE schemaname = 'res';
res=# \o grant_view.sql
res=# SELECT 'GRANT SELECT, REFERENCES ON TABLE '
res-# ||schemaname||'.'||viewname||' TO res_read;'
res-# FROM pg_views
res-# WHERE schemaname = 'res';
res=# \o grants.log
res=# \i grant_table.sql
res=# \i grant_view.sql
res=# GRANT USAGE ON SCHEMA res TO res_read;
res=# \q
postgres@bucardik:~/work> exit
bucardik:/opt #

Обновимся опять до свежей версии 4.2.2:

bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.2.2.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.2.2.tar.gz
bucardik:/opt # bucardo_ctl stop "for upgrade from 4.2.1 to 4.2.2"
bucardik:/opt # cd Bucardo-4.2.2/
bucardik:/opt/Bucardo-4.2.2 # perl Makefile.PL
bucardik:/opt/Bucardo-4.2.2 # make
bucardik:/opt/Bucardo-4.2.2 # make install
bucardik:/opt/Bucardo-4.2.2 # bucardo_ctl --version
bucardik:/opt/Bucardo-4.2.2 # cd ..; rm bucardo
bucardik:/opt # ln -s Bucardo-4.2.2 bucardo
bucardik:/opt # mv Bucardo-4.2.2.tar.gz bucardo.install/
Меняем pg_hba.conf на trust
bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl upgrade
Меняем pg_hba.conf на password
bucardik:/opt # bucardo_ctl validate all
bucardik:/opt # bucardo_ctl start "after upgrade from 4.2.1 to 4.2.2"

Проверили, всё работает.

Теперь добавляем Новотроицк.

bucardik:/opt # bucardo_ctl stop "for add ntres"
bucardik:/opt # bucardo_ctl add database ntres name=ntres host=22.22.50.2 user=res pass=sss
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> psql -h 22.22.11.71 res bucardo
res=# \o add_ntres_tables.sh \t
res=# select 'bucardo_ctl add table res.'||tablename
res-# ||' db=ntres --herd=ntres_herd --verbose'
res-# from pg_tables
res-# where tablename in
res-# (select table_name from information_schema.columns
res(# where column_name='domain_info')
res-# and tablename not like 'tmp%'
res-# and tablename not in
res-# ('rp_abon','log','dual','billsqlreport',
res(# 'tmpcounter','tmpmol',
res(# 'encustomertype','enelement',
res(# 'enelement2recordpoint','enelement2shema',
res(# 'enelementtype','enfeeder','enpost',
res(# 'enshema','ensubstation','ensubstationowner',
res(# 'ensubstationtype','enswitch',
res(# 'enswitchhistory','enswitchreason')
res-# order by tablename;
res=# \q
postgres@bucardik:~/work> exit
bucardik:/opt # bash < /var/lib/pgsql/work/add_ntres_tables.sh
bucardik:/opt # ssh root@22.22.50.2
linux01:~ # su - postgres -c "cd /files; pg_dump -C -F c -b -f pgsql.ntres "ntres""; exit
bucardik:/opt # psql -h 22.22.11.71 bucardo bucardo
bucardo=# INSERT INTO bucardo.herdmap (herd, goat)
bucardo-# SELECT 'ntres_herd', id
bucardo-# FROM goat WHERE db = 'ntres';
bucardo=# \q
bucardik:/opt # bucardo_ctl add sync ntres_sync type=pushdelta source=ntres_herd targetdb=allres --verbose
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> wget --no-proxy -c --ftp-user=sit --ftp-password=? ftp://22.22.50.2/pgsql.ntres
postgres@bucardik:~/work> pg_dump -h 22.22.11.71 -p 5432 -U res -F p -s -s -v -f "allres_schema.sql" -n 'res' "res"
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \o drop_fk_4_ntres_load.sql \t
res=# SELECT 'ALTER TABLE res.'||t.tablename
res-# ||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t,
res-# information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'f'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY t.tablename, con.conname;
res=# \o drop_fk_4_ntres_load.log \t
res=# \i drop_fk_4_ntres_load.sql
res=# \q
postgres@bucardik:~/work> psql -h 22.22.11.71 bucardo bucardo
bucardo=# \o restore_ntres_tables.sh \t
bucardo=# SELECT 'pg_restore -h 22.22.11.71 -U res -d res -a -t '
bucardo-# ||tablename||' -v "pgsql.ntres"'
bucardo-# FROM goat
bucardo-# WHERE db='ntres'
bucardo-# ORDER BY tablename;
bucardo=# \q
Меняем pg_hba.conf на trust
postgres@bucardik:~/work> bash < restore_ntres_tables.sh
Меняем pg_hba.conf на password
postgres@bucardik:~/work> grep FOREIGN -B 1 allres_schema.sql > restore_fk_allres.sql
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \i restore_fk_allres.sql \q
Тут повылазил ряд ошибок при восстановлении. Так что пока выносим FK, и запускаем репликацию без них.
postgres@bucardik:~/work> psql -h 22.22.11.71 -U res res
res=# \i drop_fk_4_ntres_load.sql \q
postgres@bucardik:~/work> exit
bucardik:/opt # bucardo_ctl start "After ntres added"

Обновляемся до версии 4.3.0

bucardik:/opt # bucardo_ctl stop "upgrade 4.2.2 -> 4.3.0"
bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.3.0.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.3.0.tar.gz
bucardik:/opt # cd Bucardo-4.3.0/
bucardik:/opt/Bucardo-4.3.0 # perl Makefile.PL
bucardik:/opt/Bucardo-4.3.0 # make
bucardik:/opt/Bucardo-4.3.0 # make install
bucardik:/opt/Bucardo-4.3.0 # bucardo_ctl --version
bucardik:/opt/Bucardo-4.3.0 # cd ..; rm bucardo
bucardik:/opt # ln -s Bucardo-4.3.0 bucardo
bucardik:/opt # mv Bucardo-4.3.0.tar.gz bucardo.install/
Меняем pg_hba.conf на trust
bucardik:/opt # /etc/init.d/postgresql reload
bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl upgrade
Меняем pg_hba.conf на password
bucardik:/opt # /etc/init.d/postgresql reload
bucardik:/opt # bucardo_ctl validate all
bucardik:/opt # bucardo_ctl start "after upgrade 4.2.2 -> 4.3.0"

Добавляем Цюрупинск:
Этот район у нас немного особенный. Ну во=первых он не расшит, так что никаких диапазонов на PK нету. Просто этот РЭС был первым. Ну и domain_info = 'root'.

bucardik:/opt # bucardo_ctl stop "for add crres"
bucardik:/opt # bucardo_ctl add database crres name=crres host=22.22.33.2 user=res pass=???
bucardik:/opt # bucardo_ctl add herd crres_herd
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> psql -h 22.22.11.71 res bucardo
res=# \o add_crres_tables.sh \t
res=# select 'bucardo_ctl add table res.'||tablename
res-# ||' db=crres --herd=crres_herd --verbose'
res-# from pg_tables
res-# where tablename in
res-# (select table_name from information_schema.columns
res(# where column_name='domain_info')
res-# and tablename not like 'tmp%'
res-# and tablename not in
res-# ('rp_abon','log','dual','billsqlreport',
res(# 'tmpcounter','tmpmol',
res(# 'encustomertype','enelement',
res(# 'enelement2recordpoint','enelement2shema',
res(# 'enelementtype','enfeeder','enpost',
res(# 'enshema','ensubstation','ensubstationowner',
res(# 'ensubstationtype','enswitch',
res(# 'enswitchhistory','enswitchreason')
res-# order by tablename;
res=# \q
postgres@bucardik:~/work> exit
bucardik:/opt # bash < /var/lib/pgsql/work/add_crres_tables.sh
bucardik:/opt # psql -h 22.22.11.71 bucardo bucardo
bucardo=# INSERT INTO bucardo.herdmap (herd, goat)
bucardo-# SELECT 'crres_herd', id
bucardo-# FROM goat WHERE db = 'crres';
bucardo=# \q
bucardik:/opt # ssh root@22.22.33.2
linux01:~ # su - postgres -c "cd /files/postgres; pg_dump -C -F c -b -f pgsql.crres "crres""; exit
bucardik:/opt # bucardo_ctl add sync crres_sync type=pushdelta source=crres_herd targetdb=allres --verbose
bucardik:/opt # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> wget --limit-rate=20000 --no-proxy -c --ftp-user=sit --ftp-password=? ftp://22.22.33.2/postgres/pgsql.crres
postgres@bucardik:~/work> psql -h 22.22.11.71 bucardo bucardo
bucardo=# \o restore_crres_tables.sh \t
bucardo=# SELECT 'pg_restore -h 22.22.11.71 -U res -d res -a -t '
bucardo-# ||tablename||' -v "pgsql.crres"'
bucardo-# FROM goat
bucardo-# WHERE db='crres'
bucardo-# ORDER BY tablename;
bucardo=# \q
Меняем pg_hba.conf на trust
postgres@bucardik:~/work> bash < restore_crres_tables.sh
postgres@bucardik:~/work> exit
bucardik:/opt # bucardo_ctl start "After crres added"

ВНИМАНИЕ!!! после каждого запуска bucardo с новым sync внимательно вычитываем логи, т.к. 99,999% вероятность, что сразу нихрена не заработает!!! А почему - сюрприз будет при вычитывании логов :)

Обновляемся до версии 4.4.0

bucardik:/opt # bucardo_ctl stop "upgrade 4.3.0 -> 4.4.0"
bucardik:/opt # wget -c "http://bucardo.org/downloads/Bucardo-4.4.0.tar.gz"
bucardik:/opt # tar -xvzf Bucardo-4.4.0.tar.gz
bucardik:/opt # cd Bucardo-4.4.0/
bucardik:/opt/Bucardo-4.4.0 # perl Makefile.PL
bucardik:/opt/Bucardo-4.4.0 # make
bucardik:/opt/Bucardo-4.4.0 # make install
bucardik:/opt/Bucardo-4.4.0 # bucardo_ctl --version
bucardik:/opt/Bucardo-4.4.0 # cd ..; rm bucardo
bucardik:/opt # ln -s Bucardo-4.4.0 bucardo
bucardik:/opt # mv Bucardo-4.4.0.tar.gz bucardo.install/
Меняем pg_hba.conf на trust
bucardik:/opt # /etc/init.d/postgresql reload
bucardik:/opt # bucardo_ctl upgrade
bucardik:/opt # bucardo_ctl upgrade
Меняем pg_hba.conf на password
bucardik:/opt # /etc/init.d/postgresql reload
bucardik:/opt # bucardo_ctl validate all
bucardik:/opt # bucardo_ctl start "after upgrade 4.3.0 -> 4.4.0"

Добавляем Белозерку:

bucardik:/opt # bucardo_ctl stop "for add bzres"

###############################

Во время заливки баз повылазили всякие нарушения целостности. Я из на этапе заливки отключил, но потом их нужно будет восстановить. Список, что нужно восстановить:

1.

FK все.

2.

CREATE UNIQUE INDEX u_cntrinvnmbr
ON res.countergen
USING btree
(invnumber);

###############################

Проверка валидности первичных ключей и доменной информации

res=# \o check_pk_code.sql \t
Показываются только записи.
### select
res=# \o check_pk_code.log \t
Режим "только записи" выключен.
res=# \i check_pk_code.sql

select 'SELECT '||ccu.column_name
||' AS "'||ccu.table_name||'.'||ccu.column_name||'.'||ccu.constraint_name
||'", domain_info'
||' FROM '||ccu.table_name
||' WHERE '||ccu.column_name||' < 80000000 OR domain_info != ''root.sk'';'
from pg_constraint pc, information_schema.constraint_column_usage ccu
where pc.contype = 'p'
and ccu.constraint_name=pc.conname
and ccu.table_name in
(select table_name from information_schema.columns
where column_name='domain_info')
and ccu.table_name not in ('rp_abon','log','dual','billsqlreport',
'tmpcounter','tmpmol','tmpcounter2counter','tmpnomenklature',
'encustomertype','enelement',
'enelement2recordpoint','enelement2shema','enelementtype','enfeeder','enpost',
'enshema','ensubstation','ensubstationowner','ensubstationtype','enswitch',
'enswitchhistory','enswitchreason')
order by ccu.table_name, ccu.column_name, ccu.constraint_name;


Читать далее

2009-09-11

Bucardo 4.0.1

Да здравствует УРА!!!
Возрадуемся други, ибо вышла новая версия bucardo, Так что будем делать прыжок с 3.0.9 на 4.0.1, благо я неуспел внедрить продакшн. А те полтора калеки, которых пихнули, лучше переделать сейчас, чем когда калек будет 18-20 штук.

Читать далее

2009-07-10

Cacti + cisco

Итак, сменили провайдера... Старый провайдер предоставлял нам статистику по каналу в mrtg, а вот новый нифига не предоставляет... А надо. Статистику нужно снимать с cisco, скорее всего по snmp протоколу. Чем снимать 2 варианта - mrtg и cacti.
Напоминаю, что используется SUSE linux (openSUSE, SLES).

Для начала проставляем все пакеты, необходимые для работы cacti. В доке это написано.
Запускаем apache2 и mysql.
Затем:

root# mysql
mysql> create database cacti;
mysql> \q
root# mysql cacti < /usr/share/cacti/cacti.sql
root# mysql cacti
mysql> show tables;
+---------------------------+
| Tables_in_cacti |
+---------------------------+
| cdef |
| cdef_items |
| colors |
| data_input |
| data_input_data |
| data_input_fields |
| data_local |
| data_template |
| data_template_data |
| data_template_data_rra |
| data_template_rrd |
| graph_local |
| graph_template_input |
| graph_template_input_defs |
| graph_templates |
| graph_templates_gprint |
| graph_templates_graph |
| graph_templates_item |
| graph_tree |
| graph_tree_items |
| host |
| host_graph |
| host_snmp_cache |
| host_snmp_query |
| host_template |
| host_template_graph |
| host_template_snmp_query |
| poller |
| poller_command |
| poller_item |
| poller_output |
| poller_reindex |
| poller_time |
| rra |
| rra_cf |
| settings |
| settings_graphs |
| settings_tree |
| snmp_query |
| snmp_query_graph |
| snmp_query_graph_rrd |
| snmp_query_graph_rrd_sv |
| snmp_query_graph_sv |
| user_auth |
| user_auth_perms |
| user_auth_realm |
| user_log |
| version |
+---------------------------+
48 rows in set (0.00 sec)

mysql>\q
root# useradd -c "User for CACTI" -d /home/cacti -p cactus -s /bin/kaznasho cacti
root# mysql cacti
mysql> grant all on cacti.* to cacti@localhost identified by 'cactus';
mysql> flush privileges;
mysql> \q

Теперь настраиваем cacti.

Редактируем /usr/share/cacti/include/config.php. Вот что получаем:

$database_type = "mysql";
$database_default = "cacti";
$database_hostname = "localhost";
$database_username = "cacti";
$database_password = "cactus";
$database_port = "3306";
?>


Подключаемся http://127.0.0.1/cacti и нас автоматом перебрасывает на http://127.0.0.1/cacti/install/. Нажимаем next. На следующем окошке выбираем тип инсталляции "New install". В следующем окне у меня везде стояло found кроме /var/log/cacti/cacti.log. Создаем его(touch /var/log/cacti/cacti.log) и обновляем окошко. Теперь у нас везде все зеленое. Нажимаем Finish. На следующем окошке вводим логин admin и парол admin. Сразу попросят поменять. Меняем. Задание в cron было автоматически добавлено непонятнокем, но приятно, что руками делать не надо...

Потом настраиваем как написано в статье http://system-administrators.info/?p=2619


Читать далее

2009-07-07

2009-07-02

Roundcube. WEB морда для почты

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

Вариантов я нашел несколько:

RoundCube
SquirrelMail
Horde
OpenWebMail
AlphaMail

Из всего указанного подошел только roundcube. Ну просто выглядит по человечески, остальное как-то прям стыдно в пользование директорату давать.

Естественно будет все крутится на любимом SLES неважнокакой версии. В моем случае SLES10.
У нас должен быть установлен postgresql неважнокакой версии, apache2 и такой набор модулей php:

apache2-mod_php5-5.2.5-9.5
php5-5.2.5-9.5
php5-curl-5.2.5-9.5
php5-dom-5.2.5-9.5
php5-gd-5.2.5-9.5
php5-gettext-5.2.5-9.5
php5-iconv-5.2.5-9.5
php5-imap-5.2.5-9.5
php5-ldap-5.2.5-9.5
php5-mbstring-5.2.5-9.5
php5-mcrypt-5.2.5-9.5
php5-mhash-5.2.5-9.5
php5-openssl-5.2.5-9.5
php5-pdo-5.2.5-9.5
php5-pgsql-5.2.5-9.5
php5-timezonedb-2008.2-0.3
php5-xmlreader-5.2.5-9.5
php5-xmlrpc-5.2.5-9.5
php5-zlib-5.2.5-9.5

С сайта roundcube.net тянем последнюю стабильную версию. На тот момент это roundcubemail-0.2.2.tar.gz. Архив распаковываем в /srv/www/htdocs и переименовываем в mail. то есть получаем директорию /srv/www/htdocs/mail. Меняем права на каталоги:

chown wwwrun /srv/www/htdocs/mail/logs -R
chown wwwrun /srv/www/htdocs/mail/temp -R

Создаем БД в postgres так как написано в инструкции, идущей в дистрибутиве.

Потом рихтуем конфиги

/srv/www/htdocs/mail/config/db.inc.php :

Здесь настраиваем связь с недавно созданной БД. То есть я поменял строку

$rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';

на строку

$rcmail_config['db_dsnw'] = 'pgsql://roundcube:пароль@ip-адрес/roundcubemail';

Потом настраиваем конфиг

/srv/www/htdocs/mail/config/main.inc.php :

Я приведу его листинг

*********************************************


$rcmail_config = array();


$rcmail_config['debug_level'] = 1;

$rcmail_config['log_driver'] = 'file';

$rcmail_config['syslog_id'] = 'roundcube';

$rcmail_config['syslog_facility'] = LOG_USER;

$rcmail_config['log_dir'] = 'logs/';

$rcmail_config['temp_dir'] = 'temp/';

$rcmail_config['enable_caching'] = TRUE;

$rcmail_config['message_cache_lifetime'] = '10d';

$rcmail_config['auto_create_user'] = TRUE;

$rcmail_config['default_host'] = 'адрес почтового сервера';

$rcmail_config['default_port'] = 143;

$rcmail_config['imap_auth_type'] = null;

$rcmail_config['imap_root'] = null;
$rcmail_config['imap_delimiter'] = null;

$rcmail_config['username_domain'] = 'имя домена';

$rcmail_config['mail_domain'] = 'имя домена';

$rcmail_config['virtuser_file'] = '';

$rcmail_config['virtuser_query'] = '';

$rcmail_config['smtp_server'] = 'адрес почтового сервера';

$rcmail_config['smtp_port'] = 25;

$rcmail_config['smtp_user'] = '';

$rcmail_config['smtp_pass'] = '';

$rcmail_config['smtp_auth_type'] = '';

$rcmail_config['smtp_helo_host'] = '';

$rcmail_config['smtp_log'] = TRUE;

$rcmail_config['sendmail_delay'] = 0;

$rcmail_config['list_cols'] = array('subject', 'from', 'date', 'size', 'flag', 'attachment');

$rcmail_config['skin_include_php'] = FALSE;

$rcmail_config['session_lifetime'] = 10;

$rcmail_config['ip_check'] = false;

$rcmail_config['double_auth'] = false;

$rcmail_config['des_key'] = 'rcmail-!24ByteDESkey*Str';

$rcmail_config['language'] = null;

$rcmail_config['date_short'] = 'D H:i';

$rcmail_config['date_long'] = 'd.m.Y H:i';

$rcmail_config['date_today'] = 'H:i';

$rcmail_config['useragent'] = 'RoundCube Webmail/0.2.2';

$rcmail_config['product_name'] = 'RoundCube Webmail';

$rcmail_config['drafts_mbox'] = 'Drafts';

$rcmail_config['junk_mbox'] = 'Junk';

$rcmail_config['sent_mbox'] = 'Sent';

$rcmail_config['trash_mbox'] = 'Trash';

$rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');

$rcmail_config['create_default_folders'] = FALSE;

$rcmail_config['protect_default_folders'] = TRUE;

$rcmail_config['quota_zero_as_unlimited'] = FALSE;

$rcmail_config['mdn_requests'] = 0;

$rcmail_config['default_charset'] = 'ISO-8859-1';

$rcmail_config['enable_spellcheck'] = TRUE;

$rcmail_config['spellcheck_engine'] = 'googie';

$rcmail_config['spellcheck_uri'] = '';

$rcmail_config['spellcheck_languages'] = NULL;

$rcmail_config['generic_message_footer'] = '';

$rcmail_config['http_received_header'] = false;

$rcmail_config['mail_header_delimiter'] = NULL;

$rcmail_config['session_domain'] = '';

$rcmail_config['address_book_type'] = 'ldap';

$rcmail_config['ldap_public'] = array();

$rcmail_config['ldap_public']['имя книги'] = array(
'name' => 'имя книги',
'hosts' => array('адрес сервера ldap с адресной книгой'),
'port' => 389,
'use_tls' => false,
'user_specific' => false,
'base_dn' => 'базовый DN',
'bind_dn' => '',
'bind_pass' => '',
'writable' => false,
'LDAP_Object_Classes' => array("top", "inetOrgPerson"),
'required_fields' => array("cn", "sn", "mail"),
'LDAP_rdn' => 'mail',
'ldap_version' => 3,
'search_fields' => array('mail', 'cn'),
'name_field' => 'cn',
'email_field' => 'mail',
'surname_field' => 'sn',
'firstname_field' => 'gn',
'sort' => 'cn',
'scope' => 'sub',
'filter' => '',
'fuzzy_search' => true);


$rcmail_config['autocomplete_addressbooks'] = array('sql');

$rcmail_config['dont_override'] = array();

$rcmail_config['identities_level'] = 0;

$rcmail_config['include_host_config'] = false;

$rcmail_config['max_pagesize'] = 200;

$rcmail_config['mime_magic'] = '/usr/share/misc/magic';

$rcmail_config['message_sort_col'] = 'date';

$rcmail_config['message_sort_order'] = 'DESC';

$rcmail_config['enable_installer'] = true;

$rcmail_config['log_logins'] = false;

$rcmail_config['delete_always'] = false;

$rcmail_config['min_keep_alive'] = 60;

$rcmail_config['skin'] = 'default';

$rcmail_config['pagesize'] = 40;

$rcmail_config['timezone'] = 'auto';

$rcmail_config['dst_active'] = (bool)date('I');

$rcmail_config['prefer_html'] = TRUE;

$rcmail_config['show_images'] = 0;

$rcmail_config['htmleditor'] = FALSE;

$rcmail_config['prettydate'] = TRUE;

$rcmail_config['draft_autosave'] = 300;

$rcmail_config['preview_pane'] = FALSE;

$rcmail_config['focus_on_new_message'] = true;

$rcmail_config['logout_purge'] = FALSE;

$rcmail_config['logout_expunge'] = FALSE;

$rcmail_config['inline_images'] = TRUE;

$rcmail_config['mime_param_folding'] = 0;

$rcmail_config['skip_deleted'] = FALSE;

$rcmail_config['read_when_deleted'] = TRUE;

$rcmail_config['flag_for_deletion'] = FALSE;

$rcmail_config['keep_alive'] = 60;

$rcmail_config['check_all_folders'] = FALSE;

?>

*********************************************

Вот... Чтобы убедиться, что все нормально, запускаем http://адрескуба/mail/installer и смотрим, что нет критичных ошибок. Потом папку /srv/www/htdocs/mail/installer переименовываем.


Читать далее

2009-06-30

Убить defunct процесс в linux

Как оказалось, команда kill для defunct процессов не работает. Как же все-таки такой процесс убить??? А вот как:

Для того, чтобы грохнуть такой процесс, нужно сначала убить родительский процесс. Родительские процессы ищем такой командой:

ps -xal | grep фильтр_процесса_который_нужно_убить

В выведенном листинге в колонке PPID будет родительский процесс. Убиваем его при помощи kill, а потом и процесс_который_нужно_убить. Вот так ;)
Читать далее

2009-06-22

Репликация PostgreSQL+Bucardo. Первые рабочие изменение структуры БД.

Вот первые рабочие изменение структуры БД.
То, что дали программисты:


-- ################################################################

-- ПРОВЕРИТЬ!!!!! должно уже быть
DROP INDEX "u_cntrgn0";
CREATE UNIQUE INDEX "u_cntrinvnmbr" ON countergen
USING btree ("invnumber");
////////////////////////////////////////////////////////


update countergen set ownershiptypecod = 1
where invnumber is not null;

-- нормы льготы для тарифов ЭлектроОбогрев
update tariff set extralimit = 25, maxlimit = 200,
usagelimit = 100, diflimit = 200 where code in (5,6,9);

-- 73 кат СIЛЬСЬКИЙ ПРАЦIВНИК КРИМIНАЛЬНО-ВИКОНАВЧОI СИСТЕМИ НА ПЕНСII
-- 50% без лимита
update benefitcategory set coeff = 50, islimitcode = 0 where code = 73;


CREATE TABLE "judicialdebt" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
"dategen" DATE,
"contractnumber" VARCHAR(50),
"contractdate" DATE,
"courtnumber" VARCHAR(50),
"courtdate" DATE,
"isincourt" DOUBLE PRECISION NOT NULL,
"operationdate" DATE,
"courtsum" NUMERIC(16,2),
"courtverdict" VARCHAR(100),
"profitsdate" DATE,
"typegen" DOUBLE PRECISION NOT NULL,
"recordpontrfcode" DOUBLE PRECISION NOT NULL,
"periodrefcode" DOUBLE PRECISION,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtcd" PRIMARY KEY("code"),
CONSTRAINT "fk_juddebtrpcd" FOREIGN KEY ("recordpontrfcode")
REFERENCES "recordpoint"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

ALTER TABLE judicialdebt
ADD CONSTRAINT "fk_jdbtprdcd" FOREIGN KEY ("periodrefcode")
REFERENCES "currentperiod"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;

CREATE INDEX "ind_jdbtprdcd" ON "judicialdebt"
USING btree ("periodrefcode");

CREATE TABLE "juddebtstatus" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
CONSTRAINT "pk_juddebtstts" PRIMARY KEY("code")
) WITHOUT OIDS;

INSERT INTO "juddebtstatus" ("code", "name")
VALUES (0, 'Отсутствует');

INSERT INTO "juddebtstatus" ("code", "name")
VALUES (1, 'Не погашено');

INSERT INTO "juddebtstatus" ("code", "name")
VALUES (2, 'Погашено');

CREATE TABLE "judicialdebtentry" (
"code" DOUBLE PRECISION NOT NULL,
"judicialdebtcode" DOUBLE PRECISION NOT NULL,
"dataenddate" DATE NOT NULL,
"datasumtopay" NUMERIC(16,2) NOT NULL,
"datapaiddate" DATE,
"datapaidsum" NUMERIC(16,2) NOT NULL,
"datastatuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtntrcd" PRIMARY KEY("code"),
CONSTRAINT "fk_judnttrdebtcd" FOREIGN KEY ("judicialdebtcode")
REFERENCES "judicialdebt"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "juddebtentrydebtcd" ON "judicialdebtentry"
USING btree ("judicialdebtcode");
CREATE INDEX "judicialdebtrpcode" ON "klres"."judicialdebt"
USING btree ("recordpontrfcode");

INSERT INTO "invstatus" ("code", "name")
VALUES (4, 'Исковый');

INSERT INTO "saldotype" ("code", "name")
VALUES (5, 'По исковой (электричество)');

INSERT INTO "saldotype" ("code", "name")
VALUES (6, 'По исковой (акты)');

CREATE TABLE "sordebttobill" (
"code" DOUBLE PRECISION NOT NULL,
"sumgen" NUMERIC(16,2),
"entrycode" DOUBLE PRECISION NOT NULL,
"billrefcode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_srdbttbll" PRIMARY KEY("code")
) WITHOUT OIDS;

CREATE TABLE "paymentjd" (
"code" DOUBLE PRECISION NOT NULL,
"paydate" DATE NOT NULL,
"value" NUMERIC(16,2) NOT NULL,
"pymntdcmntrfcode" DOUBLE PRECISION NOT NULL,
"statuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
"jdtype" DOUBLE PRECISION,
"entrycode" DOUBLE PRECISION,
CONSTRAINT "pk_pmntjd" PRIMARY KEY("code"),
CONSTRAINT "fk_pmntjdsttscd" FOREIGN KEY ("statuscode")
REFERENCES "paymentstatus"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "paymentjd_idx" ON "paymentjd"
USING btree ("pymntdcmntrfcode");

INSERT INTO "paymenttype" ("code", "name")
VALUES (16, 'По ИЗ');

INSERT INTO "paymenttype" ("code", "name")
VALUES (17, 'По ИЗ (акты)');

INSERT INTO "paymentdocmnttyp" ("code", "name")
VALUES (8, 'Корректировка иска судом');

-- #################################################################

Вот что делаем мы:

-- #################################################################

0. Останавливаем репликацию

-- #################################################################

1. Под res на на главной БД:

CREATE TABLE "judicialdebt" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
"dategen" DATE,
"contractnumber" VARCHAR(50),
"contractdate" DATE,
"courtnumber" VARCHAR(50),
"courtdate" DATE,
"isincourt" DOUBLE PRECISION NOT NULL,
"operationdate" DATE,
"courtsum" NUMERIC(16,2),
"courtverdict" VARCHAR(100),
"profitsdate" DATE,
"typegen" DOUBLE PRECISION NOT NULL,
"recordpontrfcode" DOUBLE PRECISION NOT NULL,
"periodrefcode" DOUBLE PRECISION,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtcd" PRIMARY KEY("code"),
CONSTRAINT "fk_juddebtrpcd" FOREIGN KEY ("recordpontrfcode")
REFERENCES "recordpoint"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

ALTER TABLE judicialdebt
ADD CONSTRAINT "fk_jdbtprdcd" FOREIGN KEY ("periodrefcode")
REFERENCES "currentperiod"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;

CREATE INDEX "ind_jdbtprdcd" ON "judicialdebt"
USING btree ("periodrefcode");

CREATE TABLE "juddebtstatus" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
CONSTRAINT "pk_juddebtstts" PRIMARY KEY("code")
) WITHOUT OIDS;

CREATE TABLE "judicialdebtentry" (
"code" DOUBLE PRECISION NOT NULL,
"judicialdebtcode" DOUBLE PRECISION NOT NULL,
"dataenddate" DATE NOT NULL,
"datasumtopay" NUMERIC(16,2) NOT NULL,
"datapaiddate" DATE,
"datapaidsum" NUMERIC(16,2) NOT NULL,
"datastatuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtntrcd" PRIMARY KEY("code"),
CONSTRAINT "fk_judnttrdebtcd" FOREIGN KEY ("judicialdebtcode")
REFERENCES "judicialdebt"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "juddebtentrydebtcd" ON "judicialdebtentry"
USING btree ("judicialdebtcode");
CREATE INDEX "judicialdebtrpcode" ON "judicialdebt"
USING btree ("recordpontrfcode");

CREATE TABLE "sordebttobill" (
"code" DOUBLE PRECISION NOT NULL,
"sumgen" NUMERIC(16,2),
"entrycode" DOUBLE PRECISION NOT NULL,
"billrefcode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_srdbttbll" PRIMARY KEY("code")
) WITHOUT OIDS;

CREATE TABLE "paymentjd" (
"code" DOUBLE PRECISION NOT NULL,
"paydate" DATE NOT NULL,
"value" NUMERIC(16,2) NOT NULL,
"pymntdcmntrfcode" DOUBLE PRECISION NOT NULL,
"statuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
"jdtype" DOUBLE PRECISION,
"entrycode" DOUBLE PRECISION,
CONSTRAINT "pk_pmntjd" PRIMARY KEY("code"),
CONSTRAINT "fk_pmntjdsttscd" FOREIGN KEY ("statuscode")
REFERENCES "paymentstatus"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "paymentjd_idx" ON "paymentjd"
USING btree ("pymntdcmntrfcode");

-- #################################################################

2. Под bucardo на главной БД:

INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','judicialdebt','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','juddebtstatus','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','judicialdebtentry','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','sordebttobill','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','paymentjd','code','bigint','false');

INSERT INTO herdmap (herd, goat)
SELECT 'herd_skres', id
FROM goat WHERE db = 'skres'
AND tablename IN ('judicialdebt','juddebtstatus',
'judicialdebtentry','sordebttobill','paymentjd');

UPDATE sync SET synctype = 'fullcopy' WHERE name = 'sync_skres';
UPDATE sync SET synctype = 'pushdelta' WHERE name = 'sync_skres';

-- #################################################################

3. На подчиненной БД в РЭС под res:

update judicialdebt set code = code;
update juddebtstatus set code = code;
update judicialdebtentry set code = code;
update sordebttobill set code = code;
update paymentjd set code = code;

-- #################################################################

4. Запускаем репликацию

-- #################################################################



Читать далее

2009-06-19

Монтирование windows share на linux

Используем openSUSE 11.1
Вот скриптец:

#!/bin/bash
sudo /bin/umount ~/Desktop/netshare
sudo /bin/umount ~/Desktop/netshare
sudo /bin/umount ~/Desktop/netshare
mkdir ~/Desktop/netshare
sudo /bin/mount -t cifs //111.111.111.111/netshare ~/Desktop/netshare -o user=abon111,password=abon111,rw
Читать далее

2009-06-16

Репликация PostgreSQL+Bucardo. Работа с РЭСами

Привычка все документировать :)
После всех экспериментов начинаю реализовывать промышленную схему репликации. Тут последовательность действий. Комментариев будет мало, в основном конкретные инструкции.
Поехали...

Скадовск. Первая БД.

alexsf@shaman:~> ssh alexsf@10.77.11.71
alexsf@bucardik:~> sudo -s
bucardik:/home/alexsf # /etc/init.d/bucardo_stop
postgres@bucardik:~> cd work
postgres@bucardik:~/work> mkdir old.1
postgres@bucardik:~/work> mv old old.1
postgres@bucardik:~/work> mv skres_schema.sql old.1
postgres@bucardik:~/work> pg_dump -h 10.77.25.2 -p 5432 -U postgres -F p -s -s -v -f "skres_schema.sql" -n 'res' "UTF8_sk"
postgres@bucardik:~/work> psql -h 10.77.11.71 -U postgres res
res=# drop schema res cascade;
res=# CREATE SCHEMA res AUTHORIZATION res;
res=# \q
postgres@bucardik:~/work> psql -f skres_schema.sql -h 10.77.11.71 -U postgres res
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \o drop_constr.sql
res=# \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'c'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# AND cl.relname not in ('billsqlreport','dual','rp_abon','log')
res-# ORDER BY con.conname;
res=# \o drop_rule.sql
res=# SELECT 'DROP RULE '||rulename||' ON '||tablename||';'
res-# FROM pg_rules
res-# WHERE schemaname = 'res'
res-# ORDER BY tablename, rulename;
res=# \i drop_constr.sql
res=# \i drop_rule.sql
res=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
bucardo-# VALUES ('skres','10.77.25.2','UTF8_sk','res','???');
bucardo=# INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
bucardo-# VALUES ('allres','10.77.11.71','res','res','???');
bucardo=# INSERT INTO bucardo.dbgroup(name) VALUES('slave');
bucardo=# INSERT INTO bucardo.dbgroup(name) VALUES('master');
bucardo=# INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('skres','slave');
bucardo=# INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('allres','master');
bucardo=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \o 2goat.sql
res=# \t
res=# SELECT 'INSERT INTO bucardo.goat
res'# (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
res'# VALUES (''skres'',''res'','''||cl.relname
res-# ||''','''||cc.column_name||''',''bigint'',''false'');'
res-# FROM pg_constraint con, pg_class cl, pg_tables t,
res-# information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'p'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# AND cl.relname not in ('billsqlreport','dual','rp_abon',
res(# 'log','auth_action','auth_domain',
res(# 'auth_dt_ac_type','auth_entity','auth_entity_segr',
res(# 'auth_group','auth_group_action','auth_role',
res(# 'auth_role_action','auth_segr','auth_segrtype',
res(# 'auth_user','auth_user_action','auth_user_group',
res(# 'auth_userstatus')
res-# ORDER BY cl.relname;
res=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# \i 2goat.sql
bucardo=# INSERT INTO bucardo.herd(name) VALUES('herd_skres');
bucardo=# INSERT INTO bucardo.herdmap (herd, goat)
bucardo-# SELECT 'herd_skres', id
bucardo-# FROM goat WHERE db = 'skres';
bucardo=# \q
postgres@bucardik:~/work> ssh root@10.77.25.2
linux01:~ # su - postgres -c "cd /files/ftp; pg_dump -C -F c -b -f pgsql.UTF8_sk "UTF8_sk""
linux01:~ # exit
postgres@bucardik:~/work> wget --no-proxy -c --ftp-user=sit --ftp-password=??? ftp://10.77.25.2/ftp/pgsql.UTF8_sk
postgres@bucardik:~/work> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.sync (name,source,targetdb,synctype,
bucardo(# stayalive,checktime,analyze_after_copy)
bucardo-# VALUES('sync_skres','herd_skres','allres','pushdelta','false','60 minutes','false');
bucardo=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \o drop_fk.sql
res=# \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'f'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY con.conname;
res=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \i drop_fk.sql
res=# \q
postgres@bucardik:~/work> /usr/bin/pg_restore -h 10.77.11.71 -p 5432 -U res -d res -a -v "pgsql.UTF8_sk"
postgres@bucardik:~/work> grep FOREIGN -B 1 skres_schema.sql > restore_fk.sql
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \i restore_fk.sql
res=# \q
postgres@bucardik:~/work> exit
bucardik:~ # /etc/init.d/bucardo_start

Все, проверил, Скадовск катается. Теперь Новотроицк.

bucardik:~ # /etc/init.d/bucardo_stop
bucardik:~ # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> mkdir skres
postgres@bucardik:~/work> mv 2* skres; mv d* skres
postgres@bucardik:~/work> mv p* skres; mv r* skres; mv skres_* skres
postgres@bucardik:~/work> mkdir ntres
postgres@bucardik:~/work> cd ntres
postgres@bucardik:~/work/ntres> psql -h 10.77.50.2 -U postgres ntres
ntres=# ALTER ROLE res SUPERUSER;
ntres=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.50.2 -U res ntres
ntres=# CREATE LANGUAGE plpgsql;
ntres=# CREATE LANGUAGE plperlu;
ntres=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
bucardo-# VALUES ('ntres','10.77.50.2','ntres','res','???');
bucardo=# INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('ntres','slave');
bucardo=# \q
postgres@bucardik:~/work/ntres> mkdir /u02/pgdata/prepload
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U postgres postgres
postgres=# CREATE TABLESPACE prepload OWNER res
postgres-# LOCATION '/u02/pgdata/prepload';
postgres=# CREATE DATABASE prepload WITH ENCODING='UTF8'
postgres-# OWNER=res TABLESPACE=prepload;
postgres=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# CREATE SCHEMA res AUTHORIZATION res;
prepload=# GRANT ALL ON SCHEMA res TO res;
prepload=# \q
postgres@bucardik:~/work/ntres> pg_dump -h 10.77.50.2 -p 5432 -U postgres -F p -s -s -v -f "ntres_schema.sql" -n 'res' "ntres"
postgres@bucardik:~/work/ntres> psql -f ntres_schema.sql -h 10.77.11.71 -U res prepload
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \o tmp_drop_fk.sql
prepload=# \t
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.contype = 'f'
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i tmp_drop_fk.sql
prepload=# \o tmp_drop_constr.sql
prepload=# \t
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i tmp_drop_constr.sql
prepload=# \o tmp_drop_tables.sql
prepload=# \t
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i tmp_drop_tables.sql
prepload=# \q
postgres@bucardik:~/work/ntres> grep PRIMARY -B 1 ntres_schema.sql > restore_pk.sql
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i restore_pk.sql
prepload=# \o 2goat.sql
prepload=# \t
prepload=# SELECT 'INSERT INTO bucardo.goat
prepload'# (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
prepload'# VALUES (''ntres'',''res'','''||cl.relname
prepload-# ||''','''||cc.column_name||''',''bigint'',''false'');'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.contype = 'p'
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY cl.relname;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# \i 2goat.sql
bucardo=# INSERT INTO bucardo.herd(name) VALUES('herd_ntres');
bucardo=# INSERT INTO bucardo.herdmap (herd, goat)
bucardo-# SELECT 'herd_ntres', id
bucardo-# FROM goat WHERE db = 'ntres';
bucardo=# \q
postgres@bucardik:~/work/ntres> ssh root@10.77.50.2
linux01:~ # su - postgres -c "pg_dump -C -F c -b -f pgsql.ntres "ntres""
linux01:/u02/scheduler # exit
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.sync (name,source,targetdb,synctype,
bucardo(# stayalive,checktime,analyze_after_copy)
bucardo-# VALUES('sync_ntres','herd_ntres','allres','pushdelta','false','60 minutes','false');
bucardo=# \q
postgres@bucardik:~/work/ntres> ssh root@10.77.50.2
linux01:~ # cp /var/lib/pgsql/pgsql.ntres /u02/scheduler
linux01:~ # exit
postgres@bucardik:~/work/ntres> ssh root@10.77.50.3
linux02:~ # mkdir /mnt/linux01
linux02:~ # mount 10.77.50.2:/u02/scheduler /mnt/linux01
linux02:~ # cp /mnt/linux01/pgsql.ntres /files/
linux02:~ # exit
postgres@bucardik:~/work/ntres> wget --no-proxy -c --ftp-user=sit --ftp-password=??? ftp://10.77.50.3/pgsql.ntres
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# drop schema res cascade;
prepload=# create schema res authorization res;
prepload=# \q
postgres@bucardik:~/work/ntres> /usr/bin/pg_restore -h 10.77.11.71 -p 5432 -U res -d prepload -v "pgsql.ntres"
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \o drop_tables_2load.sql
prepload=# \t
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \o tmp.log
prepload=# \i drop_tables_2load.sql \q
postgres@bucardik:~/work/ntres> pg_dump -F c -b -a -f pgsql.ntres2load -U res "prepload"
postgres@bucardik:~/work/ntres> pg_dump -F c -b -C -f pgsql.res.backup -U postgres "res"
postgres@bucardik:~/work/ntres> pg_dump -h 10.77.11.71 -p 5432 -U res -F p -s -s -v -f "res_schema.sql" -n 'res' "res"
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res res
res=# \o drop_fk_2load_tmp.sql
res=# \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'f'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY con.conname;
res=# \o tmp.log
res=# \i drop_fk_2load_tmp.sql \q
postgres@bucardik:~/work/ntres> /usr/bin/pg_restore -h 10.77.11.71 -p 5432 -U res -d res -a -v "pgsql.ntres2load"

########################################################################
-- удаление новотроицка из общей БД
select 'delete from '||table_name||' where domain_info = ''root.nt'';'
from information_schema.tables
where table_schema = 'res'
and table_type = 'BASE TABLE'
order by table_name;
########################################################################

prepload=# \o drop_tables_2load.sql
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \o tmp.log
prepload=# \i drop_tables_2load.sql


prepload=# \o drop_fk_2load.sql
prepload=# \t
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.contype = 'f'
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \o tmp.log
prepload=# \i drop_fk_2load.sql
prepload=# \o drop_constr_2load.sql
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \o tmp.log
prepload=# \i drop_constr_2load.sql
prepload=# \o drop_rule_2load.sql
prepload=# SELECT 'DROP RULE '||rulename||' ON '||tablename||';'
prepload-# FROM pg_rules
prepload-# WHERE schemaname = 'res'
prepload-# ORDER BY tablename, rulename;
prepload=# \o tmp.log
prepload=# \i drop_rule_2load.sql
prepload=# \o drop_tables_2load.sql
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \o tmp.log
prepload=# \i drop_tables_2load.sql
prepload=# \o drop_views_2load.sql
prepload=# select 'drop view '||table_name||';'
prepload-# from information_schema.views
prepload-# where table_catalog = 'prepload'
prepload-# and table_schema = 'res';
prepload=# \o tmp.log
prepload=# \i drop_views_2load.sql
prepload=# \o drop_index_2load.sql
prepload=# select 'alter table '||tablename||' drop index '||indexname||';'
prepload-# from pg_indexes
prepload-# where schemaname = 'res'
prepload-# order by tablename;
prepload=# \o tmp.log



Читать далее

2009-06-15

Репликация PostgreSQL+Bucardo. Правила при изменении структуры БД

Итак, наконец мы можем сформировать набор правил, как работать с bucardo при изменении структуры подчиненных БД.

При изменении структуры существующих таблиц, если изменения структуры не затронули первичные ключи:
1. Остановить репликацию.
2. Обновить ВСЕ подчиненные БД.
3. Теми же скриптами обновить главную БД. В скриптах ни в коем случае не должны меняться данные - только структура.
4. Запустить репликацию.
5. Проверить, что все работает.

При изменении структуры существующих таблиц, если затронуты первичные ключи:
1. Остановить репликацию.
2. Выполнить скрипты по изменению структуры подчиненных БД. Данные пока не менять.
3. Те же скрипты по изменению структуры выполнить на главной БД.
4. Изменить таблицу bucardo.goat в соответствии с изменениями поля первичного ключа подчиненной БД.
5. На подчиненных БД на таблицах, где поменялось поле первичного ключа удалить триггера bucardo_add_delta_d, bucardo_add_delta_i, bucardo_add_delta_u, bucardo_triggerkick_..._sync.
6. На главной БД выполнить обновление таблицы sync следующим образом:
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'правильная_ссылка';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'правильная_ссылка';
7. Проверить, что в подчиненных БД на таблицах с измененным полем ПК созданы новые триггера.
8. В подчиненных БД выполнить изменение данных, если это предусмотрено обновлением.
9. Запустить репликацию.
10. Проверить, что все работает.

При добавлении новых таблиц в репликацию.
1. Создать таблицы в подчиненной БД.
2. Создать таблицы в главной БД.
3. Добавить данные по таблицам в БД bucardo в goat и herdmap.
4. Остановить репликацию.
5. На главной БД выполнить обновление таблицы sync следующим образом:
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'правильная_ссылка';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'правильная_ссылка';
6. Проверить, что на новых таблицах создались триггера.
7. Запустить репликацию.
8. Проверить, что все работает.

При удалении таблиц из репликации:
1. Остановить репликацию.
2. Удалить таблицы из goat и herdmap.
3. На главной БД выполнить обновление таблицы sync следующим образом:
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'правильная_ссылка';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'правильная_ссылка';
4. На подчиненных БД на таблицах, которые больше не нужно реплицировать удалить триггера bucardo_add_delta_d, bucardo_add_delta_i, bucardo_add_delta_u, bucardo_triggerkick_..._sync.
5. Запустить репликацию.
6. Проверить, что все работает.

Читать далее

2009-06-09

Репликация PostgreSQL+Bucardo. Изменение структуры БД. Тестирование.

Итак. В рабочем варианте №1 докатились до того, что репликация поехала, но потом заткнулась на изменении структуры БД. Тема интересная и актуальная. Нужна методика поддержки репликации в рабочем состоянии в условиях постоянного изменения структуры БД. Приступим.

На своей локальной машине сделал БД alexsf_test и схему alexsf. Плюс ко всему:

ALTER ROLE alexsf SUPERUSER;
CREATE LANGUAGE plpgsql;
CREATE LANGUAGE plperlu;

и получаю: ERROR: не получилось загрузить библиотеку "/usr/lib/postgresql/plperl.so": libperl.so: невозможно открыть разделяемый объектный файл: Нет такого файла или каталога
SQL state: 58P01

Бл... Как всегда без приключений никуда... Такая библиотека есть, вот она:

/usr/lib/perl5/5.10.0/i586-linux-thread-multi/CORE/libperl.so

Че за херня!!! Как всегда отделываемся костылем:

ln -s /usr/lib/perl5/5.10.0/i586-linux-thread-multi/CORE/libperl.so /usr/lib/libperl.so

Теперь наполняем схему объектами и данными:

CREATE TABLE fio(
pk integer NOT NULL,
f character varying(100),
i character varying(100),
o character varying(100),
CONSTRAINT pk_fio PRIMARY KEY (pk)
)
WITH (OIDS=FALSE);
ALTER TABLE fio OWNER TO alexsf;

CREATE TABLE car(
pk integer NOT NULL,
model character varying(100),
nomer character varying(100),
CONSTRAINT pk_car PRIMARY KEY (pk)
)
WITH (OIDS=FALSE);
ALTER TABLE car OWNER TO alexsf;

CREATE TABLE telefon(
pk integer NOT NULL,
model character varying(100),
"operator" character varying(100),
nomer character varying(100),
CONSTRAINT pk_telefon PRIMARY KEY (pk)
)
WITH (OIDS=FALSE);
ALTER TABLE telefon OWNER TO alexsf;

insert into alexsf.fio VALUES('0','Пупкин0','Серафим0','Опанасович0');
insert into alexsf.fio VALUES('1','Пупкин1','Серафим1','Опанасович1');
insert into alexsf.fio VALUES('2','Пупкин2','Серафим2','Опанасович2');
insert into alexsf.fio VALUES('3','Пупкин3','Серафим3','Опанасович3');
insert into alexsf.fio VALUES('4','Пупкин4','Серафим4','Опанасович4');
insert into alexsf.fio VALUES('5','Пупкин5','Серафим5','Опанасович5');
insert into alexsf.fio VALUES('6','Пупкин6','Серафим6','Опанасович6');
insert into alexsf.fio VALUES('7','Пупкин7','Серафим7','Опанасович7');
insert into alexsf.fio VALUES('8','Пупкин8','Серафим8','Опанасович8');
insert into alexsf.fio VALUES('9','Пупкин9','Серафим9','Опанасович9');

insert into alexsf.car VALUES('0','Жигули0','0');
insert into alexsf.car VALUES('1','Жигули1','1');
insert into alexsf.car VALUES('2','Жигули2','2');
insert into alexsf.car VALUES('3','Жигули3','3');
insert into alexsf.car VALUES('4','Жигули4','4');
insert into alexsf.car VALUES('5','Жигули5','5');
insert into alexsf.car VALUES('6','Жигули6','6');
insert into alexsf.car VALUES('7','Жигули7','7');
insert into alexsf.car VALUES('8','Жигули8','8');
insert into alexsf.car VALUES('9','Жигули9','9');

insert into alexsf.telefon VALUES('0','Nokia0','MTS0','000');
insert into alexsf.telefon VALUES('1','Nokia1','MTS1','001');
insert into alexsf.telefon VALUES('2','Nokia2','MTS2','002');
insert into alexsf.telefon VALUES('3','Nokia3','MTS3','003');
insert into alexsf.telefon VALUES('4','Nokia4','MTS4','004');
insert into alexsf.telefon VALUES('5','Nokia5','MTS5','005');
insert into alexsf.telefon VALUES('6','Nokia6','MTS6','006');
insert into alexsf.telefon VALUES('7','Nokia7','MTS7','007');
insert into alexsf.telefon VALUES('8','Nokia8','MTS8','008');
insert into alexsf.telefon VALUES('9','Nokia9','MTS9','009');

После этого на многострадальном сервере bucardo делаю БД alexsf и схему alexsf, и создаю там аналогичные объекты. Не забываем дать alexsf права SUPERUSER. Затем настраиваем репликацию:

INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
VALUES ('alexsf_slave_db','10.77.11.200','alexsf','alexsf','alexsf');
INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
VALUES ('alexsf_master_db','10.77.11.71','alexsf_test','alexsf','alexsf');

INSERT INTO bucardo.dbgroup(name) VALUES('alexsf_slave_group');
INSERT INTO bucardo.dbgroup(name) VALUES('alexsf_master_group');

INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('alexsf_slave_db','alexsf_slave_group');
INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('alexsf_master_db','alexsf_master_group');

INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','car','pk','bigint','false');
INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','fio','pk','bigint','false');
INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','telefon','pk','bigint','false');

INSERT INTO bucardo.herd(name) VALUES('alexsf_herd');

INSERT INTO bucardo.herdmap (herd, goat)
SELECT 'alexsf_herd', id
FROM goat WHERE db = 'alexsf_slave_db';

INSERT INTO bucardo.sync (name,source,targetdb,synctype,stayalive,checktime,analyze_after_copy)
VALUES('alexsf_sync','alexsf_herd','alexsf_master_db','pushdelta','false','1 minutes','false');

Вроде все. Перед тем, как запустить репликацию, ставлю inactive на не тестовых БД в таблице bucardo.db. Ну и запускаю... Делаю пинки по таблицам в slave БД, и вижу, что репликация работает.

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

Меняем структуру нашей подчиненной БД:

alter table car add column probeg numeric;
alter table telefon drop column "operator";
alter table telefon rename column nomer to n;

Перезапускаем bucardo и получаем:

May 28 09:39:46 bucardik Bucardo[16849]: MCP Validating source table "alexsf.car" on alexsf_slave_db
May 28 09:39:47 bucardik Bucardo[16849]: MCP Comparing tables and columns on alexsf_master_db
May 28 09:39:47 bucardik Bucardo[16849]: MCP FATAL: Source database "alexsf_sync", table alexsf.car has more columns than target "alexsf_master_db"
May 28 09:39:47 bucardik Bucardo[16849]: MCP Validation of sync FAILED

Обращаем внимание на то, что несмотря на изменение двух таблиц, bucardo ругается только на одну. То есть он не делает валидацию ВСЕХ таблиц, а обрывает этот процесс на первой, не прошедшей валидацию!!! Воблинзараза!!!

Итак, повторяем изменение структуры на master базе, и перезапускаем bucardo.

И ХРЕНЕЕМ!!! Bucardo не выдает никаких ошибок!!! Просто говорит, что реплицировать нечего!!! Возникает вопрос, то ли лыжи не едут, толи реально так и надо??? Делаем пинки по таблицам и наблюдаем за реакцией... Нормальная реакция, все работает... То есть так и надо, с репликацией ничего не случилось...

Будем считать то, что мы сделали первым вариантом. А именно:
-- изменили структуру подчиненной БД.
-- изменили структуру главной БД.
-- в промежутке между первыми двумя пунктами данные в подчиненной БД не менялись.
-- количество объектов участников репликации не изменилось.

Вывод по первому варианту: да просто офигенный вариант!!! малой кровью решаем проблемы с изменением структуры БД и не нарушаем при этом работу репликации!!! Имеет 100% право на жизнь, будем использовать.

Теперь опишем второй вариант:
-- меняем структуру подчиненной БД.
-- пинаем в подчиненной БД данные со всех сторон, особенно в местах, где произошли изменения структуры.
-- меняем структуру главной БД
-- количество объектов участников репликации не меняем.

Поехали делать второй вариант:

alter table fio add column vozr numeric;
alter table fio drop column o;
update fio set vozr=100;

Bucardo начинает орать всягую лабудень. Перезапустим его на всякий случай. И видим: таблица fio не прошла валидацию... Меняем структуру в главной БД, но НЕ ТРОГАЕМ там данные!!! Перезапускаем bucardo. И зашибись, репликация поехала. все пинки среплицировались!!!

Вывод по 2-му варианту: ну нормально!!! 100% рабочий. Крови больше не стало по сравнению с 1-м. Бум использовать.

Описываем 3-й вариант:
-- меняется поле первичного ключа в подчиненной БД.
-- тусуются данные в поле первичного ключа.
-- аналогично меняется поле первичного ключа в главной БД.
-- количество объектов репликации не меняем.

Поехали:

alter table telefon rename column pk to pkey;
update telefon set pkey=pkey+1000;

И вот о чудо, ничего не получилось. При выполнении update получили ошибку:

ERROR: record "old" has no field "pk"
SQL state: 42703
Контекст:PL/pgSQL function "bucardo_add_delta_u_pk" line 3 at SQL statement

,что вполне закономерно, ведь созданные объекты bucardo в подчиненной базе вроде как подвязаны на имена первичных ключей.

Анализируем...

-- Все объекты bucardo в подчиненной БД были созданы автоматически при внесении данных в таблицу bucardo.sync главной БД. То есть процесс выполнялся удаленно с главной БД.
-- Логично предположить, что в главной БД все эти объекты, а также таблицы и ключи на которые они ссылаются, зарегистрированы в конфигурационных таблицах bucardo.
-- Логично предположить, что изменение объектов в подчиненной БД также должно проводится с главной БД для обеспечения согласованности объектов подчиненной БД и конфигурационной информации в главной БД bucardo.
-- Объекты включались в репликацию фактически тремя действиями: вставка в таблицу goat, вставка в таблицу herdmap, вставка в таблицу sync.
-- Вставка в таблицы goat и herdmap была пообектной и создала, насколько я понял, набор конфигурационной информации объектов репликации. Вставка в таблицу sync ссылалась на весь набор объектов участников, была проведена одной строкой и привела к созданию набора объектов в подчиненной БД, с которыми у нас теперь проблемы.
-- На таблице sync есть триггер validate_sync AFTER INSERT OR UPDATE, который, как я предполагаю, и выполняет работы по удаленному созданию объектов в подчиненной БД. Логично предположить, что в случае изменения конфигурационной информации в goat и herdmap достаточно будет сделать UPDATE на sync для проведения удаленной корректировки объектов в подчиненной БД.

Вроде проанализировали и придумали, что делать дальше. А делать следующее:

Вариант 1:
-- Остановить репликацию
-- Из goat и herdmap выкосить telefon
-- Провести копию изменений структуры подчиненной БД в главной БД
-- В goat и herdmap занести telefon
-- Сделать UPDATE sync
-- Попробовать сделать неотработавший UPDATE в подчиненной БД
-- Запустить репликацию.

Вариант2:
-- Остановить репликацию
-- Порихтовать таблицы goat и herdmap с учетом изменения PK в telefon.
-- Провести копию изменений структуры подчиненной БД в главной БД
-- Сделать UPDATE sync
-- Проверить, изменились ли объекты bucardo в подчиненной БД на таблице telefon.
-- Запустить репликацию.

Пробуем вариант 1. Останавливаем bucardo и:

DELETE FROM bucardo.goat
WHERE db='alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'telefon';

DELETE FROM bucardo.herdmap
WHERE goat = (SELECT id FROM bucardo.goat WHERE db='alexsf_slave_db'
AND schemaname = 'alexsf' AND tablename = 'telefon');

alter table telefon rename column pk to pkey;

INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','telefon','pkey','bigint','false');

INSERT INTO bucardo.herdmap (herd, goat)
SELECT 'alexsf_herd', id
FROM goat
WHERE db = 'alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'telefon';

UPDATE bucardo.sync SET status = 'inactive' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET status = 'active' WHERE name = 'alexsf_sync';

В подчиненной БД выполняем:

update telefon set pkey=pkey+1000;

... и получаем ту же ошибку... БЛ....!!!

Попробуем грохнуть триггера на telefon и опять обновить sync:

-- В подчиненной БД
drop trigger bucardo_add_delta_d on alexsf.telefon;
drop trigger bucardo_add_delta_i on alexsf.telefon;
drop trigger bucardo_add_delta_u on alexsf.telefon;
drop trigger bucardo_triggerkick_alexsf_sync on alexsf.telefon;

-- В главной БД
UPDATE bucardo.sync SET status = 'inactive' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET status = 'active' WHERE name = 'alexsf_sync';

Смотрим, и видим, что на таблице telefon в удаленной БД триггера не создались :( Я буду плакать... Ну почему bucardo не реплицирует DDL????

Перечитал сейчас всю доку, благо ее там не так много(или хреново, что немного), и ничего по работе с отдельными goat не нашел...

Попробую сделать еще одну таблицу и включить ее в репликацию...

-- В подчиненной БД:

CREATE TABLE komp(
pklu4 integer NOT NULL,
cpu character varying(100),
hdd character varying(100),
ozu character varying(100),
CONSTRAINT pk_komp PRIMARY KEY (pklu4)
)
WITH (OIDS=FALSE);
ALTER TABLE telefon OWNER TO alexsf;

-- В БД bucardo в главной БД:

INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','komp','pklu4','bigint','false');

INSERT INTO bucardo.herdmap (herd, goat)
SELECT 'alexsf_herd', id
FROM goat
WHERE db = 'alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'komp';

UPDATE bucardo.sync SET status = 'active' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'alexsf_sync';

И вот на synctype = 'fullcopy' я получил ошибку:

NOTICE: Issuing rollback() for database handle being DESTROY'd without explicit disconnect() at line 29.
КОНТЕКСТ: SQL-команда: "SELECT validate_sync('alexsf_sync')"
ERROR: error from Perl trigger function: error from Perl function: No such table found for database alexsf_master_db: "alexsf.komp" at line 259. at line 30.

О-о-о-о!!!!!!!!!!!!! Эврика!!!!!!!!!! Нашел!!!!!!!!!!
Триггер на таблице sync на UPDATE реагирует не при каждом UPDATE, а только каких-то конкретных полей!!!! Например очень хорошо реагирует на поле synctype. По крайней мере на таблице telefon создались триггера. Новую таблицу komp я пока выкосил...

Так, нужно теперь мысли в кучу собрать и расписать принципы работы 3-го варианта(переименования поля с PK)... Попробуем для порядка опять поменять имя ключа и проверить:

-- На подчиненной БД и на главной БД:
alter table telefon rename column pkey to pklu4;

-- На главной БД:

update bucardo.goat set pkey = 'pklu4'
where db = 'alexsf_slave_db'
and schemaname = 'alexsf'
and tablename = 'telefon';

UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'alexsf_sync';

И видим, что триггера на талбице telefon в подчиненной БД не поменялись, но при этом были созданы bucardo.bucardo_add_delta_d_pklu4, bucardo.bucardo_add_delta_i_pklu4 bucardo.bucardo_add_delta_u_pklu4 в подчиненной БД... То есть не до конца отработало, частично, так сказать, по кривому, если точнее :( Я зол.

Попробуем удалить триггера с таблицы telefon и заново пихнуть sync:

-- На пордчиненной БД alexsf:
drop trigger bucardo_add_delta_d on alexsf.telefon;
drop trigger bucardo_add_delta_i on alexsf.telefon;
drop trigger bucardo_add_delta_u on alexsf.telefon;
drop trigger bucardo_triggerkick_alexsf_sync on alexsf.telefon;

О, вот так получилось!!!

Теперь проверим, что не потеряются данные репликации при пинках по таблице sync:

Для этого мы:
- выключим репликацию
- напихаем новых данных в таблицу
- поменяем поле первичного ключа
- проведем изменения в структуре bucardo. Сделаем согласованной схему(sync)...
- опять понапихаем данных
- запустим репликацию
- проверим, что оба запихивания среплицировались

Поехали(напомню, что на данный момент у нас рабочая схема репликации):

#на хосте bucardo
/etc/init.d/bucardo_stop

-- на подчиненной БД под alexsf
insert into alexsf.telefon VALUES('20006','Nokia6','MTS6');
insert into alexsf.telefon VALUES('20007','Nokia7','MTS7');
insert into alexsf.telefon VALUES('20008','Nokia8','MTS8');
insert into alexsf.telefon VALUES('20009','Nokia9','MTS9');
alter table telefon rename column pklu4 to primokey;
drop trigger bucardo_add_delta_d on alexsf.telefon;
drop trigger bucardo_add_delta_i on alexsf.telefon;
drop trigger bucardo_add_delta_u on alexsf.telefon;

drop trigger bucardo_triggerkick_alexsf_sync on alexsf.telefon;

-- на главной БД alexsf
alter table telefon rename column pklu4 to primokey;

-- на главной БД bucardo
UPDATE bucardo.goat SET pkey = 'primokey'
WHERE db = 'alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'telefon';
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'alexsf_sync';

Ну и радость, все работает, ничего не потерялось... Вроде все варианты рассмотрели... Теперь подитожить, и сформировать набор правил...

Читать далее

2009-05-26

Настройка SQUID с авторизацией в домене Windows

От Филиппова А.С., скромного админа, на радость всем остальным скромным админам ;)

Настройка SQUID с авторизацией в домене Windows

Автор: Филиппов Алексей
Дата создания: 20 февраля 2007

Итак, необходимо настроить SQUID таким образом, чтобы он авторизовал пользователей через домен Windows.

Имеется домен mydomain.com.ua, работающий на Windows 2000 Server. В нем есть 2 сервера, alpha.mydomain.com.ua и centavr.mydomain.com.ua с адресами 192.168.1.3 и 192.168.1.2 соответственно.
SQUID будет крутится на операционной системе SLES9. На этом сервере должны быть установлены следующие пакеты:
samba-3.0.20b-3.4
samba-client-3.0.20b-3.4
samba-winbind-3.0.20b-3.4
heimdal-0.6.1rc3-55.18
sarg-2.1-10
squid-2.5.STABLE5-42.44
apache2-2.0.49-27.38

Итак, поехали.
Редактируем файл /etc/resolv.conf. Там должно быть прописано следующее:

nameserver 192.168.1.2
nameserver 192.168.1.3
search mydomain.com.ua

В итоге если мы запустим ping alpha, то обязательно должен быть ответ.
Настраиваем клиента Kerberos. Для этого редактируем файл /etc/krb5.conf. Содержание его должно быть следующим:

[libdefaults]
default_realm = mydomain.com.ua
clockskew = 300
v4_instance_resolve = false
v4_name_convert = {
host = {
rcmd = host
ftp = ftp
}
plain = {
something = something-else
}
}

[realms]
mydomain.com.ua = {
kdc = alpha.mydomain.com.ua
admin_server = alpha.mydomain.com.ua
}

[domain_realm]
.mydomain.com.ua = mydomain.com.ua

Проверяем соединение с сервером Kerberos:

root> kinit -p philippoff
philippoff@mydomain.com.ua's Password: <тут вводим пароль пользователя philippoff>
kinit: NOTICE: ticket renewable lifetime is 1 week

Если ответ отличается от приведенного выше и говорит об ошибке – значит что-то не так настроили, или еще чего-нибудь...
Проверим состояние соединения:

root> klist
Credentials cache: FILE:/tmp/krb5cc_0
Principal: philippoff@mydomain.com.ua

Issued Expires Principal
Feb 20 11:37:08 Feb 20 21:37:02 krbtgt/mydomain.com.ua@mydomain.com.ua

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

Настраиваем Samba. Для этого редактируем файл /etc/samba/smb.conf. Кроме всего, что в нем может находится, обязательно должно присутствовать следующее (или если ничего от самбы кроме авторизации сквида не надо, то достаточно быдет только этого):

[global]
workgroup = CO
server string = legion
netbios name = legion
security = ads
realm = mydomain.com.ua
password server = alpha.mydomain.com.ua
encrypt passwords = yes
winbind separator = +
winbind use default domain = yes
winbind uid = 10000-15000
winbind gid = 10000-15000
winbind enum users = yes
winbind enum groups = yes

После настройки самбы попробуем войти в домен:

root> net ads join -U admin_name%admin_password
Joined 'LEGION' to realm 'mydomain.com.ua'

Если ответ получен с ошибкой, что делать в таких случаях смотреть выше :)
После этого необходимо, чтобы запускался необходимый набор служб. Это smb, nmb, winbind. Самый простой вариант – это завалиться в YaST под root, зайти в «Runlevel Editor» и поставить сервисы nmd, smb, winbind в состояние «Включен», то есть на автостарт. Или можно руками:

root> ln -s /etc/init.d/nmb /etc/init.d/rc3.d/K15nmb
root> ln -s /etc/init.d/nmb /etc/init.d/rc3.d/S07nmb
root> ln -s /etc/init.d/smb /etc/init.d/rc3.d/K10smb
root> ln -s /etc/init.d/smb /etc/init.d/rc3.d/K12smb
root> ln -s /etc/init.d/winbind /etc/init.d/rc3.d/K14winbind
root> ln -s /etc/init.d/winbind /etc/init.d/rc3.d/S08winbind
root> ln -s /etc/init.d/nmb /etc/init.d/rc5.d/K15nmb
root> ln -s /etc/init.d/nmb /etc/init.d/rc5.d/S07nmb
root> ln -s /etc/init.d/smb /etc/init.d/rc5.d/K10smb
root> ln -s /etc/init.d/smb /etc/init.d/rc5.d/K12smb
root> ln -s /etc/init.d/winbind /etc/init.d/rc5.d/K14winbind
root> ln -s /etc/init.d/winbind /etc/init.d/rc5.d/S08winbind

Если вы включали сервисы через YaST, то они в процессе применения изменений запустятся, если нет, то есть делали руками, то и запускать из придется руками:

root> /etc/init.d/nmb start
root> /etc/init.d/smb start
root> /etc/init.d/winbind start

Проверяем работоспособность winbind:

root> wbinfo -t
checking the trust secret via RPC calls succeeded

Если появился такой ответ, значит учетная запись компьютера успешно зарегистрирована в домене Windows. Проверяем дальше:

root> wbinfo -u

Должен появится список пользователей и компьютеров домена. У меня он весьма немаленький, так что даже для примера приводить не буду, краска в принтере кончится :). Но что самое замечательное, в этом списке есть запись «legion$», что подтверждает то, что учетка нашего компьютера в домене зарегистрирована правильно. Если этой записи нет – смотрим внимательнее, она должна быть :), только у вас может называться по другому. Кстати сказать, у меня первый раз эта проверка не отработала, а свкид при этом уже всех во всю авторизовал. А потом вдруг заработала сама по себе.
Дальше проверяем:

root> wbinfo -g

В результате должны получить список групп домена.
Проверяем аутентификацию в домене:

root> wbinfo -a user_name%user_password
plaintext password authentication succeeded
challenge/response password authentication succeeded

Полученный ответ говорит о том, что все идет по плану :) Аутентификация прошла успешно.
Теперь настраиваем файл конфигурации Name Service Switch. Для этого в конец файла /etc/nsswitch.conf добавляем две строки (смотри внимательно, может они там уже есть):

passwd: files winbind
group: files winbind

Если вдруг окажется, что в данном файле уже присутствуют строки, которые начинаются на passwd или group и они отличны от тех, что мы добавляем, то просто комментируем их, если одинаковы, то можно наши строки не добавлять.
После этого:

root> /etc/init.d/nscd restart

После этого проверяем распознавание доменных пользователей линуксом (я проверяю на своей учетке):

root> id Philippoff
uid=10000(philippoff) gid=10001(Пользователи домена) группы=10001(Пользователи домена),10012(Programmers),10063(LowInternetAccess),10065(High Internet Access),10070(SitAccess),10074(RemoteAdmins),10109(Admin Internet Access)

Как видите, такой ответ подразумевает, что наш дорогой линукс знает о пользователе Philippoff если не все, то очень многое. И это хорошо, это то, что нам и нужно :) Опять же эта замечательная проверка с первого раза у меня не отработала. Только после перезапуска служб, а то и перезагрузке сервера. А может и после чего-то еще, только чего – не помню.

Ну вот, пришло время заняться собственно головоногими. SQUID у нас уже установлен. Настраиваем его. Нас интересует файл /etc/squid/squid.conf. Файл этот может быть весьма пухлым, сложным и неприятным на вид. По крайней мере у меня так и есть. В файле должны присутствовать следующие секции:

# Секция для аутентификации пользователей по NTLM
auth_param ntlm program /usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp
auth_param ntlm children 10
auth_param ntlm max_challenge_reuses 0

# Секция для базовой аутентификации пользователей
auth_param basic program /usr/bin/ntlm_auth --helper-protocol=squid-2.5-basic
auth_param basic children 10
auth_param basic realm Squid proxy-caching web server
auth_param basic credentialsttl 2 hours

acl adusers proxy_auth REQUIRED LowInternetAccess
http_access allow adusers

ВНИМАНИЕ!!! В acl нельзя использовать доменные группы, только логины. По другому, хоть убейся, работать не будет! Хотя, может у вас получиться :)
Тут показан самый простой вариант. acl-ов с виндозными логинами можете наклепать хоть миллион – ваше право, squid выдержит (хотя с миллионом я не пробовал...).
На данный момент конфиг SQUID на legion выглядит так:

##############
### GLOBAL ###
##############

cache_peer 192.168.11.70 parent 3128 3130 no-query no-digest
hierarchy_stoplist cgi-bin ?
acl QUERY urlpath_regex cgi-bin \?
no_cache deny QUERY
cache_dir ufs /var/cache/squid 5000 16 256
forwarded_for 10.77.11.70
cache_mgr legion@proxy.mydomain.com.ua
quick_abort_min 0 KB
quick_abort_max 0 KB
http_port 8080

######################
##### AUTH_PARAM #####
######################

auth_param ntlm program /usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp
auth_param ntlm children 10
auth_param ntlm max_challenge_reuses 0

auth_param basic program /usr/bin/ntlm_auth --helper-protocol=squid-2.5-basic
auth_param basic children 10
auth_param basic realm Squid proxy-caching web server
auth_param basic credentialsttl 2 hours

#################
###### ACL ######
#################

acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_objects
acl localhost src 127.0.0.1/255.255.255.255
acl SSL_ports port 443 563 5190
acl Safe_ports port 21 70 80 210 280 443 488 563 591 777 901 1025-65535 90
acl purge method PURGE
acl CONNECT method CONNECT

acl bad_url url_regex "/etc/squid/bad_url"
acl microsoft url_regex "/etc/squid/microsoft"
acl bad_files urlpath_regex .wav$ .avi$ .wmv$ .mpg$ .mp3$ .mov$ .wmf$ .3gp$ .mpeg$ .mpeg4$

acl adFull proxy_auth Philippoff
acl adHighSpeed proxy_auth setter Dyadyov Chebukin Salygin Belyaev
acl adMediumSpeed proxy_auth Solovyov Shevchuk Levin Linik Badenko
acl adLowSpeed proxy_auth Goncharov Taran Dispetcher Boyko Borisuk
acl adICQRes proxy_auth nkrash1 nkrash2 nkrash3 crrash1 crrash2 crrash3 gsrash1 gsrash2 gsrash3 kvrash1

#########################
###### HTTP_ACCESS ######
#########################

never_direct allow all

http_access allow manager localhost
http_access allow purge localhost
http_access deny purge
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost

http_access allow adFull !microsoft
http_access allow adHighSpeed !bad_url !bad_files !microsoft
http_access allow adMediumSpeed !bad_url !bad_files !microsoft
http_access allow adLowSpeed !bad_url !bad_files !microsoft
http_access allow adICQRes !bad_url !bad_files !microsoft

http_access deny all

#########################
###### DELAY_POOLS ######
#########################

delay_pools 3

delay_class 1 1
delay_parameters 1 8000/8000
delay_access 1 allow adLowSpeed
delay_access 1 deny all

delay_class 2 1
delay_parameters 2 15000/15000
delay_access 2 allow adMediumSpeed
delay_access 2 deny all

delay_class 3 1
delay_parameters 3 500/500
delay_access 3 allow adICQRes
delay_access 3 deny all


Файлы bad_url и microsoft занимаются тем, что рубят доступ к порнухе (и другим ненужным, но интересным для работников любой конторы темам) и к серверам Майкрософта. Вот листинг (bad_url приведен не полностью, т.к. ну очень большой).

/etc/squid/bad_url:

mp3
c-e-k-c
cekc
dildo
porevo
porno
porn
sex
xxx
lesbi
adult
erotic
glamur
prastitutki
prostitutki
prastitutky
prostitutky

Ну в общем бешеное буйство фантазии :)

/etc/squid/bad_url:

microsoft

Теперь ставим squid на автозагрузку так, как делали со службами самбы. То есть либо через YaST, либо руками:


root> ln -s /etc/init.d/squid /etc/init.d/rc3.d/K07squid
root> ln -s /etc/init.d/squid /etc/init.d/rc3.d/S15squid
root> ln -s /etc/init.d/squid /etc/init.d/rc5.d/K07squid
root> ln -s /etc/init.d/squid /etc/init.d/rc5.d/S15squid

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

root> /etc/init.d/squid start

Ну и маленькая мелочь – меняем права доступа на один системный каталог:

root> chmod 750 /var/lib/samba/winbindd_privileged

Ну вот и все – закончен сей великий труд, все настроено правильно и по правилам. Казалось бы, можно радоваться! Но...
Аутентификация по NTLM НЕРАБОТАЕТ!!! Базовая, понимаешь, работает, а NTLM нет. И нахрена, спрашивается мы всем этим занимались??? Что поделать, без костылей никуда. Путем мучительных проб и ошибок (хорошо, что не моих, кто-то до меня успел головой о стенку побиться) было выяснено, если провести определенный ряд последовательных действий, то заставить работать осьминога можно. Итак. Создаем файлик /etc/init.d/squid_winbind и заполняем его следующим содержимым:

#!/bin/bash
echo " ###############################################"
echo " ### START Shamanstvo wokrug SAMBA & WINBIND ###"
echo " ###############################################"
echo "chmod 750 /var/lib/samba/winbindd_privileged -R"
chmod 750 /var/lib/samba/winbindd_privileged -R
/etc/init.d/winbind stop
/etc/init.d/squid stop
/etc/init.d/winbind start
echo "chmod 777 /var/lib/samba/winbindd_privileged -R"
chmod 777 /var/lib/samba/winbindd_privileged -R
/etc/init.d/squid start
echo " ################################################"
echo " ### FINISH Shamanstvo wokrug SAMBA & WINBIND ###"
echo " ################################################"

Вот этот файлик будет правильно все запускать. Теперь ставим его на автозагрузку:

root> ln -s /etc/init.d/squid_winbind /etc/init.d/rc3.d/S99squid_winbind
root> ln -s /etc/init.d/squid_winbind /etc/init.d/rc5.d/S99squid_winbind

Внимательные люди уже заметили, что я ставлю линки только на запуск. И это правильно. А почему – догадайтесь сами :). Хотя вообще ситуация несколько неправильная (причем вдвойне), ну да ладно. Ну и собственно проверяем:

root> /etc/init.d/squid_winbind

Проверяйте, теперь все должно работать.
Ну и напоследок настроим хоть какой-нибудь мониторинг нашего головоногого. Устанавливаем sarg. Где вы его возьмете – ваши проблемы. Я утянул откуда-то из инета, так как в SLES9 его нет. Постарался найти самую последнюю версию для SLES9, нашел sarg-2.1-10. Настраиваем sarg. Предполагается, что логи sarg будет хранить в каталоге /var/log/sarg. Редактируем файлик /etc/sarg.conf. Нафиг все оттуда выкидываем, оставляем только следующее:

access_log /var/log/squid/access.log
output_dir /var/log/sarg
max_elapsed 28800000

Настраиваем расписание работы sarg. Делается это по следующей причине – sarg не является монитором реального времени, он работает только после того, как его пнешь командой (еж птица гордая, пока не пнешь – не полетит). Поэтому:

root> export EDITOR=mcedit
root> crontab -e

В открывшемся расписании cron-а добавляем следующие строки:

30 7 * * * sarg
12 12 * * * sarg
00 13 * * * sarg
30 16 * * * sarg

Вы можете настроить расписание так, как вам удобнее – ваше право. Мне удобно так.
Кроме того, при ротации логов тоже будет выполняться sarg. Об этом ниже.

Теперь настроим мониторинг реального времени. Для этого нам понадобится такая классная штука, как sqstat. Стянуть можно с http://samm.kiev.ua/sqstat/. Содержимое архива распаковываем в папку /var/log/sqstat. И настраиваем. Файлик config.inc.php.defaults копируем в эту же папку с именем config.inc.php. После редактирования у меня он выглядит следующим образом:



Кроме того для apache2 необходимо проставить php. Кстати, обратите внимание, что у меня sqstat занимается мониторингом двух хостов :)
Ну и теперь настраиваем apache2, чтоб можно было на sarg и sqstat смотреть по человечески. Редактируем файл /etc/apache2/httpd.conf, в самый конец дописываем:


ServerAdmin legion@proxy.mydomain.com.ua
ServerName legion.mydomain.com.ua
Alias /sarg "/var/log/sarg"

Order Deny,Allow
Allow from all
Options -Indexes

Alias /sqstat "/var/log/sqstat"

Order Deny,Allow
Allow from all
Options -Indexes



Запускаем апач и делаем первый сбор sarg:

root> /etc/init.d/apache2 start
root> sarg

После этого через любой обозреватель (IE, FireFox, Mozilla, Opera, NetScape, linx, Konqueror, SeaMonkey...) открываем ссылку: http://legion/sarg и смотрим содержимое. Если видим фигу – RTFM.
Кроме того открываем ссылку http://legion/sqstat/sqstat.php и смотрим на активные сессии. Опять же, если видим фигу – RTFM. Ну а че тут еще посоветовать???
Ну и занимаемся любимым делом – ставим apache2 в автозагрузку. Если руками, то так:

root> ln -s /etc/init.d/apache2 /etc/init.d/rc3.d/K08squid
root> ln -s /etc/init.d/apache2 /etc/init.d/rc3.d/S14apache2
root> ln -s /etc/init.d/apache2 /etc/init.d/rc5.d/K08apache2
root> ln -s /etc/init.d/apache2 /etc/init.d/rc5.d/S14apache2

Теперь настраиваем ротацию логов сквида, а заодно добавляем еще один сбор sarg. Для этого создаем каталог /var/log/arhiv/squid, и после этого редактируем /etc/logrotate.d/squid. Должно выглядеть так:

/var/log/squid/cache.log {
compress
dateext
maxage 365
rotate 99
size=+1024k
notifempty
missingok
create 640 squid root
postrotate
/etc/init.d/squid reload
endscript
olddir /var/log/arhiv/squid
}

/var/log/squid/access.log {
compress
dateext
maxage 365
rotate 100
daily
notifempty
missingok
create 640 squid root
prerotate
sarg
endscript
postrotate
/etc/init.d/squid reload
endscript
olddir /var/log/arhiv/squid
}

/var/log/squid/store.log {
compress
dateext
maxage 365
rotate 99
daily
notifempty
missingok
create 640 squid root
postrotate
/etc/init.d/squid reload
endscript
olddir /var/log/arhiv/squid
}

Пока все...

20 февраля 2007

Читать далее

2009-05-20

Печать с Windows на Linux

Значит так. Нужно с Windows XP или Windows 2000 печатать на принтера, установленные локально на линуксовой машине. Линукс у нас openSUSE 11.1.

1. Ну первым делом на линухе ставим cups, и samba, все что есть, не считая исходников и develop.
2. В YaST2 настраиваем принтер на общий доступ. Если все правильно настроено, то все окружающие тачки с линухой практически сразу его увидят и смогут на него печатать.


3. В YaST2 настраиваем samba. Там визард простой, разберетесь...
4. Потом в конфигах xinetd разрешаем работу SWAT.
5. Запускаем и ставим на автозапуск cups, smb, nmb, xinetd, winbind.
6. Заходим в SWAT (http://hostname_or_ip:901) и настраиваем там принтер.
7. Обращаем внимание на то, что имя принтера в CUPS и SAMBA д.б. одинаковое.
8. Ну и в консоли под root выполняем: cupsaddsmb -U root HP_LaserJet_P3005_LPT_1
9. Настраиваем принтер на масдайном клиенте.
10. Радуемся :)

Вот конфиг самбы на всякий случай(/etc/samba/smb.conf):

[global]
workgroup = NKRES
netbios name = URSEKT44
security = SHARE
map to guest = Bad User
printcap name = cups
printing = cups
printcap cache time = 750
cups options = raw
load printers = yes
use client driver = yes
add machine script = /usr/sbin/useradd -c Machine -d /var/lib/nobody -s /bin/false %m$
logon path = \\%L\profiles\.msprofile
logon drive = P:
logon home = \\%L\%U\.9xprofile
domain master = No
wins support = Yes
usershare allow guests = Yes

[homes]
comment = Home Directories
valid users = %S, %D%w%S
read only = No
inherit acls = Yes
browseable = No

[profiles]
comment = Network Profiles Service
path = %H
read only = No
create mask = 0600
directory mask = 0700
store dos attributes = Yes

[users]
comment = All users
path = /home
read only = No
inherit acls = Yes
veto files = /aquota.user/groups/shares/

[groups]
comment = All groups
path = /home/groups
read only = No
inherit acls = Yes

[printers]
comment = All Printers
path = /var/tmp
guest ok = Yes
read only = No
create mask = 0700
printable = Yes
browseable = Yes

[print$]
comment = Printer Drivers
path = /var/lib/samba/drivers
write list = @ntadmin, root
force group = ntadmin
create mask = 0664
directory mask = 0775

[HP_LaserJet_P3005_LPT_1]
comment = HP LaserJet P3005
path = /var/tmp
read only = No
create mask = 0600
administrative share = Yes
guest ok = Yes
printable = Yes
printer name = HP_LaserJet_P3005_LPT_1
use client driver = Yes
force printername = Yes
oplocks = No
share modes = No

Вот что я подпилил в конфигах CUPS, в /etc/cups/mime.convs:

application/octet-stream application/vnd.cups-raw 0 -

Ну и в принципе все :)



Читать далее

2009-05-19

Фишечки FireFox

Люблю, хороший огнелис. Только с первого пинка тормозной (на винде редко пользуюсь, так что все написанное касается linux). По крайней мере на версии 3.0.10 и ниже. Вот как исправляем тормоза:

1. В настройках снимаем галки с обоих "Информировать, не подозревается ли посещаемый веб-сайт в ...".
2. Меняем дефолтную тему например на "Chromifox Basic"
3. Ставим обязательные расширения: "Adblock Plus", "Flashblock".


А огнелис, который не тормозит мне нравится еще больше :)

Теперь исправляем хреновое и непредсказуемое поведение правой кнопки мышки:

1. Устанавливаем расширение "Mouse Gestures Redox" и нахрен в нем все отключаем.
2. Для удобства контекстных меню ставим расширение "Menu Editor", и настраиваем меню так, как нам по вкусу.
3. Запоминаем, что первые два действия можно було и не делать, если вы будете правую кнопку мышки всегда держать долго, до появления нужного меню. Я не так терпелив, поэтому и наваял первые два пункта.

Кстати, очень рекомендую установить еще такое расширения: "Google Toolbar for Firefox", "Extended Statusbar".

Читать далее

2009-04-16

Конвертирование wmv в avi в linux через bash

avidemux2_cli --nogui --audio-codec MP3 --video-codec Xvid4 --output-format AVI --load test.wmv --save test.avi
Читать далее