Logical Rabbit.

さくらのVPS

Vagrant+Ansible+VirsualBox on CentOS。

CentOS 7.5上でVagrantとAnsibleを使ってVirsualBoxを操作しようとしたら環境設定に色々ハマった記録。バグトラップな上にグーグル先生が的確な情報出してくれない!!

問題山積み

  1. VirsualBoxのインストールで失敗する (modprobe vboxdrv が云々)
    • secure bootの影響で、署名がないモジュールをロードできないのが原因。署名すればよい。
  2. だがしかし、署名に使った公開鍵がenrollできない
    • mokutilのバグ。1つ前のバージョンに戻す。
  3. Mac OS X用のVagrantfileとCentOS(Linux)用のVagrantfileではansible providerの名前が異なる
  4. なんかVagrantfileからは実行できないのに、ansible-playbookでは実行できるんですが… (これは秘密鍵のパスとか、そういう問題かも)
  5. NFSマウントが失敗する
    • firewalldがお仕事してた。vboxnet0をtrusted zoneへ叩き込む(いいのかそれで?)
  6. "CentOS VirtualBox Vagrant"とかでググると「Vagrantで(WIndowsの)VirtualBoxにCentOSを入れようず」いう話ばかりが出てくるんですよね…。しかし他に適当なキーワードもなく。

各々の対策記録

VirsualBoxのインストールで失敗する

CentOSのおそらく7.4以降~バグ修正版が出るまでは、先に「署名に使った公開鍵がenrollできない」を読んでください。二度手間になります。

RedHatの 26.8. セキュアブート用のカーネルモジュールの署名 が日本語ですし、「何をやっているのか」まで分かってよいです。

単にやるべきことを知りたいだけならば Signing VirtualBox & VMware modules 等があります。 なお、CN=以降はcommon nameを入れるところなので各自考えて置き換えることになります。

例に出ているのは「vboxdrv」だけなのですが、実際は同じディレクトリ内の全ファイルに署名しないとダメでした(全ファイル必要なのかは組み合わせテストが面倒なので確認していません)。

modinfo -n vboxdrv でこのモジュールファイルのフルパスが出てくるので、そこでパス名から必要なファイルを見つけてください。ちょっとイイ感じにやりたければ ls $(dirname $(modinfo -n vboxdrv) )/* |xargs -l1とかすればイケるんじゃないかとは思う。

署名に使った公開鍵がenrollできない

問題は、上記でモジュールに署名したあと、その公開鍵を mokutil へ登録した後で、再起動するとUEFI コンソールで mokutil にセットしたパスワードを聞かれ、パスすれば以後は公開鍵がOSへ永続登録される、という部分です。何度再起動してもそんな画面出てこないのです…っ

原因は、最新版の mokutil にバグがあり、肝心のUEFIコンソールが起動しないとのこと。 以下にその説明があります。

0014050: Failed to Enter Shim UEFI key management screen while rebooting on CentOS7 if upgrade to 7-4.1708

元々問題に気付いたのはこのあたりの記事。 "The uefi secure boot bug" の文言を読んだ時の脱力感がハンパない。

Red Hat Bugzilla – Bug 1477735 Shim was unable to measure state into the TPM

対策ですが、バグのない1つ前の mokutil はCentOSの場合7.3にあります。 http://vault.centos.org/7.3.1611/os/x86_64/Packages/ から mokutilshim のRPMをダウンロードして、最新版を yum remove で削除後にインストールします。

成功すれば、ブート時にきっちり止まりますので確実に分かります。

この作業前に mokutil へ鍵を登録したりパスワードをセットしていた場合、その作業からやり直しになるので注意してください。

Mac OS X用とCentOS(Linux)用とのVagrantfile差異

一覧に書いた通りです。Mac OS X 用は ansible 。CentOS用は ansible_local 。このあからさまな違いから見て、CentOS用は何か使い方を変えると ansible になるのかもしれませんが。

参考記事は以下。

Ansible Local Provisioner

NFSマウントが失敗する

原因がわからないときは、 vagrant ssh でゲストOSに入ったのち、おそらく画面に表示されているであろうコマンド( mount -o vers=3,udp <ホスト側IP>:<ホスト側Path> /vagrant 等)を実行してみるのがよいです。この際、mount コマンドに --verbose を追加することで、ある程度情報が増えます。

私のケースの場合 mount.nfs: portmap query failed: RPC: Unable to receive - No route to host が出ていたので、これは経路が切れてるな…と考えた次第。その後sshでゲスト→ホスト接続を試してみて、接続できたのでfirewallかな、と。

  1. firewall-cmd --add-interface vboxnet0 --zone=trusted
  2. firewall-cmd --list-all --zone=trusted (確認)
trusted (active)
  target: ACCEPT
  icmp-block-inversion: no
  interfaces: vboxnet0
  sources: 
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

のような結果になればOK。

gulp-gh-pagesを使おうとしてハマったメモ(おそらく今だけの一過性)。

発端

gulp-gh-pages を使おうとしたら、以下のような謎のエラー。

node_modules/gulp-gh-pages/node_modules/gift/lib/commit.js:145
      ref1 = /^.+? (.*) (\d+) .*$/.exec(line), m = ref1[0], actor = ref1[1], epoch = ref1[2];
                                                       ^

TypeError: Cannot read property '0' of null

エラー箇所のコードを読むと、gitのcommitログ解析でおかしくなっているように見えるのだけど、なんでcommitログの正規表現処理なんてやっているのかが不明だにゃー、と。

原因

ググると以下のページが見つかったので、取り敢えず gulp-gh-pages-will ではなくて手動で何とかする方法をとってみた。

gulpの「gulp-gh-pages」がエラー履くようになったときの対応

記事内の解説、およびgiftのissueとかを読んでみると、giftの過去バージョンに起因する問題で、gift自体では問題解決済みの版が出ている。しかし、gulp-gh-pagesのpackage.jsonが古いままなので、gulp-gh-pagesとしては問題解決できていない、ということらしい。

どうも gulp-gh-pages 本家もGitHub上では次バージョンのタグが出ていて、最新のpackage.jsonではgiftも最新版使うようになっているので、近々根本的な解決があることを期待したいところ。

なお、gulp-gh-pagesをGitHub版で使えばいいよね、と思ってやってみたところ、今度は gulp-gh-pages が依存する gulp に未リリース・GitHub版を要求され、仕方ないので gulp もGitHub版にしてみたところ、新たな謎エラーが出てしまったというオチがつきましたとさ。

解決手順

  1. "gift": "^0.10.2" を package.json に追記
  2. npm install 実行後、rm -rf node_modules/gulp-gh-pages/node_modules/gift として gulp-gh-pagesのインストール結果内giftを削除(こうしないと v0.10.2 のほうを使ってくれない)

Amazon Product Advertising APIについての備忘録。

JavaScriptベースで一通りつついてみたので、実装方法の備忘録。秘密鍵扱うので、クライアントサイドJavaScriptはNGですな。基本的にはプログラミングガイド読めば分かるものです。コーディングはお仕事しますよ? 的な。

必要なもの

アクセスキーID:
Amazonアソシエイト・セントラル →ツール →Product Advertising API で取得可能
秘密キー:
Amazonアソシエイト・セントラル →ツール →Product Advertising API で取得可能(認証情報生成時のみ表示されるようなので注意)
アソシエイトID:
Amazonアソシエイト・セントラルの右肩に出てるアレです

実装上のポイント

一先ず、ASINで指定した特定商品の情報取得を試しました。

  • エンドポイントは固定。シグネチャ生成時にhostとpathに分割することになります。
  • クエリは文字コード順でソートすることになるので、& で連結せずに扱ったほうが良さ気でした。ソートはArray.sort()のアルゴリズムで問題ない筈。
  • 各所の値はencodeURIComponent()でエンコード。
  • TimestampはISO形式の日付+時間ですが、ミリ秒以下があるとエラーになりますので(new Date()).toISOString()は使用できません。
  • シグネチャはbase64 エンコードの HMAC_SHA256です。Node.jsの場合 crypto.createHmac()が使用可能です。

うっかりハマる点として、各所に出てくるサンプルでのエンドポイントがアメリカ版ですが、日本のAmazonでアカウント登録している場合は日本のエンドポイントを使う必要があります。

処理の流れ

  1. タイムスタンプを生成します。UTC~メソッド群を使用して、ミリ秒を含まないISO形式の日付を生成。getUTCMonth()が0~11を返すことと、1桁の値は右側に0が必要になることに注意
  2. クエリを項目ごとに分割・格納したArrayを組み立てます →query

    AWSAccessKeyId
    アクセスキーID
    AssociateTag
    アソシエイトID
    Operation
    ItemLookup (今回は商品情報取得なので)
    ItemId
    ASIN
    Timestamp
    タイムスタンプ
  3. エンドポイントURLをバラします。Node.jsの場合url.parse()でパースして、hostとpathを使用します。
  4. クエリをソートし、&で連結しておきます。 →sorted_query
  5. 'GET', エンドポイントのhost, エンドポイントのpath, sorted_queryを\nで連結し、crypto.createHmac()で処理した後digest('base64')でBASE64形式で取り出し、更にencodeURIComponent()でエンコードします。 →signature
  6. エンドポイント + ? + sorted_query(queryでもいい筈) + & + signature にアクセスします。後はレスポンスを適宜調理。

リクエスト制限は「1秒に1回」とされているのですが、試行しているときにコード修正で明らかに数秒以上経過してても制限にかかってエラーになったので、もう少し余裕持ったほうが良さそう。

ところでPAAPIってやっぱり「パァイ」って読めばいいんですかね。

Vue.js+<input type="date">+初期値new Date()の場合

data() で初期値を定めるとき、new Date()の値をyyyy-mm-ddにしてやれば万事解決。←結論

細かく解説すると。

  • Vue.jsではコンポーネントの data() で初期値セットを返す
  • <input type="date" > はvalueとしてISO形式(yyyy-mm-dd)を与えないと初期状態として日付を表示してくれない(値があっても "yyyy/mm/dd" というユーザに大変お優しい表示となってしまう)
  • <input type="date" > に new Date() の値をそのままセットしても上記理由によりまともに表示してくれない

解決パターン。

Google Shortener(Google短縮URL) API。

Google Shortener APIで短縮URLを生成する処理をちょっと試してみたのでメモ的に残しておく。

  • APIキーは各自Googleアカウントで発行すること
  • fieldsクエリは全部乗せになってます
  • 正常に実行できると、アラートダイアログで結果が表示されます
  • エラー処理? なにそれおいしい?
$(function() {
  var apikey = <各自APIキーを入力>;
  var url = 'https://twitter.com/mami_tuchino'; /* これが短縮したいURL */
  $.post({
    url: 'https://www.googleapis.com/urlshortener/v1/url?fields=analytics%2Ccreated%2Cid%2Ckind%2ClongUrl%2Cstatus&key=' + apikey,
    data: JSON.stringify({ longUrl: url }),
    dataType: 'JSON',
    contentType: 'application/json',
    success: function(json) { alert(json.id); },
    error: function(error) { console.logt(error); }
  });
});
 

電源タップのホルダー ELH-01Hが便利だった。

別売りのELPAの電源タップを取り付けて、複数の方法で固定可能なタップホルダー。

4種類の方法で固定可能です(互いの位置関係が合えば複数の方法で固定も可能)。

  1. フックで吊り下げ
  2. マグネットで鉄板に貼り付け
  3. バンドを巻きつけて固定
  4. 木ネジで固定

適合タップに制限があるので、そこだけは注意。また、ホルダーと言ってもがっちり固定ではなく、片手で外せる程度の強度です。何かがぶつかるとホルダーから外れてしまう程度。

Rubyコードでパスワードを簡易生成したいとき。

ググってみると、大抵以下のようなコードが多数見つかる。

ruby -e 'p [*1..9, *"a".."z", *"A".."Z"].sample(8).join'

これ、

ruby -e 'p [*"!".."z"].sample(8).join'

でいいんぢゃねぇです? 文字コード的に半角スペース, "!" , …数字…大文字アルファベット…小文字アルファベット、と続くので。まあパスワードに半角スペース入れると入力が厄介なことになりそうだからその次の "!" から始めるとして。

あ、でも " とか ' とか ` あたりもパスワードに含めると扱いがアレ気になりそうだから、

ruby -e 'p [*"!".."z"].reject {|c| %w"\" '"'"' \`".include? c }.sample(8).join'

くらいで、どうですかね?

地図情報サービスAPIについてのまとめ (2017年版)

地図を表示したり、地図上のあれこれを検索したりする用途のAPIについて、使用条件などをまとめました。なお、2017年6月23日現在の状況ですので今後変わる可能性があります。利用規約等は最新版を確認のうえ、各人の判断にてご利用ください。解釈ミス、情報のもれについて当方は責任を負いません。

サービス名 提供される内容(概略) 利用制限 商用利用 クレジット表記
Google

https://developers.google.com/maps/documentation/api-picker?hl=ja

  • 位置の移動、拡大縮小など基本的な操作が可能な地図の表示
  • スマートフォン向けアプリケーション用API
  • プレイス(=概ね場所と解釈)、ユーザーのクチコミなどの検索
  • ジオコーディング、リバースジオコーディング
  • 複数点の緯度経度を指定して移動方法に基づいた距離、移動時間を計算(みちのりベースで計算)
  • 標高、経路
  • 機能としては未確認ですがたぶん気象情報取得、郵便番号検索あたりは可能と思います。店舗名名寄せはプレイス オートコンプリートで出来そう。
  • Google Street View

https://developers.google.com/maps/pricing-and-plans/?hl=ja

Google Maps Android API、Google Maps SDK for iOSについては制限なし。ただし「標準プランの利用規約で許可されている」との表記があるので、こちらも要確認。

Google Maps Embed APIについては無制限の無料利用。

地図表示については「1 日あたり最大 25,000 回のマップロードが無料」、Google Places API Web Serviceは「1 日あたり 150,000 回のリクエストが無料(クレジット カードによる本人確認が必要)」。その他のサービスはAndroidおよびiOS向けが「1 日 1,000 件」、Web Serviceが「1 日あたり 2,500 回」までのリクエストが無料。

無料に該当するもの以外は、少ないほうの数(スマートフォン系は1,000、Web系は2,500)で判断したほうが無難と思います。

https://developers.google.com/maps/pricing-and-plans/?hl=ja

有料サイトの場合は無条件に有料プランが必要と解釈しています。無料サイトの場合Yahoo!の「~ユーザーから利益を得ていると認められる~」のような言い回しは無いので無料プランで利用可能と思われますが、リクエスト回数の制限が厳しいので実質的に有料プランを選択することになると思われます。

その他「非営利組織、危機対応組織、および報道機関」向けに特別扱いがあるようなので、該当する場合は申請することで無料のまま利用できる可能性があります。

地図を表示させた場合は、地図画像自体にクレジット表記が埋め込まれています。

API利用の場合、基本的には「Googleが提供する地図と併用」となっていますので実質的にクレジット表記を表示することになります。PlacesAPI Web Serviceは「Google Places API Web Service のデータを Google マップには表示させず、ページまたはビューに表示するアプリケーションでは、データと一緒に「Powered by Google」ロゴを表示させる必要があります。」とあります。(https://developers.google.com/places/web-service/policies?hl=ja)

Yahoo!    

https://developer.yahoo.co.jp/webapi/map/

  • 位置の移動、拡大縮小など基本的な操作が可能な地図の表示
  • スマートフォン向けアプリケーション用API
  • 店舗(=概ね場所と解釈)、イベント、クチコミ情報などの検索
  • ジオコーディング、リバースジオコーディング
  • 2点間の緯度経度を指定して地球の楕円体に合わせた正確な距離を計算
  • 測地系変換(緯度経度を日本測地系と世界測地系で相互変換)
  • 気象情報, 郵便番号検索, 住所ディレクトリ, 経路, 施設内検索, ルート沿い検索, 業種マスター, 店舗名寄せ, 標高, カセットサーチ(YOLP独自機能(?))
1アプリケーションIDごとに1日50000回 (https://developer.yahoo.co.jp/appendix/rate.html)

Yahoo! Open Local Platformの利用方法; 2. YOLPでは、以下に列挙するもののいずれかに該当するとYahoo! JAPANが判断した場合、YOLPのライセンスを消滅させることがあります。 ; YOLPにより提供される情報の使用によりユーザーから利益を得ていると認められるサービス (https://developer.yahoo.co.jp/webapi/map/#policy)

商用利用不可、もしくは多少なりともビジネスで利用する意図があるならば一度Yahoo!へ問い合わせた方が無難と判断します。

有償プラン: YOLP Premier (https://map.yahoo.co.jp/promo/yolp/yolppremier.html)

Yahoo! JAPANの提供するAPIを利用するすべてのサイトやアプリケーションには、クレジットを表示する必要があります (https://developer.yahoo.co.jp/attribution/)

AWS SDK for PHPでAmazon S3へアクセスするコードのメモ。

ぶっちゃけ技術検証で途中まで書いたのだけど、当面使いそうに無いのでココという蔵に「お蔵入り」です。

必要なもの

サンプルコード

  • AWS SDK for PHPはComposer等を使用せずに直接展開、 lib/ 以下に配置しています。Composer使った方が楽ですが、シェルログインできない環境の場合は手作業で配置した方が状況把握できてよいので。
  • バケット名は aws-test.logicalrabbit.jp 。予め作成しておきませぅ。

認証

  <?php
    require 'lib/aws-autoloader.php';

    use Aws\S3\S3Client;

    $s3client = new S3Client( [
      'region' => 'ap-northeast-1',
      'version' => '2006-03-01',
      'signature_version' => 'v4',
      'credentials' => [
        'key' => [アクセスキー],
        'secret' => [秘密鍵],
      ],
    ] );
  ?>

オブジェクト一覧の取得

テーブル化して一覧にしています。

    <table>
      <tr>
        <th>Key</th><th>Size</th><th>Last modified</th>
      </tr>
  <?php
    $result = $s3client->listObjects( [
      'Bucket' => 'aws-test.logicalrabbit.jp',
    ] );

    foreach( $result['Contents'] as $content ) {
      echo '<tr><td>' . $content['Key'] . '</td><td>' , $content['Size'] . '</td><td>' . $content['LastModified'] . '</td></tr>';
    }
  ?>
    </table>

オブジェクトの追加

取り敢えず lib/ 内に展開前のaws.zipがあったので、それをアップロードしてみるなど。アップロード成功の有無確認として、ETagを画面に表示します。

  <?php
    $reader = fopen('lib/aws.zip', 'r');

    $result = $s3client->putObject( [
      'Bucket' => 'aws-test.logicalrabbit.jp',
      'Key' => 'aws.zip',
      'Body' => $reader,
    ] );
    fclose( $reader );

    echo '<p>Uploaded a file. ETag = ' . $result['ETag'] . '</p>';
  ?>

この後で再度オブジェクト一覧の取得を実行すれば、オブジェクトが増えているのが確認できる筈。

「さくらのレンタルサーバー」でPHPバージョンを変更してもpeclが使用するPHPバージョンが上がらなかった話(解決)

PHP_PEAR_PHP_BIN=/usr/local/bin/php を設定すればOK。←結論

どっとはらい。

…いや備忘録として残しておきたかったので。なお、PHP本体のバージョンはさくらインターネットの「コントロールパネル」にて変更可能です。

% php -v
PHP 7.1.4 (cli) (built: Apr 17 2017 11:51:56) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.4, Copyright (c) 1999-2017, by Zend Technologies

PHPはv7.1になっています。

% pecl version
PEAR Version: 1.10.1
PHP Version: 5.6.30
Zend Engine Version: 2.6.0
Running on: FreeBSD www251.sakura.ne.jp 9.1-RELEASE-p22 FreeBSD 9.1-RELEASE-p22 #0: Wed Dec  3 15:24:48 JST 2014     root@www3304.sakura.ne.jp:/usr/obj/usr/src/sys/SAKURA17 amd64

しかし、peclは相変わらずPHP v5.6のまま。おかげでphp 7.xを要求するパッケージがインストールできなかったりします。

まずはphpコマンドの場所を確認。

% which php
/usr/local/bin/php

実際には /usr/local/bin/php-wrapper へのシンボリックリンクのようではありますが。

ログイン時、phpコマンドの場所を環境変数PHP_PEAR_PHP_BINにセットするようにします。その後取り敢えず現ログイン環境に反映。

% echo "setenv PHP_PEAR_PHP_BIN /usr/local/bin/php" >> .cshrc
% source .cshrc

再度peclが使用するPHPのバージョンを確認。

% pecl version
PEAR Version: 1.10.1
PHP Version: 7.1.4
Zend Engine Version: 3.1.0
Running on: FreeBSD www251.sakura.ne.jp 9.1-RELEASE-p22 FreeBSD 9.1-RELEASE-p22 #0: Wed Dec  3 15:24:48 JST 2014     root@www3304.sakura.ne.jp:/usr/obj/usr/src/sys/SAKURA17 amd64

これにて解決。

…したんだけど、肝心のmailparseがコンパイルエラーになって… ぐぬぬ。