added callbacks for output from a remote host

This commit is contained in:
vladimir.kuznetsov 2022-12-21 08:13:06 +03:00
parent c8085a368f
commit 5075fe358e
5 changed files with 90 additions and 66 deletions

View file

@ -76,7 +76,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
{ {
QString script = QString("cat %1 | grep AllowedIPs").arg(amnezia::protocols::wireguard::serverConfigPath); QString script = QString("cat %1 | grep AllowedIPs").arg(amnezia::protocols::wireguard::serverConfigPath);
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };

View file

@ -93,8 +93,8 @@ ErrorCode ServerController::connectToHost(const ServerCredentials &credentials,
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script, ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut, const std::function<void(const QString &)> &cbReadStdOut,
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr) { const std::function<void(const QString &)> &cbReadStdErr) {
std::shared_ptr<SshSession> session = m_sshClient.getSession(); std::shared_ptr<SshSession> session = m_sshClient.getSession();
if (!session) { if (!session) {
@ -137,7 +137,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
qDebug().noquote() << "EXEC" << lineToExec; qDebug().noquote() << "EXEC" << lineToExec;
Debug::appendSshLog("Run command:" + lineToExec); Debug::appendSshLog("Run command:" + lineToExec);
error = session->writeToChannel(lineToExec); error = session->writeToChannel(lineToExec, cbReadStdOut, cbReadStdErr);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
return error; return error;
} }
@ -150,8 +150,8 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials, ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials,
DockerContainer container, QString script, DockerContainer container, QString script,
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut, const std::function<void (const QString &)> &cbReadStdOut,
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr) const std::function<void (const QString &)> &cbReadStdErr)
{ {
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh"; QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
Debug::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + QStringLiteral(":\n") + script); Debug::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + QStringLiteral(":\n") + script);
@ -183,7 +183,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
if (e) return e; if (e) return e;
QString stdOut; QString stdOut;
auto cbReadStd = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) { auto cbReadStd = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
@ -245,7 +245,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data; stdOut += data;
}; };
@ -596,14 +596,14 @@ bool ServerController::isReinstallContainerRequred(DockerContainer container, co
ErrorCode ServerController::installDockerWorker(const ServerCredentials &credentials, DockerContainer container) ErrorCode ServerController::installDockerWorker(const ServerCredentials &credentials, DockerContainer container)
{ {
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
// if (data.contains("Automatically restart Docker daemon?")) { // if (data.contains("Automatically restart Docker daemon?")) {
// proc->write("yes\n"); // proc->write("yes\n");
// } // }
}; };
auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) { auto cbReadStdErr = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
@ -633,7 +633,7 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
if (e) return e; if (e) return e;
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { // auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
@ -651,7 +651,7 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config) ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
{ {
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { // auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
@ -677,10 +677,10 @@ ErrorCode ServerController::runContainerWorker(const ServerCredentials &credenti
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config) ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
{ {
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdErr = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
@ -813,10 +813,10 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
QString ServerController::checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode) QString ServerController::checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode)
{ {
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) { auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };
auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) { auto cbReadStdErr = [&](const QString &data) {
stdOut += data + "\n"; stdOut += data + "\n";
}; };

View file

@ -67,12 +67,12 @@ public:
QString replaceVars(const QString &script, const Vars &vars); QString replaceVars(const QString &script, const Vars &vars);
ErrorCode runScript(const ServerCredentials &credentials, QString script, ErrorCode runScript(const ServerCredentials &credentials, QString script,
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut = nullptr, const std::function<void(const QString &)> &cbReadStdOut = nullptr,
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr = nullptr); const std::function<void(const QString &)> &cbReadStdErr = nullptr);
ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script, ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut = nullptr, const std::function<void(const QString &)> &cbReadStdOut = nullptr,
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr = nullptr); const std::function<void(const QString &)> &cbReadStdErr = nullptr);
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject()); Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());

View file

@ -86,6 +86,7 @@ ErrorCode SshSession::initChannel(const ServerCredentials &credentials)
if (result == SSH_OK && ssh_channel_is_open(m_channel)) { if (result == SSH_OK && ssh_channel_is_open(m_channel)) {
qDebug() << "SSH chanel opened"; qDebug() << "SSH chanel opened";
m_isChannelOpened = true;
} else { } else {
qDebug() << ssh_get_error(m_session); qDebug() << ssh_get_error(m_session);
return ErrorCode::SshAuthenticationError; return ErrorCode::SshAuthenticationError;
@ -103,22 +104,80 @@ ErrorCode SshSession::initChannel(const ServerCredentials &credentials)
return ErrorCode::SshInternalError; return ErrorCode::SshInternalError;
} }
result = ssh_channel_request_shell(m_channel); // result = ssh_channel_request_shell(m_channel);
if (result != SSH_OK) { // if (result != SSH_OK) {
qDebug() << ssh_get_error(m_session); // qDebug() << ssh_get_error(m_session);
return ErrorCode::SshInternalError; // return ErrorCode::SshInternalError;
} // }
return ErrorCode::NoError; return ErrorCode::NoError;
} }
ErrorCode SshSession::writeToChannel(const QString &data) ErrorCode SshSession::writeToChannel(const QString &data,
const std::function<void(const QString &)> &cbReadStdOut,
const std::function<void(const QString &)> &cbReadStdErr)
{ {
QFutureWatcher<ErrorCode> watcher; QFutureWatcher<ErrorCode> watcher;
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, this, &SshSession::writeToChannelFinished); connect(&watcher, &QFutureWatcher<ErrorCode>::finished, this, &SshSession::writeToChannelFinished);
QFuture<ErrorCode> future = QtConcurrent::run([this, &data]() { QFuture<ErrorCode> future = QtConcurrent::run([this, &data, &cbReadStdOut, &cbReadStdErr]() {
return write(data); const int channelReadTimeoutMs = 10;
const size_t bufferSize = 2048;
int bytesRead = 0;
int attempts = 0;
char buffer[bufferSize];
std::string output1;
if (ssh_channel_is_open(m_channel) && !ssh_channel_is_eof(m_channel)) {
bytesRead = ssh_channel_read_timeout(m_channel, buffer, sizeof(buffer), 0, channelReadTimeoutMs);
while (bytesRead > 0)
{
output1.append(buffer, bytesRead);
bytesRead = ssh_channel_read_timeout(m_channel, buffer, sizeof(buffer), 0, channelReadTimeoutMs);
}
}
qDebug().noquote() << "stdOut: " << QString(output1.c_str());
int bytesWritten = ssh_channel_write(m_channel, data.toUtf8(), (uint32_t)data.size());
if (bytesWritten == data.size()) {
std::string stdOut;
std::string stdErr;
auto readOutput = [&](bool isStdErr) {
std::string output;
if (ssh_channel_is_open(m_channel) && !ssh_channel_is_eof(m_channel)) {
bytesRead = ssh_channel_read_timeout(m_channel, buffer, sizeof(buffer), isStdErr, channelReadTimeoutMs);
while (bytesRead > 0)
{
output.append(buffer, bytesRead);
bytesRead = ssh_channel_read_timeout(m_channel, buffer, sizeof(buffer), isStdErr, channelReadTimeoutMs);
}
}
return output;
};
stdOut = readOutput(false);
stdErr = readOutput(true);
if (cbReadStdOut){
cbReadStdOut(stdOut.c_str());
}
if (cbReadStdErr){
cbReadStdErr(stdErr.c_str());
}
if (!stdOut.empty()) {
qDebug().noquote() << "stdOut: " << QString(stdOut.c_str());
}
if (!stdErr.empty()) {
qDebug().noquote() << "stdErr: " << QString(stdOut.c_str());
}
} else {
qDebug() << ssh_get_error(m_session);
return ErrorCode::SshInternalError;
}
m_isNeedSendChannelEof = true;
return ErrorCode::NoError;
}); });
watcher.setFuture(future); watcher.setFuture(future);
@ -129,39 +188,3 @@ ErrorCode SshSession::writeToChannel(const QString &data)
return watcher.result(); return watcher.result();
} }
ErrorCode SshSession::write(const QString &data)
{
const int channelReadTimeoutMs = 10;
const size_t bufferSize = 2048;
int bytesToRead = 0;
int attempts = 0;
char buffer[bufferSize];
int bytesWritten = ssh_channel_write(m_channel, data.toUtf8(), (uint32_t)data.size());
if (bytesWritten == data.size()) {
while (bytesToRead != 0 || attempts < 100){
if (ssh_channel_is_open(m_channel) && !ssh_channel_is_eof(m_channel)) {
bytesToRead = ssh_channel_read_timeout(m_channel, buffer, sizeof(buffer), 0, channelReadTimeoutMs);
if (bytesToRead > 0) {
attempts = 0;
std::string strbuf(buffer, bytesToRead);
// QByteArray qbuff(buffer, bytesToRead);
// QString outp(buffer);
// if (cbReadStdOut){
// cbReadStdOut(outp, nullptr);
// }
qDebug().noquote() << QString(strbuf.c_str());
} else {
attempts++;
}
}
}
} else {
qDebug() << ssh_get_error(m_session);
return ErrorCode::SshInternalError;
}
return ErrorCode::NoError;
}

View file

@ -18,10 +18,11 @@ public:
~SshSession(); ~SshSession();
ErrorCode initChannel(const ServerCredentials &credentials); ErrorCode initChannel(const ServerCredentials &credentials);
ErrorCode writeToChannel(const QString &data); ErrorCode writeToChannel(const QString &data,
const std::function<void(const QString &)> &cbReadStdOut,
const std::function<void(const QString &)> &cbReadStdErr);
private: private:
ErrorCode connectToHost(const ServerCredentials &credentials); ErrorCode connectToHost(const ServerCredentials &credentials);
ErrorCode write(const QString &data);
ssh_session m_session; ssh_session m_session;
ssh_channel m_channel; ssh_channel m_channel;