# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from __future__ import absolute_import
from __future__ import print_function

import logging

import common
from autotest_lib.server.hosts import host_info
from autotest_lib.utils.frozen_chromite.lib import metrics


_METRICS_PREFIX = 'chromeos/autotest/autoserv/host_info/shadowing_store/'
_REFRESH_METRIC_NAME = _METRICS_PREFIX + 'refresh_count'
_COMMIT_METRIC_NAME = _METRICS_PREFIX + 'commit_count'


logger = logging.getLogger(__file__)

class ShadowingStore(host_info.CachingHostInfoStore):
    """A composite CachingHostInfoStore that maintains a main and shadow store.

    ShadowingStore accepts two CachingHostInfoStore objects - primary_store and
    shadow_store. All refresh/commit operations are serviced through
    primary_store.  In addition, shadow_store is updated and compared with this
    information, leaving breadcrumbs when the two differ. Any errors in
    shadow_store operations are logged and ignored so as to not affect the user.

    This is a transitional CachingHostInfoStore that allows us to continue to
    use an AfeStore in practice, but also create a backing FileStore so that we
    can validate the use of FileStore in prod.
    """

    def __init__(self, primary_store, shadow_store,
                 mismatch_callback=None):
        """
        @param primary_store: A CachingHostInfoStore to be used as the primary
                store.
        @param shadow_store: A CachingHostInfoStore to be used to shadow the
                primary store.
        @param mismatch_callback: A callback used to notify whenever we notice a
                mismatch between primary_store and shadow_store. The signature
                of the callback must match:
                    callback(primary_info, shadow_info)
                where primary_info and shadow_info are HostInfo objects obtained
                from the two stores respectively.
                Mostly used by unittests. Actual users don't know / nor care
                that they're using a ShadowingStore.
        """
        super(ShadowingStore, self).__init__()
        self._primary_store = primary_store
        self._shadow_store = shadow_store
        self._mismatch_callback = (
                mismatch_callback if mismatch_callback is not None
                else _log_info_mismatch)
        try:
            self._shadow_store.commit(self._primary_store.get())
        except host_info.StoreError as e:
            metrics.Counter(
                    _METRICS_PREFIX + 'initialization_fail_count').increment()
            logger.exception(
                    'Failed to initialize shadow store. '
                    'Expect primary / shadow desync in the future.')

    def commit_with_substitute(self, info, primary_store=None,
                               shadow_store=None):
        """Commit host information using alternative stores.

        This is used to commit using an alternative store implementation
        to work around some issues (crbug.com/903589).

        Don't set cached_info in this function.

        @param info: A HostInfo object to set.
        @param primary_store: A CachingHostInfoStore object to commit instead of
            the original primary_store.
        @param shadow_store: A CachingHostInfoStore object to commit instead of
            the original shadow store.
        """
        if primary_store is not None:
            primary_store.commit(info)
        else:
            self._commit_to_primary_store(info)

        if shadow_store is not None:
            shadow_store.commit(info)
        else:
            self._commit_to_shadow_store(info)

    def __str__(self):
        return '%s[%s, %s]' % (type(self).__name__, self._primary_store,
                               self._shadow_store)

    def _refresh_impl(self):
        """Obtains HostInfo from the primary and compares against shadow"""
        primary_info = self._refresh_from_primary_store()
        try:
            shadow_info = self._refresh_from_shadow_store()
        except host_info.StoreError:
            logger.exception('Shadow refresh failed. '
                             'Skipping comparison with primary.')
            return primary_info
        self._verify_store_infos(primary_info, shadow_info)
        return primary_info

    def _commit_impl(self, info):
        """Commits HostInfo to both the primary and shadow store"""
        self._commit_to_primary_store(info)
        self._commit_to_shadow_store(info)

    def _commit_to_primary_store(self, info):
        try:
            self._primary_store.commit(info)
        except host_info.StoreError:
            metrics.Counter(_COMMIT_METRIC_NAME).increment(
                    fields={'file_commit_result': 'skipped'})
            raise

    def _commit_to_shadow_store(self, info):
        try:
            self._shadow_store.commit(info)
        except host_info.StoreError:
            logger.exception(
                    'shadow commit failed. '
                    'Expect primary / shadow desync in the future.')
            metrics.Counter(_COMMIT_METRIC_NAME).increment(
                    fields={'file_commit_result': 'fail'})
        else:
            metrics.Counter(_COMMIT_METRIC_NAME).increment(
                    fields={'file_commit_result': 'success'})

    def _refresh_from_primary_store(self):
        try:
            return self._primary_store.get(force_refresh=True)
        except host_info.StoreError:
            metrics.Counter(_REFRESH_METRIC_NAME).increment(
                    fields={'validation_result': 'skipped'})
            raise

    def _refresh_from_shadow_store(self):
        try:
            return self._shadow_store.get(force_refresh=True)
        except host_info.StoreError:
            metrics.Counter(_REFRESH_METRIC_NAME).increment(fields={
                    'validation_result': 'fail_shadow_store_refresh'})
            raise

    def _verify_store_infos(self, primary_info, shadow_info):
        if primary_info == shadow_info:
            metrics.Counter(_REFRESH_METRIC_NAME).increment(
                    fields={'validation_result': 'success'})
        else:
            self._mismatch_callback(primary_info, shadow_info)
            metrics.Counter(_REFRESH_METRIC_NAME).increment(
                    fields={'validation_result': 'fail_mismatch'})
            self._shadow_store.commit(primary_info)


def _log_info_mismatch(primary_info, shadow_info):
    """Log the two HostInfo instances.

    Used as the default mismatch_callback.
    """
    logger.warning('primary / shadow disagree on refresh.')
    logger.warning('primary: %s', primary_info)
    logger.warning('shadow: %s', shadow_info)
