imagerelease.in 5.45 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/perl -w
#
# Copyright (c) 2014 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 Data::Dumper;
use File::stat;
use File::Basename;

#
# Release an image by changing the current version in the versions table
# to point to it. We first copy the image file over to boss, and after
# we call imagevalidate to make sure the DB is consistent.
#
sub usage()
{
38
    print("Usage: imagerelease [-q] [-f] [-m] <imageid>\n" .
39
	  "Options:\n".
40
41
42
	  "       -q      Turn on quiet mode\n".
	  "       -f      Force even if it make no sense.\n".
	  "       -m      With force, just mark as ready/released.\n");
43
44
    exit(-1);
}
45
my $optlist    = "dqfm";
46
47
my $debug      = 0;
my $quiet      = 0;
Leigh B Stoller's avatar
Leigh B Stoller committed
48
my $force      = 0;
49
my $markready  = 0;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

#
# Configure variables
#
my $TB		  = "@prefix@";
my $FSNODE	  = "@FSNODE@";
my $PROJROOT      = "@PROJROOT_DIR@";
my $IMAGEVALIDATE = "$TB/sbin/imagevalidate";
my $SCP		  = "/usr/bin/scp";
my $SUDO	  = "/usr/local/bin/sudo";

# Protos
sub fatal($);

#
# 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 EmulabConstants;
use User;
use Image;
use OSinfo;

#
# 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{"q"})) {
    $quiet = 1;
}
Leigh B Stoller's avatar
Leigh B Stoller committed
95
96
if (defined($options{"f"})) {
    $force = 1;
97
98
99
    if (defined($options{"m"})) {
	$markready = 1;
    }
Leigh B Stoller's avatar
Leigh B Stoller committed
100
}
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
usage()
    if (@ARGV != 1);
my $imageid = $ARGV[0];

my ($user,$user_uid);
if ($UID) {
    $user = User->ThisUser();
    if (!defined($user)) {
	fatal("You ($UID) do not exist!");
    }
    $user_uid = $user->uid();
}

my $image = Image->Lookup($imageid);
if (!defined($image)) {
    $image = Image->LookupByName($imageid);
}
if (!defined($image)) {
    fatal("No such image!");
}
Leigh B Stoller's avatar
Leigh B Stoller committed
121
if ($image->released() && !$force) {
122
123
124
    fatal("Image is already released! ".
	  "Maybe you need to provide imageid:version");
}
125
126
127
128
129
130
if ($force && $markready) {
    print "Marking image ready/released, but not doing anything else\n";
    $image->MarkReady();
    $image->MarkReleased();
    exit(0);
}
131
132
133
if (!$image->ready()) {
    fatal("Image is not ready yet!");
}
134
135
136
if ($UID && !$user->IsAdmin()) {
    fatal("Only admins can release an image.");
}
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

#
# Grab version 0 of the descriptor, which tells us if the image is really
# stored on boss. At some point, it would be nice to store unreleased
# versions of system images on boss too, but not enough disk space to
# support that, so we put newer versions in /proj until they are released,
# and then copy them over to avoid the NFS overhead when using the image.
# If we have to copy them back, we might also have to update the path in
# the database.
#
my $updatepath   = 0;
my $copytofile   = undef;
my $copyfromfile = undef;
my $version0;

#
# Before we do anything destructive, we lock the image.
#
if ($image->Lock()) {
    fatal("Image is locked, please try again later!\n");
}
if ($image->version()) {
    $version0 = Image->Lookup($image->imageid(), 0);
    if (!defined($version0)) {
	$image->Unlock();
	fatal("Cannot lookup version zero of $image");
    }
}
else {
    $version0 = $image;
}
if ($version0->path() =~ /^\/usr\/testbed/) {
Leigh B Stoller's avatar
Leigh B Stoller committed
169
    $copytofile = "/usr/testbed/images/" . basename($image->path());
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    $copyfromfile = $image->path();
    if ($image->version()) {
	$updatepath = 1;
    }
    else {
	#
	# For version 0 of the image, create_image sticks the file out on /proj,
	# but does not change the image path. 
	#
	$copyfromfile = "$PROJROOT/" .
	    $image->pid() . "/images/" . basename($image->path());
    }
}
if (defined($copytofile)) {
    unlink($copytofile)
	if (-e $copytofile);

    if (!$quiet) {
	print "Copying ${FSNODE}:$copyfromfile $copytofile\n";
    }
    system("$SUDO $SCP -p ${FSNODE}:$copyfromfile $copytofile");
    if ($?) {
	$image->Unlock();
	fatal("Failed to scp ${FSNODE}:$copyfromfile $copytofile");
    }
    if ($updatepath) {
	if ($image->Update({"path" => $copytofile})) {
	    $image->Unlock();
	    fatal("Failed to update path");
	}
    }
Leigh B Stoller's avatar
Leigh B Stoller committed
201
202
203
204
205
206
207
208
209
210
    if (!$quiet) {
	print "Running imagevalidate ...\n";
    }
    system("$IMAGEVALIDATE -u " . ($quiet ? "-q " : "") .
	   $image->pid() . "," . $image->imagename() . ":" .
	   $image->version());
    if ($?) {
	$image->Unlock();
	fatal("Failed to validate the image!");
    }
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
}
# Now mark as released.
if ($image->Release()) {
    $image->Unlock();    
    fatal("Could not mark image as released!");
}
$image->Unlock();    
exit(0);

sub fatal($)
{
    my ($mesg) = @_;

    print STDERR "*** $0:\n".
	         "    $mesg\n";
    exit(-1);
}