diff --git a/Makefile b/Makefile index 785f54b6..c77ed1f1 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,6 @@ endif ifndef NEO4J_VERSION $(error NEO4J_VERSION is not set) endif -env_NEO4J_VERSION := $(shell record-env NEO4J_VERSION) tarball = neo4j-$(1)-$(2)-unix.tar.gz dist_site := http://dist.neo4j.org @@ -30,7 +29,7 @@ out/%/.sentinel: tmp/image-%/.sentinel tmp/.tests-pass-% > cp -r $( touch $@ -tmp/.tests-pass-%: tmp/.image-id-% $(shell find test -name 'test-*') +tmp/.tests-pass-%: tmp/.image-id-% $(shell find test -name 'test-*') $(shell find test -name '*.yml') $(shell find test -name '*.sh') > mkdir -p $(@D) > image_id=$$(cat $<) > for test in $(filter test/test-%,$^); do @@ -39,7 +38,7 @@ tmp/.tests-pass-%: tmp/.image-id-% $(shell find test -name 'test-*') > done > touch $@ -tmp/.image-id-%: tmp/local-context-%/.sentinel $(env_NEO4J_VERSION) +tmp/.image-id-%: tmp/local-context-%/.sentinel > mkdir -p $(@D) > image=test/$$RANDOM > docker build --tag=$$image \ @@ -55,7 +54,7 @@ tmp/local-context-%/.sentinel: tmp/image-%/.sentinel in/$(call tarball,%,$(NEO4J > touch $@ tmp/image-%/.sentinel: src/$(series)/Dockerfile src/$(series)/docker-entrypoint.sh \ - $(env_NEO4J_VERSION) in/$(call tarball,%,$(NEO4J_VERSION)) + in/$(call tarball,%,$(NEO4J_VERSION)) > mkdir -p $(@D) > cp $(filter %/docker-entrypoint.sh,$^) $(@D)/docker-entrypoint.sh > sha=$$(shasum --algorithm=256 $(filter %.tar.gz,$^) | cut -d' ' -f1) diff --git a/src/2.3/Dockerfile b/src/2.3/Dockerfile index 92c3399b..8b9ccd1e 100644 --- a/src/2.3/Dockerfile +++ b/src/2.3/Dockerfile @@ -4,8 +4,8 @@ RUN apt-get update --quiet --quiet \ && apt-get install --quiet --quiet --no-install-recommends lsof \ && rm -rf /var/lib/apt/lists/* -ENV NEO4J_SHA256 %%NEO4J_SHA%% -ENV NEO4J_TARBALL %%NEO4J_TARBALL%% +ENV NEO4J_SHA256=%%NEO4J_SHA%% \ + NEO4J_TARBALL=%%NEO4J_TARBALL%% ARG NEO4J_URI=%%NEO4J_DIST_SITE%%/%%NEO4J_TARBALL%% COPY ./local-package/* /tmp/ diff --git a/src/3.0/Dockerfile b/src/3.0/Dockerfile index 61032b82..e94dbaa8 100644 --- a/src/3.0/Dockerfile +++ b/src/3.0/Dockerfile @@ -1,7 +1,7 @@ FROM openjdk:8-jre -ENV NEO4J_SHA256 %%NEO4J_SHA%% -ENV NEO4J_TARBALL %%NEO4J_TARBALL%% +ENV NEO4J_SHA256=%%NEO4J_SHA%% \ + NEO4J_TARBALL=%%NEO4J_TARBALL%% ARG NEO4J_URI=%%NEO4J_DIST_SITE%%/%%NEO4J_TARBALL%% COPY ./local-package/* /tmp/ diff --git a/src/3.0/docker-entrypoint.sh b/src/3.0/docker-entrypoint.sh index 33d29706..722e4133 100755 --- a/src/3.0/docker-entrypoint.sh +++ b/src/3.0/docker-entrypoint.sh @@ -21,16 +21,64 @@ setting() { } if [ "$1" == "neo4j" ]; then - setting "dbms.tx_log.rotation.retention_policy" "${NEO4J_dbms_txLog_rotation_retentionPolicy:-100M size}" - setting "dbms.memory.pagecache.size" "${NEO4J_dbms_memory_pagecache_size:-512M}" - setting "wrapper.java.additional=-Dneo4j.ext.udc.source" "${NEO4J_UDC_SOURCE:-docker}" neo4j-wrapper.conf - setting "dbms.memory.heap.initial_size" "${NEO4J_dbms_memory_heap_maxSize:-512}" neo4j-wrapper.conf - setting "dbms.memory.heap.max_size" "${NEO4J_dbms_memory_heap_maxSize:-512}" neo4j-wrapper.conf - setting "dbms.unmanaged_extension_classes" "${NEO4J_dbms_unmanagedExtensionClasses:-}" - setting "dbms.allow_format_migration" "${NEO4J_dbms_allowFormatMigration:-}" + + # Env variable naming convention: + # - prefix NEO4J_ + # - double underscore char '__' instead of single underscore '_' char in the setting name + # - underscore char '_' instead of dot '.' char in the setting name + # Example: + # NEO4J_dbms_tx__log_rotation_retention__policy env variable to set + # dbms.tx_log.rotation.retention_policy setting + + # Backward compatibility - map old hardcoded env variables into new naming convention (if they aren't set already) + # Set some to default values if unset + : ${NEO4J_dbms_tx__log_rotation_retention__policy:=${NEO4J_dbms_txLog_rotation_retentionPolicy:-"100M size"}} + : ${NEO4J_wrapper_java_additional:=${NEO4J_UDC_SOURCE:-"-Dneo4j.ext.udc.source=docker"}} + : ${NEO4J_dbms_memory_heap_initial__size:=${NEO4J_dbms_memory_heap_maxSize:-"512"}} + : ${NEO4J_dbms_memory_heap_max__size:=${NEO4J_dbms_memory_heap_maxSize:-"512"}} + : ${NEO4J_dbms_unmanaged__extension__classes:=${NEO4J_dbms_unmanagedExtensionClasses:-}} + : ${NEO4J_dbms_allow__format__migration:=${NEO4J_dbms_allowFormatMigration:-}} + : ${NEO4J_ha_server__id:=${NEO4J_ha_serverId:-}} + : ${NEO4J_ha_initial__hosts:=${NEO4J_ha_initialHosts:-}} + + : ${NEO4J_dbms_connector_http_address:="0.0.0.0:7474"} + : ${NEO4J_dbms_connector_https_address:="0.0.0.0:7473"} + : ${NEO4J_dbms_connector_bolt_address:="0.0.0.0:7687"} + : ${NEO4J_ha_host_coordination:="$(hostname):5001"} + : ${NEO4J_ha_host_data:="$(hostname):6001"} + + # unset old hardcoded unsupported env variables + unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \ + NEO4J_dbms_memory_heap_maxSize NEO4J_dbms_memory_heap_maxSize \ + NEO4J_dbms_unmanagedExtensionClasses NEO4J_dbms_allowFormatMigration \ + NEO4J_ha_initialHosts + + if [ -d /conf ]; then + find /conf -type f -exec cp {} conf \; + fi + + if [ -d /ssl ]; then + NEO4J_dbms_directories_certificates="/ssl" + fi + + if [ -d /plugins ]; then + NEO4J_dbms_directories_plugins="/plugins" + fi + + if [ -d /logs ]; then + NEO4J_dbms_directories_logs="/logs" + fi + + if [ -d /import ]; then + NEO4J_dbms_directories_import="/import" + fi + + if [ -d /metrics ]; then + NEO4J_dbms_directories_metrics="/metrics" + fi if [ "${NEO4J_AUTH:-}" == "none" ]; then - setting "dbms.security.auth_enabled" "false" + NEO4J_dbms_security_auth__enabled=false elif [[ "${NEO4J_AUTH:-}" == neo4j/* ]]; then password="${NEO4J_AUTH#neo4j/}" if [ "${password}" == "neo4j" ]; then @@ -42,7 +90,7 @@ if [ "$1" == "neo4j" ]; then setting "dbms.connector.https.address" "127.0.0.1:7473" setting "dbms.connector.bolt.address" "127.0.0.1:7687" bin/neo4j start || \ - (cat logs/neo4j.log && echo "Neo4j failed to start" && exit 1) + (cat logs/neo4j.log && echo "Neo4j failed to start for password change" && exit 1) end="$((SECONDS+100))" while true; do @@ -73,37 +121,23 @@ if [ "$1" == "neo4j" ]; then exit 1 fi - setting "dbms.connector.http.address" "0.0.0.0:7474" - setting "dbms.connector.https.address" "0.0.0.0:7473" - setting "dbms.connector.bolt.address" "0.0.0.0:7687" - setting "dbms.mode" "${NEO4J_dbms_mode:-}" - setting "ha.server_id" "${NEO4J_ha_serverId:-}" - setting "ha.host.data" "${NEO4J_ha_host_data:-}" - setting "ha.host.coordination" "${NEO4J_ha_host_coordination:-}" - setting "ha.initial_hosts" "${NEO4J_ha_initialHosts:-}" + # list env variables with prefix NEO4J_ and create settings from them + unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL + for i in $( set | grep ^NEO4J_ | awk -F'=' '{print $1}' | sort -rn ); do + setting=$(echo ${i} | sed 's|^NEO4J_||' | sed 's|_|.|g' | sed 's|\.\.|_|g') + value=$(echo ${!i}) + if [[ -n ${value} ]]; then + if grep -q -F "${setting}=" conf/neo4j.conf; then + # Remove any lines containing the setting already + sed --in-place "/${setting}=.*/d" conf/neo4j.conf + fi + # Then always append setting to file + echo "${setting}=${value}" >> conf/neo4j.conf + fi + done [ -f "${EXTENSION_SCRIPT:-}" ] && . ${EXTENSION_SCRIPT} - if [ -d /conf ]; then - find /conf -type f -exec cp {} conf \; - fi - - if [ -d /ssl ]; then - setting "dbms.directories.certificates" "/ssl" neo4j.conf - fi - - if [ -d /plugins ]; then - setting "dbms.directories.plugins" "/plugins" neo4j.conf - fi - - if [ -d /logs ]; then - setting "dbms.directories.logs" "/logs" neo4j.conf - fi - - if [ -d /import ]; then - setting "dbms.directories.import" "/import" neo4j.conf - fi - exec bin/neo4j console elif [ "$1" == "dump-config" ]; then if [ -d /conf ]; then diff --git a/src/3.1/Dockerfile b/src/3.1/Dockerfile index 44cf4767..5c7e40cc 100644 --- a/src/3.1/Dockerfile +++ b/src/3.1/Dockerfile @@ -4,8 +4,8 @@ RUN apk add --no-cache --quiet \ bash \ curl -ENV NEO4J_SHA256 %%NEO4J_SHA%% -ENV NEO4J_TARBALL %%NEO4J_TARBALL%% +ENV NEO4J_SHA256=%%NEO4J_SHA%% \ + NEO4J_TARBALL=%%NEO4J_TARBALL%% ARG NEO4J_URI=%%NEO4J_DIST_SITE%%/%%NEO4J_TARBALL%% COPY ./local-package/* /tmp/ diff --git a/src/3.1/docker-entrypoint.sh b/src/3.1/docker-entrypoint.sh index b8700ade..1fac31e9 100755 --- a/src/3.1/docker-entrypoint.sh +++ b/src/3.1/docker-entrypoint.sh @@ -1,30 +1,82 @@ #!/bin/bash -eu -setting() { - setting="${1}" - value="${2}" - file="neo4j.conf" +if [ "$1" == "neo4j" ]; then - if [ -n "${value}" ]; then - if grep -q -F "${setting}=" conf/"${file}"; then - sed --in-place "s|.*${setting}=.*|${setting}=${value}|" conf/"${file}" - else - echo "${setting}=${value}" >>conf/"${file}" - fi + # Env variable naming convention: + # - prefix NEO4J_ + # - double underscore char '__' instead of single underscore '_' char in the setting name + # - underscore char '_' instead of dot '.' char in the setting name + # Example: + # NEO4J_dbms_tx__log_rotation_retention__policy env variable to set + # dbms.tx_log.rotation.retention_policy setting + + # Backward compatibility - map old hardcoded env variables into new naming convention (if they aren't set already) + # Set some to default values if unset + : ${NEO4J_dbms_tx__log_rotation_retention__policy:=${NEO4J_dbms_txLog_rotation_retentionPolicy:-"100M size"}} + : ${NEO4J_wrapper_java_additional:=${NEO4J_UDC_SOURCE:-"-Dneo4j.ext.udc.source=docker"}} + : ${NEO4J_dbms_memory_heap_initial__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}} + : ${NEO4J_dbms_memory_heap_max__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}} + : ${NEO4J_dbms_unmanaged__extension__classes:=${NEO4J_dbms_unmanagedExtensionClasses:-}} + : ${NEO4J_dbms_allow__format__migration:=${NEO4J_dbms_allowFormatMigration:-}} + : ${NEO4J_dbms_connectors_default__advertised__address:=${NEO4J_dbms_connectors_defaultAdvertisedAddress:-}} + : ${NEO4J_ha_server__id:=${NEO4J_ha_serverId:-}} + : ${NEO4J_ha_initial__hosts:=${NEO4J_ha_initialHosts:-}} + : ${NEO4J_causal__clustering_expected__core__cluster__size:=${NEO4J_causalClustering_expectedCoreClusterSize:-}} + : ${NEO4J_causal__clustering_initial__discovery__members:=${NEO4J_causalClustering_initialDiscoveryMembers:-}} + : ${NEO4J_causal__clustering_discovery__listen__address:=${NEO4J_causalClustering_discoveryListenAddress:-"0.0.0.0:5000"}} + : ${NEO4J_causal__clustering_discovery__advertised__address:=${NEO4J_causalClustering_discoveryAdvertisedAddress:-"$(hostname):5000"}} + : ${NEO4J_causal__clustering_transaction__listen__address:=${NEO4J_causalClustering_transactionListenAddress:-"0.0.0.0:6000"}} + : ${NEO4J_causal__clustering_transaction__advertised__address:=${NEO4J_causalClustering_transactionAdvertisedAddress:-"$(hostname):6000"}} + : ${NEO4J_causal__clustering_raft__listen__address:=${NEO4J_causalClustering_raftListenAddress:-"0.0.0.0:7000"}} + : ${NEO4J_causal__clustering_raft__advertised__address:=${NEO4J_causalClustering_raftAdvertisedAddress:-"$(hostname):7000"}} + + : ${NEO4J_dbms_connectors_default__listen__address:="0.0.0.0"} + : ${NEO4J_dbms_connector_http_listen__address:="0.0.0.0:7474"} + : ${NEO4J_dbms_connector_https_listen__address:="0.0.0.0:7473"} + : ${NEO4J_dbms_connector_bolt_listen__address:="0.0.0.0:7687"} + : ${NEO4J_ha_host_coordination:="$(hostname):5001"} + : ${NEO4J_ha_host_data:="$(hostname):6001"} + + # unset old hardcoded unsupported env variables + unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \ + NEO4J_dbms_memory_heap_maxSize NEO4J_dbms_memory_heap_maxSize \ + NEO4J_dbms_unmanagedExtensionClasses NEO4J_dbms_allowFormatMigration \ + NEO4J_dbms_connectors_defaultAdvertisedAddress NEO4J_ha_serverId \ + NEO4J_ha_initialHosts NEO4J_causalClustering_expectedCoreClusterSize \ + NEO4J_causalClustering_initialDiscoveryMembers \ + NEO4J_causalClustering_discoveryListenAddress \ + NEO4J_causalClustering_discoveryAdvertisedAddress \ + NEO4J_causalClustering_transactionListenAddress \ + NEO4J_causalClustering_transactionAdvertisedAddress \ + NEO4J_causalClustering_raftListenAddress \ + NEO4J_causalClustering_raftAdvertisedAddress + + if [ -d /conf ]; then + find /conf -type f -exec cp {} conf \; fi -} -if [ "$1" == "neo4j" ]; then - setting "dbms.tx_log.rotation.retention_policy" "${NEO4J_dbms_txLog_rotation_retentionPolicy:-100M size}" - setting "dbms.memory.pagecache.size" "${NEO4J_dbms_memory_pagecache_size:-512M}" - setting "wrapper.java.additional=-Dneo4j.ext.udc.source" "${NEO4J_UDC_SOURCE:-docker}" - setting "dbms.memory.heap.initial_size" "${NEO4J_dbms_memory_heap_maxSize:-512M}" - setting "dbms.memory.heap.max_size" "${NEO4J_dbms_memory_heap_maxSize:-512M}" - setting "dbms.unmanaged_extension_classes" "${NEO4J_dbms_unmanagedExtensionClasses:-}" - setting "dbms.allow_format_migration" "${NEO4J_dbms_allowFormatMigration:-}" + if [ -d /ssl ]; then + NEO4J_dbms_directories_certificates="/ssl" + fi + + if [ -d /plugins ]; then + NEO4J_dbms_directories_plugins="/plugins" + fi + + if [ -d /logs ]; then + NEO4J_dbms_directories_logs="/logs" + fi + + if [ -d /import ]; then + NEO4J_dbms_directories_import="/import" + fi + + if [ -d /metrics ]; then + NEO4J_dbms_directories_metrics="/metrics" + fi if [ "${NEO4J_AUTH:-}" == "none" ]; then - setting "dbms.security.auth_enabled" "false" + NEO4J_dbms_security_auth__enabled=false elif [[ "${NEO4J_AUTH:-}" == neo4j/* ]]; then password="${NEO4J_AUTH#neo4j/}" if [ "${password}" == "neo4j" ]; then @@ -38,44 +90,23 @@ if [ "$1" == "neo4j" ]; then exit 1 fi - setting "dbms.connectors.default_listen_address" "0.0.0.0" - setting "dbms.connector.http.listen_address" "0.0.0.0:7474" - setting "dbms.connector.https.listen_address" "0.0.0.0:7473" - setting "dbms.connector.bolt.listen_address" "0.0.0.0:7687" - setting "dbms.mode" "${NEO4J_dbms_mode:-}" - setting "dbms.connectors.default_advertised_address" "${NEO4J_dbms_connectors_defaultAdvertisedAddress:-}" - setting "ha.server_id" "${NEO4J_ha_serverId:-}" - setting "ha.host.data" "${NEO4J_ha_host_data:-}" - setting "ha.host.coordination" "${NEO4J_ha_host_coordination:-}" - setting "ha.initial_hosts" "${NEO4J_ha_initialHosts:-}" - setting "causal_clustering.expected_core_cluster_size" "${NEO4J_causalClustering_expectedCoreClusterSize:-}" - setting "causal_clustering.initial_discovery_members" "${NEO4J_causalClustering_initialDiscoveryMembers:-}" - setting "causal_clustering.discovery_advertised_address" "${NEO4J_causalClustering_discoveryAdvertisedAddress:-$(hostname):5000}" - setting "causal_clustering.transaction_advertised_address" "${NEO4J_causalClustering_transactionAdvertisedAddress:-$(hostname):6000}" - setting "causal_clustering.raft_advertised_address" "${NEO4J_causalClustering_raftAdvertisedAddress:-$(hostname):7000}" + # list env variables with prefix NEO4J_ and create settings from them + unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL + for i in $( set | grep ^NEO4J_ | awk -F'=' '{print $1}' | sort -rn ); do + setting=$(echo ${i} | sed 's|^NEO4J_||' | sed 's|_|.|g' | sed 's|\.\.|_|g') + value=$(echo ${!i}) + if [[ -n ${value} ]]; then + if grep -q -F "${setting}=" conf/neo4j.conf; then + # Remove any lines containing the setting already + sed --in-place "/${setting}=.*/d" conf/neo4j.conf + fi + # Then always append setting to file + echo "${setting}=${value}" >> conf/neo4j.conf + fi + done [ -f "${EXTENSION_SCRIPT:-}" ] && . ${EXTENSION_SCRIPT} - if [ -d /conf ]; then - find /conf -type f -exec cp {} conf \; - fi - - if [ -d /ssl ]; then - setting "dbms.directories.certificates" "/ssl" neo4j.conf - fi - - if [ -d /plugins ]; then - setting "dbms.directories.plugins" "/plugins" neo4j.conf - fi - - if [ -d /logs ]; then - setting "dbms.directories.logs" "/logs" neo4j.conf - fi - - if [ -d /import ]; then - setting "dbms.directories.import" "/import" neo4j.conf - fi - exec bin/neo4j console elif [ "$1" == "dump-config" ]; then if [ -d /conf ]; then diff --git a/src/3.2/Dockerfile b/src/3.2/Dockerfile index 44cf4767..6bf83a68 100644 --- a/src/3.2/Dockerfile +++ b/src/3.2/Dockerfile @@ -4,8 +4,8 @@ RUN apk add --no-cache --quiet \ bash \ curl -ENV NEO4J_SHA256 %%NEO4J_SHA%% -ENV NEO4J_TARBALL %%NEO4J_TARBALL%% +ENV NEO4J_SHA256=%%NEO4J_SHA%% \ + NEO4J_TARBALL=%%NEO4J_TARBALL%% ARG NEO4J_URI=%%NEO4J_DIST_SITE%%/%%NEO4J_TARBALL%% COPY ./local-package/* /tmp/ @@ -14,13 +14,13 @@ RUN curl --fail --silent --show-error --location --remote-name ${NEO4J_URI} \ && echo "${NEO4J_SHA256} ${NEO4J_TARBALL}" | sha256sum -csw - \ && tar --extract --file ${NEO4J_TARBALL} --directory /var/lib \ && mv /var/lib/neo4j-* /var/lib/neo4j \ - && rm ${NEO4J_TARBALL} + && rm ${NEO4J_TARBALL} \ + && mv /var/lib/neo4j/data /data \ + && ln -s /data /var/lib/neo4j/data \ + && apk del curl WORKDIR /var/lib/neo4j -RUN mv data /data \ - && ln -s /data - VOLUME /data COPY docker-entrypoint.sh /docker-entrypoint.sh diff --git a/src/3.2/docker-entrypoint.sh b/src/3.2/docker-entrypoint.sh index 31f4c5a3..1fac31e9 100755 --- a/src/3.2/docker-entrypoint.sh +++ b/src/3.2/docker-entrypoint.sh @@ -1,30 +1,82 @@ #!/bin/bash -eu -setting() { - setting="${1}" - value="${2}" - file="neo4j.conf" +if [ "$1" == "neo4j" ]; then - if [ -n "${value}" ]; then - if grep -q -F "${setting}=" conf/"${file}"; then - sed --in-place "s|.*${setting}=.*|${setting}=${value}|" conf/"${file}" - else - echo "${setting}=${value}" >>conf/"${file}" - fi + # Env variable naming convention: + # - prefix NEO4J_ + # - double underscore char '__' instead of single underscore '_' char in the setting name + # - underscore char '_' instead of dot '.' char in the setting name + # Example: + # NEO4J_dbms_tx__log_rotation_retention__policy env variable to set + # dbms.tx_log.rotation.retention_policy setting + + # Backward compatibility - map old hardcoded env variables into new naming convention (if they aren't set already) + # Set some to default values if unset + : ${NEO4J_dbms_tx__log_rotation_retention__policy:=${NEO4J_dbms_txLog_rotation_retentionPolicy:-"100M size"}} + : ${NEO4J_wrapper_java_additional:=${NEO4J_UDC_SOURCE:-"-Dneo4j.ext.udc.source=docker"}} + : ${NEO4J_dbms_memory_heap_initial__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}} + : ${NEO4J_dbms_memory_heap_max__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}} + : ${NEO4J_dbms_unmanaged__extension__classes:=${NEO4J_dbms_unmanagedExtensionClasses:-}} + : ${NEO4J_dbms_allow__format__migration:=${NEO4J_dbms_allowFormatMigration:-}} + : ${NEO4J_dbms_connectors_default__advertised__address:=${NEO4J_dbms_connectors_defaultAdvertisedAddress:-}} + : ${NEO4J_ha_server__id:=${NEO4J_ha_serverId:-}} + : ${NEO4J_ha_initial__hosts:=${NEO4J_ha_initialHosts:-}} + : ${NEO4J_causal__clustering_expected__core__cluster__size:=${NEO4J_causalClustering_expectedCoreClusterSize:-}} + : ${NEO4J_causal__clustering_initial__discovery__members:=${NEO4J_causalClustering_initialDiscoveryMembers:-}} + : ${NEO4J_causal__clustering_discovery__listen__address:=${NEO4J_causalClustering_discoveryListenAddress:-"0.0.0.0:5000"}} + : ${NEO4J_causal__clustering_discovery__advertised__address:=${NEO4J_causalClustering_discoveryAdvertisedAddress:-"$(hostname):5000"}} + : ${NEO4J_causal__clustering_transaction__listen__address:=${NEO4J_causalClustering_transactionListenAddress:-"0.0.0.0:6000"}} + : ${NEO4J_causal__clustering_transaction__advertised__address:=${NEO4J_causalClustering_transactionAdvertisedAddress:-"$(hostname):6000"}} + : ${NEO4J_causal__clustering_raft__listen__address:=${NEO4J_causalClustering_raftListenAddress:-"0.0.0.0:7000"}} + : ${NEO4J_causal__clustering_raft__advertised__address:=${NEO4J_causalClustering_raftAdvertisedAddress:-"$(hostname):7000"}} + + : ${NEO4J_dbms_connectors_default__listen__address:="0.0.0.0"} + : ${NEO4J_dbms_connector_http_listen__address:="0.0.0.0:7474"} + : ${NEO4J_dbms_connector_https_listen__address:="0.0.0.0:7473"} + : ${NEO4J_dbms_connector_bolt_listen__address:="0.0.0.0:7687"} + : ${NEO4J_ha_host_coordination:="$(hostname):5001"} + : ${NEO4J_ha_host_data:="$(hostname):6001"} + + # unset old hardcoded unsupported env variables + unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \ + NEO4J_dbms_memory_heap_maxSize NEO4J_dbms_memory_heap_maxSize \ + NEO4J_dbms_unmanagedExtensionClasses NEO4J_dbms_allowFormatMigration \ + NEO4J_dbms_connectors_defaultAdvertisedAddress NEO4J_ha_serverId \ + NEO4J_ha_initialHosts NEO4J_causalClustering_expectedCoreClusterSize \ + NEO4J_causalClustering_initialDiscoveryMembers \ + NEO4J_causalClustering_discoveryListenAddress \ + NEO4J_causalClustering_discoveryAdvertisedAddress \ + NEO4J_causalClustering_transactionListenAddress \ + NEO4J_causalClustering_transactionAdvertisedAddress \ + NEO4J_causalClustering_raftListenAddress \ + NEO4J_causalClustering_raftAdvertisedAddress + + if [ -d /conf ]; then + find /conf -type f -exec cp {} conf \; fi -} -if [ "$1" == "neo4j" ]; then - setting "dbms.tx_log.rotation.retention_policy" "${NEO4J_dbms_txLog_rotation_retentionPolicy:-100M size}" - setting "dbms.memory.pagecache.size" "${NEO4J_dbms_memory_pagecache_size:-512M}" - setting "wrapper.java.additional=-Dneo4j.ext.udc.source" "${NEO4J_UDC_SOURCE:-docker}" - setting "dbms.memory.heap.initial_size" "${NEO4J_dbms_memory_heap_maxSize:-512M}" - setting "dbms.memory.heap.max_size" "${NEO4J_dbms_memory_heap_maxSize:-512M}" - setting "dbms.unmanaged_extension_classes" "${NEO4J_dbms_unmanagedExtensionClasses:-}" - setting "dbms.allow_format_migration" "${NEO4J_dbms_allowFormatMigration:-}" + if [ -d /ssl ]; then + NEO4J_dbms_directories_certificates="/ssl" + fi + + if [ -d /plugins ]; then + NEO4J_dbms_directories_plugins="/plugins" + fi + + if [ -d /logs ]; then + NEO4J_dbms_directories_logs="/logs" + fi + + if [ -d /import ]; then + NEO4J_dbms_directories_import="/import" + fi + + if [ -d /metrics ]; then + NEO4J_dbms_directories_metrics="/metrics" + fi if [ "${NEO4J_AUTH:-}" == "none" ]; then - setting "dbms.security.auth_enabled" "false" + NEO4J_dbms_security_auth__enabled=false elif [[ "${NEO4J_AUTH:-}" == neo4j/* ]]; then password="${NEO4J_AUTH#neo4j/}" if [ "${password}" == "neo4j" ]; then @@ -38,44 +90,23 @@ if [ "$1" == "neo4j" ]; then exit 1 fi - setting "dbms.connectors.default_listen_address" "0.0.0.0" - setting "dbms.connector.http.listen_address" "0.0.0.0:7474" - setting "dbms.connector.https.listen_address" "0.0.0.0:7473" - setting "dbms.connector.bolt.listen_address" "0.0.0.0:7687" - setting "dbms.mode" "${NEO4J_dbms_mode:-}" - setting "dbms.connectors.default_advertised_address" "${NEO4J_dbms_connectors_defaultAdvertisedAddress:-}" - setting "ha.server_id" "${NEO4J_ha_serverId:-}" - setting "ha.host.data" "${NEO4J_ha_host_data:-}" - setting "ha.host.coordination" "${NEO4J_ha_host_coordination:-}" - setting "ha.initial_hosts" "${NEO4J_ha_initialHosts:-}" - setting "causal_clustering.expected_core_cluster_size" "${NEO4J_causalClustering_expectedCoreClusterSize:-}" - setting "causal_clustering.initial_discovery_members" "${NEO4J_causalClustering_initialDiscoveryMembers:-}" - setting "causal_clustering.discovery_advertised_address" "${NEO4J_causalClustering_discoveryAdvertisedAddress:-$(hostname):5000}" - setting "causal_clustering.transaction_advertised_address" "${NEO4J_causalClustering_transactionAdvertisedAddress:-$(hostname):6000}" - setting "causal_clustering.raft_advertised_address" "${NEO4J_causalClustering_raftAdvertisedAddress:-$(hostname):7000}" + # list env variables with prefix NEO4J_ and create settings from them + unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL + for i in $( set | grep ^NEO4J_ | awk -F'=' '{print $1}' | sort -rn ); do + setting=$(echo ${i} | sed 's|^NEO4J_||' | sed 's|_|.|g' | sed 's|\.\.|_|g') + value=$(echo ${!i}) + if [[ -n ${value} ]]; then + if grep -q -F "${setting}=" conf/neo4j.conf; then + # Remove any lines containing the setting already + sed --in-place "/${setting}=.*/d" conf/neo4j.conf + fi + # Then always append setting to file + echo "${setting}=${value}" >> conf/neo4j.conf + fi + done [ -f "${EXTENSION_SCRIPT:-}" ] && . ${EXTENSION_SCRIPT} - if [ -d /conf ]; then - find /conf -type f -exec cp {} conf \; - fi - - if [ -d /ssl ]; then - setting "dbms.directories.certificates" "/ssl" neo4j.conf - fi - - if [ -d /plugins ]; then - setting "dbms.directories.plugins" "/plugins" neo4j.conf - fi - - if [ -d /logs ]; then - setting "dbms.directories.logs" "/logs" neo4j.conf - fi - - if [ -d /import ]; then - setting "dbms.directories.import" "/import" neo4j.conf - fi - exec bin/neo4j console elif [ "$1" == "dump-config" ]; then if [ -d /conf ]; then diff --git a/src/3.3/Dockerfile b/src/3.3/Dockerfile new file mode 100644 index 00000000..6bf83a68 --- /dev/null +++ b/src/3.3/Dockerfile @@ -0,0 +1,31 @@ +FROM openjdk:8-jre-alpine + +RUN apk add --no-cache --quiet \ + bash \ + curl + +ENV NEO4J_SHA256=%%NEO4J_SHA%% \ + NEO4J_TARBALL=%%NEO4J_TARBALL%% +ARG NEO4J_URI=%%NEO4J_DIST_SITE%%/%%NEO4J_TARBALL%% + +COPY ./local-package/* /tmp/ + +RUN curl --fail --silent --show-error --location --remote-name ${NEO4J_URI} \ + && echo "${NEO4J_SHA256} ${NEO4J_TARBALL}" | sha256sum -csw - \ + && tar --extract --file ${NEO4J_TARBALL} --directory /var/lib \ + && mv /var/lib/neo4j-* /var/lib/neo4j \ + && rm ${NEO4J_TARBALL} \ + && mv /var/lib/neo4j/data /data \ + && ln -s /data /var/lib/neo4j/data \ + && apk del curl + +WORKDIR /var/lib/neo4j + +VOLUME /data + +COPY docker-entrypoint.sh /docker-entrypoint.sh + +EXPOSE 7474 7473 7687 + +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["neo4j"] diff --git a/src/3.3/docker-entrypoint.sh b/src/3.3/docker-entrypoint.sh new file mode 100755 index 00000000..0daf9d8e --- /dev/null +++ b/src/3.3/docker-entrypoint.sh @@ -0,0 +1,139 @@ +#!/bin/bash -eu + +if [ "$1" == "neo4j" ]; then + + # Env variable naming convention: + # - prefix NEO4J_ + # - double underscore char '__' instead of single underscore '_' char in the setting name + # - underscore char '_' instead of dot '.' char in the setting name + # Example: + # NEO4J_dbms_tx__log_rotation_retention__policy env variable to set + # dbms.tx_log.rotation.retention_policy setting + + # Backward compatibility - map old hardcoded env variables into new naming convention (if they aren't set already) + # Set some to default values if unset + : ${NEO4J_dbms_tx__log_rotation_retention__policy:=${NEO4J_dbms_txLog_rotation_retentionPolicy:-"100M size"}} + : ${NEO4J_wrapper_java_additional:=${NEO4J_UDC_SOURCE:-"-Dneo4j.ext.udc.source=docker"}} + : ${NEO4J_dbms_memory_heap_initial__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}} + : ${NEO4J_dbms_memory_heap_max__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}} + : ${NEO4J_dbms_unmanaged__extension__classes:=${NEO4J_dbms_unmanagedExtensionClasses:-}} + : ${NEO4J_dbms_allow__format__migration:=${NEO4J_dbms_allowFormatMigration:-}} + : ${NEO4J_dbms_connectors_default__advertised__address:=${NEO4J_dbms_connectors_defaultAdvertisedAddress:-}} + : ${NEO4J_ha_server__id:=${NEO4J_ha_serverId:-}} + : ${NEO4J_ha_initial__hosts:=${NEO4J_ha_initialHosts:-}} + : ${NEO4J_causal__clustering_expected__core__cluster__size:=${NEO4J_causalClustering_expectedCoreClusterSize:-}} + : ${NEO4J_causal__clustering_initial__discovery__members:=${NEO4J_causalClustering_initialDiscoveryMembers:-}} + : ${NEO4J_causal__clustering_discovery__listen__address:=${NEO4J_causalClustering_discoveryListenAddress:-"0.0.0.0:5000"}} + : ${NEO4J_causal__clustering_discovery__advertised__address:=${NEO4J_causalClustering_discoveryAdvertisedAddress:-"$(hostname):5000"}} + : ${NEO4J_causal__clustering_transaction__listen__address:=${NEO4J_causalClustering_transactionListenAddress:-"0.0.0.0:6000"}} + : ${NEO4J_causal__clustering_transaction__advertised__address:=${NEO4J_causalClustering_transactionAdvertisedAddress:-"$(hostname):6000"}} + : ${NEO4J_causal__clustering_raft__listen__address:=${NEO4J_causalClustering_raftListenAddress:-"0.0.0.0:7000"}} + : ${NEO4J_causal__clustering_raft__advertised__address:=${NEO4J_causalClustering_raftAdvertisedAddress:-"$(hostname):7000"}} + + : ${NEO4J_dbms_connectors_default__listen__address:="0.0.0.0"} + : ${NEO4J_dbms_connector_http_listen__address:="0.0.0.0:7474"} + : ${NEO4J_dbms_connector_https_listen__address:="0.0.0.0:7473"} + : ${NEO4J_dbms_connector_bolt_listen__address:="0.0.0.0:7687"} + : ${NEO4J_ha_host_coordination:="$(hostname):5001"} + : ${NEO4J_ha_host_data:="$(hostname):6001"} + + # unset old hardcoded unsupported env variables + unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \ + NEO4J_dbms_memory_heap_maxSize NEO4J_dbms_memory_heap_maxSize \ + NEO4J_dbms_unmanagedExtensionClasses NEO4J_dbms_allowFormatMigration \ + NEO4J_dbms_connectors_defaultAdvertisedAddress NEO4J_ha_serverId \ + NEO4J_ha_initialHosts NEO4J_causalClustering_expectedCoreClusterSize \ + NEO4J_causalClustering_initialDiscoveryMembers \ + NEO4J_causalClustering_discoveryListenAddress \ + NEO4J_causalClustering_discoveryAdvertisedAddress \ + NEO4J_causalClustering_transactionListenAddress \ + NEO4J_causalClustering_transactionAdvertisedAddress \ + NEO4J_causalClustering_raftListenAddress \ + NEO4J_causalClustering_raftAdvertisedAddress + + # Custom settings for dockerized neo4j + : ${NEO4J_dbms_tx__log_rotation_retention__policy:=100M size} + : ${NEO4J_dbms_memory_pagecache_size:=512M} + : ${NEO4J_wrapper_java_additional:=-Dneo4j.ext.udc.source=docker} + : ${NEO4J_dbms_memory_heap_initial__size:=512M} + : ${NEO4J_dbms_memory_heap_max__size:=512M} + : ${NEO4J_dbms_connectors_default__listen__address:=0.0.0.0} + : ${NEO4J_dbms_connector_http_listen__address:=0.0.0.0:7474} + : ${NEO4J_dbms_connector_https_listen__address:=0.0.0.0:7473} + : ${NEO4J_dbms_connector_bolt_listen__address:=0.0.0.0:7687} + : ${NEO4J_ha_host_coordination:=$(hostname):5001} + : ${NEO4J_ha_host_data:=$(hostname):6001} + : ${NEO4J_causal__clustering_discovery__listen__address:=0.0.0.0:5000} + : ${NEO4J_causal__clustering_discovery__advertised__address:=$(hostname):5000} + : ${NEO4J_causal__clustering_transaction__listen__address:=0.0.0.0:6000} + : ${NEO4J_causal__clustering_transaction__advertised__address:=$(hostname):6000} + : ${NEO4J_causal__clustering_raft__listen__address:=0.0.0.0:7000} + : ${NEO4J_causal__clustering_raft__advertised__address:=$(hostname):7000} + + if [ -d /conf ]; then + find /conf -type f -exec cp {} conf \; + fi + + if [ -d /ssl ]; then + NEO4J_dbms_directories_certificates="/ssl" + fi + + if [ -d /plugins ]; then + NEO4J_dbms_directories_plugins="/plugins" + fi + + if [ -d /logs ]; then + NEO4J_dbms_directories_logs="/logs" + fi + + if [ -d /import ]; then + NEO4J_dbms_directories_import="/import" + fi + + if [ -d /metrics ]; then + NEO4J_dbms_directories_metrics="/metrics" + fi + + if [ "${NEO4J_AUTH:-}" == "none" ]; then + NEO4J_dbms_security_auth__enabled=false + elif [[ "${NEO4J_AUTH:-}" == neo4j/* ]]; then + password="${NEO4J_AUTH#neo4j/}" + if [ "${password}" == "neo4j" ]; then + echo "Invalid value for password. It cannot be 'neo4j', which is the default." + exit 1 + fi + # Will exit with error if users already exist (and print a message explaining that) + bin/neo4j-admin set-initial-password "${password}" || true + elif [ -n "${NEO4J_AUTH:-}" ]; then + echo "Invalid value for NEO4J_AUTH: '${NEO4J_AUTH}'" + exit 1 + fi + + # list env variables with prefix NEO4J_ and create settings from them + unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL + for i in $( set | grep ^NEO4J_ | awk -F'=' '{print $1}' | sort -rn ); do + setting=$(echo ${i} | sed 's|^NEO4J_||' | sed 's|_|.|g' | sed 's|\.\.|_|g') + value=$(echo ${!i}) + if [[ -n ${value} ]]; then + if grep -q -F "${setting}=" conf/neo4j.conf; then + # Remove any lines containing the setting already + sed --in-place "/${setting}=.*/d" conf/neo4j.conf + fi + # Then always append setting to file + echo "${setting}=${value}" >> conf/neo4j.conf + fi + done + + [ -f "${EXTENSION_SCRIPT:-}" ] && . ${EXTENSION_SCRIPT} + + exec bin/neo4j console +elif [ "$1" == "dump-config" ]; then + if [ -d /conf ]; then + cp --recursive conf/* /conf + else + echo "You must provide a /conf volume" + exit 1 + fi +else + exec "$@" +fi diff --git a/test/ha-cluster-compose.yml b/test/ha-cluster-compose.yml new file mode 100644 index 00000000..abf5d3a1 --- /dev/null +++ b/test/ha-cluster-compose.yml @@ -0,0 +1,49 @@ +version: '2' + +networks: + lan: + +services: + + master: + image: neo4j:3.1-enterprise + container_name: core-placeholder + networks: + - lan + environment: + - NEO4J_AUTH=neo4j/neo + - NEO4J_ha_serverId=1 + - NEO4J_dbms_mode=HA + - NEO4J_ha_initialHosts=master:5001,slave1:5555,slave2:5001 + +# Use this to make sure master pushes TXs to both slaves, by default it will be only one +# - NEO4J_ha_tx__push__factor=2 + + slave1: + image: neo4j:3.1-enterprise + networks: + - lan + environment: + - NEO4J_AUTH=neo4j/neo + - NEO4J_dbms_mode=HA + - NEO4J_ha_serverId=2 + - NEO4J_ha_initialHosts=master:5001,slave1:5555,slave2:5001 + - NEO4J_ha_host_coordination=slave1:5555 + - NEO4J_ha_host_data=slave1:6666 + - NEO4J_ha_slave__only=true + - NEO4J_ha_pull__interval=5s # Default value is disabled but we want slave to poll master for test + + slave2: + image: neo4j:3.1-enterprise + container_name: read-placeholder + networks: + - lan + environment: + - NEO4J_AUTH=neo4j/neo + - NEO4J_dbms_mode=HA + - NEO4J_ha_server__id=3 + - NEO4J_ha_initial__hosts=master:5001,slave1:5555,slave2:5001 + - NEO4J_ha_host_coordination=slave2:5001 + - NEO4J_ha_host_data=slave2:6001 + - NEO4J_ha_slave__only=true + - NEO4J_ha_pull__interval=5s # Default value is disabled but we want slave to poll master for test diff --git a/test/helpers.sh b/test/helpers.sh index 697fa6cd..8cadf2bd 100644 --- a/test/helpers.sh +++ b/test/helpers.sh @@ -1,5 +1,10 @@ -docker_rm() { +docker_cleanup() { local cid="$1" + # Place logs in similarly named file + mkdir -p tmp/out + local l_logfile="tmp/out/${cid}.log" + + docker logs "${cid}" > "${l_logfile}" || echo "failed to write log" docker rm --force "${cid}" >/dev/null } @@ -10,22 +15,35 @@ docker_restart() { docker_run() { local l_image="$1" l_cname="$2"; shift; shift + local envs=() for env in "$@"; do envs+=("--env=${env}") done local cid="$(docker run --detach "${envs[@]}" --name="${l_cname}" "${l_image}")" - trap "docker_rm ${cid}" EXIT + echo "log: tmp/out/${cid}.log" + trap "docker_cleanup ${cid}" EXIT +} + +docker_compose_cleanup() { + local l_composefile="$1" + # Place compose logs in similarly named file + local l_logfile="${1}.log" + + docker-compose --file "${l_composefile}" --project-name neo4jcomposetest logs --no-color > "${l_logfile}" || echo "failed to write compose log" + docker-compose --file "${l_composefile}" --project-name neo4jcomposetest down --volumes > /dev/null } docker_compose_up() { - local l_image="$1" l_composefile="$2" l_cname="$3" l_rname="$4"; shift; shift; shift; shift + local l_image="$1" l_composefile="$2" l_cname="$3" l_rname="$4"; shift; shift; shift; shift; sed --in-place -e "s|image: .*|image: ${l_image}|g" "${l_composefile}" sed --in-place -e "s|container_name: core.*|container_name: ${l_cname}|g" "${l_composefile}" sed --in-place -e "s|container_name: read.*|container_name: ${l_rname}|g" "${l_composefile}" + echo "logs: ${l_composefile}.log" + docker-compose --file "${l_composefile}" --project-name neo4jcomposetest up -d - trap "docker-compose --file ${l_composefile} --project-name neo4jcomposetest down --volumes" EXIT + trap "docker_compose_cleanup ${l_composefile}" EXIT } docker_compose_ip() { @@ -52,6 +70,48 @@ neo4j_wait() { done } +neo4j_wait_for_ha_available() { + local l_time="${3:-30}" + local l_ip="$1" end="$((SECONDS+${l_time}))" + if [[ -n "${2:-}" ]]; then + local auth="--user $2" + fi + + while true; do + [[ "200" = "$(curl --silent --write-out '%{http_code}' ${auth:-} --output /dev/null http://${l_ip}:7474/db/manage/server/ha/available)" ]] && break + [[ "${SECONDS}" -ge "${end}" ]] && exit 1 + sleep 1 + done +} + +neo4j_wait_for_ha_master() { + local l_time="${3:-30}" + local l_ip="$1" end="$((SECONDS+${l_time}))" + if [[ -n "${2:-}" ]]; then + local auth="--user $2" + fi + + while true; do + [[ "200" = "$(curl --silent --write-out '%{http_code}' ${auth:-} --output /dev/null http://${l_ip}:7474/db/manage/server/ha/master)" ]] && break + [[ "${SECONDS}" -ge "${end}" ]] && exit 1 + sleep 1 + done +} + +neo4j_wait_for_ha_slave() { + local l_time="${3:-30}" + local l_ip="$1" end="$((SECONDS+${l_time}))" + if [[ -n "${2:-}" ]]; then + local auth="--user $2" + fi + + while true; do + [[ "200" = "$(curl --silent --write-out '%{http_code}' ${auth:-} --output /dev/null http://${l_ip}:7474/db/manage/server/ha/slave)" ]] && break + [[ "${SECONDS}" -ge "${end}" ]] && exit 1 + sleep 1 + done +} + neo4j_createnode() { local l_ip="$1" end="$((SECONDS+30))" if [[ -n "${2:-}" ]]; then diff --git a/test/test-causal-clustering-basic b/test/test-causal-clustering-basic index 5d6becfe..0fdf13b2 100755 --- a/test/test-causal-clustering-basic +++ b/test/test-causal-clustering-basic @@ -23,7 +23,9 @@ if ! which docker-compose >/dev/null; then fi # Make a temp copy of compose file -readonly compose_file=$(mktemp /tmp/XXXXXXXX.yml) +mkdir -p tmp/out +readonly compose_file=$(mktemp tmp/out/XXXXXXXX.yml) + cp "$(dirname "$0")/causal-cluster-compose.yml" "${compose_file}" readonly cname="core-$(uuidgen)" diff --git a/test/test-ha-clustering-basic b/test/test-ha-clustering-basic new file mode 100755 index 00000000..b92d1110 --- /dev/null +++ b/test/test-ha-clustering-basic @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -o errexit -o nounset + +. "$(dirname "$0")/helpers.sh" + +readonly image="$1" +readonly series="$2" +readonly edition="$3" + +if [[ "${series}" == "2.3" ]]; then + echo "Skipping: High-Availability Test not compatible pre 3.0" + exit 0 +fi + +if ! [[ "${edition}" == "enterprise" ]]; then + echo "Skipping: High-Availability only available in enterprise" + exit 0 +fi + +if ! which docker-compose >/dev/null; then + echo "Skipping: no docker-compose in path" + exit 0 +fi + +# Make a temp copy of compose file +mkdir -p tmp/out +readonly compose_file=$(mktemp tmp/out/XXXXXXXX.yml) + +cp "$(dirname "$0")/ha-cluster-compose.yml" "${compose_file}" + +readonly cname="core-$(uuidgen)" +readonly rname="slave-$(uuidgen)" + +docker_compose_up "${image}" "${compose_file}" "${cname}" "${rname}" +readonly master_ip="$(docker_compose_ip "${cname}")" +readonly slave_ip="$(docker_compose_ip "${rname}")" +# Make sure master and read replica are up +echo "master: ${master_ip}" +echo "slave: ${slave_ip}" + +echo "Waiting for up..." +neo4j_wait_for_ha_master "${master_ip}" "neo4j:neo" "120" +neo4j_wait_for_ha_slave "${slave_ip}" "neo4j:neo" "120" + +echo "Creating node..." +# create node on master +neo4j_createnode "${master_ip}" "neo4j:neo" + +echo "Reading node..." +# read back on slave +neo4j_readnode "${slave_ip}" "neo4j:neo" "30"