From e83b5f931a5eee548fcd4a7ba337ce5d47d9b711 Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Wed, 17 Jun 2026 19:15:41 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20add=20sentinel=20support=20to?= =?UTF-8?q?=20redis=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem** `redis.ts` reads direct-connect env vars (`HOST`, `PORT`, `PASSWORD`, `DB`, `TLS`) but not the sentinel ones. The `RedisConfig` DTO already declares the sentinel fields (`sentinels`, `name`, `sentinelPassword`) — they just had no env-var source. **Proposal** Read `Redis_SENTINELS`, `Redis_NAME`, `Redis_SENTINEL_PASSWORD`. When `Redis_SENTINELS` is non-empty, populate the sentinel fields and leave `host`/`port` undefined; otherwise keep the direct-connect fields. Document the new env vars. --- back/_doc/env-vars.md | 3 +++ back/apps/core-fca-low/src/config/redis.ts | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/back/_doc/env-vars.md b/back/_doc/env-vars.md index b70bed464e..84835fb2fc 100644 --- a/back/_doc/env-vars.md +++ b/back/_doc/env-vars.md @@ -59,8 +59,11 @@ | Redis_DB | number | | Redis_ENABLE_TLS_FOR_SENTINEL_MODE | boolean | | Redis_HOST | string | +| Redis_NAME | string | | Redis_PASSWORD | string | | Redis_PORT | number | +| Redis_SENTINELS | stringArray | +| Redis_SENTINEL_PASSWORD | string | | Session_COOKIE_SECRETS | json | | Session_USERINFO_CRYPT_KEY | string | diff --git a/back/apps/core-fca-low/src/config/redis.ts b/back/apps/core-fca-low/src/config/redis.ts index b0d6ff9b72..8a335b56d0 100644 --- a/back/apps/core-fca-low/src/config/redis.ts +++ b/back/apps/core-fca-low/src/config/redis.ts @@ -6,12 +6,22 @@ const env = new ConfigParser(process.env, "Redis"); const ca = env.file("CACERT", true); const tlsSettings = ca ? { ca } : undefined; +const sentinels = env.stringArray("SENTINELS").map((entry) => { + const [host, port] = entry.split(":"); + return { host, port: parseInt(port, 10) }; +}); + +const useSentinels = sentinels.length > 0; + export default { - host: env.string("HOST"), - port: env.number("PORT"), + host: useSentinels ? undefined : env.string("HOST"), + port: useSentinels ? undefined : env.number("PORT"), password: env.string("PASSWORD"), db: env.number("DB"), - tls: tlsSettings, + sentinels: useSentinels ? sentinels : undefined, + name: useSentinels ? env.string("NAME") : undefined, + sentinelPassword: env.string("SENTINEL_PASSWORD", true), sentinelTLS: tlsSettings, + tls: tlsSettings, enableTLSForSentinelMode: env.boolean("ENABLE_TLS_FOR_SENTINEL_MODE"), } as RedisConfig; From 8dfb66fd1397e18a04d65b6ad5e2f33e548862d5 Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Wed, 17 Jun 2026 19:16:00 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20add=20redis-sentinel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem** Local dev has only a plain `redis-pwd` (port 6379). Production runs a 1+1+3 sentinel cluster for HA, but there is no way to exercise the ioredis sentinel code path locally. **Proposal** `dks switch redis-sentinel` — local replica of the production HA topology so the ioredis [sentinel code path][ioredis-sentinel] can be exercised without deploying to k8s. [Redis Sentinel][redis-sentinel] is Redis's built-in HA mechanism. Sentinels are independent processes that monitor a master/replica pair and coordinate a failover — promoting the replica to master — when the master becomes unreachable. A quorum (the minimum number of sentinels that must agree the master is down before acting) prevents false failovers from transient network issues. At least 3 sentinels are required so quorum (N/2+1 = 2) can still be reached if one sentinel is lost. See [understanding sentinels][sentinel-tutorial]. - `redis-sentinel-master` / `redis-sentinel-replica` — [replication][redis-replication] pair; the replica is the standby that sentinels can promote on failover. - `redis-sentinel-1/2/3` — three sentinel processes monitoring `mymaster`, quorum 2; mirrors the 1+1+3 topology running in production. - `redis-sentinel` stack — aggregator that starts the full cluster in one command; waits for all nodes to be healthy before the stack is considered up. - `core-sentinel` — `core` variant whose env points at the sentinel cluster (`Redis_SENTINELS`, `Redis_NAME`) instead of the standalone `redis-pwd`; keeps `hostname: core` so nginx routes transparently without a new vhost. [ioredis-sentinel]: https://github.com/redis/ioredis#sentinel [redis-sentinel]: https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/ [sentinel-tutorial]: https://redis.io/tutorials/operate/redis-at-scale/high-availability/understanding-sentinels/ [redis-replication]: https://redis.io/docs/latest/operate/oss_and_stack/management/replication/ --- docker/compose/fca-low/.env/core-sentinel.env | 93 ++++++++++++++ docker/compose/fca-low/core.yml | 15 +++ docker/compose/fca-low/stack.yml | 12 ++ docker/compose/shared/.env/redis.env | 1 + docker/compose/shared/shared.yml | 114 ++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 docker/compose/fca-low/.env/core-sentinel.env diff --git a/docker/compose/fca-low/.env/core-sentinel.env b/docker/compose/fca-low/.env/core-sentinel.env new file mode 100644 index 0000000000..e3dc7cef99 --- /dev/null +++ b/docker/compose/fca-low/.env/core-sentinel.env @@ -0,0 +1,93 @@ +DEFAULT_MODE=dev +NESTJS_INSTANCE=core-fca-low +REQUEST_TIMEOUT=6000 +HEALTHCHECK_LIVE=https://localhost:3000/api/v2/livez +# Session configuration +SESSION_SECRET=fAh8Seik4_ahcH-3ahth/eiG@huéfuuva=opa +SESSION_NAME=fc_session +SESSION_TTL=600000 # 10 minutes + +# Maintenance notice +App_FEATURE_DISPLAY_MAINTENANCE_NOTICE=false +App_MAINTENANCE_DATETIME=mercredi 14 avril, à partir de 22h +App_MAINTENANCE_DURATION=une heure + +# OidcProvider +FQDN=core-fca-low.docker.dev-franceconnect.fr +OidcProvider_PREFIX=/api/v2 +App_PROTOCOL=https +App_HTTPS_SERVER_CERT=/etc/ssl/docker_host/app.crt +App_HTTPS_SERVER_KEY=/etc/ssl/docker_host/app.key +App_ASSETS_PATHS=["../../../apps/core-fca-low/src"] +App_VIEWS_PATHS=["../../../apps/core-fca-low/src"] +App_DSFR_ASSETS_PATHS=[{"assetPath":"../../../node_modules/@gouvfr/dsfr/dist/dsfr","prefix":"/dsfr"},{"assetPath":"../../../node_modules/@gouvfr/dsfr/dist/fonts","prefix":"/fonts"},{"assetPath":"../../../node_modules/@gouvfr/dsfr/dist/icons","prefix":"/icons"}, {"assetPath":"../../../node_modules/@gouvfr/dsfr/dist/utility/icons","prefix":"/utility"}] +App_ASSETS_CACHE_TTL=3600 +App_DEFAULT_IDP_UID=71144ab3-ee1a-4401-b7b3-79b44f7daeeb +App_SP_AUTHORIZED_FQDNS_CONFIGS=[{"spId": "6495f347513b860e6b931fae4a1ba70c8489a558a0fc74ecdc094d48a4035e77", "spName":"FSA3-LOW","spContact":"serviceclient@fsa3-low.fr","authorizedFqdns":["fia1.fr","fia2.fr"]}] +App_DEFAULT_EMAIL_RENATER=test@renater.agentconnect.gouv.fr +App_FEATURE_DISPLAY_TEST_ENV_WARNING= + +## Beware, the "kid" of "CRYPTO_SIG_ES256_PRIV_KEYS" and "CRYPTO_SIG_HSM_PUB_KEYS" must be the same ! +OidcProvider_CRYPTO_SIG_ES256_PRIV_KEYS=[{"alg": "ES256", "crv":"P-256","x":"uRxO96Oqn0BEJZYua3rkM9ntzLbt_nDbq4hwSgOUomQ","y":"o9BoK63TMCGmXjOcCZbtOTmw5HdGiy5ZzY4Qo5KG638","d":"sMJDu7_nEjB0SwTKuKR8XiZPHvoUkem3rdgxP39kkfQ","kty":"EC","kid":"pkcs11:ES256:hsm","use":"sig"}] +OidcProvider_CRYPTO_SIG_RS256_PRIV_KEYS=[{"alg": "RS256", "kty": "RSA","n": "vmTVr5evEFVha25McCxJ8D_MV_52eA6j_0VUFE-bBUWjctqXK-Xf6W1lC2e_51RmL2owzl2w4Fw90cqeBzA1S2PJJdI_ptQcnwaCiXGRUMVqLXKxOsx1zqIj69F781_Ujp7bPYMkGNlsNmsY37roOzZLCFZLIJo6o90mrjT42nTkS-lgabyBMRZu783d_W1hs0CcjcOC4Hq2jEo_DVfy1RF5qj-Cr33LJ22Co6rkWb8zZnS9PFDZBJPz1tp53Gd2V6_BGbgETFMQI9-kss9HQCaH_1VXOFNr-zg7jw-XTHxvaQHEpCkhGrusirQB1o0tf2SheVhHXDUkG2q4aVgBqxurw4YONxBQvYY0xPK-OX1jQaWnaYPmB_v7_bt9wUrL4kYqGiVw5pXZZRIOPYloNhK_p7qLTTNjS4BKgveen_Vq32HZF8sLECQorAL7nSJABd0ReZEOBUyxWZ6KbIwnhykdADV2mBKyrFP0ZDKDQQprstb0V34hYaxuYDZx5obYo0rsPl1659u5KD-s5IAYEuTitdJNT3uWLHgGqLPsd17GHMggQhSuvFIyTH1-mMG3PWF19Oqq0zuZMLw29XDjSDyNRxWauoFzaCzGvWbV2cXsBOob4iik92PPWVJw5BAy6PlK3GxB0ZlSq_Wxp3p0I33BHFxbU8LmbWnAdB-iClk","e": "AQAB","d": "Indul5MGBhbuw9v7ynK6D9v8yhEusR01YwjR57thfNrWc_xOUYwTtNYw7JejjeUheoPmwfUECBmqt0fOw85eV3-A8m_VRgYwCDnNd8QvYkfaqM-Sdep9iSKhDhemMLCwcgEf_0q2RilWBaPtpNLZJ570hlXY09YXt4JZdj_wrNtsWLGu2nVdjd1Zx9-kyDP8885GiQNTtf-A_HSUZX3-X8QCGmfU6KAFHuYcODS_kd-jFnEbsMeSAdom0kZKuTOhoM4YTueZH5gJ2_SohBYx99MB258_Ytr3OUs8vPE9moMMSB4h0vX_IC_JVHKxwn1cNyuob6cjg_W6y5vONoPQCTF7p8_S6BpTzHfxHVIIebaGd2KBqWO_WirUFZNOFa85DoQmhEw-tpKp7Ra1ckZAeBTrV2r5YwIN4YdVqfjJiuKH151-GVrbMssQeNtvCzH-QuoV5nV92D6jSjGSVUndxCcHBbLMZHr-27JW9bSVJ3LmJGR0vU5-yGZH1ViqiLNsjxBwfxD4N5Ga5MRT2e8hlyyrat3SZ8ZZ-IkoW8c4RwnUr9onk3sXCZhQOq9XESWt7HF6iJODRiDYe-AZVc4AVLAF5DPRmFKf8f3J6Rhfnyrue2qBS00DyhFyZGNbw_UaMk5tz1WYpFfcXHanZdB7LP0NnzWjGIgS-qVRaDXxNeE","p": "8gp6yLQ07LqGllcDW2uDgkfYPUO9VCZRv2Zi4gSuJfXQHCcdE9qxMMhybzERUAItcDTY78AgrT8s02B8vWVyFX7bcHrycLFoqc_jCkrIRdY1UDjdZxc-5Js-FCNVG_189yjRuvCXl43JuO2chao2m8ae7efnLA8Ka4axtI98luqcWVL5hZSeeEz6jKOo0Hk2pfgIqJABaJGhkTifhCITrH63IkwYRg4ShVTBkBFQ7IwJG2viK809LnryPtH-WPTeeaYovbo86STZwWOLPBW7KsYqcT_tRebW42PQtqNG8hmAjgLLGUMZVT1Ymdflnf7vX8UjrmYj5vpjnhM9EM0C_w","q": "yV_VAdMEyb0UrUkv1E58sQxEGaaQ982RE11-YT-R6EXOjl6kR-XmTcBWkjzI4trvfQJXi8TUlahxxGiHYgYA56GRjR-CNBot_R_oTff7VWQDHwpQTyhd33cakpdHKgNqPiQ9zYKQom4bBwf8xENKIQQ1V9khtRGsl7q4rmx7lr4oJvLe9tCGSPVGvxs5NHbZLRSiQtQkoOBQ1S2QA68nD2o7CO0-oxJ-UDEzPoWcJJhtxRysE7aJtMPcQTWKApD3Tfs5aH8KtaWhoSlkLatqKOwPcjKpJAOKjUVCDedZbjx2j4ekJyY1aCV1eRz73XjiHcFcNnPuigXffx39wtjqpw","dp": "G9MUlmoRA33V5waNvj632YxE0ZYt97SIBUbR60W6d2awy-u7LgMgB4mjjiDH6ri1XIbWwYkGuKPglVQsQuGcodf5hg68PDRI4eyiHxbFuzGK43QGD8neUw19r3b4W8ViTk-E_MaXxrZoEDhQnBUbPgExWAwmySvZeM79MtKj8f16h9JAGRkitpWy3-QYjg7BN4cyB562ar0DI9ysidYZCOVwTCMPT05i1q0Nq3AyK19V1K8sSvjHJcbAfnRJlxRfVwDBAj6crfish8zXvsqIv7wUOPyuXDDTV0SsQ7K1fzNrUegETR0nlmL9AoKNRQJ_pjTVi0D2s6DpPszbYkkPJQ","dq": "gLiFTBk7Ikl_AhWaQTe6dOHGVi8m03_PkHVe54LfHX4hvte4Y00Nnf2oWOoJ7xjLpTjuBSXYTaHStx2qDHqR8X5Rr8fITs29P-Q5dj1hpv-7DwhktXS0LLfRgIq6rpxoOTipWMhw86M2G5R7emkY5WnvPyxIY5ncnVB55OTrSzxaJitxYouAivpeMqKQOn0N7ccWwWkh0MQSZ3IscG5xpWTeP6KHO24C1_fbLcfyO2JEKI9fX2p7M9VO4U_73BAWRP6lf6pVii9J1d7Dbn336hia9wBzJdYtpofy5ThQ7iowDydBQtUlpmDranOge71drG-BJj2M6SU_692b7AUEWQ","qi": "0-TUiGRoPBWatRlzSQIvwXs5zpGn20QfgmcGQD1LWnogWG-6QwfFsRWJ78FLEK69x35hBdcyzDNC5PzvBPXatr9_bL_Fv10qwMTkFwPOuDZHEzvb3-b_L3MD4JnQ6LbT8g36scv6aEgMNt9eeugRq0bR4xba1oj2pgjfVVKiENQWPlVYZ0HKYHAwdoss4d9x0dI1g-Gl426LreDz5RmDUgzdZ3nAfdnTrLUM69RTmAUjb_GfFWvmlBesFo-npv8qNToZRWmxEClXJZQCoxnzHx29bFe6WY5Jlt3zWCmI3o6LHQx6UiMrN-B_qE4T3plK0bS_w0x-Lbp9bhPbPE9AVA"}] +OidcClient_CRYPTO_ENC_LOCALE_PRIV_KEYS=[{"e":"AQAB","n":"5OHMkVCg2xG2osiXbClpkW8YVxVeqPeQDrDZH1tiocf3S9kK1ErRP1oI1qwP3-MTZVp3O0NjO7eIkkqdogCl043vVty25KMk-lM-dAXfQFjSKBE5c2Y_mZbsvEyk885ZmEbb--S-lxZuBX1jWs574fOSsqKH5e5Mf_PjKgwZFOW0SFl6pGOp230Em5OfTbCN8AKMkw907b9DXoPocDcr3d3ZEa10f5OCI0aieTxvH5Jaq9ZMOQIj1-tTMpDecFYLO8REiQSsUp-4PLUbIBL2Iq-qwv6opkVetpiLR-wwz7e2Y_dDHCqnVHcCo_oWVFFRgKiL_dhmxFIpSkw4dc1ICQ","d":"vZepC6o9RJo8rkT44XjAYN8ky2YBPnerVe_6OrZJUnfBCowkI0xCXnbnIWPv1mZT973jTCz680mJkJzMTJi6xC4rVsmHmoblp5HzBsqibrvkgZoa-9Nz1XcmbKgUb3y7zJ7NtK97jM3gnx2JgnvONJG-L8jgR3-I0OimgHr6_8nh8Qv66at8fighlefmIp-2UVYPydKp2pi9drQAWFAYW5hgNCcmuMi8814O4hdm3zsJU6w8cwOLf2p_L3No9YonO2GcSO_ZRHqPqdj5lDwtBR2DbYAUpzOYj0FMPoG6MMM6ITK9DgHDtwVuoo6ZxI6aoAMCYZ8zehn9QuACtZZQPQ","p":"8l1JmRGOfMMxlqFaAB9sWFe29P4xIVl5Tez95Hf9qIIlcdNvrm6bep5889sMAfN3LB2NA09rwBdCPdjVT_80XgrxTsxPPOvzmxuHmHaozlkBAAgfNgIASgKaznSf8nbBkp-p6NRIc3JOCJDFopm6C43ZCexBu8or_CK554O8AMM","q":"8cJUELj52DDYoxcGsm6wIyk9QYCIRry3gxJwaHWQt4xTeX65_W27x0WVY4ZXNCIYYMxKQXN5Ud70OsdzExNHk9dn96w2cOT2tKlIixoSyDpbLsYKuQ4KlEz0S2GZJyiAT0C2N_1VlRy_OFAFmauj9SIMm3Wr3UhWa7fWRWThR0M","dp":"Rs_SzRJAG1u8hVInRZnowfb-0Z3jJOdLdeUkWThluHIuFo-8Na7DZpQf1e_OFlPYId-Qb8MorDsfc4qC6Jib6E4yKt-u1xHpXwwwFe-1anS-wg-dbt4uz3DrYh7ZDLJ95CUaM5iygmiHPCFwXQ2lOfL70tZgbkmniEdtIaNvrpk","dq":"vkXv2-l52kk3d8SbpLuxLTs71t3OY74LwME2b0B4Ub3DxQ-UWn2PGNsPJHGLGKDtBuJCXxj_Fwyes9ReIVk_MICMd0W240uRT8ccLT6sIaKsOTftIJCIiwe2Dc4Wt9cMhVOtFovwW5dweGWiwrtwI3JU8dW_Gj3gpo7duWgYVfk","qi":"Cpf7tVogmGoFr-WTWSkctb0KqNtNCY3tU__2b2GI0uW_a9TafQhU8fon4SNBPlicdAYlgO1q23tklyhGpLbw7qYgHkr-zt-v_Vfg5YP8cZYGEqW52Qjl2HeMlCCI0-38RG3wFYwXjGDZk9YW6VAWlc6i1MSLrd7NGRrwH1ZkD7U","kty":"RSA","alg": "RSA-OAEP","kid":"oidc-provider:locale","use":"enc"}] +OidcProvider_COOKIES_KEYS=["iet7jaetheezaingahThooSiem3Oothu", "aeChoomaeyi5Jeo7Viezoh8aew8ieH3m", "JaeDahngohc3athooy1Eip2ahtei8Aep", "iu5vu5EeD4goow5eipeizequaetaxo0V"] +OidcProvider_ERROR_URI_BASE=https://github.com/numerique-gouv/proconnect-documentation/blob/main/doc_fs/troubleshooting-fs.md +# OidcClient +OidcClient_SCOPE=openid uid given_name usual_name email siren siret organizational_unit belonging_population phone chorusdt +OidcClient_HTTPS_CLIENT_CERT=/etc/ssl/docker_host/app.crt +OidcClient_HTTPS_CLIENT_KEY=/etc/ssl/docker_host/app.key +OidcClient_FAPI=false +OidcClient_FEATURE_ENABLE_HYYYPERBRIDGE=true +# HyyyperbridgeBroker +HyyyperbridgeBroker_QUEUE=rie +HyyyperbridgeBroker_URLS=["amqp://fca-rie_user:fca-rie_user@172.16.6.1:5672/fca-rie"] + +# Mongo +FC_DB_TYPE=mongodb +Mongoose_HOSTS=mongo-fca-low:27017 +Mongoose_DATABASE=core-fca-low +Mongoose_USER=fc +Mongoose_PASSWORD=pass +Mongoose_TLS=true +Mongoose_TLS_INSECURE=false +Mongoose_TLS_ALLOW_INVALID_HOST_NAME=false +Mongoose_TLS_CA_FILE=/etc/ssl/docker_host/docker-stack-ca.crt +FC_DB_SYNCHRONIZE=false +FC_DB_CONNECT_OPTIONS=?replicaSet=rs0 +# Crypto +AdapterMongo_CLIENT_SECRET_CIPHER_PASS=JZBlwxfKnbn/RV025aw+dQxk+xoQT+Yr +AdapterMongo_DECRYPT_CLIENT_SECRET_FEATURE=true +Session_USERINFO_CRYPT_KEY=raePh3i+a4eiwieb-H5iePh6o/gheequ +## Redis +Redis_DB=4 +Redis_HOST= +Redis_PORT= +Redis_PASSWORD=Ivae1feiThoogahquohDei7iwie0ceeM +Redis_SENTINELS=redis-sentinel-1:26379,redis-sentinel-2:26379,redis-sentinel-3:26379 +Redis_NAME=mymaster +Redis_SENTINEL_PASSWORD=Ivae1feiThoogahquohDei7iwie0ceeM +Redis_ENABLE_TLS_FOR_SENTINEL_MODE=false +# Arbitrary DB number, default is 0 and is used by legacy core. +Session_COOKIE_SECRETS=["yahvaeJ0eiNua6te", "lidubozieKadee7w", "Eigoh6ev8xaiNoox", "veed7Oow7er5Saim"] +# Mailer +MAILER=logs +MAILER_FROM_EMAIL=ne-pas-repondre@franceconnect.gouv.fr +MAILER_FROM_NAME=NE PAS RÉPONDRE +## Bluebird potential memory leak safe guard +## @see https://gitlab.dev-franceconnect.fr/france-connect/fc/-/issues/131 +## @see http://bluebirdjs.com/docs/api/promise.config.html#promise.config +BLUEBIRD_LONG_STACK_TRACES=0 +BLUEBIRD_DEBUG=0 +## Proxy settings +NODE_USE_ENV_PROXY=1 +HTTP_PROXY=http://squid:3128 +HTTPS_PROXY=http://squid:3128 + +## API Entreprise +ApiEntreprise_API_TOKEN=CeciEstUnTokenDeTest +ApiEntreprise_API_BASE_URL=https://entreprise.api.gouv.fr +ApiEntreprise_SHOULD_MOCK_API=true +ApiEntreprise_FEATURE_FETCH_ORGANIZATION_DATA=true + +EmailValidator_FEATURE_MX_RESOLUTION_VALIDATION=true diff --git a/docker/compose/fca-low/core.yml b/docker/compose/fca-low/core.yml index 6b627fd797..db58480284 100644 --- a/docker/compose/fca-low/core.yml +++ b/docker/compose/fca-low/core.yml @@ -19,3 +19,18 @@ services: env_file: - '../shared/.env/base-app.env' - '../fca-low/.env/core-rie.env' + + core-sentinel: + extends: core + env_file: + - '../shared/.env/base-app.env' + - '../fca-low/.env/core-sentinel.env' + depends_on: + redis-sentinel-master: + condition: service_healthy + redis-sentinel-1: + condition: service_healthy + redis-sentinel-2: + condition: service_healthy + redis-sentinel-3: + condition: service_healthy diff --git a/docker/compose/fca-low/stack.yml b/docker/compose/fca-low/stack.yml index 38823d264d..f90234b62e 100644 --- a/docker/compose/fca-low/stack.yml +++ b/docker/compose/fca-low/stack.yml @@ -49,3 +49,15 @@ services: - 'squid' - 'hybridge-rie' - 'fia-rie-low' + + redis-sentinel: + image: alpine + depends_on: + - 'core-sentinel' + - 'fsa1-low' + - 'fia1-low' + - 'redis-sentinel-master' + - 'redis-sentinel-replica' + - 'redis-sentinel-1' + - 'redis-sentinel-2' + - 'redis-sentinel-3' diff --git a/docker/compose/shared/.env/redis.env b/docker/compose/shared/.env/redis.env index 80c3afa70b..18469858bc 100644 --- a/docker/compose/shared/.env/redis.env +++ b/docker/compose/shared/.env/redis.env @@ -1,2 +1,3 @@ REDIS_PASSWORD=Ivae1feiThoogahquohDei7iwie0ceeM REDIS_MASTER_PASSWORD=Ivae1feiThoogahquohDei7iwie0ceeM +REDIS_SENTINEL_PASSWORD=Ivae1feiThoogahquohDei7iwie0ceeM diff --git a/docker/compose/shared/shared.yml b/docker/compose/shared/shared.yml index e27d5a36cf..6c128f2d8e 100644 --- a/docker/compose/shared/shared.yml +++ b/docker/compose/shared/shared.yml @@ -241,6 +241,120 @@ services: data: ipv4_address: 172.16.4.105 + redis-sentinel-master: + image: bitnamilegacy/redis:6.0.15 + env_file: + - ../shared/.env/redis.env + environment: + REDIS_REPLICATION_MODE: master + healthcheck: + test: + - CMD-SHELL + - redis-cli -a $$REDIS_PASSWORD role | grep master + interval: 1s + timeout: 2s + retries: 30 + start_period: 3s + networks: + - data + + redis-sentinel-replica: + image: bitnamilegacy/redis:6.0.15 + depends_on: + redis-sentinel-master: + condition: service_healthy + env_file: + - ../shared/.env/redis.env + environment: + REDIS_REPLICATION_MODE: slave + REDIS_MASTER_HOST: redis-sentinel-master + REDIS_MASTER_PORT_NUMBER: "6379" + healthcheck: + test: + - CMD-SHELL + - redis-cli -a $$REDIS_PASSWORD role | grep slave + interval: 1s + timeout: 2s + retries: 30 + start_period: 3s + networks: + - data + + redis-sentinel-1: + image: bitnamilegacy/redis-sentinel:6.0.15 + depends_on: + redis-sentinel-master: + condition: service_healthy + env_file: + - ../shared/.env/redis.env + environment: + REDIS_SENTINEL_MASTER_NAME: mymaster + REDIS_MASTER_HOST: redis-sentinel-master + REDIS_MASTER_PORT_NUMBER: "6379" + REDIS_SENTINEL_QUORUM: "2" + REDIS_SENTINEL_DOWN_AFTER: "5000" + REDIS_SENTINEL_FAILOVER_TIMEOUT: "10000" + healthcheck: + test: + - CMD-SHELL + - redis-cli -a $$REDIS_SENTINEL_PASSWORD -p 26379 sentinel masters | grep mymaster + interval: 1s + timeout: 2s + retries: 30 + start_period: 5s + networks: + - data + + redis-sentinel-2: + image: bitnamilegacy/redis-sentinel:6.0.15 + depends_on: + redis-sentinel-master: + condition: service_healthy + env_file: + - ../shared/.env/redis.env + environment: + REDIS_SENTINEL_MASTER_NAME: mymaster + REDIS_MASTER_HOST: redis-sentinel-master + REDIS_MASTER_PORT_NUMBER: "6379" + REDIS_SENTINEL_QUORUM: "2" + REDIS_SENTINEL_DOWN_AFTER: "5000" + REDIS_SENTINEL_FAILOVER_TIMEOUT: "10000" + healthcheck: + test: + - CMD-SHELL + - redis-cli -a $$REDIS_SENTINEL_PASSWORD -p 26379 sentinel masters | grep mymaster + interval: 1s + timeout: 2s + retries: 30 + start_period: 5s + networks: + - data + + redis-sentinel-3: + image: bitnamilegacy/redis-sentinel:6.0.15 + depends_on: + redis-sentinel-master: + condition: service_healthy + env_file: + - ../shared/.env/redis.env + environment: + REDIS_SENTINEL_MASTER_NAME: mymaster + REDIS_MASTER_HOST: redis-sentinel-master + REDIS_MASTER_PORT_NUMBER: "6379" + REDIS_SENTINEL_QUORUM: "2" + REDIS_SENTINEL_DOWN_AFTER: "5000" + REDIS_SENTINEL_FAILOVER_TIMEOUT: "10000" + healthcheck: + test: + - CMD-SHELL + - redis-cli -a $$REDIS_SENTINEL_PASSWORD -p 26379 sentinel masters | grep mymaster + interval: 1s + timeout: 2s + retries: 30 + start_period: 5s + networks: + - data + postgres: image: postgres:13-bullseye volumes: From b60c9d19b738561fc65775e7c252b9c7b2ced74d Mon Sep 17 00:00:00 2001 From: Douglas DUTEIL Date: Wed, 17 Jun 2026 11:53:37 +0200 Subject: [PATCH 3/3] tmp: run CI with redis-sentinel stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WIP — remove before merge. Adds a third matrix entry to `test_e2e` so reviewers can see the sentinel code path exercised in CI alongside the regular `medium` run. --- .github/workflows/ci-tests.yml | 5 ++- docker/compose/fca-low/stack.yml | 65 ++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 4a88f3a4ea..4e83c63f2c 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -198,7 +198,7 @@ jobs: - name: Execute e2e tests run: | - yarn test:low:chrome-desktop -c video=false --env TAGS="${{ matrix.tags }}" + yarn test:low:chrome-desktop -c video=false --env TAGS="${{ matrix.tags }}" --env LOG_CONTAINER_NAME="${{ matrix.log_container || 'pc-core-1' }}" yarn report - name: Create artifacts-logs directory @@ -230,3 +230,6 @@ jobs: tags: 'not @hybridge and not @ignore' - stack: hybridge tags: '@hybridge' + - stack: redis-sentinel + tags: 'not @hybridge and not @ignore' + log_container: pc-core-sentinel-1 diff --git a/docker/compose/fca-low/stack.yml b/docker/compose/fca-low/stack.yml index f90234b62e..5b06a04b9f 100644 --- a/docker/compose/fca-low/stack.yml +++ b/docker/compose/fca-low/stack.yml @@ -11,53 +11,60 @@ services: small: image: alpine depends_on: - - 'core' - - 'fsa1-low' - - 'fia1-low' + - "core" + - "fsa1-low" + - "fia1-low" # -- used for e2e tests medium: image: alpine depends_on: - - 'core' - - 'admin' + - "core" + - "admin" # -- SP - - 'fsa1-low' - - 'fsa2-low' - - 'fsa3-low' + - "fsa1-low" + - "fsa2-low" + - "fsa3-low" # -- IdP - - 'fia1-low' - - 'fia2-low' - - 'moncomptepro' + - "fia1-low" + - "fia2-low" + - "moncomptepro" # -- DP - - 'dpa1-low' - - 'dpa2-low' + - "dpa1-low" + - "dpa2-low" lemon-ldap: image: alpine depends_on: - - 'identity-provider-llng' - - 'openldap' + - "identity-provider-llng" + - "openldap" hybridge: image: alpine depends_on: - - 'core' - - 'fsa1-low' - - 'fia1-low' + - "core" + - "fsa1-low" + - "fia1-low" ### RIE - - 'squid' - - 'hybridge-rie' - - 'fia-rie-low' + - "squid" + - "hybridge-rie" + - "fia-rie-low" redis-sentinel: image: alpine depends_on: - - 'core-sentinel' - - 'fsa1-low' - - 'fia1-low' - - 'redis-sentinel-master' - - 'redis-sentinel-replica' - - 'redis-sentinel-1' - - 'redis-sentinel-2' - - 'redis-sentinel-3' + - "admin" + - "core-sentinel" + - "dpa1-low" + - "dpa2-low" + - "fia1-low" + - "fia2-low" + - "fsa1-low" + - "fsa2-low" + - "fsa3-low" + - "moncomptepro" + - "redis-sentinel-1" + - "redis-sentinel-2" + - "redis-sentinel-3" + - "redis-sentinel-master" + - "redis-sentinel-replica"