Commit b8436171 authored by Leigh B Stoller's avatar Leigh B Stoller

Image Alias changes. Most of these changes are related to unifying

OSinfo and Image into a single object for the benefit of the perl
code. The database tables have not changed though.
parent 7aafa075
...@@ -118,7 +118,7 @@ use Experiment; ...@@ -118,7 +118,7 @@ use Experiment;
use User; use User;
use Project; use Project;
use Group; use Group;
use OSinfo; use Image;
use emutil; use emutil;
use libEmulab; use libEmulab;
use GeniDB; use GeniDB;
......
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2000-2014 University of Utah and the Flux Group. # Copyright (c) 2000-2016 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -67,7 +67,7 @@ use libdb; ...@@ -67,7 +67,7 @@ use libdb;
use libtestbed; use libtestbed;
use User; use User;
use Project; use Project;
use Image; use OSImage;
# Protos # Protos
sub fatal($); sub fatal($);
...@@ -161,6 +161,7 @@ my %xmlfields = ...@@ -161,6 +161,7 @@ my %xmlfields =
"mtype_*" => ["mtype", $SLOT_OPTIONAL], "mtype_*" => ["mtype", $SLOT_OPTIONAL],
"hash", => ["hash", $SLOT_ADMINONLY], "hash", => ["hash", $SLOT_ADMINONLY],
"notes", => ["notes", $SLOT_ADMINONLY], "notes", => ["notes", $SLOT_ADMINONLY],
"architecture" => ["architecture", $SLOT_OPTIONAL],
); );
# #
# Need a list of node types. We join this over the nodes table so that # Need a list of node types. We join this over the nodes table so that
...@@ -319,8 +320,8 @@ UserError() ...@@ -319,8 +320,8 @@ UserError()
# Now do special checks. # Now do special checks.
# #
my $image = Image->Lookup($editimageid_args{"imageid"}, my $image = OSImage->Lookup($editimageid_args{"imageid"},
$editimageid_args{"version"}); $editimageid_args{"version"});
if (!defined($image)) { if (!defined($image)) {
UserError("Image: No such image"); UserError("Image: No such image");
} }
...@@ -369,6 +370,16 @@ if (!$isadmin && exists($editimageid_args{"path"})) { ...@@ -369,6 +370,16 @@ if (!$isadmin && exists($editimageid_args{"path"})) {
} }
} }
if ($image->architecture() ||
(exists($editimageid_args{"architecture"}) &&
$editimageid_args{"architecture"} ne "")) {
foreach my $arch (split(",", $editimageid_args{"architecture"})) {
if (!exists($OSImage::IMAGE_ARCHITECTURES{$arch})) {
UserError("Architecture: Not a valid Architecture: $arch");
}
}
}
else {
# #
# See what node types this image will work on. Must be at least one! # See what node types this image will work on. Must be at least one!
# #
...@@ -446,7 +457,7 @@ if (defined($osidclause)) { ...@@ -446,7 +457,7 @@ if (defined($osidclause)) {
" and make the necessary changes!\n $msg"); " and make the necessary changes!\n $msg");
} }
} }
}
exit(0) exit(0)
if ($verify); if ($verify);
...@@ -459,8 +470,8 @@ exit(0) ...@@ -459,8 +470,8 @@ exit(0)
delete($editimageid_args{"imageid"}); delete($editimageid_args{"imageid"});
my $usrerr; my $usrerr;
my $editimageid_val = Image->EditImageid($image, my $editimageid_val = OSImage->EditImageid($image,
\%editimageid_args, \$usrerr); \%editimageid_args, \$usrerr);
UserError($usrerr) UserError($usrerr)
if (defined($usrerr)); if (defined($usrerr));
fatal("Could not create new Image!") fatal("Could not create new Image!")
......
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2000-2014 University of Utah and the Flux Group. # Copyright (c) 2000-2016 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -68,7 +68,6 @@ use libdb; ...@@ -68,7 +68,6 @@ use libdb;
use libtestbed; use libtestbed;
use User; use User;
use Project; use Project;
use OSinfo;
# Protos # Protos
sub fatal($); sub fatal($);
...@@ -161,6 +160,8 @@ my %xmlfields = ...@@ -161,6 +160,8 @@ my %xmlfields =
# Class may only be changed while making a new class. # Class may only be changed while making a new class.
"class" => ["class", $SLOT_OPTIONAL], "class" => ["class", $SLOT_OPTIONAL],
"architecture" => ["architecture", $SLOT_OPTIONAL],
# Fixed attributes. # Fixed attributes.
"isvirtnode" => ["isvirtnode", $SLOT_OPTIONAL], "isvirtnode" => ["isvirtnode", $SLOT_OPTIONAL],
...@@ -374,6 +375,12 @@ if (exists($editnodetype_args{"class"})) { ...@@ -374,6 +375,12 @@ if (exists($editnodetype_args{"class"})) {
} }
} }
if (exists($editnodetype_args{"architecture"})) {
my $architecture = $editnodetype_args{"architecture"};
push(@nodetype_data, "architecture='$architecture'");
}
# The rest of them all have names starting with "is" at present. # The rest of them all have names starting with "is" at present.
my @fixed_args = grep(/^is/, keys(%editnodetype_args)); my @fixed_args = grep(/^is/, keys(%editnodetype_args));
foreach my $name (@fixed_args) { foreach my $name (@fixed_args) {
......
#!/usr/bin/perl -w #!/usr/bin/perl -w
# #
# Copyright (c) 2000-2015 University of Utah and the Flux Group. # Copyright (c) 2000-2016 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -77,6 +77,7 @@ use libdb; ...@@ -77,6 +77,7 @@ use libdb;
use libtestbed; use libtestbed;
use User; use User;
use Project; use Project;
use OSImage;
use Image; use Image;
use OSinfo; use OSinfo;
use Node; use Node;
...@@ -223,6 +224,7 @@ my %xmlfields = ...@@ -223,6 +224,7 @@ my %xmlfields =
"lba_low", => ["lba_low", $SLOT_OPTIONAL], "lba_low", => ["lba_low", $SLOT_OPTIONAL],
"lba_high", => ["lba_high", $SLOT_OPTIONAL], "lba_high", => ["lba_high", $SLOT_OPTIONAL],
"lba_size", => ["lba_size", $SLOT_OPTIONAL], "lba_size", => ["lba_size", $SLOT_OPTIONAL],
"architecture", => ["architecture", $SLOT_OPTIONAL],
); );
# #
...@@ -420,7 +422,8 @@ if ($allpc) { ...@@ -420,7 +422,8 @@ if ($allpc) {
} }
} }
else { else {
$types_querystring = "select distinct n.type,nt.class from nodes as n ". $types_querystring =
"select distinct n.type,nt.class,nt.architecture from nodes as n ".
"left join node_types as nt on n.type=nt.type ". "left join node_types as nt on n.type=nt.type ".
"left join node_type_attributes as a on a.type=n.type ". "left join node_type_attributes as a on a.type=n.type ".
"where a.attrkey='imageable' and ". "where a.attrkey='imageable' and ".
...@@ -433,9 +436,11 @@ my $types_result = DBQueryFatal($types_querystring); ...@@ -433,9 +436,11 @@ my $types_result = DBQueryFatal($types_querystring);
# Save the valid types in a new array for later. # Save the valid types in a new array for later.
my %mtypes_array; my %mtypes_array;
my %mtypes_arch;
if ($types_result->numrows) { if ($types_result->numrows) {
while (my ($type,$class) = $types_result->fetchrow_array()) { while (my ($type,$class,$arch) = $types_result->fetchrow_array()) {
$mtypes_arch{$type} = $arch if (defined($arch));
$mtypes_array{$type} = $class; $mtypes_array{$type} = $class;
$xmlfields{"mtype_$type"} = ["mtype", $SLOT_OPTIONAL]; $xmlfields{"mtype_$type"} = ["mtype", $SLOT_OPTIONAL];
} }
...@@ -642,81 +647,67 @@ if (!$isdataset && ...@@ -642,81 +647,67 @@ if (!$isdataset &&
# #
# See what node types this image will work on. Must be at least one! # See what node types this image will work on. Must be at least one!
# #
UserError("Node Types: Must have at least one node type") UserError("Node Types: Must have at least one node type defined")
if (!$isdataset && !keys(%mtypes_array)); if (!$isdataset && !keys(%mtypes_array));
my $node_types_selected = 0;
# Check validity of mtype_* args, since the keys are dynamically generated. my $node_types_selected = 0;
my @mtype_keys = grep(/^mtype_/, keys(%newimageid_args));
foreach $key (@mtype_keys) {
my $value = $newimageid_args{$key};
print STDERR "mtype: '$key' -> '$value'\n"
if ($debug);
my $type = $key;
$type =~ s/^mtype_//;
# Treat pcvm special for now.
if ($type eq "pcvm" ||
grep(/^${type}$/, keys(%mtypes_array))) {
$node_types_selected++
if ($value eq "1");
}
else {
$errors{$key} = "Illegal node type."
}
}
# #
# When -a specified, add mappings for all pc types, does not matter if # If we have architectures defined in the node_types table, and we got
# there are nodes of that type. Skip the stub pc/pc entry though. # an architecture in the xml file for the image, we use those. Otherwise
# fall back to the old method.
# #
if ($allpc) { if (keys(%mtypes_arch) &&
foreach my $type (keys(%mtypes_array)) { (exists($newimageid_args{"architecture"}) &&
my $class = $mtypes_array{$type}; $newimageid_args{"architecture"} ne "")) {
next
if ($class ne "pc" || $type eq $class);
$newimageid_args{"mtype_${type}"} = "1"; foreach my $arch (split(",", $newimageid_args{"architecture"})) {
$node_types_selected++; if (!exists($OSImage::IMAGE_ARCHITECTURES{$arch})) {
UserError("Architecture: Not a valid Architecture: $arch");
}
} }
} }
else {
# Clear this since not using Architectures
delete($newimageid_args{"architecture"})
if (exists($newimageid_args{"architecture"}));
# Check validity of mtype_* args, since the keys are dynamically generated.
my @mtype_keys = grep(/^mtype_/, keys(%newimageid_args));
foreach $key (@mtype_keys) {
my $value = $newimageid_args{$key};
print STDERR "mtype: '$key' -> '$value'\n"
if ($debug);
my $type = $key;
$type =~ s/^mtype_//;
# Treat pcvm special for now.
if ($type eq "pcvm" ||
grep(/^${type}$/, keys(%mtypes_array))) {
$node_types_selected++
if ($value eq "1");
}
else {
$errors{$key} = "Illegal node type."
}
}
#
# When -a specified, add mappings for all pc types, does not matter if
# there are nodes of that type. Skip the stub pc/pc entry though.
#
if ($allpc) {
foreach my $type (keys(%mtypes_array)) {
my $class = $mtypes_array{$type};
next
if ($class ne "pc" || $type eq $class);
UserError("Node Types: Must select at least one node type") $newimageid_args{"mtype_${type}"} = "1";
if ($node_types_selected == 0 && !($force || $isdataset)); $node_types_selected++;
#
# We perform a further check for non-admins. When a node to snapshot
# has been specified, we check the OSID of the appropriate partition
# and see which node types it is appropriate for, and further restrict
# the list as necessary. This prevents creation of custom images based on
# old OSes from being checked as runnable on newer HW where they do not
# stand a chance.
#
if (!($isadmin || $isdataset) && defined($node) && !$node->isvirtnode()) {
my $query_result =
DBQueryFatal("select oi.type from osidtoimageid as oi ".
"left join partitions as p on oi.osid=p.osid ".
"where p.node_id='$node_id' and p.partition=$loadpart");
if ($query_result->numrows != 0) {
my %otypes;
while (my ($ntype) = $query_result->fetchrow_array()) {
$otypes{$ntype} = 1;
} }
my @invalid_node_types;
foreach my $ntype (@mtype_keys) {
$ntype =~ s/^mtype_//;
if (!exists($otypes{$ntype})) {
push @invalid_node_types, $ntype;
}
}
if (@invalid_node_types) {
UserError("Node Types: Current image on $node_id".
" cannot run on the following node types: ".
join(' ', @invalid_node_types));
}
} else {
UserError("Partition: No image originally loaded in partition $loadpart on $node_id; this is probably not the partition you meant to save");
} }
UserError("Node Types: Must select at least one node type")
if ($node_types_selected == 0 && !($force || $isdataset));
} }
# XXX Allowable OS types, OS features, and OpModes need to be # XXX Allowable OS types, OS features, and OpModes need to be
...@@ -787,13 +778,6 @@ if (!$isdataset) { ...@@ -787,13 +778,6 @@ if (!$isdataset) {
fatal("Could not create new OSID!") fatal("Could not create new OSID!")
if (!defined($new_osinfo)); if (!defined($new_osinfo));
#
# Insert a submap entry.
#
if (defined($parentos)) {
$new_osinfo->SetRunsOnParent($parentos);
}
$newimageid_args{"path"} = $ipath; $newimageid_args{"path"} = $ipath;
$osid = $new_osinfo->osid(); $osid = $new_osinfo->osid();
......
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2011-2013 University of Utah and the Flux Group. # Copyright (c) 2011-2016 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -72,7 +72,6 @@ use libdb; ...@@ -72,7 +72,6 @@ use libdb;
use libtestbed; use libtestbed;
use User; use User;
use Project; use Project;
use OSinfo;
use EmulabFeatures; use EmulabFeatures;
# Protos # Protos
......
...@@ -643,14 +643,14 @@ sub LoadEstimate($) ...@@ -643,14 +643,14 @@ sub LoadEstimate($)
{ {
my ($blockstore) = @_; my ($blockstore) = @_;
my $bsname = $blockstore->vname(); my $bsname = $blockstore->vname();
require Image; require OSImage;
if (!exists($blockstore->{'attributes'}->{"dataset"})) { if (!exists($blockstore->{'attributes'}->{"dataset"})) {
print STDERR "No dataset attribute for $bsname\n"; print STDERR "No dataset attribute for $bsname\n";
return -1; return -1;
} }
my $dataset = $blockstore->{'attributes'}->{"dataset"}; my $dataset = $blockstore->{'attributes'}->{"dataset"};
my $image = Image->Lookup($dataset); my $image = OSImage->Lookup($dataset);
if (!defined($image)) { if (!defined($image)) {
print STDERR "No image for dataset $dataset for $bsname\n"; print STDERR "No image for dataset $dataset for $bsname\n";
return -1; return -1;
......
# #
# Copyright (c) 2000-2014 University of Utah and the Flux Group. # Copyright (c) 2000-2014, 2016 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -51,7 +51,7 @@ LIB_SCRIPTS = libdb.pm Node.pm libdb.py libadminctrl.pm Experiment.pm \ ...@@ -51,7 +51,7 @@ LIB_SCRIPTS = libdb.pm Node.pm libdb.py libadminctrl.pm Experiment.pm \
EmulabFeatures.pm Port.pm BlockstoreType.pm Blockstore.pm \ EmulabFeatures.pm Port.pm BlockstoreType.pm Blockstore.pm \
IPBuddyAlloc.pm IPBuddyWrapper.pm Lease.pm Quota.pm \ IPBuddyAlloc.pm IPBuddyWrapper.pm Lease.pm Quota.pm \
libTaintStates.pm WebSession.pm WebTask.pm Brand.pm \ libTaintStates.pm WebSession.pm WebTask.pm Brand.pm \
Reservation.pm Reservation.pm OSImage.pm
# Stuff installed on plastic. # Stuff installed on plastic.
USERSBINS = genelists.proxy dumperrorlog.proxy backup USERSBINS = genelists.proxy dumperrorlog.proxy backup
......
...@@ -321,6 +321,20 @@ sub field($$) { ...@@ -321,6 +321,20 @@ sub field($$) {
} }
return undef; return undef;
} }
sub fieldExists($$) {
my ($self, $name) = @_;
return 1
if (exists($self->{'IMAGE'}->{$name}));
return 0;
}
sub fieldSet($$$) {
my ($self, $name, $value) = @_;
$self->{'IMAGE'}->{$name} = $value;
return $value;
}
sub isImageAlias($) { return 0; }
# Break circular reference someplace to avoid exit errors. # Break circular reference someplace to avoid exit errors.
sub DESTROY { sub DESTROY {
...@@ -484,33 +498,6 @@ sub LookupByAuthorityURN($$) ...@@ -484,33 +498,6 @@ sub LookupByAuthorityURN($$)
return Image->Lookup($imageid); return Image->Lookup($imageid);
} }
#
# Get a list of all running frisbee images.
# XXX if this is actually used, it will have to be fixed; DB no longer
# tracks running frisbee daemons.
#
sub ActiveImages($)
{
my ($class) = @_;
my @result = ();
my $query_result =
DBQueryWarn("select imageid,imageid_version from frisbee_blobs ".
"where frisbee_pid!=0");
return undef
if (!defined($query_result));
while (my ($imageid,$version) = $query_result->fetchrow_array()) {
my $image = Image->Lookup($imageid, $version);
if (!defined($image)) {
print STDERR "*** Could not find DB object for image $imageid\n";
return undef;
}
push(@result, $image);
}
return \@result;
}
# #
# Return a list of all images of the given format for the given pid. # Return a list of all images of the given format for the given pid.
# If format is NULL, return all formats. If pid is NULL, return for all pids. # If format is NULL, return all formats. If pid is NULL, return for all pids.
...@@ -620,6 +607,8 @@ sub Create($$$$$$$$) ...@@ -620,6 +607,8 @@ sub Create($$$$$$$$)
my $isadmin = $creator->IsAdmin(); my $isadmin = $creator->IsAdmin();
my $isdataset = (exists($argref->{"isdataset"}) ? my $isdataset = (exists($argref->{"isdataset"}) ?
$argref->{"isdataset"} : 0); $argref->{"isdataset"} : 0);
my $architecture = $argref->{'architecture'}
if (defined($argref->{'architecture'}));
# We may ignore particular partN_osid's by deleting them. # We may ignore particular partN_osid's by deleting them.
my @arg_slots = grep(/^part[1-4]_osid$/, keys(%{$argref})); my @arg_slots = grep(/^part[1-4]_osid$/, keys(%{$argref}));
...@@ -720,9 +709,13 @@ sub Create($$$$$$$$) ...@@ -720,9 +709,13 @@ sub Create($$$$$$$$)
$bquery .= ",pid='$pid',pid_idx='$pid_idx'"; $bquery .= ",pid='$pid',pid_idx='$pid_idx'";
$bquery .= ",gid='$gid',gid_idx='$gid_idx'"; $bquery .= ",gid='$gid',gid_idx='$gid_idx'";
# image_versions include all the images stuff.
my $query = "insert into image_versions set $bquery, ". my $query = "insert into image_versions set $bquery, ".
join(",", map("$_='" . $argref->{$_} . "'", @arg_slots)); join(",", map("$_='" . $argref->{$_} . "'", @arg_slots));
# except for this.
$bquery .= ",architecture='$architecture'"
if (defined($architecture));
$query .= ",creator='$uid',creator_idx='$uid_idx'"; $query .= ",creator='$uid',creator_idx='$uid_idx'";
$query .= ",uuid='$version_uuid'"; $query .= ",uuid='$version_uuid'";
$query .= ",created=now()"; $query .= ",created=now()";
...@@ -766,7 +759,8 @@ sub Create($$$$$$$$) ...@@ -766,7 +759,8 @@ sub Create($$$$$$$$)
# Create the osidtoimageid mapping. Admins have an option to do it or not. # Create the osidtoimageid mapping. Admins have an option to do it or not.
my $makedefault = exists($argref->{"makedefault"}) && my $makedefault = exists($argref->{"makedefault"}) &&
$argref->{"makedefault"} eq "1"; $argref->{"makedefault"} eq "1";
if (!$isdataset && (!$isadmin || $makedefault)) {
if (!$isdataset && !defined($architecture) && (!$isadmin || $makedefault)){
# #
# Dig out the mtypes we want to turn on. The caller has already # Dig out the mtypes we want to turn on. The caller has already
# sanity checked them to make sure the types actually exist, and # sanity checked them to make sure the types actually exist, and
...@@ -851,18 +845,9 @@ sub NewVersion($$$$) ...@@ -851,18 +845,9 @@ sub NewVersion($$$$)
# #
# Grab the current type list. # Grab the current type list.
# #
$query_result = my @typelist = $self->TypeList();
DBQueryWarn("select distinct type from osidtoimageid ". $typelist = join(",", @typelist)
"where imageid='$osid'"); if (@typelist);
goto bad
if (!$query_result);
my @types = ();
while (my ($type) = $query_result->fetchrow_array()) {
push(@types, $type);
}
$typelist = join(",", @types);
# #
# Update the type list in the image being cloned. Better to do this # Update the type list in the image being cloned. Better to do this
...@@ -1116,9 +1101,9 @@ sub Release($) ...@@ -1116,9 +1101,9 @@ sub Release($)
sub EditImageid($$$$) sub EditImageid($$$$)
{ {
my ($class, $image, $argref, $usrerr_ref) = @_; my ($class, $image, $argref, $usrerr_ref) = @_;
my %mods; my %mods;
my $noreport; my $noreport;
require NodeType;
my $imageid = $image->imageid(); my $imageid = $image->imageid();
...@@ -1127,47 +1112,55 @@ sub EditImageid($$$$) ...@@ -1127,47 +1112,55 @@ sub EditImageid($$$$)
# (Others above already did their own updates.) # (Others above already did their own updates.)
# #
my %updates; my %updates;
foreach my $col ("description", "path", "mbr_version", "hash", "notes") { foreach my $col ("description", "path", "mbr_version", "hash",
"notes") {
# Copy args we want so that others can't get through. # Copy args we want so that others can't get through.
if (exists($argref->{$col})) { if (exists($argref->{$col})) {
$updates{$col} = $mods{$col} = $argref->{$col}; $updates{$col} = $mods{$col} = $argref->{$col};
} }
} }
# See mtype_$type args below.
#
# Need a list of node types. We join this over the nodes table so that
# we get a list of just the nodes that are currently in the testbed, not
# just in the node_types table.
#
my $types_result =
DBQueryWarn("select distinct n.type from nodes as n ".
"left join node_type_attributes as a on a.type=n.type ".
"where a.attrkey='imageable' and ".
" a.attrvalue!='0'");
my @mtypes_array;
my @map_updates;
my $redo_map = 0; my $redo_map = 0;
while (my ($type) = $types_result->fetchrow_array()) { my @map_updates;
push(@mtypes_array, $type);
if (exists($argref->{"architecture"})) {
# This is in the images table, so done separately.
$mods{"architecture"} = $argref->{"architecture"};
} }