def test_timestamps_available(self, mock_rel_get):
     mock_rel_get.return_value = {}
     self.assertFalse(swift_utils.timestamps_available('proxy/1'))
     mock_rel_get.return_value = {'broker-timestamp': '1234'}
     self.assertFalse(swift_utils.timestamps_available('proxy/1'))
     mock_rel_get.return_value = {'broker-timestamp': '1234'}
     self.assertTrue(swift_utils.timestamps_available('proxy/2'))
 def test_timestamps_available(self, mock_rel_get):
     mock_rel_get.return_value = {}
     self.assertFalse(swift_utils.timestamps_available('proxy/1'))
     mock_rel_get.return_value = {'broker-timestamp': '1234'}
     self.assertFalse(swift_utils.timestamps_available('proxy/1'))
     mock_rel_get.return_value = {'broker-timestamp': '1234'}
     self.assertTrue(swift_utils.timestamps_available('proxy/2'))
def cluster_non_leader_actions():
    """Cluster relation hook actions to be performed by non-leader units.

    NOTE: must be called by non-leader from cluster relation hook.
    """
    log("Cluster changed by unit={} (local is non-leader)".format(
        remote_unit()),
        level=DEBUG)
    rx_settings = relation_get() or {}
    tx_settings = relation_get(unit=local_unit()) or {}

    token = rx_settings.get(SwiftProxyClusterRPC.KEY_NOTIFY_LEADER_CHANGED)
    if token:
        log(
            "Leader-changed notification received from peer unit. Since "
            "this most likely occurred during a ring sync proxies will "
            "be disabled until the leader is restored and a fresh sync "
            "request is set out",
            level=WARNING)
        service_stop("swift-proxy")
        return

    rx_rq_token = rx_settings.get(SwiftProxyClusterRPC.KEY_STOP_PROXY_SVC)

    # Check whether we have been requested to stop proxy service
    if rx_rq_token:
        log("Peer request to stop proxy service received ({}) - sending ack".
            format(rx_rq_token),
            level=INFO)
        service_stop('swift-proxy')
        peers_only = rx_settings.get('peers-only', None)
        rq = SwiftProxyClusterRPC().stop_proxy_ack(echo_token=rx_rq_token,
                                                   echo_peers_only=peers_only)
        relation_set(relation_settings=rq)
        return

    # Check if there are any builder files we can sync from the leader.
    broker = rx_settings.get('builder-broker', None)
    broker_token = rx_settings.get('broker-token', None)
    broker_timestamp = rx_settings.get('broker-timestamp', None)
    tx_ack_token = tx_settings.get(SwiftProxyClusterRPC.KEY_STOP_PROXY_SVC_ACK)
    if not broker:
        log("No ring/builder update available", level=DEBUG)
        if not openstack.is_unit_paused_set():
            service_start('swift-proxy')

        return
    elif broker_token:
        if tx_ack_token:
            if broker_token == tx_ack_token:
                log("Broker and ACK tokens match ({})".format(broker_token),
                    level=DEBUG)
            else:
                log("Received ring/builder update notification but tokens do "
                    "not match (broker-token={}/ack-token={})".format(
                        broker_token, tx_ack_token),
                    level=WARNING)
                return
        else:
            log(
                "Broker token available without handshake, assuming we just "
                "joined and rings won't change",
                level=DEBUG)
    else:
        log("Not taking any sync actions", level=DEBUG)
        return

    # If we upgrade from cluster that did not use timestamps, the new peer will
    # need to request a re-sync from the leader
    if not is_most_recent_timestamp(broker_timestamp):
        if not timestamps_available(excluded_unit=remote_unit()):
            log("Requesting resync")
            rq = SwiftProxyClusterRPC().request_resync(broker_token)
            relation_set(relation_settings=rq)
        else:
            log(
                "Did not receive most recent broker timestamp but timestamps "
                "are available - waiting for next timestamp",
                level=INFO)

        return

    log("Ring/builder update available", level=DEBUG)
    builders_only = int(rx_settings.get('sync-only-builders', 0))
    path = os.path.basename(get_www_dir())
    try:
        sync_proxy_rings('http://{}/{}'.format(broker, path),
                         rings=not builders_only)
    except CalledProcessError:
        log(
            "Ring builder sync failed, builders not yet available - "
            "leader not ready?",
            level=WARNING)
        return

    # Re-enable the proxy once all builders and rings are synced
    if fully_synced():
        log("Ring builders synced - starting proxy", level=INFO)
        CONFIGS.write_all()
        if not openstack.is_unit_paused_set():
            service_start('swift-proxy')
    else:
        log(
            "Not all builders and rings synced yet - waiting for peer sync "
            "before starting proxy",
            level=INFO)