前職(情シス)ではMacをユーザ用の端末として配っていて、これの初期セットアップ自動化できないかなーと思いつつ他の色々に追われて後回しになってたのを、自宅のMacのOS初期化に合わせてちょっと考えてみることにした。
概ねはhomebrewとcaskで入れるもん入れて、あとは手じゃないとできないことをやる、という感じだったが、 MacAppStoreのものはmas-cliでなんとかなるので、これくらいはAnsibleで面倒見れてもいいはず。でもプラグインない。じゃあなんとかしないとな、という話。
準備
mas-cliをインストールする。homebrewで入れられるので、mas-cli用の処理より前にPlaybookに書いとくとか、初っ端に手で打っとけばいいと思う。
brew install mas
プラグインの代わり
ただべた書きでscriptモジュールを使うのはなんか違う気がするので、冪等性を担保できそうなスクリプトを書きたい。
#!/bin/bash
APPID=$1
## Argument check
test $# -eq 1 || exit 2
## App check
mas list 2> /dev/null | grep -q "^${APPID} " && exit 0
## App install
mas install ${APPID} > /dev/null 2>&1 || exit 3
## Normal termination
exit 1
- App checkで既にインストール済みかチェック、あったら0を返す
- App installでインストール、失敗したら3を返す
- 最後まで行ったら1を返す
これで、0ならok、1ならchanged、それ以外ならfailedになるようにAnsible側でしておけば、問題ないはず。多分。
Playbook
処理部分
- name: mas install
script: 'mas.sh {{ item.id }}'
with_items: '{{ mac_apps }}'
register: result
changed_when: result.rc == 1
failed_when: result.rc not in [0, 1]
上に書いたとおりになるように、changed_whenとfailed_whenを定義しておく。not in [0, 1]
みたいな書き方ができるのが楽でいい。
アプリ定義
mac_apps:
- id: 409201541
name: Pages
- id: 409203825
name: Numbers
- id: 409183694
name: Keynote
IDと名前を書いておく。mas-cliではIDしか使わないけど、こうしておかないと後から見たときに分からなくなる。コメントで名前を書いておいてもいいけど、そうするとAnsibleの実行結果に名前が出ないので、この方が都合が良い。
動作確認
事前の状態を確認
$ mas list
409203825 Numbers (5.3)
409183694 Keynote (8.3)
NumbersとKeynoteだけ入れた状態なのを確認する。
Ansible実行
Ansibleで用意したPlaybookを読ませて実行する。
TASK [mas : mas install] *****************************************************
changed: [localhost] => (item={'id': 409201541, 'name': 'Pages'})
ok: [localhost] => (item={'id': 409203825, 'name': 'Numbers'})
ok: [localhost] => (item={'id': 409183694, 'name': 'Keynote'})
入ってないPagesはchangedになってて、他はokになってる。変なエラーも出てない。
事後確認
mas-cli
$ mas list
409203825 Numbers (5.3)
409183694 Keynote (8.3)
409201541 Pages (7.3)
Pages、Numbers、Keynoteが入ってて、余計なものもなし。
Ansible
TASK [mas : mas install] *****************************************************
ok: [localhost] => (item={'id': 409201541, 'name': 'Pages'})
ok: [localhost] => (item={'id': 409203825, 'name': 'Numbers'})
ok: [localhost] => (item={'id': 409183694, 'name': 'Keynote'})
全部ok。
終わりに
期待通りにできたけど、しっかりテストしたわけではないので、何か見落としがありそうで怖い。
あと、mas-cliで使うアプリのIDはGoogleなんかでmacappstore [アプリ名]
とかで検索して、AppStore(iOS用のストアも場合によっては出るので注意が必要)のURL (例:https://itunes.apple.com/jp/app/pages/id409201541?mt=12) から調べるしかなさそうなのがちょっとめんどくさい。でも用途が環境復元のためで、初回に調べてそれ以降ほとんど増えることもないから、最初だけ泥臭く頑張るしかない。でもダサいのでどうにかできたらどうにかしたい。