Commit adbcfd47 authored by Leigh Stoller's avatar Leigh Stoller

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) $< $@
This diff is collapsed.
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
use Errno;
use strict;
#
# A wrapper for messing with the OPS DB from boss.
#
sub usage()
{
print "Usage: bugdbproxy adduser [-m] <uid> or\n";
exit(-1);
}
my $optlist = "d";
my $debug = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $OURDOMAIN= "@OURDOMAIN@";
my $DBCONF = "/usr/testbed/etc/mysqld.pwd";
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Only real root, cause the script has to read/write a pid file that
# cannot be accessed by the user.
#
if ($UID != 0) {
die("*** $0:\n".
" Must be root to run this script!\n");
}
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libtestbed;
use libtbdb;
# Locals
my $dbname = "mysql";
my $dbuser = "root";
my $dbpass;
# Protos
sub AddUser(@);
sub DelUser(@);
sub AddDB(@);
sub DelDB(@);
sub SetDBs(@);
sub fatal($);
#
# 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;
}
if (! @ARGV) {
usage();
}
#
# The DB passwd is stored in the config file, hopefully not world
# readable. Open and parse that file, then open a connection to the
# DB.
#
if (`cat $DBCONF` =~ /^([\w]*)$/) {
$dbpass = $1;
}
else {
fatal("Bad characters in password!");
}
if (TBDBConnect($dbname, $dbuser, $dbpass) < 0) {
fatal("Could not connect to ops database!");
}
my $action = shift(@ARGV);
if ($action eq "adduser") {
exit(AddUser(@ARGV));
}
elsif ($action eq "deluser") {
exit(DelUser(@ARGV));
}
elsif ($action eq "adddb") {
exit(AddDB(@ARGV));
}
elsif ($action eq "deldb") {
exit(DelDB(@ARGV));
}
elsif ($action eq "setdbs") {
exit(SetDBs(@ARGV));
}
else {
die("*** $0:\n".
" Do not know what to do with '$action'!\n");
}
exit(0);
#
# Utility function to see if a DB already exists.
#
sub DBExists($)
{
my ($dbname) = @_;
my $query_result =
DBQueryWarn("show databases like '$dbname'");
return -1
if (! $query_result);
return $query_result->numrows;
}
#
# Utility function to see if a DB is an emulab DB
#
sub IsEmulabDB($)
{
my ($dbname) = @_;
my $query_result =
DBQueryWarn("select * from emulab_dbs where dbname='$dbname'");
return -1
if (! $query_result);
return $query_result->numrows;
}
#
# Add user.
#
sub AddUser(@)
{
my ($uid) = @_;
my ($password);
usage()
if (@_ != 1);
# Password comes in from STDIN.
$_ = <STDIN>;
usage()
if (!defined($_));
if ($_ =~ /^(.*)$/) {
$password = $1;
}
else {
fatal("AddUser: Bad line in input: $_");
}
#
# Default for users is no privs on anything. They get privs later
# on a per-db basis.
#
DBQueryFatal("replace into user (Host, User, Password) ".
"values ('localhost','$uid', PASSWORD('$password'))")
or return -1;
# Eventually, we want to allow remote access.
DBQueryFatal("replace into user (Host, User, Password) ".
"values ('%.${OURDOMAIN}','$uid', PASSWORD('$password'))")
or return -1;
DBQueryFatal("flush privileges")
or return -1;
return 0;
}
#
# Delete user.
#
sub DelUser(@)
{
my ($uid) = @_;
usage()
if (@_ != 1);
DBQueryFatal("delete from db where User='$uid'")
or return -1;
DBQueryFatal("delete from user where User='$uid'")
or return -1;
DBQueryFatal("flush privileges")
or return -1;
return 0;
}
#
# Add a DB
#
sub AddDB(@)
{
my ($dbname) = @_;
usage()
if (@_ != 1);
my $exists = DBExists($dbname);
return -1
if ($exists < 0);
my $isemulab = IsEmulabDB($dbname);
return -1
if ($isemulab < 0);
#
# We do not want to create a DB if there already is one of that
# name, and its not in the emulab DB table. That means its a
# pre-existing DB and we are screwed.
#
if ($exists && !$isemulab) {
print "DB '$dbname' already exists! Must be a conflict.\n";
return -1;
}
DBQueryFatal("create database if not exists `$dbname`")
or return -1;
# This table tells us what belongs to Emulab.
DBQueryFatal("replace into emulab_dbs values ('$dbname')")
or return -1;
return 0;
}
#
# Remove a DB.
#
sub DelDB(@)
{
my ($dbname) = @_;
usage()
if (@_ != 1);
my $exists = DBExists($dbname);
return -1
if ($exists < 0);
my $isemulab = IsEmulabDB($dbname);
return -1
if ($isemulab < 0);
#
# We do not want to remove a DB if there is no entry in the emulab_dbs
# table; it belongs to someone else!
#
if ($exists && !$isemulab) {
print "DB '$dbname' is not an Emulab DB! Not removing!\n";
return -1;
}
DBQueryFatal("drop database if exists `$dbname`")
or return -1;
# Remove any dangling entries in the Db table ...
DBQueryFatal("delete from db where Db='$dbname'")
or return -1;
# This table tells us what belongs to Emulab. Delete as last step.
DBQueryFatal("delete from emulab_dbs where dbname='$dbname'")
or return -1;
return 0;
}
#
# Set DBs that a user may access.
#
sub SetDBs(@)
{
my $uid;
my %newglist = ();
my %oldglist = ();
usage()
if (@_ < 1);
$uid = shift(@_);
# List of new DBs to grant access to.
foreach my $db (@_) {
$newglist{$db} = $db;
}
my $query_result =
DBQueryFatal("select * from user where User='$uid'");
return -1
if (!$query_result);
if (!$query_result->numrows) {
print "User $uid does not exist in the user table!\n";
return 0;
}
# Generate existing DB access list.
$query_result =
DBQueryFatal("select Db from db where User='$uid'");
while (my ($db) = $query_result->fetchrow_array()) {
$oldglist{$db} = $db;
}
# First do deletions.
foreach my $db (keys(%oldglist)) {
next
if (exists($newglist{$db}));
# Do not delete user if not an Emulab created DB.
my $isemulab = IsEmulabDB($db);
return -1
if ($isemulab < 0);
next
if (!$isemulab);
DBQueryFatal("delete from db where User='$uid' and Db='$db'")
or return -1;
}
DBQueryFatal("flush privileges")
or return -1;
# Then do additions.
foreach my $db (keys(%newglist)) {
next
if (exists($oldglist{$db}));
# Do not add user if not an Emulab created DB.
my $isemulab = IsEmulabDB($db);
return -1
if ($isemulab < 0);
next
if (!$isemulab);
DBQueryFatal("grant all on `${db}`.* to '$uid'\@'localhost'")
or return -1;
# Eventually, we want to allow remote access.
DBQueryFatal("grant all on `${db}`.* to '$uid'\@'%.${OURDOMAIN}'")
or return -1;
}
DBQueryFatal("flush privileges")
or return -1;
return 0;
}
sub fatal($)
{
my($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
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