<> <> <> <> <> <<>> DIRECTORY Atom, Basics, BasicTime, Commander, CommandTool, ComputeClient, ComputeServerClient, ComputeClientInternal, ComputeServerControllerRpcControl, ComputeUtils, Convert, DFUtilities, FileNames, FS, IO, ProcessProps, Pup USING [Address, nullSocket], PupName USING [AddressToRope, Error, NameLookup], Real, Rope, RPC; ComputeClientControllerCmdsImpl: CEDAR MONITOR IMPORTS BasicTime, Commander, CommandTool, ComputeClientInternal, ComputeServerControllerRpcControl, ComputeUtils, Convert, DFUtilities, FileNames, FS, IO, PupName, Rope, RPC EXPORTS ComputeClient = BEGIN <> ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <> SubmitPackage: Commander.CommandProc = { <> <<1) Insure .df file has a global attachment >> <<2) Process the .df file, and extract the .remoteCommands and .summonerload files, and build a list of all the exported file.>> <<3) open remoteCommands file. Check that it parses OK and is reasonable.>> <<4) open summonerload file. Check packages in summonerload for export in the .df file, and check to see that the files with these create dates exist.>> <<5) Take package bcd and generate IMPORTs. Check against list of good imports. Complain if needed. (this should be done on the controller, and be protected, but I trust people) This is a noop for now, however.>> <<6) Tell the controller about the new package.>> argv: CommandTool.ArgumentVector; fileName: ROPE; cleanFName, package: ROPE; fullDFFName: ROPE; fullDFcp: FS.ComponentPositions; attachedFile: ROPE; dfLog: IO.STREAM _ IO.ROS[]; dfLogRope: ROPE _ NIL; controllerError: BOOL _ FALSE; tryDifferentController: BOOL _ FALSE; controllerMsg: ROPE _ NIL; lastDir: REF DFUtilities.DirectoryItem _ NIL; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; remoteCommands: ROPE _ NIL; fullNameOfRemoteCommands: ROPE _ NIL; summonerLoad: ROPE _ NIL; fullNameOfSummonerLoad: ROPE _ NIL; packageDFStream: IO.STREAM; mainDFFileCreated: BasicTime.GMT; noIERRyet: BOOL _ TRUE; exportedFilesList: LIST OF exportedFiles _ NIL; exportedFiles: TYPE = RECORD [ path1: ROPE _ NIL, included: BOOL _ FALSE, file: REF DFUtilities.FileItem _ NIL, name: ROPE ]; { -- nest to get the EXIT to see variables DoOneItemFromDFFile: DFUtilities.ProcessItemProc = { <> errors, warnings, filesActedUpon: INT _ 0; WITH item SELECT FROM dir: REF DFUtilities.DirectoryItem => { lastDir _ dir; }; imports: REF DFUtilities.ImportsItem => { importsCreated: BasicTime.GMT; [created: importsCreated] _ FS.FileInfo[name: imports.path1, remoteCheck: TRUE ! FS.Error => { ERROR DFUtilities.SyntaxError[Rope.Cat["Imported df file ", imports.path1, " does not exist on the file server"]]; }; ]; IF BasicTime.Period[from: mainDFFileCreated, to: importsCreated] > 0 THEN { cmd.out.PutRope[Rope.Cat["Warning: Imported df file ", imports.path1, " newer than package df file.\n"]]; IF noIERRyet THEN { cmd.out.PutRope["Bringover the package df file and see if new attachments are made for interfaces. If so, rebuild, smodel and submit the package. If no interfaces have changed but there are newer implementations (packages in the summonerLoad file), then a package you depend on has changed. Edit the package df file (replace a space with a space), smodel it, and submit the package."]; }; noIERRyet _ FALSE; }; IF imports.exported THEN { IF imports.form # list THEN { RETURN[FALSE]; }; FOR i:NAT IN [0..imports.list.nEntries) DO using: DFUtilities.UsingEntry = imports.list[i]; exportedFilesList _ CONS[[path1: imports.path1, name: using.name, included: TRUE], exportedFilesList]; ENDLOOP; }; }; comment: REF DFUtilities.CommentItem => { }; white: REF DFUtilities.WhiteSpaceItem => { }; file: REF DFUtilities.FileItem => { shortName: ROPE = Rope.Substr[file.name, 0, Rope.Index[s1: file.name, s2: "!"]]; IF lastDir = NIL THEN ERROR DFUtilities.SyntaxError["no directory item before files"] ELSE { IF lastDir.exported THEN exportedFilesList _ CONS[[path1: lastDir.path1, file: file, included: FALSE], exportedFilesList]; }; IF Rope.Equal[remoteCommands, shortName, FALSE] THEN fullNameOfRemoteCommands _ Rope.Concat[exportedFilesList.first.path1, exportedFilesList.first.file.name]; IF Rope.Equal[summonerLoad, shortName, FALSE] THEN fullNameOfSummonerLoad _ Rope.Concat[exportedFilesList.first.path1, exportedFilesList.first.file.name]; }; ENDCASE; }; checkSummonerRemoteCommands: PROC RETURNS [good: BOOL _ TRUE] = { fileName: ROPE = fullNameOfRemoteCommands ; packageListStream: IO.STREAM; maintainer: LIST OF ROPE _ NIL; commands: LIST OF ROPE _ NIL; version: LIST OF ROPE _ NIL; count: INT _ 0 ; IF fileName = NIL THEN {msg _ "no remoteCommands file in DF file"; RETURN[FALSE]}; packageListStream _ FS.StreamOpen[fileName ! FS.Error => GOTO cantOpen]; DO token: ROPE _ NIL; tokens, tail: LIST OF ROPE _ NIL; key: ROPE _ NIL; token _ ComputeUtils.LocalToken[packageListStream, TRUE]; IF (key _ token) = NIL THEN EXIT; SELECT ComputeUtils.SkipWhite[packageListStream] FROM ': => [] _ packageListStream.GetChar[]; -- flush the ': ENDCASE => { <> DO IF packageListStream.GetChar[ ! IO.EndOfStream => EXIT] = '\n THEN EXIT; ENDLOOP; <> LOOP; }; DO list: LIST OF ROPE _ NIL; token _ ComputeUtils.LocalToken[packageListStream]; IF token = NIL THEN EXIT; list _ LIST[token]; IF tail = NIL THEN {tail _ tokens _ list} ELSE {tail.rest _ list; tail _ list}; ENDLOOP; <> SELECT TRUE FROM Rope.Equal[key, "version", FALSE] => { IF tail = NIL THEN {version _ tokens} ELSE {tail.rest _ version; version _ tokens}; }; Rope.Equal[key, "maintainer", FALSE] => { IF tail = NIL THEN {maintainer _ tokens} ELSE {tail.rest _ maintainer; maintainer _ tokens}; }; Rope.Equal[key, "commands", FALSE] => { IF tail = NIL THEN {commands _ tokens} ELSE {tail.rest _ commands; commands _ tokens}; }; Rope.Equal[key, "exclusive", FALSE] => { IF tail = NIL OR tail # tokens THEN { msg _ "exactly one parameter needed for exclusive in .remoteCommands file"; RETURN [FALSE]; } ELSE { SELECT ComputeUtils.trueOrFalse[tail.first] FROM true => {}; false => {}; ENDCASE => { msg _ "invalid parameter for exclusive in .remoteCommands file"; RETURN [FALSE]; }; }; }; Rope.Equal[key, "countActive", FALSE] => { IF tail = NIL OR tail # tokens THEN { msg _ "exactly one parameter needed for countActive in .remoteCommands file"; RETURN [FALSE]; } ELSE { count : INT; bad: BOOL _ FALSE; count _ Convert.IntFromRope[tail.first ! Convert.Error => {bad _ TRUE; CONTINUE}]; IF bad THEN { msg _ "bad parameter for countActive in .remoteCommands file"; RETURN [FALSE]; }; IF count <= 0 THEN { msg _ "count <= 0 for countActive in .remoteCommands file"; RETURN [FALSE]; }; }; }; ENDCASE => { allWhitespace: BOOL _ FALSE; tokenKind: IO.TokenKind _ tokenERROR; [tokenKind: tokenKind] _ IO.GetCedarTokenRope[IO.RIS[key] ! IO.EndOfStream => { allWhitespace _ TRUE; CONTINUE; }; IO.Error => { CONTINUE; }; ]; IF tokenKind = tokenEOF OR tokenKind = tokenCOMMENT THEN allWhitespace _ TRUE; IF ~allWhitespace THEN { packageListStream.Close[]; msg _ Rope.Concat[key, " is an unknown keyword in the remoteCommands file"]; RETURN [FALSE]; }; }; ENDLOOP; -- for that DO way back up there IF commands = NIL THEN { packageListStream.Close[]; msg _ "no commands specified in .remoteCommands file"; RETURN [FALSE]; }; packageListStream.Close[]; EXITS cantOpen => { msg _ "cannot open .remoteCommands file"; RETURN [FALSE];}; }; checkSummonerLoad: PROC RETURNS [good: BOOL _ TRUE] = { parseStateType: TYPE = {sawName, sawLeft, sawGFI, sawRight}; packageLoad: ROPE = fullNameOfSummonerLoad ; packageLoadStream: IO.STREAM; containedPackage: ROPE _ NIL; shortBcdName: ROPE _ NIL; parseState: parseStateType _ sawRight; count: INT _ 0 ; IF packageLoad = NIL THEN {msg _ "no summonerLoad file in DF file"; RETURN[FALSE]}; { packageLoadStream _ FS.StreamOpen[packageLoad ! FS.Error => GOTO cantOpen]; DO token: ROPE _ NIL; dfCreated: BasicTime.GMT; runOK: BOOL _ FALSE; differentInStd: BOOL _ FALSE; [token: token] _ packageLoadStream.GetTokenRope[IO.TokenProc ! IO.EndOfStream => EXIT]; IF token.Equal["-"] AND packageLoadStream.PeekChar[] = '- THEN { [] _ packageLoadStream.GetLineRope[ ! IO.EndOfStream => EXIT]; LOOP; }; SELECT parseState FROM sawName, sawRight => { IF token.Equal["("] THEN { parseState _ sawLeft; LOOP;}; parseState _ sawName; }; sawLeft => { [] _ Convert.IntFromRope[token ! Convert.Error => { msg _ Rope.Cat["Expected ", token, " to be the number of GFI's for", shortBcdName]; GOTO return; }; ]; parseState _ sawGFI; LOOP; }; sawGFI => { IF token.Equal[")"] THEN { parseState _ sawLeft; LOOP;}; msg _ Rope.Cat["Expected ')' after gfi number for", shortBcdName]; GOTO return; }; ENDCASE; containedPackage _ token.Substr[0, token.Index[0, ".", FALSE]]; shortBcdName _ containedPackage.Concat[".bcd"]; FOR exports: LIST OF exportedFiles _ exportedFilesList, exports.rest WHILE exports # NIL DO IF (exports.first.included AND Rope.Equal[exports.first.name, shortBcdName, FALSE]) OR (~exports.first.included AND Rope.Equal[exports.first.file.name.Substr[0, Rope.Index[s1: exports.first.file.name, s2: "!"]], shortBcdName, FALSE]) THEN { IF exports.first.included THEN EXIT; -- too hard to check imports [created: dfCreated] _ FS.FileInfo[name: shortBcdName, remoteCheck: FALSE, wDir: exports.first.path1 ! FS.Error => { msg _ Rope.Cat[exports.first.path1, shortBcdName, " missing from server"]; GOTO return; } ]; EXIT; }; REPEAT FINISHED => { msg _ Rope.Cat["cannot find ", shortBcdName, " in df file"]; RETURN [FALSE]; }; ENDLOOP; ENDLOOP; packageLoadStream.Close[ ! FS.Error => CONTINUE;]; EXITS cantOpen => { msg _ "cannot open .remoteCommands file"; RETURN [FALSE];}; return => {}; }; }; checkImports: PROC RETURNS [good: BOOL _ TRUE] = { }; <<>> <> IF ComputeClientInternal.Enabled # true THEN RETURN[msg: "Client is not enabled"]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc < 2 THEN RETURN[$Failure, "No package specified"]; cleanFName _ FileNames.ResolveRelativePath[argv[1]]; cleanFName _ cleanFName.Substr[0, Rope.Index[s1: cleanFName, s2: "."]]; [fullFName: fullDFFName, cp: fullDFcp] _ FS.ExpandName[cleanFName]; package _ fullDFFName.Substr[fullDFcp.base.start, fullDFcp.base.length]; remoteCommands _ Rope.Concat[package, ".remoteCommands"]; summonerLoad _ Rope.Concat[package, ".summonerLoad"]; fileName _ Rope.Concat[cleanFName, ".df"]; <<1) Insure .df file has a global attachment>> [attachedTo: attachedFile] _ FS.FileInfo[name: fileName, remoteCheck: FALSE ! FS.Error => { msg _ Rope.Concat["Submitted df file is not attached to a global file since ", error.explanation]; GOTO returnError; }; ]; IF attachedFile = NIL THEN { fullFName: ROPE; cp: FS.ComponentPositions; dirOmitted: BOOLEAN; [fullFName: fullFName, cp: cp, dirOmitted: dirOmitted] _ FS.ExpandName[name: fileName, wDir: NIL]; IF cp.server.length > 0 THEN attachedFile _ fileName ELSE RETURN[$Failure, "local file submitted, not attached to a global file"]; }; <<>> <<2) Process the .df file, and extract the .remoteCommands and .summonerload files, and build a list of all the exported file.>> [created: mainDFFileCreated] _ FS.FileInfo[name: fileName ! FS.Error => { msg _ Rope.Concat["Could not get info (FS.FileInfo) about submitted df file since ", error.explanation]; GOTO returnError; } ]; packageDFStream _ FS.StreamOpen[fileName: fileName ! FS.Error => { msg _ Rope.Concat["Submitted df file could not be opened since ", error.explanation]; GOTO returnError; } ]; DFUtilities.ParseFromStream[packageDFStream, DoOneItemFromDFFile ! DFUtilities.SyntaxError => { msg _ reason; packageDFStream.Close[! FS.Error => CONTINUE]; GOTO returnError; } ]; packageDFStream.Close[! FS.Error => CONTINUE]; IF msg # NIL THEN RETURN[$Failure, msg]; <<3) open remoteCommands file. Check that it parses OK and is reasonable.>> IF ~checkSummonerRemoteCommands[] THEN GOTO returnError; <<4) open summonerload file. Check packages in summonerload for export in the .df file, and check to see that the files with these create dates exist.>> IF ~checkSummonerLoad[] THEN GOTO returnError; <<5) Take package bcd and generate IMPORTs. Check against list of good imports. Complain if needed. (this should be done on the controller, and be protected, but I trust people) This is a noop for now, however.>> IF ~checkImports[] THEN GOTO returnError; <<6) Tell the controller about the new package.>> tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, "Compute Server Controller Down - try again later"] ; }; [error: controllerError, tryDifferentController: tryDifferentController, msg: controllerMsg] _ tempControllerInterface.NoticeNewPackage[attachedFile ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ "RPC Call Failed - controller might be down or recovering"; GOTO returnError; }; ]; IF tryDifferentController THEN RETURN[$Failure, "Compute Server Controller Recovering. Package may or may not have been added. - Resubmit package"] ; IF controllerMsg # NIL THEN RETURN[$Failure, Rope.Concat["Controller rejected package because ", controllerMsg]]; msg _ "New package accepted; please wait about 20 seconds before trying to use it."; EXITS returnError => { RETURN[$Failure, msg] }; }; }; <> RemovePackage: Commander.CommandProc = { <> argv: CommandTool.ArgumentVector; cleanFName: ROPE; controllerError: BOOL _ FALSE; controllerMsg: ROPE _ NIL; tryDifferentController: BOOL _ FALSE; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; IF ComputeClientInternal.Enabled # true THEN RETURN[msg: "Client is not enabled"]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc < 2 THEN RETURN[$Failure, "No package specified"]; cleanFName _ argv[1].Substr[0, Rope.Index[s1: argv[1], s2: "."]]; tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, "Compute Server Controller Down - try again later"] ; }; [error: controllerError, tryDifferentController: tryDifferentController, msg: controllerMsg] _ tempControllerInterface.RemoveOldPackage[cleanFName ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ "RPC Call Failed - controller might be down or recovering"; GOTO returnError; }; ]; IF tryDifferentController THEN RETURN[$Failure, "Compute Server Controller Recovering. Package may or may not have been removed. - retry"] ; IF controllerMsg # NIL THEN RETURN[$Failure, Rope.Concat["Controller rejected package removal because ", controllerMsg]]; msg _ "Package Removed."; EXITS returnError => { RETURN[$Failure, msg] }; }; <> SummonerInfoProc: Commander.CommandProc = { <> tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; controllerError: BOOL; tryDifferentController: BOOL; serverList: LIST OF Rope.ROPE; bestFOM: REAL; remoteMsg: Rope.ROPE; <> IF ComputeClientInternal.Enabled # true THEN msg _ "Compute Server Client not enabled\n" ELSE msg _ "Compute Server Client enabled\n"; tempControllerInterface _ ComputeClientInternal.ControllerInterface; msg _ Rope.Cat[msg, "Cluster: ", ComputeClientInternal.ControllerGVName, "\n"]; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, msg.Concat["Compute Server Controller Down; can't import controller - try again later"]] ; }; [error: controllerError, tryDifferentController: tryDifferentController, msg: remoteMsg, serverList: serverList, bestFOM: bestFOM ] _ tempControllerInterface.GetSomeInfo[ ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ msg.Concat["RPC Call Failed - controller might be down or recovering"]; GOTO returnError; }; ]; IF controllerError THEN RETURN[$Failure, msg.Concat[" Controller returned an error"]] ELSE { firstItem: BOOL _ TRUE; IF tryDifferentController THEN msg _ Rope.Concat[msg, " controller has moved\n"]; FOR l: LIST OF ROPE _ serverList, l.rest WHILE l # NIL DO IF firstItem THEN { msg _ Rope.Cat[msg, "Servers: ", l.first]; firstItem _ FALSE; } ELSE { msg _ Rope.Cat[msg, ", ", l.first]; }; ENDLOOP; IF ~firstItem THEN msg _ Rope.Concat[msg, "\n"]; msg _ Rope.Concat[msg, IO.PutFR["Best Figure of Merit (0.0 is idle) is %8.3f", IO.real[bestFOM]]]; }; EXITS returnError => { RETURN[$Failure, msg] }; }; <> BadCommandProc: Commander.CommandProc = { <> argv: CommandTool.ArgumentVector; serverName, commandName: ROPE _ NIL; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; IF ComputeClientInternal.Enabled # true THEN RETURN[msg: "Client is not enabled"]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc # 3 THEN RETURN[$Failure, "Wrong number of arguments"]; serverName _ argv[1]; commandName _ argv[2]; IF Rope.Find[serverName, "#"] < 0 THEN { pupAddress: Pup.Address; pupAddress _ PupName.NameLookup[serverName, Pup.nullSocket ! PupName.Error => GOTO badName]; serverName _ PupName.AddressToRope[pupAddress]; }; tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, msg.Concat["Compute Server Controller Down; can't import controller - try again later"]] ; }; tempControllerInterface.CommandUnavailable[serverMachineName: serverName, commandName: commandName, version: NIL ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ msg.Concat["RPC Call Failed - controller might be down or recovering"]; GOTO returnError; }; ]; EXITS returnError => RETURN[$Failure, msg]; badName => RETURN[$Failure, "Cannot find pup address for server"]; }; GoodCommandProc: Commander.CommandProc = { <> argv: CommandTool.ArgumentVector; serverName, commandName: ROPE _ NIL; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; IF ComputeClientInternal.Enabled # true THEN RETURN[msg: "Client is not enabled"]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc # 3 THEN RETURN[$Failure, "Wrong number of arguments"]; serverName _ argv[1]; commandName _ argv[2]; IF Rope.Find[serverName, "#"] < 0 THEN { pupAddress: Pup.Address; pupAddress _ PupName.NameLookup[serverName, Pup.nullSocket ! PupName.Error => GOTO badName]; serverName _ PupName.AddressToRope[pupAddress]; }; tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, msg.Concat["Compute Server Controller Down; can't import controller - try again later"]] ; }; tempControllerInterface.ExtraCommandAvailable[serverMachineName: serverName, commandName: commandName, version: NIL ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ msg.Concat["RPC Call Failed - controller might be down or recovering"]; GOTO returnError; }; ]; EXITS returnError => RETURN[$Failure, msg]; badName => RETURN[$Failure, "Cannot find pup address for server"]; }; <> ClusterProc: Commander.CommandProc = { <> argv: CommandTool.ArgumentVector; IF ComputeClientInternal.Enabled # true THEN RETURN[msg: "Client is not enabled"]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc < 2 THEN RETURN[$Failure, "No cluster specified"]; ComputeClientInternal.ControllerGVName _ argv[1]; ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; }; <> BestServerStats: PUBLIC PROC RETURNS[success: ComputeServerClient.RemoteSuccess _ false, selfIsBest: BOOL_ TRUE, FOM: REAL _ 1.0] = { bestInstance: RPC.ShortROPE; bestFOM: REAL; retryCounter: INT _ 0 ; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; DO tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN RETURN[false, TRUE, 1.0]; }; [instance: bestInstance, FOM: bestFOM] _ tempControllerInterface.BestServerStats[ ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; retryCounter _ retryCounter + 1; IF retryCounter < 3 THEN LOOP ELSE GOTO controllerCallFailed; }; ]; IF bestInstance = NIL OR Rope.Equal[bestInstance, ComputeClientInternal.myNetAddressRope, FALSE] THEN RETURN[true, TRUE, bestFOM] ELSE RETURN [true, FALSE, bestFOM]; ENDLOOP; EXITS controllerCallFailed => RETURN[false, TRUE, 0.0]; }; <> Commander.Register[key: "///Commands/SubmitSummonerPackage", proc: SubmitPackage, doc: "Submit to the Compute Server the .df file specified as the argument into the current cluster"]; Commander.Register[key: "///Commands/RemoveSummonerPackage", proc: RemovePackage, doc: "Remove the package specified by short name as the argument from the current Compute Server cluster"]; Commander.Register[key: "///Commands/SummonerInfo", proc: SummonerInfoProc, doc: "Get and print out some info about the state of the compute server cluster"]; Commander.Register[key: "///Commands/SummonerCluster", proc: ClusterProc, doc: "Set the compute server cluster"]; Commander.Register[key: "///Commands/SummonerBadCommand", proc: BadCommandProc, doc: "SummonerBadCommand server commandname - Set a command bad for a server; servers may be named by pup address (e.g., 3#277#) or by name (e.g., Bataan), the the command is the remote command name (e.g., RemoteCompiler)"]; Commander.Register[key: "///Commands/SummonerGoodCommand", proc: GoodCommandProc, doc: "SummonerGoodCommand server commandname - Set a command good for a server, reversing a previous SummonerBadCommand"]; END. <> <> <> <<>> <<>>