Macの初期セットアップをAnsibleで自動化する ~ osx_defaultsモジュール編 ~



これは [Ansible Blogger 2018 （sponsored by Red Hat） Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ansibleblogger) の10日目の記事です。

今回はMacをセットアップするときに役立つ `osx_defaults` を紹介したいとおもいます。

PCのセットアップは個人だとそんなに機会は多くないですが、会社だと新しいPCを導入するたびにセットアップする必要があります。
僕の場合は会社のPCのセットアップはAnsibleを使って自動化させていますし、もちろん個人のPCもAnsibleを使ってセットアップしてます。 
https://github.com/winky/mac-provisioning

## 1. osx_defaultsモジュールとは
Ansible v2.0から導入された macの `defaults` コマンドで設定できる内容をAnsibleから設定するためのモジュールです。
https://docs.ansible.com/ansible/latest/modules/osx_defaults_module.html

`defaults` コマンドを使うことで普段`システム環境設定`からGUIで設定している内容をCUIから操作できるようになり、Macのほとんどの設定を自動化することができます。
またスクリーンセーバーの起動時間や共有設定、アカウント設定などの設定内容を一元化できるので企業内におけるMacのセキュリティ設定などを共通化させることもできます。

## 2. 使い方
[個人用のPlaybook](https://github.com/winky/mac-provisioning/tree/master/ansible)を例にしていきます。

## 2-1. ディレクトリ構成
https://github.com/winky/mac-provisioning/tree/master/ansible/roles

```
roles
├── brew
│   ├── defaults
│   │   └── main.yml
│   └── tasks
│       ├── app.yml
│       ├── configure.yml
│       ├── install.yml
│       └── main.yml
︙
├── macos
│   ├── defaults
│   │   └── main.yml
│   ├── handlers
│   │   └── main.yml
│   └── tasks
│       ├── defaults.yml
│       ├── main.yml
│       ├── network.yml
│       └── user.yml
︙
```

`osx_defautls` モジュールを実行するroleは `roles/macos/tasks/defaults.yml` と `roles/macos/defaults/main.yml` に書いています。

## 2-2. 使用例
```defaults.yml
#
# macos/tasks/default.yml
# macos defaults settings
#
- name: set NSGlobalDomain
  osx_defaults:
    host: "{{ item.host | default() }}"
    key: "{{ item.key }}"
    type: "{{ item.type }}"
    value: "{{ item.value }}"
  with_items: "{{ global_defaults }}"
  tags:
    - setting

- name: set com.apple defaults
  osx_defaults:
    host: "{{ item.host | default() }}"
    domain: "com.apple.{{ item.domain }}"
    key: "{{ item.key }}"
    type: "{{ item.type }}"
    value: "{{ item.value | default() }}"
  register: defaults_out
  with_items:
    - "{{ apple_defaults }}"
  tags:
    - setting

- debug: var=defaults_out
```

`osx_defauls` モジュールのパラメータの１つ `domain` に関してはデフォルトでは `NSGlobalDomain` というMac全体に関する設定 (言語設定など）　が含まれていて、僕の場合は `domain` ごとにtaskを分けています。

そしてこのtaskに渡す変数を `roles/macos/defaults/main.yml` に書きます。

```main.yml
global_defaults:
  ###############################################################################
  # General
  ###############################################################################
  # InterfaceStyle
  - key: AppleInterfaceStyle
    type: string
    value: Dark
  ###############################################################################
  # Language & Region
  ###############################################################################
  # Langages
  - key: AppleLanguages
    type: array
    value:
      - "en-JP"
      - "ja-JP"
  - key: AppleLocale
    type: string
    value: "en_JP"
  - key: AppleMeasurementUnits
    type: string
    value: Centimeters
  - key: AppleTemperatureUnit
    type: string
    value: Celsius
  - key: AppleMetricUnits
    type: bool
    value: true

apple_defaults:
  ###############################################################################
  # Finder
  ###############################################################################
  # Finder: Hide files and folders on Desktop
  - domain: finder
    key: CreateDesktop
    type: bool
    value: false
  # Finder: Show dotfiles
  - domain: finder
    key: AppleShowAllFiles
    type: bool
    value: true
  - domain: systemuiserver
    key: menuExtras
    type: array
    value:
      - "/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
      - "/System/Library/CoreServices/Menu Extras/Battery.menu"
      - "/System/Library/CoreServices/Menu Extras/Clock.menu"
```


上記のPlaybookを実行すると

- Darkモードにする
- 言語設定を英語にする
- デスクトップのファイルとフォルダを隠す
- 隠しファイルを表示する
- メニューバーに `Bluetooth`, `バッテリー`, `時計`を表示する

という５つの内容が設定されます。

## 2-3. 注意点
`osx_defaults` モジュールでは `type` として `array` を指定できるのですが、このとき `value` としてはこのように書きます。

```
value:
  - "/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
  - "/System/Library/CoreServices/Menu Extras/Battery.menu"
  - "/System/Library/CoreServices/Menu Extras/Clock.menu"
```

`array` だからとこのように書くとうまく配列として認識してくれないので注意が必要です。

```
value:
  - "{/System/Library/CoreServices/Menu Extras/Bluetooth.menu, /System/Library/CoreServices/Menu Extras/Battery.menu, /System/Library/CoreServices/Menu Extras/Clock.menu}"
```

##2-4. defaultsの設定内容
Ansibleから少し外れますが、実はこのモジュールを使う上での一番の厄介どころは `defaults`　の公式的な設定内容がどこにもないのです。
じゃあどうやってこの設定内容を探してきて書いているかというのをまとめておきます。

- 現在の設定内容を書き出す  
下記のコマンドを実行することで現在の設定内容が `before_defaults` ファイルに書き出されます。  

```
$ defaults read > before_defaults
```

- システム環境設定から設定したい内容を変更してみる  
例えばMojaveから導入されたダークテーマに変更してみます。

- 変更後の設定内容を書き出す  
1と同じように `defaults read` コマンドで変更後の設定内容を `after_defaults` ファイルに書き出します。

```
$ defaults read > after_defaults
```

- 差分表示  
変更前と変更後の差分を表示してダークモードにするための設定項目を確認します。

```
$ diff before_defaults after_defaults
108a109
>         AppleInterfaceStyle = Dark;
```

これでどの項目を設定すれば `defautls` コマンドでダークモードにすることができるかわかります。

また有志の方が設定内容をまとめてくださっているのでそちらを参考にしてみるのもいいでしょう。

- https://qiita.com/djmonta/items/17531dde1e82d9786816
- https://github.com/hjuutilainen/dotfiles/tree/master/bin


## まとめ
セットアップの自動化というと `homebrew` とか `homebrew_cask` が有名かなと思い今回は `osx_defaults` を取り上げてみました。
`brew install` とかは自動化してるけど、システム環境設定に関しては手動でGUIをいじっているという人もいると思うので、ぜひこのモジュールを使って完全自動化してみてください。