guests/{ubuntu,debian}: fix change_host_name for trailing dots [GH-2610]

When `/etc/hosts` contained a FQDN with a trailing dot, the `\b` in the
sed expression would not match, since dot is not considered to be a word
character.

Fix this by regexp-escaping the hostname search, and matching the end of
the line on optional space followed by additional characters.

Also add some tests that extract the regexp used by sed and verify that
it does what we want. These will hopefully serve us in the future if we
ever need to test additional edge cases.
This commit is contained in:
Paul Hinze 2013-12-09 14:47:28 -06:00
parent 25b0018759
commit abe0731d2e
4 changed files with 79 additions and 13 deletions

View File

@ -47,8 +47,8 @@ module VagrantPlugins
# 127.0.1.1 host.fqdn.com host.fqdn host
def update_etc_hosts
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
search = "^(#{ip_address})\\s+#{current_hostname}\\b.*$"
replace = "\\1\\t#{fqdn} #{short_hostname}"
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$"
replace = "\\1 #{fqdn} #{short_hostname}"
expression = ['s', search, replace, 'g'].join('@')
sudo("sed -ri '#{expression}' /etc/hosts")

View File

@ -7,10 +7,11 @@ describe "VagrantPlugins::GuestDebian::Cap::ChangeHostName" do
end
let(:machine) { double("machine") }
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
let(:old_hostname) { 'oldhostname.olddomain.tld' }
before do
machine.stub(:communicate).and_return(communicator)
communicator.stub_command('hostname -f', stdout: 'oldhostname.olddomain.tld')
communicator.stub_command('hostname -f', stdout: old_hostname)
end
after do

View File

@ -4,15 +4,6 @@ shared_examples "a debian-like host name change" do
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
end
it "flips out the old hostname in /etc/hosts" do
sed_find = '^(([0-9]{1,3}\.){3}[0-9]{1,3})\s+oldhostname.olddomain.tld\b.*$'
sed_replace = '\1\tnewhostname.newdomain.tld newhostname'
communicator.expect_command(
%Q(sed -ri 's@#{sed_find}@#{sed_replace}@g' /etc/hosts)
)
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
end
it "updates mailname to prevent problems with the default mailer" do
communicator.expect_command(%q(hostname --fqdn > /etc/mailname))
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
@ -22,4 +13,77 @@ shared_examples "a debian-like host name change" do
described_class.change_host_name(machine, 'oldhostname.olddomain.tld')
communicator.received_commands.should == ['hostname -f']
end
describe "flipping out the old hostname in /etc/hosts" do
let(:sed_command) do
# Here we run the change_host_name through and extract the recorded sed
# command from the dummy communicator
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
communicator.received_commands.find { |cmd| cmd =~ /^sed/ }
end
# Now we extract the regexp from that sed command so we can do some
# verification on it
let(:expression) { sed_command.sub(%r{^sed -ri '\(.*\)' /etc/hosts$}, "\1") }
let(:search) { Regexp.new(expression.split('@')[1], Regexp::EXTENDED) }
let(:replace) { expression.split('@')[2] }
it "works on an simple /etc/hosts file" do
original_etc_hosts = <<-ETC_HOSTS.gsub(/^ */, '')
127.0.0.1 localhost
127.0.1.1 oldhostname.olddomain.tld oldhostname
ETC_HOSTS
modified_etc_hosts = original_etc_hosts.gsub(search, replace)
modified_etc_hosts.should == <<-RESULT.gsub(/^ */, '')
127.0.0.1 localhost
127.0.1.1 newhostname.newdomain.tld newhostname
RESULT
end
it "does not modify lines which contain similar hostnames" do
original_etc_hosts = <<-ETC_HOSTS.gsub(/^ */, '')
127.0.0.1 localhost
127.0.1.1 oldhostname.olddomain.tld oldhostname
# common prefix, but different fqdn
192.168.12.34 oldhostname.olddomain.tld.different
# different characters at the dot
192.168.34.56 oldhostname-olddomain.tld
ETC_HOSTS
modified_etc_hosts = original_etc_hosts.gsub(search, replace)
modified_etc_hosts.should == <<-RESULT.gsub(/^ */, '')
127.0.0.1 localhost
127.0.1.1 newhostname.newdomain.tld newhostname
# common prefix, but different fqdn
192.168.12.34 oldhostname.olddomain.tld.different
# different characters at the dot
192.168.34.56 oldhostname-olddomain.tld
RESULT
end
context "when the old fqdn has a trailing dot" do
let(:old_hostname) { 'oldhostname.withtrailing.dot.' }
it "modifies /etc/hosts properly" do
original_etc_hosts = <<-ETC_HOSTS.gsub(/^ */, '')
127.0.0.1 localhost
127.0.1.1 oldhostname.withtrailing.dot. oldhostname
ETC_HOSTS
modified_etc_hosts = original_etc_hosts.gsub(search, replace)
modified_etc_hosts.should == <<-RESULT.gsub(/^ */, '')
127.0.0.1 localhost
127.0.1.1 newhostname.newdomain.tld newhostname
RESULT
end
end
end
end

View File

@ -7,10 +7,11 @@ describe "VagrantPlugins::GuestUbuntu::Cap::ChangeHostName" do
end
let(:machine) { double("machine") }
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
let(:old_hostname) {'oldhostname.olddomain.tld' }
before do
machine.stub(:communicate).and_return(communicator)
communicator.stub_command('hostname -f', stdout: 'oldhostname.olddomain.tld')
communicator.stub_command('hostname -f', stdout: old_hostname)
end
after do