Commit 11cb4009 authored by Leigh Stoller's avatar Leigh Stoller

The next round of table changes. All tables indexed by pid,eid are now

indexed by exptidx. I also got the last of the pid and pid,gid tables.
parent 55712c70
This diff is collapsed.
......@@ -22,6 +22,7 @@ use English;
use Data::Dumper;
use File::Basename;
use overload ('""' => 'Stringify');
use vars qw($MEMBERLIST_FLAGS_UIDSONLY $MEMBERLIST_FLAGS_ALLUSERS);
# Configure variables
my $TB = "@prefix@";
......@@ -38,6 +39,10 @@ my $MIN_UNIX_GID = @MIN_UNIX_GID@;
my %groups = ();
my $debug = 0;
# MemberList flags.
$MEMBERLIST_FLAGS_UIDSONLY = 0x01;
$MEMBERLIST_FLAGS_ALLUSERS = 0x02;
# Little helper and debug function.
sub mysystem($)
{
......@@ -51,9 +56,44 @@ sub mysystem($)
#
# Lookup by idx.
#
sub Lookup($$)
sub Lookup($$;$)
{
my ($class, $gid_idx) = @_;
my ($class, $arg1, $arg2) = @_;
my $gid_idx;
#
# A single arg is either an index or a "pid,gid" or "pid/gid" string.
#
if (!defined($arg2)) {
if ($arg1 =~ /^(\d*)$/) {
$gid_idx = $1;
}
elsif ($arg1 =~ /^([-\w]*),([-\w]*)$/ ||
$arg1 =~ /^([-\w]*)\/([-\w]*)$/) {
$arg1 = $1;
$arg2 = $2;
}
else {
return undef;
}
}
elsif (! (($arg1 =~ /^[-\w]*$/) && ($arg2 =~ /^[-\w]*$/))) {
return undef;
}
#
# Two args means pid/gid lookup instead of gid_idx.
#
if (defined($arg2)) {
my $groups_result =
DBQueryWarn("select gid_idx from groups ".
"where pid='$arg1' and gid='$arg2'");
return undef
if (! $groups_result || !$groups_result->numrows);
($gid_idx) = $groups_result->fetchrow_array();
}
# Look in cache first
return $groups{"$gid_idx"}
......@@ -100,16 +140,7 @@ sub LookupByPidGid($$$)
{
my ($class, $pid, $gid) = @_;
my $query_result =
DBQueryWarn("select gid_idx from groups ".
"where pid='$pid' and gid='$gid'");
return undef
if (! $query_result || !$query_result->numrows);
my ($gid_idx) = $query_result->fetchrow_array();
return Group->Lookup($gid_idx);
return Group->Lookup($pid, $gid);
}
#
......@@ -266,8 +297,8 @@ sub Create($$$$$$)
return undef;
}
if (! DBQueryWarn("insert into group_stats (pid, gid, gid_idx) ".
"values ('$pid', '$gid', $gid_idx)")) {
if (! DBQueryWarn("insert into group_stats (pid, gid, gid_idx, pid_idx) ".
"values ('$pid', '$gid', $gid_idx, $pid_idx)")) {
DBQueryFatal("delete from groups where gid_idx='$gid_idx'");
return undef;
}
......@@ -279,7 +310,7 @@ sub Create($$$$$$)
}
#
# Delete a group.
# Delete a group. This will eventually change to group archival.
#
sub Delete($)
{
......@@ -291,11 +322,90 @@ sub Delete($)
my $gid_idx = $self->gid_idx();
DBQueryWarn("delete from group_stats where gid_idx='$gid_idx'");
DBQueryWarn("delete from groups where gid_idx='$gid_idx'");
# Order matters, groups table should be last so we can repeat if failure.
my @tables = ("group_policies", "group_stats", "groups");
foreach my $table (@tables) {
return -1
if (!DBQueryWarn("delete from $table where gid_idx='$gid_idx'"));
}
return 0;
}
#
# Generic function to look up some table values given a set of desired
# fields and some conditions. Pretty simple, not widely useful, but it
# helps to avoid spreading queries around then we need to.
#
sub TableLookUp($$$;$)
{
my ($self, $table, $fields, $conditions) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $gid_idx = $self->gid_idx();
if (defined($conditions) && "$conditions" ne "") {
$conditions = "and ($conditions)";
}
else {
$conditions = "";
}
return DBQueryWarn("select distinct $fields from $table ".
"where gid_idx='$gid_idx' $conditions");
}
#
# Ditto for update.
#
sub TableUpdate($$$;$)
{
my ($self, $table, $sets, $conditions) = @_;
# Must be a real reference.
return -1
if (! ref($self));
if (ref($sets) eq "HASH") {
$sets = join(",", map("$_='" . $sets->{$_} . "'", keys(%{$sets})));
}
my $gid_idx = $self->gid_idx();
if (defined($conditions) && "$conditions" ne "") {
$conditions = "and ($conditions)";
}
else {
$conditions = "";
}
return 0
if (DBQueryWarn("update $table set $sets ".
"where gid_idx='$gid_idx' $conditions"));
return -1;
}
#
# Check permissions.
#
sub AccessCheck($$$)
{
my ($self, $user, $access_type) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $uid = (ref($user) ? $user->uid() : $user);
my $pid = $self->pid();
my $gid = $self->gid();
return TBProjAccessCheck($uid, $pid, $gid, $access_type);
}
#
# Change the leader for a group.
#
......@@ -612,7 +722,62 @@ sub LeaderMailList($)
return $mailstr;
}
#
# Return list of members in this group, by specific trust.
#
sub MemberList($$;$$)
{
my ($self, $prval, $flags, $desired_trust) = @_;
# Must be a real reference.
return -1
if (! ref($self));
$flags = 0
if (!defined($flags));
my $gid_idx = $self->gid_idx();
my $pid_idx = $self->pid_idx();
my @result = ();
my $uids_only = ($flags & $MEMBERLIST_FLAGS_UIDSONLY ? 1 : 0);
my $trust_clause;
if (defined($desired_trust)) {
$trust_clause = "and trust='$desired_trust'"
}
elsif ($flags & $MEMBERLIST_FLAGS_ALLUSERS) {
$trust_clause = "";
}
else {
$trust_clause = "and trust!='none'"
}
my $query_result =
DBQueryWarn("select distinct m.uid_idx ".
" from group_membership as m ".
"where m.pid_idx='$pid_idx' and ".
" m.gid_idx='$gid_idx' $trust_clause");
return -1
if (!$query_result);
while (my ($uid_idx) = $query_result->fetchrow_array()) {
if ($uids_only) {
push(@result, $uid_idx);
next;
}
my $user = User->Lookup($uid_idx);
if (!defined($user)) {
print "Group::Memberlist: Could not map $uid_idx to object\n";
return undef;
}
push(@result, $user);
}
@$prval = @result;
return 0;
}
############################################################################
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
# Copyright (c) 2005-2007 University of Utah and the Flux Group.
# All rights reserved.
#
package Node;
......@@ -269,6 +269,12 @@ sub CreateVnodes($$)
my $vtype = $options->{'vtype'};
my $pnode = $options->{'nodeid'};
my $exptidx;
if (!TBExptIDX($pid, $eid, \$exptidx)) {
print STDERR "*** CreateVnodes: No such experiment $pid/$eid!\n";
return -1;
}
#
# Need the vtype node_type info.
#
......@@ -442,9 +448,10 @@ sub CreateVnodes($$)
$statement =
"insert into reserved set ".
" node_id='$vnodeid', " .
" exptidx=$exptidx, ".
" pid='$pid', ".
" eid='$eid', ".
" vname='$vnodeid', " .
" vname='$vnodeid', ".
" old_pid='', ".
" old_eid=''";
......
......@@ -262,6 +262,23 @@ sub Create($$$$)
return $newproject;
}
#
# Check permissions.
#
sub AccessCheck($$$)
{
my ($self, $user, $access_type) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $uid = (ref($user) ? $user->uid() : $user);
my $pid = $self->pid();
return TBProjAccessCheck($uid, $pid, $pid, $access_type);
}
#
# Send newproject email; separate function so email can be resent.
#
......@@ -388,6 +405,34 @@ sub GetLeader($)
return User->Lookup($self->head_idx());
}
#
# Return project group.
#
sub GetProjectGroup($)
{
my ($self) = @_;
# Must be a real reference.
return undef
if (! ref($self));
return $self->{'GROUP'};
}
#
# Return membership for user in the default group
#
sub LookupUser($$)
{
my ($self, $user) = @_;
# Must be a real reference.
return undef
if (! (ref($self) && ref($user)));
return $self->{'GROUP'}->LookupUser($user);
}
#
# Change the leader for a project. Done *only* before project is approved.
#
......
......@@ -678,5 +678,49 @@ sub SendVerifiedEmail($)
return 0;
}
#
# Return group membership for a user.
#
sub GroupMembershipList($$;$)
{
my ($self, $prval, $desired_trust) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $uid_idx = $self->uid_idx();
my $none = $Group::MemberShip::TRUSTSTRING_NONE;
my @result = ();
my $trust_clause;
if (!defined($desired_trust)) {
$trust_clause = "trust!='$none'"
}
else {
$trust_clause = "trust='$desired_trust'"
}
my $query_result =
DBQueryWarn("select distinct gid_idx from group_membership ".
"where uid_idx='$uid_idx' and $trust_clause");
return -1
if (!$query_result);
while (my ($gid_idx) = $query_result->fetchrow_array()) {
my $group = Group->Lookup($gid_idx);
if (!defined($group)) {
print("*** User::GroupMembershipList: ".
"Could not load group $gid_idx!");
return -1;
}
push(@result, $group);
}
@$prval = @result;
return 0;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -83,7 +83,7 @@ else {
die("Tainted argument $pid!\n");
}
# Temporary ...
# Temporary ... See utils/firstuser ...
DBQueryFatal("update group_membership set pid_idx=1,gid_idx=1 ".
"where pid='$TBOPSPID' and pid=gid");
......
......@@ -193,6 +193,7 @@ use English;
use libdb;
use libtestbed;
use libtblog;
use Group;
# Configure variables
my $TB = "@prefix@";
......@@ -220,6 +221,9 @@ sub TBADMINCTRL_POLICY_CLASS() { "class"; }
sub TBADMINCTRL_POLICY_ATTR() { "attribute"; }
sub TBADMINCTRL_POLICY_MEMBERSHIP() { "membership"; }
my $MINUS_GIDIDX = 0;
my $PLUS_GIDIDX = 999999;
#
# The current usage data structure, filled in below.
#
......@@ -771,7 +775,7 @@ sub TestPolicies($$$$)
$query_result =
DBQueryWarn("select distinct * from group_policies ".
"where (pid='$pid' and (pid=gid or gid='$gid')) or ".
" pid='+' or pid='-' ".
" pid='' or pid='-' ".
"order by pid,gid desc");
return -1
if (!$query_result);
......@@ -994,6 +998,7 @@ sub UpdateNodeTypeXpidPermissions()
if (!$query_result);
while (my $rowref = $query_result->fetchrow_hashref()) {
my $gid_idx = $rowref->{'gid_idx'};
my $ppid = $rowref->{'pid'};
my $pgid = $rowref->{'gid'};
my $policy = $rowref->{'policy'};
......@@ -1007,14 +1012,18 @@ sub UpdateNodeTypeXpidPermissions()
next
if ($count == 0);
my $group = Group->Lookup($gid_idx);
next
if (!defined($group) || !$group->IsProjectGroup());
next
if (exists($plus_policies{$auxdata}) &&
plus_policies{$auxdata} == 0);
$permissions{"$ppid"} = {}
if (!exists($permissions{"$ppid"}));
$permissions{"$gid_idx"} = {}
if (!exists($permissions{"$gid_idx"}));
$permissions{"$ppid"}->{$auxdata} = 1;
$permissions{"$gid_idx"}->{$auxdata} = 1;
}
#
......@@ -1037,13 +1046,16 @@ sub UpdateNodeTypeXpidPermissions()
return -1
if (!DBQueryWarn($create_def));
foreach my $pid (keys(%permissions)) {
my @typelist = keys(%{ $permissions{$pid} });
foreach my $gid_idx (keys(%permissions)) {
my @typelist = keys(%{ $permissions{$gid_idx} });
my $group = Group->Lookup($gid_idx);
my $pid = $group->pid();
foreach my $type (@typelist) {
return -1
if (! DBQueryWarn("insert into libadminctrl_table (pid, type)".
" values ('$pid', '$type')"));
if (! DBQueryWarn("insert into libadminctrl_table ".
" (pid_idx, pid, type)".
" values ($gid_idx, '$pid', '$type')"));
}
}
$query_result =
......
......@@ -1915,10 +1915,16 @@ sub MarkNodeDown($)
$pid = NODEDEAD_PID;
$eid = NODEDEAD_EID;
my $exptidx;
if (!TBExptIDX($pid, $eid, \$exptidx)) {
print "*** WARNING: No such experiment $pid/$eid!\n";
return -1;
}
my $query_result =
DBQueryFatal("replace into next_reserve " .
"(node_id, pid, eid) " .
"values ('$node', '$pid', '$eid')");
"(node_id, exptidx, pid, eid) " .
"values ('$node', '$exptidx', '$pid', '$eid')");
if ($query_result->num_rows < 1) {
DBWarn("WARNING: Could not mark $node down");
......@@ -2989,11 +2995,17 @@ sub MarkPhysNodeDown($)
$pid = NODEDEAD_PID;
$eid = NODEDEAD_EID;
my $exptidx;
if (!TBExptIDX($pid, $eid, \$exptidx)) {
print "*** WARNING: No such experiment $pid/$eid!\n";
return -1;
}
DBQueryFatal("lock tables reserved write");
DBQueryFatal("update reserved set " .
" pid='$pid',eid='$eid',rsrv_time=now() ".
" exptidx=$exptidx, pid='$pid',eid='$eid',rsrv_time=now() ".
"where node_id='$pnode'");
DBQueryFatal("unlock tables");
......@@ -4360,6 +4372,12 @@ sub TBSetExptFirewallVlan($$$$) {
return 0;
}
my $exptidx;
if (!TBExptIDX($pid, $eid, \$exptidx)) {
print "*** WARNING: No such experiment $pid/$eid!\n";
return -1;
}
#
# Need the virtual name since we use that to ensure uniqness in the
# firewalls table.
......@@ -4376,8 +4394,9 @@ sub TBSetExptFirewallVlan($$$$) {
#
# Change the firewalls table entry to reflect the VLAN
#
DBQueryWarn("replace into firewalls (pid,eid,fwname,vlan,vlanid) ".
"values ('$pid', '$eid', '$fwname', $fwvlan, $fwvlanid)");
DBQueryWarn("replace into firewalls (exptidx,pid,eid,fwname,vlan,vlanid) ".
"values ('$exptidx', '$pid', '$eid', ".
" '$fwname', $fwvlan, $fwvlanid)");
#
# Change the reserved table entries for all firewalled nodes to reflect it.
......
......@@ -341,12 +341,19 @@ def TBValidNodeLogType(type):
def MarkPhysNodeDown(pnode):
pid = NODEDEAD_PID;
eid = NODEDEAD_EID;
exptidx = 0
try:
exptidx = TBExptIDX(pid, eid)
except:
print "*** WARNING: No such experiment %s/%s!" % (pid,eid)
return
DBQueryFatal("lock tables reserved write")
DBQueryFatal("update reserved set "
" pid=%s,eid=%s,rsrv_time=now() "
" exptidx=%d,pid=%s,eid=%s,rsrv_time=now() "
"where node_id=%s",
(pid, eid, pnode))
(exptidx,pid, eid, pnode))
DBQueryFatal("unlock tables")
TBSetNodeHistory(pnode, TB_NODEHISTORY_OP_MOVE, os.getuid(), pid, eid)
return
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# Copyright (c) 2000-2005, 2007 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -101,6 +101,12 @@ if ($UID) {
}
TBDebugTimeStamp("nalloc checked exp permission");
my $exptidx;
if (!TBExptIDX($pid, $eid, \$exptidx)) {
print "*** WARNING: No such experiment $pid/$eid!\n";
exit -1;
}
#
# Before locking any tables, do a quick check to make sure the project
# is allowed to allocate the nodes, by type/class, plus other checks.
......@@ -172,7 +178,7 @@ foreach my $n (@node_names) {
#
# Add info the list of nodes to reserve; done in a single query below.
#
push(@newvals, "('$n','$pid','$eid','$n','','')");
push(@newvals, "('$n',$exptidx,'$pid','$eid','$n','','')");
push(@nodes, "$n");
}
TBDebugTimeStamp("nalloc checked all nodes");
......@@ -188,7 +194,7 @@ if ((!$noalloc || $partial) && (@newvals || @oldnodes)) {
if (@newvals &&
! DBQueryWarn("replace into reserved ".
" (node_id,pid,eid,vname,old_pid,old_eid) ".
" (node_id,exptidx,pid,eid,vname,old_pid,old_eid) ".
"values ". join(",",@newvals))) {
$error++;
}
......@@ -197,8 +203,8 @@ if ((!$noalloc || $partial) && (@newvals || @oldnodes)) {
# wrong; might need to rethink this.
foreach my $node (@oldnodes) {
if (!DBQueryWarn("update reserved " .
"set pid='$pid',eid='$eid', ".
" old_pid='', old_eid='' ".
"set exptidx=$exptidx,pid='$pid',eid='$eid', ".
" old_exptidx=0, old_pid='', old_eid='' ".
"where node_id='$node'")) {
$error++;
}
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -177,6 +177,12 @@ else {
$eid = "all";
}
my $exptidx;
if (!TBExptIDX($pid, $eid, \$exptidx)) {
fatal("*** $0:\n".
" No such experiment $pid/$eid!\n");
}
#
# Lets see if a known IP. If so we want to reuse the existing record.
#
......@@ -269,8 +275,9 @@ else {
" 'fxp', '$control_iface', '$ifacerole')");
DBQueryFatal("insert into reserved ".
"(node_id, pid, eid, rsrv_time, vname) ".
"values ('$nodename', '$pid', '$eid', now(), '$nickname')");
"(node_id, exptidx, pid, eid, rsrv_time, vname) ".
"values ('$nodename', $exptidx, ".
" '$pid', '$eid', now(), '$nickname')");
}
#
......
......@@ -2,7 +2,7 @@
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2006 University of Utah and the Flux Group.
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -33,6 +33,8 @@ my $TESTMODE = @TESTMODE@;
use lib "@prefix@/lib";
use libdb;
use libtestbed;
use User;
use Experiment;
use Node;
my $consetup = "$TB/libexec/console_setup";
......@@ -41,7 +43,6 @@ my $nodereboot = "$TB/bin/node_reboot";
my $makeconf = "$TB/sbin/dhcpd_makeconf";
my $reloadpid = "emulab-ops";
my $pendingeid = "reloadpending";
my $reloadeid = "reloading";
my $rppendingeid= "repositionpending";
my $oldreserved_pid = OLDRESERVED_PID;
my $oldreserved_eid = OLDRESERVED_EID;
......@@ -96,12 +97,42 @@ if ($eid =~ /^([-\@\w]+)$/) { $eid = $1; }
else { die("Bad data in eid: $eid."); }
# Make sure that the experiment actually exists
if (!ExpState($pid,$eid)) {
my $experiment = Experiment->Lookup($pid, $eid);
if (!defined($experiment)) {
die("There is no experiment '$eid' in project '$pid'.\n");
}
# Need the project index below.
my $pid_idx = $experiment->pid_idx();
my $exptidx = $experiment->idx();
my $old_exptidx;
if (!TBExptIDX($oldreserved_pid, $oldreserved_eid, \$old_exptidx)) {
die("No such experiment $oldreserved_pid/$oldreserved_eid!\n");
}
my $locker_exptidx;
if (!TBExptIDX($lockedpid, $lockedeid, \$locker_exptidx)) {
die("No such experiment $lockedpid/$lockedeid!\n");
}
my $reload_exptidx;
if (!TBExptIDX($reloadpid, $pendingeid, \$reload_exptidx)) {
die("No such experiment $reloadpid/$pendingeid!\n");
}
# Only in Utah, see below
my $rppend_exptidx;
#
# Verify user and get his DB uid for later.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
die("You ($UID) do not exist!\n");
}
my $user_uid = $this_user->uid();
# Make sure the user has the ability to modify this experiment
if (!TBExptAccessCheck($UID, $pid, $eid, TB_EXPT_MODIFY)) {
if (!$experiment->AccessCheck($this_user, TB_EXPT_MODIFY)) {
die("You do not have permission to modify '$eid' in project '$pid'.\n");
}
......@@ -187,10 +218,15 @@ foreach my $n (@nodes) {
if ( $moveToOldReserved ) {
# Move to holding reservation. Node is not free, but is no longer
# owned by the pid/eid, so cannot be mucked with.
if (! DBQueryWarn("update reserved " .
"set vname='$n', pid='$oldreserved_pid', ".
"eid='$oldreserved_eid', old_pid='$pid', ".
"old_eid='$eid' where node_id='$n'")) {
"set vname='$n', ".
" exptidx=$exptidx, ".
" pid='$oldreserved_pid', ".
" eid='$oldreserved_eid', ".