Commit 5acdd9ce authored by Leigh B Stoller's avatar Leigh B Stoller

Checkpoint image provenance/versioning.

parent 5aff2d89
......@@ -1308,36 +1308,49 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
if (imageid != NULL) {
/* Interested in a specific image */
if (can_access(imageidx, ei, 1)) {
res = mydb_query("SELECT pid,gid,imagename,"
" path,imageid"
" FROM images WHERE"
" pid='%s'"
" AND imagename='%s'",
res = mydb_query("SELECT i.pid,i.gid,"
" i.imagename,v.path,i.imageid"
" FROM images as i "
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE i.pid='%s'"
" AND i.imagename='%s'",
5, wantpid, wantname);
} else {
/*
* Pid of expt must be same as pid of image
* and gid the same or image "shared".
*/
res = mydb_query("SELECT pid,gid,imagename,"
"path,imageid"
" FROM images WHERE"
" pid='%s' AND imagename='%s'"
" AND pid='%s'"
" AND (gid='%s' OR"
" (gid=pid AND shared=1))",
res = mydb_query("SELECT i.pid,i.gid,"
" i.imagename,v.path,i.imageid"
" FROM images as i "
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE i.pid='%s' "
" AND i.imagename='%s'"
" AND i.pid='%s'"
" AND (i.gid='%s' OR"
" (i.gid=i.pid AND "
" v.shared=1))",
5, wantpid, wantname,
ei->pid, ei->gid);
}
} else {
/* Find all images that this pid/gid can PUT */
res = mydb_query("SELECT pid,gid,imagename,"
"path,imageid"
" FROM images"
" WHERE pid='%s'"
" AND (gid='%s' OR"
" (gid=pid AND shared=1))"
" ORDER BY pid,gid,imagename",
res = mydb_query("SELECT i.pid,i.gid,i.imagename,"
"v.path,i.imageid"
" FROM images as i"
" LEFT JOIN image_versions as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE i.pid='%s'"
" AND (i.gid='%s' OR"
" (i.gid=i.pid AND v.shared=1))"
" ORDER BY i.pid,i.gid,i.imagename",
5, ei->pid, ei->gid);
}
assert(res != NULL);
......@@ -1436,34 +1449,48 @@ emulab_get_host_authinfo(struct in_addr *req, struct in_addr *host,
if (imageid != NULL) {
/* Interested in a specific image */
if (can_access(imageidx, ei, 0)) {
res = mydb_query("SELECT pid,gid,imagename,"
"path,imageid"
" FROM images WHERE"
" pid='%s'"
" AND imagename='%s'",
res = mydb_query("SELECT i.pid,i.gid,"
"i.imagename,v.path,i.imageid"
" FROM images as i "
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
"WHERE i.pid='%s'"
" AND i.imagename='%s'",
5, wantpid, wantname);
} else {
res = mydb_query("SELECT pid,gid,imagename,"
"path,imageid"
" FROM images WHERE"
" pid='%s' AND imagename='%s'"
" AND (global=1"
" OR (pid='%s'"
" AND (gid='%s'"
" OR shared=1)))"
res = mydb_query("SELECT i.pid,i.gid,"
"i.imagename,v.path,i.imageid"
" FROM images as i"
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE i.pid='%s' "
" AND i.imagename='%s'"
" AND (v.global=1"
" OR (i.pid='%s'"
" AND (i.gid='%s'"
" OR v.shared=1)))"
" ORDER BY pid,gid,imagename",
5, wantpid, wantname,
ei->pid, ei->gid);
}
} else {
/* Find all images that this pid/gid can GET */
res = mydb_query("SELECT pid,gid,imagename,"
"path,imageid"
" FROM images WHERE"
" (global=1"
" OR (pid='%s'"
" AND (gid='%s' OR shared=1)))"
" ORDER BY pid,gid,imagename",
res = mydb_query("SELECT i.pid,i.gid,i.imagename,"
"v.path,i.imageid"
" FROM images as i"
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE"
" (v.global=1"
" OR (i.pid='%s'"
" AND (i.gid='%s' OR v.shared=1)))"
" ORDER BY i.pid,i.gid,i.imagename",
5, ei->pid, ei->gid);
}
assert(res != NULL);
......@@ -1610,10 +1637,14 @@ dump_image_aliases(FILE *fd)
char *lastpid;
/* First the global image alias */
res = mydb_query("SELECT pid,imagename"
" FROM images"
" WHERE global=1"
" ORDER BY pid,imagename", 2);
res = mydb_query("SELECT i.pid,i.imagename"
" FROM images as i"
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE v.global=1"
" ORDER BY i.pid,i.imagename", 2);
assert(res != NULL);
nrows = mysql_num_rows(res);
......@@ -1662,10 +1693,14 @@ dump_image_aliases(FILE *fd)
free(lastpid);
lastpid = mystrdup(row[0]);
res2 = mydb_query("SELECT imagename"
" FROM images"
" WHERE pid='%s' AND shared=1"
" ORDER BY imagename",
res2 = mydb_query("SELECT i.imagename"
" FROM images as i"
" LEFT JOIN image_versions "
" as v on "
" v.imageid=i.imageid and "
" v.version=i.version "
" WHERE i.pid='%s' AND v.shared=1"
" ORDER BY i.imagename",
1, lastpid);
assert(res2 != NULL);
......
......@@ -659,6 +659,7 @@ TBOPSEMAIL
IPV6_SUBNET_PREFIX
IPV6_ENABLED
NFSMAPTOUSER
IMAGEPROVENANCE
BROWSER_CONSOLE_ENABLE
EC2META_ENABLE
NOSITECHECKIN
......@@ -5091,6 +5092,7 @@ MANAGEMENT_NETWORK="10.249.249.0"
MANAGEMENT_NETMASK="255.255.255.0"
MANAGEMENT_ROUTER="10.249.249.253"
NFSMAPTOUSER="root"
IMAGEPROVENANCE=0
#
# XXX You really don't want to change these!
......
......@@ -291,6 +291,7 @@ AC_SUBST(BROWSER_CONSOLE_ENABLE)
AC_SUBST(IPV6_ENABLED)
AC_SUBST(IPV6_SUBNET_PREFIX)
AC_SUBST(NFSMAPTOUSER)
AC_SUBST(IMAGEPROVENANCE)
#
# Offer both versions of the email addresses that have the @ escaped
......@@ -433,6 +434,7 @@ MANAGEMENT_NETWORK="10.249.249.0"
MANAGEMENT_NETMASK="255.255.255.0"
MANAGEMENT_ROUTER="10.249.249.253"
NFSMAPTOUSER="root"
IMAGEPROVENANCE=0
#
# XXX You really don't want to change these!
......
......@@ -193,10 +193,13 @@ $EXPT_RESOURCESHOSED = 0;
# These are slots in the node table that need to be restored.
@nodetable_fields = ("def_boot_osid",
"def_boot_osid_vers",
"def_boot_path",
"def_boot_cmd_line",
"temp_boot_osid",
"temp_boot_osid_vers",
"next_boot_osid",
"next_boot_osid_vers",
"next_boot_path",
"next_boot_cmd_line",
"pxe_boot_path",
......@@ -4506,12 +4509,14 @@ sub LinkTestCapable($$)
my $idx = $self->idx();
my $query_result =
DBQueryWarn("select v.vname, FIND_IN_SET('linktest',osfeatures) ".
DBQueryWarn("select v.vname, FIND_IN_SET('linktest',ov.osfeatures) ".
" from virt_nodes as v ".
"left join reserved as r on r.pid=v.pid and ".
" r.eid=v.eid and r.vname=v.vname ".
"left join nodes as n on n.node_id=r.node_id ".
"left join os_info as o on o.osid=n.def_boot_osid ".
"left join os_info_versions as ov on ".
" ov.osid=n.def_boot_osid and ".
" ov.vers=n.def_boot_osid_vers ".
"where v.exptidx='$idx' and v.role!='bridge'");
return -1
if (!defined($query_result));
......
This diff is collapsed.
......@@ -360,7 +360,7 @@ sub Create($$$$)
{
my ($class, $node_id, $experiment, $argref) = @_;
my ($control_iface,$virtnode_capacity,$adminmfs,$adminmfs_osid);
my ($priority, $osid, $opmode, $state);
my ($priority, $osid, $osid_vers, $opmode, $state);
require OSinfo;
require NodeType;
......@@ -392,6 +392,7 @@ sub Create($$$$)
if (!defined($typeinfo));
my $isremote = $typeinfo->isremotenode();
$osid_vers = 0;
if ($role eq "testnode") {
if ($typeinfo->virtnode_capacity(\$virtnode_capacity)) {
......@@ -415,8 +416,9 @@ sub Create($$$$)
"*** Could not find OSinfo object for $osid!\n";
return undef;
}
$osid = $osinfo->osid();
$opmode = $osinfo->op_mode();
$osid = $osinfo->osid();
$osid_vers = $adminmfs->vers();
$opmode = $osinfo->op_mode();
}
}
else {
......@@ -436,8 +438,9 @@ sub Create($$$$)
"*** Could not find OSinfo object for adminmfs!\n";
return undef;
}
$osid = $adminmfs->osid();
$opmode = $adminmfs->op_mode();
$osid = $adminmfs->osid();
$osid_vers = $adminmfs->vers();
$opmode = $adminmfs->op_mode();
}
}
else {
......@@ -486,7 +489,7 @@ sub Create($$$$)
" phys_nodeid='$node_id', role='$role', ".
" priority=$priority, " .
" eventstate='$state', op_mode='$opmode', " .
" def_boot_osid=$osid, " .
" def_boot_osid=$osid, def_boot_osid_vers='$osid_vers'" .
" inception=now(), uuid=$uuid, ".
" state_timestamp=unix_timestamp(NOW()), " .
" op_mode_timestamp=unix_timestamp(NOW())")) {
......@@ -1687,6 +1690,7 @@ sub ClearBootAttributes($)
"tarballs='',failureaction='fatal', routertype='none', ".
"def_boot_cmd_line='',next_boot_cmd_line='', ".
"temp_boot_osid=NULL,next_boot_osid=NULL, ".
"temp_boot_osid_vers=0,next_boot_osid_vers=0, ".
"update_accounts=0,ipport_next=ipport_low,rtabid=0, ".
"sfshostid=NULL,allocstate='$allocFreeState',boot_errno=0, ".
"destination_x=NULL,destination_y=NULL, ".
......@@ -2171,17 +2175,13 @@ sub CreateVnodes($$$)
# table.
#
my $osid = $nodetype->default_osid();
my $query_result =
DBQueryWarn("select op_mode from os_info where osid='$osid'");
return -1
if (! $query_result);
if (! $query_result->numrows) {
my $osinfo = OSinfo->Lookup($osid);
if (!defined($osinfo)) {
print STDERR "*** CreateVnodes: No such OSID '$osid'\n";
return -1;
}
my ($opmode) = $query_result->fetchrow_array();
my ($opmode) = $osinfo->op_mode();
my $osid_vers = $osinfo->vers();
#
# Need IP for jailed nodes.
......@@ -2426,6 +2426,7 @@ sub CreateVnodes($$$)
"eventstate" => $eventstate,
"allocstate" => $allocstate,
"def_boot_osid" => $osid,
"def_boot_osid_vers" => $osid_vers,
"update_accounts" => 1,
"jailflag" => $isjailed);
......@@ -2759,6 +2760,8 @@ sub SetNodeHistory($$$$)
# Set the scheduled_reloads for a node. Type is optional and defaults to
# testbed default load type. See above.
#
# No image version info; we always reload the most current image.
#
sub SetSchedReload($$;$)
{
my ($self, $imageid, $type) = @_;
......@@ -3136,13 +3139,18 @@ sub OSSelect($$$$)
if (!defined($field)) {
# Clear all osids.
DBQueryWarn("update nodes set ".
"def_boot_osid=NULL,next_boot_osid=NULL,temp_boot_osid=NULL ".
"def_boot_osid=NULL,next_boot_osid=NULL,".
"temp_boot_osid=NULL, ".
"def_boot_osid_vers=0,next_boot_osid_vers=0,".
"temp_boot_osid_vers=0 ".
"where node_id='$nodeid'")
or return -1;
} else {
# Set/Clear the osid.
DBQueryWarn("update nodes set ${field}=".
(defined($osinfo) ? "'" . $osinfo->osid() . "' " : "NULL ") .
my $osid = (defined($osinfo) ? "'" . $osinfo->osid() . "'" : "NULL");
my $vers = (defined($osinfo) ? "'" . $osinfo->vers() . "'" : "'0'");
DBQueryWarn("update nodes set ${field}=$osid,${field}_vers=$vers ".
"where node_id='$nodeid'")
or return -1;
......@@ -3353,13 +3361,19 @@ sub ClearOsids($) {
DBQueryWarn("update nodes set ".
" def_boot_osid=NULL,".
" next_boot_osid=NULL,".
" temp_boot_osid=NULL ".
" temp_boot_osid=NULL, ".
" def_boot_osid_vers=0,".
" next_boot_osid_vers=0,".
" temp_boot_osid_vers=0 ".
"where node_id='$node_id'")
or return -1;
$self->{"DBROW"}{"def_boot_osid"} = undef;
$self->{"DBROW"}{"temp_boot_osid"} = undef;
$self->{"DBROW"}{"next_boot_osid"} = undef;
$self->{"DBROW"}{"def_boot_osid_vers"} = 0;
$self->{"DBROW"}{"temp_boot_osid_vers"} = 0;
$self->{"DBROW"}{"next_boot_osid_vers"} = 0;
return 0;
}
......@@ -3401,11 +3415,13 @@ sub IsOSLoaded($$)
$osinfo = $tmp;
}
my $osid = $osinfo->osid();
my $vers = $osinfo->vers();
my $nodeid = $self->node_id();
my $query_result =
DBQueryWarn("select osid from partitions as p ".
"where p.node_id='$nodeid' and p.osid='$osid'");
"where p.node_id='$nodeid' and p.osid='$osid' and ".
" p.osid_vers='$vers'");
return -1
if (!$query_result);
......@@ -3683,9 +3699,10 @@ sub RunningOsImage($)
my ($self) = @_;
my $nodeid = $self->node_id();
my $osid = $self->def_boot_osid();
my $imageid;
my $vers = $self->def_boot_osid_vers();
my $image;
my $osinfo = OSinfo->Lookup($osid);
my $osinfo = OSinfo->Lookup($osid, $vers);
return ()
if (!defined($osinfo));
......@@ -3693,19 +3710,19 @@ sub RunningOsImage($)
# No partition entries for virtnodes, they are plain EZ images.
#
if ($self->isvirtnode()) {
$imageid = $osid;
# XXX No version info, need that.
$image = Image->Lookup($osid, $vers);
}
else {
my $query_result =
DBQueryWarn("select imageid from partitions as p ".
DBQueryWarn("select imageid,imageid_version from partitions as p ".
"where p.node_id='$nodeid' and p.osid='$osid'");
return ()
if (!$query_result || !$query_result->numrows);
($imageid) = $query_result->fetchrow_array();
my ($imageid,$version) = $query_result->fetchrow_array();
$image = Image->Lookup($imageid, $version);
}
# This might not exist for a virtnode; caller has to deal with it.
my $image = Image->Lookup($imageid);
return ($osinfo, $image);
}
......@@ -3836,14 +3853,14 @@ sub SyncTaintStates($)
my $node_id = $self->node_id();
my $query_result =
DBQueryWarn("select osid from partitions ".
DBQueryWarn("select osid,osid_vers from partitions ".
"where node_id='$node_id' and osid is not null");
return -1
if (!$query_result);
my @taint_states = ();
while (my ($osid) = $query_result->fetchrow_array()) {
my $osinfo = OSinfo->Lookup($osid);
while (my ($osid, $vers) = $query_result->fetchrow_array()) {
my $osinfo = OSinfo->Lookup($osid, $vers);
if (defined($osinfo) && $osinfo->IsTainted()) {
push @taint_states, $osinfo->GetTaintStates();
}
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2007-2013 University of Utah and the Flux Group.
# Copyright (c) 2007-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -104,74 +104,146 @@ sub mysystem($)
return system($command);
}
sub BlessRow($$)
{
my ($class, $row) = @_;
my $self = {};
my $osid = $row->{"osid"};
$self->{'OSINFO'} = $row;
bless($self, $class);
return $self;
}
#
# Lookup by idx or pid,osname, depending on the args.
# Lookup by idx or pid,osname[:version] depending on the args. We always
# return highest numbered version on this path, if no version specified.
#
sub Lookup($$;$)
sub Lookup($$;$$)
{
my ($class, $arg1, $arg2) = @_;
my $osid;
my ($class, $arg1, $arg2, $arg3) = @_;
#
# A single arg is either an index or a "pid,osname" or "pid/osname" string.
# A single arg is either an index or "pid,osname[:version]" or
# "pid/osname[:version]" string.
#
if (!defined($arg2)) {
if ($arg1 =~ /^(\d*)$/) {
$osid = $1;
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid and v.vers=o.version ".
"where o.osid='$arg1'");
return undef
if (! $result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
elsif ($arg1 =~ /^([-\w]*),([-\w\.\+]*)$/ ||
$arg1 =~ /^([-\w]*)\/([-\w\.\+]*)$/) {
$arg1 = $1;
$arg2 = $2;
$arg1 =~ /^([-\w]*)\/([-\w\.\+]*)$/) {
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid and v.vers=o.version ".
"where o.pid='$1' and o.osname='$2'");
return undef
if (! $result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
else {
return undef;
elsif ($arg1 =~ /^([-\w]*),([-\w\.\+]*):(\d*)$/ ||
$arg1 =~ /^([-\w]*)\/([-\w\.\+]*):(\d*)$/) {
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid ".
"where o.pid='$arg1' and o.osname='$arg2' and ".
" v.vers='$arg3' and v.deleted is null");
return undef
if (!$result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
elsif ($arg1 =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/) {
my $result =
DBQueryWarn("select * from os_info ".
"where uuid='$arg1' and deleted is null");
return undef
if (! $result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
return undef;
}
elsif (! (($arg1 =~ /^[-\w\.\+]*$/) && ($arg2 =~ /^[-\w\.\+]*$/))) {
elsif (!defined($arg3)) {
if ($arg1 =~ /^\d+$/ && $arg2 =~ /^\d+$/) {
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid ".
"where o.osid='$arg1' and v.vers='$arg2'");
return undef
if (! $result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
elsif ($arg1 =~ /^[-\w]*$/ && $arg2 =~ /^([-\w\.\+]*):(\d+)$/) {
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid ".
"where o.pid='$arg1' and o.osname='$1' and ".
" v.vers='$2'");
return undef
if (! $result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
elsif ($arg1 =~ /^[-\w]*$/ && $arg2 =~ /^[-\w\.\+]*$/) {
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid and v.vers=o.version ".
"where o.pid='$arg1' and o.osname='$arg2'");
return undef
if (! $result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
return undef;
}
#
# Two args means pid/osname lookup instead of gid_idx.
#
if (defined($arg2)) {
my $osid_result =
DBQueryWarn("select osid from os_info ".
"where pid='$arg1' and osname='$arg2'");
return undef
if (! $osid_result || !$osid_result->numrows);
($osid) = $osid_result->fetchrow_array();
else {
if ($arg1 =~ /^[-\w]*$/ &&
$arg2 =~ /^[-\w\.\+]*$/ && $arg3 =~ /^\d+$/) {
my $result =
DBQueryWarn("select o.*,v.* from os_info as o ".
"left join os_info_versions as v on ".
" v.osid=o.osid ".
"where o.pid='$arg1' and o.osname='$arg2' and ".
" v.vers='$arg3' and v.deleted is null");
return undef
if (!$result || !$result->numrows);
return BlessRow($class, $result->fetchrow_hashref());
}
return undef;
}
# Look in cache first