Commit 750be519 authored by Leigh B Stoller's avatar Leigh B Stoller

Add new API call CreateImage; create/snapshot a geni sliver node.

This call allows a geni user to create a sliver, customise the node,
and then take a snapshot (possibly creating a new image descriptor)
without having to use the Emulab web interface. The API looks like:

  int CreateImage(slice_urn, sliver_urn, imagename, credentials[]);

The slice must be unlocked and the sliver in the ready state. Once
the operation starts, the slice is locked until the backend finishes.
This is something that I might revisit later, but this was the easiest
approach that ensures consistency. 

The imagename is looked up in the current project the node is attached
to. If it does not exists, create it. Then snapshot the node. You can
call this again of course, to take a new snapshot, without having to
provide a new imagename.

The image file is written to the images directory of the project,
which is available to the node via /proj, so the user can get to it
(since the user might not have a local account).
parent b01c991d
......@@ -68,6 +68,8 @@ my $TARFILES_SETUP = "$TB/bin/tarfiles_setup";
my $MAPPER = "$TB/bin/mapper";
my $VTOPGEN = "$TB/bin/vtopgen";
my $SNMPIT = "$TB/bin/snmpit";
my $CLONEIMAGE = "$TB/sbin/clone_image";
my $CREATEIMAGE = "$TB/bin/create_image";
my $XMLLINT = "/usr/local/bin/xmllint";
my $PRERENDER = "$TB/libexec/vis/prerender";
my $EMULAB_PEMFILE = "@prefix@/etc/genicm.pem";
......@@ -2229,5 +2231,137 @@ sub InjectEvent($)
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
#
# Emulab specific function to create an image from a node.
#
sub CreateImage($)
{
my ($argref) = @_;
my $slice_urn = $argref->{'slice_urn'};
my $credentials = $argref->{'credentials'};
my $imagename = $argref->{'imagename'};
my $sliver_urn = $argref->{'sliver_urn'};
my $wholedisk = 0;
require Image;
if (! (defined($credentials) && defined($imagename) &&
defined($slice_urn) && defined($sliver_urn))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
}
if (! ($imagename =~ /^[-\w]*$/)) {
return GeniResponse->MalformedArgsResponse("Improper name argument");
}
$wholedisk = 1
if (exists($argref->{'wholedisk'}) && $argref->{'wholedisk'});
my $credential = CheckCredentials($credentials);
return $credential
if (GeniResponse::IsResponse($credential));
my ($slice, $aggregate) = Credential2SliceAggregate($credential);
return $slice
if (defined($slice) && GeniResponse::IsResponse($slice));
if (! (defined($slice) && defined($aggregate))) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"Slice does not exist");
}
if ($slice_urn ne $slice->urn()) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN(), undef,
"Credential does not match the URN");
}
my $sliver = GeniSliver->Lookup($sliver_urn);
if (!defined($sliver)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"Sliver does not exist");
}
if ($sliver->slice_uuid() ne $slice->uuid()) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"Sliver is not in slice");
}
my $status;
if ($sliver->ComputeStatus(\$status)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"Could not compute status for sliver");
}
if ($status ne "ready") {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"sliver is not ready");
}
my $node_id = $sliver->resource_id();
my $node = Node->Lookup($node_id);
if (!defined($node)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"No node for sliver urn");
}
my $experiment = $slice->GetExperiment();
if (!defined($experiment)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"No local experiment for slice");
}
my $pid = $experiment->pid();
if (! $experiment->SameExperiment($node->Reservation())) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Node is not in the proper experiment");
}
#
# Lock the slice; we do not the user to mess with things.
#
if ($slice->Lock() != 0) {
return GeniResponse->BusyResponse();
}
my $opt = ($wholedisk ? "-e" : "");
my $output =
GeniUtil::ExecQuiet("$CLONEIMAGE $opt -s -d $imagename $node_id");
# Not a typical op, so always print debugging info;
print STDERR $output;
if ($?) {
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef, $output);
}
#
# Make sure we can get the image descriptor.
#
my $image = Image->Lookup($experiment->pid(), $imagename);
if (!defined($image)) {
$slice->UnLock();
print STDERR "Cannot lookup descriptor for $imagename\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
#
# We used the -s (nosnapshot) option above, to get the descriptor
# built, so now run create_image so that we can capture its output.
# At some point this might change to let clone do the snapshot,
# but when that happens, the email is sent to geniuser.
#
my $mypid = fork();
if ($mypid) {
# Let the child get going.
sleep(1);
return GeniResponse->Create(GENIRESPONSE_SUCCESS, undef, $output);
}
# This switches the file that we are writing to.
libaudit::AuditFork();
#
# Do the snapshot.
#
my $output =
GeniUtil::ExecQuiet("$CREATEIMAGE -f -p $pid $imagename $node_id");
# Not a typical op, so always print debugging info;
print STDERR $output;
if ($?) {
print STDERR "Failed to take the snapshot of $node_id\n";
$slice->UnLock();
return -1;
}
$slice->UnLock();
return 0;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
#! /usr/bin/env python
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2012 University of Utah and the Flux Group.
# All rights reserved.
#
# Permission to use, copy, modify and distribute this software is hereby
# granted provided that (1) source code retains these copyright, permission,
# and disclaimer notices, and (2) redistributions including binaries
# reproduce the notices in supporting documentation.
#
# THE UNIVERSITY OF UTAH ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
# CONDITION. THE UNIVERSITY OF UTAH DISCLAIMS ANY LIABILITY OF ANY KIND
# FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
#
#
#
import sys
import pwd
import getopt
import os
import time
import re
ACCEPTSLICENAME=1
debug = 0
impotent = 1
execfile( "test-common.py" )
if len(REQARGS) != 2:
Usage()
sys.exit(1)
pass
imagename = REQARGS[0]
sliver_urn = REQARGS[1]
#
# Get a credential for myself, that allows me to do things at the SA.
#
mycredential = get_self_credential()
print "Got my SA credential"
#
# Lookup slice and get credential.
#
myslice = resolve_slice( SLICENAME, mycredential )
print "Asking for slice credential for " + SLICENAME
slicecredential = get_slice_credential( myslice, mycredential )
print "Got the slice credential"
#
# Create the image
#
print "Creating the Image ..."
params = {}
params["credentials"] = (slicecredential,)
params["slice_urn"] = myslice["urn"]
params["sliver_urn"] = sliver_urn
params["imagename"] = imagename
rval,response = do_method("cm", "CreateImage", params, version="2.0")
if rval:
Fatal("Could not create image")
pass
output = response["value"]
print str(output)
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# Copyright (c) 2008-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -76,6 +76,7 @@ elsif ($GENI_VERSION eq "2.0") {
"ListHistory" => \&GeniCMV2::ListHistory,
"ReserveVlanTags" => \&GeniCMV2::ReserveVlanTags,
"InjectEvent" => \&GeniCMV2::InjectEvent,
"CreateImage" => \&GeniCMV2::CreateImage,
};
}
......
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