forked from qt-creator/qt-creator
Docker: Handle daemon globally
The daemon state is not a device dependent setting. Change-Id: Ic972fdc5cbb06395e04709858312b4d336321577 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#include "dockerdevice.h"
|
#include "dockerdevice.h"
|
||||||
|
|
||||||
#include "dockerconstants.h"
|
#include "dockerconstants.h"
|
||||||
|
#include "dockerplugin.h"
|
||||||
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
@@ -329,14 +330,6 @@ public:
|
|||||||
QFileSystemWatcher m_mergedDirWatcher;
|
QFileSystemWatcher m_mergedDirWatcher;
|
||||||
|
|
||||||
Environment m_cachedEnviroment;
|
Environment m_cachedEnviroment;
|
||||||
|
|
||||||
enum LocalAccessState
|
|
||||||
{
|
|
||||||
NotEvaluated,
|
|
||||||
NoDaemon,
|
|
||||||
Accessible,
|
|
||||||
NotAccessible
|
|
||||||
} m_accessible = NotEvaluated;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DockerDeviceWidget final : public IDeviceWidget
|
class DockerDeviceWidget final : public IDeviceWidget
|
||||||
@@ -364,16 +357,15 @@ public:
|
|||||||
|
|
||||||
auto daemonStateLabel = new QLabel(tr("Daemon state:"));
|
auto daemonStateLabel = new QLabel(tr("Daemon state:"));
|
||||||
m_daemonReset = new QToolButton;
|
m_daemonReset = new QToolButton;
|
||||||
m_daemonReset->setIcon(Icons::INFO.icon());
|
|
||||||
m_daemonReset->setToolTip(tr("Clear detected daemon state. "
|
m_daemonReset->setToolTip(tr("Clear detected daemon state. "
|
||||||
"It will be automatically re-evaluated next time an access is needed."));
|
"It will be automatically re-evaluated next time an access is needed."));
|
||||||
|
|
||||||
m_daemonState = new QLabel(tr("Daemon state not evaluated."));
|
m_daemonState = new QLabel;
|
||||||
|
updateDaemonStateTexts();
|
||||||
|
|
||||||
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
|
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
|
||||||
dockerDevice->resetDaemonState();
|
DockerPlugin::setGlobalDaemonState(Utils::nullopt);
|
||||||
m_daemonReset->setIcon(Icons::INFO.icon());
|
updateDaemonStateTexts();
|
||||||
m_daemonState->setText(tr("Daemon state not evaluated."));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
|
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
|
||||||
@@ -410,16 +402,11 @@ public:
|
|||||||
dockerDevice->tryCreateLocalFileAccess();
|
dockerDevice->tryCreateLocalFileAccess();
|
||||||
m_kitItemDetector.autoDetect(id);
|
m_kitItemDetector.autoDetect(id);
|
||||||
|
|
||||||
if (!dockerDevice->isDaemonRunning()) {
|
if (DockerPlugin::isDaemonRunning().value_or(false) == false)
|
||||||
logView->append(tr("Docker daemon appears to be not running."));
|
logView->append(tr("Docker daemon appears to be not running."));
|
||||||
m_daemonState->setText(tr("Docker daemon not running."));
|
else
|
||||||
m_daemonReset->setIcon(Icons::CRITICAL.icon());
|
|
||||||
} else {
|
|
||||||
logView->append(tr("Docker daemon appears to be running."));
|
logView->append(tr("Docker daemon appears to be running."));
|
||||||
m_daemonState->setText(tr("Docker daemon running."));
|
updateDaemonStateTexts();
|
||||||
m_daemonReset->setIcon(Icons::OK.icon());
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, id = data.id()] {
|
connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, id = data.id()] {
|
||||||
@@ -450,6 +437,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateDeviceFromUi() final {}
|
void updateDeviceFromUi() final {}
|
||||||
|
void updateDaemonStateTexts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLineEdit *m_idLineEdit;
|
QLineEdit *m_idLineEdit;
|
||||||
@@ -753,7 +741,7 @@ void DockerDevice::tryCreateLocalFileAccess() const
|
|||||||
|
|
||||||
void DockerDevicePrivate::stopCurrentContainer()
|
void DockerDevicePrivate::stopCurrentContainer()
|
||||||
{
|
{
|
||||||
if (m_container.isEmpty() || m_accessible == NoDaemon)
|
if (m_container.isEmpty() || !DockerPlugin::isDaemonRunning().value_or(false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_shell) {
|
if (m_shell) {
|
||||||
@@ -821,7 +809,7 @@ void DockerDevicePrivate::startContainer()
|
|||||||
// negative exit codes indicate problems like no docker daemon, missing permissions,
|
// negative exit codes indicate problems like no docker daemon, missing permissions,
|
||||||
// no shell and seem to result in exit codes 125+
|
// no shell and seem to result in exit codes 125+
|
||||||
if (m_shell->exitCode() > 120) {
|
if (m_shell->exitCode() > 120) {
|
||||||
m_accessible = NoDaemon;
|
DockerPlugin::setGlobalDaemonState(false);
|
||||||
LOG("DOCKER DAEMON NOT RUNNING?");
|
LOG("DOCKER DAEMON NOT RUNNING?");
|
||||||
MessageManager::writeFlashing(tr("Docker Daemon appears to be not running. "
|
MessageManager::writeFlashing(tr("Docker Daemon appears to be not running. "
|
||||||
"Verify daemon is up and running and reset the "
|
"Verify daemon is up and running and reset the "
|
||||||
@@ -836,6 +824,7 @@ void DockerDevicePrivate::startContainer()
|
|||||||
m_shell->waitForStarted();
|
m_shell->waitForStarted();
|
||||||
|
|
||||||
if (m_shell->state() != QProcess::Running) {
|
if (m_shell->state() != QProcess::Running) {
|
||||||
|
DockerPlugin::setGlobalDaemonState(false);
|
||||||
LOG("DOCKER SHELL FAILED");
|
LOG("DOCKER SHELL FAILED");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -850,22 +839,24 @@ void DockerDevicePrivate::startContainer()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == 20 || m_accessible == NoDaemon) {
|
if (i == 20 || !DockerPlugin::isDaemonRunning().value_or(true)) {
|
||||||
qWarning("Docker cid file empty.");
|
qWarning("Docker cid file empty.");
|
||||||
return; // No
|
return; // No
|
||||||
}
|
}
|
||||||
qApp->processEvents(); // FIXME turn this for-loop into QEventLoop
|
qApp->processEvents(); // FIXME turn this for-loop into
|
||||||
QThread::msleep(100);
|
QThread::msleep(100);
|
||||||
}
|
}
|
||||||
|
DockerPlugin::setGlobalDaemonState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockerDevicePrivate::tryCreateLocalFileAccess()
|
void DockerDevicePrivate::tryCreateLocalFileAccess()
|
||||||
{
|
{
|
||||||
if (!m_container.isEmpty() || m_accessible == NoDaemon)
|
if (!m_container.isEmpty() || DockerPlugin::isDaemonRunning().value_or(true) == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
startContainer();
|
startContainer();
|
||||||
|
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
||||||
|
return;
|
||||||
QtcProcess proc;
|
QtcProcess proc;
|
||||||
proc.setCommand({"docker", {"inspect", "--format={{.GraphDriver.Data.MergedDir}}", m_container}});
|
proc.setCommand({"docker", {"inspect", "--format={{.GraphDriver.Data.MergedDir}}", m_container}});
|
||||||
LOG(proc.commandLine().toUserOutput());
|
LOG(proc.commandLine().toUserOutput());
|
||||||
@@ -889,13 +880,11 @@ void DockerDevicePrivate::tryCreateLocalFileAccess()
|
|||||||
// of using wsl or a named pipe.
|
// of using wsl or a named pipe.
|
||||||
// TODO investigate how to make it possible nevertheless.
|
// TODO investigate how to make it possible nevertheless.
|
||||||
m_mergedDir.clear();
|
m_mergedDir.clear();
|
||||||
m_accessible = NotAccessible;
|
|
||||||
MessageManager::writeSilently(tr("This is expected on Windows."));
|
MessageManager::writeSilently(tr("This is expected on Windows."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_accessible = Accessible;
|
|
||||||
m_mergedDirWatcher.addPath(m_mergedDir);
|
m_mergedDirWatcher.addPath(m_mergedDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,24 +893,6 @@ bool DockerDevice::hasLocalFileAccess() const
|
|||||||
return !d->m_mergedDir.isEmpty();
|
return !d->m_mergedDir.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isDaemonRunning() const
|
|
||||||
{
|
|
||||||
switch (d->m_accessible) {
|
|
||||||
case DockerDevicePrivate::NoDaemon:
|
|
||||||
return false;
|
|
||||||
case DockerDevicePrivate::NotEvaluated: // FIXME?
|
|
||||||
case DockerDevicePrivate::Accessible:
|
|
||||||
case DockerDevicePrivate::NotAccessible:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DockerDevice::resetDaemonState()
|
|
||||||
{
|
|
||||||
d->m_accessible = DockerDevicePrivate::NotEvaluated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DockerDevice::setMounts(const QStringList &mounts) const
|
void DockerDevice::setMounts(const QStringList &mounts) const
|
||||||
{
|
{
|
||||||
d->m_data.mounts = mounts;
|
d->m_data.mounts = mounts;
|
||||||
@@ -1394,7 +1365,9 @@ bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray
|
|||||||
void DockerDevice::runProcess(QtcProcess &process) const
|
void DockerDevice::runProcess(QtcProcess &process) const
|
||||||
{
|
{
|
||||||
tryCreateLocalFileAccess();
|
tryCreateLocalFileAccess();
|
||||||
if (d->m_container.isEmpty() || d->m_accessible == DockerDevicePrivate::NoDaemon) {
|
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
||||||
|
return;
|
||||||
|
if (d->m_container.isEmpty()) {
|
||||||
LOG("No container set to run " << process.commandLine().toUserOutput());
|
LOG("No container set to run " << process.commandLine().toUserOutput());
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
process.setResult(QtcProcess::StartFailed);
|
process.setResult(QtcProcess::StartFailed);
|
||||||
@@ -1410,7 +1383,7 @@ void DockerDevice::runProcess(QtcProcess &process) const
|
|||||||
cmd.addArgs({"-w", workingDir.path()});
|
cmd.addArgs({"-w", workingDir.path()});
|
||||||
if (process.keepsWriteChannelOpen())
|
if (process.keepsWriteChannelOpen())
|
||||||
cmd.addArg("-i");
|
cmd.addArg("-i");
|
||||||
if (env.size() != 0 && d->m_accessible != DockerDevicePrivate::Accessible) {
|
if (env.size() != 0 && hasLocalFileAccess()) {
|
||||||
process.unsetEnvironment();
|
process.unsetEnvironment();
|
||||||
// FIXME the below would be probably correct if the respective tools would use correct
|
// FIXME the below would be probably correct if the respective tools would use correct
|
||||||
// environment already, but most are using the host environment which usually makes
|
// environment already, but most are using the host environment which usually makes
|
||||||
@@ -1460,7 +1433,7 @@ void DockerDevicePrivate::fetchSystemEnviroment()
|
|||||||
|
|
||||||
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
||||||
{
|
{
|
||||||
if (m_accessible == NoDaemon)
|
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
||||||
return false;
|
return false;
|
||||||
CommandLine dcmd{"docker", {"exec", m_container}};
|
CommandLine dcmd{"docker", {"exec", m_container}};
|
||||||
dcmd.addArgs(cmd);
|
dcmd.addArgs(cmd);
|
||||||
@@ -1478,7 +1451,7 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
|||||||
|
|
||||||
bool DockerDevicePrivate::runInShell(const CommandLine &cmd) const
|
bool DockerDevicePrivate::runInShell(const CommandLine &cmd) const
|
||||||
{
|
{
|
||||||
if (m_accessible == NoDaemon)
|
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
||||||
return false;
|
return false;
|
||||||
QTC_ASSERT(m_shell, return false);
|
QTC_ASSERT(m_shell, return false);
|
||||||
QMutexLocker l(&m_shellMutex);
|
QMutexLocker l(&m_shellMutex);
|
||||||
@@ -1500,7 +1473,7 @@ static QByteArray randomHex()
|
|||||||
|
|
||||||
QString DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
|
QString DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
|
||||||
{
|
{
|
||||||
if (m_accessible == NoDaemon)
|
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
||||||
return {};
|
return {};
|
||||||
QTC_ASSERT(m_shell, return {});
|
QTC_ASSERT(m_shell, return {});
|
||||||
QMutexLocker l(&m_shellMutex);
|
QMutexLocker l(&m_shellMutex);
|
||||||
@@ -1665,5 +1638,20 @@ IDevice::Ptr DockerDeviceFactory::create() const
|
|||||||
return wizard.device();
|
return wizard.device();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DockerDeviceWidget::updateDaemonStateTexts()
|
||||||
|
{
|
||||||
|
Utils::optional<bool> daemonState = DockerPlugin::isDaemonRunning();
|
||||||
|
if (!daemonState.has_value()) {
|
||||||
|
m_daemonReset->setIcon(Icons::INFO.icon());
|
||||||
|
m_daemonState->setText(tr("Daemon state not evaluated."));
|
||||||
|
} else if (daemonState.value()) {
|
||||||
|
m_daemonReset->setIcon(Icons::OK.icon());
|
||||||
|
m_daemonState->setText(tr("Docker daemon running."));
|
||||||
|
} else {
|
||||||
|
m_daemonReset->setIcon(Icons::CRITICAL.icon());
|
||||||
|
m_daemonState->setText(tr("Docker daemon not running."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
} // Docker
|
} // Docker
|
||||||
|
@@ -107,8 +107,6 @@ public:
|
|||||||
|
|
||||||
void tryCreateLocalFileAccess() const;
|
void tryCreateLocalFileAccess() const;
|
||||||
bool hasLocalFileAccess() const;
|
bool hasLocalFileAccess() const;
|
||||||
bool isDaemonRunning() const;
|
|
||||||
void resetDaemonState();
|
|
||||||
void setMounts(const QStringList &mounts) const;
|
void setMounts(const QStringList &mounts) const;
|
||||||
|
|
||||||
Utils::FilePath mapToLocalAccess(const Utils::FilePath &filePath) const;
|
Utils::FilePath mapToLocalAccess(const Utils::FilePath &filePath) const;
|
||||||
|
@@ -58,10 +58,31 @@ public:
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
// DockerBuildStepFactory buildStepFactory;
|
// DockerBuildStepFactory buildStepFactory;
|
||||||
|
Utils::optional<bool> daemonRunning;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DockerPlugin *s_instance = nullptr;
|
||||||
|
|
||||||
|
DockerPlugin::DockerPlugin()
|
||||||
|
{
|
||||||
|
s_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utils::null_opt for not evaluated, true or false if it had been evaluated already
|
||||||
|
Utils::optional<bool> DockerPlugin::isDaemonRunning()
|
||||||
|
{
|
||||||
|
return s_instance ? s_instance->d->daemonRunning : Utils::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockerPlugin::setGlobalDaemonState(Utils::optional<bool> state)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(s_instance, return);
|
||||||
|
s_instance->d->daemonRunning = state;
|
||||||
|
}
|
||||||
|
|
||||||
DockerPlugin::~DockerPlugin()
|
DockerPlugin::~DockerPlugin()
|
||||||
{
|
{
|
||||||
|
s_instance = nullptr;
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <extensionsystem/iplugin.h>
|
#include <extensionsystem/iplugin.h>
|
||||||
|
|
||||||
|
#include <utils/optional.h>
|
||||||
|
|
||||||
namespace Docker {
|
namespace Docker {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -34,6 +36,11 @@ class DockerPlugin final : public ExtensionSystem::IPlugin
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Docker.json")
|
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Docker.json")
|
||||||
|
public:
|
||||||
|
DockerPlugin();
|
||||||
|
|
||||||
|
static Utils::optional<bool> isDaemonRunning();
|
||||||
|
static void setGlobalDaemonState(Utils::optional<bool> state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~DockerPlugin() final;
|
~DockerPlugin() final;
|
||||||
|
Reference in New Issue
Block a user