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($$$) ...@@ -1178,6 +1178,36 @@ sub EncryptBlocks($$$)
return 0; 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($) sub IsHead($)
{ {
my ($self) = @_; my ($self) = @_;
......
...@@ -247,7 +247,7 @@ fatal($@) ...@@ -247,7 +247,7 @@ fatal($@)
# #
# Make sure all the required arguments were provided. # 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'") fatal("Missing required attribute '$key'")
if (! (exists($xmlparse->{'attribute'}->{"$key"}) && if (! (exists($xmlparse->{'attribute'}->{"$key"}) &&
defined($xmlparse->{'attribute'}->{"$key"}) && defined($xmlparse->{'attribute'}->{"$key"}) &&
...@@ -258,7 +258,11 @@ foreach my $key ("username", "email", "profile") { ...@@ -258,7 +258,11 @@ foreach my $key ("username", "email", "profile") {
# Gather up args and sanity check. # Gather up args and sanity check.
# #
my ($value, $user_urn, $user_uid, $user_hrn, $user_email, $project, $pid, 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. # Username and email has to be acceptable to Emulab user system.
...@@ -687,6 +691,20 @@ $tmp = APT_Profile::EncryptBlocks(\$rspecstr, $alt_certificate, \$errmsg); ...@@ -687,6 +691,20 @@ $tmp = APT_Profile::EncryptBlocks(\$rspecstr, $alt_certificate, \$errmsg);
if ($tmp) { if ($tmp) {
($tmp < 0 ? fatal($errmsg) : UserError($errmsg)); ($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. # Generate credentials we need.
......
...@@ -770,6 +770,13 @@ sub GetTicketAuxAux($$$$$$$$$$$) ...@@ -770,6 +770,13 @@ sub GetTicketAuxAux($$$$$$$$$$$)
# #
my $packing_option = GeniXML::PackingStrategy($rspec); 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. # Add global vtypes.
# #
...@@ -834,8 +841,29 @@ sub GetTicketAuxAux($$$$$$$$$$$) ...@@ -834,8 +841,29 @@ sub GetTicketAuxAux($$$$$$$$$$$)
$virtexperiment->multiplex_factor(2); $virtexperiment->multiplex_factor(2);
} }
} }
#
# Note that we set the mounts to "genidefault" when we create the
# container experiment. So this overrides.
#
if ($PROTOGENI_NONFSMOUNTS) { if ($PROTOGENI_NONFSMOUNTS) {
$virtexperiment->nonfsmounts(1); $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($$$$$$$$$$$) ...@@ -1743,6 +1771,8 @@ sub GetTicketAuxAux($$$$$$$$$$$)
# #
if ($fwsettings->{'style'} eq "closed") { if ($fwsettings->{'style'} eq "closed") {
$virtexperiment->nonfsmounts(1); $virtexperiment->nonfsmounts(1);
# This is the new way of doing things.
$virtexperiment->nfsmounts("none");
} }
my $ruleno = 0; my $ruleno = 0;
foreach my $exception (@{ $fwsettings->{'exceptions'} }) { foreach my $exception (@{ $fwsettings->{'exceptions'} }) {
...@@ -6700,7 +6730,8 @@ sub GeniExperiment($;$) ...@@ -6700,7 +6730,8 @@ sub GeniExperiment($;$)
} }
$experiment = Experiment->Lookup($uuid); $experiment = Experiment->Lookup($uuid);
$experiment->SetState(EXPTSTATE_SWAPPED()); $experiment->SetState(EXPTSTATE_SWAPPED());
$experiment->Update({"geniflags" => $Experiment::EXPT_GENIFLAGS_EXPT}); $experiment->Update({"geniflags" => $Experiment::EXPT_GENIFLAGS_EXPT,
"nfsmounts" => "genidefault"});
$experiment->TableUpdate("experiment_stats", $experiment->TableUpdate("experiment_stats",
"geniflags='$Experiment::EXPT_GENIFLAGS_EXPT', ". "geniflags='$Experiment::EXPT_GENIFLAGS_EXPT', ".
"slice_uuid='$uuid'"); "slice_uuid='$uuid'");
......
...@@ -910,6 +910,40 @@ sub MultiplexFactor($) ...@@ -910,6 +910,40 @@ sub MultiplexFactor($)
return undef; 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($) sub PackingStrategy($)
{ {
my ($rspec) = @_; my ($rspec) = @_;
......
...@@ -257,7 +257,7 @@ typedef struct { ...@@ -257,7 +257,7 @@ typedef struct {
int swapper_isadmin; int swapper_isadmin;
int genisliver_idx; int genisliver_idx;
int geniflags; int geniflags;
int nonfsmounts; char nfsmounts[TBDB_FLEN_TINYTEXT];
unsigned int taintstates; unsigned int taintstates;
char nodeid[TBDB_FLEN_NODEID]; char nodeid[TBDB_FLEN_NODEID];
char vnodeid[TBDB_FLEN_NODEID]; char vnodeid[TBDB_FLEN_NODEID];
...@@ -3250,15 +3250,15 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -3250,15 +3250,15 @@ COMMAND_PROTOTYPE(doaccounts)
goto skipkeys; goto skipkeys;
/* /*
* Skip pubkeys locally unless the node/experiment has * Skip pubkeys locally unless the node/experiment has no
* no shared mounts (nonfsmounts), is a GENI sliver * shared mounts, is a GENI sliver (no /users mounts). is
* (genisliver_idx), is running Windows ("windows" arg), * running Windows ("windows" arg), or explicitly asks for
* or explicitly asks for them ("pubkeys" arg). * them ("pubkeys" arg).
*/ */
#ifndef NOSHAREDFS #ifndef NOSHAREDFS
if (reqp->islocal && if (reqp->islocal &&
! reqp->nonfsmounts && ! (strcmp(reqp->nfsmounts, "none") == 0 ||
! reqp->genisliver_idx && strcmp(reqp->nfsmounts, "genidefault") == 0) &&
! reqp->sharing_mode[0] && ! reqp->sharing_mode[0] &&
! (strncmp(rdata, "pubkeys", 7) == 0 ! (strncmp(rdata, "pubkeys", 7) == 0
|| strncmp(rdata, "windows", 7) == 0)) || strncmp(rdata, "windows", 7) == 0))
...@@ -3417,8 +3417,10 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -3417,8 +3417,10 @@ COMMAND_PROTOTYPE(doaccounts)
* on a pnode, but lets be careful. * on a pnode, but lets be careful.
* *
* No more accounts will be added if the node has 'blackbox' taint. * 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 && if (reqp->genisliver_idx && !didnonlocal &&
strcmp(reqp->nfsmounts, "emulabdefault") &&
(reqp->isvnode || !reqp->sharing_mode[0]) && (reqp->isvnode || !reqp->sharing_mode[0]) &&
!HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX)) { !HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX)) {
didnonlocal = 1; didnonlocal = 1;
...@@ -3980,7 +3982,7 @@ COMMAND_PROTOTYPE(dorpms) ...@@ -3980,7 +3982,7 @@ COMMAND_PROTOTYPE(dorpms)
#ifdef NOVIRTNFSMOUNTS #ifdef NOVIRTNFSMOUNTS
useweb = 1; useweb = 1;
#endif #endif
if (reqp->nonfsmounts || if ((strcmp(reqp->nfsmounts, "none") == 0) ||
(reqp->sharing_mode[0] && reqp->isvnode)) { (reqp->sharing_mode[0] && reqp->isvnode)) {
useweb = 1; useweb = 1;
} }
...@@ -4059,7 +4061,7 @@ COMMAND_PROTOTYPE(dotarballs) ...@@ -4059,7 +4061,7 @@ COMMAND_PROTOTYPE(dotarballs)
#ifdef NOVIRTNFSMOUNTS #ifdef NOVIRTNFSMOUNTS
useweb = 1; useweb = 1;
#endif #endif
if (reqp->nonfsmounts || if ((strcmp(reqp->nfsmounts, "none") == 0) ||
(reqp->sharing_mode[0] && reqp->isvnode)) { (reqp->sharing_mode[0] && reqp->isvnode)) {
useweb = 1; useweb = 1;
} }
...@@ -4861,12 +4863,14 @@ COMMAND_PROTOTYPE(domounts) ...@@ -4861,12 +4863,14 @@ COMMAND_PROTOTYPE(domounts)
char buf[MYBUFSIZE]; char buf[MYBUFSIZE];
char *bufp, *ebufp = &buf[sizeof(buf)]; char *bufp, *ebufp = &buf[sizeof(buf)];
int nrows, usesfs; int nrows, usesfs;
int nomounts = reqp->nonfsmounts; int nomounts = 0;
char *fsnode = FSNODE; char *fsnode = FSNODE;
#ifdef ISOLATEADMINS #ifdef ISOLATEADMINS
int isadmin; int isadmin;
#endif #endif
if (strcmp(reqp->nfsmounts, "none") == 0) {
nomounts = 1;
}
/* /*
* Do we export filesystems at all? * Do we export filesystems at all?
*/ */
...@@ -5234,10 +5238,11 @@ COMMAND_PROTOTYPE(domounts) ...@@ -5234,10 +5238,11 @@ COMMAND_PROTOTYPE(domounts)
} }
/* /*
* Remote nodes do not get per-user mounts. * 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. * 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)) HAS_TAINT(reqp->taintstates, TB_TAINTSTATE_BLACKBOX))
return 0; return 0;
...@@ -7416,7 +7421,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7416,7 +7421,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, " " r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,n.uuid, " " r.sharing_mode,e.geniflags,n.uuid, "
" n.nonfsmounts,e.nonfsmounts AS enonfs, " " 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 " "FROM nodes AS n "
"LEFT JOIN reserved AS r ON " "LEFT JOIN reserved AS r ON "
" r.node_id=n.node_id " " r.node_id=n.node_id "
...@@ -7445,7 +7451,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7445,7 +7451,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" (SELECT node_id FROM widearea_nodeinfo " " (SELECT node_id FROM widearea_nodeinfo "
" WHERE privkey='%s') " " WHERE privkey='%s') "
" AND notmcdinfo_types.attrvalue IS NULL", " AND notmcdinfo_types.attrvalue IS NULL",
39, nodekey); 41, nodekey);
} }
else if (reqp->isvnode) { else if (reqp->isvnode) {
char clause[BUFSIZ]; char clause[BUFSIZ];
...@@ -7482,7 +7488,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7482,7 +7488,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, " " r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,nv.uuid, " " r.sharing_mode,e.geniflags,nv.uuid, "
" nv.nonfsmounts,e.nonfsmounts AS enonfs, " " 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 " "from nodes as nv "
"left join nodes as np on " "left join nodes as np on "
" np.node_id=nv.phys_nodeid " " np.node_id=nv.phys_nodeid "
...@@ -7503,7 +7510,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7503,7 +7510,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
"left join users as u on " "left join users as u on "
" u.uid_idx=e.swapper_idx " " u.uid_idx=e.swapper_idx "
"where nv.node_id='%s' and (%s)", "where nv.node_id='%s' and (%s)",
39, reqp->vnodeid, clause); 41, reqp->vnodeid, clause);
} }
else { else {
char clause[BUFSIZ]; char clause[BUFSIZ];
...@@ -7533,7 +7540,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7533,7 +7540,8 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" r.genisliver_idx,r.tmcd_redirect, " " r.genisliver_idx,r.tmcd_redirect, "
" r.sharing_mode,e.geniflags,n.uuid, " " r.sharing_mode,e.geniflags,n.uuid, "
" n.nonfsmounts,e.nonfsmounts AS enonfs, " " 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 " "from interfaces as i "
"left join nodes as n on n.node_id=i.node_id " "left join nodes as n on n.node_id=i.node_id "
"left join reserved as r on " "left join reserved as r on "
...@@ -7561,7 +7569,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7561,7 +7569,7 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
" on n.type=dedicated_wa_types.type " " on n.type=dedicated_wa_types.type "
"where (%s) " "where (%s) "
" and notmcdinfo_types.attrvalue is NULL", " and notmcdinfo_types.attrvalue is NULL",
39, clause); 41, clause);
} }
if (!res) { if (!res) {
...@@ -7686,13 +7694,13 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey) ...@@ -7686,13 +7694,13 @@ iptonodeid(struct in_addr ipaddr, tmcdreq_t *reqp, char* nodekey)
reqp->iscontrol = (! strcasecmp(row[10], "ctrlnode") ? 1 : 0); reqp->iscontrol = (! strcasecmp(row[10], "ctrlnode") ? 1 : 0);
/* nonfsmounts - per-experiment disable overrides per-node setting */ /* nfsmounts - per-experiment disable overrides per-node setting */
if (row[36] && atoi(row[36]) != 0) if (strcmp(row[40], "none") == 0)
reqp->nonfsmounts = atoi(row[36]); strcpy(reqp->nfsmounts, "none");
else if (row[35]) else if (row[39])
reqp->nonfsmounts = atoi(row[35]); strcpy(reqp->nfsmounts, row[39]);
else else
reqp->nonfsmounts = 0; strcpy(reqp->nfsmounts, row[40]);
/* taintstates - find the strings and set the bits. */ /* taintstates - find the strings and set the bits. */
reqp->taintstates = 0; 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