SONiCのconfig-setup hookを使ってみる

# SONiCのイメージ更新
PCやスマートフォンのOSはたびたびアップデートが発生します。機能の追加だったり、バグの修正であったり、理由はさまざまです。Windowsのように小さな更新がたくさん適用されるものもあれば、iOSのように更新の際にイメージを書き換えてしまうものもあります。

SONiCはホワイトボックススイッチ用のOSで、現在も開発が進んでいるため、日々機能が追加されたりバグが修正されたりしています。安定しているとはいいがたい最新の機能を試してみたいような場合には、都度スイッチにインストールされているSONiCを最新に入れ替える必要があります。

# SONiCのイメージ更新方法 - sonic_installer
SONiCのイメージを更新する方法はいくつかありますが、SONiCが動作している間に更新の準備を整え、再起動すれば新しいイメージで起動する、設定は新しいイメージに引き継がれる、という仕組みを実装しているのが`sonic_installer`です。

```
sonic_installer install sonic-broadcom.bin
```

実行すると、確認を求められ`yes`と打ち込むとインストールが実行されます。動作中のイメージが上書きされるわけではなく、SONiCの起動イメージはストレージ上に2種類存在することになります。これをGRUBのデフォルト起動エントリー指定によって切り替える仕組みです。

# sonic_installerの設定引継ぎ - config-setup
2020年2月現在、少なくともmasterブランチでは、[以前のエントリ](https://qiita.com/masru0714/items/efcf5640ea2c5b392504)で書いた`/etc/ssh`引継ぎパッチを当てることができなくなっています。`sonic_installer`周りのコードが大幅に書き換えられたからです。以前は`sonic_installer`の中に直接`cp`がべたっと書かれていたのですが、これが整理され、`config-setup`スクリプトを呼び出すように変更されています。ZTP (Zero Touch Provisioning - 自動的に初期設定を完了させる仕組み) に対応させる際に必要だったようです。ちなみに、`config-setup`は`bash`スクリプトです。

## config-setupの動作
使い方はパラメータなしで起動したときに表示されます。

```
 Usage:  config-setup < backup | boot | factory >

         backup  - Take a backup copy of SONiC configuration.
         boot    - Initialize/migrate SONiC configuration during system boot.
         factory - Create factory default SONiC configuration and save it to
                   to /etc/sonic/config_db.json.
```

`config-setup backup`を実行すれば(`/host/old_config/`に)バックアップが作られ、`config-setup boot`が実行されたときに(migration flagのファイルが存在していれば)バックアップから書き戻されるという動作になっています。

## hook
`/etc/ssh`を設定と同様にバックアップ、リストアしたいと考えたとき、まっさきに思いつくのはこの`config-setup`スクリプトを(以前`sonic_installer`に対してやったように)改造することでした。しかし、`config-setup`の中身を読んでいくと、どうやらその改造をしなくて済むらしいことがわかってきました。backupとmigrationの処理の前後にhookが用意されているのです。つまり、スクリプトには手を加えず、hook処理のファイルを置いておけば、イメージ更新時にバックアップされ、更新したイメージの起動時にリストアされるようなのです。

`config-setup`の中を調べると、`run_hookdir`によってhookが実行されることがわかります。そして、`run_hookdir`が呼び出されているのは3か所でした。

- 出荷時設定時の呼び出し (`generate_config`から呼ばれる)
- バックアップ時の呼び出し (`do_config_backup`から呼ばれる)
- リストア時の呼び出し (`do_config_migration`から呼ばれる)

# config-setup hookを用意する
せっかくなので作成方法を調べつつ、以前パッチで仕込んでいた`/etc/ssh`のバックアップとリストアをhookで実現してみます。

## バックアップ
呼び出し自体は下記のようになっています。

```
run_hookdir ${CONFIG_PRE_MIGRATION_HOOKS} ${CONFIG_SETUP_PRE_MIGRATION_FLAG}
```

変数ですが、下記のように定義されています。

```
CONFIG_PRE_MIGRATION_HOOKS=/etc/config-setup/config-migration-pre-hooks.d
CONFIG_SETUP_PRE_MIGRATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_pre_migration
```

ディレクトリの中に置かれているスクリプトを順次実行するようになっていますので、ディレクトリを掘って`/etc/ssh`をバックアップするスクリプトを用意します。

```sh:/etc/config-setup/config-migration-pre-hooks.d/00ssh
#!/bin/sh
mkdir -p /host/old_ssh
cp -ar /etc/ssh/* /host/old_ssh/
```

`. $script`で呼び出されるので実行権限をつける必要はないようです。つまり`#!/bin/sh`も不要なのですが、ファイルを開いたときにシェルスクリプトと一目でわかるようにおまじないな感じで残しています。

## リストア
バックアップと対応するようになっています。

呼び出し

```
run_hookdir ${CONFIG_POST_MIGRATION_HOOKS} ${CONFIG_SETUP_POST_MIGRATION_FLAG}
```

変数

```
CONFIG_POST_MIGRATION_HOOKS=/etc/config-setup/config-migration-post-hooks.d
CONFIG_SETUP_POST_MIGRATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_post_migration
```

用意するスクリプトは下記です。

```sh:/etc/config-setup/config-migration-post-hooks.d/00ssh
#!/bin/sh
cp -ar /host/old_ssh/* /etc/ssh/
rm -rf /host/old_ssh
```

## 動かしてみた

```
$ sudo sonic_installer install -y sonic-broadcom.bin
(中略)
Installed SONiC base image SONiC-OS successfully

Command: grub-set-default --boot-directory=/host 0

Command: config-setup backup
Taking backup of curent configuration

Command: sync;sync;sync

Command: sleep 3

Done
$ sudo shutdown -r now
$ Connection to XX.XXX.X.XXX closed by remote host.
Connection to XX.XXX.X.XXX closed.
host$ ssh admin@sonic
admin@XX.XXX.X.XXX's password:
```

hookは無事動いた!

のはいいのですが。更新後のディレクトリを眺めてみると問題が。

```
$ ls /etc/config-setup/
config-migration-post-hooks.d
```

**preどこいった!?**

# preを保存するhookを用意する

たしかにリストア時の処理だけやればいいならこれでいいんですけど、うーん。
しかたがないのでpreのバックアップ・リストアもhookに仕込むことにします。本当はpostと同じように最終的に`/etc/sonic/old_config/`に残るようにしておくのがいいんでしょうけど、そこは若干手抜きです。

バックアップ

```sh:/etc/config-setup/config-migration-pre-hooks.d/01pre-hooks
#!/bin/sh
cp -ar /etc/config-setup/config-migration-pre-hooks.d /host/
```

リストア

```sh:/etc/config-setup/config-migration-post-hooks.d/01pre-hooks
#!/bin/sh
cp -ar /host/config-migration-pre-hooks.d /etc/config-setup/
rm -rf /host/config-migration-pre-hooks.d
```

無事リストアされて、めでたしめでたし。

# おまけ: sonic_installerの新機能

```
$ sonic_installer
Usage: sonic_installer [OPTIONS] COMMAND [ARGS]...

  SONiC image installation manager

Options:
  --help  Show this message and exit.

Commands:
  binary_version   Get version from local binary image file
  cleanup          Remove installed images which are not current...
  install          Install image from local binary or URL
  list             Print installed images
  remove           Uninstall image
  rollback_docker  Rollback docker image to previous version
  set_default      Choose image to boot from by default
  set_next_boot    Choose image for next reboot (one time...
  upgrade_docker   Upgrade docker image from local binary or URL
```

docker imageをいじくるコマンドが増えているようです。イメージを更新しても動作中のコンテナには影響ないはずですし、動作に反映させる際に整合性など考えるとおそらく再起動が必要でしょうから、現時点ではあまり使い道がないような感じもします。デバッグはやりやすくなるのかもしれません。