Ansibleにはユーザーの入力を受け付ける仕組みが用意されています。まずあらかじめ言っておきますと、全自動でプロビジョニングをする場合はユーザー入力を求めるような作りにはしないと思いますが、なかなかそこまで全自動でやってはいけないという障壁がある場合も多々あるかと思います。

特に多いのはきっと「パスワードは都度入力するようにしたい」という要件です。 ansible-vault 使おうよ、って話はいったん置いておきましょう。では、ユーザーの入力を受け付ける機能について見ていきましょう。大きくは以下の二つがあります。

vars_prompt

vars_prompt が一番それっぽいのですが、実は弱点がありまして、 when との併用ができないのです。なので、 「◯◯なときだけ入力を受け付ける」という使い方ができません。例えば、「ユーザーを作るときにパスワードを設定したい」から vars_prompt を使ったとします。たぶん、一度そのユーザーを作ったあとはこのタスクを実行する必要性ってほとんど無いと思うのですが、例えそのタスクが必要なかったとしても play_bookvars_prompt が設定されていれば prompt 自体は必ず聞かれちゃいます。結構これは痛いです。「何もしないときは空白のままEnter」という運用にしてもいいのかもしれませんが、環境が多かったりするとやっぱりしんどいです。 vars_prompt には入力文字を表示させない private というオプションもついているのですが、残念ながら when と併用できないのは痛すぎます。

pauseモジュール

さて、 pause モジュールを使った方法が残ります。 pausewhen と併用ができます。 pause の prompt オプションを使うことで入力文字を待ち受けることができ、 register と組み合わせることで変数に代入することもできます。下のようなイメージです。

- name: Prompt password
  pause:
    prompt: Enter the crypted password
  register: foo_pass

これで foo_pass という変数の user_input というプロパティに、ユーザーが入力した文字が入ります。これを後ろのタスクで使うことができます。こんな感じに使えたらなんとなく pause の響きに違和感を覚えつつも、簡単でいいですよね!

落とし穴

ただし、これにはイケてない点と落とし穴があります。まず、イケてない点としてはAnsible 2.5以前だと、ユーザー入力に private 的なものがありません。なので入力中の文字はがっつり見えちゃいます。パスワードとかだと心が穏やかじゃありませんよね。 Ansible2.5以降であれば echo オプションが追加されており、これを no にしておけば表示されません!これは地味にうれしいアップデートなのです。

- name: Prompt password
  pause:
    prompt: Enter the crypted password
    echo: no  # ←これを追加
  register: foo_pass

こうすることで下のキャプチャみたいにいい感じに入力を隠してくれます。

SS-2018-03-30-18.34.40

さて、落とし穴についてですが、 register は、あくまで タスクが実行されたホストに 変数を代入するだけです。これの何が問題なのかといいますと、 pause は標準では1回しか実行されない特殊なタスクです。複数ホストいたとしても、ユーザー入力は一度しか発生しません。UX的にはこれが自然ですよね。

ただし! register も1回しか実行されないということなので、冗長化などで複数のホストに対して playbook を実行する場合には、どれか1つのホストしか foo_pass を持たないことになります。これでは困ってしまいます。 host_vars で抜き取ってくる方法もありますが、ちょっと汚いですよね。そこで1つのやり方として set_fact モジュールを使う方法があります。 set_fact した情報は play 中であれば情報が残る仕様になっています。つまり、以下のように書きます

- name: Prompt password
  pause:
    prompt: Enter the crypted password
    echo: no
  register: foo_pass
- name: Set password fact
  set_fact:
    foo_pass: "{{ foo_pass.user_input }}"
  run_once: true

ポイントなのは run_once としている点です。 foo_pass を持っているホストで1回だけ実行すれば、他のホストでも変数が使えるのでこのように設定しておきます。あとは、これを後ろのタスクで通常通り変数として使っていくことができます。以下は configure_usertrue のときだけ、 foo というユーザーを作る例です。

- block:
  - name: Prompt password
    pause:
      prompt: Enter the crypted password
      echo: no
    register: foo_pass
  - name: Set password fact
    set_fact:
      foo_pass: "{{ foo_pass.user_input }}"
    run_once: true
  - name: Configure user
    user:
      name: foo
      password: "{{ vars['foo_pass'] }}"
      state: present
    when: vars['foo_pass'] | length > 0
  when: configure_user

こちら のリポジトリにサンプルを公開しているのでぜひ試してみて下さい。

© 2018. SuperSoftware Co., Ltd. All Rights Reserved.