You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cvm/src/packages/exec-lvm/commands/get-logical-volumes.js

189 lines
8.8 KiB
JavaScript

"use strict";
const Promise = require("bluebird");
const execBinary = require("../../exec-binary");
const parseIECBytes = require("../../parse-bytes-iec");
const matchValue = require("match-value");
const asJson = require("../modifiers/as-json");
const mapFlag = require("../map-flag");
const parseStringList = require("../parse-string-list");
const parseOptionalString = require("../parse-optional-string");
const parseOptionalDate = require("../parse-optional-date");
const parseIntStrict = require("../../parse-int-strict");
function isUppercase(string) {
return (string === string.toUpperCase());
}
module.exports = function () {
return Promise.try(() => {
return execBinary("lvs")
.asRoot()
.withFlags({
options: "lv_all"
})
.withModifier(asJson((result) => {
return {
volumes: result.report[0].lv.map((volume) => {
return {
path: volume.lv_path,
name: volume.lv_name, // NOTE: Not unique!
fullName: volume.lv_full_name,
uuid: volume.lv_uuid,
deviceMapperPath: volume.lv_dm_path,
// FIXME: lv_parent -- is this just for thin pools?
// FIXME: lv_active, only known value is 'active' but it's not documented
layoutAttributes: parseStringList(volume.lv_layout), // linear, mirrored, striped // FIXME: check for specific values here? and can there really be multiple?
roles: parseStringList(volume.lv_role),
tags: parseStringList(volume.lv_tags),
configurationProfile: parseOptionalString(volume.lv_profile),
creationTime: parseOptionalDate(volume.lv_time),
creationHost: parseOptionalString(volume.lv_host),
neededKernelModules: parseStringList(volume.lv_modules),
dataVolume: parseOptionalString(volume.data_lv), // For thin and cache pools only
metadataVolume: parseOptionalString(volume.metadata_lv), // For thin and cache pools only
poolVolume: parseOptionalString(volume.pool_lv), // For thin volumes only
persistentMajorNumber: (volume.lv_major !== "-1") ? parseIntStrict(volume.lv_major) : undefined,
persistentMinorNumber: (volume.lv_minor !== "-1") ? parseIntStrict(volume.lv_minor) : undefined,
// Volume type: (C)ache, (m)irrored, (M)irrored without initial sync, (o)rigin, (O)rigin with merging snapshot, (r)aid, (R)aid without initial sync, (s)napshot, merging (S)napshot, (p)vmove, (v)irtual, mirror or raid (i)mage, mirror or raid (I)mage out-of-sync, mirror (l)og device, under (c)onversion, thin (V)olume, (t)hin pool, (T)hin pool data, v(d)o pool, v(D)o pool data, raid or pool m(e)tadata or pool metadata spare.
type: mapFlag(volume.lv_attr, 0, {
C: "CACHE",
m: "MIRRORED",
M: "MIRRORED",
o: "ORIGIN",
O: "ORIGIN",
r: "RAID",
R: "RAID",
s: "SNAPSHOT",
S: "SNAPSHOT",
p: "PVMOVE",
v: "VIRTUAL",
i: "IMAGE",
I: "IMAGE",
l: "LOG_DEVICE",
c: "UNDER_CONVERSION",
V: "THIN_VOLUME",
t: "THIN_POOL",
T: "THIN_POOL_DATA",
d: "VDO_POOL",
D: "VDO_POOL_DATA",
e: "METADATA",
"-": "NORMAL"
}),
// Permissions: (w)riteable, (r)ead-only, (R)ead-only activation of non-read-only volume
isReadOnly: mapFlag(volume.lv_attr, 1, {
w: false,
r: true,
R: false
}),
isCurrentlyReadOnly: mapFlag(volume.lv_attr, 1, {
w: false,
r: true,
R: true
}),
// Allocation policy: (a)nywhere, (c)ontiguous, (i)nherited, c(l)ing, (n)ormal This is capitalised if the volume is currently locked against allocation changes, for example during pvmove(8).
isAllocationLocked: isUppercase(volume.lv_attr[2]),
allocationPolicy: mapFlag(volume.lv_attr, 2, {
a: "ANYWHERE",
A: "ANYWHERE",
c: "CONTIGUOUS",
C: "CONTIGUOUS",
i: "INHERITED",
I: "INHERITED",
l: "CLING",
L: "CLING",
n: "NORMAL",
N: "NORMAL"
}),
// State: (a)ctive, (h)istorical, (s)uspended, (I)nvalid snapshot, invalid (S)uspended snapshot, snapshot (m)erge failed, suspended snapshot (M)erge failed, mapped (d)evice present without tables, mapped device present with (i)nactive table, thin-pool (c)heck needed, suspended thin-pool (C)heck needed, (X) unknown
status: mapFlag(volume.lv_attr, 4, {
a: "ACTIVE",
h: "HISTORICAL",
s: null,
I: "SNAPSHOT_INVALID",
S: "SNAPSHOT_INVALID",
m: "SNAPSHOT_MERGE_FAILED",
M: "SNAPSHOT_MERGE_FAILED",
d: "TABLES_MISSING",
i: "TABLES_INACTIVE",
c: "THIN_POOL_CHECK_NEEDED",
C: "THIN_POOL_CHECK_NEEDED",
X: "UNKNOWN"
}),
// isSuspended: mapFlag(volume.lv_attr, 4, {
// a: false,
// h: false,
// s: true,
// I: false,
// S: true,
// m: false,
// M: true,
// d: false,
// i: false,
// c: false,
// C: true,
// X: false
// }),
// Newly-allocated data blocks are overwritten with blocks of (z)eroes before use.
// isZeroFilled: mapFlag(volume.lv_attr, 7, {
// z: true,
// "-": false
// }),
// Volume Health, where there are currently three groups of attributes identified:
// (p)artial signifies that one or more of the Physical Volumes this Logical Volume uses is missing from the system. (X) unknown signifies the status is unknown.
// (r)efresh signifies that one or more of the Physical Volumes this RAID Logical Volume uses had suffered a write error. The write error could be due to a temporary failure of that Physical Volume or an indication that it is failing. The device should be refreshed or replaced. (m)ismatches signifies that the RAID logical volume has portions of the array that are not coherent. Inconsistencies are detected by initiating a "check" on a RAID logical volume. (The scrubbing operations, "check" and "repair", can be performed on a RAID logical volume via the 'lvchange' command.) (w)ritemostly signifies the devices in a RAID 1 logical volume that have been marked write-mostly. Re(s)haping signifies a RAID Logical Volume is either undergoing a stripe addition/removal, a stripe size or RAID algorithm change. (R)emove after reshape signifies freed striped raid images to be removed.
// (F)ailed is set if thin pool encounters serious failures and hence no further I/O is permitted at all. The out of (D)ata space is set if thin pool has run out of data space. (M)etadata read only signifies that thin pool encounters certain types of failures but it's still possible to do reads at least, but no metadata changes are allowed.
// (F)ailed is set when related thin pool enters Failed state and no further I/O is permitted at all.
// (E)rror is set dm-writecache reports an error.
healthStatus: mapFlag(volume.lv_attr, 8, {
X: "UNKNOWN",
p: "PV_MISSING",
r: "RAID_REPLACE_DEVICE",
m: "RAID_MISMATCH",
w: "RAID_PREFER_WRITE_ONLY",
s: "RAID_RESHAPING",
R: "RAID_REMOVE_UNNECESSARY",
F: "FAILED",
D: "OUT_OF_DATA_SPACE",
M: "METADATA_FAILURE_READ_ONLY",
E: "WRITECACHE_ERROR_REPORTED",
"-": "HEALTHY"
}),
// s(k)ip activation: this volume is flagged to be skipped during activation.
// isActivationSkipped: mapFlag(volume.lv_attr, 9, {
// k: true,
// "-": false
// }),
isInitiallySynchronized: (volume.lv_initial_image_sync === "initial image sync"),
isCurrentlySynchronized: (volume.lv_image_synced === "image synced"),
isMerging: (volume.lv_merging === "merging"),
isConverting: (volume.lv_converting === "converting"),
isSuspended: (volume.lv_suspended === "suspended"),
isActivationSkipped: (volume.lv_skip_activation === "skip activation"),
isOpened: (volume.lv_device_open === "open"),
isActiveLocally: (volume.lv_active_locally === "active locally"),
isActiveRemotely: (volume.lv_active_remotely === "active remotely"),
isActiveExclusively: (volume.lv_active_exclusively === "active exclusively"),
isMergeFailed: (volume.lv_merge_failed === "merge failed"),
isSnapshotInvalid: (volume.lv_merge_failed === "snapshot invalid"), // Snapshots only
isLiveTablePresent: (volume.lv_live_table === "live table present"),
isInactiveTablePresent: (volume.lv_live_table === "inactive table present"),
isZeroFilled: (volume.zero === "zero"), // Thin pools only
hasFixedMinorNumber: (volume.lv_fixed_minor === "fixed minor"),
outOfSpacePolicy: matchValue(volume.lv_when_full, {
error: "ERROR",
queue: "QUEUE",
"": null
})
};
})
};
}))
.execute();
}).then((output) => {
return output.result;
});
};