def cluster_as_json(cluster: 'Cluster') -> Dict[str, Any]:
    """Get a JSON representation of *cluster*.

    :param cluster: the :class:`~patroni.dcs.Cluster` object to be parsed as JSON.

    :returns: JSON representation of *cluster*.

    These are the possible keys in the returning object depending on the available information in *cluster*:

        * ``members``: list of members in the cluster. Each value is a :class:`dict` that may have the following keys:

            * ``name``: the name of the host (unique in the cluster). The ``members`` list is sorted by this key;
            * ``role``: ``leader``, ``standby_leader``, ``sync_standby``, ``quorum_standby``, or ``replica``;
            * ``state``: one of :class:`~patroni.postgresql.misc.PostgresqlState`;
            * ``api_url``: REST API URL based on ``restapi->connect_address`` configuration;
            * ``host``: PostgreSQL host based on ``postgresql->connect_address``;
            * ``port``: PostgreSQL port based on ``postgresql->connect_address``;
            * ``timeline``: PostgreSQL current timeline;
            * ``pending_restart``: ``True`` if PostgreSQL is pending to be restarted;
            * ``scheduled_restart``: scheduled restart timestamp, if any;
            * ``tags``: any tags that were set for this member;
            * ``lsn``: current WAL position. See :meth:`Postgresql._wal_position`
            * ``receive_lsn``: receive LSN (``pg_catalog.pg_last_(xlog|wal)_receive_(location|lsn)()``),
                if applicable;
            * ``replay_lsn``: replay LSN (``pg_catalog.pg_last_(xlog|wal)_replay_(location|lsn)()``),
                if applicable;
            * ``lag``: replication lag for ``lsn``, if applicable;
            * ``receive_lag``: lag of the receive LSN;
            * ``replay_lag``: lag of the replay LSN;

        * ``pause``: ``True`` if cluster is in maintenance mode;
        * ``scheduled_switchover``: if a switchover has been scheduled, then it contains this entry with these keys:

            * ``at``: timestamp when switchover was scheduled to occur;
            * ``from``: name of the member to be demoted;
            * ``to``: name of the member to be promoted.
    """
    from . import global_config
    from .postgresql.misc import format_lsn

    config = global_config.from_cluster(cluster)
    leader_name = cluster.leader.name if cluster.leader else None
    cluster_lsn = cluster.status.last_lsn

    ret: Dict[str, Any] = {'members': []}
    sync_role = 'quorum_standby' if config.is_quorum_commit_mode else 'sync_standby'
    for m in cluster.members:
        if m.name == leader_name:
            role = 'standby_leader' if config.is_standby_cluster else 'leader'
        elif config.is_synchronous_mode and cluster.sync.matches(m.name):
            role = sync_role
        else:
            role = 'replica'

        state = (m.data.get('replication_state', '') if role != 'leader' else '') or m.data.get('state', '')
        member = {'name': m.name, 'role': role, 'state': state, 'api_url': m.api_url}
        conn_kwargs = m.conn_kwargs()
        if conn_kwargs.get('host'):
            member['host'] = conn_kwargs['host']
            if conn_kwargs.get('port'):
                member['port'] = int(conn_kwargs['port'])
        optional_attributes = ('timeline', 'pending_restart', 'pending_restart_reason', 'scheduled_restart', 'tags')
        member.update({n: m.data[n] for n in optional_attributes if n in m.data})

        if m.name != leader_name:
            for location in ('receive_', 'replay_', ''):
                lsn_type, lag_type = f'{location}lsn', f'{location}lag'

                lsn = getattr(m, lsn_type)
                if not lsn:
                    member[lsn_type] = member[lag_type] = 'unknown'
                elif cluster_lsn >= lsn:
                    member[lag_type] = cluster_lsn - lsn
                    member[lsn_type] = format_lsn(lsn)
                else:
                    member[lag_type] = 0
                    member[lsn_type] = format_lsn(lsn)

        ret['members'].append(member)

    # sort members by name for consistency
    cmp: Callable[[Dict[str, Any]], bool] = lambda m: m['name']
    ret['members'].sort(key=cmp)
    if config.is_paused:
        ret['pause'] = True
    if cluster.failover and cluster.failover.scheduled_at:
        ret['scheduled_switchover'] = {'at': cluster.failover.scheduled_at.isoformat()}
        if cluster.failover.leader:
            ret['scheduled_switchover']['from'] = cluster.failover.leader
        if cluster.failover.candidate:
            ret['scheduled_switchover']['to'] = cluster.failover.candidate
    return ret
Get a JSON representation of *cluster*.

    :param cluster: the :class:`~patroni.dcs.Cluster` object to be parsed as JSON.

    :returns: JSON representation of *cluster*.

    These are the possible keys in the returning object depending on the available information in *cluster*:

        * ``members``: list of members in the cluster. Each value is a :class:`dict` that may have the following keys:

            * ``name``: the name of the host (unique in the cluster). The ``members`` list is sorted by this key;
            * ``role``: ``leader``, ``standby_leader``, ``sync_standby``, ``quorum_standby``, or ``replica``;
            * ``state``: one of :class:`~patroni.postgresql.misc.PostgresqlState`;
            * ``api_url``: REST API URL based on ``restapi->connect_address`` configuration;
            * ``host``: PostgreSQL host based on ``postgresql->connect_address``;
            * ``port``: PostgreSQL port based on ``postgresql->connect_address``;
            * ``timeline``: PostgreSQL current timeline;
            * ``pending_restart``: ``True`` if PostgreSQL is pending to be restarted;
            * ``scheduled_restart``: scheduled restart timestamp, if any;
            * ``tags``: any tags that were set for this member;
            * ``lsn``: current WAL position. See :meth:`Postgresql._wal_position`
            * ``receive_lsn``: receive LSN (``pg_catalog.pg_last_(xlog|wal)_receive_(location|lsn)()``),
                if applicable;
            * ``replay_lsn``: replay LSN (``pg_catalog.pg_last_(xlog|wal)_replay_(location|lsn)()``),
                if applicable;
            * ``lag``: replication lag for ``lsn``, if applicable;
            * ``receive_lag``: lag of the receive LSN;
            * ``replay_lag``: lag of the replay LSN;

        * ``pause``: ``True`` if cluster is in maintenance mode;
        * ``scheduled_switchover``: if a switchover has been scheduled, then it contains this entry with these keys:

            * ``at``: timestamp when switchover was scheduled to occur;
            * ``from``: name of the member to be demoted;
            * ``to``: name of the member to be promoted.
    
patroni/utils.py