わたねこコーリング

野良プログラマ発、日々のアウトプット

DNS ゾーンレコード変更を監視して音声でお知らせ

最近ブログ書いてないので小ネタも山の賑わい的な。

当方では自分のドメインバリュードメインさんで管理しているのですが、コンパネからゾーン情報を編集しても DNS サーバに反映されるまで5〜30分程(公称)かかるんですよね。「変わったかな?」と数分毎に dig を叩くのも面倒なので、10秒おきにチェックして音声で知らせるワンライナーを書きました(Mac 限定)。

以下は、TXT レコードの一部を hogehoge を含む内容に書き換えた際、プライマリネームサーバをチェックして変更が反映されたらお知らせする例です。ご利用にあたっては <> 内を書き換えて下さい。

while :; do date ; dig @<プライマリネームサーバ> -t TXT <当該レコードのドメイン> | grep hogehoge && say "やったー、変わりましたよ!" ; sleep 10 ; done

これでお知らせが来たら、あとは設定してある TTL だけ待てば第三者からの名前解決にも「浸透」を期待できるという訳ですな。

※音声出力がマクの say コマンドなので、他プラットフォームの場合はその辺を適宜アレンジして下さい。

手元の phpMyAdmin からリモートホストのデータベースを SSH トンネル経由で操作する

ウェブ開発では、かつては MySQL サーバを立てたら次は同サーバ内か同一 LAN 内に phpMyAdmin のセットアップをというのが定石でしたが、コンテナ時代の今では phpMyAdmin もデスクトップアプリと同様の手軽さで利用できるようになりますた。という訳で、手元の開発用マシンで phpMyAdmin を Docker コンテナで起動して、リモートホストMySQL サーバに SSH ポートフォワード経由で繋いでしまおうという小ネタです。

まず、DB を立ててあるリモートホスト foo@bar.net との間にトンネルを掘ります。トンネルの入り口は localhost じゃなくて Docker コンテナ内から接続できるようにホストマシンのローカル IP (例では 192.168.12.34)にしておくのがミソ。

ssh foo@bar.net -N -L 192.168.12.34:3306:localhost:3306

phpMyAdmin純正イメージを使って、コンテナを起動します。環境変数 PMA_HOST で DB サーバアドレスを指定できます。

docker run --rm --name pma -d -e PMA_HOST=192.168.12.34 -p 8080:80 phpmyadmin/phpmyadmin

あとは http://localhost:8080/ から phpMyAdmin 使い放題、と。

受注開発で DB は用意されていても必ずしも phpMyAdmin が使えるとは限らない等、割とよくあるユースケースじゃないかと思うのですが、不思議にネットでソリューションが見つからなかったので書いてみました。

既存 RDB 用の GraphQL API サーバを Apollo Server + TypeORM で書いてみた

コロナ巣篭もりを良い機会にという訳でもないですが、ここひと月程 GraphQL について学習してました。が、書籍でもネット記事でもデータベースを含めた新規開発なストーリー(データストレージはたいてい NoSQL タイプ)が殆どで、「既存の RDB データベースの為に API サーバを立てる」という(少なくとも自分には)とても良くありそうなユースケースが無かったので、簡単な CRUD が出来るプログラムを書いてみました。これです↓。

github.com

既存 RDB前回記事で紹介した world database を採用。動作までの手順は以下の通りです。

  1. world database をセットアップ(前回記事紹介の Docker イメージを使えば簡単)。
  2. cp ormconfig.json.sample ormconfig.json して、上記 DB の諸元を記入。
  3. npm install
  4. npm start

http://localhost:4000/graphql から Apollo Server ビルトインの PlayGround で API を試せます。こんな感じ↓です。

f:id:mariyudu:20200505175459p:plain

プログラミングの参考にしたのは下記の書籍とネット記事です。

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

medium.com

既存 DB 用に TypeORM エンティティをガリガリ書くのはしんどいなぁと思ってたら typeorm-model-generator という便利なものがあったので、これで生成後に調整する、という手順がラクラクでした。

TypeORM は触り始めたばかりで未だよく分かっておらず、特に更新時のリレーションについては GraphQL なスキーマの枠組みの中でどのように実装したら良いのか未だ答えが出ていないので、現状では手つかずです。誰か良いやりかたをご存知でしたら教えて下さい。

データ入りの演習用 MySQL DB を1分で用意する

プログラマやってると、ミドルウェアフレームワーク等を検証したり、チュートリアルを試してみるということは日常的にあるあるな訳ですが、そんな時にゃテンポラリな演習用 DB がちょくちょく必要になりますよね。今回はそんな煩わしい作業を超スピードで片付けよう、という話です(MySQL 限定ですが)。

データの入ったボイラープレート的な DB って誰か作って無いかなーと探してたら、MySQL サイトにちゃんと情報が↓。

f:id:mariyudu:20200427185453p:plain

5種類の DB が紹介されているのですが、今回は「world database」と「employee data」を利用させてもらいます。データが提供されているとは言え、これを手作業でちまちま流し込んでたんじゃ全然時短にならないので、構築済 DB の Docker コンテナでも作るかぁ、と思ったら… もうありましたw やっぱり皆考えることは同じ。では、DB 毎に利用できるようなるまでの手順を。

World Database

世界の都市と利用言語を格納したシンプルな DB です。内容説明とコンテナ提供元はこちら↓。

dev.mysql.com

hub.docker.com

コンテナ生成はこんな感じです↓。

$ docker run -it --name mysql-example-world -e BIND-ADDRESS=0.0.0.0 -p 3306:3306 -e TZ=Asia/Tokyo -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d kakakakakku/mysql-world-database

ホスト側から DB 接続してみます↓。

$ mysql -h 127.0.0.1 -u root world
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.24    |
+-----------+
1 row in set (0.00 sec)

mysql> SHOW TABLES;
+-----------------+
| Tables_in_world |
+-----------------+
| city            |
| country         |
| countrylanguage |
+-----------------+
3 rows in set (0.00 sec)

イイ感じですね。city テーブルには4079件の、country テーブルには239件のレコードが格納されています。ちなみに、下記が ERAlchemy で生成したこの DB の ER 図です。
f:id:mariyudu:20200426165506p:plain

Employee Data

架空の従業員データベースです。テーブル数は8で、中心となる社員テーブル employees には300,024件のレコードと、かなり本格的な内容です。内容説明とコンテナ提供元はこちら↓。

dev.mysql.com

hub.docker.com

コンテナ生成します↓。

$ docker run -it --name mysql-example-employee -e BIND-ADDRESS=0.0.0.0 -p 3306:3306 -e TZ=Asia/Tokyo -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d harrymartland/employees-practice-mysql

ホスト側から DB 接続します↓。

$ mysql -h127.0.0.1 -utest_user -ptest_password employees
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.1-dmr |
+-----------+
1 row in set (0.00 sec)

mysql> SHOW TABLES;
+----------------------+
| Tables_in_employees  |
+----------------------+
| current_dept_emp     |
| departments          |
| dept_emp             |
| dept_emp_latest_date |
| dept_manager         |
| employees            |
| salaries             |
| titles               |
+----------------------+
8 rows in set (0.01 sec)

これだけの規模だとスケールを意識した作業が出来るのでイイですねー。

以上です。出来合いの接続アカウントを変えたい場合は適宜

GRANT ALL ON yourdb.* TO yourname@'172.17.0.1' IDENTIFIED BY 'yourpassword';

等とすれば良いかと。他3件のデータベースも同じ要領でコンテナ化出来ると思うので、どんどん活用していきましょー。

AWS DcoumentDB クラスタに SSH トンネル越しで Node.js プログラムから接続する

小ネタですが表題件、地味にハマったので備忘録として。

下記情報を元に、VPC 外(つまりおうち or 職場のパソコン)で開発中の Node.js プログラムから DocumentDB に接続しようとしたらタイムアウトでなかなか接続できませんですた。

docs.aws.amazon.com

docs.aws.amazon.com

あれこれトライ&エラーを繰り返して、ようやく動作するようになったのが下記コード。

var MongoClient = require('mongodb').MongoClient,
  f = require('util').format,
  fs = require('fs');

//Specify the Amazon DocumentDB cert
var ca = [fs.readFileSync("/somewhere/over/the/rainbow/rds-combined-ca-bundle.pem")];

//Create a MongoDB client, open a connection to Amazon DocumentDB as a replica set, 
//  and specify the read preference as secondary preferred
var client = MongoClient.connect(
'mongodb://<sample-user>:<password>@localhost:27017/?ssl=true', 
{
  useUnifiedTopology: true,
  sslValidate: false,
  sslCA:ca,
  useNewUrlParser: true
},
function(err, client) {
    if(err)
        throw err;
        
    //Specify the database to be used
    db = client.db('sample-database');
    
    //Specify the collection to be used
    col = db.collection('sample-collection');

    //Insert a single document
    col.insertOne({'hello':'Amazon DocumentDB'}, function(err, result){
      //Find the document that was previously written
      col.findOne({'hello':'Amazon DocumentDB'}, function(err, result){
        //Print the result to the screen
        console.log(result);
        
        //Close the connection
        client.close()
      });
   });
});

キモは、MongoClient.connect() に渡す URL とオプションでした(↓)。AWS サンプルコードとの差分はこちら http://mergely.com/TXE4OQbw/ を。

  • URL のパラメータは、DocumentDB コンソールで提供されるものに含まれている ssl_ca_certs やら replicaSet 等は一切取っ払って、ssl=true だけにする。
  • オプションの sslValidate は false に(mongo shell オプションの sslAllowInvalidHostnames に相当するっぽい)。
  • useUnifiedTopology も付与すると吉(将来の設計変更に関するワーニングを抑止できる)。

以上。尚、諸元は以下のとおりです。

  • DocumentDB エンジンバージョン docdb 3.6.0
  • Node.js v12.16.0
  • MonboDB Node.js driver v3.5.6

バンジョーギタレレ買ったのでレポートしてみる

皆さん、引き籠もり生活エンジョイできてますか? 先頃、バンジョーギタレレというヘンな楽器をポチッてしまったので、評価レポートしてみます。こいつです↓。

テナーバンジョー奏者の CD を聴いてたら楽器も欲しくなってしまい、アマゾンをウロウロしてて偶然みつけたものです。要はテナーウクレレサイズなギター(所謂ギタレレ)のバンジョー版なのですが、これはありそうでなかなか見た事が無かったので「珍楽器は一期一会」の掟に従ってポチりました。お値段もリーズナブルですしね。

製造元は、中国の Beijing Palace Musical Instrument (北京王宮楽器?)という会社の Musoo というブランドです。製品ラインナップを見るとなかなか多彩。ギブソンフェンダー、オベイション、テイラー、コールクラークと様々な有名ブランドの意匠がマッシュアップ(笑)された、昔のジャンプ裏表紙広告な感じですなw

ポチったのが先月中頃なので、こういう時期だから時間がかかりそうだなーと思ってたらこんな箱(↓)が10日足らずで届いたので、ちょっと驚きでした。

f:id:mariyudu:20200412164437j:plain

早速取り出して上から下までチェキラウト! ちなみにケースは付いていません。

ヘッドのデザインは他の製品群には無い、波型が付いたギターヘッド型なんだけど、プロトタイプ的な製品なのかな? バイオリンベースで有名なホフナーを連想させるので、ビーオタとして無意味に嬉しいですw ブランド刻印が無いのは潔いですねw

f:id:mariyudu:20200412164834j:plain

ペグはグローヴァーっぽい形のノンブランドもの。ビンボー症なので保護の白いビニールも貼ったままw 調弦してみて特に不都合はありませんでした。

f:id:mariyudu:20200412164952j:plain

アマゾンの商品説明にはナイロン弦とありましたが、実際はブロンズ弦(たぶんミディアムクラス)が張ってあり、ナット溝もスティール弦仕様でした。

f:id:mariyudu:20200412165045j:plain
バンジョーギタレレ - ナット

ナットからブリッジまでの弦長は約420mmで、通常のギタレレより少し短め。指板・フレットもやはりスティール弦仕様でアールが付いてます。

f:id:mariyudu:20200412165206j:plain
f:id:mariyudu:20200412165228j:plain

ドラムヘッドはちゃんと REMO なのでお値段の割に頑張ってる感じ。光沢有りタイプです。弦のテンションが強すぎるのか、ブリッジの所でスキンがけっこう凹んでしまってるのがちょっと心配。

f:id:mariyudu:20200412165259j:plain

ボディはサペリ合板だそうで、昨今のエントリー〜ミドルクラスの楽器ではポピュラーらしいです。裏板も省略されずに貼ってあるのですが、ここは樹脂かな? バンジョーなので材による鳴りの良し悪しまではよく分からないのですが、普通に良いと思いました。

f:id:mariyudu:20200412165549j:plain

テールピースはご覧のように、弦のループエンド(えっ?ww)をボディの金具に引っ掛けてあります。これって弦交換めんどくせー! 多分ボールエンドな弦をテールピースに通すだけでも大丈夫だと思うので、次の交換でやってみようっと。

f:id:mariyudu:20200412165634j:plain

さて、弾いてみました(↓)。4・5弦がビビり気味なのが不満ですね(どこでビビってんだろ…)。音程はまぁまぁ(低音弦はちょっと甘いかな)で、爪や指頭での指弾きはどうもパンチに欠けるというか、ピックを使った方が実用的な音になる印象です。もともとテナーバンジョー代替という感じでフラットピック弾きを想定してたので、自分的にはオッケーです。貼ってあるブロンズ弦はちょっとキツ過ぎな気がするので、次はニッケル弦で試してみようと思ってます。

この投稿をInstagramで見る

バンジョーギタレレ買ったので弾いてみた

Akihiro Takioto(@mariyudu)がシェアした投稿 -

という訳で、中華製バンジョー・ギタレレのレポートでした。引き籠もり生活はまだ暫く続きそうなので、連休頃までに1曲仕込んでつべ公開しようと思います。皆様も元気に明るく、サバイブしていきましょうねー。

lightweight-charts でローソク足チャートをサクサク生成

以前、TechanJS というフィナンシャルチャート作画ライブラリの紹介をしましたが、今日はまた別のチャート作画ライブラリ↓の紹介を。

github.com

上記にあるように lightweight-charts は、トレーダー向けに各種ツールを提供している TradingView さんが OSS として公開しているものです。流石にその筋のプロが作ったというべきか、軽量・コンパクトながらツボを押さえた機能設計がなされていて、使いやすい印象を持ちました。ドキュメント類はリファレンスが見つからなかったのですが、サンプル利用ガイドを読みながら見様見真似で、何とか欲しかった機能が実現できました。CodePen に日経平均データを使ったサンプルを置いたので、どうぞ↓。


See the Pen
lightweight-charts でお手軽ローソク足チャート作画
by まりゆどぅ (@Mariyudu)
on CodePen.

そもそもの発端は、ある条件でスクリーニングした銘柄の値動きを一定期間ウォッチする環境を作ろう、というものでした。さらには、過去のデータを使って値動きを予想する訓練にも使いたいので、指定日付以降の日足はグラフ表示させずに一日単位でスクロール表示させたいな、と。TechanJS でももちろん実現出来ますが、lightweight-charts のほうが少ないコード量で書けました。よく出来たライブラリなので、もっとユーザが増えるといいですねー。