testcontainers-python icon indicating copy to clipboard operation
testcontainers-python copied to clipboard

KeycloakContainer image

Open expploitt opened this issue 3 years ago • 5 comments

Hi! I was trying to change from jboss/keycloak image to quay.io/keycloak/keycloak:latest because the jboss repo is not longer supported. However, I don't know why, I'm getting TimeoutException during port mapping for container.

Here I have the logs:

============================= test session starts ==============================
collecting ... collected 1 item
run-last-failure: rerun previous 1 failure

test_security_controller.py::TestSecurityController::test_auth_token FAILED [100%]Pulling image quay.io/keycloak/keycloak:latest
Container started: 4f0e9d085c71
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...

eees_eas_discovery/test/test_security_controller.py:8 (TestSecurityController.test_auth_token)
self = <eees_eas_discovery.test.test_security_controller.TestSecurityController testMethod=test_auth_token>

    def test_auth_token(self):
        keycloak_container = KeycloakContainer()
    
>       with KeycloakContainer(image='quay.io/keycloak/keycloak:latest') as kc:

test_security_controller.py:12: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../venv/lib/python3.8/site-packages/testcontainers/core/container.py:71: in __enter__
    return self.start()
../../venv/lib/python3.8/site-packages/testcontainers/keycloak.py:61: in start
    self._connect()
../../venv/lib/python3.8/site-packages/testcontainers/core/waiting_utils.py:49: in wrapper
    return wrapped(*args, **kwargs)
../../venv/lib/python3.8/site-packages/testcontainers/keycloak.py:54: in _connect
    url = self.get_url()
../../venv/lib/python3.8/site-packages/testcontainers/keycloak.py:49: in get_url
    port = self.get_exposed_port(self.port_to_expose)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

wrapped = <bound method DockerContainer.get_exposed_port of <testcontainers.keycloak.KeycloakContainer object at 0x7fe0ae54a310>>
instance = <testcontainers.keycloak.KeycloakContainer object at 0x7fe0ae54a310>
args = (8080,), kwargs = {}

    @wrapt.decorator
    def wrapper(wrapped, instance, args, kwargs):
        exception = None
        logger.info("Waiting to be ready...")
        for attempt_no in range(config.MAX_TRIES):
            try:
                return wrapped(*args, **kwargs)
            except transient_exceptions as e:
                logger.debug(f"Connection attempt '{attempt_no + 1}' of '{config.MAX_TRIES + 1}' "
                             f"failed: {traceback.format_exc()}")
                time.sleep(config.SLEEP_TIME)
                exception = e
>       raise TimeoutException(
            f'Wait time ({config.MAX_TRIES * config.SLEEP_TIME}s) exceeded for {wrapped.__name__}'
            f'(args: {args}, kwargs {kwargs}). Exception: {exception}'
        )
E       testcontainers.core.exceptions.TimeoutException: Wait time (120s) exceeded for get_exposed_port(args: (8080,), kwargs {}). Exception: port mapping for container 4f0e9d085c712ddc2edd35cd34c9e88cf93e30c7555a46a7569f61d3ae4ae3b6 and port 8080 is not available

../../venv/lib/python3.8/site-packages/testcontainers/core/waiting_utils.py:55: TimeoutException

This is my tests:

 def test_auth_token(self):

        with KeycloakContainer(image='quay.io/keycloak/keycloak:latest') as kc:
            keycloak = kc.get_client()

...

expploitt avatar Dec 28 '22 17:12 expploitt

Do you have the full code for the test handy? It looks like there is a kc and also a keycloak_container variable in the traceback (see below).

def test_auth_token(self):
        keycloak_container = KeycloakContainer()  # Here.
    
>       with KeycloakContainer(image='quay.io/keycloak/keycloak:latest') as kc:  # Here.

tillahoffmann avatar Jan 04 '23 23:01 tillahoffmann

Hi, yeah, I did't realize that I had two KeycloakContainer objects. I tried again with only kc but the output it's the same.

    def test_auth_token(self):

        with KeycloakContainer(image='quay.io/keycloak/keycloak:latest') as kc:

            keycloak = kc.get_client()

            realm = json.load(open('./realm.json'))
            keycloak.import_realm(realm)

            token = keycloak.get_token()

            validation = function_to_test(token)

            self.assertNotEqual(validation, None)

Output:


Pulling image quay.io/keycloak/keycloak:latest
Container started: 15fab070147c
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...


 def test_auth_token(self):
    
>       with KeycloakContainer(image='quay.io/keycloak/keycloak:latest') as kc:

test_security_controller.py:14: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../venv/lib/python3.8/site-packages/testcontainers/core/container.py:71: in __enter__
    return self.start()
../../venv/lib/python3.8/site-packages/testcontainers/keycloak.py:61: in start
    self._connect()
../../venv/lib/python3.8/site-packages/testcontainers/core/waiting_utils.py:49: in wrapper
    return wrapped(*args, **kwargs)
../../venv/lib/python3.8/site-packages/testcontainers/keycloak.py:54: in _connect
    url = self.get_url()
../../venv/lib/python3.8/site-packages/testcontainers/keycloak.py:49: in get_url
    port = self.get_exposed_port(self.port_to_expose)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

wrapped = <bound method DockerContainer.get_exposed_port of <testcontainers.keycloak.KeycloakContainer object at 0x7ff18f50b820>>
instance = <testcontainers.keycloak.KeycloakContainer object at 0x7ff18f50b820>
args = (8082,), kwargs = {}

    @wrapt.decorator
    def wrapper(wrapped, instance, args, kwargs):
        exception = None
        logger.info("Waiting to be ready...")
        for attempt_no in range(config.MAX_TRIES):
            try:
                return wrapped(*args, **kwargs)
            except transient_exceptions as e:
                logger.debug(f"Connection attempt '{attempt_no + 1}' of '{config.MAX_TRIES + 1}' "
                             f"failed: {traceback.format_exc()}")
                time.sleep(config.SLEEP_TIME)
                exception = e
>       raise TimeoutException(
            f'Wait time ({config.MAX_TRIES * config.SLEEP_TIME}s) exceeded for {wrapped.__name__}'
            f'(args: {args}, kwargs {kwargs}). Exception: {exception}'
        )
E       testcontainers.core.exceptions.TimeoutException: Wait time (120s) exceeded for get_exposed_port(args: (8082,), kwargs {}). Exception: port mapping for container 15fab070147c6a01d5f44b18791aecf3e040929e867898283501562b48d182cc and port 8082 is not available

../../venv/lib/python3.8/site-packages/testcontainers/core/waiting_utils.py:55: TimeoutException

expploitt avatar Jan 05 '23 08:01 expploitt

Would you be up for sending a PR with the failing test? Then we can ensure any changes we introduce address the problem you've encountered?

tillahoffmann avatar Jan 06 '23 19:01 tillahoffmann

Hi! Just wanted to add my 2 cents here since I'm looking at the library as an interesting alternative to sidecars in the pipeline as we need integration testing to test an update in the infrastructure.

I haven't tested yet but I have a hunch this is happening because since versions 17 (which I believe is the latest in jboss repo) the /auth endpoint which is used for health checking either no longer exists or lost it's purpose as a health check.

Instead, by lookin at here, we can see how to enable the new health check endpoint and how to access it. Hope I was helpful :P

TheForgottened avatar Jul 03 '23 13:07 TheForgottened

Hi! Just wanted to add my 2 cents here since I'm looking at the library as an interesting alternative to sidecars in the pipeline as we need integration testing to test an update in the infrastructure.

I haven't tested yet but I have a hunch this is happening because since versions 17 (which I believe is the latest in jboss repo) the /auth endpoint which is used for health checking either no longer exists or lost it's purpose as a health check.

Instead, by lookin at here, we can see how to enable the new health check endpoint and how to access it. Hope I was helpful :P

I can confirm this. Using a bitnami/keycloak version 20 image the following error is thrown: testcontainers.core.exceptions.TimeoutException: Wait time (120s) exceeded for _connect(args: (), kwargs {}). Exception: ('Connection aborted.', RemoteDisconnected('... whereas using a jboss version my same test will pass.

owainrutherford avatar Jul 03 '23 16:07 owainrutherford

This issue is already solved by #480. The solution was to update the health probes to the new versions of Keyclock that is presented in Quay.io repository. I believe this issues can be closed @tillahoffmann

matheusvnm avatar Mar 27 '24 01:03 matheusvnm

Thank you for the update @matheusvnm. Closing this one as #480 seems to have done the trick.

santi avatar Mar 30 '24 16:03 santi