diff --git a/cdist/conf/explorer/hostname b/cdist/conf/explorer/hostname index 7715c6b0..dca004d1 100755 --- a/cdist/conf/explorer/hostname +++ b/cdist/conf/explorer/hostname @@ -1,7 +1,6 @@ #!/bin/sh # -# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2019 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) # # This file is part of cdist. # @@ -19,7 +18,12 @@ # along with cdist. If not, see . # # +# Retrieve the running hostname +# -if command -v uname >/dev/null; then - uname -n +if command -v hostname >/dev/null +then + hostname +else + uname -n fi diff --git a/cdist/conf/type/__hostname/explorer/has_hostnamectl b/cdist/conf/type/__hostname/explorer/has_hostnamectl index 9040023d..2f531f30 100755 --- a/cdist/conf/type/__hostname/explorer/has_hostnamectl +++ b/cdist/conf/type/__hostname/explorer/has_hostnamectl @@ -21,4 +21,4 @@ # Check whether system has hostnamectl # -command -v hostnamectl || true +command -v hostnamectl 2>/dev/null || true diff --git a/cdist/conf/type/__hostname/explorer/hostname_file b/cdist/conf/type/__hostname/explorer/hostname_file deleted file mode 100755 index 6a00aa9f..00000000 --- a/cdist/conf/type/__hostname/explorer/hostname_file +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# -# 2014 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Retrieve the contents of /etc/hostname -# - -# Almost any distribution -if [ -f /etc/hostname ]; then - cat /etc/hostname -# SuSE -elif [ -f /etc/HOSTNAME ]; then - cat /etc/HOSTNAME -fi diff --git a/cdist/conf/type/__hostname/explorer/hostname_sysconfig b/cdist/conf/type/__hostname/explorer/hostname_sysconfig deleted file mode 100755 index d0d7b4e7..00000000 --- a/cdist/conf/type/__hostname/explorer/hostname_sysconfig +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# -# 2014 Nico Schottelius (nico-cdist at schottelius.org) -# -# This file is part of cdist. -# -# cdist is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# cdist is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with cdist. If not, see . -# -# -# Retrieve the contents of /etc/hostname -# - -if [ -f /etc/sysconfig/network ]; then - awk -F= '/^HOSTNAME=/ { print $2 }' /etc/sysconfig/network -fi diff --git a/cdist/conf/type/__hostname/explorer/max_len b/cdist/conf/type/__hostname/explorer/max_len new file mode 100644 index 00000000..fb863949 --- /dev/null +++ b/cdist/conf/type/__hostname/explorer/max_len @@ -0,0 +1,10 @@ +#!/bin/sh -e + +command -v getconf >/dev/null || exit 0 + +val=$(getconf HOST_NAME_MAX 2>/dev/null) || exit 0 + +if test -n "${val}" -a "${val}" != 'undefined' +then + echo "${val}" +fi diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 8b5797dd..ae224611 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -2,6 +2,7 @@ # # 2014-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) +# 2019 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) # # This file is part of cdist. # @@ -19,60 +20,81 @@ # along with cdist. If not, see . # -if [ -f "$__object/parameter/name" ]; then - name_should="$(cat "$__object/parameter/name")" -else - name_should="${__target_host%%.*}" -fi - os=$(cat "$__global/explorer/os") name_running=$(cat "$__global/explorer/hostname") -name_config=$(cat "$__object/explorer/hostname_file") -name_sysconfig=$(cat "$__object/explorer/hostname_sysconfig") has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") + +if test -s "$__object/parameter/name" +then + name_should=$(cat "$__object/parameter/name") +else + case $os + in + # RedHat-derivatives and BSDs + centos|fedora|redhat|scientific|freebsd|macosx|netbsd|openbsd) + # Hostname is FQDN + name_should="${__target_host}" + ;; + *) + # Hostname is only first component of FQDN + name_should="${__target_host%%.*}" + ;; + esac +fi + + ################################################################################ -# If everything is ok -> exit +# Check if the (running) hostname is already correct # -case "$os" in - archlinux|debian|suse|ubuntu|devuan|coreos|alpine) - if [ "$name_config" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then - exit 0 - fi - ;; - scientific|centos|freebsd|openbsd) - if [ "$name_sysconfig" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then - exit 0 - fi - ;; - *) - echo "Unsupported os: $os" >&2 - exit 1 - ;; -esac +test "$name_running" != "$name_should" || exit 0 + ################################################################################ # Setup hostname # -echo changed >> "$__messages_out" +echo 'changed' >>"$__messages_out" -# Use the good old way to set the hostname even on machines running systemd. -case "$os" in - archlinux|debian|ubuntu|devuan|centos|coreos|alpine) - printf "printf '%%s\\\\n' '$name_should' > /etc/hostname\\n" - echo "hostname -F /etc/hostname" +# Use the good old way to set the hostname. +case $os +in + alpine|debian|devuan|ubuntu) + echo 'hostname -F /etc/hostname' ;; - freebsd|openbsd) + archlinux) + echo 'command -v hostnamectl >/dev/null 2>&1' \ + "&& hostnamectl set-hostname '$name_should'" \ + "|| hostname '$name_should'" + ;; + centos|fedora|redhat|scientific|freebsd|netbsd|openbsd|gentoo|void) echo "hostname '$name_should'" ;; - suse) + macosx) + echo "scutil --set HostName '$name_should'" + ;; + solaris) + echo "uname -S '$name_should'" + ;; + slackware|suse|opensuse-leap) + # We do not read from /etc/HOSTNAME, because the running + # hostname is the first component only while the file contains + # the FQDN. echo "hostname '$name_should'" - printf "printf '%%s\\\\n' '$name_should' > /etc/HOSTNAME\\n" + ;; + *) + # Fall back to set the hostname using hostnamectl, if available. + if test -n "$has_hostnamectl" + then + # Don't use hostnamectl as the primary means to set the hostname for + # systemd systems, because it cannot be trusted to work reliably and + # exit with non-zero when it fails (e.g. hostname too long, + # D-Bus failure, etc.). + + echo "hostnamectl set-hostname \"\$(cat /etc/hostname)\"" + echo "test \"\$(hostname)\" = \"\$(cat /etc/hostname)\"" \ + " || hostname -F /etc/hostname" + else + printf "echo 'Unsupported OS: %s' >&2\nexit 1\n" "$os" + fi ;; esac - -if [ "$has_hostnamectl" ]; then - # Allow hostnamectl set-hostname to fail silently. - # Who the fuck invented a tool that needs dbus to set the hostname anyway ... - echo "hostnamectl set-hostname '$name_should' || true" -fi diff --git a/cdist/conf/type/__hostname/man.rst b/cdist/conf/type/__hostname/man.rst index d23a3b8a..72aefbab 100644 --- a/cdist/conf/type/__hostname/man.rst +++ b/cdist/conf/type/__hostname/man.rst @@ -8,7 +8,10 @@ cdist-type__hostname - Set the hostname DESCRIPTION ----------- -Set's the hostname on various operating systems. +Sets the hostname on various operating systems. + +**Tip:** For advice on choosing a hostname, see +`RFC 1178 `_. REQUIRED PARAMETERS @@ -18,7 +21,7 @@ None. OPTIONAL PARAMETERS ------------------- name - The hostname to set. Defaults to the first segment of __target_host + The hostname to set. Defaults to the first segment of __target_host (${__target_host%%.*}) diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 8f1adf12..75a90027 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -2,6 +2,7 @@ # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) +# 2019 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) # # This file is part of cdist. # @@ -19,50 +20,170 @@ # along with cdist. If not, see . # +not_supported() { + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 +} + +set_hostname_systemd() { + echo "$1" | __file /etc/hostname --source - +} + os=$(cat "$__global/explorer/os") -if [ -f "$__object/parameter/name" ]; then - name_should="$(cat "$__object/parameter/name")" +os_version=$(cat "$__global/explorer/os_version") +os_major=$(echo "$os_version" | grep -o '^[0-9][0-9]*') + +max_len=$(cat "$__object/explorer/max_len") +has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") + +if test -s "$__object/parameter/name" +then + name_should=$(cat "$__object/parameter/name") else - case "$os" in - openbsd) - name_should="${__target_host}" - ;; - *) - name_should="${__target_host%%.*}" - ;; + case $os + in + # RedHat-derivatives and BSDs + centos|fedora|redhat|scientific|freebsd|netbsd|openbsd|slackware) + # Hostname is FQDN + name_should="${__target_host}" + ;; + suse|opensuse-leap) + # Classic SuSE stores the FQDN in /etc/HOSTNAME, while + # systemd does not. The running hostname is the first + # component in both cases. + # In versions before 15.x, the FQDN is stored in /etc/hostname. + if test -n "$has_hostnamectl" && test "$os_major" -ge 15 \ + && test "$os_major" -ne 42 + then + name_should="${__target_host%%.*}" + else + name_should="${__target_host}" + fi + ;; + *) + # Hostname is only first component of FQDN on all other systems. + name_should="${__target_host%%.*}" + ;; esac fi +if test -n "$max_len" && test "$(printf '%s' "$name_should" | wc -c)" -gt "$max_len" +then + printf "Host name too long. Up to %u characters allowed.\n" "${max_len}" >&2 + exit 1 +fi -not_supported() { - echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 - echo "Please contribute an implementation for it if you can." >&2 - exit 1 -} +case $os +in + alpine|debian|devuan|ubuntu|void) + echo "$name_should" | __file /etc/hostname --source - + ;; + archlinux) + if test -n "$has_hostnamectl" + then + set_hostname_systemd "$name_should" + else + echo 'Ancient ArchLinux variants without hostnamectl are not supported.' >&2 + exit 1 + # Only for ancient ArchLinux, write to /etc/rc.conf on pre-systemd + # versions. There are some versions which use /etc/hostname but not + # systemd. It is unclear which ones these are. -case "$os" in - archlinux|debian|suse|ubuntu|devuan|coreos|alpine) + # __key_value '/etc/rc.conf:HOSTNAME' \ + # --file /etc/rc.conf \ + # --delimiter '=' --exact_delimiter \ + # --key 'HOSTNAME' \ + # --value "\"$name_should\"" + fi + ;; + centos|fedora|redhat|scientific) + if test -z "$has_hostnamectl" + then + # Only write to /etc/sysconfig/network on non-systemd versions. + # On systemd-based versions this entry is ignored. + __key_value '/etc/sysconfig/network:HOSTNAME' \ + --file /etc/sysconfig/network \ + --delimiter '=' --exact_delimiter \ + --key HOSTNAME \ + --value "\"$name_should\"" + else + set_hostname_systemd "$name_should" + fi + ;; + gentoo) + # Only write to /etc/conf.d/hostname on OpenRC-based installations. + # On systemd use hostnamectl(1) in gencode-remote. + if test -z "$has_hostnamectl" + then + __key_value '/etc/conf.d/hostname:hostname' \ + --file /etc/conf.d/hostname \ + --delimiter '=' --exact_delimiter \ + --key 'hostname' \ + --value "\"$name_should\"" + else + set_hostname_systemd "$name_should" + fi + ;; + freebsd) + __key_value '/etc/rc.conf:hostname' \ + --file /etc/rc.conf \ + --delimiter '=' --exact_delimiter \ + --key 'hostname' \ + --value "\"$name_should\"" + ;; + macosx) # handled in gencode-remote : ;; - scientific|centos) - __key_value sysconfig-hostname \ - --file /etc/sysconfig/network \ - --delimiter '=' \ - --key HOSTNAME \ - --value "$name_should" --exact_delimiter - ;; - freebsd) - __key_value rcconf-hostname \ + netbsd) + __key_value '/etc/rc.conf:hostname' \ --file /etc/rc.conf \ - --delimiter '=' \ + --delimiter '=' --exact_delimiter \ --key 'hostname' \ - --value "$name_should" + --value "\"$name_should\"" + + # To avoid confusion, ensure that the hostname is only stored once. + __file /etc/myname --state absent ;; openbsd) echo "$name_should" | __file /etc/myname --source - ;; + slackware) + # We write the FQDN into /etc/HOSTNAME. But /etc/rc.d/rc.M will only + # read the first component from this file and set it as the running + # hostname on boot. + echo "$name_should" | __file /etc/HOSTNAME --source - + ;; + solaris) + echo "$name_should" | __file /etc/nodename --source - + ;; + suse|opensuse-leap) + # Modern SuSE provides /etc/HOSTNAME as a symlink for + # backwards-compatibility. Unfortunately it cannot be used + # here as __file does not follow the symlink. + # Therefore, we use the presence of the hostnamectl binary as + # an indication of which file to use. This unfortunately does + # not work correctly on openSUSE 12.x which provides + # hostnamectl but not /etc/hostname. + + if test -n "$has_hostnamectl" -a "$os_major" -gt 12 + then + hostname_file='/etc/hostname' + else + hostname_file='/etc/HOSTNAME' + fi + + echo "$name_should" | __file "$hostname_file" --source - + ;; *) - not_supported + # On other operating systems we fall back to systemd's + # hostnamectl if available… + if test -n "$has_hostnamectl" + then + set_hostname_systemd "$name_should" + else + not_supported + fi ;; esac