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
|
PenaltyReturnTypeOnItsOwnLine: 300
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ReflowComments: false
|
ReflowComments: false
|
||||||
|
RemoveBracesLLVM: true
|
||||||
SortIncludes: true
|
SortIncludes: true
|
||||||
SortUsingDeclarations: true
|
SortUsingDeclarations: true
|
||||||
SpaceAfterCStyleCast: true
|
SpaceAfterCStyleCast: true
|
||||||
|
@@ -2,6 +2,7 @@ add_qtc_plugin(Docker
|
|||||||
PLUGIN_DEPENDS Core ProjectExplorer QtSupport
|
PLUGIN_DEPENDS Core ProjectExplorer QtSupport
|
||||||
SOURCES
|
SOURCES
|
||||||
docker_global.h
|
docker_global.h
|
||||||
|
dockerapi.cpp dockerapi.h
|
||||||
dockerbuildstep.cpp dockerbuildstep.h
|
dockerbuildstep.cpp dockerbuildstep.h
|
||||||
dockerconstants.h
|
dockerconstants.h
|
||||||
dockerdevice.cpp dockerdevice.h
|
dockerdevice.cpp dockerdevice.h
|
||||||
|
@@ -12,6 +12,8 @@ QtcPlugin {
|
|||||||
|
|
||||||
files: [
|
files: [
|
||||||
"docker_global.h",
|
"docker_global.h",
|
||||||
|
"dockerapi.cpp",
|
||||||
|
"dockerapi.h",
|
||||||
"dockerbuildstep.cpp",
|
"dockerbuildstep.cpp",
|
||||||
"dockerbuildstep.h",
|
"dockerbuildstep.h",
|
||||||
"dockerconstants.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()
|
void DockerDevicePrivate::stopCurrentContainer()
|
||||||
{
|
{
|
||||||
if (m_container.isEmpty() || !DockerPlugin::isDaemonRunning().value_or(false))
|
if (m_container.isEmpty() || !DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_shell) {
|
if (m_shell) {
|
||||||
@@ -412,7 +412,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 (exitCode > 120) {
|
if (exitCode > 120) {
|
||||||
DockerPlugin::setGlobalDaemonState(false);
|
DockerApi::recheckDockerDaemon();
|
||||||
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 "
|
||||||
@@ -428,12 +428,10 @@ void DockerDevicePrivate::startContainer()
|
|||||||
m_shell->waitForStarted();
|
m_shell->waitForStarted();
|
||||||
|
|
||||||
if (!m_shell->isRunning()) {
|
if (!m_shell->isRunning()) {
|
||||||
DockerPlugin::setGlobalDaemonState(false);
|
DockerApi::recheckDockerDaemon();
|
||||||
LOG("DOCKER SHELL FAILED");
|
LOG("DOCKER SHELL FAILED");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DockerPlugin::setGlobalDaemonState(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockerDevicePrivate::updateContainerAccess()
|
void DockerDevicePrivate::updateContainerAccess()
|
||||||
@@ -441,7 +439,7 @@ void DockerDevicePrivate::updateContainerAccess()
|
|||||||
if (!m_container.isEmpty())
|
if (!m_container.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (DockerPlugin::isDaemonRunning().value_or(true) == false)
|
if (DockerApi::isDockerDaemonAvailable().value_or(true) == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_shell)
|
if (m_shell)
|
||||||
@@ -899,7 +897,7 @@ bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray
|
|||||||
void DockerDevice::runProcess(QtcProcess &process) const
|
void DockerDevice::runProcess(QtcProcess &process) const
|
||||||
{
|
{
|
||||||
updateContainerAccess();
|
updateContainerAccess();
|
||||||
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
if (!DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||||
return;
|
return;
|
||||||
if (d->m_container.isEmpty()) {
|
if (d->m_container.isEmpty()) {
|
||||||
LOG("No container set to run " << process.commandLine().toUserOutput());
|
LOG("No container set to run " << process.commandLine().toUserOutput());
|
||||||
@@ -979,7 +977,7 @@ void DockerDevicePrivate::fetchSystemEnviroment()
|
|||||||
|
|
||||||
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
||||||
{
|
{
|
||||||
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
if (!DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||||
return false;
|
return false;
|
||||||
CommandLine dcmd{"docker", {"exec", m_container}};
|
CommandLine dcmd{"docker", {"exec", m_container}};
|
||||||
dcmd.addCommandLineAsArgs(cmd);
|
dcmd.addCommandLineAsArgs(cmd);
|
||||||
@@ -997,7 +995,7 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
|||||||
|
|
||||||
bool DockerDevicePrivate::runInShell(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());
|
LOG("No daemon. Could not run " << cmd.toUserOutput());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1021,7 @@ static QByteArray randomHex()
|
|||||||
|
|
||||||
QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
|
QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
|
||||||
{
|
{
|
||||||
if (!DockerPlugin::isDaemonRunning().value_or(false))
|
if (!DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||||
return {};
|
return {};
|
||||||
QTC_ASSERT(m_shell && m_shell->isRunning(), return {});
|
QTC_ASSERT(m_shell && m_shell->isRunning(), return {});
|
||||||
QMutexLocker l(&m_shellMutex);
|
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."));
|
"It will be automatically re-evaluated next time access is needed."));
|
||||||
|
|
||||||
m_daemonState = new QLabel;
|
m_daemonState = new QLabel;
|
||||||
|
|
||||||
|
connect(DockerApi::instance(), &DockerApi::dockerDaemonAvailableChanged, this, [this]{
|
||||||
|
updateDaemonStateTexts();
|
||||||
|
});
|
||||||
|
|
||||||
updateDaemonStateTexts();
|
updateDaemonStateTexts();
|
||||||
|
|
||||||
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
|
connect(m_daemonReset, &QToolButton::clicked, this, [] {
|
||||||
DockerPlugin::setGlobalDaemonState(Utils::nullopt);
|
DockerApi::recheckDockerDaemon();
|
||||||
updateDaemonStateTexts();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
|
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());
|
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."));
|
logView->append(tr("Docker daemon appears to be not running."));
|
||||||
else
|
else
|
||||||
logView->append(tr("Docker daemon appears to be running."));
|
logView->append(tr("Docker daemon appears to be running."));
|
||||||
@@ -208,7 +212,7 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
|
|||||||
|
|
||||||
void DockerDeviceWidget::updateDaemonStateTexts()
|
void DockerDeviceWidget::updateDaemonStateTexts()
|
||||||
{
|
{
|
||||||
Utils::optional<bool> daemonState = DockerPlugin::isDaemonRunning();
|
Utils::optional<bool> daemonState = DockerApi::instance()->dockerDaemonAvailable();
|
||||||
if (!daemonState.has_value()) {
|
if (!daemonState.has_value()) {
|
||||||
m_daemonReset->setIcon(Icons::INFO.icon());
|
m_daemonReset->setIcon(Icons::INFO.icon());
|
||||||
m_daemonState->setText(tr("Daemon state not evaluated."));
|
m_daemonState->setText(tr("Daemon state not evaluated."));
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "dockerconstants.h"
|
#include "dockerconstants.h"
|
||||||
|
|
||||||
|
#include "dockerapi.h"
|
||||||
#include "dockerbuildstep.h"
|
#include "dockerbuildstep.h"
|
||||||
#include "dockerdevice.h"
|
#include "dockerdevice.h"
|
||||||
#include "dockersettings.h"
|
#include "dockersettings.h"
|
||||||
@@ -43,13 +44,15 @@ namespace Internal {
|
|||||||
class DockerPluginPrivate
|
class DockerPluginPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// DockerSettings settings;
|
// DockerSettings settings;
|
||||||
// DockerOptionsPage optionsPage{&settings};
|
// DockerOptionsPage optionsPage{&settings};
|
||||||
|
|
||||||
DockerDeviceFactory deviceFactory;
|
DockerDeviceFactory deviceFactory;
|
||||||
|
|
||||||
// DockerBuildStepFactory buildStepFactory;
|
// DockerBuildStepFactory buildStepFactory;
|
||||||
Utils::optional<bool> daemonRunning;
|
Utils::optional<bool> daemonRunning;
|
||||||
|
|
||||||
|
DockerApi dockerApi;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DockerPlugin *s_instance = nullptr;
|
static DockerPlugin *s_instance = nullptr;
|
||||||
@@ -59,16 +62,10 @@ DockerPlugin::DockerPlugin()
|
|||||||
s_instance = this;
|
s_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utils::null_opt for not evaluated, true or false if it had been evaluated already
|
DockerApi *DockerPlugin::dockerApi()
|
||||||
Utils::optional<bool> DockerPlugin::isDaemonRunning()
|
|
||||||
{
|
{
|
||||||
return s_instance ? s_instance->d->daemonRunning : Utils::nullopt;
|
QTC_ASSERT(s_instance, return nullptr);
|
||||||
}
|
return &s_instance->d->dockerApi;
|
||||||
|
|
||||||
void DockerPlugin::setGlobalDaemonState(Utils::optional<bool> state)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(s_instance, return);
|
|
||||||
s_instance->d->daemonRunning = state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DockerPlugin::~DockerPlugin()
|
DockerPlugin::~DockerPlugin()
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "dockerapi.h"
|
||||||
|
|
||||||
#include <extensionsystem/iplugin.h>
|
#include <extensionsystem/iplugin.h>
|
||||||
|
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
@@ -36,11 +38,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:
|
public:
|
||||||
DockerPlugin();
|
DockerPlugin();
|
||||||
|
|
||||||
static Utils::optional<bool> isDaemonRunning();
|
static DockerApi *dockerApi();
|
||||||
static void setGlobalDaemonState(Utils::optional<bool> state);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~DockerPlugin() final;
|
~DockerPlugin() final;
|
||||||
|
Reference in New Issue
Block a user