親愛なるジョンからの手紙

雑記です。ゲームとか漫画とかプログラミングとか。

KnowledgeのDBをH2DBからPostgreSQLへ移行した際のメモとかやったこととか

概要

弊社はナレッジベースにKnowledgeを利用しております。

Knowledge https://information-knowledge.support-project.org/ja/

そのKnowledgeのDBを組み込みDBからPostgreSQLに移行しました。 その際にハマった点がいくつかあったので、備忘録の意味も込めて書いたものの転載がこちらになります。

環境

CentOS 6(VirtualBox)

なんで6系なんだろうね。まあいいか。プライベートだし。

一発移行できなかった原因

  • Knowledge側が想定するPostgreSQLのバージョンが9.3以降だったが、実環境のバージョンが8系だった。(今の最新バージョンだと9.6以上くらいになってるはず。なんにしろKnowledge公式はpostgresqlの動作確認済バージョンをreadmeに書くべきな気がする)
  • PostgreSQLの認証方式がidentだったため、id - password認証が通っていなかった。

修正手順

バックアップ

何はともあれバックアップ。 VirtualBox経由でマシンを立ち上げていると、スナップショット一発でバックアップが取れるので、スナップショットだけ取って終了。 https://pc-karuma.net/virtualbox-snapshot/

ログ確認

まずはログの確認。 Knowledgeはすべてのログを$TOMCAT_ROOT/logs/catalina.outに吐き出すので、lessとかtail -fとかで適当に見て原因を確定させます。

ログを読む限り、一部のSQLが構文ミスだよ、となっていたので、PostgreSQLのバージョン違いと確信。 githubのissueから探して同様の症状が出ているものもあったので、とりあえずPostgreSQLのバージョンアップを試してみる。

既存のDBのバックアップ

PostgreSQLのdump_allを利用してバックアップ。 バックアップファイルは適当なところに置いておきます。 レストア時にsudoで動かすと怒られたので、postgresにsuしてからやった方がいいかも。

コマンドは以下の感じで。

pg_dumpall -o -f /path/to/temp/dump.sql

PostgreSQLのアップグレード

CentOS6系でPostgreSQL9系をダウンロードするためには、yumの標準リポジトリでは取れないので、既にインストールしてある8系のPostgreSQLyum removeしてから作業開始。

手順はほぼ下記URLのまま。 標準リポジトリからpostgresqlの利用を禁じて、PostgreSQLの対象バージョンのrpmを追加し、あとはlist grepしつつ必要なライブラリを落とすだけ。 今回はPostgreSQL-Serverだけ落としています。 https://weblabo.oscasierra.net/postgresql-installing-postgresql9-centos6-1/

なお、今回使用したrpmはPostgreSQL9.3 以下のCentOS6 x86_64です。 https://yum.postgresql.org/repopackages.php#pg93

また、この方法で行うとService名にバージョン数値がついたり、データ周りの情報が/var/pgsql/9.3/data以下となったりで、ググって出てきたコマンドをコピペ駆動できなくなったりします。注意。

PostgreSQLのアクセス制御

yumから落としたばかりのPostgreSQLはアクセス制御がident方式になっているので、ログイン中のユーザーが一致しないと入れません。 作業するにもアプリからアクセスするにも面倒なので、md5認証にしてしまいます。

https://www.dbonline.jp/postgresql/ini/index2.html

hba.confファイルを弄ったら、次はpostgres.confでlisten対象を変更。 ひとまずワイルドカードで対応しました。別に公開してないからね、ええやろ。多分localhostでもいけるんやないか。知らんけど。

変更が終わったらservice postgresql-9.3 restartで認証を認識させます。

DBのレストア

以下コマンドで行えます。 このときsudoすると怒られるので、postgresql用のユーザーで行うと吉。

psql -f dump.sql

あとはKnowledgeで利用するユーザーでログインして、認証が通ったか、Knowledgeで利用するDBが作成されているか、そのユーザーにDBを触る権利があるかなどをpg_shadow等で確認しつつ準備完了です。

KnowledgeのPostgreSQL移行

Knowledgeに管理者ユーザーでログインし、システム設定→データベースの接続先変更から、各設定値を入力。接続先変更が有効になったら、組み込みDBで~DBにコピーを行って完了です。

max connectionはひとまずJDBCのデフォルト値である100に設定。これにて完了。

Digest認証環境でもTestcafeしたい!(ラノベ)

対象バージョン

Testcafe Ver.0.13.0 でもTestcafeあんまり関係ないよ だいたいApacheだよ

ここまでのあらすじ

営業氏「プロジェクトのステージング環境をデモサイトとしても使用したい」

じゃあ外部にも公開しよう

ステージングサイトに無制限にアクセスされるとマズいから、Digest認証をかけましょう

そういえばDigest認証のページに対してTestcafeって動くのかな

401 Not Authorized/(^o^)\

TestcafeのAPIにhttp認証のAPIあるやんけ。使ったろ(https://devexpress.github.io/testcafe/documentation/test-api/http-authentication.html)

401 Not Authorized(Basic Authentication Only)\(^o^)/

あれ……コレは自動テスト化の夢が潰えるのでは……?←今ここ

そもそもなぜBasic認証できてDigest認証できないのか

調べてみたところ、UI上は同じだが、暗号化の方法が違うらしい。 また、それに伴ってHTTP Headerの中身もゴッソリ変わってしまう模様。 (http://dackdive.hateblo.jp/entry/2014/06/24/220557)

これに合わせてTestcafeを魔改造し、Digest認証に対応させるのも手だが、今後アップデートされた際に地獄を見るのは明らかなので、違う手を打ってみる。

結論

Digest認証が通らないのなら、Digest認証を外してしまえばいいじゃない。

というわけで、手の一つとしてBasic認証にしてしまう手があります。 とはいえ、暗号化方式としてはDigest認証の方が強固なため、やはりDigest認証の方を採用したいところ。

それなら特定の場所に絞ってDigest認証をかけてしまえばいいじゃない。 大枠の方針としては以下の通り。

  • 基本的には認証を持っていないユーザーはdenyする。
  • 特定のIP(弊社のグローバルIP)からのアクセスのみallowする。

これらの方針を、Apacheのコンフィグファイルを利用して実装します。

実装例

まずは通常のDigest認証のユーザーとパスワードを生成

cd /path/to/apache/bin
htdigest -c "/path/to/digest/config/file/<digest pass setting file name>" <Digest Auth Name> <User Name>

パスワードが要求されるので、認証に利用したいパスワードを入力します

New password:*******
Re-Type new password: *******

htdigestで設定した場所に、暗号化された認証ファイルが作成されます。

続いて、認証で守りたいフォルダを設定します。

httpd.conf

<Directory "/path/to/auth/folder">
    AuthType Digest
    AuthName "<Digest Auth Name>"
    AuthUserFile "/path/to/digest/config/file/<digest pass setting file name>"
    Require valid-user
</Directory>

また、Digest認証に利用するモジュールをロードするようにしておきます。

httpd.conf

LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
#LoadModule auth_digest_module modules/mod_auth_digest.so ←コメントを外す
#LoadModule authn_anon_module modules/mod_authn_anon.so
#LoadModule authn_dbm_module modules/mod_authn_dbm.so

ここまででDigest認証の準備は完了。 設定したユーザーIDとパスワードで認証がかかっているかどうかを確認します。

続いて、特定IPのホワイトリストを作るために、先ほど設定したDirectoryにプロパティを追加します。

httpd.conf

<Directory "/path/to/auth/folder">
    AuthType Digest
    AuthName "<Digest Auth Name>"
    AuthUserFile "/path/to/digest/config/file/<digest pass setting file name>"
    Require valid-user
    ## ----ここから下を追加---- ##
    Satisfy Any
    
    Order deny,allow
    deny from all
    Allow from <Test Client Global IP>
</Directory>

ホワイトリストには会社のIPとか入れておけばいいんじゃないでしょうか。 あとは他にテスト利用したい場所に向けてIPを順次解放していく形。

Tomcat併用環境だとダメだった

問題は以下のタグ部分

<Directory "/path/to/auth/folder">
  …
</Directory>

このディレクトリ指定に、tomcatwebapps/tmtと、www/htmlで検証してみました。 が、駄目。

直ファイルではTomcatの方を優先してしまうらしく、イイ感じにauth対象を取ってくれませんでした。 そのため、httpd.confを以下のように変更。

<Location />
    AuthType Digest
    AuthName "<Digest Auth Name>"
    AuthUserFile "/path/to/digest/config/file/<digest pass setting file name>"
    Require valid-user

    Satisfy Any
    
    Order deny,allow
    deny from all
    Allow from <Test Client Global IP>
</Location>

Locationでルートフォルダ指定により、すべてのアクセスをdenyすることで対策を取りました。 Apacheそんなに詳しくないので、マサカリはあるだろうなーと思ったけどとりあえず良さそうな動きしてるしこのままで

参考資料

https://www.adminweb.jp/apache/allow/index8.html http://kakikukeko.sakura.ne.jp/blog/allow-ip-or-digest-authentication-on-apache/

ブラウザの自動テストをTestcafeで回してみたら神がかっていたという話

対象読者

  • ブラウザでの自動テストの導入の糸口として、参考にしてみたい人
  • ブラウザの回帰テストが面倒な人。つまり俺

概要

Testcafeとは

node.jsのライブラリの一つ。 node.js内でブラウザを呼び出し、ブラウザの操作をシミュレートすることで、自動テストを可能にする。

詳しくは以下公式を参考。 https://github.com/DevExpress/testcafe

動きとしては、まずnode.jsでサーバーを立て、そのサーバーがクライアントのブラウザ本体を呼び出し、操作に介入するという動きを取っている。

Seleniumとの違い

SeleniumはWebDriverを利用してブラウザに介入するが、TestcafeはWebDriverを利用せずにブラウザを直で使い、動きをシミュレートしている。

つまりWebDriver不要。 その分テスト対象のブラウザをインストールする必要があるが、WebDriverを組み合わせて設定してごちゃごちゃやるよりは遥かに労力が低い。

独断と偏見が入り混じったメリット

  • Easy Start。導入からテスト実施までが本当に早い。
  • WebDriverに依存しないため、最新ブラウザの挙動だろうがなんだろうが構わず介入してくれる。
  • ES6だろうがESNextだろうが勝手にtestcafe内でテストコードをバベってくれる。神。
  • 呼び出し時の変数で、介入先となるブラウザを決定できる。GOD。

独断と偏見が入り混じったデメリット

  • ESNextの嵐。というかasync awaitを多用する。js初心者が下手にコードを書こうとすると死ぬ。
  • 一部の挙動が微妙。ダブルクリックがGoogle Chrome以外で効いていない気がする……。おそらくクリックの感覚が長すぎて、ダブルクリックとして判定されていない。

ぶっちゃけ今のところこれだけなので、JavaScriptに自信マンの人は積極的に使って損はないと思う。

実プロジェクトでの利用

フォルダ構成

# 実プロジェクトとはちょっと違うけど大体こんな感じ
│  .gitignore
│  .jshintrc
│  ConfigValidation.js
│  package.json
│  readme.md
│
├─config
│      default.json
│      TestConfig.js
│
├─TestComponents
│  ├─Guest
│  └─User
│      ├─LoginPage
│      │      LoginTest.js
│      │
│      └─MainPage
│              LogoutTest.js
│
└─UIDrivers
   ├─LoginPage
   │      DomId.js
   │      Selector.js
   │
   └─MainPage
           DomId.js
           Selector.js

config: node-configのデフォルトをそのまま使用。テスト実施時に環境を切り替えるために使う。 TestComponents: テストコードを格納するフォルダ。 UIDriver: テスト時に取得するDOM要素等を持ってきてくれるAdapterクラス諸々。htmlはしばしばDOMツリーが変わるので必須。 ConfigValidation.js: configファイルの書き洩らし等が無いかを検証してくれる。テストのためのテスト。 あとはnode.js書く時のお約束みたいなファイル諸々。

UIDriverは、FriendlyにおけるApplication Driver Patternを参考に作成。(http://www.codeer.co.jp/AutoTest/acceptance-test-design-consideration) Action相当となるクラスがないが、そう長いテストケースもないので、テストに直書きで対応。

npm script

global installしたくなかったので、npm scriptからtestcafeを呼び出す構成にしてある。

package.json

{
  "author": "俺",
  "name": "auto_test",
  "version": "1.0.0",
  "scripts": {
    "validate": "node ConfigValidation.js",
    "edge": "testcafe edge TestComponents/",
    "chrome": "testcafe chrome TestComponents/",
    "ie": "testcafe ie TestComponents/",
    "firefox": "testcafe firefox TestComponents/"
  },
  "description": "大体こんな感じ。nodeは6系で動作確認済み",
  "dependencies": {
    "config": "^1.25.1",
    "testcafe": "^0.13.0"
  },
  "devDependencies": {
    "colors": "^1.1.2",
    "date-utils": "^1.2.21"
  },
  "private": true
}

テストコードのルートフォルダを指定しておけば、再帰的にテストコードを見つけ出して実行してくれる。

npm run edgeとかで呼び出せば、Testcafeが勝手にブラウザを立ち上げて操作し、テスト結果を出力してくれる。

効果のほどは?

劇的にテスト速度が向上したというわけでもないが、回帰テストが楽になったのは確か。 開発者が実装段階で実装失敗に気づきやすくなり、早め早めのバグ対策が打てるようになると思われる。

テストコード意味わからないんだけど

公式ドキュメンテーションが一番充実した内容が乗っている。 ActionsとSelectorあたりを見ながら進めるだけでも十分理解可能。 http://devexpress.github.io/testcafe/documentation/

aglio使ってAPIドキュメント書いたら捗った話と、書いててハマったところのまとめ

aglioとは

既定の書き方で書かれたマークダウンファイルを、 良い感じのAPIドキュメントに仕上げてくれるnodeのパッケージ。

aglioの記法

API Blueprint という規格に従って、mdファイルを書く。 https://apiblueprint.org/

実際にやったプロジェクト内での実装

aglioを直呼びするのは面倒かつ、いちいちaglioをインストールしてもらうのも面倒なので、gulpからaglioを呼んで、対象となるmdファイルをすべてまとめてhtml化している。

gulp.task('docs', () => {
  gulp.src(['src/*.md'])                  //1. srcフォルダ内のすべてのmdファイルを
    .pipe(concat('all_ref.md'))           //2. all_ref.mdに結合させて、
    .pipe(aglio({ template: 'default' })) //3. aglioに食わせてhtml化させて、
    .pipe(gulp.dest('docs'));             //4. docsフォルダ内にhtmlとして出力する
});

そもnodeをインストールするのが面倒という部分もなきにしもあらずですが、結局プロジェクト本体でnodeを使ってるしいいかな、という感じでガンガン使ってます。

実際に生成する

前提として、node.jsとgitのインストールを済ませているPCで行うこととします。

# console

> cd path/to/apidoc/root
> git clone https://hogehoge/fugafuga/git/repository.git
> npm install
> gulp docs

関連リンク

http://dev.classmethod.jp/server-side/api-document-with-api-blueprint/

書いててハマったところ

階層を構成する空白

mdファイルでの階層を作るための文頭に置く空白文字は、半角スペース4つでないとaglioに食わせてもいい感じにhtml化してくれない模様。

#### 処理概要
* hogeの一覧を取得する。

+ Response 200 (application/json)
    * adm_divs内にはすべてのProvinceオブジェクトが格納される。 //←文頭はスペース4つ
    ```js
    {
        hoge_code   : {string} - hogeのコード。数字によって構成される。
        hoge_name   : {string} - hogeの名称。
    }
    ```

ResponseのAttribute記述時、array内のobjectに対し、説明文がつかない。

+ Response 200 (application/json)
    ```js
    {
        hoge_code    : {string} - hogeのコード。2桁の数字によって構成される。
        fuga_code    : {string} - fugaのコード。2桁の数字によって構成される。
        piyo_code    : {string} - piyoのコード。2桁の数字によって構成される。
        hoge_name    : {string} - hogeの名称。
        fuga_name    : {string} - fugaの名称。
        piyo_name    : {string} - piyoの名称。
    }
    ```
    + Attributes
        + fugas (array, required)
            + (object)
                + hoge_code : 01 (string) - こういう風に半角ダッシュ以降に説明文を書くと
                + fuga_code : 02 (string) - 良い感じにhtml化してくれそうだが、
                + piyo_code : 03 (string) - 実際には半角ダッシュ以降の説明文はhtmlには記載されない。
                + hoge_name : hoge name (string) - そのため、苦肉の策として、
                + fuga_name : fuga name(string) - Attribute以前に内部オブジェクトの情報を
                + piyo_name : piyo name(string) - コードブロックとして記述するようにしている。
            + (object)
                + hoge_code  : 01 (string)
                + fuga_code  : 02 (string)
                + piyo_code  : 03 (string)
                + hoge_name  : hoge name(string)
                + fuga_name  : fuga_name (string)
                + piyo_name  : piyo_name(string)

泥の中の足跡を探して(世界樹の不思議なダンジョン2・表クリア記事)

とりあえずは

セカダン2、第八迷宮までクリアしました。

セカダン1から思ってたことなんですけど、下手に仲間増やしていくよりも一人で突っ込んでガンガンレベル上げてパッシブとアイテムでゴリ押す方がサクッと行けるかつ安定しますね。
というわけで、ケンカク一人旅で進んでたんですが、特に何の苦労もなくラスボスを叩き殺して終了です。

葉っぱしゃぶって粉吸って剣で殴れば相手は死ぬねん。

というわけで、以下ゲーム的な感想とストーリー的な感想。表クリアまでのネタバレを含みます。

PC能力ハイパーインフレ型ダンジョンゲーム

やってて一番感じたのはコレです。

パッシブ・アクティブ共に強力過ぎるスキルが多すぎて、スキル適当に振ってぶっぱしてるだけでザクザク敵が死んでいく。
サブクラスシステムも相まって、結構簡単に強力なスキルビルドが達成できるので、ダンジョンシリーズに不慣れな人間でもわりと楽にクリアまで持っていけるようなバランス。
不思議なダンジョンというプレイヤー能力の上昇がクリアに直結するゲームスタイルと相反してはいるような気はしますが、世界樹というキャラクター能力・スキル構成に楽しみを見出すゲームとしては順当という感じ。
そういう意味では、「世界樹の不思議なダンジョン」というゲームとしての終着点には到達しちゃったのかなー、という気がしています。

レベル1ダンジョンに関しては、そのPC性能を組み込んだうえでのバランス調整という感じ。
インフレにインフレがどんどん重なって非常に楽しい。特に一階で死霊の騎士とばったりしたときなど射精するほど気持ちがいい。
ダンジョンゲーとして、初心者に勧めやすく、スキルビルドやPT構成でいくらでも縛れる分、上級者に対しても楽しみを提供してくれる点が良ポイントだと思います。

鍛冶・武器強化に関しても、世界樹のシステムを組み込んだがゆえにイカれた武器ビルドがサクっとできるので、やはり難易度はそこまで高くない印象。三方向攻撃や確定会心はありませんが、その辺は操作可能パーティや攻撃スキルで十分代用できるので、そこは解放なくてよかったと思います。キャラスキルも死ぬしね。

というわけで、個人的にダンジョン系ゲームとしてはすっごい好感度高いです。
世界樹としては、キャラビルド面に関しては色々触れたので満足。D.O.Eを前にした時の一手一手を考える感覚もダンジョンRPGの緊迫感と重なって楽しかったです。
D.O.Eや仲間AIに関しては、前作通りめんどくせえなあと思う部分は多いものの、圧倒的パワーでその辺の要素をなぎ倒していけるので、そうそうストレスにはならないなあ、という感じでした。
なおIQは下がる模様。力こそパワー。俺の脳は筋肉で俺の全身も筋肉だ。つまり俺はお前よりかしこい。

とは言えテキストは

なんすかこれ(辛辣)

全体的に土の匂いがしないというか、そこにいるキャラクターのセリフがいちいちシステム的なのもあり、その地に生きる人間の匂いがそんなにしなかったのが個人的マイナスポイントでした。
ダンジョンというゲームシステムを動かすうえでそういった「そこに生きる人間」が存在するのは邪魔だったのかもしれないですが、個人的に世界樹に求めているのがそういった「地に足の着いたファンタジー」である身としては、「えぇ……」と思う点がいくつかありました。

個人的に一番マイナスなのは妖魔とか精霊周りとか。ナディカの正体も妖魔や精霊周りの設定も、出すための整合性があり、出しても構わない舞台があり、出すこと自体は特に鼻につかなかったのですが、そのあたりをラストクリアした後に「実は〇〇だったのだー!」とおまけの様にネタバラシするのはRPGのフレーバーとしてどうなんだ。というカンジ。いや第八の中盤あたりのテキストでいきなり出てくるのはいいけど、こう、そうするならもっと精霊組の深掘りをメインでですね……。

サブキャラクターはサブキャラクターなりの、今まで歩んだ道しるべを示してくれないと、ぽっと出で出てきて「お前を助けるぞ!」と少年漫画の最終回で終結されても「は?お前なんやねん」という感想を抱いてしまうというか……。せっかくのサブダンジョンクエストがあるので、その辺でフレーバーあったらもっと感情移入しながら最終戦やれたのかな、と思います。

でも振り向いたナディカの一枚絵は白黒目反転大好きマンとしてはカワイイポイントでした。あのままゲストキャラとして加入してほしい。

これから

ひとまずは表クリアしたのでゆっくりレベル1ダンジョン進もうと思います。あのダンジョンガチャ感、チョコボで延々とダンジョン潜りしていたときの気持ちを思い出して気持ちいい。

あと、裏ダンジョンで設定周りとかキャラ深掘りとか出たらストーリー面に関して手のひら大回転かますと思います。さてどうなるか。どっとはらい