阶段提交

This commit is contained in:
zhaominyong 2021-11-11 16:03:58 +08:00
parent 2c2815d433
commit 2b1f31aef0
10 changed files with 620 additions and 12 deletions

View File

@ -37,6 +37,7 @@ HEADERS += \
myprocess/rsyncpathtodirprocess.h \
parsebackuplist.h \
systembackupproxy.h \
udisksystembackupproxy.h \
workerfactory.h
SOURCES += \
@ -54,6 +55,7 @@ SOURCES += \
myprocess/rsyncpathtodirprocess.cpp \
parsebackuplist.cpp \
systembackupproxy.cpp \
udisksystembackupproxy.cpp \
workerfactory.cpp
# Default rules for deployment.

View File

@ -35,6 +35,7 @@ int main(int argc, char *argv[])
QString qsAppPath = QCoreApplication::applicationDirPath();
Utils::initSysRootPath(qsAppPath);
qInstallMessageHandler(Utils::customMessageHandler);
Utils::initSystemInfo();
// test begin
qDebug() << QString("测试 begin");

View File

@ -1,10 +1,10 @@
#include "rsyncpathtodirprocess.h"
#include <unistd.h>
#include <QDebug>
RsyncPathToDirProcess::RsyncPathToDirProcess(QObject *parent) :
QObject(parent),
m_p(new QProcess(this))
m_p(new QProcess(this)),
m_syncProcess(new QProcess(this))
{
m_currentRate = 0;
m_bSuccess = false;
@ -19,7 +19,6 @@ RsyncPathToDirProcess::RsyncPathToDirProcess(QObject *parent) :
if (m_currentRate == tmpRate)
return;
m_currentRate = tmpRate;
sync();
emit progress(m_currentRate);
}
});
@ -34,7 +33,13 @@ RsyncPathToDirProcess::RsyncPathToDirProcess(QObject *parent) :
m_p->kill();
});
connect(m_p, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
connect(m_p, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(rsync_finished(int, QProcess::ExitStatus)));
connect(m_syncProcess, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
Q_UNUSED(error)
m_syncProcess->kill();
});
connect(m_syncProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(sync_finished(int, QProcess::ExitStatus)));
}
RsyncPathToDirProcess::~RsyncPathToDirProcess()
@ -49,6 +54,7 @@ bool RsyncPathToDirProcess::start(QStringList args, bool block)
qDebug() << "RsyncPathToDirProcess::start invoke begin";
m_currentRate = 0;
m_bSuccess = false;
m_block = block;
QString cmd("rsync");
for (const QString& item : args) {
@ -63,7 +69,7 @@ bool RsyncPathToDirProcess::start(QStringList args, bool block)
return false;
}
if (block) {
if (m_block) {
if (!m_p->waitForFinished()) {
qCritical("rsync finished failed");
return false;
@ -74,18 +80,40 @@ bool RsyncPathToDirProcess::start(QStringList args, bool block)
return m_bSuccess;
}
void RsyncPathToDirProcess::processFinished(int exitCode, QProcess::ExitStatus)
void RsyncPathToDirProcess::rsync_finished(int exitCode, QProcess::ExitStatus)
{
qDebug() << "RsyncPathToDirProcess::processFinished invoke begin";
qDebug() << "RsyncPathToDirProcess::rsync_finished invoke begin";
if (exitCode == QProcess::NormalExit || exitCode == 24 || exitCode == 23) {
sync();
if (m_block) {
m_bSuccess = true;
emit progress(100);
emit finished(true);
} else {
m_syncProcess->start("sync");
if (!m_syncProcess->waitForStarted()) {
m_bSuccess = false;
emit finished(false);
}
}
} else {
m_bSuccess = false;
emit finished(false);
}
qDebug() << "RsyncPathToDirProcess::rsync_finished invoke end";
}
void RsyncPathToDirProcess::sync_finished(int exitCode, QProcess::ExitStatus)
{
qDebug() << "RsyncPathToDirProcess::sync_finished invoke begin";
if (exitCode == QProcess::NormalExit || exitCode == 24 || exitCode == 23) {
m_bSuccess = true;
emit progress(100);
emit finished(true);
} else {
m_bSuccess = false;
emit finished(false);
}
qDebug() << "RsyncPathToDirProcess::processFinished invoke end";
qDebug() << "RsyncPathToDirProcess::sync_finished invoke end";
}

View File

@ -12,6 +12,11 @@ public:
bool start(QStringList args, bool block = true);
inline void stop() {
m_p->kill();
m_syncProcess->kill();
}
signals:
// 结果信号
void finished(bool result);
@ -20,12 +25,16 @@ signals:
private slots:
// m_p执行结束
void processFinished(int exitCode, QProcess::ExitStatus);
void rsync_finished(int exitCode, QProcess::ExitStatus);
// m_syncProcess执行结束
void sync_finished(int exitCode, QProcess::ExitStatus);
private:
QProcess * m_p;
QProcess* m_syncProcess;
int m_currentRate;
bool m_bSuccess;
bool m_block;
};
#endif // RSYNCPATHTODIRPROCESS_H

View File

@ -31,6 +31,10 @@
#define TYPE "Type"
#define POSITION "Position"
#define USERID "UserId"
#define OS "OS"
#define ARCH "Arch"
#define ARCHDETECT "ArchDetect"
#define STATUE_BACKUP_FINESHED "backup finished"
ParseBackupList::ParseBackupList(const QString& xmlPath)
@ -312,6 +316,18 @@ void ParseBackupList::elementNodeToBackupPoint(const QDomElement& node, BackupPo
QDomElement eleUserId = node.firstChildElement(USERID);
if (!eleUserId.isNull())
backupPoint.m_userId = eleUserId.text();
QDomElement eleOS = node.firstChildElement(OS);
if (!eleOS.isNull())
backupPoint.m_os = eleOS.text();
QDomElement eleArch = node.firstChildElement(ARCH);
if (!eleArch.isNull())
backupPoint.m_arch = eleArch.text();
QDomElement eleArchDetect = node.firstChildElement(ARCHDETECT);
if (!eleArchDetect.isNull())
backupPoint.m_archdetect = eleArchDetect.text();
}
/**
@ -328,8 +344,19 @@ void ParseBackupList::backupPointToElementNode(const BackupPoint& backupPoint, Q
node.appendChild(createTextElement(doc, STATE, backupPoint.m_state));
node.appendChild(createTextElement(doc, TYPE, QString::number(backupPoint.m_type)));
node.appendChild(createTextElement(doc, POSITION, QString::number(backupPoint.m_iPosition)));
if (!backupPoint.m_userId.isEmpty()) {
node.appendChild(createTextElement(doc, USERID, backupPoint.m_userId));
}
if (!backupPoint.m_os.isEmpty()) {
node.appendChild(createTextElement(doc, OS, backupPoint.m_os));
}
if (!backupPoint.m_arch.isEmpty()) {
node.appendChild(createTextElement(doc, ARCH, backupPoint.m_arch));
}
if (!backupPoint.m_archdetect.isEmpty()) {
node.appendChild(createTextElement(doc, ARCHDETECT, backupPoint.m_archdetect));
}
}
/**
* @brief createTextElement

View File

@ -35,6 +35,14 @@ public:
QString m_state;
// 备份用户id
QString m_userId;
// 备份机器操作系统
QString m_os;
// 备份机器架构
QString m_arch;
// 备份机器引导方式
QString m_archdetect;
// 备份点所在设备挂载路径(这个暂只在查询中界面展示选择中使用)
QString m_path;
bool isNull() { return m_uuid.isEmpty(); }

View File

@ -0,0 +1,349 @@
#include "udisksystembackupproxy.h"
#include "systembackupproxy.h"
#include <QStorageInfo>
#include <QDateTime>
#include <QDebug>
#include <kysec/status.h>
#include "../common/utils.h"
#include "../common/mydusizetool.h"
#include "mymountproxy.h"
IMPLEMENT_DYNCREATE(UDiskSystemBackupProxy)
UDiskSystemBackupProxy::UDiskSystemBackupProxy()
{
m_bSuccess = false;
m_p = nullptr;
m_size = 0;
m_calc = new CalcBackupSize(this);
m_isOnlyCheck = true;
}
UDiskSystemBackupProxy::~UDiskSystemBackupProxy()
{
delete m_p;
m_p = nullptr;
delete m_calc;
m_calc = nullptr;
}
/**
* @brief
* @return false,;true,
*/
bool UDiskSystemBackupProxy::checkEnvEx()
{
qDebug() << "UDiskSystemBackupProxy::checkEnv invoke begin";
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备都得保证/backup挂载上); 若没挂载,挂载
MyMountProxy mountProxy;
if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) {
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
return false;
}
// 2、计算备份大小
calcSizeForBackup();
qDebug() << "UDiskSystemBackupProxy::checkEnv invoke end";
return true;
}
/**
* @brief
*/
void UDiskSystemBackupProxy::doWorkEx()
{
qDebug() << "UDiskSystemBackupProxy::doWorkEx invoke begin";
m_isOnlyCheck = false;
// 环境检测
checkEnvEx();
qDebug() << "UDiskSystemBackupProxy::doWorkEx invoke end";
}
void UDiskSystemBackupProxy::cancelEx()
{}
/**
* @brief
* @return true, false
*/
bool UDiskSystemBackupProxy::isIncBackup()
{
QString backupPath;
ParseBackupList::BackupPoint point;
if (m_backupWrapper.m_uuid.isEmpty()) {
QString xmlPath(m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH);
xmlPath.replace("//", "/");
ParseBackupList parser(xmlPath);
point = parser.getLastSysBackupPoint();
if (point.m_uuid.isEmpty())
return false;
backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + point.m_uuid + "/data";
} else {
backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
}
backupPath.replace("//", "/");
if (Utils::isDirExist(backupPath)) {
m_backupWrapper.m_baseUuid = point.m_uuid;
m_backupWrapper.m_bIncrement = true;
m_backupWrapper.m_type = BackupType::INC_BACKUP_SYSTEM;
return true;
}
return false;
}
/**
* @brief
*/
void UDiskSystemBackupProxy::checkFreeCapacity(qint64 itotalSize)
{
qDebug() << "UDiskSystemBackupProxy::checkFreeCapacity invoke begin";
// 1、计算待备份数据的大小
m_size = itotalSize;
// 备份过程中会有一些临时文件产生会占用一部分空间故我们预留500M的空间
itotalSize += 500 * MB;
// 2、计算备份分区剩余空间大小
QString backupPath(m_backupWrapper.m_prefixDestPath);
backupPath.replace("//", "/");
QStorageInfo backupDisk(backupPath);
qint64 freeSize = backupDisk.bytesFree();
// 3、校验空间是否足够
if (itotalSize > freeSize) {
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
} else {
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
}
if (m_isOnlyCheck)
return ;
// 开始备份
doBackup();
qDebug() << "UDiskSystemBackupProxy::checkFreeCapacity invoke end";
}
/**
* @brief
* @return ,
*/
void UDiskSystemBackupProxy::calcSizeForBackup()
{
// 拼接备份源路径和目标路径,测试所需备份空间大小;目标路径为一虚拟路径
QString srcPath = Utils::getSysRootPath();
srcPath += "/";
srcPath.replace("//", "/");
QString destPath = Utils::getSysRootPath();
destPath += CHECK_PATH;
destPath.replace("//", "/");
Utils::mkpath(destPath);
QStringList args = getRsyncArgs(UDiskSystemBackupScene::TRY_SYSTEM_BACKUP);
args << srcPath;
args << destPath;
connect(m_calc, &CalcBackupSize::finished, this, &UDiskSystemBackupProxy::checkFreeCapacity);
m_calc->start(args, false);
}
/**
* @brief rsync命令参数
* @param scene
* @return rsync的参数信息
*/
QStringList UDiskSystemBackupProxy::getRsyncArgs(UDiskSystemBackupScene scene)
{
QStringList args;
switch (scene) {
case UDiskSystemBackupScene::SYSTEM_BACKUP :
args << "-avAHXW";
args << "--progress";
args << "--no-inc-recursive";
args << "--ignore-missing-args";
break ;
case UDiskSystemBackupScene::TRY_SYSTEM_BACKUP :
args << "-aAHXWn";
args << "--stats";
args << "--ignore-missing-args";
break ;
default:
return args;
}
return args;
}
/**
* @brief
*/
void UDiskSystemBackupProxy::doBackup()
{
qDebug() << "UDiskSystemBackupProxy::doBackup invoke begin";
// 准备
if (!doPrepare())
return ;
// 启动备份efi, 修改为和其它目录统一备份,不再单独进行备份
// if (!backupEfi()) {
// emit checkResult(int(BackupResult::EFI_RSYNC_FAIL));
// return ;
// }
// 启动系统备份
backupSystem();
qDebug() << "UDiskSystemBackupProxy::doBackup invoke end";
}
/**
* @brief
* @return true,false
*/
bool UDiskSystemBackupProxy::doPrepare()
{
qDebug() << "UDiskSystemBackupProxy::doPrepare invoke begin";
m_bSuccess = false;
// 1、设置当前备份的Uuid
m_curUuid += Utils::createUuid();
// 2、准备备份目录及文件
m_destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
m_destPath.replace("//", "/");
if (!Utils::mkpath(m_destPath)) {
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
return false;
}
QString userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
userFile.replace("//", "/");
if (!Utils::writeFileByLines(userFile, m_backupWrapper.m_backupPaths)) {
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
qCritical() << QString("create file %1 failed !").arg(userFile) ;
return false;
}
QString excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
excludeUserFile.replace("//", "/");
if (!Utils::writeFileByLines(excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
qCritical() << QString("create file %1 failed !").arg(excludeUserFile) ;
return false;
}
// 3、记录/backup/snapshots/backuplist.xml文件
if (!recordBackupPoint()) {
qCritical() << "add or update item to backuplist.xml failed !";
return false;
}
qDebug() << "UDiskSystemBackupProxy::doPrepare invoke end";
return true;
}
/**
* @brief /backup/snapshots/backuplist.xml文件
* @return true-false-
*/
bool UDiskSystemBackupProxy::recordBackupPoint()
{
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
m_backupPoint.m_uuid = m_curUuid;
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
m_backupPoint.m_type = m_backupWrapper.m_type;
m_backupPoint.m_size = Utils::StringBySize(m_size);
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
m_backupPoint.m_os = SystemInfo::m_os;
m_backupPoint.m_arch = SystemInfo::m_arch;
m_backupPoint.m_archdetect = SystemInfo::m_archDetect;
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
xmlPath.replace("//", "/");
ParseBackupList parse(xmlPath);
if (m_backupWrapper.m_uuid.isEmpty() || !m_backupWrapper.m_bIncrement) {
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
return false;
}
} else {
if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) {
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL));
return false;
}
}
return true;
}
/**
* @brief
* @return truefalse
*/
bool UDiskSystemBackupProxy::backupSystem()
{
qDebug() << "UDiskSystemBackupProxy::backupSystem invoke begin";
// 全量备份场景
QStringList args = getRsyncArgs(UDiskSystemBackupScene::SYSTEM_BACKUP);
// 拼接备份源路径和目标路径
QString srcPath = Utils::getSysRootPath();
srcPath += "/";
srcPath.replace("//", "/");
args << srcPath;
QString destPath = m_destPath + "/";
destPath.replace("//", "/");
args << destPath;
m_p = new RsyncPathToDirProcess(this);
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskSystemBackupProxy::progress);
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
if (result) {
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
xmlPath.replace("//", "/");
ParseBackupList parse(xmlPath);
parse.updateItem(m_backupPoint);
Utils::writeBackupLog(m_backupPoint.m_time + ","
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size);
m_bSuccess = true;
}
emit this->workResult(result);
});
m_p->start(args, false);
do_kylin_security(m_destPath);
qDebug() << "UDiskSystemBackupProxy::backupSystem invoke end";
return true;
}
void UDiskSystemBackupProxy::do_kylin_security(const QString& dstDir)
{
int ret = 0;
ret = kysec_getstatus();
if (ret > 0) {
QString seFilePath(dstDir + "/.exectl");
QFile file(seFilePath);
file.open(QIODevice::WriteOnly);
file.close();
}
}

View File

@ -0,0 +1,88 @@
#ifndef UDISKSYSTEMBACKUPPROXY_H
#define UDISKSYSTEMBACKUPPROXY_H
#include "workerfactory.h"
#include "myprocess/rsyncpathtodirprocess.h"
#include "parsebackuplist.h"
#include "myprocess/calcbackupsize.h"
class UDiskSystemBackupProxy : public Worker
{
Q_OBJECT
DECLARE_DYNCREATE(UDiskSystemBackupProxy)
public:
// 系统备份的几种场景
enum UDiskSystemBackupScene {
SYSTEM_BACKUP, // 系统备份
TRY_SYSTEM_BACKUP, // 测试系统备份,可用于计算备份传输数据大小
};
explicit UDiskSystemBackupProxy();
virtual ~UDiskSystemBackupProxy();
public:
// 环境检测
virtual bool checkEnvEx();
// 任务处理
virtual void doWorkEx();
// 任务取消
virtual void cancelEx();
private slots:
// 校验剩余空间是否满足备份
void checkFreeCapacity(qint64 itotalSize);
private:
// 判断是否增量备份
bool isIncBackup();
// 计算备份所需空间大小
void calcSizeForBackup();
/**
* @brief rsync命令参数
* @param scene
* @return rsync的参数信息
*/
QStringList getRsyncArgs(UDiskSystemBackupScene scene);
/**
* @brief /backup/snapshots/backuplist.xml文件
* @return true-false-
*/
bool recordBackupPoint();
// 备份准备
bool doPrepare();
// 备份
void doBackup();
// 备份系统
bool backupSystem();
void do_kylin_security(const QString& dstDir);
// 计算备份空间大小的进程
CalcBackupSize *m_calc;
// 是否备份成功
bool m_bSuccess;
// 当前备份uuid
QString m_curUuid;
// 当前备份目标目录
QString m_destPath;
// 当前备份所需空间大小
qint64 m_size;
// 备份进程
RsyncPathToDirProcess *m_p;
// 当前备份节点
ParseBackupList::BackupPoint m_backupPoint;
// 是否只是检测
bool m_isOnlyCheck;
};
#endif // UDISKSYSTEMBACKUPPROXY_H

View File

@ -21,6 +21,10 @@
#include "mylittleparse.h"
#include "mydefine.h"
QString SystemInfo::m_os;
QString SystemInfo::m_arch;
QString SystemInfo::m_archDetect;
QString Utils::m_sysRootPath = "/";
/**
@ -897,3 +901,59 @@ QList<BackupWrapper> Utils::getBackupLogList()
return list;
}
/**
* @brief
*/
void Utils::initSystemInfo()
{
SystemInfo::m_os = Utils::getOs();
SystemInfo::m_arch = Utils::getArch();
SystemInfo::m_archDetect = Utils::getArchDetect();
}
/**
* @brief getOs
* @return ,
* Kylin-Desktop V10-SP1
* Build 20210407
*/
QString Utils::getOs()
{
QString path = Utils::getSysRootPath() + "/etc/kylin-build";
path.replace("//", "/");
QFile file(path);
/* 文件内容形如:
Kylin-Desktop V10-SP1
Build 20210407
*/
QString os;
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
if (!in.atEnd()) {
os = in.readLine();
}
}
return os;
}
/**
* @brief getArch
* @return arch命令的结果x86_64
*/
QString Utils::getArch()
{
QString arch = Utils::executeCmd("arch");
return arch.replace("\n", "");
}
/**
* @brief getArchDetect
* @return archdetect命令的结果amd64/efi
*/
QString Utils::getArchDetect()
{
QString arch = Utils::executeCmd("archdetect");
return arch.replace("\n", "");
}

View File

@ -5,6 +5,17 @@
#include <QtDebug>
#include "mydefine.h"
class SystemInfo
{
public:
// 操作系统
static QString m_os;
// 架构
static QString m_arch;
// 引导方式
static QString m_archDetect;
};
/**
* @brief
* @author zhaominyong
@ -212,6 +223,31 @@ public:
*/
static QList<BackupWrapper> getBackupLogList();
/**
* @brief
*/
static void initSystemInfo();
/**
* @brief getOs
* @return ,
* Kylin-Desktop V10-SP1
* Build 20210407
*/
static QString getOs();
/**
* @brief getArch
* @return arch命令的结果x86_64
*/
static QString getArch();
/**
* @brief getArchDetect
* @return archdetect命令的结果amd64/efi
*/
static QString getArchDetect();
private:
// 系统根目录,默认"/"
static QString m_sysRootPath;