Commit d859078e authored by Leigh Stoller's avatar Leigh Stoller

Add gid to project_leases, and allow creation in subgroups.

This is not exposed to users, the main reason for this is so that the name
space for leases (datasets) is per-group instead of per-project. We need
this when creating datasets via the geni interface (backend to APT), since
all leases are created in the holding project. Without a subgroup, we would
run into name collisions on the backend. It also gives us finer access
permission control for the same reason.

Note that I yanked out the lease cache from Lease.pm (not worth the
trouble), and I expanded Lookup to allow for the usual variety of
possibilities that we allow in other Lookup methods.
parent a9440d74
......@@ -175,8 +175,6 @@ my %LEASE_TRANSITIONS = (
);
# Cache of instances to avoid regenerating them.
my %leases = ();
my $debug = 0;
# Little helper and debug function.
......@@ -195,6 +193,7 @@ sub mysystem($)
sub lease_id($) {return $_[0]->{'DBROW'}->{'lease_id'}; }
sub uuid($) {return $_[0]->{'DBROW'}->{'uuid'}; }
sub pid($) {return $_[0]->{'DBROW'}->{'pid'}; }
sub gid($) {return $_[0]->{'DBROW'}->{'gid'}; }
sub idx($) {return $_[0]->{'DBROW'}->{'lease_idx'}; }
sub lease_idx($) {return $_[0]->idx(); }
sub owner($) {return $_[0]->{'DBROW'}->{'owner_uid'}; }
......@@ -214,33 +213,53 @@ sub lockpid($) {return $_[0]->{'DBROW'}->{'locker_pid'}; }
#
# Lookup a lease in the DB and return an object representing it.
#
sub Lookup($$;$)
sub Lookup($$;$$)
{
my ($class, $pid, $lease_id) = @_;
my ($class, $arg1, $arg2, $arg3) = @_;
my ($wclause);
# Determine how we were called. If only a single parameter was passed
# to the method, then it should be a lease index. If both are passed in,
# then they are what their variable names imply.
if (!defined($lease_id)) {
my $idx = $pid;
if ($idx !~ /^\d+$/) {
print STDERR "Lease->Lookup: single parameter to call must be a numeric index.\n";
if (!defined($arg2)) {
# idx, or pid/lease or pid/gid/lease
if ($arg1 =~ /^\d+$/) {
$wclause = "lease_idx='$arg1'";
}
elsif ($arg1 =~ /^([-\w]+)\/([-\w]+)$/) {
$wclause = "pid='$1' and gid='$1' and lease_id='$2'";
}
elsif ($arg1 =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$wclause = "pid='$1' and gid='$2' and lease_id='$arg2'";
}
else {
return undef;
}
# Look in cache first
return $leases{$idx}
if (exists($leases{$idx}));
$wclause = "lease_idx=$idx";
} else {
# Look in cache first
return $leases{"$pid:$lease_id"}
if (exists($leases{"$pid:$lease_id"}));
}
elsif (!defined($arg3)) {
# arg2 is the lease id.
return undef
if ($arg2 !~ /^[-\w]+$/);
$wclause = "pid='$pid' and lease_id='$lease_id'";
# arg1 is pid or pid/gid
if ($arg1 =~ /^[-\w]+$/) {
$wclause = "pid='$arg1' and gid='$arg1' and lease_id='$arg2'";
}
elsif ($arg1 =~ /^([-\w]+)\/([-\w]+)$/) {
$wclause = "pid='$1' and gid='$2' and lease_id='$arg2'";
}
else {
return undef;
}
}
else {
# arg3 is the lease id.
return undef
if ($arg3 !~ /^[-\w]+$/);
# arg1 is pid and arg2 is gid
return undef
if ($arg2 !~ /^[-\w]+$/ || $arg3 !~ /^[-\w]+$/);
$wclause = "pid='$arg1' and gid='$arg2' and lease_id='$arg3'";
}
my $self = {};
$self->{"LOCKED"} = 0;
$self->{"LOCKER_PID"} = 0;
......@@ -256,40 +275,16 @@ sub Lookup($$;$)
$self->{'DBROW'} = $query_result->fetchrow_hashref();;
bless($self, $class);
# Add to cache (dual lookup).
$leases{$self->pid() .":". $self->lease_id()} = $self;
$leases{$self->idx()} = $self;
return $self;
}
#
# Force a reload of the data.
#
sub LookupSync($$;$) {
my ($class, $pid, $lease_id) = @_;
my ($lease_idx, $plid);
if (!defined($lease_id)) {
$lease_idx = $pid;
if (exists($leases{$lease_idx})) {
$plid =
$leases{$lease_idx}->pid() .":".
$leases{$lease_idx}->lease_id();
}
} else {
$plid = "$pid:$lease_id";
if (exists($leases{$plid})) {
$lease_idx = $leases{$plid}->idx();
}
}
sub LookupSync($$;$$) {
my ($class, $arg1, $arg2, $arg3) = @_;
# delete from cache
delete($leases{$lease_idx})
if (defined($lease_idx) && exists($leases{$lease_idx}));
delete($leases{$plid})
if (defined($plid) && exists($leases{$plid}));
return Lookup($class, $lease_idx);
return Lookup($class, $arg1, $arg2, $arg3);
}
#
......@@ -310,19 +305,20 @@ sub DESTROY($) {
sub Create($$;$) {
my ($class, $argref, $attrs) = @_;
my ($lease_id, $pid, $uid, $type, $lease_end, $state);
my ($lease_id, $pid, $gid, $uid, $type, $lease_end, $state, $group);
return undef
if (!ref($argref));
$lease_id = $argref->{'lease_id'};
$pid = $argref->{'pid'};
$gid = $argref->{'gid'};
$uid = $argref->{'uid'};
$type = $argref->{'type'};
$lease_end = $argref->{'lease_end'};
$state = $argref->{'state'};
if (!($lease_id && $pid && $uid && $type &&
if (!($lease_id && $pid && $type &&
defined($lease_end) && $state)) {
print STDERR "Lease->Create: Missing required parameters in argref\n";
return undef;
......@@ -335,13 +331,24 @@ sub Create($$;$) {
return undef;
}
if (ref($pid) ne "Project") {
my $npid = Project->Lookup($pid);
if (!defined($npid)) {
print STDERR "Lease->Create: Bad/Unknown project: $pid\n";
if (ref($pid) eq "Project") {
$group = $pid->GetProjectGroup();
$pid = $gid = $group->pid();
}
elsif (ref($pid) eq "Group") {
$group = $pid;
$gid = $group->gid();
$pid = $group->pid();
}
else {
if (!defined($gid)) {
$gid = $pid;
}
$group = Group->Lookup("$pid/$pid");
if (!defined($group)) {
print STDERR "Lease->Create: Bad/Unknown project: $pid/$gid\n";
return undef;
}
$pid = $npid;
}
if (ref($uid) ne "User") {
......@@ -356,8 +363,9 @@ sub Create($$;$) {
# User must belong to incoming project. The code calling into Create()
# should have already checked to be sure that the caller has permission
# to create the lease in the first place.
if (!$pid->LookupUser($uid)) {
print STDERR "Lease->Create: Owner $uid is not a member of project $pid\n";
if (!$group->LookupUser($uid)) {
print STDERR
"Lease->Create: Owner $uid is not a member of project $pid/$gid\n";
return undef;
}
......@@ -392,7 +400,7 @@ sub Create($$;$) {
DBQueryWarn("insert into project_leases set ".
"lease_idx=$lease_idx,".
"lease_id='$lease_id',".
"pid='". $pid->pid() ."',".
"pid='$pid',gid='$gid', ".
"owner_uid='". $uid->uid() ."',".
"type='$type',".
($lease_end ? "lease_end=FROM_UNIXTIME($lease_end)," : "").
......@@ -421,8 +429,7 @@ sub Create($$;$) {
or return undef;
}
}
return Lookup($class, $pid->pid(), $lease_id);
return Lookup($class, $group->pid(), $group->gid(), $lease_id);
}
#
......@@ -435,7 +442,6 @@ sub Delete($) {
if (!ref($self));
my $idx = $self->idx();
my $plid = $self->pid() .":". $self->lease_id();
DBQueryWarn("delete from project_leases where lease_idx=$idx")
or return LEASE_ERROR_FAILED();
......@@ -446,11 +452,6 @@ sub Delete($) {
DBQueryWarn("delete from lease_permissions where lease_idx=$idx")
or return LEASE_ERROR_FAILED();
delete($leases{$idx})
if (exists($leases{$idx}));
delete($leases{$plid})
if (exists($leases{$plid}));
return 0
}
......@@ -801,14 +802,14 @@ sub AllProjectLeases($$;$)
}
my $query_result =
DBQueryWarn("select lease_id from project_leases where ".
DBQueryWarn("select lease_idx from project_leases where ".
"pid='$pid' $tclause order by lease_idx");
return ()
if (!$query_result || !$query_result->numrows);
while (my ($lease_id) = $query_result->fetchrow_array()) {
my $lease = Lookup($class, $pid, $lease_id);
while (my ($lease_idx) = $query_result->fetchrow_array()) {
my $lease = Lookup($class, $lease_idx);
# Something went wrong?
return ()
......@@ -919,18 +920,10 @@ sub Refresh($)
#
sub Flush($)
{
my ($self) = @_;
if (ref($self)) {
delete($leases{$self->pid().":".$self->lease_id()});
delete($leases{$self->lease_idx()});
}
}
sub FlushAll($)
{
my ($class) = @_;
%leases = ();
}
#
......@@ -1125,17 +1118,21 @@ sub AccessCheck($$$) {
}
# Need this for trust checks below.
my $proj = Project->Lookup($self->pid());
my $pid = $self->pid();
my $gid = $self->gid();
$gid = $pid
if ($gid eq "");
my $group = Group->Lookup($pid, $gid);
# Project managers can do anything to a lease that is attributed
# to their project.
if (TBMinTrust($proj->Trust($user), PROJMEMBERTRUST_GROUPROOT())) {
if (TBMinTrust($group->Trust($user), PROJMEMBERTRUST_GROUPROOT())) {
return 1;
}
# If the user is a member of the owning project, then they can at
# least grab the lease's info.
if (TBMinTrust($proj->Trust($user), PROJMEMBERTRUST_USER())) {
if (TBMinTrust($group->Trust($user), PROJMEMBERTRUST_USER())) {
$user_access = LEASE_ACCESS_READINFO();
}
......@@ -1285,9 +1282,10 @@ sub Stringify($)
my $lease_id = $self->lease_id();
my $pid = $self->pid();
my $gid = $self->gid();
my $uid = $self->owner();
return "[Lease: $pid/$lease_id/$uid]";
return "[Lease: $pid/$gid/$lease_id/$uid]";
}
#
......
......@@ -536,7 +536,8 @@ sub graceify($$)
if ($grace > 0) {
my $ghours = sprintf("%.1f", $grace / (60 * 60));
my $reason = ($expired ? "expired" : "been idle too long");
my $name = $lease->pid() . "/" . $lease->lease_id();
my $name = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $msg =
"Your '$ltype' lease $name has $reason.\n".
"It has entered a $ghours hour grace period.\n\n";
......@@ -564,7 +565,8 @@ sub lockify($)
return 1;
}
my $name = $lease->pid() . "/" . $lease->lease_id();
my $name = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $msg =
"Your '$ltype' lease $name has expired.\n".
"It has been administratively locked.\n";
......@@ -625,7 +627,8 @@ sub destroy($)
return 4;
}
my $name = $lease->pid() . "/" . $lease->lease_id();
my $name = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $ltype = $lease->type();
my $uid = $lease->owner();
......@@ -695,7 +698,8 @@ sub lease_list(@)
}
}
my $lname = $lease->pid() . "/" . $lease->lease_id();
my $lname = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $stime = strftime("%D %R", localtime($lease->inception()));
my $etime = strftime("%D %R", localtime($lease->lease_end()));
my $ltime = "never";
......
......@@ -44,6 +44,7 @@ sub usage()
my $optlist = "dhs:w:D:";
my $debug = 0;
my $pid;
my $gid;
my $state = "valid";
my $lname;
my $lease;
......@@ -68,6 +69,7 @@ use libdb;
use libtestbed;
use Lease;
use Project;
use Group;
use User;
#
......@@ -114,9 +116,15 @@ if (@ARGV != 1) {
# lease name must include a project
$lname = $ARGV[0];
if ($lname =~ /^([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$pid = $gid = $1;
$lname = $2;
} else {
}
elsif ($lname =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$gid = $2;
$lname = $3;
}
else {
fatal("Lease name $lname not in the form <pid>/<lname>.");
}
......@@ -133,15 +141,10 @@ if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
my $project = Project->Lookup($pid);
if (!defined($project)) {
fatal("No such project $pid\n");
}
#
# Check name: must exist, be modifiable and in the unapproved state.
#
$lease = Lease->Lookup($pid, $lname);
$lease = Lease->Lookup($pid, $gid, $lname);
if (!$lease) {
fatal("$pid/$lname: lease does not exist.");
}
......
......@@ -49,6 +49,7 @@ my $optlist = "dhUo:s:t:e:a:f:b";
my $debug = 0;
my $background = 0;
my $pid;
my $gid;
my $uid;
my $expire;
my $dstype = "stdataset";
......@@ -87,6 +88,7 @@ use libdb;
use Quota;
use Lease;
use Project;
use Group;
use User;
#
......@@ -170,9 +172,15 @@ if (!$size || @ARGV != 1) {
# name must include a project
$lname = $ARGV[0];
if ($lname =~ /^([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$pid = $gid = $1;
$lname = $2;
} else {
}
elsif ($lname =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$gid = $2;
$lname = $3;
}
else {
fatal("Dataset name $lname not in the form <pid>/<lname>.");
}
......@@ -204,13 +212,14 @@ if ($uid) {
#
# Check project: caller must be admin or have local_root access in the project.
#
my $project = Project->Lookup($pid);
if (!defined($project)) {
fatal("No such project $pid");
my $group = Group->Lookup($pid, $gid);
if (!defined($group)) {
fatal("No such group $pid/$gid");
}
my $project = $group->GetProject();
if (!TBAdmin() &&
!$project->AccessCheck($this_user, TB_PROJECT_CREATELEASE())) {
fatal("Must have local_root privileges in pid $pid");
fatal("Must have local_root privileges in $pid");
}
#
......@@ -315,8 +324,8 @@ if ($fstype) {
#
# Check name: lease with this name must not already exist.
#
if (Lease->Lookup($pid, $lname)) {
fatal("Lease $pid/$lname already exists.");
if (Lease->Lookup($pid, $gid, $lname)) {
fatal("Lease $pid/$gid/$lname already exists.");
}
#
......@@ -363,7 +372,8 @@ if ($vars->{"usequotas"}) {
my $args = {
"lease_id" => $lname,
"pid" => $project,
"pid" => $pid,
"gid" => $gid,
"uid" => $user,
"type" => $dstype,
"lease_end" => $expire,
......@@ -371,9 +381,10 @@ my $args = {
};
my $lease = Lease->Create($args, \%attrs);
if (!$lease) {
fatal("Could not create dataset lease $lname in $pid.");
fatal("Could not create dataset lease $lname in $pid/$gid.");
}
my $lease_idx = $lease->lease_idx();
my $lease_idx = $lease->lease_idx();
my $lease_uuid = $lease->uuid();
# No longer need to hold the quota lock
if (defined($quota)) {
......@@ -418,9 +429,9 @@ if ($approveme) {
#
if ($background) {
SENDMAIL($TBOPS, "Lease allocation failed!",
"Background resource allocation for Lease '$pid/$lname' ".
"failed!\n\n",
$TBOPS, undef, $logname);
"Background resource allocation for Lease '$pid/$gid/$lname' ".
"failed!\n\n",
$TBOPS, undef, $logname);
}
}
$lease->Unlock();
......@@ -435,7 +446,7 @@ if ($approveme) {
noapprove:
}
print "Created lease '$pid/$lname' for " . $descrip{$dstype};
print "Created lease '$pid/$gid/$lname' for " . $descrip{$dstype};
if ($expire == 0) {
print ", never expires.\n";
} else {
......@@ -445,8 +456,8 @@ if (!$approveme) {
# Note that the lease daemon sends out periodic email about
# unapproved leases.
SENDMAIL($TBOPS, "Lease approval required",
"Lease '$pid/$lname' requires approval. You can view it at\n".
"$TBBASE/show-dataset.php?idx=$lease_idx\n\n");
"Lease '$pid/$gid/$lname' requires approval. You can view it at\n".
"$TBBASE/show-dataset.php?uuid=$lease_uuid\n\n");
print "NOTE: lease must still be approved before it can be used\n";
}
......
......@@ -46,6 +46,7 @@ my $force = 0;
my $background = 0;
my $logname;
my $pid;
my $gid;
my $lname;
my $lease;
my $waittime;
......@@ -67,6 +68,7 @@ use libtestbed;
use libdb;
use Lease;
use Project;
use Group;
use User;
#
......@@ -115,9 +117,15 @@ if (@ARGV != 1) {
$lname = $ARGV[0];
if ($lname =~ /^([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$pid = $gid = $1;
$lname = $2;
} else {
}
elsif ($lname =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$gid = $2;
$lname = $3;
}
else {
fatal("Lease name $lname not in the form <pid>/<lname>.");
}
......@@ -130,8 +138,11 @@ if (! defined($this_user)) {
# Check lease: project must exist, lease must exist,
# caller must have privilege to destroy.
#
if (!Project->Lookup($pid) || !($lease = Lease->Lookup($pid, $lname)) ||
!$lease->AccessCheck($this_user, LEASE_ACCESS_DESTROY())) {
$lease = Lease->Lookup($pid, $gid, $lname);
if (!defined($lease)) {
fatal("No such lease $pid/$lname.");
}
if (!$lease->AccessCheck($this_user, LEASE_ACCESS_DESTROY())) {
fatal("Cannot access lease $pid/$lname.");
}
......@@ -218,9 +229,9 @@ if ($lease->DeallocResources()) {
#
if ($background) {
SENDMAIL($TBOPS, "Lease deallocation failed!",
"Background resource deallocation for Lease '$pid/$lname' ".
"failed!\n\n",
$TBOPS, undef, $logname);
"Background resource deallocation for Lease '$pid/$gid/$lname' ".
"failed!\n\n",
$TBOPS, undef, $logname);
}
fatal("$pid/$lname: could not deallocate resources, left in 'locked' state.");
}
......
......@@ -52,6 +52,7 @@ sub usage()
my $optlist = "dh";
my $debug = 0;
my $pid;
my $gid;
my $lname;
my $now = time();
my $lease;
......@@ -72,6 +73,7 @@ use lib "@prefix@/lib";
use libdb;
use Lease;
use Project;
use Group;
use User;
#
......@@ -113,9 +115,15 @@ if (@ARGV != 1) {
# lease name must include a project
$lname = $ARGV[0];
if ($lname =~ /^([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$pid = $gid = $1;
$lname = $2;
} else {
}
elsif ($lname =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$gid = $2;
$lname = $3;
}
else {
fatal("Lease name $lname not in the form <pid>/<lname>.");
}
......@@ -128,8 +136,11 @@ if (! defined($this_user)) {
# Check lease: project must exist, lease must exist,
# caller must have privilege to modify.
#
if (!Project->Lookup($pid) || !($lease = Lease->Lookup($pid, $lname)) ||
!$lease->AccessCheck($this_user, LEASE_ACCESS_MODIFY())) {
$lease = Lease->Lookup($pid, $gid, $lname);
if (!$lease) {
fatal("$pid/$gid/$lname: lease does not exist.");
}
if (!$lease->AccessCheck($this_user, LEASE_ACCESS_MODIFY())) {
fatal("Cannot access lease $pid/$lname.");
}
......
......@@ -51,6 +51,7 @@ sub usage()
my $optlist = "dhRUw:s:e:l:a:r:";
my $debug = 0;
my $pid;
my $gid;
my $state;
my $expire;
my $lastused;
......@@ -78,6 +79,7 @@ use lib "@prefix@/lib";
use libdb;
use Lease;
use Project;
use Group;
use User;
#
......@@ -169,9 +171,15 @@ if (@ARGV != 1) {
# lease name must include a project
$lname = $ARGV[0];
if ($lname =~ /^([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$pid = $gid = $1;
$lname = $2;
} else {
}
elsif ($lname =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$pid = $1;
$gid = $2;
$lname = $3;
}
else {
fatal("Lease name $lname not in the form <pid>/<lname>.");
}
......@@ -188,11 +196,6 @@ if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
my $project = Project->Lookup($pid);
if (!defined($project)) {
fatal("No such project $pid\n");
}
#
# Check dates: must be appropriately in the past/future.
#
......@@ -206,7 +209,7 @@ if (defined($lastused) && $lastused > $now) {
#
# Check name: must exist and be modifiable.
#
$lease = Lease->Lookup($pid, $lname);
$lease = Lease->Lookup($pid, $gid, $lname);
if (!$lease) {
fatal("$pid/$lname: lease does not exist.");
}
......
......@@ -181,16 +181,21 @@ elsif ($uid) {
}
elsif (@lnames > 0) {
foreach my $name (@lnames) {
my $lid;
# lease names must have a project context
if ($name =~ /^([-\w]+)\/([-\w]+)$/) {
my $lid = Lease->Lookup($1, $2);
if (!defined($lid)) {
fatal("Could not access lease $name\n.");
}
push @lids, $lid;
} else {
fatal("Lease name $name not in the form <pid>/<lname>.");
$lid = Lease->Lookup($1, $2);
}
elsif ($name =~ /^([-\w]+)\/([-\w]+)\/([-\w]+)$/) {
$lid = Lease->Lookup($1, $2, $3);
}
else {
fatal("Lease name $name not in the form <pid>/<lname>");
}
if (!defined($lid)) {
fatal("Could not access lease $name");
}
push @lids, $lid;
}
}
# special case: no args, show all leases owned by the caller
......@@ -229,7 +234,8 @@ if (@lids > 0) {
foreach my $lease (@lids) {
if ($showlockers) {
my $lname = $lease->pid() . "/" . $lease->lease_id();
my $lname = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $lproc = $lease->lockpid();
my $ltime;
if ($lproc != 0) {
......@@ -272,7 +278,8 @@ if (@lids > 0) {
} elsif ($sitevars{$ltype}->{'maxidle'} != 0) {
$policy = "idle";
}
my $lname = $lease->pid() . "/" . $lease->lease_id();
my $lname = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $stime = datestr($lease->statestamp());
my $etime = datestr($grace);
my $lchecked = datestr($lease->last_checked());
......@@ -295,7 +302,8 @@ if (@lids > 0) {
}
}
my $lname = $lease->pid() . "/" . $lease->lease_id();
my $lname = $lease->pid() . "/" .
$lease->gid() . "/" . $lease->lease_id();
my $stime = datestr($lease->inception());
my $etime = datestr($lease->lease_end());
my $ltime = datestr($lease->last_used());
......
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