...
 
Commits (22)
...@@ -207,6 +207,12 @@ sub STATUS($$;$) ...@@ -207,6 +207,12 @@ sub STATUS($$;$)
$self->{'STATUS'}->{$name} = $newval; $self->{'STATUS'}->{$name} = $newval;
return $self->{'STATUS'}->{$name}; return $self->{'STATUS'}->{$name};
} }
sub IsUp($)
{
my ($self) = @_;
return $self->status() eq "up" ? 1 : 0;
}
# #
# Insert a status (change) event. # Insert a status (change) event.
...@@ -315,8 +321,14 @@ sub CheckStatus($$;$) ...@@ -315,8 +321,14 @@ sub CheckStatus($$;$)
$self->name() . " cluster: " . $perrmsg; $self->name() . " cluster: " . $perrmsg;
} }
else { else {
$$perrmsg = "The " . $self->name() . " cluster ". my $message = "The " . $self->name() . " cluster ".
"is currently unreachable, please try again later."; "is currently unavailable";
if ($$perrmsg ne "") {
$message .= ": " . $$perrmsg;
}
$message .= ". ";
$message .= "Please try again later.";
$$perrmsg = $message;
} }
return 1; return 1;
} }
......
...@@ -498,6 +498,16 @@ sub SetStatus($$) ...@@ -498,6 +498,16 @@ sub SetStatus($$)
} }
sub SetAggregateStatus($$)
{
my ($self, $status) = @_;
foreach my $agg ($self->AggregateList()) {
$agg->SetStatus($status);
}
return 0;
}
sub ActiveAggregateList($) sub ActiveAggregateList($)
{ {
my ($self) = @_; my ($self) = @_;
...@@ -2915,9 +2925,9 @@ sub CredentialError() ...@@ -2915,9 +2925,9 @@ sub CredentialError()
# #
# Ask aggregate to terminate a sliver. # Ask aggregate to terminate a sliver.
# #
sub Terminate($) sub Terminate($;$)
{ {
my ($self) = @_; my ($self, $withprivs) = @_;
my $method; my $method;
my @params; my @params;
my $authority = $self->GetGeniAuthority(); my $authority = $self->GetGeniAuthority();
...@@ -2946,6 +2956,14 @@ sub Terminate($) ...@@ -2946,6 +2956,14 @@ sub Terminate($)
} }
else { else {
my $credentials; my $credentials;
if ($withprivs) {
my $slice_credential = APT_Geni::GenAuthCredential($slice);
return CredentialError()
if (!defined($slice_credential));
$credentials = [$slice_credential->asString()];
}
else {
my ($slice_credential, $speaksfor_credential) = my ($slice_credential, $speaksfor_credential) =
APT_Geni::GenCredentials($slice, $geniuser, undef, 1); APT_Geni::GenCredentials($slice, $geniuser, undef, 1);
return CredentialError() return CredentialError()
...@@ -2953,7 +2971,9 @@ sub Terminate($) ...@@ -2953,7 +2971,9 @@ sub Terminate($)
$credentials = [$slice_credential->asString()]; $credentials = [$slice_credential->asString()];
if (defined($speaksfor_credential)) { if (defined($speaksfor_credential)) {
$credentials = [@$credentials, $speaksfor_credential->asString()]; $credentials = [@$credentials,
$speaksfor_credential->asString()];
}
} }
$method = "DeleteSliver"; $method = "DeleteSliver";
@params = ($slice->urn(), $credentials, @params = ($slice->urn(), $credentials,
......
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2007-2016, 2018 University of Utah and the Flux Group. # Copyright (c) 2007-2016, 2018, 2019 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -42,6 +42,7 @@ use vars qw(@ISA @EXPORT); ...@@ -42,6 +42,7 @@ use vars qw(@ISA @EXPORT);
use emdb; use emdb;
use libtestbed; use libtestbed;
use APT_Instance; use APT_Instance;
use APT_Aggregate;
use Project; use Project;
use Group; use Group;
use GeniHRN; use GeniHRN;
...@@ -226,3 +227,24 @@ sub ReservationUtilization($$) ...@@ -226,3 +227,24 @@ sub ReservationUtilization($$)
return 0; return 0;
} }
#
# Look using all the various lookup ways.
#
sub LookupAggregate($)
{
my ($token) = @_;
my $aggregate = APT_Aggregate->Lookup($token);
return $aggregate
if (defined($aggregate));
$aggregate = APT_Aggregate->LookupByNickname($token);
return $aggregate
if (defined($aggregate));
$aggregate = APT_Aggregate->LookupByDomain($token);
return $aggregate
if (defined($aggregate));
return undef;
}
...@@ -83,7 +83,7 @@ sub usage() ...@@ -83,7 +83,7 @@ sub usage()
exit(-1); exit(-1);
} }
my $optlist = "du:p:o:n:CRB:N"; my $optlist = "du:p:o:n:CRB:Nr:h:";
my $basename = "py-cage"; my $basename = "py-cage";
my $jailname = "py-cage-$$"; my $jailname = "py-cage-$$";
my $user = "nobody"; my $user = "nobody";
...@@ -92,6 +92,8 @@ my $gid; ...@@ -92,6 +92,8 @@ my $gid;
my $pfile; my $pfile;
my $ofile; my $ofile;
my $ifile; my $ifile;
my $repo;
my $reporef;
my $limits = 1; my $limits = 1;
my $haverctl = 0; my $haverctl = 0;
...@@ -109,6 +111,8 @@ sub mysystem($); ...@@ -109,6 +111,8 @@ sub mysystem($);
# #
my $TBROOT = "@prefix@"; my $TBROOT = "@prefix@";
my $GENILIB = "$TBROOT/lib/geni-lib/"; my $GENILIB = "$TBROOT/lib/geni-lib/";
my $REPODIR = "/repos";
my $GIT = "/usr/local/bin/git";
my $debug = 0; my $debug = 0;
# Watch for this being defined in the calling environment and use that. # Watch for this being defined in the calling environment and use that.
...@@ -229,6 +233,31 @@ if (defined($options{"B"})) { ...@@ -229,6 +233,31 @@ if (defined($options{"B"})) {
} }
$basename = $base; $basename = $base;
} }
if (defined($options{"r"})) {
$repo = $options{"r"};
# Must taint check
if ($repo =~ /^([-\w]+)$/) {
$repo = $1;
}
else {
print STDERR "Bad data in argument: $repo\n";
usage();
}
if (! -e "$REPODIR/$repo") {
print STDERR "No such repo '$repo'\n";
usage();
}
if (defined($options{"h"})) {
$reporef = $options{"h"};
# Must taint check
if ($reporef =~ /^([-\w\/]+)$/) {
$reporef = $1;
}
else {
die("Bad data in argument: $reporef");
}
}
}
# #
# Extract params from the environment (if invoked via rungenilib.proxy). # Extract params from the environment (if invoked via rungenilib.proxy).
...@@ -387,6 +416,32 @@ if ($action != 1) { ...@@ -387,6 +416,32 @@ if ($action != 1) {
print STDERR "Could not populate jail\n"; print STDERR "Could not populate jail\n";
exit(-1); exit(-1);
} }
if (defined($repo)) {
if (mysystem("$GIT clone -q $REPODIR/$repo ".
" ${jailrootdir}${tempdir}/repository")) {
print STDERR "Could not clone repo in the jail\n";
exit(-1);
}
# The root of the repository for module imports.
$ENV{"PYTHONPATH"} = "/${tempdir}/repository:" . $ENV{"PYTHONPATH"};
if (defined($reporef)) {
if ($reporef =~ m"^(refs/|)heads/(.+)") {
my $branchname = $2;
mysystem("cd ${jailrootdir}${tempdir}/repository; ".
"$GIT checkout -q $branchname");
}
else {
mysystem("cd ${jailrootdir}${tempdir}/repository; ".
"$GIT checkout -q $reporef");
}
if ($?) {
print STDERR "Could not clone repo in the jail\n";
exit(-1);
}
}
}
# #
# XXX adjust the environment for the portal module to reflect the jail. # XXX adjust the environment for the portal module to reflect the jail.
......
#!/usr/bin/perl -w #!/usr/bin/perl -w
# #
# Copyright (c) 2000-2018 University of Utah and the Flux Group. # Copyright (c) 2000-2019 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -34,7 +34,7 @@ use POSIX qw(:signal_h); ...@@ -34,7 +34,7 @@ use POSIX qw(:signal_h);
sub usage() sub usage()
{ {
print STDOUT print STDOUT
"Usage: gitrepo.proxy -n reponame clone url\n". "Usage: gitrepo.proxy -n reponame clone [-c] url\n".
"Usage: gitrepo.proxy -n reponame update\n". "Usage: gitrepo.proxy -n reponame update\n".
"Usage: gitrepo.proxy -n reponame delete\n"; "Usage: gitrepo.proxy -n reponame delete\n";
...@@ -127,8 +127,17 @@ exit(-1); ...@@ -127,8 +127,17 @@ exit(-1);
# #
sub Clone() sub Clone()
{ {
my $checkout = 0;
usage() usage()
if (!@ARGV); if (!@ARGV);
if ($ARGV[0] eq "-c") {
$checkout = 1;
shift(@ARGV);
usage()
if (!@ARGV);
}
my $repourl = shift(@ARGV); my $repourl = shift(@ARGV);
if (-e "$REPODIR/$reponame") { if (-e "$REPODIR/$reponame") {
...@@ -137,7 +146,7 @@ sub Clone() ...@@ -137,7 +146,7 @@ sub Clone()
chdir($REPODIR) or chdir($REPODIR) or
fatal("Could not chdir to $REPODIR"); fatal("Could not chdir to $REPODIR");
my $status = RunCommand("$GIT clone --bare ". my $status = RunCommand("$GIT clone " . ($checkout ? "" : "--bare ") .
" $repourl $reponame"); " $repourl $reponame");
if ($status) { if ($status) {
fatal("Not able to clone repo from $repourl"); fatal("Not able to clone repo from $repourl");
...@@ -152,12 +161,39 @@ sub Clone() ...@@ -152,12 +161,39 @@ sub Clone()
chdir("$REPODIR/$reponame") or chdir("$REPODIR/$reponame") or
fatal("Could not chdir to $REPODIR/$reponame"); fatal("Could not chdir to $REPODIR/$reponame");
#
# If we did a checkout, look for submodules that need to be initialized
#
if ($checkout) {
if (-e ".gitmodules") {
if (system("$GIT submodule init") ||
system("$GIT submodule update")) {
fatal("Could not initialize submodules");
}
}
# Need to force getting all the remote branches.
# -p prunes deleted branches. But tags are not pruned.
if (system("$GIT fetch -u -f -p -t origin '+refs/*:refs/*'")) {
fatal("Could not fetch remote branches");
}
if (-e "profile.py") {
system("/bin/cat profile.py");
}
elsif (-e "profile.rspec") {
system("/bin/cat profile.rspec");
}
else {
print STDERR "No geni-lib script or rspec in this repository\n";
}
}
else {
my $refspec = GetDefaultBranch($reponame); my $refspec = GetDefaultBranch($reponame);
if (system("$GIT cat-file -e ${refspec}:profile.py") && if (system("$GIT cat-file -e ${refspec}:profile.py") &&
system("$GIT cat-file -e ${refspec}:profile.rspec")) { system("$GIT cat-file -e ${refspec}:profile.rspec")) {
print STDERR "No geni-lib script or rspec in this repository\n"; print STDERR "No geni-lib script or rspec in this repository\n";
} }
}
return 0; return 0;
} }
...@@ -187,12 +223,31 @@ sub Update() ...@@ -187,12 +223,31 @@ sub Update()
chdir("$REPODIR/$reponame") or chdir("$REPODIR/$reponame") or
fatal("Could not chdir to $REPODIR/$reponame"); fatal("Could not chdir to $REPODIR/$reponame");
#
# When not using a bare repo, we have to force the fetch to update
# the current banch.
#
my $fopt = (-e ".git" ? "-u -f" : "");
# -p prunes deleted branches. But tags are not pruned. # -p prunes deleted branches. But tags are not pruned.
my $status = RunCommand("$GIT fetch -p -t origin '+refs/*:refs/*'"); my $status = RunCommand("$GIT fetch $fopt -p -t origin '+refs/*:refs/*'");
if ($status) { if ($status) {
fatal("Not able to update repo"); fatal("Not able to update repo");
} }
#
# Local checkout, must merge. This is done when we have submodules.
#
if (-e ".git") {
my $status = RunCommand("$GIT merge");
if ($status) {
fatal("Not able to fetch repo");
}
$status = RunCommand("$GIT submodule update");
if ($status) {
fatal("Not able to update submodules");
}
}
my $current_refspec = GetDefaultBranch($reponame); my $current_refspec = GetDefaultBranch($reponame);
my $remote_refspec = GetRemoteDefaultBranch($reponame); my $remote_refspec = GetRemoteDefaultBranch($reponame);
...@@ -206,10 +261,23 @@ sub Update() ...@@ -206,10 +261,23 @@ sub Update()
} }
$current_refspec = $remote_refspec; $current_refspec = $remote_refspec;
} }
if (-e ".git") {
if (-e "profile.py") {
system("/bin/cat profile.py");
}
elsif (-e "profile.rspec") {
system("/bin/cat profile.rspec");
}
else {
print STDERR "No geni-lib script or rspec in this repository\n";
}
}
else {
if (system("$GIT cat-file -e ${current_refspec}:profile.py") && if (system("$GIT cat-file -e ${current_refspec}:profile.py") &&
system("$GIT cat-file -e ${current_refspec}:profile.rspec")) { system("$GIT cat-file -e ${current_refspec}:profile.rspec")) {
print STDERR "No geni-lib script or rspec in this repository\n"; print STDERR "No geni-lib script or rspec in this repository\n";
} }
}
return 0; return 0;
} }
......
...@@ -42,6 +42,8 @@ sub usage() ...@@ -42,6 +42,8 @@ sub usage()
print STDERR " manage_aggregate ping [-a <agg>]\n"; print STDERR " manage_aggregate ping [-a <agg>]\n";
print STDERR " manage_aggregate portals [-a <agg>] add <portal> \n"; print STDERR " manage_aggregate portals [-a <agg>] add <portal> \n";
print STDERR " manage_aggregate portals [-a <agg>] rem <portal> \n"; print STDERR " manage_aggregate portals [-a <agg>] rem <portal> \n";
print STDERR " manage_aggregate feature [-a <agg>] set <feature> \n";
print STDERR " manage_aggregate feature [-a <agg>] clear \n";
print STDERR "Options:\n"; print STDERR "Options:\n";
print STDERR " -a agg - URN, nickname or domain of aggregate\n"; print STDERR " -a agg - URN, nickname or domain of aggregate\n";
exit(-1); exit(-1);
...@@ -88,7 +90,7 @@ sub DoShow(); ...@@ -88,7 +90,7 @@ sub DoShow();
sub DoFlags(); sub DoFlags();
sub DoPing(); sub DoPing();
sub DoPortals(); sub DoPortals();
sub LookupAggregate($); sub DoFeature();
# #
# Parse command arguments. Once we return from getopts, all that should be # Parse command arguments. Once we return from getopts, all that should be
...@@ -109,7 +111,7 @@ my $action = shift(@ARGV); ...@@ -109,7 +111,7 @@ my $action = shift(@ARGV);
# #
# Default to local cluster, unless overridden in the action. # Default to local cluster, unless overridden in the action.
# #
my $aggregate = LookupAggregate($MYURN); my $aggregate = APT_Utility::LookupAggregate($MYURN);
if (!defined($aggregate)) { if (!defined($aggregate)) {
fatal("Could not lookup local aggregate: $MYURN"); fatal("Could not lookup local aggregate: $MYURN");
} }
...@@ -134,6 +136,9 @@ elsif ($action eq "ping") { ...@@ -134,6 +136,9 @@ elsif ($action eq "ping") {
elsif ($action eq "portals") { elsif ($action eq "portals") {
DoPortals(); DoPortals();
} }
elsif ($action eq "feature") {
DoFeature();
}
else { else {
usage(); usage();
} }
...@@ -187,7 +192,7 @@ sub DoShow() ...@@ -187,7 +192,7 @@ sub DoShow()
if (@ARGV); if (@ARGV);
if (defined($options{"a"})) { if (defined($options{"a"})) {
$aggregate = LookupAggregate($options{"a"}); $aggregate = APT_Utility::LookupAggregate($options{"a"});
fatal("No such aggregate") fatal("No such aggregate")
if (!defined($aggregate)); if (!defined($aggregate));
} }
...@@ -207,6 +212,7 @@ sub DoShow() ...@@ -207,6 +212,7 @@ sub DoShow()
print "LocalImages: " . ($aggregate->nolocalimages() ? "No" : "Yes")."\n"; print "LocalImages: " . ($aggregate->nolocalimages() ? "No" : "Yes")."\n";
print "PanicPowerOff: " . ($aggregate->panicpoweroff() ? "Yes" : "No")."\n"; print "PanicPowerOff: " . ($aggregate->panicpoweroff() ? "Yes" : "No")."\n";
print "Portals: " . $aggregate->portals() . "\n"; print "Portals: " . $aggregate->portals() . "\n";
print "Use Feature: " . ($aggregate->canuse_feature() || "") . "\n";
print "Status: " . $aggregate->status() . "\n"; print "Status: " . $aggregate->status() . "\n";
return 0; return 0;
} }
...@@ -226,7 +232,7 @@ sub DoFlags() ...@@ -226,7 +232,7 @@ sub DoFlags()
if (@ARGV != 2 || $ARGV[1] !~ /^(yes|no)$/); if (@ARGV != 2 || $ARGV[1] !~ /^(yes|no)$/);
if (defined($options{"a"})) { if (defined($options{"a"})) {
$aggregate = LookupAggregate($options{"a"}); $aggregate = APT_Utility::LookupAggregate($options{"a"});
fatal("No such aggregate") fatal("No such aggregate")
if (!defined($aggregate)); if (!defined($aggregate));
} }
...@@ -304,7 +310,7 @@ sub DoPing() ...@@ -304,7 +310,7 @@ sub DoPing()
if (@ARGV); if (@ARGV);
if (defined($options{"a"})) { if (defined($options{"a"})) {
$aggregate = LookupAggregate($options{"a"}); $aggregate = APT_Utility::LookupAggregate($options{"a"});
fatal("No such aggregate") fatal("No such aggregate")
if (!defined($aggregate)); if (!defined($aggregate));
} }
...@@ -327,7 +333,7 @@ sub DoPortals() ...@@ -327,7 +333,7 @@ sub DoPortals()
usage(); usage();
} }
if (defined($options{"a"})) { if (defined($options{"a"})) {
$aggregate = LookupAggregate($options{"a"}); $aggregate = APT_Utility::LookupAggregate($options{"a"});
fatal("No such aggregate") fatal("No such aggregate")
if (!defined($aggregate)); if (!defined($aggregate));
} }
...@@ -364,6 +370,44 @@ sub DoPortals() ...@@ -364,6 +370,44 @@ sub DoPortals()
print "Portals set to: ". join(",", @portals) . "\n"; print "Portals set to: ". join(",", @portals) . "\n";
} }
#
# Set or clear the canuse feature
#
sub DoFeature()
{
my $optlist = "a:";
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"a"})) {
$aggregate = APT_Utility::LookupAggregate($options{"a"});
fatal("No such aggregate")
if (!defined($aggregate));
}
usage()
if (@ARGV < 1 || @ARGV > 2);
my $action = shift(@ARGV);
fatal("Must be one of 'set' or 'clear'")
if ($action ne "set" && $action ne "clear");
if ($action eq "clear") {
$aggregate->Update({"canuse_feature" => "NULL"}) == 0
or fatal("Could not clear feature");
}
else {
usage()
if (!@ARGV);
my $feature = shift(@ARGV);
$aggregate->Update({"canuse_feature" => $feature}) == 0
or fatal("Could not set feature");
}
}
exit(0); exit(0);
sub fatal($) sub fatal($)
...@@ -375,21 +419,3 @@ sub fatal($) ...@@ -375,21 +419,3 @@ sub fatal($)
exit(-1); exit(-1);
} }
sub LookupAggregate($)
{
my ($token) = @_;
my $aggregate = APT_Aggregate->Lookup($token);
return $aggregate
if (defined($aggregate));
$aggregate = APT_Aggregate->LookupByNickname($token);
return $aggregate
if (defined($aggregate));
$aggregate = APT_Aggregate->LookupByDomain($token);
return $aggregate
if (defined($aggregate));
return undef;
}
...@@ -108,6 +108,8 @@ sub DoCommitList(); ...@@ -108,6 +108,8 @@ sub DoCommitList();
sub DoCommitInfo(); sub DoCommitInfo();
sub DoGetSource(); sub DoGetSource();
sub DoGetRepoSize(); sub DoGetRepoSize();
sub DoRemoveRepo();
sub DoPruneStaleRepos();
sub GetRepoSource($;$$); sub GetRepoSource($;$$);
sub GetRepoSize($); sub GetRepoSize($);
sub GetBranchList($); sub GetBranchList($);
...@@ -195,6 +197,12 @@ elsif ($action eq "commitinfo") { ...@@ -195,6 +197,12 @@ elsif ($action eq "commitinfo") {
elsif ($action eq "reposize") { elsif ($action eq "reposize") {
DoGetRepoSize(); DoGetRepoSize();
} }
elsif ($action eq "remove") {
DoRemoveRepo();
}
elsif ($action eq "prune") {
DoPruneStaleRepos();
}
else { else {
usage(); usage();
} }
...@@ -264,15 +272,17 @@ sub DoCheckRemote() ...@@ -264,15 +272,17 @@ sub DoCheckRemote()
# Use -o to write the file to stdout or a file. # Use -o to write the file to stdout or a file.
# Use -r to remove repo after getting the script/rspec. # Use -r to remove repo after getting the script/rspec.
# Add -u to update if repo is already cloned. # Add -u to update if repo is already cloned.
# Add -c for a full checkout. Only admins for now.
# #
sub DoClone() sub DoClone()
{ {
my $optlist = "o:rn:uS:"; my $optlist = "o:rn:uS:c";
my $ofile; my $ofile;
my $remove; my $remove;
my $reponame; my $reponame;
my $update; my $update;
my $sourcename; my $sourcename;
my $checkout = 0;
my %options = (); my %options = ();
if (! getopts($optlist, \%options)) { if (! getopts($optlist, \%options)) {
...@@ -286,6 +296,9 @@ sub DoClone() ...@@ -286,6 +296,9 @@ sub DoClone()
if ($repourl =~ /^(.*)$/) { if ($repourl =~ /^(.*)$/) {
$repourl = $1; $repourl = $1;
} }
if (defined($options{"c"})) {
$checkout = 1;
}
if (defined($options{"o"})) { if (defined($options{"o"})) {
$ofile = $options{"o"}; $ofile = $options{"o"};
} }
...@@ -320,7 +333,11 @@ sub DoClone() ...@@ -320,7 +333,11 @@ sub DoClone()
$cmd .= "-n $reponame update"; $cmd .= "-n $reponame update";
} }
else { else {
$cmd .= "-n $reponame clone '$repourl'"; $cmd .= "-n $reponame clone ";
if ($checkout) {
$cmd .= " -c ";
}
$cmd .= "'$repourl'";
} }
if ($debug) { if ($debug) {
print "'$cmd'\n"; print "'$cmd'\n";
...@@ -345,7 +362,7 @@ sub DoClone() ...@@ -345,7 +362,7 @@ sub DoClone()
RemoveRepo($reponame); RemoveRepo($reponame);
fatal("Could not estimate repository size"); fatal("Could not estimate repository size");
} }
if ($size > 500) { if ($size > 150) {
RemoveRepo($reponame); RemoveRepo($reponame);
UserError("Repository is too big: greate then 500MiB"); UserError("Repository is too big: greate then 500MiB");
} }
...@@ -368,6 +385,7 @@ sub DoClone() ...@@ -368,6 +385,7 @@ sub DoClone()
$webtask->log($log); $webtask->log($log);
$webtask->hash($hash); $webtask->hash($hash);
$webtask->size("$size MiB"); $webtask->size("$size MiB");
$webtask->name($reponame);
} }
if (defined($ofile)) { if (defined($ofile)) {
if ($ofile eq "-") { if ($ofile eq "-") {
...@@ -622,40 +640,43 @@ sub GetRepoSource($;$$) ...@@ -622,40 +640,43 @@ sub GetRepoSource($;$$)
fatal("Could not chdir to $repodir: $!"); fatal("Could not chdir to $repodir: $!");
foreach my $maybe (@locations) { foreach my $maybe (@locations) {
my $file;
if (system("$GIT cat-file -e ". if (system("$GIT cat-file -e ".
"$refspec:${maybe}.py >/dev/null 2>&1") == 0) { "$refspec:${maybe}.py >/dev/null 2>&1") == 0) {
$source = "${maybe}.py"; $file = "${maybe}.py";
} }
elsif (system("$GIT cat-file -e ". elsif (system("$GIT cat-file -e ".
" $refspec:${maybe}.rspec >/dev/null 2>&1") == 0) { " $refspec:${maybe}.rspec >/dev/null 2>&1") == 0) {
$source = "${maybe}.rspec"; $file = "${maybe}.rspec";
}
last
if ($source);
}
if (!$source) {
print STDERR "$repodir, $refspec\n";
print STDERR `/usr/bin/id`;
print STDERR `/bin/ls -la`;
print STDERR "Could not find source code in repository: $reponame\n";
return undef;
} }
if ($file) {
# #
# Do this seemingly odd cat-file, simply cause its the only way # Do this seemingly odd cat-file, simply cause its the only way
# --follow-symlinks works. It adds the commit hash as the first # --follow-symlinks works. It adds the commit hash as the first
# line of output, so see below where that first line is killed. # line of output, so see below where that first line is killed.
# #
my $stuff = $source =
emutil::ExecQuiet("echo '$refspec:$source' | ". emutil::ExecQuiet("echo '$refspec:$file' | ".
" $GIT cat-file --batch --follow-symlinks"); " $GIT cat-file --batch ".
" --follow-symlinks");
if ($?) { if ($?) {
print STDERR $stuff; print STDERR $source;
return undef; return undef;
} }
# Kill first line. # Kill first line.
$stuff =~ s/^(?:.*\n){1}//; $source =~ s/^(?:.*\n){1}//;
return $stuff; last;
}
}
if (!$source) {
print STDERR "$repodir, $refspec\n";
print STDERR `/usr/bin/id`;
print STDERR `/bin/ls -la`;
print STDERR "Could not find source code in repository: $reponame\n";
return undef;
}
return $source;
} }
# #
...@@ -756,6 +777,36 @@ sub RemoveRepo($) ...@@ -756,6 +777,36 @@ sub RemoveRepo($)
return 0; return 0;
} }
#
# Remove a repo
#
sub DoRemoveRepo()
{
my $optlist = "n:p:";
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
my $reponame = GetRepoName(\%options);
if (! -e "$REPODIR/$reponame") {
fatal("Repository does not exist.");
}
if (RemoveRepo($reponame)) {
if (defined($webtask)) {
$webtask->Exited(-1);
}
exit(-1);
}
else {
if (defined($webtask)) {
$webtask->Exited(0);
}
exit(0);
}
}
# #
# Return a branch list. # Return a branch list.
# #
...@@ -1222,6 +1273,48 @@ sub GetRepoSize($) ...@@ -1222,6 +1273,48 @@ sub GetRepoSize($)
return $mebi; return $mebi;
} }
#
# Prune stale repos (repos we left behind).
#
sub DoPruneStaleRepos()
{
my $optlist = "n";
my $impotent = 1;
my @stale = ();
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$impotent = 1;
}
chdir("$REPODIR") or
fatal("Could not chdir to $REPODIR");
opendir(DIR, $REPODIR) or
fatal("Unable to open directory $REPODIR");
while (my $dirent = readdir(DIR)) {
next
if ($dirent eq "." || $dirent eq "..");
next
if (!ValidUUID($dirent));
my $query_result =
DBQueryFatal("select uuid,deleted from apt_profile_versions ".
"where reponame='$dirent'");
if (!$query_result->numrows) {
if ($impotent) {
print "Would delete stale repo $dirent\n";
}
push(@stale, $dirent);
next;
}
}
exit(0);
}
# #
# Get estimated repository size. # Get estimated repository size.
# #
......
...@@ -1337,6 +1337,14 @@ sub DoTerminate() ...@@ -1337,6 +1337,14 @@ sub DoTerminate()
$takelock = 1; $takelock = 1;
} }
#
# Admins can terminate a paniced experiment, we will pass along an
# admin credential to tell the CM its okay.
#
if ($instance->paniced() && !$this_user->IsAdmin()) {
fatal("Only administrators can terminate a paniced experiment")
}
my $slice = $instance->GetGeniSlice(); my $slice = $instance->GetGeniSlice();
if (!defined($slice)) { if (!defined($slice)) {
# #
...@@ -1426,7 +1434,16 @@ sub DoTerminate() ...@@ -1426,7 +1434,16 @@ sub DoTerminate()
} }
my $response; my $response;
$errcode = CallMethodOnAggregates("Terminate", 10, \$response, @agglist); #
# Helper callback to send the proper arguments.
#
my $coderef = sub {
my ($sliver) = @_;
# Flag that we want to clear the panic, so send an auth credential.
return $sliver->Terminate($instance->paniced() ? 1 : undef);
};
$errcode = CallMethodOnAggregates($coderef, 10, \$response, @agglist);
if ($errcode) { if ($errcode) {
$exitcode = -1; $exitcode = -1;
......
...@@ -121,7 +121,7 @@ sub CanDelete($$); ...@@ -121,7 +121,7 @@ sub CanDelete($$);
sub PublishProfile($); sub PublishProfile($);
sub InsertImageRecords($); sub InsertImageRecords($);
sub ListImages(); sub ListImages();
sub GetScriptParameters($$); sub GetScriptParameters($$$);
sub VerifyXML($$); sub VerifyXML($$);
sub ModifyProfileInternal($$$); sub ModifyProfileInternal($$$);
sub UseNewGenilib($); sub UseNewGenilib($);
...@@ -254,6 +254,7 @@ sub CreateProfile() ...@@ -254,6 +254,7 @@ sub CreateProfile()
my $parent_profile; my $parent_profile;
my $node_id; my $node_id;
my $usererror; my $usererror;
my $reponame;
my %errors = (); my %errors = ();
my %options = (); my %options = ();
...@@ -308,12 +309,13 @@ sub CreateProfile() ...@@ -308,12 +309,13 @@ sub CreateProfile()
# Need to do initial clone. # Need to do initial clone.
# #
if (exists($new_args{'repourl'})) { if (exists($new_args{'repourl'})) {
$reponame = NewUUID();
my $repourl = $new_args{'repourl'}; my $repourl = $new_args{'repourl'};
my $reponame = NewUUID();
my $repohash; my $repohash;
my $checkout = ($this_user->IsAdmin() ? "-c" : "");
my $output = my $output =
emutil::ExecQuiet("$MANAGEGITREPO clone -n $reponame ". emutil::ExecQuiet("$MANAGEGITREPO clone $checkout -n $reponame ".
" -S " . $new_args{"name"} . " '$repourl'"); " -S " . $new_args{"name"} . " '$repourl'");
if ($?) { if ($?) {
UserError($output); UserError($output);
...@@ -344,7 +346,7 @@ sub CreateProfile() ...@@ -344,7 +346,7 @@ sub CreateProfile()
# Script parameters # Script parameters
if (defined($script) && $script ne "" && $script =~ /^import/m) { if (defined($script) && $script ne "" && $script =~ /^import/m) {
my $paramdefs; my $paramdefs;
my $retval = GetScriptParameters($script, \$paramdefs); my $retval = GetScriptParameters($script, $reponame, \$paramdefs);
if ($retval) { if ($retval) {
if ($retval < 0) { if ($retval < 0) {
fatal("Could not get paramdefs: $paramdefs!"); fatal("Could not get paramdefs: $paramdefs!");
...@@ -738,7 +740,8 @@ sub ModifyProfileInternal($$$) ...@@ -738,7 +740,8 @@ sub ModifyProfileInternal($$$)
# data. Only python scripts of course. # data. Only python scripts of course.
# #
my $output; my $output;
my $retval = GetScriptParameters($script, \$output); my $retval = GetScriptParameters($script,
$profile->reponame(), \$output);
if ($retval) { if ($retval) {
if ($retval < 0) { if ($retval < 0) {
$$pmsg = $output; $$pmsg = $output;
...@@ -1008,6 +1011,8 @@ sub UpdateProfileFromRepo() ...@@ -1008,6 +1011,8 @@ sub UpdateProfileFromRepo()
fatal("Could not open temporary file for script"); fatal("Could not open temporary file for script");
} }
my $opts = ($usenewgenilib ? "-N" : ""); my $opts = ($usenewgenilib ? "-N" : "");
# Import repo into jail.
$opts .= " -r " . $profile->reponame();
print $fh $script; print $fh $script;
$output = emutil::ExecQuiet("$RUNGENILIB $opts $filename"); $output = emutil::ExecQuiet("$RUNGENILIB $opts $filename");
if ($?) { if ($?) {
...@@ -1064,9 +1069,9 @@ sub UpdateProfileFromRepo() ...@@ -1064,9 +1069,9 @@ sub UpdateProfileFromRepo()
# For a Parameterized Profile, need to generate and store the form # For a Parameterized Profile, need to generate and store the form
# data. Only python scripts of course. Does not return on error. # data. Only python scripts of course. Does not return on error.
# #
sub GetScriptParameters($$) sub GetScriptParameters($$$)
{ {
my ($script, $pref) = @_; my ($script, $reponame, $pref) = @_;
my ($fh, $filename) = tempfile(UNLINK => 1); my ($fh, $filename) = tempfile(UNLINK => 1);
if (!defined($fh)) { if (!defined($fh)) {
...@@ -1074,6 +1079,8 @@ sub GetScriptParameters($$) ...@@ -1074,6 +1079,8 @@ sub GetScriptParameters($$)
return -1; return -1;
} }
my $opts = ($usenewgenilib ? "-N" : ""); my $opts = ($usenewgenilib ? "-N" : "");
# Import repo into jail.
$opts .= " -r $reponame" if (defined($reponame));
print $fh $script; print $fh $script;
my $output = emutil::ExecQuiet("$RUNGENILIB $opts -p $filename"); my $output = emutil::ExecQuiet("$RUNGENILIB $opts -p $filename");
......
#!/usr/local/bin/python #!/usr/local/bin/python
# #
# Copyright (c) 2005-2018 University of Utah and the Flux Group. # Copyright (c) 2005-2019 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -232,6 +232,10 @@ for child in tree.getroot(): ...@@ -232,6 +232,10 @@ for child in tree.getroot():
pass pass
elif element.tag == "routertype" and element.text: elif element.tag == "routertype" and element.text:
routertype = element.text routertype = element.text
if routertype == "static-old":
Fatal("Unsupported routertype static-old on node " +
vname + ": " + element.text)
pass
if routertype == "static-ddijk": if routertype == "static-ddijk":
routertype = "static" routertype = "static"
pass pass
......
...@@ -45,14 +45,18 @@ sub usage() ...@@ -45,14 +45,18 @@ sub usage()
print STDERR " -P file - Generate and write parameter block to file\n"; print STDERR " -P file - Generate and write parameter block to file\n";
print STDERR " -b file - Run script using the parameter defs in file\n"; print STDERR " -b file - Run script using the parameter defs in file\n";
print STDERR " -W - Python warnings are fatal.\n"; print STDERR " -W - Python warnings are fatal.\n";
print STDERR " -r repo - Map repo into jail.\n";
print STDERR " -h hash - With -r, set the checkout hash.\n";
exit(-1); exit(-1);
} }
my $optlist = "do:pP:b:WN"; my $optlist = "do:pP:b:WNr:h:";
my $debug = 0; my $debug = 0;
my $getparams = 0; my $getparams = 0;
my $paramfile; my $paramfile;
my $ofile; my $ofile;
my $repo;
my $reporef;
my $newgenilib = 0; my $newgenilib = 0;
my $warningsfatal = 0; my $warningsfatal = 0;
...@@ -64,6 +68,7 @@ my $TBOPS = "@TBOPSEMAIL@"; ...@@ -64,6 +68,7 @@ my $TBOPS = "@TBOPSEMAIL@";
my $CONTROL = "@USERNODE@"; my $CONTROL = "@USERNODE@";
my $MAINSITE = @TBMAINSITE@; my $MAINSITE = @TBMAINSITE@;
my $TAR = "/usr/bin/tar"; my $TAR = "/usr/bin/tar";
my $REPODIR = "/repos";
# Locals # Locals
my $SAVEUID = $UID; my $SAVEUID = $UID;
...@@ -147,6 +152,29 @@ if (defined($options{"b"})) { ...@@ -147,6 +152,29 @@ if (defined($options{"b"})) {
if (defined($options{"o"})) { if (defined($options{"o"})) {
$ofile = $options{"o"}; $ofile = $options{"o"};
} }
if (defined($options{"r"})) {
$repo = $options{"r"};
# Must taint check
if ($repo =~ /^([-\w]+)$/) {
$repo = $1;
}
else {
die("Bad data in argument: $repo");
}
if (! -e "$REPODIR/$repo") {
die("No such repo $repo\n");
}
if (defined($options{"h"})) {
$reporef = $options{"h"};
# Must taint check
if ($reporef =~ /^([-\w\/]+)$/) {
$reporef = $1;
}
else {
die("Bad data in argument: $reporef");
}
}
}
if (@ARGV != 1) { if (@ARGV != 1) {
usage(); usage();
} }
...@@ -219,6 +247,8 @@ $cmdargs .= " -u " . $this_user->uid(); ...@@ -219,6 +247,8 @@ $cmdargs .= " -u " . $this_user->uid();
$cmdargs .= ($getparams ? " -p " : ""); $cmdargs .= ($getparams ? " -p " : "");
$cmdargs .= ($warningsfatal ? " -W " : ""); $cmdargs .= ($warningsfatal ? " -W " : "");
$cmdargs .= ($newgenilib ? " -N " : ""); $cmdargs .= ($newgenilib ? " -N " : "");
$cmdargs .= (defined($repo) ? " -r $repo " : "");
$cmdargs .= (defined($reporef) ? " -h $reporef " : "");
# #
# We want to send over both files via STDIN, so combine them, and pass # We want to send over both files via STDIN, so combine them, and pass
...@@ -260,6 +290,9 @@ while (<ERR>) { ...@@ -260,6 +290,9 @@ while (<ERR>) {
$errs .= $_; $errs .= $_;
} }
close(ERR); close(ERR);
if ($debug) {
print STDERR $errs;
}
my $exit_status = $?; my $exit_status = $?;
if ($exit_status) { if ($exit_status) {
......
...@@ -40,13 +40,15 @@ sub usage() ...@@ -40,13 +40,15 @@ sub usage()
exit(-1); exit(-1);
} }
my $optlist = "u:vpb:WJB:N"; my $optlist = "u:vpb:WJB:Nr:h:";
my $user; my $user;
my $getparams= 0; my $getparams= 0;
my $paramsize; my $paramsize;
my $warningsfatal = 0; my $warningsfatal = 0;
my $usejail = 0; my $usejail = 0;
my $iocagepath; my $iocagepath;
my $repo;
my $reporef;
# #
# Configure variables # Configure variables
...@@ -56,6 +58,7 @@ my $TBOPS = "@TBOPSEMAIL@"; ...@@ -56,6 +58,7 @@ my $TBOPS = "@TBOPSEMAIL@";
my $TESTMODE = 0; my $TESTMODE = 0;
my $GENILIB = "$TB/lib/geni-lib"; my $GENILIB = "$TB/lib/geni-lib";
my $JAILPROG = "$TB/libexec/genilib-jail"; my $JAILPROG = "$TB/libexec/genilib-jail";
my $REPODIR = "/repos";
my $TAR = "/usr/bin/tar"; my $TAR = "/usr/bin/tar";
my $debug = 0; my $debug = 0;
...@@ -119,6 +122,29 @@ if (defined($options{"J"})) { ...@@ -119,6 +122,29 @@ if (defined($options{"J"})) {
$iocagepath = $options{"B"}; $iocagepath = $options{"B"};
} }
} }
if (defined($options{"r"})) {
$repo = $options{"r"};
# Must taint check
if ($repo =~ /^([-\w]+)$/) {
$repo = $1;
}
else {
die("Bad data in argument: $repo");
}
if (! -e "$REPODIR/$repo") {
die("No such repo $repo\n");
}
if (defined($options{"h"})) {
$reporef = $options{"h"};
# Must taint check
if ($reporef =~ /^([-\w\/]+)$/) {
$reporef = $1;
}
else {
die("Bad data in argument: $reporef");
}
}
}
# #
# First option has to be the -u option, the user to run this script as. # First option has to be the -u option, the user to run this script as.
...@@ -232,6 +258,14 @@ if ($warningsfatal) { ...@@ -232,6 +258,14 @@ if ($warningsfatal) {
my $exit_status; my $exit_status;
if ($usejail) { if ($usejail) {
my $bopt = (defined($iocagepath) ? "-B $iocagepath" : ""); my $bopt = (defined($iocagepath) ? "-B $iocagepath" : "");
my $ropt = "";
if (defined($repo)) {
$ropt = "-r $repo";
if (defined($reporef)) {
$ropt .= " -h $reporef";
}
}
# #
# We are executing the command in a jail, fire off the jail script. # We are executing the command in a jail, fire off the jail script.
...@@ -245,7 +279,7 @@ if ($usejail) { ...@@ -245,7 +279,7 @@ if ($usejail) {
# name space. Those copies will be owned by the user so they can be # name space. Those copies will be owned by the user so they can be
# read/written. # read/written.
# #
$exit_status = system("$JAILPROG $bopt -u $user $ifile"); $exit_status = system("$JAILPROG $bopt $ropt -u $user $ifile");
# #
# Now that we are done with the files, chown them to the user and # Now that we are done with the files, chown them to the user and
......
...@@ -143,6 +143,9 @@ my %options = (); ...@@ -143,6 +143,9 @@ my %options = ();
if (! GetOptions(\%options, @optlist)) { if (! GetOptions(\%options, @optlist)) {
usage(); usage();
} }
if (defined($options{"d"})) {
$debug = 1;
}
usage() usage()
if (@ARGV != 1 || !defined($pid)); if (@ARGV != 1 || !defined($pid));
...@@ -164,6 +167,9 @@ if (!defined($project)) { ...@@ -164,6 +167,9 @@ if (!defined($project)) {
} }
if (!defined($portal)) { if (!defined($portal)) {
$portal = $project->Brand()->brand(); $portal = $project->Brand()->brand();
if ($portal eq "classic") {
$portal = "emulab";
}
} }
# This was a dumb mistake, I need to convert from servername to portal. # This was a dumb mistake, I need to convert from servername to portal.
$ENV{"SERVER_NAME"} = $project->Brand()->Server(); $ENV{"SERVER_NAME"} = $project->Brand()->Server();
...@@ -367,7 +373,7 @@ if (defined($stop_at)) { ...@@ -367,7 +373,7 @@ if (defined($stop_at)) {
} }
@args = (@args, $xmlfile); @args = (@args, $xmlfile);
if ($debug) { if (0 && $debug) {
print "@args\n"; print "@args\n";
system("/bin/cat $xmlfile"); system("/bin/cat $xmlfile");
} }
...@@ -377,7 +383,7 @@ if ($debug) { ...@@ -377,7 +383,7 @@ if ($debug) {
# attached to a tty. In general, this script is going to get called in # attached to a tty. In general, this script is going to get called in
# a disconnected state. # a disconnected state.
# #
if (isatty(\*STDOUT)) { if (isatty(\*STDOUT) && !$debug) {
$logfile = TBMakeLogname("start-experiment"); $logfile = TBMakeLogname("start-experiment");
if (my $childpid = TBBackGround($logfile)) { if (my $childpid = TBBackGround($logfile)) {
......
...@@ -1603,6 +1603,23 @@ sub GetCreator($) ...@@ -1603,6 +1603,23 @@ sub GetCreator($)
return $user; return $user;
} }
sub GetUpdater($)
{
my ($self) = @_;
require User;
return undef
if (!$self->updater_idx());
my $user = User->Lookup($self->updater_idx());
if (! defined($user)) {
print("*** WARNING: Could not lookup user object for $self!\n");
return undef;
}
return $user;
}
# #
# Check permissions. Note that root may ask permission, which comes in # Check permissions. Note that root may ask permission, which comes in
# as an undef user. # as an undef user.
...@@ -2122,6 +2139,32 @@ sub Unlock($) ...@@ -2122,6 +2139,32 @@ sub Unlock($)
return 0; return 0;
} }
#
# Steal the lock
#
sub TakeLock($)
{
my ($self) = @_;
return -1
if (!DBQueryWarn("lock tables images write"));
my $imageid = $self->imageid();
my $query_result =
DBQueryWarn("update images set locker_pid=$PID " .
"where imageid='$imageid' and locked is not null");
if (! $query_result ||
$query_result->numrows == 0) {
DBQueryWarn("unlock tables");
return -1;
}
DBQueryWarn("unlock tables");
$self->{'IMAGE'}->{'locker_pid'} = $PID;
return 0;
}
sub GotLock($) sub GotLock($)
{ {
my ($self) = @_; my ($self) = @_;
...@@ -2503,6 +2546,34 @@ sub ListForURN($$) ...@@ -2503,6 +2546,34 @@ sub ListForURN($$)
return @result; return @result;
} }
#
# List of images for a Group
#
sub ListForGroup($$)
{
my ($class, $group) = @_;
my @result = ();
my $pid_idx = $group->pid_idx();
my $gid_idx = $group->gid_idx();
my $query_result =
DBQueryWarn("select imageid,version from image_versions ".
"where pid_idx='$pid_idx' and gid_idx='$gid_idx' and ".
" deleted is null and isdataset=0 ".
"order by imagename,version");
while (my ($imageid,$version) = $query_result->fetchrow_array()) {
# Want latest version.
my $image = Image->Lookup($imageid, $version);
next
if (!defined($image));
push(@result, $image);
}
return @result;
}
# #
# Set to use the logfile. It becomes the "current" spew. # Set to use the logfile. It becomes the "current" spew.
# #
......
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2007-2013, 2017 University of Utah and the Flux Group. # Copyright (c) 2007-2019 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -466,13 +466,31 @@ sub SetMetadata($$$) ...@@ -466,13 +466,31 @@ sub SetMetadata($$$)
DBQueryWarn("delete from logfile_metadata where logidx='$logidx'") DBQueryWarn("delete from logfile_metadata where logidx='$logidx'")
if ($purge); if ($purge);
foreach my $ref (@{$argref}) { my $coderef = sub {
my ($key,$val) = @{$ref}; my ($key,$val) = @_;
$key = DBQuoteSpecial($key); $key = DBQuoteSpecial($key);
$val = DBQuoteSpecial($val); $val = DBQuoteSpecial($val);
return -1 return -1
if (! DBQueryWarn("replace into logfile_metadata set ". if (! DBQueryWarn("replace into logfile_metadata set ".
" logidx='$logidx',metakey=$key,metaval=$val")); " logidx='$logidx',metakey=$key,metaval=$val"));
return 0;
};
#
# Silly choice a long time ago.
#
if (ref($argref) eq "ARRAY") {
foreach my $ref (@{$argref}) {
return -1
if (&$coderef(@{$ref}));
}
}
else {
foreach my $key (keys(%{$argref})) {
return -1
if (&$coderef($key, $argref->{$key}));
}
} }
return 0; return 0;
} }
......
...@@ -608,6 +608,12 @@ sub GetCreator($) ...@@ -608,6 +608,12 @@ sub GetCreator($)
return $self->image()->GetCreator(); return $self->image()->GetCreator();
} }
sub GetUpdater($)
{
my ($self) = @_;
return $self->image()->GetUpdater();
}
# #
# Load the group object for an image # Load the group object for an image
...@@ -818,6 +824,13 @@ sub GotLock($) ...@@ -818,6 +824,13 @@ sub GotLock($)
return $self->image()->GotLock(); return $self->image()->GotLock();
} }
sub TakeLock($)
{
my ($self) = @_;
return $self->image()->TakeLock();
}
# #
# Wait to get lock. # Wait to get lock.
# #
...@@ -918,6 +931,29 @@ sub ListForURN($$) ...@@ -918,6 +931,29 @@ sub ListForURN($$)
return @result; return @result;
} }
#
# List of images in a project/group
#
sub ListForGroup($$)
{
my ($class, $group) = @_;
my @result = ();
my @images = Image->ListForGroup($group);
foreach my $image (@images) {
my $imageid = $image->imageid();
my $version = $image->version();
my $tmp = OSImage->Lookup($imageid, $version);
if (!defined($tmp)) {
print STDERR "Could not lookup image $imageid,$version\n";
next;
}
push(@result, $tmp);
}
return @result;
}
# #
# Set to use the logfile. It becomes the "current" spew. # Set to use the logfile. It becomes the "current" spew.
# #
......
...@@ -600,6 +600,28 @@ sub IsLeader($$) ...@@ -600,6 +600,28 @@ sub IsLeader($$)
return $user->SameUser($self->GetLeader()); return $user->SameUser($self->GetLeader());
} }
sub IsManager($$)
{
my ($self, $user) = @_;
# Must be a real reference.
return 0
if (! (ref($self) && ref($user)));
return TBMinTrust($self->Trust($user), PROJMEMBERTRUST_GROUPROOT());
}
sub IsMember($$)
{
my ($self, $user) = @_;
# Must be a real reference.
return 0
if (! (ref($self) && ref($user)));
return TBMinTrust($self->Trust($user), PROJMEMBERTRUST_USER());
}
# #
# Return project group. # Return project group.
# #
......
...@@ -1887,6 +1887,8 @@ sub GList($$) ...@@ -1887,6 +1887,8 @@ sub GList($$)
print STDERR "*** Unexpected results from 'id -G $user_uid': $glist\n"; print STDERR "*** Unexpected results from 'id -G $user_uid': $glist\n";
return undef; return undef;
} }
return $glist
if (!defined($default));
# #
# Remove current group from glist, then add gid twice at the front # Remove current group from glist, then add gid twice at the front
...@@ -1973,6 +1975,35 @@ sub FlipTo($$) ...@@ -1973,6 +1975,35 @@ sub FlipTo($$)
return 0; return 0;
} }