novaとcinderホストにおけるmy_ip設定

novaとcinderの設定ファイルでは、my_ipというパラメータで自身のIPアドレスを指定できます。
必須パラメータというわけでもないので特に指定していなかったのですが、そのせいでちょっと残念な挙動になったのでメモ。

■設定ファイルの値を取り込む(flags.py)

設定ファイルから値を取り込む処理は、flags.pyの中に書かれています。

●global_opts

設定ファイル(nova.conf/cinder.conf)の内容を取得するflags.pyの中では以下のように書かれています。

global_opts = [
    cfg.StrOpt('my_ip',
               default=_get_my_ip(),
               help='ip address of this host'),
    <...省略...>
]

_get_my_ip()が呼ばれて戻り値がデフォルトのmy_ipの値になる訳ですね。なるほど。

●_get_my_ip()

うぅ...8.8.8.8:80にconnectしてる...これ、某社のpublic dns(だよね?)だけど、ほんとにコレでいいの!?
クローズドな環境だと当然ながらsocket.errorになるので127.0.0.1になります。
cinderだと、iscsi_ip_addressが指定されていないと、こいつがiscsiターゲットのIPとして利用されるみたいなので、ヘタをするとcsock.getsockname()が返す表側のインターフェイスを回ってiscsiの通信が行われることになります。

def _get_my_ip():
    """
    Returns the actual ip of the local machine.

    This code figures out what source address would be used if some traffic
    were to be sent out to some well known address on the Internet. In this
    case, a Google DNS server is used, but the specific address does not
    matter much.  No traffic is actually sent.
    """
    try:
        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        csock.connect(('8.8.8.8', 80))       <--- ナニコレ!あんまりよ!
        (addr, port) = csock.getsockname()
        csock.close()
        return addr
    except socket.error:
        return "127.0.0.1"

■結論

以上、そんなわけだから、my_ipはちゃんと設定ファイルに書きましょうね!という話でした。