@@ -12,6 +12,18 @@ function secure_mode_enabled
12
12
test " ${SECURE_FILE_PERMISSIONS:= no} " = " yes"
13
13
}
14
14
15
+ function debugging_enabled
16
+ {
17
+ test " ${NEO4J_DEBUG+yes} " = " yes"
18
+ }
19
+
20
+ function debug_msg
21
+ {
22
+ if debugging_enabled; then
23
+ echo " $@ "
24
+ fi
25
+ }
26
+
15
27
function containsElement
16
28
{
17
29
local e match=" $1 "
@@ -71,13 +83,6 @@ function is_writable
71
83
return 1
72
84
}
73
85
74
- function expand_commands_optionally
75
- {
76
- if [ " ${EXTENDED_CONF+" yes" } " == " yes" ]; then
77
- echo " --expand-commands"
78
- fi
79
- }
80
-
81
86
function print_permissions_advice_and_fail
82
87
{
83
88
_directory=${1}
@@ -96,6 +101,7 @@ If the folder is owned by the current user, this can be done by adding this flag
96
101
function check_mounted_folder_readable
97
102
{
98
103
local _directory=${1}
104
+ debug_msg " checking ${_directory} is readable"
99
105
if ! is_readable " ${_directory} " ; then
100
106
print_permissions_advice_and_fail " ${_directory} "
101
107
fi
@@ -126,6 +132,7 @@ function check_mounted_folder_writable_with_chown
126
132
# (This is a very unlikely use case).
127
133
128
134
local mountFolder=${1}
135
+ debug_msg " checking ${mountFolder} is writable"
129
136
if running_as_root && ! secure_mode_enabled; then
130
137
# check folder permissions
131
138
if ! is_writable " ${mountFolder} " ; then
@@ -138,9 +145,7 @@ function check_mounted_folder_writable_with_chown
138
145
chown -R " ${userid} " :" ${groupid} " " ${mountFolder} "
139
146
fi
140
147
else
141
- # if ! is_writable "${mountFolder}"; then
142
148
if [[ ! -w " ${mountFolder} " ]] && [[ " $( stat -c %U ${mountFolder} ) " != " neo4j" ]]; then
143
- # echo >&2 "Consider unsetting SECURE_FILE_PERMISSIONS environment variable, to enable docker to write to ${mountFolder}."
144
149
print_permissions_advice_and_fail " ${mountFolder} "
145
150
fi
146
151
fi
@@ -182,6 +187,7 @@ function load_plugin_from_github
182
187
local _plugins_dir=" /plugins"
183
188
fi
184
189
local _versions_json_url=" $( jq --raw-output " with_entries( select(.key==\" ${_plugin_name} \" ) ) | to_entries[] | .value.versions" /startup/neo4jlabs-plugins.json ) "
190
+ debug_msg " Will read ${_plugin_name} versions.json from ${_versions_json_url} "
185
191
# Using the same name for the plugin irrespective of version ensures we don't end up with different versions of the same plugin
186
192
local _destination=" ${_plugins_dir} /${_plugin_name} .jar"
187
193
local _neo4j_version=" $( neo4j --version | cut -d' ' -f2) "
@@ -205,30 +211,34 @@ function load_plugin_from_github
205
211
206
212
function apply_plugin_default_configuration
207
213
{
208
- # Set the correct Load a plugin at runtime. The provided github repository must have a versions.json on the master branch with the
209
- # correct format.
210
- local _plugin_name=" ${1} " # e.g. apoc, graph-algorithms, graph-ql
211
- local _reference_conf=" ${2} " # used to determine if we can override properties
212
- local _neo4j_conf=" ${NEO4J_HOME} /conf/neo4j.conf"
213
-
214
- local _property _value
215
- echo " Applying default values for plugin ${_plugin_name} to neo4j.conf"
216
- for _entry in $( jq --compact-output --raw-output " with_entries( select(.key==\" ${_plugin_name} \" ) ) | to_entries[] | .value.properties | to_entries[]" /startup/neo4jlabs-plugins.json) ; do
217
- _property=" $( jq --raw-output ' .key' <<< " ${_entry}" ) "
218
- _value=" $( jq --raw-output ' .value' <<< " ${_entry}" ) "
219
-
220
- # the first grep strips out comments
221
- if grep -o " ^[^#]*" " ${_reference_conf} " | grep -q --fixed-strings " ${_property} =" ; then
222
- # property is already set in the user provided config. In this case we don't override what has been set explicitly by the user.
223
- echo " Skipping ${_property} for plugin ${_plugin_name} because it is already set"
224
- else
225
- if grep -o " ^[^#]*" " ${_neo4j_conf} " | grep -q --fixed-strings " ${_property} =" ; then
226
- sed --in-place " s/${_property} =/&${_value} ,/" " ${_neo4j_conf} "
227
- else
228
- echo " ${_property} =${_value} " >> " ${_neo4j_conf} "
229
- fi
230
- fi
231
- done
214
+ # Set the correct Load a plugin at runtime. The provided github repository must have a versions.json on the master branch with the
215
+ # correct format.
216
+ local _plugin_name=" ${1} " # e.g. apoc, graph-algorithms, graph-ql
217
+ local _reference_conf=" ${2} " # used to determine if we can override properties
218
+ local _neo4j_conf=" ${NEO4J_HOME} /conf/neo4j.conf"
219
+
220
+ local _property _value
221
+ echo " Applying default values for plugin ${_plugin_name} to neo4j.conf"
222
+ for _entry in $( jq --compact-output --raw-output " with_entries( select(.key==\" ${_plugin_name} \" ) ) | to_entries[] | .value.properties | to_entries[]" /startup/neo4jlabs-plugins.json) ; do
223
+ _property=" $( jq --raw-output ' .key' <<< " ${_entry}" ) "
224
+ _value=" $( jq --raw-output ' .value' <<< " ${_entry}" ) "
225
+ debug_msg " ${_plugin_name} requires setting ${_property} =${_value} "
226
+
227
+ # the first grep strips out comments
228
+ if grep -o " ^[^#]*" " ${_reference_conf} " | grep -q --fixed-strings " ${_property} =" ; then
229
+ # property is already set in the user provided config. In this case we don't override what has been set explicitly by the user.
230
+ echo " Skipping ${_property} for plugin ${_plugin_name} because it is already set."
231
+ echo " You may need to add ${_value} to the ${_property} setting in your configuration file."
232
+ else
233
+ if grep -o " ^[^#]*" " ${_neo4j_conf} " | grep -q --fixed-strings " ${_property} =" ; then
234
+ sed --in-place " s/${_property} =/&${_value} ,/" " ${_neo4j_conf} "
235
+ debug_msg " ${_property} was already in the configuration file, so ${_value} was added to it."
236
+ else
237
+ echo " ${_property} =${_value} " >> " ${_neo4j_conf} "
238
+ debug_msg " ${_property} =${_value} has been added to the configuration file."
239
+ fi
240
+ fi
241
+ done
232
242
}
233
243
234
244
function install_neo4j_labs_plugins
@@ -239,10 +249,13 @@ function install_neo4j_labs_plugins
239
249
for plugin_name in $( echo " ${NEO4JLABS_PLUGINS} " | jq --raw-output ' .[]' ) ; do
240
250
local _location=" $( jq --raw-output " with_entries( select(.key==\" ${plugin_name} \" ) ) | to_entries[] | .value.location" /startup/neo4jlabs-plugins.json ) "
241
251
if [ " ${_location} " != " null" -a -n " $( shopt -s nullglob; echo ${_location} ) " ]; then
252
+ debug_msg " $plugin_name is already in the container at ${_location} "
242
253
load_plugin_from_location " ${plugin_name} " " ${_location} "
243
254
else
255
+ debug_msg " $plugin_name must be downloaded."
244
256
load_plugin_from_github " ${plugin_name} "
245
257
fi
258
+ debug_msg " Applying plugin specific configurations"
246
259
apply_plugin_default_configuration " ${plugin_name} " " ${_old_config} "
247
260
done
248
261
rm " ${_old_config} "
@@ -253,11 +266,11 @@ function add_docker_default_to_conf
253
266
# docker defaults should NOT overwrite values already in the conf file
254
267
local _setting=" ${1} "
255
268
local _value=" ${2} "
256
- local _neo4j_home=" ${3} "
257
269
258
- if ! grep -q " ^${_setting} =" " ${_neo4j_home } " /conf/neo4j.conf
270
+ if ! grep -q " ^${_setting} =" " ${NEO4J_HOME } " /conf/neo4j.conf
259
271
then
260
- echo -e " \n" ${_setting} =${_value} >> " ${_neo4j_home} " /conf/neo4j.conf
272
+ debug_msg " Appended ${_setting} =${_value} to ${NEO4J_HOME} /conf/neo4j.conf"
273
+ echo -e " \n" ${_setting} =${_value} >> " ${NEO4J_HOME} " /conf/neo4j.conf
261
274
fi
262
275
}
263
276
@@ -266,14 +279,15 @@ function add_env_setting_to_conf
266
279
# settings from environment variables should overwrite values already in the conf
267
280
local _setting=${1}
268
281
local _value=${2}
269
- local _neo4j_home=${3}
270
282
271
- if grep -q -F " ${_setting} =" " ${_neo4j_home } " /conf/neo4j.conf; then
283
+ if grep -q -F " ${_setting} =" " ${NEO4J_HOME } " /conf/neo4j.conf; then
272
284
# Remove any lines containing the setting already
273
- sed --in-place " /^${_setting} =.*/d" " ${_neo4j_home} " /conf/neo4j.conf
285
+ debug_msg " Removing existing setting for ${_setting} "
286
+ sed --in-place " /^${_setting} =.*/d" " ${NEO4J_HOME} " /conf/neo4j.conf
274
287
fi
275
288
# Then always append setting to file
276
- echo " ${_setting} =${_value} " >> " ${_neo4j_home} " /conf/neo4j.conf
289
+ debug_msg " Appended ${_setting} =${_value} to ${NEO4J_HOME} /conf/neo4j.conf"
290
+ echo " ${_setting} =${_value} " >> " ${NEO4J_HOME} " /conf/neo4j.conf
277
291
}
278
292
279
293
function set_initial_password
@@ -283,11 +297,13 @@ function set_initial_password
283
297
# set the neo4j initial password only if you run the database server
284
298
if [ " ${cmd} " == " neo4j" ]; then
285
299
if [ " ${_neo4j_auth:- } " == " none" ]; then
286
- add_env_setting_to_conf " dbms.security.auth_enabled" " false" " ${NEO4J_HOME} "
300
+ debug_msg " Authentication is requested to be unset"
301
+ add_env_setting_to_conf " dbms.security.auth_enabled" " false"
287
302
elif [[ " ${_neo4j_auth:- } " =~ ^([^/]+)\/ ([^/]+)/? ([tT][rR][uU][eE])? $ ]]; then
288
303
admin_user=" ${BASH_REMATCH[1]} "
289
304
password=" ${BASH_REMATCH[2]} "
290
305
do_reset=" ${BASH_REMATCH[3]} "
306
+ debug_msg " NEO4J_AUTH has been parsed as user \" ${admin_user} \" , password \" ${password} \" , do_reset \" ${do_reset} \" "
291
307
292
308
if [ " ${password} " == " neo4j" ]; then
293
309
echo >&2 " Invalid value for password. It cannot be 'neo4j', which is the default."
@@ -302,16 +318,28 @@ function set_initial_password
302
318
# running set-initial-password as root will create subfolders to /data as root, causing startup fail when neo4j can't read or write the /data/dbms folder
303
319
# creating the folder first will avoid that
304
320
mkdir -p /data/dbms
321
+ debug_msg " Making sure /data/dbms is owned by ${userid} :${groupid} "
305
322
chown " ${userid} " :" ${groupid} " /data/dbms
306
323
fi
307
324
308
- # Will exit with error if users already exist (and print a message explaining that)
309
- # we probably don't want the message though, since it throws an error message on restarting the container.
325
+ local extra_args=()
310
326
if [ " ${do_reset} " == " true" ]; then
311
- ${neo4j_admin_cmd} set-initial-password " ${password} " --require-password-change $( expand_commands_optionally) 2> /dev/null || true
327
+ extra_args+=(" --require-password-change" )
328
+ fi
329
+ if [ " ${EXTENDED_CONF+" yes" } " == " yes" ]; then
330
+ extra_args+=(" --expand-commands" )
331
+ fi
332
+ debug_msg " Setting initial password"
333
+ debug_msg " ${neo4j_admin_cmd} set-initial-password ${password} ${extra_args[*]} "
334
+ if debugging_enabled; then
335
+ # don't suppress any output or errors in debugging mode
336
+ ${neo4j_admin_cmd} set-initial-password " ${password} " " ${extra_args[@]} "
312
337
else
313
- ${neo4j_admin_cmd} set-initial-password " ${password} " $( expand_commands_optionally) 2> /dev/null || true
338
+ # Will exit with error if users already exist (and print a message explaining that)
339
+ # we probably don't want the message though, since it throws an error message on restarting the container.
340
+ ${neo4j_admin_cmd} set-initial-password " ${password} " " ${extra_args[@]} " 2> /dev/null || true
314
341
fi
342
+
315
343
elif [ -n " ${_neo4j_auth:- } " ]; then
316
344
echo " $_neo4j_auth is invalid"
317
345
echo >&2 " Invalid value for NEO4J_AUTH: '${_neo4j_auth} '"
@@ -320,6 +348,9 @@ function set_initial_password
320
348
fi
321
349
}
322
350
351
+ # ==== CODE STARTS ====
352
+ debug_msg " DEBUGGING ENABLED"
353
+
323
354
# If we're running as root, then run as the neo4j user. Otherwise
324
355
# docker is running with --user and we simply use that user. Note
325
356
# that su-exec, despite its name, does not replicate the functionality
@@ -330,12 +361,14 @@ if running_as_root; then
330
361
groups=($( id -G neo4j) )
331
362
exec_cmd=" exec gosu neo4j:neo4j"
332
363
neo4j_admin_cmd=" gosu neo4j:neo4j neo4j-admin"
364
+ debug_msg " Running as root user inside neo4j image"
333
365
else
334
366
userid=" $( id -u) "
335
367
groupid=" $( id -g) "
336
368
groups=($( id -G) )
337
369
exec_cmd=" exec"
338
370
neo4j_admin_cmd=" neo4j-admin"
371
+ debug_msg " Running as user ${userid} :${groupid} inside neo4j image"
339
372
fi
340
373
readonly userid
341
374
readonly groupid
@@ -346,9 +379,11 @@ readonly neo4j_admin_cmd
346
379
347
380
# Need to chown the home directory
348
381
if running_as_root; then
382
+ debug_msg " chowning ${NEO4J_HOME} recursively to ${userid} " :" ${groupid} "
349
383
chown -R " ${userid} " :" ${groupid} " " ${NEO4J_HOME} "
350
384
chmod 700 " ${NEO4J_HOME} "
351
385
find " ${NEO4J_HOME} " -mindepth 1 -maxdepth 1 -type d -exec chmod -R 700 {} \;
386
+ debug_msg " Setting all files in ${NEO4J_HOME} /conf to permissions 600"
352
387
find " ${NEO4J_HOME} " /conf -type f -exec chmod -R 600 {} \;
353
388
fi
354
389
@@ -403,6 +438,7 @@ if [ "${NEO4J_EDITION}" == "enterprise" ];
403
438
then
404
439
: ${NEO4J_causal__clustering_expected__core__cluster__size:= ${NEO4J_causalClustering_expectedCoreClusterSize:- } }
405
440
: ${NEO4J_causal__clustering_initial__discovery__members:= ${NEO4J_causalClustering_initialDiscoveryMembers:- } }
441
+ debug_msg " Copying contents of /conf to ${NEO4J_HOME} /conf/*"
406
442
: ${NEO4J_causal__clustering_discovery__advertised__address:= ${NEO4J_causalClustering_discoveryAdvertisedAddress:- } }
407
443
: ${NEO4J_causal__clustering_transaction__advertised__address:= ${NEO4J_causalClustering_transactionAdvertisedAddress:- } }
408
444
: ${NEO4J_causal__clustering_raft__advertised__address:= ${NEO4J_causalClustering_raftAdvertisedAddress:- } }
@@ -427,6 +463,7 @@ unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \
427
463
if [ -d /conf ]; then
428
464
check_mounted_folder_readable " /conf"
429
465
rm -rf " ${NEO4J_HOME} " /conf/*
466
+ debug_msg " Copying contents of /conf to ${NEO4J_HOME} /conf/*"
430
467
find /conf -type f -exec cp --preserve=ownership,mode {} " ${NEO4J_HOME} " /conf \;
431
468
fi
432
469
438
475
439
476
if [ -d /plugins ]; then
440
477
if [[ -n " ${NEO4JLABS_PLUGINS:- } " ]]; then
441
- # We need write permissions
478
+ # We need write permissions to write the required plugins to /plugins
479
+ debug_msg " Extra plugins were requested. Ensuring the mounted /plugins folder has the required write permissions."
442
480
check_mounted_folder_writable_with_chown " /plugins"
443
481
fi
444
482
check_mounted_folder_readable " /plugins"
487
525
# # == DOCKER SPECIFIC DEFAULT CONFIGURATIONS ===
488
526
# # these should not override *any* configurations set by the user
489
527
490
- add_docker_default_to_conf " dbms.tx_log.rotation.retention_policy" " 100M size" " ${NEO4J_HOME} "
491
- add_docker_default_to_conf " dbms.memory.pagecache.size" " 512M" " ${NEO4J_HOME} "
492
- add_docker_default_to_conf " dbms.default_listen_address" " 0.0.0.0" " ${NEO4J_HOME} "
528
+ debug_msg " Setting docker specific configuration overrides"
529
+ add_docker_default_to_conf " dbms.tx_log.rotation.retention_policy" " 100M size"
530
+ add_docker_default_to_conf " dbms.memory.pagecache.size" " 512M"
531
+ add_docker_default_to_conf " dbms.default_listen_address" " 0.0.0.0"
493
532
# set enterprise only docker defaults
494
533
if [ " ${NEO4J_EDITION} " == " enterprise" ];
495
534
then
496
- add_docker_default_to_conf " causal_clustering.discovery_advertised_address" " $( hostname) :5000" " ${NEO4J_HOME} "
497
- add_docker_default_to_conf " causal_clustering.transaction_advertised_address" " $( hostname) :6000" " ${NEO4J_HOME} "
498
- add_docker_default_to_conf " causal_clustering.raft_advertised_address" " $( hostname) :7000" " ${NEO4J_HOME} "
535
+ debug_msg " Setting docker specific Enterprise Edition overrides"
536
+ add_docker_default_to_conf " causal_clustering.discovery_advertised_address" " $( hostname) :5000"
537
+ add_docker_default_to_conf " causal_clustering.transaction_advertised_address" " $( hostname) :6000"
538
+ add_docker_default_to_conf " causal_clustering.raft_advertised_address" " $( hostname) :7000"
499
539
fi
500
540
501
541
# # == ENVIRONMENT VARIABLE CONFIGURATIONS ===
502
542
# # these override BOTH defaults and any existing values in the neo4j.conf file
503
543
504
- # save NEO4J_HOME and NEO4J_AUTH to temp variables that don't begin with NEO4J_ so they don't get added to the conf
505
- temp_neo4j_home=" ${NEO4J_HOME} "
506
- temp_neo4j_auth=" ${NEO4J_AUTH:- } "
544
+ # these are docker control envs that have the NEO4J_ prefix but we don't want to add to the config.
545
+ not_configs=(" NEO4J_ACCEPT_LICENSE_AGREEMENT" " NEO4J_AUTH" " NEO4J_DEBUG" " NEO4J_EDITION" \
546
+ " NEO4J_HOME" " NEO4J_PLUGINS" " NEO4J_SHA256" " NEO4J_TARBALL" )
547
+
548
+ debug_msg " Applying configuration settings that have been set using environment variables."
507
549
# list env variables with prefix NEO4J_ and create settings from them
508
- unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL NEO4J_EDITION NEO4J_ACCEPT_LICENSE_AGREEMENT NEO4J_HOME
509
550
for i in $( set | grep ^NEO4J_ | awk -F' =' ' {print $1}' | sort -rn ) ; do
551
+ if containsElement " $i " " ${not_configs[@]} " ; then
552
+ continue
553
+ fi
510
554
setting=$( echo " ${i} " | sed ' s|^NEO4J_||' | sed ' s|_|.|g' | sed ' s|\.\.|_|g' )
511
555
value=$( echo " ${! i} " )
512
556
# Don't allow settings with no value or settings that start with a number (neo4j converts settings to env variables and you cannot have an env variable that starts with a number)
513
557
if [[ -n ${value} ]]; then
514
558
if [[ ! " ${setting} " =~ ^[0-9]+.* $ ]]; then
515
- add_env_setting_to_conf " ${setting} " " ${value} " " ${temp_neo4j_home} "
559
+ add_env_setting_to_conf " ${setting} " " ${value} "
516
560
else
517
561
echo >&2 " WARNING: ${setting} not written to conf file because settings that start with a number are not permitted"
518
562
fi
519
563
fi
520
564
done
521
- export NEO4J_HOME=" ${temp_neo4j_home} "
522
- unset temp_neo4j_home
523
565
524
566
# ==== SET PASSWORD AND PLUGINS ====
525
567
526
- set_initial_password " ${temp_neo4j_auth } "
568
+ set_initial_password " ${NEO4J_AUTH :- } "
527
569
528
570
529
571
if [[ ! -z " ${NEO4JLABS_PLUGINS:- } " ]]; then
550
592
# the command is something like: `java ...[lots of java options]... neo4j.mainClass ...[some neo4j options]...`
551
593
function get_neo4j_run_cmd {
552
594
553
- local extraArgs =()
595
+ local extra_args =()
554
596
555
597
if [ " ${EXTENDED_CONF+" yes" } " == " yes" ]; then
556
- extraArgs+=(" --expand-commands" )
598
+ extra_args+=(" --expand-commands" )
599
+ fi
600
+ if debugging_enabled ; then
601
+ extra_args+=(" --verbose" )
557
602
fi
558
603
559
604
if running_as_root; then
560
- gosu neo4j:neo4j neo4j console --dry-run " ${extraArgs [@]} "
605
+ gosu neo4j:neo4j neo4j console --dry-run " ${extra_args [@]} "
561
606
else
562
- neo4j console --dry-run " ${extraArgs [@]} "
607
+ neo4j console --dry-run " ${extra_args [@]} "
563
608
fi
564
609
}
565
610
@@ -569,7 +614,9 @@ function get_neo4j_run_cmd {
569
614
if [ " ${cmd} " == " neo4j" ]; then
570
615
# separate declaration and use of get_neo4j_run_cmd so that error codes are correctly surfaced
571
616
neo4j_console_cmd=" $( get_neo4j_run_cmd) "
617
+ debug_msg " ${exec_cmd} ${neo4j_console_cmd} "
572
618
eval ${exec_cmd} ${neo4j_console_cmd?: No Neo4j command was generated}
573
619
else
620
+ debug_msg " ${exec_cmd} " " $@ "
574
621
${exec_cmd} " $@ "
575
622
fi
0 commit comments