Chefレシピの中でsshdのポートを変更した時、プロビジョニングやloginの際に、変更前後でtest-kitchen
などの設定を都度変えないといけない。
めんどくさいので、複数のsshポートの候補から接続可能なポートを探しだして決定する機構がないか探したが、ちょっと探した感じだと見当たらなかったのでモンキーパッチ当てて逃げた。
実装
sshd
のlisten
ポートが
-
22
=>2222
と変わる場合に、
.kitchen.yml
driver:
name: vagrant
network:
- ["forwarded_port", {guest: 22, host: 2200}]
- ["forwarded_port", {guest: 2222, host: 2201}]
provisioner:
name: chef_solo
platforms:
- name: centos-6.4
と変更前後のポートフォワーディングを共に設定した上で
# -*- encoding: utf-8 -*-
module Kitchen
class SSH
def login_command
args = %W{ -o UserKnownHostsFile=/dev/null }
args += %W{ -o StrictHostKeyChecking=no }
args += %W{ -o IdentitiesOnly=yes } if options[:keys]
args += %W{ -o LogLevel=#{logger.debug? ? "VERBOSE" : "ERROR"} }
args += %W{ -o ForwardAgent=#{options[:forward_agent] ? "yes" : "no"} } if options.key? :forward_agent
Array(options[:keys]).each { |ssh_key| args += %W{ -i #{ssh_key}} }
args += %W{ -p #{port}}
args += %W{ #{username}@#{hostname}}
LoginCommand.new(["ssh", *args])
end
private
def establish_connection
logger.debug("[SSH] opening connection to #{self}")
Net::SSH.start(hostname, username, options.merge(port: port))
end
def port
rescue_exceptions = [
Errno::EACCES, Errno::EADDRINUSE, Errno::ECONNREFUSED,
Errno::ECONNRESET, Errno::ENETUNREACH, Errno::EHOSTUNREACH,
Net::SSH::Disconnect
]
@__port ||= candidacy_ports.find do |port|
retries = 3
begin
Net::SSH.start(hostname, username, options.merge(port: port))
true
rescue *rescue_exceptions => e
if (retries -= 1) > 0
logger.info("[SSH] connection failed, retrying (#{e.inspect})")
sleep 1
retry
else
logger.warn("[SSH] connection failed, terminating (#{e.inspect})")
false
end
end
end
if @__port.nil?
raise SSHFailed.new('not found enable ssh ports')
end
@__port
end
def candidacy_ports
yaml = YAML.load(
ERB.new(
open(yaml_path).read
).result
)
@_candidacy_ports ||= yaml['driver']['network'].map {|config| config[1]['host'] }
end
def yaml_path
File.expand_path(
File.join(
Dir.pwd,
ENV['KITCHEN_YAML'] || '.kitchen.yml'
)
)
end
end
end
このパッチをロードすると、候補となるポートをフォワードポートの中から探索していき、成功すると以後全てのssh接続で成功ポートを使用するようになる。
$ kitchen login centos-64
[SSH] connection failed, retrying (#<Errno::ECONNREFUSED: Connection refused - connect(2) for "127.0.0.1" port 2200>)
[SSH] connection failed, retrying (#<Errno::ECONNREFUSED: Connection refused - connect(2) for "127.0.0.1" port 2200>)
$$$$$$ [SSH] connection failed, terminating (#<Errno::ECONNREFUSED: Connection refused - connect(2) for "127.0.0.1" port 2200>)
Last login: Sat Jul 19 17:01:24 2014 from 10.0.2.2
[vagrant@centos-64 ~]$
明らかに内部実装に追従できないし、パッチにすべきではないではないんだけどとりあえず動かすことを優先でやった。
なので、test-kitchen
のバージョンによって動かない可能性が高いので注意。