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)