Commit 0b324bcd authored by Mike Hibler's avatar Mike Hibler

Merge branch 'master' into arm64

Conflicts:
	clientside/os/imagezip/ffs/disklabel.h
	config.h.in
	configure
	configure.ac
parents c9abc61b f201d7bd
......@@ -10,6 +10,7 @@ clientside/os/imagezip/fat
clientside/os/imagezip/ntfs/liblocale
clientside/lib/event/event_wrap*
clientside/tmcc/cygwinxp/site-lisp
clientside/tmcc/freebsd/init
clientside/tmcc/plab
os/shd
www/cvsweb
......@@ -49,3 +50,8 @@ LGPL-COPYING
AGPL-COPYING
TODO.plab
MOVED-TO-WIKI
VERSION
protogeni/flack/js/forge
protogeni/flack/src/com/hurlant
protogeni/flack/src/com/mattism
protogeni/protogeniflash/src/com/mattism
......@@ -214,7 +214,7 @@ print STDERR Dumper($xmlparse)
if (exists($xmlparse->{'attribute'}->{"genesis"})) {
$genesis = $xmlparse->{'attribute'}->{"genesis"}->{'value'};
delete($xmlparse->{'attribute'}->{"genesis"});
if (! ($genesis eq "aptlab.net" || $genesis eq "cloudlab")) {
if (! ($genesis eq "aptlab" || $genesis eq "cloudlab")) {
fatal("Bad genesis: $genesis");
}
# Remove these, we do not require them on the APT path.
......
......@@ -495,6 +495,14 @@ sub AddUser()
if ($user ne $PROTOUSER && system("$ADDKEY -i $user")) {
fatal("Could not generate initial ssh key for $user");
}
#
# And the mailman lists if enabled. All users must get this cause
# mailman is used for project mail lists. when MAILMANSUPPORT=1
#
system("$ADDMMUSER $user")
if ($MAILMANSUPPORT);
if ($isnonlocal) {
$EUID = 0;
goto skipstuff;
......@@ -543,10 +551,6 @@ sub AddUser()
system("$ADDCHATUSER $user")
if ($CHATSUPPORT && $user ne $PROTOUSER);
# And the mailman lists if enabled.
system("$ADDMMUSER $user")
if ($MAILMANSUPPORT);
# And to the trac system if enabled.
system("$ADDTRACUSER $user")
if ($TRACSUPPORT && $user ne $PROTOUSER);
......
......@@ -1143,7 +1143,7 @@ SSLEngine on
# SSL Protocol support:
# List the enable protocol levels with which clients will be able to
# connect. Disable SSLv2 access by default:
SSLProtocol all -SSLv2
SSLProtocol all -SSLv2 -SSLv3
# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
......
......@@ -1142,7 +1142,7 @@ SSLEngine on
# SSL Protocol support:
# List the enable protocol levels with which clients will be able to
# connect. Disable SSLv2 access by default:
SSLProtocol all -SSLv2
SSLProtocol all -SSLv2 -SSLv3
# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
......
This diff is collapsed.
#!/usr/bin/perl -wT
#
# Copyright (c) 2007-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/>.
#
# }}}
#
package APT_Geni;
use strict;
use English;
use Data::Dumper;
use Carp;
use Exporter;
use vars qw(@ISA @EXPORT $AUTOLOAD);
@ISA = "Exporter";
@EXPORT = qw ( );
# Must come after package declaration!
use EmulabConstants;
use emdb;
use libtestbed;
use GeniCertificate;
use GeniCredential;
# Configure variables
my $TB = "@prefix@";
my $MAINSITE = @TBMAINSITE@;
my $TBOPS = "@TBOPSEMAIL@";
my $SACERT = "$TB/etc/genisa.pem";
#
# Generate the credentials we need.
#
sub GenCredentials($$;$)
{
my ($target, $geniuser, $privs) = @_;
my ($speaksfor, $credential);
my $speaker_signer = $GeniCredential::LOCALSA_FLAG;
#
# Utah; Guest users use the apt CA, and so we must sign the speaksfor
# credential with the APT SA as well so that the target of the
# speaksfor credential is in the same namespace as the signer.
#
if (!$geniuser->IsLocal() && $MAINSITE) {
$speaker_signer = "/usr/testbed/etc/utah-apt.sa";
}
#
# The Utah SA is always the speaker, even if the user is a guest
# with the alternate CA.
#
my $sa_certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($sa_certificate)) {
print STDERR "Could not load certificate from $SACERT\n";
goto bad;
}
my $sa_authority = GeniAuthority->Lookup($sa_certificate->urn());
if (!defined($sa_authority)) {
prnt STDERR "Could not load SA authority object\n";
goto bad;
}
#
# If a local user account, but a nonlocal id, then we should
# have a speaksfor credential stored, as well as a certificate
# for the user.
#
if ($geniuser->IsLocal() && $geniuser->emulab_user()->IsNonLocal()) {
my ($speaksfor_string, $certificate_string) =
$geniuser->emulab_user()->GetStoredCredential();
if (! (defined($speaksfor_string) &&
defined($certificate_string))) {
print STDERR "No stored speaksfor/certificate for $geniuser\n";
goto bad;
}
$speaksfor = GeniCredential->CreateFromSigned($speaksfor_string);
if (!defined($speaksfor)) {
print STDERR "Could not create speaksfor credential\n";
goto bad;
}
my $certificate =
GeniCertificate->LoadFromString($certificate_string);
if (!defined($certificate)) {
print STDERR "Could not load certificate from string\n";
goto bad;
}
$credential = GeniCredential->Create($target, $certificate);
}
else {
$speaksfor = GeniCredential->Create($geniuser, $sa_authority);
if (!defined($speaksfor)) {
print STDERR "Could not create speaksfor credential\n";
goto bad;
}
$speaksfor->SetType("speaksfor");
if ($speaksfor->Sign($speaker_signer)) {
print STDERR "Could not sign speaksfor credential\n";
goto bad;
}
$credential = GeniCredential->Create($target, $geniuser);
}
if (!defined($credential)) {
print STDERR "Could not create credential for $target\n";
goto bad;
}
# Add optional privs.
if (defined($privs)) {
foreach my $priv (@{ $privs }) {
$credential->AddCapability($priv, 0);
}
}
# And sign it.
if ($credential->Sign($GeniCredential::LOCALSA_FLAG) != 0) {
$credential->Delete();
print STDERR "Could not sign $target credential\n";
goto bad;
}
return ($credential, $speaksfor);
bad:
return ();
}
#
# Return the authority object for a URN.
#
sub GetAuthority($)
{
my ($urn) = @_;
my $cm_authority = GeniAuthority->Lookup($urn);
if (!defined($cm_authority)) {
$cm_authority = GeniAuthority->CreateFromRegistry("cm", $urn);
if (!defined($cm_authority)) {
print STDERR "Could not load CM authority object\n";
return undef;
}
}
return $cm_authority;
}
#
# Load the context operate as; always the same for APT.
#
sub GeniContext()
{
my $certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($certificate)) {
print STDERR "Could not load certificate from $SACERT\n";
return undef;
}
return Genixmlrpc->Context($certificate);
}
# _Always_ make sure that this 1 is at the end of the file...
1;
This diff is collapsed.
......@@ -46,7 +46,9 @@ use vars qw(@ISA @EXPORT $AUTOLOAD);
use EmulabConstants;
use emutil;
use emdb;
use APT_Dataset;
use GeniXML;
use GeniHRN;
use libtestbed;
use English;
use Data::Dumper;
......@@ -58,6 +60,14 @@ my $TBOPS = "@TBOPSEMAIL@";
my $debug = 0;
# Concat id/vers.
sub versid($)
{
my ($self) = @_;
return $self->profileid() . ":" . $self->version();
}
sub BlessRow($$)
{
my ($class, $row) = @_;
......@@ -314,6 +324,9 @@ sub Create($$$$$$)
$vquery .= ",parent_profileid=" . $parent->profileid();
$vquery .= ",parent_version=" . $parent->version();
}
if (exists($argref->{'script'}) && $argref->{'script'} ne "") {
$vquery .= ",script=" . DBQuoteSpecial($argref->{'script'});
}
# Back to the main table.
$cquery .= ",uuid='$puuid'";
......@@ -484,8 +497,8 @@ sub Delete($$)
if ($purge) {
goto bad
if (! QueryWarn("delete from apt_profile_versions ".
"where profileid='$profileid'"));
if (! DBQueryWarn("delete from apt_profile_versions ".
"where profileid='$profileid'"));
}
else {
# Set deleted on all of the versions.
......@@ -674,6 +687,53 @@ sub UpdateDiskImage($$)
return 0;
}
#
# Check blockstores.
#
sub CheckDatasets($$$)
{
my ($xml, $project, $pmsg) = @_;
my $rspec = GeniXML::Parse($xml);
if (! defined($rspec)) {
print STDERR "CheckDatasets: Could not parse rspec\n";
return -1;
}
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
foreach my $blockref (GeniXML::FindNodesNS("n:blockstore",
$ref,
$GeniXML::EMULAB_NS)->get_nodelist()) {
my $leaseurn = GeniXML::GetText("persistent", $blockref);
if (defined($leaseurn) && !GeniHRN::IsValid($leaseurn)) {
$$pmsg = "Persistent dataset name is not a valid URN";
return 1;
}
my ($authority, $type, $id) = GeniXML::Parse($leaseurn);
#
# Not all backends have blockstore support.
#
if (!APT_Dataset::ValidBlockstoreBackend($authority)) {
$$pmsg = "Persistent dataset is not on a valid aggregate";
return 1;
}
#
# Dataset must already exists on the aggregate.
#
my $pid = $project->pid();
my $dataset = APT_Dataset->Lookup("$pid/$id");
if (!defined($dataset)) {
$$pmsg = "Persistent dataset '$pid/$id' does not exist";
return 1;
}
my ($d_authority) = GeniXML::Parse($dataset->aggregate_urn());
if ($d_authority ne $authority) {
$$pmsg = "Persistent dataset '$pid/$id' in not on $authority";
return 1;
}
}
}
return 0;
}
sub IsHead($)
{
my ($self) = @_;
......
......@@ -30,15 +30,18 @@ include $(OBJDIR)/Makeconf
SUBDIRS =
BIN_SCRIPTS = manage_profile manage_instance
BIN_SCRIPTS = manage_profile manage_instance manage_dataset \
create_instance rungenilib
SBIN_SCRIPTS =
LIB_SCRIPTS = APT_Profile.pm APT_Instance.pm
WEB_BIN_SCRIPTS = webmanage_profile webmanage_instance
LIB_SCRIPTS = APT_Profile.pm APT_Instance.pm APT_Dataset.pm APT_Geni.pm
WEB_BIN_SCRIPTS = webmanage_profile webmanage_instance webmanage_dataset \
webcreate_instance webrungenilib
WEB_SBIN_SCRIPTS=
LIBEXEC_SCRIPTS = $(WEB_BIN_SCRIPTS) $(WEB_SBIN_SCRIPTS)
USERLIBEXEC = rungenilib.proxy
# These scripts installed setuid, with sudo.
SETUID_BIN_SCRIPTS =
SETUID_BIN_SCRIPTS = rungenilib
SETUID_SBIN_SCRIPTS =
SETUID_SUEXEC_SCRIPTS=
......@@ -47,7 +50,7 @@ SETUID_SUEXEC_SCRIPTS=
# configure if the .in file is changed.
#
all: $(BIN_SCRIPTS) $(SBIN_SCRIPTS) $(LIBEXEC_SCRIPTS) $(SUBDIRS) \
$(LIB_SCRIPTS) all-subdirs
$(LIB_SCRIPTS) $(USERLIBEXEC) all-subdirs
subboss:
......@@ -57,6 +60,8 @@ install: $(addprefix $(INSTALL_BINDIR)/, $(BIN_SCRIPTS)) \
$(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_LIBDIR)/, $(LIB_SCRIPTS)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/libexec/, $(USERLIBEXEC))
boss-install: install install-subdirs
......@@ -89,4 +94,9 @@ clean: clean-subdirs
@$(MAKE) -C $(dir $@) $(basename $(notdir $@))
%-subdirs: $(addsuffix /%.MAKE,$(SUBDIRS)) ;
$(INSTALL_DIR)/opsdir/libexec/%: %
@echo "Installing $<"
-mkdir -p $(INSTALL_DIR)/opsdir/libexec
$(INSTALL) $< $@
.PHONY: $(SUBDIRS) install
This diff is collapsed.
This diff is collapsed.
......@@ -35,19 +35,18 @@ use POSIX qw(setsid);
#
sub usage()
{
print("Usage: manage_profile [-u uuid | -s uuid] <xmlfile>\n");
print("Usage: manage_profile [-r | -p] profile\n");
print("Usage: manage_profile create [-s uuid] <xmlfile>\n");
print("Usage: manage_profile update <profile> <xmlfile>\n");
print("Usage: manage_profile publish <profile>\n");
print("Usage: manage_profile delete <profile>\n");
exit(-1);
}
my $optlist = "du:rs:t:fp";
my $optlist = "ds:t:";
my $debug = 0;
my $verify = 0; # Check data and return status only.
my $update = 0;
my $snap = 0;
my $delete = 0;
my $skipadmin = 0;
my $force = 0; # With delete.
my $uuid;
my $rspec;
my $profile;
my $instance;
my $webtask;
......@@ -56,9 +55,9 @@ my $webtask_id;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $QUICKVM = "$TB/sbin/protogeni/quickvm";
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $MANAGEINSTANCE = "$TB/bin/manage_instance";
#
# Untaint the path
......@@ -85,7 +84,6 @@ use APT_Instance;
use GeniXML;
use GeniHRN;
use WebTask;
use libaudit;
# Protos
sub fatal($);
......@@ -93,6 +91,31 @@ sub UserError(;$);
sub DeleteProfile($);
sub PublishProfile($);
# Parse args below.
if (@ARGV < 2) {
usage();
}
my $action = shift(@ARGV);
# The web interface (and in the future the xmlrpc interface) sets this.
my $this_user = User->ImpliedUser();
if (! defined($this_user)) {
$this_user = User->ThisUser();
if (!defined($this_user)) {
fatal("You ($UID) do not exist!");
}
}
if ($action eq "delete") {
exit(DeleteProfile($ARGV[0]));
}
elsif ($action eq "publish") {
exit(PublishProfile($ARGV[0]));
}
elsif (! ($action eq "create" || $action eq "update")) {
usage();
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
......@@ -104,16 +127,6 @@ if (! getopts($optlist, \%options)) {
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"v"})) {
$verify = 1;
}
if (defined($options{"u"})) {
$update = 1;
$uuid = $options{"u"};
}
if (defined($options{"s"})) {
$snap = 1;
$uuid = $options{"s"};
......@@ -121,27 +134,11 @@ if (defined($options{"s"})) {
if (defined($options{"t"})) {
$webtask_id = $options{"t"};
}
if (@ARGV != 1) {
usage();
}
# The web interface (and in the future the xmlrpc interface) sets this.
my $this_user = User->ImpliedUser();
if (! defined($this_user)) {
$this_user = User->ThisUser();
if (!defined($this_user)) {
fatal("You ($UID) do not exist!");
}
}
# Remove profile.
if (defined($options{"r"})) {
exit(DeleteProfile($ARGV[0]));
}
elsif (defined($options{"p"})) {
exit(PublishProfile($ARGV[0]));
if ($action eq "update") {
$update = 1;
$uuid = shift(@ARGV);
}
my $xmlfile = shift(@ARGV);
my $xmlfile = shift(@ARGV);
#
# These are the fields that we allow to come in from the XMLfile.
......@@ -163,6 +160,7 @@ my %xmlfields =
"profile_public" => ["public", $SLOT_OPTIONAL|$SLOT_UPDATE],
"profile_shared" => ["shared", $SLOT_OPTIONAL|$SLOT_UPDATE],
"rspec" => ["rspec", $SLOT_REQUIRED|$SLOT_UPDATE],
"script" => ["script", $SLOT_OPTIONAL|$SLOT_UPDATE],
);
#
......@@ -233,7 +231,7 @@ foreach $key (keys(%{ $xmlparse->{'attribute'} })) {
$value = $default;
}
}
if ($required & $SLOT_ADMINONLY && !$skipadmin) {
if ($required & $SLOT_ADMINONLY) {
# Admin implies optional, but thats probably not correct approach.
$errors{$key} = "Administrators only"
if (! $this_user->IsAdmin());
......@@ -248,6 +246,10 @@ foreach $key (keys(%{ $xmlparse->{'attribute'} })) {
$new_args{$dbslot} = $value;
$update_args{$dbslot} = $value
if ($update && ($required & $SLOT_UPDATE));
if ($key eq "rspec") {
$rspec = $value;
}
}
UserError()
if (keys(%errors));
......@@ -292,20 +294,29 @@ if ($update) {
delete($update_args{"description"});
#
# If the rspec changed, then make a new version of the profile.
# If the rspec/script changed, then make a new version of the profile.
# Everything else is metadata.
#
if (exists($update_args{"rspec"})) {
if ($update_args{"rspec"} ne $profile->rspec()) {
if (exists($update_args{"rspec"}) || exists($update_args{"script"})) {
if ((exists($update_args{"rspec"}) &&
$update_args{"rspec"} ne $profile->rspec()) ||
(exists($update_args{"script"}) &&
$update_args{"script"} ne $profile->script())) {
if ($this_user->IsAdmin()) {
$profile = $profile->NewVersion($this_user);
if (!defined($profile)) {
fatal("Could not create new version of the profile");
}
}
$profile->UpdateVersion({"rspec" => $update_args{"rspec"}});
$profile->UpdateVersion({"rspec" => $update_args{"rspec"}})
if (exists($update_args{"rspec"}));
$profile->UpdateVersion({"script" => $update_args{"script"}})
if (exists($update_args{"script"}));
}
delete($update_args{"rspec"});
delete($update_args{"rspec"})
if (exists($update_args{"rspec"}));
delete($update_args{"script"})
if (exists($update_args{"script"}));
}
$profile->UpdateMetaData(\%update_args) == 0 or
fatal("Could not update profile record");
......@@ -346,12 +357,16 @@ if (defined($instance)) {
}
my ($node) = GeniXML::FindNodes("n:node", $manifest)->get_nodelist();
my $sliver_urn = GeniXML::GetSliverId($node);
my $node_id = GeniXML::GetVirtualId($node);
my $apt_uuid = $instance->uuid();
my $imagename = $profile->name();
#
# Grab the webtask object so we can watch it. We are looking
# for it to finish, so we can unlock the profile for use.
# for it to finish, so we can unlock the profile for use. Note
# this always creates a webtask, even if not directed to on the
# commmand line, so that we can communicate with the script we
# call that does the work.
#
$webtask = WebTask->Create($profile->uuid(), $webtask_id);
if (!defined($webtask)) {
......@@ -364,34 +379,32 @@ if (defined($instance)) {
fatal("Could not lock new profile");
}
my $command = "$QUICKVM " . ($webtask_id ? "-t $webtask_id " : " ") .
"-s $apt_uuid $sliver_urn $imagename";
my $command = "$MANAGEINSTANCE -t " . $webtask->task_id() . " ".
"snapshot $apt_uuid $imagename $node_id";
#
# This returns pretty fast, and then the imaging takes place in
# the background at the aggregate. quickvm keeps a process running
# in the background waiting for the sliver to unlock and the
# sliverstatus to indicate the node is running again.
# the background at the aggregate. The script keeps a process
# running in the background waiting for the sliver to unlock and
# the sliverstatus to indicate the node is running again.
#
my $output = emutil::ExecQuiet($command);
if ($?) {
$profile->Delete(1);
$webtask->Delete();
$webtask->Delete()
if (!defined($webtask_id));