diff --git a/plugins/volume/org.xen.xapi.storage.zfs-vol/sr.py b/plugins/volume/org.xen.xapi.storage.zfs-vol/sr.py index 885fb82..c081245 100755 --- a/plugins/volume/org.xen.xapi.storage.zfs-vol/sr.py +++ b/plugins/volume/org.xen.xapi.storage.zfs-vol/sr.py @@ -25,14 +25,15 @@ def create(self, dbg, sr_uuid, configuration, name, description): log.debug('{}: SR.create: config={}, sr_uuid={}'.format( dbg, configuration, sr_uuid)) - # 2 ways to create a SR: + # 3 ways to create a SR: # - from an existing zpool (manually created for complex configs) # - from a "device" config string (comma-separated list of devices) + # - from a "vdev" config string (vdev specification suitable for `zfs create`) if 'zpool' in configuration: - if 'device' in configuration: - log.error('"zpool" specified, "device" should not be used') - raise Exception('"zpool" specified, "device" should not be used') + if 'device' in configuration or 'vdev' in configuration: + log.error('"zpool" specified, "device" or "vdev" should not be used') + raise Exception('"zpool" specified, "device" or "vdev" should not be used') # FIXME do we reject pools not under MOUNT_ROOT? @@ -40,10 +41,14 @@ def create(self, dbg, sr_uuid, configuration, name, description): pool_name = configuration['zpool'] elif 'device' in configuration: - devs = configuration['device'].split(',') + if 'vdev' in configuration: + log.error('"device" specified, "vdev" should not be used') + raise Exception('"device" specified, "vdev" should not be used') + + vdev_defn = configuration['device'].split(',') pool_name = "sr-{}".format(sr_uuid) - zfsutils.pool_create(dbg, pool_name, devs) + zfsutils.pool_create(dbg, pool_name, vdev_defn) # "device" is only used once to create the zpool, which # then becomes the sole way to designate the SR @@ -51,9 +56,25 @@ def create(self, dbg, sr_uuid, configuration, name, description): del configuration['device'] configuration["zpool"] = pool_name + elif 'vdev' in configuration: + vdev_defn = configuration['vdev'].split(' ') + # check no word attempts to play tricks us passing arbitrary options + for word in vdev_defn: + if not (word[0].isalpha() or word[0] == "/"): + raise Exception('"vdev" contain invalid-looking string %r' % (word,)) + + pool_name = "sr-{}".format(sr_uuid) + zfsutils.pool_create(dbg, pool_name, vdev_defn) + + # "vdev" is only used once to create the zpool, which + # then becomes the sole way to designate the SR + configuration["orig-vdev"] = configuration['vdev'] + del configuration['vdev'] + configuration["zpool"] = pool_name + else: - log.error('devices config must have "zpool" or "device"') - raise Exception('devices config must have "zpool" or "device"') + log.error('devices config must have "zpool", "vdev", or "device"') + raise Exception('devices config must have "zpool", "vdev", or "device"') # FIXME this assumes zpool is mounted/attached mountpoint = zfsutils.pool_mountpoint(dbg, pool_name) diff --git a/plugins/volume/org.xen.xapi.storage.zfs-vol/zfsutils.py b/plugins/volume/org.xen.xapi.storage.zfs-vol/zfsutils.py index 94a6aa5..6dbddc9 100644 --- a/plugins/volume/org.xen.xapi.storage.zfs-vol/zfsutils.py +++ b/plugins/volume/org.xen.xapi.storage.zfs-vol/zfsutils.py @@ -78,10 +78,10 @@ def pool_mountpoint(dbg, pool_name): cmd = "zfs get mountpoint -H -o value".split() + [ pool_name ] return call(dbg, cmd).strip() -def pool_create(dbg, pool_name, devs): +def pool_create(dbg, pool_name, vdev_defn): cmd = ("zpool create".split() + [pool_name] # FIXME '-f' ? + ['-R', MOUNT_ROOT] - + devs) + + vdev_defn) call(dbg, cmd) def pool_destroy(dbg, pool_name):