OvhKvm/dedicatedserverinfowidget.cpp

223 lines
9.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dedicatedserverinfowidget.h"
#include "ui_dedicatedserverinfowidget.h"
#include <QTimer>
#include <QNetworkRequest>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <QUrlQuery>
#include <QDate>
#include <QDebug>
#include <QDesktopServices>
#include <QMessageBox>
#include <QInputDialog>
#include <ranges>
#include "ovhapi.h"
const auto ten_years = 87600h;
// Translated QString, stored there for easy single translation...
QString monitoringWithIntervention, monitoringWithoutIntervention, noMonitoring;
DedicatedServerInfoWidget::DedicatedServerInfoWidget(OvhApi *api, const QString &serverName, QWidget *parent) :
QWidget(parent),
api(api),
_serverName(serverName),
ui(new Ui::DedicatedServerInfoWidget)
{
ui->setupUi(this);
QTimer::singleShot(0, this, &DedicatedServerInfoWidget::fetchOvhServerInfo);
if (monitoringWithIntervention.isEmpty()) {
monitoringWithIntervention = tr("Enabled with intervention");
monitoringWithoutIntervention = tr("Enabled without intervention");
noMonitoring = tr("Disabled");
}
}
DedicatedServerInfoWidget::~DedicatedServerInfoWidget()
{
delete ui;
}
QCoro::Task<> DedicatedServerInfoWidget::fetchOvhServerInfo()
{
auto serverInfo = (co_await api->get("/dedicated/server/" + _serverName, 1h)).object();
qDebug() << serverInfo;
ui->serverName->setText(serverInfo["name"].toString());
ui->datacenter->setText(serverInfo["datacenter"].toString());
ui->rack->setText(serverInfo["rack"].toString());
if (serverInfo["monitoring"].toBool()) {
if (serverInfo["noIntervention"].toBool())
ui->ovhMonitoring->setText(monitoringWithoutIntervention);
else
ui->ovhMonitoring->setText(monitoringWithIntervention);
} else {
ui->ovhMonitoring->setText(noMonitoring);
}
auto serviceInfo = (co_await api->get(QString("/dedicated/server/%1/serviceInfos").arg(_serverName), 1h)).object();
auto serviceId = serviceInfo["serviceId"].toInt();
auto servicesData = (co_await api->get(QString("/services/%1").arg(serviceId), 6h)).object();
auto billingData = servicesData["billing"].toObject();
auto pricingData = billingData["pricing"].toObject();
qDebug() << serviceInfo;
QDate creationDate = QDate::fromString(serviceInfo["creation"].toString(), Qt::ISODate);
QDate expirationDate = QDate::fromString(serviceInfo["expiration"].toString(), Qt::ISODate);
QString serverDates = QString{"%1 - %2"}.arg(creationDate.toString()).arg(expirationDate.toString());
ui->serverDates->setText(serverDates);
if (!billingData["engagement"].isNull()) {
// Now figure out the mess here.
auto engagementConfiguration = pricingData["engagementConfiguration"].toObject();
auto engagementInfo = billingData["engagement"].toObject();
QDate engageDate = QDate::fromString(engagementInfo["endDate"].toString(), Qt::ISODate);
QString strategy = engagementInfo["endRule"].toObject()["strategy"].toString();
QString engagementLine1, engagementLine2;
if (strategy == "REACTIVATE_ENGAGEMENT") {
engagementLine1 = tr("Until %1, <b>automatic reactivation</b>").arg(engageDate.toString());
} else if (strategy == "STOP_ENGAGEMENT_FALLBACK_DEFAULT_PRICE") {
engagementLine1 = tr("Until %1, stopping engagement after").arg(engageDate.toString());
} else {
engagementLine1 = tr("Until %1, unknown strategy %2").arg(engageDate.toString()).arg(strategy);
}
int periodDuration = -1;
QRegularExpression engagementDurationRegex{"^P(\\d+)M"};
auto match = engagementDurationRegex.match(engagementConfiguration["duration"].toString());
if (match.hasMatch()) {
periodDuration = match.captured(1).toInt();
} else {
qDebug() << "No match for " << engagementConfiguration["duration"].toString();
}
auto type = engagementConfiguration["type"].toString();
if (type == "upfront") {
engagementLine2 = tr("<b>Upfront payment for %1 months at once</b>").arg(periodDuration);
} else if (type == "periodic") {
engagementLine2 = tr("Periodic payment, engage for %1 months at once").arg(periodDuration);
} else {
engagementLine2 = tr("Unknown type %1 for %2 months at once").arg(type).arg(periodDuration);
}
ui->engagement->setText(engagementLine1 + "<br />" + engagementLine2);
} else {
ui->engagement->setText(tr("No engagement"));
}
auto networkInfo = (co_await api->get(QString("/dedicated/server/%1/specifications/network").arg(_serverName), 240h)).object();
qDebug() << networkInfo;
auto routingInfo = networkInfo["routing"].toObject();
auto v4Info = routingInfo["ipv4"].toObject();
ui->ipv4->setText(v4Info["ip"].toString());
ui->ipv4gateway->setText(v4Info["gateway"].toString());
auto v6Info = routingInfo["ipv6"].toObject();
ui->ipv6->setText(v6Info["ip"].toString());
ui->ipv6gateway->setText(v6Info["gateway"].toString());
auto hardwareInfo = (co_await api->get(QString("/dedicated/server/%1/specifications/hardware").arg(_serverName), 240h)).object();
qDebug() << hardwareInfo;
ui->description->setText(hardwareInfo["description"].toString());
ui->cpu->setText(QString("%1 × %2").arg(hardwareInfo["numberOfProcessors"].toInt()).arg(hardwareInfo["processorName"].toString()));
auto memoryInfo = hardwareInfo["memorySize"].toObject();
ui->ram->setText(QString("%1 %2").arg(memoryInfo["value"].toInt()).arg(memoryInfo["unit"].toString()));
QStringList storages;
for (auto storage: hardwareInfo["diskGroups"].toArray()) {
storages.append(storage.toObject()["description"].toString());
}
ui->storage->setText(storages.join("\n"));
// Check KVM support on IPMI, HTML5 only so far.
auto ipmiInfo = (co_await api->get(QString("/dedicated/server/%1/features/ipmi").arg(_serverName), 24h)).object();
qDebug() << ipmiInfo;
if (!ipmiInfo["activated"].toBool()) {
ui->kvmButton->setEnabled(false);
ui->kvmButton->setText(tr("IPMI disabled, no KVM"));
}
if (!ipmiInfo["supportedFeatures"].toObject()["kvmipHtml5URL"].toBool()
&&
!ipmiInfo["supportedFeatures"].toObject()["kvmipJnlp"].toBool()) {
ui->kvmButton->setEnabled(false);
ui->kvmButton->setText(tr("No KVM available"));
}
// Calculate monthly cost, using the /services API
double totalCost = pricingData["price"].toObject()["value"].toDouble();
totalCost = totalCost / pricingData["interval"].toInt();
QString currency = pricingData["price"].toObject()["currency"].toString();
ui->monthlyCost->setText(QString("%1 %2").arg(totalCost).arg(currency));
}
QCoro::Task<> DedicatedServerInfoWidget::on_findLastBill_clicked()
{
ui->findLastBill->setEnabled(false);
auto textBackup = ui->findLastBill->text();
ui->findLastBill->setText(tr("Searching"));
// Let the pain begin
auto billList = (co_await api->get("/me/bill/", 12h)).array();
for (int i = billList.size() - 1 ; i >= 0 ; i--) {
auto billId = billList[i].toString();
qDebug() << "Checking bill " << billId;
auto billItems = (co_await api->get(QString("/me/bill/%1/details").arg(billId), ten_years)).array();
for (auto billItemId: billItems) {
qDebug() << "Checking bill " << billId << " item " << billItemId.toString();
auto billItem = (co_await api->get(QString("/me/bill/%1/details/%2").arg(billId).arg(billItemId.toString()), ten_years)).object();
qDebug() << billItem["domain"].toString() << " vs " << _serverName;
if (billItem["domain"].toString().startsWith(_serverName)) {
qDebug() << "EUREKA !";
auto billInfo = (co_await api->get(QString("/me/bill/%1").arg(billId), ten_years)).object();
QDesktopServices::openUrl(billInfo["url"].toString());
ui->findLastBill->setText(textBackup);
ui->findLastBill->setEnabled(true);
co_return;
}
}
}
ui->findLastBill->setText(textBackup);
ui->findLastBill->setEnabled(true);
}
void DedicatedServerInfoWidget::on_kvmButton_clicked()
{
emit kvmRequested();
}
void DedicatedServerInfoWidget::on_renewCgi_clicked()
{
// best OVH page ever. trust me I know.
QUrl renewCgiUrl{"https://www.ovh.com/fr/cgi-bin/order/renew.cgi"};
QUrlQuery renewQuery{{"domainChooser", _serverName}};
renewCgiUrl.setQuery(renewQuery);
QDesktopServices::openUrl(renewCgiUrl);
}
QCoro::Task<> DedicatedServerInfoWidget::on_changeMonitoringButton_clicked()
{
QStringList monitoringStatus = {monitoringWithIntervention, monitoringWithoutIntervention, noMonitoring};
int currentStatus = monitoringStatus.indexOf(ui->ovhMonitoring->text());
bool ok;
auto newMode = QInputDialog::getItem(this, tr("New monitoring mode"), tr("What status do you want for OVH monitoring"), monitoringStatus, currentStatus, false, &ok);
if (ok && newMode != ui->ovhMonitoring->text()) {
// Build change data
QJsonObject data;
if (newMode == noMonitoring)
data.insert("monitoring", false);
else {
data.insert("monitoring", true);
if (newMode == monitoringWithIntervention)
data.insert("noIntervention", false);
else
data.insert("noIntervention", true);
}
// Put and refresh
co_await api->put("/dedicated/server/" + _serverName, QJsonDocument(data).toJson());
co_await api->get("/dedicated/server/" + _serverName, 1h, true);
fetchOvhServerInfo();
}
}