• jenkinsの DRY pluginで CPD

    jenkinsを使って継続的インテグレーションを行なっている。
    数年前はCruiseControl .NETを使っていたのだけど、hudsonを試したときユーザフレンドリーさに打たれて乗り換えた)

    以前からmakeなどで1手順ビルドできる仕組みを作ることにはこだわりがあった。
    たけど、単にビルドの1手順化だけでなく、
    •  複数の環境でビルドしたものを統合(CIサーバに集約)
    •  リポジトリのコミットとビルドを結びつけ(さらにITSのチケットに結びつく)
    •  複数の環境で自動テスト実行、その結果とビルドの結びつけ
    •  ビルドのログやテストのログなど記録をとる(確認したいときにすぐ辿れる)
    継続的インテグレーション入門 開発プロセスを自動化する47の作法
    ということを手間なく繰り返し可能とする仕組みには大きな意味があると思う。

    SCM、自動テスト、ITSそれぞれ単独でも役立つけど、
    ビルドとこれらを結びつけられるCIの存在は大きい。


    で、そのビルドと結びついた記録を取りたいものの1つがコードメトリクス。
    気にしている指標はいくつかあるけど、コードクローンについて。

    コードクローンの検出にCPD(PMD)を使っている。
    CPDのレポートxmlをjenkinsのDRY Pluginに食わせるだけ。ビルドごとの静的解析の結果をとりまとめてくれるプラグインでトレンドを見ることができる。
    正直に言えばjenkinsのビュー内でコードクローン部分そのものを見るのはあまり意味が無いというかかえって見づらいと思っている。eclipseにPMDプラグインをインストールしてクローン部分にアクセスする方が便利。
    あくまでjenkins上では時系列(ビルド)でコードクローンの増減を概観したい。


    ここの環境ではjenkinsのmasterをlinux上で動かしている。
    CPDの実行はWindowsスレーブ上で行なっている。
    入力はSJIS(MS932)でエンコードされたjavaソース。
    jenkinsのslave配下でjavaモジュールのビルドをantで行う。同様にantでCPDのレポートを作成している。

    PMDのlib下jarをCLASSPATHに指定してantタスクを定義
        <path id="cp.cpd">
            <fileset dir="${pmd.lib}">
                <include name="*.jar"/>
            </fileset>
        </path>
    
        <taskdef name="cpd" classpathref="cp.cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />

    cpdタスクを実行
        
    <cpd encoding="Windows-31J" minimumTokenCount="100" format="xml" language="java" outputFile="${reports.cpd}/cpd.xml"> <fileset dir="${src.dir}"> <include name="**/*.java"/> </fileset> </cpd>

    で、後はjenkinsのワークスペースに出力されたxmlのpathをDry Pluginの入力に設定するだけ。


    当初、cpdタスクの入力エンコーディングを"MS932"にしていた。出力XMLのxml宣言にあるencodingも"MS932"になるのだけどこのままDry Pluginに読み込ませようとするとエラーになってしまう。
    Dry Pluginのソースをgithubからcloneして、自動テストの入力xmlのencodingをMS932に書き換えて実行したらスタックトレースに
    「Invalid encoding name "MS932".」と出ていた。
    org.apache.xerces.*が使われるから?


    環境:

    Windows 7 x64
     JDK6 u26 x86
     ant-1.8.2
    CentOS 5.6 x64
     JDK u26 x64
     ant-1.8.1

  • MT5に移行した

    「GAEに移行した」で書いたようにここのサイトは、手元のサーバ上においてMTで編集/生成した静的HTMLを、GAEのアプリケーションにリソースとして組み込みServletで返しているだけなので、MT4でもMT5でも関係ないといえばない。

    MT4のときはSQLiteを使っていたので、MySQLに移行せざるを得なかった。
    • [MT4]システムメニューからバックアップ
    • [MT4]MySQLにMT用のDBとユーザを作成
    • [MT4]mt-config.cgiを書き換えてMySQLを参照する設定に。
    • [MT4]この状態でmt.cgiにアクセスすると新規セットアップになるので、適当に。
    • [MT4]システムメニューからバックアップを復元
    • [MT5]MT5のファイルをおいてアップグレード→再構築
    てな感じで移行自体はできたんだけど、よく見るとカテゴリのリンクがまったく張られていない。
    なんでかと思ったら全ての記事からカテゴリの情報が消えてた!!

    ちまちまちまちま全記事にカテゴリを設定しなおすはめに。
    記事の一括編集でカテゴリ設定できることに途中まで気がつかず無駄にしんどかった。あーぁ。

    結果的に過去のエントリを見返すことになったのだけど、今も使ってるアプリ/OSSが結構古いバージョンのときから使ってたので驚いた。

    環境:
     CentOS 5.5 x86
      MovableType 5.04


  • Arduinoと ATtiny2313で SPI

    気がついたら前回工作してから半年もたってた。
    SN3E0090.jpg

    ArduinoからATtinyに指示を送ってモーターの制御をする、てなことをやるつもり。で、まずはSPIで指示を送り、これに従って何かする、ことをやってみたい。

     ※以下の内容は単にやってみたことの記録です。すべて無保証で、障害・損害・不利益・不都合に対し、筆者は一切の責任を負いません。

    SPI自体についてはこのへんを参照。
    なんでSPIを選んだかというと、
    I2Cよりも、仕組みが単純、転送速度も速くできるみたいだから。

    • Arduinoをマスター、AVR ATtiny2313Vをスレーブとする。
    • ATtiny2313にはSSがないみたいなので、PB4をLOWにしたらスレーブ選択、という体(てい)で。
    • マスターから送ったデータ8ビットを、スレーブ側でLED点灯で表現(面倒だったのでLEDは4つ。下位4ビットだけ・・・)&前回データを反転したものをマスターに返すことで、通信がうまくいったことを確認する。Arduino側はスレーブから受け取ったデータをSerialに書きだす。
    ATtiny2313は、外部クリスタル8Mhzを使用かつCKDIV8を無効にしているので、システムクロックは8Mhz。
    電源はUSBからArduinoに給電。ATtinyはArduinoから出ている5Vを使う。
    spi_test.PNG


    マスター:
    最近公開されたarduino 0022ではSPIが標準ライブラリになっているので、マスター側はこれを利用した。

    #include <SPI.h>
    #include <util/delay.h>

    void setup()
    {
    Serial.begin(9600);

    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setClockDivider(SPI_CLOCK_DIV8);
    SPI.setDataMode(SPI_MODE0);

    pinMode(2, OUTPUT);
    digitalWrite(2, HIGH);

    uint8_t d = 0;
    for (;;)
    {
    digitalWrite(2, LOW);
    uint8_t a = SPI.transfer(d);
    digitalWrite(2, HIGH);

    Serial.print(d, HEX);
    Serial.write(", ");
    Serial.println(a, HEX);
    d++;
    _delay_ms(300);
    }
    }


    void loop()
    {
    }


    スレーブ:

    試しながら学ぶAVR入門―マイコンの基礎と電子工作とWindowsアプリケーションの作り方 (SkiLL up mycomputerシリーズ)
    スレーブ側は、ATtinyのデータシートに、アセンブリ言語で書かれた実装例があるので、ニーモニックの説明を見つつC言語に書き下してみた。
    ニーモニックについてはデータシートに説明がある。

    外部割り込みがどういう挙動か知りたかったこともあり、SS相当のPB4で割り込みがかかるようにした。
    PB4がLOWになったら受信開始。8ビット受信する。受信にあたりマスターへの送信データは、前回受け取ったデータをビット反転したものとした。特に意味はない。
    受け取った8ビットのうち下位4ビットのON/OFFをPB0~PB3につないだLEDに反映する。


    #include <avr/interrupt.h>
    #include <avr/io.h>
    #include <util/delay.h>


    #define USCK PB7
    #define MOSI PB5
    #define MISO PB6


    volatile uint8_t triggered = 0;

    ISR(PCINT_vect)
    {
    if (!bit_is_set(PINB, 4))
    {
    triggered = 1;
    }
    }

    uint8_t spi_slave_receive(uint8_t send)
    {
    USIDR = send;
    USISR = (1<<USIOIF);
    while (!(USISR & (1<<USIOIF)));
    uint8_t receive = USIDR;

    return receive;
    }

    void spi_slave_init()
    {
    USICR = (1<<USIWM0)|(1<<USICS1);

    // MISO(PB6)は出力に
    DDRB |= _BV(MISO);
    // MOSI(PB5)/USCKは入力に
    DDRB &= ~(_BV(MOSI) | _BV(USCK));

    // MOSI(PB5)/USCK(PB7)プルアップ
    PORTB |= (_BV(MOSI) | _BV(USCK));
    }

    int main(void)
    {
    spi_slave_init();

    // LED(PB0..PB3)は出力に
    DDRB |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);

    // LEDを消灯
    PORTB &= ~(_BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3));

    // PB4プルアップ
    PORTB |= _BV(PB4);

    // PB4の変化割込み
    GIMSK |= _BV(PCIE);
    PCMSK |= _BV(PB4);

    sei();

    uint8_t d = 0x00;
    for (;;)
    {
    while (!triggered)
    {
    }

    // PB4がLOWになった

    // clear
    triggered = 0;


    // 1バイト受信+送信
    d = spi_slave_receive(~d);


    // display bits as LED
    for (int i = 0, check = 1; i < 4; i++, check*=2)
    {
    if (d & check)
    {
    PORTB |= check;
    }
    else
    {
    PORTB &= ~(check);
    }
    }
    }
    }


    おわり:
    ようやくマイコン間で8ビット転送できるようになった。
    普段やってることは、重層な抽象化レイヤの上に成り立っているので、8ビットどころかネットワークを超えて簡単に送り放題だし、RPCでもなんでもいくらでもやりようがある。たまにこうやってプリミティブなところから積み上げるのもいい訓練になるなと思った。

    環境:
     Windows 7 x64 Ultimate
      arduino 0022
      AVR Studio 4.18 + SP3
      WinAVR 20100110
    Arduino Duemilanove
    AVR ATtiny 2313V




  • GAEに移行した

    すっきりわかるGoogle App Engine for Javaクラウドプログラミング


    オープンソース徹底活用 Slim3 on Google App Engine for Java
    今年の夏は暑かったせいか、このブログをホストしているサーバが時々ハングしていた。
    ので、なんとなく思い立ってGoogle App Engineに移行した。

    ほぼ静的htmlしか公開していないサイトなので、静的ファイルのみのアプリケーションをGAEでホストするというゴージャス仕様。

    短時間でなんとかしたいなと考え、まずは以下のように。

    • MTはperlで書かれているけど、これをGAE上で動くようにするのは道のりが遠いので、コメント/トラックバックの機能は閉じることにする。
      • MTの管理画面で両者を無効にして、サイト全体を再構築。
    • GAEアプリケーションのwar/ディレクトリ配下に公開する静的ファイルを全部置く。
    • デプロイする。
    GAEのアカウントとったりアプリケーション登録したりと、こまごまやることはあったけど、静的ファイルを公開するだけならこれでおしまい。

    ・・・なのだけどハマったことがいくつか。

    • 静的ファイル数の制限が3000個。
      • cgiやライブラリを除くMTのファイル(画像やテーマなど)もまとめてデプロイしようとしたのだけど、ファイル数制限を超えてデプロイできなかった。使ってないファイルを調べてちまちま削除した。
    • ファイル数が多かったのでデプロイに妙に時間がかかった。
      • ftpやscpでアップロードするのとは状況が違い、単純にファイルとして格納されるわけではないそうで。自分ところではデプロイ開始から50分かかってしまった。

    毎回デプロイに一時間近くかかってはこまるよなぁ、と。
    ということで現在は以下のように変更。

    • 対象となる静的ファイルを、pathのハッシュを基準にいくつかのzipアーカイブに分割して保存。(現在は16分割している)
    • すべてのURLを受け付けるサーブレットを作成。
    • リクエストされたパスからハッシュ値をとって格納zipアーカイブを決定。
    • zipアーカイブから指定されたパスのリソースを取り出して応答。
    • 静的コンテンツ1つ1つを、毎アクセスごとにzipから読み込んではさすがに無駄があるので、キャッシュAPIを使う。
    てなことをしたら、デプロイも数十秒で収まるようになった。

    アプリケーションが自分でOpenするファイルは、リソースファイルとしてデプロイしておく必要がある。

    ここのサイト用アプリは次のようなディレクトリ構成になっていて、

    gae-static-content/
      src/
        サーブレットなどのソース
      war/
        static-contents/
          passing-static-0.zip
          passing-static-1.zip
          passing-static-2.zip
          passing-static-4.zip以下 -f.zipの16分割。
        WEB-INF/
          classes/
          lib/
          appengine-web.xml
          logging.properties
          web.xml

    war/static-contens/*.zipをリソースファイルとしてデプロイするために、appengine-web.xmlに以下のように指定している。デフォルトではstatic-fileとリソースファイルの両方としてデプロイされるそうなので、静的ファイルからは除外、とした。

    	<static-files>
    <exclude path="/static-contents/*" />
    </static-files>

    MTで記事編集→
    再構築してhtml生成→
    静的ファイルのpathに応じて分割アーカイブ→
    アプリケーションとしてデプロイ

    てな流れ。分割アーカイブはperlで書いたスクリプトで一括処理。

    処理と作業の単純化のため、pathのハッシュ基準にzip分割しているのだけど、ファイルサイズを考慮していないのでそれぞれのアーカイブがGAEのファイルサイズ制限にひっかかってしまう可能性がある。が、今のところ最も大きいzipでも3MBなので、まあいいかと思っている。


    環境:
     Windows 7
      JDK6u20
      Eclipse 3.6
     App Engine SDK 1.3.7


  • Windows 2008な DC相手に keytabで kinitする話

    統合Windows認証用にktpass.exeを用いてサービス用のkeytabを作成。
    Active Directoryと apacheで 統合Windows認証
    kinitにこのkeytabを指定することで、パスワードを入力することなしでTGTを得ることができる。

    W2k8がDCな環境(krb5.confにおいて当該REALMのkdcにこの2008を指定している状態)で、上記エントリで作成したkeytabをkinitしようとすると、以下のエラーになってしまった。

    kinit(v5): Key table entry not found while getting initial credentials
    下のリンクは、2000と2003環境の話だけど、要領は同じみたい。
    IBM Tivoli | Microsoft Windows Server 2003環境でのWindows統合認証設定の考慮点 (Tivoli-08-030):

    クライアント側が合わせる場合:
    上記keytabはRC4で暗号化されたエントリが入っているので、krb5.conf側で暗号化にRC4を明示する。

    [libdefaults]
    default_tkt_enctypes = rc4-hmac
    default_tgs_enctypes = rc4-hmac

    keytab側をAESで暗号化する場合:
    以下のようにして暗号化にAESを明示する。

    ktpass -princ HTTP/somehost.example.com@EXAMPLE.COM -mapuser マップするユーザ名 -crypto AES256-SHA1 -ptype KRB5_NT_SRV_HST +rndPass -out 適当なファイル.keytab

    複数の暗号化でエントリを作成してもいいかも。だけど、どうせなら暗号強度が強い方に倒した方がいいのかなーと。

    $ kinit -kt keytabファイル HTTP/somehost.example.com
    $ klist
    Ticket cache: FILE:/tmp/krb5cc_9999
    Default principal: HTTP/somehost.example.com@EXAMPLE.COM

    Valid starting Expires Service principal
    08/30/10 19:02:41 08/31/10 05:02:42 krbtgt/EXAMPLE.COM@EXAMPLE.COM
            renew until 08/31/10 19:02:41


    Kerberos 4 ticket cache: /tmp/tkt9999
    klist: You have no tickets cached

    まずはこの状態で、SASL-GSSAPIによる認証を用い、ldapsearchでAD上のオブジェクトを検索できるとこまで確認した。つづきはそのうち。


    環境:
    Windows Server 2008 Standard x64
    CentOS 5.5
     krb5-workstation-1.6.1-36.el5_5.5
     krb5-libs-1.6.1-36.el5_5.5