Esempio n. 1
0
 def test_with_context(self):
     with ConsulServiceController().start_service() as service:
         consul_client = service.create_consul_client()
         lock_manager = ConsulLockManager(consul_client=consul_client)
         with lock_manager.acquire(KEY_1) as lock_information:
             self.assertEqual(lock_information, lock_manager.find(KEY_1))
         self.assertIsNone(lock_manager.find(KEY_1))
Esempio n. 2
0
def _acquire_lock(lock_manager: ConsulLockManager, configuration: CliLockConfiguration) \
        -> Optional[ConnectedConsulLockInformation]:
    """
    TODO
    :param lock_manager:
    :param configuration:
    :return:
    """
    event_listeners: LockEventListener = {}
    if configuration.on_before_locked_executables is not None:
        event_listeners["on_before_lock"] = _generate_event_listener_caller(
            configuration.on_before_locked_executables)
    if configuration.on_lock_already_locked_executables is not None:
        event_listeners["on_lock_already_locked"] = _generate_event_listener_caller(
            configuration.on_lock_already_locked_executables)

    try:
        return lock_manager.acquire(
            key=configuration.key, blocking=not configuration.non_blocking,
            timeout=configuration.timeout, metadata=configuration.metadata, **event_listeners,
            lock_poll_interval_generator=lambda i: configuration.lock_poll_interval)
    except LockAcquireTimeoutError as e:
        logger.debug(e)
        logger.error(f"Timed out whilst waiting to acquire lock: {configuration.key}")
        print(json.dumps(None))
        exit(LOCK_ACQUIRE_TIMEOUT_EXIT_CODE)
Esempio n. 3
0
 def test_with_context(self):
     with ConsulServiceController().start_service() as service:
         consul_client = service.create_consul_client()
         lock_manager = ConsulLockManager(consul_client=consul_client)
         with lock_manager.acquire(KEY_1) as lock_information:
             self.assertEqual(lock_information, lock_manager.find(KEY_1))
         self.assertIsNone(lock_manager.find(KEY_1))
Esempio n. 4
0
 def test_unlock_all(self):
     test_keys = [f"{KEY_1}_{i}" for i in range(5)]
     with ConsulServiceController().start_service() as service:
         lock_manager = ConsulLockManager(consul_client=service.create_consul_client())
         for key in test_keys:
             lock = lock_manager.acquire(key)
             assert isinstance(lock, ConsulLockInformation)
         unlock_results = lock_manager.release_all(test_keys)
     for unlock_result in unlock_results:
         self.assertTrue(unlock_result)
Esempio n. 5
0
 def test_unlock_all(self):
     test_keys = [f"{KEY_1}_{i}" for i in range(5)]
     with ConsulServiceController().start_service() as service:
         lock_manager = ConsulLockManager(
             consul_client=service.create_consul_client())
         for key in test_keys:
             lock = lock_manager.acquire(key)
             assert isinstance(lock, ConsulLockInformation)
         unlock_results = lock_manager.release_all(test_keys)
     for unlock_result in unlock_results:
         self.assertTrue(unlock_result)
Esempio n. 6
0
 def first_locker(key: str, service: ConsulDockerisedService) -> CaptureResult:
     lock_manager = ConsulLockManager(consul_client=service.create_consul_client())
     lock_information = lock_manager.acquire(KEY_1)
     return CaptureResult(return_value=lock_information)
Esempio n. 7
0
class ConsulChecksumStorage(ChecksumStorage):
    """
    Consul storage for configuration -> checksum mappings.
    """
    CONSUL_HTTP_TOKEN_ENVIRONMENT_VARIABLE = "CONSUL_HTTP_TOKEN"
    CONSUL_SESSION_LOCK_DEFAULT_TIMEOUT = 120
    TEXT_ENCODING = "utf-8"
    _IMPORT_MISSING_ERROR_MESSAGE = "To use Consul storage, please install the requirements in " \
                                    "`consul_requirements.txt`"

    @staticmethod
    def _load_consul_class() -> Type:
        """
        Loads the Consul class at run time (optional requirement).
        :return: the Consul class
        :raises MissingOptionalDependencyError: if a required dependency is not installed
        """
        try:
            from consul import Consul
        except ImportError as e:
            raise MissingOptionalDependencyError(
                ConsulChecksumStorage._IMPORT_MISSING_ERROR_MESSAGE) from e
        return Consul

    @staticmethod
    def _load_consul_lock_manager() -> Type:
        """
        Loads the ConsulLockManager class at run time (optional requirement).
        :return: the Consul class
        :raises MissingOptionalDependencyError: if a required dependency is not installed
        """
        try:
            from consullock.managers import ConsulLockManager
        except ImportError as e:
            raise MissingOptionalDependencyError(
                ConsulChecksumStorage._IMPORT_MISSING_ERROR_MESSAGE) from e
        return ConsulLockManager

    @property
    def url(self) -> str:
        return self._consul_client.http.base_uri

    @property
    def token(self) -> str:
        return self._consul_client.token

    def __init__(self,
                 data_key: str,
                 lock_key: str,
                 url: str = None,
                 token: str = None,
                 consul_client=None,
                 configuration_checksum_mappings: Mapping[str, str] = None):
        Consul = ConsulChecksumStorage._load_consul_class()
        ConsulLockManager = ConsulChecksumStorage._load_consul_lock_manager()

        if url is not None and consul_client is not None:
            raise ValueError("Cannot use both `url` and `consul_client`")

        self.data_key = data_key
        self.lock_key = lock_key

        consul_client_kwargs: Dict = {}
        if url is not None:
            parsed_url = urlparse(url)
            consul_client_kwargs["host"] = parsed_url.hostname
            consul_client_kwargs["port"] = parsed_url.port
            consul_client_kwargs["scheme"] = parsed_url.scheme if len(
                parsed_url.scheme) > 0 else "http"
        self._consul_client = consul_client if consul_client is not None else Consul(
            **consul_client_kwargs)

        if token is None:
            token = os.environ.get(
                ConsulChecksumStorage.CONSUL_HTTP_TOKEN_ENVIRONMENT_VARIABLE,
                None)
        if token is not None:
            # Work around for https://github.com/cablehead/python-consul/issues/170
            self._consul_client.token = token
            self._consul_client.http.session.headers.update(
                {"X-Consul-Token": token})

        self._lock_manager = ConsulLockManager(
            consul_client=self._consul_client,
            session_ttl_in_seconds=ConsulChecksumStorage.
            CONSUL_SESSION_LOCK_DEFAULT_TIMEOUT)

        super().__init__(configuration_checksum_mappings)

    def get_checksum(self, configuration_id: str) -> Optional[str]:
        return self.get_all_checksums().get(configuration_id)

    def get_all_checksums(self) -> Dict[str, str]:
        value = self._consul_client.kv.get(self.data_key)[1]
        if value is None:
            return {}
        value = value["Value"].decode(ConsulChecksumStorage.TEXT_ENCODING)
        return json.loads(value)

    def set_checksum(self, configuration_id: str, checksum: str):
        with self._lock_manager.acquire(self.lock_key):
            value = self.get_all_checksums()
            value[configuration_id] = checksum
            self._consul_client.kv.put(self.data_key,
                                       json.dumps(value, sort_keys=True))

    def set_all_checksums(self, configuration_checksum_mappings: Mapping[str,
                                                                         str]):
        with self._lock_manager.acquire(self.lock_key):
            value = self.get_all_checksums()
            value.update(configuration_checksum_mappings)
            self._consul_client.kv.put(self.data_key,
                                       json.dumps(value, sort_keys=True))
Esempio n. 8
0
 def first_locker(key: str,
                  service: ConsulDockerisedService) -> CaptureResult:
     lock_manager = ConsulLockManager(
         consul_client=service.create_consul_client())
     lock_information = lock_manager.acquire(KEY_1)
     return CaptureResult(return_value=lock_information)