読者です 読者をやめる 読者になる 読者になる

It's raining cats and dogs.

無駄なことなんてないはず

ansibleで "Encountered unknown tag 'd'." なエラーがでた

ansible

どうして今までハマらなかったんだろう的な話で、ansibleでapacheの設定ファイルで表題のエラーがでた。

apacheのLogFormatを追加してprovisionしたときに出たのだけど、原因としては追加したLogFormatの記述がansibleで使っているJinja2テンプレートとして解釈されてエラーとなっていた。
ちなみに追加したフォーマットを一部抜粋

LogFormat "... time:%{%d/%b/%Y:%H:%M:%S %z}t ..." my_format

具体的にはここ→ time:%{%d/%b/%Y:%H:%M:%S %z}t

ansibleのplaybookは以下のような感じ

- name: apache conf
  template: src=templates/apache/httpd.conf dest=/etc/httpd/conf/httpd.conf

回避策としては以下2つのどちらか

Jinja2の表記でJinja2の書式として認識させない

rawでそのまま出力

{% raw %}
LogFormat "... time:%{%d/%b/%Y:%H:%M:%S %z}t ..." my_format
{% endraw %}

Jinja2のテンプレートとして扱わない

playbookで templatecopy に変えることで、テンプレートとして解釈せずにそのまま単にコピーするだけ。

- name: apache conf
  copy: src=templates/apache/httpd.conf dest=/etc/httpd/conf/httpd.conf

ということで

どちらでも良いと思うけど、単にコピーしてほしいだけだったので、後者を選択した

slim3のMiddlewareの実行順

メモ php slim

slim3のMiddlewareは後から追加した順に実行されるらしい

<?php

$app = new \Slim\App;

$app->add(new \MyMiddleware1);  // 実行順 3
$app->add(new \MyMiddleware2);  // 実行順 2
$app->add(new \MyMiddleware3);  // 実行順 1

上から実行されてほしい感ある

slim3でクライアントIPアドレスを取得する

php slim3

slim2では

<?php
$app->request->getIp();

的なことができたのだけど、slim3だとどうやら取得する術が標準では存在しないぽい。マニュアルにも、サードパーティなライブラリ使えって書いてある。

てかどうしてなくした。普通クライアントIPとりたくなるだろ。

本体になくてもいいけど、せめて公式のコンポーネントとして作って欲しいなぁと。

apacheでS3にプロキシさせるときにbasic(digest)認証をかませていると400 bad requestになる

apache mod_proxy

S3にBasic認証付きリクエストをすると400:Bad Requestになる | Siguniang's Blog

この記事のapache版。

apacheのmod_proxyでS3においてある画像にプロキシさせた時に、basic認証をかませているとS3から400 bad requestが返ってきてしまって画像が表示されなくなってしまった。
上記ブログはnginxだったので、apacheで解決したやり方をメモっておく。

<Location "/s3-images/">
  RequestHeader set Authorization ""
</Location>

ProxyPass        /s3-images/  http://hogehoge.s3-ap-northeast-1.amazonaws.com/s3-images/
ProxyPassReverse /s3-images/  http://hogehoge.s3-ap-northeast-1.amazonaws.com/s3-images/

やっていることは同じで、S3用のロケーションパス以下は Authorization ヘッダを潰している。
これで解決。

ところで、原因を調べていたんだけど、S3のサイトにそれっぽいことが書いてあった。

docs.aws.amazon.com

どうやらS3のREST APIは認証の時に Authorization ヘッダを使っていて、普通に(Authorizationヘッダがない状態で)プロキシしているだけだと認証情報を求められないのでそのままプロキシしてくれるんだけど、basic認証なりで Authorization ヘッダがついてしまうとS3側で認証しようとしてコケている感じなんだろうな。(IAMの話かもだけど)

学びがあった

余談

はてなブログシンタックスハイライト、 apachestyle なんてのがあったんだ。

多次元配列をうまいことマージしてくれるarray_replace_recursive便利

PHP

今更感あるけど、array_replace_recursive というメソッドが便利だった。

設定ファイルなんかはphpでサクッと書いちゃうことが多い。例えば

<?php
return [
    'key1' => [
        'key11' => 'val11',
        'key12' => 'val12'
    ],
    'key2' => 'val2'
];

みたいなファイルにしておけば

<?php
$config = require '/path/to/config.php';

な感じでrequireするだけだし、phpのコードでしかないから早いし、パースしなくていいし、記述ミスがあってもsyntax errorでコケてくれるし、OPcacheでもかませればメモリに乗ってくれるしいいコトづくめ。
なんだけど、例えばベースのconfig用配列をrequireした後に、個別の処理でconfigを上書きしたい時があったりしたときに、array_mergeでマージしてしまうと子要素がまるっと上書きされてしまうので、泥臭く手でマージしたりしてたんだけど、表題のarray_replace_recursive を使えば簡単に解決することがわかった。

たとえば、array_mergeだと

<?php
$a = [
    'key1' => [
        'key11' => 'val11',
        'key12' => 'val12'
    ],
    'key2' => 'val2'
];
// key12だけ上書きしたい
$b = [
    'key1' => [
        'key12' => 'hoge12'
    ]
];

var_dump(array_merge($a, $b));

// key11がなくなっちゃった!
array(2) {
  'key1' =>
  array(1) {
    'key12' =>
    string(6) "hoge12"
  }
  'key2' =>
  string(4) "val2"
}

こんな感じで子要素がまるっと上書きされてしまう。
でも、array_replace_recursive だと

<?php
$a = [
    'key1' => [
        'key11' => 'val11',
        'key12' => 'val12'
    ],
    'key2' => 'val2'
];
// key12だけ上書きしたい
$b = [
    'key1' => [
        'key12' => 'hoge12'
    ]
];

var_dump(array_replace_recursive($a, $b));

// key12だけ上書きされた!
array(2) {
  'key1' =>
  array(2) {
    'key11' =>
    string(5) "val11"
    'key12' =>
    string(6) "hoge12"
  }
  'key2' =>
  string(4) "val2"
}

こんな具合に key11 を残したまま key12 だけ上書きしてくれた。便利!

anyenvのphpenvでphp5.5を入れた時にapcの設定でハマった件

anyenvでphpenvを入れて、php5.5を入れて適当なphp書いて、ビルトインサーバで実行してみたら以下の様なnoticeが出た。

Notice: Unknown: 1. h->opened_path=[null] h->filename=[/private/var/apps/sample/index.php] in Unknown on line 0
Notice: Unknown: apc_cache_find [220575364] in Unknown on line 0
Notice: Unknown: 2. h->opened_path=[/private/var/apps/sample/index.php] h->filename=[/private/var/apps/sample/index.php] in Unknown on line 0
Notice: Unknown: apc_cache_make_file_entry: entry->data.file.filename is [/private/var/apps/sample/index.php] in Unknown on line 0
Notice: Unknown: Inserting [/private/var/apps/sample/index.php] in Unknown on line 0

php5.5からデフォルトOpecacheになったのになんでapcとか使われてるんだろうとおもって、php -iしてみたら

$ php -i | grep apc
Configure Command =>  './configure'  '--with-apxs2=/usr/sbin/apxs' '--enable-option-checking' '--enable-phar' '--disable-intl' '--with-libxml-dir=/usr/local/opt/libxml2' '--with-openssl=/usr/local/opt/openssl' '--with-openssl-dir=/usr/local/opt/openssl' '--with-kerberos=/usr' '--with-zlib' '--with-zlib-dir=/usr/local/opt/zlib' '--enable-bcmath' '--with-bz2=/usr' '--enable-calendar' '--enable-exif' '--with-png-dir=/usr/local/opt/libpng' '--with-jpeg-dir=/usr/local/opt/jpeg' '--with-freetype-dir=/usr/local/opt/freetype' '--with-xpm-dir=/usr/X11' '--with-gd=/usr/local' '--enable-gd-native-ttf' '--with-pear' '--enable-mbstring' '--enable-mbregex' '--enable-shmop' '--enable-soap' '--enable-sockets' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--enable-wddx' '--with-xmlrpc' '--with-xsl=/usr/local/opt/libxslt' '--enable-zip' '--with-pcre-regex=/usr/local/opt/pcre' '--with-vpx-dir=/usr/local/opt/libvpx' '--with-pcre-dir=/usr/local/opt/pcre' '--with-curl=/usr/local/opt/curl' '--with-iconv-dir=/usr/local/opt/libiconv' '--with-mcrypt=/usr/local/opt/mcrypt' '--with-libexpat-dir=/usr/local/opt/expat' '--with-gettext=/usr/local/opt/gettext' '--enable-pcntl' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--with-mysql-sock=/tmp/mysql.sock' '--with-readline=/usr/local/opt/readline' '--enable-apc' '--enable-apc-debug' '--enable-apc-filehits' '--enable-igbinary' '--enable-memcached' '--with-libmemcached-dir=/usr/local/opt/libmemcached' '--enable-memcached-igbinary' '--with-http-curl-requests=/usr/local/opt/curl' '--with-http-curl-libevent=/usr/local/opt/libevent' '--with-http-zlib-compression=/usr/local/opt/zlib' '--with-http-magic-mime=/usr/local/opt/libmagic' '--with-config-file-path=/Users/t-yamaguchi/.anyenv/envs/phpenv/versions/5.5.9/etc' '--with-config-file-scan-dir=/Users/t-yamaguchi/.anyenv/envs/phpenv/versions/5.5.9/etc/conf.d' '--prefix=/Users/t-yamaguchi/.anyenv/envs/phpenv/versions/5.5.9'
apc
apc.cache_by_default => On => On
apc.canonicalize => On => On
apc.coredump_unmap => Off => Off
apc.enable_cli => Off => Off
apc.enabled => On => On
apc.file_md5 => Off => Off
apc.file_update_protection => 2 => 2
apc.filters => no value => no value
apc.gc_ttl => 3600 => 3600
apc.include_once_override => Off => Off
apc.lazy_classes => Off => Off
apc.lazy_functions => Off => Off
apc.max_file_size => 1M => 1M
apc.mmap_file_mask => no value => no value
apc.num_files_hint => 1000 => 1000
apc.preload_path => no value => no value
apc.report_autofilter => Off => Off
apc.rfc1867 => On => On
apc.rfc1867_freq => 0 => 0
apc.rfc1867_name => APC_UPLOAD_PROGRESS => APC_UPLOAD_PROGRESS
apc.rfc1867_prefix => upload_ => upload_
apc.rfc1867_ttl => 3600 => 3600
apc.serializer => igbinary => igbinary
apc.shm_segments => 1 => 1
apc.shm_size => 32M => 32M
apc.shm_strings_buffer => 4M => 4M
apc.slam_defense => On => On
apc.stat => On => On
apc.stat_ctime => Off => Off
apc.ttl => 0 => 0
apc.use_request_time => On => On
apc.user_entries_hint => 4096 => 4096
apc.user_ttl => 0 => 0
apc.write_lock => On => On

なぜかapcが有効になっているし、コンパイルオプションでも--enable-apcとか付いてる。ひとまずphp.ini

-apc.enabled=1
+apc.enabled=0

な感じでapcを無効にしたらnoticeはでなくなりました。

ところで、anyenvで入れたphpenvはよくあるCHH/phpenvではなくて、phpenv/phpenvが使われる。CHH/phpenvでphp5.5を使っていた時はこんなことはなかったので、phpenv/phpenv側の設定だろうとおもってgithubリポジトリを眺めていたら、↓あたりでそれっぽい感じのことをしていた。

https://github.com/phpenv/phpenv/blob/dev/etc/php-5.5.Darwin.source https://github.com/phpenv/phpenv/blob/dev/etc/ext/apc.ini

そもそもphp5.5でapcって動かせたっけ?APCuじゃなくて。

android studioで2段階認証設定済みのgithubからcloneする

android github

android studioを使ってgithubからコードをcheckoutするときに、github側で2段階認証(two factor authentication)を設定しているときはpersonal access tokenを使うそうです。

http://michaelcarrano.com/blog/using-github-with-android-studio

githubの画面からtokenを発行しても良いけど、android studioからtokenを取得することもできるようだ。

  1. android studio起動
  2. 起動後のメニューから「configure」→「preferences」を選択
  3. 左メニューから「Version Control」「GitHub」を選択
  4. Auth TypeのプルダウンをTokenにすると「Create API Token」ボタンが出てくるので押す
  5. ログインダイアログがでてgithubのID/PWを入れると認証コードを入力するウィンドウがでるので、2段階認証の認証コードを入力する
  6. Token欄にtokenらしき●印がでるので、「Test」ボタンを押すと接続確認が取れる
  7. 右下の「OK」ボタンを押して完了

あとは起動後のメニューから「Check out from Version Control」からgithubを選んでプロジェクトをcheckoutしたらおk