Commit e369c1a8 authored by Leigh Stoller's avatar Leigh Stoller

NFS mount changes, still a work in progress, bound to change:

* The Emulab portal now adds a toplevel element (Emulab namespace)
  directing the CM to use standard emulab mounts (read: /users).
  We clear that element from the other portals.

* The CM looks for that tag, and allows it only if the caller is the local
  SA. The default for nfsmounts setting for geni experiment containers is
  "genidefault", but that is set to "emulabdefault" when allowed.

* tmcd changes; no using nfsmounts slot instead of nonfsmounts. "none"
  means no mounts (duh), "emulabdefault" means standard mounts we all know
  and love, "genidefault" means no /users mounts.

  In addition, when we are doing emulabdefault mounts on a geni experiment
  node, we do not return accounts that are specified in the rspec, but
  rather we return the local project accounts only.
parent eb939e55
......@@ -1178,6 +1178,36 @@ sub EncryptBlocks($$$)
return 0;
}
#
# Add a portal element.
#
sub AddPortalTag($$$)
{
my ($pxml, $tag, $pmsg) = @_;
my $rspec = GeniXML::Parse($$pxml);
if (! defined($rspec)) {
$$pmsg = "AddPortalTag: Could not parse rspec";
return -1;
}
GeniXML::SetPortal($rspec, $tag);
$$pxml = GeniXML::Serialize($rspec);
return 0;
}
sub ClearPortalTag($$)
{
my ($pxml, $pmsg) = @_;
my $rspec = GeniXML::Parse($$pxml);
if (! defined($rspec)) {
$$pmsg = "AddPortalTag: Could not parse rspec";
return -1;
}
GeniXML::ClearPortal($rspec);
$$pxml = GeniXML::Serialize($rspec);
return 0;
}
sub IsHead($)
{
my ($self) = @_;
......
......@@ -247,7 +247,7 @@ fatal($@)
#
# Make sure all the required arguments were provided.
#
foreach my $key ("username", "email", "profile") {
foreach my $key ("username", "email", "profile", "portal") {
fatal("Missing required attribute '$key'")
if (! (exists($xmlparse->{'attribute'}->{"$key"}) &&
defined($xmlparse->{'attribute'}->{"$key"}) &&
......@@ -258,7 +258,11 @@ foreach my $key ("username", "email", "profile") {
# Gather up args and sanity check.
#
my ($value, $user_urn, $user_uid, $user_hrn, $user_email, $project, $pid,
$sshkey, $profile, $profileid, $version, $rspecstr, $errmsg, $userslice_id);
$sshkey, $profile, $profileid, $version, $rspecstr, $errmsg,
$userslice_id, $portal);
# This is used internally to determine which portal was used.
$portal = $xmlparse->{'attribute'}->{"portal"}->{'value'};
#
# Username and email has to be acceptable to Emulab user system.
......@@ -687,6 +691,20 @@ $tmp = APT_Profile::EncryptBlocks(\$rspecstr, $alt_certificate, \$errmsg);
if ($tmp) {
($tmp < 0 ? fatal($errmsg) : UserError($errmsg));
}
#
# Tell the CM to do normal NFS mounts if this is the "Emulab" portal
# making the request. The CM is of course free to ignore this.
#
# XXX Need to handle this differently if we use the stitcher.
#
if ($portal ne "emulab") {
if (APT_Profile::ClearPortalTag(\$rspecstr, $errmsg)) {
fatal($errmsg);
}
}
elsif (APT_Profile::AddPortalTag(\$rspecstr, $portal, $errmsg)) {
fatal($errmsg);
}
#
# Generate credentials we need.
......
......@@ -770,6 +770,13 @@ sub GetTicketAuxAux($$$$$$$$$$$)
#
my $packing_option = GeniXML::PackingStrategy($rspec);
#
# Look for top level NFS mounts directive, which is used to maintain
# compatibility with Emulab Classic users; when we receive this
# directive *and* PROTOGENI_LOCALUSER=1, then we can do mounts the
# way Emulab users expect (they get a shared home directory).
#
#
# Add global vtypes.
#
......@@ -834,8 +841,29 @@ sub GetTicketAuxAux($$$$$$$$$$$)
$virtexperiment->multiplex_factor(2);
}
}
#
# Note that we set the mounts to "genidefault" when we create the
# container experiment. So this overrides.
#
if ($PROTOGENI_NONFSMOUNTS) {
$virtexperiment->nonfsmounts(1);
# This is the new way of doing things.
$virtexperiment->nfsmounts("none");
}
elsif (GeniXML::FromEmulabPortal($rspec) && $PROTOGENI_LOCALUSER) {
#
# By not setting, we get standard emulab mounts which include
# /users. Not sure if I want to explictly set this.
#
# But we do not let anyone do this, at the moment only the local
# SA can do that, which means the authority that contacted us
# must be our SA. Not even users from our SA can specify this.
#
my $hrn = GeniHRN->new($ENV{"GENIURN"});
if (defined($hrn) &&
$hrn->domain() eq $OURDOMAIN && $hrn->IsSA()) {
$virtexperiment->nfsmounts("emulabdefault");
}
}
#
......@@ -1743,6 +1771,8 @@ sub GetTicketAuxAux($$$$$$$$$$$)
#
if ($fwsettings->{'style'} eq "closed") {
$virtexperiment->nonfsmounts(1);
# This is the new way of doing things.
$virtexperiment->nfsmounts("none");
}
my $ruleno = 0;
foreach my $exception (@{ $fwsettings->{'exceptions'} }) {
......@@ -6700,7 +6730,8 @@ sub GeniExperiment($;$)
}
$experiment = Experiment->Lookup($uuid);
$experiment->SetState(EXPTSTATE_SWAPPED());
$experiment->Update({"geniflags" => $Experiment::EXPT_GENIFLAGS_EXPT});
$experiment->Update({"geniflags" => $Experiment::EXPT_GENIFLAGS_EXPT,
"nfsmounts" => "genidefault"});
$experiment->TableUpdate("experiment_stats",
"geniflags='$Experiment::EXPT_GENIFLAGS_EXPT', ".
"slice_uuid='$uuid'");
......
......@@ -910,6 +910,40 @@ sub MultiplexFactor($)
return undef;
}
sub FromEmulabPortal($)
{
my ($rspec) = @_;
my $element = FindNodesNS("n:portal", $rspec, $EMULAB_NS)->pop();
if (defined($element)) {
my $which = GetText("name", $element);
return 1
if (defined($which) && $which eq "emulab");
}
return 0;
}
sub SetPortal($$)
{
my ($rspec, $portal) = @_;
my $element = FindNodesNS("n:portal", $rspec, $EMULAB_NS)->pop();
if (!defined($element)) {
$element = AddElement("portal", $rspec, $EMULAB_NS);
}
SetText("name", $element, $portal);
return 0;
}
sub ClearPortal($)
{
my ($rspec) = @_;
my $element = FindNodesNS("n:portal", $rspec, $EMULAB_NS)->pop();
if (defined($element)) {
$rspec->removeChild($element);
}
return 0;
}
sub PackingStrategy($)
{
my ($rspec) = @_;
......
......@@ -257,7 +257,7 @@ typedef struct {
int swapper_isadmin;
int genisliver_idx;
int geniflags;
int nonfsmounts;
char nfsmounts[TBDB_FLEN_TINYTEXT];
unsigned int taintstates;
char nodeid[TBDB_FLEN_NODEID];
char vnodeid[TBDB_FLEN_NODEID];
......@@ -3250,15 +3250,15 @@ COMMAND_PROTOTYPE(doaccounts)
goto skipkeys;
/*
* Skip pubkeys locally unless the node/experiment has
* no shared mounts (nonfsmounts), is a GENI sliver
* (genisliver_idx), is running Windows ("windows" arg),
* or explicitly asks for them ("pubkeys" arg).
* Skip pubkeys locally unless the node/experiment has no
* shared mounts, is a GENI sliver (no /users mounts). is
* running Windows ("windows" arg), or explicitly asks for
* them ("pubkeys" arg).
*/
#ifndef NOSHAREDFS
if (reqp->islocal &&
! reqp->nonfsmounts &&
! reqp->genisliver_idx &&
! (strcmp(reqp->nfsmounts, "none") == 0 ||
strcmp(reqp->nfsmounts, "genidefault") == 0) &&
! reqp->sharing_mode[0] &&
! (strncmp(rdata, "pubkeys", 7) == 0
|| strncmp(rdata, "windows", 7) == 0))
......@@ -3417,8 +3417,10 @@ COMMAND_PROTOTYPE(doaccounts)
* on a pnode, but lets be careful.
*
* No more accounts will be added if the node has 'blackbox' taint.
* If nfsmounts=emulabdefault, then we use the local users only.
*/
if (reqp->genisliver_idx && !didnonlocal &&
strcmp(reqp->nfsmounts, "emulabdefault") &&
(reqp->isvnode || !reqp->sharing_mode[0]) &&
!HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX)) {
didnonlocal = 1;
......@@ -3980,7 +3982,7 @@ COMMAND_PROTOTYPE(dorpms)
#ifdef NOVIRTNFSMOUNTS
useweb = 1;
#endif
if (reqp->nonfsmounts ||
if ((strcmp(reqp->nfsmounts, "none") == 0) ||
(reqp->sharing_mode[0] && reqp->isvnode)) {
useweb = 1;
}
......@@ -4059,7 +4061,7 @@ COMMAND_PROTOTYPE(dotarballs)
#ifdef NOVIRTNFSMOUNTS
useweb = 1;
#endif
if (reqp->nonfsmounts ||
if ((strcmp(reqp->nfsmounts, "none") == 0) ||
(reqp->sharing_mode[0] && reqp->isvnode)) {
useweb = 1;
}
......@@ -4861,12 +4863,14 @@ COMMAND_PROTOTYPE(domounts)
char buf[MYBUFSIZE];
char *bufp, *ebufp = &buf[sizeof(buf)];
int nrows, usesfs;
int nomounts = reqp->nonfsmounts;
int nomounts = 0;
char *fsnode = FSNODE;
#ifdef ISOLATEADMINS
int isadmin;
#endif
if (strcmp(reqp->nfsmounts, "none") == 0) {
nomounts = 1;
}
/*
* Do we export filesystems at all?
*/
......@@ -5234,10 +5238,11 @@ COMMAND_PROTOTYPE(domounts)
}
/*
* Remote nodes do not get per-user mounts.
* ProtoGeni nodes do not get them either.
* Geni nodes do not get them either.
* Nodes tainted with 'blackbox' do not get them either.
*/
if (!reqp->islocal || reqp->genisliver_idx ||
if (!reqp->islocal ||
!strcmp(reqp->nfsmounts, "genidefault") ||
HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX))
return 0;
......@@ -7416,7 +7421,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,n.uuid, "
" n.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole, n.taint_states "
" r.erole, n.taint_states, "
" n.nfsmounts,e.nfsmounts AS enfsmounts "
"FROM nodes AS n "
"LEFT JOIN reserved AS r ON "
" r.node_id=n.node_id "
......@@ -7445,7 +7451,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" (SELECT node_id FROM widearea_nodeinfo "
" WHERE privkey='%s') "
" AND notmcdinfo_types.attrvalue IS NULL",
39, nodekey);
41, nodekey);
}
else if (reqp->isvnode) {
char clause[BUFSIZ];
......@@ -7482,7 +7488,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,nv.uuid, "
" nv.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole, nv.taint_states "
" r.erole, nv.taint_states, "
" nv.nfsmounts,e.nfsmounts AS enfsmounts "
"from nodes as nv "
"left join nodes as np on "
" np.node_id=nv.phys_nodeid "
......@@ -7503,7 +7510,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
"left join users as u on "
" u.uid_idx=e.swapper_idx "
"where nv.node_id='%s' and (%s)",
39, reqp->vnodeid, clause);
41, reqp->vnodeid, clause);
}
else {
char clause[BUFSIZ];
......@@ -7533,7 +7540,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,n.uuid, "
" n.nonfsmounts,e.nonfsmounts AS enonfs, "
" r.erole, n.taint_states "
" r.erole, n.taint_states, "
" n.nfsmounts,e.nfsmounts AS enfsmounts "
"from interfaces as i "
"left join nodes as n on n.node_id=i.node_id "
"left join reserved as r on "
......@@ -7561,7 +7569,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" on n.type=dedicated_wa_types.type "
"where (%s) "
" and notmcdinfo_types.attrvalue is NULL",
39, clause);
41, clause);
}
if (!res) {
......@@ -7686,13 +7694,13 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
reqp->iscontrol = (! strcasecmp(row[10], "ctrlnode") ? 1 : 0);
/* nonfsmounts - per-experiment disable overrides per-node setting */
if (row[36] && atoi(row[36]) != 0)
reqp->nonfsmounts = atoi(row[36]);
else if (row[35])
reqp->nonfsmounts = atoi(row[35]);
/* nfsmounts - per-experiment disable overrides per-node setting */
if (strcmp(row[40], "none") == 0)
strcpy(reqp->nfsmounts, "none");
else if (row[39])
strcpy(reqp->nfsmounts, row[39]);
else
reqp->nonfsmounts = 0;
strcpy(reqp->nfsmounts, row[40]);
/* taintstates - find the strings and set the bits. */
reqp->taintstates = 0;
......
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