Commit adbcfd47 authored by Leigh B. Stoller's avatar Leigh B. Stoller
Browse files

Add suport for building per project, group, experiment DBs on ops. At

present the per-experiment stuff is not hooked in, but will be for
templates later. Anyway, each user gets a mysql account on ops, with
password set to the same as their mailman password (which is also
their jabber password, etc). Each project gets a DB named by the
project, and each group gets a DB named by pid,gid. Users are placed
on the access lists for the DBs as you would expect.

There is a little bit of complexity to make sure that we can create
DBs on ops outside the Emulab path and grant access to them, without
Emulab getting confused or mucking things up.

I'll get a news item done ...
parent 77e46ebb
......@@ -42,6 +42,7 @@ my $BOSSNODE = "@BOSSNODE@";
my $WITHSFS = @SFSSUPPORT@;
my $WIKISUPPORT = @WIKISUPPORT@;
my $BUGDBSUPPORT= @BUGDBSUPPORT@;
my $OPSDBSUPPORT= @OPSDBSUPPORT@;
my $CHATSUPPORT = @CHATSUPPORT@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
my $PROTOUSER = 'elabman';
......@@ -71,6 +72,7 @@ my $DELCHATUSER = "$TB/sbin/deljabberuser";
my $MMMODIFYUSER= "$TB/sbin/mmmodifymember";
my $ADDMMUSER = "$TB/sbin/addmmuser";
my $DELMMUSER = "$TB/sbin/delmmuser";
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
my $NOLOGIN = "/sbin/nologin";
my $SSH = "$TB/bin/sshtb";
my $SAVEUID = $UID;
......@@ -370,6 +372,10 @@ sub AddUser()
system("$ADDBUGDBUSER $user")
if ($BUGDBSUPPORT && $user ne $PROTOUSER);
# And to the OPS db if enabled.
system("$OPSDBCONTROL adduser $user")
if ($OPSDBSUPPORT && $user ne $PROTOUSER);
# And to the chat server if enabled.
system("$ADDCHATUSER $user")
if ($CHATSUPPORT && $user ne $PROTOUSER);
......@@ -510,6 +516,11 @@ sub UpdatePassword()
# And to the bugdb if enabled.
system("$ADDBUGDBUSER -m $user")
if ($BUGDBSUPPORT && $user ne $PROTOUSER);
# And to the OPS db if enabled.
system("$OPSDBCONTROL adduser $user")
if ($OPSDBSUPPORT && $user ne $PROTOUSER);
$EUID = 0;
return 0;
......
......@@ -1428,6 +1428,7 @@ PLAB_ROOTBALL="change.me"
PLAB_SLICEPREFIX="utah_elab"
WIKISUPPORT=0
BUGDBSUPPORT=0
OPSDBSUPPORT=0
MAILMANSUPPORT=0
WINSUPPORT=0
CVSSUPPORT=0
......@@ -2629,6 +2630,7 @@ s%@PLABSUPPORT@%$PLABSUPPORT%g
s%@WIKISUPPORT@%$WIKISUPPORT%g
s%@MAILMANSUPPORT@%$MAILMANSUPPORT%g
s%@BUGDBSUPPORT@%$BUGDBSUPPORT%g
s%@OPSDBSUPPORT@%$OPSDBSUPPORT%g
s%@NFSTRACESUPPORT@%$NFSTRACESUPPORT%g
s%@TBLOGFACIL@%$TBLOGFACIL%g
s%@PLAB_ROOTBALL@%$PLAB_ROOTBALL%g
......
......@@ -115,6 +115,7 @@ AC_SUBST(PLABSUPPORT)
AC_SUBST(WIKISUPPORT)
AC_SUBST(MAILMANSUPPORT)
AC_SUBST(BUGDBSUPPORT)
AC_SUBST(OPSDBSUPPORT)
AC_SUBST(NFSTRACESUPPORT)
AC_SUBST(TBLOGFACIL)
AC_SUBST(PLAB_ROOTBALL)
......@@ -209,6 +210,7 @@ PLAB_ROOTBALL="change.me"
PLAB_SLICEPREFIX="utah_elab"
WIKISUPPORT=0
BUGDBSUPPORT=0
OPSDBSUPPORT=0
MAILMANSUPPORT=0
WINSUPPORT=0
CVSSUPPORT=0
......
......@@ -52,6 +52,7 @@ CVSSUPPORT=1
CHATSUPPORT=1
NFSTRACESUPPORT=1
ARCHIVESUPPORT=1
OPSDBSUPPORT=1
#
# SSL Certificate stuff. Used to customize config files in ssl directory.
# Note that OrganizationalUnit is set in the cnf file.
......
......@@ -956,6 +956,14 @@ Phase "database", "Setting up database", sub {
ExecQuietFatal("$MYSQLADMIN -u mysql ping");
};
Phase "dbpatch", "Patching up mysql DB", sub {
if (!ExecQuiet("$MYSQLDUMP -u root mysql emulab_dbs")) {
PhaseSkip("DB already patched");
}
ExecQuietFatal("$MYSQL -u root mysql < $TOP_SRCDIR/sql/opsdb.sql");
};
# Once the password is inserted and privs flushed, will need a password
# from this point forward!
Phase "privs", "Initializing mysqld priv system", sub {
......@@ -1269,7 +1277,7 @@ if ($WIKISUPPORT) {
}
ExecQuietFatal("$CHMOD 770 $WIKIDIR");
PhaseSkip("Flyspray already unpacked")
PhaseSkip("TWiki already unpacked")
if (-e "$WIKIDIR/data");
ExecQuietFatal("$TAR zxf $localtarfile -C $WIKIDIR");
};
......
......@@ -36,10 +36,13 @@ my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $ELABINELAB = @ELABINELAB@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
my $BUGDBSUPPORT= @BUGDBSUPPORT@;
my $OPSDBSUPPORT= @OPSDBSUPPORT@;
my $PROJROOT = "/proj";
my $GRPROOT = "/groups";
my $SSH = "$TB/bin/sshtb";
my $ADDMMLIST = "$TB/sbin/addmmlist";
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
my $GROUPADD = "/usr/sbin/pw groupadd";
my @DIRLIST = ("exp", "images", "logs", "tarfiles", "rpms", "tiplogs");
my $SAVEUID = $UID;
......@@ -265,11 +268,19 @@ if ($pid ne $gid) {
}
}
if ($MAILMANSUPPORT && !$ELABINELAB) {
if (($MAILMANSUPPORT || $OPSDBSUPPORT) && !$ELABINELAB) {
$UID = $SAVEUID;
$EUID = $UID;
system("$ADDMMLIST -a ${pid}-${gid}-users") == 0 or
fatal("$ADDMMLIST -a ${pid}-${gid}-users failed!");
if ($MAILMANSUPPORT) {
system("$ADDMMLIST -a ${pid}-${gid}-users") == 0 or
fatal("$ADDMMLIST -a ${pid}-${gid}-users failed!");
}
if ($OPSDBSUPPORT) {
system("$OPSDBCONTROL addgroup $pid $gid") == 0 or
fatal("$OPSDBCONTROL addgroup $pid $gid failed!");
}
$EUID = 0;
}
}
......
......@@ -32,12 +32,14 @@ my $CHOWN = "/usr/sbin/chown";
my $GRANTTYPE= "$TB/sbin/grantnodetype -d";
my $WIKISUPPORT = @WIKISUPPORT@;
my $BUGDBSUPPORT = @BUGDBSUPPORT@;
my $OPSDBSUPPORT = @OPSDBSUPPORT@;
my $CVSSUPPORT = @CVSSUPPORT@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
my $ADDWIKIPROJ = "$TB/sbin/addwikiproj";
my $ADDBUGDBPROJ= "$TB/sbin/addbugdbproj";
my $ADDMMLIST = "$TB/sbin/addmmlist";
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
my $PROJROOT = "/proj";
my $GRPROOT = "/groups";
my $TFTPROOT = "/tftpboot";
......@@ -146,6 +148,10 @@ if ($BUGDBSUPPORT) {
system("$ADDBUGDBPROJ $pid") == 0 or
fatal("$ADDBUGDBPROJ $pid failed!");
}
if ($OPSDBSUPPORT) {
system("$OPSDBCONTROL addproj $pid") == 0 or
fatal("$OPSDBCONTROL addproj $pid failed!");
}
if ($MAILMANSUPPORT) {
system("$ADDMMLIST -a ${pid}-users") == 0 or
fatal("$ADDMMLIST -a ${pid}-users failed!");
......
......@@ -49,6 +49,8 @@ my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $ELABINELAB = @ELABINELAB@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
my $BUGDBSUPPORT = @BUGDBSUPPORT@;
my $OPSDBSUPPORT = @OPSDBSUPPORT@;
my $PROJROOT = "/proj";
my $GRPROOT = "/groups";
......@@ -56,6 +58,7 @@ my $SSH = "$TB/bin/sshtb";
my $GROUPDEL = "/usr/sbin/pw groupdel";
my $DELMMLIST= "$TB/sbin/delmmlist";
my $MODGROUPS= "$TB/sbin/modgroups";
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
#
# Untaint the path
......@@ -224,6 +227,14 @@ if ($MAILMANSUPPORT && !$ELABINELAB) {
$EUID = 0;
}
if ($OPSDBSUPPORT && !$ELABINELAB) {
# For perl
$EUID = $UID;
system("$OPSDBCONTROL delgroup $pid $gid") == 0 or
fatal("$OPSDBCONTROL delgroup $pid $gid failed!");
$EUID = 0;
}
#
# Be real root for ssh.
#
......
......@@ -47,8 +47,10 @@ my $ADMINGRP= "@TBADMINGROUP@";
my $ELABINELAB = @ELABINELAB@;
my $WIKISUPPORT = @WIKISUPPORT@;
my $BUGDBSUPPORT = @BUGDBSUPPORT@;
my $OPSDBSUPPORT = @OPSDBSUPPORT@;
my $SETWIKIGROUPS = "$TB/sbin/setwikigroups";
my $SETBUGDBGROUPS= "$TB/sbin/setbugdbgroups";
my $OPSDBCONTROL = "$TB/sbin/opsdb_control";
my $SSH = "$TB/bin/sshtb";
my $USERMOD = "/usr/sbin/pw usermod";
......@@ -386,7 +388,7 @@ $UID = $SAVEUID;
$EUID = $UID;
# and the twiki.
if ($WIKISUPPORT || $BUGDBSUPPORT) {
if ($WIKISUPPORT || $BUGDBSUPPORT || $OPSDBSUPPORT) {
foreach $user (@userlist) {
if ($WIKISUPPORT) {
system("$SETWIKIGROUPS $optarg $user") == 0 or
......@@ -396,6 +398,11 @@ if ($WIKISUPPORT || $BUGDBSUPPORT) {
system("$SETBUGDBGROUPS $optarg $user") == 0 or
fatal("$SETBUGDBGROUPS $user failed!");
}
if ($OPSDBSUPPORT) {
system("$OPSDBCONTROL $optarg setgroups $user") == 0 or
fatal("$OPSDBCONTROL setgroups $user failed!");
}
}
}
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# Copyright (c) 2000-2006 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -20,23 +20,25 @@ SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl \
eventping grantnodetype import_commitlog dhcpd_wrapper \
opsreboot deletenode node_statewait grabwebcams \
grabswitchconfig backupswitches cvsinit checkquota \
spewconlog
spewconlog opsdb_control
LIBEXEC_SCRIPTS = webcreateimage newnode webdeletenode spewleds webcopy \
websetdest spewsource weblinkmon_ctl webcvsweb \
webspewconlog xlogin webviewvc
CTRLSBIN_SCRIPTS= opsdb_control.proxy
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(BIN_SCRIPTS) $(SBIN_SCRIPTS) $(LIBEXEC_SCRIPTS) $(SUBDIRS) \
firstuser setbuildinfo
all: $(BIN_SCRIPTS) $(SBIN_SCRIPTS) $(LIBEXEC_SCRIPTS) $(CTRLSBIN_SCRIPTS) \
$(SUBDIRS) firstuser setbuildinfo
include $(TESTBED_SRCDIR)/GNUmakerules
install: $(addprefix $(INSTALL_BINDIR)/, $(BIN_SCRIPTS)) \
$(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRLSBIN_SCRIPTS)) \
subdir-install
$(INSTALL_PROGRAM) loghole $(INSTALL_DIR)/opsdir/bin/loghole
-mkdir -p $(INSTALL_DIR)/opsdir/man/man1
......@@ -55,6 +57,8 @@ post-install:
chmod u+s $(INSTALL_SBINDIR)/checkquota
chown root $(INSTALL_SBINDIR)/spewconlog
chmod u+s $(INSTALL_SBINDIR)/spewconlog
chown root $(INSTALL_SBINDIR)/opsdb_control
chmod u+s $(INSTALL_SBINDIR)/opsdb_control
chown root $(INSTALL_LIBEXECDIR)/xlogin
chmod u+s $(INSTALL_LIBEXECDIR)/xlogin
......@@ -73,3 +77,9 @@ clean: subdir-clean
subdir-clean:
@$(MAKE) -C nsgen clean
$(INSTALL_DIR)/opsdir/sbin/%: %
@echo "Installing $<"
-mkdir -p $(INSTALL_DIR)/opsdir/sbin
$(INSTALL) $< $@
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
use Errno qw(EEXIST);
use strict;
#
# Control the privilege tables on the ops DB.
#
sub usage()
{
print STDOUT "Usage: opsdb_control adduser <uid>\n";
exit(-1);
}
my $optlist = "d";
my $debug = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $OPSDBSUPPORT= @OPSDBSUPPORT@;
# Locals
my $SSH = "$TB/bin/sshtb";
my $OPSDBPROXY = "$TB/sbin/opsdb_control.proxy";
my $SAVEUID = $UID;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
# Protos
sub AddUser(@);
sub DelUser(@);
sub AddProj(@);
sub AddGroup(@);
sub DelProj(@);
sub DelGroup(@);
sub SetGroups(@);
sub AddExpDB(@);
sub DelExpDB(@);
sub DoOpsStuff($;$);
sub Initialize();
sub fatal($);
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
#
# We don't want to run this script unless its the real version.
#
if ($EUID != 0) {
die("*** $0:\n".
" Must be setuid! Maybe its a development version?\n");
}
#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
#
if ($UID == 0) {
die("*** $0:\n".
" Please do not run this as root! Its already setuid!\n");
}
#
# If no opsdb support, just exit.
#
if (! $OPSDBSUPPORT) {
print "OPS DB support is not enabled. Exiting ...\n";
exit(0);
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
usage()
if (@ARGV < 1);
my $action = shift(@ARGV);
if ($action eq "adduser") {
exit(AddUser(@ARGV));
}
elsif ($action eq "deluser") {
exit(DelUser(@ARGV));
}
elsif ($action eq "addproj") {
exit(AddProj(@ARGV));
}
elsif ($action eq "addgroup") {
exit(AddGroup(@ARGV));
}
elsif ($action eq "delproj") {
exit(DelProj(@ARGV));
}
elsif ($action eq "delgroup") {
exit(DelGroup(@ARGV));
}
elsif ($action eq "setgroups") {
exit(SetGroups(@ARGV));
}
elsif ($action eq "addexpdb") {
exit(AddExpDB(@ARGV));
}
elsif ($action eq "delexpdb") {
exit(DelExpDB(@ARGV));
}
elsif ($action eq "setup") {
exit(Initialize());
}
else {
die("*** $0:\n".
" Do not know what to do with '$action'!\n");
}
exit(0);
#
# Add user. The user ID and password are added to the user table on ops,
# but with no privs to do anything.
#
sub AddUser(@)
{
my ($target_uid) = @_;
usage()
if (@_ != 1);
#
# Untaint args.
#
if ($target_uid =~ /^([-\w]+)$/) {
$target_uid= $1;
}
else {
die("Bad data in uid: $target_uid");
}
my $query_result =
DBQueryFatal("select mailman_password ".
"from users where uid='$target_uid'");
fatal("No such user in DB: $target_uid!")
if (!$query_result->numrows);
my ($password) = $query_result->fetchrow_array();
fatal("No password defined for $target_uid!")
if (!defined($password) || $password eq "");
print "Adding user '$target_uid' to mysql database on $CONTROL.\n";
my $retval = DoOpsStuff("adduser $target_uid", $password);
if ($retval) {
if ($retval == EEXIST()) {
# Not an error.
return 0;
}
fatal("$OPSDBPROXY failed on $CONTROL!");
}
return 0;
}
#
# Delete user.
#
sub DelUser(@)
{
my ($target_uid) = @_;
usage()
if (@_ != 1);
#
# Untaint args.
#
if ($target_uid =~ /^([-\w]+)$/) {
$target_uid= $1;
}
else {
die("Bad data in uid: $target_uid");
}
my $query_result =
DBQueryFatal("select mailman_password ".
"from users where uid='$target_uid'");
fatal("No such user in DB: $target_uid!")
if (!$query_result->numrows);
print "Removing user '$target_uid' from mysql database on $CONTROL.\n";
my $retval = DoOpsStuff("deluser $target_uid");
if ($retval) {
fatal("$OPSDBPROXY failed on $CONTROL!");
}
return 0;
}
#
# Add a project or group to the list of DBs on ops.
#
sub AddProj(@)
{
my ($pid) = @_;
usage()
if (@_ != 1);
return AddGroup($pid, $pid);
}
sub AddGroup(@)
{
my ($pid, $gid) = @_;
usage()
if (@_ != 2);
#
# Untaint args.
#
if ($pid =~ /^([-\w]+)$/) {
$pid = $1;
}
else {
die("Bad data in uid: $pid");
}
if ($gid =~ /^([-\w]+)$/) {
$gid = $1;
}
else {
die("Bad data in uid: $gid");
}
my $dbname = ($pid eq $gid ? $pid : "$pid,$gid");
my $query_result =
DBQueryFatal("select pid,gid from groups ".
"where pid='$pid' and gid='$gid'");
fatal("No such group in DB: $pid/$gid!")
if (!$query_result->numrows);
print "Adding DB '$dbname' to mysql database on $CONTROL.\n";
my $retval = DoOpsStuff("adddb $dbname");
if ($retval) {
fatal("$OPSDBPROXY failed on $CONTROL!");
}
return 0;
}
#
# Delete project or group from the list of DBs on ops.
#
sub DelProj(@)
{
my ($pid) = @_;
usage()
if (@_ != 1);
return DelGroup($pid, $pid);
}
sub DelGroup(@)
{
my ($pid, $gid) = @_;
usage()
if (@_ != 2);
#
# Untaint args.
#
if ($pid =~ /^([-\w]+)$/) {
$pid = $1;
}
else {
die("Bad data in uid: $pid");
}
if ($gid =~ /^([-\w]+)$/) {
$gid = $1;
}
else {
die("Bad data in uid: $gid");
}
my $dbname = ($pid eq $gid ? $pid : "$pid,$gid");
my $query_result =
DBQueryFatal("select pid,gid from groups ".
"where pid='$pid' and gid='$gid'");
fatal("No such group in DB: $pid/$gid!")
if (!$query_result->numrows);
print "Removing DB '$dbname' from mysql database on $CONTROL.\n";
my $retval = DoOpsStuff("deldb $dbname");
if ($retval) {
fatal("$OPSDBPROXY failed on $CONTROL!");
}
return 0;
}
#
# Set the groups for a user; the list of DBs they can use on OPS.
#
sub SetGroups(@)
{
my ($uid) = @_;
my @glist = ();
usage()
if (@_ != 1);
#
# Untaint args.
#
if ($uid =~ /^([-\w]+)$/) {
$uid = $1;
}
else {
die("Bad data in uid: $uid");
}