Commit 3f5e4ef8 authored by Russ Fish's avatar Russ Fish

Move newimageid page form logic to a backend Perl script.

     www/newimageid.php3 - The reworked PHP page.
     www/imageid_defs.php - Add an Image::NewImageId class method
                            bridging to the script via XML.
     backend/{newimageid,GNUmakefile}.in configure configure.in - New backend script.
     db/Image.pm.in - Add a Create class method for script arg checking.
     sql/database-fill.sql - Add to the table_regex 'images' checking patterns.
parent 978c891a
......@@ -13,9 +13,9 @@ UNIFIED = @UNIFIED_BOSS_AND_OPS@
include $(OBJDIR)/Makeconf
BIN_SCRIPTS = moduserinfo newgroup newmmlist editexp editimageid \
editnodetype editsitevars
editnodetype editsitevars newimageid
WEB_BIN_SCRIPTS = webmoduserinfo webnewgroup webnewmmlist webeditimageid \
webeditnodetype webeditsitevars
webeditnodetype webeditsitevars webnewimageid
WEB_SBIN_SCRIPTS=
LIBEXEC_SCRIPTS = $(WEB_BIN_SCRIPTS) $(WEB_SBIN_SCRIPTS)
......
This diff is collapsed.
......@@ -2429,7 +2429,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
account/quotamail account/mkusercert account/newproj account/newuser \
backend/GNUmakefile backend/moduserinfo backend/newgroup \
backend/newmmlist backend/editexp backend/editimageid backend/editnodetype \
backend/editsitevars \
backend/editsitevars backend/newimageid \
tbsetup/GNUmakefile tbsetup/console_setup tbsetup/spewlogfile \
tbsetup/spewrpmtar tbsetup/gentopofile tbsetup/power_sgmote.pm \
tbsetup/console_reset tbsetup/bwconfig tbsetup/power_rpc27.pm \
......
......@@ -809,7 +809,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
account/quotamail account/mkusercert account/newproj account/newuser \
backend/GNUmakefile backend/moduserinfo backend/newgroup \
backend/newmmlist backend/editexp backend/editimageid backend/editnodetype \
backend/editsitevars \
backend/editsitevars backend/newimageid \
tbsetup/GNUmakefile tbsetup/console_setup tbsetup/spewlogfile \
tbsetup/spewrpmtar tbsetup/gentopofile tbsetup/power_sgmote.pm \
tbsetup/console_reset tbsetup/bwconfig tbsetup/power_rpc27.pm \
......
......@@ -164,6 +164,163 @@ sub Refresh($)
return 0;
}
#
# Create a new os_info. This installs the new record in the DB,
# and returns an instance. There is some bookkeeping along the way.
#
sub Create($$$$)
{
my ($class, $project, $group, $creator, $imagename, $argref, $usrerr_ref) = @_;
my $idx;
my $now = time();
return undef
if (ref($class) || !ref($project));
my $isadmin = $creator->IsAdmin();
# We may ignore particular partN_osid's by deleting them.
my @arg_slots = grep(/^part[1-4]_osid$/, keys(%{$argref}));
# Pass-through a bunch of required slots, ignoring any extras
# and stuff we handle explicitly.
foreach my $key ("loadpart", "loadlength", "default_osid") {
if (!exists($argref->{$key})) {
$$usrerr_ref = "Error: $key missing in Image->Create!";
return undef;
}
push(@arg_slots, $key);
}
# Pass-through optional slots, otherwise the DB default is used.
foreach my $key ("path", "shared", "global") {
if (exists($argref->{$key})) {
push(@arg_slots, $key);
}
}
my $pid = $project->pid();
my $pid_idx = $project->pid_idx();
my $gid = $group->gid();
my $gid_idx = $group->gid_idx();
my $uid = $creator->uid();
my $uid_idx = $creator->uid_idx();
#
# The pid/imageid has to be unique, so lock the table for the check/insert.
#
DBQueryWarn("lock tables images write, emulab_indicies write")
or return undef;
my $query_result =
DBQueryWarn("select imagename from images ".
"where pid_idx='$pid_idx' and imagename='$imagename'");
if ($query_result->numrows) {
DBQueryWarn("unlock tables");
$$usrerr_ref = "Error: IMAGE $imagename in project $pid already exists!";
return undef;
}
#
# Grab unique ID. Table already locked.
#
my $imageid = TBGetUniqueIndex("next_imageid", undef, 1);
my $uuid = NewUUID();
my $desc = "''";
# Some fields special cause of quoting.
#
if (exists($argref->{'description'})) {
$desc = DBQuoteSpecial($argref->{'description'});
}
my $query = "insert into images set ".
join(",", map("$_='" . $argref->{$_} . "'", @arg_slots));
# Append the rest
$query .= ",imagename='$imagename'";
$query .= ",imageid='$imageid'";
$query .= ",uuid='$uuid'";
$query .= ",pid='$pid',pid_idx='$pid_idx'";
$query .= ",gid='$gid',gid_idx='$gid_idx'";
$query .= ",creator='$uid',creator_idx='$uid_idx'";
$query .= ",created=now()";
$query .= ",description=$desc";
if (! DBQueryWarn($query)) {
DBQueryWarn("unlock tables");
tberror("Error inserting new images record for $pid/$imagename!");
return undef;
}
my $image = Image->Lookup($imageid);
# Create the osidtoimageid mapping. Admins have an option to do it or not.
my $makedefault = exists($argref->{"makedefault"}) &&
$argref->{"makedefault"} eq "1";
if (!$isadmin || $makedefault) {
# Lock tables unlocks previous locks as a side-effect.
DBQueryWarn("lock tables osidtoimageid write, images write, ".
"nodes as n write, node_type_attributes as a write");
#
# 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;
while (my ($type) = $types_result->fetchrow_array()) {
push(@mtypes_array, $type);
# Remember when we get one of the mtype_$type args. These aren't DB
# columns to update, but instead control re-creating the rows in the
# osidtoimageid table for this imageid, below.
my $mtype = "mtype_$type";
if (exists($argref->{$mtype})) {
my $value = $argref->{$mtype};
##printf "argref->{$mtype} %s\n", $value;
if ($value eq "1") {
push(@map_updates, $type);
}
}
}
my @osid_array;
for (my $i = 1; $i <= 4; $i++) {
my $foo = $image->field("part${i}_osid");
if (defined($foo)) {
push(@osid_array, $foo);
}
}
for (my $i = 0; $i <= $#map_updates; $i++) {
for (my $j = 0; $j <= $#osid_array; $j++) {
my $query = "INSERT INTO osidtoimageid ".
" (osid, type, imageid) ".
"VALUES ('$osid_array[$j]', ".
" '$map_updates[$i]', ".
" '$imageid')";
##print "$query\n";
if (! DBQueryWarn($query)) {
DBQueryWarn("unlock tables");
tberror("Error inserting new ostoimageid mapping for ".
"$pid/$imagename!");
return undef;
}
}
}
}
DBQueryWarn("unlock tables");
return $image;
}
#
# Worker class method to edit image descriptor.
# Assumes most argument checking was done elsewhere.
......@@ -196,7 +353,7 @@ sub EditImageid($$$$)
# just in the node_types table.
#
my $types_result =
DBQueryFatal("select distinct n.type from nodes as n ".
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'");
......@@ -230,13 +387,13 @@ sub EditImageid($$$$)
}
if (keys %updates || $redo_map) {
DBQueryFatal("lock tables images write, os_info write, ".
DBQueryWarn("lock tables images write, os_info write, ".
"osidtoimageid write");
}
if (keys %updates) {
if ($image->Update(\%updates)) {
$$usrerr_ref = "DB: Error updating the images table";
DBQueryFatal("unlock tables");
DBQueryWarn("unlock tables");
return undef;
}
}
......@@ -245,7 +402,7 @@ sub EditImageid($$$$)
# Update the osidtoimageid table too.
#
# Must delete old entries first.
DBQueryFatal("delete from osidtoimageid ".
DBQueryWarn("delete from osidtoimageid ".
"where imageid='$imageid'");
my @osid_array;
......@@ -263,12 +420,12 @@ sub EditImageid($$$$)
" '$map_updates[$i]', ".
" '$imageid')";
##print "$query\n";
DBQueryFatal($query);
DBQueryWarn($query);
}
}
}
if (keys %updates || $redo_map) {
DBQueryFatal("unlock tables");
DBQueryWarn("unlock tables");
}
return 1;
......
......@@ -789,12 +789,24 @@ REPLACE INTO table_regex VALUES ('experiments','elab_in_elab','int','redirect','
REPLACE INTO table_regex VALUES ('experiments','elabinelab_singlenet','int','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('experiments','elabinelab_cvstag','text','regex','^[-\\w\\@\\/\\.]+$',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','imageid','text','redirect','default:int',0,100000000,NULL);
REPLACE INTO table_regex VALUES ('images','imagename','text','regex','^[a-zA-Z0-9][-\\w\\.+]+$',2,30,NULL);
REPLACE INTO table_regex VALUES ('images','imageid','text','redirect','default:int',0,100000000,NULL);
REPLACE INTO table_regex VALUES ('images','pid','text','redirect','projects:pid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','gid','text','redirect','groups:gid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','description','text','regex','^[\\040-\\176\\012\\015\\011]*$',1,256,NULL);
REPLACE INTO table_regex VALUES ('images','loadpart','text','redirect','default:tinyint',0,4,NULL);
REPLACE INTO table_regex VALUES ('images','loadlength','text','redirect','default:tinyint',1,4,NULL);
REPLACE INTO table_regex VALUES ('images','part1_osid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','part2_osid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','part3_osid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','part4_osid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','default_osid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','path','text','regex','^[-_\\w\\.\\/:+]*$',1,256,NULL);
REPLACE INTO table_regex VALUES ('images','shared','text','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','global','text','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','makedefault','text','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','mtype','text','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','osid','text','redirect','os_info:osid',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','node_id','text','redirect','nodes:node_id',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','load_address','text','redirect','default:text',0,0,NULL);
REPLACE INTO table_regex VALUES ('images','frisbee_pid','text','redirect','default:int',0,0,NULL);
......
......@@ -115,7 +115,94 @@ class Image
}
#
# Class function to edit image descriptor.
# Class function to create a new image descriptor.
#
function NewImageId($imagename, $args, &$errors) {
global $suexec_output, $suexec_output_array;
#
# Generate a temporary file and write in the XML goo.
#
$xmlname = tempnam("/tmp", "newimageid");
if (! $xmlname) {
TBERROR("Could not create temporary filename", 0);
$errors[] = "Transient error(1); please try again later.";
return null;
}
if (! ($fp = fopen($xmlname, "w"))) {
TBERROR("Could not open temp file $xmlname", 0);
$errors[] = "Transient error(2); please try again later.";
return null;
}
# Add these. Maybe caller should do this?
$args["imagename"] = $imagename;
fwrite($fp, "<image>\n");
foreach ($args as $name => $value) {
fwrite($fp, "<attribute name=\"$name\">");
fwrite($fp, " <value>" . htmlspecialchars($value) . "</value>");
fwrite($fp, "</attribute>\n");
}
fwrite($fp, "</image>\n");
fclose($fp);
chmod($xmlname, 0666);
$retval = SUEXEC("nobody", "nobody", "webnewimageid $xmlname",
SUEXEC_ACTION_IGNORE);
if ($retval) {
if ($retval < 0) {
$errors[] = "Transient error(3); please try again later.";
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
else {
# unlink($xmlname);
if (count($suexec_output_array)) {
for ($i = 0; $i < count($suexec_output_array); $i++) {
$line = $suexec_output_array[$i];
if (preg_match("/^([-\w]+):\s*(.*)$/",
$line, $matches)) {
$errors[$matches[1]] = $matches[2];
}
else
$errors[] = $line;
}
}
else
$errors[] = "Transient error(4); please try again later.";
}
return null;
}
#
# Parse the last line of output. Ick.
#
unset($matches);
if (!preg_match("/^IMAGE\s+([^\/]+)\/(\d+)\s+/",
$suexec_output_array[count($suexec_output_array)-1],
$matches)) {
$errors[] = "Transient error; please try again later.";
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
return null;
}
$image = $matches[2];
$newimage = image::Lookup($image);
if (! $newimage) {
$errors[] = "Transient error; please try again later.";
TBERROR("Could not lookup new image $image", 0);
return null;
}
# Unlink this here, so that the file is left behind in case of error.
# We can then create the image by hand from the xmlfile, if desired.
unlink($xmlname);
return $newimage;
}
#
# Class function to edit an image descriptor.
#
function EditImageid($image, $args, &$errors) {
global $suexec_output, $suexec_output_array;
......
This diff is collapsed.
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