/// <summary> /// Code that does the actual work. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="execute"></param> /// <returns></returns> private T InternalExecuteInConnection <T>(Func <ISSHConnection, T> execute) { if (_connection == null) { _connection = _makeConnection(); if (_connection == null) { throw new NullSSHConnectionException("Attempted to create a recoverable SSHConnection, but was given a null value!"); } } bool hasThrown = true; try { var r = execute(_connection); hasThrown = false; return(r); } finally { // If an error happened, even though we are reporting it, reset the connection. if (hasThrown) { Trace.WriteLine($"Failed In Connection to {_connection.MachineName}"); _connection.Dispose(); _connection = null; } } }
/// <summary> /// Returns the list of files associated with a dataset, as fetched from the grid. /// </summary> /// <param name="connection"></param> /// <param name="dataSetName"></param> /// <param name="dumpOnly">Dump only commands that are issues to standard logging interface.</param> /// <param name="failNow">Returns true to bail out as quickly as possible</param> /// <returns></returns> public static async Task <List <GRIDFileInfo> > FileInfoFromGRIDAsync(this ISSHConnection connection, string dataSetName, Func <bool> failNow = null, bool dumpOnly = false) { // If we have a cache hit, then avoid the really slow lookup. var c = _GRIDFileInfoCache.Value[dataSetName] as GRIDFileInfo[]; if (c != null) { return(c.ToList());; } // Run it in rucio and bring back our answers. var fileNameList = new List <GRIDFileInfo>(); var filenameMatch = new Regex(@"\| +(?<fname>\S*) +\| +[^\|]+\| +[^\|]+\| +(?<fsize>[0-9\.]*) *(?<fsizeunits>[kMGTB]*) *\| +(?<events>[0-9]*) +\|"); bool bad = false; try { await connection.ExecuteLinuxCommandAsync(string.Format("rucio list-files {0}", dataSetName), l => { if (l.Contains("Data identifier not found")) { bad = true; } if (!bad) { var m = filenameMatch.Match(l); if (m.Success) { var fname = m.Groups["fname"].Value; if (fname != "SCOPE:NAME") { // Parse it all out var gi = new GRIDFileInfo() { name = fname, eventCount = m.Groups["events"].Value == "" ? 0 : int.Parse(m.Groups["events"].Value), size = ConvertToMB(m.Groups["fsize"].Value, m.Groups["fsizeunits"].Value) }; fileNameList.Add(gi); } } } }, failNow : failNow, dumpOnly : dumpOnly ); } catch (LinuxCommandErrorException e) when(e.Message.Contains("status error") && bad) { // Swallow a command status error that we "sort-of" know about. } if (bad & !dumpOnly) { throw new DataSetDoesNotExistException($"Dataset '{dataSetName}' does not exist - can't get its list of files ({connection.MachineName})."); } _GRIDFileInfoCache.Value[dataSetName] = fileNameList.ToArray(); return(fileNameList); }
/// <summary> /// Run an command function as a future. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="execute"></param> /// <returns></returns> private async Task <T> InternalExecuteInConnectionAsync <T>(Func <ISSHConnection, Task <T> > execute) { if (_connection == null) { _connection = await _makeConnectionAsync(); if (_connection == null) { throw new NullSSHConnectionException("Attempted to create a recoverable SSHConnection, but was given a null value!"); } } bool hasThrown = true; try { var r = await execute(_connection); hasThrown = false; return(r); } finally { if (hasThrown) { Trace.WriteLine($"Failed In Connection to {_connection.MachineName}"); _connection.Dispose(); _connection = null; } } }
public CommandResult InternalExecute(ICommandTarget target, params IAdaptable[] args) { ISSHConnection sshConnection = GetSSHConnection(target); // Note: Currently, SCPClient supports only SSH2. if (sshConnection == null || sshConnection.SSHProtocol != SSHProtocol.SSH2) { return(CommandResult.Ignored); } string connectionName = GetTerminalName(target); if (connectionName == null) { connectionName = SFTPPlugin.Instance.StringResource.GetString("Common.UnknownPeer"); } Form ownerForm = GetForm(target); if (!ConfirmToUse(ownerForm, "SCP")) { return(CommandResult.Cancelled); } SCPClient scp = new SCPClient(sshConnection); SCPForm form = new SCPForm(ownerForm, scp, connectionName); form.Show(); // Note: don't specify owner to avoid fixed z-order. return(CommandResult.Succeeded); }
/// <summary> /// Build the work area /// </summary> /// <param name="connection"></param> /// <param name="dumpOnly">Dump commands only to standard logging interface rather than execute them</param> /// <param name="failNow">Return true to abort right away</param> /// <returns></returns> public static async Task <ISSHConnection> BuildWorkAreaAsync(this ISSHConnection connection, Func <bool> failNow = null, bool dumpOnly = false) { string findPkgError = null; var buildLines = new List <string>(); try { await connection.ExecuteLinuxCommandAsync("rc find_packages", l => findPkgError = l, failNow : failNow, dumpOnly : dumpOnly); return(await connection.ExecuteLinuxCommandAsync("rc compile", l => buildLines.Add(l), failNow : failNow, dumpOnly : dumpOnly)); } catch (LinuxCommandErrorException lerr) { if (buildLines.Count > 0) { var errors = buildLines.Where(ln => ln.Contains("error:")); var err = new StringBuilder(); err.AppendLine("Unable to compile package:"); foreach (var errline in errors) { err.AppendLine(" -> " + errline); } throw new LinuxCommandErrorException(err.ToString(), lerr); } else { throw new LinuxCommandErrorException(string.Format("Failed to run 'rc find_packages': {0}", findPkgError), lerr); } } }
//profに対応したSSHConnectionを返す。接続がなければparentを親に認証ダイアログを出して認証する public ISSHConnection GetOrCreateConnection(ChannelProfile prof, Form parent) { //ホスト名とアカウントのペアからコネクションを共有する仕組みがあるとよいかも ISSHConnection c = _profileToConnection[prof] as ISSHConnection; if (c != null) { return(c); } SSHShortcutLoginDialog dlg = new SSHShortcutLoginDialog(prof); if (dlg.ShowDialog(parent) == DialogResult.OK) { c = dlg.Result.Connection; try { dlg.Result.WaitRequest(); } catch (Exception ex) { Debug.WriteLine(ex.StackTrace); Util.Warning(parent, ex.Message); c.Close(); return(null); } _profileToConnection[prof] = c; Env.MainForm.RefreshProfileStatus(prof); } return(c); }
/// <summary> /// Check out a Git package from the CERN git repro, of what is pecified in the package. /// </summary> /// <param name="connection">Connection on which to do the checkout</param> /// <param name="scPackagePath">Path to the package, perhaps a short-cut (see remarks)</param> /// <param name="scRevision">Revision for the package, or empty to grab the head</param> /// <param name="failNow">Fuction that returns true if we should bail right away</param> /// <param name="dumpOnly">Just dump the commands output - don't actually do anything.</param> /// <returns></returns> public static async Task <ISSHConnection> CheckoutPackageGitAsync(this ISSHConnection connection, string scPackagePath, string scRevision, Func <bool> failNow = null, bool dumpOnly = false) { // The revision must be specified. if (string.IsNullOrWhiteSpace(scRevision)) { throw new ArgumentException($"The commit hash for {scPackagePath} must be specified - it may well move with time"); } if (scRevision.Length < 15) { throw new ArgumentException($"The SHA {scRevision} for git package {scPackagePath} doesn't look like a full git SHA (e.g. 77658117c62ac99610068228668563d29baa3912)."); } // Determine if this was short-hand, and we need to put the gitlab specification in front. if (!scPackagePath.Contains("://")) { scPackagePath = $"https://:@gitlab.cern.ch:8443/{scPackagePath}"; } // Do the check out await connection.ExecuteLinuxCommandAsync($"git clone --recursive {scPackagePath}", refreshTimeout : true, secondsTimeout : 8 *60, failNow : failNow, dumpOnly : dumpOnly); // Now, we have to move to that revision. var pkgName = Path.GetFileNameWithoutExtension(scPackagePath.Split('/').Last()); string error = ""; await connection.ExecuteLinuxCommandAsync($"cd {pkgName}; git checkout {scRevision}; cd ..", processLine : l => error = l.Contains("error")?l : error); if (error.Length > 0) { throw new LinuxCommandErrorException($"Unable to check out package {scPackagePath} with SHA {scRevision} ({connection.MachineName}): {error}"); } return(connection); }
//終了のハンドリング 非同期に別スレッドから呼ばれるので注意 public void ConnectionClosed(ISSHConnection connection) { IDictionaryEnumerator e = _profileToConnection.GetEnumerator(); while (e.MoveNext()) { if (connection == e.Value) { ChannelProfile prof = (ChannelProfile)e.Key; _profileToConnection.Remove(e.Key); bool manual = false; lock (this) { manual = _manualClosingConnections.Contains(connection); if (manual) { _manualClosingConnections.Remove(connection); } } if (!manual) { Util.InterThreadWarning(Env.Strings.GetString("Message.ConnectionManager.Disconnected")); } Env.MainForm.Invoke(new RefreshProfileStatusDelegate(Env.MainForm.RefreshProfileStatus), prof); break; } } }
/// <summary> /// Execute a Linux command. Throw if the command does not return 0 to the shell. Provides for ways to capture (or ignore) /// the output of the command. /// </summary> /// <param name="connection">The connection onwhich to execute the command.</param> /// <param name="command">The command to execute</param> /// <param name="dumpOnly">If true, then only print out the commands</param> /// <param name="failNow">If true, attempt to bail out of the command early.</param> /// <param name="processLine">A function called for each line read back while the command is executing</param> /// <param name="seeAndRespond">If a string is seen in the output, then the given response is sent</param> /// <param name="refreshTimeout">If we see text, reset the timeout counter</param> /// <param name="secondsTimeout">How many seconds with no output or since beginning of command before we declare failure?</param> /// <returns>The connection we ran this on. Enables fluent progreamming</returns> /// <remarks> /// We check the status by echoing the shell variable $? - so this actually runs two commands. /// </remarks> public static async Task <ISSHConnection> ExecuteLinuxCommandAsync(this ISSHConnection connection, string command, Action <string> processLine = null, Func <bool> failNow = null, bool dumpOnly = false, int secondsTimeout = 60 *60, bool refreshTimeout = false, Dictionary <string, string> seeAndRespond = null) { string rtnValue = ""; processLine = processLine == null ? l => { } : processLine; try { await connection.ExecuteCommandAsync(command, processLine, failNow : failNow, dumpOnly : dumpOnly, seeAndRespond : seeAndRespond, refreshTimeout : refreshTimeout, secondsTimeout : secondsTimeout); await connection.ExecuteCommandAsync("echo $?", l => rtnValue = l, dumpOnly : dumpOnly); } catch (TimeoutException te) { throw new TimeoutException($"{te.Message} - While executing command {command} on {connection.MachineName}.", te); } if (rtnValue != "0" && !dumpOnly) { throw new LinuxCommandErrorException($"The remote command '{command}' return status error code '{rtnValue}' on {connection.MachineName}"); } return(connection); }
/// <summary> /// Opens channel. /// </summary> /// <param name="connection">SSH connection object</param> /// <param name="command">Remote command</param> /// <param name="millisecondsTimeout">timeout in milliseconds</param> /// <exception cref="SCPClientInvalidStatusException">Channel has been already opened or already closed.</exception> /// <exception cref="SCPClientTimeoutException">Timeout has occurred while waiting for READY status.</exception> public void Open(ISSHConnection connection, string command, int millisecondsTimeout) { if (_status != StreamStatus.NotOpened) { throw new SCPClientInvalidStatusException(); } ISSHChannel channel = null; SCPClientChannelEventHandler eventHandler = connection.ExecCommand( (ch) => { channel = ch; return(new SCPClientChannelEventHandler( new DataReceivedDelegate(OnDataReceived), new ChannelStatusChangedDelegate(OnChannelStatusChanged) )); }, command ); _eventHandler = eventHandler; _channel = channel; if (!_eventHandler.WaitStatus(SCPChannelStatus.READY, millisecondsTimeout)) { throw new SCPClientTimeoutException(); } lock (_statusSync) { if (_status == StreamStatus.NotOpened) { _status = StreamStatus.Opened; } } }
/// <summary> /// Apply a async function to a connection. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="connection"></param> /// <param name="what"></param> /// <param name="doit"></param> /// <returns></returns> public static async Task <ISSHConnection> ApplyAsync <T>(this ISSHConnection connection, IEnumerable <T> what, Func <ISSHConnection, T, Task> doit) { foreach (var w in what) { await doit(connection, w); } return(connection); }
/// <summary> /// Get the PID for a process back. /// </summary> /// <param name="c"></param> /// <returns></returns> private async Task <string> GetPID(ISSHConnection c) { var pid = ""; await c.ExecuteLinuxCommandAsync("echo $$", s => pid = s); Assert.IsTrue(!string.IsNullOrWhiteSpace(pid)); return(pid); }
/// <summary> /// Fetch a dataset from the grid using Rucio to a local directory. /// </summary> /// <param name="connection">A previously configured connection with everything ready to go for GRID access.</param> /// <param name="dataSetName">The rucio dataset name</param> /// <param name="localDirectory">The local directory (on Linux) where the file should be downloaded</param> /// <param name="fileStatus">Gets updates as new files are downloaded. This will contain just the filename.</param> /// <param name="fileNameFilter">Filter function to alter the files that are to be downloaded</param> /// <param name="failNow">Checked periodically, if ever returns true, then bail out</param> /// <param name="timeout">How long before we should timeout in seconds</param> /// <returns>The connections used so you can chain</returns> public static ISSHConnection DownloadFromGRID(this ISSHConnection connection, string dataSetName, string localDirectory, Action <string> fileStatus = null, Func <string[], string[]> fileNameFilter = null, Func <bool> failNow = null, int timeout = 3600) { return(connection.DownloadFromGRIDAsync(dataSetName, localDirectory, fileStatus, fileNameFilter, failNow, timeout) .WaitAndUnwrapException()); }
/// <summary> /// Helper function to use in the middle of this thing /// </summary> /// <param name="connection"></param> /// <param name="doit"></param> /// <returns></returns> public static ISSHConnection Apply(this ISSHConnection connection, Action doit) { if (doit == null) { throw new ArgumentNullException(nameof(doit)); } doit(); return(connection); }
/// <summary> /// Check out SVN or a GIT package. /// </summary> /// <param name="connection">Connection on which we should be checking this out on</param> /// <param name="scPackagePath">The svn path to the package. Basically what you would hand to the rc checkout command. Nohting like "tags" or "trunk" is permitted.</param> /// <param name="scRevision">The revision number. A SVN revision number. If blank, then the version associated with the build is checked out.</param> /// <returns></returns> public static Task <ISSHConnection> CheckoutPackageAsync(this ISSHConnection connection, string scPackagePath, string scRevision, Func <bool> failNow = null, bool dumpOnly = false) { if (string.IsNullOrWhiteSpace(scPackagePath)) { throw new ArgumentNullException("scPackagePath", "Package must be a valid path to a source control repro!"); } var isGit = scPackagePath.EndsWith(".git"); return(isGit ? connection.CheckoutPackageGitAsync(scPackagePath, scRevision, failNow, dumpOnly) : connection.CheckoutPackageSVNAsync(scPackagePath, scRevision, failNow, dumpOnly)); }
/// <summary> /// Execute a Linux command. Throw if the command does not return 0 to the shell. Provides for ways to capture (or ignore) /// the output of the command. /// </summary> /// <param name="connection">The connection onwhich to execute the command.</param> /// <param name="command">The command to execute</param> /// <param name="dumpOnly">If true, then only print out the commands</param> /// <param name="failNow">If true, attempt to bail out of the command early.</param> /// <param name="processLine">A function called for each line read back while the command is executing</param> /// <param name="seeAndRespond">If a string is seen in the output, then the given response is sent</param> /// <param name="refreshTimeout">If we see text, reset the timeout counter</param> /// <param name="secondsTimeout">How many seconds with no output or since beginning of command before we declare failure?</param> /// <returns>The connection we ran this on. Enables fluent progreamming</returns> /// <remarks> /// We check the status by echoing the shell variable $? - so this actually runs two commands. /// </remarks> public static ISSHConnection ExecuteLinuxCommand(this ISSHConnection connection, string command, Action <string> processLine = null, Func <bool> failNow = null, bool dumpOnly = false, int secondsTimeout = 60 * 60, bool refreshTimeout = false, Dictionary <string, string> seeAndRespond = null) { return(connection.ExecuteLinuxCommandAsync(command, processLine, failNow, dumpOnly, secondsTimeout, refreshTimeout, seeAndRespond) .WaitAndUnwrapException()); }
/// <summary> /// Send all files over to the remote client. Make sure the directory exists. /// </summary> /// <param name="connection"></param> /// <param name="dumpLine"></param> private async Task SendAllFiles(ISSHConnection connection, Action <string> dumpLine) { foreach (var f in _filesToCopyOver) { string linuxPath = $"{f.remoteLinuxDirectory}/{f.localFileName.Name}"; dumpLine?.Invoke($"Copying {f.localFileName.Name} -> {linuxPath}"); await connection.ExecuteLinuxCommandAsync($"mkdir -p {f.remoteLinuxDirectory}", dumpLine); await connection.CopyLocalFileRemotelyAsync(f.localFileName, linuxPath); } _filesToCopyOver.Clear(); }
/// <summary> /// We will run the job submission. We assume that any checking has already gone one /// and we are just going to execute all the commands required of this job request. /// Assume setupATLAS and rucio and voms proxy init have all been done before /// this guy is called! /// </summary> /// <param name="connection"></param> /// <param name="job"></param> /// <param name="datasetToStartWith"></param> /// <param name="credSet">Set of credentials to load. Default to CERN</param> /// <returns></returns> public static async Task <ISSHConnection> SubmitJobAsync(this ISSHConnection connection, AtlasJob job, string inputDataSet, string resultingDataSet, Action <string> statusUpdate = null, Func <bool> failNow = null, bool sameJobAsLastTime = false, string credSet = "CERN", bool dumpOnly = false) { // Get the status update protected. Action <string> update = statusUpdate != null ? statusUpdate : s => { }; // Figure out the proper submit command. string submitCmd = (job.SubmitPatternCommands.Length > 0 ? MatchSubmitPattern(job.SubmitPatternCommands, inputDataSet) : job.SubmitCommand.SubmitCommand.CommandLine) .Replace("*INPUTDS*", "{0}") .Replace("*OUTPUTDS*", "{1}"); var cernCred = new CredentialSet(credSet) .Load() .FirstOrDefault() .ThrowIfNull(() => new GRIDSubmitException($"Please create a windows generic credential with a target of '{credSet}' to allow access to kinit")); // If this is the first time through with a single job, then setup a directory we can use. if (!sameJobAsLastTime) { var linuxLocation = string.Format("/tmp/{0}", resultingDataSet); await connection.Apply(() => update("Removing old build directory")) .ExecuteLinuxCommandAsync("rm -rf " + linuxLocation, dumpOnly: dumpOnly); await connection .Apply(() => update("Setting up panda")) .ExecuteLinuxCommandAsync("lsetup panda", dumpOnly: dumpOnly); await connection.Apply(() => update("Setting up release")) .SetupRcReleaseAsync(linuxLocation, job.Release.Name, dumpOnly: dumpOnly); await connection.Apply(() => update("Getting CERN credentials")) .KinitAsync(cernCred.Username, cernCred.Password, dumpOnly: dumpOnly); await connection .ApplyAsync(job.Packages, (c, j) => c.Apply(() => update("Checking out package " + j.Name)).CheckoutPackageAsync(j.Name, j.SCTag, failNow: failNow, dumpOnly: dumpOnly)); await connection .ApplyAsync(job.Commands, (co, cm) => co.Apply(() => update("Running command " + cm.CommandLine)).ExecuteLinuxCommandAsync(cm.CommandLine, failNow: failNow, dumpOnly: dumpOnly)); await connection .Apply(() => update("Compiling release")) .BuildWorkAreaAsync(failNow: failNow, dumpOnly: dumpOnly); } // We should now be in the directory where everything is - so submit! return(await connection .Apply(() => update($"Running submit command ({inputDataSet})")) .ExecuteLinuxCommandAsync(string.Format(submitCmd, inputDataSet, resultingDataSet), failNow: failNow, dumpOnly: dumpOnly)); }
/// <summary> /// Run the setup ATLAS command asyncronously. /// </summary> /// <param name="connection">The connection that will understand the setupATLAS command</param> /// <param name="dumpOnly">If true, then tex tis dumpped to standard logging</param> /// <returns>A reconfigured SSH shell connection (same as what went in)</returns> public static async Task <ISSHConnection> setupATLASAsync(this ISSHConnection connection, bool dumpOnly = false) { bool badCommand = false; var r = await connection .ExecuteLinuxCommandAsync("setupATLAS", dumpOnly : dumpOnly, processLine : l => badCommand = badCommand || l.Contains("command not found"), secondsTimeout : 120); if (badCommand) { throw new LinuxConfigException($"Unable to setupATLAS - command is not known! ({connection.MachineName})"); } return(r); }
/* * private static Socks CreateSocksParam(string dest_host, int dest_port) { * Socks s = new Socks(); * s.DestName = dest_host; * s.DestPort = (short)dest_port; * s.Account = Env.Options.SocksAccount; * s.Password = Env.Options.SocksPassword; * s.ServerName = Env.Options.SocksServer; * s.ServerPort = (short)Env.Options.SocksPort; * s.ExcludingNetworks = Env.Options.SocksNANetworks; * return s; * } */ public void ManualClose(ChannelProfile prof) { if (!IsConnected(prof)) { Debug.WriteLine("ManualClose - Not connected"); return; } lock (this) { ISSHConnection c = (ISSHConnection)_profileToConnection[prof]; _manualClosingConnections.Add(c); c.Disconnect(DisconnectionReasonCode.ByApplication, "close by application"); } }
public void AttachTransmissionSide(ISSHConnection con, AuthenticationStatus authStatus) { _sshSocket.SetSSHConnection(con); if (authStatus == AuthenticationStatus.Success) { SSHSocket ss = (SSHSocket)_sshSocket; ss.OpenShell(); } else if (authStatus == AuthenticationStatus.NeedKeyboardInput) { SSHSocket ss = (SSHSocket)_sshSocket; ss.OpenKeyboardInteractiveShell(); } }
/// <summary> /// Setup Rucio. ATLAS must have been previously configured, or this will "crash". Execute Asyncrohonously. /// </summary> /// <param name="connection">Connection on-which we will set everything up</param> /// <param name="rucioUserName">The user alias used on the grid</param> /// <param name="dumpOnly">Dump output to the logging interface rather than actually executing anything</param> /// <returns>A shell on-which rucio has been setup (the same connection that went in)</returns> public static async Task <ISSHConnection> setupRucioAsync(this ISSHConnection connection, string rucioUserName, bool dumpOnly = false) { int hashCount = 0; var r = await connection.ExecuteLinuxCommandAsync(string.Format("export RUCIO_ACCOUNT={0}", rucioUserName), dumpOnly : dumpOnly, secondsTimeout : 30); r = await r.ExecuteLinuxCommandAsync("lsetup rucio", dumpOnly : dumpOnly, secondsTimeout : 30); r = await r.ExecuteLinuxCommandAsync("hash rucio", l => hashCount += 1, dumpOnly : dumpOnly, secondsTimeout : 30); if (hashCount != 0 && !dumpOnly) { throw new LinuxConfigException("Unable to setup Rucio... did you forget to setup ATLAS first? ({connection.MachineName})"); } return(connection); }
/// <summary> /// Fetch back all files we probably need to know about. /// </summary> /// <param name="sshConnection"></param> /// <param name="dumpLine"></param> private async Task ReceiveAllFiles(ISSHConnection connection, Action <string> dumpLine) { foreach (var f in _filesToBringBack) { string linuxPath = $"{f.remoteLinuxDirectory}/{f.localFileName.Name}"; dumpLine?.Invoke($"Copying {linuxPath} -> {f.localFileName.Directory}"); f.localFileName.Directory.Refresh(); if (!f.localFileName.Directory.Exists) { f.localFileName.Directory.Create(); } await connection.CopyRemoteFileLocallyAsync(linuxPath, f.localFileName); } _filesToBringBack.Clear(); }
public CommandResult InternalExecute(ICommandTarget target, params IAdaptable[] args) { ISSHConnection sshConnection = GetSSHConnection(target) as ISSHConnection; if (sshConnection == null || sshConnection.SSHProtocol != SSHProtocol.SSH2) { return(CommandResult.Ignored); } string connectionName = GetTerminalName(target); if (connectionName == null) { connectionName = SFTPPlugin.Instance.StringResource.GetString("Common.UnknownPeer"); } Form ownerForm = GetForm(target); if (!ConfirmToUse(ownerForm, "SFTP")) { return(CommandResult.Cancelled); } SFTPClient sftp = null; try { sftp = SFTPClient.OpenSFTPChannel(sshConnection); SFTPForm form = new SFTPForm(ownerForm, sftp, connectionName); form.Show(); // Note: don't specify owner to avoid fixed z-order. return(CommandResult.Succeeded); } catch (Exception e) { if (sftp != null) { try { sftp.Close(); } catch (Exception) { } sftp = null; } RuntimeUtil.ReportException(e); return(CommandResult.Failed); } }
/// <summary> /// Create a fresh, clean, repro on the remote machine /// </summary> public void CreateRepro(string remote_path = null) { if (remote_path == null) { remote_path = RemotePath; } // Make sure no one is debing a dick by accident. Assert.AreNotEqual(".", remote_path); Assert.IsFalse(string.IsNullOrWhiteSpace(remote_path)); Assert.IsFalse(remote_path.Contains("*")); // Create the new repro Connection = new SSHConnectionTunnel(RemoteHostInfo); Connection.ExecuteLinuxCommand($"rm -rf {remote_path}") .ExecuteLinuxCommand($"mkdir -p {remote_path}"); }
/// <summary> /// Execute a kinit /// </summary> /// <param name="connection"></param> /// <param name="userName"></param> /// <param name="password"></param> /// <param name="dumpOnly">Dump commands to logging interface rather than execute them</param> /// <returns></returns> public static async Task <ISSHConnection> KinitAsync(this ISSHConnection connection, string userName, string password, bool dumpOnly = false) { var allStrings = new List <string>(); await connection.ExecuteLinuxCommandAsync(string.Format("echo {0} | kinit {1}", password, userName), l => allStrings.Add(l), dumpOnly : dumpOnly); var errorStrings = allStrings.Where(l => l.StartsWith("kinit:")).ToArray(); if (errorStrings.Length > 0) { throw new LinuxCommandErrorException($"Failed to execute kinit command: {errorStrings[0]} ({connection.MachineName})"); } if (!allStrings.Where(l => l.StartsWith("Password for")).Any() && !dumpOnly) { throw new LinuxCommandErrorException($"Failed to execute kinit command: {allStrings[0]} ({connection.MachineName})"); } return(connection); }
/// <summary> /// Setup a release. If it can't be found, error will be thrown /// </summary> /// <param name="connection"></param> /// <param name="releaseName">Full release name (e.g. 'Base,2.3.30')</param> /// <param name="linuxLocation">Directory where the linux location can be found</param> /// <param name="dumpOnly">Dump commands to standard logging, but do not execute anything</param> /// <returns></returns> public static async Task <ISSHConnection> SetupRcReleaseAsync(this ISSHConnection connection, string linuxLocation, string releaseName, bool dumpOnly = false) { // Check the arguments for something dumb if (string.IsNullOrWhiteSpace(releaseName)) { throw new ArgumentException("A release name must be provided"); } if (string.IsNullOrWhiteSpace(linuxLocation) || !linuxLocation.StartsWith("/")) { throw new ArgumentException("The release directory must be an absolute Linux path (start with a '/')"); } // First we have to create the directory. bool dirCreated = true; bool dirAlreadyExists = false; await connection.ExecuteLinuxCommandAsync(string.Format("mkdir {0}", linuxLocation), l => { dirCreated = !dirCreated ? false : string.IsNullOrWhiteSpace(l); dirAlreadyExists = dirAlreadyExists ? true : l.Contains("File exists"); }, dumpOnly : dumpOnly); if (dirAlreadyExists) { throw new LinuxMissingConfigurationException($"Release directory '{linuxLocation}' already exists - we need a fresh start ({connection.MachineName})"); } if (!dirCreated) { throw new LinuxMissingConfigurationException(string.Format($"Unable to create release directory '{linuxLocation}' ({connection.MachineName}).")); } // Next, put our selves there await connection.ExecuteLinuxCommandAsync(string.Format("cd {0}", linuxLocation), dumpOnly : dumpOnly); // And then do the setup bool found = false; await connection.ExecuteLinuxCommandAsync(string.Format("rcSetup {0}", releaseName), l => found = found?true : l.Contains("Found ASG release with"), dumpOnly : dumpOnly); if (!found && !dumpOnly) { throw new LinuxMissingConfigurationException($"Unable to find release '{releaseName}' ({connection.MachineName})"); } // Return the connection to make it a functional interface. return(connection); }
/// <summary> /// Use apply to make repeated application of things to a connection easy to read. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="connection"></param> /// <param name="what"></param> /// <param name="doit"></param> /// <returns></returns> public static ISSHConnection Apply <T>(this ISSHConnection connection, IEnumerable <T> what, Action <ISSHConnection, T> doit) { if (what == null) { throw new ArgumentNullException(nameof(what)); } if (doit == null) { throw new ArgumentNullException(nameof(doit)); } foreach (var w in what) { doit(connection, w); } return(connection); }
/// <summary> /// Gets SSHConnection from the target. /// Returns null if current terminal doesn't have SSH connection. /// </summary> /// <param name="target">Target object which has been passed to the IPoderosaCommand's method.</param> /// <returns>A SSH connection object corresponding with current terminal. Null if it cannot be found.</returns> protected ISSHConnection GetSSHConnection(ICommandTarget target) { ITerminalConnection connection = GetTerminalConnection(target); // Implementation classes for SSH connection are internal classes in another assembly. // We need to use reflection to get an instance of SSHChannel. if (connection != null && connection.Socket != null) { Type socketType = connection.Socket.GetType(); PropertyInfo prop = socketType.GetProperty("Connection", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty); if (prop != null && prop.CanRead) { ISSHConnection sshConnection = prop.GetValue(connection.Socket, null) as ISSHConnection; return(sshConnection); } } return(null); }
/// <summary> /// Initializes the VOMS proxy for use on the GRID. The connection must have already been configured so that /// the command voms-proxy-init works. /// </summary> /// <param name="connection">The configured SSH shell</param> /// <param name="GRIDUsername">The username to use to fetch the password for the voms proxy file</param> /// <param name="voms">The name of the voms to connect to</param> /// <param name="dumpOnly">Only print out proposed commands</param> /// <returns>Connection on which the grid is setup and ready to go</returns> public static async Task <ISSHConnection> VomsProxyInitAsync(this ISSHConnection connection, string voms, Func <bool> failNow = null, bool dumpOnly = false) { // Get the GRID VOMS password var sclist = new CredentialSet("GRID"); var passwordInfo = sclist.Load().FirstOrDefault(); if (passwordInfo == null) { throw new ArgumentException("There is no generic windows credential targeting the network address 'GRID' for username. This password should be your cert pass phrase and your on-the-grid username. Please create one on this machine."); } // Run the command bool goodProxy = false; var whatHappened = new List <string>(); var r = await connection .ExecuteLinuxCommandAsync(string.Format("echo {0} | voms-proxy-init -voms {1}", passwordInfo.Password, voms), l => { goodProxy = goodProxy || l.Contains("Your proxy is valid"); whatHappened.Add(l); }, secondsTimeout : 20, failNow : failNow, dumpOnly : dumpOnly ); // If we failed to get the proxy, then build an error message that can be understood. Since this // could be for a large range of reasons, we are going to pass back a lot of info to the user // so they can figure it out (not likely a program will be able to sort this out). if (goodProxy == false && !dumpOnly) { var error = new StringBuilder(); error.AppendLine($"Failed to get the proxy ({connection.MachineName}): "); foreach (var l in whatHappened) { error.AppendLine(string.Format(" -> {0}", l)); } throw new ArgumentException(error.ToString()); } return(connection); }
//終了のハンドリング 非同期に別スレッドから呼ばれるので注意 public void ConnectionClosed(ISSHConnection connection) { IDictionaryEnumerator e = _profileToConnection.GetEnumerator(); while (e.MoveNext()) { if (connection == e.Value) { ChannelProfile prof = (ChannelProfile)e.Key; _profileToConnection.Remove(e.Key); bool manual = false; lock (this) { manual = _manualClosingConnections.Contains(connection); if (manual) _manualClosingConnections.Remove(connection); } if (!manual) { Util.InterThreadWarning(Env.Strings.GetString("Message.ConnectionManager.Disconnected")); } Env.MainForm.Invoke(new RefreshProfileStatusDelegate(Env.MainForm.RefreshProfileStatus), prof); break; } } }
public void FixConnection(ISSHConnection con) { _connection = con; Env.Log.LogConnectionOpened(this.ChannelProfile, _id); }
/// <summary> /// Opens SFTP channel and creates a new instance. /// </summary> /// <param name="connection">SSH2 connection object</param> /// <returns>New instance.</returns> public static SFTPClient OpenSFTPChannel(ISSHConnection connection) { ISSHChannel channel = null; SFTPClientChannelEventHandler eventHandler = connection.OpenSubsystem( (ch) => { channel = ch; return new SFTPClientChannelEventHandler(); }, "sftp" ); return new SFTPClient(channel, eventHandler); }
public void ConnectionError(ISSHConnection connection, Exception error) { Debug.WriteLine(error.StackTrace); Util.InterThreadWarning(error.Message); ConnectionClosed(connection); }
public Reader(ISSHConnection conn) { _conn = conn; }
private static void DoRucioDownload(ISSHConnection connection, string localDirectory, Action<string> fileStatus, Func<bool> failNow, int timeout, string fileListName) { string filesThatFailedToDownload = ""; bool foundClockSkewMessage = false; connection.ExecuteCommand(string.Format("rucio download --dir {1} `cat {0}`", fileListName, localDirectory), l => { // Look for something that indicates which file we are currently getting from the GRID. if (fileStatus != null) { const string fileNameMarker = "Starting the download of "; var idx = l.IndexOf(fileNameMarker); if (idx >= 0) { var closeBracket = l.IndexOf(']', idx); var startOfFileName = idx + fileNameMarker.Length; fileStatus(l.Substring(startOfFileName, closeBracket - startOfFileName)); } } // Watch for the end to see the overall status if (l.Contains("Files that cannot be downloaded :")) { filesThatFailedToDownload = l.Split(' ').Where(i => !string.IsNullOrWhiteSpace(i)).Last(); } foundClockSkewMessage |= l.Contains("check clock skew between hosts."); }, refreshTimeout: true, failNow: failNow, secondsTimeout: timeout); // Check for errors that happened while running the command. if (filesThatFailedToDownload != "0") { // Special case - there was a clock skew error. if (foundClockSkewMessage) { throw new ClockSkewException($"Failed to download {filesThatFailedToDownload} files due to clock skew. Please double check!"); } // Something else - will likely require a human to get involved. throw new FileFailedToDownloadException($"Failed to download all the files from the GRID - {filesThatFailedToDownload} files failed to download!"); } }
/// <summary> /// Init the connection for use by other parts of this object. /// </summary> /// <returns></returns> private ISSHConnection InitConnection(Action<string> statusUpdater) { if (_connection != null) return _connection; if (statusUpdater != null) statusUpdater("Setting up GRID Environment"); _connection = new SSHConnection(_linuxHost, _username); _connection .setupATLAS() .setupRucio(_username) .VomsProxyInit("atlas"); return _connection; }
//SSHConnection確立時に呼ぶ public void SetSSHConnection(ISSHConnection connection) { _connection = connection; }
/// <summary> /// Opens channel. /// </summary> /// <param name="connection">SSH connection object</param> /// <param name="command">Remote command</param> /// <param name="millisecondsTimeout">timeout in milliseconds</param> /// <exception cref="SCPClientInvalidStatusException">Channel has been already opened or already closed.</exception> /// <exception cref="SCPClientTimeoutException">Timeout has occurred while waiting for READY status.</exception> public void Open(ISSHConnection connection, string command, int millisecondsTimeout) { if (_status != StreamStatus.NotOpened) throw new SCPClientInvalidStatusException(); ISSHChannel channel = null; SCPClientChannelEventHandler eventHandler = connection.ExecCommand( (ch) => { channel = ch; return new SCPClientChannelEventHandler( new DataReceivedDelegate(OnDataReceived), new ChannelStatusChangedDelegate(OnChannelStatusChanged) ); }, command ); _eventHandler = eventHandler; _channel = channel; if (!_eventHandler.WaitStatus(SCPChannelStatus.READY, millisecondsTimeout)) { throw new SCPClientTimeoutException(); } lock(_statusSync) { if (_status == StreamStatus.NotOpened) { _status = StreamStatus.Opened; } } }
/// <summary> /// Constructor /// </summary> /// <param name="connection">SSH connection. Currently only SSH2 connection is accepted.</param> public SCPClient(ISSHConnection connection) { this._connection = connection; }