2010年12月11日土曜日

LDAP で MySQLバックエンド

■メリット
・LDAPをDBの変更だけで管理できる。
・Aliasが簡単に作れる。(objectClass不要)

■必要なものをインストール
yum install openldap-servers-sql
yum install mysql-connector-odbc

■設定ファイルを修正
・/etc/odbcinst.ini
・/etc/odbc.ini
・/etc/openldap/slapd.conf
(下記参照)

■SQLを準備
・example.sql
(下記参照)

■DBを作成
mysql -uroot -e "create database example default charset utf8"
mysql -uroot example --default-character-set=utf8 < example.sql

■接続確認
isql example

■LDAP起動
/etc/init.d/slapd start

■検索確認
ldapsearch -x -D cn=manager,dc=example,dc=com -w secret -b dc=example,dc=com "(uid=*)"
ldapsearch -x -D uid=sample1,ou=people,dc=example,dc=com -w sample -b uid=sample1,ou=people,dc=example,dc=com
ldapsearch -x -D uid=sample-x,ou=alias,dc=example,dc=com -w sample -b uid=sample-x,ou=alias,dc=example,dc=com


以上
(以下設定・SQL)

■/etc/odbcinst.ini
[MySQL]
Description = ODBC for MySQL
Driver = /usr/lib/libmyodbc5.so
Setup = /usr/lib/libodbcmyS.so
FileUsage = 1


■/etc/odbc.ini
[example]
Driver = MySQL
Server = localhost
Port =
Database = example
User = root
Password =
Charset = utf8


■/etc/openldap/slapd.conf
include      /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema

modulepath /usr/lib/openldap
moduleload back_sql.la

pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args

database sql
suffix "dc=example,dc=com"
rootdn "cn=manager,dc=example,dc=com"
rootpw secret

dbname example
dbuser root
dbpasswd ""

subtree_cond "ldap_entries.dn LIKE CONCAT('%',?)"
has_ldapinfo_dn_ru no


■example.sql
-- 内部処理用テーブル
drop table if exists ldap_oc_mappings;
create table ldap_oc_mappings
(
id int key auto_increment,
name varchar(64),
keytbl varchar(64),
keycol varchar(64),
create_proc varchar(255),
delete_proc varchar(255),
expect_return tinyint
);

drop table if exists ldap_attr_mappings;
create table ldap_attr_mappings
(
id int key auto_increment,
oc_map_id int references ldap_oc_mappings(id),
name varchar(255),
sel_expr varchar(255),
sel_expr_u varchar(255),
from_tbls varchar(255),
join_where varchar(255),
add_proc varchar(255),
delete_proc varchar(255),
param_order tinyint,
expect_return tinyint
);

drop table if exists ldap_entries;
create table ldap_entries
(
id int key auto_increment,
dn varchar(255),
oc_map_id int references ldap_oc_mappings(id),
parent int,
keyval int,
unique(dn)
);

drop table if exists ldap_entry_objclasses;
create table ldap_entry_objclasses
(
entry_id int references ldap_entries(id),
oc_name varchar(64)
);

-- データ用テーブル
drop table if exists domains;
create table domains (
id int key,
name varchar(255)
);

drop table if exists units;
create table units (
id int key,
name varchar(255)
);

drop table if exists persons;
create table persons (
id int key,
uid varchar(255),
name varchar(255),
password varchar(64),
unique(uid)
);

-- データ登録
-- objectClass定義
insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return)
values (1,'organization','domains','id',NULL,NULL,0);

insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return)
values (2,'organizationalUnit','units','id',NULL,NULL,0);

insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return)
values (3,'inetOrgPerson','persons','id',NULL,NULL,0);

-- 属性定義
insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (1,1,'dc','name','domains',NULL,NULL,NULL,3,0);

insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (2,1,'o','name','domains',NULL,NULL,NULL,3,0);

insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (3,2,'ou','name','units',NULL,NULL,NULL,3,0);

insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (4,3,'uid','uid','persons',NULL,NULL,NULL,3,0);

insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (5,3,'cn','name','persons',NULL,NULL,NULL,3,0);

insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (6,3,'sn','name','persons',NULL,NULL,NULL,3,0);

insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return)
values (7,3,'userPassword','password','persons',NULL,NULL,NULL,3,0);

-- ベースDN
insert into domains (id,name)
values (1,'example');
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (1,'dc=example,dc=com',1,0,1);
insert into ldap_entry_objclasses (entry_id,oc_name)
values (1,'dcObject');

-- ピープルOU
insert into units (id,name)
values (1,'people');
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (2,'ou=people,dc=example,dc=com',2,1,1);

-- AliasOU
insert into units (id,name)
values (2,'alias');
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (3,'ou=alias,dc=example,dc=com',2,1,2);


-- サンプルピープル
insert into persons (id,uid,name,password)
values (1,'sample1','サンプル1','sample');
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (4,'uid=sample1,ou=people,dc=example,dc=com',3,2,1);

insert into persons (id,uid,name,password)
values (2,'sample2','サンプル2','sample');
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (5,'uid=sample2,ou=people,dc=example,dc=com',3,2,2);

insert into persons (id,uid,name,password)
values (3,'sample3','サンプル3','sample');
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (6,'uid=sample3,ou=people,dc=example,dc=com',3,2,3);

-- サンプルAlias
insert into ldap_entries (id,dn,oc_map_id,parent,keyval)
values (7,'uid=sample-x,ou=alias,dc=example,dc=com',3,3,1);

2010年11月26日金曜日

TerracottaでTomcat(CAS)のクラスタリング

■Terracottaとは?
「Terracotta 3.4.0 - Simple Scale for Enterprise Java」(『README.txt』より)
よく分かりません。
要は、JAVAの実行プロセスにフックをかけることで、
内部データがTerracottaサーバを経由するようにできる。

■テスト環境
1. 2つのサーバ:
 ホスト名=dog、IPアドレス=192.168.1.11
 ホスト名=cat、IPアドレス=192.168.1.12
 ※ 時間設定があっていること!
2. 各Tomcatディレクトリ($CATALINA_HOME):「/usr/local/tomcat」
3. 各Java実行ディレクトリ($JAVA_HOME):「/usr/local/tomcat/jre」

■テラコッタダウンロード・設置
「http://www.terracotta.org/」の「DOWNLOAD」> 「Get Open Source」
> 適当にフォーム入力するとダウンロード先がメールで送られてくる。
ダウンロード先:http://www.terracotta.org/dl/oss-download-catalog
「Terracotta Tarball Binary」の「terracotta-3.4.0.tar.gz」をダウンロード。

■解凍してできたディレクトリを「tc」として、各「$CATALINA_HOME」に入れる。
以下「$CATALINA_HOME」での作業。
※JAVA_HOMEを設定
export JAVA_HOME=/usr/local/tomcat/jre

■設定ファイルを作成
1. CASサーバ用の設定をダウンロード
wget https://source.jasig.org/cas3/tags/cas-server-3.4.3.1/etc/terracotta/sample-terracotta-config.xml -O tc/tc-config.xml

2. 設定を修正
vi tc/tc-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<tc:tc-config xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd" xmlns:tc="http://www.terracotta.org/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- サーバを2つ設定 -->
<servers>
<server name="dog" host="192.168.1.11" />
<server name="cat" host="192.168.1.12" />
</servers>
<!-- モジュール設定を追加 -->
<clients>
<modules>
<module name="tim-tomcat-6.0"/>
<module name="tim-spring-webflow-2.0"/>
<module name="tim-spring-security-2.0"/>
</modules>
</clients>
...
</tc:tc-config>


■必要なモジュール(上の「<modules>」設定したもの)のダウンロード・インストールを行う。
1. プロキシ設定が必要な場合は以下のファイルを編集
vi tc/lib/resource/tim-get.properties
org.terracotta.modules.tool.proxyUrl = http://プロキシサーバ:ポート


2. サポートされているモジュールを確認
tc/bin/tim-get.sh list

3. ダウンロード・インストール
tc/bin/tim-get.sh upgrade tc/tc-config.xml

4. インストールされたものを確認
ls tc/platform/modules/org/terracotta/modules

■テラコッタの起動
tc/bin/start-tc-server.sh -f tc/tc-config.xml &

■Tomcat起動時のブート・クラス(jar)を作成
tc/bin/platform/bin/make-boot-jar.sh -o tc/lib/dso-boot.jar

■Tomcat起動時の環境変数(JAVA_OPTS)を確認
export TC_INSTALL_DIR=tc
export TC_CONFIG_PATH=192.168.1.11:9510,192.168.1.12:9510
export DSO_BOOT_JAR=tc/lib/dso-boot.jar
tc/bin/platform/dso-evn.sh
↓出力(最終行)
-Xbootclasspath/p:tc/lib/dso-boot.jar -Dtc.install-root=tc -Dtc.config=192.168.1.11:9510,192.168.1.12:9510


■Tomcatを起動
# 上の結果を「JAVA_OPTS」に設定する
export JAVA_OPTS="-Xbootclasspath/p:tc/lib/dso-boot.jar -Dtc.install-root=tc -Dtc.config=192.168.1.11:9510,192.168.1.12:9510"
export CATALINA_PID=logs/catalina.pid
bin/startup.sh; tail -f logs/catalina.out


■デベロッパ・コンソールで、データ確認
tc/bin/dev-console.sh
Platform > Clustered heep > Object browser > ...

■Tomcatの停止
export JAVA_OPTS= #テラコッタは無視
bin/shutdown.sh 3 -force #約3秒待機して、残っていたら殺す


■Terracottaの停止
tc/bin/stop-tc-server.sh -f tc/tc-config.xml -n dog
※「-n」に自分のサーバのホスト名(<server>の`name`属性)を指定

■テラコッタのログ/データについて
設定ファイル「tc-config.xml」で、ログ/データの保存先を全く指定しなかった場合、以下のようなファイルが作成されます。
・サーバデータ(デフォルト=data)→ tomcat/tc/data/*
・サーバログ(デフォルト=logs)→ tomcat/tc/logs/terracotta-server.log*
・サーバ統計(デフォルト=statistics)→ tomcat/tc/statistics/statistics-*
・クライアントログ(デフォルト=logs-%i)→ tomcat/logs-127.0.0.1/terracotta-client.log*


つまり、
1. サーバの場合は、「tc-config.xml」の場所からの相対パス。
2. クライアントの場合は、実行位置からの相対パス。
、、、になってしまいます。
「logs-127.0.0.1」が嫌な場合は、設定(「tc-config.xml」の<clients>)を例えば以下のように変更
<clients>
<!-- Tomcatのログディレクトリに保存 -->
<logs>logs</logs>
</clients>


■「$CATALINA_HOME」内のMakefileの例
JAVA_HOME=jre
CATALINA_HOME=.
CATALINA_PID=logs/catalina.pid

TC_INSTALL_DIR=tc
TC_DSO_BOOT_JAR=$(TC_INSTALL_DIR)/lib/dso-boot.jar
TC_CONFIG_FILE=$(TC_INSTALL_DIR)/tc-config.xml
TC_CONFIG_HOSTS=192.168.1.11:9510,192.168.1.12:9510
TC_STOP_HOST=$(shell hostname -s) #自分のサーバのホスト名

TC_JAVA_OPTS=-Xbootclasspath/p:$(TC_DSO_BOOT_JAR)
TC_JAVA_OPTS+=-Dtc.install-root=$(TC_INSTALL_DIR)
TC_JAVA_OPTS+=-Dtc.config=$(TC_CONFIG_HOSTS)

export JAVA_HOME

#Tomcatの起動
start:$(TC_DSO_BOOT_JAR)
export CATALINA_PID=$(CATALINA_PID); \
export JAVA_OPTS="$(TC_JAVA_OPTS)"; \
$(CATALINA_HOME)/bin/startup.sh

#Tomcatの停止
stop:
export CATALINA_PID=$(CATALINA_PID); \
$(CATALINA_HOME)/bin/shutdown.sh 3 -force

#ブートJarの作成
$(TC_DSO_BOOT_JAR):
$(TC_INSTALL_DIR)/platform/bin/make-boot-jar.sh -o $@

#環境チェック
check-tc:
export TC_INSTALL_DIR=$(TC_INSTALL_DIR); \
export TC_CONFIG_PATH=$(TC_CONFIG_HOSTS); \
export DSO_BOOT_JAR=$(TC_DSO_BOOT_JAR); \
$(TC_INSTALL_DIR)/platform/bin/dso-env.sh

#Terracotta起動
start-tc:
$(TC_INSTALL_DIR)/bin/start-tc-server.sh -f $(TC_CONFIG_FILE) &

#Terracottaの停止
stop-tc:
$(TC_INSTALL_DIR)/bin/stop-tc-server.sh -f $(TC_CONFIG_FILE) -n $(TC_STOP_HOST) &


■Eclipse・Tomcatプラグインの設定
ウィンドー > 設定 > Tomcat > JVMの設定
、、、で「JAVA_OPTS」の各パラメタを追加(ただし絶対パス指定)
・-Xbootclasspath/p:/usr/local/tomcat/tc/lib/dso-boot.jar
・-Dtc.install-root=/usr/local/tomcat/tc
・-Dtc.config=192.168.1.11:9510,192.168.1.12:951

2010年10月24日日曜日

file要素を隠す方法

ファイルアップロードするための「file」要素とういのは
「参照...」ボタンなどの外観をコントロールできない。
以前は「file」要素を見えないようにして、
$("a.upload").click(function(){ $("input[type=file]").click(); });
などとできた気がしたのだが、
いつの間にかできなくなっていた。
、、、で、フォーム初期化時に「file」要素のスタイルをいじる方法。

<a class="upload" href="javascript:;">
アップロード
<input type="file" style="display:none;" />
</a>

<script type="text/javascript">
$(function(){
$("a.upload")
.css({display:'block',position:'relative',overflow:'hidden'})
.find("input[type=file]")
.css({position:'absolute',right:'0',opacity:'',display:''})
.change(function(){
//アップロード処理
alert($(this).val());
});
});
</script>

2010年10月21日木曜日

クロージャ?

クロージャの定義がいまいち分からないのですが、、、
要するに名前空間が「とある局所」で維持できればいいので、、、

インラインスクリプト
<div class="portlet" id="portlet-1">
<script type="text/javascript">
(function() { //無名関数を実行
//スクリプトファイルを同期で読み込んで実行
eval($.ajax({url:'portlet.js',async:false}).responseText);
var portletName = 'ポートレット1'; //ローカル変数の上書き
$(initPortlet); //「portlet.js」の初期化関数呼出
})();
</script>
</div>

<div class="portlet" id="portlet-2">
<script type="text/javascript">
(function() {
eval($.ajax({url:'portlet.js',async:false}).responseText);
var portletName = 'ポートレット2';
/////////////////////////////////////////////////////////
//「portlet.js」で定義されている関数のオーバーライド
var superClickPortlet = clickPortlet;
var clickPortlet = function() {
superClickPortlet.call(this,this,'Override');
};
/////////////////////////////////////////////////////////
$(initPortlet);
})();
</script>
</div>


外部スクリプト(portlet.js)
//スクリプトタブの親を判定
var container = $("script:last").parents("div:first");

//ローカル変数
var portletName = 'ポートレット';

//ローカル関数
var clickPortlet = function(e,a) {
alert("portletName:"+portletName+", containerId:"+this.id+", arg1:"+a);
};

//ローカル関数
var initPortlet = function() {
$(container).click(clickPortlet);
};

2010年10月9日土曜日

SCRIPTタグのDOM要素位置の取得

同じ画面にまったく同じ(JavaScriptを含む)HTML要素を出力して、
それぞれのブロックが別々に動作するようにしたい場合の方法。

<div id="p1" class="portlet">
<script type="text/javascript">
(function(){
var container = $("script:last").parents("div:first");
var hello = function() {
alert(this.id);
};
$(function(){
container.click(hello);
});
})();
</script>
</div>

<!-- 上のDIVと中身は全く同じ -->
<div id="p2" class="portlet">
<script type="text/javascript">
(function(){
var container = $("script:last").parents("div:first");
var hello = function() {
alert(this.id);
};
$(function(){
container.click(hello);
});
})();
</script>

</div>