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:
Christian Stenger
2021-08-10 16:50:23 +02:00
parent bfe2a7b9d1
commit f95d6c6009
4 changed files with 68 additions and 54 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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;