Add zgenhostid utility script

Turning the multihost property on requires that a hostid be set to allow
ZFS to determine when a foreign system is attemping to import a pool.
The error message instructing the user to set a hostid refers to
genhostid(1).

Genhostid(1) is not available on SUSE Linux.  This commit adds a script
modeled after genhostid(1) for those users.

Zgenhostid checks for an /etc/hostid file; if it does not exist, it
creates one and stores a value.  If the user has provided a hostid as an
argument, that value is used.  Otherwise, a random hostid is generated
and stored.

This differs from the CENTOS 6/7 versions of genhostid, which overwrite
the /etc/hostid file even though their manpages state otherwise.

A man page for zgenhostid is added. The one for genhostid is in (1), but
I put zgenhostid in (8) because I believe it's more appropriate.

The mmp tests are modified to use zgenhostid to set the hostid instead
of using the spl_hostid module parameter.  zgenhostid will not replace
an existing /etc/hostid file, so new mmp_clear_hostid calls are
required.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Olaf Faaland <faaland1@llnl.gov>
Closes #6358
Closes #6379
This commit is contained in:
Olaf Faaland 2017-07-18 18:11:08 -07:00 committed by Brian Behlendorf
parent ffb195c256
commit b9373170e3
14 changed files with 151 additions and 11 deletions

View File

@ -1,3 +1,3 @@
SUBDIRS = zfs zpool zdb zhack zinject zstreamdump ztest zpios
SUBDIRS += mount_zfs fsck_zfs zvol_id vdev_id arcstat dbufstat zed
SUBDIRS += arc_summary raidz_test
SUBDIRS += arc_summary raidz_test zgenhostid

View File

@ -0,0 +1 @@
dist_bin_SCRIPTS = zgenhostid

61
cmd/zgenhostid/zgenhostid Executable file
View File

@ -0,0 +1,61 @@
#!/bin/bash
# Emulate genhostid(1) available on RHEL/CENTOS, for use on distros
# which do not provide that utility.
#
# Usage:
# zgenhostid
# zgenhostid <value>
#
# If /etc/hostid already exists and is size > 0, the script exits immediately
# and changes nothing. Unlike genhostid, this generates an error message.
#
# The first form generates a random hostid and stores it in /etc/hostid.
# The second form checks that the provided value is between 0x1 and 0xFFFFFFFF
# and if so, stores it in /etc/hostid. This form is not supported by
# genhostid(1).
hostid_file=/etc/hostid
function usage {
echo "$0 [value]"
echo "If $hostid_file is not present, store a hostid in it." >&2
echo "The optional value must be an 8-digit hex number between" >&2
echo "1 and 2^32-1. If no value is provided, a random one will" >&2
echo "be generated. The value must be unique among your systems." >&2
}
# hostid(1) ignores contents of /etc/hostid if size < 4 bytes. It would
# be better if this checked size >= 4 bytes but it the method must be
# widely portable.
if [ -s $hostid_file ]; then
echo "$hostid_file already exists. No change made." >&2
exit 1
fi
if [ -n "$1" ]; then
host_id=$1
else
# $RANDOM goes from 0..32k-1
number=$((((RANDOM % 4) * 32768 + RANDOM) * 32768 + RANDOM))
host_id=$(printf "%08x" $number)
fi
if egrep -o '^0{8}$' <<< $host_id >/dev/null 2>&1; then
usage
exit 2
fi
if ! egrep -o '^[a-fA-F0-9]{8}$' <<< $host_id >/dev/null 2>&1; then
usage
exit 3
fi
a=${host_id:6:2}
b=${host_id:4:2}
c=${host_id:2:2}
d=${host_id:0:2}
echo -ne \\x$a\\x$b\\x$c\\x$d > $hostid_file
exit 0

View File

@ -2177,7 +2177,7 @@ show_import(nvlist_t *config)
break;
case ZPOOL_STATUS_HOSTID_REQUIRED:
(void) printf(gettext(" action: Set a unique system "
"hostid with the genhostid(1) command.\n"));
"hostid with the zgenhostid(8) command.\n"));
break;
default:
(void) printf(gettext(" action: The pool cannot be "
@ -2304,7 +2304,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
(void) fprintf(stderr, gettext("Cannot import '%s': "
"pool has the multihost property on and the\n"
"system's hostid is not set. Set a unique hostid "
"with the genhostid(1) command.\n"), name);
"with the zgenhostid(8) command.\n"), name);
} else {
char *hostname = "<unknown>";
uint64_t timestamp = 0;

View File

@ -113,6 +113,7 @@ AC_CONFIG_FILES([
cmd/arc_summary/Makefile
cmd/zed/Makefile
cmd/raidz_test/Makefile
cmd/zgenhostid/Makefile
contrib/Makefile
contrib/bash_completion.d/Makefile
contrib/dracut/Makefile

View File

@ -1865,7 +1865,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
"the multihost property on and "
"the\nsystem's hostid is not set. "
"Set a unique system hostid with "
"the genhostid(1) command.\n"));
"the zgenhostid(8) command.\n"));
}
(void) zfs_error_aux(hdl, aux);

View File

@ -4,6 +4,7 @@ dist_man_MANS = \
vdev_id.8 \
zdb.8 \
zfs.8 \
zgenhostid.8
zinject.8 \
zpool.8 \
zstreamdump.8

72
man/man8/zgenhostid.8 Normal file
View File

@ -0,0 +1,72 @@
.\"
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
.\" or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions
.\" and limitations under the License.
.\"
.\" When distributing Covered Code, include this CDDL HEADER in each
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
.\" If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" CDDL HEADER END
.\"
.\"
.\" Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
.\"
.Dd July 24, 2017
.Dt ZGENHOSTID 8 SMM
.Os Linux
.Sh NAME
.Nm zgenhostid
.Nd generate and store a hostid in
.Em /etc/hostid
.Sh SYNOPSIS
.Nm
.Op Ar hostid
.Sh DESCRIPTION
If
.Em /etc/hostid
does not exist, create it and store a hostid in it. If the user provides
.Op Ar hostid
on the command line, store that value. Otherwise, randomly generate a
value to store.
.Pp
This emulates the
.Xr genhostid 1
utility and is provided for use on systems which do not include the utility.
.Pp
.Sh OPTIONS
.Op Ar hostid
Specifies the value to be placed in
.Em /etc/hostid .
It must be a number with a value between 1 and 2^32-1. This value
.Sy must
be unique among your systems. It must be expressed in hexadecimal and be
exactly 8 digits long.
.Sh EXAMPLES
.Bl -tag -width Ds
.It Generate a random hostid and store it
.Bd -literal
# zgenhostid
.Ed
.It Record the libc-generated hostid in Em /etc/hostid
.Bd -literal
# zgenhostid $(hostid)
.Ed
.It Record a custom hostid (0xdeadbeef) in Em etc/hostid
.Bd -literal
# zgenhostid deadbeef
.Ed
.El
.Sh SEE ALSO
.Xr spl-module-parameters 5 ,
.Xr genhostid 1 ,
.Xr hostid 1

View File

@ -732,7 +732,7 @@ in the
man page. In order to enable this property each host must set a unique hostid.
See
.Xr genhostid 1
and
.Xr zgenhostid 8
.Xr spl-module-paramters 5
for additional details. The default value is
.Sy off .

View File

@ -141,6 +141,7 @@ export ZFS_FILES='zdb
arcstat.py
dbufstat.py
zed
zgenhostid
zstreamdump'
export ZFSTEST_FILES='chg_usr_exec

View File

@ -79,12 +79,7 @@ function mmp_set_hostid
{
typeset hostid=$1
a=${hostid:6:2}
b=${hostid:4:2}
c=${hostid:2:2}
d=${hostid:0:2}
printf "\\x$a\\x$b\\x$c\\x$d" >$HOSTID_FILE
zgenhostid $1
if [ $(hostid) != "$hostid" ]; then
return 1
@ -107,10 +102,12 @@ function mmp_pool_create # pool dir
log_must mkdir -p $dir
log_must truncate -s $MINVDEVSIZE $dir/vdev1 $dir/vdev2
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID1
log_must zpool create -f $pool mirror $dir/vdev1 $dir/vdev2
log_must zpool set multihost=on $pool
log_must zpool export $pool
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_note "Starting ztest in the background as hostid $HOSTID1"
@ -146,6 +143,7 @@ function mmp_pool_set_hostid # pool hostid
typeset pool=$1
typeset hostid=$2
log_must mmp_clear_hostid
log_must mmp_set_hostid $hostid
log_must zpool export $pool
log_must zpool import $pool

View File

@ -86,6 +86,7 @@ log_must mmp_set_hostid $HOSTID1
MMP_IMPORTED_MSG="The pool can be imported"
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "action" $MMP_IMPORTED_MSG
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
MMP_IMPORTED_MSG="The pool was last accessed by another system."
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "status" $MMP_IMPORTED_MSG

View File

@ -62,6 +62,7 @@ done
for opt in "" "-f"; do
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
log_must zpool export $TESTPOOL
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_must import_no_activity_check $TESTPOOL $opt
done
@ -87,6 +88,7 @@ done
for opt in "" "-f"; do
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
log_must zpool export $TESTPOOL
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_must import_no_activity_check $TESTPOOL $opt
done

View File

@ -60,6 +60,7 @@ done
# 3. Verify multihost=off and hostids differ (no activity check)
log_must zpool export -F $TESTPOOL
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_mustnot import_no_activity_check $TESTPOOL ""
log_must import_no_activity_check $TESTPOOL "-f"
@ -81,6 +82,7 @@ done
# 6. Verify multihost=on and hostids differ (activity check)
log_must zpool export -F $TESTPOOL
log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_mustnot import_activity_check $TESTPOOL ""
log_must import_activity_check $TESTPOOL "-f"