orlangure / gnomock

Test your code without writing mocks with ephemeral Docker containers 📦 Setup popular services with just a couple lines of code ⏱️ No bash, no yaml, only code 💻
MIT License
1.39k stars 66 forks source link

Bug: Container creation stuck when creating mongo with entrypoint #1088

Open zahidcakici opened 4 weeks ago

zahidcakici commented 4 weeks ago

Describe the bug I am trying to create a gnomock container with mongo preset with replica set using WithEntrypoint() method. When I debug the code it creates container as expected however it gets stuck on code-side.

To Reproduce

c, err := gnomock.Start(mongoGnomock.Preset(
        mongoGnomock.WithVersion("7"),
    ),
        gnomock.WithUseLocalImagesFirst(),
        gnomock.WithDebugMode(),
        gnomock.WithContainerName("test-mongo"),
        gnomock.WithEntrypoint("mongod", "--replSet", "myReplSet", "--bind_ip_all"),
    )

Expected behavior I expect it to create the container and continue.

System (please complete the following information):

Additional context Is there a more effective method using Gnomock to make a replica set other then creating it like this and then running a replicaset init command? Please feel free to recommend one.

orlangure commented 3 weeks ago

Hi @zahidcakici,

I suggest using gnomock.WithLogWriter(os.Stdout) when starting the container to look into internal container logs, maybe you'll see a hint there. Additionally, it would help to know which stage of container setup is stuck. You can also figure this out from the logs.

In addition to debugging hints, I don't think setting up a replica set that way is something gnomock is built to do. Replica set means a number of containers speaking one to another, but gnomock starts individual containers and assigns host ip to every one of them randomly. To have a replica set, you would need to create containers serially one after the other, and provide the address of the previous one to the next one, using host ip. This sounds like a networking hell to me.

zahidcakici commented 2 weeks ago

I get this error constantly:

{"t":{"$date":"2024-10-09T14:15:38.004+00:00"},"s":"W",  "c":"QUERY",    "id":23799,   "ctx":"ftdc","msg":"Aggregate command executor error","attr":{"error":{"code":26,"codeName":"NamespaceNotFound","errmsg":"Unable to retrieve storageStats in $collStats stage :: caused by :: Collection [local.oplog.rs] not found."},"stats":{},"cmd":{"aggregate":"oplog.rs","cursor":{},"pipeline":[{"$collStats":{"storageStats":{"waitForLock":false,"numericOnly":true}}}],"$db":"local"}}}

Yeah I don't want to deal with that networking hell neither however I want to use transactions and mongodb supports transaction only in replica sets or clusters unfortunately. So replicaset with just one db instance is sufficient to me. I can do that on my local with some configurations and wanted to do it also for tests.

  mongo1:
    image: mongo:7
    hostname: mongo1
    container_name: mongo1
    restart: always
    volumes:
      - ./mongo/mongo1-volume:/data/db
    ports:
      - 27018:27017
    entrypoint: [ "mongod", "--replSet", "myReplicaSet", "--bind_ip", "localhost,mongo1" ]
    environment:
      MONGO_INITDB_DATABASE: myDB
    networks:
        - myNetwork

  mongo-setup:
    image: mongo:7
    depends_on:
      - mongo1
    volumes:
      - ../scripts/mongo-cluster:/scripts
    restart: "no"
    entrypoint: [ "bash", "/scripts/mongo_setup.sh" ]
    networks:
      - myNetwork

The first container is set up by --replSet entrypoint and the second one is just for initializing the replicaSet. I wanted to do what mongo_setup.shscript does, in code side (Connecting db and initialize replSet like rs.initiate())

I can connect db container and run some commands but container should be initialized with --replSetcommand. When I add that code stuck with the output I shared earlier.

orlangure commented 4 days ago

I see that you already are using a custom entrypoint, so the only other thing that I think can cause this, is invalid mongo client setup, which should be created with SetReplicaSet option.

Even if you use a proper client internally in your code, Gnomock creates its own client to perform healthcheck and mark the container as ready to use. I suggest you try overwriting the default preset healthcheck function using WithHealthCheck, starting with some sleep operations just to make sure your code works, and Gnomock doesn't, and then writing an actual healthcheck function that connects to the cluster as a replica set.

If while debugging you discover a need to run extra operations on the container before it is marked as ready, we can discuss adding the missing features, such as command execution and all that, but I hope this won't be needed.