forked from qt-creator/qt-creator
Docker: Improve error output when bridge fails to start
Change-Id: I86d9d3972c483d21cd2ff64d3581b518e6b0a819 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -68,22 +68,31 @@ expected_str<void> FileAccess::deployAndInit(
|
|||||||
|
|
||||||
qCDebug(faLog) << "Found dd on remote host:" << *whichDD;
|
qCDebug(faLog) << "Found dd on remote host:" << *whichDD;
|
||||||
|
|
||||||
const auto unameOs = run({remoteRootPath.withNewPath("uname"), {"-s"}});
|
const expected_str<QString> unameOs = run({remoteRootPath.withNewPath("uname"), {"-s"}});
|
||||||
if (!unameOs)
|
if (!unameOs) {
|
||||||
return make_unexpected(
|
return make_unexpected(
|
||||||
QString("Could not determine OS on remote host: %1").arg(unameOs.error()));
|
QString("Could not determine OS on remote host: %1").arg(unameOs.error()));
|
||||||
|
}
|
||||||
|
Utils::expected_str<OsType> osType = osTypeFromString(unameOs.value());
|
||||||
|
if (!osType)
|
||||||
|
return make_unexpected(osType.error());
|
||||||
|
|
||||||
qCDebug(faLog) << "Remote host OS:" << *unameOs;
|
qCDebug(faLog) << "Remote host OS:" << *unameOs;
|
||||||
|
|
||||||
const auto unameArch = run({remoteRootPath.withNewPath("uname"), {"-m"}});
|
const expected_str<QString> unameArch = run({remoteRootPath.withNewPath("uname"), {"-m"}});
|
||||||
if (!unameArch)
|
if (!unameArch) {
|
||||||
return make_unexpected(
|
return make_unexpected(
|
||||||
QString("Could not determine architecture on remote host: %1").arg(unameArch.error()));
|
QString("Could not determine architecture on remote host: %1").arg(unameArch.error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Utils::expected_str<OsArch> osArch = osArchFromString(unameArch.value());
|
||||||
|
if (!osArch)
|
||||||
|
return make_unexpected(osArch.error());
|
||||||
|
|
||||||
qCDebug(faLog) << "Remote host architecture:" << *unameArch;
|
qCDebug(faLog) << "Remote host architecture:" << *unameArch;
|
||||||
|
|
||||||
const Utils::expected_str<Utils::FilePath> cmdBridgePath = Client::getCmdBridgePath(
|
const Utils::expected_str<Utils::FilePath> cmdBridgePath
|
||||||
osTypeFromString(unameOs.value()), osArchFromString(unameArch.value()), libExecPath);
|
= Client::getCmdBridgePath(*osType, *osArch, libExecPath);
|
||||||
|
|
||||||
if (!cmdBridgePath) {
|
if (!cmdBridgePath) {
|
||||||
return make_unexpected(
|
return make_unexpected(
|
||||||
|
@@ -259,15 +259,19 @@ expected_str<QFuture<Environment>> Client::start()
|
|||||||
d->jobs.writeLocked()->map.insert(-1, [envPromise](QVariantMap map) {
|
d->jobs.writeLocked()->map.insert(-1, [envPromise](QVariantMap map) {
|
||||||
envPromise->start();
|
envPromise->start();
|
||||||
QString type = map.value("Type").toString();
|
QString type = map.value("Type").toString();
|
||||||
QTC_CHECK(type == "environment");
|
|
||||||
if (type == "environment") {
|
if (type == "environment") {
|
||||||
OsType osType = osTypeFromString(map.value("OsType").toString());
|
expected_str<OsType> osType = osTypeFromString(map.value("OsType").toString());
|
||||||
Environment env(map.value("Env").toStringList(), osType);
|
QTC_CHECK_EXPECTED(osType);
|
||||||
|
Environment env(map.value("Env").toStringList(), osType.value_or(OsTypeLinux));
|
||||||
envPromise->addResult(env);
|
envPromise->addResult(env);
|
||||||
} else if (type == "error") {
|
} else if (type == "error") {
|
||||||
QString err = map.value("Error", QString{}).toString();
|
QString err = map.value("Error", QString{}).toString();
|
||||||
qCWarning(clientLog) << "Error: " << err;
|
qCWarning(clientLog) << "Error: " << err;
|
||||||
envPromise->setException(std::make_exception_ptr(std::runtime_error(err.toStdString())));
|
envPromise->setException(std::make_exception_ptr(std::runtime_error(err.toStdString())));
|
||||||
|
} else {
|
||||||
|
qCWarning(clientLog) << "Unknown initial response type: " << type;
|
||||||
|
envPromise->setException(
|
||||||
|
std::make_exception_ptr(std::runtime_error("Unknown response type")));
|
||||||
}
|
}
|
||||||
|
|
||||||
envPromise->finish();
|
envPromise->finish();
|
||||||
@@ -284,9 +288,11 @@ expected_str<QFuture<Environment>> Client::start()
|
|||||||
|
|
||||||
connect(d->process, &Process::done, d->process, [this] {
|
connect(d->process, &Process::done, d->process, [this] {
|
||||||
if (d->process->resultData().m_exitCode != 0) {
|
if (d->process->resultData().m_exitCode != 0) {
|
||||||
qCWarning(clientLog).noquote() << d->process->resultData().m_errorString;
|
qCWarning(clientLog)
|
||||||
qCWarning(clientLog).noquote() << d->process->readAllStandardError();
|
<< "Process exited with error code:" << d->process->resultData().m_exitCode
|
||||||
qCWarning(clientLog).noquote() << d->process->readAllStandardOutput();
|
<< "Error:" << d->process->errorString()
|
||||||
|
<< "StandardError:" << d->process->readAllStandardError()
|
||||||
|
<< "StandardOutput:" << d->process->readAllStandardOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto j = d->jobs.writeLocked();
|
auto j = d->jobs.writeLocked();
|
||||||
|
@@ -31,7 +31,8 @@ bool HostOsInfo::m_useOverrideFileNameCaseSensitivity = false;
|
|||||||
|
|
||||||
OsArch HostOsInfo::hostArchitecture()
|
OsArch HostOsInfo::hostArchitecture()
|
||||||
{
|
{
|
||||||
static const OsArch arch = osArchFromString(QSysInfo::currentCpuArchitecture());
|
static const OsArch arch
|
||||||
|
= osArchFromString(QSysInfo::currentCpuArchitecture()).value_or(OsArchUnknown);
|
||||||
return arch;
|
return arch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "expected.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -33,7 +36,7 @@ inline QString osTypeToString(OsType osType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline OsType osTypeFromString(const QString &string)
|
inline Utils::expected_str<OsType> osTypeFromString(const QString &string)
|
||||||
{
|
{
|
||||||
if (string.compare("windows", Qt::CaseInsensitive) == 0)
|
if (string.compare("windows", Qt::CaseInsensitive) == 0)
|
||||||
return OsTypeWindows;
|
return OsTypeWindows;
|
||||||
@@ -44,10 +47,11 @@ inline OsType osTypeFromString(const QString &string)
|
|||||||
return OsTypeMac;
|
return OsTypeMac;
|
||||||
if (string.compare("other unix", Qt::CaseInsensitive) == 0)
|
if (string.compare("other unix", Qt::CaseInsensitive) == 0)
|
||||||
return OsTypeOtherUnix;
|
return OsTypeOtherUnix;
|
||||||
return OsTypeOther;
|
|
||||||
|
return Utils::make_unexpected(QString::fromLatin1("Unknown os type: %1").arg(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline OsArch osArchFromString(const QString &architecture)
|
inline Utils::expected_str<OsArch> osArchFromString(const QString &architecture)
|
||||||
{
|
{
|
||||||
if (architecture == QLatin1String("x86_64"))
|
if (architecture == QLatin1String("x86_64"))
|
||||||
return OsArchAMD64;
|
return OsArchAMD64;
|
||||||
@@ -59,7 +63,8 @@ inline OsArch osArchFromString(const QString &architecture)
|
|||||||
return OsArchArm;
|
return OsArchArm;
|
||||||
if (architecture == QLatin1String("arm64") || architecture == QLatin1String("aarch64"))
|
if (architecture == QLatin1String("arm64") || architecture == QLatin1String("aarch64"))
|
||||||
return OsArchArm64;
|
return OsArchArm64;
|
||||||
return OsArchUnknown;
|
|
||||||
|
return Utils::make_unexpected(QString::fromLatin1("Unknown architecture: %1").arg(architecture));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace OsSpecificAspects {
|
namespace OsSpecificAspects {
|
||||||
|
@@ -313,7 +313,7 @@ public:
|
|||||||
QString repoAndTagEncoded() const { return deviceSettings->repoAndTagEncoded(); }
|
QString repoAndTagEncoded() const { return deviceSettings->repoAndTagEncoded(); }
|
||||||
QString dockerImageId() const { return deviceSettings->imageId(); }
|
QString dockerImageId() const { return deviceSettings->imageId(); }
|
||||||
|
|
||||||
QPair<Utils::OsType, Utils::OsArch> osTypeAndArch() const;
|
expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const;
|
||||||
|
|
||||||
expected_str<Environment> environment();
|
expected_str<Environment> environment();
|
||||||
|
|
||||||
@@ -332,6 +332,8 @@ public:
|
|||||||
void stopCurrentContainer();
|
void stopCurrentContainer();
|
||||||
expected_str<void> fetchSystemEnviroment();
|
expected_str<void> fetchSystemEnviroment();
|
||||||
|
|
||||||
|
expected_str<FilePath> getCmdBridgePath() const;
|
||||||
|
|
||||||
std::optional<FilePath> clangdExecutable() const
|
std::optional<FilePath> clangdExecutable() const
|
||||||
{
|
{
|
||||||
if (deviceSettings->clangdExecutable().isEmpty())
|
if (deviceSettings->clangdExecutable().isEmpty())
|
||||||
@@ -594,7 +596,22 @@ DockerDevice::DockerDevice(std::unique_ptr<DockerDeviceSettings> deviceSettings)
|
|||||||
: ProjectExplorer::IDevice(std::move(deviceSettings))
|
: ProjectExplorer::IDevice(std::move(deviceSettings))
|
||||||
, d(new DockerDevicePrivate(this))
|
, d(new DockerDevicePrivate(this))
|
||||||
{
|
{
|
||||||
setFileAccess([this]() -> DeviceFileAccess * {
|
auto createBridgeFileAccess = [this]() -> expected_str<std::unique_ptr<DeviceFileAccess>> {
|
||||||
|
expected_str<FilePath> cmdBridgePath = d->getCmdBridgePath();
|
||||||
|
|
||||||
|
if (!cmdBridgePath)
|
||||||
|
return make_unexpected(cmdBridgePath.error());
|
||||||
|
|
||||||
|
auto fAccess = std::make_unique<DockerDeviceFileAccess>(d);
|
||||||
|
expected_str<void> initResult = fAccess->init(
|
||||||
|
rootPath().withNewPath("/tmp/_qtc_cmdbridge"));
|
||||||
|
if (!initResult)
|
||||||
|
return make_unexpected(initResult.error());
|
||||||
|
|
||||||
|
return fAccess;
|
||||||
|
};
|
||||||
|
|
||||||
|
setFileAccess([this, createBridgeFileAccess]() -> DeviceFileAccess * {
|
||||||
if (DeviceFileAccess *fileAccess = d->m_fileAccess.readLocked()->get())
|
if (DeviceFileAccess *fileAccess = d->m_fileAccess.readLocked()->get())
|
||||||
return fileAccess;
|
return fileAccess;
|
||||||
|
|
||||||
@@ -603,15 +620,16 @@ DockerDevice::DockerDevice(std::unique_ptr<DockerDeviceSettings> deviceSettings)
|
|||||||
if (*fileAccess)
|
if (*fileAccess)
|
||||||
return fileAccess->get();
|
return fileAccess->get();
|
||||||
|
|
||||||
auto fAccess = std::make_unique<DockerDeviceFileAccess>(d);
|
expected_str<std::unique_ptr<DeviceFileAccess>> fAccess = createBridgeFileAccess();
|
||||||
expected_str<void> initResult = fAccess->init(
|
|
||||||
rootPath().withNewPath("/tmp/_qtc_cmdbridge"));
|
if (fAccess) {
|
||||||
QTC_CHECK_EXPECTED(initResult);
|
*fileAccess = std::move(*fAccess);
|
||||||
if (initResult) {
|
|
||||||
*fileAccess = std::move(fAccess);
|
|
||||||
return fileAccess->get();
|
return fileAccess->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qCWarning(dockerDeviceLog) << "Failed to start CmdBridge:" << fAccess.error()
|
||||||
|
<< ", falling back to slow direct access";
|
||||||
|
|
||||||
*fileAccess = std::make_unique<DockerFallbackFileAccess>(rootPath());
|
*fileAccess = std::make_unique<DockerFallbackFileAccess>(rootPath());
|
||||||
return fileAccess->get();
|
return fileAccess->get();
|
||||||
});
|
});
|
||||||
@@ -835,13 +853,18 @@ expected_str<void> isValidMountInfo(const DockerDevicePrivate::MountPair &mi)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DockerDevicePrivate::createMountArgs() const
|
expected_str<FilePath> DockerDevicePrivate::getCmdBridgePath() const
|
||||||
{
|
{
|
||||||
auto osAndArch = osTypeAndArch();
|
auto osAndArch = osTypeAndArch();
|
||||||
|
if (!osAndArch)
|
||||||
|
return make_unexpected(osAndArch.error());
|
||||||
|
return CmdBridge::Client::getCmdBridgePath(
|
||||||
|
osAndArch->first, osAndArch->second, Core::ICore::libexecPath());
|
||||||
|
};
|
||||||
|
|
||||||
const Utils::expected_str<Utils::FilePath> cmdBridgePath = CmdBridge::Client::getCmdBridgePath(
|
QStringList DockerDevicePrivate::createMountArgs() const
|
||||||
osAndArch.first, osAndArch.second, Core::ICore::libexecPath());
|
{
|
||||||
|
const Utils::expected_str<Utils::FilePath> cmdBridgePath = getCmdBridgePath();
|
||||||
QTC_CHECK_EXPECTED(cmdBridgePath);
|
QTC_CHECK_EXPECTED(cmdBridgePath);
|
||||||
|
|
||||||
QStringList cmds;
|
QStringList cmds;
|
||||||
@@ -1325,7 +1348,7 @@ void DockerDeviceFactory::shutdownExistingDevices()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<Utils::OsType, Utils::OsArch> DockerDevicePrivate::osTypeAndArch() const
|
expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAndArch() const
|
||||||
{
|
{
|
||||||
Process proc;
|
Process proc;
|
||||||
proc.setCommand(
|
proc.setCommand(
|
||||||
@@ -1333,13 +1356,21 @@ QPair<Utils::OsType, Utils::OsArch> DockerDevicePrivate::osTypeAndArch() const
|
|||||||
{"image", "inspect", repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}});
|
{"image", "inspect", repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}});
|
||||||
proc.runBlocking();
|
proc.runBlocking();
|
||||||
if (proc.result() != ProcessResult::FinishedWithSuccess)
|
if (proc.result() != ProcessResult::FinishedWithSuccess)
|
||||||
return {Utils::OsType::OsTypeOther, Utils::OsArch::OsArchUnknown};
|
return make_unexpected(Tr::tr("Failed to inspect image: %1").arg(proc.allOutput()));
|
||||||
|
|
||||||
const QString out = proc.cleanedStdOut().trimmed();
|
const QString out = proc.cleanedStdOut().trimmed();
|
||||||
const QStringList parts = out.split('\t');
|
const QStringList parts = out.split('\t');
|
||||||
if (parts.size() != 2)
|
if (parts.size() != 2)
|
||||||
return {Utils::OsType::OsTypeOther, Utils::OsArch::OsArchUnknown};
|
return make_unexpected(Tr::tr("Could not parse image inspect output: %1").arg(out));
|
||||||
return {osTypeFromString(parts.at(0)), osArchFromString(parts.at(1))};
|
|
||||||
|
auto os = osTypeFromString(parts.at(0));
|
||||||
|
auto arch = osArchFromString(parts.at(1));
|
||||||
|
if (!os)
|
||||||
|
return make_unexpected(os.error());
|
||||||
|
if (!arch)
|
||||||
|
return make_unexpected(arch.error());
|
||||||
|
|
||||||
|
return qMakePair(os.value(), arch.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
expected_str<Environment> DockerDevicePrivate::environment()
|
expected_str<Environment> DockerDevicePrivate::environment()
|
||||||
|
@@ -500,7 +500,7 @@ void IDevice::fromMap(const Store &map)
|
|||||||
settings()->fromMap(map);
|
settings()->fromMap(map);
|
||||||
|
|
||||||
d->id = Id::fromSetting(map.value(IdKey));
|
d->id = Id::fromSetting(map.value(IdKey));
|
||||||
d->osType = osTypeFromString(map.value(ClientOsTypeKey, osTypeToString(OsTypeLinux)).toString());
|
d->osType = osTypeFromString(map.value(ClientOsTypeKey).toString()).value_or(OsTypeLinux);
|
||||||
if (!d->id.isValid())
|
if (!d->id.isValid())
|
||||||
d->id = newId();
|
d->id = newId();
|
||||||
d->origin = static_cast<Origin>(map.value(OriginKey, ManuallyAdded).toInt());
|
d->origin = static_cast<Origin>(map.value(OriginKey, ManuallyAdded).toInt());
|
||||||
|
Reference in New Issue
Block a user