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 getHostStatus(self, hostId): try: hosts = sanlock.get_hosts(self._sdUUID, hostId) except sanlock.SanlockException as e: self.log.debug("Unable to get host %d status in lockspace %s: %s", hostId, self._sdUUID, e) return HOST_STATUS_UNAVAILABLE else: status = hosts[0]["flags"] return self.STATUS_NAME[status]
def getHostStatus(self, hostId): try: hosts = sanlock.get_hosts(self._lockspace_name, hostId) except sanlock.SanlockException as e: self.log.debug("Unable to get host %d status in lockspace %s: %s", hostId, self._sdUUID, e) return HOST_STATUS_UNAVAILABLE else: status = hosts[0]['flags'] return self.STATUS_NAME[status]
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 getHostStatus(self, hostId): # Note: get_hosts has off-by-one bug when asking for particular host # id, so get all hosts info and filter. # See https://bugzilla.redhat.com/1111210 try: hosts = sanlock.get_hosts(self._sdUUID) except sanlock.SanlockException as e: self.log.debug("Unable to get host %d status in lockspace %s: %s", hostId, self._sdUUID, e) return HOST_STATUS_UNAVAILABLE for info in hosts: if info['host_id'] == hostId: status = info['flags'] return self.STATUS_NAME[status] # get_hosts with host_id=0 returns only hosts with timestamp != 0, # which means that no host is using this host id now. If there a # timestamp, sanlock will return HOST_UNKNOWN and then HOST_LIVE or # HOST_FAIL. return HOST_STATUS_FREE
def test_get_hosts_parse_args(no_sanlock_daemon, name): with raises_sanlock_errno(): sanlock.get_hosts(name, 1)
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)
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 == []