Skip to content

Commit

Permalink
✨(apps) add elasticsearch application
Browse files Browse the repository at this point in the history
Add  an  independant  elasticsearch   app  with  a  configurable  high
availability cluster. It is designed  to run without persistent volume
and it  supports rolling updates without  any data loss. On  the other
hand,  a full  restart  of  the ES  cluster  (without rolling  update)
results in data loss and requires to recreate indexes.
  • Loading branch information
madmatah committed Jan 29, 2020
1 parent 6e45ccb commit 5a915b1
Show file tree
Hide file tree
Showing 18 changed files with 470 additions and 39 deletions.
87 changes: 60 additions & 27 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "hello"
# Test service deployed with the next route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "next"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "next"
- run:
name: Test the "hello" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "hello"
# Test service switched to the current route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold"
- run:
name: Test the "hello" application rollback
Expand All @@ -219,13 +219,13 @@ jobs:
# Switch next route to current and current to previous
bin/ci-ansible-playbook switch.yml "hello"
# Test service switched to the current/previous route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold"
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "previous"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "previous"
# Rollback previous to current and current to next
bin/ci-ansible-playbook rollback.yml "hello"
# Test service switched to the current/next route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold"
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "next"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "next"
# Test the redirect application
test-redirect:
Expand Down Expand Up @@ -255,7 +255,7 @@ jobs:
name: Test the "www" to root domain redirection
command: |
# Test service switched to the current route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "www"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "www"
# Test the bootstrap playbook on the "mailcatcher" application
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -278,7 +278,7 @@ jobs:
name: Test the "mailcatcher" application bootstrapping
command: |
bin/ci-ansible-playbook bootstrap.yml "mailcatcher"
bin/ci-test-service "mailcatcher" "MailCatcher"
bin/ci-test-route "mailcatcher" "MailCatcher"
# Test the bootstrap playbook on the "richie" application
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -303,15 +303,15 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "richie"
# Test service deployed with the next route
bin/ci-test-service "richie" "Django administration" "/en/admin" "next"
bin/ci-test-route "richie" "Django administration" "/en/admin" "next"
- run:
name: Test the "richie" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "richie"
# Test service switched to the current route
bin/ci-test-service "richie" "Django administration" "/en/admin"
bin/ci-test-route "richie" "Django administration" "/en/admin"
# Test the bootstrap playbook on the "forum" application
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -336,15 +336,15 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "forum"
# Test service deployed with the next route
bin/ci-test-service "forum" "collection" "/api/v1/threads?api_key=thisisafakeapikey" "next"
bin/ci-test-route "forum" "collection" "/api/v1/threads?api_key=thisisafakeapikey" "next"
- run:
name: Test the "forum" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "forum"
# Test service switched to the current route
bin/ci-test-service "forum" "collection" "/api/v1/threads?api_key=thisisafakeapikey"
bin/ci-test-route "forum" "collection" "/api/v1/threads?api_key=thisisafakeapikey"
# Test the bootstrap playbook on the "edxapp" application
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -369,17 +369,17 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "edxapp,redis"
# Test services deployed with the next route
bin/ci-test-service "cms" "Welcome to Your Platform Studio" "/" "next"
bin/ci-test-service "lms" "It works! This is the default homepage for this Open edX instance." "/" "next"
bin/ci-test-route "cms" "Welcome to Your Platform Studio" "/" "next"
bin/ci-test-route "lms" "It works! This is the default homepage for this Open edX instance." "/" "next"
- run:
name: Test the "edxapp" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "edxapp"
# Test service switched to the current route
bin/ci-test-service "cms" "Welcome to Your Platform Studio"
bin/ci-test-service "lms" "It works! This is the default homepage for this Open edX instance."
bin/ci-test-route "cms" "Welcome to Your Platform Studio"
bin/ci-test-route "lms" "It works! This is the default homepage for this Open edX instance."
# Test the bootstrap playbook on the "edxec" application
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -404,14 +404,14 @@ jobs:
# Bootstrap edxec
bin/ci-ansible-playbook bootstrap.yml "edxec"
# Test the service
bin/ci-test-service "edxec" "OK" "/health/" "next"
bin/ci-test-route "edxec" "OK" "/health/" "next"
- run:
name: Test the "edxec" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "edxec"
bin/ci-test-service "edxec" "OK" "/health/"
bin/ci-test-route "edxec" "OK" "/health/"
# Test the bootstrap playbook on the "marsha" application
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -436,15 +436,15 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "marsha"
# Test services deployed with the next route
bin/ci-test-service "marsha" "Api Root" "/api/" "next"
bin/ci-test-route "marsha" "Api Root" "/api/" "next"
- run:
name: Test the "marsha" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "marsha"
# Test service switched to the current route
bin/ci-test-service "marsha" "Api Root" "/api/"
bin/ci-test-route "marsha" "Api Root" "/api/"
# Test the bootstrap playbook on the "learninglocker" application.
# We also need redis and mailcatcher for this application
Expand All @@ -468,15 +468,38 @@ jobs:
name: Test the "learninglocker" application bootstrapping
command: |
bin/ci-ansible-playbook bootstrap.yml "redis,mailcatcher,learninglocker"
bin/ci-test-service "learninglocker" "OK" "/api" "next"
bin/ci-test-route "learninglocker" "OK" "/api" "next"
- run:
name: Test the "learninglocker" application switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "learninglocker"
# Test service switched to the current route
bin/ci-test-service "learninglocker" "OK" "/api"
bin/ci-test-route "learninglocker" "OK" "/api"
# Test the bootstrap playbook on the "elasticsearch" application.
test-bootstrap-elasticsearch:
machine:
docker_layer_caching: false

working_directory: ~/fun

steps:
- checkout
- *attach_workspace
- *docker_load
- *ci_env
- *install_openshift_cluster
- *configure_openshift_cluster
- *run_openshift_cluster

- run:
name: Test the "elasticsearch" application bootstrapping
command: |
bin/ci-ansible-playbook bootstrap.yml "elasticsearch"
oc project ci-eugene
bin/ci-test-service elasticsearch 9200 "green" /_cluster/health
# Test the delete_app tasks for blue-green applications
# nota bene: we use a real OpenShift cluster installed in CircleCI's VM.
Expand All @@ -501,15 +524,15 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "richie"
# Test service deployed with the next route
bin/ci-test-service "richie" "Django administration" "/en/admin" "next"
bin/ci-test-route "richie" "Django administration" "/en/admin" "next"
- run:
name: Test "richie"'s next stack substitution (create + delete)
command: |
# Deploy the next stack a second time
bin/ci-ansible-playbook deploy.yml "richie"
# Test service re-deployed with the next route
bin/ci-test-service "richie" "Django administration" "/en/admin" "next"
bin/ci-test-route "richie" "Django administration" "/en/admin" "next"
- run:
name: Check that only one pod is running Richie's app
Expand Down Expand Up @@ -544,17 +567,17 @@ jobs:
# Bootstrap app
bin/ci-ansible-playbook bootstrap.yml "hello"
# Test service deployed with the next route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "next"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "next"
- run:
name: Test "hello"'s switch
command: |
# Switch next route to current
bin/ci-ansible-playbook switch.yml "hello"
# Test service on the current route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "current"
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "current"
# Test that the service is not responding on next route
bin/ci-test-service "hello" "Hello OpenShift! by Arnold" "/" "next" && exit 1 || true
bin/ci-test-route "hello" "Hello OpenShift! by Arnold" "/" "next" && exit 1 || true
- run:
name: Test that a second switch fails to execute with an error
Expand Down Expand Up @@ -775,6 +798,15 @@ workflows:
filters:
tags:
only: /.*/
- test-bootstrap-elasticsearch:
requires:
- lint-bash
- lint-docker
- lint-ansible
- lint-plugins
filters:
tags:
only: /.*/
- test-delete-app:
requires:
- test-bootstrap-richie
Expand Down Expand Up @@ -812,6 +844,7 @@ workflows:
- test-bootstrap-marsha
- test-bootstrap-forum
- test-bootstrap-learninglocker
- test-bootstrap-elasticsearch
- test-redirect
- test-delete-app
- test-prevent-switch-to-nothing
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Versioning](http://semver.org/spec/v2.0.0.html).

### Added

- New application `elasticsearch` deployable _via_ Arnold
- Configured nginx cache for statics and media files for the following apps:
- `richie`
- `marsha`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cluster.name: {{ elasticsearch_cluster_name }}

# Bind address (listen to all interfaces)
network.host: "0.0.0.0"

{% if elasticsearch_image_tag is version('6.0', '<') %}
bootstrap.mlockall: {{elasticsearch_memory_lock}}
{% else %}
bootstrap.memory_lock: {{elasticsearch_memory_lock}}
{% endif %}

# Cluster discovery address, to get the peer list.
# This is a kubernetes service that target every ES running nodes, even if they
# are not ready yet.
discovery.zen.ping.unicast.hosts: elasticsearch-discovery.{{ project_name }}.svc

discovery.zen.minimum_master_nodes: {{ elasticsearch_minimum_master_nodes }}

# Security features are disabled by default on ES basic and trial licenses
xpack.security.enabled: false

# Monitoring is not supported in this arnold application yet
xpack.monitoring.enabled: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash

set -eo pipefail

declare -r ES_HOST="127.0.0.1"
declare -i ES_PORT={{ elasticsearch_api_port }}
declare -r ES_STARTED="/tmp/es_started"

function testStatus() {
status_to_test="${1}"
expected_status="${2}"

declare -A statuses=( ["red"]=1 ["yellow"]=2 ["green"]=3 )

if [[ -z "${status_to_test}" || -z "${statuses[${status_to_test}]}" ]] ; then
echo "Error: unknown status_to_test [${status_to_test}]" 1>&2
exit 1
fi

if [[ -z "${expected_status}" || -z "${statuses[${expected_status}]}" ]]; then
echo "Error: unknown expected_status [${expected_status}]" 1>&2
exit 2
fi

if [ "${statuses[$status_to_test]}" -lt "${statuses[${expected_status}]}" ]; then
echo "Assertion failed: ${status_to_test} < ${expected_status}"
exit 3
fi
}

if [ -f "${ES_STARTED}" ]; then
echo -n "Elasticsearch is already running. Checking if API is alive..."
curl -fsSL "http://${ES_HOST}:${ES_PORT}/" > /dev/null
echo "OK"
else
echo "Waiting for elasticsearch cluster to be running and in green state..."
health_status=$(
curl -fsSL "http://${ES_HOST}:${ES_PORT}/_cat/health?h=status" | \
sed -r 's/^[[:space:]]+|[[:space:]]+$//g'
)
testStatus "${health_status}" "green"

echo "Waiting for initializing_shards to be 0"
init_shards=$(
curl -fsSL "http://${ES_HOST}:${ES_PORT}/_cat/health?h=init" | \
sed -r 's/^[[:space:]]+|[[:space:]]+$//g'
)

if [ "${init_shards}" -gt 0 ]; then
echo "Synchronization not ready yet, initializing_shards = ${init_shards}"
exit 4
fi

touch "${ES_STARTED}"

echo "Elasticsearch cluster is up (status = ${health_status})"
fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash

set -eo pipefail

declare -i MAX_RETRY=20
declare -i RETRY_DELAY=5
declare -i retry=0

echo -n "Waiting for ES service to be up."
while ! curl --output /dev/null --silent --max-time 1 --connect-timeout 1 --head --fail "http://elasticsearch.{{project_name}}.svc:{{ elasticsearch_api_port }}/"
do
echo -n "."
((retry++)) && ((retry==MAX_RETRY)) && echo "ERROR: timeout" && exit 62
sleep $RETRY_DELAY
done

curl -fssL \
-X PUT "http://elasticsearch.{{ project_name }}.svc:{{ elasticsearch_api_port }}/_template/default" \
-H 'Content-Type: application/json' \
-d \
'{
{% if elasticsearch_image_tag is version('6.0', '<') %}
"template" : "*",
{% else %}
"index_patterns": ["*"],
{% endif %}
"settings" : {
"number_of_shards": {{ elasticsearch_index_default_shards }},
"number_of_replicas": {{ elasticsearch_index_default_replicas }},
"index.store.type": "{{ elasticsearch_index_store_type }}",
"index.unassigned.node_left.delayed_timeout": "{{ elasticsearch_index_node_left_delayed_timeout }}"
}
}'
Loading

0 comments on commit 5a915b1

Please sign in to comment.