def test_write_resource( tmpdir, sanlock_daemon, filename, encoding, size, offset): path = util.generate_path(tmpdir, filename, encoding) util.create_file(path, size) disks = [(path, offset)] # Test read and write with default alignment and sector size values. sanlock.write_resource(b"ls_name", b"res_name", disks) res = sanlock.read_resource(path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } # Test read and write with explicit alignment and sector size values. sanlock.write_resource( b"ls_name", b"res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) res = sanlock.read_resource( path, offset=offset, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } owners = sanlock.read_resource_owners(b"ls_name", b"res_name", disks) assert owners == [] magic = util.read_magic(path, offset) assert magic == constants.PAXOS_DISK_MAGIC util.check_guard(path, size)
def test_read_resource_path_length(no_sanlock_daemon): path = "x" * constants.SANLK_PATH_LEN with pytest.raises(ValueError): sanlock.read_resource(path) path = "x" * (constants.SANLK_PATH_LEN - 1) with raises_sanlock_errno(): sanlock.read_resource(path)
def test_read_resource_4k_invalid_sector_size(sanlock_daemon, user_4k_path): disks = [(user_4k_path, 0)] sanlock.write_resource(b"ls_name", b"res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_4K) with pytest.raises(sanlock.SanlockException) as e: sanlock.read_resource(user_4k_path, sector=SECTOR_SIZE_512) assert e.value.errno == errno.EINVAL
def test_read_resource_4k_invalid_sector_size(sanlock_daemon, user_4k_path): disks = [(user_4k_path, 0)] sanlock.write_resource( "ls_name", "res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_4K) with pytest.raises(sanlock.SanlockException) as e: sanlock.read_resource(user_4k_path, sector=SECTOR_SIZE_512) assert e.value.errno == errno.EINVAL
def test_write_resource_4k(sanlock_daemon, user_4k_path, align): disks = [(user_4k_path, 0)] # Poison resource area, ensuring that previous tests will not break this # test, and sanlock does not write beyond the lockspace area. with io.open(user_4k_path, "rb+") as f: f.write(align * b"x") util.write_guard(user_4k_path, align) sanlock.write_resource( b"ls_name", b"res_name", disks, align=align, sector=SECTOR_SIZE_4K) res = sanlock.read_resource( user_4k_path, align=align, sector=SECTOR_SIZE_4K) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } owners = sanlock.read_resource_owners( b"ls_name", b"res_name", disks, align=align, sector=SECTOR_SIZE_4K) assert owners == [] # Verify that resource was written. magic = util.read_magic(user_4k_path) assert magic == constants.PAXOS_DISK_MAGIC # Check that sanlock did not write beyond the lockspace area. util.check_guard(user_4k_path, align)
def test_write_resource_4k(sanlock_daemon, user_4k_path, align): disks = [(user_4k_path, 0)] # Poison resource area, ensuring that previous tests will not break this # test, and sanlock does not write beyond the lockspace area. with io.open(user_4k_path, "rb+") as f: f.write(align * b"x") util.write_guard(user_4k_path, align) sanlock.write_resource( "ls_name", "res_name", disks, align=align, sector=SECTOR_SIZE_4K) res = sanlock.read_resource( user_4k_path, align=align, sector=SECTOR_SIZE_4K) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } owners = sanlock.read_resource_owners( "ls_name", "res_name", disks, align=align, sector=SECTOR_SIZE_4K) assert owners == [] # Verify that resource was written. with io.open(user_4k_path, "rb") as f: magic, = struct.unpack("< I", f.read(4)) assert magic == constants.PAXOS_DISK_MAGIC # Check that sanlock did not write beyond the lockspace area. util.check_guard(user_4k_path, align)
def _read_resource(path, offset, alignment=sc.ALIGNMENT_1M, block_size=sc.BLOCK_SIZE_512): """ Helper for reading sanlock resoruces, supporting both non-existing and deleted resources. Returns: ResourceInfo Raises: NoSuchResource if there is no resource at this offset """ try: res = sanlock.read_resource(path, offset, align=alignment, sector=block_size) except sanlock.SanlockException as e: if e.errno != SANLK_LEADER_MAGIC: raise raise NoSuchResource(path, offset) if res["resource"] == b"": # lease deleted with a version of sanlock not supporting # resource clearning. raise NoSuchResource(path, offset) return ResourceInfo(res["lockspace"].decode("utf-8"), res["resource"].decode("utf-8"), res["version"])
def test_write_resource(tmpdir, sanlock_daemon, size, offset): path = str(tmpdir.join("resources")) util.create_file(path, size) disks = [(path, offset)] # test read and write with default alignment and sector size values sanlock.write_resource("ls_name", "res_name", disks) res = sanlock.read_resource(path, offset=offset) assert res == { "lockspace": "ls_name", "resource": "res_name", "version": 0 } # test read and write with explicit alignment and sector size values sanlock.write_resource("ls_name", "res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) res = sanlock.read_resource(path, offset=offset, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) assert res == { "lockspace": "ls_name", "resource": "res_name", "version": 0 } owners = sanlock.read_resource_owners("ls_name", "res_name", disks) assert owners == [] with io.open(path, "rb") as f: f.seek(offset) magic, = struct.unpack("< I", f.read(4)) assert magic == constants.PAXOS_DISK_MAGIC # TODO: check more stuff here... util.check_guard(path, size)
def test_clear_resource(tmpdir, sanlock_daemon): path = util.generate_path(tmpdir, "clear_test") util.create_file(path, MiB) disks = [(path, 0)] sanlock.write_resource(b"ls_name", b"res_name", disks) sanlock.write_resource(b"ls_name", b"res_name", disks, clear=True) with pytest.raises(sanlock.SanlockException) as e: sanlock.read_resource(path) assert e.value.errno == constants.SANLK_LEADER_MAGIC magic = util.read_magic(path) assert magic == constants.PAXOS_DISK_CLEAR util.check_guard(path, MiB) # run clear on already cleared resource sanlock.write_resource(b"ls_name", b"res_name", disks, clear=True) magic = util.read_magic(path) assert magic == constants.PAXOS_DISK_CLEAR
def test_write_resource(tmpdir, sanlock_daemon, filename, encoding, size, offset): path = util.generate_path(tmpdir, filename, encoding) util.create_file(path, size) disks = [(path, offset)] # Test read and write with default alignment and sector size values. sanlock.write_resource("ls_name", "res_name", disks) res = sanlock.read_resource(path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } # Test read and write with explicit alignment and sector size values. sanlock.write_resource( "ls_name", "res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) res = sanlock.read_resource( path, offset=offset, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } owners = sanlock.read_resource_owners("ls_name", "res_name", disks) assert owners == [] with io.open(path, "rb") as f: f.seek(offset) magic, = struct.unpack("< I", f.read(4)) assert magic == constants.PAXOS_DISK_MAGIC # TODO: check more stuff here... util.check_guard(path, size)
def inquire(self): resource = sanlock.read_resource(self._leasesPath, SDM_LEASE_OFFSET) owners = sanlock.read_resource_owners(self._sdUUID, SDM_LEASE_NAME, self.getLockDisk()) if len(owners) == 1: return resource.get("version"), owners[0].get("host_id") elif len(owners) > 1: self.log.error("Cluster lock is reported to have more than " "one owner: %s", owners) raise RuntimeError("Cluster lock multiple owners error") return None, None
def inquire(self, lease): resource = sanlock.read_resource(lease.path, lease.offset) owners = sanlock.read_resource_owners(self._sdUUID, lease.name, [(lease.path, lease.offset)]) if len(owners) == 1: return resource.get("version"), owners[0].get("host_id") elif len(owners) > 1: self.log.error("Cluster lock is reported to have more than " "one owner: %s", owners) raise RuntimeError("Multiple owners for %s" % (lease,)) return None, None
def inquire(self): resource = sanlock.read_resource(self._leasesPath, SDM_LEASE_OFFSET) owners = sanlock.read_resource_owners(self._sdUUID, SDM_LEASE_NAME, self.getLockDisk()) if len(owners) == 1: return resource.get("version"), owners[0].get("host_id") elif len(owners) > 1: self.log.error( "Cluster lock is reported to have more than " "one owner: %s", owners) raise RuntimeError("Cluster lock multiple owners error") return None, None
def inquire(self, lease): resource = sanlock.read_resource(lease.path, lease.offset) if resource["resource"] != lease.name: raise InvalidLeaseName(resource["resource"], lease) owners = sanlock.read_resource_owners(self._sdUUID, lease.name, [(lease.path, lease.offset)]) if len(owners) == 1: return resource.get("version"), owners[0].get("host_id") elif len(owners) > 1: self.log.error("Cluster lock is reported to have more than " "one owner: %s", owners) raise RuntimeError("Multiple owners for %s" % (lease,)) return None, None
def test_read_resource_parse_args(no_sanlock_daemon, filename, encoding): path = util.generate_path("/tmp/", filename, encoding) with raises_sanlock_errno(): sanlock.read_resource(path)
def test_acquire_release_resource(tmpdir, sanlock_daemon, size, offset): ls_path = str(tmpdir.join("ls_name")) util.create_file(ls_path, size) res_path = str(tmpdir.join("res_name")) util.create_file(res_path, size) sanlock.write_lockspace(b"ls_name", ls_path, offset=offset, iotimeout=1) sanlock.add_lockspace(b"ls_name", 1, ls_path, offset=offset, iotimeout=1) # Host status is not available until the first renewal. with pytest.raises(sanlock.SanlockException) as e: sanlock.get_hosts(b"ls_name", 1) assert e.value.errno == errno.EAGAIN time.sleep(1) host = sanlock.get_hosts(b"ls_name", 1)[0] assert host["flags"] == sanlock.HOST_LIVE disks = [(res_path, offset)] sanlock.write_resource(b"ls_name", b"res_name", disks) res = sanlock.read_resource(res_path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } owners = sanlock.read_resource_owners(b"ls_name", b"res_name", disks) assert owners == [] fd = sanlock.register() sanlock.acquire(b"ls_name", b"res_name", disks, slkfd=fd) res = sanlock.read_resource(res_path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 1 } owner = sanlock.read_resource_owners(b"ls_name", b"res_name", disks)[0] assert owner["host_id"] == 1 assert owner["flags"] == 0 assert owner["generation"] == 1 assert owner["io_timeout"] == 0 # Why 0? # TODO: check timestamp. host = sanlock.get_hosts(b"ls_name", 1)[0] assert host["flags"] == sanlock.HOST_LIVE assert host["generation"] == owner["generation"] sanlock.release(b"ls_name", b"res_name", disks, slkfd=fd) res = sanlock.read_resource(res_path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 1 } owners = sanlock.read_resource_owners(b"ls_name", b"res_name", disks) assert owners == []
def inspect(self, lease): resource = sanlock.read_resource( lease.path, lease.offset, align=self._alignment, sector=self._block_size) resource_name = lease.name.encode("utf-8") if resource["resource"] != resource_name: raise InvalidLeaseName(resource["resource"], lease) owners = sanlock.read_resource_owners( self._lockspace_name, resource_name, [(lease.path, lease.offset)], align=self._alignment, sector=self._block_size) if len(owners) > 1: self.log.error("Cluster lock is reported to have more than " "one owner: %s", owners) raise RuntimeError("Multiple owners for %s" % (lease,)) elif not owners: return None, None resource_owner = owners[0] resource_version = resource["version"] host_id = resource_owner["host_id"] try: host = sanlock.get_hosts(self._lockspace_name, host_id)[0] except sanlock.SanlockException as e: if e.errno == errno.ENOENT: # add_lockspace has not been completed yet, # the inquiry has to be retried. raise TemporaryFailure("inspect", lease, str(e)) elif e.errno == errno.EAGAIN: # The host status is not available yet. # Normally, we'd raise it to the caller, but this # breaks the "Remove DC" flow in engine, so we assume # the lease is currently held by the host # See: https://bugzilla.redhat.com/1613838 self.log.debug("host %s status in not available yet, " "it may hold the lease %s", host_id, lease) return resource_version, host_id else: raise host_status = self.STATUS_NAME[host["flags"]] if resource_owner["generation"] != host["generation"]: # The lease is considered free by sanlock because # the host reconnected to the storage but it no # longer has the lease self.log.debug("host %r generation %r does not match resource " "generation %r, lease %s is free", host_id, host, resource_owner["generation"], lease) return resource_version, None if host_status in (HOST_STATUS_DEAD, HOST_STATUS_FREE): # These are the only states that mean the host cannot hold # this lease. Any other state means the host either holding the # lease or could be holding the lease. self.log.debug("host %s cannot hold %s is effectively free", host, lease) return resource_version, None return resource_version, host_id
def test_acquire_release_resource(tmpdir, sanlock_daemon, size, offset): ls_path = str(tmpdir.join("ls_name")) util.create_file(ls_path, size) res_path = str(tmpdir.join("res_name")) util.create_file(res_path, size) sanlock.write_lockspace("ls_name", ls_path, offset=offset, iotimeout=1) sanlock.add_lockspace("ls_name", 1, ls_path, offset=offset, iotimeout=1) # Host status is not available until the first renewal. with pytest.raises(sanlock.SanlockException) as e: sanlock.get_hosts("ls_name", 1) assert e.value.errno == errno.EAGAIN time.sleep(1) host = sanlock.get_hosts("ls_name", 1)[0] assert host["flags"] == sanlock.HOST_LIVE disks = [(res_path, offset)] sanlock.write_resource("ls_name", "res_name", disks) res = sanlock.read_resource(res_path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 0 } owners = sanlock.read_resource_owners("ls_name", "res_name", disks) assert owners == [] fd = sanlock.register() sanlock.acquire("ls_name", "res_name", disks, slkfd=fd) res = sanlock.read_resource(res_path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 1 } owner = sanlock.read_resource_owners("ls_name", "res_name", disks)[0] assert owner["host_id"] == 1 assert owner["flags"] == 0 assert owner["generation"] == 1 assert owner["io_timeout"] == 0 # Why 0? # TODO: check timestamp. host = sanlock.get_hosts("ls_name", 1)[0] assert host["flags"] == sanlock.HOST_LIVE assert host["generation"] == owner["generation"] sanlock.release("ls_name", "res_name", disks, slkfd=fd) res = sanlock.read_resource(res_path, offset=offset) assert res == { "lockspace": b"ls_name", "resource": b"res_name", "version": 1 } owners = sanlock.read_resource_owners("ls_name", "res_name", disks) assert owners == []