forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -99,6 +99,7 @@ PenaltyExcessCharacter: 50
|
||||
PenaltyReturnTypeOnItsOwnLine: 300
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
|
@@ -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
|
||||
|
@@ -12,6 +12,8 @@ QtcPlugin {
|
||||
|
||||
files: [
|
||||
"docker_global.h",
|
||||
"dockerapi.cpp",
|
||||
"dockerapi.h",
|
||||
"dockerbuildstep.cpp",
|
||||
"dockerbuildstep.h",
|
||||
"dockerconstants.h",
|
||||
|
121
src/plugins/docker/dockerapi.cpp
Normal file
121
src/plugins/docker/dockerapi.cpp
Normal file
@@ -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
|
68
src/plugins/docker/dockerapi.h
Normal file
68
src/plugins/docker/dockerapi.h
Normal file
@@ -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
|
@@ -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);
|
||||
|
@@ -71,11 +71,15 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
|
||||
"It will be automatically re-evaluated next time access is needed."));
|
||||
|
||||
m_daemonState = new QLabel;
|
||||
|
||||
connect(DockerApi::instance(), &DockerApi::dockerDaemonAvailableChanged, this, [this]{
|
||||
updateDaemonStateTexts();
|
||||
});
|
||||
|
||||
updateDaemonStateTexts();
|
||||
|
||||
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
|
||||
DockerPlugin::setGlobalDaemonState(Utils::nullopt);
|
||||
updateDaemonStateTexts();
|
||||
connect(m_daemonReset, &QToolButton::clicked, this, [] {
|
||||
DockerApi::recheckDockerDaemon();
|
||||
});
|
||||
|
||||
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
|
||||
@@ -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."));
|
||||
|
@@ -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()
|
||||
DockerApi *DockerPlugin::dockerApi()
|
||||
{
|
||||
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;
|
||||
QTC_ASSERT(s_instance, return nullptr);
|
||||
return &s_instance->d->dockerApi;
|
||||
}
|
||||
|
||||
DockerPlugin::~DockerPlugin()
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user