無印吉澤

Site Reliability Engineering(SRE)、ソフトウェア開発、クラウドコンピューティングなどについて、吉澤が調べたり試したことを書いていくブログです。

Playbook 側から Ansible のバージョンを指定する方法(あるいは Ansible 2.x.0 を絶対使わせない方法)

f:id:muziyoshiz:20160331232512p:plain:w300

もうすぐ Ansible 2.5 がリリースされますね。僕もそろそろ Ansible 2.5 Porting Guide とか読み始めました。

ところで、僕は Ansible のバージョンが上がった最初のリリースでつまづくことが多くて、どうしてもしばらく様子見してしまいます。例えば、Ansible 2.4.0 では aws_s3 モジュールに不具合があって、既存の playbook が動かなくなったりしました(下記)。

github.com

しかし、いくら自分が注意していても、そういう経験の無い人が気軽に Ansible のバージョンを上げてしまい、あとから「動かなくなったんだけど」と言われることもあります。そんなわけで、playbook 側から実行環境の Ansible のバージョンを指定できないか?と考えてみたら、うまく動いたので紹介します。

対象読者

  • Ansible 2.x.0 を基本的に信用していない
  • 同じ Ansible playbook を操作・編集する人が自分以外にもいる
  • ある程度動作確認が終わってから、Ansible のバージョンを上げたい

実現方法

Ansible では、always という特別なタグを付けたタスクは「毎回必ず呼ばれるタスク」として扱われます。そこで、Ansible のバージョンをチェックするタスクを、この「毎回必ず呼ばれるタスク」として playbook に登録すれば、今回やりたいことを実現できます。

There is a special always tag that will always run a task, unless specifically skipped (--skip-tags always) Tags — Ansible Documentation

実行環境の Ansible のバージョン番号は、ansible_version という変数から参照できます。例えば、debug モジュールでこの変数を参照すると、以下のように出力されます。

- debug: msg="{{ ansible_version }}"
TASK [common : debug] ************************************************************************************************
ok: [localhost] => {
    "msg": {
        "full": "2.4.3.0",
        "major": 2,
        "minor": 4,
        "revision": 3,
        "string": "2.4.3.0"
    }
}

バージョン番号の4番目は個別に取得できませんが、そこまで確認する機会は考えにくいので大丈夫でしょう。

具体例

どの playbook からも常に呼ばれるロールを作ります。この例では "common" という名前にします。

まず、固定したいバージョンを表す変数 expected_ansible_version を作ります。今回は、Ansible 2.4.0 だけは使われたくないので、2.4.1 以降なら許すということにします。

roles/common/vars/main.yml

---
expected_ansible_version:
  major: 2
  minor: 4
  revision: 1

そして、この変数と ansible_version を比較するタスクを作ります。

roles/common/tasks/main.yml

---
- name: Ansible major & minor version check
  fail:
    msg:
      - Expected Ansible version is
        {{ expected_ansible_version.major }}.{{ expected_ansible_version.minor }},
        but actual version is {{ ansible_version.major }}.{{ ansible_version.minor }}
  when: not (expected_ansible_version.major == ansible_version.major
             and expected_ansible_version.minor == ansible_version.minor)
  run_once: True
  tags: always

- name: Ansible revision check
  fail:
    msg:
      - Expected Ansible version is
        {{ expected_ansible_version.major }}.{{ expected_ansible_version.minor }}.{{ expected_ansible_version.revision }}+,
        but actual version is {{ ansible_version.full }}
  when: not (expected_ansible_version.major == ansible_version.major
             and expected_ansible_version.minor == ansible_version.minor
             and expected_ansible_version.revision <= ansible_version.revision)
  run_once: True
  tags: always

この例では、revision(バージョン番号の3番目)が想定より大きい場合は許しています。また、エラーメッセージをわかりやすくするために、タスクを2個に分けていますが、Ansible revision check の方だけでも十分です。

あとは、その環境のすべての playbook で、ロールの先頭にこの common を追加すれば OK です。

playbook1.yml

---
- hosts: all
  roles:
    - common

こうすると、ansible-playbook コマンドでタグを指定してもしなくても、必ずバージョンチェックが実行されます。when でチェックを実行しているので、チェックに成功すると "skipping" と表示されます(この表示は若干わかりにくいので、他にいい方法があったら教えてください)。

$ ansible-playbook -i inventory -c local playbook1.yml

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [common : Ansible major & minor version check] ******************************************************************
skipping: [localhost]

TASK [common : Ansible revision check] *******************************************************************************
skipping: [localhost]

TASK [common : Example task 1] ***************************************************************************************
ok: [localhost] => {
    "msg": "Example task 1 is executed."
}

TASK [common : Example task 2] ***************************************************************************************
ok: [localhost] => {
    "msg": "Example task 2 is executed."
}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0

$ ansible-playbook -i inventory -c local playbook1.yml --tags=tag1

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [common : Ansible major & minor version check] ******************************************************************
skipping: [localhost]

TASK [common : Ansible revision check] *******************************************************************************
skipping: [localhost]

TASK [common : Example task 1] ***************************************************************************************
ok: [localhost] => {
    "msg": "Example task 1 is executed."
}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

メジャーバージョンかマイナーバージョンが合わないと処理が止まります。例えば、Ansible 2.4.3 以上を指定したのに Ansible 2.5 で実行されると、以下のように表示されます。

$ ansible-playbook -i inventory -c local playbook1.yml --tags=tag1

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [common : Ansible major & minor version check] ******************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": ["Expected Ansible version is 2.4, but actual version is 2.5"]}
    to retry, use: --limit @/Users/myoshiz/devel/ansible_version/playbook1.retry

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1

同じく、リビジョンが小さすぎても止まります。例えば、Ansible 2.4.3 以上を指定したのに Ansible 2.4.0 で実行されると、以下のように表示されます。

$ ansible-playbook -i inventory -c local playbook1.yml --tags=tag1

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [common : Ansible major & minor version check] ******************************************************************
skipping: [localhost]

TASK [common : Ansible revision check] *******************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": ["Expected Ansible version is 2.4.3+, but actual version is 2.4.0.0"]}
    to retry, use: --limit @/Users/myoshiz/devel/ansible_version/playbook1.retry

まとめ

Ansible は頻繁にバージョンアップされるので、特に問題がないなら、最新版に追従したほうがいいのは確かです。Ansible 2.5.0 を安心して使う気になれるまでの一時しのぎとして、よかったら試してみてください。

余談:Ansible 2.5 での仕様変更

Ansible 2.5 Porting Guide の冒頭に書いてありますが、include_tasks に付けられた属性(タグなど)の扱いが変わるようです。以下の記事で紹介した事象は、Ansible 2.4 でのみ発生する一時的な問題だったみたいですね。

muziyoshiz.hatenablog.com

2018-03-13追記

Ansible のバージョンチェックは1回で十分なので、run_once: True を付けました(参考)。

艦これアーケード第3回イベント「索敵機、発艦始め!」プレイデータ解析

f:id:muziyoshiz:20170128164643p:plain

はじめに

1年半くらい前から、艦これアーケードのプレイデータ管理ツール "Admiral Stats" を開発・運用しています。自分のプレイデータを記録するためにツールが欲しかったのと、他の人のプレイデータを見てみたかったというのが理由です。

そんなわけで今回の記事は、2017年11月30日から2018年1月9日まで開催されていた第3回イベント「索敵機、発艦始め!」のプレイデータ解析です。

最初に断っておくと、このプレイデータは、Admiral Stats を使ってくれているプレイヤーのものに限られています。そのため、プレイヤーの母集団と比べると、ヘビープレイヤーに寄った結果になっている可能性が高いです。それを念頭に置いて、大まかな傾向だけ参考にしてください。

第3回イベント「索敵機、発艦始め!」について

解析結果について話す前に、今回のイベントの簡単な紹介から。

今回は、第2回イベントと同様に「前段作戦」「後段作戦」に分かれたイベントでした。以下のように、前段作戦でクリアした難易度のみ、後段作戦でも出撃できます。詳しくは 第2回イベントのプレイデータ解析 に書きました。

f:id:muziyoshiz:20180223215553p:plain

今回のイベント期間は1ヶ月以上あり、しかも正月を挟んでいたので、ネット上でも期間の長さに関する不満は少なかったようです。第2回イベントは前段作戦36日、後段作戦21日で、期間が短いとの不満があったので、その点はかなり改善されていました。

  • 前段作戦:2017年11月30日 7:00 〜 2018年1月9日 23:59 (41日)
  • 後段作戦:2017年12月14日 7:00 〜 2018年1月9日 23:59 (27日)

また、今回はクリスマス前後に1週間、期間限定クリスマスフレーム艦娘カード が排出されるキャンペーン期間があり、イベントを早めに終わらせてしまった人もうまく集客していました。SEGA 恐るべし……。

  • クリスマスフレーム排出:2017年12月20日 7:00 〜 12月27日 6:59 (7日)

難易度については、レア艦娘がいなくてもできる攻略法(時間ギリギリまで空母で削ってから戦闘開始)が発見されたおかげで、時間さえかければ甲E-6クリアも簡単でした(※個人の感想です)。それ以外の正攻法でのクリアは、練度とプレイヤースキルがないと難しそうというか……僕はチャレンジしましたが無理でした。

また、今回は前段の報酬(天津風、Prinz Eugen)と後段の報酬(大鳳、Bismarck)がはっきり分かれていました。前回はこれが分かれてなくて、大和がいつまでも出ずにハマる人が多かったので、おそらくはその救済策ですね。

全体的に、第2回よりも改善されたイベントだったと思います。個人的には楽しかったですよ。

集計対象のプレイデータ

今回は前段作戦145名、後段作戦136名分のプレイデータが集まりました。第2回イベントより約50名プレイヤーが増えています。いつも Admiral Stats のご利用ありがとうございます。

集計対象としたプレイデータの詳しい情報は、以下の通りです。

  • 集計対象とした提督
    • 第3回イベントに参加して、Admiral Stats に1回以上プレイデータをアップロードした提督
  • 集計対象としたプレイデータ(イベント進捗情報、艦娘一覧など)
    • イベント攻略率と艦娘カード入手率は、2018年1月16日までにエクスポートされたプレイデータを集計
    • レベルや経験値については、各プレイヤーの、イベント終了時刻に最もプレイデータを集計

集計対象を1月16日までとしたのは、SEGA の公式サイト(提督情報ページ)でプレイデータを閲覧できたのがこの日までだったからです。イベント終了1週間後に消える、というのは第2回イベント時と一緒でした。

以下、プレイデータの解析結果です。

プレイデータの解析結果

イベント攻略率

第2回イベントと比べると、甲難易度の攻略率は大幅に上がりました。これは、開催期間が長かったことと、手軽な攻略法が存在したことが理由と思われます。

イベント 「甲」攻略率(前段) 「甲」攻略率(後段)
第2回 57.9 % 57.5 %
第3回 72.4 % 72.1 %

イベント攻略率:前段作戦の詳細

前段作戦の甲難易度をクリアしたのは、前段作戦に出撃した提督の 72.4 % でした。

また、甲難易度をクリアした提督のうち、63.8 % 以上がレアカード(甲種勲章がプリントされた艦娘カード)を求めて2周以上クリアしていました。100周超えている提督が複数居るのは、もう凄いとしか言いようがないですね……。

f:id:muziyoshiz:20180223211848p:plain
f:id:muziyoshiz:20180223213957p:plain:w675

詳細:イベント攻略率(索敵機、発艦始め! 前段作戦) - Admiral Stats

イベント攻略率:後段作戦の詳細

後段作戦の甲難易度をクリアしたのは、後段作戦に出撃した提督の 72.1 % でした。

また、甲難易度をクリアした提督の 63.3 % 以上が2周以上クリアしていました。難易度が高い分、前段作戦よりも周回数は減っていますが、それでも50周近く回ってる提督がいるのはすごいです。

f:id:muziyoshiz:20180223211947p:plain
f:id:muziyoshiz:20180223214024p:plain:w675

詳細:イベント攻略率(索敵機、発艦始め! 後段作戦) - Admiral Stats

艦娘カード入手率

以下は、このイベントでの新艦娘を入手できた提督の割合です。ちなみに、自分でドロップしたカードだけでなく、買ったり借りたりして読み込んだカードも「入手」に含みます。これは、公式プレイヤーズサイトの仕様による制限です。

作戦 図鑑 No. 艦名 N Nホロ N中破
前段 176 Prinz Eugen 84.1 % 20.3 % 7.2 %
前段 181 天津風 87.0 % 22.5 % 10.1 %
後段 153 大鳳 73.9 % 10.9 % 2.9 %
後段 171 Bismarck 73.9 % 10.9 % 2.9 %

この結果を見る限り、艦娘ごとのドロップ率に大きな偏りはなさそうです。後段作戦のほうが大鳳・Bismarck ともに入手率が低いのは、前段よりも周回するのが難しくて、片方の艦娘しか手に入らなかった提督が多かったということかもしれません。

それと、今回のイベントでは、前段・後段ともに夕立改二の限定カードがドロップしました。入手率は意外と高く、半分以上の提督の手に渡ったようです(でもうちにはいません……)。

作戦 図鑑 No. 艦名 入手率
前段/後段 144 夕立改二 50.7 %

さらに、今回のイベントでは、第2回イベントでドロップした以下の限定カードも再度ドロップしました。11/30 3:00時点のアクティブ提督(過去60日)の入手率と比較すると、イベント後には入手率が15〜20%程度上がったようです。

作戦 図鑑 No. 艦名 11/30時点の入手率 イベント終了時の入手率
前段 103 日向改 41.2 % 61.6 %
後段 102 伊勢改 42.0 % 57.2 %

艦隊司令部レベル、および経験値

ここから先は、Admiral Stats 上で表示していない(自動集計機能がまだない)集計結果の紹介です。

まず、前回と同様に、ステージのクリア回数とステージの難易度によって増える「艦隊司令部レベル」の分布を出してみました。

艦隊司令部レベル 提督数 割合 (参考)第2回終了時の割合
0 以上 10 未満 0 0.00% 3.16%
10 以上 20 未満 2 1.38% 1.05%
20 以上 30 未満 1 0.69% 2.11%
30 以上 40 未満 3 2.07% 5.26%
40 以上 50 未満 5 3.45% 5.26%
50 以上 60 未満 3 2.07% 10.53%
60 以上 70 未満 12 8.28% 7.37%
70 以上 80 未満 9 6.21% 7.37%
80 以上 90 未満 7 4.83% 8.42%
90 以上 100 未満 38 26.21% 29.47%
100 以上 110 未満 56 38.62% 18.95%
110 (上限) 9 6.21% 1.05%
総計 145 100.00% 100.00%

艦隊司令部レベルの平均値と中央値は以下の通りです。

艦隊司令部レベル 第3回終了時 第2回終了時
平均 90.1 77.0
中央値 99.0 87.0

艦隊司令部レベルを経験値に換算すると、次のようになりました。レベル99に必要な経験値は 1,000,000 なので、イベント参加提督の 51.72 % がレベル99以上ということになります。このプレイデータは、間違いなくヘビープレイヤーに寄ってますね……。

経験値 提督数 割合 (参考) 第2回終了時
0 以上 100000 未満 9 6.21% 14.74%
100000 以上 200000 未満 8 5.52% 14.74%
200000 以上 300000 未満 15 10.34% 8.42%
300000 以上 400000 未満 6 4.14% 6.32%
400000 以上 500000 未満 3 2.07% 6.32%
500000 以上 600000 未満 4 2.76% 3.16%
600000 以上 700000 未満 5 3.45% 6.32%
700000 以上 800000 未満 9 6.21% 3.16%
800000 以上 900000 未満 11 7.59% 3.16%
900000 以上 1000000 未満 0 0.00% 0.00%
1000000 以上 2000000 未満 30 20.69% 24.21%
2000000 以上 3000000 未満 12 8.28% 5.26%
3000000 以上 4000000 未満 11 7.59% 2.11%
4000000 以上 5000000 未満 8 5.52% 0.00%
5000000 以上 6000000 未満 14 9.66% 2.11%
総計 145 100.00% 100.00%
経験値 第3回終了時 第2回終了時
平均 1712572.4 808893.7
中央値 1000000.0 491500.0

イベントの間に6ヶ月空いたので、全体的にかなり底上げされてます。新規プレイヤーがあまり入ってこなかったとも解釈できますが、ただ、それは Admiral Stats のユーザに限った話かもしれません。

攻略度と艦隊司令部レベルの比較

甲難易度をクリアするのに必要なレベルを知るために、攻略度と、艦隊司令部レベルの関係を調べた結果が以下の表です。

前段 - 後段 攻略度 提督数 提督数 (割合) 最大 最小 平均 中央値 標準偏差
甲 - 甲 98 67.59% 110 62.0 99.1 101.0 10.7
甲 - 乙 2 1.38% 99 64.0 81.5 81.5 17.5
甲 - 丙 1 0.69% 72 72.0 72.0 72.0 -
甲 - 未出撃 4 2.76% 107 95.0 101.0 101.0 4.3
乙 - 乙 8 5.52% 100 41.0 82.1 95.5 20.8
乙 - 丙 3 2.07% 87 34.0 57.3 51.0 22.1
乙 - 未攻略 2 1.38% 97 63.0 80.0 80.0 17.0
乙 - 未出撃 1 0.69% 80 80.0 80.0 80.0 -
丙 - 丙 12 8.28% 99 37.0 63.7 64.5 18.7
丙 - 未攻略 4 2.76% 74 64.0 68.8 68.5 4.0
丙 - 未出撃 3 2.07% 102 54.0 85.3 100.0 22.2
未攻略 - 未攻略 6 4.14% 99 17.0 40.8 32.0 28.2
未攻略 - 未出撃 1 0.69% 98 98.0 98.0 98.0 -
全体 145 100.00% 110 17.0 90.1 99.0 21.3

「未出撃」とあるのは、後段作戦に出撃しなかったか、後段作戦の期間中に Admiral Stats にプレイデータをアップロードしなかったユーザです。

後段作戦の甲E-6をクリアした提督と、それ以外の提督で、レベル差があることがわかります。しかし、乙E-6までしかクリアしていない提督(表の「乙 - 乙」の行)も中央値はそれほど低くありません。このあたりの提督が、どういう理由で甲をクリアしなかったのかは気になるところです。

攻略度と艦娘レベルの比較

攻略に艦娘のレベルの高さは必須だったのかどうかを調べるために、各提督の、レベルが一定値(50, 70, 90, 99)以上の艦娘数を調べてみました。 すると、レベル90あたりが、関係がありそうな結果になりました。

以下の表は、各提督の攻略度と、Lv90以上の艦娘数の関係です。

前段 - 後段 攻略度 提督数 提督数 (割合) 最大 最小 平均 中央値 標準偏差
甲 - 甲 98 67.59% 119 0 17.5 9 21.0
甲 - 乙 2 1.38% 5 0 2.5 2.5 2.5
甲 - 丙 1 0.69% 0 0 0.0 0 -
甲 - 未出撃 4 2.76% 35 0 13.3 9 14.0
乙 - 乙 8 5.52% 8 0 1.6 1 2.5
乙 - 丙 3 2.07% 0 0 0.0 0 0.0
乙 - 未攻略 2 1.38% 3 0 1.5 1.5 1.5
乙 - 未出撃 1 0.69% 1 1 1.0 1 -
丙 - 丙 12 8.28% 5 0 0.4 0 1.4
丙 - 未攻略 4 2.76% 1 0 0.3 0 0.4
丙 - 未出撃 3 2.07% 13 0 8.0 11 5.7
未攻略 - 未攻略 6 4.14% 0 0 0.0 0 0.0
未攻略 - 未出撃 1 0.69% 0 0 0.0 0 -
全体 145 100.00% 119 0 12.5 3 19.0

甲難易度をクリアした艦隊とそうでない艦隊では、Lv90以上の艦娘数に明らかな違いがあることがわかります。

攻略度と空母の練度の比較

今回のイベントは、空母を育てていれば使える攻略法がありました。そこで、攻略度と、各提督が所持する空母のレベルに関係があったかを調べてみました。

以下は、攻略度と、各提督が所持する空母(正規空母、装甲空母、軽空母)の上位5隻の平均レベルを比較した結果です。

前段 - 後段 攻略度 提督数 提督数 (割合) 最大 最小 平均 中央値 標準偏差
甲 - 甲 98 67.59% 99 18.8 74.1 75.4 20.2
甲 - 乙 2 1.38% 40.4 29.2 34.8 34.8 5.6
甲 - 丙 1 0.69% 47.6 47.6 47.6 47.6 -
甲 - 未出撃 4 2.76% 93.2 39.4 74.2 82.1 20.9
乙 - 乙 8 5.52% 70.6 26.2 52.2 56.4 15.4
乙 - 丙 3 2.07% 37.6 19.6 29.7 31.8 7.5
乙 - 未攻略 2 1.38% 60.2 44.8 52.5 52.5 7.7
乙 - 未出撃 1 0.69% 63.6 63.6 63.6 63.6 -
丙 - 丙 12 8.28% 77.6 16 40.0 37.5 17.2
丙 - 未攻略 4 2.76% 49.8 35.4 43.0 43.3 5.1
丙 - 未出撃 3 2.07% 90.2 28.6 62.9 70 25.6
未攻略 - 未攻略 6 4.14% 64 10.8 25.0 16.9 18.4
未攻略 - 未出撃 1 0.69% 72.4 72.4 72.4 72.4 -
全体 145 100.00% 99 10.8 64.9 66.4 24.5

これを見ると、空母の平均レベルが高いほど、甲難易度を攻略できた可能性は高そうですね。ただ、平均レベルが18.8でも甲E-6をクリアできている提督がいるのはちょっと驚きです。空母のレベルが低くても行けたのか、他の方法で攻略したのか……?

まとめ

いくつかの方法で、甲種勲章を入手した提督と、そうでない提督のプレイデータを比較してみました。

今回は甲難易度をクリアできた提督が全体の70%以上と多かったため、「甲提督 vs それ以外」という比較はあまりうまく行きませんでした。「レベルがある程度高ければクリアできた」という感じでしたね。第2回イベントのように「大井改二・北上改二がいれば」「甲標的があれば」といったレベル以外の条件による影響は見つけられませんでした。

もし、「こういう観点で調べてほしい」といったアイディアがありましたら Admiral Stats のお知らせ用アカウント @admiral_stats までお寄せください。今後のネタにさせていただきます。

最後に、艦これアーケードをプレイしていて、こういうプレイデータに興味があったら是非 Admiral Stats を使ってみてください。よろしくお願いします。

おまけ:2/16 のケッコンカッコカリ実装時に、レベル99到達済みの艦娘数を集計した結果

あわせて読みたい

muziyoshiz.hatenablog.com

muziyoshiz.hatenablog.com

muziyoshiz.hatenablog.com

muziyoshiz.hatenablog.com

Ansible 2.4 で import_tasks/include_tasks に tags を付けるときの注意点

f:id:muziyoshiz:20160331232512p:plain:w300

前提:Ansible 2.4 から include は非推奨になった

Ansible 2.4 を使っていたら既に嫌というほど見てると思いますが、include を使うと以下のような警告が出るようになりました。

[DEPRECATION WARNING]: The use of 'include' for tasks has been deprecated. Use 'import_tasks' for static inclusions or 'include_tasks' for dynamic inclusions. This feature will be removed in a future release. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

Ansible 2.4 から、いままで include が持っていた機能は以下の4つのアクションに分けられました。

Action Operation Reusable content
import_tasks static task
include_tasks dynamic task
import_playbook static playbook
include_playbook dynamic playbook
include (DEPRECATED) both static and dynamic task or playbook

この変更は、静的(static)な読み込みと動的(dynamic)な読み込み、そして読み込む対象(task ファイルか playbook ファイルか)を明確に区別することを目的に行われたようです。

static と dynamic の違い

ここで言う static と dynamic の意味は、公式サイトの Creating Reusable Playbooks によると次の通りです。

  • 静的な読み込み(static import)は、Playbook をパースする段階で、事前に実行される
  • 動的な読み込み(dynamic include)は、タスクを順に処理して、その行に来た段階で実行される

include は基本的には static import を行いますが、状況によって dynamic include を行うなどして動作がわかりづらいため、Ansible 2.8 で廃止予定とのことです。

じゃあ今までに書いた include はどうすればいいのか?というと、個人的な意見ですが、特に理由がなければ import_tasksimport_playbook に書き換えておけばいい と思います。dynamic include にすると文法ミスの事前検知が行われなくなるので、デバッグが面倒になります。

もっと詳しく知りたい方は、以下のページをどうぞ。@heriet さんによる Qiita の記事は、Ansible 2.2 の時点で書かれたものですが、具体例が多く、基本的な考え方の勉強になりました。

本題:import_tasks/include_tasks に tags を付けた場合の動作

ここまでは前提の話で、ここからやっと本題です。

以下のように import_tasks/include_tasks に tags を付けると、その中に含まれるすべてのタスクに同じタグを付けることができます。これは公式の Tags — Ansible Documentation にも書かれた方法です。

- import_tasks: main.yml
  tags: [ tag1 ]
- include_tasks: main.yml
  tags: [ tag1 ]

例えば、main.yml の中身が、

- debug: msg="Task 1"

- debug: msg="Task 2"

の場合、ansible-playbook --tags=tag1 で両方のタスクが実行されます。

しかし、何かの理由で Task 2 だけ実行したくなったとします(Ansible 使ってるとよくありますよね?)。そこで、

- debug: msg="Task 1"

- debug: msg="Task 2"
  tags: [ tag2 ]

と直して、ansible-playbook --tags=tag2 を実行すると、include_tasks を使った場合は Task 2 が実行されません。どうやら、以下のような動作の違いがあるようです。

  • import_tasks に tags を付けた場合は、「main.yml 内のすべてのタスクに追加するタグ」として扱われる
  • include_tasks に tags を付けた場合は、「include_tasks アクション自体に追加するタグ」のように扱われる

ローカルホストで実験

ローカルホストで簡単に実験できるのでやってみましょう。Gist にファイルを用意しました。

Example of import_tasks/include_tasks with tags

これらのファイルを同じディレクトリに置いて、以下のように実行してください。

$ ansible-playbook playbook1.yml --tags=tag1

Ansible 2.4.2.0 で実行した結果は、以下の通りです。include_tasks の場合だけ、tag2 を付けたタスク(Task 2)が無視されているのがわかります。

No. Playbook How to import --tags option Task 0 Task 1 Task 2
1 playbook1.yml include None ok ok ok
2 --tags=tag1 ok ok ok
3 --tags=tag2 - - ok
4 playbook2.yml import_tasks None ok ok ok
5 --tags=tag1 ok ok ok
6 --tags=tag2 - - ok
7 playbook3.yml include_tasks None ok ok ok
8 --tags=tag1 ok ok ok
9 --tags=tag2 - - -

まとめ:結局どうしたらいいのか?

import_tasksinclude_tasks を使った場合で、タグの扱いに微妙な違いがあることがわかりました。

上記の結果を見ると、「include_tasks 使うとタグが無視されることがあるのか。使うのやめよう」と思うかもしれません。しかし、以下のように書かれているのに、main.yml 内に tag1 以外のタグがついているというのは、それはそれで可読性に問題があります。

- import_tasks: main.yml
  tags: [ tag1 ]

そう考えると、結論としては「import_tasks/include_tasks で読み込むタスクにはタグを付けない」というルールを設けるのが良いのではないでしょうか。

ansible コマンドでのログ検索結果を TSV や Markdown 形式に変換する方法

f:id:muziyoshiz:20171211235628p:plain

これは Ansible Advent Calendar 2017 の13日目の記事です。

ansible コマンドでログ検索

ansible コマンドって使ってますか?

Ansible と言えば普段は ansible-playbook コマンドを使うと思うので一応解説しておくと、ansible コマンドは Ansible モジュールを1個だけ実行するコマンドです。-m でモジュール、-a でそのモジュールに渡す引数を指定します。Running Ad Hoc Commands - Ansible Tips and Tricks あたりが詳しいです。

この ansible コマンドで shell モジュール を使うと、複数サーバ上のログを簡単に検索できます。

例えば以下のように、すべてのアプリケーションサーバに対して、一括で ERROR ログ数を検索できます。

$ ansible -i hosts app -m shell -a "cat /var/log/foobar | grep "ERROR" | wc -l"
app1 | SUCCESS | rc=0 >>
177

app2 | SUCCESS | rc=0 >>
84

app3 | SUCCESS | rc=0 >>
37

僕の場合は wc の代わりに head を使って ERROR ログを何件か表示し、サーバごとの傾向の違いを調べることもあります。

$ ansible -i hosts app -m shell -a "cat /var/log/foobar | grep "ERROR" | head -5"

もちろん、普段の運用に必要なログは、特定のサーバやデータベースに集めておくべきです。わかってますよ、わかってるんですが、集めてないログを調べたくなるときはどうしてもあって。そういうときに ansible コマンドで手軽に検索できるのは便利です。

ansible コマンドの結果を TSV/JSON/Markdown/Backlog 形式に変換

ログを調べたら、(それが仕事なら)たいてい他の人に共有したくなるわけですが、この出力は若干使い勝手がよくありません。

Excel や Google Spreadsheet で処理するにも手作業でのコピペが必要になりますし、Wiki にそのまま貼るにも不便です。以前からこの出力がちょっと気になっていました。

そこで Go の勉強がてら、ansible コマンドの結果を他の形式に変換する ansible2tab コマンドを作ってみました。

github.com

先ほど例に挙げた出力をこの ansible2tab に通すと、以下のように変換されます。

$ ansible -i hosts app -m shell -a "cat /var/log/foobar | wc -l" | ansible2tab
app1    177
app2    84
app3    37

デフォルトが TSV なので ansible2tab という名前にしましたが、--format を指定すると JSON などにも変換できます。ちなみに、僕が仕事で使うので Backlog 記法にも対応しました。

$ ansible -i hosts app -m shell -a "cat /var/log/foobar | wc -l" | ansible2tab --format json
{"app1":"177","app2":"84","app3":"37"}
$ ansible -i hosts app -m shell -a "cat /var/log/foobar | wc -l" | ansible2tab --format markdown
|Host|Value|
|---|---|
|app1|177|
|app2|84|
|app3|37|
$ ansible -i hosts app -m shell -a "cat /var/log/foobar | wc -l" | ansible2tab --format backlog
|Host|Value|h
|app1|177|
|app2|84|
|app3|37|

出力が複数行の場合はうまく表になりません。その場合は --format markdown-code--format backlog-code と指定すると、以下のようなコードブロックに変換します。

gist.github.com

できることはこれだけの、地味なツールです。でも、個人的には日常業務で結構こういうことしてるんですよね……。

この ansible2tab コマンドですが、Mac なら brew 経由でインストールできます。

$ brew tap muziyoshiz/ansible2tab
$ brew install ansible2tab

それ以外の環境では リリースページ からダウンロードしてパスを通すか、あるいは Go の開発環境があれば以下のコマンドでインストールできます。

$ go get github.com/muziyoshiz/ansible2tab

まとめ

ansible コマンドは、複数サーバ上のログを手軽に検索するには便利です。今回は、このログ検索した結果を TSV/JSON/Markdown/Backlog 出力する ansible2tab を作りました。Go で実装したおかげで、さくっとクロスプラットフォーム対応できました。

世間に似たようなニーズがどれくらいあるかわからないですが、よかったら使ってみてください。別の形式にも対応して欲しい、JSON はもっと違う形式がいい、などの要望は GitHub の Issue@muziyoshiz までお願いします。

あと、Go 初心者なのでコードがあまりイケてないと思います。そのあたりのツッコミも歓迎です。

今回の参考情報

Go 言語全般

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】

Go のコードに詰まってから読み返すと、ヒントになることが書いてある(と気づく)本でした。良い本です。

以下、今回参考にさせて頂いた Web 上の情報です。

バイナリの配布方法