Support inactive RAID devices.

This commit is contained in:
Caio Carvalho 2018-07-15 10:31:27 -03:00
parent 5828e9daac
commit a0b9a93b6b
3 changed files with 131 additions and 12 deletions

View File

@ -39,9 +39,10 @@ public:
qint64 m_arraySize;
QString m_UUID;
QStringList m_devicePathList;
bool m_active;
};
SoftwareRAID::SoftwareRAID(const QString& name, const QString& iconName)
SoftwareRAID::SoftwareRAID(const QString& name, bool active, const QString& iconName)
: VolumeManagerDevice(std::make_shared<SoftwareRAIDPrivate>(),
name,
(QStringLiteral("/dev/") + name),
@ -56,6 +57,7 @@ SoftwareRAID::SoftwareRAID(const QString& name, const QString& iconName)
d_ptr->m_arraySize = getArraySize(deviceNode());
d_ptr->m_UUID = getUUID(deviceNode());
d_ptr->m_devicePathList = getDevicePathList(deviceNode());
d_ptr->m_active = active;
initPartitions();
}
@ -92,7 +94,23 @@ bool SoftwareRAID::shrinkArray(Report &report, const QStringList &devices)
QString SoftwareRAID::prettyName() const
{
return VolumeManagerDevice::prettyName() + xi18nc("@item:inlistbox [RAID level]", " [RAID %1]", raidLevel());
return VolumeManagerDevice::prettyName() +
(isActive() ? xi18nc("@item:inlistbox [RAID level]", " [RAID %1]", raidLevel()) :
QStringLiteral(" [RAID]"));
}
bool SoftwareRAID::operator ==(const Device& other) const
{
bool equalDeviceNode = Device::operator ==(other);
if (other.type() == Device::Type::SoftwareRAID_Device) {
const SoftwareRAID& raid = static_cast<const SoftwareRAID&>(other);
if (!equalDeviceNode)
return raid.uuid() == uuid();
}
return equalDeviceNode;
}
qint32 SoftwareRAID::raidLevel() const
@ -125,9 +143,37 @@ QStringList SoftwareRAID::devicePathList() const
return d_ptr->m_devicePathList;
}
bool SoftwareRAID::isActive() const
{
return d_ptr->m_active;
}
void SoftwareRAID::setActive(bool active)
{
d_ptr->m_active = active;
}
void SoftwareRAID::scanSoftwareRAID(QList<Device*>& devices)
{
// TODO: Check configuration file and load all the devices that aren't in /proc/mdstat as innactive
QList<Device *> scannedRaid;
// TODO: Support custom config files.
QString config = getRAIDConfiguration(QStringLiteral("/etc/mdadm.conf"));
if (!config.isEmpty()) {
QRegularExpression re(QStringLiteral("[\\t\\r\\n\\f\\s]ARRAY \\/dev\\/([\\/\\w-]+)"));
QRegularExpressionMatchIterator i = re.globalMatch(config);
while (i.hasNext()) {
QRegularExpressionMatch reMatch = i.next();
QString deviceName = reMatch.captured(1).trimmed();
SoftwareRAID *raidDevice = new SoftwareRAID(deviceName, false);
scannedRaid << raidDevice;
}
}
ExternalCommand scanRaid(QStringLiteral("cat"), { QStringLiteral("/proc/mdstat") });
if (scanRaid.run(-1) && scanRaid.exitCode() == 0) {
@ -136,14 +182,18 @@ void SoftwareRAID::scanSoftwareRAID(QList<Device*>& devices)
while (i.hasNext()) {
QRegularExpressionMatch reMatch = i.next();
QString deviceNode = QStringLiteral("/dev/") + QStringLiteral("md") + reMatch.captured(1).trimmed();
QString deviceNode = QStringLiteral("/dev/md") + reMatch.captured(1).trimmed();
Device* d = CoreBackendManager::self()->backend()->scanDevice(deviceNode);
SoftwareRAID* d = static_cast<SoftwareRAID *>(CoreBackendManager::self()->backend()->scanDevice(deviceNode));
if ( d )
devices << d;
if (scannedRaid.contains(d))
d->setActive(true);
else
scannedRaid << d;
}
}
devices << scannedRaid;
}
qint32 SoftwareRAID::getRaidLevel(const QString &path)
@ -193,8 +243,51 @@ qint64 SoftwareRAID::getArraySize(const QString &path)
QString SoftwareRAID::getUUID(const QString &path)
{
Q_UNUSED(path)
return QStringLiteral();
QString output = getDetail(path);
if (!output.isEmpty()) {
QRegularExpression re(QStringLiteral("UUID :\\s+([\\w:]+)"));
QRegularExpressionMatch reMatch = re.match(output);
if (reMatch.hasMatch())
return reMatch.captured(1);
}
// If UUID was not found in detail output, it should be searched in config file
// TODO: Support custom config files.
QString config = getRAIDConfiguration(QStringLiteral("/etc/mdadm.conf"));
if (!config.isEmpty()) {
QRegularExpression re(QStringLiteral("[\\t\\r\\n\\f\\s]ARRAY \\/dev\\/md([\\/\\w-]+)(.*)"));
QRegularExpressionMatchIterator i = re.globalMatch(config);
while (i.hasNext()) {
QRegularExpressionMatch reMatch = i.next();
QString deviceNode = QStringLiteral("/dev/md") + reMatch.captured(1).trimmed();
QString otherInfo = reMatch.captured(2).trimmed();
// Consider device node as name=host:deviceNode when the captured device node string has '-' character
// It happens when user have included the device to config file using 'mdadm --examine --scan'
if (deviceNode.contains(QLatin1Char('-'))) {
QRegularExpression reName(QStringLiteral("name=[\\w:]+\\/dev\\/md\\/([\\/\\w]+)"));
QRegularExpressionMatch nameMatch = reName.match(otherInfo);
if (nameMatch.hasMatch())
deviceNode = nameMatch.captured(1);
}
if (deviceNode == path) {
QRegularExpression reUUID(QStringLiteral("(UUID=|uuid=)([\\w:]+)"));
QRegularExpressionMatch uuidMatch = reUUID.match(otherInfo);
if (uuidMatch.hasMatch())
return uuidMatch.captured(2);
}
}
}
return QString();
}
QStringList SoftwareRAID::getDevicePathList(const QString &path)
@ -266,5 +359,12 @@ QString SoftwareRAID::getDetail(const QString &path)
{
ExternalCommand cmd(QStringLiteral("mdadm"),
{ QStringLiteral("--misc"), QStringLiteral("--detail"), path });
return (cmd.run(-1) && cmd.exitCode() == 0) ? cmd.output() : QStringLiteral();
return (cmd.run(-1) && cmd.exitCode() == 0) ? cmd.output() : QString();
}
QString SoftwareRAID::getRAIDConfiguration(const QString &configurationPath)
{
ExternalCommand cmd(QStringLiteral("cat"), { configurationPath });
return (cmd.run(-1) && cmd.exitCode() == 0) ? cmd.output() : QString();
}

View File

@ -27,7 +27,7 @@ class LIBKPMCORE_EXPORT SoftwareRAID : public VolumeManagerDevice
Q_DISABLE_COPY(SoftwareRAID)
public:
SoftwareRAID(const QString& name, const QString& iconName = QString());
SoftwareRAID(const QString& name, bool active = true, const QString& iconName = QString());
const QStringList deviceNodes() const override;
const QStringList& partitionNodes() const override;
@ -39,12 +39,17 @@ public:
virtual QString prettyName() const override;
virtual bool operator==(const Device& other) const override;
qint32 raidLevel() const;
qint64 chunkSize() const;
qint64 totalChunk() const;
qint64 arraySize() const;
QString uuid() const;
QStringList devicePathList() const;
bool isActive() const;
void setActive(bool active);
public:
static void scanSoftwareRAID(QList<Device*>& devices);
@ -80,6 +85,8 @@ protected:
private:
static QString getDetail(const QString& path);
static QString getRAIDConfiguration(const QString& configurationPath);
};
#endif // SOFTWARERAID_H

View File

@ -21,6 +21,7 @@
#include "core/device.h"
#include "core/partitiontable.h"
#include "core/partition.h"
#include "core/raid/softwareraid.h"
#include "jobs/createpartitiontablejob.h"
@ -93,7 +94,18 @@ bool CreatePartitionTableOperation::execute(Report& parent)
*/
bool CreatePartitionTableOperation::canCreate(const Device* device)
{
return (device != nullptr) && (device->partitionTable() == nullptr || !device->partitionTable()->isChildMounted()) && (device->type() != Device::Type::LVM_Device);
if (device == nullptr)
return false;
if (device->type() == Device::Type::SoftwareRAID_Device) {
const SoftwareRAID* raid = static_cast<const SoftwareRAID *>(device);
if (!raid->isActive())
return false;
}
return (device->partitionTable() == nullptr || !device->partitionTable()->isChildMounted())
&& (device->type() != Device::Type::LVM_Device);
}
QString CreatePartitionTableOperation::description() const