Move LVM schema into dlayer module
parent
a768a3f246
commit
300c58533f
@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
const Promise = require("bluebird");
|
||||
const memoizee = require("memoizee");
|
||||
|
||||
// FIXME: Figure out a reasonable way to make this symbol its own (conflict-free) package, given that it'll be used all across both sysquery and CVM
|
||||
const All = require("../graphql-interface/symbols/all");
|
||||
|
||||
// This generates a (memoized) source function for commands that always produce an entire list, that needs to be filtered for the desired item(s)
|
||||
module.exports = function evaluateAndPick({ command, selectResult, selectID, many }) {
|
||||
let commandOnce = memoizee(command);
|
||||
|
||||
return function (ids) {
|
||||
return Promise.try(() => {
|
||||
return commandOnce();
|
||||
}).then((result) => {
|
||||
if (selectResult != null) {
|
||||
return selectResult(result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}).then((items) => {
|
||||
return ids.map((id) => {
|
||||
if (id === All) {
|
||||
return items;
|
||||
} else if (many === true) {
|
||||
// NOTE: This produces nested arrays! One array for each input ID.
|
||||
return items.filter((item) => selectID(item) === id);
|
||||
} else {
|
||||
// TODO: Can this be more performant? Currently it is a nested loop
|
||||
return items.find((item) => selectID(item) === id);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
const Promise = require("bluebird");
|
||||
const All = require("../graphql-interface/symbols/all");
|
||||
|
||||
module.exports = async function mapFromSource(source, ids, mapper) {
|
||||
let results = (ids === All || ids == null)
|
||||
? await source.load(All)
|
||||
: await Promise.map(ids, (id) => source.load(id));
|
||||
|
||||
return results.map(mapper);
|
||||
};
|
@ -1,64 +1,183 @@
|
||||
"use strict";
|
||||
|
||||
const Promise = require("bluebird");
|
||||
const DataLoader = require("dataloader");
|
||||
const dlayerSource = require("../dlayer-source");
|
||||
const evaluateAndPick = require("../evaluate-and-pick");
|
||||
const mapFromSource = require("../map-from-source");
|
||||
const lvm = require("../exec-lvm");
|
||||
const All = require("../graphql-interface/symbols/all");
|
||||
|
||||
module.exports = {
|
||||
name: "LVM",
|
||||
initialize: function () {
|
||||
let types = {
|
||||
"sysquery.lvm.PhysicalVolume": function PhysicalVolume({ path }) {
|
||||
|
||||
},
|
||||
"sysquery.lvm.VolumeGroup": function VolumeGroup({ name }) {
|
||||
|
||||
},
|
||||
"sysquery.lvm.LogicalVolume": function LogicalVolume({ path }) {
|
||||
|
||||
}
|
||||
makeContext: function () {
|
||||
return {
|
||||
physicalVolumes: new DataLoader(evaluateAndPick({
|
||||
command: lvm.getPhysicalVolumes,
|
||||
selectResult: (result) => result.volumes,
|
||||
selectID: (device) => device.path
|
||||
})),
|
||||
volumeGroups: new DataLoader(evaluateAndPick({
|
||||
command: lvm.getVolumeGroups,
|
||||
selectResult: (result) => result.groups,
|
||||
selectID: (group) => group.name
|
||||
})),
|
||||
logicalVolumes: new DataLoader(evaluateAndPick({
|
||||
command: lvm.getLogicalVolumes,
|
||||
selectResult: (result) => result.volumes,
|
||||
selectID: (volume) => volume.path
|
||||
}))
|
||||
};
|
||||
},
|
||||
root: {
|
||||
resources: {
|
||||
lvm: {
|
||||
physicalVolumes: ({ paths }, { physicalVolumes, $make }) => {
|
||||
return mapFromSource(physicalVolumes, paths, (volume) => {
|
||||
return $make("sysquery.lvm.PhysicalVolume", { path: volume.path });
|
||||
});
|
||||
},
|
||||
volumeGroups: ({ names }, { volumeGroups, $make }) => {
|
||||
return mapFromSource(volumeGroups, names, (group) => {
|
||||
return $make("sysquery.lvm.VolumeGroup", { name: group.name });
|
||||
});
|
||||
},
|
||||
logicalVolumes: ({ paths }, { logicalVolumes, $make }) => {
|
||||
// FIXME: Aren't these scoped to a volume group?
|
||||
return mapFromSource(logicalVolumes, paths, (volume) => {
|
||||
return $make("sysquery.lvm.LogicalVolume", { path: volume.path });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
extensions: {
|
||||
"sysquery.core.BlockDevice": {
|
||||
lvmPhysicalVolume: async function (_, { physicalVolumes, $getProperty, $make }) {
|
||||
let volume = physicalVolumes.get(await $getProperty(this, "path"));
|
||||
|
||||
return {
|
||||
sources: () => {
|
||||
return {
|
||||
physicalVolumes: ,
|
||||
volumeGroups: ,
|
||||
logicalVolumes:
|
||||
};
|
||||
},
|
||||
types: types,
|
||||
extensions: {
|
||||
"sysquery.core.BlockDevice": {
|
||||
lvmPhysicalVolume: function (_, { $getProperty, sources }) {
|
||||
|
||||
if (volume != null) {
|
||||
return $make("sysquery.lvm.PhysicalVolume", { path: volume.path });
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
types: {
|
||||
"sysquery.lvm.PhysicalVolume": function PhysicalVolume({ path }) {
|
||||
return dlayerSource.withSources({
|
||||
$sources: {
|
||||
physicalVolumes: {
|
||||
[dlayerSource.ID]: path,
|
||||
path: "path",
|
||||
format: "format",
|
||||
totalSpace: "totalSpace",
|
||||
freeSpace: "freeSpace",
|
||||
isExported: "isExported",
|
||||
isMissing: "isMissing",
|
||||
isAllocatable: "isAllocatable",
|
||||
isDuplicate: "isDuplicate",
|
||||
isUsed: "isUsed",
|
||||
volumeGroup: (volume, { $make }) => {
|
||||
return $make("sysquery.lvm.VolumeGroup", { name: volume.volumeGroup });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
"sysquery.lvm.VolumeGroup": function VolumeGroup({ name }) {
|
||||
return dlayerSource.withSources({
|
||||
physicalVolumes: function (_args, { physicalVolumes, $make }) {
|
||||
return Promise.try(() => {
|
||||
return physicalVolumes.load(All);
|
||||
}).filter((volume) => {
|
||||
return (volume.volumeGroup === name);
|
||||
}).map((volume) => {
|
||||
return $make("sysquery.lvm.PhysicalVolume", { path: volume.path });
|
||||
});
|
||||
},
|
||||
logicalVolumes: function (_args, { logicalVolumes, $make }) {
|
||||
return Promise.try(() => {
|
||||
return logicalVolumes.load(All);
|
||||
}).filter((volume) => {
|
||||
return (volume.volumeGroup === name);
|
||||
}).map((volume) => {
|
||||
return $make("sysquery.lvm.LogicalVolume", { path: volume.path });
|
||||
});
|
||||
},
|
||||
$sources: {
|
||||
volumeGroups: {
|
||||
[dlayerSource.ID]: name,
|
||||
name: "name",
|
||||
totalSpace: "totalSpace",
|
||||
freeSpace: "freeSpace",
|
||||
physicalVolumeCount: "physicalVolumeCount",
|
||||
logicalVolumeCount: "logicalVolumeCount",
|
||||
snapshotCount: "snapshotCount",
|
||||
isReadOnly: "isReadOnly",
|
||||
isResizeable: "isResizeable",
|
||||
isExported: "isExported",
|
||||
isIncomplete: "isIncomplete",
|
||||
allocationPolicy: "allocationPolicy",
|
||||
mode: "mode"
|
||||
}
|
||||
}
|
||||
},
|
||||
root: {
|
||||
resources: {
|
||||
lvm: {
|
||||
physicalVolumes: ({ paths }, { sources }) => {
|
||||
return makeTypeFromSource({
|
||||
source: sources.physicalVolumes,
|
||||
ids: paths,
|
||||
make: (result) => types.PhysicalVolume({ path: result.path }),
|
||||
});
|
||||
},
|
||||
volumeGroups: ({ names }, { sources }) => {
|
||||
return makeTypeFromSource({
|
||||
source: sources.volumeGroups,
|
||||
ids: names,
|
||||
make: (result) => types.VolumeGroup({ name: result.name }),
|
||||
});
|
||||
},
|
||||
logicalVolumes: ({ paths }, { sources }) => {
|
||||
// FIXME: Aren't these scoped to a volume group?
|
||||
return makeTypeFromSource({
|
||||
source: sources.logicalVolumes,
|
||||
ids: paths,
|
||||
make: (result) => types.LogicalVolume({ path: result.path }),
|
||||
});
|
||||
});
|
||||
},
|
||||
"sysquery.lvm.LogicalVolume": function LogicalVolume({ path }) {
|
||||
return dlayerSource.withSources({
|
||||
$sources: {
|
||||
logicalVolumes: {
|
||||
[dlayerSource.ID]: path,
|
||||
path: "path",
|
||||
name: "name",
|
||||
fullName: "fullName",
|
||||
size: "size",
|
||||
uuid: "uuid",
|
||||
deviceMapperPath: "deviceMapperPath",
|
||||
layoutAttributes: "layoutAttributes",
|
||||
roles: "roles",
|
||||
tags: "tags",
|
||||
configurationProfile: "configurationProfile",
|
||||
creationTime: "creationTime",
|
||||
creationHost: "creationHost",
|
||||
neededKernelModules: "neededKernelModules",
|
||||
dataVolume: "dataVolume", // FIXME: Reference?
|
||||
metadataVolume: "metadataVolume", // FIXME: Reference?
|
||||
poolVolume: "poolVolume", // FIXME: Reference?
|
||||
persistentMajorNumber: "persistentMajorNumber",
|
||||
persistentMinorNumber: "persistentMinorNumber",
|
||||
type: "type",
|
||||
isReadOnly: "isReadOnly",
|
||||
isCurrentlyReadOnly: "isCurrentlyReadOnly",
|
||||
isAllocationLocked: "isAllocationLocked",
|
||||
allocationPolicy: "allocationPolicy",
|
||||
status: "status",
|
||||
healthStatus: "healthStatus",
|
||||
isInitiallySynchronized: "isInitiallySynchronized",
|
||||
isCurrentlySynchronized: "isCurrentlySynchronized",
|
||||
isMerging: "isMerging",
|
||||
isConverting: "isConverting",
|
||||
isSuspended: "isSuspended",
|
||||
isActivationSkipped: "isActivationSkipped",
|
||||
isOpened: "isOpened",
|
||||
isActiveLocally: "isActiveLocally",
|
||||
isActiveRemotely: "isActiveRemotely",
|
||||
isActiveExclusively: "isActiveExclusively",
|
||||
isMergeFailed: "isMergeFailed",
|
||||
isSnapshotInvalid: "isSnapshotInvalid",
|
||||
isLiveTablePresent: "isLiveTablePresent",
|
||||
isInactiveTablePresent: "isInactiveTablePresent",
|
||||
isZeroFilled: "isZeroFilled",
|
||||
hasFixedMinorNumber: "hasFixedMinorNumber",
|
||||
outOfSpacePolicy: "outOfSpacePolicy",
|
||||
volumeGroup: (volume, { $make }) => {
|
||||
return $make("sysquery.lvm.VolumeGroup", { name: volume.volumeGroup });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue