Commit 46eceecc authored by Leigh Stoller's avatar Leigh Stoller

Another checkpoint. Raw geni slivers working nicely. See new client

program protogeni/xmlrpc/client.py ... it is much easier to get a
simple python client running on your desktop then a perl client. Only
package you need to install is M2Crypto, which is easy. Perl needs
about 10 packages installed to xmlrpc over ssl. Sheesh.
parent 47798d81
......@@ -28,7 +28,7 @@ CREATE TABLE `geni_users` (
`status` enum('active','archived','frozen') NOT NULL default 'frozen',
`name` tinytext,
`email` tinytext,
`sa_idx` int(10) unsigned NOT NULL default '0',
`sa_uuid` varchar(40) NOT NULL default '',
PRIMARY KEY (`idx`),
KEY `hrn` (`hrn`),
UNIQUE KEY `uuid` (`uuid`)
......@@ -71,13 +71,14 @@ CREATE TABLE `geni_components` (
# UUIDs generated (signed) by and registered must have these top
# 8 bytes. See wiki discussion.
#
DROP TABLE IF EXISTS `geni_sliceauthorities`;
CREATE TABLE `geni_sliceauthorities` (
DROP TABLE IF EXISTS `geni_authorities`;
CREATE TABLE `geni_authorities` (
`hrn` varchar(256) NOT NULL default '',
`idx` mediumint(8) unsigned NOT NULL default '0',
`uuid` varchar(40) NOT NULL default '',
`uuid_prefix` varchar(12) NOT NULL default '',
`created` datetime default NULL,
`type` enum('sa','ma','ch') NOT NULL default 'sa',
`url` tinytext,
PRIMARY KEY (`idx`),
UNIQUE KEY `uuid` (`uuid`)
......@@ -102,7 +103,7 @@ CREATE TABLE `geni_slices` (
`created` datetime default NULL,
`creator_uuid` varchar(40) NOT NULL default '',
`name` tinytext,
`sa_idx` int(10) unsigned NOT NULL default '0',
`sa_uuid` varchar(40) NOT NULL default '',
PRIMARY KEY (`idx`),
UNIQUE KEY `hrn` (`hrn`),
UNIQUE KEY `uuid` (`uuid`)
......@@ -119,6 +120,7 @@ CREATE TABLE `geni_slivers` (
`slice_uuid` varchar(40) NOT NULL default '',
`creator_uuid` varchar(40) NOT NULL default '',
`resource_uuid` varchar(40) NOT NULL default '',
`resource_type` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`credential_idx` int(10) unsigned default NULL,
`ticket_idx` int(10) unsigned default NULL,
......@@ -137,19 +139,22 @@ DROP TABLE IF EXISTS `geni_aggregates`;
CREATE TABLE `geni_aggregates` (
`idx` mediumint(8) unsigned NOT NULL default '0',
`uuid` varchar(40) NOT NULL default '',
`type` varchar(40) NOT NULL default '',
`slice_uuid` varchar(40) NOT NULL default '',
`creator_uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`credential_idx` int(10) unsigned default NULL,
`ticket_idx` int(10) unsigned default NULL,
`component_idx` int(10) unsigned NOT NULL default '0',
`aggregate_idx` int(10) unsigned default NULL,
`status` enum('ready','broken') NOT NULL default 'ready',
PRIMARY KEY (`idx`),
UNIQUE KEY `uuid` (`uuid`),
INDEX `slice_uuid` (`slice_uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
# Table to remember the tickets that a component manager hands out.
# Table to remember tickets.
#
DROP TABLE IF EXISTS `geni_tickets`;
CREATE TABLE `geni_tickets` (
......@@ -160,10 +165,12 @@ CREATE TABLE `geni_tickets` (
`redeem_before` datetime default NULL,
`valid_until` datetime default NULL,
`component_idx` int(10) unsigned NOT NULL default '0',
`seqno` int(10) unsigned NOT NULL default '0',
`ticket_string` text,
PRIMARY KEY (`idx`),
PRIMARY KEY (`idx`),
INDEX `owner_uuid` (`owner_uuid`),
INDEX `slice_uuid` (`slice_uuid`)
INDEX `slice_uuid` (`slice_uuid`),
UNIQUE KEY `compseqno` (`component_idx`, `seqno`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
......@@ -198,12 +205,39 @@ CREATE TABLE `geni_certificates` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
# A clearinghouse table to hold sshkeys associated with geni users.
# A clearinghouse table to hold keys associated with geni users.
#
DROP TABLE IF EXISTS `geni_sshkeys`;
CREATE TABLE `geni_sshkeys` (
DROP TABLE IF EXISTS `geni_userkeys`;
CREATE TABLE `geni_userkeys` (
`type` enum('ssh','password') NOT NULL default 'ssh',
`uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`sshkey` text,
PRIMARY KEY (`uuid`)
`key` text,
INDEX `uuid` (`uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
# This table maps between resources and their component manager.
#
DROP TABLE IF EXISTS `geni_resources`;
CREATE TABLE `geni_resources` (
`idx` mediumint(8) unsigned NOT NULL default '0',
`resource_uuid` varchar(40) NOT NULL default '',
`resource_type` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`component_idx` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`idx`),
UNIQUE KEY `resource_uuid` (`resource_uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
# Hold the users that are bound to slices.
#
DROP TABLE IF EXISTS `geni_bindings`;
CREATE TABLE `geni_bindings` (
`slice_uuid` varchar(40) NOT NULL default '',
`user_uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL,
PRIMARY KEY (`slice_uuid`,`user_uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
......@@ -220,6 +220,33 @@ sub Delete($)
return 0;
}
#
# Look up a list of aggregates for a locally instantiated slice.
# Used by the CM.
#
sub SliceAggregates($$$)
{
my ($class, $slice, $pref) = @_;
my $slice_uuid = $slice->uuid();
my @result = ();
my $query_result =
DBQueryWarn("select idx from geni_aggregates ".
"where slice_uuid='$slice_uuid'");
return -1
if (!$query_result);
while (my ($idx) = $query_result->fetchrow_array()) {
my $aggregate = GeniAggregate->Lookup($idx);
return -1
if (!defined($aggregate));
push(@result, $aggregate);
}
@$pref = @result;
return 0;
}
#
# List of slivers for this aggregate.
#
......
......@@ -146,10 +146,10 @@ sub Resolve($)
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"No such user $uuid");
}
# Grab ssh key.
my $sshkey;
if ($user->GetSSHKey(\$sshkey) != 0) {
print STDERR "Could not get ssh key for $user\n";
# Grab keys.
my @sliverkeys;
if ($user->GetKeys(\@sliverkeys) != 0) {
print STDERR "Could not get sliver keys for $user\n";
}
# Return a blob.
......@@ -161,8 +161,8 @@ sub Resolve($)
"name" => $user->name(),
"sa_uuid" => $user->sa_uuid(),
};
$blob->{'sshkey'} = $sshkey
if (defined($sshkey));
$blob->{'sliverkeys'} = \@sliverkeys
if (@sliverkeys);
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
}
......@@ -295,7 +295,7 @@ sub Register($)
if ($type eq "User") {
my $name = $info->{'name'};
my $email = $info->{'email'};
my $sshkey= $info->{'sshkey'};
my $keys = $info->{'sliverkeys'};
if (! TBcheck_dbslot($name, "users", "usr_name",
TBDB_CHECKDBSLOT_ERROR)) {
......@@ -307,9 +307,20 @@ sub Register($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"email: ". TBFieldErrorString());
}
if (defined($sshkey) && ! ($sshkey =~ /^[\012\015\040-\176]*$/)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"sshkey: Invalid characters");
if (defined($keys)) {
foreach my $keyref (@{ $keys }) {
my $type = $keyref->{'type'};
my $key = $keyref->{'key'};
if ($type ne 'ssh') {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"key: Invalid key type");
}
if (! ($key =~ /^[\012\015\040-\176]*$/)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"key: Invalid characters");
}
}
}
#
# Need to verify the UUID is permitted for the SA making the request.
......@@ -345,7 +356,7 @@ sub Register($)
}
my $newuser = GeniUser->Create($hrn, $uid, $uuid,
$name, $email, $cert, $authority,
$sshkey);
$keys);
if (!defined($newuser)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$hrn/$email could not be registered");
......
......@@ -157,12 +157,12 @@ sub Register($$$$)
#
sub RegisterUser($$$$$)
{
my ($hrn, $name, $email, $cert, $sshkey) = @_;
my ($hrn, $name, $email, $cert, $keys) = @_;
my $info = { "name" => $name,
"email" => $email };
$info->{"sshkey"} = $sshkey
if (defined($sshkey));
$info->{"sliverkeys"} = $keys
if (defined($keys));
return Register($hrn, "User", $cert, $info);
}
......
This diff is collapsed.
......@@ -23,8 +23,6 @@ use Genixmlrpc;
use GeniResponse;
use GeniTicket;
use GeniCredential;
use libtestbed;
use Experiment;
use libdb qw(TBGetUniqueIndex);
use English;
use overload ('""' => 'Stringify');
......@@ -296,10 +294,9 @@ sub DiscoverResources($$$$$)
my $response =
Genixmlrpc::CallMethodHTTP($self->url(),
$user,
"CM::DiscoverResources",
{ "slice" => $slice->cert(),
"credential" => $credential->asString()
});
"DiscoverResources",
{ "credential" => $credential->asString()
});
return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
......@@ -326,8 +323,7 @@ sub GetTicket($$$$$;$)
if (ref($rspec_xml)) {
$rspec_xml = XMLout($rspec_xml, RootName => "rspec");
}
my $args = { "slice" => $slice->cert(),
"credential" => $credential->asString(),
my $args = { "credential" => $credential->asString(),
"impotent" => $impotent,
"rspec" => $rspec_xml };
$args->{'virtual_topology'} = $vtopo
......@@ -335,7 +331,7 @@ sub GetTicket($$$$$;$)
my $response =
Genixmlrpc::CallMethodHTTP($self->url(),
$user, "CM::GetTicket", $args);
$user, "GetTicket", $args);
return undef
if (!defined($response));
......@@ -362,7 +358,7 @@ sub CreateSliver($$$$)
my $response =
Genixmlrpc::CallMethodHTTP($self->url(), $user,
"CM::CreateSliver",
"RedeemTicket",
{ "ticket" => $ticket->asString(),
"impotent" => $impotent });
......@@ -407,9 +403,8 @@ sub DestroySliver($$$)
my $response =
Genixmlrpc::CallMethodHTTP($self->url(), $user,
"CM::DestroySliver",
{ "sliver" => $sliver->cert(),
"impotent" => $impotent,
"DeleteSliver",
{ "impotent" => $impotent,
"credential" =>
$credential->asString() });
......@@ -437,9 +432,8 @@ sub StartSliver($$$)
my $response =
Genixmlrpc::CallMethodHTTP($self->url(), $user,
"CM::StartSliver",
{ "sliver" => $sliver->cert(),
"impotent" => $impotent,
"StartSliver",
{ "impotent" => $impotent,
"credential" =>
$credential->asString() });
......
......@@ -201,6 +201,12 @@ sub Resolve($)
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
}
# Grab keys.
my @sliverkeys;
if ($geniuser->GetKeys(\@sliverkeys) != 0) {
print STDERR "Could not get sliver keys for $geniuser\n";
}
# Return a blob.
my $blob = { "uid" => $geniuser->uid(),
"hrn" => $geniuser->hrn(),
......@@ -209,6 +215,9 @@ sub Resolve($)
"cert" => $geniuser->cert(),
"name" => $geniuser->name(),
};
$blob->{'sliverkeys'} = \@sliverkeys
if (@sliverkeys);
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
}
if ($type eq "Slice") {
......@@ -228,7 +237,7 @@ sub Resolve($)
}
if (!defined($slice)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"No such slice register here");
"No such slice registered here");
}
# User bindings too.
......@@ -401,10 +410,17 @@ sub Remove($)
{
my ($argref) = @_;
my $uuid = $argref->{'uuid'};
my $hrn = $argref->{'hrn'};
my $cred = $argref->{'credential'};
my $type = $argref->{'type'};
if (! (defined($uuid) && ($uuid =~ /^[-\w]*$/))) {
if (! (defined($uuid) || defined($hrn))) {
return GeniResponse->MalformedArgsResponse();
}
if (defined($uuid) && !($uuid =~ /^[-\w]*$/)) {
return GeniResponse->MalformedArgsResponse();
}
if (defined($hrn) && !($hrn =~ /^[-\w\.]*$/)) {
return GeniResponse->MalformedArgsResponse();
}
if (! (defined($type) && ($type =~ /^(SA|MA|Component|Slice|User)$/))) {
......@@ -463,10 +479,23 @@ sub Remove($)
}
if ($type eq "Slice") {
my $slice = GeniSlice->Lookup($uuid);
my $slice;
if (defined($uuid)) {
$slice = GeniSlice->Lookup($uuid);
}
else {
#
# XXX Form hrn from the uid and domain. This is backwards.
#
if (! ($hrn =~ /\./)) {
$hrn = "${OURDOMAIN}.slices.${hrn}";
}
$slice = GeniSlice->Lookup($hrn);
}
if (!defined($slice)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"No such slice $uuid");
"No such slice");
}
#
......
......@@ -44,6 +44,8 @@ my $AVAIL = "$TB/sbin/avail";
my $NALLOC = "$TB/bin/nalloc";
my $NFREE = "$TB/bin/nfree";
my $NODEREBOOT = "$TB/bin/node_reboot";
my $NAMEDSETUP = "$TB/sbin/named_setup";
my $GENTOPOFILE = "$TB/libexec/gentopofile";
# Cache of instances to avoid regenerating them.
my %slivers = ();
......@@ -401,6 +403,33 @@ sub GetSlice($)
return $slice;
}
#
# Look up a list of slivers for a locally instantiated slice.
# Used by the CM.
#
sub SliceSlivers($$$)
{
my ($class, $slice, $pref) = @_;
my $slice_uuid = $slice->uuid();
my @result = ();
my $query_result =
DBQueryWarn("select idx from geni_slivers ".
"where slice_uuid='$slice_uuid'");
return -1
if (!$query_result);
while (my ($idx) = $query_result->fetchrow_array()) {
my $sliver = GeniSliver->Lookup($idx);
return -1
if (!defined($sliver));
push(@result, $sliver);
}
@$pref = @result;
return 0;
}
#
# Client side method to contact the sliver component and destroy it.
#
......@@ -528,6 +557,9 @@ sub Provision($)
return -1;
}
if ($reservation->SameExperiment($experiment)) {
my $pid = $reservation->pid();
my $eid = $reservation->eid();
if ($experiment->InsertVirtNode($node) != 0) {
print STDERR "Could not add virtnode entry for $node to $self\n";
return -1;
......@@ -542,6 +574,18 @@ sub Provision($)
if ($node->SelectOS() != 0) {
return -1;
}
# Must have the topofile for node boot. Might need locking on this.
if (system("$GENTOPOFILE $pid $eid")) {
print STDERR "$GENTOPOFILE failed\n";
return -1;
}
# The node will not boot locally unless there is a DNS record.
if (system("$NAMEDSETUP")) {
print STDERR "$NAMEDSETUP failed\n";
return -1;
}
}
else {
print STDERR "$node is reserved to another, not $self\n";
......
......@@ -21,7 +21,6 @@ use lib '@prefix@/lib';
use GeniDB;
use GeniCredential;
use GeniCertificate;
use libtestbed;
use Experiment;
use libdb qw(TBGetUniqueIndex);
use English;
......@@ -78,6 +77,11 @@ sub Lookup($$)
return undef
if (!defined($ticket));
# Mark as coming from the DB.
$ticket->{'idx'} = $idx;
$ticket->{'stored'} = 1;
# Cache.
$tickets{"$idx"} = $ticket;
return $ticket;
}
......@@ -143,7 +147,9 @@ sub Stringify($)
my $seqno = $self->seqno();
$idx = "S$seqno";
}
return "[GeniTicket: $idx]";
my $slice_uuid = $self->slice_uuid();
return "[GeniTicket: $idx, slice:$slice_uuid]";
}
#
......@@ -418,8 +424,36 @@ sub GetExperiment($)
return Experiment->Lookup($self->slice_uuid());
}
#
# Look up a list of tickets for a locally instantiated slice.
# Used by the CM.
#
sub SliceTickets($$$)
{
my ($class, $slice, $pref) = @_;
my $slice_uuid = $slice->uuid();
my @result = ();
my $query_result =
DBQueryWarn("select idx from geni_tickets ".
"where slice_uuid='$slice_uuid'");
return -1
if (!$query_result);
while (my ($idx) = $query_result->fetchrow_array()) {
my $ticket = GeniTicket->Lookup($idx);
return -1
if (!defined($ticket));
push(@result, $ticket);
}
@$pref = @result;
return 0;
}
#
# Release a ticket. Need to release the nodes ...
# Used by the CM.
#
sub Release($)
{
......@@ -433,7 +467,8 @@ sub Release($)
my $eid = $experiment->eid();
my @nodeids = ();
foreach my $resource_uuid (keys(%{$self->rspec()->{'node'}})) {
foreach my $ref (@{$self->rspec()->{'node'}}) {
my $resource_uuid = $ref->{'uuid'};
my $node = Node->Lookup($resource_uuid);
next
if (!defined($node));
......@@ -445,7 +480,7 @@ sub Release($)
}
}
if (@nodeids) {
system("$NFREE $pid $eid @nodeids");
system("export NORELOAD=1; $NFREE $pid $eid @nodeids");
}
$self->Delete();
return 0;
......
......@@ -160,7 +160,7 @@ sub CheckExisting($$$)
sub Create($$$$$$$$$;$)
{
my ($class, $hrn, $uid, $uuid, $name, $email,
$cert, $authority, $sshkey) = @_;
$cert, $authority, $keys) = @_;
my @insert_data = ();
# Every user gets a new unique index.
......@@ -197,18 +197,21 @@ sub Create($$$$$$$$$;$)
}
# Insert the sshkey if we got one.
if (defined($sshkey)) {
my $safe_sshkey = DBQuoteSpecial($sshkey);
DBQueryWarn("replace into geni_sshkeys set ".
" uuid=$safe_uuid, created=now(), ".
" sshkey=$safe_sshkey") or return undef;
if (defined($keys)) {
foreach my $keyref (@{ $keys }) {
my $safe_key = DBQuoteSpecial($keyref->{'key'});
my $safe_type = DBQuoteSpecial($keyref->{'type'});
DBQueryWarn("replace into geni_userkeys set ".
" uuid=$safe_uuid, created=now(), ".
" key=$safe_key, type=$safe_type") or return undef;
}
}
# Insert into DB.
if (! DBQueryWarn("insert into geni_users set " .
join(",", @insert_data))) {
DBQueryWarn("delete from geni_sshkeys where uuid=$safe_uuid");
DBQueryWarn("delete from geni_userkeys where uuid=$safe_uuid");
return undef;
}
......@@ -227,7 +230,7 @@ sub CreateFromLocal($$)
}
#
# Delete the user, as for registration errors.
# Delete the user.
#
sub Delete($)
{
......@@ -241,6 +244,8 @@ sub Delete($)
DBQueryWarn("delete from geni_bindings where user_uuid='$uuid'")
or return -1;
DBQueryWarn("delete from geni_userkeys where user_uuid='$uuid'")
or return -1;
DBQueryWarn("delete from geni_certificates where uuid='$uuid'")
or return -1;
DBQueryWarn("delete from geni_users where idx='$idx'")
......@@ -250,27 +255,53 @@ sub Delete($)
}
#
# Get the sshkey for a user.
# Get the sshkeys for a user.
#
sub GetSSHKey($$)
sub GetSSHKeys($$)
{
my ($self, $pref) = @_;
my @results = ();
return -1
if (! (ref($self) && ref($pref)));
$$pref = undef;
my $uuid = $self->uuid();
my $query_result =
DBQueryWarn("select key from geni_userkeys ".
"where uuid='$uuid' and type='ssh'");
return -1
if (!$query_result);
while (my ($sshkey) = $query_result->fetchrow_array()) {
push(@results, $sshkey);
}
@$pref = @results;
return 0;
}
#
# Get the keys for a user.
#
sub GetKeys($$)
{
my ($self, $pref) = @_;
my @results = ();
return -1
if (! (ref($self) && ref($pref)));
my $uuid = $self->uuid();
my $query_result =
DBQueryWarn("select sshkey from geni_sshkeys where uuid='$uuid'");
DBQueryWarn("select type,key from geni_userkeys ".
"where uuid='$uuid'");
return -1
if (!$query_result);
return 0
if (!$query_result->numrows);
my ($sshkey) = $query_result->fetchrow_array();
$$pref = $sshkey;
while (my ($type,$key) = $query_result->fetchrow_array()) {
push(@results, {"type" => $type,
"key" => $key});
}
@$pref = @results;
return 0;
}
......@@ -284,15 +315,15 @@ sub CreateNonLocal($)
return undef
if (! ref($self));
my $sshkey;
$self->GetSSHKey(\$sshkey);
my @sshkeys = ();
$self->GetSSHKeys(\@sshkeys);
return User::NonLocal->Create($self->idx(),
$self->uid(),
$self->uuid(),
$self->name(),
$self->email(),
$sshkey);
\@sshkeys);
}
#
......@@ -365,8 +396,12 @@ sub Archive($)
# Wrapper for local users.
#
package GeniUser::LocalUser;
use vars qw(@ISA);
@ISA = "GeniUser";
use English;
use GeniDB;
use GeniUser;
use GeniCertificate;
use overload ('""' => 'Stringify');
......@@ -392,12 +427,13 @@ sub Create($$)
return $self;
}
sub idx($) { return $_[0]->{'USER'}->uid_idx(); }
sub uid($) { return $_[0]->{'USER'}->uid(); }
sub uuid { return $_[0]->{'USER'}->uuid(); }
sub created($) { return $_[0]->{'USER'}->created(); }
sub name($) { return $_[0]->{'USER'}->name(); }
sub email($) { return $_[0]->{'USER'}->email(); }
sub GetSSHKey($$) { return $_[0]->{'USER'}->GetSSHKey($_[1]); }
sub GetSSHKeys($$) { return $_[0]->{'USER'}->GetSSHKeys($_[1]); }
# Need to construct this since not in User structure.
sub hrn($) { return $OURDOMAIN . "." . $_[0]->uid(); }
......@@ -416,16 +452,58 @@ sub Register($)
# Register this user at the ClearingHouse, if not already registered.
if (GeniCHClient::LookupUser($self->uuid(), \$blob) != 0) {
my $sshkey;
$self->GetSSHKey(\$sshkey);
my @sliverkeys = ();
$self->GetKeys(\@sliverkeys);
return GeniCHClient::RegisterUser($self->hrn(),
$self->name(), $self->email(),
$self->cert(), $sshkey);
$self->cert(), \@sliverkeys);
}
return 0;
}