Commit ad2a3e70 authored by Leigh Stoller's avatar Leigh Stoller

Working on issue #269 ...

Add new script to "deprecate" images:

	boss> wap deprecate_image
	Usage: deprecate_image [-e|-w] <image> [warning message to users]
	Options:
	       -e     Use of image is an error; default is warning
	       -w     Use of image is a warning

When an image is deprecated with just warnings, new classic experiments
generate warnings in the output. Swapping in an experiment also
generates warnings in the output, but also sends email to the user.
When the image set for error, both new experiment and swapin will fail
with prejudice.

Same deal on the Geni path; we generate warnings/errors and send email.
Errors are reflected back in the Portal interface.

At the moment the image server knows nothing about deprecated images, so
the Portal constraint checker will not be bothered nor tell the user
until later when the cluster throws an error. As a result, when we
deprecate an image, we need to do it on all clusters. Needs to think
about this a bit more.
parent 72323b79
......@@ -6549,5 +6549,53 @@ sub AddProfileParameter($$$)
return 0;
}
#
# Check for deprecated images.
#
sub CheckForDeprecatedImages($$$)
{
my ($self, $user, $sendmail) = @_;
my $pid = $self->pid();
my $eid = $self->eid();
my %needwarning = ();
require OSImage;
my $deprecated_result =
DBQueryFatal("select vname,osname from virt_nodes ".
"where pid='$pid' and eid='$eid' and ".
" osname is not null and osname!=''");
while (my ($vname,$osname) = $deprecated_result->fetchrow_array()) {
my $image = OSImage->Lookup($osname);
if (!defined($image)) {
$image = OSImage->LookupByName($osname);
if (!defined($image)) {
# Lets not worry, we will catch is later.
next;
}
}
my $deprecated = 0;
my $iserror = 0;
if ($image->IsDeprecated(\$deprecated, undef, \$iserror)) {
tberror("Could not get deprecation info for $image\n");
return -1;
}
next
if (!$deprecated);
if ($iserror && !$user->IsAdmin()) {
tberror($image->DeprecatedMessage() . "\n");
return 1;
}
$needwarning{$image->imageid()} = $image;
}
foreach my $image (values(%needwarning)) {
print STDERR "*** WARNING: " . $image->DeprecatedMessage() . "\n";
if ($sendmail) {
$image->SendDeprecatedMail($user, $self);
}
}
return 0;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -2759,6 +2759,86 @@ sub SetCredential($$)
return $self->Update({"credential_string" => $credstr});
}
#
# Deprecate an image.
#
sub Deprecate($;$$)
{
my ($self, $message, $iserror) = @_;
my $imageid = $self->imageid();
if (defined($iserror)) {
$iserror = ($iserror ? 1 : 0);
}
my $query = "update image_versions set deprecated=now()";
$query .= ",deprecated_iserror='$iserror'" if (defined($iserror));
if (defined($message)) {
if ($message ne "") {
$query .= ",deprecated_message=" . DBQuoteSpecial($message);
}
else {
$query .= ",deprecated_message=NULL";
}
}
DBQueryWarn("$query where imageid='$imageid'")
or return -1;
return 0;
}
sub IsDeprecated($$;$$)
{
my ($self, $pval, $pmessage, $piserror) = @_;
my $imageid = $self->imageid();
my $version = $self->version();
my $query_result =
DBQueryWarn("select deprecated,deprecated_message,deprecated_iserror ".
" from image_versions ".
"where imageid='$imageid' and version='$version'");
return -1
if (! ($query_result && $query_result->numrows));
my ($deprecated, $message, $iserror) = $query_result->fetchrow_array();
$$pval = $deprecated;
$$pmessage = $message if (defined($pmessage));
$$piserror = $iserror if (defined($piserror));
return 0;
}
sub DeprecatedMessage($;$)
{
my ($self, $experiment) = @_;
my $message = $self->deprecated_message();
my $iserror = $self->deprecated_iserror();
my $name = $self->pid() . "/" . $self->imagename();
my $result;
if ($iserror) {
$result = "Image $name is deprecated and no longer available to use".
(defined($message) && $message ne "" ? ": ${message}" : "") .
". " . "Please choose a different image!";
}
else {
$result = "Image $name is deprecated and no longer available to use".
(defined($message) && $message ne "" ? ": ${message}" : "") .
". " . "You can continue to use this image for now but you should ".
"choose a different one before this image is deleted!";
}
if (defined($experiment)) {
my $pid = $experiment->pid();
my $eid = $experiment->eid();
$result = "Experiment $pid/$eid: $result";
}
return $result;
}
sub SendDeprecatedMail($$;$)
{
my ($self, $user, $experiment) = @_;
my $message = $self->DeprecatedMessage($experiment);
$user->SendEmail("Deprecated Image Warning", $message);
return 0;
}
#
# Path and Directory stuff.
#
......
......@@ -1179,6 +1179,31 @@ sub IsSystemImage($)
return $self->image()->IsSystemImage();
}
sub Deprecate($;$$)
{
my ($self,$message,$iserror) = @_;
return $self->image()->Deprecate($message, $iserror);
}
sub IsDeprecated($$;$$)
{
my ($self,$val,$message,$iserror) = @_;
return $self->image()->IsDeprecated($val, $message, $iserror);
}
sub DeprecatedMessage($;$)
{
my ($self, $experiment) = @_;
return $self->image()->DeprecatedMessage($experiment);
}
sub SendDeprecatedMail($$;$)
{
my ($self, $user, $experiment) = @_;
return $self->image()->SendDeprecatedMail($user, $experiment);
}
################################################################################
# This is the stuff from OSinfo.pm
################################################################################
......
......@@ -2759,6 +2759,9 @@ sub GetTicketAuxAux($$$$$$$$$$$)
goto bad;
}
}
$response = CheckForDeprecatedImages($slice_experiment, $user);
goto bad
if (GeniResponse::IsResponse($response));
# Must chdir to the work directory for the mapper.
if (! chdir($slice_experiment->WorkDir())) {
......@@ -8284,5 +8287,53 @@ sub AddInternalNodeToRspec($$$)
return $newnode;
}
#
#
#
sub CheckForDeprecatedImages($$)
{
my ($experiment, $user) = @_;
my $pid = $experiment->pid();
my $eid = $experiment->eid();
my %needwarning = ();
require OSImage;
my $deprecated_result =
emdb::DBQueryFatal("select vname,osname from virt_nodes ".
"where pid='$pid' and eid='$eid' and ".
" osname is not null and osname!=''");
while (my ($vname,$osname) = $deprecated_result->fetchrow_array()) {
my $image = OSImage->Lookup($osname);
if (!defined($image)) {
$image = OSImage->LookupByName($osname);
if (!defined($image)) {
# Lets not worry, we will catch is later.
next;
}
}
my $deprecated = 0;
my $iserror = 0;
if ($image->IsDeprecated(\$deprecated, undef, \$iserror)) {
print STDERR "Could not get deprecation info for $image\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not get deprecation info for $image");
}
next
if (!$deprecated);
if ($iserror) {
print STDERR "*** " . $image->DeprecatedMessage() . "\n";
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
$image->DeprecatedMessage());
}
$needwarning{$image->imageid()} = $image;
}
foreach my $image (values(%needwarning)) {
print STDERR "*** WARNING: " . $image->DeprecatedMessage() . "\n";
$image->SendDeprecatedMail($user);
}
return 0;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -844,6 +844,7 @@ sub BumpActivity($) { return $_[0]->{'USER'}->BumpActivity(); }
sub DefaultProject($) { return $_[0]->{'USER'}->DefaultProject(); }
sub FlipTo($$) { return $_[0]->{'USER'}->FlipTo($_[1]); }
sub UpdateExports($) { return $_[0]->{'USER'}->UpdateExports(); }
sub SendEmail($$$;$) { return $_[0]->{'USER'}->SendEmail($_[1],$_[2],$_[3]); }
# Need to construct this since not in User structure.
sub hrn($) { return "${PGENIDOMAIN}." . $_[0]->uid(); }
......
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -74,6 +74,7 @@ use libtblog;
use User;
use Experiment;
use Template;
use OSImage;
#
# Turn off line buffering on output
......@@ -222,6 +223,14 @@ if ($events_result->num_rows) {
fatal("Oops, cannot send static events to linkdelay agents on Linux!");
}
#
# Prelim check for deprecated images.
#
if ($experiment->CheckForDeprecatedImages($this_user, 0)) {
cleanup();
exit(-1);
}
#
# Only admins can set the sharing mode on nodes.
#
......
......@@ -980,6 +980,12 @@ sub doSwapin($) {
# Just the physnodes ...
my @deleted_pnodes = ();
if ($type == REAL) {
if ($experiment->CheckForDeprecatedImages($this_user, 1)) {
return 1;
}
}
# Special IP assignment. Must do before mapper runs and moves
# IPs from virt_lans to interfaces table.
if ($experiment->SetupNetworkFabrics()) {
......@@ -1075,7 +1081,7 @@ sub doSwapin($) {
tberror "Failed ($exitcode) to map to reality.";
# Wrapper sets this bit when recovery is possible.
# Wrapper sets this bit when recoveryppxu is possible.
if ($exitcode & 64) {
# We can recover.
tbreport(SEV_SECONDARY, 'assign_wrapper_failed', $exitcode);
......
......@@ -57,7 +57,8 @@ SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl \
node_exclude managetaint shutdown-shared imagerelease \
runsonxen pxelinux_makeconf attend atten \
addrfdevice addrfpath reserve announce createimagealias \
predict test-reserve prunelogfiles notify-reservations
predict test-reserve prunelogfiles notify-reservations \
deprecate_image
WEB_SBIN_SCRIPTS= webnewnode webdeletenode webspewconlog webarchive_list \
webwanodecheckin webspewimage webdumpdescriptor webemulabfeature \
......
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use File::Basename;
use Data::Dumper;
#
# Delete an image (descriptor)
#
sub usage()
{
print("Usage: deprecate_image [-e|-w] <image> [warning message to users]\n".
"Options:\n".
" -e Use of image is an error; default is warning\n".
" -w Use of image is a warning\n");
exit(-1);
}
my $optlist = "ewd";
my $debug = 0;
my $doerror = 0;
my $dowarning = 0;
my $deprecated = 0;
my $iserror = 0;
my $message;
#
# Configure variables
#
my $TB = "@prefix@";
#
# Untaint the path
#
$ENV{'PATH'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use User;
use OSImage;
# Protos
sub fatal($);
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"e"})) {
$doerror = 1;
}
if (defined($options{"w"})) {
$dowarning = 1;
}
usage()
if (@ARGV < 1 || @ARGV > 2);
usage()
if ($doerror && $dowarning);
#
# Map invoking user to object.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
my $image = OSImage->Lookup($ARGV[0]);
if (!defined($image)) {
fatal("Image does not exist in the DB!");
}
if ($this_user->IsAdmin()) {
fatal("Only admins can deprecate an image");
}
if ($image->IsDeprecated(\$deprecated, \$message, \$iserror)) {
fatal("Could not get current deprecation info for image");
}
if ($doerror) {
$iserror = 1;
}
elsif ($dowarning) {
$iserror = 0;
}
if (@ARGV > 1) {
$message = $ARGV[1];
}
$image->Deprecate($message, $iserror) == 0 or
fatal("Could not set deprecation info for image");
exit(0);
sub fatal($)
{
my ($mesg) = @_;
die("*** $0:\n".
" $mesg\n");
}
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