一見これで良さそうだが
Ansibleで対象ホストのIPアドレスを変更して、さらに処理が継続されるようなplaybookを考えてみる。
Ansible v2で操作対象がCentOS 7だと以下のような感じになる。
- hosts: all
tasks:
- (前処理)
- command: nmcli connection modify {{ nic }} ipv4.method manual ipv4.addresses {{ new_addr }}/{{ prefix }} ipv4.gateway {{ gateway }} ipv4.dns {{ dns }}
- shell: sleep 1; ifdown {{ nic }} && ifup {{ nic }}
async: -1
poll: 0
- block:
- lineinfile: dest=/etc/hosts backrefs=yes regexp='^S+( .*{{ inventory_hostname | regex_escape }}.*)$' line='{{ new_addr }}1'
- wait_for: host={{ new_addr }} port=22 delay=1 timeout=50
delegate_to: localhost
- (後続処理)
ここではAnsible実行側の/etc/hostsを使っている。処理対象のIPアドレス変更後に/etc/hostsも変更して、継続して処理ができるようしたわけだ。
.ssh/configなどを使っても同様のことができるだろう。
実際には
しかし一見上手く行きそうなこの方法だが、実際には大抵の環境で上手く行かない。
それは何故か。
AnsibleはSSH接続を行う時、標準設定だとControlMasterを使用している。ControlPersist=60sなので1分の間は接続先を覚えている。
従って如何に/etc/hostsなどを変更したとしても接続しに行く先はなお変更前のまま、というわけだ。
それではどうすれば良いか。
一例として接続元の残っているSSHプロセスをkillしてやるのが良い。
Ansibleの使っているControlPathは$HOME/.ansible/cp/ansible-ssh-%h-%p-%r
(%h,%p,%rはそれぞれ対象ホスト、対象ポート、対象ユーザ)なので以下のようにすれば良いだろう。
このやり方だとAnsible実行側で同じユーザが2つ以上Ansibleを実行していると良くないことが起こりそうだが、それはないこととしておく。
- hosts: all
tasks:
- (前処理)
- command: nmcli connection modify {{ nic }} ipv4.method manual ipv4.addresses {{ new_addr }}/{{ prefix }} ipv4.gateway {{ gateway }} ipv4.dns {{ dns }}
- shell: sleep 1; ifdown {{ nic }} && ifup {{ nic }}
async: -1
poll: 0
- block:
- command: pkill -f {{ lookup('pipe', 'echo $HOME') }}/.ansible/cp/ansible-ssh-
ignore_errors: yes
run_once: yes
- lineinfile: dest=/etc/hosts backrefs=yes regexp='^S+( .*{{ inventory_hostname | regex_escape }}.*)$' line='{{ new_addr }}1'
- wait_for: host={{ new_addr }} port=22 delay=1 timeout=50
delegate_to: localhost
- (後続処理)
なお、pkillのところは実害はあまりないがshellモジュールではエラーになったのでcommandモジュールを使っている。(理由を調べてはいない)
おまけ:nmcliモジュールなどここまで辿り着くまでの色々
この文章を書くのにnmcliモジュールを使おうとしたらipv4.methodを変更する方法がなくdhcpからautoにできなかったので没。
nmcliモジュールが使えるようになるまでも一苦労だったし。試行錯誤の結果、操作される側でyumで(インストールされていなければ)NetworkManager-glib, dbus-python, pygobject2をインストールし、pipでpython-nmcliをインストールするのが一番楽っぽい。
最初Fedora 23でやろうとしたらPython 3が標準になったせいでdnfモジュールすら動かないし。python2-dnfをインストールする必要があるのだが、dnfモジュールが使えないのでrawモジュールを使わなければならない。
なお、Fedora 23だと上記のnmcliモジュールに必要なpygobject2はpython-gobjectという名前に変わっている。