From d54472ee5dced2a206aaf6bf3c6397e6079f7771 Mon Sep 17 00:00:00 2001 From: Cyril Galibern Date: Mon, 3 May 2021 15:43:50 +0200 Subject: [PATCH 1/3] Update freenas pool driver capabilities with 'rox' and 'rwx' --- opensvc/drivers/pool/freenas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opensvc/drivers/pool/freenas.py b/opensvc/drivers/pool/freenas.py index 3c0c054d77..84e2852018 100644 --- a/opensvc/drivers/pool/freenas.py +++ b/opensvc/drivers/pool/freenas.py @@ -11,7 +11,7 @@ class Pool(BasePool): type = "freenas" - capabilities = ["roo", "rwo", "shared", "blk", "iscsi"] + capabilities = ["roo", "rwo", "rox", "rwx", "shared", "blk", "iscsi"] @lazy def insecure_tpc(self): From f56d3fc7a36384a2e2629194af0f5bb12e4f94c9 Mon Sep 17 00:00:00 2001 From: Cyril Galibern Date: Tue, 4 May 2021 21:29:14 +0200 Subject: [PATCH 2/3] Fix provisioning unresolved reference on defer volume exposed_devs # for example provision where parallel subset is used [pid1] provision need provision volume#1, volume#2, disk#1 launch pid2 subprocess need volume#1 provisioned [pid2] provision resource volume#1 ... unset_lazy res[volume#1].volsvc [pid3] provision resource volume#2 ... unset_lazy res[volume#2].volsvc [pid1] disk#1 with vdev = {volume#1.exposed_devs[0]} may use old version of res[volume#1].volsvc => unable to resolve vdev during zpool create ... vdev provision example will fail on second provisioned node (vol/example provisioned failed) example warn! ha 1/2 | O^ >provisioned X!*P provision failed vol/example up! 1/0 | O !! provision failed vol/example-vdev1 up 2/0 | O O vol/example-vdev2 up 2/0 | O O error because: during disk#1, vdev = self.oget("vdev") <-- is empty Config for bug: cluster.conf [array#freenas] type = freenas api = https://infra-2/api/v1.0 username = root password = system/sec/freenas [pool#freenas1] type = freenas array = freenas diskgroup = osvcdata sparse = true [pool#vpool1] type = virtual template = templates/vol/vpool1 capabilities = roo rwo rox rwx om templates/vol/vpool1 print config [DEFAULT] nodes = * disable = true id = 63752664-f34c-4565-8458-27e069f2ccad [env] size = 2g [subset#volume:s0] parallel = true [volume#1] pool = freenas1 format = false name = {name}-vdev1 size = {env.size} subset = s0 [volume#2] pool = freenas1 format = false name = {name}-vdev2 size = {env.size} subset = s0 [disk#1] create_options = -O acltype=posixacl -O xattr=sa -o listsnapshots=on type = zpool name = {name}.{namespace}.{kind} vdev = mirror {volume#1.exposed_devs[0]} {volume#2.exposed_devs[0]} [sync#i0] disable = True om example print config [DEFAULT] id = cbbf8799-78e0-4b6d-a958-d6005b11850a nodes = * orchestrate = ha topology = flex flex_min_nodes = 2 id = 247c41dc-6e3f-4cb0-bbcd-75ee05b9c4c2 [volume#1] pool = vpool1 name = {name} size = 100m --- opensvc/core/resourceset.py | 3 +++ opensvc/drivers/resource/volume/__init__.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/opensvc/core/resourceset.py b/opensvc/core/resourceset.py index 4a651ee0b5..8a8252f8b6 100644 --- a/opensvc/core/resourceset.py +++ b/opensvc/core/resourceset.py @@ -330,6 +330,9 @@ def action(self, action, **kwargs): # the action_job tells us what to do with it through its exitcode resource.can_rollback = True + if action == "provision" and resource.type == "volume": + # need reset lazy in current process, (subprocess reset lazy has no effect) + resource.post_provision_reset_lazy() if len(err) > 0: raise ex.Error("%s non-optional resources jobs returned " "with error" % ",".join(err)) diff --git a/opensvc/drivers/resource/volume/__init__.py b/opensvc/drivers/resource/volume/__init__.py index 2e1ce26e24..605c8e2bfa 100644 --- a/opensvc/drivers/resource/volume/__init__.py +++ b/opensvc/drivers/resource/volume/__init__.py @@ -655,6 +655,9 @@ def provisioner(self): raise ex.Error("volume provision returned %d" % ret) self.can_rollback = True self.can_rollback_vol_instance = True + self.post_provision_reset_lazy() + + def post_provision_reset_lazy(self): self.unset_lazy("device") self.unset_lazy("mount_point") self.unset_lazy("volsvc") From cc7de66c55c216fec116f006dfbe2c0f02a070ae Mon Sep 17 00:00:00 2001 From: Cyril Galibern Date: Tue, 4 May 2021 23:55:29 +0200 Subject: [PATCH 3/3] [pool freenas] protect delete_disk with lock Now delete_disk and create_disk use same lock name freenas_update_disk --- opensvc/drivers/pool/freenas.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/opensvc/drivers/pool/freenas.py b/opensvc/drivers/pool/freenas.py index 84e2852018..5cc4dc7cf9 100644 --- a/opensvc/drivers/pool/freenas.py +++ b/opensvc/drivers/pool/freenas.py @@ -1,13 +1,12 @@ from __future__ import print_function -import sys - import core.exceptions as ex from utilities.lazy import lazy from drivers.array.freenas import Freenass from core.pool import BasePool -LOCK_NAME = "freenas_create_disk" +LOCK_NAME = "freenas_update_disk" +LOCK_TIMEOUT = 120 class Pool(BasePool): type = "freenas" @@ -30,7 +29,16 @@ def blocksize(self): return self.oget("blocksize") def delete_disk(self, name=None, disk_id=None): - return self.array.del_iscsi_zvol(name=name, volume=self.diskgroup) + lock_id = None + result = {} + try: + lock_id = self.node._daemon_lock(LOCK_NAME, timeout=LOCK_TIMEOUT, on_error="raise") + self.log.info("lock acquired: name=%s id=%s", LOCK_NAME, lock_id) + result = self.array.del_iscsi_zvol(name=name, volume=self.diskgroup) + finally: + self.node._daemon_unlock(LOCK_NAME, lock_id) + self.log.info("lock released: name=%s id=%s", LOCK_NAME, lock_id) + return result def create_disk(self, name, size, nodes=None): mappings = self.get_mappings(nodes) @@ -39,7 +47,7 @@ def create_disk(self, name, size, nodes=None): lock_id = None result = {} try: - lock_id = self.node._daemon_lock(LOCK_NAME, timeout=120, on_error="raise") + lock_id = self.node._daemon_lock(LOCK_NAME, timeout=LOCK_TIMEOUT, on_error="raise") self.log.info("lock acquired: name=%s id=%s", LOCK_NAME, lock_id) result = self.array.add_iscsi_zvol(name=name, size=size, volume=self.diskgroup, @@ -51,7 +59,7 @@ def create_disk(self, name, size, nodes=None): finally: self.node._daemon_unlock(LOCK_NAME, lock_id) self.log.info("lock released: name=%s id=%s", LOCK_NAME, lock_id) - return result + return result def translate(self, name=None, size=None, fmt=True, shared=False): data = []