Commit 328b61d8 authored by Leigh Stoller's avatar Leigh Stoller

Initial ZFS support. Just the runtime support, no support for actually

creating the initial ZFS volumes, that is described in Mike's notes
file on how to setup ZFS on ops. But once that is done, the runtime
supports takes care of creating volumes for users and projects/groups.
New configure variables, with defaults to:

	WITHZFS=0
	ZFS_ROOT=z
	ZFS_QUOTA_USER="1G"
	ZFS_QUOTA_PROJECT="100G"
	ZFS_QUOTA_GROUP="10G"
parent 83b8cebf
#
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2011, 2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -34,7 +34,7 @@ SBIN_STUFF = tbacct addsfskey addpubkey mkusercert quotamail genpubkeys \
manageremote
LIBEXEC_STUFF = webtbacct webaddsfskey webaddpubkey webmkusercert \
webnewuser webnewproj webspewcert webmanageremote
CTRLSBIN_STUFF = adduserhook
CTRLSBIN_STUFF = adduserhook accountsetup
# These scripts installed setuid, with sudo.
SETUID_BIN_SCRIPTS =
......@@ -74,7 +74,8 @@ boss-install: all script-install
@echo "Don't forget to do a post-install as root"
script-install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_STUFF)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF))
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF)) \
$(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRLSBIN_STUFF))
post-install:
chmod 775 $(INSTALL_BINDIR)
......
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2014 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
# GENI Public License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
#
# Setup accounts/projects/group stuff on ops/fs. This is installed on
# op/fs and invoked from boss by tbaccy and the proj/group scripts/
#
sub usage()
{
print "Usage: accountsetup adduser ...\n";
print " accountsetup deluser ...\n";
print " accountsetup moduser ...\n";
print " accountsetup addproject ...\n";
print " accountsetup addgroup ...\n";
print " accountsetup delproject ...\n";
print " accountsetup delgroup ...\n";
exit(1);
}
my $optlist = "dnf";
my $debug = 0;
my $force = 0;
my $impotent = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $WITHZFS = @WITHZFS@;
my $ZFS_ROOT = "@ZFS_ROOT@";
my $ZFS_QUOTA_USER = "@ZFS_QUOTA_USER@";
my $ZFS_QUOTA_PROJECT = "@ZFS_QUOTA_PROJECT@";
my $ZFS_QUOTA_GROUP = "@ZFS_QUOTA_GROUP@";
my $USERADD = "/usr/sbin/pw useradd";
my $USERDEL = "/usr/sbin/pw userdel";
my $USERMOD = "/usr/sbin/pw usermod";
my $GROUPADD = "/usr/sbin/pw groupadd";
my $GROUPDEL = "/usr/sbin/pw groupdel";
my $CHPASS = "/usr/bin/chpass";
my $ZFS = "/sbin/zfs";
my $SKEL = "/usr/share/skel";
# XXX
my $NOSUCHUSER = 67;
my $USEREXISTS = 65;
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libtestbed;
# Defined in libtestbed;
my $PROJROOT = PROJROOT();
my $GROUPROOT = GROUPROOT();
#
# Function prototypes
#
sub AddUser();
sub DeleteUser();
sub ModifyUser();
sub AddProject();
sub AddGroup();
sub DelProject();
sub DelGroup();
sub fatal($);
sub ZFSexists($);
#
# Check args.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
usage()
if (@ARGV < 1);
my $cmd = shift(@ARGV);
#
# Now dispatch operation.
#
SWITCH: for ($cmd) {
/^adduser$/ && do {
AddUser();
last SWITCH;
};
/^deluser$/ && do {
DeleteUser();
last SWITCH;
};
/^moduser$/ && do {
ModifyUser();
last SWITCH;
};
/^addproject$/ && do {
AddProject();
last SWITCH;
};
/^addgroup$/ && do {
AddGroup();
last SWITCH;
};
/^delproject$/ && do {
DelProject();
last SWITCH;
};
/^delgroup$/ && do {
DelGroup();
last SWITCH;
};
# Default
usage();
}
exit(0);
sub AddUser()
{
if (@ARGV < 6) {
fatal("adduser: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $uid = shift(@ARGV);
my $name = shift(@ARGV);
my $hdir = shift(@ARGV);
my $gid = shift(@ARGV);
my $shell = shift(@ARGV);
my $hash = (@ARGV ? shift(@ARGV) : undef);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${hdir}";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_USER} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
}
}
if (system("egrep -q -s '^${user}:' /etc/passwd") &&
system("$USERADD $user -u $uid -c \"$name\" ".
"-k $SKEL -h - -m -d $hdir -g $gid -s $shell")) {
if (($? >> 8) != $USEREXISTS) {
fatal("$USERADD: could not add account");
}
}
if ($WITHZFS) {
#
# Since the directory exists before the useradd call, the skeleton
# files are not copied in. Do that now.
#
if (! -e "$hdir/.cshrc") {
opendir(DIR, "$SKEL") or
fatal("Unable to open skeleton directory");
while (my $file = readdir(DIR)) {
if ($file =~ /^dot(.*)$/) {
system("/bin/cp -fp $SKEL/$file $hdir/$1") == 0
or fatal("Could not copy $SKEL/$file to $hdir/$1");
}
}
}
#
# And for the same reason, need to chown/chgrp everything.
#
system("/usr/sbin/chown -R $user:$gid $hdir") == 0
or fatal("Could not chown $hdir");
}
if (defined($hash) &&
system("$CHPASS -p '$hash' $user")) {
fatal("Could not initialize password");
}
return 0;
}
sub DeleteUser()
{
if (@ARGV != 2) {
fatal("deluser: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $hdir = shift(@ARGV);
if (system("$USERDEL $user")) {
if (($? >> 8) != $NOSUCHUSER) {
fatal("Could not remove user $user");
}
}
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${hdir}";
if (ZFSexists($path)) {
system("$ZFS unmount -f $path");
system("$ZFS destroy $path");
if ($?) {
fatal("Could not destroy ZFS $path");
}
}
}
return 0;
}
sub ModifyUser()
{
fatal("moduser: Not implemented yet");
}
sub AddProject()
{
if (@ARGV != 3) {
fatal("addproject: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
my $gid = shift(@ARGV);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${PROJROOT}/$name";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_PROJECT} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
}
$path = "${ZFS_ROOT}${GROUPROOT}/$name";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_GROUP} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
}
}
if (system("egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name ...\n";
if (system("$GROUPADD $unix_name -g $gid")) {
fatal("Could not add group $unix_name ($gid)!\n");
}
}
return 0;
}
sub AddGroup()
{
if (@ARGV != 3) {
fatal("addgroup: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
my $gid = shift(@ARGV);
if (system("egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name ...\n";
if (system("$GROUPADD $unix_name -g $gid")) {
fatal("Could not add group $unix_name ($gid)!\n");
}
}
return 0;
}
sub DelProject()
{
if (@ARGV != 2) {
fatal("delproject: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${PROJROOT}/$name";
if (ZFSexists($path)) {
system("$ZFS unmount -f $path");
system("$ZFS destroy $path");
if ($?) {
fatal("Could not destroy ZFS $path");
}
}
$path = "${ZFS_ROOT}${GROUPROOT}/$name";
if (ZFSexists($path)) {
system("$ZFS unmount -f $path");
system("$ZFS destroy $path");
if ($?) {
fatal("Could not destroy ZFS $path");
}
}
}
if (system("egrep -q -s '^${unix_name}:' /etc/group") == 0) {
print "Deleting project $unix_name ...\n";
if (system("$GROUPDEL $unix_name")) {
fatal("Could not delete group $unix_name!\n");
}
}
return 0;
}
sub DelGroup()
{
if (@ARGV != 2) {
fatal("delgroup: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
if (system("egrep -q -s '^${unix_name}:' /etc/group") == 0) {
print "Deleting group $unix_name ...\n";
if (system("$GROUPDEL $unix_name")) {
fatal("Could not delete group $unix_name!\n");
}
}
return 0;
}
sub fatal($) {
my ($msg) = @_;
print STDERR "$msg\n";
exit(-1);
}
#
# Check for ZFS existence.
#
sub ZFSexists($)
{
my ($path) = @_;
system("$ZFS list $path >/dev/null 2>&1");
return ($? ? 0 : 1);
}
......@@ -61,6 +61,7 @@ my $TBLOGS = "@TBLOGSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $WITHZFS = @WITHZFS@;
my $WITHSFS = @SFSSUPPORT@;
my $WIKISUPPORT = @WIKISUPPORT@;
my $TRACSUPPORT = @TRACSUPPORT@;
......@@ -83,6 +84,7 @@ my $USERADD = "/usr/sbin/pw useradd";
my $USERDEL = "/usr/sbin/pw userdel";
my $USERMOD = "/usr/sbin/pw usermod";
my $CHPASS = "/usr/bin/chpass";
my $ACCOUNTPROXY= "$TB/sbin/accountsetup";
my $SFSKEYGEN = "/usr/local/bin/sfskey gen";
my $GENELISTS = "$TB/sbin/genelists";
my $MKUSERCERT = "$TB/sbin/mkusercert";
......@@ -423,7 +425,7 @@ sub AddUser()
print "Adding user $user ($user_number) to local node.\n";
if (system("$USERADD $user -u $user_number -c \"$fullname\" ".
"-k /usr/share/skel -h - -m -d $HOMEDIR/$user ".
"-h - -d $HOMEDIR/$user ".
"-g $default_groupname -s $PBAG")) {
fatal("Could not add user $user to local node.");
}
......@@ -439,10 +441,10 @@ sub AddUser()
print "Adding user $user ($user_number) to $CONTROL.\n";
if (system("$SSH -host $CONTROL ".
"'$USERADD $user -u $user_number -c \"$fullname\" ".
"-k /usr/share/skel -h - -m -d $HOMEDIR/$user ".
"-g $default_groupname -s $shellpaths{$usr_shell}'")) {
if (($? >> 8) != $USEREXISTS) {
"'$ACCOUNTPROXY adduser $user $user_number \"$fullname\" ".
"$HOMEDIR/$user $default_groupname ".
"$shellpaths{$usr_shell}'")) {
if ($?) {
fatal("Could not add user $user ($user_number) to $CONTROL.");
}
}
......@@ -471,6 +473,19 @@ sub AddUser()
system("$SSH -host $CONTROL $ADDHOOK $user");
}
}
if ($WITHZFS) {
#
# There is some lag before the automounter can mount the new
# volume. Lets delay until we can access the directory.
#
for (my $i = 0; $i < 10; $i++) {
sleep(1)
if (! -r "$HOMEDIR/$user/.cshrc");
}
if (! -r "$HOMEDIR/$user/.cshrc") {
fatal("Could not access new user directory");
}
}
$UID = $SAVEUID;
#
......@@ -590,8 +605,9 @@ sub DelUser()
if (1) {
print "Removing user $user from $CONTROL\n";
if (system("$SSH -host $CONTROL '$USERDEL $user'")) {
if (($? >> 8) != $NOSUCHUSER) {
if (system("$SSH -host $CONTROL ".
" '$ACCOUNTPROXY deluser $user $HOMEDIR/$user'")) {
if ($?) {
fatal("Could not remove user $user from $CONTROL.");
}
}
......
......@@ -660,6 +660,11 @@ IPV6_SUBNET_PREFIX
IPV6_ENABLED
NFSMAPTOUSER
IMAGEPROVENANCE
WITHZFS
ZFS_ROOT
ZFS_QUOTA_USER
ZFS_QUOTA_PROJECT
ZFS_QUOTA_GROUP
NOVIRTNFSMOUNTS
IMAGEDELTAS
PROFILEVERSIONS
......@@ -5099,6 +5104,11 @@ IMAGEPROVENANCE=0
IMAGEDELTAS=0
PROFILEVERSIONS=0
NOVIRTNFSMOUNTS=0;
WITHZFS=0
ZFS_ROOT=z
ZFS_QUOTA_USER="1G"
ZFS_QUOTA_PROJECT="100G"
ZFS_QUOTA_GROUP="10G"
#
# XXX You really don't want to change these!
......
......@@ -295,6 +295,11 @@ AC_SUBST(IMAGEPROVENANCE)
AC_SUBST(IMAGEDELTAS)
AC_SUBST(PROFILEVERSIONS)
AC_SUBST(NOVIRTNFSMOUNTS)
AC_SUBST(WITHZFS)
AC_SUBST(ZFS_ROOT)
AC_SUBST(ZFS_QUOTA_USER)
AC_SUBST(ZFS_QUOTA_PROJECT)
AC_SUBST(ZFS_QUOTA_GROUP)
#
# Offer both versions of the email addresses that have the @ escaped
......@@ -441,6 +446,11 @@ IMAGEPROVENANCE=0
IMAGEDELTAS=0
PROFILEVERSIONS=0
NOVIRTNFSMOUNTS=0
WITHZFS=0
ZFS_ROOT=z
ZFS_QUOTA_USER="1G"
ZFS_QUOTA_PROJECT="100G"
ZFS_QUOTA_GROUP="10G"
#
# XXX You really don't want to change these!
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -57,10 +57,12 @@ my $BUGDBSUPPORT= @BUGDBSUPPORT@;
my $OPSDBSUPPORT= @OPSDBSUPPORT@;
my $TBBASE = "@TBBASE@";
my $TBWWW = "@TBWWW@";
my $WITHZFS = @WITHZFS@;
my $SSH = "$TB/bin/sshtb";
my $ADDMMLIST = "$TB/sbin/addmmlist";
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
my $GROUPADD = "/usr/sbin/pw groupadd";
my $ACCOUNTPROXY= "$TB/sbin/accountsetup";
my @DIRLIST = ("exp", "images", "logs", "tarfiles", "rpms", "tiplogs");
my $SAVEUID = $UID;
......@@ -178,6 +180,7 @@ my $isnonlocal = $project->IsNonLocal();
#
# The group directory lives here.
#
my $projdir = "$PROJROOT/$pid";
my $groupdir = "$GRPROOT/$pid/$gid";
my $grouplink = "$PROJROOT/$pid/groups/$gid";
......@@ -201,13 +204,23 @@ $UID = $EUID;
#
# Create group on the control node if it does not exist.
#
my $proxy_command = ($pid eq $gid ? "addproject" : "addgroup");
print "Adding group $unix_name to $control_node.\n";
if (system("$SSH -host $control_node ".
"egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name to $control_node.\n";
if (system("$SSH -host $control_node ".
"$GROUPADD $unix_name -g $unix_gid")) {
fatal("Could not add $unix_name ($unix_gid) to $control_node!\n");
" $ACCOUNTPROXY $proxy_command $gid $unix_name $unix_gid")) {
fatal("Could not add $unix_name ($unix_gid) to $control_node!\n");
}
if ($WITHZFS && $pid ne $gid) {
#
# There is some lag before the automounter can mount the new
# volume. Lets delay until we can access the project directory.
#
for (my $i = 0; $i < 10; $i++) {
sleep(1)
if (! -r $projdir);
}
if (! -r $projdir) {
fatal("Could not access new project directory: $projdir");
}
}
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -73,6 +73,7 @@ my $GROUPDEL = "/usr/sbin/pw groupdel";
my $DELMMLIST = "$TB/sbin/delmmlist";
my $MODGROUPS = "$TB/sbin/modgroups";
my $OPSDBCONTROL = "$TB/sbin/opsdb_control";
my $ACCOUNTPROXY = "$TB/sbin/accountsetup";
#
# Untaint the path
......@@ -249,10 +250,13 @@ if (system("grep -q '^${unix_gid}:' /etc/group")) {
$UID = 0;
if ($CONTROL ne $BOSSNODE) {
my $proxy_command = ($pid eq $gid ? "delproject" : "delgroup");
print "Removing group $unix_name ($unix_gid) on $CONTROL.\n";
if (system("$SSH -host $CONTROL $GROUPDEL $unix_name")) {
if (($? >> 8) != 65) {
if (system("$SSH -host $CONTROL ".
" $ACCOUNTPROXY $proxy_command $gid $unix_name")) {
if ($?) {
fatal("Could not remove group $unix_name from $CONTROL!");
}
}
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -38,6 +38,7 @@ use strict;
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $CONTROL = "@USERNODE@";
my $WITHZFS = @WITHZFS@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
my $RMGROUP = "$TB/sbin/rmgroup";
......@@ -136,7 +137,7 @@ my $savename = "${pid}-${pid_idx}";
#
# Rename the project directory.
#
if (-e "$PROJROOT/$pid") {
if (!$WITHZFS && -e "$PROJROOT/$pid") {
my $oldname = "$PROJROOT/$pid";
my $newname = "$PROJROOT/$savename";
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -51,6 +51,7 @@ my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $CONTROL = "@USERNODE@";
my $BOSSNODE= "@BOSSNODE@";
my $WITHZFS = @WITHZFS@;
my $OURDOMAIN = "@OURDOMAIN@";
my $PGENISUPPORT = @PROTOGENI_SUPPORT@;
my $PORTAL_ENABLE = @PORTAL_ENABLE@;
......@@ -376,7 +377,7 @@ EmulabFeatures->DeleteAll($target_user) == 0 or
#
# Rename the users home dir if its there.
#
if (-d "$HOMEDIR/$target_uid") {
if (!$WITHZFS && -d "$HOMEDIR/$target_uid") {
my $newname = "$HOMEDIR/$target_uid-" . TBDateTimeFSSafe();
if (rename("$HOMEDIR/$target_uid", $newname)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment