1つのロールでホスト毎に同一ユーザーを作成し、それぞれのユーザーにバラバラなパスワードを付けたい

例えばこんなhostsファイルがあったとして

```hosts:hosts
[web]
192.0.2.1
192.0.2.2
192.0.2.3
[db]
192.0.2.4
```

こんな感じで共通のロールを適用する際にOSユーザーとパスワードも設定したい、ポリシー上パスワードの使い回しは厳禁なので全てユニークにしたい場合の方法

```yaml:site.yml
---
- hosts: all
  roles:
    - common
   .
   .
   .
```

#lookup pluginの作成
Jinja2で用意されてるフィルタってやつでいい感じにできるのかなと思ったけど探しても見つからなかった。
結局ansibleに用意されている[lookup plugin](http://docs.ansible.com/ansible/playbooks_lookups.html)という機能を利用することにした。
元々ansibleにはパスワード用プラグインも用意されているけど、どうも一度生成したパスワードはファイルに書き込んで、二度目以降はそのファイルの中身を参照するようになってて今回の用途には合わないので、既存のプラグインをちょっと改造
元々のコードは[password.py][]

[password.py]:https://raw.githubusercontent.com/ansible/ansible/stable-2.1/lib/ansible/plugins/lookup/password.py

改造した部分の抜粋

```python:password-uniq.py
    def run(self, terms, variables, **kwargs):

        ret = []

        for term in terms:
            relpath, params = _parse_parameters(term)

            # get password or create it if file doesn't exist
            path = self._loader.path_dwim(relpath)
            if not os.path.exists(path):
                pathdir = os.path.dirname(path)
                try:
                    makedirs_safe(pathdir, mode=0o700)
                except OSError as e:
                    raise AnsibleError("cannot create the path for the password lookup: %s (error was %s)" % (pathdir, str(e)))

            chars = "".join(getattr(string, c, c) for c in params['chars']).replace('"', '').replace("'", '')
            password = ''.join(random.choice(chars) for _ in range(params['length']))

            if params['encrypt'] is not None:
                salt = self.random_salt()
                content = '%s salt=%s' % (password, salt)
            else:
                content = password
            with open(path, 'a') as f:
                os.chmod(path, 0o600)
                f.write(content + '\n')

            if params['encrypt']:
                password = do_encrypt(password, params['encrypt'], salt=salt)

            ret.append(password)

        return ret
```

[password.py][]との差分

```diff
124,125c124,125
<                 chars = "".join(getattr(string, c, c) for c in params['chars']).replace('"', '').replace("'", '')
<                 password = ''.join(random.choice(chars) for _ in range(params['length']))
---
>             chars = "".join(getattr(string, c, c) for c in params['chars']).replace('"', '').replace("'", '')
>             password = ''.join(random.choice(chars) for _ in range(params['length']))
127,134c127,129
<                 if params['encrypt'] is not None:
<                     salt = self.random_salt()
<                     content = '%s salt=%s' % (password, salt)
<                 else:
<                     content = password
<                 with open(path, 'w') as f:
<                     os.chmod(path, 0o600)
<                     f.write(content + '\n')
---
>             if params['encrypt'] is not None:
>                 salt = self.random_salt()
>                 content = '%s salt=%s' % (password, salt)
136,156c131,134
<                 content = open(path).read().rstrip()
<
<                 password = content
<                 salt = None
<
<                 try:
<                     sep = content.rindex(' salt=')
<                 except ValueError:
<                     # No salt
<                     pass
<                 else:
<                     salt = password[sep + len(' salt='):]
<                     password = content[:sep]
<
<                 if params['encrypt'] is not None and salt is None:
<                     # crypt requested, add salt if missing
<                     salt = self.random_salt()
<                     content = '%s salt=%s' % (password, salt)
<                     with open(path, 'w') as f:
<                         os.chmod(path, 0o600)
<                         f.write(content + '\n')
---
>                 content = password
>             with open(path, 'a') as f:
>                 os.chmod(path, 0o600)
>                 f.write(content + '\n')
```

プラグインで指定したパスに元々ファイルが存在した場合もパスワードを生成してファイルに追記するようにしただけ

これをplaybookのディレクトリにlookup_pluginsってディレクトリに「{{ 任意の名前 }}.py」として放り込んでやると「{{ 任意の名前 }}」で呼び出せる

```yaml:main.yml
- name: 管理者ユーザー追加
  user: name={{ item.name }} password={{ item.user_pass }}
  with_items:
    - { name: 'admin1', user_pass: "{{ lookup('password-uniq','~/playbook/.pass/user-pass')  }}" }

```

これを実行するとそれぞれのユーザーのパスワードがユニークになる

```
TASK [common : 管理者ユーザー追加] *************************************************
changed: [192.0.2.1] => (item={u'name': u'admin1', u'user_pass': u'nyan'})
changed: [192.0.2.2] => (item={u'name': u'admin1', u'user_pass': u'wan'})
changed: [192.0.2.3] => (item={u'name': u'admin1', u'user_pass': u'caa'})
changed: [192.0.2.4] => (item={u'name': u'admin1', u'user_pass': u'chun'})
```

パスワードはプラグインで指定したファイルに追記されるけど、特にホスト名と紐づけされた形で書かれるわけではないので注意

元々用意されてたパスワードプラグインを改造しただけなので、引数の詳細などは[ここ](http://docs.ansible.com/ansible/playbooks_lookups.html#the-password-lookup)を

参考：[Ansibleのlookup pluginについて調べてみた](http://qiita.com/yunano/items/4325935b8567572cc172 "Ansibleのlookup pluginについて調べてみた")