Skip to content

Commit c352705

Browse files
Fix issue 2017: setting localhost as default in docker-compose based setups (#2601)
Fixed validator,sv,localnet docker-compose to use localhost by default, with option to expose externally. Added Release notes, and missing flags Added Integration test to check if by default SV and validator bind to only localhost, when used with docker compose. /cluster_test checked
1 parent 3b31722 commit c352705

File tree

10 files changed

+113
-18
lines changed

10 files changed

+113
-18
lines changed

apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/DockerComposeFullNetworkFrontendIntegrationTest.scala

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import org.lfdecentralizedtrust.splice.util.{FrontendLoginUtil, WalletFrontendTe
55

66
import scala.concurrent.duration.*
77
import scala.sys.process.*
8+
import java.io.{BufferedReader, InputStreamReader}
9+
import scala.util.Try
10+
import java.lang.ProcessBuilder
11+
import scala.jdk.CollectionConverters.*
812

913
class DockerComposeFullNetworkFrontendIntegrationTest
1014
extends FrontendIntegrationTest("frontend")
@@ -91,10 +95,61 @@ class DockerComposeFullNetworkFrontendIntegrationTest
9195

9296
}
9397
}
98+
clue("full network (SV) stack should bind to localhost by default") {
99+
withComposeFullNetwork() { () =>
100+
var binding = getPortBinding("splice-sv-nginx-1", "80")
101+
binding should startWith("127.0.0.1")
102+
binding = getPortBinding("splice-validator-nginx-1", "80")
103+
binding should startWith("127.0.0.1")
104+
}
105+
}
106+
}
107+
} finally {
108+
Seq("build-tools/splice-compose.sh", "stop_network", "-D", "-f").!
109+
}
110+
}
111+
112+
def getPortBinding(containerName: String, internalPort: String): String = {
113+
val command = Seq("docker", "port", containerName, internalPort)
114+
val process = new ProcessBuilder(command.asJava).start()
115+
val reader = new BufferedReader(new InputStreamReader(process.getInputStream))
116+
val output = Try(reader.readLine()).toOption.getOrElse("")
117+
if (process.waitFor() != 0 || output.isEmpty) {
118+
fail(
119+
s"Could not get port binding for $containerName:$internalPort. Is the container running?"
120+
)
121+
}
122+
output
123+
}
124+
125+
def withComposeFullNetwork[A](startFlags: Seq[String] = Seq.empty)(
126+
test: () => A
127+
): A = {
128+
try {
129+
val command =
130+
(Seq("build-tools/splice-compose.sh", "start_network", "-w") ++ startFlags).asJava
131+
132+
val builder = new ProcessBuilder(command)
133+
if (builder.! != 0) {
134+
fail("Failed to start docker-compose full network")
94135
}
136+
test()
95137
} finally {
96138
Seq("build-tools/splice-compose.sh", "stop_network", "-D", "-f").!
97139
}
98140
}
99141

142+
"docker-compose networking bindings work" in { implicit env =>
143+
registerHttpConnectionPoolsCleanup(env)
144+
145+
clue("full network (SV) stack should bind to 0.0.0.0 with -E flag") {
146+
withComposeFullNetwork(startFlags = Seq("-E")) { () =>
147+
var binding = getPortBinding("splice-sv-nginx-1", "80")
148+
binding should startWith("0.0.0.0")
149+
binding = getPortBinding("splice-validator-nginx-1", "80")
150+
binding should startWith("0.0.0.0")
151+
}
152+
}
153+
}
154+
100155
}

build-tools/splice-compose.sh

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ function _start_validator {
104104
if [ "$trust_single" -eq 1 ]; then
105105
extra_flags+=("-b")
106106
fi
107+
if [ "${external_access:-0}" -eq 1 ]; then
108+
extra_flags+=("-E")
109+
fi
107110

108111
secret_url="${sv_from_script}/api/sv/v0/devnet/onboard/validator/prepare"
109112
_info "Curling ${secret_url} for the secret"
@@ -178,7 +181,9 @@ function subcmd_start {
178181
party_hint="$(whoami)-composeValidator-1"
179182
participant_id=""
180183
trust_single=0
181-
while getopts 'haldn:m:Mwt:i:p:P:b' arg; do
184+
external_access=0
185+
186+
while getopts 'haldn:m:Mwt:i:p:P:bE' arg; do
182187
case ${arg} in
183188
h)
184189
subcmd_help
@@ -221,6 +226,9 @@ function subcmd_start {
221226
b)
222227
trust_single=1
223228
;;
229+
E)
230+
external_access=1
231+
;;
224232
?)
225233
subcmd_help
226234
exit 1
@@ -254,7 +262,7 @@ function subcmd_start {
254262
fi
255263
}
256264
function usage_start {
257-
_info " Options: [-a] [-l] [-d] [-n <network_name>] [-m <migration_id>] [-M] [-w] [-t <image_tag>] [-i <identities_dump>] [-p <party_hint>] [-P <participant_id>]"
265+
_info " Options: [-a] [-l] [-d] [-n <network_name>] [-m <migration_id>] [-M] [-w] [-t <image_tag>] [-i <identities_dump>] [-p <party_hint>] [-P <participant_id>] [-b] [-E]"
258266
_info " -a: Enable authentication"
259267
_info " -l: Start the validator against a local SV (for integration tests). Default is against a cluster determined by GCP_CLUSTER_HOSTNAME"
260268
_info " -d: Use images from the DA-internal repository (default: use locally built images)"
@@ -267,6 +275,7 @@ function usage_start {
267275
_info " -p <party_hint>: party hint (by default, <local_user>-composeValidator-1)"
268276
_info " -P <participant_id>: participant identifier (by default, identical to the party hint)"
269277
_info " -b: Disable BFT reads&writes and trust a single SV."
278+
_info " -E: Bind to 0.0.0.0 for external access."
270279
}
271280

272281
subcommand_whitelist[stop]='stop a validator'
@@ -307,9 +316,9 @@ function usage_stop {
307316

308317
subcommand_whitelist[start_network]='Starts a full network (one SV + one validator)'
309318
function subcmd_start_network {
310-
319+
external_access=0
311320
wait=0
312-
while getopts 'hw' arg; do
321+
while getopts 'hwE' arg; do
313322
case ${arg} in
314323
h)
315324
subcmd_help
@@ -318,6 +327,9 @@ function subcmd_start_network {
318327
w)
319328
wait=1
320329
;;
330+
E)
331+
external_access=1
332+
;;
321333
?)
322334
subcmd_help
323335
exit 1
@@ -330,8 +342,13 @@ function subcmd_start_network {
330342
# Locally built images (the default when using this script)
331343
export IMAGE_REPO=""
332344

345+
sv_flags=()
346+
if [ $external_access -eq 1 ]; then
347+
sv_flags+=("-E")
348+
fi
349+
333350
_info "Starting SV"
334-
"${SV_DIR}/start.sh"
351+
"${SV_DIR}/start.sh" "${sv_flags[@]}"
335352

336353
for c in validator participant scan sv-app sequencer-mediator nginx; do
337354
docker logs -f splice-sv-${c}-1 >> "${SPLICE_ROOT}/log/compose-sv-${c}.clog" 2>&1 &
@@ -340,7 +357,7 @@ function subcmd_start_network {
340357
# We must wait for the SV to be ready before starting the validator
341358
# start.sh is idempotent, so running it again with -w should not interfere with the deployment, only wait for it to be ready
342359
_info "Waiting for the SV to be ready"
343-
"${SV_DIR}/start.sh" -w
360+
"${SV_DIR}/start.sh" -w "${sv_flags[@]}"
344361

345362
get_secret_url="sv.localhost:8080/api/sv/v0/devnet/onboard/validator/prepare"
346363
_info "Curling $get_secret_url for the secret"
@@ -365,13 +382,14 @@ function subcmd_start_network {
365382
curl -sf "scan.localhost:8080/api/scan/readyz" || _error "Scan is not ready after 5 minutes" || exit 1
366383

367384
_info "Starting validator"
368-
_do_start_validator -l -o "$secret" -p "local-composeValidator-1" -m 0
385+
_do_start_validator -l -o "$secret" -p "local-composeValidator-1" -m 0 "${sv_flags[@]}"
369386

370387
_info "The full network is ready"
371388
}
372389
function usage_start_network {
373-
_info " Options: [-w]"
374-
_info " -w: Wait also for the validator to be ready (for the SV we must always wait before starting the validator)"
390+
_info " Options: [-w] [-E]"
391+
_info " -w: Wait also for the validator to be ready (for the SV we must always wait before starting the validator)"
392+
_info " -E: Bind to 0.0.0.0 for external access."
375393
}
376394

377395
subcommand_whitelist[stop_network]='Stop a full network, started with start_network'

cluster/compose/localnet/compose.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ services:
7070
- ${LOCALNET_DIR}/conf/nginx/sv.conf:/etc/nginx/templates/sv.c${SV_PROFILE}f.template
7171
- ${LOCALNET_DIR}/conf/nginx/swagger-ui:/etc/nginx/includes
7272
ports:
73-
- "${SV_UI_PORT}:${SV_UI_PORT}"
74-
- "${APP_PROVIDER_UI_PORT}:${APP_PROVIDER_UI_PORT}"
75-
- "${APP_USER_UI_PORT}:${APP_USER_UI_PORT}"
73+
- "${HOST_BIND_IP:-127.0.0.1}:${SV_UI_PORT}:${SV_UI_PORT}"
74+
- "${HOST_BIND_IP:-127.0.0.1}:${APP_PROVIDER_UI_PORT}:${APP_PROVIDER_UI_PORT}"
75+
- "${HOST_BIND_IP:-127.0.0.1}:${APP_USER_UI_PORT}:${APP_USER_UI_PORT}"
7676
depends_on:
7777
wallet-web-ui-sv:
7878
condition: service_healthy

cluster/compose/sv/compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ services:
338338
volumes:
339339
- ./nginx.conf:/etc/nginx/nginx.conf
340340
ports:
341-
- 8080:80
341+
- "${HOST_BIND_IP:-127.0.0.1}:8080:80"
342342
depends_on:
343343
- validator
344344
- scan

cluster/compose/sv/start.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ set -euo pipefail
88
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
99

1010
function usage() {
11-
echo "Usage: $0 -[h] [-w]"
11+
echo "Usage: $0 -[h] [-w] [-E]"
1212
echo " -h: Show this help message"
1313
echo " -w: Wait for the SV node to be ready"
14+
echo " -E: Use this flag to bind the Nginx proxy to 0.0.0.0 (external access) instead of 127.0.0.1 (default)."
1415
}
1516

1617
# issue a user friendly red error
@@ -29,7 +30,9 @@ function _info(){
2930
}
3031

3132
wait=0
32-
while getopts "hw" opt; do
33+
HOST_BIND_IP="127.0.0.1"
34+
35+
while getopts "hwE" opt; do
3336
case ${opt} in
3437
h)
3538
usage
@@ -38,6 +41,9 @@ while getopts "hw" opt; do
3841
w)
3942
wait=1
4043
;;
44+
E)
45+
HOST_BIND_IP="0.0.0.0"
46+
;;
4147
?)
4248
usage
4349
exit 1
@@ -60,4 +66,7 @@ extra_args=()
6066
if [ $wait -eq 1 ]; then
6167
extra_args+=("--wait" "--wait-timeout" "600")
6268
fi
69+
70+
export HOST_BIND_IP
71+
6372
docker compose -f "${script_dir}/compose.yaml" up -d "${extra_args[@]}"

cluster/compose/sv/stop.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function _info(){
1717
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
1818

1919
export IMAGE_TAG=""
20+
export HOST_BIND_IP=""
2021

2122
docker compose -f "$script_dir/compose.yaml" down
2223

cluster/compose/validator/compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ services:
160160
- ./nginx.conf:/etc/nginx/nginx.conf
161161
- ./nginx:/etc/nginx/includes
162162
ports:
163-
- 80:80
163+
- "${HOST_BIND_IP:-127.0.0.1}:80:80"
164164
depends_on:
165165
- ans-web-ui
166166
- wallet-web-ui

cluster/compose/validator/start.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function _info(){
2121
}
2222

2323
function usage() {
24-
echo "Usage: $0 -s <sponsor_sv_address> -o <onboarding_secret> -p <party_hint> -m <migration_id> [-a] [-b] [-c <scan_address>] [-C <host_scan_address>] [-q <sequencer_address>] [-n <network_name>] [-M] [-i <identities_dump>] [-P <participant_id>] [-w] [-l]"
24+
echo "Usage: $0 -s <sponsor_sv_address> -o <onboarding_secret> -p <party_hint> -m <migration_id> [-a] [-b] [-c <scan_address>] [-C <host_scan_address>] [-q <sequencer_address>] [-n <network_name>] [-M] [-i <identities_dump>] [-P <participant_id>] [-w] [-l] [-E]"
2525
echo " -s <sponsor_sv_address>: The full URL of the sponsor SV"
2626
echo " -o <onboarding_secret>: The onboarding secret to use. May be empty (\"\") if you are already onboarded."
2727
echo " -p <party_hint>: The party hint to use for the validator operator, by default also your participant identifier."
@@ -43,6 +43,7 @@ function usage() {
4343
echo " -b: Disable BFT reads&writes and trust a single SV."
4444
echo " -c <scan_address>: The full URL of a Scan app. If not provided, it will be derived from the sponsor SV address."
4545
echo " -q <sequencer_address>: The full URL of the sequencer. Must be provided if BFT reads&writes are disabled."
46+
echo " -E: Use this flag to bind the Nginx proxy to 0.0.0.0 (external access) instead of 127.0.0.1 (default)."
4647
}
4748

4849
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -62,7 +63,9 @@ participant_id=""
6263
restore_identities_dump=""
6364
local_compose_sv=0
6465
wait=0
65-
while getopts 'has:c:C:t:o:n:bq:m:Mp:P:i:wl' arg; do
66+
HOST_BIND_IP="127.0.0.1"
67+
68+
while getopts 'has:c:C:t:o:n:bq:m:Mp:P:i:wlE' arg; do
6669
case ${arg} in
6770
h)
6871
usage
@@ -113,6 +116,9 @@ while getopts 'has:c:C:t:o:n:bq:m:Mp:P:i:wl' arg; do
113116
l)
114117
local_compose_sv=1
115118
;;
119+
E)
120+
HOST_BIND_IP="0.0.0.0"
121+
;;
116122
?)
117123
usage
118124
exit 1
@@ -264,4 +270,7 @@ extra_args=()
264270
if [ $wait -eq 1 ]; then
265271
extra_args+=("--wait" "--wait-timeout" "600")
266272
fi
273+
274+
export HOST_BIND_IP
275+
267276
docker compose -f "${script_dir}/compose.yaml" "${extra_compose_files[@]}" up -d "${extra_args[@]}"

cluster/compose/validator/stop.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export SPLICE_APP_UI_NAME_SERVICE_NAME=""
3131
export SPLICE_APP_UI_NAME_SERVICE_NAME_ACRONYM=""
3232
export VALIDATOR_PARTICIPANT_IDENTITIES_DUMP="v" # A non-empty dummy value, just to make the docker-compose spec valid
3333
export VALIDATOR_NEW_PARTICIPANT_IDENTIFIER=""
34+
export HOST_BIND_IP=""
3435

3536
# We include also compose-restore-from-id.yaml, so that if that was included in the start and created the init container,
3637
# that container is also included in the down and removed

docs/src/release_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ Release Notes
5454

5555
- Replace ``-Dscala.concurrent.context.minThreads=8`` with ``-Dscala.concurrent.context.numThreads=8`` and set ``-XX:ActiveProcessorCount=8`` in the ``defaultJvmOptions`` for all the helm charts that deploy scala apps. This should ensure that the internal execution contexts spawn 8 threads to handle processing and that the JVM is configured for 8 CPUs as well. The previous behavior would spawn up to number of available processors, which can be up to the number of CPUs on the actual node if no CPU limit is set. This should avoid overloading the nodes during heavy processing.
5656

57+
- Docker-compose based deployments of LocalNet, validator, and SV expose only to 127.0.0.1 by default. If you want to expose externally, use ``-E`` in validator and superValidator ``start.sh``. For LocalNet, set ``export HOST_BIND_IP=0.0.0.0`` manually.
58+
5759
- SV
5860

5961
- UI

0 commit comments

Comments
 (0)