freebsdのpythonでmysqlを使いたい

freebsdのpythonでmysqlを使いたい。

具体的にはtracでバックエンドのサーバをmysqlにしたかった。

今回稼働中のpythonは26で、apache上でfcgi(fast cgi)として動いてる。

あまり理解せずに断言すると、pythonは都度、soファイルを呼び出してるらしい。そこでpython用mysqlバイディングなsoファイルを作ればいい。

portsからできれば入れたかったので探してみる。

それっぽいのがいくつかあって困ったけど、どうやらMySQLdbってやつを使うといいらしい。

%sudo portinstall databases/py-MySQLdb

proftpdでドットファイルを表示させるようにしたい

proftpdでドットファイルを表示させるようにしたい。

クライアント側の設定かな、っておもって、FFFTPの設定いじってたけど、サーバ側の設定な気がしてきた。

Normally, FTP commands involving directory listings (NLST, LIST and STAT) use the arguments (options) passed by the client to determine what files are displayed and the format they are displayed in. The ListOptions directive can alter the behaviour of such listings by making it such that a certain option (or options) is always in effect, or is always disabled.

ListOptions – Proftpd: A User’s Guide

ファイルの表示にはいくつかコマンドがあったりして、クライアントによっては既にドットファイルが見えたりしてた。でもFFFTPで使ってるコマンドだと見れない。これをサーバ側でいじってやろうと。

proftpd.confに以下の行を追加。

ListOptions "-a"

表示するファイルが増えまくるので、FFFTP側の設定で見えなくすることもできる。

バージョンが1.2.8から、って書いてあって、今使ってるproftpdが1.3系列だったのでこれを採用。他にも方法ある、ような気がした。

courierで.forwardを使ってメールを転送する

courierで.forwardを使ってメールを転送する。

The dotforward program is a compatibility module that reads forwarding instructions in $HOME/.forward. dotforward is used for compatibility with sendmail or other mail servers that use the $HOME/.forward file. The dotforward program is intended to be executed from a dot-courier(5) delivery instruction file. The system administrator can add it to the default set of delivery instructions, thus unilaterally implementing $HOME/.forward systemwide. To read forwarding instructions from $HOME/.forward, put “|| dotforward” on the first line of $HOME/.courier*. “|| dotforward” can also be added to the DEFAULTDELIVERY setting in the courierd configuration file. In both cases it must be followed by a newline, and the remaining delivery instructions, which will be used if $HOME/.forward does not exist.

dot-forward - couerie.mta

勘を便りに適当に要約すると、sendmailとかで使ってた.forwardを使えるようにするには、$HOMEで指定されたディレクトリに、.courier (-*)的なファイルを作って、そこに下記のとおり書きます。

|| dotforward
./Maildir

こうやって書くと$HOMEにある.forwardファイルを読んで、転送を適当にやってくれますよ、ってことらしいです。

二行目の./Maildirが無いと、そこのアカウント自身に配送されなくて困りました。

$HOMEはuserdbで定義してあるやつです。うちだとMaildirが入ってるディレクトリでした。

tracの導入に当たっての注意点他

FreeBSD7.3-R, 32bit版にtrac-0.12を入れてみた。

長らく使用してたtrac-0.11はマルチリポジトリに対応して無くて、対応するぞーって言ってた0.12を待ってた。ちょくちょくインストールしたりしてたけど、これまでうまくいかなかった。なんとなく動くようになったぽいのでメモ。

FreeBSD7.3-R i386
apache-2.2.16
py26-sqlite3-2.6.5_1
sqlite3-3.6.23.1_1
trac-0.12

fast cgiモード?で動かす
マルチリポジトリ
全部のリポジトリで共通の認証。リポジトリごとに分けたりもできるぞたぶん。

まずリポジトリのおいてあるサーバとtracを稼働させようとしているサーバが違うのでそこをなんとかする。tracは必ずtracを動かしたローカルにリポジトリがないと駄目らしい。

nfsで見れるようにしようかと思ったけど、うちのnfsってだいたいrw出しちゃうから、一方的に読み取りのみの参照&ネットワークの負荷もかけないってことからrsyncしてみる。良いか悪いかわかんないけど。

crontabに下記を追加。先だって一発コマンドを通しておくとknown_hostsがどうのこうのするはず。ディレクトリが無いとか怒られないためにも。

*/10    *       *       *       *       root    /usr/local/bin/rsync -arv -e "ssh -i /usr/home/hogetan/.ssh/id_dsa" [email protected]:/usr/local/repositories/ /usr/local/repositories/ > /dev/null 2>&1

各種必要なパッケージ?はportinstallで適当に入れる。

%sudo portinstall /usr/ports/www/mod_fcgid

公式を見ながら設定する。

まずはapacheのhttpd.conf

LoadModule fcgid_module libexec/apache22/mod_fcgid.so
<IfModule alias_module>
  ScriptAlias /trac "/usr/local/share/trac/cgi-bin/trac.fcgi"
</IfModule>
<IfModule mod_fcgid.c>
  AddHandler fcgid-script .fcgi
</IfModule>
<LocationMatch "/trac/login">
  AuthType Basic
  AuthName "Trac"
  AuthUserFile /var/trac/.htpasswd
  Require valid-user
</LocationMatch>

scriptaliasを書く位置に注意。あとは.htpasswdが読めないと後で怒られる。.htpassswdの作成とかconfの参考とかは公式
TRAC_ENVはtrac.fcgiに直接書く。なんか理由があったけど忘れた。公式のどこかに書いてあった気がする。

basic認証させるディレクトリの記述に注意。公式通りだと/trac/hogehoge/loginしか受け付けなかったりする。

%sudo ee /usr/local/share/trac.fcgi
import os
os.environ['TRAC_ENV'] = "/var/trac"
os.environ['PYTHON_EGG_CACHE'] = "/tmp"

ここの設定で、TRAC_ENVを書くとそこのディレクトリにあるconf/trac.iniを読もうとするみたい。ここをマルチリポジトリだから~、って、TRAC_ENV_PARENT_DIRを設定すると、そのディレクトリから一つしたのディレクトリをそれぞれの独立したtracのプロジェクトと認識してしまうっぽかった。

(/var/trac/hogeproject/conf/trac.ini, /var/trac/hoge2project/conf/trac.ini, …)と、どんどん参照しちゃうみたい。ここでちょっとはまった。というか以前こんなことやってたけど、それぞれのディレクティブをhttpd.confに書いたりしてた・・・。これを知ってれば、ってかんじ。

次にtracのなんとかディレクトリ?(tracディレクトリとでも呼ぶのかな)、TRAC_ENVで設定されたディレクトリを作成してやる、tracのフォーマットで。

%sudo trac-admin /var/trac initenv

これでできる。nfsだとエラー。ミスったら消して直せば良い。気にくわなければ消して直せば良い。

.htpasswdは個人的な好みで/var/trac直下に。作り方は割愛。このファイルが残っててもinitenvできない。うざい。

次にconf/trac.iniを編集。

Trac 0.12b1が出たね - watawata日記
[repositories]
hoge1.dir=/usr/local/repositories/hoge1
hoge2.dir=/usr/local/repositories/hoge2
hoge3.dir=/usr/local/repositories/hoge3

こんな感じで列挙。元サイトにはtypeとかdescriptionとかあったけど、desc書いたらごちゃごちゃしちゃったし、typeはデフォルトでsvnなので今回はdirのみ定義。下記のコード+適当に選び出すでおk。

%php -r '$h = opendir("/usr/local/repositories"); while($f = readdir($h)){ print basename($f).".dir = /usr/local/repositories/$f\n";}'

そろそろ見て確認してみる。対象サーバのURLにscriptaliasで名付けた/tracとか付ける。


パーミッションとかよく怒ってくるので適当に対処。pythonのエラーは見慣れないので困ったら泣く。結構同じエラーにはまってる人とか少なかったりして泣ける。

tracの管理者権限をそれっぽいユーザに付与。これするとtrac画面の一番右端の方にadminってのが出てきて管理ができるらしい。

%sudo trac-admin /var/trac permission list
%sudo trac-admin /var/trac permission add tracadminisry TRAC_ADMIN

ログインしてTracを使う - へたれプログラマな日々

このあと、adminの画面の一番左下の方にあるrepositriesをクリック。
リポジトリが複数あるかチェック

これだとまだ利用できない。同期?が必要らしい。でも何を同期するんだろう。他にはどんなタイミングで同期すれば良いんだろう。

%sudo trac-admin /var/trac repository resync '*'
%sudo trac-admin /var/trac changeset added '*'

リビジョンが多いと結構時間がかかる。
これが終わったらさっきの管理画面でリビジョンが出てたりする。そんでなんかうまくいけたっぽい。

ここから先はこれから試す。

以上

apacheでhtpasswd使った認証とかできない

apacheでhtpasswd使った認証(?)とかができない。ベーシック認証。httpd.confにAuthUserFileを書いたら怒られたぽい。

l2tp.org%sudo /usr/local/etc/rc.d/apache22 reload
Performing sanity check on apache22 configuration:
Syntax error on line 504 of /usr/local/etc/apache22/httpd.conf:
Invalid command 'AuthUserFile', perhaps misspelled or defined by a module not included in the server configuration

ロードすべきモジュールがわかんないからググった。

何ヶ月ぶりかの動き:apache2 2.2.3-1~exp.r170 – vdrめも

まず authn_file モジュールを有効に。けどこれだけでは駄目で、
次に auth_basic モジュールを有効に。まだ駄目で、
最後に authz_user モジュールを有効にしてやると、これまで通りに使えるようになった。

うちはauthn_fileがコメントアウトされてたのでコメントを外す。

l2tp.org%sudo /usr/local/etc/rc.d/apache22 reload
Performing sanity check on apache22 configuration:
httpd: Syntax error on line 54 of /usr/local/etc/apache22/httpd.conf: Cannot load /usr/local/libexec/apache22/mod_authn_file.so into server: Cannot open "/usr/local/libexec/apache22/mod_authn_file.so"

と思ったらモジュールがなかった。適当に入れてやって再起動。

%cd /usr/ports/www/apache22; sudo make config; sudo portupgrade -f apache22

tracの初期化でこける

tracの初期化でこける。I/O Errorとか言うやつ。

エラーが出ても一応ディレクトリはできてて、そのままtracのpythonで読ませられるけど、やっぱりその先でI/Oエラーって怒られる。

l2tp.org%trac-admin ./hogehoge initenv
Creating a new Trac environment at /usr/home/yousan/trac/hogehoge
Trac will first ask a few questions about your environment
in order to initialize and prepare the project database.
 Please enter the name of your project.
 This name will be used in page titles and descriptions.
Project Name [My Project]> hogehoge
 Please specify the connection string for the database to use.
 By default, a local SQLite database is created in the environment
 directory. It is also possible to use an already existing
 PostgreSQL database (check the Trac documentation for the exact
 connection string syntax).
Database connection string [sqlite:db/trac.db]>
Creating and Initializing Project
Initenv for '/usr/home/yousan/trac/hogehoge' failed.
Failed to create environment.
disk I/O error
Traceback (most recent call last):
 File "build/bdist.freebsd-7.3-RELEASE-i386/egg/trac/admin/console.py", line 413, in do_initenv
 options=options)
 File "build/bdist.freebsd-7.3-RELEASE-i386/egg/trac/env.py", line 221, in __init__
 self.create(options)
 File "build/bdist.freebsd-7.3-RELEASE-i386/egg/trac/env.py", line 409, in create
 DatabaseManager(self).init_db()
 File "build/bdist.freebsd-7.3-RELEASE-i386/egg/trac/db/api.py", line 146, in init_db
 connector.init_db(**args)
 File "build/bdist.freebsd-7.3-RELEASE-i386/egg/trac/db/sqlite_backend.py", line 196, in init_db
 cursor.execute(stmt)
OperationalError: disk I/O error

ググっても大して良い情報が見つからなかった。コードもうまく追っかけられなかった。でもふと気付いた。

tracのディレクトリにしようとしたところがNFSだった。これが駄目だった。ローカルHDDの/varにしたらうまくいった。うーん。

以前phpのpukiwikiでも、nfsのロックが取得できないだかで困った覚えがあって、おそらくそれと同じような内容なんじゃないかな、って助かった。

python追えないのでなんともいえないけど。こんなん報告したら対応してもらえるのかな。まーいいやめんどうだし。

democracyが不調っぽかった

考えてみればアンケートの送付先はashuraになる。

ここらで整理して、送付先もpolkにしよう、と。

wordpress_fsをインクルードするように変更。変更点が出始めたのでsvn管理下に。

dbの整合性をとる。

reagan.l3tp.org%mysqldump -h ashura -u yousan -p wordpress_yousan wp_democracyIP –skip-extended-insert > ~/tmp/hoge.sql

CREATE TABLE  `wordpress_yousan`.`wp_democracyIPP` (
`ip` int(11) NOT NULL DEFAULT ‘0’,
`qid` int(10) unsigned NOT NULL DEFAULT ‘0’,
KEY `ip` (`ip`,`qid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

ALTER TABLE `wordpress_yousan`.`wp_democracyIPP` ADD UNIQUE INDEX `Index_2`(`ip`, `qid`);

select distinct *  from wordpress_yousan.wp_democracyIP;
SELECT * FROM wordpress_yousan.wp_democracyIP w;

ここら辺で異常に気づく。ipってどうやらlongにキャストして保管してるけど、たぶんこれ全部fordのipだ。面倒だから全部統括してやる。

mysqldumpの–no-create-infoをつけないと、droptableが入ってしまって元あるデータを壊す。今回はpolk由来のデータをなくしてしまって、clintonから復旧させようとしたもののレプリケーションが反映されてて、しょうがないからtylerから復旧した。

さらに異常。IPテーブルは単なるログで集計結果はAにあるらしい。ashuraのAテーブルを元にdumpしたやつをpolkのAAに復元してしたのupdate文を流す。

update wordpress_yousan.wp_democracyA a1
left outer join wordpress_yousan.wp_democracyAA a2 on a1.aid = a2.aid
set a1.votes=a1.votes+a2.votes;

SELECT sum(votes) FROM wordpress_yousan.wp_democracyA;

合計9200ぐらい。数値は目で確認しながら。

先のIPテーブルが5000強(ashura)、3000強(polk)だったからだいたい一致する。

mysqlサーバに接続ができなくなった。

wordpressでmysqlサーバに接続ができなくなった。

Error establishing a database connection

こればっかりが出ちゃう。他のホストから同じwordpressのファイルを参照して表示させるとうまく表示される。何かがおかしい。

そのつながらないホストからmysqlコマンドを叩いてみる。

www2.l2tp.org%mysql -h ashura -u yousan  -p
Enter password:
ERROR 1129 (HY000): Host ‘192.168.xxx.xxx’ is blocked because of many connection \
errors; unblock with ‘mysqladmin flush-hosts’
どうやら前にコネクションはりすぎでお怒りの様子。

対象ホストでflush-hostsをしてみる。

Where command is a one or more of: (Commands may be shortened)
create databasename   Create a new database
debug                 Instruct server to write debug information to log
drop databasename     Delete a database and all its tables
extended-status       Gives an extended status message from the server
flush-hosts           Flush all cached hosts
flush-logs            Flush all logs
flush-status          Clear status variables
flush-tables          Flush all tables
flush-threads         Flush the thread cache
flush-privileges      Reload grant tables (same as reload)
kill id,id,…        Kill mysql threads
password new-password Change old password to new-password, MySQL 4.1 hashing.
old-password new-password Change old password to new-password in old format.

どうやらホスト情報をキャッシュしてるみたいで、それを飛ばすことで拒否から外れるらしい。

キャッシュにフラグでもあるのかな。

うまくつながるようになりました。

Javascriptでフォームの省略入力コマンド

テーブル的なフォームでデータを大量に入力する必要が有る場合、時々前の行と同じだったり連番だったりして、一々入力するのが面倒だったので作った。vim使いなので何かvimライク。

// 入力値省略コマンド作成
function editor_cmd(elem) {
  /*
  初期化は省略
  */
  $(inputs).keyup(function(){
    // (focusとblurで代入したほうが良いと思う)
    prev = $(this).closest("tr.tracks").prev(); // 前の行
    next = $(this).closest("tr.tracks").next(); // 次の行
    val = $(this).val();
    // キーアップイベント時にcaseに当てはまる値なら値を置き換える
    switch (val) {                                                                             
      case ":=p": // 前の行と同じ
        if ($(prev).size()) {
          $(this).val($(prev).find("input.t1").val());
        }
        break;
      case ":=n": // 次の行と同じ
        if ($(next).size()) {
          $(this).val($(next).find("input.t1").val());
        }
        break;
      case ":+p": // 前の行の数字+1
        if ($(prev).size()) {
          $(this).val(
            val_incdec($(prev).find("input.t1").val(), true)
          );
        }
        break;
      case ":-n": // 次の行の数字を-1
        if ($(next).size()) {
          $(this).val(
            val_incdec($(next).find("input.t1").val(), false)
          );
        }
        break;
    }
  });
}

// 文字列中の数字をインクリメント, デクリメント
// 第二引数がtrueならインクリメント
function val_incdec(val, inc) {
  var len, num;

  val = val.replace(/\d+/, function(match){
    len = String(match).length;
    if (inc) {
      num = Number(match) + 1;
    }
    else {
      num = Number(match) - 1;
    }
    num = String(num);
    while (num.length < len) {
      num = '0' + num;
    } 
    return num;
  });
  return val;
}