# Buggy code
def ClusterInfo(self, request, context=None) -> ray_client_pb2.ClusterInfoResponse:
    resp = ray_client_pb2.ClusterInfoResponse()
    resp.type = request.type
    if request.type == ray_client_pb2.ClusterInfoType.CLUSTER_RESOURCES:
        with disable_client_hook():
            resources = ray.cluster_resources()
        # Normalize resources into floats
        # (the function may return values that are ints)
        float_resources = {k: float(v) for k, v in resources.items()}
        resp.resource_table.CopyFrom(
            ray_client_pb2.ClusterInfoResponse.ResourceTable(table=float_resources)
        )
    elif request.type == ray_client_pb2.ClusterInfoType.AVAILABLE_RESOURCES:
        with disable_client_hook():
            resources = ray.available_resources()
        # Normalize resources into floats
        # (the function may return values that are ints)
        float_resources = {k: float(v) for k, v in resources.items()}
        resp.resource_table.CopyFrom(
            ray_client_pb2.ClusterInfoResponse.ResourceTable(table=float_resources)
        )
    else:
        with disable_client_hook():
            resp.json = self._return_debug_cluster_info(request, context)
    return resp


# Traceback (AttributeError)
Traceback (most recent call last):
File "test.py", line 4, in <module>
print(ray.get_runtime_context().node_id.hex())
File "/Users/eoakes/code/ray/python/ray/runtime_context.py", line 58, in node_id
node_id = self.worker.current_node_id
File "/Users/eoakes/code/ray/python/ray/worker.py", line 148, in current_node_id
return self.core_worker.get_current_node_id()
AttributeError: 'Worker' object has no attribute 'core_worker'

# Fixed code
def ClusterInfo(self, request, context=None) -> ray_client_pb2.ClusterInfoResponse:
    resp = ray_client_pb2.ClusterInfoResponse()
    resp.type = request.type
    if request.type == ray_client_pb2.ClusterInfoType.CLUSTER_RESOURCES:
        with disable_client_hook():
            resources = ray.cluster_resources()
        # Normalize resources into floats
        # (the function may return values that are ints)
        float_resources = {k: float(v) for k, v in resources.items()}
        resp.resource_table.CopyFrom(
            ray_client_pb2.ClusterInfoResponse.ResourceTable(table=float_resources)
        )
    elif request.type == ray_client_pb2.ClusterInfoType.AVAILABLE_RESOURCES:
        with disable_client_hook():
            resources = ray.available_resources()
        # Normalize resources into floats
        # (the function may return values that are ints)
        float_resources = {k: float(v) for k, v in resources.items()}
        resp.resource_table.CopyFrom(
            ray_client_pb2.ClusterInfoResponse.ResourceTable(table=float_resources)
        )
    elif request.type == ray_client_pb2.ClusterInfoType.RUNTIME_CONTEXT:
        ctx = ray_client_pb2.ClusterInfoResponse.RuntimeContext()
        with disable_client_hook():
            rtc = ray.get_runtime_context()
            ctx.job_id = rtc.job_id.binary()
            ctx.node_id = rtc.node_id.binary()
            ctx.capture_client_tasks = rtc.should_capture_child_tasks_in_placement_group
        resp.runtime_context.CopyFrom(ctx)
    else:
        with disable_client_hook():
            resp.json = self._return_debug_cluster_info(request, context)
    return resp