summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Tillmanns <marcus.tillmanns@qt.io>2022-04-05 11:43:56 +0200
committerMarcus Tillmanns <marcus.tillmanns@qt.io>2022-04-07 12:58:48 +0000
commit3af260b7826fe0509723e12d29d71ca407cc50b5 (patch)
tree16541c3980b78ed8cba987e3267e66af0057f27d
parent1d63eaee238824af2ed59c748a9a8c33977cf52f (diff)
downloadqt-creator-3af260b7826fe0509723e12d29d71ca407cc50b5.tar.gz
docker-plugin: fix daemon state
Changed daemon state to actually check the docker runtime to determine if its available or not. Change-Id: I9e183658dfc7c34e229aec2a332cf303793284e5 Reviewed-by: hjk <hjk@qt.io>
-rw-r--r--.clang-format1
-rw-r--r--src/plugins/docker/CMakeLists.txt1
-rw-r--r--src/plugins/docker/docker.qbs2
-rw-r--r--src/plugins/docker/dockerapi.cpp121
-rw-r--r--src/plugins/docker/dockerapi.h68
-rw-r--r--src/plugins/docker/dockerdevice.cpp18
-rw-r--r--src/plugins/docker/dockerdevicewidget.cpp14
-rw-r--r--src/plugins/docker/dockerplugin.cpp21
-rw-r--r--src/plugins/docker/dockerplugin.h6
9 files changed, 223 insertions, 29 deletions
diff --git a/.clang-format b/.clang-format
index 97f7f2b234..7077765291 100644
--- a/.clang-format
+++ b/.clang-format
@@ -99,6 +99,7 @@ PenaltyExcessCharacter: 50
PenaltyReturnTypeOnItsOwnLine: 300
PointerAlignment: Right
ReflowComments: false
+RemoveBracesLLVM: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
diff --git a/src/plugins/docker/CMakeLists.txt b/src/plugins/docker/CMakeLists.txt
index 3153b10bb1..68903c630b 100644
--- a/src/plugins/docker/CMakeLists.txt
+++ b/src/plugins/docker/CMakeLists.txt
@@ -2,6 +2,7 @@ add_qtc_plugin(Docker
PLUGIN_DEPENDS Core ProjectExplorer QtSupport
SOURCES
docker_global.h
+ dockerapi.cpp dockerapi.h
dockerbuildstep.cpp dockerbuildstep.h
dockerconstants.h
dockerdevice.cpp dockerdevice.h
diff --git a/src/plugins/docker/docker.qbs b/src/plugins/docker/docker.qbs
index 3c6680604a..1e79fa8f5b 100644
--- a/src/plugins/docker/docker.qbs
+++ b/src/plugins/docker/docker.qbs
@@ -12,6 +12,8 @@ QtcPlugin {
files: [
"docker_global.h",
+ "dockerapi.cpp",
+ "dockerapi.h",
"dockerbuildstep.cpp",
"dockerbuildstep.h",
"dockerconstants.h",
diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp
new file mode 100644
index 0000000000..b733b18320
--- /dev/null
+++ b/src/plugins/docker/dockerapi.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "dockerapi.h"
+
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <utils/qtcprocess.h>
+
+#include <QLoggingCategory>
+#include <QtConcurrent>
+
+#include <thread>
+
+Q_LOGGING_CATEGORY(dockerApiLog, "qtc.docker.api", QtDebugMsg);
+
+namespace Docker {
+namespace Internal {
+
+using namespace Utils;
+
+DockerApi *s_instance{nullptr};
+
+DockerApi::DockerApi()
+{
+ s_instance = this;
+}
+
+DockerApi *DockerApi::instance()
+{
+ return s_instance;
+}
+
+bool DockerApi::canConnect()
+{
+ QtcProcess process;
+ FilePath dockerExe = findDockerClient();
+ if (dockerExe.isEmpty() || !dockerExe.isExecutableFile())
+ return false;
+
+ bool result = false;
+
+ process.setCommand(CommandLine(dockerExe, QStringList{"info"}));
+ connect(&process, &QtcProcess::done, [&process, &result] {
+ qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput());
+ if (process.result() == ProcessResult::FinishedWithSuccess)
+ result = true;
+ });
+
+ process.start();
+ process.waitForFinished();
+
+ return result;
+}
+
+void DockerApi::checkCanConnect()
+{
+ std::unique_lock lk(m_daemonCheckGuard, std::try_to_lock);
+ if (!lk.owns_lock())
+ return;
+
+ m_dockerDaemonAvailable = nullopt;
+ dockerDaemonAvailableChanged();
+
+ auto future = QtConcurrent::run(QThreadPool::globalInstance(), [lk = std::move(lk), this] {
+ m_dockerDaemonAvailable = canConnect();
+ dockerDaemonAvailableChanged();
+ });
+
+ Core::ProgressManager::addTask(future, tr("Checking docker daemon"), "DockerPlugin");
+}
+
+void DockerApi::recheckDockerDaemon()
+{
+ QTC_ASSERT(s_instance, return );
+ s_instance->checkCanConnect();
+}
+
+Utils::optional<bool> DockerApi::dockerDaemonAvailable()
+{
+ if (!m_dockerDaemonAvailable.has_value())
+ checkCanConnect();
+ return m_dockerDaemonAvailable;
+}
+
+Utils::optional<bool> DockerApi::isDockerDaemonAvailable()
+{
+ QTC_ASSERT(s_instance, return nullopt);
+ return s_instance->dockerDaemonAvailable();
+}
+
+FilePath DockerApi::findDockerClient()
+{
+ if (m_dockerExecutable.isEmpty() || m_dockerExecutable.isExecutableFile())
+ m_dockerExecutable = FilePath::fromString("docker").searchInPath();
+ return m_dockerExecutable;
+}
+
+} // namespace Internal
+} // namespace Docker
diff --git a/src/plugins/docker/dockerapi.h b/src/plugins/docker/dockerapi.h
new file mode 100644
index 0000000000..186a5ccfd9
--- /dev/null
+++ b/src/plugins/docker/dockerapi.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QMutex>
+#include <QObject>
+
+#include <utils/filepath.h>
+#include <utils/guard.h>
+#include <utils/optional.h>
+
+namespace Docker {
+namespace Internal {
+
+class DockerApi : public QObject
+{
+ Q_OBJECT
+
+public:
+ DockerApi();
+
+ static DockerApi *instance();
+
+ bool canConnect();
+ void checkCanConnect();
+ static void recheckDockerDaemon();
+
+signals:
+ void dockerDaemonAvailableChanged();
+
+public:
+ Utils::optional<bool> dockerDaemonAvailable();
+ static Utils::optional<bool> isDockerDaemonAvailable();
+
+private:
+ Utils::FilePath findDockerClient();
+
+private:
+ Utils::FilePath m_dockerExecutable;
+ Utils::optional<bool> m_dockerDaemonAvailable;
+ QMutex m_daemonCheckGuard;
+};
+
+} // namespace Internal
+} // namespace Docker
diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp
index 314119ead3..772d9c541a 100644
--- a/src/plugins/docker/dockerdevice.cpp
+++ b/src/plugins/docker/dockerdevice.cpp
@@ -317,7 +317,7 @@ void DockerDevice::updateContainerAccess() const
void DockerDevicePrivate::stopCurrentContainer()
{
- if (m_container.isEmpty() || !DockerPlugin::isDaemonRunning().value_or(false))
+ if (m_container.isEmpty() || !DockerApi::isDockerDaemonAvailable().value_or(false))
return;
if (m_shell) {
@@ -412,7 +412,7 @@ void DockerDevicePrivate::startContainer()
// negative exit codes indicate problems like no docker daemon, missing permissions,
// no shell and seem to result in exit codes 125+
if (exitCode > 120) {
- DockerPlugin::setGlobalDaemonState(false);
+ DockerApi::recheckDockerDaemon();
LOG("DOCKER DAEMON NOT RUNNING?");
MessageManager::writeFlashing(tr("Docker daemon appears to be not running. "
"Verify daemon is up and running and reset the "
@@ -428,12 +428,10 @@ void DockerDevicePrivate::startContainer()
m_shell->waitForStarted();
if (!m_shell->isRunning()) {
- DockerPlugin::setGlobalDaemonState(false);
+ DockerApi::recheckDockerDaemon();
LOG("DOCKER SHELL FAILED");
return;
}
-
- DockerPlugin::setGlobalDaemonState(true);
}
void DockerDevicePrivate::updateContainerAccess()
@@ -441,7 +439,7 @@ void DockerDevicePrivate::updateContainerAccess()
if (!m_container.isEmpty())
return;
- if (DockerPlugin::isDaemonRunning().value_or(true) == false)
+ if (DockerApi::isDockerDaemonAvailable().value_or(true) == false)
return;
if (m_shell)
@@ -899,7 +897,7 @@ bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray
void DockerDevice::runProcess(QtcProcess &process) const
{
updateContainerAccess();
- if (!DockerPlugin::isDaemonRunning().value_or(false))
+ if (!DockerApi::isDockerDaemonAvailable().value_or(false))
return;
if (d->m_container.isEmpty()) {
LOG("No container set to run " << process.commandLine().toUserOutput());
@@ -979,7 +977,7 @@ void DockerDevicePrivate::fetchSystemEnviroment()
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
{
- if (!DockerPlugin::isDaemonRunning().value_or(false))
+ if (!DockerApi::isDockerDaemonAvailable().value_or(false))
return false;
CommandLine dcmd{"docker", {"exec", m_container}};
dcmd.addCommandLineAsArgs(cmd);
@@ -997,7 +995,7 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
bool DockerDevicePrivate::runInShell(const CommandLine &cmd) const
{
- if (!QTC_GUARD(DockerPlugin::isDaemonRunning().value_or(false))) {
+ if (!QTC_GUARD(DockerApi::isDockerDaemonAvailable().value_or(false))) {
LOG("No daemon. Could not run " << cmd.toUserOutput());
return false;
}
@@ -1023,7 +1021,7 @@ static QByteArray randomHex()
QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
{
- if (!DockerPlugin::isDaemonRunning().value_or(false))
+ if (!DockerApi::isDockerDaemonAvailable().value_or(false))
return {};
QTC_ASSERT(m_shell && m_shell->isRunning(), return {});
QMutexLocker l(&m_shellMutex);
diff --git a/src/plugins/docker/dockerdevicewidget.cpp b/src/plugins/docker/dockerdevicewidget.cpp
index 5409bc31d1..a652cc27c3 100644
--- a/src/plugins/docker/dockerdevicewidget.cpp
+++ b/src/plugins/docker/dockerdevicewidget.cpp
@@ -71,13 +71,17 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
"It will be automatically re-evaluated next time access is needed."));
m_daemonState = new QLabel;
- updateDaemonStateTexts();
- connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
- DockerPlugin::setGlobalDaemonState(Utils::nullopt);
+ connect(DockerApi::instance(), &DockerApi::dockerDaemonAvailableChanged, this, [this]{
updateDaemonStateTexts();
});
+ updateDaemonStateTexts();
+
+ connect(m_daemonReset, &QToolButton::clicked, this, [] {
+ DockerApi::recheckDockerDaemon();
+ });
+
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
m_runAsOutsideUser->setToolTip(tr("Uses user ID and group ID of the user running Qt Creator "
"in the docker container."));
@@ -150,7 +154,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
m_kitItemDetector.autoDetect(dockerDevice->id().toString(), searchPaths());
- if (DockerPlugin::isDaemonRunning().value_or(false) == false)
+ if (DockerApi::instance()->dockerDaemonAvailable().value_or(false) == false)
logView->append(tr("Docker daemon appears to be not running."));
else
logView->append(tr("Docker daemon appears to be running."));
@@ -208,7 +212,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
void DockerDeviceWidget::updateDaemonStateTexts()
{
- Utils::optional<bool> daemonState = DockerPlugin::isDaemonRunning();
+ Utils::optional<bool> daemonState = DockerApi::instance()->dockerDaemonAvailable();
if (!daemonState.has_value()) {
m_daemonReset->setIcon(Icons::INFO.icon());
m_daemonState->setText(tr("Daemon state not evaluated."));
diff --git a/src/plugins/docker/dockerplugin.cpp b/src/plugins/docker/dockerplugin.cpp
index d195c81d6b..3c07eb2985 100644
--- a/src/plugins/docker/dockerplugin.cpp
+++ b/src/plugins/docker/dockerplugin.cpp
@@ -27,6 +27,7 @@
#include "dockerconstants.h"
+#include "dockerapi.h"
#include "dockerbuildstep.h"
#include "dockerdevice.h"
#include "dockersettings.h"
@@ -43,13 +44,15 @@ namespace Internal {
class DockerPluginPrivate
{
public:
-// DockerSettings settings;
-// DockerOptionsPage optionsPage{&settings};
+ // DockerSettings settings;
+ // DockerOptionsPage optionsPage{&settings};
DockerDeviceFactory deviceFactory;
-// DockerBuildStepFactory buildStepFactory;
+ // DockerBuildStepFactory buildStepFactory;
Utils::optional<bool> daemonRunning;
+
+ DockerApi dockerApi;
};
static DockerPlugin *s_instance = nullptr;
@@ -59,16 +62,10 @@ 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)
+DockerApi *DockerPlugin::dockerApi()
{
- QTC_ASSERT(s_instance, return);
- s_instance->d->daemonRunning = state;
+ QTC_ASSERT(s_instance, return nullptr);
+ return &s_instance->d->dockerApi;
}
DockerPlugin::~DockerPlugin()
diff --git a/src/plugins/docker/dockerplugin.h b/src/plugins/docker/dockerplugin.h
index aa9c093556..7eb1d3b10b 100644
--- a/src/plugins/docker/dockerplugin.h
+++ b/src/plugins/docker/dockerplugin.h
@@ -25,6 +25,8 @@
#pragma once
+#include "dockerapi.h"
+
#include <extensionsystem/iplugin.h>
#include <utils/optional.h>
@@ -36,11 +38,11 @@ class DockerPlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
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);
+ static DockerApi *dockerApi();
private:
~DockerPlugin() final;