def test_read_resource_owners_path_length(no_sanlock_daemon): path = "x" * constants.SANLK_PATH_LEN with pytest.raises(ValueError): sanlock.read_resource_owners(b"ls_name", b"res_name", [(path, 0)]) path = "x" * (constants.SANLK_PATH_LEN - 1) with raises_sanlock_errno(): sanlock.read_resource_owners(b"ls_name", b"res_name", [(path, 0)])
def test_read_resource_owners_parse_args(no_sanlock_daemon, name, filename, encoding): path = util.generate_path("/tmp/", filename, encoding) disks = [(path, 0)] with raises_sanlock_errno(): sanlock.read_resource_owners(name, b"res_name", disks) with raises_sanlock_errno(): sanlock.read_resource_owners(b"ls_name", name, disks)
def test_read_resource_owners_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_owners( b"ls_name", b"res_name", disks, sector=SECTOR_SIZE_512) assert e.value.errno == errno.EINVAL
def test_read_resource_owners_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_owners( "ls_name", "res_name", disks, 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( 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_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 main(): signal.signal(signal.SIGTERM, sigTermHandler) print "Creating the sanlock disk" fd, disk = tempfile.mkstemp() os.close(fd) os.chown(disk, pwd.getpwnam("sanlock").pw_uid, grp.getgrnam("sanlock").gr_gid) offset = sanlock.get_alignment(disk) SNLK_DISKS = [(disk, offset)] print "Registering to sanlock" fd = sanlock.register() print "Initializing '%s'" % (LOCKSPACE_NAME, ) sanlock.write_lockspace(LOCKSPACE_NAME, disk) print "Initializing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.write_resource(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS) print "Acquiring the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME) sanlock.add_lockspace(LOCKSPACE_NAME, HOST_ID, disk) try: print "Acquiring '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.acquire(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd, version=0) while True: print "Trying to get lockspace '%s' hosts" % LOCKSPACE_NAME try: hosts_list = sanlock.get_hosts(LOCKSPACE_NAME) except sanlock.SanlockException as e: if e.errno != os.errno.EAGAIN: raise else: print "Lockspace '%s' hosts: " % LOCKSPACE_NAME, hosts_list break time.sleep(5) print "Resource '%s' owners: " % RESOURCE_NAME, \ sanlock.read_resource_owners( LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS) print "Releasing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.release(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd) except Exception as e: print "Exception: ", e finally: print "Releasing the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME) sanlock.rem_lockspace(LOCKSPACE_NAME, HOST_ID, disk) print "Removing the sanlock disk" os.remove(disk)
def test_read_resource_owners_invalid_align_size(tmpdir, sanlock_daemon): path = str(tmpdir.join("path")) util.create_file(path, GiB) disks = [(path, 0)] sanlock.write_resource(b"ls_name", b"res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) with pytest.raises(sanlock.SanlockException) as e: sanlock.read_resource_owners(b"ls_name", b"res_name", disks, align=ALIGNMENT_2M, sector=SECTOR_SIZE_512) assert e.value.errno == errno.EINVAL
def test_read_resource_owners_invalid_align_size(tmpdir, sanlock_daemon): path = str(tmpdir.join("path")) util.create_file(path, GiB) disks = [(path, 0)] sanlock.write_resource( "ls_name", "res_name", disks, align=ALIGNMENT_1M, sector=SECTOR_SIZE_512) with pytest.raises(sanlock.SanlockException) as e: sanlock.read_resource_owners( "ls_name", "res_name", disks, align=ALIGNMENT_2M, sector=SECTOR_SIZE_512) assert e.value.errno == errno.EINVAL
def main(): signal.signal(signal.SIGTERM, sigTermHandler) print "Creating the sanlock disk" fd, disk = tempfile.mkstemp() os.close(fd) os.chown(disk, pwd.getpwnam("sanlock").pw_uid, grp.getgrnam("sanlock").gr_gid) offset = sanlock.get_alignment(disk) SNLK_DISKS = [(disk, offset)] print "Registering to sanlock" fd = sanlock.register() print "Initializing '%s'" % (LOCKSPACE_NAME,) sanlock.write_lockspace(LOCKSPACE_NAME, disk, max_hosts=0, iotimeout=0, align=1048576, sector=512) print "Initializing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.write_resource(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, align=1048576, sector=512) print "Acquiring the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME) sanlock.add_lockspace(LOCKSPACE_NAME, HOST_ID, disk) try: print "Acquiring '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.acquire(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd, version=0) while True: print "Trying to get lockspace '%s' hosts" % LOCKSPACE_NAME try: hosts_list = sanlock.get_hosts(LOCKSPACE_NAME) except sanlock.SanlockException as e: if e.errno != os.errno.EAGAIN: raise else: print "Lockspace '%s' hosts: " % LOCKSPACE_NAME, hosts_list break time.sleep(5) print "Resource '%s' owners: " % RESOURCE_NAME, \ sanlock.read_resource_owners( LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, align=1048576, sector=512) print "Releasing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.release(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd) except Exception as e: print "Exception: ", e finally: print "Releasing the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME) sanlock.rem_lockspace(LOCKSPACE_NAME, HOST_ID, disk) print "Removing the sanlock disk" os.remove(disk)
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): 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_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_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 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 == []
def test_read_resource_owners_parse_args(no_sanlock_daemon, name): with raises_sanlock_errno(): sanlock.read_resource_owners(name, "res_name", [("disk_path",0)]) with raises_sanlock_errno(): sanlock.read_resource_owners("ls_name", name, [("disk_path",0)])
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 == []
SANLOCK_PATH = '/var/lib/libvirt/sanlock/' SANLOCK_PATH = os.path.abspath(SANLOCK_PATH + RESOURCE_NAME) offset = sanlock.get_alignment(SANLOCK_PATH) SNLK_DISKS = [(SANLOCK_PATH, offset)] def sanlock_acquire(hostId, lockspacePath, leasePath): sfd = sanlock.register() if not sanlock.inq_lockspace(LOCKSPACE_NAME, hostId, lockspacePath): msg = "Try to acquire host id %s:%s:%s:0" % (LOCKSPACE_NAME, hostId, lockspacePath) print(msg) sanlock.add_lockspace(LOCKSPACE_NAME, hostId, lockspacePath) msg = "Try to acquire leader lease:%s" % str(leasePath) print(msg) sanlock.acquire(LOCKSPACE_NAME, RESOURCE_NAME, [(leasePath, 0)], sfd) if __name__ == "__main__": host_id = int(sys.argv[1]) lockspace_path = sys.argv[2] lease_path = sys.argv[3] hosts_list = sanlock.get_hosts(LOCKSPACE_NAME) msg = 'sanlock hosts:%s' % str(hosts_list) print msg sanlock_acquire(host_id, lockspace_path, lease_path) time.sleep(180) resource_owners = sanlock.read_resource_owners(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS) print 'resource_owners:%s' % str(resource_owners)