Commit 4a0d7873 authored by Leigh Stoller's avatar Leigh Stoller

Image List/Delete changes:

List) Allow for a project credential giving user permission for a list
of all images belonging to the project. This allows the Portal to show a
list to project leaders/managers to allow easier management of space
used across the remote clusters.

Delete) Allow a project level credential giving the user permission to
delete images belonging to another user. As above, the portal will grant
this credential to project leaders/managers.
parent 6cd39228
......@@ -1603,6 +1603,23 @@ sub GetCreator($)
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
# as an undef user.
......@@ -2529,6 +2546,34 @@ sub ListForURN($$)
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.
#
......
......@@ -608,6 +608,12 @@ sub GetCreator($)
return $self->image()->GetCreator();
}
sub GetUpdater($)
{
my ($self) = @_;
return $self->image()->GetUpdater();
}
#
# Load the group object for an image
......@@ -925,6 +931,29 @@ sub ListForURN($$)
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.
#
......
......@@ -4155,24 +4155,46 @@ sub DeleteImage($)
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Not enough permission to delete image; wrong SA or user");
}
my $fliptouser = $user;
#
# New approach is a project credential which the Portal will grant
# to the project leader/managers. We leave the old checks in place.
#
if ($credential->target_urn()->IsProject()) {
if ($credential->target_urn()->authority() ne
$project->nonlocalurn()->authority()) {
return GeniResponse->BadArgsResponse(
"Project credential does not match image domain/project");
}
#
# If not the creator, operate as project leader. This can result
# in the email not providing the actual person doing the deletion
# unless we move the email here instead of in delete_image.
#
if (! (defined($creator_urn) &&
($creator_urn eq $user->urn() ||
$creator_urn eq $ENV{'REALGENIURN'}))) {
# fliptouser will flip to image project creator.
$fliptouser = undef;
}
}
#
# If not the creator, then require override to prevent
# accidental removal of images not belonging to current user.
# Note that not all images have the creator_urn set (yet).
#
if (!((defined($creator_urn) &&
!($creator_urn eq $user->urn() ||
$creator_urn eq $ENV{'REALGENIURN'})) ||
($user->IsLocal() &&
$image->AccessCheck($user->emulab_user(),
elsif (!((defined($creator_urn) &&
!($creator_urn eq $user->urn() ||
$creator_urn eq $ENV{'REALGENIURN'})) ||
($user->IsLocal() &&
$image->AccessCheck($user->emulab_user(),
EmulabConstants::TB_IMAGEID_DESTROY())))) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Not your image; please specify original creator urn")
if (!defined($overide_urn) || $overide_urn ne $creator_urn);
}
if (!defined(GeniCM::FlipToUser($image, $user))) {
if (!defined(GeniCM::FlipToUser($image, $fliptouser))) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"FlipToUser failed");
}
......@@ -4439,6 +4461,7 @@ sub ListImages($)
{
my ($argref) = @_;
my $user_urn = $argref->{'user_urn'};
my $project_urn = $argref->{'project_urn'};
my $credentials = $argref->{'credentials'};
my @images = ();
require OSImage;
......@@ -4449,6 +4472,9 @@ sub ListImages($)
if (defined($user_urn) && !GeniHRN::IsValid($user_urn)) {
return GeniResponse->MalformedArgsResponse("Invalid User URN");
}
if (defined($project_urn) && !GeniHRN::IsValid($project_urn)) {
return GeniResponse->MalformedArgsResponse("Invalid Project URN");
}
my ($credential,$speaksfor) = GeniStd::CheckCredentials($credentials);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4469,17 +4495,48 @@ sub ListImages($)
my $isadmin = ($user->IsLocal() && $user->admin() ? 1 : 0);
if (defined($user_urn) && $user->urn() ne $user_urn) {
my ($userauth,undef,undef) = GeniHRN::Parse($user_urn);
my ($thisauth,undef,undef) = GeniHRN::Parse($authority->urn());
my $hrn = GeniHRN->new($user_urn);
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"No permission to list images")
if ($userauth ne $thisauth && !$isadmin);
if ($hrn->authority() ne
$authority->urn()->authority() && !$isadmin);
@images = OSImage->ListForURN($user_urn);
return GeniResponse->Create(GENIRESPONSE_SUCCESS, [])
if (!@images);
}
elsif (defined($project_urn)) {
my $hrn = GeniHRN->new($project_urn);
#
# Must have a project credential granting permission to get the list.
#
if (!$credential->target_urn()->IsProject()) {
return GeniResponse->BadArgsResponse("Not a project credential");
}
if ($project_urn ne $credential->target_urn()) {
return GeniResponse->BadArgsResponse("Credential does not match ".
"project URN");
}
my $project;
if ($hrn->IsOurDomain()) {
$project = Project->Lookup($hrn->id());
}
else {
my $temp = GeniHRN::Generate($hrn->authority(), "authority", "sa");
$project = Project->LookupNonLocal($temp);
}
if (!defined($project)) {
return GeniResponse->SearchFailedResponse(
"No local project for $project_urn");
}
@images = OSImage->ListForGroup($project->GetProjectGroup());
if (!@images) {
return GeniResponse->Create(GENIRESPONSE_SUCCESS, [])
}
}
else {
$user_urn = $user->urn();
@images = OSImage->ListForURN($user_urn);
......@@ -4509,7 +4566,18 @@ sub ListImages($)
"format" => $image->format(),
"description" => $image->description(),
};
if (defined($project_urn)) {
print STDERR "$image\n";
$blob->{"creator_urn"} =
($image->creator_urn() ? $image->creator_urn() :
$image->GetCreator()->nonlocalurn());
if (defined($image->updater())) {
$blob->{"updater_urn"} =
($image->updater_urn() ? $image->updater_urn() :
$image->GetUpdater()->nonlocalurn());
}
}
#
# Get the file size on disk.
#
......@@ -4533,7 +4601,6 @@ sub ListImages($)
}
push(@result, $blob);
}
print STDERR "Image for $user_urn:\n";
print STDERR Dumper(\@result);
return GeniResponse->Create(GENIRESPONSE_SUCCESS, \@result);
}
......
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