diff options
author | Tim Smith <tsmith@chef.io> | 2018-01-25 20:47:28 -0800 |
---|---|---|
committer | Tim Smith <tsmith@chef.io> | 2018-02-14 10:55:28 -0800 |
commit | 405bacfb425046d0d38521f738677d483e7cef4e (patch) | |
tree | 0e3bb266bf3e2d72689416768e2c268b5c5c9494 /lib/chef/resource | |
parent | c563a379b2ac9a47f5bd5c9e0c40bebed86aae8c (diff) | |
download | chef-405bacfb425046d0d38521f738677d483e7cef4e.tar.gz |
Add hostname resource from chef_hostname cookbook
Add in a new resource for managing hostnames
Signed-off-by: Tim Smith <tsmith@chef.io>
Diffstat (limited to 'lib/chef/resource')
-rw-r--r-- | lib/chef/resource/hostname.rb | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/lib/chef/resource/hostname.rb b/lib/chef/resource/hostname.rb new file mode 100644 index 0000000000..d7fed09b8c --- /dev/null +++ b/lib/chef/resource/hostname.rb @@ -0,0 +1,229 @@ +class Chef + class Resource + # Sets the hostname and updates /etc/hosts on *nix systems + # @since 14.0.0 + class Hostname < Chef::Resource + provides :hostname + resource_name :hostname + + property :hostname, String, name_property: true + property :compile_time, [ true, false ], default: true + property :ipaddress, [ String, nil ], default: lazy { node["ipaddress"] } + property :aliases, [ Array, nil ], default: nil + property :windows_reboot, [ true, false ], default: true + + default_action :set + + action_class do + def append_replacing_matching_lines(path, regex, string) + text = IO.read(path).split("\n") + text.reject! { |s| s =~ regex } + text += [ string ] + file path do + content text.join("\n") + "\n" + owner "root" + group node["root_group"] + mode "0644" + not_if { IO.read(path).split("\n").include?(string) } + end + end + + # read in the xml file used by Ec2ConfigService and update the Ec2SetComputerName + # setting to disable updating the computer name so we don't revert our change on reboot + # @return [String] + def updated_ec2_config_xml + begin + require "nokogiri" + config_file = 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml' + config = ::Nokogiri::XML(::File.read(config_file)) + # find an element named State with a sibling element whose value is Ec2SetComputerName + setting = config.at_xpath("//Plugin/State[../Name/text() = 'Ec2SetComputerName']") + setting.content = "Disabled" + rescue + return "" + end + config.to_s + end + end + + action :set do + ohai "reload hostname" do + plugin "hostname" + action :nothing + end + + if node["platform_family"] != "windows" + # set the hostname via /bin/hostname + declare_resource(:execute, "set hostname to #{new_resource.hostname}") do + command "/bin/hostname #{new_resource.hostname}" + not_if { shell_out!("hostname").stdout.chomp == new_resource.hostname } + notifies :reload, "ohai[reload hostname]" + end + + # make sure node['fqdn'] resolves via /etc/hosts + unless new_resource.ipaddress.nil? + newline = "#{new_resource.ipaddress} #{new_resource.hostname}" + newline << " #{new_resource.aliases.join(" ")}" if new_resource.aliases && !new_resource.aliases.empty? + newline << " #{new_resource.hostname[/[^\.]*/]}" + r = append_replacing_matching_lines("/etc/hosts", /^#{new_resource.ipaddress}\s+|\s+#{new_resource.hostname}\s+/, newline) + r.atomic_update false if docker? + r.notifies :reload, "ohai[reload hostname]" + end + + # setup the hostname to perist on a reboot + case + when ::File.exist?("/usr/sbin/scutil") + # darwin + declare_resource(:execute, "set HostName via scutil") do + command "/usr/sbin/scutil --set HostName #{new_resource.hostname}" + not_if { shell_out!("/usr/sbin/scutil --get HostName").stdout.chomp == new_resource.hostname } + notifies :reload, "ohai[reload hostname]" + end + declare_resource(:execute, "set ComputerName via scutil") do + command "/usr/sbin/scutil --set ComputerName #{new_resource.hostname}" + not_if { shell_out!("/usr/sbin/scutil --get ComputerName").stdout.chomp == new_resource.hostname } + notifies :reload, "ohai[reload hostname]" + end + shortname = new_resource.hostname[/[^\.]*/] + declare_resource(:execute, "set LocalHostName via scutil") do + command "/usr/sbin/scutil --set LocalHostName #{shortname}" + not_if { shell_out!("/usr/sbin/scutil --get LocalHostName").stdout.chomp == shortname } + notifies :reload, "ohai[reload hostname]" + end + when node["os"] == "linux" + case + when ::File.exist?("/usr/bin/hostnamectl") && !docker? + # use hostnamectl whenever we find it on linux (as systemd takes over the world) + # this must come before other methods like /etc/hostname and /etc/sysconfig/network + declare_resource(:execute, "hostnamectl set-hostname #{new_resource.hostname}") do + notifies :reload, "ohai[reload hostname]" + not_if { shell_out!("hostnamectl status", { :returns => [0, 1] }).stdout =~ /Static hostname:\s+#{new_resource.hostname}/ } + end + when ::File.exist?("/etc/hostname") + # debian family uses /etc/hostname + # arch also uses /etc/hostname + # the "platform: iox_xr, platform_family: wrlinux, os: linux" platform also hits this + # the "platform: nexus, platform_family: wrlinux, os: linux" platform also hits this + # this is also fallback for any linux systemd host in a docker container (where /usr/bin/hostnamectl will fail) + declare_resource(:file, "/etc/hostname") do + atomic_update false if docker? + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + when ::File.file?("/etc/sysconfig/network") + # older non-systemd RHEL/Fedora derived + append_replacing_matching_lines("/etc/sysconfig/network", /^HOSTNAME\s*=/, "HOSTNAME=#{new_resource.hostname}") + when ::File.exist?("/etc/HOSTNAME") + # SuSE/OpenSUSE uses /etc/HOSTNAME + declare_resource(:file, "/etc/HOSTNAME") do + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + when ::File.exist?("/etc/conf.d/hostname") + # Gentoo + declare_resource(:file, "/etc/conf.d/hostname") do + content "hostname=\"#{new_resource.hostname}\"\n" + owner "root" + group node["root_group"] + mode "0644" + end + else + # This is a failsafe for all other linux distributions where we set the hostname + # via /etc/sysctl.conf on reboot. This may get into a fight with other cookbooks + # that manage sysctls on linux. + append_replacing_matching_lines("/etc/sysctl.conf", /^\s+kernel\.hostname\s+=/, "kernel.hostname=#{new_resource.hostname}") + end + when ::File.exist?("/etc/rc.conf") + # *BSD systems with /etc/rc.conf + /etc/myname + append_replacing_matching_lines("/etc/rc.conf", /^\s+hostname\s+=/, "hostname=#{new_resource.hostname}") + + declare_resource(:file, "/etc/myname") do + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + when ::File.exist?("/etc/nodename") + # Solaris <= 5.10 systems prior to svccfg taking over this functionality (must come before svccfg handling) + declare_resource(:file, "/etc/nodename") do + content "#{new_resource.hostname}\n" + owner "root" + group node["root_group"] + mode "0644" + end + # Solaris also has /etc/inet/hosts (copypasta alert) + unless new_resource.ipaddress.nil? + newline = "#{new_resource.ipaddress} #{new_resource.hostname}" + newline << " #{new_resource.aliases.join(" ")}" if new_resource.aliases && !new_resource.aliases.empty? + newline << " #{new_resource.hostname[/[^\.]*/]}" + r = append_replacing_matching_lines("/etc/inet/hosts", /^#{new_resource.ipaddress}\s+|\s+#{new_resource.hostname}\s+/, newline) + r.notifies :reload, "ohai[reload hostname]" + end + when ::File.exist?("/usr/sbin/svccfg") + # Solaris >= 5.11 systems using svccfg (must come after /etc/nodename handling) + declare_resource(:execute, "svccfg -s system/identity:node setprop config/nodename=\'#{new_resource.hostname}\'") do + notifies :run, "execute[svcadm refresh]", :immediately + notifies :run, "execute[svcadm restart]", :immediately + not_if { shell_out!("svccfg -s system/identity:node listprop config/nodename").stdout.chomp =~ /config\/nodename\s+astring\s+#{new_resource.hostname}/ } + end + declare_resource(:execute, "svcadm refresh") do + command "svcadm refresh system/identity:node" + action :nothing + end + declare_resource(:execute, "svcadm restart") do + command "svcadm restart system/identity:node" + action :nothing + end + else + raise "Do not know how to set hostname on os #{node["os"]}, platform #{node["platform"]},"\ + "platform_version #{node["platform_version"]}, platform_family #{node["platform_family"]}" + end + + else # windows + + # suppress EC2 config service from setting our hostname + if ::File.exist?('C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml') + xml_contents = updated_ec2_config_xml + if xml_contents.empty? + Chef::Log.warn('Unable to properly parse and update C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml contents. Skipping file update.') + else + declare_resource(:file, 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml') do + content xml_contents + end + end + end + + # update via netdom + declare_resource(:powershell_script, "set hostname") do + code <<-EOH + $sysInfo = Get-WmiObject -Class Win32_ComputerSystem + $sysInfo.Rename("#{new_resource.hostname}") + EOH + notifies :request_reboot, "reboot[setting hostname]" + not_if { Socket.gethostbyname(Socket.gethostname).first == new_resource.hostname } + end + + # reboot because $windows + declare_resource(:reboot, "setting hostname") do + reason "chef setting hostname" + action :nothing + only_if { new_resource.windows_reboot } + end + end + end + + # this resource forces itself to run at compile_time + def after_created + if compile_time + Array(action).each do |action| + run_action(action) + end + end + end + end + end +end |