From 0768c332d1d2932098c5a49977d8f516bbd5d4f0 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Mon, 25 Mar 2024 17:25:45 +0100 Subject: [PATCH] zfs-ng: implement volume-create 2/2: Volume.create Note that if Volume.set were not implemented yet (or indeed cannot complete and returns an error), we face xapi-project/xen-api#5530: if the Volume.set call fails (to add the vdi-type=user custom-key record), then the VDI object is not created (though, as this happens after Volume.create, the zvol and DB entries were indeed created and there suppression was not requested by SMAPI after the error). But since all the VDI information that count are here, "xe sr-scan" will bring those VDI to life (after implementation of SR.ls). Originally-by: Matias Ezequiel Vara Larsen Signed-off-by: Yann Dirson --- .../org.xen.xapi.storage.zfs-ng/plugin.py | 1 + .../org.xen.xapi.storage.zfs-ng/volume.py | 39 ++++++++++++++++++- .../org.xen.xapi.storage.zfs-ng/zfs-ng.py | 3 ++ .../org.xen.xapi.storage.zfs-ng/zfsutils.py | 11 ++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/plugins/volume/org.xen.xapi.storage.zfs-ng/plugin.py b/plugins/volume/org.xen.xapi.storage.zfs-ng/plugin.py index f20707e..deb04a8 100755 --- a/plugins/volume/org.xen.xapi.storage.zfs-ng/plugin.py +++ b/plugins/volume/org.xen.xapi.storage.zfs-ng/plugin.py @@ -20,6 +20,7 @@ def query(self, dbg): "version": "3.0", "required_api_version": "5.0", "features": [ + "VDI_CREATE", ], "configuration": {}, "required_cluster_stack": []} diff --git a/plugins/volume/org.xen.xapi.storage.zfs-ng/volume.py b/plugins/volume/org.xen.xapi.storage.zfs-ng/volume.py index 08e3b58..48e8b00 100755 --- a/plugins/volume/org.xen.xapi.storage.zfs-ng/volume.py +++ b/plugins/volume/org.xen.xapi.storage.zfs-ng/volume.py @@ -16,10 +16,45 @@ from xapi.storage.libs.libcow.volume_implementation import Implementation as \ DefaultImplementation +import zfsutils + @util.decorate_all_routines(util.log_exceptions_in_function) class Implementation(DefaultImplementation): "Volume driver to provide volumes from zvol's" + def create(self, dbg, sr, name, description, size, sharable): + meta = util.get_sr_metadata(dbg, 'file://' + sr) + pool_name = meta["zpool"] + + with VolumeContext(self.callbacks, sr, 'w') as opq: + # FIXME how should we choose image format? + image_type = ImageFormat.IMAGE_RAW + image_format = ImageFormat.get_format(image_type) + vdi_uuid = str(uuid.uuid4()) + + with PollLock(opq, 'gl', self.callbacks, 0.5): + with self.callbacks.db_context(opq) as db: + volume = db.insert_new_volume(size, image_type) + db.insert_vdi( + name, description, vdi_uuid, volume.id, sharable) + path = zfsutils.zvol_path(pool_name, volume.id) + zfsutils.vol_create(dbg, path, size) + + vdi_uri = self.callbacks.getVolumeUriPrefix(opq) + vdi_uuid + + return { + 'key': vdi_uuid, # FIXME check this + 'uuid': vdi_uuid, + 'name': name, + 'description': description, + 'read_write': True, + 'virtual_size': size, + 'physical_utilisation': size, # FIXME - incidently psize gets null in the db + 'uri': [image_format.uri_prefix + vdi_uri], + 'sharable': False, + 'keys': {} + } + def call_volume_command(): """Parse the arguments and call the required command""" log.log_call_argv() @@ -27,7 +62,9 @@ def call_volume_command(): cmd = xapi.storage.api.v5.volume.Volume_commandline( Implementation(fsp.Callbacks())) base = os.path.basename(sys.argv[0]) - if base == "Volume.set": + if base == "Volume.create": + cmd.create() + elif base == "Volume.set": cmd.set() elif base == "Volume.unset": cmd.unset() diff --git a/plugins/volume/org.xen.xapi.storage.zfs-ng/zfs-ng.py b/plugins/volume/org.xen.xapi.storage.zfs-ng/zfs-ng.py index ca379fd..fcfe685 100755 --- a/plugins/volume/org.xen.xapi.storage.zfs-ng/zfs-ng.py +++ b/plugins/volume/org.xen.xapi.storage.zfs-ng/zfs-ng.py @@ -3,3 +3,6 @@ class Callbacks(xapi.storage.libs.libcow.callbacks.Callbacks): "ZFS-ng callbacks" + + def getVolumeUriPrefix(self, opq): + return "zfs-ng/" + opq + "|" diff --git a/plugins/volume/org.xen.xapi.storage.zfs-ng/zfsutils.py b/plugins/volume/org.xen.xapi.storage.zfs-ng/zfsutils.py index 2ddda98..3109370 100644 --- a/plugins/volume/org.xen.xapi.storage.zfs-ng/zfsutils.py +++ b/plugins/volume/org.xen.xapi.storage.zfs-ng/zfsutils.py @@ -4,6 +4,11 @@ MOUNT_ROOT = '/var/run/sr-mount' +def zvol_path(pool_name, vol_id): + return "{}/{}".format(pool_name, vol_id) + +### + def pool_mountpoint(dbg, pool_name): cmd = "zfs get mountpoint -H -o value".split() + [ pool_name ] return call(dbg, cmd).strip() @@ -27,3 +32,9 @@ def pool_get_free_space(dbg, sr_path): # size is returned in bytes cmd = "zpool get -Hp -o value free".split() + [ sr_path ] return int(call(dbg, cmd)) + +def vol_create(dbg, zvol_path, size_mib): + cmd = ("zfs create".split() + [zvol_path] + + ['-V', str(size_mib)] + ) + call(dbg, cmd)