Proxy環境下でXenServerを使う

本稿では，XenServerをプロキシ環境下で使う場合にDebianやUbuntuの[Network Installation Notes](http://docs.vmd.citrix.com/XenServer/6.5.0/1.0/en_gb/guest.html#installingVM-guest_installer-network_repository)[^1]を使用すると，`xenopsd internal error`が出てゲストOSのカーネルが起動しない問題への対処法について説明します．
ちなみに，経緯としてはXenServerのドキュメント[^2] [^3] [^4]には記載がなく，ぐぐっても全然情報が出てこないので，コードをいじって対応しようとしたら既に[実装済み](https://github.com/xapi-project/xcp-eliloader/blob/164a7fd50896d747189c344d15895c6aa52748ad/eliloader#L891)でしたというお話．

[^1]: 表記ゆれがありますが，netboot, network install, webinstall, netinstallなんて言葉で呼ばれてるようです．
[^2]: [Citrix XenServer ® 6.5 Service Pack 1 Installation Guide](http://docs.vmd.citrix.com/XenServer/6.5.0/1.0/en_gb/guest.html)
[^3]: [Citrix XenServer ® 6.5 Service Pack 1 Virtual Machine User's Guide](http://docs.vmd.citrix.com/XenServer/6.5.0/1.0/en_gb/guest.html)
[^4]: [Citrix XenServer ® 6.5 Service Pack 1 Administrator's Guide](http://docs.vmd.citrix.com/XenServer/6.5.0/1.0/en_gb/reference.html)

# エラーの追跡
未対策のXenServer上でNetwork Installation Notesを実施すると，下記のエラーが発生します．`/usr/bin/eliloader`で指定されたインストールソースを発見できないとのこと．

```pytb
xenopsd internal error: VM = d795dc39-7539-267d-9977-26ec5ca09e42; domid = 16; Bootloader.Bad_error Traceback (most recent call last):
  File "/usr/bin/eliloader", line 1153, in ?
    sys.exit(main())
  File "/usr/bin/eliloader", line 1143, in main
    handle_first_boot(vm, img, args, other_config)
  File "/usr/bin/eliloader", line 872, in handle_first_boot
    kernel, ramdisk = debian_first_boot_handler(vm, repo_url, other_config)
  File "/usr/bin/eliloader", line 739, in debian_first_boot_handler
    fetchFile(vmlinuz_url, vmlinuz_file, pv_kernel_max_size)
  File "/usr/bin/eliloader", line 329, in fetchFile
    raise ResourceNotFound, source
__main__.ResourceNotFound
```

[`/usr/bin/eliloader`](https://github.com/xapi-project/xcp-eliloader/blob/master/eliloader)のコードを読んでみると，[891行目](https://github.com/xapi-project/xcp-eliloader/blob/164a7fd50896d747189c344d15895c6aa52748ad/eliloader#L891)にurllib2を使ったプロキシ関連の実装があります．[`other_config['install-proxy']`](https://github.com/xapi-project/xcp-eliloader/blob/164a7fd50896d747189c344d15895c6aa52748ad/eliloader#L892)からプロキシの接続先を取得していることがわかります．

```py3:/usr/bin/eliloader
    # Make urllib2 use proxy server if one is supplied
    proxy = other_config['install-proxy']
    if proxy:
        proxy_support = urllib2.ProxyHandler({"http" : proxy})
        opener = urllib2.build_opener(proxy_support)
        urllib2.install_opener(opener)
```

`other_config`は`canonicaliseOtherConfig`の返り値[(881行目)](https://github.com/xapi-project/xcp-eliloader/blob/164a7fd50896d747189c344d15895c6aa52748ad/eliloader#L881)で，
[`canonicaliseOtherConfig`](https://github.com/xapi-project/xcp-eliloader/blob/164a7fd50896d747189c344d15895c6aa52748ad/eliloader#L309)の中でXenAPIから取得されている[(314行目)](https://github.com/xapi-project/xcp-eliloader/blob/164a7fd50896d747189c344d15895c6aa52748ad/eliloader#L314)ことがわかります．

こんなわけで，VMのother_configにinstall-proxyをセットしてやればプロキシ環境下でも`/usr/bin/eliloader`が動作しそうだとわかります．

# 対処法
何も考えずにXenCenterとかを使ってインストール元URL(Install from URL)を指定した上でVMを作ります．CUIから実施する場合は，[Creating a Linux VM by Installing from an Internet Repository](http://docs.vmd.citrix.com/XenServer/6.5.0/1.0/en_gb/guest.html#linux_vm_internet_install)を参照．

この後，XenServerのコンソールから下記のコマンドを実行すると，プロキシの設定が追加される．

```bash
VMUUID=`xe vm-list name-label="<VMの名前>" --minimal`
xe vm-param-set uuid=$VMUUID other-config:install-proxy="<プロキシのURL>"

# 実行例はこんな感じ
VMUUID=`xe vm-list name-label="debian9" --minimal`
xe vm-param-set uuid=$VMUUID other-config:install-proxy="http://proxy.example.com:8080"
```

あとは通常通り起動すれば問題なく動作する．

# プロキシ設定済みのテンプレートを作る
毎回これをやるのが億劫なので，プロキシ設定済みのテンプレートを作ります．テンプレートをクローンしてパラメータを設定するだけです．

XenServerのコンソールから下記のコマンドを実行する．

```bash
BASEUUID=$(xe template-list name-label="<ベースとなるテンプレートの名前>" --minimal)
NEWUUID=$(xe vm-clone uuid=$BASEUUID new-name-label="<新しいテンプレートの名前>")
xe template-param-set uuid=$NEWUUID other-config:install-proxy="<プロキシのURL>" other-config:default_template=true
# 毎回ミラーを入れるのが面倒なので，ついでにその辺りのパラメータもセットする．
xe template-param-set other-config:install-methods=http other-config-install-repository=http://cdn.debian.or.jp/debian/

# 実行例はこんな感じ
BASEUUID=$(xe template-list name-label="Debian Wheezy 7.0 (64-bit)" --minimal)
NEWUUID=$(xe vm-clone uuid=$BASEUUID new-name-label="Debian Wheezy 7.0 (64-bit) with proxy")
xe template-param-set uuid=$NEWUUID other-config:install-proxy="http://proxy.example.com:8080" other-config:default_template=true
xe template-param-set other-config:install-methods=http other-config-install-repository=http://cdn.debian.or.jp/debian/
```

テンプレートの名前を変更するときは下記コマンドを実行する．

```bash
xe template-param-set uuid=`xe template-list name-label="<元の名前>" --minimal` name-label="<新しい名前>"
```