ansibleでuserが作成された時にだけ何かの処理をしたい場合


ansibleではuserモジュールでuserの作成ができますが、userがcreateされた時だけ、処理を実行したい場合があります。例えばpasswdの有効期限の設定とか。
私が今いるところでは、「初回時にデフォルトパスワードを有効期限切れにして、かつパスワードの有効期限を180日にする」というポリシーがあります。
これはshellでchage(読み方はチャゲですかね...)

```
chage -d 0 -M 180　${USER_NAME}
```

で設定できます。なので、これをcreateされた時だけ、ansibleで実行すればいいわけです。

でも、userの中には

1. state=presentだけど、すでに存在するので作らないアカウント
2. state=presentとなっているけど、まだいないので作成するアカウント

が当然いるわけですね。
なので、userモジュールの対象となるユーザファイルのアカウントすべてで上記のchageコマンドを実行するのではなく、あくまでcreateされた時だけ実行する必要あります。
(ansibleには当然冪等性があるので、今いる人もこれから作る人も同じファイルで管理してます)。

## userを作成するtask
モジュールでそこまで判定できればいいのですが、できません。なので、ユーザの作成を例えば下記のようなファイルを準備した上で実行するとして、

```users_vars.yml
users:
- {name: ryo_user,
   uid: '500',
   home: /home/ryo_user,
   group: base_group,
   groups: user,
   passwd: '$6$rounds=100000$0tPrpjXqzj/4fMt7$ha73fP0ChovXoeO4MGf.UBLuX0RYEmn9fvuVACtA4sClZw7ePss/GWM0nLafhHgBZsPUuHu78Kx.6uaVa4ppI.',
   state: present }
- {name: ryo_admin,
   uid: '501',
   home: /home/ryo_admin,
   group: base_group,
   groups: admin,
   passwd: '$6$rounds=100000$ROsP2RU2MkCAVVvn$mM5wtX6Kf8KMLSdLCxkfbf1slX5ks4FdhuWAFHkvbmBdAI4lr7ZYoG4t3VGvK2f5SmhqMbltxWTpHS6fAuAYv1',
   state: present }
```
これを実行するために、下記のようなtaskを実行します。

```
- hosts: test
  remote_user: vagrant
  sudo: yes
  vars_files:
    - users_vars.yml
  tasks:
  - name: check user (present or absent)
    user:
      name="{{ item.name }}"
      uid="{{ item.uid }}"
      group="{{ item.group }}"
      groups="{{ item.groups }}"
      home="{{ item.home }}"
      password="{{ item.passwd }}"
      update_password="on_create"
      state="{{ item.state }}"
    register: user_add
    with_items: users
    tags:
      - users
```
## whenで条件をわける
先ほどのchageをcreateのときだけ実行するようにするには、(カッコ悪いですが)下記のtaskを追加します(追記で修正していますので、そっちも見てください)。


```
- name: passwd setting
  shell:
    "chage -d 0 -M 180 {{ item.item.name }}"
  when: item.changed == true and item.item.state == "present"
  with_items: user_add.results
  tags:
    - users
```

whenの条件が重要です。ここでやっているのは、
1. usersモジュールの結果がuser_addに入っていて、そのresultsでループを回す
2. resultsには作成されたユーザの情報や、createされたかどうか(item.changed == true)が入っているので、それを条件にする
3. itemの中に、さらにitemが入っていて、そのstateがpresentのときもand条件にする(absentでパスワード設定してもこけるので)
ということをしています。
ちょっとわかりにくいですね。user_addにどんな結果が入るのかというと下記のような感じです。


```
  1 ok: [192.168.33.12] => {
  2     "user_add": {
  3         "changed": true,
  4         "msg": "All items completed",
  5         "results": [
  6             {↲
  7                 "append": false,
  8                 "changed": false,
  9                 "comment": "",
 10                 "group": 11800,
 11                 "groups": "user",
 12                 "home": "/home/ryo_user",
 13                 "invocation": {
 14                     "module_args": "name=\"ryo_user\" uid=\"500\" group=\"base_group\" groups=\"user\" home=\"/home/ryo_user\" password=\"$6$rounds=100000$0tPrpjXqzj/4fMt7$ha73fP0ChovXoeO4MGf.UBLuX0RYEmn9f    vuV$
 15 CtA4sClZw7ePss/GWM0nLafhHgBZsPUuHu78Kx.6uaVa4ppI.\" update_password=\"on_create\" state=\"present\"",
 16                     "module_name": "user"
 17                 },
 18                 "item": {
 19                     "group": "base_group",
 20                     "groups": "user",
 21                     "home": "/home/ryo_user",
 22                     "name": "ryo_user",
 23                     "passwd": "$6$rounds=100000$0tPrpjXqzj/4fMt7$ha73fP0ChovXoeO4MGf.UBLuX0RYEmn9fvuVACtA4sClZw7ePss/GWM0nLafhHgBZsPUuHu78Kx.6uaVa4ppI.",
 24                     "state": "present",
 25                     "uid": "500"
 26                 },
 27                 "move_home": false,
 28                 "name": "ryo_user",
 29                 "password": "NOT_LOGGING_PASSWORD",
 30                 "shell": "/bin/bash",
 31                 "state": "present",
 32                 "uid": 500
 33             },
 34                         {
 35                 "changed": true,
 36                 "comment": "",
 37                 "createhome": true,
 38                 "group": 11800,
 39                 "groups": "admin",
 40                 "home": "/home/ryo_admin",
 41                 "invocation": {
 42                     "module_args": "name=\"ryo_admin\" uid=\"501\" group=\"base_group\" groups=\"admin\" home=\"/home/ryo_admin\" password=\"$6$rounds=100000$ROsP2RU2MkCAVVvn$mM5wtX6Kf8KMLSdLCxkfbf1slX5ks4    Fdh$WAFHkvbmBdAI4lr7ZYoG4t3VGvK2f5SmhqMbltxWTpHS6fAuAYv1\" update_password=\"on_create\" state=\"present\"",
 43                     "module_name": "user"
 44                 },
 45                 "item": {
 46                     "group": "base_group",
 47                     "groups": "admin",
 48                     "home": "/home/ryo_admin",
 49                     "name": "ryo_admin",
 50                     "passwd": "$6$rounds=100000$ROsP2RU2MkCAVVvn$mM5wtX6Kf8KMLSdLCxkfbf1slX5ks4FdhuWAFHkvbmBdAI4lr7ZYoG4t3VGvK2f5SmhqMbltxWTpHS6fAuAYv1",
 51                     "state": "present",
 52                     "uid": "501"
 53                 },
 54                 "name": "ryo_admin",
 55                 "password": "NOT_LOGGING_PASSWORD",
 56                 "shell": "/bin/bash",
 57                 "state": "present",
 58                 "system": false,
 59                 "uid": 501
 60             }
 61         ]
 62     }
 63 }
 ```

resultsのvalue(5行目)がリストになっていて、その中にさらにitemが入っていて、そこにnameとかstateとかが入っているのがわかります(18行目、45行目)。今回の例では、ryo_userはすでに存在するアカウントで、ryo_adminは新しく作られたアカウントです。なので、前者は(8行目　changed: false)、後者は(35行目 changed: ture)となっているのがわかります。

最初のchanged:true(3行目)はこのタスク全体の結果なので、ユーザひとりひとりが作成されたかどうかでは関係ないです。間違えないように気をつけてください。こんなふうに実行結果の変数を別のタスクの変数として使うと、たとえばuserがcreateされたとき、つまりchangedがtureになっているとき、という条件で何かしらのtasksを実行させることができます。

と、つらつらと書いてきましたが、他にもっとスマートな方法があれば教えていただきたいです。。

## 追記
whenで、

```
when: item.changed == true and item.item.state == "present"
```

としましたが、これだと、ユーザアカウントが作られた時だけでなく、サブグループが変わった時も実行されてしまいます...。なので下記のようにします。

```
when: item.createhome is defined and item.createhome == true
```

### createhomeって
ansibleのuserモジュールでは、userが作成されて、createhomeされた時だけ、createhomeという変数がdefinedされます。常にcreatehomeがdefinedされていると、前半の`is defined`はもちろんいらないのですが、この変数、ユーザが作成されたタイミングでしかdefinedされません。なので、ユーザがすでに存在する場合、whenでこけてしまいます。ということで、definedされてかつそれがtrueという条件が必要になります。`state == present`は`createhome == true`に自動的に内包されるので、外せます。

### ということで
下記のようにすると、ユーザが追加された時だけskipされずにじっこうされます。

```
- name: passwd setting
  shell:
    "chage -d 0 -M 180 {{ item.item.name }}"
  when: item.createhome is defined and item.createhome == true
  with_items: user_add.results
  tags:
    - users
```