summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtkapiper <andy.piper@arcticwolf.com>2023-07-11 18:23:03 +0000
committerLars Wirzenius <liw@liw.fi>2023-07-14 16:03:24 +0000
commitaa1a1a54989865587ebabefacd372245a85ecdce (patch)
tree7b81ed196412b82709553c84c33cdaed73eaa90b
parent33d56f35e39d0d3872d06400456d5f99f7986dc1 (diff)
downloadvmdb2-aa1a1a54989865587ebabefacd372245a85ecdce.tar.gz
lvscan_plugin: support for existing images with logical volumes
The lvscan_plugin is used to detect logical volumes in existing disk images. The volumes are tagged by the plugin, enabling them to be mounted.
-rw-r--r--vmdb/plugins/lvscan.mdwn23
-rw-r--r--vmdb/plugins/lvscan_plugin.py74
2 files changed, 97 insertions, 0 deletions
diff --git a/vmdb/plugins/lvscan.mdwn b/vmdb/plugins/lvscan.mdwn
new file mode 100644
index 0000000..ff4304c
--- /dev/null
+++ b/vmdb/plugins/lvscan.mdwn
@@ -0,0 +1,23 @@
+Step: lvscan
+-----------------------------------------------------------------------------
+
+Scans for existing LVM2 logical volumes (LVs) within a named volume group.
+This is useful when using an existing image as input which has been
+pre-populated with LVM logical volumes, allowing the volumes to be mounted.
+
+Step keys:
+
+* `lvscan` &mdash; REQUIRED; value is the name of the volume group containing
+ the logical volumes.
+
+* `tags` &mdash; REQUIRED; list of tags to apply to the discovered logical
+ volumes. The tags must match names of volumes in the volume group. Volumes
+ in the image which do not need to be mounted can be omitted from the tags
+ list
+
+Example (in the .vmdb file):
+
+ - lvscan: the_volume_group
+ tags:
+ - lv_one
+ - lv_two
diff --git a/vmdb/plugins/lvscan_plugin.py b/vmdb/plugins/lvscan_plugin.py
new file mode 100644
index 0000000..08bf31d
--- /dev/null
+++ b/vmdb/plugins/lvscan_plugin.py
@@ -0,0 +1,74 @@
+# Copyright 2023 Andy Piper
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# =*= License: GPL-3+ =*=
+
+import json
+
+import vmdb
+
+
+class LvscanPlugin(vmdb.Plugin):
+ def enable(self):
+ self.app.step_runners.add(LvscanStepRunner())
+
+
+class LvscanStepRunner(vmdb.StepRunnerInterface):
+ def get_key_spec(self):
+ return {"lvscan": str, "tags": []}
+
+ def run(self, values, settings, state):
+ for v in get_logical_volumes(values):
+ dev = v["lv_path"]
+ tag = v["lv_name"]
+ vmdb.progress(f"remembering {dev} as {tag}")
+ state.tags.append(tag)
+ state.tags.set_dev(tag, dev)
+ vmdb.runcmd(["lvchange", "-a", "y", dev])
+
+ def teardown(self, values, settings, state):
+ vgname = values["lvscan"]
+ vmdb.runcmd(["vgchange", "-an", vgname])
+
+
+def get_logical_volumes(values):
+ vgname = values["lvscan"]
+ tags = values["tags"]
+ vmdb.runcmd(["lvscan"])
+ volumes = json.loads(
+ vmdb.runcmd(
+ [
+ "lvdisplay",
+ "-C",
+ "-o",
+ "lv_name,vg_name,lv_path",
+ "--report-format",
+ "json",
+ ]
+ )
+ )["report"][0]["lv"]
+
+ # ensure all tags have a corresponding volume, but not all volumes need
+ # a matching tag
+ matched_vols = [
+ v for v in volumes if v["lv_name"] in tags and v["vg_name"] == vgname
+ ]
+ if len(matched_vols) < len(tags):
+ matched_tags = [v["lv_name"] for v in matched_vols]
+ unmatched_tags = sorted(set(tags).difference(matched_tags))
+ raise RuntimeError(
+ f'unmatched tags in volume group "{vgname}": {unmatched_tags}'
+ )
+ return matched_vols