Files
qt5-legatus-legacy/Lts/Tools/DBAdministration/db_administration.cpp
T
2026-08-13 18:33:10 +02:00

442 lines
14 KiB
C++
Executable File

/*
* @RDE_HEADER@
* <short description>
* $Id$
* $HeadURL$
* $Author$
* Created by Malte Schröder, SLSE, 2016-06-08
*/
#include "db_administration.h"
#include "ui_db_administration.h"
#include "server_databases_model.h"
#include "local_databases_model.h"
#include "settings.h"
#include <ngldb/dbconnection.h>
#include <ngldb/nsqlquery.h>
#include <nglsettings/nglsettings_settings.h>
#include <ngltools/ngltools_filesystem.h>
#include <QMessageBox>
#include <QTimer>
#include <QMenu>
#include <QSettings>
#include <QDir>
#include <QNetworkInterface>
#include <QHostInfo>
namespace DBAdministration
{
DBAdministration::DBAdministration(QWidget *parent)
: QMainWindow(parent)
, m_ui(new Ui::DBAdministration)
, m_proc(nullptr)
, m_progressDialog(nullptr)
, m_timer(nullptr)
, m_menuBar(new QMenuBar(this))
, m_showLog(new ShowLogFile)
, m_copyExercise(new CopyExercise(getLogger("CopyExercise"), CopyExercise::CopyForEvaluation, this))
, m_bRunsOnEvaluationServer(checkRunsOnEvaluationServer())
, m_logger(getLogger("DBAdministration"))
{
m_ui->setupUi(this);
m_serverDatabasesModel = new ServerDatabasesModel(this);
m_proxyModelServer = new ServerDatabasesProxyModel(this);
m_proxyModelServer->setSourceModel(m_serverDatabasesModel);
m_ui->tableViewServerDatabases->setModel(m_proxyModelServer);
m_localDatabasesModel = new LocalDatabasesModel(this);
m_proxyModelLocal = new LocalDatabasesProxyModel(this);
m_proxyModelLocal->setSourceModel(m_localDatabasesModel);
m_ui->tableViewLocalDatabases->setModel(m_proxyModelLocal);
connect(m_ui->pbCopy, &QPushButton::clicked, this, &DBAdministration::onCopyButtonClicked);
connect(m_ui->pbClose, &QPushButton::clicked, this, &DBAdministration::onClosedClicked);
connect(m_ui->pbRemove, &QPushButton::clicked, this, &DBAdministration::onRemoveClicked);
connect(m_ui->pbActivate, &QPushButton::clicked, this, &DBAdministration::onActivateClicked);
connect(m_ui->tableViewServerDatabases->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DBAdministration::enaDisa);
connect(m_ui->tableViewLocalDatabases->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DBAdministration::enaDisa);
setWindowTitle(QLatin1String("DBAdministration"));
connect(m_ui->actionShow, &QAction::triggered, this, &DBAdministration::onShowLogFile);
connect(m_ui->actionStart, &QAction::triggered, this, &DBAdministration::onStartApp);
connect(m_ui->actionStop, &QAction::triggered, this, &DBAdministration::onStopApp);
connect(m_copyExercise, &CopyExercise::copyDbFailed, this, &DBAdministration::onCopyDbFailed);
connect(m_copyExercise, &CopyExercise::copyDbFinished, this, &DBAdministration::onCopyDbFinished);
m_ui->actionStart->setEnabled(m_bRunsOnEvaluationServer);
m_ui->actionStop->setEnabled(m_bRunsOnEvaluationServer);
m_ui->menuService_Management->setEnabled(m_bRunsOnEvaluationServer);
enaDisa();
}
DBAdministration::~DBAdministration()
{
delete m_ui;
delete m_serverDatabasesModel;
delete m_progressDialog;
delete m_timer;
delete m_menuBar;
delete m_showLog;
if (m_proc)
m_proc->deleteLater();
}
bool DBAdministration::init()
{
if (!m_copyExercise->init(0,
Settings::serverDatabaseHost(),
Settings::serverDatabaseName(),
Settings::evaluationDatabaseHost(),
Settings::evaluationDatabaseName()))
return false;
m_serverDatabasesModel->initModel(m_copyExercise->serverDb());
m_localDatabasesModel->initModel(m_copyExercise->evaluationDb());
m_ui->tableViewServerDatabases->resizeColumnsToContents();
m_ui->tableViewLocalDatabases->resizeColumnsToContents();
return true;
}
void DBAdministration::onClosedClicked()
{
close();
}
void DBAdministration::onRemoveClicked()
{
disableButtons();
m_localDatabaseToRemove = m_localDatabasesModel->getRowData(m_ui->tableViewLocalDatabases->currentIndex().row());
QString strMsg = QStringLiteral("Do you really want to remove the database '%1'?").arg (m_localDatabaseToRemove.dbName);
int result = QMessageBox::question(this, tr("Remove Database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (result == QMessageBox::No)
{
enableButtons();
return;
}
DEBUG_LOG(m_logger) << "onRemoveClicked: dbName = " << m_localDatabaseToRemove.dbName;
const QStringList args({QStringLiteral("-U"),
QStringLiteral("postgres"),
QStringLiteral("-h"),
Settings::evaluationDatabaseHost(),
m_localDatabaseToRemove.dbName
});
QString errStr;
const QString exePath = NGL::postgresExecutablePath(QStringLiteral("dropdb"), errStr);
if (!errStr.isEmpty())
WARNING_LOG(m_logger) << errStr;
handleProcInit(exePath, args);
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DBAdministration::onDropDbFinished);
// start process
m_proc->start();
}
void DBAdministration::onActivateClicked()
{
LocalExercise le = m_localDatabasesModel->getRowData(m_ui->tableViewLocalDatabases->currentIndex().row());
QString strMsg = QStringLiteral("Do you really want to active database '%1'?").arg(le.dbName);
int result = QMessageBox::question(this, tr("Activate Database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (result == QMessageBox::No)
return;
DEBUG_LOG(m_logger) << "onActivateClicked: dbName = " << le.dbName;
QString configFileName = QStringLiteral("/lts-cc.conf");
QString filename;
QScopedPointer<QSettings> settings;
filename = QDir::homePath() + configFileName;
if (QFile::exists(filename))
{
settings.reset(new QSettings(filename, QSettings::Format::IniFormat));
}
else
{
#ifdef Q_OS_UNIX
filename = QStringLiteral("/etc") + configFileName;
#else
filename = QCoreApplication::applicationDirPath() + QLatin1String("\\") + configFileName;
#endif
if (QFile::exists(filename))
{
settings.reset(new QSettings(filename, QSettings::Format::IniFormat));
}
else
// fallback
settings.reset(new QSettings(QLatin1String("RDE"), QLatin1String("LTS-CC")));
}
ERROR_LOG(m_logger) << "FileName: " << filename;
settings->setValue(QStringLiteral("Global") + QStringLiteral("/DatabaseName"), le.dbName);
}
void DBAdministration::enaDisa()
{
if (!m_ui)
return;
int selected = m_ui->tableViewServerDatabases->selectionModel()->selectedRows().size();
m_ui->pbCopy->setEnabled(selected > 0);
selected = m_ui->tableViewLocalDatabases->selectionModel()->selectedRows().size();
m_ui->pbRemove->setEnabled(selected > 0);
m_ui->pbActivate->setEnabled(selected > 0 && m_bRunsOnEvaluationServer);
}
void DBAdministration::onCopyButtonClicked()
{
disableButtons();
auto exercise = m_serverDatabasesModel->getRowData(m_proxyModelServer->mapToSource(m_ui->tableViewServerDatabases->currentIndex()).row());
m_copyExercise->doCopy(exercise.id);
if (!m_progressDialog)
m_progressDialog = new QProgressDialog(this);
m_progressDialog->setLabelText(tr("Copying database..."));
m_progressDialog->setMinimum(0);
m_progressDialog->setMaximum(0);
m_progressDialog->show();
}
void DBAdministration::onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
INFO_LOG(m_logger) << "onDropDbFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus;
bool bRemoveLocal = true;
if (exitCode > 0)
{
const QString str = QString::fromLocal8Bit(m_proc->readAllStandardError()) + QLatin1Char('\n') +
QString::fromLocal8Bit(m_proc->readAllStandardOutput());
ERROR_LOG(m_logger) << "Can not drop database: " << str;
QString db0 = QLatin1String("ERROR: database \"")+m_localDatabaseToRemove.dbName+QLatin1String("\" does not exist");
if (!str.contains(db0))
{
bRemoveLocal = false;
QMessageBox::critical(this, tr ("Remove Database"), tr("Database cannot be removed:\n%1.").arg(str), QMessageBox::Ok);
}
}
if (bRemoveLocal)
{
NSqlQuery q(m_copyExercise->evaluationDb());
QString stmt = QStringLiteral("DELETE FROM local_databases WHERE id = ") + QString::number(m_localDatabaseToRemove.id);
if (!q.exec(stmt))
QMessageBox::critical(this, tr ("Remove Database"), tr("Database entry cannot be removed."), QMessageBox::Ok);
else
{
m_localDatabasesModel->initModel(m_copyExercise->evaluationDb());
m_ui->tableViewLocalDatabases->resizeColumnsToContents();
}
m_localDatabaseToRemove = LocalExercise();
}
enableButtons();
}
void DBAdministration::onErrorOccured(QProcess::ProcessError error)
{
ERROR_LOG(m_logger) << "error: " << error;
}
void DBAdministration::incrementProgressBar()
{
m_progressDialog->setValue(m_progressDialog->value()+1);
}
void DBAdministration::onShowLogFile()
{
ERROR_LOG(m_logger) << "IN onShowLogFile";
if (!m_showLog->init())
{
QMessageBox::critical(this, tr ("Show Logfile"), tr("Logfile does not exist."), QMessageBox::Ok);
return;
}
m_showLog->show();
}
void DBAdministration::onStartApp()
{
if (!m_bRunsOnEvaluationServer)
return;
handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")});
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DBAdministration::onPsauxFinished);
m_proc->start();
}
void DBAdministration::onPsauxFinished()
{
enableButtons();
QByteArray output = m_proc->readAllStandardOutput();
if (output.contains("svcServiceManagement"))
{
ERROR_LOG(m_logger) << "ServiceManagement already started";
QMessageBox::critical(this, tr ("Service Management"), tr("Service Management already started."), QMessageBox::Ok);
}
else
{
ERROR_LOG(m_logger) << "Start svcServiceManagement";
handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-z")});
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DBAdministration::onStartAppFinished);
m_proc->start();
}
}
void DBAdministration::onStartAppFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
handleProcFinished(exitCode, exitStatus);
}
void DBAdministration::onStopApp()
{
if (!m_bRunsOnEvaluationServer)
return;
disableButtons();
handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")});
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DBAdministration::onPsauxStopFinished);
m_proc->start();
}
void DBAdministration::onPsauxStopFinished()
{
enableButtons();
QByteArray output = m_proc->readAllStandardOutput();
if (output.contains("svcServiceManagement"))
{
ERROR_LOG(m_logger) << "ServiceManagement started - stopping";
handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-s")});
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DBAdministration::onStopAppFinished);
m_proc->start();
}
else
{
QMessageBox::critical(this, tr("Service Management"), tr("Service Management already stopped."), QMessageBox::Ok);
ERROR_LOG(m_logger) << "ServiceManagement already stopped";
}
}
void DBAdministration::onStopAppFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
handleProcFinished(exitCode, exitStatus);
}
void DBAdministration::onCopyDbFailed()
{
QMessageBox::critical(this, tr ("Exercise"), tr("Could not copy exercise - maybe the exercise already exists."), QMessageBox::Ok);
enableButtons();
m_progressDialog->hide();
}
void DBAdministration::onCopyDbFinished()
{
m_localDatabasesModel->initModel(m_copyExercise->evaluationDb());
m_ui->tableViewLocalDatabases->resizeColumnsToContents();
enableButtons();
m_progressDialog->hide();
}
void DBAdministration::handleProcInit(const QString &program, const QStringList &args)
{
if (m_proc)
{
m_proc->disconnect(this);
m_proc->deleteLater();
}
m_proc = new QProcess(this);
NOTICE_LOG(m_logger) << "Starting process '" << program << "' with args '"
<< args.join(QLatin1Char(' ')) << "'";
m_proc->setProgram(program);
m_proc->setArguments(args);
connect(m_proc, &QProcess::errorOccurred,
this, &DBAdministration::onErrorOccured);
disableButtons();
}
void DBAdministration::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
enableButtons();
if (!m_proc)
return;
if (exitCode != 0 || exitStatus != 0)
{
QByteArray out = m_proc->readAllStandardError();
if (!out.isEmpty())
out += '\n';
out += m_proc->readAllStandardOutput();
ERROR_LOG(m_logger) << "Process finished - exitCode: " << exitCode << ", exitStatus = " << exitStatus << ", " << out;
QMessageBox::critical(this,
tr ("Execute process"), tr("Error executing process, exitCode: %1, exitStatus: %2, output: %3")
.arg(exitCode).arg(exitStatus).arg(QString::fromLocal8Bit(out)),
QMessageBox::Ok);
}
m_proc->disconnect(this);
m_proc->deleteLater();
m_proc = nullptr;
}
void DBAdministration::enaDisaButtons(bool bEnable)
{
{
const QList<QPushButton*> l = findChildren<QPushButton*>();
for (QPushButton *pb : l)
pb->setEnabled(bEnable);
}
{
const QList<QAction*> l = findChildren<QAction*>();
for (QAction *a : l)
a->setEnabled(bEnable);
}
if (bEnable)
enaDisa();
}
bool DBAdministration::checkRunsOnEvaluationServer() const
{
const QHostInfo hostInfoEvaluationDb = QHostInfo::fromName(Settings::evaluationDatabaseHost());
const auto evaluationDbAddresses = hostInfoEvaluationDb.addresses();
if (hostInfoEvaluationDb.addresses().isEmpty())
return false; // we don't know better ...
const QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
for (const QHostAddress &address : addresses)
{
if (address.isLoopback() || address.isNull())
continue;
if (address.protocol() != QAbstractSocket::IPv4Protocol)
continue;
for (const QHostAddress &evaluationAddress : evaluationDbAddresses)
if (address.isEqual(evaluationAddress))
return true;
}
return false;
}
} // namespace DBAdministration