ansibleではuserモジュールでuserの作成ができますが、userがcreateされた時だけ、処理を実行したい場合があります。例えばpasswdの有効期限の設定とか。
私が今いるところでは、「初回時にデフォルトパスワードを有効期限切れにして、かつパスワードの有効期限を180日にする」というポリシーがあります。
これはshellでchage(読み方はチャゲですかね...)
chage -d 0 -M 180 ${USER_NAME}
で設定できます。なので、これをcreateされた時だけ、ansibleで実行すればいいわけです。
でも、userの中には
- state=presentだけど、すでに存在するので作らないアカウント
- state=presentとなっているけど、まだいないので作成するアカウント
が当然いるわけですね。
なので、userモジュールの対象となるユーザファイルのアカウントすべてで上記のchageコマンドを実行するのではなく、あくまでcreateされた時だけ実行する必要あります。
(ansibleには当然冪等性があるので、今いる人もこれから作る人も同じファイルで管理してます)。
userを作成するtask
モジュールでそこまで判定できればいいのですが、できません。なので、ユーザの作成を例えば下記のようなファイルを準備した上で実行するとして、
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