refactoring ubuntu/debian change_host_name
there's been a lot of churn around this code, so i figure it was worth trying to clean it up. - the methods were doing a lot, so make them into template methods with one helper per step - spread out /etc/hosts regexp into a couple of helper variables for clarity - remove handling for broken hostname implementations (like basing all of the checks on name.split('.')[0]), since it seems reasonable to remove code dedicated only to handling broken boxes - DRY up the shared code between debian/ubuntu implementations, which clarifies the differences as well - add unit tests around the behavior; this will help us in the future to separate flaws in our understanding from flaws in implementation - includes a new DummyCommunicator in tests which should be useful in supporting additional unit testing of this kind - manually tested this on squeeze, wheezy, precise, quantal, raring, and saucy successfully. handles the issue in #2333
This commit is contained in:
parent
0379853202
commit
688bca14f5
|
@ -3,33 +3,79 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
machine.communicate.tap do |comm|
|
||||
|
||||
# Get the current hostname
|
||||
# if existing fqdn setup improperly, this returns just hostname
|
||||
old = ''
|
||||
comm.sudo "hostname -f" do |type, data|
|
||||
if type == :stdout
|
||||
old = data.chomp
|
||||
end
|
||||
new(machine, name).change!
|
||||
end
|
||||
|
||||
# this works even if they're not both fqdn
|
||||
if old.split('.')[0] != name.split('.')[0]
|
||||
attr_reader :machine, :new_hostname
|
||||
|
||||
comm.sudo("sed -i 's/.*$/#{name.split('.')[0]}/' /etc/hostname")
|
||||
|
||||
# hosts should resemble:
|
||||
# 127.0.0.1 localhost host.fqdn.com host
|
||||
# 127.0.1.1 host.fqdn.com host
|
||||
comm.sudo("sed -ri 's@^(([0-9]{1,3}\.){3}[0-9]{1,3})\\s+(localhost)\\b.*$@\\1\\t\\3 #{name} #{name.split('.')[0]}@g' /etc/hosts")
|
||||
comm.sudo("sed -ri 's@^(([0-9]{1,3}\.){3}[0-9]{1,3})\\s+(#{old.split('.')[0]})\\b.*$@\\1\\t#{name} #{name.split('.')[0]}@g' /etc/hosts")
|
||||
|
||||
comm.sudo("hostname -F /etc/hostname")
|
||||
comm.sudo("hostname --fqdn > /etc/mailname")
|
||||
comm.sudo("ifdown -a; ifup -a; ifup eth0")
|
||||
def initialize(machine, new_hostname)
|
||||
@machine = machine
|
||||
@new_hostname = new_hostname
|
||||
end
|
||||
|
||||
def change!
|
||||
return unless should_change?
|
||||
|
||||
update_etc_hostname
|
||||
update_etc_hosts
|
||||
refresh_hostname_service
|
||||
update_mailname
|
||||
renew_dhcp
|
||||
end
|
||||
|
||||
def should_change?
|
||||
new_hostname != current_hostname
|
||||
end
|
||||
|
||||
def current_hostname
|
||||
@current_hostname ||= get_current_hostname
|
||||
end
|
||||
|
||||
def get_current_hostname
|
||||
sudo "hostname -f" do |type, data|
|
||||
return data.chomp if type == :stdout
|
||||
end
|
||||
''
|
||||
end
|
||||
|
||||
def update_etc_hostname
|
||||
sudo("echo '#{short_hostname}' > /etc/hostname")
|
||||
end
|
||||
|
||||
# /etc/hosts should resemble:
|
||||
# 127.0.0.1 localhost
|
||||
# 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}"
|
||||
expression = ['s', search, replace, 'g'].join('@')
|
||||
|
||||
sudo("sed -ri '#{expression}' /etc/hosts")
|
||||
end
|
||||
|
||||
def refresh_hostname_service
|
||||
sudo("hostname -F /etc/hostname")
|
||||
end
|
||||
|
||||
def update_mailname
|
||||
sudo("hostname --fqdn > /etc/mailname")
|
||||
end
|
||||
|
||||
def renew_dhcp
|
||||
sudo("ifdown -a; ifup -a; ifup eth0")
|
||||
end
|
||||
|
||||
def fqdn
|
||||
new_hostname
|
||||
end
|
||||
|
||||
def short_hostname
|
||||
new_hostname.split('.').first
|
||||
end
|
||||
|
||||
def sudo(cmd, &block)
|
||||
machine.communicate.sudo(cmd, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,45 +1,26 @@
|
|||
module VagrantPlugins
|
||||
module GuestUbuntu
|
||||
module Cap
|
||||
class ChangeHostName
|
||||
class ChangeHostName < VagrantPlugins::GuestDebian::Cap::ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
machine.communicate.tap do |comm|
|
||||
|
||||
# Get the current hostname
|
||||
# if existing fqdn setup improperly, this returns just hostname
|
||||
old = ''
|
||||
comm.sudo "hostname -f" do |type, data|
|
||||
if type == :stdout
|
||||
old = data.chomp
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
# this works even if they're not both fqdn
|
||||
if old.split('.')[0] != name.split('.')[0]
|
||||
|
||||
comm.sudo("sed -i 's/.*$/#{name.split('.')[0]}/' /etc/hostname")
|
||||
|
||||
# hosts should resemble:
|
||||
# 127.0.0.1 localhost
|
||||
# 127.0.1.1 host.fqdn.com host
|
||||
if name.split('.').length > 1
|
||||
# if there's an FQDN, put it in the right format
|
||||
comm.sudo("sed -ri 's@^(([0-9]{1,3}\.){3}[0-9]{1,3})\\s+(#{old.split('.')[0]})\\b.*$@\\1\\t#{name} #{name.split('.')[0]}@g' /etc/hosts")
|
||||
def refresh_hostname_service
|
||||
if hardy?
|
||||
# hostname.sh returns 1, so use `true` to get a 0 exitcode
|
||||
sudo("/etc/init.d/hostname.sh start; true")
|
||||
else
|
||||
# if there's not an FQDN, don't print the hostname twice
|
||||
comm.sudo("sed -ri 's@^(([0-9]{1,3}\.){3}[0-9]{1,3})\\s+(#{old.split('.')[0]})\\b.*$@\\1\\t#{name}@g' /etc/hosts")
|
||||
sudo("service hostname start")
|
||||
end
|
||||
end
|
||||
|
||||
if comm.test("[ `lsb_release -c -s` = hardy ]")
|
||||
# hostname.sh returns 1, so I grep for the right name in /etc/hostname just to have a 0 exitcode
|
||||
comm.sudo("/etc/init.d/hostname.sh start; grep '#{name}' /etc/hostname")
|
||||
else
|
||||
comm.sudo("service hostname start")
|
||||
end
|
||||
comm.sudo("hostname --fqdn > /etc/mailname")
|
||||
comm.sudo("ifdown -a; ifup -a; ifup -a --allow=hotplug")
|
||||
end
|
||||
def hardy?
|
||||
machine.communicate.test("[ `lsb_release -c -s` = hardy ]")
|
||||
end
|
||||
|
||||
def renew_dhcp
|
||||
sudo("ifdown -a; ifup -a; ifup -a --allow=hotplug")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,8 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
guest_capability("ubuntu", "change_host_name") do
|
||||
# ubuntu is just just a specialization of the debian code for this capability
|
||||
require_relative "../debian/cap/change_host_name"
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
|
|
@ -10,6 +10,7 @@ $:.unshift File.expand_path("../../", __FILE__)
|
|||
|
||||
# Load in helpers
|
||||
require "support/tempdir"
|
||||
require "unit/support/dummy_communicator"
|
||||
require "unit/support/dummy_provider"
|
||||
require "unit/support/shared/base_context"
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path("../../../../../base", __FILE__)
|
||||
require File.expand_path("../../../support/shared/debian_like_host_name_examples", __FILE__)
|
||||
|
||||
describe "VagrantPlugins::GuestDebian::Cap::ChangeHostName" do
|
||||
let(:described_class) do
|
||||
VagrantPlugins::GuestDebian::Plugin.components.guest_capabilities[:debian].get(:change_host_name)
|
||||
end
|
||||
let(:machine) { double("machine") }
|
||||
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
|
||||
|
||||
before do
|
||||
machine.stub(:communicate).and_return(communicator)
|
||||
communicator.stub_command('hostname -f', stdout: 'oldhostname.olddomain.tld')
|
||||
end
|
||||
|
||||
after do
|
||||
communicator.verify_expectations!
|
||||
end
|
||||
|
||||
describe ".change_host_name" do
|
||||
it_behaves_like "a debian-like host name change"
|
||||
|
||||
it "refreshes the hostname service with the hostname command" do
|
||||
communicator.expect_command(%q(hostname -F /etc/hostname))
|
||||
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
|
||||
end
|
||||
|
||||
it "renews dhcp on the system with the new hostname" do
|
||||
communicator.expect_command(%q(ifdown -a; ifup -a; ifup eth0))
|
||||
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
shared_examples "a debian-like host name change" do
|
||||
it "updates /etc/hostname on the machine" do
|
||||
communicator.expect_command(%q(echo 'newhostname' > /etc/hostname))
|
||||
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')
|
||||
end
|
||||
|
||||
it "does nothing when the provided hostname is not different" do
|
||||
described_class.change_host_name(machine, 'oldhostname.olddomain.tld')
|
||||
communicator.received_commands.should == ['hostname -f']
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path("../../../../../base", __FILE__)
|
||||
require File.expand_path("../../../support/shared/debian_like_host_name_examples", __FILE__)
|
||||
|
||||
describe "VagrantPlugins::GuestUbuntu::Cap::ChangeHostName" do
|
||||
let(:described_class) do
|
||||
VagrantPlugins::GuestUbuntu::Plugin.components.guest_capabilities[:ubuntu].get(:change_host_name)
|
||||
end
|
||||
let(:machine) { double("machine") }
|
||||
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
|
||||
|
||||
before do
|
||||
machine.stub(:communicate).and_return(communicator)
|
||||
communicator.stub_command('hostname -f', stdout: 'oldhostname.olddomain.tld')
|
||||
end
|
||||
|
||||
after do
|
||||
communicator.verify_expectations!
|
||||
end
|
||||
|
||||
describe ".change_host_name" do
|
||||
it_behaves_like "a debian-like host name change"
|
||||
|
||||
it "refreshes the hostname service with upstart" do
|
||||
communicator.expect_command(%q(service hostname start))
|
||||
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
|
||||
end
|
||||
|
||||
it "renews dhcp on the system with the new hostname (with hotplug allowed)" do
|
||||
communicator.expect_command(%q(ifdown -a; ifup -a; ifup -a --allow=hotplug))
|
||||
described_class.change_host_name(machine, 'newhostname.newdomain.tld')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,79 @@
|
|||
module VagrantTests
|
||||
module DummyCommunicator
|
||||
class Communicator < Vagrant.plugin("2", :communicator)
|
||||
def ready?
|
||||
true
|
||||
end
|
||||
|
||||
attr_reader :known_commands
|
||||
|
||||
def initialize(machine)
|
||||
@known_commands = Hash.new do |hash, key|
|
||||
hash[key] = { expected: 0, received: 0, response: nil }
|
||||
end
|
||||
end
|
||||
|
||||
def expected_commands
|
||||
known_commands.select do |command, info|
|
||||
info[:expected] > 0
|
||||
end
|
||||
end
|
||||
|
||||
def received_commands
|
||||
known_commands.select do |command, info|
|
||||
info[:received] > 0
|
||||
end.keys
|
||||
end
|
||||
|
||||
def stub_command(command, response)
|
||||
known_commands[command][:response] = response
|
||||
end
|
||||
|
||||
def expect_command(command)
|
||||
known_commands[command][:expected] += 1
|
||||
end
|
||||
|
||||
def received_summary
|
||||
received_commands.map { |cmd| " - #{cmd}" }.unshift('received:').join("\n")
|
||||
end
|
||||
|
||||
def verify_expectations!
|
||||
expected_commands.each do |command, info|
|
||||
if info[:expected] != info[:received]
|
||||
fail([
|
||||
"expected to receive '#{command}' #{info[:expected]} times",
|
||||
"got #{info[:received]} times instead",
|
||||
received_summary
|
||||
].join("\n"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def execute(command, opts=nil)
|
||||
known = known_commands[command]
|
||||
known[:received] += 1
|
||||
response = known[:response]
|
||||
return unless response
|
||||
|
||||
if block_given?
|
||||
[:stdout, :stderr].each do |type|
|
||||
Array(response[type]).each do |line|
|
||||
yield type, line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if response[:raise]
|
||||
raise response[:raise]
|
||||
end
|
||||
|
||||
response[:exit_code]
|
||||
end
|
||||
|
||||
def sudo(command, opts=nil, &block)
|
||||
execute(command, opts, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue